Microsoftが提唱するオープンなカード交換フレームワーク「Adaptive Cards」とは? その概要をbotアプリを作りながら見ていく。
2018年3月7日に開催された「Windows Developer Day 2018 March」では、訓練済みのモデルをWindowsアプリに組み込むためのWindows MLなど、開発者の関心を引きそうな発表がいろいろと行われた。Adaptive Cardsもそうしたものの1つだ。
「Adaptive Cards Overview」ページによれば、Adaptive Cardsとは「カードを交換するためのオープンなフォーマットであり、これにより開発者は一貫性を持った共通の方法でUIコンテンツを交換できるようになる」というものだ。本稿執筆時点(2018年3月26日)でのバージョンは1.0となっている。
ここでいう「カード」とは、JSON形式で記述された、何らかのメッセージを含む小サイズのデータのこと。他者に伝えたい情報をJSONオブジェクトにパッケージングして、それを何らかの手段で送信すると、受け取る側ではそのときに使用しているデバイスやアプリに適切な形式で書式設定された情報が表示されるというのが、Adaptive Cardsが目指すところだ。
「Adaptive Cards for Bot Developers」ページと「Adaptive Cards for Windows Developers」ページの2つがあることから、プラットフォームという意味での当初の適用範囲はbotアプリ開発、それからWindows OS上でのAdaptive Cardsの利用が考えられているようだ。
ただし、Windowsについては「Adaptive CardsのサポートをWindowsで最初に体験できるのはWindows Timelineとなる」とのことで、なおかつ、ドキュメントもそれほど多くはない状況だ(Windows Timelineでの利用についてはMSDNブログの「Adaptive Cards, Desktop Bridge and Timeline in Windows 10」などを参照されたい)。そこで、本稿ではbotを作成しながら、プラットフォームでどう見方が変わるかや、カードとユーザーの対話をどう処理するかを見てみよう。
まずはAzure Bot Serviceを使い「Web App Bot」プロジェクトを作成して、Adaptive Cardsを利用してみよう。
botの作成に関する詳細は割愛する。ここでは、作成されたプロジェクトからユーザーとの対話(ダイアログ)を実際に処理している部分に注目しよう。これは作成したプロジェクトのDialogディレクトリにあるEchoDialog.csファイルで行われている。
EchoDialogクラスのMessageReceivedAsyncメソッドを、ここでは以下のように変更した。
public async Task MessageReceivedAsync(IDialogContext context,
IAwaitable<object> argument)
{
var activity = await argument as Activity;
var reply = activity.CreateReply();
string json =
$@"{{
'type': 'AdaptiveCard',
'version': '1.0',
'body': [
{{
'type': 'TextBlock',
'text': 'Hello From Insider.NET (with json)',
'size': 'large'
}},
{{
'type': 'TextBlock',
'text': 'Adaptive Cards sample',
'separation': 'none'
}},
{{
'type': 'TextBlock',
'text': 'your input: {activity.Text}',
}}
],
'actions': [
{{
'type': 'Action.OpenUrl',
'url': 'http://www.atmarkit.co.jp',
'title': 'Learn More'
}}
]
}}";
var attachment = new Attachment
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(json)
};
reply.Attachments.Add(attachment);
await context.PostAsync(reply);
context.Wait(MessageReceivedAsync);
}
詳細な解説は省略するが、これはMicrosoft Bot Framework(以下、Bot Framework)を利用したコードであり、botからユーザーへの送信にはcontextパラメーターを利用している。また、argumentsパラメーターにはユーザーから送信されたデータなどの情報が含まれている。このうちのargumentsパラメーターをActivityオブジェクトに変換した後に、ユーザーに対するレスポンスを作成し、そこにJSONライクに記述したカードを入れ込むことで、ユーザーにそれを表示するようになっている(ここで使用しているActivityクラスとAttachmentクラスはBot Frameworkが提供しているものだ。Bot Frameworkでは「リッチ」なコンテンツをユーザーに届けるための器としてAttachmentクラスを用意しているので、ここではそれを利用している)。
話がずれたが、変数jsonが参照している文字列値が本題であるAdaptive Cardsの本体だ。「$」で表される補間文字列と、「@」で表される逐語的文字列リテラルを組み合わせているため、波かっこを「{{……}}」のようにエスケープしている点に注意しよう。エスケープを除くと、これは次のようなデータを定義している。
{
'type': 'AdaptiveCard',
'version': '1.0',
'body': [
{
'type': 'TextBlock',
'text': 'Hello From Insider.NET (with json)',
'size': 'large'
},
{
'type': 'TextBlock',
'text': 'Adaptive Cards sample',
'separation': 'none'
},
{
'type': 'TextBlock',
'text': 'your input: {activity.Text}'
}
],
'actions': [
{
'type': 'Action.OpenUrl',
'url': 'http://www.atmarkit.co.jp',
'title': 'Learn More'
}
]
}
Adaptive Cardsでは、そのスキーマが定められている。詳細は「Schema Explorer」ページを参考にしてほしいが、typeプロパティとversionプロパティが必須であり、上ではそれぞれ「AdaptiveCard」と「1.0」となっている。bodyプロパティとactionsプロパティはオプションの要素だが、ここにカードに表示されるコンテンツを記述していくので、実質的には必須の要素といってもよいだろう。
ここでは、bodyプロパティには3つの「TextBlock」要素を含めている。また、actionsプロパティには1つの「Action.OpenUrl」アクションが含まれている。前者はユーザーに表示したりそこに何らかの情報を入力してもらったりするためのコンテンツを、後者はユーザーが操作可能なアクションを表す。アクションには、クリックすると対応付けられたUrlがWebブラウザに表示されるものや、ユーザー入力をサブミットするためのものなどがある。ユーザーが操作した結果は、上で簡単に触れたActivityクラスを通じて、botへと返送される。
TextBlock要素やAction.OpenUrl要素も当然、Adaptive Cardsのスキーマとして定められていて、例えば、TextBlock要素にはその文字色を指定するcolorプロパティや、実際に表示されるテキストを表すtextプロパティ、フォントサイズを指定するsizeプロパティ、要素間の間隔を示すseparationプロパティなどが定義されている(なお、separationプロパティは既に古くなって、現在ではspacingプロパティの使用が推奨されている)。
一方のAction.OpenUrl要素が持つプロパティは上で使用しているtype/title/urlの3つのみだ(全て必須)。typeプロパティは「Action.OpenUrl」決め打ちで、titleプロパティはユーザーに表示されるボタンのラベルとなる。urlプロパティの値はもちろん、そのボタンをクリックしたときに開かれるURLだ。
次ページでは今書いたコードの動作を確認してみよう。
Copyright© Digital Advantage Corp. All Rights Reserved.