Bagikan melalui


Buat permintaan Anda sendiri untuk mengumpulkan input pengguna

BERLAKU UNTUK: SDK v4

Percakapan antara bot dan pengguna sering melibatkan meminta (meminta) pengguna untuk informasi, mengurai respons pengguna, lalu bertindak berdasarkan informasi tersebut. Bot Anda harus melacak konteks percakapan, sehingga dapat mengelola perilakunya dan mengingat jawaban atas pertanyaan sebelumnya. Status bot adalah informasi yang dilacaknya untuk merespons pesan masuk dengan tepat.

Tip

Pustaka dialog menyediakan perintah bawaan yang menyediakan lebih banyak fungsionalitas yang dapat digunakan pengguna. Contoh perintah tersebut dapat ditemukan di artikel Terapkan alur percakapan berurutan.

Catatan

Bot Framework JavaScript, C#, dan Python SDK akan terus didukung, namun, Java SDK dihentikan dengan dukungan jangka panjang akhir yang berakhir pada November 2023.

Bot yang ada yang dibangun dengan Java SDK akan terus berfungsi.

Untuk pembuatan bot baru, pertimbangkan untuk menggunakan Microsoft Copilot Studio dan baca tentang memilih solusi salinan yang tepat.

Untuk informasi selengkapnya, lihat Masa depan pembuatan bot.

Prasyarat

Tentang kode sampel

Contoh bot mengajukan serangkaian pertanyaan kepada pengguna, memvalidasi beberapa jawaban mereka, dan menyimpan input mereka. Diagram berikut menunjukkan hubungan antara bot, profil pengguna, dan kelas alur percakapan.

Diagram kelas untuk sampel C#.

  • Kelas UserProfile untuk informasi pengguna yang akan dikumpulkan bot.
  • Kelas ConversationFlow untuk mengontrol status percakapan kami saat mengumpulkan informasi pengguna.
  • Enumerasi dalam ConversationFlow.Question untuk melacak di mana Anda berada dalam percakapan.

Status pengguna akan melacak nama pengguna, usia, dan tanggal yang dipilih, dan status percakapan akan melacak apa yang terakhir Anda tanyakan kepada pengguna. Karena Anda tidak berencana untuk menyebarkan bot ini, Anda akan mengonfigurasi status pengguna dan percakapan untuk menggunakan penyimpanan memori.

Anda menggunakan penangan giliran pesan bot ditambah properti status pengguna dan percakapan untuk mengelola alur percakapan dan kumpulan input. Di bot, Anda akan merekam informasi properti status yang diterima selama setiap perulangan penangan giliran pesan.

Membuat percakapan dan objek pengguna

Buat objek status pengguna dan percakapan saat startup dan gunakan melalui injeksi dependensi di konstruktor bot.

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>();

Bot/CustomPromptBot.cs

private readonly BotState _userState;
private readonly BotState _conversationState;

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

Membuat aksesor properti

Buat aksesor properti untuk profil pengguna dan properti alur percakapan lalu panggil GetAsync untuk mengambil nilai properti dari status.

Bot/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);

Sebelum belokan berakhir, panggil SaveChangesAsync untuk menulis perubahan status apa pun pada penyimpanan.

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

Penangan giliran pesan

Saat menangani aktivitas pesan, handler pesan menggunakan metode pembantu untuk mengelola percakapan dan meminta pengguna. Metode pembantu dijelaskan di bagian berikut.

Bot/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);
}

Mengisi profil pengguna

Bot meminta informasi kepada pengguna, berdasarkan pertanyaan mana, jika ada, yang diminta bot pada giliran sebelumnya. Input diurai menggunakan metode validasi.

Setiap metode validasi mengikuti desain serupa:

  • Nilai pengembalian menunjukkan apakah input adalah jawaban yang valid untuk pertanyaan ini.
  • Jika validasi lolos, validasi menghasilkan nilai yang diurai dan dinormalisasi untuk disimpan.
  • Jika validasi gagal, bot dapat meminta informasi lagi.

Metode validasi dijelaskan di bagian berikut.

Bot/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;
            }
    }
}

Mengurai dan memvalidasi input

Bot menggunakan kriteria berikut untuk memvalidasi input.

  • Nama harus berupa string yang tidak kosong. Ini dinormalisasi dengan memangkas spasi putih.
  • Usia harus antara 18 dan 120. Ini dinormalisasi dengan mengembalikan bilangan bulat.
  • Tanggal harus tanggal atau waktu apa pun setidaknya satu jam di masa mendatang. Ini dinormalisasi dengan mengembalikan hanya bagian tanggal input yang diurai.

Catatan

Untuk input usia dan tanggal, sampel menggunakan pustaka Microsoft/Recognizers-Text untuk melakukan penguraian awal. Ini hanya salah satu cara untuk mengurai input. Untuk informasi selengkapnya tentang pustaka ini, lihat README proyek.

Bot/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;
}

Menguji bot secara lokal

Unduh dan instal Emulator Kerangka Kerja Bot untuk menguji bot secara lokal.

  1. Jalankan sampel secara lokal di komputer Anda. Jika Anda memerlukan instruksi, lihat README file untuk sampel C#, sampel JS, atau sampel Python.
  2. Uji menggunakan Emulator.

Sumber Daya Tambahan:

Pustaka Dialog menyediakan kelas yang mengotomatiskan banyak aspek pengelolaan percakapan.

Langkah selanjutnya