본문으로 건너뛰기

생성

대화가 아니라 이미지, 음성, 전사 또는 동영상이 필요할 수 있습니다. 이 모든 것은 하나의 요청과 하나의 결과로 이루어진 생성입니다. 모두 같은 형태를 공유하므로 하나를 익히면 나머지도 사용할 수 있습니다.

가장 빠른 방법

결과를 스트리밍하는 서버 라우트입니다.

import { generateImage, toServerSentEventsResponse } from '@tanstack/ai'
import { openaiImage } from '@tanstack/ai-openai'

export async function POST(request: Request) {
const { prompt } = await request.json()
const stream = generateImage({
adapter: openaiImage('dall-e-3'),
prompt: typeof prompt === 'string' ? prompt : '',
stream: true,
})
return toServerSentEventsResponse(stream)
}

이를 호출하는 훅입니다.

import { fetchServerSentEvents, useGenerateImage } from '@tanstack/ai-react'

function ImageGenerator() {
const { generate, result, isLoading, error } = useGenerateImage({
connection: fetchServerSentEvents('/api/generate/image'),
})

return (
<div>
<button onClick={() => generate({ prompt: 'A sunset over mountains' })}>
{isLoading ? 'Generating…' : 'Generate'}
</button>
{error && <p role="alert">{error.message}</p>}
{result?.images.map((img, i) => (
<img key={i} src={img.url || `data:image/png;base64,${img.b64Json}`} />
))}
</div>
)
}

이것이 전체 루프입니다. 아래 표의 다른 쌍으로 generateImageuseGenerateImage를 바꾸면 다른 것은 변경할 필요가 없습니다.

어떤 전송 방식인가요?

전송 방식사용 시점방법
스트리밍 라우트API 라우트가 있을 때 사용합니다. 기본 방식이며 위 스니펫에서 사용합니다.stream: truetoServerSentEventsResponse를 사용하고 훅에 connection:을 전달합니다.
직접 호출서버 함수를 호출하고 일반 JSON을 반환받을 때 사용합니다. 가장 간단하며 스트리밍하지 않습니다.함수에서 결과를 반환하고 훅에 fetcher:를 전달합니다.
스트리밍하는 서버 함수TanStack Start 서버 함수를 사용하며 타입이 지정된 입력과 스트리밍이 필요할 때 사용합니다.함수에서 toServerSentEventsResponse(...)를 반환하고 fetcher:를 전달합니다.

Start를 사용할 때는 세 번째 방식이 두 장점을 모두 제공합니다. 입력에 타입이 완전히 지정되고 스트리밍이 자동으로 처리됩니다. 세 가지 방식 모두 전송 방식 전체 보기에 설명되어 있습니다.

사용 가능한 생성

활동서버 함수클라이언트 훅(React)가이드
이미지 생성generateImage()useGenerateImage()이미지 생성
오디오 생성generateAudio()useGenerateAudio()오디오 생성
텍스트 음성 변환generateSpeech()useGenerateSpeech()텍스트 음성 변환
전사generateTranscription()useTranscription()전사
요약summarize()useSummarize()-
동영상 생성generateVideo()useGenerateVideo()동영상 생성

참고: 동영상 생성은 작업/폴링 아키텍처를 사용합니다. useGenerateVideo 훅은 폴링 수명 주기를 추적할 수 있도록 jobId, videoStatus, onJobCreated, onStatusUpdate도 추가로 제공합니다. 자세한 내용은 동영상 생성 가이드를 참고합니다.

고급

전송 방식 전체 보기

스트리밍 모드(Connection Adapter)

서버는 생성 함수에 stream: true를 전달하고 결과를 SSE로 보냅니다. 클라이언트는 fetchServerSentEvents()를 사용해 스트림을 소비합니다.

서버:

import { generateImage, toServerSentEventsResponse } from '@tanstack/ai'
import { openaiImage } from '@tanstack/ai-openai'

// In your API route handler
const stream = generateImage({
adapter: openaiImage('dall-e-3'),
prompt: 'A sunset over mountains',
stream: true,
})

return toServerSentEventsResponse(stream)

클라이언트:

import { useGenerateImage, fetchServerSentEvents } from '@tanstack/ai-react'

const { generate, result, isLoading } = useGenerateImage({
connection: fetchServerSentEvents('/api/generate/image'),
})

직접 호출 모드(Fetcher)

클라이언트는 서버 함수를 직접 호출하고 결과를 JSON으로 받습니다. 스트리밍 프로토콜은 필요하지 않습니다.

서버:

import { createServerFn } from '@tanstack/react-start'
import { generateImage } from '@tanstack/ai'
import { openaiImage } from '@tanstack/ai-openai'

export const generateImageFn = createServerFn({ method: 'POST' })
.inputValidator((data: { prompt: string }) => data)
.handler(async ({ data }) => {
return generateImage({
adapter: openaiImage('dall-e-3'),
prompt: data.prompt,
})
})

클라이언트:

import { useGenerateImage } from '@tanstack/ai-react'
import { generateImageFn } from '../lib/server-functions'

const { generate, result, isLoading } = useGenerateImage({
fetcher: (input) => generateImageFn({ data: input }),
})

서버 함수 스트리밍(Fetcher + Response)

두 방식의 장점을 결합합니다. fetcher 패턴의 타입 안전 입력과 SSE Response를 반환하는 서버 함수의 스트리밍을 함께 사용합니다. fetcher가 일반 결과가 아닌 Response 객체를 반환하면 클라이언트가 이를 SSE 스트림으로 자동 파싱합니다.

서버:

import { createServerFn } from '@tanstack/react-start'
import { generateImage, toServerSentEventsResponse } from '@tanstack/ai'
import { openaiImage } from '@tanstack/ai-openai'

export const generateImageStreamFn = createServerFn({ method: 'POST' })
.inputValidator((data: { prompt: string }) => data)
.handler(({ data }) => {
return toServerSentEventsResponse(
generateImage({
adapter: openaiImage('dall-e-3'),
prompt: data.prompt,
stream: true,
}),
)
})

클라이언트:

import { useGenerateImage } from '@tanstack/ai-react'
import { generateImageStreamFn } from '../lib/server-functions'

const { generate, result, isLoading } = useGenerateImage({
fetcher: (input) => generateImageStreamFn({ data: input }),
})

TanStack Start 서버 함수를 사용할 때 권장하는 방식입니다. 입력에 타입이 완전히 지정되고(예: ImageGenerateInput) 스트리밍 프로토콜이 투명하게 처리됩니다.

스트리밍 작동 방식

생성 함수에 stream: true를 전달하면 일반 결과 대신 StreamChunk 이벤트의 비동기 이터러블을 반환합니다.

1. RUN_STARTED          → Client sets status to 'generating'
2. CUSTOM → Client receives the result
name: 'generation:result'
value: <your result>
3. RUN_FINISHED → Client sets status to 'success'

함수에서 예외가 발생하면 대신 RUN_ERROR 이벤트가 방출됩니다.

1. RUN_STARTED          → Client sets status to 'generating'
2. RUN_ERROR → Client sets error + status to 'error'
error: { message: '...' }

이는 채팅 스트리밍에서 사용하는 것과 동일한 이벤트 프로토콜이므로 두 경우 모두 같은 전송 계층(toServerSentEventsResponse, fetchServerSentEvents)이 작동합니다.

서버가 RUN_ERROR를 방출하면 클라이언트는 이를 error에 표시하고 status'error'로 설정합니다. 이에 대응하려면 onError 콜백을 사용하고 UI에 error?.message를 렌더링합니다.

import { useGenerateImage, fetchServerSentEvents } from '@tanstack/ai-react'

function ImageGenerator() {
const { generate, result, error, status } = useGenerateImage({
connection: fetchServerSentEvents('/api/generate/image'),
onError: (err) => console.error('Generation failed:', err.message),
})

return (
<div>
<button onClick={() => generate({ prompt: 'A sunset over mountains' })}>
Generate
</button>
{status === 'error' && <p role="alert">Error: {error?.message}</p>}
{result?.images.map((img, i) => (
<img key={i} src={img.url || `data:image/png;base64,${img.b64Json}`} />
))}
</div>
)
}

공통 훅 API

모든 생성 훅은 동일한 인터페이스를 공유합니다.

옵션타입설명
connectionConnectionAdapter스트리밍 전송(SSE, HTTP 스트림, 사용자 지정)
fetcher(input) => Promise<Result | Response>직접 호출하는 비동기 함수 또는 SSE Response를 반환하는 서버 함수
threadIdstring이 생성의 안정적인 범위입니다. persistence가 켜져 있을 때 필요하며, 일시적인 실행에서는 선택 사항입니다.
bodyRecord<string, any>추가 본문 매개변수(연결 모드)
onResult(result) => T | null | void결과를 변환하거나 결과에 반응합니다.
onError(error) => void오류 콜백
onProgress(progress, message?) => void진행률 업데이트(0-100)
반환값타입설명
generate(input) => Promise<void>생성 시작
resultT | null결과(선택적으로 변환됨) 또는 null
isLoadingboolean생성 진행 여부
errorError | undefined현재 오류(있는 경우)
statusGenerationClientState'idle' | 'generating' | 'success' | 'error'
stop() => void현재 생성 중단
reset() => void모든 상태를 지우고 idle 상태로 돌아갑니다.

결과 변환

onResult 콜백은 저장된 결과를 선택적으로 변환할 수 있습니다.

  • null이 아닌 값을 반환하면 저장된 결과를 변환된 값으로 바꿉니다.
  • **null**을 반환하면 이전 결과를 변경하지 않습니다(필터링에 유용합니다).
  • 아무것도 반환하지 않으면(void) 원시 결과를 그대로 저장합니다.

TypeScript는 onResult 반환값에서 결과 타입을 자동으로 추론하므로 명시적인 제네릭 매개변수가 필요하지 않습니다.

import { useGenerateSpeech, fetchServerSentEvents } from '@tanstack/ai-react'
import type { TTSResult } from '@tanstack/ai'

function SpeechPlayer() {
const { result } = useGenerateSpeech({
connection: fetchServerSentEvents('/api/generate/speech'),
onResult: (raw: TTSResult) => ({
audioUrl: `data:${raw.contentType};base64,${raw.audio}`,
duration: raw.duration,
}),
})
// result is typed as { audioUrl: string; duration?: number } | null
}

아키텍처

flowchart TB
subgraph Server ["Server"]
direction TB
activities["generateImage({ ..., stream: true })
generateSpeech({ ..., stream: true })
generateTranscription({ ..., stream: true })
summarize({ ..., stream: true })
generateVideo({ ..., stream: true })"]
transport["toServerSentEventsResponse()"]
activities --> transport
end

transport -- "StreamChunks via SSE
RUN_STARTED → generation:result → RUN_FINISHED" --> adapter

subgraph Client ["Client"]
direction TB
adapter["fetchServerSentEvents('/api/...')"]
gc["GenerationClient
(state machine)"]
hooks["Framework Hooks
useGenerateImage() · useGenerateSpeech()
useGenerateVideo() · useSummarize()
useTranscription()"]
adapter --> gc
gc -- "result, isLoading, error, status" --> hooks
end

핵심은 서버의 모든 생성 활동이 결과를 반환하는 비동기 함수일 뿐이라는 점입니다. stream: true를 전달하면 함수는 일반 결과 대신 StreamChunk 이터러블을 반환하며, 클라이언트는 이를 이미 소비할 수 있습니다.