Logo

這裡提供完整的開發指南與最佳實踐,幫助您快速上手。

進階

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 可在任意時點出現,出現後串流結束。

串流事件對照表

EventOrderRequiredData shapeDescription
head
1translation: { source_lang: string } asr: { detected_language: string }串流開始事件,攜帶來源/偵測到的語言。翻譯為 source_lang、語音辨識為 detected_language(欄位名稱不同)。
chunk
2..Nstring輸出文字片段,data 即為片段字串。0 至多筆。客戶端依序 concat 即可重組完整輸出。
tail
N+1translation: (empty) asr: { segments?: Segment[] }輸出結束標記。翻譯無 data 欄位;語音辨識可能附帶 segments(當客戶端要求 timestamp_format 時)。
meta
N+2translation: { 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 可附在問題回報。
回應 Header 含 Content-Type: text/event-stream、Cache-Control: no-cache、Connection: keep-alive、X-Accel-Buffering: no。每筆事件以空行(\n\n)收尾。

客戶端解析

本 API 可用標準瀏覽器 EventSource(僅支援 GET)或 fetch + ReadableStream(支援 POST + 自訂 Header,本 API 必走此路徑)解析。下方範例展示 fetch 路線:讀取串流、依空行切事件、取出 data: 行 JSON parse,再以 type 分流處理。

fetch + ReadableStream + TextDecoder 解析 SSE。注意 buffer.split + buffer.pop 處理跨封包的不完整事件。

javascript
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 兩個欄位作為診斷起點。

json
data: {
  "type": "error",
  "data": {
    "code": "translation_failed",
    "message": "Translation service temporarily unavailable",
    "details": {},
    "request_id": "0af7651916cd43dd8448eb211c80319c"
  }
}

SSE 業務錯誤的 HTTP status 仍是 200

串流連線一旦建立,HTTP status 就鎖定為 200。模型錯誤、逾時等情況不會改寫 status,而是改以 error 事件送回。請以 event payload(payload.type === "error")判斷成敗,不要只看 HTTP status。

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。