diff --git a/a b/a
deleted file mode 100644
index 7133736ae..000000000
--- a/a
+++ /dev/null
@@ -1,18 +0,0 @@
-curl 'https://ark.cn-beijing.volces.com/api/v3/bots/chat/completions' \
--H "Authorization: Bearer 168deb3d-fd0c-4912-b9f1-aaee5c6743e6" \
--H 'Content-Type: application/json' \
--d '{
- "model": "bot-20250405211523-l7c9r",
- "stream": true,
- "stream_options": {"include_usage": true},
- "messages": [
- {
- "role": "system",
- "content": "You are a helpful assistant."
- },
- {
- "role": "user",
- "content": "Hello!"
- }
- ]
-}'
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index f120cc1f7..23c380fb0 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -27,6 +27,15 @@
+
+
+
+
+
+
+
+
= Build.VERSION_CODES.S) {
+ arrayOf(
+ Manifest.permission.RECORD_AUDIO,
+ Manifest.permission.BLUETOOTH_CONNECT,
+ Manifest.permission.BLUETOOTH_SCAN,
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.SEND_SMS,
+ Manifest.permission.READ_CONTACTS,
+ Manifest.permission.CALL_PHONE,
+ Manifest.permission.POST_NOTIFICATIONS
+ )
+ } else {
+ arrayOf(
+ Manifest.permission.RECORD_AUDIO,
+ Manifest.permission.BLUETOOTH,
+ Manifest.permission.BLUETOOTH_ADMIN,
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.SEND_SMS,
+ Manifest.permission.READ_CONTACTS,
+ Manifest.permission.CALL_PHONE
+ )
+ }
+
// 广播接收器
private val voiceInteractionReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
- Log.d(TAG, "收到广播: ${intent?.action}")
+ FileLogger.d(TAG, "收到广播: ${intent?.action}")
when (intent?.action) {
VoiceInteractionService.ACTION_RECOGNITION_STARTED -> {
val timestamp = intent.getLongExtra("timestamp", 0)
- Log.d(TAG, "收到语音识别启动广播: timestamp=$timestamp")
sendVoiceInteractionEvent(mapOf(
"type" to "recognition_started",
"timestamp" to timestamp
@@ -54,6 +82,12 @@ class MainActivity: FlutterActivity() {
sendChatHistoryEvent(agentId, userMessage, assistantMessage, timestamp)
}
+ VoiceInteractionService.ACTION_ENTER_TRANSLATION_MODE -> {
+ sendVoiceInteractionEvent(mapOf(
+ "type" to "enter_translation_mode",
+ "timestamp" to System.currentTimeMillis()
+ ))
+ }
}
}
}
@@ -249,6 +283,9 @@ class MainActivity: FlutterActivity() {
// 初始化 FileLogger
FileLogger.init(applicationContext)
+ // 请求必要权限
+ requestRequiredPermissions()
+
// 初始化 Azure 语音服务
classicBluetoothHelper = ClassicBluetoothHelper(applicationContext)
@@ -267,7 +304,14 @@ class MainActivity: FlutterActivity() {
val voiceInteractionFilter = IntentFilter().apply {
addAction(VoiceInteractionService.ACTION_RECOGNITION_STARTED)
addAction(VoiceInteractionService.ACTION_CHAT_HISTORY_UPDATED)
+ addAction(VoiceInteractionService.ACTION_ENTER_TRANSLATION_MODE)
}
+
+ // 打印已注册的广播
+ FileLogger.d(TAG, "已注册语音交互广播:${VoiceInteractionService.ACTION_RECOGNITION_STARTED}, " +
+ "${VoiceInteractionService.ACTION_CHAT_HISTORY_UPDATED}, " +
+ "${VoiceInteractionService.ACTION_ENTER_TRANSLATION_MODE}")
+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
registerReceiver(voiceInteractionReceiver, voiceInteractionFilter, Context.RECEIVER_NOT_EXPORTED)
} else {
@@ -550,14 +594,19 @@ class MainActivity: FlutterActivity() {
private fun sendVoiceInteractionEvent(event: Map) {
if (voiceInteractionEventSink == null) {
Log.e(TAG, "无法发送语音交互事件:事件通道未准备好")
+ FileLogger.e(TAG, "无法发送语音交互事件:事件通道未准备好")
return
}
+ FileLogger.d(TAG, "准备发送事件到Flutter: ${event["type"]}")
+
runOnUiThread {
try {
voiceInteractionEventSink?.success(event)
+ FileLogger.d(TAG, "成功发送事件到Flutter: ${event["type"]}")
} catch (e: Exception) {
- Log.e(TAG, "发送语音交互事件到Flutter失败: ${e.message}", e)
+ Log.e(TAG, "发送语音交互事件到Flutter失败: ${e.message}")
+ FileLogger.e(TAG, "发送语音交互事件到Flutter失败: ${e.message}")
}
}
}
@@ -598,5 +647,54 @@ class MainActivity: FlutterActivity() {
super.onDestroy()
}
+
+ /**
+ * 请求必要权限
+ */
+ private fun requestRequiredPermissions() {
+ val permissionsToRequest = ArrayList()
+
+ for (permission in REQUIRED_PERMISSIONS) {
+ if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
+ permissionsToRequest.add(permission)
+ }
+ }
+
+ if (permissionsToRequest.isNotEmpty()) {
+ ActivityCompat.requestPermissions(
+ this,
+ permissionsToRequest.toTypedArray(),
+ PERMISSION_REQUEST_CODE
+ )
+ }
+ }
+
+ /**
+ * 处理权限请求结果
+ */
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+
+ if (requestCode == PERMISSION_REQUEST_CODE) {
+ val deniedPermissions = ArrayList()
+
+ for (i in permissions.indices) {
+ if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
+ deniedPermissions.add(permissions[i])
+ }
+ }
+
+ if (deniedPermissions.isNotEmpty()) {
+ // 记录未授权的权限
+ FileLogger.w(TAG, "未授权的权限: ${deniedPermissions.joinToString()}")
+ } else {
+ FileLogger.d(TAG, "所有必要权限已授权")
+ }
+ }
+ }
}
diff --git a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/SystemFunctionHandler.kt b/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/SystemFunctionHandler.kt
new file mode 100644
index 000000000..4e28f26aa
--- /dev/null
+++ b/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/SystemFunctionHandler.kt
@@ -0,0 +1,225 @@
+package com.yunqiinnovation.deepsound
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.provider.ContactsContract
+import android.telephony.SmsManager
+import com.yunqiinnovation.deepsound.core.utils.FileLogger
+
+/**
+ * 系统功能处理器 - 负责调用系统API执行各种功能
+ */
+class SystemFunctionHandler(private val context: Context) {
+ companion object {
+ private const val TAG = "SystemFunctionHandler"
+ }
+
+ /**
+ * 启动翻译模式
+ * @return 操作结果
+ */
+ fun enterTranslationMode(): Result {
+ FileLogger.d(TAG, "进入翻译模式")
+ // 此处应添加实际的翻译模式实现
+ // 可能需要启动一个专门的翻译服务或活动
+
+ // 广播通知APP的其他部分进入翻译模式
+ // 使用VoiceInteractionService中定义的常量
+ val intent = Intent(VoiceInteractionService.ACTION_ENTER_TRANSLATION_MODE).apply {
+
+ putExtra("timestamp", System.currentTimeMillis())
+ }
+
+ // 发送广播
+ context.sendBroadcast(intent)
+ FileLogger.d(TAG, "已发送广播: ${VoiceInteractionService.ACTION_ENTER_TRANSLATION_MODE}")
+
+ return Result(
+ success = true,
+ message = "已进入翻译模式"
+ )
+ }
+
+ /**
+ * 发送短信
+ * @param contact 联系人(名称或电话号码)
+ * @param message 短信内容
+ * @return 操作结果
+ */
+ fun sendTextMessage(contact: String, message: String): Result {
+ FileLogger.d(TAG, "发送短信给 $contact: $message")
+
+ try {
+ val phoneNumber = getPhoneNumberForContact(contact)
+ if (phoneNumber.isEmpty()) {
+ return Result(
+ success = false,
+ message = "未找到联系人信息: $contact"
+ )
+ }
+
+ // 使用SmsManager发送短信
+ val smsManager = SmsManager.getDefault()
+ smsManager.sendTextMessage(phoneNumber, null, message, null, null)
+
+ return Result(
+ success = true,
+ message = "已向${contact}发送短信: $message"
+ )
+ } catch (e: Exception) {
+ FileLogger.e(TAG, "发送短信失败: ${e.message}", e)
+ return Result(
+ success = false,
+ message = "发送短信失败: ${e.message}"
+ )
+ }
+ }
+
+ /**
+ * 拨打电话
+ * @param contact 联系人(名称或电话号码)
+ * @return 操作结果
+ */
+ fun makePhoneCall(contact: String): Result {
+ FileLogger.d(TAG, "拨打电话给 $contact")
+
+ try {
+ val phoneNumber = getPhoneNumberForContact(contact)
+ if (phoneNumber.isEmpty()) {
+ return Result(
+ success = false,
+ message = "未找到联系人信息: $contact"
+ )
+ }
+
+ // 创建拨号意图
+ val intent = Intent(Intent.ACTION_CALL)
+ intent.data = Uri.parse("tel:$phoneNumber")
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ context.startActivity(intent)
+
+ return Result(
+ success = true,
+ message = "正在拨打${contact}的电话"
+ )
+ } catch (e: Exception) {
+ FileLogger.e(TAG, "拨打电话失败: ${e.message}", e)
+ return Result(
+ success = false,
+ message = "拨打电话失败: ${e.message}"
+ )
+ }
+ }
+
+ /**
+ * 打开应用程序
+ * @param appName 应用名称
+ * @return 操作结果
+ */
+ fun openApp(appName: String): Result {
+ FileLogger.d(TAG, "打开应用: $appName")
+
+ try {
+ // 查找应用的包名
+ val packageManager = context.packageManager
+ val intent = Intent(Intent.ACTION_MAIN, null)
+ intent.addCategory(Intent.CATEGORY_LAUNCHER)
+
+ val apps = packageManager.queryIntentActivities(intent, 0)
+
+ for (resolveInfo in apps) {
+ val appLabel = resolveInfo.loadLabel(packageManager).toString()
+ if (appLabel.equals(appName, ignoreCase = true) ||
+ appLabel.contains(appName, ignoreCase = true)) {
+
+ // 找到匹配的应用
+ val packageName = resolveInfo.activityInfo.packageName
+ val launchIntent = packageManager.getLaunchIntentForPackage(packageName)
+
+ if (launchIntent != null) {
+ launchIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ context.startActivity(launchIntent)
+
+ return Result(
+ success = true,
+ message = "正在打开${appName}应用"
+ )
+ }
+ }
+ }
+
+ return Result(
+ success = false,
+ message = "未找到应用: $appName"
+ )
+ } catch (e: Exception) {
+ FileLogger.e(TAG, "打开应用失败: ${e.message}", e)
+ return Result(
+ success = false,
+ message = "打开应用失败: ${e.message}"
+ )
+ }
+ }
+
+ /**
+ * 根据联系人名称获取电话号码
+ * @param contact 联系人名称或电话号码
+ * @return 电话号码
+ */
+ private fun getPhoneNumberForContact(contact: String): String {
+ // 如果输入的是电话号码(简单判断,包含数字和特殊符号)
+ if (contact.matches(Regex("^[+\\d\\s\\-()]*\$")) && contact.any { it.isDigit() }) {
+ // 移除非数字字符
+ return contact.replace(Regex("[^+\\d]"), "")
+ }
+
+ // 从联系人数据库查询
+ try {
+ val contentResolver = context.contentResolver
+ val uri = Uri.withAppendedPath(
+ ContactsContract.Contacts.CONTENT_FILTER_URI,
+ Uri.encode(contact)
+ )
+
+ val projection = arrayOf(
+ ContactsContract.Contacts._ID,
+ ContactsContract.Contacts.DISPLAY_NAME,
+ ContactsContract.Contacts.HAS_PHONE_NUMBER
+ )
+
+ contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
+ if (cursor.moveToFirst()) {
+ val hasPhoneNumber = cursor.getInt(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.HAS_PHONE_NUMBER))
+
+ if (hasPhoneNumber > 0) {
+ val contactId = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts._ID))
+ val phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI
+ val phoneProjection = arrayOf(ContactsContract.CommonDataKinds.Phone.NUMBER)
+ val phoneSelection = "${ContactsContract.CommonDataKinds.Phone.CONTACT_ID} = ?"
+ val phoneSelectionArgs = arrayOf(contactId)
+
+ contentResolver.query(phoneUri, phoneProjection, phoneSelection, phoneSelectionArgs, null)?.use { phoneCursor ->
+ if (phoneCursor.moveToFirst()) {
+ return phoneCursor.getString(phoneCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER))
+ }
+ }
+ }
+ }
+ }
+ } catch (e: Exception) {
+ FileLogger.e(TAG, "查询联系人信息失败: ${e.message}", e)
+ }
+
+ return ""
+ }
+
+ /**
+ * 操作结果数据类
+ */
+ data class Result(
+ val success: Boolean,
+ val message: String
+ )
+}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceFunctionHandler.kt b/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceFunctionHandler.kt
index 78a55b642..c15ca7e17 100644
--- a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceFunctionHandler.kt
+++ b/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceFunctionHandler.kt
@@ -4,18 +4,22 @@ import org.json.JSONArray
import org.json.JSONObject
import com.yunqiinnovation.open_ai_service.OpenAIService
import com.yunqiinnovation.deepsound.core.utils.FileLogger
+import android.content.Context
/**
* 语音功能处理器 - 处理AI函数调用
*/
class VoiceFunctionHandler(
private val openAIService: OpenAIService,
- private val systemPrompt: String
+ private val context: Context
) {
companion object {
private const val TAG = "VoiceFunctionHandler"
}
+ // 添加系统功能处理器
+ private val systemFunctionHandler = SystemFunctionHandler(context)
+
/**
* 初始化并注册所有可用的函数
*/
@@ -24,6 +28,18 @@ class VoiceFunctionHandler(
// 注册退出交互函数
registerExitInteractionFunction()
+ // 注册翻译模式函数
+ registerTranslationModeFunction()
+
+ // 注册发送短信函数
+ registerSendTextMessageFunction()
+
+ // 注册拨打电话函数
+ registerMakePhoneCallFunction()
+
+ // 注册打开应用函数
+ registerOpenAppFunction()
+
// 在这里可以注册更多函数
} catch (e: Exception) {
@@ -53,6 +69,113 @@ class VoiceFunctionHandler(
}
}
+ /**
+ * 注册翻译模式函数
+ */
+ private fun registerTranslationModeFunction() {
+ try {
+ openAIService.registerFunction(
+ "enter_translation_mode",
+ "进入翻译模式",
+ JSONObject("""
+ {
+ "type": "object",
+ "properties": {},
+ "required": []
+ }
+ """)
+ )
+ FileLogger.d(TAG, "翻译模式功能已注册")
+ } catch (e: Exception) {
+ FileLogger.e(TAG, "注册翻译模式函数失败: ${e.message}", e)
+ }
+ }
+
+ /**
+ * 注册发送短信函数
+ */
+ private fun registerSendTextMessageFunction() {
+ try {
+ openAIService.registerFunction(
+ "send_text_message",
+ "发送短信",
+ JSONObject("""
+ {
+ "type": "object",
+ "properties": {
+ "contact": {
+ "type": "string",
+ "description": "联系人姓名或电话号码"
+ },
+ "message": {
+ "type": "string",
+ "description": "短信内容"
+ }
+ },
+ "required": ["contact", "message"]
+ }
+ """)
+ )
+ FileLogger.d(TAG, "发送短信功能已注册")
+ } catch (e: Exception) {
+ FileLogger.e(TAG, "注册发送短信函数失败: ${e.message}", e)
+ }
+ }
+
+ /**
+ * 注册拨打电话函数
+ */
+ private fun registerMakePhoneCallFunction() {
+ try {
+ openAIService.registerFunction(
+ "make_phone_call",
+ "拨打电话",
+ JSONObject("""
+ {
+ "type": "object",
+ "properties": {
+ "contact": {
+ "type": "string",
+ "description": "联系人姓名或电话号码"
+ }
+ },
+ "required": ["contact"]
+ }
+ """)
+ )
+ FileLogger.d(TAG, "拨打电话功能已注册")
+ } catch (e: Exception) {
+ FileLogger.e(TAG, "注册拨打电话函数失败: ${e.message}", e)
+ }
+ }
+
+ /**
+ * 注册打开应用函数
+ */
+ private fun registerOpenAppFunction() {
+ try {
+ openAIService.registerFunction(
+ "open_app",
+ "打开应用",
+ JSONObject("""
+ {
+ "type": "object",
+ "properties": {
+ "app_name": {
+ "type": "string",
+ "description": "应用名称"
+ }
+ },
+ "required": ["app_name"]
+ }
+ """)
+ )
+ FileLogger.d(TAG, "打开应用功能已注册")
+ } catch (e: Exception) {
+ FileLogger.e(TAG, "注册打开应用函数失败: ${e.message}", e)
+ }
+ }
+
/**
* 处理函数调用
*
@@ -74,6 +197,22 @@ class VoiceFunctionHandler(
handleExitInteraction(functionCall, messages, callback)
true
}
+ "enter_translation_mode" -> {
+ handleEnterTranslationMode(functionCall, messages, callback)
+ true
+ }
+ "send_text_message" -> {
+ handleSendTextMessage(functionCall, messages, callback)
+ true
+ }
+ "make_phone_call" -> {
+ handleMakePhoneCall(functionCall, messages, callback)
+ true
+ }
+ "open_app" -> {
+ handleOpenApp(functionCall, messages, callback)
+ true
+ }
else -> {
// 未知函数,返回默认结果
handleUnknownFunction(functionCall, messages, callback)
@@ -96,7 +235,6 @@ class VoiceFunctionHandler(
openAIService.sendFunctionCallResult(
messages = messages,
- systemPrompt = systemPrompt,
functionCall = functionCall,
functionResult = "{\"result\": \"已退出语音交互\"}",
callback = object : OpenAIService.StreamCallback {
@@ -126,6 +264,199 @@ class VoiceFunctionHandler(
)
}
+ /**
+ * 处理进入翻译模式函数
+ */
+ private fun handleEnterTranslationMode(
+ functionCall: JSONObject,
+ messages: JSONArray,
+ callback: FunctionCallCallback
+ ) {
+ FileLogger.d(TAG, "处理进入翻译模式函数")
+
+ // 调用系统功能处理器执行翻译模式操作
+ val result = systemFunctionHandler.enterTranslationMode()
+
+ val responseBuilder = StringBuilder()
+
+ openAIService.sendFunctionCallResult(
+ messages = messages,
+ functionCall = functionCall,
+ functionResult = "{\"result\": \"${result.message}\"}",
+ callback = object : OpenAIService.StreamCallback {
+ override fun onToken(token: String) {
+ responseBuilder.append(token)
+ callback.onTokenReceived(token)
+ }
+
+ override fun onComplete() {
+ FileLogger.d(TAG, "handleEnterTranslationMode onComplete: ${responseBuilder.toString()}")
+ callback.onComplete()
+ }
+
+ override fun onError(e: Exception) {
+ FileLogger.e(TAG, "处理进入翻译模式函数调用出错: ${e.message}")
+ callback.onError("进入翻译模式时出错")
+ }
+
+ override fun onFunctionCall(nestedCall: JSONObject) {
+ callback.onFunctionCall(nestedCall)
+ }
+ }
+ )
+ }
+
+ /**
+ * 处理发送短信函数
+ */
+ private fun handleSendTextMessage(
+ functionCall: JSONObject,
+ messages: JSONArray,
+ callback: FunctionCallCallback
+ ) {
+ FileLogger.d(TAG, "处理发送短信函数")
+
+ try {
+ val arguments = JSONObject(functionCall.getString("arguments"))
+ val contact = arguments.getString("contact")
+ val message = arguments.getString("message")
+
+ // 调用系统功能处理器发送短信
+ val result = systemFunctionHandler.sendTextMessage(contact, message)
+
+ val responseBuilder = StringBuilder()
+
+ openAIService.sendFunctionCallResult(
+ messages = messages,
+ functionCall = functionCall,
+ functionResult = "{\"result\": \"${result.message}\"}",
+ callback = object : OpenAIService.StreamCallback {
+ override fun onToken(token: String) {
+ responseBuilder.append(token)
+ callback.onTokenReceived(token)
+ }
+
+ override fun onComplete() {
+ FileLogger.d(TAG, "handleSendTextMessage onComplete: ${responseBuilder.toString()}")
+ callback.onComplete()
+ }
+
+ override fun onError(e: Exception) {
+ FileLogger.e(TAG, "处理发送短信函数调用出错: ${e.message}")
+ callback.onError("发送短信时出错")
+ }
+
+ override fun onFunctionCall(nestedCall: JSONObject) {
+ callback.onFunctionCall(nestedCall)
+ }
+ }
+ )
+ } catch (e: Exception) {
+ FileLogger.e(TAG, "解析发送短信参数失败: ${e.message}")
+ callback.onError("发送短信参数错误")
+ }
+ }
+
+ /**
+ * 处理拨打电话函数
+ */
+ private fun handleMakePhoneCall(
+ functionCall: JSONObject,
+ messages: JSONArray,
+ callback: FunctionCallCallback
+ ) {
+ FileLogger.d(TAG, "处理拨打电话函数")
+
+ try {
+ val arguments = JSONObject(functionCall.getString("arguments"))
+ val contact = arguments.getString("contact")
+
+ // 调用系统功能处理器拨打电话
+ val result = systemFunctionHandler.makePhoneCall(contact)
+
+ val responseBuilder = StringBuilder()
+
+ openAIService.sendFunctionCallResult(
+ messages = messages,
+ functionCall = functionCall,
+ functionResult = "{\"result\": \"${result.message}\"}",
+ callback = object : OpenAIService.StreamCallback {
+ override fun onToken(token: String) {
+ responseBuilder.append(token)
+ callback.onTokenReceived(token)
+ }
+
+ override fun onComplete() {
+ FileLogger.d(TAG, "handleMakePhoneCall onComplete: ${responseBuilder.toString()}")
+ callback.onComplete()
+ }
+
+ override fun onError(e: Exception) {
+ FileLogger.e(TAG, "处理拨打电话函数调用出错: ${e.message}")
+ callback.onError("拨打电话时出错")
+ }
+
+ override fun onFunctionCall(nestedCall: JSONObject) {
+ callback.onFunctionCall(nestedCall)
+ }
+ }
+ )
+ } catch (e: Exception) {
+ FileLogger.e(TAG, "解析拨打电话参数失败: ${e.message}")
+ callback.onError("拨打电话参数错误")
+ }
+ }
+
+ /**
+ * 处理打开应用函数
+ */
+ private fun handleOpenApp(
+ functionCall: JSONObject,
+ messages: JSONArray,
+ callback: FunctionCallCallback
+ ) {
+ FileLogger.d(TAG, "处理打开应用函数")
+
+ try {
+ val arguments = JSONObject(functionCall.getString("arguments"))
+ val appName = arguments.getString("app_name")
+
+ // 调用系统功能处理器打开应用
+ val result = systemFunctionHandler.openApp(appName)
+
+ val responseBuilder = StringBuilder()
+
+ openAIService.sendFunctionCallResult(
+ messages = messages,
+ functionCall = functionCall,
+ functionResult = "{\"result\": \"${result.message}\"}",
+ callback = object : OpenAIService.StreamCallback {
+ override fun onToken(token: String) {
+ responseBuilder.append(token)
+ callback.onTokenReceived(token)
+ }
+
+ override fun onComplete() {
+ FileLogger.d(TAG, "handleOpenApp onComplete: ${responseBuilder.toString()}")
+ callback.onComplete()
+ }
+
+ override fun onError(e: Exception) {
+ FileLogger.e(TAG, "处理打开应用函数调用出错: ${e.message}")
+ callback.onError("打开应用时出错")
+ }
+
+ override fun onFunctionCall(nestedCall: JSONObject) {
+ callback.onFunctionCall(nestedCall)
+ }
+ }
+ )
+ } catch (e: Exception) {
+ FileLogger.e(TAG, "解析打开应用参数失败: ${e.message}")
+ callback.onError("打开应用参数错误")
+ }
+ }
+
/**
* 处理未知函数调用
*/
@@ -139,7 +470,6 @@ class VoiceFunctionHandler(
try {
openAIService.sendFunctionCallResult(
messages = messages,
- systemPrompt = systemPrompt,
functionCall = functionCall,
functionResult = "{\"result\": \"处理函数调用中\"}",
callback = object : OpenAIService.StreamCallback {
diff --git a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceInteractionHandler.kt b/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceInteractionHandler.kt
index fa179c279..1d6a528b3 100644
--- a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceInteractionHandler.kt
+++ b/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceInteractionHandler.kt
@@ -30,21 +30,9 @@ class VoiceInteractionHandler(
// OpenAI服务
private val openAIService = OpenAIService()
- // 系统提示词
- private val systemPrompt = """
- 你是一个智能语音助手,能够简洁明了地回答用户的问题。
-时刻关心用户的情绪和需求,主动提供鼓励和温暖。
-语言风格活泼、亲切,能够幽默地互动,陪伴用户,缓解压力,增添生活乐趣。
-
-请始终以用户为中心,保持回应的高效性、准确性和温暖体贴,成为用户真正的灵魂伴侣。
-
- 当用户说"退出"、"再见"、"结束对话"等类似意图时,你应该使用exit_interaction函数来结束对话,
- 并在结束前说一句友好的告别语,例如"再见,有需要随时找我"。
- """.trimIndent()
-
// 语音功能处理
- private val voiceFunctionHandler = VoiceFunctionHandler(openAIService, systemPrompt)
+ private val voiceFunctionHandler = VoiceFunctionHandler(openAIService, context)
// 当前用户输入
private var currentUserInput = ""
@@ -127,12 +115,14 @@ class VoiceInteractionHandler(
override fun onResult(result: String, detectedLanguage: String) {
if (result.isNotEmpty()) {
+ notifyStateChanged()
+
processWithOpenAI(result)
+
}
// 重置状态,继续识别
hasSpeechDetected = false
- notifyStateChanged()
}
override fun onSessionStarted() {
@@ -227,7 +217,6 @@ class VoiceInteractionHandler(
openAIService.sendMessageStream(
messages = messages,
- systemPrompt = systemPrompt,
callback = object : OpenAIService.StreamCallback {
override fun onToken(token: String) {
// 累加响应内容
diff --git a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceInteractionService.kt b/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceInteractionService.kt
index 76faa6f33..1cb132e1a 100644
--- a/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceInteractionService.kt
+++ b/android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceInteractionService.kt
@@ -46,7 +46,7 @@ class VoiceInteractionService : Service() {
private const val CHANNEL_ID = "voice_interaction_channel"
// 语音识别超时时间(毫秒)
- private const val RECOGNITION_TIMEOUT = 8000L
+ private const val RECOGNITION_TIMEOUT = 10000L
// 用于跟踪服务是否正在运行
private val isRunning = AtomicBoolean(false)
@@ -58,6 +58,7 @@ class VoiceInteractionService : Service() {
const val ACTION_RECOGNITION_STARTED = "com.yunqiinnovation.deepsound.ACTION_RECOGNITION_STARTED"
const val ACTION_PAUSE_VOICE_INTERACTION = "com.yunqiinnovation.deepsound.ACTION_PAUSE_VOICE_INTERACTION"
const val ACTION_CHAT_HISTORY_UPDATED = "com.yunqiinnovation.deepsound.ACTION_CHAT_HISTORY_UPDATED"
+ const val ACTION_ENTER_TRANSLATION_MODE = "com.yunqiinnovation.deepsound.ACTION_ENTER_TRANSLATION_MODE"
}
// 服务状态
@@ -293,12 +294,12 @@ class VoiceInteractionService : Service() {
if (!isActive) {
isActive = true
}
-
+ // FileLogger.d(TAG, "服务状态: isActive=${isActive}, isRecognitionActive=${voiceInteractionHandler.isRecognitionActive}, isTimeoutPaused=${isTimeoutPaused}")
// 检查语音识别状态
if (voiceInteractionHandler.isRecognitionActive) {
val currentTime = System.currentTimeMillis()
val elapsedTime = currentTime - lastActivityTime
-
+ FileLogger.d(TAG, "hasSpeechDetected=${voiceInteractionHandler.hasSpeechDetected}, isTtsSpeaking=${voiceInteractionHandler.isTtsSpeaking}, elapsedTime=${elapsedTime}")
// 如果超过指定时间没有检测到语音,且不在TTS播放中,暂停语音识别
if (!voiceInteractionHandler.hasSpeechDetected &&
!voiceInteractionHandler.isTtsSpeaking &&
diff --git a/lib/core/bindings/initial_binding.dart b/lib/core/bindings/initial_binding.dart
index 3f42d9560..748589f63 100644
--- a/lib/core/bindings/initial_binding.dart
+++ b/lib/core/bindings/initial_binding.dart
@@ -8,6 +8,7 @@ import '../../data/services/classic_bluetooth_service.dart';
import '../../data/services/bluetooth_media_button_service.dart';
import '../../core/utils/logger.dart';
import '../../data/services/voice_interaction_service.dart';
+import '../../data/services/open_ai_service_adapter.dart';
/// 初始绑定,用于管理全局依赖
class InitialBinding extends Bindings {
@@ -29,6 +30,13 @@ class InitialBinding extends Bindings {
Get.lazyPut(() => VolcanoTranslationService(),
fenix: true);
+ // OpenAI服务适配器
+ Get.lazyPut(() {
+ final adapter = OpenAIServiceAdapter();
+ adapter.initialize();
+ return adapter;
+ }, fenix: true);
+
// 火山AI服务
Get.lazyPut(() => VolcanoAIService(), fenix: true);
@@ -41,6 +49,7 @@ class InitialBinding extends Bindings {
() => BluetoothMediaButtonService(),
fenix: true);
+ // 语音交互服务
Get.lazyPut(() => VoiceInteractionService(),
fenix: true);
diff --git a/lib/data/models/events/voice_interaction_event.dart b/lib/data/models/events/voice_interaction_event.dart
index 4bfa636df..81860de23 100644
--- a/lib/data/models/events/voice_interaction_event.dart
+++ b/lib/data/models/events/voice_interaction_event.dart
@@ -26,4 +26,17 @@ class RecognitionStartedEvent extends VoiceInteractionEvent {
RecognitionStartedEvent({
required int timestamp,
}) : super(timestamp: timestamp);
+}
+
+/// 通用语音交互事件
+/// 用于处理其他类型的事件
+class GenericVoiceInteractionEvent extends VoiceInteractionEvent {
+ final String type;
+ final Map? data;
+
+ GenericVoiceInteractionEvent({
+ required this.type,
+ this.data,
+ required int timestamp,
+ }) : super(timestamp: timestamp);
}
\ No newline at end of file
diff --git a/lib/data/services/ai_service.dart b/lib/data/services/ai_service.dart
index 37a1f5df0..c1a0a1bcd 100644
--- a/lib/data/services/ai_service.dart
+++ b/lib/data/services/ai_service.dart
@@ -1,5 +1,7 @@
/// AI回复服务接口
abstract class AiService {
+
+
/// 非流式输出方法
Future sendMessage({
required List