Browse Source

refactor(语音识别): 重构语音识别语言配置逻辑

将语音识别语言配置从AgentController移至BleManager统一处理
移除废弃的setSupportedLanguages方法,改为通过服务启动参数传递
优化Android端对supportedLanguages参数的处理和存储
weicu
lxm 1 year ago
parent
commit
4bcdcc9fbf
  1. 36
      lib/data/services/ble_manager.dart
  2. 44
      lib/modules/agent/controllers/agent_controller.dart
  3. 13
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentServicePlugin.kt
  4. 80
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt
  5. 15
      local_plugins/agent_service/lib/agent_service.dart

36
lib/data/services/ble_manager.dart

@ -549,6 +549,40 @@ class BleManager extends GetxService {
// 从Flutter资源包中加载.mcp.json // 从Flutter资源包中加载.mcp.json
final jsonData = AppConfig.mcpConfig(); final jsonData = AppConfig.mcpConfig();
// 根据APP语言动态配置语音识别语言
List<String> supportedLanguages = [];
try {
// 使用 GetX 获取 APP 当前语言环境 (Locale)
final appLocale = Get.locale;
if (appLocale != null) {
final lang = appLocale.languageCode; // e.g., 'en'
final country = appLocale.countryCode; // e.g., 'US'
// 构造 Azure SDK 需要的格式 (e.g., 'en-US')
if (country != null && country.isNotEmpty) {
supportedLanguages.add('$lang-$country');
} else {
supportedLanguages.add(lang); // fallback only language code
}
}
// 添加 en-US 作为备选
if (!supportedLanguages.contains('en-US')) {
supportedLanguages.add('en-US');
}
// 最终兜底
if (supportedLanguages.isEmpty) {
supportedLanguages.add('en-US');
}
Logger.info('动态配置语音识别语言: ${supportedLanguages.join(', ')}');
} catch (e) {
Logger.error('获取APP语言配置失败,使用默认语言: $e');
supportedLanguages = ['zh-CN', 'en-US'];
}
final config = <String, dynamic>{ final config = <String, dynamic>{
// 语音代理配置参数 // 语音代理配置参数
'azureSpeechKey': azureSpeechKey, 'azureSpeechKey': azureSpeechKey,
@ -563,7 +597,7 @@ class BleManager extends GetxService {
'volcanoToken': 'mcJTh6OelBqU_L78lgGd77Nyrc_-5-En', 'volcanoToken': 'mcJTh6OelBqU_L78lgGd77Nyrc_-5-En',
'serverurl': serverurl, 'serverurl': serverurl,
'usertoken': jsonString, 'usertoken': jsonString,
'supportedLanguages': ['zh-CN'], 'supportedLanguages': supportedLanguages,
}; };
// 记录日志(不记录敏感信息) // 记录日志(不记录敏感信息)

44
lib/modules/agent/controllers/agent_controller.dart

@ -153,7 +153,7 @@ class AgentController extends GetxController {
_setupMediaSessionCallbacks(); //设置媒体会话回调 _setupMediaSessionCallbacks(); //设置媒体会话回调
_setupTextInputListener(); //设置文本输入监听器 _setupTextInputListener(); //设置文本输入监听器
_configureSpeechRecognitionLanguages(); //配置语音识别语言
startVoiceInput(); //开启语音输入 startVoiceInput(); //开启语音输入
} }
@ -1013,49 +1013,7 @@ class AgentController extends GetxController {
} }
} }
//根据APP语言配置语音识别语言
Future<void> _configureSpeechRecognitionLanguages() async {
try {
// 1. 使用 GetX 获取 APP 当前语言环境 (Locale)
final appLocale = Get.locale;
List<String> languagesToSupport = [];
if (appLocale != null) {
final lang = appLocale.languageCode; // e.g., 'en'
final country = appLocale.countryCode; // e.g., 'US'
// 2. 构造 Azure SDK 需要的格式 (e.g., 'en-US')
if (country != null && country.isNotEmpty) {
languagesToSupport.add('$lang-$country');
} else {
languagesToSupport.add(lang); // fallback only language code
}
}
// 3. 添加 en-US 作为备选
if (!languagesToSupport.contains('en-US')) {
languagesToSupport.add('en-US');
}
// 4. 最终兜底
if (languagesToSupport.isEmpty) {
languagesToSupport.add('en-US');
}
// 5. 调用原生设置
Logger.i(TAG, '支持的语言: ${languagesToSupport.join(', ')}');
AgentService.setSupportedLanguages(languagesToSupport).then((success) {
if (success) {
Logger.i(TAG, 'asr的语言已根据 APP 设置语言: ${languagesToSupport.join(', ')}');
} else {
Logger.w(TAG, '根据 APP 设置asr语言失败');
}
});
} catch (e) {
Logger.e(TAG, "获取 APP 语言并设置失败: $e");
AgentService.setSupportedLanguages(['zh-CN', 'en-US']);
}
}
// 开始语音输入 // 开始语音输入
Future<void> startVoiceInput() async { Future<void> startVoiceInput() async {

13
local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentServicePlugin.kt

@ -74,6 +74,19 @@ class AgentServicePlugin : FlutterPlugin, MethodCallHandler, EventChannel.Stream
config["serverurl"]?.toString()?.let { intent.putExtra("serverurl", it) } config["serverurl"]?.toString()?.let { intent.putExtra("serverurl", it) }
config["usertoken"]?.toString()?.let { intent.putExtra("usertoken", it) } config["usertoken"]?.toString()?.let { intent.putExtra("usertoken", it) }
// 添加 supportedLanguages 参数处理
config["supportedLanguages"]?.let { languages ->
when (languages) {
is List<*> -> {
// 将 List<String> 转换为 ArrayList<String> 以便传递给 Intent
val languageList = languages.filterIsInstance<String>()
if (languageList.isNotEmpty()) {
intent.putStringArrayListExtra("supportedLanguages", ArrayList(languageList))
}
}
}
}
// 启动前台服务 // 启动前台服务
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

80
local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt

@ -51,6 +51,7 @@ class BleMediaService : Service(), CoroutineScope {
private const val KEY_SERVER_URL = "serverurl" private const val KEY_SERVER_URL = "serverurl"
private const val KEY_USER_TOKEN = "usertoken" private const val KEY_USER_TOKEN = "usertoken"
private const val KEY_SUPPORTED_LANGUAGES = "supportedLanguages"
// 用于跟踪服务是否正在运行 // 用于跟踪服务是否正在运行
private val isRunning = AtomicBoolean(false) private val isRunning = AtomicBoolean(false)
@ -130,7 +131,10 @@ class BleMediaService : Service(), CoroutineScope {
Log.d(TAG, "当前配置参数: $config") Log.d(TAG, "当前配置参数: $config")
// 检查必要的配置是否存在 // 检查必要的配置是否存在
if (config[KEY_AZURE_SPEECH_KEY].isNullOrEmpty() || config[KEY_OPENAI_API_KEY].isNullOrEmpty()) { val azureSpeechKey = config[KEY_AZURE_SPEECH_KEY]?.toString() ?: ""
val openaiApiKey = config[KEY_OPENAI_API_KEY]?.toString() ?: ""
if (azureSpeechKey.isEmpty() || openaiApiKey.isEmpty()) {
Log.w(TAG, "语音代理初始化失败: API密钥未配置") Log.w(TAG, "语音代理初始化失败: API密钥未配置")
return return
} }
@ -159,8 +163,8 @@ class BleMediaService : Service(), CoroutineScope {
/** /**
* 从Intent中提取配置参数 * 从Intent中提取配置参数
*/ */
private fun extractConfigFromIntent(intent: Intent?): Map<String, String> { private fun extractConfigFromIntent(intent: Intent?): Map<String, Any> {
val config = mutableMapOf<String, String>() val config = mutableMapOf<String, Any>()
intent?.let { intent?.let {
// 提取可能存在的配置参数 // 提取可能存在的配置参数
it.getStringExtra(KEY_AZURE_SPEECH_KEY)?.let { value -> config[KEY_AZURE_SPEECH_KEY] = value } it.getStringExtra(KEY_AZURE_SPEECH_KEY)?.let { value -> config[KEY_AZURE_SPEECH_KEY] = value }
@ -175,6 +179,13 @@ class BleMediaService : Service(), CoroutineScope {
it.getStringExtra(KEY_VOLCANO_TOKEN)?.let { value -> config[KEY_VOLCANO_TOKEN] = value } it.getStringExtra(KEY_VOLCANO_TOKEN)?.let { value -> config[KEY_VOLCANO_TOKEN] = value }
it.getStringExtra(KEY_SERVER_URL)?.let { value -> config[KEY_SERVER_URL] = value } it.getStringExtra(KEY_SERVER_URL)?.let { value -> config[KEY_SERVER_URL] = value }
it.getStringExtra(KEY_USER_TOKEN)?.let { value -> config[KEY_USER_TOKEN] = value } it.getStringExtra(KEY_USER_TOKEN)?.let { value -> config[KEY_USER_TOKEN] = value }
// 提取 supportedLanguages 参数
it.getStringArrayListExtra(KEY_SUPPORTED_LANGUAGES)?.let { languages ->
if (languages.isNotEmpty()) {
config[KEY_SUPPORTED_LANGUAGES] = languages
}
}
} }
Log.i(TAG, "从Intent中提取到配置参数: $config") Log.i(TAG, "从Intent中提取到配置参数: $config")
return config return config
@ -183,11 +194,25 @@ class BleMediaService : Service(), CoroutineScope {
/** /**
* 将配置参数保存到SharedPreferences * 将配置参数保存到SharedPreferences
*/ */
private fun saveConfigToPreferences(config: Map<String, String>, prefs: SharedPreferences) { private fun saveConfigToPreferences(config: Map<String, Any>, prefs: SharedPreferences) {
prefs.edit().apply { prefs.edit().apply {
config.forEach { (key, value) -> config.forEach { (key, value) ->
if (value.isNotEmpty()) { when (value) {
putString(key, value) is String -> {
if (value.isNotEmpty()) {
putString(key, value)
}
}
is List<*> -> {
// 处理 supportedLanguages 列表
if (key == KEY_SUPPORTED_LANGUAGES) {
val languageList = value.filterIsInstance<String>()
if (languageList.isNotEmpty()) {
// 将语言列表转换为逗号分隔的字符串保存
putString(key, languageList.joinToString(","))
}
}
}
} }
} }
apply() apply()
@ -197,21 +222,34 @@ class BleMediaService : Service(), CoroutineScope {
/** /**
* 从SharedPreferences获取配置 * 从SharedPreferences获取配置
*/ */
private fun getConfigFromPreferences(prefs: SharedPreferences): Map<String, String> { private fun getConfigFromPreferences(prefs: SharedPreferences): Map<String, Any> {
return mapOf( val config = mutableMapOf<String, Any>()
KEY_AZURE_SPEECH_KEY to getConfigString(prefs, KEY_AZURE_SPEECH_KEY, ""),
KEY_AZURE_SPEECH_REGION to getConfigString(prefs, KEY_AZURE_SPEECH_REGION, "eastasia"), // 添加字符串类型的配置参数
KEY_OPENAI_API_KEY to getConfigString(prefs, KEY_OPENAI_API_KEY, ""), config[KEY_AZURE_SPEECH_KEY] = getConfigString(prefs, KEY_AZURE_SPEECH_KEY, "")
KEY_OPENAI_BASE_URL to getConfigString(prefs, KEY_OPENAI_BASE_URL, "https://api.openai.com/v1"), config[KEY_AZURE_SPEECH_REGION] = getConfigString(prefs, KEY_AZURE_SPEECH_REGION, "eastasia")
KEY_OPENAI_MODEL to getConfigString(prefs, KEY_OPENAI_MODEL, "gpt-3.5-turbo"), config[KEY_OPENAI_API_KEY] = getConfigString(prefs, KEY_OPENAI_API_KEY, "")
KEY_OPENAI_VISION_MODEL to getConfigString(prefs, KEY_OPENAI_VISION_MODEL, "gpt-4-vision-preview"), config[KEY_OPENAI_BASE_URL] = getConfigString(prefs, KEY_OPENAI_BASE_URL, "https://api.openai.com/v1")
KEY_SYSTEM_PROMPT to getConfigString(prefs, KEY_SYSTEM_PROMPT, "gpt-3.5-turbo"), config[KEY_OPENAI_MODEL] = getConfigString(prefs, KEY_OPENAI_MODEL, "gpt-3.5-turbo")
KEY_MCP_SERVER to getConfigString(prefs, KEY_MCP_SERVER, ""), config[KEY_OPENAI_VISION_MODEL] = getConfigString(prefs, KEY_OPENAI_VISION_MODEL, "gpt-4-vision-preview")
KEY_VOLCANO_APP_ID to getConfigString(prefs, KEY_VOLCANO_APP_ID, ""), config[KEY_SYSTEM_PROMPT] = getConfigString(prefs, KEY_SYSTEM_PROMPT, "gpt-3.5-turbo")
KEY_VOLCANO_TOKEN to getConfigString(prefs, KEY_VOLCANO_TOKEN, ""), config[KEY_MCP_SERVER] = getConfigString(prefs, KEY_MCP_SERVER, "")
KEY_SERVER_URL to getConfigString(prefs, KEY_SERVER_URL, ""), config[KEY_VOLCANO_APP_ID] = getConfigString(prefs, KEY_VOLCANO_APP_ID, "")
KEY_USER_TOKEN to getConfigString(prefs, KEY_USER_TOKEN, "") config[KEY_VOLCANO_TOKEN] = getConfigString(prefs, KEY_VOLCANO_TOKEN, "")
) config[KEY_SERVER_URL] = getConfigString(prefs, KEY_SERVER_URL, "")
config[KEY_USER_TOKEN] = getConfigString(prefs, KEY_USER_TOKEN, "")
// 添加 supportedLanguages 参数处理
val supportedLanguagesStr = getConfigString(prefs, KEY_SUPPORTED_LANGUAGES, "")
if (supportedLanguagesStr.isNotEmpty()) {
// 将逗号分隔的字符串转换回语言列表
val languageList = supportedLanguagesStr.split(",").map { it.trim() }.filter { it.isNotEmpty() }
if (languageList.isNotEmpty()) {
config[KEY_SUPPORTED_LANGUAGES] = languageList
}
}
return config
} }
/** /**

15
local_plugins/agent_service/lib/agent_service.dart

@ -332,20 +332,7 @@ class AgentService {
} }
} }
/// 设置支持的语音识别语言
///
/// [languages] 支持的语言列表,如 ['zh-CN', 'en-US']
/// 返回是否设置成功
static Future<bool> setSupportedLanguages(List<String> languages) async {
try {
final bool result = await _channel.invokeMethod('setSupportedLanguages', {
'languages': languages,
});
return result;
} on PlatformException catch (e) {
throw AgentServiceException(e.code, e.message ?? '设置支持语言失败', e.details);
}
}
/// 停止语音合成 /// 停止语音合成
static Future<bool> stopAiSteam() async { static Future<bool> stopAiSteam() async {

Loading…
Cancel
Save