Skip to main content
POST
https://sajuapi.dev
/
v1
/
fortunes
/
stream
운세 스트리밍 (SSE)
curl --request POST \
  --url https://sajuapi.dev/v1/fortunes/stream \
  --header 'Content-Type: application/json' \
  --header 'X-API-Key: <api-key>' \
  --data '
{
  "profile_id": "<string>",
  "fortune_type": "<string>",
  "fortune_date": "<string>",
  "model": "<string>"
}
'
v1 Enterprise API (Coming Soon)이 엔드포인트는 Enterprise 버전에서 제공될 예정입니다. 현재는 v0 API를 사용하세요.
Server-Sent Events(SSE)를 사용하여 운세를 실시간으로 스트리밍합니다. AI 모델의 응답이 생성되는 대로 클라이언트에 전달되어 사용자 경험을 향상시킵니다.
스트리밍 API는 텍스트가 생성되는 즉시 전달되므로, 전체 응답을 기다리는 것보다 체감 응답 속도가 빠릅니다. 채팅 UI나 실시간 표시가 필요한 경우 이 API를 사용하세요.

Request Body 파라미터

profile_id
string
required
운세를 생성할 프로필의 ID입니다. prf_ 접두사로 시작합니다.
fortune_type
string
required
운세 유형입니다. daily, yearly, monthly 중 하나입니다.
fortune_date
string
운세 날짜입니다. ISO 8601 형식(YYYY-MM-DD)입니다. 기본값은 오늘입니다.
model
string
default:"haiku"
사용할 AI 모델입니다. haiku, sonnet, gpt4o 중 하나입니다.

Response

스트리밍 응답은 text/event-stream 형식으로 반환됩니다. 각 이벤트는 다음 형식을 따릅니다.

이벤트 타입

이벤트설명
start스트리밍 시작. 운세 ID와 메타데이터를 포함합니다.
delta텍스트 조각. 생성된 텍스트의 일부입니다.
category카테고리별 운세 완료. 각 카테고리가 완료될 때 발생합니다.
done스트리밍 완료. 최종 통계를 포함합니다.
error에러 발생. 에러 정보를 포함합니다.

실패

상태 코드에러 타입설명
400validation_error요청 데이터가 유효하지 않음
401authentication_errorAPI 키가 유효하지 않음
404not_found프로필을 찾을 수 없음
429rate_limited요청 한도 초과

요청 예시

curl -X POST https://api.sajuapi.dev/v1/fortunes/stream \
  -H "X-API-Key: bs_live_xxx" \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "profile_id": "prf_abc123def456",
    "fortune_type": "daily",
    "model": "sonnet"
  }'

응답 예시

event: start
data: {"event":"start","id":"ftn_xyz789abc123","profile_id":"prf_abc123def456","fortune_type":"daily","model":"sonnet"}

event: delta
data: {"event":"delta","text":"오늘은 "}

event: delta
data: {"event":"delta","text":"새로운 기회가 "}

event: delta
data: {"event":"delta","text":"찾아오는 날입니다."}

event: category
data: {"event":"category","category":"overall","score":85,"description":"전반적으로 긍정적인 하루가 예상됩니다."}

event: category
data: {"event":"category","category":"wealth","score":75,"description":"재물운이 안정적입니다."}

event: category
data: {"event":"category","category":"love","score":90,"description":"인간관계가 원만합니다."}

event: category
data: {"event":"category","category":"health","score":80,"description":"건강은 양호합니다."}

event: category
data: {"event":"category","category":"career","score":88,"description":"업무에서 좋은 성과가 기대됩니다."}

event: done
data: {"event":"done","id":"ftn_xyz789abc123","score":85,"latency_ms":2340,"tokens_used":456}

React 예시

import { useState, useEffect } from 'react';

function FortuneStream({ profileId }) {
  const [fortune, setFortune] = useState('');
  const [categories, setCategories] = useState({});
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const fetchFortune = async () => {
      const response = await fetch('/v1/fortunes/stream', {
        method: 'POST',
        headers: {
          'X-API-Key': 'bs_live_xxx',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          profile_id: profileId,
          fortune_type: 'daily'
        })
      });

      const reader = response.body.getReader();
      const decoder = new TextDecoder();

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;

        const lines = decoder.decode(value).split('\n');
        for (const line of lines) {
          if (!line.startsWith('data: ')) continue;
          const data = JSON.parse(line.slice(6));

          switch (data.event) {
            case 'delta':
              setFortune(prev => prev + data.text);
              break;
            case 'category':
              setCategories(prev => ({
                ...prev,
                [data.category]: data
              }));
              break;
            case 'done':
              setIsLoading(false);
              break;
          }
        }
      }
    };

    fetchFortune();
  }, [profileId]);

  return (
    <div>
      <p>{fortune}</p>
      {isLoading && <span>생성 중...</span>}
    </div>
  );
}

연결 관리

  • 연결 타임아웃: 30초
  • 최대 스트리밍 시간: 60초
  • 클라이언트가 연결을 끊으면 서버도 생성을 중단합니다
  • 네트워크 오류 시 error 이벤트가 발생합니다