Udostępnij za pośrednictwem


Tworzenie własnych monitów o zebranie danych wejściowych użytkownika

DOTYCZY: ZESTAW SDK w wersji 4

Rozmowa między botem a użytkownikiem często wiąże się z monitowaniem (monitowaniem) użytkownika o informacje, analizowaniem odpowiedzi użytkownika, a następnie działaniem na tych informacjach. Bot powinien śledzić kontekst konwersacji, aby mógł zarządzać swoim zachowaniem i pamiętać odpowiedzi na poprzednie pytania. Stan bota to informacje, które śledzi, aby odpowiednio reagować na przychodzące komunikaty.

Napiwek

Biblioteka okien dialogowych udostępnia wbudowane monity, które zapewniają większą funkcjonalność, z których mogą korzystać użytkownicy. Przykłady tych monitów można znaleźć w artykule Implementowanie sekwencyjnego przepływu konwersacji.

Uwaga

Zestawy SDK języka JavaScript, C# i Python platformy Bot Framework będą nadal obsługiwane, jednak zestaw SDK języka Java jest wycofywany z ostatecznym długoterminowym wsparciem kończącym się w listopadzie 2023 r.

Istniejące boty utworzone za pomocą zestawu JAVA SDK będą nadal działać.

W przypadku tworzenia nowych botów rozważ użycie programu Microsoft Copilot Studio i przeczytaj o wyborze odpowiedniego rozwiązania copilot.

Aby uzyskać więcej informacji, zobacz Przyszłość tworzenia botów.

Wymagania wstępne

Informacje o przykładowym kodzie

Przykładowy bot zadaje użytkownikowi serię pytań, weryfikuje niektóre odpowiedzi i zapisuje swoje dane wejściowe. Na poniższym diagramie przedstawiono relację między klasami przepływu bota, profilu użytkownika i konwersacji.

Diagram klas dla przykładu języka C#.

  • UserProfile Klasa informacji o użytkowniku zbieranych przez bota.
  • ConversationFlow Klasa do kontrolowania stanu konwersacji podczas zbierania informacji o użytkowniku.
  • Wewnętrzne ConversationFlow.Question wyliczenie do śledzenia miejsca, w którym jesteś w konwersacji.

Stan użytkownika będzie śledzić nazwę użytkownika, wiek i wybraną datę, a stan konwersacji będzie śledzić to, co ostatnio zapytał użytkownika. Ponieważ nie planujesz wdrożenia tego bota, skonfigurujesz stan użytkownika i konwersacji w celu korzystania z magazynu pamięci.

Aby zarządzać przepływem konwersacji i kolekcją danych wejściowych, należy użyć programu obsługi kolei wiadomości bota oraz właściwości stanu konwersacji. W botze zapiszesz informacje o właściwości stanu odebrane podczas każdej iteracji programu obsługi kolei komunikatów.

Tworzenie konwersacji i obiektów użytkownika

Utwórz obiekty stanu użytkownika i konwersacji podczas uruchamiania i korzystaj z nich za pośrednictwem wstrzykiwania zależności w konstruktorze bota.

Startup.cs

// Create the Bot Adapter with error handling enabled.
services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

// Create the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.)
services.AddSingleton<IStorage, MemoryStorage>();

// Create the User state.
services.AddSingleton<UserState>();

// Create the Conversation state.
services.AddSingleton<ConversationState>();

Boty/CustomPromptBot.cs

private readonly BotState _userState;
private readonly BotState _conversationState;

public CustomPromptBot(ConversationState conversationState, UserState userState)
{
    _conversationState = conversationState;
    _userState = userState;
}

Tworzenie metod dostępu do właściwości

Utwórz metody dostępu właściwości dla właściwości profilu użytkownika i przepływu konwersacji, a następnie wywołaj metodę GetAsync , aby pobrać wartość właściwości ze stanu.

Boty/CustomPromptBot.cs

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    var conversationStateAccessors = _conversationState.CreateProperty<ConversationFlow>(nameof(ConversationFlow));
    var flow = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationFlow(), cancellationToken);

    var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
    var profile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile(), cancellationToken);

Przed zakończeniem kolei wywołaj metodę SaveChangesAsync , aby zapisać zmiany stanu w magazynie.

    await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}

Obsługa kolei komunikatów

Podczas obsługi działań związanych z komunikatami program obsługi komunikatów używa metody pomocniczej do zarządzania konwersacją i monitowania użytkownika. Metoda pomocnika została opisana w poniższej sekcji.

Boty/CustomPromptBot.cs

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    var conversationStateAccessors = _conversationState.CreateProperty<ConversationFlow>(nameof(ConversationFlow));
    var flow = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationFlow(), cancellationToken);

    var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
    var profile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile(), cancellationToken);

    await FillOutUserProfileAsync(flow, profile, turnContext, cancellationToken);

    // Save changes.
    await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}

Wypełnianie profilu użytkownika

Bot monituje użytkownika o podanie informacji na podstawie tego, które pytanie, jeśli istnieje, że bot zapytał w poprzednim skręcie. Dane wejściowe są analizowane przy użyciu metody weryfikacji.

Każda metoda walidacji jest zgodna z podobnym projektem:

  • Wartość zwracana wskazuje, czy dane wejściowe są prawidłową odpowiedzią na to pytanie.
  • Jeśli walidacja przebiegnie pomyślnie, generuje przeanalizowaną i znormalizowaną wartość do zapisania.
  • Jeśli walidacja zakończy się niepowodzeniem, zostanie wyświetlony komunikat, za pomocą którego bot może ponownie poprosić o podanie informacji.

Metody weryfikacji opisano w poniższej sekcji.

Boty/CustomPromptBot.cs

{
    var input = turnContext.Activity.Text?.Trim();
    string message;

    switch (flow.LastQuestionAsked)
    {
        case ConversationFlow.Question.None:
            await turnContext.SendActivityAsync("Let's get started. What is your name?", null, null, cancellationToken);
            flow.LastQuestionAsked = ConversationFlow.Question.Name;
            break;
        case ConversationFlow.Question.Name:
            if (ValidateName(input, out var name, out message))
            {
                profile.Name = name;
                await turnContext.SendActivityAsync($"Hi {profile.Name}.", null, null, cancellationToken);
                await turnContext.SendActivityAsync("How old are you?", null, null, cancellationToken);
                flow.LastQuestionAsked = ConversationFlow.Question.Age;
                break;
            }
            else
            {
                await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.", null, null, cancellationToken);
                break;
            }

        case ConversationFlow.Question.Age:
            if (ValidateAge(input, out var age, out message))
            {
                profile.Age = age;
                await turnContext.SendActivityAsync($"I have your age as {profile.Age}.", null, null, cancellationToken);
                await turnContext.SendActivityAsync("When is your flight?", null, null, cancellationToken);
                flow.LastQuestionAsked = ConversationFlow.Question.Date;
                break;
            }
            else
            {
                await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.", null, null, cancellationToken);
                break;
            }

        case ConversationFlow.Question.Date:
            if (ValidateDate(input, out var date, out message))
            {
                profile.Date = date;
                await turnContext.SendActivityAsync($"Your cab ride to the airport is scheduled for {profile.Date}.");
                await turnContext.SendActivityAsync($"Thanks for completing the booking {profile.Name}.");
                await turnContext.SendActivityAsync($"Type anything to run the bot again.");
                flow.LastQuestionAsked = ConversationFlow.Question.None;
                profile = new UserProfile();
                break;
            }
            else
            {
                await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.", null, null, cancellationToken);
                break;
            }
    }
}

Analizowanie i weryfikowanie danych wejściowych

Bot używa następujących kryteriów do weryfikowania danych wejściowych.

  • Nazwa musi być ciągiem niepustym. Jest znormalizowany przez przycinanie białych znaków.
  • Wiek musi należeć do przedziału od 18 do 120 lat. Jest znormalizowany przez zwrócenie liczby całkowitej.
  • Data musi być dowolną datą lub godziną co najmniej godziny w przyszłości. Jest znormalizowany przez zwrócenie tylko części daty przeanalizowanych danych wejściowych.

Uwaga

W przypadku danych wejściowych dotyczących wieku i daty przykład używa bibliotek Microsoft/Recognizers-Text do wykonywania początkowej analizy. Jest to tylko jeden ze sposobów analizowania danych wejściowych. Aby uzyskać więcej informacji na temat tych bibliotek, zobacz plik README projektu.

Boty/CustomPromptBot.cs

private static bool ValidateName(string input, out string name, out string message)
{
    name = null;
    message = null;

    if (string.IsNullOrWhiteSpace(input))
    {
        message = "Please enter a name that contains at least one character.";
    }
    else
    {
        name = input.Trim();
    }

    return message is null;
}

private static bool ValidateAge(string input, out int age, out string message)
{
    age = 0;
    message = null;

    // Try to recognize the input as a number. This works for responses such as "twelve" as well as "12".
    try
    {
        // Attempt to convert the Recognizer result to an integer. This works for "a dozen", "twelve", "12", and so on.
        // The recognizer returns a list of potential recognition results, if any.

        var results = NumberRecognizer.RecognizeNumber(input, Culture.English);

        foreach (var result in results)
        {
            // The result resolution is a dictionary, where the "value" entry contains the processed string.
            if (result.Resolution.TryGetValue("value", out var value))
            {
                age = Convert.ToInt32(value);
                if (age >= 18 && age <= 120)
                {
                    return true;
                }
            }
        }

        message = "Please enter an age between 18 and 120.";
    }
    catch
    {
        message = "I'm sorry, I could not interpret that as an age. Please enter an age between 18 and 120.";
    }

    return message is null;
}

private static bool ValidateDate(string input, out string date, out string message)
{
    date = null;
    message = null;

    // Try to recognize the input as a date-time. This works for responses such as "11/14/2018", "9pm", "tomorrow", "Sunday at 5pm", and so on.
    // The recognizer returns a list of potential recognition results, if any.
    try
    {
        var results = DateTimeRecognizer.RecognizeDateTime(input, Culture.English);

        // Check whether any of the recognized date-times are appropriate,
        // and if so, return the first appropriate date-time. We're checking for a value at least an hour in the future.
        var earliest = DateTime.Now.AddHours(1.0);

        foreach (var result in results)
        {
            // The result resolution is a dictionary, where the "values" entry contains the processed input.
            var resolutions = result.Resolution["values"] as List<Dictionary<string, string>>;

            foreach (var resolution in resolutions)
            {
                // The processed input contains a "value" entry if it is a date-time value, or "start" and
                // "end" entries if it is a date-time range.
                if (resolution.TryGetValue("value", out var dateString)
                    || resolution.TryGetValue("start", out dateString))
                {
                    if (DateTime.TryParse(dateString, out var candidate)
                        && earliest < candidate)
                    {
                        date = candidate.ToShortDateString();
                        return true;
                    }
                }
            }
        }

        message = "I'm sorry, please enter a date at least an hour out.";
    }
    catch
    {
        message = "I'm sorry, I could not interpret that as an appropriate date. Please enter a date at least an hour out.";
    }

    return false;
}

Testowanie bota lokalnie

Pobierz i zainstaluj program Bot Framework Emulator , aby przetestować bota lokalnie.

  1. Uruchom przykład lokalnie na maszynie. Jeśli potrzebujesz instrukcji, zapoznaj się z plikiem przykładu README języka C#, przykładu JS lub przykładu języka Python.
  2. Przetestuj go przy użyciu emulatora.

Dodatkowe zasoby

Biblioteka Dialogs udostępnia klasy, które automatyzują wiele aspektów zarządzania konwersacjami.

Następny krok