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〜複数件。到着順に連結して完全出力を再構成。
tail
N+1translation: (empty) asr: { segments?: Segment[] }出力終了マーカー。翻訳は data なし、音声認識は timestamp_format 指定時に segments を併載することがある。
meta
N+2translation: { 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 は問題報告時に併記可。
応答ヘッダは Content-Type: text/event-stream、Cache-Control: no-cache、Connection: keep-alive、X-Accel-Buffering: no。各イベントは空行(\n\n)で終端。

クライアント側の解析

解析方法は標準 EventSource(GET のみ)または fetch + ReadableStream(POST + カスタムヘッダ対応、本 API は POST のため後者を使用)の 2 通り。下記は 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 に固定されます。モデルエラーやタイムアウトはステータスを書き換えず、error イベントとして返却されます。HTTP ステータスではなくイベント payload(payload.type === "error")で成否を判定してください。

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 が返ります。