SSE API
Retranslate
連線資訊
| 項目 | 值 |
|---|---|
| 基礎路徑 | https://vas-poc.vurbo.ai/api/v1/sse |
| 協定 | HTTP + Server-Sent Events (SSE) |
| 資料格式 | text/event-stream |
| 認證方式 | Header X-API-Key: {KEY} |
注意:瀏覽器原生 EventSource API 不支援自訂 Header,需使用 fetch API 搭配 ReadableStream,或使用支援 Header 的 SSE 客戶端套件。
端點總覽
| 方法 | 端點 | 說明 |
|---|---|---|
| GET | /api/v1/sse/retranslate/{taskId} | 重新翻譯全文 |
| GET | /api/v1/sse/retranslate/summary/{taskId} | 重新翻譯摘要 |
| GET | /api/v1/sse/recordings/{taskId}/entries/{sid}/retranslate | 重新翻譯單一句子(編輯原文後使用) |
GET /api/v1/sse/retranslate/{taskId}
功能說明
將指定任務的所有句子重新翻譯為目標語言。透過 SSE 串流逐條發送翻譯結果。
使用場景
- 切換顯示語言
- 更新翻譯內容
認證方式
Header:X-API-Key(詳見 認證機制)
請求參數
| 參數 | 位置 | 類型 | 必填 | 說明 |
|---|---|---|---|---|
taskId | path | string | 是 | 錄音 ID(UUID) |
targetLang | query | string | 是 | 目標語言代碼(如 en-US) |
請求範例
curl -N "https://vas-poc.vurbo.ai/api/v1/sse/retranslate/550e8400-e29b-41d4-a716-446655440000?targetLang=en-US" \
-H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"
// 使用 fetch API(因 EventSource 不支援 Header)
async function retranslateSSE(taskId, targetLang, apiKey) {
const response = await fetch(
`https://vas-poc.vurbo.ai/api/v1/sse/retranslate/${taskId}?targetLang=${targetLang}`,
{
headers: {
'X-API-Key': apiKey
}
}
);
const reader = response.body.getReader();
// ... 處理 SSE 事件
}
事件序列
1. translation → 逐條發送翻譯結果(成功句,重複 N 次)
error → 句子翻譯失敗(per-sid,與 translation 交錯出現)
2. done → 翻譯完成
失敗句不發
translation,改發event: error帶sid+error_code,前端可用同一套translationError.ts攔截器處理(與 WebSocket spec 對齊)。
事件格式
translation
{
"sid": 1,
"text": "Hello",
"is_final": true
}
| 欄位 | 類型 | 說明 |
|---|---|---|
sid | number | 句子 ID |
text | string | 翻譯結果 |
is_final | boolean | 是否為最終結果 |
error(per-sid 失敗)
當某句翻譯失敗(如內容過濾、provider error),不發 translation 而是發 error:
{
"error_code": "sse_translation_failed",
"severity": "error",
"message": "SSE translation failed",
"context": "sse",
"sid": 5,
"request_id": "req_abc123",
"timestamp": "2026-04-26T10:30:45.123Z",
"details": {
"translation_language": "ja",
"original_error": "..."
}
}
| 欄位 | 類型 | 說明 |
|---|---|---|
error_code | string | 錯誤碼,常見 sse_translation_failed |
severity | string | 嚴重度 |
message | string | 人類可讀訊息 |
context | string | 錯誤上下文(translation) |
sid | int | 失敗的句子編號 |
details | object | 含 translation_language、original_error 等 debug 資訊 |
失敗的句子會被儲存為翻譯錯誤記錄(見 history-playback),下次載入歷史時可看到失敗標記。
done
{
"totalUpdated": 10
}
| 欄位 | 類型 | 說明 |
|---|---|---|
totalUpdated | number | 更新的句子總數(不含失敗句) |
特有錯誤碼
| 錯誤碼 | HTTP 狀態碼 | 說明 | 處理建議 |
|---|---|---|---|
sse_missing_target_lang | 422 | 缺少目標語言參數 | 提供 targetLang 參數 |
sse_unsupported_language | 422 | 不支援的目標語言 | 使用有效的語言代碼 |
sse_translation_failed | 500 | 翻譯失敗(per-sid) | 失敗的單句仍透過 event: error 通知,整體流程不中斷 |
前端範例
async function retranslate(taskId, targetLang, apiKey) {
const response = await fetch(
`https://vas-poc.vurbo.ai/api/v1/sse/retranslate/${taskId}?targetLang=${targetLang}`,
{
headers: {
'X-API-Key': apiKey
}
}
);
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const events = parseSSE(decoder.decode(value));
for (const event of events) {
if (event.type === 'translation') {
console.log(`句子 ${event.data.sid}: ${event.data.text}`);
} else if (event.type === 'done') {
console.log(`完成,共更新 ${event.data.totalUpdated} 句`);
}
}
}
}
GET /api/v1/sse/retranslate/summary/{taskId}
功能說明
將指定任務的摘要重新翻譯為目標語言。透過 SSE 串流逐段發送翻譯結果。
使用場景
- 切換摘要顯示語言
- 獲取不同語言的摘要
認證方式
Header:X-API-Key(詳見 認證機制)
請求參數
| 參數 | 位置 | 類型 | 必填 | 說明 |
|---|---|---|---|---|
taskId | path | string | 是 | 錄音 ID(UUID) |
targetLang | query | string | 是 | 目標語言代碼(如 en-US) |
請求範例
curl -N "https://vas-poc.vurbo.ai/api/v1/sse/retranslate/summary/550e8400-e29b-41d4-a716-446655440000?targetLang=en-US" \
-H "X-API-Key: vas_aB3dE5fG7hI9jK1lM3nO5pQ7rS9tU1vW"
// 使用 fetch API(因 EventSource 不支援 Header)
async function retranslateSummarySSE(taskId, targetLang, apiKey) {
const response = await fetch(
`https://vas-poc.vurbo.ai/api/v1/sse/retranslate/summary/${taskId}?targetLang=${targetLang}`,
{
headers: {
'X-API-Key': apiKey
}
}
);
const reader = response.body.getReader();
// ... 處理 SSE 事件
}
事件序列
1. summary_translation → 逐段發送摘要翻譯(重複 N 次)
2. done → 翻譯完成
事件格式
summary_translation
{
"text": "累積翻譯結果...",
"is_final": false
}
| 欄位 | 類型 | 說明 |
|---|---|---|
text | string | 累積的翻譯結果(串流式,逐漸增長) |
is_final | boolean | 是否為最終結果(最後一筆為 true) |
done
{
"totalUpdated": 1
}
| 欄位 | 類型 | 說明 |
|---|---|---|
totalUpdated | number | 更新的摘要數(固定為 1) |
特有錯誤碼
| 錯誤碼 | HTTP 狀態碼 | 說明 | 處理建議 |
|---|---|---|---|
sse_summary_not_found | 404 | 找不到摘要 | 該錄音沒有摘要 |
sse_summary_translation_failed | 500 | 摘要翻譯失敗 | 稍後重試 |
GET /api/v1/sse/recordings/{taskId}/entries/{sid}/retranslate
功能說明
重新翻譯單一句子。最常見場景:使用者透過 PATCH /api/v1/recordings/{id}/entries/{sid} 編輯原文後,呼叫此端點將該句的所有翻譯重做。
與全文重翻 (/retranslate/{taskId}) 的差異:
- 全文重翻:翻譯所有句子到指定語言(單一目標語言)
- 單句重翻:只翻譯一個句子,但可同時翻所有已存在的目標語言
使用場景
- 使用者編輯 STT 原文後自動觸發
- 個別句子翻譯失敗的補救
認證方式
Query:api_key(SSE 端點限制,瀏覽器 EventSource 無法帶 Header)。詳見 認證機制。
請求參數
| 參數 | 位置 | 類型 | 必填 | 說明 |
|---|---|---|---|---|
taskId | path | string | 是 | 錄音 ID(UUID) |
sid | path | number | 是 | 句子 ID(1-based) |
targetLang | query | string | 否 | 目標語言代碼。省略時會重翻該句已存在 translated_texts 中的所有語言 |
expectedRevision | query | number | 否 | 樂觀鎖:當前 transcript revision;不符會回 transcript_revision_conflict |
api_key | query | string | 是 | API Key |
請求範例
# 重翻所有已存在語言
curl -N "https://vas-poc.vurbo.ai/api/v1/sse/recordings/{taskId}/entries/5/retranslate?api_key=vas_xxx"
# 只重翻 en-US,並要求 revision 必須是 3
curl -N "https://vas-poc.vurbo.ai/api/v1/sse/recordings/{taskId}/entries/5/retranslate?targetLang=en-US&expectedRevision=3&api_key=vas_xxx"
事件序列
1. connected → 連線確認
2. progress → 開始翻譯某語言(每語言 1 次)
3. translated → 該語言翻譯完成(每語言 1 次)
或 error → 該語言翻譯失敗
4. done → 全部完成
事件格式
progress
{ "sid": 5, "lang": "en-US", "status": "translating" }
translated
{
"sid": 5,
"lang": "en-US",
"text": "Hello world",
"tokens_used": 25
}
error(單語言失敗)
{
"error_code": "sse_translation_failed",
"sid": 5,
"details": { "translation_language": "ja-JP", "original_error": "..." }
}
done
{
"sid": 5,
"revision": 6,
"original_text_edited_at": "2026-05-06T10:30:00.000000Z",
"languages_translated": ["en-US"],
"languages_failed": ["ja-JP"]
}
| 欄位 | 類型 | 說明 |
|---|---|---|
sid | number | 句子 ID |
revision | number | 寫入後的新 revision(用於下次樂觀鎖) |
original_text_edited_at | string|null | 原文編輯時間(若該句被編輯過) |
languages_translated | array | 翻譯成功的語言代碼 |
languages_failed | array | 翻譯失敗的語言代碼 |
特有錯誤碼
| 錯誤碼 | HTTP 狀態碼 | 說明 | 處理建議 |
|---|---|---|---|
recording_not_found | 404 | 錄音不存在或不屬於該使用者 | 確認 taskId 正確 |
recording_not_completed | 422 | 錄音尚未完成處理 | 等待錄音完成後重試 |
entry_not_found | 404 | 找不到指定的句子 | 確認 sid 正確 |
entry_text_empty | 422 | 該句原文為空 | 先透過 PATCH 編輯原文 |
transcript_revision_conflict | 409 | revision 不符(已被其他請求修改) | 重新載入 transcript 取得最新 revision 後重試 |
storage_upload_failed | 500 | 逐字稿儲存失敗 | 稍後重試 |
版本:V1.5.7 最後更新:2026-05-20