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 |   61 ++++++++++++++++++++++++++++++
 1 files changed, 61 insertions(+), 0 deletions(-)

diff --git a/privatevoice.src/internal/modelselection/selection_test.go b/privatevoice.src/internal/modelselection/selection_test.go
index 96875d9..fe72cad 100644
--- a/privatevoice.src/internal/modelselection/selection_test.go
+++ b/privatevoice.src/internal/modelselection/selection_test.go
@@ -40,6 +40,46 @@
 	}
 }
 
+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
@@ -105,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
@@ -116,6 +159,24 @@
 	}
 }
 
+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

--
Gitblit v1.9.3