Есть ли какой-нибудь возможный способ применить luis после захвата пользовательского ввода из адаптивного текстового блока? - PullRequest
0 голосов
/ 18 февраля 2019

В боте у нас есть адаптивная карта, на которой пользователь может выбрать «да» или «нет».При выборе ДА пользователю предлагается ввести ключевые слова.После того, как пользователь вводит данные в текстовом блоке адаптивной карты, ввод должен быть записан и отправлен в качестве входного параметра в веб-API.Однако после того, как введен ввод, нам придется применить luis, так как существует возможность иметь синонимы для входного текста.В приведенном ниже коде переменная ключевых слов относится к вводимому пользователем тексту, для которого должен применяться LUIS.

    private async Task CustomisePPT(IDialogContext context, IAwaitable<object> result)
    {          
        try
        {                
            var replyMessage = context.MakeMessage();
            var newMessage = context.Activity.AsMessageActivity();
            var userMessage = newMessage.Value;
            var take=userMessage.ToString().Substring(userMessage.ToString().IndexOf("GetUserInputKeywords"));
            var split = take.ToString().Substring("GetUserInputKeywords".Length+2);
            string keywords = split.Trim();
            keywords = keywords.Substring(1, keywords.Length - 5);

            using (HttpClient client = new HttpClient())
            {
                // api takes the user message as a query paramater
                string RequestURI = "https://xyz" + ***keywords***;
                HttpResponseMessage responsemMsg = await client.GetAsync(RequestURI);
                // TODO: handle fail case

                if (responsemMsg.IsSuccessStatusCode)
                {
                    var apiResponse = await responsemMsg.Content.ReadAsStringAsync();
                }
            }
        }
        catch (Exception ex)
        {

        }
        //throw new NotImplementedException();
        await Task.CompletedTask;
    }

Ответы [ 2 ]

0 голосов
/ 18 февраля 2019

@ Ответ Тахера поможет вам интегрировать LUIS.Этот поможет вам использовать его с адаптивными картами.

Адаптивные карты отправляют свои результаты отправки немного иначе, чем текст обычного пользователя.Когда пользователь набирает в чате и отправляет обычное сообщение, оно заканчивается на Context.Activity.Text.Когда пользователь заполняет ввод на адаптивной карте, он заканчивается на Context.Activity.Value, который является объектом, в котором имена ключей равны id на вашей карте, а значения - значения полей в адаптивной карте.

Например, json:

{
    "type": "AdaptiveCard",
    "body": [
        {
            "type": "TextBlock",
            "text": "Test Adaptive Card"
        },
        {
            "type": "ColumnSet",
            "columns": [
                {
                    "type": "Column",
                    "items": [
                        {
                            "type": "TextBlock",
                            "text": "Text:"
                        }
                    ],
                    "width": 20
                },
                {
                    "type": "Column",
                    "items": [
                        {
                            "type": "Input.Text",
                            "id": "userText",
                            "placeholder": "Enter Some Text"
                        }
                    ],
                    "width": 80
                }
            ]
        }
    ],
    "actions": [
        {
            "type": "Action.Submit",
            "title": "Submit"
        }
    ],
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.0"
}

.. создает карту, которая выглядит следующим образом:

Test Adaptive Card

Если пользователь вводит «Testing Testing 123» в текстовое поле и нажимает «Отправить», Context.Activity будет выглядеть примерно так:

{ type: 'message',
  value: { userText: 'Testing Testing 123' },
  from: { id: 'xxxxxxxx-05d4-478a-9daa-9b18c79bb66b', name: 'User' },
  locale: '',
  channelData: { postback: true },
  channelId: 'emulator',
  conversation: { id: 'xxxxxxxx-182b-11e9-be61-091ac0e3a4ac|livechat' },
  id: 'xxxxxxxx-182b-11e9-ad8e-63b45e3ebfa7',
  localTimestamp: 2019-01-14T18:39:21.000Z,
  recipient: { id: '1', name: 'Bot', role: 'bot' },
  timestamp: 2019-01-14T18:39:21.773Z,
  serviceUrl: 'http://localhost:58453' }

Представление пользователя можно увидеть в Context.Activity.Value.userText.

Обратите внимание, что отправка адаптивной карты отправляется как postBack, что означает, что данные отправки не отображаются в окне чата как часть разговора - они остаются на адаптивной карте.

Использование адаптивных карт с Waterfall Dialogs

Ваш вопрос не совсем связан с этим, но, поскольку вы можете попытаться это сделать, я подумал, что важно включить его в свойответ.

Собственно, адаптивные карты не работают как подсказки.При появлении приглашения оно будет отображаться и ждать ввода пользователя, прежде чем продолжить.Но с адаптивными картами (даже если они содержат поле ввода и кнопку отправки), в адаптивной карте нет кода, который заставлял бы диалоговое окно «Водопад» ожидать ввода пользователя, прежде чем продолжить диалог.

Итак,если вы используете адаптивную карту, которая принимает пользовательский ввод, вы, как правило, хотите обрабатывать все, что пользователь отправляет, вне контекста диалога водопада.

При этом, если вы хотите использовать адаптивную карту какчасть диалога водопада, есть обходной путь.По сути, вы:

  1. Отображение адаптивной карты
  2. Отображение текстовой подсказки
  3. Преобразование ввода адаптивной карты пользователя во ввод текстовой подсказки

В вашем классе Waterfall Dialog (шаги 1 и 2):

private async Task<DialogTurnResult> DisplayCardAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    // Create the Adaptive Card
    var cardPath = Path.Combine(".", "AdaptiveCard.json");
    var cardJson = File.ReadAllText(cardPath);
    var cardAttachment = new Attachment()
    {
        ContentType = "application/vnd.microsoft.card.adaptive",
        Content = JsonConvert.DeserializeObject(cardJson),
    };

    // Create the text prompt
    var opts = new PromptOptions
    {
        Prompt = new Activity
        {
            Attachments = new List<Attachment>() { cardAttachment },
            Type = ActivityTypes.Message,
            Text = "waiting for user input...", // You can comment this out if you don't want to display any text. Still works.
        }
    };

    // Display a Text Prompt and wait for input
    return await stepContext.PromptAsync(nameof(TextPrompt), opts);
}

private async Task<DialogTurnResult> HandleResponseAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    // Do something with step.result
    // Adaptive Card submissions are objects, so you likely need to JObject.Parse(step.result)
    await stepContext.Context.SendActivityAsync($"INPUT: {stepContext.Result}");
    return await stepContext.NextAsync();
}

В вашем классе основного бота (<your-bot>.cs) (шаг 3):

var activity = turnContext.Activity;

if (string.IsNullOrWhiteSpace(activity.Text) && activity.Value != null)
{
    activity.Text = JsonConvert.SerializeObject(activity.Value);
}

Используя это, чтобы ответить на ваш вопрос

Вы можете справиться с интеграцией этого с LUIS либо в HandleResponseAsync() (если вас действительно не волнует, что точный пользовательский ввод заканчивается в Step.Result, или вы можете справиться с этимв блоке if (channelData.ContainsKey("postback")) (если вы хотите изменить пользовательский ввод перед отправкой на следующий шаг в вашем диалоге.

0 голосов
/ 18 февраля 2019

Это на самом деле просто вызов API, который необходимо настроить.

Во-первых, вы должны добавить конфигурацию Luis в ваш файл .bot.

{
"name": "LuisBot",
"description": "",
"services": [
    {
        "type": "endpoint",
        "name": "development",
        "endpoint": "http://localhost:3978/api/messages",
        "appId": "",
        "appPassword": "",
        "id": "166"
    },
    {
        "type": "luis",
        "name": "LuisBot",
        "appId": "<luis appid>",
        "version": "0.1",
        "authoringKey": "<luis authoring key>",
        "subscriptionKey": "<luis subscription key>",
        "region": "<luis region>",
        "id": "158"
    }
],
"padlock": "",
"version": "2.0"

}

Далее мы инициализируем новый экземпляр класса BotService в BotServices.cs, который извлекает вышеуказанную информацию из вашего файла .bot.Внешняя служба настраивается с использованием класса BotConfiguration.

public class BotServices
{
    // Initializes a new instance of the BotServices class
    public BotServices(BotConfiguration botConfiguration)
    {
        foreach (var service in botConfiguration.Services)
        {
            switch (service.Type)
            {
                case ServiceTypes.Luis:
                {
                    var luis = (LuisService)service;
                    if (luis == null)
                    {
                        throw new InvalidOperationException("The LUIS service is not configured correctly in your '.bot' file.");
                    }

                    var app = new LuisApplication(luis.AppId, luis.AuthoringKey, luis.GetEndpoint());
                    var recognizer = new LuisRecognizer(app);
                    this.LuisServices.Add(luis.Name, recognizer);
                    break;
                    }
                }
            }
        }

    // Gets the set of LUIS Services used. LuisServices is represented as a dictionary.  
    public Dictionary<string, LuisRecognizer> LuisServices { get; } = new Dictionary<string, LuisRecognizer>();
}

Затем зарегистрируйте приложение LUIS в качестве одиночного файла в файле Startup.cs, используя следующий код в методе ConfigureServices.

// Initialize Bot Connected Services clients.
var connectedServices = new BotServices(botConfig);
services.AddSingleton(sp => connectedServices);
services.AddSingleton(sp => botConfig);

Внедрить службы, настроенные в файле .bot, в ваш Bot.cs Класс:

public class LuisBot : IBot
{
    // Services configured from the ".bot" file.
    private readonly BotServices _services;

    // Initializes a new instance of the LuisBot class.
    public LuisBot(BotServices services)
    {
        _services = services ?? throw new System.ArgumentNullException(nameof(services));
        if (!_services.LuisServices.ContainsKey(LuisKey))
        {
            throw new System.ArgumentException($"Invalid configuration....");
        }
    }
}

Ввод adaptivecard может быть зафиксирован в массиве действийadaptivecard как Action.Submit вот так:

"type": "Action.Submit"

СЕЙЧАС вы можете сделать вызов Luis API, который вам действительно нужен.Этот вызов может быть выполнен в любом месте вашего класса, в который добавляется служба Luis:

 var recognizerResult = await _services.LuisServices[LuisKey].RecognizeAsync(turnContext, cancellationToken);

Этот фрагмент кода взят из MS Docs здесь

...