🐨

FlutterアプリでGPTからのレスポンスをリアルタイムに表示する方法

2024/04/21に公開

やりたいこと

Flutterで作っているChatアプリを作成しています。
MicrosoftのBing Chatみたいに、GPTからのレスポンスをストリーミングで表示させたいので、方法を調べてみました。

前提

1. API側について

API側は既にストリーミングでレスポンスをするように処理をしています。
こちらの記事で実装してますので参考までに。

https://zenn.dev/headwaters/articles/bf9532e71fb844


2. アプリの基礎実装

実装はこちらの記事で作ったチャットアプリをベースにやっていきます。

https://zenn.dev/headwaters/articles/e1886f10aa404e

実装

httpのPOSTリクエストで送った後にlistenでレスポンスをリアルタイムで受け取るようにします。

先に全体

main.dart
  Future<void> requestMessageToGPTApi(requestMessage) async {
    setState(() {
      messageList.add({
        'role': 'user',
        'message': requestMessage,
      });
    });
    _textController.clear();

    final client = http.Client();
    final url = Uri.parse("<your endpoint>");
    var request = http.Request(
      'POST',
      url,
    );
    Map<String, String> headers = {
      'content-type': 'application/json; charset=UTF-8',
      'accept': 'text/event-stream',
    };
    final body = json.encode({'message': requestMessage});
    request.headers.addAll(header);
    request.body = json.encode(body);

    setState(() {
      messageList.add({
        "role": "copilot",
        "message": "",
      });
    });
    final http.StreamedResponse response = await client.send(request);
    response.stream.transform(const Utf8Decoder()).listen((data) {
      setState(() {
        messageList.last["message"] = messageList.last["message"] + data;
      });
    });
  }


1. Clientをインスタンス化

http.postでリクエストを送っていましたが、Clientをインスタンス化して、そこから送るように修正します。
また、header情報として新たに「'accept' : 'text/event-stream'」を追加します。

main.dart
    final client = http.Client();
    final url = Uri.parse("<your endpoint>");
    var request = http.Request(
      'POST',
      url,
    );
    Map<String, String> headers = {
      'content-type': 'application/json; charset=UTF-8',
      // 追加
      'accept': 'text/event-stream',
    };
    final body = json.encode({'message': requestMessage});
    request.headers.addAll(header);
    request.body = json.encode(body);


2. APIに送信

先にmessageListに空文字で追加して、後から文字を足していくようにします。
受け取る方は「http.StreamedResponse」にしてください。

main.dart
    setState(() {
      messageList.add({
        "role": "copilot",
        "message": "",
      });
    });
    final http.StreamedResponse response = await client.send(request);


3. レスポンスを受け取る

レスポンスの情報をlistenすることでリアルタイムにデータが返ってきます。
返ってきたテキストを先ほど追加したmessageListのmessageにどんどん追加していきます。
この辺りはもっと最適な実装でやったほうがいいですが、今回はデモなのでこれでいきます。

main.dart
    response.stream.transform(const Utf8Decoder()).listen((data) {
      setState(() {
        messageList.last["message"] = messageList.last["message"] + data;
      });
    });

検証

上手くできました。

ヘッドウォータース

Discussion