給HoneyChat接入Inworld TTS-1.5 Max的時候,我們在提示詞里撒了一把[laugh]、[sigh]、[breathe]標簽。這是過去一年表現力TTS的常見做法——一半的模型演示都在用內聯副語言標記。心想這下語音消息該有嘆氣、該有笑聲了吧。
出來的音頻聽著沒問題,就是跟之前一模一樣。沒有笑聲,沒有嘆氣。這些標簽最理想的情況是讀成了一段沉默,碰上某些聲音,干脆把"sigh"這個詞給念出來了。把所有能想到的變體全測了一遍,一個起作用的都沒有。
先說HoneyChat現在的語音技術棧:引擎用的是Inworld TTS-1.5 Max,每百萬字符10美元,目前在TTS Arena排行榜上以1259分排第一。支持15種語言的本地發音——英語、俄語、日語、中文、韓語、西班牙語、法語、德語、意大利語、葡萄牙語、波蘭語、印地語、阿拉伯語、希伯來語、荷蘭語。聲音庫里有312個設計好的聲音,對應26種角色原型乘12種語言,以voiceId字符串存在config/archetype_voice_ids.json里,通過Voice Design API生成,用core/voice_design.py管理。
自定義聲音走Voice Clone Manager,也就是core/voice_clone_manager.py,從WAV或MP3樣本生成固定voiceId。緩存方面,聲音預覽和測試樣本從Storj S3延遲加載,通過core/voice_cache.py處理。降級方案是gTTS——Google的免費方案,不用API密鑰,Inworld返回5xx或者預算耗盡時頂上。在此之前我們砍掉了兩個方案:Kokoro跑在CPU Docker上,延遲太高;Chatterbox用Vast.ai的GPU,運維成本過高。Inworld用統一按字符計費替換了這兩個,表現力還強出一大截。有一點值得注意:性別參數用的是VOICE_GENDER_MALE和VOICE_GENDER_FEMALE枚舉,不是"male""female"字符串,傳字符串會靜默返回400。
回到標簽問題。同一句話、同一個聲音,并排對比音頻,結論很明確:內聯副語言標記在Inworld上根本不生效。Inworld的API并沒有文檔說明支持這些標記。我們之前以為這是通用慣例——網上所有TTS帖子都在用——但實際上不是。Inworld真正暴露出來的是temperature和speakingRate這兩個請求參數,外加一小部分SSML。表現力得從這些參數以及文本本身的塑造上找。
在26種聲音原型乘15種語言上反復對照測試之后,找到了四個能穩定改變音頻輸出的模式。第一個是星號強調。"You did *what?*"——星號在語音中被剝離,但被強調的詞明顯帶上重音,每個聲音都奏效,是成本最低、命中率最高的標記方式。第二個是省略號帶情緒的停頓。"Fine... you can come in."三個點產生真實停頓,伴有語調下沉,相當于嘆氣的聲音效果,用不著偽造[sigh]標簽。五個點代表更長的停頓,模型把它們當成韻律線索來解讀。
第三個是SSML打斷標簽。She paused. "Fine, you can come in."——Inworld接受一部分SSML,標簽可以精確控制停頓時長,0.4秒的沉默放在"她停頓了一下"和"進來吧"之間,節奏自然得多。第四個是在文本中直接描述聲音動作,比如在對話前面寫"她嘆了口氣"或"他笑了",而不是依賴標簽來觸發這些聲音。模型在理解上下文和情緒走向上,遠比處理特殊標記標簽要穩定。
把這四種方法組合使用——星號強調關鍵臺詞、省略號制造情緒停頓、SSML打斷控制節奏、文本描述引導情緒——HoneyChat的語音消息質量明顯提升。這批312個聲音在15種語言下都對相同的文本修飾產生一致反應,不需要按聲音或按語言做特殊適配。回頭來看,寄希望于一套未經驗證的標簽體系是個教訓:在語音合成上,控制表現力的方式得從API實際提供的參數出發,而不是從社區通用的演示文本出發。
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.