kita / notes

约 3 分钟

话说到一半就断了

「那个……我是可不,花谱姐姐的妹妹。 喜欢唱歌,也喜…」

这是一条直播回复的原话。念到"也喜"就停了,后面只有省略号。听起来像播放被掐断,但那个省略号让我有点在意——正常的截断不会补省略号。

我先按"播放被打断"这条线查。插件播放音频走的是这几条路:优先 ffplay,找不到就退回系统播放,再不行用 winsound。检查下来:

which ffplay
/f/AI-VTuber/tools/ffmpeg/bin/ffplay

ffplay 在 PATH 里。播放日志一条报错都没有——如果三条路全失败,代码里会打 未找到可用播放器 的 warning,但日志里零条。再看音频文件本身:

gsv_tts_20260930205053735_a234.wav | 时长 5.700000s | pcm_s16le s16 32000 1

PCM 16bit、32kHz、单声道,标准格式,时长 5.7 秒。还去翻了 _mouth_sync_tasks 的取消逻辑,确认播放任务只在插件卸载(terminate())的时候才会被 cancel,正常跑不会中断。

播放这条线全排除了。

把文本和音频并排看

真正管用的是把几组数据摆在一起。日志里每条 TTS 都记了文本,音频文件在 data/temp/ 下,用 ffprobe 量时长:

你好呀,欢迎来到直播间。                   16 字   2.82s
那个……吹牛不好哦,我们聊点温柔的吧。      23 字   3.66s
那个……我是可不,花谱姐姐的妹妹。 喜欢唱歌,也喜…   32 字   5.70s

字数和时长是对得上的,音频本身完整。问题在最后那行的文本——它自己就是半句话。

回去看插件怎么处理长度的(main.py:3044):

max_length = self._safe_parse_int(
    self.config.get("bili_live_auto_reply_max_length"), 80
)
if max_length > 0 and len(cleaned) > max_length:
    cleaned = cleaned[:max_length].rstrip() + "..."

按字符硬砍,再补个省略号。 不是让模型重写,是直接切。

我自己把这个参数一路调小

事情到这儿就有点好笑了。这个参数原来是 80,我为了压语音合成的耗时,一路往下调:80 → 50 → 35 → 25。每调一次都觉得"短一点合成快一点",完全没意识到它是在切句子。

25 字对中文来说是什么概念——上面那句"那个……我是可不,花谱姐姐的妹妹。"就已经 18 个字了。稍微带点语气词和铺垫,一句话就 30 字往上。我等于把上限设在了"一句话说不完"的位置,然后奇怪它为什么说不完。

改法

把上限放回 45 字——留余量,不追求卡着极限。真正控制长度的应该是提示词,让模型自己往短里写:

- 一次说 1~2 句完整的话,总长 40 字以内;宁可短,但句子必须说完整

提示词里能表达"说完整",而参数只能表达"砍到第几个字"。这两个的区别,我花了四轮调参才想明白。

改完之后语音合成确实变慢了——45 字的合成大约 8 到 9 秒,比 25 字多了三四秒。但内容完整比快三秒重要得多,这个账我认。

顺带记住的

排查"听起来不对劲"的问题,光听是没用的,得把中间产物摊开看。这次的中间产物是两列:日志里要念的文本、磁盘上生成的音频。两列一对照,是文本问题还是播放问题,一眼就分得开。

我在播放器那边绕的那一圈,本来可以省掉。

← 回到全部笔记