В конце концов я реализовал что-то, что будет работать для собственного клиента бота / клиента прямого канала бота.
Весь смысл в том, что вызов API qnamaker должен происходить со старым контекстным объектом, всякий раз, когда выбирается опция, даже если она находится вне контекста.
Сначала позвольте мнеобъясните, как это работает в текущей версии кода. Способ, которым код бота пытался решить многооборотный диалог, заключался в сохранении текущего ответа, если у него были подсказки / опции, и возвращении состояния разговора в режиме ожидания. Когда будет получен следующий вопрос, он автоматически предположит, что новый вопрос является частью подсказок / опций старого вопроса. Затем он передаст oldstate вместе с QnAMaker. Я заметил, что даже если вопрос во втором повороте не является частью подсказок / опций (что-то, что пользователь набрал вручную, и это совершенно другой вопрос), он все равно отправит объект oldstate в QnAMaker. Вызов API QnAMaker, похоже, игнорирует oldstate, если новый вопрос не является частью запросов / опций oldstate. Он будет работать правильно, получая ответ на новый вопрос, набранный вручную. Это был ключ. Если мы сможем сосредоточиться на том, что попадет в qnamaker, то мы сможем решить нашу первоначальную проблему.
Я понял, что возвращение бота в состояние ожидания - это всего лишь механизм для создания условия для извлечения старого состояния в следующем ходу,Однако, если я смогу перестроить старое состояние в любое время, когда будет выбран выбранный параметр, то вызов qnamaker будет работать одинаково хорошо.
Это то, что я сделал сейчас. В моем собственном коде хоста бота (который является клиентом прямой линии) я отправляю поле ReplyToID, заполненное исходным вопросом, при каждом нажатии на приглашение. Затем в коде бота я изменил его так, что, если присутствует answertoid, тогда создайте новый объект oldstate с данными из ответа на id. Ниже приведен класс QnABotState, представляющий старое состояние. Это очень простой класс, содержащий предыдущий идентификатор вопроса qna и текст вопроса.
public int PreviousQnaId { get; set; }
public string PreviousUserQuery { get; set; }
Класс QnABoState
Теперь проблема заключалась в том, что объект Activity содержит ReplyToId, но нене содержит ReplyToQuery (или что-то подобное). Объект действия используется для отправки данных от клиента бота к боту. Итак, мне нужно будет использовать другое поле или отправить PreviousUserQuery в виде пустой строки. У меня была догадка, что это сработает только с предыдущим сообщением.
//starting the process to get the old context (create an object that will hold the Process function's current state from the dialog state)
//if there is replyToId field is present, then it is a direct channel request who is replying to an old context
//get the reply to id from summary field
var curReplyToId = "";
curReplyToId = dialogContext.Context.Activity.ReplyToId;
var curReplyToQuery = "";
var oldState = GetPersistedState(dialogContext.ActiveDialog);
//if oldstate is null also check if there is replytoid populated, if it is then it maybe a new conversation but it is actually an "out of turn option" selection.
if (oldState == null)
{
if (!string.IsNullOrEmpty(curReplyToId))
{
//curReplyToId is not empty. this is an option that was selected out-of-context
int prevQnaId = -1;
int.TryParse(curReplyToId, out prevQnaId);
oldState = new QnABotState() { PreviousQnaId = prevQnaId, PreviousUserQuery = curReplyToQuery };
}
}
После этого мой вызов API qnamaker получит объект oldstate, даже если он будет вызван вне контекста.
Я попробовал код, и он работал. Отсутствие предыдущего запроса qna не имело значения. Он работал только при заполнении поля PreviousQnaId.
Однако, обратите внимание, это не будет работать для других каналов. Это будет работать для каналов, где вы можете установить поле ReplyToId, например Direct Channel Client.
Вот код с моего хоста бота:
// to create a new message
Activity userMessage = new Activity
{
From = new ChannelAccount(User.Identity.Name),
Text = questionToBot,
Type = ActivityTypes.Message,
Value = paramChatCode,// + "|" + "ShahID-" + DateTime.Now.TimeOfDay,
Id = "ShahID-" + DateTime.Now.TimeOfDay,
ChannelData = botHostId//this will be added as the bot host identifier
};
//userMessage.Type = "imBack";
if (paramPreviousChatId > 0)
{
//we have a valid replytoid (as a part of dialog)
userMessage.ReplyToId = paramPreviousChatId.ToString();
}