コンテンツにスキップ

ストリーミングチャット UI

ストリーミング UI は、トークンが到着するたびに表示されるため即時感があります。パターンは共通: サーバルートが ai& にストリームを開き、SSE のボディをそのままブラウザに流し、クライアントが delta を描画します。

app/api/chat/route.ts
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.aiand.com/v1",
apiKey: process.env.AIAND_API_KEY!,
});
export async function POST(req: Request) {
const { messages } = await req.json();
const stream = await client.chat.completions.create({
model: "deepseek-ai/deepseek-v4-flash",
messages,
stream: true,
stream_options: { include_usage: true },
});
const encoder = new TextEncoder();
const body = new ReadableStream({
async start(controller) {
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content ?? "";
if (delta) controller.enqueue(encoder.encode(delta));
}
controller.close();
},
});
return new Response(body, {
headers: { "Content-Type": "text/plain; charset=utf-8" },
});
}
"use client";
import { useState } from "react";
export default function Chat() {
const [input, setInput] = useState("");
const [output, setOutput] = useState("");
async function send() {
setOutput("");
const res = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages: [{ role: "user", content: input }] }),
});
const reader = res.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { value, done } = await reader.read();
if (done) break;
setOutput((prev) => prev + decoder.decode(value));
}
}
return (
<div>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={send}>Send</button>
<pre>{output}</pre>
</div>
);
}

Node SDK の for await ループはコンテンツチャンクのみを iterate し、metrics trailer イベントを直接公開しません。コストとリクエスト ID を取得するには:

  • リクエスト ID はレスポンスヘッダ X-Request-ID から読む。
  • コストはリクエストヘッダ X-Aiand-Metrics: true を付与した上で、fetch + SSE パーサで data: [DONE] の後の event: metrics を読む — ペイロードにはトークン数・cost・currency が含まれます。ストリーミングイベント を参照。
  • アップストリームのレスポンスボディは OpenAI の形式と完全に一致するため、ベース URL を切り替えるだけで既存パーサがそのまま動作します。
  • API キーをクライアントコードに埋め込まず、必ずサーバ経由で呼び出します。
  • Vercel AI SDK の useChat 連携については Vercel AI SDK を参照。