目錄(30 節)

TTS Webhook 回調點做?喺輪詢型 API 上自建回調層

冇原生 webhook 唔使等——三個組件自建回調層,百幾行 code 搞掂。

— 港嘢內容團隊約 11 分鐘粵語TTSWebhook後端API教學
分享:

一句答你: 港嘢生成 API 係「提交+輪詢」型,冇內建 webhook 端點;想要「任務完成即刻通知你嘅系統」,正路係自建一層好薄嘅輪詢 worker:佢負責 poll,poll 到結果就 POST 回調去你嘅業務端點——成層嘢百幾行 code 搞掂。

Key Takeaways

  • API 現實:202 提交 → 自己 poll → completed 攞網址;讀取接口唔計限流,輪詢成本極低
  • 回調層三組件:提交器、輪詢 worker、回調發送器——職責分開先易維護
  • 回調要即刻下載音頻:預簽網址時效最短 1 小時
  • 回調發送要有重試同簽名(HMAC),唔好開一個唔驗簽嘅內部端點
  • failed/cancelled 都要回調——知衰咗先可以補做
  • 批量 25 項逐項 poll,聚合完一次過回調業務端最乾淨

先接受現實:完成訊號係點嚟

根據 2026-10 嘅公開文件,港嘢 API 嘅生成流程係:

POST /v1/audio/jobs      →  202 { job_id, poll_url }
GET  /v1/audio/jobs/{id} →  queued → processing → completed | failed | cancelled
completed 之後:回應帶 audio_url(預簽下載)

即係話:平台唔會主動話你知「搞掂喇」——你(或者你嘅 worker)要自己問。咁「webhook 回調」點做?答案係:回調呢一截由你自己起——用一個輪詢 worker 做橋,平台狀態一變,就 POST 通知你嘅業務系統。

呢個模式嘅好處:業務端(訂單系統、內容系統、影片流水線)完全唔使識輪詢,佢只係收一個「搞掂,喺度」嘅 POST。未行過一次完整生成流程嘅話,建議先睇粵語 TTS API 快速上手;港嘢語音生成嘅整體面貌,睇廣東話 TTS 完全指南。

架構:三個組件

┌──────────┐   提交    ┌─────────────┐
│ 業務系統  │ ───────→ │ 提交器       │ ──→ 港嘢 API(202 + job_id)
└──────────┘           └──────┬──────┘
                              │ 記錄 job_id ↔ 業務參考號
                       ┌──────▼──────┐
                       │ 輪詢 worker  │ ──→ GET 狀態(2–5 秒退避)
                       └──────┬──────┘ 終態?
                       ┌──────▼──────┐
                       │ 回調發送器   │ ──→ POST 業務回調網址(HMAC 簽名)
                       └─────────────┘

組件一:提交器

包一次 POST /v1/audio/jobs:帶語音 slug、文字(≤500 字符)、格式;成功即刻將 任務編號 ↔ 你嘅業務參考號 綁定入庫。呢個映射係成個架構嘅黏合劑——冇咗佢,poll 完你都唔知嗰個檔案係邊張單嘅。

function submit(reference, voiceSlug, text):
    resp = POST /v1/audio/jobs { voice, text }
    if resp.status == 202:
        入庫(reference, resp.job_id, 提交時間)
        入輪詢隊列(resp.job_id)
    else:
        按錯誤碼分類處理(4xx 記錄、429 照 Retry-After)

組件二:輪詢 worker

一個簡單隊列:所有未終態嘅任務編號入列,worker 逐個 poll。三個要點:

  1. 節奏:2 至 5 秒退避起步;輪詢接口唔計限流,但都唔使 poll 到毫秒級
  2. 提交先受限:每分鐘限流(預設 60 次,金鑰可調)係提交動作先計;worker 只做查詢,冇壓力
  3. 終態處理:completed/failed/cancelled 都係終態——三種都要觸發回調,然後出隊
loop:
    job = 隊列取最舊未終態
    st = GET /v1/audio/jobs/{job.id}
    if st.status in {completed, failed, cancelled}:
        組 payload → 交回調發送器
        出隊
    else:
        sleep(退避秒數)

組件三:回調發送器

poll 到終態,組一個 payload POST 去業務端點:

function dispatch(job):
    payload = {
        reference: job.reference,
        job_id: job.id,
        status: job.status,
        audio_path: job.status == "completed" ? 下載並存檔後嘅本地路徑 : null
    }
    for attempt in 1..3:
        ok = POST 業務回調網址, payload, 帶HMAC簽名
        if ok: 記「已通知」;return
        sleep(1 * 4^(attempt-1) 秒)
    入死信隊列

payload 範例:

{
  "reference": "order-20261008-001",
  "job_id": "b7e6f2a1-4c3d-4e5f-8a9b-0c1d2e3f4a5b",
  "status": "completed",
  "audio_path": "/storage/2026/10/order-20261008-001.mp3",
  "srt": "1\n00:00:00,000 --> 00:00:02,400\n……(有開先有)"
}

四個實現細節,決定成敗

細節一:回調要即刻下載音頻

audio_url 係預簽網址,有時效:已入音頻庫嘅 1 小時,生成端直出未入庫嘅 7 日。正確姿勢:回調層收到 completed 就即刻下載,存去你自己嘅儲存,回調 payload 帶你自己嘅永久檔案位置——業務端唔應該攞住條預簽網址過夜。下載失敗都係同一處理:重試下載、失敗入死信,任務狀態照樣回調(標明「音頻待補」),唔好因為下載一環卡住成單嘅通知。下載細節睇TTS MP3 下載指南。

細節二:回調要有重試同簽名

業務端點可能暫時收唔到(重啟、網絡抖)。回調發送器要有:指數退避重試(例如 1 秒/4 秒/16 秒三次)、失敗入死信記錄人手跟。簽名方面,payload 加 HMAC(用你自己嘅共享密鑰),業務端驗簽先處理——唔好開一個唔驗簽嘅內部端點俾人亂 POST。呢啲係你自己系統內部嘅工程衛生,漏咗會出大件事。

重試設計多一個細位:回調重試同生成輪詢嘅重試係兩回事,唔好撈亂——前者係你嘅業務端收唔收貨,後者係平台生成好未。兩條獨立嘅重試鏈,各自有上限、各自有日誌,排查先唔會黐埋一齊。

細節三:失敗同取消都係「訊號」

failed/cancelled 嘅任務冇 audio_url,但佢哋更需要回調——業務端要知呢單衰咗,先可以補做或者警報。一個實用約定:回調 payload 嘅 status 欄位照抄平台狀態,業務端按值分流處理,唔好由回調層自行「演繹」成另一套狀態——訊息鏈每多一次翻譯,就多一次走樣機會。另外記住:在途任務有上限(免費 3/入門 5/專業 10/工作室 20),過期唔要嘅任務用取消接口(DELETE /v1/audio/jobs/{id})主動清,名額先釋放得到。

細節四:429 唔好變成回調風暴

提交撞 429(限流或是在途上限),提交器要識等:限流照 Retry-After 等;在途上限就等 worker poll 完一個先再交。錯誤分類同退避策略,睇TTS API 錯誤碼大全。

批量場景:聚合回調

批量一次交 25 項,202 逐項回任務編號。回調層兩個做法,各有適用場景:

做法流程適合
逐項回調每項終態就 POST 一次業務端逐項即時處理
聚合回調25 項全部終態,一併 POST成批先有意義(例如成集教材)

聚合回調多一個小狀態機:計住「25 項入面幾多項已終態」,齊數先發。批量策略本身(幾時用批量、分批點切)睇批量生成工作流。

幾時根本唔使回調?

老實講:量少嘅場景,回調層係殺雞用牛刀。

  • 一日幾單生成:定時任務每 30 秒 poll 晒未完成嘅任務,簡單過起三個組件
  • 人手觸發:playground 出檔,連 API 都唔使

回調層嘅價值,喺「業務端要即時反應」或者「並發量大到定時任務追唔切」先浮現。基建要同需求匹配。仲有一個升級訊號可以留意:當你發現定時腳本嘅間隔愈改愈密(由 60 秒改到 30 秒改到 10 秒),就係時候升常駐 worker——腳本加密係用複雜度換延遲,去到某個位,常駐反而簡單。

幾時唔使回調嘅極端:直接人手

再退多一步:有啲「自動化需求」其實係半自動就夠——一星期三五條音頻,用 playground 人手出,加一個共享資料夾做交付,可能已經解決九成痛點。自動化嘅門檻唔係技術,係量:量未到,基建就係負債。誠實評估自己嘅量,係工程判斷嘅第一步。

對帳同冪等:回調設計嘅護城河

兩條不變量,早啲接受早啲安樂:

  • 回調可能重複(重試機制嘅代價):業務端處理回調要冪等——同一個任務編號收兩次,第二次要認得並且唔重複處理。簡單做法:業務端記低已處理嘅任務編號,重複就即回 200 跳過
  • 回調可能永遠唔到(worker 掛咗):所以要有對帳——業務端可以主動問「我呢批參考號嘅任務而家點?」。實現上係 worker 提供一個內部查詢接口,或者定期出對帳報表

三個習慣令你半夜唔使起身:

  1. 每個任務入庫嗰刻記提交時間,超過某個時限未終態就警報
  2. 「知結果」同「通知咗業務」分開記——兩個狀態,唔好撈埋
  3. 死信隊有人負責睇,哪怕一日掃一次

監察:worker 健康四個指標

指標意義
在途任務數貼近方案上限=提交要開始等
終態耗時分佈突然變長=平台側或者你嘅並發有變
回調成功率跌=業務端或者網絡問題
死信堆積量持續上升=有人工問題要跟

四個指標唔使乜嘢豪華監察台——定時腳本記落一個表,有異樣出警報,已經夠九成場景用。

一個場景示例:影片配音流水線

想象一個內容團隊,每星期幾十條短片要粵語旁白,點行呢套架構:

  1. 提交器:文稿入內容系統時觸發提交——每條片一段旁白稿(約 500 字符,正好單任務);超過就按標點拆兩段兩個任務
  2. 輪詢 worker:全部任務入隊,2 秒退避 poll,終態出隊
  3. 回調:completed 就下載 mp3 入媒體庫,POST 返內容系統帶檔案位置;系統自動將音頻掛返嗰條片
  4. 失敗處理:failed 回調觸發人手覆核(多數係稿面問題),改好重新提交一次過

呢條流水線嘅特點:內容團隊全程只接觸文稿同成片,語音生成呢截完全隱形——呢個就係回調架構嘅價值:語音係基建,唔係工序。

部署形態:三種行法

同樣三個組件,部署形態可以由輕到重:

形態點行適合
定時腳本cron 每 30–60 秒行一次,poll 晒未終態任務量細、可容忍延遲
常駐 worker一個長駐進程,隊列驅動量中、要即時回調
任務系統用現成嘅隊列/任務框架行三個組件量大、團隊已有基建

唔好一開波就上最重嗰種。定時腳本行得順、量真係上咗嚟,先升常駐;已有隊列基建嘅團隊,接入係水到渠成。反行嘅順序(一開波就起大基建)係回調架構最常見嘅死法——未死於流量,先死於複雜度。

優先級同擁塞控制:唔好讓雞毛塞死條渠

並發一高,就要有優先級,否則重要任務畀雞毛任務阻住:

  • 分級隊列:即時互動(用家等緊)係高優先,批量產量係低優先;worker 先 poll 高優先
  • 提交節流:低優先任務喺在途名額緊張時讓路——名額留俾用家等緊嗰啲
  • 公平性:批量任務分小批提交,一批行完先交下一批,唔好一口氣食晒全部名額

擁塞控制嘅目標好簡單:最高優先嘅任務,任何時刻都有名額用。

業務端點嘅驗證與安全細節

回調嘅接收位(你嘅業務端點)係整條鏈最後一公里,安全細節唔好慳:

  • 驗 HMAC 簽名先處理:簽名對不上,直接 403——唔好「先處理再說」
  • 帶時間戳防重放:payload 加時間戳,業務端拒收太舊嘅請求
  • 回 200 要快:收到、驗完簽、入本地隊列就回 200,重活(落庫、觸發後續流程)交俾自己嘅 worker——回調處理慢會拖累發送器重試節奏
  • 日誌帶 reference:排查嗰陣「邊單嚟嘅」永遠係第一條問題

呢啲全部係你自己系統內部嘅工程,但漏一樣,成條鏈嘅可信度就打折扣。

一單任務嘅一生(時間線)

用一單具體嘅任務行一次全流程:

14:00:00  業務系統:新訂單 → 叫提交器(reference=order-087)
14:00:01  提交器:POST /v1/audio/jobs → 202(job_id=b7e6…)
14:00:01  入庫:order-087 ↔ b7e6…、入輪詢隊列
14:00:03  worker:GET → queued
14:00:06  worker:GET → processing
14:00:12  worker:GET → completed+audio_url
14:00:12  worker:下載 mp3 入 /storage/2026/10/order-087.mp3
14:00:13  發送器:POST 業務回調(帶簽名)→ 200
14:00:13  記錄:order-087「已終態、已通知」

由提交到業務端知道結果:13 秒,全自動。呢個就係「輪詢型 API+自建回調」嘅實際體感——對業務端嚟講,同原生 webhook 冇分別。

冇終態嘅任務:卡死咗點算?

理論上每個任務都會去到終態,但你嘅系統要預「萬一」:任務提交後超過合理時間(例如你場景正常終態時間嘅十倍)仍然未見終態,就標記為「可疑」並出警報;確定唔要嘅,用取消接口主動終結,釋放在途名額。唔好畀一個殭屍任務長期佔住名額——在途上限係稀缺資源,殭屍唔清,新任務就入唔到。

常見問題 FAQ

平台幾時會有原生 webhook?

路線圖嘢唔喺呢篇答。現實係:輪詢接口唔計限流,自建橋接層成本低,多數團隊自建已經夠用有餘。而且自建層仲有一個隱藏好處:回調格式、重試策略、簽名機制全部由你話事,第日對接第二個生成服務,業務端一行 code 都唔使改。

回調 payload 應該包邊啲內容?

最少:你嘅業務參考號、任務編號、status、音頻嘅你自己檔案位置。避免將預簽網址當永久連結傳——佢會過期。

輪詢 worker 乜都 poll 會唔會有問題?

讀取接口唔計限流,poll 幾多都得;真正要管嘅係你自己嘅資源——終態任務記得出隊,唔好無限重 poll。

業務端點收唔到回調點算?

回調發送器重試三次(指數退避)之後入死信記錄。另外業務端可以有對帳機制:worker 定期將「超過 N 分鐘仍無確認」嘅任務重發。兩層網兜住,回調失聯就由「事故」變成「例行補件」。

一個 worker 處理到幾多任務?

取決於你嘅退避設計同終態時間分佈,唔取決於平台(讀取唔限流)。粗略心算:2 秒退避、單任務 10 秒內終態,一個 worker 串行都處理到幾十個並發任務嘅輪詢——瓶頸通常先出現喺提交端:限流(預設 60 次/分鐘,開金鑰可調)同在途上限(按方案 3/5/10/20)。

定時腳本同回調 worker,可唔可以並存?

可以,而且係常見演化路徑:日常行定時腳本;有即時需求嘅流程(例如用家等緊嗰單)先行輪詢 worker。兩者共用同一張任務表,狀態互不干擾——記得冪等照做,兩條路都可能通知同一單。

SRT 字幕都經回調傳?

得。提交時 srt 設 true,completed 回應會帶字幕內容,照樣入 payload 或者直接同音頻一齊存檔。留意字幕有附加計費(帳單字符多過正文),量大嘅團隊記得喺成本模型入面計埋呢筆。字幕工作流全貌睇SRT 字幕工作流。

[!CTA]

起你嘅第一個輪詢 worker 之前,先出第一個音頻

免費開戶每月 5,000 字符,由一個 curl 開始驗證成條鏈。

相關文章