ユーザー入力を収集するために独自のプロンプトを作成するCreate your own prompts to gather user input

適用対象: SDK v4APPLIES TO: SDK v4

多くの場合、ボットとユーザー間の会話では、ユーザーに情報の入力を求め、ユーザーの応答を解析し、その情報に基づいてアクションを実行する必要があります。A conversation between a bot and a user often involves asking (prompting) the user for information, parsing the user's response, and then acting on that information. お使いのボットは会話のコンテキストを追跡する必要があります。これにより、自身の動作を管理し、以前の質問に対する回答を記憶することができます。Your bot should track the context of a conversation, so that it can manage its behavior and remember answers to previous questions. ボットの "状態" は、受信メッセージに適切に応答するためにボットが追跡する情報です。A bot's state is information it tracks to respond appropriately to incoming messages.

ヒント

ダイアログ ライブラリには、ユーザーが使用できるより多くの機能を提供する組み込みのプロンプトが提供されます。The dialogs library provides built-in prompts that provide more functionality that users can use. これらのプロンプトの例については、「連続して行われる会話フローの実装」を参照してください。Examples of those prompts can be found in the Implement sequential conversation flow article.

前提条件Prerequisites

サンプル コードについてAbout the sample code

サンプル ボットでは、ユーザーに対して一連の質問を行い、その回答の一部を検証して、入力を保存します。The sample bot asks the user a series of questions, validates some of their answers, and saves their input. 次の図は、ボット、ユーザー プロファイル、および会話フロー クラスの間の関係を示しています。The following diagram shows the relationship between the bot, user profile, and conversation flow classes.

C でのカスタム プロンプト#

  • ボットによって収集されるユーザー情報を表す UserProfile クラス。A UserProfile class for the user information that the bot will collect.
  • ユーザー情報を収集しているときに、会話状態を制御する ConversationFlow クラス。A ConversationFlow class to control our conversation state while gathering user information.
  • 会話内 ConversationFlow.Question の場所を追跡する内部列挙体。An inner ConversationFlow.Question enumeration for tracking where you are in the conversation.

ユーザーの状態は、ユーザーの名前、年齢、選択した日付を追跡し、会話の状態は、ユーザーに尋ねたことを追跡します。The user state will track the user's name, age, and chosen date, and conversation state will track what you've just asked the user. このボットをデプロイする予定はいらないので、メモリ ストレージ を使用するためにユーザーと会話の両方の状態を 構成しますSince you don't plan to deploy this bot, you'll configure both user and conversation state to use memory storage.

ボットのメッセージ ターン ハンドラーとユーザーと会話状態のプロパティを使用して、会話のフローと入力のコレクションを管理します。You use the bot's message turn handler plus user and conversation state properties to manage the flow of the conversation and the collection of input. ボットでは、メッセージ ターン ハンドラーの各イテレーション中に受信した状態プロパティ情報を記録します。In your bot, you'll record the state property information received during each iteration of the message turn handler.

会話およびユーザー オブジェクトを作成するCreate conversation and user objects

ユーザーおよび会話状態オブジェクトをスタートアップ時に作成し、ボット コンストラクターで依存関係挿入によりそれらを使用します。Create the user and conversation state objects at startup and consume them via dependency injection in the bot constructor.

Startup.csStartup.cs

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

Bots/CustomPromptBot.csBots/CustomPromptBot.cs

private readonly BotState _userState;
private readonly BotState _conversationState;

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

プロパティ アクセサーを作成するCreate property accessors

ユーザー プロファイルと会話フローのプロパティのプロパティ アクセサーを作成し、GetAsync を呼び出して、状態からプロパティ値を取得します。Create property accessors for the user profile and conversation flow properties and then call GetAsync to retrieve the property value from state.

Bots/CustomPromptBot.csBots/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);

ターンを終了する前に、SaveChangesAsync を呼び出して、状態の変更をストレージに書き込みます。Before the turn ends, call SaveChangesAsync to write any state changes to storage.

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

ボットのメッセージ ターン ハンドラーThe bot's message turn handler

メッセージ アクティビティを処理する場合、メッセージ ハンドラーではヘルパー メソッドを使用して会話を管理し、ユーザーにメッセージを表示します。When handling message activities, the message handler uses a helper method to manage the conversation and prompt the user. ヘルパー メソッドについては、次のセクションで説明します。The helper method is described in the following section.

Bots/CustomPromptBot.csBots/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);
}

ユーザー プロファイルを入力するFilling out the user profile

ボットは、ボットが前のターンで尋ねた質問 (存在する場合) に基づいて、ユーザーに情報の入力を求めます。The bot prompts the user for information, based on which question, if any, that the bot asked on the previous turn. 入力は検証メソッドを使用して解析されます。Input is parsed using a validation method.

各検証メソッドは、次のような同様の設計に従います。Each validation method follows a similar design:

  • 戻り値は、入力が、この質問に対して有効な回答であるかどうか示しています。The return value indicates whether the input is a valid answer for this question.
  • 検証に合格すると、解析および正規化された値が生成され、保存されます。If validation passes, it produces a parsed and normalized value to save.
  • 検証に失敗した場合はメッセージが生成され、ボットはこれを使用して情報を再度求めることができます。If validation fails, it produces a message with which the bot can ask for the information again.

検証メソッドについては、以下のセクションで説明します。The validation methods are described in the following section.

Bots/CustomPromptBot.csBots/CustomPromptBot.cs

private static async Task FillOutUserProfileAsync(ConversationFlow flow, UserProfile profile, ITurnContext turnContext, CancellationToken cancellationToken)
{
    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;
            }
    }
}

入力を解析して検証するParse and validate input

ボットでは、次の条件を使用して入力が検証されます。The bot uses the following criteria to validate input.

  • name は、空でない文字列にする必要があります。The name must be a non-empty string. 空白文字を削除することで正規化されます。It's normalized by trimming white-space.
  • age は、18 から 120 の値にする必要があります。The age must be between 18 and 120. 整数を返すことで正規化されます。It's normalized by returning an integer.
  • date は、1 時間以上未来の日付または時刻にする必要があります。The date must be any date or time at least an hour in the future. 解析された入力の日付部分のみを返すことで正規化されます。It's normalized by returning just the date portion of the parsed input.

注意

年齢と日付の入力では 、Microsoft/Recognizers-Text ライブラリを使用して初期解析を実行します。For the age and date input, you use the Microsoft/Recognizers-Text libraries to perform the initial parsing. サンプル コードを提供する一方で、テキスト認識エンジン ライブラリの動作を説明する必要はありません。これは入力を解析する 1 つの方法にすらすみではありません。While you provide sample code, you do not explain how the text recognizers libraries work, and this is just one way to parse the input. これらのライブラリの詳細については、リポジトリの README を参照してください。For more information about these libraries, see the repository's README.

Bots/CustomPromptBot.csBots/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;
}

ボットをローカルでテストするTest the bot locally

ボットをローカルでテストするための Bot Framework Emulator をダウンロードし、インス―ルします。Download and install the Bot Framework Emulator to test the bot locally.

  1. ご自身のマシンを使ってローカルでサンプルを実行します。Run the sample locally on your machine. 手順については、README ファイルで C# サンプルJS サンプル、または Python サンプルを参照してください。If you need instructions, refer to the README file for C# sample, JS sample, or the Python sample.
  2. 次に示すようにエミュレーターを使用してテストします。Test it using the Emulator as shown below.

エミュレーターでのサンプル操作

その他のリソースAdditional resources

ダイアログ ライブラリには、会話の管理に関するさまざまな側面を自動化するクラスが用意されています。The Dialogs library provides classes that automate many aspects of managing conversations.

次のステップNext step