LoginSignup
13
16

ChatGPTライクなUIを実装する【FastAPI + Next.js】

Last updated at Posted at 2023-05-30

目次

完成イメージ
バックエンド(FastAPI)の実装
フロントエンド(Next.js)の実装
成果物

完成イメージ

ChatGPTのようにレスポンスを1文字ずつ表示する仕組みを作りたい。
videos.gif

バックエンドの実装

  • app/routers/chatai.py ファイルを作成し、streamレスポンスを返すプログラムを書く。
    以下のファイルを作っただけではもちろん動かないので、main.pyでインスタンスを書いてあげよう。
import openai
from fastapi import APIRouter, Request
from fastapi.responses import StreamingResponse

router = APIRouter()


def chatgpt_streamer(msg: str):
    openai.api_key = "ここにはあなたのopenaiのapiキーを書いてください"
    result = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": msg}],
        stream=True,
    )
    for chunk in result:
        if chunk is not None:
            content = chunk["choices"][0]["delta"].get("content")
            if content is not None:
                yield content


@router.post("/chatgpt")
async def chatgpt_stream(request: Request):
    # request.bodyはjson形式でリクエストが投げられることを想定
    # 例) {"message": "100文字の文章を書いて"}
    msg = await request.body()
    return StreamingResponse(
        chatgpt_streamer(msg=msg.decode()), media_type="text/event-stream"
    )

フロントエンドの実装

サンプルではconsole.logで結果を表示しているが、本来はuseStateを使って文字列を画面に表示することになる。

const response = await fetch(`/chatgpt`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ message: "100文字の文章を書いて" }),
});

const data = response.body;
const reader = data.getReader();
const decoder = new TextDecoder();
let done = false;
let result = "";

while (!done) {
    const { value, done: doneReading } = await reader.read();
    done = doneReading;
    const chunkValue = decoder.decode(value);

    result += chunkValue;
    console.log(result + (done ? "" : ""));
}

成果物

sample_chagpt.gif

ロードバランサ(BIGIPなど)を使っているとstreamができないように設定されているサービスもあるので、その場合は設定を変更してあげよう

13
16
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
13
16