From 7eb0b4196ce15c8bfbb0514c54b51cf019c78d24 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Tue, 23 Jun 2026 13:15:33 +0800
Subject: [PATCH] Prepare 2.1.34 input settings QA build

---
 privatevoice.src/internal/model/registry.go |  226 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 219 insertions(+), 7 deletions(-)

diff --git a/privatevoice.src/internal/model/registry.go b/privatevoice.src/internal/model/registry.go
index 8e30239..5da545f 100644
--- a/privatevoice.src/internal/model/registry.go
+++ b/privatevoice.src/internal/model/registry.go
@@ -8,10 +8,23 @@
 const (
 	BackendSenseVoice     = "sensevoice"
 	BackendMoonshine      = "moonshine"
+	BackendTransducer     = "transducer"
 	BackendNemoTransducer = "nemo_transducer"
 	BackendQwen3ASR       = "qwen3_asr"
 	BackendXASRStreaming  = "x_asr_streaming"
 )
+
+var languageProfileOrder = []string{
+	DefaultLanguageID,
+	EnglishLanguageID,
+	FrenchLanguageID,
+	GermanLanguageID,
+	SpanishLanguageID,
+	ItalianLanguageID,
+	PortugueseLanguageID,
+	JapaneseLanguageID,
+	KoreanLanguageID,
+}
 
 var modelProfiles = map[string]ModelProfile{
 	DefaultModelID: {
@@ -132,6 +145,132 @@
 		ProviderOrder: []string{"cpu"},
 		NumThreads:    4,
 	},
+	ParakeetV3ModelID: {
+		ID:          ParakeetV3ModelID,
+		DisplayName: "Parakeet TDT v3",
+		BackendKind: BackendNemoTransducer,
+		Tier:        "default",
+		SupportedLanguageIDs: []string{
+			FrenchLanguageID,
+			GermanLanguageID,
+			SpanishLanguageID,
+			ItalianLanguageID,
+			PortugueseLanguageID,
+		},
+		RecommendedFor: []string{
+			FrenchLanguageID,
+			GermanLanguageID,
+			SpanishLanguageID,
+			ItalianLanguageID,
+			PortugueseLanguageID,
+		},
+		Description: "欧洲多语种离线模型,适合法语、德语、西班牙语、意大利语和葡萄牙语听写。",
+		ApproxSize:  "约 640 MiB 解压后模型目录",
+		DownloadURLs: []string{
+			"https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8.tar.bz2",
+		},
+		InstallDirName: "parakeet-tdt-0.6b-v3",
+		RequiredFiles: []RequiredFileRule{
+			{
+				Role:     "encoder",
+				AllOf:    []string{"encoder.int8.onnx"},
+				Required: true,
+			},
+			{
+				Role:     "decoder",
+				AllOf:    []string{"decoder.int8.onnx"},
+				Required: true,
+			},
+			{
+				Role:     "joiner",
+				AllOf:    []string{"joiner.int8.onnx"},
+				Required: true,
+			},
+			{
+				Role:     "tokens",
+				AllOf:    []string{"tokens.txt"},
+				Required: true,
+			},
+		},
+		ProviderOrder: []string{"cpu"},
+		NumThreads:    2,
+	},
+	JapaneseModelID: {
+		ID:                   JapaneseModelID,
+		DisplayName:          "Zipformer Japanese",
+		BackendKind:          BackendTransducer,
+		Tier:                 "default",
+		SupportedLanguageIDs: []string{JapaneseLanguageID},
+		RecommendedFor:       []string{JapaneseLanguageID},
+		Description:          "日语专项离线模型,基于 ReazonSpeech 日语语料。",
+		ApproxSize:           "约 165 MiB int8 关键模型文件,解压目录包含 fp32 对照文件",
+		DownloadURLs: []string{
+			"https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-zipformer-ja-reazonspeech-2024-08-01.tar.bz2",
+		},
+		InstallDirName: "zipformer-ja-reazonspeech",
+		RequiredFiles: []RequiredFileRule{
+			{
+				Role:     "encoder",
+				AllOf:    []string{"encoder-epoch-99-avg-1.int8.onnx"},
+				Required: true,
+			},
+			{
+				Role:     "decoder",
+				AllOf:    []string{"decoder-epoch-99-avg-1.onnx"},
+				Required: true,
+			},
+			{
+				Role:     "joiner",
+				AllOf:    []string{"joiner-epoch-99-avg-1.int8.onnx"},
+				Required: true,
+			},
+			{
+				Role:     "tokens",
+				AllOf:    []string{"tokens.txt"},
+				Required: true,
+			},
+		},
+		ProviderOrder: []string{"cpu"},
+		NumThreads:    1,
+	},
+	KoreanModelID: {
+		ID:                   KoreanModelID,
+		DisplayName:          "Zipformer Korean",
+		BackendKind:          BackendTransducer,
+		Tier:                 "default",
+		SupportedLanguageIDs: []string{KoreanLanguageID},
+		RecommendedFor:       []string{KoreanLanguageID},
+		Description:          "韩语专项离线模型,适合韩语听写。",
+		ApproxSize:           "约 73 MiB int8 关键模型文件,解压目录包含 fp32 对照文件",
+		DownloadURLs: []string{
+			"https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-zipformer-korean-2024-06-24.tar.bz2",
+		},
+		InstallDirName: "zipformer-ko",
+		RequiredFiles: []RequiredFileRule{
+			{
+				Role:     "encoder",
+				AllOf:    []string{"encoder-epoch-99-avg-1.int8.onnx"},
+				Required: true,
+			},
+			{
+				Role:     "decoder",
+				AllOf:    []string{"decoder-epoch-99-avg-1.onnx"},
+				Required: true,
+			},
+			{
+				Role:     "joiner",
+				AllOf:    []string{"joiner-epoch-99-avg-1.int8.onnx"},
+				Required: true,
+			},
+			{
+				Role:     "tokens",
+				AllOf:    []string{"tokens.txt"},
+				Required: true,
+			},
+		},
+		ProviderOrder: []string{"cpu"},
+		NumThreads:    2,
+	},
 	Qwen3ASRModelID: {
 		ID:                   Qwen3ASRModelID,
 		DisplayName:          "Qwen3-ASR",
@@ -237,6 +376,62 @@
 		DefaultModelID:  MoonshineModelID,
 		UpgradeModelIDs: []string{ParakeetModelID, XASRZhEn960ModelID},
 	},
+	FrenchLanguageID: {
+		ID:             FrenchLanguageID,
+		DisplayName:    "French",
+		NativeName:     "Français",
+		UILocale:       "fr",
+		SystemMatchers: []string{"fr", "fr-FR", "fr-BE", "fr-CA", "fr-CH"},
+		DefaultModelID: ParakeetV3ModelID,
+	},
+	GermanLanguageID: {
+		ID:             GermanLanguageID,
+		DisplayName:    "German",
+		NativeName:     "Deutsch",
+		UILocale:       "de",
+		SystemMatchers: []string{"de", "de-DE", "de-AT", "de-CH"},
+		DefaultModelID: ParakeetV3ModelID,
+	},
+	SpanishLanguageID: {
+		ID:             SpanishLanguageID,
+		DisplayName:    "Spanish",
+		NativeName:     "Español",
+		UILocale:       "es",
+		SystemMatchers: []string{"es", "es-ES", "es-MX", "es-US", "es-AR"},
+		DefaultModelID: ParakeetV3ModelID,
+	},
+	ItalianLanguageID: {
+		ID:             ItalianLanguageID,
+		DisplayName:    "Italian",
+		NativeName:     "Italiano",
+		UILocale:       "it",
+		SystemMatchers: []string{"it", "it-IT", "it-CH"},
+		DefaultModelID: ParakeetV3ModelID,
+	},
+	PortugueseLanguageID: {
+		ID:             PortugueseLanguageID,
+		DisplayName:    "Portuguese",
+		NativeName:     "Português",
+		UILocale:       "pt",
+		SystemMatchers: []string{"pt", "pt-PT", "pt-BR"},
+		DefaultModelID: ParakeetV3ModelID,
+	},
+	JapaneseLanguageID: {
+		ID:             JapaneseLanguageID,
+		DisplayName:    "Japanese",
+		NativeName:     "日本語",
+		UILocale:       "ja",
+		SystemMatchers: []string{"ja", "ja-JP"},
+		DefaultModelID: JapaneseModelID,
+	},
+	KoreanLanguageID: {
+		ID:             KoreanLanguageID,
+		DisplayName:    "Korean",
+		NativeName:     "한국어",
+		UILocale:       "ko",
+		SystemMatchers: []string{"ko", "ko-KR"},
+		DefaultModelID: KoreanModelID,
+	},
 }
 
 func GetModelProfile(id string) (ModelProfile, error) {
@@ -279,21 +474,38 @@
 
 func ListLanguageProfiles() []LanguageProfile {
 	profiles := make([]LanguageProfile, 0, len(languageProfiles))
-	for _, profile := range languageProfiles {
-		profiles = append(profiles, profile)
+	seen := make(map[string]bool, len(languageProfiles))
+	for _, id := range languageProfileOrder {
+		if profile, ok := languageProfiles[id]; ok {
+			profiles = append(profiles, profile)
+			seen[id] = true
+		}
+	}
+	for id, profile := range languageProfiles {
+		if !seen[id] {
+			profiles = append(profiles, profile)
+		}
 	}
 	sort.Slice(profiles, func(i, j int) bool {
-		if profiles[i].ID == DefaultLanguageID {
-			return true
-		}
-		if profiles[j].ID == DefaultLanguageID {
-			return false
+		left := languageOrderIndex(profiles[i].ID)
+		right := languageOrderIndex(profiles[j].ID)
+		if left != right {
+			return left < right
 		}
 		return profiles[i].ID < profiles[j].ID
 	})
 	return profiles
 }
 
+func languageOrderIndex(id string) int {
+	for i, orderedID := range languageProfileOrder {
+		if id == orderedID {
+			return i
+		}
+	}
+	return len(languageProfileOrder)
+}
+
 func NormalizeLanguageID(id string) string {
 	if _, err := GetLanguageProfile(id); err != nil {
 		return DefaultLanguageID

--
Gitblit v1.9.3