這裡提供完整的開發指南與最佳實踐,幫助您快速上手。
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 至多筆。客戶端依序 concat 即可重組完整輸出。 | |
tail | N+1 | translation: (empty) asr: { segments?: Segment[] } | 輸出結束標記。翻譯無 data 欄位;語音辨識可能附帶 segments(當客戶端要求 timestamp_format 時)。 | |
meta | N+2 | translation: { usage } asr: { usage; vocabulary_used; forced_replacement_count } | 後設資料事件。翻譯只帶 usage(token 用量);語音辨識除 usage 外多了 vocabulary_used 與 forced_replacement_count(後者於 SSE 恆為 0)。 | |
error | any | { code; message; details?; request_id? } | 業務錯誤事件,可在任何時點出現並結束串流。code 與 JSON 模式一致;request_id 可附在問題回報。 |
客戶端解析
本 API 可用標準瀏覽器 EventSource(僅支援 GET)或 fetch + ReadableStream(支援 POST + 自訂 Header,本 API 必走此路徑)解析。下方範例展示 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。

