Changelog
V1.5.7(2026-05-20)
文件更新(無 API 行為變更)
對外 API 行為完全不變,本版為文件補充與用詞調整版。
新增使用指南:摘要 Prompt 客製化
新增 摘要 Prompt 客製化指南,把原先散落在 6 份 reference 文件中的摘要客製化規格集中為單一 guide:
builtin/custom兩種摘要模式的互斥規則與適用場景- REST
POST /api/v1/summary、WebSocketstartaction、SSEregenerate/summary三條入口的對應欄位 - 逐字稿記錄欄位(含
summary_prompt_snapshot審計欄位、summary_fallback_level/summary_dropped_segments兩個 fallback 審計欄位) - 敏感詞與不雅字眼處理章節,整合三條路徑(客戶 prompt → 中性模式、逐字稿 → STT
profanity_handling遮罩、逐字稿 → 摘要層段落省略)並明示「API 層不會主動拒絕含敏感詞的請求」 - 內建安全防護機制(內容中性化指引、prompt injection 防護)與字元長度限制
- Node.js / Python / WebSocket 三組完整範例
README.md 的「功能指南」表格新增此 guide 入口。
文件用詞調整
對外文件移除部分曝露後端結構的內部用詞,以更通用的描述取代:
- 內部架構名稱(如「IPEVO 三層」、
System Prompt + Template Prompt + Output Format)→ 改為「內建模板規則」、「模板完整內容」 - LLM 供應商品牌名(
AOAI/Azure OpenAI)→ 改為「LLM 服務」 - 後端機制名(
sandwich pattern、binary search 定位觸發段)→ 改為「內建安全防護機制」、「自動定位並省略觸發段落」 - Fallback chain 階層命名(
L1/L2/L3)→ 對應改為「標準模式」/「中性模式」/「段落省略模式」(summary_fallback_level欄位值維持2/3不變,僅文字描述調整)
本次調整僅限新指南 guides/summary-customization.md。其餘 reference 文件、changelog 歷史條目維持原貌,後續會在獨立版本中陸續對齊。
Changelog 內部編號清理
- 移除 V1.5.4 章節標題的內部 task 編號(
(Task 15)) - 移除 V1.5.4 內文的內部規範引用(
(安全紀律 §J3 #3))
參考文件
V1.5.6(2026-05-19)
文件對齊修正版(無 API 行為變更)
本版為文件校對版,對外 API 行為完全不變。下列項目若你曾依舊文件實作,請依當前規格調整。
Token 格式
broadcast_token:4 字元短碼(字符集 a-z0-9)viewer_access_token:64 字元 alphanumeric 字串(非 JWT,無 payload 結構,請勿嘗試解析)
HTTP 狀態碼
sse_missing_target_lang/sse_unsupported_language:422broadcast_token_invalid(viewer verify 端點):401
錯誤碼字串
POST /api/v1/imports配額不足:stt_quota_exceeded- 廣播觀眾 SSE 找不到廣播:
broadcast_session_not_found - 廣播觀眾 SSE 容量已滿:
broadcast_capacity_exceeded sse_translation_failederror 事件的context為sse
WebSocket 事件命名
retranslate成功事件:action: "translation"- 儲存層上傳失敗:以
type: "error"envelope 送出(error_code為storage_upload_failed/storage_connection_failed/storage_queue_full),無獨立upload_erroraction
新列入文件的錯誤碼
| 端點 / Action | 錯誤碼 | 說明 |
|---|---|---|
WebSocket set_name | set_name_empty / set_name_too_long / set_name_not_ready | 取代舊文件的 name_too_long |
WebSocket audio | audio_process_failed | STT 寫入持續失敗(HTTP 500,建議重新連線) |
參考文件
- reference/rest/viewer.md
- reference/websocket/events.md
- reference/websocket/voice-translation.md
- reference/sse/retranslate.md
V1.5.5(2026-05-13)
Breaking Change:摘要 API 改為 mode-aware
V1.5.4 推出的「template + custom_prompt 共用」設計改為互斥:客戶必須在每次摘要請求中選擇 mode=builtin(套用 IPEVO 內建模板)或 mode=custom(客戶 prompt 完整取代三層)。
客戶端必須遷移:v1.5.4 客戶端不修改欄位將收到 422。
REST POST /api/v1/summary、SSE regenerate/summary、WebSocket start 三條入口統一新欄位
舊(v1.5.4)→ 新(v1.5.5)對照:
| 舊欄位 | 新欄位 | 備註 |
|---|---|---|
template / templateSlug / summary_template | 同名(僅 builtin mode) | 不變、但 custom mode 下禁帶 |
custom_prompt / customPrompt / summary_custom_prompt | prompt / summary_prompt(僅 custom mode) | 改名 |
custom_prompt_slug / customPromptSlug / summary_custom_prompt_slug | prompt_slug / summary_prompt_slug(僅 custom mode) | 改名 |
persist_custom_prompt / persistCustomPrompt | (移除) | custom mode 強制 snapshot、無 opt-in |
custom_instructions | (移除) | legacy 欄位、不再支援 |
| (無) | mode / summary_mode(required) | 新增必填、enum builtin / custom |
互斥規則:
mode=builtin:template必填、prompt/prompt_slug禁帶mode=custom:prompt/prompt_slug必填、template禁帶- 違反 → 422
summary_mode_field_mismatch
GET /api/v1/tasks/ 回應欄位
data.tasks[] 中:
- 新增
summary_mode(builtin/custom/null) summary_template改為 effective slug(custom mode 下回傳客戶 slug,等同送出時的prompt_slug)- 移除
summary_custom_prompt_slug(合併至summary_template)
舊資料相容:未生成摘要的錄音 summary_mode 為 null;既有 builtin 模式錄音的 summary_template 保留原值。
逐字稿記錄結構異動
新增 top-level 欄位(不是 nested 在 summary 物件下):
| 欄位 | 說明 |
|---|---|
summary_mode | builtin / custom |
summary_template | effective slug — builtin → 內建 slug;custom → 客戶 slug |
summary_plain_text | bool |
summary_prompt_snapshot | 僅 custom mode 出現,為客戶原樣傳入的 prompt 內容(builtin mode 不寫入) |
summary_fallback_level | 僅 fallback 觸發時出現(值為 2 或 3),代表本次摘要實際走的 AOAI 內容過濾 fallback 路徑。L1 直接成功則 omit |
summary_dropped_segments | 僅 fallback_level=3 時出現,為被剝除的逐字稿段 indices(原序整數陣列) |
GET /api/v1/sse/history/transcribe/{taskId} 的 init_summary 事件除既有 text 外,新增 mode / template / plain_text / prompt_snapshot(custom mode 才有值)讓客戶端追溯,以及 fallback_level / dropped_segments(fallback 觸發時才有值)。
WebSocket 新增 outbound event
summary_done:摘要生成完成(含summary_mode/summary_template(effective) /summary_plain_text/tokens_used/summary_fallback_level/summary_dropped_segments,不含final_content)summary_error:摘要生成失敗(含error_code/message)
客戶端不再需要輪詢逐字稿記錄判斷摘要是否完成。
AOAI 內容過濾自動降級(fallback chain)
Custom mode 的客戶 prompt 或逐字稿內容若觸發 Azure OpenAI 的內容過濾(finish_reason=content_filter),系統會自動依下列順序降級而非直接回失敗:
| 階段 | 動作 | UI 提示建議 |
|---|---|---|
| L1(預設) | 用 sandwich pattern 保護的 customer prompt 直接呼叫 | 不顯示提示 |
| L2 | 剝掉 customer prompt、改用中性 fallback prompt 重打 | 「您的自訂指令含 Azure 內容過濾無法處理的詞彙,已使用中性模式產生摘要」 |
| L3 | 逐字稿按段切片、binary search 定位觸發段、剝除後重打 | 「逐字稿含 N 段無法處理,已省略相關內容後產生摘要」(N = summary_dropped_segments 長度) |
| 終點 | L3 也失敗 → emit summary_error with error_code=llm_content_filtered | 「本段內容無法產生摘要(內容過濾規則限制)」 |
L3 binary search 預算上限為 5 次 AOAI 呼叫(hard cap,避免 token 失控)。最壞情況單次摘要會耗用 L1 + L2 + L3 共 7 次 AOAI 呼叫的 token,所有呼叫都會進 usage_logs 計費。
客戶端對應實作:依 summary_fallback_level 顯示 UI 提示(見上表),summary_dropped_segments 可用於告知用戶實際省略了哪些區段。
規格範圍:本版 fallback chain 對 WebSocket realtime 摘要(錄音結束自動生成)與 檔案匯入摘要 兩條路徑生效。SSE
regenerate/summary端點的 fallback 整合屬 follow-up,當前版本被擋下時仍回llm_content_filtered。
Custom mode prompt 安全規則(v1.5.5 新增規則 4)
Custom mode 的 system prompt 安全 wrapper(sandwich pattern)的 header 與 footer 各新增一條規則,要求 LLM「對於原文中可能出現的口語化、情緒性或敏感詞彙,請以中性、客觀的語言概括其意旨,避免逐字引用或重複」。此規則由後端強制注入,不曝露給客戶端設定,目的是降低 L1 階段觸發內容過濾的機率。
wrapper 內容永遠不會寫入後端儲存或 log(已有跨語言 sha256 雜湊回歸測試保證)。客戶 prompt 原文仍透過 summary_prompt_snapshot 欄位儲存作為審計依據,與 summary_fallback_level 互補:
summary_prompt_snapshot= 客戶意圖(原 prompt 內容)summary_fallback_level= 實際執行路徑(L1 直接 / L2 中性 / L3 丟段)
Custom mode prompt injection 防護
Custom mode 下,後端對客戶提供的 prompt 加上 prompt injection 防護,避免客戶 prompt 中的指令覆蓋系統規則。客戶仍應注意不要把不可信的終端用戶輸入直接拼進 prompt。
新增錯誤碼
| 錯誤碼 | HTTP | 觸發條件 |
|---|---|---|
summary_invalid_mode | 422(SSE)/ 400(其他) | mode 不是 builtin / custom |
summary_mode_field_mismatch | 422 / 400 | mode 與欄位組合不符(必填缺漏 / 禁帶被帶入) |
summary_prompt_too_long | 422 / 400 | prompt 超過 2000 字元 |
summary_prompt_slug_too_long | 422 / 400 | prompt_slug 超過 64 字元 |
summary_prompt_slug_invalid | 422 / 400 | prompt_slug 含控制字元(\n / \r / \t / \0 等) |
客戶端建議
- 新增
mode必填欄位 — 既有呼叫templateSlug=meeting的請求改為mode=builtin&template=meeting - 欄位重新命名 —
customPrompt→prompt、customPromptSlug→promptSlug;且這兩欄只在mode=custom下使用 - 移除
persistCustomPrompt— custom mode 自動保留 prompt 內容 templateSlug改為template— 並且僅限mode=builtin使用- 逐字稿記錄改為 top-level 欄位 — 不再嵌套在
summary物件下 - 客戶端可從 done event / summary_done event 判斷是否已儲存 — 看
persisted: true/false,不需要再依 HTTP method 推斷
參考文件
- reference/rest/summary.md
- reference/sse/regenerate-summary.md
- reference/rest/summary-templates.md
- reference/websocket/voice-translation.md
- reference/websocket/events.md
V1.5.4(2026-05-12)
新增功能:摘要 Prompt 客戶客製化
企業客戶現在可以在不改動 IPEVO 內建模板的前提下,為摘要 API 加入自家規則。本版新增三個正交的客戶端參數,並把摘要重生成端點拆成「預覽」與「存檔」兩個動詞,避免 HTTP GET 帶副作用的設計斷層。
完全向後相容 — 不傳新欄位 = 行為與舊版一致。
POST /api/v1/summary 新增欄位
| 欄位 | 類型 | 限制 | 說明 |
|---|---|---|---|
custom_prompt | string | ≤2000 字元 | Layer 4 客戶自訂指示(append 在內建三層之後) |
custom_prompt_slug | string | ≤64 字元、Unicode、禁控制字元 | 客戶端自訂模板識別碼(pass-through) |
plain_text | bool | 預設 false | 要求純文字輸出(後端做 Markdown 後處理) |
persist_custom_prompt | bool | 預設 false | opt-in:done event 是否回顯 custom_prompt 內容 |
SSE start / done event 也增補對應欄位(custom_prompt_slug、plain_text、final_content、custom_prompt_snapshot),詳見 reference/rest/summary.md。
/api/v1/sse/regenerate/summary/{taskId} 拆兩個端點
| 方法 | 用途 | 寫 DB | 儲存逐字稿 | 計費 |
|---|---|---|---|---|
| GET | 預覽(試跑、比較不同 prompt 結果) | ❌ | ❌ | ✅ |
| POST | 存檔(正式儲存) | ✅ | ✅ + bump revision | ✅ |
客戶端建議:若你的整合方原本依賴「打 GET 後後端記錄自動更新」,請改打 POST。GET 改為純預覽,不再寫入任何後端狀態。
done event 新增
persisted: bool欄位,客戶端可直接從 payload 判斷此次是否已儲存,不需要再依靠 HTTP method 推斷。
WebSocket start action 新增 4 欄位
summary_custom_prompt / summary_custom_prompt_slug / summary_plain_text / summary_persist_custom_prompt,與 REST 端點欄位一一對應,限制相同。
新增端點:GET /api/v1/summary-templates/{slug}
曝露 IPEVO 內建模板的三層 Prompt 完整原始文字(system_prompt / template_prompt / output_format),供企業客戶整合時參考既有基礎,再決定 custom_prompt 該補什麼。
GET /api/v1/summary-templates 同時新增 ?category=summary|medical|legal|all 篩選與回應 data[].category 欄位(預設 summary,向後相容)。
新增錯誤碼
| 錯誤碼 | HTTP | 觸發條件 |
|---|---|---|
custom_prompt_too_long | 400 | custom_prompt 超過 2000 字元 |
custom_prompt_slug_too_long | 400 | custom_prompt_slug 超過 64 字元 |
custom_prompt_slug_invalid | 400 | custom_prompt_slug 含控制字元 |
template_not_found | 404 | 指定 slug 的模板不存在或已停用 |
invalid_category | 400 | ?category= 不在白名單內 |
行為變更
summary_text_empty/summary_text_too_longHTTP 狀態碼修正:原本因後端錯誤碼未明確映射而 fall through 到 500,本版修為符合語意的 400。POST /api/v1/summary錯誤事件details不再包含 LLM raw error:raw error 僅進 server log,回給客戶端的details只保留provider標示。- GET preview 仍會計費:LLM 真實消耗 token,不能讓 GET 端點白嫖。重複呼叫 GET 會重複計費,但不會改變 DB / Blob 狀態。
路徑與欄位命名規範
customPromptSlug是客戶自訂 pass-through 識別碼(與既有templateSlugexists 校驗的語意不同)。命名上前者為「客戶端追溯用」,後者為「VAS 內建模板查表用」。summary_custom_prompt_slug寫入recordings表的VARCHAR(64)欄位,方便事後查詢「這份摘要對應哪個客戶模板」。custom_prompt_snapshot(opt-in)只在客戶設定persist_custom_prompt=true時才儲存於逐字稿記錄,永遠不進 DB。
安全控管
- 所有端點需 API Key 認證
- VAS server log 不會 log
custom_prompt或逐字稿全文(僅 log 長度與 slug) - LLM 錯誤訊息會被 sanitize(不曝露 raw error 給客戶端)
custom_prompt跨租戶完全隔離(Session-scope,無記憶持久化)
Bug 修正與內部改善
- WebSocket
startaction 的recording_id欄位 deprecation 預告版號統一為 V2.0.0(events.md 原寫 V1.6.0,與程式碼註解不一致) - SSE
sse-api.md修正失效的 TOC anchor(指向 audio 段落但本文已遷移至獨立reference/sse/audio.md) - 改善文字清理:CJK 字元與 Emoji(含 ZWJ 序列)不再被誤切或誤拒
- 摘要重生成的 fullText 加入 100,000 字元上限
參考文件
- reference/rest/summary.md(新增)
- reference/rest/summary-templates.md(補
?category=與GET /{slug}) - reference/sse/regenerate-summary.md(重寫為 GET / POST 二端點規格)
- reference/websocket/voice-translation.md(補
summary_custom_prompt*4 欄位 + 3 錯誤碼)
V1.5.3(2026-05-07)
Breaking Change:speaker_id 命名翻轉
V1.3.12 為了支援語者編輯,新增 original_speaker_id 欄位來保留原始 ID,但留下「同一名稱在不同階段語意不同」的設計斷層:WebSocket 即時錄音的 speaker_id 是原始 ID(如 Guest-1),SSE 歷史音檔載入後 speaker_id 變成顯示名(如 王經理,已套 alias)。前端常因此拿錯欄位丟進 PATCH /speakers/reassign。
本版做一次性翻轉,不向下相容:
| 舊名 | 新名 | 語意 |
|---|---|---|
speaker_id(顯示名) | speaker_label | 顯示標籤(套 alias 後;可變、人類可讀) |
original_speaker_id(原始 ID) | speaker_id | 原始說話者 ID(不可變、永遠穩定) |
翻轉後,speaker_id 在所有上下文(WebSocket / SSE / REST / blob / log)一致指向原始 ID;新增 speaker_label 表示套 alias 後的顯示標籤。語者編輯(rename / reassign / merge)一律以 speaker_id 為定位 key。
REST API 欄位變更
PATCH /api/v1/tasks/{taskId}/speakers/rename
| 位置 | 舊欄位 | 新欄位 |
|---|---|---|
| Request body | original_name | speaker_id(最大 100 字元) |
| Request body | new_name | new_label(最大 100 字元,禁控制字元 \x00-\x1F / \x7F 與換行) |
| Response data | original_name | speaker_id |
| Response data | new_name | new_label |
speaker_id 仍可同時接受顯示標籤做連續改名(如先把 Guest-1 改名為「王經理」,再用「王經理」改為「王總」);解析後的 response speaker_id 永遠是原始 ID。
PATCH /api/v1/tasks/{taskId}/speakers/reassign
| 位置 | 舊欄位 | 新欄位 |
|---|---|---|
| Request body | target_speaker_id | 不變(語意已對齊原始 ID) |
| Response data | new_speaker_name | new_speaker_label |
target_speaker_id 必須是原始 ID(取自 init_sentence.speaker_id);reassign 不接受顯示標籤。
PATCH /api/v1/tasks/{taskId}/speakers/merge
| 位置 | 舊欄位 | 新欄位 |
|---|---|---|
| Request body | source_speaker_id / target_speaker_id | 不變(仍接受原始 ID 或當前顯示標籤) |
| Response data | target_speaker_name | target_speaker_label |
WebSocket 事件變更
| 事件 | 舊欄位 | 新欄位 |
|---|---|---|
rename_speaker action body | original_name / new_name | speaker_id / new_label |
result event 的 origin / translations[lang] | 僅 speaker_id(混用顯示名) | speaker_id(原始 ID)+ speaker_label(顯示標籤) |
speaker_renamed event | original_name / new_name | speaker_id / new_label |
speaker_reassigned event | new_speaker_name | new_speaker_label |
speakers_merged event | (缺 target 標籤) | 新增 target_speaker_label |
SSE 事件變更
| 事件 | 舊欄位 | 新欄位 |
|---|---|---|
init_sentence | speaker_id(顯示名)+ original_speaker_id(原始 ID) | speaker_id(原始 ID)+ speaker_label(顯示標籤) |
Broadcast viewer origin / translation | 僅 speaker_id(混用) | speaker_id + speaker_label |
Broadcast viewer speaker_renamed / speaker_reassigned / speakers_merged | 同 WebSocket 對應事件 | 同上 |
init_metadata.speaker_aliases(「原始 ID → 顯示標籤」映射)行為與欄位不變。
客戶端建議
- 使用 WebSocket 即時錄音的客戶:升版前同步
result.origin.speaker_id與新增result.origin.speaker_label的處理;rename body 改送{ "speaker_id": "...", "new_label": "..." } - 使用 SSE 歷史音檔的客戶:
init_sentence.speaker_id現在是原始 ID(過去是顯示名),改用speaker_label顯示 - 做語者編輯(rename / reassign / merge)的客戶:
- rename → 用
speaker_id(原始 ID 或當前顯示標籤皆可)+new_label - reassign →
target_speaker_id必須是原始 ID(取自init_sentence.speaker_id,不能送顯示標籤) - merge →
source_speaker_id/target_speaker_id仍可送原始 ID 或當前顯示標籤
- rename → 用
- 做 TXT/SRT/CSV 匯出整合的客戶:
new_label新增控制字元/換行驗證;若先前送過含換行的標籤會收到 422,請改為單行內容 - 不做語者編輯、僅消費 transcript 文字的客戶:影響極小,唯一行為差異是若有舊代碼把
speaker_id當顯示名直接渲染,需改用speaker_label
資料相容性
- 不做向下相容:舊 transcript blob(V1.3.12 ~ V1.5.1,含
speaker+original_speaker_id)需經 migration 才能在新版讀取;POC 階段沒有跨版本資料保留承諾 - 新錄音不受影響:V1.5.3 以後新建的 transcript blob 直接使用新欄位
文件更新
- reference/rest/speakers.md:rename / reassign / merge 三端點 body / response 全面對齊
- rest-api.md L2280–2455:speakers 摘要對齊新欄位
- reference/websocket/voice-translation.md L975–1127:rename_speaker / reassign_speaker / merge_speakers 三 action
- reference/websocket/events.md L405–495:speaker_renamed / reassigned / merged 三 event
- websocket-api.md L1310–2552:rename / reassign / merge 兩段(前段 actions + 後段 events)對齊
- reference/sse/history.md L135–195:
init_sentenceschema + 客戶端建議 - reference/sse/broadcast-viewer.md L300–365、L605–630:viewer 廣播事件 + JS 範例
- sse-api.md L240–475、L750–795:broadcast origin/translation + history init_sentence schema
- guides/speaker-management.md L140–390:範例 + JS handler
- examples/curl.md、examples/python.md、examples/javascript.md:所有 rename / reassign / merge 範例 + TS interface
參考文件
V1.5.1(2026-05-07)
Bug 修正:POST /api/v1/imports 補上術語 / 校正欄位的長度驗證
文件多處承諾的長度限制(如 term 最大 100 字元)過去在檔案匯入路徑沒有真正生效,超長內容會被悄悄接受。本版補回,行為與文件承諾對齊。
行為變更(與文件承諾對齊)
POST /api/v1/imports 對下列欄位新增 422 拒絕條件(先前會被接受):
| 欄位 | 限制 |
|---|---|
terminology.<lang> | 陣列,最多 500 個術語(每語言) |
terminology.<lang>[].term | string,最大 100 字元 |
terminology.<lang>[].boost | numeric,0.5–5.0(可省略,預設 1.0) |
fuzzy_correction.<lang>[].correct | string,最大 200 字元 |
fuzzy_correction.<lang>[].incorrect[] | string,最大 200 字元 |
限制值與 WebSocket
configaction 一致;先前只有 WebSocket 路徑會擋,本版把檔案匯入路徑補齊。
客戶端建議
若先前曾透過 POST /api/v1/imports 送過超長 term(>100 字元),現在會收到 422。前端應在送出前自行檢查長度並提示使用者。WebSocket 路徑無變化。
V1.5.0(2026-05-07)
內部命名統一(無對外 API 變更)
延續 V1.4.1 啟動的 task_id 命名統一,本版完成內部協議層的過渡。
對外公開 API(WebSocket、REST、Webhook、SSE)完全不變,客戶無需任何動作。
舊命名(recording_id)將於 V1.6.0 全面移除,相關客戶端遷移指引請見 V1.4.1 客戶端建議。
V1.4.3(2026-05-07)
內部觀測層命名統一(無對外 API 變更)
承接 V1.4.1,本版針對 log 與監控層做命名統一過渡。
對外公開 API 完全不變,客戶無需任何動作。
V1.4.2(2026-05-07)
內部程式碼命名統一(無對外 API 變更)
承接 V1.4.1,本版把 task_id 命名推進到後端程式碼層級。
對外公開 API 完全不變,客戶無需任何動作。
V1.4.1(2026-05-06)
命名統一:以 task_id 為跨介面任務識別碼
過去同一筆任務在不同介面有不同欄位名(WebSocket 用 recording_id、Webhook 用 task_id、部分 REST path 變數混用 {recordingId} / {taskId}),整合方需自行對齊三邊命名。本版啟動命名統一週期,新整合請統一使用 task_id。
WebSocket 變更(向後相容)
session_started事件 payload 同時帶task_id與recording_id,兩者值完全相同(同一筆錄音的 UUID)recording_id欄位標記為 Deprecated,仍正常送出;預計 V1.6.0 移除- 文件補強:
session_id為 WS 連線層級識別碼(連線結束即失效),與task_id(任務識別碼)為不同層級
REST API 變更(向後相容)
新增 /api/v1/tasks/{taskId}/... alias 路徑,與既有 /api/v1/recordings/{recordingId}/... 行為完全相同:
| 推薦(V1.4.1 起) | Deprecated(V1.6.0 移除) |
|---|---|
PATCH /api/v1/tasks/{taskId}/speakers/rename | PATCH /api/v1/recordings/{recordingId}/speakers/rename |
PATCH /api/v1/tasks/{taskId}/speakers/reassign | PATCH /api/v1/recordings/{recordingId}/speakers/reassign |
PATCH /api/v1/tasks/{taskId}/entries/{sid} | PATCH /api/v1/recordings/{recordingId}/entries/{sid} |
客戶端建議
- 新整合:統一使用
task_id欄位與/api/v1/tasks/{taskId}/...路徑,避免後續再次遷移 - 既有整合:無需立即修改。
recording_id與/api/v1/recordings/...在 V1.x 期間持續可用,建議在排程內遷移,最遲於 V1.6.0 釋出前完成 - ID 對齊邏輯:若同時依賴 WS 與 Webhook,可直接以 WS 的
task_id(或舊名recording_id)對齊 Webhookdata.task_id,三者為同一 UUID session_id不要用於對齊:session_id僅在 WS 連線生命週期內有意義,不會出現在 Webhook 與 REST
移除時程預告(V1.6.0)
V1.6.0 將移除 WS payload 中的 recording_id 欄位,並移除 /api/v1/recordings/{recordingId}/... 路徑。詳細時程將於 V1.6.0 釋出前另行公布。
不變項
- Webhook payload:
data.task_id既有命名不變 - 既有
/api/v1/tasks/{taskId}/...端點:保持不變
V1.4.0(2026-05-06)
新功能:歷史錄音原文編輯 + 自動重翻
使用者可修正 STT 辨識錯誤後重新生成翻譯,工作流見 Entries API 典型工作流。
- 新端點
PATCH /api/v1/recordings/{recordingId}/entries/{sid}:編輯單句原文;首次編輯時自動備份 STT 原始輸出至original_text_raw,記錄original_text_edited_at,清除該句所有語言的 TTS 快取 - 新端點
GET /api/v1/sse/recordings/{taskId}/entries/{sid}/retranslate:重新翻譯單一句子(可指定語言或重翻所有已存在語言),支援樂觀鎖(expectedRevision) - 編輯與重翻分離:PATCH 只改原文不動翻譯,前端可決定何時觸發重翻
歷史紀錄 SSE 暴露編輯標記
historyTranscribe init_sentence 事件在被編輯句子上會帶 original_text_raw(STT 原始)與 original_text_edited_at,前端可顯示「已編輯」標記與「還原原文」功能。
安全性修補
retranslate/retranslateSummary加入使用者過濾:兩個既有 SSE 端點先前存在水平權限漏洞(IDOR),允許讀取他人錄音。本版補上權限檢查,他人錄音回recording_not_found。- 重翻 / 重生摘要要求錄音已完成:
retranslate/retranslateSummary/retranslateEntry/regenerateSummary四個端點要求processing_status === completed,避免與處理中流程競爭。未完成時回recording_not_completed。
新增錯誤碼
| 錯誤碼 | HTTP | 說明 |
|---|---|---|
recording_not_completed | 422 | 錄音尚未完成處理,不允許重翻 / 編輯 / 重生摘要 |
entry_not_found | 404 | 找不到指定的句子 |
entry_text_empty | 422 | 句子原文為空 |
entry_text_too_long | 422 | 句子原文超過 2000 字元上限 |
transcript_revision_conflict | 409 | 逐字稿已被其他請求修改(樂觀鎖衝突) |
詳見 error-codes.md。
客戶端建議
- 編輯 STT 原文後:建議呼叫 PATCH 後立即觸發單句重翻 SSE,並帶上 PATCH 回應的
revision作expectedRevision,避免併發覆寫 - 顯示編輯標記:以
init_sentence事件內original_text_raw欄位存在性('original_text_raw' in data)判斷是否被編輯過,不要用文字比對(使用者可能編輯後又改回原值) - 錄音狀態:對未完成的錄音呼叫重翻 / 編輯 / 重生摘要會回
recording_not_completed,前端應在 UI 阻擋這些操作直到processing_status === completed
V1.3.13(2026-05-06)
行為變更(Breaking Changes)
- WebSocket
audio_format鎖定為pcm與webm:原本接受 5 種格式(pcm/webm/mp3/wav/m4a)收斂為僅接受pcm與webm,與文件reference/websocket/voice-translation.md既有規格一致。客戶若送mp3/wav/m4a將收到audio_format_unsupported(過去會被悄悄解碼成功,屬未文件化的隱性行為)。檔案匯入仍走POST /api/v1/imports,不受影響。
文件更新
- 音檔下載 Content-Type 一律
audio/mp4:rest-api / SSE audio / tasks export / history playback / curl / javascript 多處文件統一為「所有錄音音檔一律以 M4A 容器(AAC 編碼)回傳」,移除原本「動態決定」的循環敘述。 - 檔案匯入支援格式收斂為
mp3/wav/m4a:移除文件中對mp4與webm的提及,以對齊實際接受的格式(guides/file-import.md、reference/rest/imports.md)。
客戶端建議
- 使用 WebSocket
startaction 的客戶:請務必明確指定audio_format為pcm或webm;若先前曾依賴未文件化的mp3/wav/m4a隱性支援(極少數情境),請改走 檔案匯入 API。 - 下載錄音音檔的客戶:所有新錄音 Content-Type 固定為
audio/mp4、副檔名.m4a。若儲存中仍存有舊錄音,下載仍可能收到audio/webm,建議保留對舊副檔名的處理分支以涵蓋歷史資料。
參考文件
V1.3.12(2026-05-04)
⚠️ 已於 V1.5.3 翻轉:本版引入的
original_speaker_id欄位與「speaker_id為顯示名」的設計已被 V1.5.3 的命名翻轉取代。本段保留作為歷史紀錄;新整合請直接參考 V1.5.3 規範,不需再實作此版的客戶端建議。
新增功能
- History SSE 補欄位以對齊 Transcribe 語者編輯 UX:歷史紀錄的
init_metadata與init_sentence事件各補一個欄位,讓前端能完整重用即時錄音頁的說話者編輯選單(單句重新指派 + 全域重命名)。init_metadata新增speaker_aliases(object):「原始說話者 ID → 顯示名」映射。無別名時為{}(空物件,非空陣列)。供前端在送PATCH /speakers/rename前做撞名預檢,可涵蓋「在後端存在但因被 rename 過而畫面上沒出現的原始 ID」這類隱性衝突。init_sentence新增original_speaker_id(string|null):未經 alias 替換的原始說話者識別碼,提供給PATCH /speakers/reassign作為target_speaker_id來源。- 舊資料 fallback:pre-v2.24.0 的舊版逐字稿記錄若無
original_speaker_id,SSE 出口會自動退回speaker_id,避免新欄位帶 null 對舊錄音造成編輯入口失效。
行為變更
- 無 breaking change。兩個欄位皆為純新增;既有 SSE client 用 Zod
z.object(預設 strip extra)不會解析失敗,無須版本協商。
文件更新
- sse-api.md L156-198:
init_metadata/init_sentence範例與欄位表加入新欄位說明 - reference/sse/history.md L103-180:同步補齊 reference 細節版的 schema
客戶端建議
- History 詳情頁要做語者編輯的客戶:請從
init_sentence.original_speaker_id取得 reassign 用的原始 ID(不要用speaker_id,那是已套 alias 的顯示名);用init_metadata.speaker_aliases做 rename 前的撞名預檢。 - 不做語者編輯的客戶:可忽略新欄位,現有解析行為不受影響。
參考文件
V1.3.11(2026-05-04)
行為變更(Breaking Changes)
- STT 拒絕 bare
en代碼(V1.3.10 changelog 原宣稱已移除但實際未生效):客戶若送en將收到 422invalid_transcription_language,請改用en-US/en-GB等完整 BCP 47 代碼。 - TTS 移除 4 個供應商不支援的 locale:
it-CH、ar-IL、ar-PS、en-GH。語音服務供應商的 TTS 從未支援這 4 個 locale,過去客戶若請求其 voice 會在供應商端 runtime 失敗。STT 仍支援這 4 個 locale。
新增功能
- TTS 補齊至供應商完整真值(154 種語言、325 個 voice):與語音服務供應商的 Monolingual Neural Voice 清單完全對齊(含 GA + Preview)
- 中國方言(4 個新增):
zh-CN-henan、zh-CN-guangxi、zh-CN-liaoning、zh-CN-shaanxi - 南亞語系(5 個新增):
bn-BD孟加拉語(孟加拉)、ta-LK坦米爾語(斯里蘭卡)、ta-MY坦米爾語(馬來西亞)、ta-SG坦米爾語(新加坡)、ur-PK烏爾都語(巴基斯坦) - 東南亞語系(1 個新增):
su-ID巽他語(印尼) - 東歐語系(1 個新增):
sr-Latn-RS塞爾維亞語(拉丁字母) - 北美原住民語系(2 個新增):
iu-Cans-CA因紐特語(加拿大音節)、iu-Latn-CA因紐特語(加拿大拉丁字母)
- 中國方言(4 個新增):
文件更新
- languages.md TTS 區段重寫,明確標示:
- 145 個 STT locale 中有 141 個 STT/TTS 雙端皆支援;4 個(
it-CH、ar-IL、ar-PS、en-GH)僅 STT 支援 - 154 個 TTS locale 中有 13 個僅 TTS 支援(4 個 zh-CN 方言 + 9 個其他語言)
- 145 個 STT locale 中有 141 個 STT/TTS 雙端皆支援;4 個(
- guides/tts.md 數字更新(142→154 種語言、304→325 個 voice)
- README.md TTS 描述更新
驗證結果
對比語音服務供應商官方的 STT 與 TTS voice 清單,VAS 完全對齊:
| 來源 | STT | TTS locale | TTS voice | Diarization |
|---|---|---|---|---|
| 供應商官方 | 145 | 154 | 325 | 31 |
| VAS | 145 | 154 | 325 | 31 |
客戶端建議
- 使用
en簡碼的客戶:請改為en-US或其他完整 BCP 47 代碼。 - 使用
it-CH/ar-IL/ar-PS/en-GH做 TTS 的客戶:原本就會在 Azure 端失敗,請改用同語系的其他 locale(例:it-CH→it-IT、ar-IL→ar-SA、en-GH→en-NG)。STT 不受影響。 - 想用新增的 13 個 TTS-only locale 的客戶:可直接呼叫
GET /api/v1/tts/voices?language=zh-CN-henan等取得 voice 列表。
參考文件
V1.3.10(2026-04-30)
文件更新
- languages.md 數字修正
- 語音辨識語言總數
119 種→145 種(與 Azure STT 主表對齊) - 語音翻譯支援
117 種→143 種(145 扣除jv-ID爪哇語、wuu-CN吳語)
- 語音辨識語言總數
本版有遺留問題,請見 V1.3.11:本版原宣稱「已移除
en、語言數完全一致為 145」,但實際並未移除"en"(仍為 146),亦未處理 TTS 端的it-CH/ar-IL/ar-PS/en-GH(供應商 TTS 不支援)與 13 個 TTS-only locale 的缺漏。完整對齊修正於 V1.3.11 完成。
客戶端建議
- 本版僅文件層數字修正,不影響運行中的整合。
參考文件
V1.3.9(2026-04-29)
新增功能
- Webhook Secret Bootstrap 流程:解決客戶端首次整合 webhook 時無法取得 secret 的矛盾。Dashboard 新增「產生 Webhook Secret」按鈕(Lazy 產生),讓使用者先取得 secret 設定到接收端,再回頭設定 webhook URL。設定 URL 時的 probe 將以雙方一致的 secret 簽名,可一次通過。對齊 Stripe / Shopify 業界主流模式。
- 新增端點:
POST /dashboard/api-keys/{id}/webhook/regenerate-secret(Dashboard 限定,沿用webhook-updaterate limiter,10/min/user) - 行為:產 64 字元隨機 secret 寫入 DB,不送 probe、不動 webhook URL,flash session 一次性回傳明文供 Dashboard 顯示
- 重生影響:執行後舊 secret 立即失效,既有接收端會收到簽章不符的 webhook 直到接收端切換新 secret
- 新增端點:
行為變更
- 清除 Webhook URL 不再清除 Secret:
PATCH /dashboard/api-keys/{id}/webhook在webhook_url設為 null 時,webhook_secret將保留不動。Secret 與 URL 改為各自獨立 lifecycle。客戶可先產 secret、稍後再設 URL,中途送空 URL 不會弄丟 secret。 - Dashboard 不再以明文回傳 webhook_secret:
GET /dashboard/api-keys/{id}回傳改為webhook_secret_masked(前綴遮罩 + 後 4 碼)與has_webhook_secret布林。明文僅在剛產生時透過 flash session 顯示一次(對齊 Stripe)。
文件更新
- guides/webhook.md:「方式二:API Key 級 webhook_url」改寫為兩步流程(產生 secret → 設定 URL),新增 Webhook Secret 生命週期章節,安全驗證章節加 Bootstrap callout。
客戶端建議
- 首次整合:在 Dashboard 點「產生 Webhook Secret」、複製到接收端
.env、啟用 HMAC 驗證並重啟服務後,再回 Dashboard 填入 webhook URL。 - 既有客戶:完全相容,無需任何改動。既有 webhook_url 與 webhook_secret 行為不變。
- Secret rotation:建議在接收端短暫接受新舊兩把 secret,dashboard 重生後 in-flight webhook 處理完畢再下架舊 secret。
V1.3.8(2026-04-27)
新增功能
- 翻譯服務不可用偵測(session-level):新增錯誤碼
translation_service_unavailable。當 LLM 翻譯服務連續失敗達閾值,後端會發出一次 session-level 錯誤事件,讓前端能顯示全域「翻譯暫不可用」提示,避免使用者只看到滿頁失敗的個別句子灰字。- 觸發條件:
llm_timeout/llm_provider_error/llm_rate_limit/llm_request_failed連續失敗 5 次升級llm_auth_failed/llm_deployment_not_found/llm_quota_exceeded1 次就立即升級(設定/帳務問題)llm_content_filtered不計入(內容問題,非服務問題)
- 去重:每個 session 只通知一次;任一句翻譯成功則重置計數,可再次觸發
- payload:
type: "error",severity: "error"(不是 fatal — 不應斷線),不帶sid,details含provider、last_error_code、fail_count - 觀眾通知:廣播模式下,所有觀眾(不限語言)也會收到此事件(透過 SSE
event: error通道)
- 觸發條件:
文件更新(規範同步)
延續 V1.3.7+ 前端反應的規範盲點,本次完成:
- error-codes.md — 句子級錯誤判斷規則:在「嚴重程度說明」表下方新增 sid 規則段落,明示**「當錯誤帶
sid時,無論severity為何都應視為 sentence-level 錯誤,不應斷線」**。fatal+sid的組合僅代表該句嚴重失敗,session 整體仍可繼續。 - error-codes.md —
translation_service_unavailable錯誤碼註冊:在「翻譯服務錯誤」段落新增此錯誤碼及完整觸發規則說明 - websocket-api.md:「錯誤訊息格式」段落新增 session-level translation 錯誤範例(不帶 sid,severity error)
- sse-api.md — retranslate 段補 per-sid error 規則:明確列出「失敗句改發
event: error帶sid+error_code,與translation交錯出現」的規範與 payload 格式(V1.3.7 已實作但只在 reference 子目錄記載) - reference/sse/broadcast-viewer.md:補
translation_service_unavailable範例與特有錯誤碼條目 - reference/websocket/events.md:清掉
translation_errordead spec(程式碼從未發出此 action 事件,實際走的是type: "error"通道)
客戶端建議
- 既有的句子級錯誤處理(
type: "error"帶sid)無需任何改動。 - 若想顯示「翻譯服務不可用」全域提示,新增監聽:當收到
error_code === "translation_service_unavailable"(不帶sid)時顯示 banner / toast;待後續任一句翻譯成功(再收到translation事件)即可解除。 - 切勿把
translation_service_unavailable視為斷線訊號 — STT(原文)仍會持續運作。
參考文件:
- 錯誤碼參考
- WebSocket API – 錯誤訊息格式
- SSE API – retranslate 事件格式
- reference/sse/retranslate.md
- reference/sse/broadcast-viewer.md – 特有錯誤碼
V1.3.7(2026-04-24)
行為變更
- 即時錄音:靜音任務統一走正常完成流程:即時錄音(WebSocket)過程全程靜音、雜訊或無法辨識出任何句子時,現在仍會產生空逐字稿(
entries: []),並以task_complete事件結束。此行為與 V1.3.5 的檔案匯入流程對齊,realtime 與 import 兩條來源現在共用「零辨識結果視為合法 completed」語意。 - SSE 歷史紀錄:不再回
sse_transcript_not_found於靜音情境:GET /api/v1/sse/history/transcribe/{taskId}對靜音任務不再回傳sse_transcript_not_found錯誤,而是發送完整事件序列(init_metadata → init_summary(text='') → init_done(totalSentences=0))。客戶端應以totalSentences === 0判斷並顯示「無語音內容」空狀態。
Bug 修正
- 修正 History 頁面靜音錄音卡在「處理中」:先前即時錄音若全程靜音,後端因
segmentsCount == 0條件跳過 transcript 上傳,但task_complete仍送出task_id,導致前端載入歷史紀錄時收到sse_transcript_not_found(語意上為「尚未處理完成」),使 UI 永久停在 loading。修正後 realtime 路徑與 import 路徑一致,永遠上傳 transcript(空 entries 亦然)。
客戶端建議
- 若先前對
sse_transcript_not_found有「待重試 / 輪詢中」的處理邏輯,可保留作為防禦性 fallback(例如 blob 上傳延遲),但不應再用於判斷「任務無語音」——應改以init_done.totalSentences === 0判斷。 - 建議 UI 在
totalSentences === 0時提示可能原因(音量過小、全程靜音、辨識語言與音檔不符),與 V1.3.5 匯入場景的提示文案一致。
文件更新
- 歷史紀錄 SSE 新增「邊界情境:無語音內容」章節,並訂正
sse_transcript_not_found的處理建議描述
參考文件:
V1.3.6(2026-04-23)
新增功能
- Tasks API:新增
POST /api/v1/tasks/{taskId}/force-fail:將卡在非終態(recording/importing/uploading/pending/processing)的任務強制標記為失敗- Body 可選
reason(最長 500 字元) - 觸發
recording.failedwebhook,payload.failure_source為user_forced - 已是終態的任務會得到
invalid_processing_status(422)
- Body 可選
- Tasks API:新增
POST /api/v1/tasks/{taskId}/retry:將failed狀態的任務重新排入處理佇列- 前置條件:
processing_status = failed且audio_status = success且transcript_status = success - 使用
ProcessRecordingJob::dispatch()->afterCommit()確保 queue worker 不會在 DB 交易 commit 前讀到舊值 - 不符前置條件回
invalid_processing_status(422),details欄位會帶audio_status/transcript_status幫助定位
- 前置條件:
行為變更
- 內部 API
PATCH /api/v1/internal/recordings/{id}/status加入終態保護:對已處於completed/failed的錄音若嘗試寫入不同狀態會回 409 Conflict(payload 帶current_status與attempted_status)。幂等放行:推相同終態視為 no-op 回 200。此變更配合force-fail端點,避免 Go WebSocket 仍在運行時把使用者手動操作的結果覆蓋回去。 - 錯誤碼
invalid_processing_status(422)擴充適用範圍:新增為force-fail與retry的通用回應;details會帶current_status,retry場景額外帶audio_status與transcript_status
文件更新
參考文件:
V1.3.5(2026-04-22)
行為優化
- 音檔匯入:空白辨識結果過濾:當音檔因整段靜音、音量過小、雜訊或辨識語言與音檔不符而導致語音辨識結果為空時,後端現會統一過濾空白 phrase,不再產生大量
00:00/ 空文字的佔位片段 - 零辨識結果為合法
completed狀態:此情境下匯入任務仍以status: completed結束(不是failed),task_id正常產出,但後續載入的逐字稿entries為空陣列、segments_count為0 - 預算依實際時長扣除:無法辨識的音檔仍依音檔時長扣除月度預算(不退還)
客戶端建議
- 載入逐字稿(SSE
/api/v1/sse/history/transcribe/{taskId})後,若累計句子數為0,顯示「此音檔未辨識出語音內容」空狀態 - 不應將零辨識結果視為錯誤分支,應走完成分支後以句子數判斷
- 建議 UI 同時提示可能原因(音量過小、全程靜音、辨識語言與音檔不符)
文件更新
- 音檔匯入指南 新增「音檔無法辨識時的行為」章節
- Imports API 在
status狀態流轉下補充completed邊界情境說明 - 匯入進度 SSE 在
completed事件下補充零辨識結果的行為註記
參考文件:
V1.3.4(2026-04-22)
新增功能
- Tasks API:新增
GET /api/v1/tasks/{taskId}/transcript/export:下載任務逐字稿,支援 五種格式 —txt、srt、sbv、vtt、csv- 輸出內容包含原文與所有翻譯語言
- CSV 以 UTF-8 BOM 開頭、欄位
index,start,end,speaker,text,<每翻譯語言一欄>、時間HH:MM:SS(無毫秒) - SRT 時間
HH:MM:SS,mmm;SBV 時間H:MM:SS.mmm,原文與翻譯以|串為單行;VTT 使用WEBVTT表頭 - 檔名採用
{錄音名稱}-transcript.{ext}(RFC 5987 UTF-8 編碼) - 新增錯誤碼
recording_transcript_not_ready(422)
行為變更(Breaking)
- 語者分離與多語言互斥改為硬性拒絕:
recognition_mode: multi_speaker搭配多個transcription_languages時,原本會發出警告並自動截斷到第一個語言,現改為直接回傳diarization_multilang_conflict錯誤並拒絕開始- 錯誤 severity 從
warning調整為error - 前端需在使用者送出
start前即限制「語者分離」與「多語言」二擇一,或處理此錯誤並引導使用者調整設定 - 影響端點:WebSocket
voice-translation / start
- 錯誤 severity 從
文件更新
- Tasks API 新增
transcript/export完整規格與五種格式輸出範例 - 錯誤碼參考 新增
recording_transcript_not_ready - curl、Python、JavaScript 範例新增「任務匯出」章節
- README API 參考表 Tasks 端點計數從 8 更新為 9
參考文件:
V1.3.3(2026-04-21)
新增文件
- Tasks API:補上
GET /api/v1/tasks/{taskId}/audio/export端點的完整文件(原先實作存在但文件遺漏),包含參數、動態 Content-Type、錯誤碼及前端下載範例 - 說明該端點與 SSE
/api/v1/sse/audio/{taskId}的差異:前者用於離線下載(Content-Disposition: attachment),後者用於播放(支援 Range Request)
文件修正
- 修正 Voice Translation Actions 互譯模式
speakers欄位說明表格:欄位名從speaker更正為id,與 JSON 範例及實際服務行為一致 - 修正 README API 參考表端點計數:Tasks 從 7 改為 8(新增 audio/export)、Broadcasts 從 9 改為 6(原本計數錯誤)
參考文件:
V1.3.2(2026-04-07)
文件結構調整
- 移除 3 個已棄用的舊版文件(
error-codes.mdV0.6、languages.mdV0.1、authentication.mdV0.1) - 將
appendix/error-codes.md和appendix/languages.md移至根目錄,取代棄用版本 - 更新所有交叉引用連結
V1.3.1(2026-03-26)
批次任務管理
- 新增
PUT /api/v1/tasks/batch/pin:批次更新釘選狀態,單次最多 100 筆 - 新增
DELETE /api/v1/tasks/batch:批次刪除任務,單次最多 100 筆 - 兩個端點皆僅影響屬於當前用戶的任務,回應包含
affected_count
批次廣播撤銷
- 新增
DELETE /api/v1/broadcasts/batch:批次撤銷 PENDING 狀態的廣播,單次最多 100 筆 - 非 PENDING 狀態的 ID 會被忽略,回應包含
affected_count
參考文件:
版本:V1.5.7 最後更新:2026-05-20