From 0ffbf1935c9d091cce22a5583275ac0902f7a693 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Thu, 02 Jul 2026 03:04:51 +0800
Subject: [PATCH] Add Cantonese language model support
---
privatevoice.src/internal/modelselection/selection_test.go | 137 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 137 insertions(+), 0 deletions(-)
diff --git a/privatevoice.src/internal/modelselection/selection_test.go b/privatevoice.src/internal/modelselection/selection_test.go
index db311aa..fe72cad 100644
--- a/privatevoice.src/internal/modelselection/selection_test.go
+++ b/privatevoice.src/internal/modelselection/selection_test.go
@@ -40,6 +40,83 @@
}
}
+func TestResolveManualCantoneseUsesSenseVoiceYueDefault(t *testing.T) {
+ cfg := config.Default()
+ cfg.LanguageMode = config.LanguageModeManual
+ cfg.LanguageID = model.CantoneseLanguageID
+ cfg.ModelSelectionMode = config.ModelSelectionModeAuto
+
+ current := Resolve(cfg, fakeDetector{locale: "en-US"})
+ if current.LanguageSettings.EffectiveLanguageID != model.CantoneseLanguageID {
+ t.Fatalf("effective language = %q, want %q", current.LanguageSettings.EffectiveLanguageID, model.CantoneseLanguageID)
+ }
+ if current.ModelID != model.SenseVoiceYueModelID {
+ t.Fatalf("model id = %q, want %q", current.ModelID, model.SenseVoiceYueModelID)
+ }
+ if current.Profile.BackendKind != model.BackendSenseVoice {
+ t.Fatalf("backend = %q, want %q", current.Profile.BackendKind, model.BackendSenseVoice)
+ }
+}
+
+func TestResolveManualCantoneseRejectsChineseUpgradeModels(t *testing.T) {
+ tests := []string{
+ model.Qwen3ASRModelID,
+ model.XASRZhEn960ModelID,
+ }
+ for _, modelID := range tests {
+ cfg := config.Default()
+ cfg.LanguageMode = config.LanguageModeManual
+ cfg.LanguageID = model.CantoneseLanguageID
+ cfg.ModelSelectionMode = config.ModelSelectionModeManual
+ cfg.SelectedModelID = modelID
+
+ current := Resolve(cfg, fakeDetector{locale: "en-US"})
+ if current.ModelID != model.SenseVoiceYueModelID {
+ t.Fatalf("%s resolved model id = %q, want %q", modelID, current.ModelID, model.SenseVoiceYueModelID)
+ }
+ if current.FallbackReason != "manual model not available for language" {
+ t.Fatalf("%s fallback reason = %q, want language incompatibility", modelID, current.FallbackReason)
+ }
+ }
+}
+
+func TestResolveAutoUsesEuropeanDefaultModel(t *testing.T) {
+ cfg := config.Default()
+ cfg.LanguageMode = config.LanguageModeAuto
+ cfg.ModelSelectionMode = config.ModelSelectionModeAuto
+
+ current := Resolve(cfg, fakeDetector{locale: "fr-FR"})
+ if current.ModelID != model.ParakeetV3ModelID {
+ t.Fatalf("model id = %q, want %q", current.ModelID, model.ParakeetV3ModelID)
+ }
+ if current.Profile.BackendKind != model.BackendNemoTransducer {
+ t.Fatalf("backend = %q, want %q", current.Profile.BackendKind, model.BackendNemoTransducer)
+ }
+}
+
+func TestResolveAutoUsesJapaneseAndKoreanDefaults(t *testing.T) {
+ tests := []struct {
+ locale string
+ modelID string
+ }{
+ {"ja-JP", model.JapaneseModelID},
+ {"ko-KR", model.KoreanModelID},
+ }
+ for _, tt := range tests {
+ cfg := config.Default()
+ cfg.LanguageMode = config.LanguageModeAuto
+ cfg.ModelSelectionMode = config.ModelSelectionModeAuto
+
+ current := Resolve(cfg, fakeDetector{locale: tt.locale})
+ if current.ModelID != tt.modelID {
+ t.Fatalf("%s model id = %q, want %q", tt.locale, current.ModelID, tt.modelID)
+ }
+ if current.Profile.BackendKind != model.BackendTransducer {
+ t.Fatalf("%s backend = %q, want %q", tt.locale, current.Profile.BackendKind, model.BackendTransducer)
+ }
+ }
+}
+
func TestResolveOldConfigMissingSelectionModeUsesAuto(t *testing.T) {
cfg := config.Default()
cfg.LanguageMode = config.LanguageModeAuto
@@ -68,6 +145,9 @@
}
func TestResolveManualUsesQwen3ASRForChinese(t *testing.T) {
+ if !model.IsModelSupportedInCurrentBuild(model.Qwen3ASRModelID) {
+ t.Skip("qwen3-asr is disabled in this build")
+ }
cfg := config.Default()
cfg.LanguageMode = config.LanguageModeAuto
cfg.ModelSelectionMode = config.ModelSelectionModeManual
@@ -76,6 +156,48 @@
current := Resolve(cfg, fakeDetector{locale: "zh-CN"})
if current.ModelID != model.Qwen3ASRModelID {
t.Fatalf("model id = %q, want manual selected %q", current.ModelID, model.Qwen3ASRModelID)
+ }
+}
+
+func TestResolveManualQwen3ASRFallsBackWhenUnsupported(t *testing.T) {
+ if model.IsModelSupportedInCurrentBuild(model.Qwen3ASRModelID) {
+ t.Skip("qwen3-asr is supported in this build")
+ }
+ cfg := config.Default()
+ cfg.LanguageMode = config.LanguageModeAuto
+ cfg.ModelSelectionMode = config.ModelSelectionModeManual
+ cfg.SelectedModelID = model.Qwen3ASRModelID
+
+ current := Resolve(cfg, fakeDetector{locale: "zh-CN"})
+ if current.ModelID != model.DefaultModelID {
+ t.Fatalf("model id = %q, want fallback %q", current.ModelID, model.DefaultModelID)
+ }
+ if current.FallbackReason != "manual model not supported in current build" {
+ t.Fatalf("fallback reason = %q, want unsupported build reason", current.FallbackReason)
+ }
+}
+
+func TestResolveManualUsesXASRForChinese(t *testing.T) {
+ cfg := config.Default()
+ cfg.LanguageMode = config.LanguageModeAuto
+ cfg.ModelSelectionMode = config.ModelSelectionModeManual
+ cfg.SelectedModelID = model.XASRZhEn960ModelID
+
+ current := Resolve(cfg, fakeDetector{locale: "zh-CN"})
+ if current.ModelID != model.XASRZhEn960ModelID {
+ t.Fatalf("model id = %q, want manual selected %q", current.ModelID, model.XASRZhEn960ModelID)
+ }
+}
+
+func TestResolveManualUsesXASRForEnglish(t *testing.T) {
+ cfg := config.Default()
+ cfg.LanguageMode = config.LanguageModeAuto
+ cfg.ModelSelectionMode = config.ModelSelectionModeManual
+ cfg.SelectedModelID = model.XASRZhEn960ModelID
+
+ current := Resolve(cfg, fakeDetector{locale: "en-US"})
+ if current.ModelID != model.XASRZhEn960ModelID {
+ t.Fatalf("model id = %q, want manual selected %q", current.ModelID, model.XASRZhEn960ModelID)
}
}
@@ -109,6 +231,21 @@
}
}
+func TestResolveManualParakeetV3FallsBackForJapanese(t *testing.T) {
+ cfg := config.Default()
+ cfg.LanguageMode = config.LanguageModeAuto
+ cfg.ModelSelectionMode = config.ModelSelectionModeManual
+ cfg.SelectedModelID = model.ParakeetV3ModelID
+
+ current := Resolve(cfg, fakeDetector{locale: "ja-JP"})
+ if current.ModelID != model.JapaneseModelID {
+ t.Fatalf("model id = %q, want Japanese default %q", current.ModelID, model.JapaneseModelID)
+ }
+ if current.FallbackReason == "" {
+ t.Fatal("expected fallback reason")
+ }
+}
+
func TestResolveInvalidManualFallsBackToLanguageDefault(t *testing.T) {
cfg := config.Default()
cfg.LanguageMode = config.LanguageModeAuto
--
Gitblit v1.9.3