Files
sundynix-agentix/sundynix-gateway/internal/voice/sentence_buffer_test.go
T
Blizzard 644b635d73 feat(voice): 攒句器——语音下行 TTS 的 token 攒句(JARVIS 地基第一块)
语音交互(VOICE_DESIGN.md)不依赖火山账号的第一块地基:SentenceBuffer 把 LLM 逐 token
输出攒成'适合喂 TTS 的句子片段'。逐字喂 TTS 太碎(单字合成不自然、首包延迟高);句末标点
(。!?.!?;;换行)即成一句,从句标点(,,::)且攒够 12 rune 也吐(让长回答尽早出声)。
跨 Push 续半句,Flush 收尾吐无标点结尾。纯逻辑无外部依赖、4 个单测(跨 Push/短从句不断/
长从句先吐/Flush 收尾)。

WS 会话 + 火山 ASR/TTS 客户端 + 控制面配置等到真 API 参数到手再按真形状做,不写猜测桩。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 16:30:50 +08:00

63 lines
1.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package voice
import (
"reflect"
"testing"
)
// 逐 token 喂入,句末标点成句、跨 Push 的半句能续上。
func TestSentenceBuffer_SplitsAcrossPushes(t *testing.T) {
b := NewSentenceBuffer()
var got []string
// 模拟 token 流一个字一个字来
for _, tok := range []string{"帮", "你", "查", "一下", "天气", "。", "今天", "晴", "", "气温二十五度", "。"} {
got = append(got, b.Push(tok)...)
}
got = append(got, nonEmpty(b.Flush())...)
want := []string{"帮你查一下天气。", "今天晴,气温二十五度。"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("got %v want %v", got, want)
}
}
// 从句标点:够长才断(短逗号不单吐,攒进句末标点成一句)。
func TestSentenceBuffer_ShortClauseNotSplit(t *testing.T) {
b := NewSentenceBuffer()
out := b.Push("你好,") // 3 rune < 12 阈值,不该断
if len(out) != 0 {
t.Fatalf("短从句不该断句,得 %v", out)
}
out = append(out, b.Push("在。")...) // 到句末标点 → 整句吐
if len(out) != 1 || out[0] != "你好,在。" {
t.Fatalf("短从句应攒到句末再吐,得 %v", out)
}
}
// 长从句:够长即在逗号处先吐,让长回答尽早出声。
func TestSentenceBuffer_LongClauseSplits(t *testing.T) {
b := NewSentenceBuffer()
out := b.Push("关于人工智能在医疗领域的应用,")
if len(out) != 1 {
t.Fatalf("长从句应在逗号处先吐一段,得 %v", out)
}
}
// Flush 收尾:模型没给句末标点也要把剩余吐出。
func TestSentenceBuffer_FlushRemainder(t *testing.T) {
b := NewSentenceBuffer()
b.Push("这是没有标点的结尾")
if s := b.Flush(); s != "这是没有标点的结尾" {
t.Fatalf("Flush 应吐出剩余,得 %q", s)
}
if s := b.Flush(); s != "" {
t.Fatalf("再 Flush 应为空,得 %q", s)
}
}
func nonEmpty(s string) []string {
if s == "" {
return nil
}
return []string{s}
}