目錄(19 節)
- emotion 參數係咩?9 個值一覽
- 完整實作:async 提交 + poll 到完成
- 第 1 步:拎 API key 同聲線 slug
- 第 2 步:提交 job(帶 emotion)
- 第 3 步:poll 到 completed
- 第 4 步:攞 audio_url 下載
- 關於 sync 捷徑(現況必讀)
- emotion vs style vs instruction:分別同配搭
- 實用配搭建議:邊種內容配邊種情緒
- 常見錯誤同排查
- 常見問題 FAQ
- emotion 同 style 可以一齊用嗎?邊個行先?
- 唔填 emotion 會點?有冇預設值?
- 我想用中文情緒詞(例:「雀躍」、「感慨」),可以放入 emotion 嗎?
- instruction 同 style 一齊用,邊個話事?
- 點解官方文件有 sync endpoint,但你叫我用 async?
- Job 生成緊,可唔可以中途改 emotion?
- 同一段稿想試齊幾個情緒,點做最有效率?
- 由一句「試下唔同版本」開始
TTS 情緒控制實作:emotion 參數點用(附 API 範例)
廣東話 TTS 嘅情緒控制,係提交任務時加一個 emotion 參數(9 個固定英文值之一)。佢會同 style、instruction 合併成一條演繹指示,次序鎖死 style → emotion → instruction。附可跟住跑嘅 async 提交同 poll 範例。
一句答你:廣東話 TTS 嘅情緒控制,係喺提交生成任務時加一個
emotion參數(9 個固定英文值之一);佢會同style、instruction一齊合併成一條演繹指示,次序係style→emotion→instruction,所以instruction永遠有最終話事權。
同一句「恭喜晒!你哋嘅努力終於開花結果!」,用平靜聲讀同用興奮聲讀,聽落係兩條片。前者似新聞報道,後者似頒獎典禮。TTS 嘅情緒控制,就係幫你喺提交任務嗰刻,將「點樣讀」同「讀咩」分開嚟設定。
呢篇係實作教學。先講 emotion 係咩、有幾個值,再逐步示範完整 async 提交+poll 流程(可以直接複製去跑),然後拆解 emotion/style/instruction 三者嘅分別同配搭,最後俾你一張「邊種內容配邊種情緒」嘅起點表。想先補基礎,可以睇《粵語 TTS API 快速上手》;想知產品面有咩功能,睇《點樣用 API 生成地道粵語語音》。
Key Takeaways
emotion係提交任務時嘅選填參數,只收 9 個固定英文值:happy/sad/angry/fearful/disgusted/surprised/neutral/excited/gentle- 傳錯值會回
400 invalid_emotion— 唔係靜靜當冇填(fail loud,唔會偷偷降級)- 三個「演繹類」參數會合併成同一條指示,次序鎖死:
style→emotion→instruction;instruction排最後,最終話事- 生成係 async 為主:
POST /v1/audio/jobs回202+job_id,再 pollGET /v1/audio/jobs/{id}到completed,攞audio_url下載- ⚠️ Sync 捷徑
POST /v1/audio/speech而家恆回503 pool_cold— 可以知有呢條路,但唔好當主路徑- 配搭嘅原則係:
style定「點樣講」,emotion定「咩心情」,instruction補「你講唔清嘅細節」;三個一齊用唔會撞,只會疊
emotion 參數係咩?9 個值一覽
emotion 描述嘅係講嘢嗰一刻嘅情感狀態 — 係「呢句嘢而家係咩心情」,唔係聲線本身嘅質地,亦唔係角色人設。所以同一把聲、同一段文字,換一個 emotion 就出一個唔同版本。
| 值 | 中文對應 | 典型場景(起點建議) |
|---|---|---|
happy | 開心 | 產品介紹、活動預告 |
excited | 興奮 | 頒獎、優惠宣布、短片 hook |
gentle | 溫柔 | 客服、睡前故事、品牌關懷 |
neutral | 中性 | 新聞、財經、教學、企業培訓 |
surprised | 驚訝 | 開箱、劇情、遊戲旁白 |
sad | 悲傷 | 劇情、抒情內容、公益呼籲 |
angry | 憤怒 | 遊戲角色、衝突劇情 |
fearful | 害怕 | 驚悚、遊戲、危機情境 |
disgusted | 厭惡 | 角色對白、喜劇效果 |
三點要注意:
- 值係英文 enum,唔係中文。 想用中文情緒詞(例:「雀躍」、「感慨」),唔好塞入
emotion,放去instruction嘅自由文字入面。 - 係選填。 唔填就唔會加 emotion 呢一段落指示;輸出主要由聲線、
style同文字本身決定。 - 值域有硬界。 超出 9 個值就係
400 invalid_emotion,唔會被忽略、唔會被截斷 — 呢個對寫 code 嘅人係好事,錯喺開發階段就會爆,唔會出到街先發現。
如果你用過其他語音系統,呢套「情緒/風格/自由指示」係對應緊業界標準嘅概念。W3C 嘅 Speech Synthesis Markup Language (SSML) 1.1 就係用 <prosody> 控制速率/音高/音量、用 <emphasis> 標示強調,同本 API 嘅 style(節奏、聲底)同理;而 emotion 同 instruction 就相當於「用一句話描述你想要嘅演繹」,唔使自己砌 XML。
完整實作:async 提交 + poll 到完成
呢個係官方文件嘅主路徑:POST 提交 → 202 + job_id → poll → completed → 下載。下面四步可以直接跟住跑。
第 1 步:拎 API key 同聲線 slug
API 入門或以上全速開放(免費方案有 Sandbox 模式,每日 50 個生成請求,可以試接);key 用 Authorization: Bearer 傳,前綴 sk_live_。key 嘅查看/管理規則以 API keys 頁面為準,唔見咗就 revoke 再開一把新。
export CANTOGEN_API_KEY="sk_live_…"
curl -s https://canto-gen.com/v1/voices \
-H "Authorization: Bearer $CANTOGEN_API_KEY"
聲線用 slug(ASCII 穩定 id),唔係中文名。例:sum = 心妍,female,adult。永遠由你自己 GET /v1/voices 嘅回應揀 slug,唔好照抄文件範例。
想知某把聲支援咩演繹風格,可以問 GET /v1/voices/{slug}/styles。
第 2 步:提交 job(帶 emotion)
curl -s -X POST https://canto-gen.com/v1/audio/jobs \
-H "Authorization: Bearer $CANTOGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "cantogen-tts",
"voice": "sum",
"text": "恭喜晒!你哋嘅努力終於開花結果!",
"emotion": "excited",
"style": "brisk",
"instruction": "講快啲,尾音上揚,好似現場宣布咁",
"response_format": "mp3"
}'
成功會回 202 Accepted:
{
"job_id": "b7e6f2a1-4c3d-4e5f-8a9b-0c1d2e3f4a5b",
"status": "queued",
"poll_url": "/v1/audio/jobs/b7e6f2a1-4c3d-4e5f-8a9b-0c1d2e3f4a5b",
"srt_requested": false
}
model 可以省略,"cantogen-tts" 係唯一值。文字上限 500 字,超出回 400 text_too_long,唔會靜靜截斷。
第 3 步:poll 到 completed
狀態生命周期:queued → processing → completed|failed|cancelled。建議每隔幾秒 poll 一次,帶少少 backoff。
JOB_ID="b7e6f2a1-4c3d-4e5f-8a9b-0c1d2e3f4a5b"
curl -s "https://canto-gen.com/v1/audio/jobs/$JOB_ID" \
-H "Authorization: Bearer $CANTOGEN_API_KEY"
想寫入程式,呢段 Node 範例係一個實用嘅 poll loop(2 秒起步、每次放大 1.5 倍、最多等 5 秒一次):
async function pollJob(jobId) {
let delayMs = 2000;
for (let attempt = 0; attempt < 60; attempt++) {
const res = await fetch(`https://canto-gen.com/v1/audio/jobs/${jobId}`, {
headers: { Authorization: `Bearer ${process.env.CANTOGEN_API_KEY}` },
});
const job = await res.json();
if (job.status === "completed") return job; // 有 audio_url
if (job.status === "failed" || job.status === "cancelled") {
throw new Error(`job ${jobId} ended as ${job.status}`);
}
await new Promise((r) => setTimeout(r, delayMs));
delayMs = Math.min(delayMs * 1.5, 5000);
}
throw new Error("poll timeout");
}
const job = await pollJob("b7e6f2a1-4c3d-4e5f-8a9b-0c1d2e3f4a5b");
console.log(job.audio_url);
第 4 步:攞 audio_url 下載
completed 之後回應會多一個 audio_url:
{
"job_id": "b7e6f2a1-4c3d-4e5f-8a9b-0c1d2e3f4a5b",
"status": "completed",
"poll_url": "/v1/audio/jobs/b7e6f2a1-4c3d-4e5f-8a9b-0c1d2e3f4a5b",
"srt_requested": false,
"audio_url": "https://canto-gen.com/storage/v1/object/sign/audio_history/…"
}
呢條係預簽名 URL,下載唔使再帶 Authorization:
curl -sL -o excited.mp3 "$AUDIO_URL"
⚠️ audio_url 有期限。過期唔等於要重新生成 — 再 poll 一次同一個 job,會攞到新簽嘅 URL。所以做法係:即刻下載,或將 job_id 存起,需要時重新 poll。
關於 sync 捷徑(現況必讀)
POST /v1/audio/speech 係短文本同步捷徑:≤300 字符、只支援 voice/design 模式,直接回 200 + audio bytes。聽落方便,但而家恆回 503 pool_cold:
HTTP/1.1 503 Service Unavailable
{ "error": "pool_cold", "hint": "use POST /v1/audio/jobs (async)" }
而且佢係 fail closed — 唔會偷偷幫你轉行 async。所以寫 code 嘅時候,主路徑一律用 /v1/audio/jobs;sync 可以當「將來可能有」嘅優化,唔好當 now 嘅方案。另外 clone 同 srt: true 本身都唔支援 sync 軌(分別回 400 clone_not_supported_sync / 400 srt_not_supported_sync)。
emotion vs style vs instruction:分別同配搭
三個參數都係「演繹類」,但分工唔同。佢哋最後會合併成同一條演繹指示,以逗號串接,次序鎖死:style → emotion → instruction。
| 參數 | 係咩 | 值域 | 合併次序 | 幾時用 |
|---|---|---|---|---|
style | 演繹風格:節奏、音色、場景、角色 | canonical 英文 slug(中文 preset 別名都收);亦可傳自由文字 | 最先 | 定「點樣講」— 快慢、起伏、聲底 |
emotion | 講嘢嗰刻嘅情感狀態 | 9 個固定英文 enum | 中間 | 定「咩心情」— 要穩定、可預期 |
instruction | 自由文字演繹指示(廣東話/中文/英文都得) | 自由文字,最多 500 字 | 最後(最終話事) | 補細節 — 你講唔清、但聽得出嘅位 |
幾條實用規則:
style同emotion可以一齊用,唔會互相覆蓋,會疊埋一齊。instruction排最後,所以佢贏。 如果你emotion: "gentle"但instruction寫「用興奮嘅語氣講」,聽落會偏興奮 — 因為指示疊到最後。呢個係設計,唔係 bug:佢俾你「用 preset 打底、再用文字微調」。style中文別名都收。 英文 slug 係 canonical,但原本嘅中文 preset 值照收,內部會正規化到同一個值。instruction超出 500 字回400 invalid_instruction,唔會截斷。- 三個演繹參數同
voice/design/clone三個生成模式互斥:模式一次只可以送一個,否則400 voice_mode_conflict。
一句總結:style = 點樣講;emotion = 咩心情;instruction = 你講唔清嘅嗰啲細節。
實用配搭建議:邊種內容配邊種情緒
下表係起點建議(唔係實測最佳組合)。做法係先由內容類型揀一個 emotion 打底,再用 style 定節奏,最後有需要先加 instruction。
| 內容類型 | emotion 起點 | style 起點 | instruction 例子 |
|---|---|---|---|
| 產品廣告/優惠宣布 | excited | brisk | 「尾句上揚,好似現場宣布咁」 |
| 新聞/財經旁白 | neutral | steady | 「保持平穩,唔好加情緒起伏」 |
| 教學/教材 | neutral 或 gentle | slow | 「慢半拍,每句尾停一停」 |
| 有聲書/講古 | gentle(悲情段可 sad) | drawl | 「娓娓道來,句與句之間留白」 |
| 企業形象/培訓 | neutral | composed | 「沉穩自信,唔急」 |
| 短片 hook | excited 或 surprised | rapid | 「頭三個字加快,製造懸念」 |
| 客服/提示音 | gentle | steady | 「親切啲,語速放慢」 |
| 遊戲角色對白 | angry 或 fearful | sharp | 「咬牙切齒,聲線壓低」 |
上表係按參數語意同常見配音慣例砌出嘅起點,未做過 A/B 實測。真正邊個組合好聽,要你攞自己嘅稿實測;情緒效果冇「一定啱」嘅組合,只有「你條片啱用」嘅組合。
配套兩篇可以一齊睇:語氣詞(「喇」、「囉」、「㗎」)嘅情緒落點,見《粵語語氣詞 AI 讀法》;要出字幕就見《TTS SRT 字幕工作流》。
常見錯誤同排查
| 情況 | 你見到 | 點解/點做 |
|---|---|---|
emotion 打錯字 | 400 invalid_emotion | 只收 9 個值之一;對一次 spell 再送 |
instruction 太長 | 400 invalid_instruction | 上限 500 字;精簡重點,唔好貼成段稿 |
同時送 voice 同 design | 400 voice_mode_conflict | 三個模式互斥,一次只送一個 |
| 文字超長 | 400 text_too_long | 上限 500 字,唔會截斷;拆句提交 |
| 短時間送太多 | 429 rate_limit_exceeded | 預設 60/min per key;跟 Retry-After 退避 |
| 月配額用完 | 403 monthly_cap_reached | 等 UTC 月份重置,或調高 key 上限 |
| Poll 一個唔存在嘅 id | 404 job_not_found | id 可能錯、或屬另一條 key |
撞到 503 | jobs_unavailable 類 | 屬暫時性後端問題,backoff retry |
| 用咗 sync endpoint | 503 pool_cold | 改用 POST /v1/audio/jobs(async) |
兩個小提醒:
- 讀取 endpoint 唔受 rate limit(
GET /v1/voices、GET /v1/audio/jobs/{id}),所以 poll 唔會食你嘅 per-minute 額度。 - API 用量同 playground 共用同一份月配額,試音同正式生成係同一池。
想一次試幾個情緒版本,可以並行提交幾個 job(每個 emotion 一個)再一齊 poll;要大量試就見《TTS 批量生成工作流》。想睇唔同平台喺粵語情緒演繹上嘅分別,見《廣東話 TTS 2026 對比》。
常見問題 FAQ
emotion 同 style 可以一齊用嗎?邊個行先?
可以,兩個都係選填,而且會疊埋一齊。合併次序係 style → emotion → instruction,所以你兩個都送,兩個都會生效;最後由 instruction 話事。
唔填 emotion 會點?有冇預設值?
emotion 係選填。唔填就唔會加入 emotion 呢一段指示,輸出主要由你揀嘅聲線、style 同文字本身決定。想有明確情緒,就明寫一個值。
我想用中文情緒詞(例:「雀躍」、「感慨」),可以放入 emotion 嗎?
唔可以。emotion 只收 9 個固定英文 enum(happy/sad/angry/fearful/disgusted/surprised/neutral/excited/gentle),其他值一律 400 invalid_emotion。中文情緒描述請放去 instruction 嘅自由文字。
instruction 同 style 一齊用,邊個話事?
instruction。合併次序鎖死係 style → emotion → instruction,排最後嘅有最終話事權。呢個設計令你可以「用 style/emotion 打底,再用 instruction 微調」。記住 instruction 上限 500 字,超出會回 400 invalid_instruction。
點解官方文件有 sync endpoint,但你叫我用 async?
因為 POST /v1/audio/speech 而家恆回 503 pool_cold,而且係 fail closed(唔會偷偷轉 async)。sync 語法上係短文本捷徑(≤300 字符、只支援 voice/design),但現階段唔可以當主路徑。用 POST /v1/audio/jobs + poll 就穩陣。
Job 生成緊,可唔可以中途改 emotion?
唔可以。參數喺提交嗰刻就鎖定。要改就要取消原本個 job(DELETE /v1/audio/jobs/{id})再重新提交一個。取消嘅可用性同計費處理,請以提交時嘅文件同實際回應為準。
同一段稿想試齊幾個情緒,點做最有效率?
並行提交幾個 job,每個一個 emotion,然後一齊 poll。因為 poll 讀取唔受 per-minute rate limit,可以放心輪詢;提交就留意預設 60/min 嘅限制,加少少 backoff 就好。
由一句「試下唔同版本」開始
情緒控制唔係「揀一個最靚嘅值」,而係一個可比較嘅實驗:同一句稿、同一把聲,只換 emotion,聽齊幾個版本,你就即刻知邊個啱你條片。
- 想即場試音 → 去 playground(貼一句「恭喜晒!你哋嘅努力終於開花結果!」,輪住試
excited同neutral) - 開發者想由 API 入手 → 睇《粵語 TTS API 快速上手》同《點樣用 API 生成地道粵語語音》
- 想由頭認識廣東話 TTS → 返去《廣東話 TTS 完全指南》
情緒係演繹嘅一半,另一半係讀音;香港人講嘢,兩樣都值得認真對待。