Browse Source

1

newdev_shunjiawei
fdp 1 year ago
parent
commit
f9f4e665d0
  1. 240
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt

240
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<String, Any> {
private fun extractConfigFromIntent(intent: Intent?): Map<String, Any> {
val config = mutableMapOf<String, Any>()
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<String, Any>, 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<String>()
if (languageList.isNotEmpty()) {
// 将语言列表转换为逗号分隔的字符串保存
putString(key, languageList.joinToString(","))
}
}
}
}
}
apply()
}
}
/**
* 获取系统支持的语言列表
* 根据系统当前语言设置动态配置语音识别语言
* 从SharedPreferences获取配置
*/
private fun getSystemSupportedLanguages(): List<String> {
val supportedLanguages = mutableListOf<String>()
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<String, Any> {
val config = mutableMapOf<String, Any>()
// 添加字符串类型的配置参数
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()
}
}
}
Loading…
Cancel
Save