前回は基本的なアダプティブカードを使ってダイアログを作成しました。今回はより高度で複雑なものを試していきます。
アダプティブカードの要素
色々試す前に、まずアダプティブカードで出来ることを見ていきます。詳細は Card Schema を参照。
アダプティブカードには以下の要素があります。
- Card Elements - テキストや画像などカード上に表示される要素
- Containers - 複数の Card Elements を 1 つにまとめる箱
- Actions - ボタンクリック時の動作
- Inputs - データを入力するための機能
- Speech - 音声用の情報
Card Elements
- TextBlock - テキストの表示。フォントのサイズや色、スタイルを設定できる
- Image - 画像の表示
- Media - 動画や音声の再生ができる
- MediaSource - メディアのソース定義
テキストのマークダウン
太字やイタリック、ブレットポイントなどの書式をマークダウンで指定可能
Containers
- Container - 複数のアイテムをグループ化
- ColumnSet - 複数の列を作成し、横並びに表示
- Column - ColumnSet で使う 1 列の定義
- FactSet - キー/値ペアをテーブル形式で表示
- Fact - FactSet で使う 1 つのキー/値の定義
- ImageSet - 複数イメージのグループ化
Actions
- Action.OpenUrl - 指定した URL を開く
- Action.Submit - Inputs で指定したデータを集めて送る
- Action.ShowCard - 定義したアダプティブカードを開く
Inputs
- Input.Text - テキストの入力。メールアドレスや URL などスタイルの指定や既定値などが設定可能
- Input.Number - 数値の入力
- Input.Date - 日付の入力
- Input.Time - 時間の入力
- Input.Toggle - 2 つのオプションのトグル
- Input.ChoiceSet - 選択肢の提示
- Input.Choice - ChoiseSet で使う選択肢の定義
プロファイルダイアログの拡張
前回プロファイルダイアログをアダプティブカード化しましたが、内容を拡張してみます。
1. まず Models フォルダの UserProfile.cs を以下の様に変更。追加の情報を持てるようにする。
using System;
using System.Collections.Generic;
public class UserProfile
{
public string Name { get; set; }
public int Age { get; set; }
public DateTime BirthDay { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string CatNum { get; set; }
public List<string> CatTypes { get; set; }
public bool HasCat { get; set; }
public bool PlayWithCat { get; set; }
}
2. 次に Profile.json を以下の様に変更。
- Input.ChoiceSet を複数の方法で利用
- Input.Text のスタイルを複数利用
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": 2,
"items": [
{
"type": "TextBlock",
"text": "プロファイルを登録します。",
"weight": "bolder",
"size": "medium"
},
{
"type": "TextBlock",
"text": "ボットの利用にあたり、もう少し詳しくあなたの情報が必要です。",
"isSubtle": true,
"wrap": true
},
{
"type": "TextBlock",
"text": "名前",
"wrap": true
},
{
"type": "Input.Text",
"id": "name",
"placeholder": "姓名",
"style": "text"
},
{
"type": "TextBlock",
"text": "誕生日",
"wrap": true
},
{
"type": "Input.Date",
"id": "birthday"
},
{
"type": "TextBlock",
"text": "メールアドレス",
"wrap": true
},
{
"type": "Input.Text",
"id": "email",
"placeholder": "youremail@example.com",
"style": "email"
},
{
"type": "TextBlock",
"text": "電話番号"
},
{
"type": "Input.Text",
"id": "phone",
"placeholder": "(xx)-xxxx-xxxx",
"style": "tel"
},
{
"type": "TextBlock",
"text": "ネコ飼っていますか?"
},
{
"type": "Input.ChoiceSet",
"id": "hasCat",
"style": "expanded",
"value":"true",
"choices": [
{
"title": "はい",
"value": "true"
},
{
"title": "いいえ",
"value": "false"
}
]
},
{
"type": "TextBlock",
"text": "飼っているネコの種類を教えてください。(複数選択可)"
},
{
"type": "Input.ChoiceSet",
"id": "catTypes",
"isMultiSelect": true,
"choices": [
{
"title": "サバトラ",
"value": "サバトラ"
},
{
"title": "キジトラ",
"value": "キジトラ"
},
{
"title": "ハチワレ",
"value": "ハチワレ"
},
{
"title": "その他",
"value": "その他"
}
]
},
{
"type": "TextBlock",
"text": "全部で何匹いますか?"
},
{
"type": "Input.ChoiceSet",
"id": "catNum",
"style": "compact",
"value": "1",
"choices": [
{
"title": "1",
"value": "1"
},
{
"title": "2",
"value": "2"
},
{
"title": "3",
"value": "3"
},
{
"title": "4",
"value": "4"
},
{
"title": "5",
"value": "5"
},
{
"title": "6匹以上",
"value": "6+"
}
]
},
{
"type": "TextBlock",
"text": "毎日ネコと遊んでいますか?"
},
{
"type": "Input.Toggle",
"title": "毎日ネコを遊んでいます。",
"valueOn": "true",
"valueOff": "false",
"id": "playWithCat"
}
]
},
{
"type": "Column",
"width": 1,
"items": [
{
"type": "Image",
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Pumiforme.JPG/1280px-Pumiforme.JPG",
"size": "auto"
}
]
}
]
}
],
"actions": [
{
"type": "Action.Submit",
"title": "登録"
}
]
}
3. AdaptiveCardResponseValidators.cs の ValidateInput メソッドを以下の様に変更。
public static Task<bool> ValidateInput(PromptValidatorContext<string> promptContext, CancellationToken cancellationToken)
{
// 文字は返ってこないため Succeeded の場合は false
if (promptContext.Recognized.Succeeded)
{
return Task.FromResult(false);
}
// オプションの検証プロパティから NumberRange を取得。
NumberRange range = promptContext.Options.Validations is NumberRange ?
(NumberRange)promptContext.Options.Validations :
new NumberRange() { MinValue = 0, MaxValue = 120 };
// 一旦 JObject として中身をパース
var input = JObject.Parse(promptContext.Context.Activity.Value.ToString());
// CatTypes がある場合、対応する UserProfile クラスのプロパティが 、
// List<string> のため、JArray に変換。
if(input.ContainsKey("catTypes"))
input["catTypes"] = new JArray(input["catTypes"].ToString().Split(','));
// 誕生日から年齢を計算し新しいプロパティとして追加
var birthday = DateTime.Parse(input["birthday"].ToString());
var age = DateTime.Now.Year - birthday.Year;
if (DateTime.Now < birthday.AddYears(age))
age--;
input["age"] = age;
// 0 より小さいか 120 より大きい場合は False
if (age < range.MinValue ||age > range.MaxValue)
{
promptContext.Context.SendActivityAsync($"年齢が{age}歳になります。ただしい誕生日を入れてください。");
return Task.FromResult(false);
}
// 値を入れ替え
promptContext.Context.Activity.Value = input;
return Task.FromResult(true);
}
4. ProfileDialog.cs の SummaryStepAsync をシンプルに変更。
private async Task<DialogTurnResult> SummaryStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var input = JsonConvert.DeserializeObject<UserProfile>(stepContext.Context.Activity.Value.ToString());
await stepContext.Context.SendActivityAsync(MessageFactory.Text("プロファイルを保存します。"));
await accessors.UserProfile.SetAsync(stepContext.Context, input, cancellationToken);
return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
}
5. 挨拶などにペットの情報を適当に入れてみる。
await turnContext.SendActivityAsync(MessageFactory.Text($"ようこそ '{userProfile.Name}' さん!"));
if (userProfile.HasCat)
await turnContext.SendActivityAsync(MessageFactory.Text($"{userProfile.CatNum}匹の猫は元気ですか?"));
テスト
1. F5 キーを押下してデバッグ実行。エミュレーターで接続。「はい」をクリック。
2. アダプティブカードの中身を埋めて、「登録」をクリック。
4. Restart conversation をクリックして挨拶が変わることを確認。
もっと色々ためす
アダプティブカードはもっと沢山の事が出来ます。以下のサンプル集の JSON も試してください。ボタンをクリックした際に追加で内容を表示するなど、色々できます。
アダプティブカード : サンプル
C# でアダプティブカード
C# ですべてを書きたい場合は、AdaptiveCards NuGet パッケージを使います。
GitHub : AdaptiveCards
ただしこの記事を書いた時点では問題があり、うまく動作しません。どうしても C# で書きたい場合は古いライブラリですが、Microsoft.AdaptiveCards NuGet パッケージを使ってください。
まとめ
アダプティブカードを使うと表現の自由が上がるだけでなく、入力フォームとしてまとめて質問する事もできるため、是非色々試してください。次回はボットの多言語サポートを見ていきます。