diff --git a/lib/data/models/user_Info.dart b/lib/data/models/user_Info.dart index 2fb4dc20b..6d64c1533 100644 --- a/lib/data/models/user_Info.dart +++ b/lib/data/models/user_Info.dart @@ -112,7 +112,7 @@ class User { ); _instance = u; Logger.i("User", - "初始化用户: uid=${u.uid}, name=${u.name}, viplv=${u.viplv}, vipexptime=${u.vipexptime}, ai聊天=${u.aichatintegral}/${u.aichattotalintegral}, 翻译=${u.tradeintegral}/${u.tradetotalintegral}, 会议=${u.meetintegral}/${u.meettotalintegral}"); + "初始化用户: uid=${u.uid}, name=${u.name}, gender=${u.gender}, viplv=${u.viplv}, vipexptime=${u.vipexptime}, ai聊天=${u.aichatintegral}/${u.aichattotalintegral}, 翻译=${u.tradeintegral}/${u.tradetotalintegral}, 会议=${u.meetintegral}/${u.meettotalintegral}"); return u; } @@ -149,7 +149,7 @@ class User { ); _instance = u; Logger.i("User", - "初始化用户(token): uid=${u.uid}, name=${u.name}, viplv=${u.viplv}, vipexptime=${u.vipexptime}, ai聊天=${u.aichatintegral}/${u.aichattotalintegral}, 翻译=${u.tradeintegral}/${u.tradetotalintegral}, 会议=${u.meetintegral}/${u.meettotalintegral}"); + "初始化用户(token): uid=${u.uid}, name=${u.name}, gender=${u.gender}, viplv=${u.viplv}, vipexptime=${u.vipexptime}, ai聊天=${u.aichatintegral}/${u.aichattotalintegral}, 翻译=${u.tradeintegral}/${u.tradetotalintegral}, 会议=${u.meetintegral}/${u.meettotalintegral}"); return u; } diff --git a/lib/data/services/language_manager.dart b/lib/data/services/language_manager.dart index 5abcdad97..648eafb96 100644 --- a/lib/data/services/language_manager.dart +++ b/lib/data/services/language_manager.dart @@ -534,14 +534,24 @@ class LanguageManager extends GetxService { return languageInfo?.shortCode; } + /// 根据 shortCode 获取性别适配的 TTS 音色(用于 findBestMatchingProvider) + String? _getGenderAwareTtsCode(String shortCode) { + final asrCode = _shortCodeToAsrCodeMap[shortCode]; + if (asrCode == null) return null; + return _getVoiceByGender(_languageMap[asrCode]); + } + /// 根据用户性别获取对应的 TTS 语音名称 /// gender: 0=未设置(默认女声), 1=男, 2=女 String? _getVoiceByGender(LanguageInfo? info) { if (info == null) return null; try { final gender = User.instance.gender; - return gender == 1 ? info.ttsVoiceNameMale : info.ttsVoiceName; + final voice = gender == 1 ? info.ttsVoiceNameMale : info.ttsVoiceName; + Logger.debug('TTS音色选择: gender=$gender, voice=$voice'); + return voice; } catch (_) { + Logger.debug('TTS音色选择: 用户未初始化,使用默认女声'); return info.ttsVoiceName; } } @@ -662,27 +672,31 @@ class LanguageManager extends GetxService { for (final spec in ttsSpecs) { if (spec['shortCode'] == sourceShortCode) { - sourceTransSpec["ttsCode"] = spec["ttsVoiceName"]!; + sourceTransSpec["ttsCode"] = + _getGenderAwareTtsCode(spec['shortCode']!) ?? spec["ttsVoiceName"]!; } if (spec['shortCode'] == targetShortCode) { - targetTransSpec["ttsCode"] = spec["ttsVoiceName"]!; + targetTransSpec["ttsCode"] = + _getGenderAwareTtsCode(spec['shortCode']!) ?? spec["ttsVoiceName"]!; } } } else if (provider == SpeechServiceType.alibaba) { final ttsSpecs = _getTtsSpecs(provider); for (final spec in ttsSpecs) { if (spec['shortCode'] == sourceShortCode) { - sourceTransSpec["ttsCode"] = spec["ttsVoiceName"]!; + sourceTransSpec["ttsCode"] = + _getGenderAwareTtsCode(spec['shortCode']!) ?? spec["ttsVoiceName"]!; } if (spec['shortCode'] == targetShortCode) { - targetTransSpec["ttsCode"] = spec["ttsVoiceName"]!; + targetTransSpec["ttsCode"] = + _getGenderAwareTtsCode(spec['shortCode']!) ?? spec["ttsVoiceName"]!; } } } final providerString = _providerStringFromType(provider); Logger.info( - 'Found best provider: $providerString for $sourceShortCode -> $targetShortCode'); + 'Found best provider: $providerString for $sourceShortCode -> $targetShortCode, sourceTts=${sourceTransSpec["ttsCode"]}, targetTts=${targetTransSpec["ttsCode"]}'); return BestProviderResult( providerString, sourceTransSpec, targetTransSpec); } diff --git a/lib/modules/profile/controllers/profile_controller.dart b/lib/modules/profile/controllers/profile_controller.dart index fc21eccbd..7d73f5bbe 100644 --- a/lib/modules/profile/controllers/profile_controller.dart +++ b/lib/modules/profile/controllers/profile_controller.dart @@ -261,6 +261,9 @@ class ProfileController extends GetxController { if (u != null) { u.name = response['name'] ?? u.name; u.avatar = response['avatar'] ?? u.avatar; + if (response['gender'] != null) { + u.gender = response['gender'] as int? ?? u.gender; + } } }); diff --git a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureTtsHelper.kt b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureTtsHelper.kt index 8bd155e6f..1578fa6d9 100644 --- a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureTtsHelper.kt +++ b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureTtsHelper.kt @@ -418,8 +418,9 @@ class AzureTtsHelper(private val context: Context) : ITtsService { private fun warmupSynthesizer() { try { // 使用极短文本进行预热 + val lang = getLanguageFromVoice(currentVoice) val warmupSsml = """ - + . @@ -500,11 +501,12 @@ class AzureTtsHelper(private val context: Context) : ITtsService { } // 4. 构造简化的SSML文档,减少嵌套层级 + val lang = getLanguageFromVoice(currentVoice) return """ + xml:lang="$lang"> @@ -516,6 +518,14 @@ class AzureTtsHelper(private val context: Context) : ITtsService { """.trimIndent() } + /** + * 从语音名称中提取语言代码,如 "tr-TR-AhmetNeural" -> "tr-TR" + */ + private fun getLanguageFromVoice(voiceName: String): String { + val parts = voiceName.split("-") + return if (parts.size >= 2) "${parts[0]}-${parts[1]}" else DEFAULT_LANGUAGE + } + /** * 生成优化的SSML(减少复杂度提升速度) */ @@ -530,9 +540,11 @@ class AzureTtsHelper(private val context: Context) : ITtsService { .replace(Regex("[😀-🟿]+"), "") // 简化表情符号移除 .trim() + val currentLanguage = getLanguageFromVoice(currentVoice) + if(enableVoiceFlocking) { return """ - + $processedText @@ -542,7 +554,7 @@ class AzureTtsHelper(private val context: Context) : ITtsService { """.trimIndent() } else { return """ - + $processedText