diff --git a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt index 98c4af6c0..97d2e9a1d 100644 --- a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt +++ b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt @@ -8,10 +8,8 @@ import android.app.Service import android.content.Context import android.content.Intent import android.content.SharedPreferences -import android.content.res.AssetManager import android.os.Build import android.os.IBinder -import android.os.LocaleList import androidx.core.app.NotificationCompat import android.util.Log import kotlinx.coroutines.CoroutineScope @@ -23,9 +21,6 @@ import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.Dispatchers import com.yunqiinnovation.ble_service.BleConst import com.yunqiinnovation.ble_service.BleService -import java.io.IOException -import java.util.Locale -import org.json.JSONObject /** * BLE代理服务 @@ -33,7 +28,6 @@ import org.json.JSONObject * 1. 语音代理初始化和管理 * 2. BLE设备连接管理 * 3. 后台扫描结果处理 - * 4. 自主配置获取和管理 */ class BleMediaService : Service(), CoroutineScope { @@ -54,12 +48,12 @@ class BleMediaService : Service(), CoroutineScope { private const val KEY_MCP_SERVER = "mcpServer" private const val KEY_VOLCANO_APP_ID = "volcanoAppId" private const val KEY_VOLCANO_TOKEN = "volcanoToken" + private const val KEY_SERVER_URL = "serverurl" private const val KEY_USER_TOKEN = "usertoken" private const val KEY_SUPPORTED_LANGUAGES = "supportedLanguages" private const val KEY_MUSICSERVICE_TYPE = "musicServiceType" private const val APP_NAVIGATION_MODE = "navigationMode" - // 用于跟踪服务是否正在运行 private val isRunning = AtomicBoolean(false) @@ -78,6 +72,9 @@ class BleMediaService : Service(), CoroutineScope { // 语音代理是否已初始化 private var isChatAgentInitialized = false + + // 当前启动Intent + private var currentIntent: Intent? = null override fun onCreate() { super.onCreate() @@ -93,6 +90,9 @@ class BleMediaService : Service(), CoroutineScope { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.i(TAG, "BleAgentService.onStartCommand: ${intent?.action}") + // 保存当前Intent,用于后续初始化 + currentIntent = intent + // 初始化语音代理 if (!isChatAgentInitialized) { initializeChatAgent() @@ -113,14 +113,24 @@ class BleMediaService : Service(), CoroutineScope { /** * 初始化语音交互代理 - * 自主获取配置参数,不依赖Flutter层传入 */ private fun initializeChatAgent() { try { - Log.i(TAG, "开始自主获取配置参数...") + // 获取SharedPreferences + val prefs = applicationContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + + // 尝试从Intent中获取参数 + val configFromIntent = extractConfigFromIntent(currentIntent) + + // 如果Intent中有参数,则保存到SharedPreferences + if (configFromIntent.isNotEmpty()) { + Log.d(TAG, "从Intent中获取到配置参数,保存到SharedPreferences") + saveConfigToPreferences(configFromIntent, prefs) + } - // 获取配置参数 - val config = getServiceConfig() + // 合并Intent和SharedPreferences中的参数 + val config = getConfigFromPreferences(prefs) + Log.d(TAG, "当前配置参数: $config") // 检查必要的配置是否存在 val azureSpeechKey = config[KEY_AZURE_SPEECH_KEY]?.toString() ?: "" @@ -128,8 +138,6 @@ class BleMediaService : Service(), CoroutineScope { if (azureSpeechKey.isEmpty() || openaiApiKey.isEmpty()) { Log.w(TAG, "语音代理初始化失败: API密钥未配置") - Log.w(TAG, "Azure Speech Key: ${if (azureSpeechKey.isEmpty()) "未配置" else "已配置"}") - Log.w(TAG, "OpenAI API Key: ${if (openaiApiKey.isEmpty()) "未配置" else "已配置"}") return } @@ -140,7 +148,7 @@ class BleMediaService : Service(), CoroutineScope { if(config.isNotEmpty()) { // 初始化ChatAgent - Log.i(TAG, "开始初始化ChatAgent,配置参数数量: ${config.size}") + Log.i(TAG, "开始初始化ChatAgent") val success = BleAgent.initialize(applicationContext, config) if (success) { isChatAgentInitialized = true @@ -155,145 +163,98 @@ class BleMediaService : Service(), CoroutineScope { } /** - * 自主获取服务配置 - * 从多个源获取配置参数:SharedPreferences、Assets、系统设置等 + * 从Intent中提取配置参数 */ - private fun getServiceConfig(): Map { + private fun extractConfigFromIntent(intent: Intent?): Map { val config = mutableMapOf() - - try { - // 1. 从SharedPreferences获取基础配置 - val prefs = getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) - - // 添加字符串类型的配置参数(使用默认值) - config[KEY_AZURE_SPEECH_KEY] = getConfigString(prefs, KEY_AZURE_SPEECH_KEY, "") - config[KEY_AZURE_SPEECH_REGION] = getConfigString(prefs, KEY_AZURE_SPEECH_REGION, "eastasia") - config[KEY_OPENAI_API_KEY] = getConfigString(prefs, KEY_OPENAI_API_KEY, "") - config[KEY_OPENAI_BASE_URL] = getConfigString(prefs, KEY_OPENAI_BASE_URL, "https://api.openai.com/v1") - config[KEY_OPENAI_MODEL] = getConfigString(prefs, KEY_OPENAI_MODEL, "gpt-3.5-turbo") - config[KEY_OPENAI_VISION_MODEL] = getConfigString(prefs, KEY_OPENAI_VISION_MODEL, "gpt-4-vision-preview") - config[KEY_SYSTEM_PROMPT] = getConfigString(prefs, KEY_SYSTEM_PROMPT, "") - config[KEY_VOLCANO_APP_ID] = getConfigString(prefs, KEY_VOLCANO_APP_ID, "2316081933") - config[KEY_VOLCANO_TOKEN] = getConfigString(prefs, KEY_VOLCANO_TOKEN, "mcJTh6OelBqU_L78lgGd77Nyrc_-5-En") - config[KEY_SERVER_URL] = getConfigString(prefs, KEY_SERVER_URL, "") - config[KEY_USER_TOKEN] = getConfigString(prefs, KEY_USER_TOKEN, "") - config[KEY_MUSICSERVICE_TYPE] = getConfigString(prefs, KEY_MUSICSERVICE_TYPE, "AUTO") - config[APP_NAVIGATION_MODE] = getConfigString(prefs, APP_NAVIGATION_MODE, "external_auto") - - // 2. 从Assets获取MCP配置 - val mcpConfig = loadMcpConfigFromAssets() - if (mcpConfig.isNotEmpty()) { - config[KEY_MCP_SERVER] = mcpConfig - Log.d(TAG, "成功从Assets加载MCP配置") - } else { - Log.w(TAG, "未能从Assets加载MCP配置,使用空配置") - config[KEY_MCP_SERVER] = "{\"mcpServers\":{}}" + intent?.let { + // 提取可能存在的配置参数 + it.getStringExtra(KEY_AZURE_SPEECH_KEY)?.let { value -> config[KEY_AZURE_SPEECH_KEY] = value } + it.getStringExtra(KEY_AZURE_SPEECH_REGION)?.let { value -> config[KEY_AZURE_SPEECH_REGION] = value } + it.getStringExtra(KEY_OPENAI_API_KEY)?.let { value -> config[KEY_OPENAI_API_KEY] = value } + it.getStringExtra(KEY_OPENAI_BASE_URL)?.let { value -> config[KEY_OPENAI_BASE_URL] = value } + it.getStringExtra(KEY_OPENAI_MODEL)?.let { value -> config[KEY_OPENAI_MODEL] = value } + it.getStringExtra(KEY_OPENAI_VISION_MODEL)?.let { value -> config[KEY_OPENAI_VISION_MODEL] = value } + it.getStringExtra(KEY_SYSTEM_PROMPT)?.let { value -> config[KEY_SYSTEM_PROMPT] = value } + it.getStringExtra(KEY_MCP_SERVER)?.let { value -> config[KEY_MCP_SERVER] = value } + it.getStringExtra(KEY_VOLCANO_APP_ID)?.let { value -> config[KEY_VOLCANO_APP_ID] = 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_USER_TOKEN)?.let { value -> config[KEY_USER_TOKEN] = value } + it.getStringExtra(KEY_MUSICSERVICE_TYPE)?.let { value -> config[KEY_MUSICSERVICE_TYPE] = value } + it.getStringExtra(APP_NAVIGATION_MODE)?.let { value -> config[APP_NAVIGATION_MODE] = value } + // 提取 supportedLanguages 参数 + it.getStringArrayListExtra(KEY_SUPPORTED_LANGUAGES)?.let { languages -> + if (languages.isNotEmpty()) { + config[KEY_SUPPORTED_LANGUAGES] = languages + } } - - // 3. 获取系统语言配置 - val supportedLanguages = getSystemSupportedLanguages() - config[KEY_SUPPORTED_LANGUAGES] = supportedLanguages - Log.d(TAG, "系统支持的语言: ${supportedLanguages.joinToString(", ")}") - - Log.d(TAG, "配置获取完成,参数数量: ${config.size}") - - } catch (e: Exception) { - Log.e(TAG, "获取服务配置时发生异常", e) } - + Log.i(TAG, "从Intent中提取到配置参数: $config") return config } /** - * 从Assets目录加载MCP配置文件 + * 将配置参数保存到SharedPreferences */ - private fun loadMcpConfigFromAssets(): String { - return try { - val assetManager: AssetManager = assets - val inputStream = assetManager.open(".mcp.json") - val size = inputStream.available() - val buffer = ByteArray(size) - inputStream.read(buffer) - inputStream.close() - val jsonString = String(buffer, Charsets.UTF_8) - Log.d(TAG, "成功从Assets加载.mcp.json文件") - jsonString - } catch (e: IOException) { - Log.w(TAG, "无法从Assets加载.mcp.json文件: ${e.message}") - // 返回默认的空MCP配置 - "{\"mcpServers\":{}}" + private fun saveConfigToPreferences(config: Map, prefs: SharedPreferences) { + prefs.edit().apply { + config.forEach { (key, value) -> + when (value) { + is String -> { + if (value.isNotEmpty()) { + putString(key, value) + } + } + is List<*> -> { + // 处理 supportedLanguages 列表 + if (key == KEY_SUPPORTED_LANGUAGES) { + val languageList = value.filterIsInstance() + if (languageList.isNotEmpty()) { + // 将语言列表转换为逗号分隔的字符串保存 + putString(key, languageList.joinToString(",")) + } + } + } + } + } + apply() } } /** - * 获取系统支持的语言列表 - * 根据系统当前语言设置动态配置语音识别语言 + * 从SharedPreferences获取配置 */ - private fun getSystemSupportedLanguages(): List { - val supportedLanguages = mutableListOf() - - try { - // 获取系统当前语言设置 - val currentLocale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - LocaleList.getDefault().get(0) - } else { - @Suppress("DEPRECATION") - Locale.getDefault() - } - - val language = currentLocale.language - val country = currentLocale.country - - // 构造Azure Speech SDK需要的语言格式 - when (language) { - "zh" -> { - when (country) { - "CN" -> supportedLanguages.add("zh-CN") - "TW" -> supportedLanguages.add("zh-TW") - "HK" -> supportedLanguages.add("zh-HK") - else -> supportedLanguages.add("zh-CN") // 默认简体中文 - } - } - "en" -> { - when (country) { - "US" -> supportedLanguages.add("en-US") - "GB" -> supportedLanguages.add("en-GB") - "AU" -> supportedLanguages.add("en-AU") - "CA" -> supportedLanguages.add("en-CA") - else -> supportedLanguages.add("en-US") // 默认美式英语 - } - } - "ja" -> supportedLanguages.add("ja-JP") - "ko" -> supportedLanguages.add("ko-KR") - "fr" -> supportedLanguages.add("fr-FR") - "de" -> supportedLanguages.add("de-DE") - "es" -> supportedLanguages.add("es-ES") - "it" -> supportedLanguages.add("it-IT") - "pt" -> supportedLanguages.add("pt-BR") - "ru" -> supportedLanguages.add("ru-RU") - else -> { - // 对于不支持的语言,添加通用格式 - if (country.isNotEmpty()) { - supportedLanguages.add("$language-$country") - } else { - supportedLanguages.add("en-US") // 最终兜底 - } - } - } - - // 确保至少有一个语言 - if (supportedLanguages.isEmpty()) { - supportedLanguages.add("en-US") + private fun getConfigFromPreferences(prefs: SharedPreferences): Map { + val config = mutableMapOf() + + // 添加字符串类型的配置参数 + config[KEY_AZURE_SPEECH_KEY] = getConfigString(prefs, KEY_AZURE_SPEECH_KEY, "") + config[KEY_AZURE_SPEECH_REGION] = getConfigString(prefs, KEY_AZURE_SPEECH_REGION, "eastasia") + config[KEY_OPENAI_API_KEY] = getConfigString(prefs, KEY_OPENAI_API_KEY, "") + config[KEY_OPENAI_BASE_URL] = getConfigString(prefs, KEY_OPENAI_BASE_URL, "https://api.openai.com/v1") + config[KEY_OPENAI_MODEL] = getConfigString(prefs, KEY_OPENAI_MODEL, "gpt-3.5-turbo") + config[KEY_OPENAI_VISION_MODEL] = getConfigString(prefs, KEY_OPENAI_VISION_MODEL, "gpt-4-vision-preview") + config[KEY_SYSTEM_PROMPT] = getConfigString(prefs, KEY_SYSTEM_PROMPT, "gpt-3.5-turbo") + config[KEY_MCP_SERVER] = getConfigString(prefs, KEY_MCP_SERVER, "") + config[KEY_VOLCANO_APP_ID] = getConfigString(prefs, KEY_VOLCANO_APP_ID, "") + 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, "") + config[KEY_MUSICSERVICE_TYPE] = getConfigString(prefs, KEY_MUSICSERVICE_TYPE, "") + config[APP_NAVIGATION_MODE] = getConfigString(prefs, APP_NAVIGATION_MODE, "") + + // 添加 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 } - - Log.d(TAG, "检测到系统语言: $language-$country,配置语音识别语言: ${supportedLanguages.joinToString(", ")}") - - } catch (e: Exception) { - Log.e(TAG, "获取系统语言配置失败,使用默认语言: $e") - supportedLanguages.add("en-US") } - - return supportedLanguages + + return config } /** @@ -317,9 +278,6 @@ class BleMediaService : Service(), CoroutineScope { super.onDestroy() } - /** - * 检查BLE连接状态并尝试连接 - */ private fun checkBleConnection() { Log.i(TAG, "checkBleConnection收到连接请求") @@ -377,4 +335,4 @@ class BleMediaService : Service(), CoroutineScope { return builder.build() } -} \ No newline at end of file +} \ No newline at end of file