Chatbotで画像コミュニケーションを実現する
前回までは、Chatbotとの会話の手段として、ダイアログのボタンによるメニュー選択と、AIによる文字列解析を行うために直接テキスト文字を入力する方法を紹介してきました。この二つの方法は、文字によるコミュニケーションを想定して実装したもので、入力ミスを減らす意味合いもあります。
これ以外にもChatbotと会話する方法として、Bot Frameworkには画像によるコミュニケーションを実現する仕組みが用意されています。チャットによるコミュニケーションでは文字だけではなく、写真のやり取りや宣伝のために商品のイメージの表示、さらにLINEのスタンプのようにそれだけでも会話が成り立ってしまうほど、画像によるコミュニケーションは一般的に利用されています。加えて、単なる文字の羅列だけではなくアプリケーションの中に画像を適度に配置することで、インターフェースとしての見栄えの向上にも有効な手段となっています。今回は、Chatbotの画像によるコミュニケーション方法を紹介します。
今回の記事で使用するファイル一式は、以下のリンクからダウンロード可能です。
ユーザーから画像を送信する
まずは、ユーザー側から画像を送信する方法です。画像の送信機能は、最初から用意されているのでとても簡単です。Bot Frameworkのエミュレーターを見てみると、メッセージ入力のテキストボックスの左に画像送信のボタンがあります。エミュレーターに限らずBot Frameworkが提供しているチャンネルで利用できるアプリケーションにはすべて共通の機能が実装されています。こちらをクリックして送信したい画像を選択します。
送信した画像は、対話の中に表示されます。あとはこの画像に対するロジックを実装することになります。例えばAIを使って画像を解析して、その画像が何の写真なのかを判断してメッセージを表示したり、対話の中で文字の代わりにスタンプとして利用したりするといったことが考えられます。
Chatbotから画像を送信する
Chabot側から画像を送信する場合は、対話のメッセージに画像などを添付して表示するという考え方となります。
メッセージの送信方法としては、RootDialog.csを例にすると
await context.PostAsync($@"いらっしゃいませ!ご注文を伺います。 (メニューをご覧になる場合は「メニュー」と入力してください。)");
のように、「context.PostAsync」メソッドを利用できます。この場合送信する内容はテキスト文字列だけでしたが、ダイアログの中でメッセージを作成して送信することが可能です。メッセージの中には文字列だけではなく、画像やボタン、クリックされた時のアクションも含められるようになっています。具体例として、Chatbot201707のデザートメニューのDessertDialog.csで、画像送信ができるように修正していきましょう。
DessertDialog.csは呼び出されるとすぐに選択ボタンが表示されるようになっていますが、まずはこちらをメッセージが表示されるように変更します。
public async Task StartAsync(IDialogContext context) { var message = context.MakeMessage(); message.Text = "デザートをお選びください。"; await context.PostAsync(message); context.Wait(MessageReceivedAsync); } private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result) { var activity = await result as Activity; context.Done(activity.Text); }
重要な箇所なので、1行ずつ説明していきます。
StartAsync
ダイアログが開かれた時に最初に処理される部分です。
var message = context.MakeMessage()
Chatbotから送信するメッセージオブジェクトを作成します。
message.Text = "デザートをお選びください。"
メッセージオブジェクトに送信するテキストを指定します。
await context.PostAsync(message)
作成したメッセージを送信します。
context.Wait(MessageReceivedAsync)
メッセージを送信したらユーザーからの入力を待ちます。
MessageReceivedAsync
ユーザーから入力があった場合の処理です。
context.Done(activity.Text)
ユーザーからの入力内容を戻り値としてダイアログを終了します。終了後はRootDialogに戻ります。
ここまでの状態を確認してみましょう。デザートメニューを選択するとメッセージが表示されています。
送信するメッセージが作成できたので、こちらに画像を添付してみましょう。表示するための画像を「img」フォルダを作成して配置しておきます。
public async Task StartAsync(IDialogContext context) { var message = context.MakeMessage(); message.Text = "デザートをお選びください。"; message.Attachments.Add(new Attachment { ContentUrl = "https://chatbot201707.azurewebsites.net/img/strawberry.jpg", ContentType = "image/jpeg", Name = "季節のフルーツ" }); await context.PostAsync(message); context.Wait(MessageReceivedAsync); }
message.Attachments.Add(new Attachment{~})
メッセージに添付します。添付する内容は、画像のパス、ContentType、名前です。
変更内容を確認してみましょう。以下のように、Chatbotから画像が送信されるようになりました。
シンプルにChatbotからのメッセージに写真を添付するだけであればこれでよいのですが、デザートメニューとして利用するには機能が足りません。そこで次は、複数のデザートの画像を表示して、画像の説明と選択するためのボタンを追加しましょう。そうなると、メッセージに画像だけでなく、ボタンやボタンをクリックした際の動作を追加する必要があります。このような場合には「カード」を利用します。カードに画像やボタンを追加してメッセージに添付することで、上記のデザートメニューを実現できます。今回はカードの一種である「HeroCard」を使って、デザートメニューを作成します。
まずはカードの作り方です。
private static HeroCard SetHeroCard(string title, string imagePath) { var cardImage = new CardImage { Url = imagePath }; var cardAction = new CardAction { Type = ActionTypes.ImBack, Title = "注文する", Value = title, Image = imagePath }; var heroCard = new HeroCard { Title = title, Images = new List<CardImage> { cardImage }, Buttons = new List<CardAction> { cardAction }, Tap = cardAction }; return heroCard; }
各行のポイントを説明します。
SetHeroCard
「HeroCard」を作成するSetHeroCardメソッドを定義します。
var cardImage = new CardImage { Url = imagePath }
カードに表示する画像を定義します。
var cardAction = new CardAction ……
カードもしくは、ボタンをクリックしたときの動作を定義します。ActionTypes.ImBack は、Valueに指定した値をChatbotに送信するという意味です。この他にも、様々な種類の動作を指定することができます。
var heroCard = new HeroCard ……
「HeroCard」を作成します。タイトル、画像(配列型)、ボタン(配列型)、選択した場合の動作を設定します。
カードは複数作成してメッセージに添付できるので、デザートメニューのアイテムごとにカードを作成し、配列として格納します。
public static HeroCard[] SetHeroCards() { var cards = new HeroCard[3]; cards[0] = SetHeroCard("季節のフルーツ", "https://chatbot201707.azurewebsites.net/img/strawberry.jpg"); cards[1] = SetHeroCard("アイスクリーム", "https://chatbot201707.azurewebsites.net/img/icecream.jpg"); cards[2] = SetHeroCard("プリン", "https://chatbot201707.azurewebsites.net/img/pudding.jpg"); return cards; }
着目すべき点をおさえておきましょう。
SetHeroCards
複数のカードを配列として一つにまとめるメソッドを定義します。
var cards = new HeroCard[3]
デザートは3種類あるので、配列に3つのHeroCardを格納します。
cards[0] = SetHeroCard ……
デザートのアイテムごとにSetHeroCardメソッドを呼び出してカードを作成します。
return cards
3つのカードが格納された配列を戻り値としています。
StartAsyncメソッドを修正します。
public async Task StartAsync(IDialogContext context) { var message = context.MakeMessage(); message.Text = "デザートをお選びください。"; var menuCards = SetHeroCards(); foreach (var card in menuCards) { message.Attachments.Add(card.ToAttachment()); } message.AttachmentLayout = AttachmentLayoutTypes.Carousel; await context.PostAsync(message); context.Wait(MessageReceivedAsync); }
着目すべき点をおさえておきましょう。
var menuCards = SetHeroCards()
3つのデザートのカードが格納された配列を取得します。
foreach (var card in menuCards)
配列に格納されたカード一つずつをメッセージに添付します。
message.AttachmentLayout = ……
通常メッセージに添付されたカードは縦に並べて表示されます。この設定を行うことで、複数のカードを横スクロールで表示することができます。
では、エミュレーターで確認してみましょう。おいしそうなデザートメニューが表示されました。デザートを選択したときの動作としても、選択名が表示されて、Chatbotに送信されているのが確認できます。
最終的なDessertDialog.csは以下となります。
using System; using System.Threading.Tasks; using Microsoft.Bot.Builder.Dialogs; using Microsoft.Bot.Connector; using System.Collections.Generic; namespace Chatbot201707.Dialogs { [Serializable] public class DessertDialog : IDialog<string> { public async Task StartAsync(IDialogContext context) { var message = context.MakeMessage(); message.Text = "デザートをお選びください。"; var menuCards = SetHeroCards(); foreach (var card in menuCards) { message.Attachments.Add(card.ToAttachment()); } message.AttachmentLayout = AttachmentLayoutTypes.Carousel; await context.PostAsync(message); context.Wait(MessageReceivedAsync); } public static HeroCard[] SetHeroCards() { var cards = new HeroCard[3]; cards[0] = SetHeroCard("季節のフルーツ", "https://chatbot201707.azurewebsites.net/img/strawberry.jpg"); cards[1] = SetHeroCard("アイスクリーム", "https://chatbot201707.azurewebsites.net/img/icecream.jpg"); cards[2] = SetHeroCard("プリン", "https://chatbot201707.azurewebsites.net/img/pudding.jpg"); return cards; } private static HeroCard SetHeroCard(string title, string imagePath) { var cardImage = new CardImage { Url = imagePath }; var cardAction = new CardAction { Type = ActionTypes.ImBack, Title = "注文する", Value = title, Image = imagePath }; var heroCard = new HeroCard { Title = title, Images = new List<CardImage> { cardImage }, Buttons = new List<CardAction> { cardAction }, Tap = cardAction }; return heroCard; } private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result) { var activity = await result as Activity; context.Done(activity.Text); } } }
今回は、Chatbotの画像によるコミュニケーション方法を紹介しました。デザート以外のメニューについても画像を用意してメニューを表示することで、見栄よく使いやすいChatbotに生まれ変わります。また少しChatbotが成長しましたね。