fix(#23)+feat(#24): stop 后不再下发周期 usage 帧;gummy 预连接 spare 会话
ci / server (push) Failing after 9s
ci / design-tokens (push) Failing after 10s

#23 修复(服务端根治,五端客户端提交信号自动变安全):
- finish 先冻结会话并停 usageLoop,再 flush provider——此前 usageLoop 在
  waitResults(最长 3s)期间继续 tick,周期 usage 帧会抢在尾部 final 之前
  下发,客户端以 partial 文本提前上屏、丢失 final 修正(12B 实测 8s 会话
  4/4 复现;修复后 6/6 归零)
- 桌面端收尾兜底超时 350ms → 800ms(实测 8s 会话 final flush 需 350~540ms,
  350ms 会截丢尾 final)

#24 预连接(12B 调优):
- GummyProvider 常备一条已完成 run-task 握手的 spare 会话,start 直取,
  后台异步补位 + 40s 定期换新(DashScope 空闲 60s 断连,实测 60s 存活/
  120s Idle timeout,留余量 45s)
- 实测网关 start 处理 120~670ms → 3~4ms;消除 dial 抖动(实测 60ms~3.7s)
  对 first_partial 尾部的放大

gummycheck 增加 -model / -pace / -idle 参数,支持模型对比与闲置存活实验

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-07-10 19:44:25 +08:00
parent 7b693b0f63
commit d22e02fa2e
4 changed files with 135 additions and 13 deletions
+12 -2
View File
@@ -20,6 +20,9 @@ import (
func main() {
wavPath := flag.String("wav", "", "16kHz/16bit/mono wav 文件路径")
model := flag.String("model", "gummy-realtime-v1", "DashScope 实时识别模型")
paceMs := flag.Int("pace", 50, "每 100ms 帧的推流间隔 ms50=2x 加速,100=实时)")
idleSec := flag.Int("idle", 0, "会话建立后先闲置 N 秒再推流(测预连接会话的存活时间)")
flag.Parse()
if *wavPath == "" {
fmt.Fprintln(os.Stderr, "用法: rbw get dashscope-api-key | gummycheck -wav test.wav")
@@ -41,6 +44,8 @@ func main() {
fmt.Printf("音频 %d 字节 ≈ %.1fs\n", len(pcm), float64(len(pcm))/32000)
p := asr.NewGummy(key)
p.Model = *model
fmt.Printf("模型 %s · 推流间隔 %dms/帧\n", *model, *paceMs)
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
@@ -51,6 +56,11 @@ func main() {
os.Exit(1)
}
fmt.Printf("会话建立 %v\n", time.Since(start).Round(time.Millisecond))
if *idleSec > 0 {
fmt.Printf("闲置 %ds...\n", *idleSec)
time.Sleep(time.Duration(*idleSec) * time.Second)
start = time.Now() // 重新计时,测闲置后的识别延迟
}
done := make(chan struct{})
var firstPartial time.Duration
@@ -79,11 +89,11 @@ func main() {
fmt.Fprintln(os.Stderr, "SendAudio 失败:", err)
os.Exit(1)
}
time.Sleep(50 * time.Millisecond) // 2x 实时推流
time.Sleep(time.Duration(*paceMs) * time.Millisecond)
}
_ = sess.Close()
<-done
fmt.Printf("首个结果延迟 %v含 2x 推流速度因素\n", firstPartial.Round(time.Millisecond))
fmt.Printf("首个结果延迟 %v推流 %dms/帧\n", firstPartial.Round(time.Millisecond), *paceMs)
}
// readWavData 提取 wav 的 data chunk(仅支持 PCM)。