1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Microsoft.Bot.Framework で作成される EchoBot.cs をいじってみた

Posted at

自分はどちらかと言うとインフラ寄りの CI/CD エンジニアなのですが、専門外の私にも ChatGPT との連携を検証する日がやって来ました。いちユーザーとして ChatGPT を使うだけの幸せな日常から、仕事として携わる日も近いかもしれません。という事で趣味がてら EchoBot.cs をいじって OpenAI の REST API に会話を送ったり、CosmosDB にチャット履歴を保存したりを試してみました。

C# VSCode CLI でボットアプリを作成

こちらのドキュメントを参考にボットアプリを作成します。

bash
$ dotnet --version
6.0.300

$ dotnet new -i Microsoft.Bot.Framework.CSharp.EchoBot
次のパッケージがインストールされます:
   Microsoft.Bot.Framework.CSharp.EchoBot

Microsoft.Bot.Framework.CSharp.EchoBot は既にインストールされています。バージョン: 4.17.1、バージョン  に置き換えられます。
Microsoft.Bot.Framework.CSharp.EchoBot::4.17.1 が正常にアンインストールされました。
成功: Microsoft.Bot.Framework.CSharp.EchoBot::4.17.1により次のテンプレートがインストールされました。
テンプレート名                    短い名前  言語  タグ                                           
--------------------------------  --------  ----  -----------------------------------------------
Bot Framework Echo Bot (v4.17.1)  echobot   [C#]  Bot/Bot Framework/Echo Bot/Conversational AI/AI

$ dotnet new echobot -n mnrechobot
テンプレート "Bot Framework Echo Bot (v4.17.1)" が正常に作成されました。

作成後の操作を処理しています...
復元するプライマリ出力はありません。

$ cd mnrechobot

$ dotnet run

テンプレートが生成する EchoBot.cs を確認

Bots/EchoBots.cs
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with EchoBot .NET Template version v4.17.1

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;

namespace EchoBot.Bots
{
    public class EchoBot : ActivityHandler
    {
        protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            var replyText = $"Echo: {turnContext.Activity.Text}";
            await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken);
        }

        protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
        {
            var welcomeText = "Hello and welcome!";
            foreach (var member in membersAdded)
            {
                if (member.Id != turnContext.Activity.Recipient.Id)
                {
                    await turnContext.SendActivityAsync(MessageFactory.Text(welcomeText, welcomeText), cancellationToken);
                }
            }
        }
    }
}

検証のために色々いじった EchoBots.cs

OpenAI の REST API に会話を送ったり、CosmosDB にチャット履歴を保存したり、チャット履歴をクリアしたりする機能を検証してみました。

dotnet add package Microsoft.Azure.Cosmos とかは必要に応じて。

Bots/EchoBots.cs
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with EchoBot .NET Template version v4.17.1

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using System.Net.Http;
using System.Net.Http.Headers;
using System;
using System.Text.Json;
using System.Text;
using System.Net;
using Newtonsoft.Json.Linq;
using Microsoft.Azure.Cosmos;

namespace EchoBot.Bots
{
    public class EchoBot : ActivityHandler
    {
        protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            // デフォルトで返す値
            var replyText = $"You Say: {turnContext.Activity.Text}";

            // OpenAI の REST API 準備
            HttpClient httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
            JObject postData = JObject.Parse(@"{
                ""model"": ""gpt-3.5-turbo"",
                ""messages"": []
            }");
            JArray messages = (JArray)postData["messages"];

            // CosmosDB 準備
            var client = new CosmosClient(Environment.GetEnvironmentVariable("CDB_ENDPOINT"), Environment.GetEnvironmentVariable("CDB_KEY"));
            var databaseResponse = await client.CreateDatabaseIfNotExistsAsync("chat");
            var containerProperties = new ContainerProperties(turnContext.Activity.From.Id, "/id");
            var containerResponse = await databaseResponse.Database.CreateContainerIfNotExistsAsync(containerProperties);
            var database = client.GetDatabase("chat");
            var container = database.GetContainer(turnContext.Activity.From.Id);

            // チャット履歴を削除
            if (turnContext.Activity.Text == "clear")
            {
                await container.DeleteContainerAsync();
                containerResponse = await databaseResponse.Database.CreateContainerIfNotExistsAsync(containerProperties);
                container = database.GetContainer(turnContext.Activity.From.Id);
                await turnContext.SendActivityAsync(MessageFactory.Text("チャット履歴をクリアしました!", replyText), cancellationToken);
                return;
            }

            // CosmosDB からチャット履歴を取得
            var sqlQueryText = "SELECT * FROM c";
            var queryDefinition = new QueryDefinition(sqlQueryText);
            var results = container.GetItemQueryIterator<dynamic>(queryDefinition);
            while (results.HasMoreResults)
            {
                var items = await results.ReadNextAsync();
                foreach (var item in items)
                {
                    // OpenAI のリクエストに追加
                    JObject history = new JObject();
                    history.Add("role", item["role"]);
                    history.Add("content", item["content"]);
                    messages.Add(history);
                }
            }

            // OpenAI のリクエストの最後に今回のプロンプトを追加
            JObject message = new JObject();
            message.Add("role", "user");
            message.Add("content", turnContext.Activity.Text);
            messages.Add(message);

            // OpenAI の REST API を実行
            var post = postData.ToString();
            var response = await httpClient.PostAsync("https://api.openai.com/v1/chat/completions",
                new StringContent(post, Encoding.UTF8, "application/json"));
            if (response.StatusCode == HttpStatusCode.OK)
            {
                // 実行結果のテキストを格納
                replyText = "";
                JObject completions = JObject.Parse(await response.Content.ReadAsStringAsync());
                foreach (var value in completions.GetValue("choices"))
                {
                    replyText += value["message"]?["content"];
                }

                // CosmosDB にチャット履歴を保存
                var newItem = new {
                    id = Guid.NewGuid().ToString(),
                    role = "user",
                    content = turnContext.Activity.Text
                };
                await container.CreateItemAsync(newItem);
                var addItem = new {
                    id = Guid.NewGuid().ToString(),
                    role = "assistant",
                    content = replyText
                };
                await container.CreateItemAsync(addItem);
            }

            // チャット返信
            await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken);
        }

        protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
        {
            var welcomeText = "Hello and welcome!";
            foreach (var member in membersAdded)
            {
                if (member.Id != turnContext.Activity.Recipient.Id)
                {
                    await turnContext.SendActivityAsync(MessageFactory.Text(welcomeText, welcomeText), cancellationToken);
                }
            }
        }
    }
}

Teams でチャットしてる例

teams-botframework-sample.png

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?