| | |
| | | package engine |
| | | |
| | | import ( |
| | | "os" |
| | | "path/filepath" |
| | | "testing" |
| | | |
| | |
| | | t.Fatalf("tokens = %q, want empty for qwen3-asr", config.ModelConfig.Tokens) |
| | | } |
| | | } |
| | | |
| | | func TestOnlineConfigForXASRUsesStreamingTransducer(t *testing.T) { |
| | | root := t.TempDir() |
| | | files := map[string]string{ |
| | | "encoder": filepath.Join(root, "encoder-960ms.onnx"), |
| | | "decoder": filepath.Join(root, "decoder-960ms.onnx"), |
| | | "joiner": filepath.Join(root, "joiner-960ms.onnx"), |
| | | "tokens": filepath.Join(root, "tokens.txt"), |
| | | } |
| | | resolved := model.ResolvedModel{ |
| | | ModelID: model.XASRZhEn960ModelID, |
| | | BackendKind: model.BackendXASRStreaming, |
| | | Profile: model.ModelProfile{ |
| | | DisplayName: "X-ASR zh-en 960ms", |
| | | BackendKind: model.BackendXASRStreaming, |
| | | ProviderOrder: []string{"cpu"}, |
| | | NumThreads: 1, |
| | | }, |
| | | Files: files, |
| | | } |
| | | |
| | | config, err := onlineConfigForResolvedModel(resolved, "cpu") |
| | | if err != nil { |
| | | t.Fatal(err) |
| | | } |
| | | if config.ModelConfig.Transducer.Encoder != files["encoder"] { |
| | | t.Fatalf("encoder = %q, want %q", config.ModelConfig.Transducer.Encoder, files["encoder"]) |
| | | } |
| | | if config.ModelConfig.Transducer.Decoder != files["decoder"] { |
| | | t.Fatalf("decoder = %q, want %q", config.ModelConfig.Transducer.Decoder, files["decoder"]) |
| | | } |
| | | if config.ModelConfig.Transducer.Joiner != files["joiner"] { |
| | | t.Fatalf("joiner = %q, want %q", config.ModelConfig.Transducer.Joiner, files["joiner"]) |
| | | } |
| | | if config.ModelConfig.Tokens != files["tokens"] { |
| | | t.Fatalf("tokens = %q, want %q", config.ModelConfig.Tokens, files["tokens"]) |
| | | } |
| | | if config.ModelConfig.ModelType != "zipformer2" { |
| | | t.Fatalf("model type = %q, want zipformer2", config.ModelConfig.ModelType) |
| | | } |
| | | if config.DecodingMethod != "greedy_search" { |
| | | t.Fatalf("decoding method = %q, want greedy_search", config.DecodingMethod) |
| | | } |
| | | } |
| | | |
| | | func TestRememberNonEmptyTextKeepsLastPartial(t *testing.T) { |
| | | got := rememberNonEmptyText("最后一句", " ") |
| | | if got != "最后一句" { |
| | | t.Fatalf("rememberNonEmptyText() = %q, want last non-empty text", got) |
| | | } |
| | | |
| | | got = rememberNonEmptyText("旧内容", "新内容") |
| | | if got != "新内容" { |
| | | t.Fatalf("rememberNonEmptyText() = %q, want new non-empty text", got) |
| | | } |
| | | } |
| | | |
| | | func TestXASRTailPaddingMatchesFlushWindow(t *testing.T) { |
| | | if xasrTailPaddingSamples != 24000 { |
| | | t.Fatalf("tail padding samples = %d, want 24000", xasrTailPaddingSamples) |
| | | } |
| | | if len(xasrTailPadding) != xasrTailPaddingSamples { |
| | | t.Fatalf("tail padding len = %d, want %d", len(xasrTailPadding), xasrTailPaddingSamples) |
| | | } |
| | | } |
| | | |
| | | func TestXASRRealModelSmoke(t *testing.T) { |
| | | if os.Getenv("PRIVATEVOICE_XASR_SMOKE") != "1" { |
| | | t.Skip("set PRIVATEVOICE_XASR_SMOKE=1 to run the real X-ASR model smoke test") |
| | | } |
| | | |
| | | resolved, err := model.ResolveModel(model.XASRZhEn960ModelID) |
| | | if err != nil { |
| | | t.Fatal(err) |
| | | } |
| | | if !resolved.IsUsable() { |
| | | t.Fatalf("x-asr model is not usable: status=%s missing=%v problems=%v", resolved.Status, resolved.Missing, resolved.Problems) |
| | | } |
| | | |
| | | eng, err := NewWithResolvedModel(resolved) |
| | | if err != nil { |
| | | t.Fatal(err) |
| | | } |
| | | defer eng.Close() |
| | | |
| | | text, err := eng.Recognize(make([]float32, 16000)) |
| | | if err != nil { |
| | | t.Fatal(err) |
| | | } |
| | | t.Logf("hardware=%s silence_text=%q", eng.HardwareInfo(), text) |
| | | } |