본문 바로가기

Tips

FastAPI에서 openai의 stream을 text/event-stream으로 반환하기

Backend

router = APIRouter(tags=['foo'], prefix='/foo')


class FooRequest(BaseModel):
    message: str


@router.post('')
def respond(args: FooRequest):
    return StreamingResponse(ask(args.message), media_type='text/event-stream')


def ask(question):
    stream = chat.completions.create(...) # openai 인스턴스화 및 세부 호출 내용은 생략
    for chunk in stream:
        if chunk.choices[0].delta.content is not None:
             yield chunk.choices[0].delta.content

Frontend

const readStream = function() {
    reader.read().then(({done, value}) => {
    if (done) {
      console.log('Stream End');
      return;
    }

    const text = decoder.decode(value, {stream: true});
    console.log(text);
    // 이 부분에 아래와 같은 형식으로 코딩하면, ChatGPT(https://chat.openai.com/)에서처럼
    // 타자치듯 내용이 나오는 구현 가능
    // for (let i in text) {
    //   const c = text[i] === '\n' ? '<br>' : text[i]
    //   대상노드.innerHTML = 대상노드.innerHTML + c;
    // }
    readStream();
  }).catch(error => {
    console.error('Error reading stream:', error);
  });
};

fetch('/chat', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'text/event-stream',
    },
    body: JSON.stringify({message})
  })
  .then(response => {
    addStreamMessage(response);
  })
  .catch(error => {
    console.error('Error:', error);
  });