この記事は
- ChatGPT APIをC#で叩くよ
- Betalgo.OpenAI v7.0.1 を利用するよ
- 成果物はこちら TellMin/ChatGPT_Blazor - stream
対象読者
- C#でChatGPT APIを叩きたい人へ
- ChatGPTの画面のように、少しずつレスポンスを返したい方へ
初めに
以前、 C#でChatGPT APIを触りたい with Betalgo.OpenAI.GPT3
という記事の中でBetalgo.OpenAI.GPT3
の利用方法について紹介しました。
時がたち、名前空間や機能に変更がありましたので、試してみました。
実装
レスポンスをReadableStream - Web API|MDN
として扱ってくれる、CreateCompletionAsStream
メソッドを利用し、画面描画までを行います。
まずはCreateCompletionAsStream
メソッドの呼び出しです。
public async IAsyncEnumerable<string> StreamChat(string prompt)
{
var messages = new List<ChatMessage>()
{
ChatMessage.FromSystem("The following is a conversation with an AI assistant. The assistant is helpful, creative, clever, and very friendly."),
ChatMessage.FromUser(prompt)
};
var completionResult = openAIService.ChatCompletion.CreateCompletionAsStream(
new ChatCompletionCreateRequest()
{
Messages = messages,
Model = Models.ChatGpt3_5Turbo
});
await foreach (var completion in completionResult)
{
if (completion.Successful)
{
yield return completion.Choices.FirstOrDefault()?.Message.Content ?? string.Empty;
}
else
{
if (completion.Error == null)
{
throw new Exception("Unknown Error");
}
Console.WriteLine($"{completion.Error.Code}: {completion.Error.Message}");
}
}
Console.WriteLine("Complete");
}
注目すべきは、StreamChat
メソッドの戻り値が IAsyncEnumerable<string>
型である点です。
これは非同期ストリームを表しており、レスポンスを受け取る度にその中身を呼び出し元に返すことが可能です。
参考文献: 非同期ストリーム - C# によるプログラミング入門
Blazor Serverで非同期ストリームを受け取る
非同期ストリームから受けとった文字列を画面に表示させる場合、注意が必要です。
private async void GetChatCompletion()
{
isChatting = true;
responseMessage = string.Empty;
var response = StreamChatService.StreamChat(chatMessage);
await foreach(var blob in response)
{
responseMessage += blob;
await InvokeAsync(StateHasChanged);
// Allowing control to return to the renderer to update UI.
await Task.Delay(1);
}
isChatting = false;
await InvokeAsync(StateHasChanged);
}
コメントでも補足していますが、await Task.Delay(1);
を実行し、制御をメインのイベントループに戻す必要があります。
ComponentBase.csがその実装箇所であり、新しいレンダリングをキューに入れ、実行を待機します。
どうやら処理を譲るだけで良さそうですので、Task.Delay(1)
の長さは問題にはならなさそうですが、このあたりに詳しい方、是非ご教授いただきたいです。
まとめ
Betalgo.OpenAI
を用いて少しずつレスポンスを返す画面を実装しました。
IAsyncEnumerable
の使い方やBlazorのレンダリングの仕組みについての理解が進んだのであれば幸いです。
最近ではChatGPTにFunction Calingの機能が追加されたりと、新しいことばかりですね。
また進展があれば記事にします
では