WebSocket 回應事件
概述
所有 WebSocket 可能收到的回應事件格式參考。關於連線與認證方式,請參考 連線與認證;關於請求操作,請參考 Voice Translation Actions。
目錄
- session_started - Session 啟動成功
- resume_ok - 斷線續接成功
- result - 辨識/翻譯結果
- status - 通用狀態回應
- task_complete - 任務處理完成
- config_updated - 設定更新完成
- tts_ready - TTS 語音就緒
- tts_error - TTS 合成失敗
- viewer_count - 觀眾人數更新
- broadcast_phase_changed - 廣播階段變更
- broadcast_recording_ready - 廣播錄音就緒
- speaker_renamed - 說話者重命名
- speaker_reassigned - 語者身份修改
- speakers_merged - 語者合併
- language_switch_start - 語言切換開始
- batch_retranslation - 批次重翻結果
- language_switch_done - 語言切換完成
- translation_language_removed - 翻譯語言已移除
- tts_mode_changed - TTS 模式變更
- language_switched - 互譯語言切換完成
- tts_updated - 互譯 TTS 設定更新
- conversation_mode_changed - 對話模式變更
- speaker_language_changed - 用戶語言變更
- speaking_speed_changed - 語速變更
- summary_updated - 摘要設定更新
- segment_uploaded - 音訊分段上傳完成
- stt_event - STT 連線狀態事件
- channel_status - 聲道狀態變更
- segment_discarded - 句子作廢
- viewer_joined - 觀眾加入事件
- viewer_left - 觀眾離開事件
- error - 錯誤事件
- upload_error - 上傳錯誤
- speakers_auto_merged - 說話者自動合併
- summary_done - 摘要生成完成
- summary_error - 摘要生成失敗或未產生
session_started
說明
當 start action 成功後,伺服器回傳包含完整 Session 初始資訊的事件。前端可透過 recording_type 區分錄音類型。
一般錄音(transcribe / conversation / record)
{
"type": "voice-translation",
"data": {
"action": "session_started",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"task_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"recording_type": "transcribe",
"recognition_mode": "single",
"resume_token": "L0VBAwIy...(43 字元)",
"resume_grace_seconds": 45,
"server_time": 1749550000000,
"message": "語音辨識已開始"
}
}
廣播模式(broadcast)
{
"type": "voice-translation",
"data": {
"action": "session_started",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"task_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"recording_type": "broadcast",
"recognition_mode": "multi_speaker",
"phase": "standby",
"viewer_count": 0,
"queue_count": 0,
"peak_viewers": 0,
"total_viewers": 0,
"resume_token": "L0VBAwIy...(43 字元)",
"resume_grace_seconds": 45,
"server_time": 1749550000000,
"message": "語音辨識已開始"
}
}
多聲道模式(multi_channel)
多聲道(實體聲道分離)場次的 session_started 額外帶 channel_mode 與 channels[],回傳伺服器實際生效的聲道設定快照。
{
"type": "voice-translation",
"data": {
"action": "session_started",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"task_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"recording_type": "transcribe",
"recognition_mode": "multi_channel",
"channel_mode": "per_channel",
"channels": [
{
"channel_id": 1,
"speaker_name": "主持人",
"transcription_languages": ["zh-TW"],
"status": "preparing"
},
{
"channel_id": 2,
"speaker_name": "與談人",
"transcription_languages": ["en-US"],
"status": "preparing"
}
],
"resume_token": "L0VBAwIy...(43 字元)",
"resume_grace_seconds": 45,
"server_time": 1749550000000,
"message": "語音辨識已開始"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
session_id | string | 會話 ID(WS 連線層級,連線結束即失效) |
task_id | string | 任務 ID(與 REST /api/v1/tasks/{taskId} 及 Webhook data.task_id 為同一識別碼) |
recording_type | string | 錄音類型:transcribe、conversation、record、broadcast |
recognition_mode | string | 辨識模式:single、multi_speaker、multi_language、multi_channel |
channel_mode | string | 多聲道子模式(僅 multi_channel 場次出現):per_channel(每路聲道獨立辨識)或 shared(各路輪流發言、共用一條辨識) |
channels | object[] | 聲道設定快照(僅 multi_channel 場次出現),每路元素欄位如下 |
channels[].channel_id | int | 聲道編號(1–8,場內唯一) |
channels[].speaker_name | string | 該路綁定的語者名稱(未設定時不出現) |
channels[].transcription_languages | string[] | 該路綁定的轉錄語言(恰 1 個) |
channels[].status | string | 該路狀態:preparing / ready / removed / error,狀態機詳見 channel_status |
resume_token | string | 斷線續接權杖(43 字元)。斷線後於 resume_grace_seconds 寬限期內,重連時帶它即可接回原會話;於 session_started 預先發送,請保存到本次會話結束 |
resume_grace_seconds | int | 重連寬限秒數(預設 45)。為 wall-clock 真實時間,斷線後持續倒數 |
server_time | int64 | 伺服器當下 unix 毫秒。前端可用「(server_time, 收到當下的 client 時間)」估算時鐘偏差作為參考;但 grace 倒數仍以 client wall-clock 為準 |
message | string | 狀態描述訊息 |
phase | string | 廣播階段:standby 或 live(僅廣播模式) |
viewer_count | int | 目前在線觀眾數(僅廣播模式) |
queue_count | int | 排隊等待中的觀眾數(僅廣播模式) |
peak_viewers | int | 本次廣播峰值觀眾數(僅廣播模式) |
total_viewers | int | 累計曾連線的觀眾總數(僅廣播模式) |
ID 對齊提示:WebSocket、REST、Webhook 三個介面以
task_id(UUID)作為任務的統一識別碼。session_id是 WS 連線層級的識別碼,與 task 不同概念。
多聲道場次請驗證
channel_mode:多聲道start成功時,session_started一定帶channel_mode與channels[];若回應沒有這兩個欄位,代表本次連線未以多聲道模式啟動(例如服務正在版本更新、本次連線的服務版本尚未支援多聲道),請立即停止並重新連線,不要當作多聲道場次繼續送音訊。
resume_ok
說明
斷線後於 resume_grace_seconds 寬限期內,以 resume_token 重連成功時,伺服器回傳的事件。收到後請像 start 之後一樣重新開始送音訊流(WebM/Opus 須送全新容器、PCM 直接續送),並依 server_last_sid / server_last_offset_ms 對齊本地內容。若 is_paused 為 true,代表斷線前處於暫停狀態,請續接後維持暫停(重開音訊流後立即暫停、不送音訊),不要逕自恢復錄音。完整續接握手流程請參考 連線與認證。
{
"type": "voice-translation",
"data": {
"action": "resume_ok",
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"task_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"recording_type": "transcribe",
"recognition_mode": "single",
"server_last_sid": 42,
"server_last_offset_ms": 125000,
"server_recording_ms": 127500,
"is_paused": false,
"settings": { ... },
"message": "已續接原會話"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
session_id | string | 會話 ID(WS 連線層級,連線結束即失效) |
task_id | string | 任務 ID(與原會話相同,續接後維持同一識別碼) |
recording_type | string | 錄音類型:transcribe、conversation、record、broadcast |
recognition_mode | string | 辨識模式:single、multi_speaker、multi_language、multi_channel |
server_last_sid | int | 伺服器目前最後一個句子編號(sid)。前端應忽略 sid ≤ 此值的重複訊息 |
server_last_offset_ms | int64 | 斷點對應的逐字稿時間軸位置(毫秒),基於已處理的音訊長度(非 wall-clock;斷線期間音訊時間軸凍結)。前端用它把重連後的新內容接在正確的時間軸位置 |
server_recording_ms | int64 | 續接後逐字稿時間軸實際接續的錄音頭時間(毫秒,含靜音)。前端用它把錄音秒數標頭對齊到逐字稿所用的同一條時間軸。與 server_last_offset_ms 的差值即為斷點前最後一句定稿之後、尚未產出逐字稿的尾端音訊(靜音或未斷句的語音)。省略時為 0 |
is_paused | bool | 續接後伺服器認定的暫停狀態:true=斷線前已暫停,前端應維持暫停(重開音訊流後立即暫停、不送音訊);false=正常錄音中。供斷網重連與整頁 refresh 後對齊暫停 UI。省略時視為 false(向下相容舊版伺服器) |
settings | object | session 目前持有的本次錄音設定(state reconcile 用,v1.6.4 新增);詳見連線文件 |
message | string | 狀態描述訊息(固定為「已續接原會話」) |
注意:兩種時間不可混用:逐字稿時間軸(
server_last_offset_ms)基於音檔、斷線時凍結;grace 重連窗口(resume_grace_seconds)是 wall-clock 真實時間、斷線時持續倒數。判斷「還能不能重連」必須用 wall-clock,不能用音檔時間位置。
多聲道模式(multi_channel):
settings內含channel_mode與channels[](欄位同 session_started 的channels[])。斷線續接不會重新驗證start參數,前端請以這份快照確認伺服器仍在多聲道模式、各路語言綁定未變,並依各路status還原狀態顯示——續接後尚在準備中的路為preparing,約 4 秒後開始出字(期間講話不會丟失,只是延遲出字)。
result
說明
語音辨識與翻譯結果。一個 result 事件可能包含 origin(辨識結果)和/或 translations(翻譯結果)。
origin(語音辨識結果)
{
"type": "voice-translation",
"data": {
"action": "result",
"origin": {
"sid": 1,
"language": "zh-TW",
"text": "你好,很高興認識你",
"is_final": true,
"speaker_id": "0",
"detected_language": "zh-TW",
"start_time": "00:05"
}
}
}
origin 欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
sid | int | 句子編號,從 1 開始 |
language | string | 來源語言代碼。互譯模式與多語轉錄模式下為系統判定的語言——多語模式逐句判定(同一場錄音中會隨每句實際語言變動),判定不可信時維持設定值、欄位不留空 |
text | string | 辨識出的文字 |
is_final | boolean | 是否為最終結果 |
speaker_id | string | 說話者原始 ID |
speaker_label | string | (多人模式)顯示標籤(套 alias 後;無 alias 時等於 speaker_id) |
detected_language | string | 偵測到的語言。互譯模式下由系統自動判定 |
start_time | string | 句子開始時間(mm:ss);廣播 standby 階段不送此欄位,進 live 後從 00:00 起算 |
channel_id | int | (多聲道模式)該句來源的聲道編號;僅 multi_channel 場次出現,每句必帶 |
多聲道模式(multi_channel):
origin每句帶channel_id,且speaker_id格式固定為channel_{N}(N為聲道編號,如channel_3)——語者身分由實體聲道決定、整場穩定不變,不經模型推斷。speaker_label為顯示名稱:經rename_speaker改過時用新名稱,否則為該路設定的speaker_name,兩者皆無時等於speaker_id。
translations(翻譯結果)
{
"type": "voice-translation",
"data": {
"action": "result",
"translations": {
"en-US": {
"sid": 1,
"text": "Hello, nice to meet you",
"is_final": true
}
}
}
}
translations 欄位說明
翻譯結果以語言代碼為 key,每個語言的翻譯物件包含:
| 欄位 | 類型 | 說明 |
|---|---|---|
sid | int | 句子編號 |
text | string | 翻譯後的文字 |
is_final | boolean | 是否為最終結果 |
is_retranslation | boolean | 是否為重新翻譯結果(僅 retranslate 時) |
speaker_id | string | (多人模式)原始語者 ID(自 v1.5.3 與 origin 對齊) |
speaker_label | string | (多人模式)顯示標籤(套 alias 後;無 alias 時等於 speaker_id) |
多語言翻譯(v1.6.7):
translation_languages指定多個語言時,每個語言各回一則獨立的result事件——同一sid會收到 N 則result,每則的translations僅含單一語言 key,不會在一則事件中合併多語言。客戶端需以「sid+ 語言代碼」累積譯文、不可互相覆蓋;各語言到達順序不固定(並行翻譯)。
多聲道模式(multi_channel):
translations不帶channel_id。請以sid對回同句的origin,即可取得該句的聲道與語者資訊。
重要:
retranslateaction 的成功回應走獨立的action: "translation"事件(非result),payload 結構與本表相同。詳見voice-translation.mdretranslate 成功回應。
status
說明
通用狀態回應,用於 pause、resume、stop、set_name、tts_stop、start_speaking 等操作的確認。
{
"type": "voice-translation",
"data": {
"action": "status",
"status": "paused",
"message": "語音辨識已暫停"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
status | string | 機器可讀的錄音生命週期狀態:live(恢復)/ paused(暫停)/ ended(停止)。僅 pause / resume / stop 帶此欄位;set_name 等不帶。ended 一定在 task_complete 之前送出。 |
message | string | 狀態顯示文字(不保證格式,請勿解析;一律以 status 欄位判斷狀態) |
浮動字幕消費端(SSE 浮動字幕)應依
status動作:paused→ 凍結、ended→ 關閉視窗、live→ 恢復。
task_complete
說明
當 stop 後音檔和逐字稿上傳完成時觸發。task_id 可用於後續 REST API 查詢任務詳情。
- 一定在
status: "ended"之後送出。 - 逐字稿含摘要,所以本事件要等標題與摘要生成完成。通常數秒到數十秒;摘要較長或服務較慢時會更久,最長約 8 分鐘。
- 同時錄音名額在送出本事件的當下釋放:收到後即可開始下一場錄音。
- 判斷錄音是否完成,建議同時支援 Webhook 或 REST 查詢,不要只依賴本事件。
- 錄音因為長時間沒有語音而自動結束時,同樣會收到本事件。
{
"type": "voice-translation",
"data": {
"action": "task_complete",
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"message": "任務處理完成"
}
}
整場沒有收到音訊的錄音:不論是送出 stop、點數不足或自動結束,只要整場沒有收到任何音訊,仍會依序收到 status: "ended" 與本事件,並帶 noAudio: true。這筆錄音沒有逐字稿與音檔,狀態為 failed,同時送出 recording.failed Webhook(failure_source 為 no_audio);請不要再去讀取逐字稿,改提示使用者沒有收到聲音。已經過的分鐘照常計費。
{
"type": "voice-translation",
"data": {
"action": "task_complete",
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"noAudio": true,
"message": "任務處理完成"
}
}
廣播在預備階段就結束(還沒開播)時,只會收到
status: "ended",不會收到本事件:預備階段不建立錄音。
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
task_id | string | Recording UUID,可用於後續 API 查詢 |
noAudio | boolean | 只在整場沒有收到任何音訊時出現,值一定是 true;有錄到音訊時不帶這個欄位 |
message | string | 狀態描述 |
config_updated
說明
設定更新完成事件,在 config action 成功後觸發。
注意:僅在設定被接受時觸發。設定被拒絕時回傳的是
type: "error",客戶端需一併監聽,否則會誤判為無回應。
{
"type": "voice-translation",
"data": {
"action": "config_updated",
"updated": ["terminology", "fuzzy_correction", "translation_dict"],
"message": "設定已更新"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
updated | string[] | 已更新的設定類型:terminology、fuzzy_correction、translation_dict |
message | string | 狀態訊息 |
terminology_effective | string | (可選)錄製中更新術語庫時出現,值為 "next_turn":新術語從下一句生效。初始 config 不會出現 |
unknown_languages | string[] | (可選)無法辨識的字庫語言代碼(例如 zh、chinese)。這些字庫不會生效,但 config 仍算成功 |
inactive_languages | string[] | (可選)代碼合法、但本場錄音沒有使用的語言。錄音尚未開始時不會出現(此時語言清單還沒定案) |
inactive_dict_languages | string[] | (可選)同上,但針對翻譯字典的目標語言 |
homophone_conflicts | object[] | (可選)字庫中讀音相同的術語組合,每筆含 languages 與 terms。錄音尚未開始時不會出現(此時語言清單還沒定案) |
homophone_conflicts怎麼看:兩個讀音相同的術語同時登記時(例如「公事包」與「公式包」), 逐字稿出現讀音相同的第三種寫法,系統只能改成其中一個,改成哪一個不保證。 兩個術語本身都仍然生效,不確定的只有「沒登記過的同音錯字歸誰」。這是警告不是錯誤 —— 字庫照樣收下、
config照樣成功。 若這組術語對你很重要,建議用fuzzy_correction明確列出該錯字對應到哪一個術語。
languages是共用同一份術語索引的所有語言。中文各地區代碼(zh-TW/zh-CN/zh-HK等) 在字庫比對上視為同一群,所以它們共用一筆衝突,而不是各報一次。"homophone_conflicts": [ { "languages": ["zh-TW"], "terms": ["公事包", "公式包"] } ]
tts_ready
說明
TTS 語音合成完成事件。包含音訊資料和 Word Boundary 資訊(可用於卡拉 OK 效果)。
{
"type": "voice-translation",
"data": {
"action": "tts_ready",
"sid": 1,
"language": "en-US",
"transcript": "你好,很高興認識你",
"text": "Hello, nice to meet you",
"audio": "Base64EncodedMP3...",
"format": "mp3",
"duration_ms": 2500,
"boundaries": [
{"offset_ms": 0, "duration_ms": 350, "text_offset": 0, "word_length": 5, "text": "Hello", "boundary_type": "WordBoundary"},
{"offset_ms": 350, "duration_ms": 100, "text_offset": 5, "word_length": 1, "text": ",", "boundary_type": "PunctuationBoundary"},
{"offset_ms": 500, "duration_ms": 250, "text_offset": 7, "word_length": 4, "text": "nice", "boundary_type": "WordBoundary"},
{"offset_ms": 750, "duration_ms": 200, "text_offset": 12, "word_length": 2, "text": "to", "boundary_type": "WordBoundary"},
{"offset_ms": 950, "duration_ms": 350, "text_offset": 15, "word_length": 4, "text": "meet", "boundary_type": "WordBoundary"},
{"offset_ms": 1300, "duration_ms": 300, "text_offset": 20, "word_length": 3, "text": "you", "boundary_type": "WordBoundary"}
]
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
sid | int | 句子編號 |
language | string | TTS 語言 |
transcript | string | 原始逐字稿(STT 識別結果) |
text | string | 翻譯文字(TTS 合成來源) |
audio | string | Base64 編碼的 MP3 音訊 |
format | string | 音訊格式(固定為 mp3) |
duration_ms | int | 音訊總時長(毫秒) |
boundaries | array | Word Boundary 陣列 |
Word Boundary 欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
offset_ms | int | 該字詞在音訊中的起始時間(毫秒) |
duration_ms | int | 該字詞持續時間(毫秒) |
text_offset | int | 在原文字串中的位置(字元索引) |
word_length | int | 字詞長度(字元數) |
text | string | 字詞內容 |
boundary_type | string | 邊界類型,常見值:WordBoundary、PunctuationBoundary、SentenceBoundary 等 |
tts_error
說明
TTS 合成失敗事件。
{
"type": "voice-translation",
"data": {
"action": "tts_error",
"sid": 1,
"language": "en-US",
"error": "translation_not_found",
"message": "No translation available for language: en-US"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
sid | int | 句子編號 |
language | string | TTS 語言 |
error | string | 錯誤碼 |
message | string | 錯誤訊息 |
transcript | string | 對應原始逐字稿,便於前端定位失敗位置。此欄位一律存在,找不到句子時為空字串 "" |
TTS 錯誤碼
| 錯誤碼 | 說明 |
|---|---|
sentence_not_found | 找不到指定的句子(tts_play 帶的 sid 不存在) |
translation_not_found | 找不到該語言的翻譯 |
tts_invalid_language | 不支援的 TTS 語言 |
tts_invalid_voice | 語音名稱無效 |
tts_connection_failed | 語音合成服務連線失敗 |
tts_timeout | 語音合成逾時 |
tts_synthesis_failed | 語音合成失敗 |
viewer_count
廣播模式專用
說明
廣播進行中,觀眾人數有變動時會推送此事件給主講者;更新頻率最快約每 3 秒一次。
{
"type": "voice-translation",
"data": {
"action": "viewer_count",
"viewer_count": 45,
"queue_count": 8,
"peak_viewers": 50,
"total_viewers": 123
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
viewer_count | int | 目前在線觀眾數 |
queue_count | int | 排隊等待中的觀眾數 |
peak_viewers | int | 本次廣播峰值觀眾數 |
total_viewers | int | 累計曾連線的觀眾總數 |
注意:此事件僅在觀眾人數或排隊人數有變動時才會推送,避免不必要的訊息傳輸。
broadcast_phase_changed
說明
當廣播階段從預備(standby)切換到正式(live)時觸發。
{
"type": "voice-translation",
"data": {
"action": "broadcast_phase_changed",
"phase": "live",
"message": "廣播已開始"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
phase | string | 新的階段:standby 或 live |
message | string | 狀態描述訊息 |
broadcast_recording_ready
說明
廣播正式開播(live)後觸發,帶回本場廣播定案後的 task_id。
- start 時直接指定正式開播(
broadcast_phase: "live",預設)時,本事件一定在session_started之後送達。 - 主講者斷線後,在寬限期內用同一個
broadcast_token重新start(接管),新連線收到的本事件會帶新的task_id。同一場廣播因此會有接管前、接管後兩筆錄音,各自完成、各自送出完成通知。
session_started帶的task_id是連線階段的初始值,不是本場廣播的最終 ID。不論是經預備階段(standby)轉正式開播、或 start 時直接指定正式開播(broadcast_phase: "live",預設),都會在開播後收到本事件。後續操作(例如換取浮動字幕 Feed Token)須以本事件的task_id為準——使用初始值會查無資料。
{
"type": "voice-translation",
"data": {
"action": "broadcast_recording_ready",
"task_id": "3f9a1c2e-..."
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
task_id | string | 本場廣播定案後的錄音 ID(正式開播後有效) |
speaker_renamed
說明
全域重命名說話者完成事件。
{
"type": "voice-translation",
"data": {
"action": "speaker_renamed",
"speaker_id": "Guest-1",
"new_label": "王經理",
"affected_sids": [1, 3, 5, 8]
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
speaker_id | string | 解析後的原始語者 ID(即使輸入是顯示標籤,事件回傳仍是原始 ID) |
new_label | string | 新顯示標籤 |
affected_sids | int[] | 受影響的句子編號列表 |
speaker_reassigned
說明
修改單句語者身份完成事件。
{
"type": "voice-translation",
"data": {
"action": "speaker_reassigned",
"sid": 5,
"old_speaker_id": "Guest-1",
"new_speaker_id": "Guest-2",
"new_speaker_label": "李小華"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
sid | int | 修改的句子編號 |
old_speaker_id | string | 原始語者 ID |
new_speaker_id | string | 新的原始語者 ID |
new_speaker_label | string | 新語者顯示標籤(套用 speaker_aliases 後;無 alias 時等於 new_speaker_id) |
speakers_merged
說明
語者合併完成事件。合併後,該 source 語者未來產生的辨識結果也會自動轉換為 target 語者(僅限當前辨識工作:連線中斷後恢復會重新編號,屆時需重新合併)。
{
"type": "voice-translation",
"data": {
"action": "speakers_merged",
"source_speaker_id": "Guest-2",
"target_speaker_id": "Guest-1",
"affected_sids": [3, 5, 7]
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
source_speaker_id | string | 被合併的原始語者 ID |
target_speaker_id | string | 合併目標的原始語者 ID |
affected_sids | number[] | 受影響的句子 ID 列表:原屬來源語者的句子,加上顯示名稱因合併而改變的目標語者原有句子(例如來源語者的自訂名稱轉給目標語者時) |
若需取得 target 語者顯示標籤,請查詢
speaker_aliases或下次init_metadata事件。
language_switch_start
說明
語言切換開始事件,在 switch_language action 觸發後送出。
{
"type": "voice-translation",
"data": {
"action": "language_switch_start",
"translation_language": "ja-JP",
"translation_languages": ["en-US", "ja-JP"],
"total_segments": 15
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
translation_language | string | 本次操作的單一語言(置換的新目標,或 op:add 新增的語言) |
translation_languages | string[] | 當前完整翻譯語言集的權威快照。多語場次 op:add 時為「含既有語言的完整集」,消費端應直接以此覆寫本地語言集,不要從 translation_language 推測是「附加」或「置換」(1→2 附加時只看單一語言會誤判為置換而洗掉既有語言)。 |
total_segments | int | 需要重新翻譯的句子數 |
batch_retranslation
說明
批次重翻結果事件,在語言切換過程中逐句送出。
{
"type": "voice-translation",
"data": {
"action": "batch_retranslation",
"sid": 3,
"translations": {
"ja-JP": {
"sid": 3,
"text": "今日はプロジェクトの進捗について話し合いましょう",
"is_final": true,
"is_retranslation": true
}
}
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
sid | int | 句子編號 |
translations | object | 翻譯結果(格式同 result 的 translations) |
language_switch_done
說明
語言切換完成事件。
{
"type": "voice-translation",
"data": {
"action": "language_switch_done",
"translation_language": "ja-JP",
"translation_languages": ["en-US", "ja-JP"],
"success_count": 15,
"failed_count": 2,
"failed_sids": [3, 7]
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
translation_language | string | 本次操作的單一語言 |
translation_languages | string[] | 當前完整翻譯語言集的權威快照(同 language_switch_start,消費端直接覆寫本地語言集) |
success_count | int | 成功翻譯的句子數 |
failed_count | int | 翻譯失敗的句子數 |
failed_sids | int[] | 翻譯失敗的句子編號列表(failed_count > 0 時才包含) |
translation_language_removed
說明
翻譯語言移除成功事件(v1.6.7 新增)。多語言場次送出 switch_language(op: "remove")成功時回傳。該語言既有的歷史譯文保留,後續新句子不再翻譯該語言。
{
"type": "voice-translation",
"data": {
"action": "translation_language_removed",
"translation_language": "ko-KR",
"translation_languages": ["en-US", "ja-JP"]
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
translation_language | string | 已移除的翻譯語言 |
translation_languages | string[] | 移除後的完整翻譯語言集權威快照,消費端直接以此覆寫本地語言集 |
tts_mode_changed
說明
TTS 播放模式變更事件。
{
"type": "voice-translation",
"data": {
"action": "tts_mode_changed",
"tts_mode": "async"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
tts_mode | string | 新的模式:sync 或 async |
language_switched
說明
互譯模式(conversation)語言切換完成事件。當 switch_language 在互譯模式下成功切換 STT 來源語言後觸發。
{
"type": "voice-translation",
"data": {
"action": "language_switched",
"language": "en-US",
"translation_language": "zh-TW",
"message": "語言已切換"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
language | string | 新的 active 語言(STT 來源) |
translation_language | string | 新的翻譯目標語言 |
message | string | 狀態訊息 |
tts_updated
說明
互譯模式(conversation)TTS 設定更新事件。當 set_tts 成功更新 TTS 開關或語音設定後觸發。
{
"type": "voice-translation",
"data": {
"action": "tts_updated",
"tts_enabled": true,
"tts_config": {
"zh-TW": { "voice": "zh-TW-HsiaoChenNeural", "speaking_rate": 1.0 },
"en-US": { "voice": "en-US-GuyNeural", "speaking_rate": 1.2 }
}
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
tts_enabled | boolean | TTS 是否啟用 |
tts_config | object | 各語言的 TTS 設定(voice、speaking_rate) |
conversation_mode_changed
說明
互譯模式(conversation)對話模式變更事件。當 switch_conversation_mode 成功切換自動/手動模式後觸發。
{
"type": "voice-translation",
"data": {
"action": "conversation_mode_changed",
"conversation_mode": "manual"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
conversation_mode | string | 新的對話模式:auto 或 manual |
speaker_language_changed
說明
互譯模式(conversation)用戶語言變更事件。當 set_speaker_language 成功變更用戶語言後觸發,包含變更後的完整語言映射。
{
"type": "voice-translation",
"data": {
"action": "speaker_language_changed",
"speaker_language_map": {
"1": "ja-JP",
"2": "en-US"
}
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
speaker_language_map | object | 變更後的用戶語言映射(key 為用戶編號字串) |
speaking_speed_changed
說明
錄音中語速變更事件。當 set_speaking_speed 成功套用新語速(重建 STT 完成)後觸發,帶回已套用的語速等級。非多人(multi_speaker)辨識模式皆支援(含廣播、多語 LID)。
{
"type": "voice-translation",
"data": {
"action": "speaking_speed_changed",
"speaking_speed": "slow"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
speaking_speed | string | 已套用的語速:very_slow / slow / normal / fast / very_fast |
summary_updated
說明
錄音中摘要設定更新事件。當 set_summary 成功套用後觸發,帶回當前生效的摘要設定。
基於安全考量,事件不包含 summary_prompt 全文;custom 模式請以 summary_prompt_slug 辨識。
{
"type": "voice-translation",
"data": {
"action": "summary_updated",
"summary_mode": "custom",
"summary_prompt_slug": "meeting-actions-v2",
"summary_language": "zh-TW",
"auto_summary": true,
"summary_plain_text": false,
"message": "摘要設定已更新"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
summary_mode | string | 當前摘要模式:builtin / custom |
summary_template | string | 當前通用樣板識別碼(builtin 模式才有值) |
summary_prompt_slug | string | 當前自訂 prompt 識別碼(custom 模式才有值) |
summary_language | string | 當前摘要輸出語言 |
auto_summary | boolean | 停止時是否自動生成摘要 |
summary_plain_text | boolean | 是否以純文字輸出 |
message | string | 狀態訊息 |
segment_uploaded
說明
音訊分段上傳完成事件。每當一個音訊片段成功上傳至雲端儲存時觸發,可用於前端顯示上傳進度。
{
"type": "voice-translation",
"data": {
"action": "segment_uploaded",
"segment_index": 0,
"duration_sec": 30.5
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
segment_index | number | 分段索引(從 0 開始) |
duration_sec | number | 該分段的時長(秒) |
stt_event
說明
STT 連線狀態事件。當語音辨識服務的連線狀態發生變化時觸發,可用於前端顯示 STT 服務狀態。
{
"type": "voice-translation",
"data": {
"action": "stt_event",
"event": "reconnected",
"message": "STT 已重連"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
event | string | 事件類型:session_started(辨識會話建立)/session_stopped(辨識會話結束)/canceled(辨識被中止,原因見 message)/reconnecting(連線異常,自動重連中)/reconnected(已重新連線) |
message | string | 事件描述訊息。內容不保證固定,請一律以 event 判斷狀態 |
channel_status
多聲道模式(multi_channel)專用
說明
聲道狀態變更事件。多聲道場次中,任何一路聲道的狀態改變時觸發:add_channel / remove_channel 的成功回應、set_channel_language / set_speaking_speed 觸發的設定切換、暫停後恢復(resume)、異常自動重連,以及該路異常且無法自動恢復時。前端可據此逐路顯示即時狀態(例如新路準備中的載入指示、異常路的警示)。
{
"type": "voice-translation",
"data": {
"action": "channel_status",
"channel": {
"channel_id": 3,
"speaker_name": "王經理",
"transcription_languages": ["ja-JP"],
"status": "preparing"
},
"active_channels": 3,
"stt_stream_count": 3,
"reason": "added"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
channel | object | 狀態變更的聲道快照,欄位同 session_started 的 channels[] 元素(channel_id、speaker_name、transcription_languages、status) |
channel.status | string | 該路目前狀態:preparing / ready / removed / error(見下方狀態機) |
active_channels | int | 目前仍在收音的聲道數(不含已移除的路) |
stt_stream_count | int | 當下採計的辨識路數(每一分鐘開始時依此計費;remove_channel 後立即下降);shared 模式固定為 1 |
reason | string | 可選。狀態變更原因:added / language_change / reconnect / resumed / removed / speaking_speed / stt_error(見下表)。省略時代表該路首次就緒(見狀態機說明) |
reason 值域
| reason | 觸發時機 |
|---|---|
added | add_channel 新增一路(狀態轉 preparing) |
language_change | set_channel_language 切換語言 |
reconnect | 該路異常後自動重連;斷線續接(resume_token)後的恢復亦用此原因 |
resumed | 暫停後恢復(resume),各路重新準備 |
removed | remove_channel 停用一路(狀態轉 removed) |
speaking_speed | set_speaking_speed 逐路套用新設定 |
stt_error | 該路異常且無法自動恢復(狀態轉 error) |
status 狀態機
preparing:每一次該路開始或重新準備辨識都會回到此狀態——start的初始建立、add_channel的加入、set_channel_language/set_speaking_speed的設定切換、自動重連與暫停後恢復。此期間該路約需 4 秒完成準備,講的話不會丟失、只是延遲出字;唯獨切換或重連當下正說到一半的那一句無法保留,會另外收到 segment_discarded。ready:該路收到第一個辨識結果(開始出字)時轉入。由設定切換觸發的ready事件沿用觸發該次preparing的同一reason,讓前端把「這一次就緒」對回「哪一次操作」;start與add_channel後的首次就緒不帶reason。removed:該路被remove_channel停用。已產生的逐字稿與音檔保留;該編號不可再重用(含add_channel)。error:該路異常且無法自動恢復(reason: "stt_error")。該路後續若自動恢復,會再依preparing(reason: "reconnect")→ready回報,或於恢復出字時直接轉ready。
shared 模式:只有第一路(
channels[]的第一個元素)實際進行辨識,其他聲道的preparing/ready/error跟著第一路——第一路轉ready時全部一起轉ready,第一路重新準備辨識時全部一起回到preparing;每一路各收到一則事件,reason與第一路相同。add_channel新增的聲道直接套用第一路當下的狀態;removed依各路自己。第一路變成error時,其他聲道也一起變成error(reason相同);第一路恢復時一起恢復。
這四個狀態值與 session_started 的
channels[].status、resume_ok 的settings.channels[].status快照一致——斷線續接後請以快照還原各路的狀態顯示(error也會出現在快照中,不會被漂白)。
時序範例(add_channel)
→ 送出 add_channel(channel_id: 3、語言 ja-JP)
← channel_status channel.status: "preparing"、reason: "added"、
active_channels: 3、stt_stream_count: 3
(約 4 秒準備期;期間第 3 路的音訊照常送、不會丟失,僅延遲出字)
← channel_status channel.status: "ready"(不帶 reason)
(該路首次出字;此後該路的 result 事件 origin 帶
channel_id: 3、speaker_id: "channel_3")
時序範例(set_channel_language)
→ 送出 set_channel_language(channel_id: 2、換為 en-US)
← channel_status channel.status: "preparing"、reason: "language_change"
(切換約 4 秒後生效;channel_id 與 speaker_id 不變、逐字稿連續)
← channel_status channel.status: "ready"、reason: "language_change"
segment_discarded
說明
句子作廢通知。告知某個 sid 已作廢,不會再有任何後續事件 —— 不會有該句 is_final: true 的原文,也不會有該句的翻譯。
有些操作會讓辨識中斷,若當下正好有一句話說到一半,那一句無法保留。前端可能已經收到過該句 is_final: false 的中間結果,收到本事件後請把該 sid 從「翻譯中」狀態移除。
互譯模式(自動與手動)不會收到本事件 —— 自動模式下,說到一半的句子會直接以 is_final: true 收尾送出;手動模式下,說話期間辨識若中途重建(例如改語速、連線恢復),那一段會併入該句的定稿。內容都保留在逐字稿中。
{
"type": "voice-translation",
"data": {
"action": "segment_discarded",
"sid": 7,
"reason": "speaking_speed",
"channel_id": 1
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
sid | int | 被作廢的句子編號 |
reason | string | 作廢原因:speaking_speed / language_change / reconnect / resumed / broadcast_go_live(見下表) |
channel_id | int | 可選。來源聲道編號;僅多聲道模式帶,其餘模式不帶 |
reason 值域
| reason | 觸發時機 |
|---|---|
speaking_speed | set_speaking_speed 套用新語速 |
language_change | set_channel_language 切換該路語言 |
reconnect | 辨識連線異常後自動重連 |
resumed | 斷線續接(resume_token),或暫停後恢復(resume) |
broadcast_go_live | broadcast_go_live 由預備進入直播;預備階段的句子不進正式逐字稿 |
前四個值與 channel_status 的 reason 是同一組值,可據以把兩個事件對應到同一次操作。例外是斷線續接(resume_token):channel_status 用 reconnect,本事件用 resumed。
set_speaking_speed失敗(set_speaking_speed_failed)時仍可能已經收到本事件 —— 辨識在重建之前就已中斷,該句無論重建成敗都保不住。收到失敗回應不代表「什麼都沒發生」。
viewer_joined
說明
觀眾加入事件(僅廣播模式)。當觀眾加入廣播時,主講者會收到此事件。
{
"type": "voice-translation",
"data": {
"action": "viewer_joined",
"viewer": {
"id": "viewer_abc123",
"ip": "192.168.1.100",
"language": "zh-TW"
},
"viewer_count": 5,
"queue_count": 2
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
viewer | object | 加入的觀眾資訊 |
viewer.id | string | 觀眾 ID |
viewer.ip | string | 觀眾 IP 地址 |
viewer.language | string | 觀眾選擇的語言 |
viewer_count | number | 目前觀眾人數 |
queue_count | number | 排隊中的人數 |
viewer_left
說明
觀眾離開事件(僅廣播模式)。當觀眾離開廣播時,主講者會收到此事件。
{
"type": "voice-translation",
"data": {
"action": "viewer_left",
"viewer_id": "viewer_abc123",
"viewer_count": 4,
"queue_count": 1
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
viewer_id | string | 離開的觀眾 ID |
viewer_count | number | 目前觀眾人數 |
queue_count | number | 排隊中的人數 |
error
說明
錯誤事件。當操作失敗或系統異常時觸發。
{
"type": "error",
"data": {
"error_code": "session_not_started",
"severity": "error",
"message": "語音辨識尚未開始",
"context": "voice-translation",
"request_id": "req_abc123xyz789",
"timestamp": "2026-01-15T10:30:45.123Z"
}
}
句子級錯誤(如某句的某個語言翻譯失敗)會額外帶上 sid 與 details:
{
"type": "error",
"data": {
"error_code": "llm_content_filtered",
"severity": "warning",
"message": "LLM 內容被過濾",
"context": "translation",
"sid": 5,
"request_id": "req_abc123xyz789",
"timestamp": "2026-04-26T10:30:45.123Z",
"details": {
"provider": "llm_service",
"source_lang": "zh-TW",
"translation_language": "ja-JP"
}
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
error_code | string | 錯誤碼(程式化處理用) |
severity | string | 嚴重程度:fatal / error / warning |
message | string | 人類可讀的錯誤訊息 |
context | string | 錯誤來源分類 |
sid | int | 可選。句子級錯誤的句子編號(如該句翻譯失敗);非句子級錯誤不帶 |
request_id | string | 請求追蹤 ID |
timestamp | string | 錯誤發生時間(ISO 8601) |
details | object | 可選。錯誤上下文,常見 key:provider、translation_language、source_lang;internal_error(單則訊息處理失敗)會額外帶 message_type(必有)與 action(best-effort,解析失敗時不出現),詳見 websocket-api.md 單一訊息錯誤 |
嚴重程度說明
| severity | 說明 | 處理建議 |
|---|---|---|
fatal | 致命錯誤 | 停止服務,要求重新連線 |
error | 操作失敗 | 顯示錯誤提示,允許重試 |
warning | 警告 | 顯示警告,不阻斷操作 |
warning等級的預警不代表錄音結束,例如stt_silence_warning(即將因為沒有語音而自動結束)、broadcast_standby_warning(預備階段即將達到時間上限)。錄音照常進行,真正結束時會另外收到對應的fatal錯誤與status: "ended"。
完整錯誤碼列表請參考 錯誤碼參考。
upload_error
v1.5.6 文件修正:早期文件描述
type: "voice-translation"+action: "upload_error"的獨立事件格式,但實際 wire 上從未送出此格式。儲存上傳失敗一律走統一errorenvelope,錯誤碼為下表三者之一。若你的 client 監聽
action === "upload_error",應改為監聽type === "error"並比對error_code。
儲存層錯誤碼(透過 error 事件送出)
| 錯誤碼 | 說明 |
|---|---|
storage_connection_failed | 儲存服務連線失敗 |
storage_upload_failed | 檔案上傳失敗 |
storage_queue_full | 上傳佇列已滿 |
speakers_auto_merged
多人模式下,系統判定兩個說話者其實是同一人並自動合併時送出。
{
"type": "voice-translation",
"data": {
"action": "speakers_auto_merged",
"source_speaker_id": "Guest-2",
"target_speaker_id": "Guest-1"
}
}
| 欄位 | 類型 | 說明 |
|---|---|---|
source_speaker_id | string | 被合併掉的說話者 |
target_speaker_id | string | 合併後保留的說話者 |
自動合併通常發生在尚未產生任何逐字稿條目時,因此不帶受影響的句子清單。客戶端收到後把本地的說話者清單中 source_speaker_id 併入 target_speaker_id 即可。
summary_done
說明
錄音停止後、Server 端非串流摘要生成完成時推送的事件。客戶端收到此事件後可呼叫 GET /api/v1/sse/history/transcribe/{taskId} 取得摘要內容(payload 不含 final_content,避免 WebSocket 訊息肥大)。
v1.5.5 新增 summary_fallback_level / summary_dropped_segments 兩個 fallback 審計欄位:當 custom prompt 或逐字稿內容觸發 LLM 服務內容過濾時,系統會自動降級重新產生摘要(標準模式 → 中性模式 → 段落省略模式),並透過這兩欄通知客戶端實際走的路徑。
範例
標準模式直接成功(無 fallback、未觸發過濾):
{
"type": "voice-translation",
"data": {
"action": "summary_done",
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"summary_id": "sum_a1b2c3d4e5f6g7h8",
"summary_mode": "custom",
"summary_template": "skin-clinic-acme-v2",
"summary_plain_text": true,
"tokens_used": { "input": 1234, "output": 567 }
}
}
段落省略模式觸發(省略部分逐字稿段落後產出摘要):
{
"type": "voice-translation",
"data": {
"action": "summary_done",
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"summary_id": "sum_a1b2c3d4e5f6g7h8",
"summary_mode": "custom",
"summary_template": "skin-clinic-acme-v2",
"summary_plain_text": true,
"tokens_used": { "input": 3456, "output": 789 },
"summary_fallback_level": 3,
"summary_dropped_segments": [3, 7]
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
action | string | 固定為 summary_done |
task_id | string | Recording UUID |
summary_id | string | 此次摘要的內部 ID |
summary_mode | string | "builtin" 或 "custom" |
summary_template | string | effective slug — builtin → 內建模板 slug(如 meeting);custom → 客戶 slug |
summary_plain_text | boolean | 是否為純文字輸出 |
tokens_used.input / .output | int | Token 用量(觸發 fallback 時為本次摘要所有生成請求的累計值) |
summary_fallback_level | int (omit) | 僅 fallback 觸發時出現(2 或 3),標準模式直接成功則 omit。2=中性模式(改用中性指令重新生成);3=段落省略模式(省略觸發段落後重新生成) |
summary_dropped_segments | int[] (omit) | 僅 fallback_level=3 時出現,被剝除的逐字稿段 indices(原序) |
Fallback level 解讀(供前端 UI 對應提示)
summary_fallback_level | 意義 | 建議 UI 提示 |
|---|---|---|
| (欄位 omit) | 標準模式直接成功,無 fallback | 不顯示提示 |
2 | Customer prompt 觸發過濾,改用中性 fallback prompt | 「您的自訂指令含內容過濾機制無法處理的詞彙,已使用中性模式產生摘要」 |
3 | 逐字稿內容觸發過濾,自動定位並省略觸發段落後產出 | 「逐字稿含 N 段無法處理,已省略相關內容後產生摘要」(N = summary_dropped_segments.length) |
段落省略模式仍失敗時不會發送
summary_done,而是summary_errorwitherror_code=llm_content_filtered(見下方 §summary_error)。注意:payload 刻意不含
final_content。客戶端需自行呼叫GET /api/v1/sse/history/transcribe/{taskId}取得摘要全文。summary_fallback_level與summary_dropped_segments也會在歷史回放時透過init_summaryevent 的 top-level 欄位提供。
summary_error
說明
摘要生成失敗,或因可用點數不足而未產生摘要時推送的事件,客戶端不需要再輪詢判斷。
範例
{
"type": "voice-translation",
"data": {
"action": "summary_error",
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"error_code": "summary_failed",
"message": "摘要生成失敗"
}
}
欄位說明
| 欄位 | 類型 | 說明 |
|---|---|---|
action | string | 固定為 summary_error |
task_id | string | Recording UUID |
error_code | string | 摘要錯誤碼(如 summary_failed / summary_timeout / summary_mode_field_mismatch / summary_insufficient_credit 等) |
message | string | 人類可讀錯誤訊息(已 sanitize,不含 LLM raw error) |
error_code為summary_insufficient_credit時,表示可用點數不足(錄音因點數不足而結束,或結束時點數不足以支付摘要費用);逐字稿與錄音照常保存,儲值後可透過重新生成摘要取得。
版本:V1.24.1 最後更新:2026-10-07