ごった煮

色々な事を書いてます

Botと自作のアプリで会話する

Bot Frameworkには、Direct LineというRESTで対話する手段とそれを扱うライブラリが提供されているのでその使い方についてまとめます。

接続の準備

今回は、C#のコンソールアプリを使用します。

HttpClientでガチャガチャやるのもありですがとりあえずライブラリがあるのでそれを使いましょう。

NuGetから以下のパッケージを入れます。

image

Bot Frameworkとの連携は、フレームワークのDirectLineというAPIを使用します。

認証用トークンの取得

まず初めにサーバから認証情報を取得します。

最初にアプリ用の認証トークンを使用するのでBot FrameworkのサイトのDirectLineの画面から取得します。

image

以下の画面は、相変わらずEdgeだとテキストボックスの中身をドラッグできないのでおとなしくChromeとかを使いましょう。

image

会話を始める

以下のコードでConversationsクラス(Botとの対話に使うメインクラス)のインスタンスを生成します。

DirectLineで使用するエンドポイントは、Botのデプロイ先のエンドポイントではなく、”https://directline.botframework.com/” という決まったエンドポイントを使用します。


    private static string baseUrl = "https://directline.botframework.com/"; private static string directLineAuthToken = "取得済みのトークン";
private static Conversations GetConversation() { var credentials = new DirectLineClientCredentials(directLineAuthToken); var directLine = new Microsoft.Bot.Connector.DirectLine.DirectLineClient(new Uri(baseUrl), credentials); return new Microsoft.Bot.Connector.DirectLine.Conversations(directLine); }

会話用のIDを作成する

会話用のインスタンスが生成できたら次は、リクエストに使うためのIDを取得します。

以下の一行でOKです。

var token = await conversation.NewConversationAsync();

これで返ってくるConversationクラスのインスタンスには、DirectLineでメッセージを送受信するためのIDと認証トークンが含まれます。

ETagプロパティも含まれていますが、サーバからのレスポンスに含まれていないのでなくなるのか何か別に使い道があるのか謎です。

メッセージを送受信する

最後にメッセージの送受信をしてみます。

以下のコードで2度メッセージを送ります。

Botのレスポンスは、SendMessageで適当なメッセージを一つとこちらから送信したメッセージの文字数を教えてくれるメッセージの2つです。

        private static async Task SendMessage(Conversations conversation, Conversation token)
        {
            conversation.PostMessage(token.ConversationId, new Microsoft.Bot.Connector.DirectLine.Models.Message
            {
                Text = "hogehoge"
            });
            var messages = await conversation.GetMessagesAsync(token.ConversationId);
            foreach(var message in messages.Messages)
            {
                Console.WriteLine(message.Text);
            }
            var wateMark = messages.Watermark;

            conversation.PostMessage(token.ConversationId, new Microsoft.Bot.Connector.DirectLine.Models.Message
            {
                Text = "hogehoge"
            });
            messages = await conversation.GetMessagesAsync(token.ConversationId, wateMark);
            foreach (var message in messages.Messages)
            {
                Console.WriteLine(message.Text);
            }
            wateMark = messages.Watermark;
        }

PostMessageに、Cnversationクラスに含まれるConversationIdとMessageクラスのインスタンスを渡します。

ちなみにこのMessageクラスは、Microsoft.Bot.Connector.DirectLine.Models名前空間のMessageクラスなのでMicrosoft.Bot.Connector名前空間以下のMessageクラスと混同しないように気を付けましょう。

メッセージをPostした後のサーバからのレスポンスは、PostMessageの戻り値としては返らないのでGetMessagesAsyncメソッドで取得します。このGetMessagesAsyncメソッドは、第二引数に何も渡さないと現在の会話のすべてのメッセージのやり取りを返します。

wateMarkプロパティは、取得したメッセージが会話全体のどこになるのかを持つプロパティになります。このWatemarkプロパティをGetMessagesAsyncに渡すとこのWatemarkプロパティが示す位置より前のメッセージを返さないようにできます。

Watemarkプロパティの有無による挙動の違いの例

Watemarkプロパティをセットした場合

最初にhogehogeというメッセージ、次にtextextというメッセージを投げています。

image

それぞれのメッセージのやり取り単位でしっかりメッセージが取得できています。

Watemarkプロパティをセットしていない場合

以下の場合では、二回目のGetMessagesですべての会話が返されています。

image

Watemarkをセットしないと会話が長引くにつれてレスポンスのサイズが倍々ゲームになっていくので基本はセットしましょう。

 

まとめ

自作のメッセージシステムなんかに組み込みたい場合は、こういった感じのことが必須になります。

具体的なHTTP通信の中身は、暇なときにまとめます。

ぶっちゃけこのライブラリ資料なさ過ぎてどうにも使い方よくわからないんでSwaggerドキュメント見ながら自前でHttpClientで再実装したほうが早かった気がする()