はじめに
Bot Frameworkとdocomo雑談対話APIを使用したチャットBotを作ってみました。
Bot Frameworkとは
- Microsoftが提供するBotを簡単に作れるフレームワーク
- 1つBotを作ることで複数のクライアントに対応出来る
- 作ったBotはAzureにデプロイでき簡単に公開も出来る
といった感じのすごいやつ。
詳しくは↓とか
MS公式:About the Bot Framework
↓とかを参照。
SlideShare:Bot frameworkでbot入門
docomo雑談対話APIとは
- NTTドコモが提供するユーザーの発話テキストに対して、自然な会話となる雑談を応答するAPI
- ユーザーの情報を設定するとそれに合わせた応答をしてくれる
- NTTドコモが提供するdアカウントによる認証を行うと、より趣味嗜好に合わせた応答をしてくれる
- しりとりが出来る!!!!!
詳しくは↓を参照。
https://dev.smt.docomo.ne.jp/?p=docs.api.page&api_name=dialogue&p_name=api_usage_scenario
前提条件
開発環境
- Visual Studio 2017 Community
-
Bot Application テンプレートをダウンロードし、テンプレートディレクトリに配置。
テンプレートディレクトリは通常は以下の通り。
%USERPROFILE%\Documents\Visual Studio 2017\Templates\ProjectTemplates\Visual C#\
アカウントなど
- Azure登録済みのMicrosoftアカウント
- docomo Developer support 開発者アカウント登録はdocomo Developer supportから
- 開発者アカウント登録後、雑談対話API開発用APIキーを取得しておく。
実際にやってみる
プログラム作成
プロジェクト作成
Visual Studioからプロジェクトの新規作成を行います。
Bot Applicationテンプレートが正しく配置されている場合、Bot Applicationが一覧に表示され選択出来ます。
新規作成した直後のソリューションエクスプローラーはこんな感じ。
テンプレートから新規作成した状態では、各種NuGetパッケージがソリューションに存在しないので復元をしてください。
docomo雑談対話APIのREST APIやりとりJSON用クラスの作成
docomo雑談対話APIリファレンスを確認して、
リクエストボディJSON、レスポンスボディJSON用のクラスを作成します。
※2017年11月01日時点ですので、JSONの内容が変更になっていたら適宜変更してください。
[Serializable]
public class RequestBody
{
[JsonProperty(PropertyName = "utt")]
public string Utt { get; set; }
[JsonProperty(PropertyName = "context")]
public string Context { get; set; }
[JsonProperty(PropertyName = "nickname")]
public string Nickname { get; set; }
[JsonProperty(PropertyName = "nickname_y")]
public string Nickname_y { get; set; }
[JsonProperty(PropertyName = "sex")]
public string Sex { get; set; }
[JsonProperty(PropertyName = "bloodtype")]
public string Bloodtype { get; set; }
[JsonProperty(PropertyName = "birthdateY")]
public string BirthdateY { get; set; }
[JsonProperty(PropertyName = "birthdateM")]
public string BirthdateM { get; set; }
[JsonProperty(PropertyName = "birthdateD")]
public string BirthdateD { get; set; }
[JsonProperty(PropertyName = "age")]
public string Age { get; set; }
[JsonProperty(PropertyName = "constellations")]
public string Constellations { get; set; }
[JsonProperty(PropertyName = "place")]
public string Place { get; set; }
[JsonProperty(PropertyName = "mode")]
public string Mode { get; set; }
[JsonProperty(PropertyName = "t")]
public string T { get; set; }
}
public class ResponseBody
{
[JsonProperty(PropertyName = "utt")]
public string Utt { get; set; }
[JsonProperty(PropertyName = "yomi")]
public string Yomi { get; set; }
[JsonProperty(PropertyName = "mode")]
public string Mode { get; set; }
[JsonProperty(PropertyName = "da")]
public string Da { get; set; }
[JsonProperty(PropertyName = "context")]
public string Context { get; set; }
}
チャットBotとユーザーのやりとり作成
Bot Frameworkで実際にユーザーとのやりとりを記述するのは、RootDialog.csです。
今回はテンプレートで作成されるクラスの中で修正するのはこいつのみです。
テンプレートで新規作成されるRootDialogクラスの内容は以下の通り。
入力した文字列と文字列長を返すBot。
これだけでも動作するので、手っ取り早く動かしたい人はソースを修正しなくてもOK。
[Serializable]
public class RootDialog : IDialog<object>
{
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;
// calculate something for us to return
int length = (activity.Text ?? string.Empty).Length;
// return our reply to the user
await context.PostAsync($"You sent {activity.Text} which was {length} characters");
context.Wait(MessageReceivedAsync);
}
}
####クラス変数
requestUrlは雑談対話APIのリクエストURLを設定します。
apiKeyは取得した雑談対話API開発用APIキーを設定します。
private const string requestUrl = @"https://api.apigw.smt.docomo.ne.jp/dialogue/v1/dialogue";
private const string apiKey = @"{雑談対話API開発用APIキー}";
private string[] settings = new string[] { "名前(ニックネーム)", "性別", "血液型", "年齢", "星座", "地域", "生年月日", "設定終了" };
private Entity.RequestBody requestBody;
####StartAsyncメソッド
ユーザーから何かしらメッセージ受け取るとこのメソッドが呼ばれます。
最初にリクエストボディ用のクラスの初期化を行っています。
MessageReceivedAsyncへ処理を渡しています。
public Task StartAsync(IDialogContext context)
{
this.requestBody = new Entity.RequestBody();
context.Wait(MessageReceivedAsync);
return Task.CompletedTask;
}
####MessageReceivedAsyncメソッド
Botの機能の説明をユーザーに返しています。
DialogueMessageReceivedAsyncに処理を渡しています。
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
await context.PostAsync($"雑談・しりとりBotです。なにか話しかけてください。");
await context.PostAsync($"あなたの情報を元に雑談をしたい場合は、「初期設定」と入力してあなたの情報を教えてください。");
await context.PostAsync($"しりとりをしたい場合は、「しりとり」をしようと話しかけてみてください。");
await context.PostAsync($"終了する際には、「終わり」と入力してください。");
context.Wait(DialogueMessageReceivedAsync);
}
####DialogueMessageReceivedAsyncメソッド
private async Task DialogueMessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
// return our reply to the user
if (activity.Text == "終わり")
{
await context.PostAsync($"BOT終わります");
context.Done<object>(null);
return;
}
else if (activity.Text == "初期設定")
{
await context.PostAsync($"初期設定を始めます。");
PromptDialog.Choice(context, SettingChoiceReceivedAsync, settings, "何を設定しますか?");
}
else
{
var response = await GetDialogue(activity.Text);
var dialogue = JsonConvert.DeserializeObject<Entity.ResponseBody>(response.Content.ReadAsStringAsync().Result);
await context.PostAsync($"{dialogue.Utt}");
this.requestBody.Context = dialogue.Context;
this.requestBody.Mode = dialogue.Mode;
context.Wait(DialogueMessageReceivedAsync);
}
}
if (activity.Text == "終わり")
{
await context.PostAsync($"BOT終わります");
context.Done<object>(null);
return;
}
ユーザーが「終わり」と入力するとBotの処理を終了します。
else if (activity.Text == "初期設定")
{
await context.PostAsync($"初期設定を始めます。");
PromptDialog.Choice(context, SettingChoiceReceivedAsync, settings, "何を設定しますか?");
}
ユーザーが「初期設定」と入力すると、クラス変数 settings に定義した文字列配列を選択ダイアログで表示し、選択した内容と共にSettingChoiceReceivedAsyncメソッドに処理を渡します。
選択ダイアログは以下のような感じ。
使用しているクライアントによって変わります。
else
{
var response = await GetDialogue(activity.Text);
var dialogue = JsonConvert.DeserializeObject<Entity.ResponseBody>(response.Content.ReadAsStringAsync().Result);
await context.PostAsync($"{dialogue.Utt}");
this.requestBody.Context = dialogue.Context;
this.requestBody.Mode = dialogue.Mode;
context.Wait(DialogueMessageReceivedAsync);
}
private async Task<HttpResponseMessage> GetDialogue(string writeString)
{
var client = new HttpClient();
this.requestBody.Utt = writeString;
var content = new StringContent(JsonConvert.SerializeObject(requestBody));
var response = await client.PostAsync($"{requestUrl}?APIKEY={apiKey}", content);
return response;
}
ユーザーが入力したテキストをGetDialogueメソッドで雑談対話APIに渡し、レスポンスを取得、レスポンスのメッセージをユーザーに返しています。
レスポンスのContextとModeを次のリクエストに設定することにより、
継続的な会話やしりとりが出来るようにしています。
####SettingChoiceReceivedAsyncメソッド
選択ダイアログから選択された内容毎に処理を振り分けます。
選択出来る項目が決まっているものは、選択ダイアログを表示することで、
ユーザーの想定外の入力を可能な限り除外します。
private async Task SettingChoiceReceivedAsync(IDialogContext context, IAwaitable<string> argument)
{
var choiceSetting = await argument;
switch (choiceSetting)
{
case "名前(ニックネーム)":
await context.PostAsync($"あなたの名前(ニックネーム)は?");
context.Wait(SettingSetp01ReceivedAsync);
break;
case "性別":
var sexs = new string[] { "男", "女"};
PromptDialog.Choice(context, SettingSetp03ReceivedAsync, sexs, "あなたの性別は?");
break;
case "血液型":
var bloodtypes = new string[] { "A", "B", "AB", "O" };
PromptDialog.Choice(context, SettingSetp04ReceivedAsync, bloodtypes, "あなたの血液型は?");
break;
case "年齢":
await context.PostAsync($"あなたの年齢は?");
context.Wait(SettingSetp05ReceivedAsync);
break;
case "星座":
var constellations = new string[] { "牡羊座", "牡牛座", "双子座", "蟹座", "獅子座", "乙女座", "天秤座", "蠍座", "射手座", "山羊座", "水瓶座", "魚座" };
PromptDialog.Choice(context, SettingSetp06ReceivedAsync, constellations, "あなたの血液型は?");
break;
case "地域":
var places = new string[] { "北海道", "東北", "関東甲信越", "中部", "関西", "中国・四国", "九州・沖縄", "海外" };
PromptDialog.Choice(context, SettingSetp07ReceivedAsync, places, "あなたの今いる地域は?");
break;
case "生年月日":
await context.PostAsync($"あなたの生年月日は? 9999/99/99形式で入力してください。");
context.Wait(SettingSetp09ReceivedAsync);
break;
case "設定終了":
await context.PostAsync($"設定終了します。");
context.Wait(DialogueMessageReceivedAsync);
break;
}
}
ソース全体を最後に載せています。
Bot Framework PortalへのBotの登録
Visual Studioから一旦離れ、
Bot Framework PortalへBotを登録します。
MicrosoftアカウントでBot Framework Portalにサインインをします。
[MyBot]ボタンをクリックすると他のBotを登録済みの場合、Botの一覧が表示されます。
[Create a bot]ボタンをクリックし、Botを登録していきます。
[Create]ボタンをクリックします。
プログラムは作成済みのため、[Register an existing bot built using Bot Builder SDK.]を選択し、OKをクリック。
Bot profileセクションでBotの情報を入力します。
Display name:Botの名前
Bot handle:全世界で一意な名前
Long desctiption:Botの説明
Bot handleは全世界で一意な名前をつけないと行けないので、
Visual StudioのGUIDの作成で一意なIDを作成すればいいと思います。
※画面のBot handleは仮の値なので、使えないです。
Configurationセクションでは[Create Microsoft App ID and password]ボタンをクリックし、Microsoft App IDを作成します。
[アプリパスワードを生成して続行]ボタンをクリックすることで、アプリパスワードが生成されます。
※書いてある通り一度しか表示されないので必ずメモしておいてください。
作成したBotのAzureへの登録
再びVisual Studioに戻り、
ソリューションエクスプローラーの[Connected Services]を開きます。
[Microsoft Azure App Service(A)]を選択し、新規作成を選択した状態で発行ボタンをクリックします。
Microsoftアカウントでログインし、各種パラメータを設定し[作成]ボタンをクリックします。
Azureポータルの設定したアプリ名でApp Serviceにアプリが作成されていることを確認し、アプリケーション設定を開く。
アプリケーション設定のアプリ設定に
キー名:MicrosoftAppId
値:Bot登録時に作成されたアプリID
キー名:MicrosoftAppPassword
値:Bot登録時に作成されたアプリパスワード
を登録します。
Bot情報の更新
Bot Framework Portalで登録したBot情報を更新します。
Messaging endpoint:Azureに登録したアプリのURL/api/messages
※URLは"https"で登録する必要あり。
[Save changes]で更新。
動作させてみる
Bot Framework PortalのBotの詳細欄には[← Test]ボタンがあるのでクリックすると、Webチャット形式でテストが出来ます。
#次回は
slackをクライアントにした場合の設定方法でも書きます。
#ソース全体
using System;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
using System.Net.Http;
using Newtonsoft.Json;
namespace SiritoriBot.Dialogs
{
[Serializable]
public class RootDialog : IDialog<object>
{
private const string requestUrl = @"https://api.apigw.smt.docomo.ne.jp/dialogue/v1/dialogue";
private const string apiKey = @"{雑談対話API開発用APIキー}";
private string[] settings = new string[] { "名前(ニックネーム)", "性別", "血液型", "年齢", "星座", "地域", "生年月日", "設定終了" };
private Entity.RequestBody requestBody;
public Task StartAsync(IDialogContext context)
{
this.requestBody = new Entity.RequestBody();
context.Wait(MessageReceivedAsync);
return Task.CompletedTask;
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
if (activity.ChannelId == "slack")
{
if (activity.Type == "message" && activity.Text.StartsWith($"@zatsudansiritoribot"))
{
await context.PostAsync($"雑談・しりとりBotです。なにか話しかけてください。");
await context.PostAsync($"あなたの情報を元に雑談をしたい場合は、「初期設定」と入力してあなたの情報を教えてください。");
await context.PostAsync($"しりとりをしたい場合は、「しりとり」をしようと話しかけてみてください。");
await context.PostAsync($"終了する際には、「終わり」と入力してください。");
context.Wait(DialogueMessageReceivedAsync);
}
}
else if (activity.ChannelId == "webchat")
{
if (activity.Type == "message")
{
await context.PostAsync($"雑談・しりとりBotです。なにか話しかけてください。");
await context.PostAsync($"あなたの情報を元に雑談をしたい場合は、「初期設定」と入力してあなたの情報を教えてください。");
await context.PostAsync($"しりとりをしたい場合は、「しりとり」をしようと話しかけてみてください。");
await context.PostAsync($"終了する際には、「終わり」と入力してください。");
context.Wait(DialogueMessageReceivedAsync);
}
}
else
{
if (activity.Type == "message" && activity.Text.StartsWith($"@zatsudansiritoribot"))
{
await context.PostAsync($"雑談・しりとりBotです。なにか話しかけてください。");
await context.PostAsync($"あなたの情報を元に雑談をしたい場合は、「初期設定」と入力してあなたの情報を教えてください。");
await context.PostAsync($"終了する際には、「終わり」と入力してください。");
context.Wait(DialogueMessageReceivedAsync);
}
}
}
private async Task DialogueMessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
// return our reply to the user
if (activity.Text == "終わり")
{
await context.PostAsync($"BOT終わります");
context.Done<object>(null);
return;
}
else if (activity.Text == "初期設定")
{
await context.PostAsync($"初期設定を始めます。");
PromptDialog.Choice(context, SettingChoiceReceivedAsync, settings, "何を設定しますか?");
}
else
{
var response = await GetDialogue(activity.Text);
var dialogue = JsonConvert.DeserializeObject<Entity.ResponseBody>(response.Content.ReadAsStringAsync().Result);
await context.PostAsync($"{dialogue.Utt}");
this.requestBody.Context = dialogue.Context;
this.requestBody.Mode = dialogue.Mode;
context.Wait(DialogueMessageReceivedAsync);
}
}
private async Task<HttpResponseMessage> GetDialogue(string writeString)
{
var client = new HttpClient();
this.requestBody.Utt = writeString;
var content = new StringContent(JsonConvert.SerializeObject(requestBody));
var response = await client.PostAsync($"{requestUrl}?APIKEY={apiKey}", content);
return response;
}
private async Task SettingReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
PromptDialog.Choice(context, SettingChoiceReceivedAsync, settings, "何を設定しますか?");
}
private async Task SettingChoiceReceivedAsync(IDialogContext context, IAwaitable<string> argument)
{
var choiceSetting = await argument;
switch (choiceSetting)
{
case "名前(ニックネーム)":
await context.PostAsync($"あなたの名前(ニックネーム)は?");
context.Wait(SettingSetp01ReceivedAsync);
break;
case "性別":
var sexs = new string[] { "男", "女"};
PromptDialog.Choice(context, SettingSetp03ReceivedAsync, sexs, "あなたの性別は?");
break;
case "血液型":
var bloodtypes = new string[] { "A", "B", "AB", "O" };
PromptDialog.Choice(context, SettingSetp04ReceivedAsync, bloodtypes, "あなたの血液型は?");
break;
case "年齢":
await context.PostAsync($"あなたの年齢は?");
context.Wait(SettingSetp05ReceivedAsync);
break;
case "星座":
var constellations = new string[] { "牡羊座", "牡牛座", "双子座", "蟹座", "獅子座", "乙女座", "天秤座", "蠍座", "射手座", "山羊座", "水瓶座", "魚座" };
PromptDialog.Choice(context, SettingSetp06ReceivedAsync, constellations, "あなたの血液型は?");
break;
case "地域":
var places = new string[] { "北海道", "東北", "関東甲信越", "中部", "関西", "中国・四国", "九州・沖縄", "海外" };
PromptDialog.Choice(context, SettingSetp07ReceivedAsync, places, "あなたの今いる地域は?");
break;
case "生年月日":
await context.PostAsync($"あなたの生年月日は? 9999/99/99形式で入力してください。");
context.Wait(SettingSetp09ReceivedAsync);
break;
case "設定終了":
await context.PostAsync($"設定終了します。");
context.Wait(DialogueMessageReceivedAsync);
break;
}
}
private async Task SettingSetp01ReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
this.requestBody.Nickname = activity.Text;
await context.PostAsync($"あなたの名前(ニックネーム)の読み方(カタカナ)は?");
context.Wait(SettingSetp02ReceivedAsync);
}
private async Task SettingSetp02ReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
this.requestBody.Nickname_y = activity.Text;
PromptDialog.Choice(context, SettingChoiceReceivedAsync, settings, "何を設定しますか?");
}
private async Task SettingSetp03ReceivedAsync(IDialogContext context, IAwaitable<string> argument)
{
var sex = await argument;
this.requestBody.Sex = sex;
PromptDialog.Choice(context, SettingChoiceReceivedAsync, settings, "何を設定しますか?");
}
private async Task SettingSetp04ReceivedAsync(IDialogContext context, IAwaitable<string> argument)
{
var bloodtype = await argument;
this.requestBody.Bloodtype = bloodtype;
PromptDialog.Choice(context, SettingChoiceReceivedAsync, settings, "何を設定しますか?");
}
private async Task SettingSetp05ReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
this.requestBody.Age = activity.Text;
PromptDialog.Choice(context, SettingChoiceReceivedAsync, settings, "何を設定しますか?");
}
private async Task SettingSetp06ReceivedAsync(IDialogContext context, IAwaitable<string> argument)
{
var constellations = await argument;
this.requestBody.Constellations = constellations;
PromptDialog.Choice(context, SettingChoiceReceivedAsync, settings, "何を設定しますか?");
}
private async Task SettingSetp07ReceivedAsync(IDialogContext context, IAwaitable<string> argument)
{
var choicePlace = await argument;
var places = new string[] { };
switch (choicePlace)
{
case "北海道":
places = new string[] { "稚内", "旭川", "留萌", "網走", "北見", "紋別", "根室", "釧路", "帯広", "室蘭", "浦河", "札幌", "岩見沢", "倶知安", "函館", "江差" };
PromptDialog.Choice(context, SettingSetp08ReceivedAsync, places, "あなたの今いる地域は?");
break;
case "東北":
places = new string[] { "青森", "弘前", "深浦", "むつ", "八戸", "秋田", "横手", "鷹巣", "盛岡", "二戸", "一関", "宮古", "大船渡", "山形", "米沢", "酒田", "新庄", "仙台", "古川", "石巻", "白石", "福島", "郡山", "白河", "小名浜", "相馬", "若松", "田島" };
PromptDialog.Choice(context, SettingSetp08ReceivedAsync, places, "あなたの今いる地域は?");
break;
case "関東甲信越":
places = new string[] { "宇都宮", "大田原", "水戸", "土浦", "前橋", "みなかみ", "さいたま", "熊谷", "秩父", "東京", "大島", "八丈島", "父島", "千葉", "銚子", "館山", "横浜", "小田原", "甲府", "河口湖", "長野", "松本", "諏訪", "軽井沢", "飯田", "新潟", "津川", "長岡", "湯沢", "高田", "相川" };
PromptDialog.Choice(context, SettingSetp08ReceivedAsync, places, "あなたの今いる地域は?");
break;
case "中部":
places = new string[] { "静岡", "網代", "石廊崎", "三島", "浜松", "御前崎", "富山", "伏木", "岐阜", "高山", "名古屋", "豊橋", "福井", "大野", "敦賀", "金沢", "輪島" };
PromptDialog.Choice(context, SettingSetp08ReceivedAsync, places, "あなたの今いる地域は?");
break;
case "関西":
places = new string[] { "大津", "彦根", "津", "上野", "四日市", "尾鷲", "京都", "舞鶴", "奈良", "風屋", "和歌山", "潮岬", "大阪", "神戸", "姫路", "洲本", "豊岡" };
PromptDialog.Choice(context, SettingSetp08ReceivedAsync, places, "あなたの今いる地域は?");
break;
case "中国・四国":
places = new string[] { "鳥取", "米子", "岡山", "津山", "松江", "浜田", "西郷", "広島", "呉", "福山", "庄原", "下関", "山口", "柳井", "萩", "高松", "徳島", "池田", "日和佐", "松山", "新居浜", "宇和島", "高知", "室戸岬", "清水" };
PromptDialog.Choice(context, SettingSetp08ReceivedAsync, places, "あなたの今いる地域は?");
break;
case "九州・沖縄":
places = new string[] { "福岡", "八幡", "飯塚", "久留米", "佐賀", "伊万里", "長崎", "佐世保", "厳原", "福江", "大分", "中津", "日田", "佐伯", "熊本", "阿蘇乙姫", "牛深", "人吉", "宮崎", "油津", "延岡", "都城", "高千穂", "鹿児島", "阿久根", "枕崎", "鹿屋", "種子島", "名瀬", "沖永良部", "那覇", "名護", "久米島", "南大東島", "宮古島", "石垣島", "与那国島" };
PromptDialog.Choice(context, SettingSetp08ReceivedAsync, places, "あなたの今いる地域は?");
break;
case "海外":
this.requestBody.Place = choicePlace;
PromptDialog.Choice(context, SettingChoiceReceivedAsync, settings, "何を設定しますか?");
break;
}
}
private async Task SettingSetp08ReceivedAsync(IDialogContext context, IAwaitable<string> argument)
{
var place = await argument;
this.requestBody.Place = place;
PromptDialog.Choice(context, SettingChoiceReceivedAsync, settings, "何を設定しますか?");
}
private async Task SettingSetp09ReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
var birthday = activity.Text.Split('/');
if (birthday.Length >= 3)
{
this.requestBody.BirthdateY = birthday[0];
this.requestBody.BirthdateM = birthday[1];
this.requestBody.BirthdateD = birthday[2];
}
else
{
await context.PostAsync($"生年月日の入力フォーマットがおかしいです。");
}
PromptDialog.Choice(context, SettingChoiceReceivedAsync, settings, "何を設定しますか?");
}
}
}