Проблема с настройкой бота Form Flow

Я хочу создать бота, который может использовать API QnA и поисковый API Google Диска. Я спрошу пользователя, хочет ли он запросить базу знаний или он хочет найти файл на диске. Для этого я выбрал шаблон бота Form Flow от Bot Framework. В этом случае, если пользователь выбирает запрос qna api, я хочу опубликовать вопрос в QNA api. Как я могу реализовать это в моем боте? Где я могу найти выбор пользователя в потоке.

Вот MessageController.cs

        public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
        {
            if (activity.Type == ActivityTypes.Message)
            {
                await Conversation.SendAsync(activity, MakeRootDialog);
            }
            else
            {
                HandleSystemMessage(activity);
            }
            var response = Request.CreateResponse(HttpStatusCode.OK);
            return response;
        }

        private Activity HandleSystemMessage(Activity message)
        {
            if (message.Type == ActivityTypes.DeleteUserData)
            {
                // Implement user deletion here
                // If we handle user deletion, return a real message
            }
            else if (message.Type == ActivityTypes.ConversationUpdate)
            {
                // Handle conversation state changes, like members being added and removed
                // Use Activity.MembersAdded and Activity.MembersRemoved and Activity.Action for info
                // Not available in all channels
            }
            else if (message.Type == ActivityTypes.ContactRelationUpdate)
            {
                // Handle add/remove from contact lists
                // Activity.From + Activity.Action represent what happened
            }
            else if (message.Type == ActivityTypes.Typing)
            {
                // Handle knowing tha the user is typing
            }
            else if (message.Type == ActivityTypes.Ping)
            {
            }

            return null;
        }
        internal static IDialog<UserIntent> MakeRootDialog()
        {
            return Chain.From(() => FormDialog.FromForm(UserIntent.BuildForm));
        }

Конструктор форм

public static IForm<UserIntent> BuildForm()
 {
   return new FormBuilder<UserIntent>()
     .Message("Welcome to the bot!")
     .OnCompletion(async (context, profileForm) =>
      {
         await context.PostAsync("Thank you");
      }).Build();
 }

person Sonali    schedule 12.03.2018    source источник


Ответы (2)


FormFlow больше подходит для управляемой беседы. Мне не кажется, что это соответствует вашим требованиям. Вы можете просто использовать PromptDialog, чтобы получить ответ пользователя, для какого типа поиска он предпочитает, а затем перенаправить следующее сообщение в соответствующее диалоговое окно. Что-то вроде:

[Serializable]
public class RootDialog : IDialog<object>
{
    const string QnAMakerOption = "QnA Maker";
    const string GoogleDriveOption = "Google Drive";
    const string QueryTypeDataKey = "QueryType";

    public Task StartAsync(IDialogContext context)
    {
        context.Wait(MessageReceivedAsync);

        return Task.CompletedTask;
    }

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
    {
        var activity = await result as Activity;

        if(context.UserData.ContainsKey(QueryTypeDataKey))
        {
            var userChoice = context.UserData.GetValue<string>(QueryTypeDataKey);
            if(userChoice == QnAMakerOption)
                await context.Forward(new QnAMakerDialog(), ResumeAfterQnaMakerSearch, activity);
            else
                await context.Forward(new GoogleDialog(), ResumeAfterGoogleSearch, activity);
        }
        else
        {
            PromptDialog.Choice(
                  context: context,
                  resume: ChoiceReceivedAsync,
                  options: new[] { QnAMakerOption, GoogleDriveOption },
                  prompt: "Hi. How would you like to perform the search?",
                  retry: "That is not an option. Please try again.",
                  promptStyle: PromptStyle.Auto
            );
        }            
    }
    private Task ResumeAfterGoogleSearch(IDialogContext context, IAwaitable<object> result)
    {
        //do something after the google search dialog finishes
        return Task.CompletedTask;
    }
    private Task ResumeAfterQnaMakerSearch(IDialogContext context, IAwaitable<object> result)
    {
        //do something after the qnamaker dialog finishes
        return Task.CompletedTask;
    }

    private async Task ChoiceReceivedAsync(IDialogContext context, IAwaitable<object> result)
    {
        var userChoice = await result;
        context.UserData.SetValue(QueryTypeDataKey, userChoice);

        await context.PostAsync($"Okay, your preferred search is {userChoice}.  What would you like to search for?");
    }
}
person Eric Dahlvang    schedule 12.03.2018

Сначала вам нужно создать приложение LUIS через портал LUIS, добавить туда свои намерения с высказываниями, например: - intent - это «KnowlegeBase», внутри которого вы можете создать столько высказываний, которые будут возвращать это намерение.

Внутри приложения создайте класс LUISDialog и вызовите его из своей BuildForm: -

    await context.Forward(new MyLuisDialog(), ResumeDialog, activity, CancellationToken.None);

LuisDialog класс: -

  public class MyLuisDialog : LuisDialog<object>
{
    private static ILuisService GetLuisService()
    {
        var modelId = //Luis modelID;
        var subscriptionKey = //Luis subscription key
        var staging = //whether point to staging or production LUIS
        var luisModel = new LuisModelAttribute(modelId, subscriptionKey) { Staging = staging };
        return new LuisService(luisModel);
    }

    public MyLuisDialog() : base(GetLuisService())
    {

    }

 [LuisIntent("KnowledgeBase")]
    public async Task KnowledgeAPICall(IDialogContext context, LuisResult result)
    {
        //your code
    }

Чтобы использовать сообщение, переданное пользователем, вы можете использовать его из контекста в параметре.

person Shikhar Thakur    schedule 12.03.2018
comment
как я могу вызвать await context.Forward(new MyLuisDialog(), ResumeDialog, activity, CancellationToken.None); из конструктора форм. Во-первых, я хочу сначала определить выбор пользователя. - person Sonali; 12.03.2018
comment
Использование LUIS здесь может быть бесполезным, поскольку OP явно запрашивал службу QnA, и ему просто нужно знать, хочет ли пользователь использовать эту службу или использовать другую службу (поиск на Google Диске) - person Nicolas R; 13.03.2018