目的
ChatGTPなどのLLMに問い合わせを行った時の回答など最近Server Sent Eventsを使う場面が増えてきました。
今開発してるチャットボットの回答もWebAPI経由で問い合わせを行っているのでその回答をServer Sent Eventsで受け取るべくサンプルプログラムを作成しました。
動作するソースこちらです。
動かす
上記のリポジトリからクローンし、Visual Studioで開き、ServerSentEvents.APIをでばっぐ実行してください
ブラウザが立ち上がり、Blazorの画面が表示されます。
Server Side
キモは
コンテントタイプにtext/event-streamを設定し、WriteAsyncしたのちFlushAsyncするです
// コンテントタイプにtext/event-streamを設定
context.Response.Headers.Append(HeaderNames.ContentType, "text/event-stream");
var counter = 0;
while (!context.RequestAborted.IsCancellationRequested)
{
counter++;
var message = $"data: 現在は {counter} 回目です ({DateTime.Now:HH:mm:ss})\n\n";
// Response.WriteAsyncでデータを返す
await context.Response.WriteAsync(message);
// 強制的に送信
await context.Response.Body.FlushAsync();
apiService.Logger.LogInformation("SSEAsync Send");
await Task.Delay(5000);
}
Client Side
キモは
HttpResponseMessage response;
// streaming is enabled
httpRequestMessage.SetBrowserResponseStreamingEnabled(true);
でストリーミングをenableにし
using Stream responseStream = await response.Content.ReadAsStreamAsync(cancellationToken);
await foreach (SseItem<string> item in SseParser.Create(responseStream).EnumerateAsync())
{
if (cancellationToken.IsCancellationRequested)
{
break;
}
SSEMessages.Add(item.Data);
await InvokeAsync(() => StateHasChanged());
}
ReadAsStreamAsyncでStreamを取得し、SseParser.Create(responseStream).EnumerateAsync()でデータを都度受け取りといった流れです。
SseItemとSseParserを使うにあたり
NugetからSystem.Net.ServerSentEventsをインストールしてください
追加情報
サーバが送信するデータについて
data:で始まり、改行を2つ入れる必要があることが判明しました。
サンプルで上げているコードにはすでに開業が入っています。