Action types of Adaptive Cards (in Microsoft Bot Framework WebChat)
Microsoft Bot Framework の Adaptive Cards で行えるアクションの種類を調べました。
環境
- Server side
- C#, Microsoft.Bot.Builder 3.8.4.0
- Channel
- Bot Framework Channel Emulator 3.5.29
- WebChat 0.11.0
他の Rich Card とアクションの種類が違う
Bot Framework では、メッセージや画像の他に、カードの表現でメッセージを送信できます。そのカードには、ここのドキュメント の「Types of rich cards」にあるように、AdaptiveCard を含め、AnimationCard、AudioCard といった8個の種類があります。このうちの1つの Adaptive Card は、Build 2017 で発表されたものです。それまで固定のレイアウトしかできなかったカードですが、Adaptive Card では、開発者がある程度自由にレイアウトできます。
カードで行えるアクションは Adaptive Card とその他のカードで種類が違うようです。
- Adaptive Card カード以外で使えるアクションの種類(参照)
- openUrl, imBack, postBack, call, playAudio, playVido, showImage, downloadFile, signin
- Adaptive Card で使えるアクションの種類(参照 Action.*の項目)
- OpenUrl, Submit, Http, ShowCard
例えば、Adaptive Card 内で「imBack」の処理(imBackは、ボタンを選択するとその値のメッセージをユーザーから Bot に送信します)を行いたい場合は、Adaptive Card のアクションの種類「Submit」を利用して、同じような挙動を実現します。
※Adaptive Card は発表されたばかりなので、今後種類が増えていく可能性はあります。
※Adaptive Card の性質を考えると、既存のカードの実装を置き換えてもよさそうですが、実際にどのような実装になっているかはわからず。代わりに次のような記述を見つけました。
The existing Bot Builder SDK card types (Hero, Thumbnail, Audio, Video, Animation, SignIn, Receipt) are now implemented as Adaptive Cards. BotFramework-WebChat/AdaptiveCards.md at master · Microsoft/BotFramework-WebChat
アクションボタンのレイアウト
Adaptive Card のアクションは、一つのカードに対して複数のアクションを設定する、という形のようです。ですので、次の図のようにボタンが下部に配置されます。文章やとある Column の中にボタンを置く、といった自由なレイアウトはできませんでした。
Channel が WebChat の場合のアクション
Channel を WebChat に限定し、Adaptive Card で使えるアクションがどのようなものか調べました。 WebChat の場合は、「Http」のアクションはサポートしていません。その他 WebChat での Adaptive Card については下記にあります。
BotFramework-WebChat/AdaptiveCards.md at master · Microsoft/BotFramework-WebChat
実装方法の調べ方としては、上のサイトに加え、Adaptive Card のスキーマの定義をみつつ(Adaptive Cards)、Adaptive Card の C# のサンプルをみる(BotBuilder-Samples/CSharp/cards-AdaptiveCards at master · Microsoft/BotBuilder-Samples)、が良さそうです。
OpenUrl
OpenUrl は、ボタンを選択するとブラウザでそのURLにアクセスします。
ShowCard
ShowCard は、ボタンを選択すると、別の Adaptive Card を表示します。
「コメント」をタップすると、下のように別の Adaptive Card が表示されます。
こちらにもサンプルがあります。 ActivityUpdate | Adaptive Cards
Submit
Submit は、ボタンを選択すると、input 要素に入力された値を送信します。
こちらと同じサンプルです:InputForm | Adaptive Cards
入力された値を受け取るには、context.Wait(...)
などでユーザーの IMessageActivity
を受け取り、そのプロパティのValue
から値を取得します。下記はそのサンプルです。
private async Task SelectedCardAsync(IDialogContext context, IAwaitable<string> result) { //Adaptive Cardを送信する await context.PostAsync(AdaptiveCardGenerator.CreateAdaptiveCard(context, AdaptiveCardGenerator.CreateShowCard())); context.Wait(FormReceivedAsync); } /// <summary> /// 入力フォームを受け取った後 /// </summary> /// <param name="context"></param> /// <param name="result"></param> /// <returns></returns> private async Task FormReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result) { var message = await result; if (message.Value != null) { dynamic value = message.Value; await context.PostAsync($"received: myName:{value.myName}, myEmail:{value.myEmail}, myTel:{value.myTel}. "); } //...
先の方で「imBack」のような挙動は Adapptive Card では「Submit」で代わりに実装する、と書きました。「Submit」では、input要素以外に任意のキーと値のペアを送信できるので(該当の場所のコード)、その値でユーザーの選択したボタンを区別し、分岐することにより「imBack」のような挙動を真似できます。
この Submit で注意したいことですが、私の環境の Bot Framework Channel Emulator 3.5.29 では入力値を受け取ることができませんでした(Value プロパティが null。値の送信もしてない様子)。しかし、ブラウザ上からの WebChat と、Bot Framework のポータルサイトの Test では、正常な動作を確認しました。下記のサイトでは、Mac では動いたけど Windows では動かない、といった記述があります。Emulator のバージョンの確認や再インストールで動いたとありますが、私の環境ではそれでもできませんでした。Adaptive card not working on Emulator · Issue #244 · Microsoft/BotFramework-Emulator
Synonyms in Azure Search - Japanese
Azure Search にシノニム機能が Public Preview として追加されたので、日本語で試しました。
※追記:2018/7/3 Public Previewが外れGAしました。
Azure Search で synonyms が GA! https://t.co/04MESGlJhi
— Takekazu Omi (@takekazuomi) July 3, 2018
API Versionが、2016-09-01-Preview から、2017-11-11 になった。 SDK version 5.0.0 でサポート。
ドキュメントの更新を漁ったが、この程度の変更らしいhttps://t.co/kiScsjscD2#azurejp
参照:
- Azure Search releases support for synonyms (public preview) | Blog | Microsoft Azure
- Synonyms preview tutorial in Azure Search | Microsoft Docs
- Synonyms in Azure Search (preview) | Microsoft Docs
- Synonyms in Azure Search | Data Exposed | Channel 9
シノニム
シノニム - Wikipedia シノニム(synonym)とは、類語や同意語といった意味です。 検索エンジンでは、ある言葉で検索した場合に、違う言葉でヒットさせるための機能をいいます。
- シノニム(同義語)機能でユーザーに柔軟な検索システムを提供する (1/3):CodeZine(コードジン)
- Amazon CloudSearch のテキスト分析スキームの設定 - Amazon CloudSearch
たとえば、ユーザーが「いか」と検索したときは「するめ」を表すドキュメントをヒットさせたい、といったときに、”「いか」は「するめ」”という意味のシノニム辞書を作成します。
Azure Search でのシノニム機能
Azure Search では、現在シノニム機能は Public Preview です。よってプロダクション環境での使用は推奨されません。
また、REST API (api-version=2016-09-01-Preview)と、.NET SDK にて使えます(ポータルでは対応していません)。(GAしました。API-Versionはドキュメントにて確認します)
ステップ
シノニム機能を使うには、次の2ステップを行います。
- シノニムマップを作成する。
- (この言葉はこの言葉にマップする、という情報を登録する)
- インデックス定義のフィールドに、シノニムマップを適用する。
- (このフィールドは、このシノニムマップを参照して検索できるようにする、という情報を登録する)
この2ステップは、Azure Search releases support for synonyms (public preview) | Blog | Microsoft Azure ここに記載されている API のことです。シノニムマップは、REST API の POST・PUT のメソッドにより作成・更新します。
その他
他に以下のような特徴があります(把握している範囲です)。
- シノニムマップを更新した場合、インデックスの再構築やサービスが中断されるということは無い。
- 1つのフィールドには、1つのシノニムマップしか適用できない(現在は)。
- ヒットハイライティングとスコアリングプロファイルは、元のワードと同意語の両方を同等として扱う。
- Filter, Facet, Suggestion は、シノニムマップが適用されない。
- シノニムマップは、Solr の SynonymFilterFactory のフォーマットで記述する。
シノニムマップのフォーマットはこんな感じです:
インターネット,internet,ワイファイ,wifi\n five star=>高級\n 旅亭,旅荘=>旅館
インデックスの再構築を行わない、ということは、あまりに複雑で大量なシノニムマップを作成すると、検索が遅くなるのかな?と推測しています。
コンソールアプリで試してみる
ということで、日本語で試してみました。.NET SDK を使い、コンソールアプリケーションを作成します。 Azrue Search が提供するサンプル こちらをベースに、日本語に書き換えてみました。
インデックスの定義や、ドキュメントの作成など全てコンソールアプリケーションから行っています。
手順
・Azure Search をプロビジョニングします。
・Azrue Search が提供するサンプルを取得し、App.config にある設定(サービス名・管理キー・クエリキー)を書き換えます。
・Hotel.cs の Category と Tags のフィールドに [Analyzer(AnalyzerName.AsString.JaLucene)]
を定義します。
[IsSearchable, IsFilterable, IsSortable, IsFacetable] [Analyzer(AnalyzerName.AsString.JaLucene)] public string Category { get; set; } [IsSearchable, IsFilterable, IsFacetable] [Analyzer(AnalyzerName.AsString.JaLucene)] public string[] Tags { get; set; }
・ドキュメントを作成している UploadDocuments メソッドにて、次のように日本語に置き換えます。
private static void UploadDocuments(ISearchIndexClient indexClient) { var hotels = new Hotel[] { new Hotel() { HotelName = "東京ホテル", Category = "ホテル", Tags = new[] { "ジャグジー", "夜景", "wifi", "送迎", "高級"}, HotelId = "1", //略 }, new Hotel() { HotelName = "神奈川旅館", Category = "旅館", Tags = new[] { "温泉", "内湯", "大浴場", "露天風呂"}, HotelId = "2", // 略
・シノニムマップを作成している UploadSynonyms メソッドにて、次のように記述します。
private static void UploadSynonyms(SearchServiceClient serviceClient) { var synonymMap = new SynonymMap() { Name = "desc-synonymmap", Format = "solr", Synonyms = "インターネット,internet,ワイファイ,wifi\nfive star=>高級\n旅亭,旅荘=>旅館" }; serviceClient.SynonymMaps.CreateOrUpdate(synonymMap); Console.WriteLine("UploadSynonyms"); }
コードは gist にアップしました:gist
こんな感じ
以上の手順により、次の2つのドキュメントを作成しています。
Name | Category | Tags |
---|---|---|
東京ホテル | ホテル | [ジャグジー, 夜景, wifi, 送迎, 高級] |
神奈川旅館 | 旅館 | [温泉, 内湯, 大浴場, 露天風呂] |
シノニムマップはこのように。
インターネット,internet,ワイファイ,wifi\n five star=>高級\n 旅亭,旅荘=>旅館
以下の検索に対応したいため、上記のようなシノニムマップを作成しました。
- 「"five star"」(double quot付き)で検索すると「東京ホテル」がヒットする
- 「インターネット」で検索すると「東京ホテル」がヒットする
- 「旅亭」で検索すると「神奈川旅館」がヒットする
結果
シノニムを作成する前 は、検索しても該当しません。
1. Search the entire index for the phrase "five star": no document matched 2. Search the entire index for the term 'インターネット': no document matched 3. Search the entire index for the term '旅亭': no document matched 4. Search the entire index for the terms 'インターネット' AND 'five star': no document matched
シノニムを作成した後は、期待したように検索結果がヒットします。
1. Search the entire index for the phrase "five star": Name: 東京ホテル Category: ホテル Tags: [ジャグジー, 夜景, wifi, 送迎, 高級] 2. Search the entire index for the term 'インターネット': Name: 東京ホテル Category: ホテル Tags: [ジャグジー, 夜景, wifi, 送迎, 高級] 3. Search the entire index for the term '旅亭': Name: 神奈川旅館 Category: 旅館 Tags: [温泉, 内湯, 大浴場, 露天風呂] 4. Search the entire index for the terms 'インターネット' AND 'five star': Name: 東京ホテル Category: ホテル Tags: [ジャグジー, 夜景, wifi, 送迎, 高級]
シノニムマップを更新する
さらに、「リッチ」で検索したときに「高級」でヒットするように、シノニムマップを更新します。
次のように「リッチ」を追加して、UploadSynonyms
メソッドを実行します。
これはつまり、API: PUT https://[servicename].search.windows.net/synonymmaps/desc-synonymmap?api-version=2016-09-01-Preview
を送信します。インデックスの定義は更新していません。
private static void UploadSynonyms(SearchServiceClient serviceClient) { var synonymMap = new SynonymMap() { Name = "desc-synonymmap", Format = "solr", Synonyms = "インターネット,internet,ワイファイ,wifi\nリッチ,five star=>高級\n旅亭,旅荘=>旅館" };
更新後、検索すると「リッチ」で「東京ホテル」がヒットするようになりました。
5. Search the entire index for the term 'リッチ': Name: 東京ホテル Category: ホテル Tags: [ジャグジー, 夜景, wifi, 送迎, 高級]