自分はどちらかと言うとインフラ寄りの 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 でチャットしてる例
参考