包括的な開発者ガイドとベストプラクティスで、すばやく開発を始められます。
SSE ストリーミング
翻訳・音声認識エンドポイントは共に stream=true に対応します。本章では 5 種類のイベント構造、クライアント解析例、mid-stream エラーハンドリング、ASR と翻訳の主な違いをまとめます。
SSE(Server-Sent Events)モードでは、API はモデルの完了を待たず、結果を複数イベントに分割して順次返却します。応答の Content-Type は text/event-stream、各イベントは data: <JSON> で始まり空行(\n\n)で終端。イベント順序は head → chunk* → tail → meta、失敗時は任意の時点で error イベントが残りを置換しストリームを終了します。
イベント構造
下表に 5 種類のイベントの順序と payload をまとめます。head / tail / meta は必須(ストリームごとに 1 件)、chunk は 0〜複数件、error は任意の時点で発生し、出現後はストリームを終了します。
ストリームイベント一覧
| Event | Order | Required | Data shape | Description |
|---|---|---|---|---|
head | 1 | translation: { source_lang: string } asr: { detected_language: string } | ストリーム開始イベント。翻訳は source_lang、音声認識は detected_language(フィールド名が異なる)。 | |
chunk | 2..N | string | 出力テキスト片。data がそのまま片の文字列。0〜複数件。到着順に連結して完全出力を再構成。 | |
tail | N+1 | translation: (empty) asr: { segments?: Segment[] } | 出力終了マーカー。翻訳は data なし、音声認識は timestamp_format 指定時に segments を併載することがある。 | |
meta | N+2 | translation: { usage } asr: { usage; vocabulary_used; forced_replacement_count } | メタデータイベント。翻訳は usage のみ、音声認識は vocabulary_used と forced_replacement_count を追加で含む(後者は SSE では恒常 0)。 | |
error | any | { code; message; details?; request_id? } | 業務エラーイベント。任意の時点で発生しストリームを終了。code は JSON モードと同一、request_id は問題報告時に併記可。 |
クライアント側の解析
解析方法は標準 EventSource(GET のみ)または fetch + ReadableStream(POST + カスタムヘッダ対応、本 API は POST のため後者を使用)の 2 通り。下記は fetch 経路の例:ストリームを読み、空行で分割し、data: 行を JSON.parse し、type で分岐します。
fetch + ReadableStream + TextDecoder で SSE を解析。buffer.split + buffer.pop により、パケットを跨ぐ不完全イベントを処理。
const res = await fetch("https://abemono.abestar.com.tw/api/v1/translations/text", { method: "POST", headers: { "X-API-Key": process.env.ABESTAR_API_KEY, "Content-Type": "application/json", Accept: "text/event-stream", }, body: JSON.stringify({ text: "今天的會議改到下午三點。", target_language: "en", stream: true, }), }); const reader = res.body.getReader(); const decoder = new TextDecoder(); let buffer = ""; let output = ""; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); // Events are separated by a blank line; the last partial event stays in the buffer. const events = buffer.split("\n\n"); buffer = events.pop() ?? ""; for (const evt of events) { const dataLine = evt.split("\n").find((l) => l.startsWith("data: ")); if (!dataLine) continue; const payload = JSON.parse(dataLine.slice(6)); switch (payload.type) { case "head": console.log("source_lang:", payload.data.source_lang); break; case "chunk": output += payload.data; break; case "tail": console.log("output:", output); break; case "meta": console.log("usage:", payload.data.usage); break; case "error": console.error(payload.data.code, payload.data.request_id); break; } } }
mid-stream エラーハンドリング
ストリーム中にエラーや処理タイムアウトが発生すると、サーバーは error イベントを送信してストリームを終了します。受信済み chunk は有効なまま残り、部分結果を保持するか全破棄するかは利用側の判断。エラー code は JSON モードと同一(translation_failed / asr_timeout / content_policy_violation 等)。
mid-stream error イベント例。診断の起点として code と request_id を取り出してください。
data: {
"type": "error",
"data": {
"code": "translation_failed",
"message": "Translation service temporarily unavailable",
"details": {},
"request_id": "0af7651916cd43dd8448eb211c80319c"
}
}SSE の業務エラーでも HTTP status は 200
ASR と翻訳の違い
- head のフィールド名が異なる:翻訳は source_lang、音声認識は detected_language。
- tail の payload が異なる:翻訳の tail は data なし、音声認識の tail は timestamp_format 指定時に segments を併載。
- meta の payload が異なる:翻訳の meta は usage のみ、音声認識の meta は vocabulary_used と forced_replacement_count を追加で含む。
- エラーコードのプレフィックスが異なる:翻訳は translation_*、音声認識は asr_*(asr_failed / asr_timeout 等)。
- 両エンドポイント共に forced_replacement と排他:stream=true と forced_replacement_dictionary_id を同時送信すると、ストリーム開始前に 400 validation_error が返ります。

