Browse Source

feat(asr): 添加讯飞ASR支持并记录ASR提供商信息

在Azure ASR服务中集成讯飞ASR支持,添加ASR提供商字段并记录日志
修改各平台代码以传递和记录ASR提供商信息
添加讯飞ASR相关配置参数传递逻辑
weicu
lxm 9 months ago
parent
commit
9065c39ef5
  1. 7
      lib/data/services/asr_service.dart
  2. 15
      lib/data/services/ble_manager.dart
  3. 24
      lib/data/services/speech_impl/azure_asr_service.dart
  4. 4
      lib/data/services/speech_impl/azure_ast_service.dart
  5. 2
      lib/modules/agent/controllers/agent_controller.dart
  6. 2
      lib/modules/translation/controllers/translation_controller.dart
  7. 28
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt
  8. 3
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentServicePlugin.kt
  9. 9
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt
  10. 30
      local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift
  11. 4
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt
  12. 8
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt
  13. 4
      local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift
  14. 14
      local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureSpeechPlugin.swift

7
lib/data/services/asr_service.dart

@ -112,6 +112,8 @@ class RecognitionEvent {
/// 检测到的语言 /// 检测到的语言
final String detectedLanguage; final String detectedLanguage;
final String provider;
/// 角色 /// 角色
final String role; final String role;
@ -125,6 +127,7 @@ class RecognitionEvent {
required this.type, required this.type,
this.text = '', this.text = '',
this.detectedLanguage = '', this.detectedLanguage = '',
this.provider = '',
this.role = '', this.role = '',
this.audio, this.audio,
this.error = '', this.error = '',
@ -134,11 +137,13 @@ class RecognitionEvent {
factory RecognitionEvent.finalResult({ factory RecognitionEvent.finalResult({
required String text, required String text,
String detectedLanguage = '', String detectedLanguage = '',
String provider = '',
}) { }) {
return RecognitionEvent( return RecognitionEvent(
type: RecognitionEventType.finalResult, type: RecognitionEventType.finalResult,
text: text, text: text,
detectedLanguage: detectedLanguage, detectedLanguage: detectedLanguage,
provider: provider,
); );
} }
@ -160,6 +165,6 @@ class RecognitionEvent {
@override @override
String toString() { String toString() {
return 'RecognitionEvent{type: $type, text: $text, detectedLanguage: $detectedLanguage, error: $error}'; return 'RecognitionEvent{type: $type, provider: $provider, text: $text, detectedLanguage: $detectedLanguage, error: $error}';
} }
} }

15
lib/data/services/ble_manager.dart

@ -875,6 +875,10 @@ class BleManager extends GetxService {
} }
final navigationMode = final navigationMode =
AppConfig.env('APP_NAVIGATION_MODE') ?? 'external_auto'; AppConfig.env('APP_NAVIGATION_MODE') ?? 'external_auto';
final xunfeiAppId = AppConfig.env('XUNFEI_ASR_APP_ID') ?? '';
final xunfeiAccessKeyId = AppConfig.env('XUNFEI_ASR_ACCESS_KEY_ID') ?? '';
final xunfeiAccessKeySecret =
AppConfig.env('XUNFEI_ASR_ACCESS_KEY_SECRET') ?? '';
// 从Flutter资源包中加载.mcp.json // 从Flutter资源包中加载.mcp.json
final jsonData = AppConfig.mcpConfig(); final jsonData = AppConfig.mcpConfig();
Logger.info('启动BLE服务,musicServiceType: ${musicServiceType}'); Logger.info('启动BLE服务,musicServiceType: ${musicServiceType}');
@ -939,6 +943,9 @@ class BleManager extends GetxService {
// 语音代理配置参数 // 语音代理配置参数
'azureSpeechKey': azureSpeechKey, 'azureSpeechKey': azureSpeechKey,
'azureSpeechRegion': azureSpeechRegion, 'azureSpeechRegion': azureSpeechRegion,
'xunfeiAppId': xunfeiAppId,
'xunfeiAccessKeyId': xunfeiAccessKeyId,
'xunfeiAccessKeySecret': xunfeiAccessKeySecret,
'openaiApiKey': openaiApiKey, 'openaiApiKey': openaiApiKey,
'openaiBaseUrl': openaiBaseUrl, 'openaiBaseUrl': openaiBaseUrl,
'openaiModel': openaiModel, 'openaiModel': openaiModel,
@ -958,8 +965,12 @@ class BleManager extends GetxService {
"insufficientIntegralText": "insufficientIntegral".tr, "insufficientIntegralText": "insufficientIntegral".tr,
}; };
// 记录日志(不记录敏感信息) Logger.info('启动BLE服务,配置参数键名: ${config.keys.toList()}');
Logger.info('启动BLE服务,配置参数键名: ${config}'); if (xunfeiAppId.isEmpty ||
xunfeiAccessKeyId.isEmpty ||
xunfeiAccessKeySecret.isEmpty) {
Logger.warning('XUNFEI_ASR_* 未完整配置,ASR 将不会切到讯飞');
}
if (azureSpeechKey.isEmpty || openaiApiKey.isEmpty) { if (azureSpeechKey.isEmpty || openaiApiKey.isEmpty) {
Logger.warning('缺少必要的API密钥,请检查.env文件配置'); Logger.warning('缺少必要的API密钥,请检查.env文件配置');

24
lib/data/services/speech_impl/azure_asr_service.dart

@ -50,6 +50,9 @@ class AzureAsrService extends GetxService implements AsrService {
String _latestDetectedLanguage = ''; String _latestDetectedLanguage = '';
String get latestDetectedLanguage => _latestDetectedLanguage; String get latestDetectedLanguage => _latestDetectedLanguage;
String _latestAsrProvider = '';
String get latestAsrProvider => _latestAsrProvider;
// 音频数据事件订阅 // 音频数据事件订阅
StreamSubscription? _audioDataEventSubscription; StreamSubscription? _audioDataEventSubscription;
// 音频数据流控制器 // 音频数据流控制器
@ -74,7 +77,8 @@ class AzureAsrService extends GetxService implements AsrService {
_serviceRegion = AppConfig.env('AZURE_SPEECH_REGION') ?? ''; _serviceRegion = AppConfig.env('AZURE_SPEECH_REGION') ?? '';
_xunfeiAppId = AppConfig.env('XUNFEI_ASR_APP_ID') ?? ''; _xunfeiAppId = AppConfig.env('XUNFEI_ASR_APP_ID') ?? '';
_xunfeiAccessKeyId = AppConfig.env('XUNFEI_ASR_ACCESS_KEY_ID') ?? ''; _xunfeiAccessKeyId = AppConfig.env('XUNFEI_ASR_ACCESS_KEY_ID') ?? '';
_xunfeiAccessKeySecret = AppConfig.env('XUNFEI_ASR_ACCESS_KEY_SECRET') ?? ''; _xunfeiAccessKeySecret =
AppConfig.env('XUNFEI_ASR_ACCESS_KEY_SECRET') ?? '';
if (_subscriptionKey.isEmpty || _serviceRegion.isEmpty) { if (_subscriptionKey.isEmpty || _serviceRegion.isEmpty) {
throw Exception( throw Exception(
@ -334,6 +338,17 @@ class AzureAsrService extends GetxService implements AsrService {
final Map<dynamic, dynamic> eventMap = event; final Map<dynamic, dynamic> eventMap = event;
final String eventType = eventMap['type'] as String? ?? ''; final String eventType = eventMap['type'] as String? ?? '';
final String provider = eventMap['provider'] as String? ?? '';
if (provider.isNotEmpty) {
if (provider != _latestAsrProvider) {
_latestAsrProvider = provider;
Logger.info('ASR provider: $_latestAsrProvider');
}
} else {
if (eventType == 'sessionStarted') {
Logger.warning('ASR provider missing in event');
}
}
// 添加日志帮助调试 // 添加日志帮助调试
@ -348,6 +363,7 @@ class AzureAsrService extends GetxService implements AsrService {
type: RecognitionEventType.finalResult, type: RecognitionEventType.finalResult,
text: text, text: text,
detectedLanguage: detectedLanguage, detectedLanguage: detectedLanguage,
provider: _latestAsrProvider,
)); ));
break; break;
case 'result1': case 'result1':
@ -360,6 +376,7 @@ class AzureAsrService extends GetxService implements AsrService {
type: RecognitionEventType.finalResult1, type: RecognitionEventType.finalResult1,
text: text, text: text,
detectedLanguage: detectedLanguage, detectedLanguage: detectedLanguage,
provider: _latestAsrProvider,
)); ));
break; break;
@ -371,11 +388,13 @@ class AzureAsrService extends GetxService implements AsrService {
type: RecognitionEventType.intermediateResult, type: RecognitionEventType.intermediateResult,
text: text, text: text,
detectedLanguage: detectedLanguage, detectedLanguage: detectedLanguage,
provider: _latestAsrProvider,
)); ));
break; break;
case 'sessionStarted': case 'sessionStarted':
_eventStreamController?.add(RecognitionEvent( _eventStreamController?.add(RecognitionEvent(
type: RecognitionEventType.sessionStarted, type: RecognitionEventType.sessionStarted,
provider: _latestAsrProvider,
)); ));
break; break;
@ -383,6 +402,7 @@ class AzureAsrService extends GetxService implements AsrService {
_isContinuousRecognitionActive = false; _isContinuousRecognitionActive = false;
_eventStreamController?.add(RecognitionEvent( _eventStreamController?.add(RecognitionEvent(
type: RecognitionEventType.sessionStopped, type: RecognitionEventType.sessionStopped,
provider: _latestAsrProvider,
)); ));
break; break;
@ -398,6 +418,7 @@ class AzureAsrService extends GetxService implements AsrService {
_eventStreamController?.add(RecognitionEvent( _eventStreamController?.add(RecognitionEvent(
type: RecognitionEventType.canceled, type: RecognitionEventType.canceled,
error: '$reason: $errorDetails', error: '$reason: $errorDetails',
provider: _latestAsrProvider,
)); ));
break; break;
@ -407,6 +428,7 @@ class AzureAsrService extends GetxService implements AsrService {
_eventStreamController?.add(RecognitionEvent( _eventStreamController?.add(RecognitionEvent(
type: RecognitionEventType.error, type: RecognitionEventType.error,
error: error, error: error,
provider: _latestAsrProvider,
)); ));
break; break;
} }

4
lib/data/services/speech_impl/azure_ast_service.dart

@ -78,8 +78,6 @@ class AzureAstService extends GetxService implements AstService {
final Map<dynamic, dynamic> eventMap = event; final Map<dynamic, dynamic> eventMap = event;
final String eventType = eventMap['type'] as String? ?? ''; final String eventType = eventMap['type'] as String? ?? '';
// 添加日志帮助调试
switch (eventType) { switch (eventType) {
case 'result': case 'result':
final String text = eventMap['text'] as String? ?? ''; final String text = eventMap['text'] as String? ?? '';
@ -105,6 +103,7 @@ class AzureAstService extends GetxService implements AstService {
)); ));
break; break;
case 'sessionStarted': case 'sessionStarted':
Logger.info('AST provider: azure');
_eventStreamController?.add(RecognitionEvent1( _eventStreamController?.add(RecognitionEvent1(
type: RecognitionEventType1.sessionStarted, type: RecognitionEventType1.sessionStarted,
)); ));
@ -309,6 +308,7 @@ class AzureAstService extends GetxService implements AstService {
_isInitialized = result; _isInitialized = result;
_setupEventChannel(); _setupEventChannel();
Logger.info('Azure 语音识别服务初始化${result ? '成功' : '失败'}'); Logger.info('Azure 语音识别服务初始化${result ? '成功' : '失败'}');
if (result) Logger.info('AST provider: azure');
return result; return result;
} catch (e) { } catch (e) {
Logger.error('Azure 语音识别服务初始化失败: ${e.toString()}'); Logger.error('Azure 语音识别服务初始化失败: ${e.toString()}');

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

@ -569,6 +569,8 @@ class AgentController extends GetxController with WidgetsBindingObserver {
// 订阅代理服务事件 // 订阅代理服务事件
void _subscribeToEvents() { void _subscribeToEvents() {
_eventSubscription = AgentService.events.listen((event) { _eventSubscription = AgentService.events.listen((event) {
final String asrProvider = (event.data['provider'] ?? '').toString();
if (asrProvider.isNotEmpty) Logger.i(TAG, 'ASR provider: $asrProvider');
switch (event.type) { switch (event.type) {
case AgentServiceEventType.recognitionStarted: case AgentServiceEventType.recognitionStarted:
isListening.value = true; isListening.value = true;

2
lib/modules/translation/controllers/translation_controller.dart

@ -1034,6 +1034,8 @@ class TranslationController extends GetxController with WidgetsBindingObserver {
/// [event] 识别事件 /// [event] 识别事件
void _handleRecognitionEvent(RecognitionEvent event) { void _handleRecognitionEvent(RecognitionEvent event) {
// Logger.info("处理识别事件:${event}"); // Logger.info("处理识别事件:${event}");
final String asrProvider = event.provider;
if (asrProvider.isNotEmpty) Logger.info('ASR provider: $asrProvider');
switch (event.type) { switch (event.type) {
case RecognitionEventType.finalResult: case RecognitionEventType.finalResult:
if (event.text.isEmpty) break; if (event.text.isEmpty) break;

28
local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt

@ -73,6 +73,9 @@ object AgentService : CoroutineScope {
private var azureSpeechKey: String = "" private var azureSpeechKey: String = ""
private var azureSpeechRegion: String = "" private var azureSpeechRegion: String = ""
private var xunfeiAppId: String = ""
private var xunfeiAccessKeyId: String = ""
private var xunfeiAccessKeySecret: String = ""
// 协程相关 // 协程相关
private val job = SupervisorJob() private val job = SupervisorJob()
@ -238,6 +241,9 @@ object AgentService : CoroutineScope {
//保存配置 //保存配置
this.azureSpeechKey = config["azureSpeechKey"]?.toString() ?: "" this.azureSpeechKey = config["azureSpeechKey"]?.toString() ?: ""
this.azureSpeechRegion = config["azureSpeechRegion"]?.toString() ?: "" this.azureSpeechRegion = config["azureSpeechRegion"]?.toString() ?: ""
this.xunfeiAppId = config["xunfeiAppId"]?.toString() ?: ""
this.xunfeiAccessKeyId = config["xunfeiAccessKeyId"]?.toString() ?: ""
this.xunfeiAccessKeySecret = config["xunfeiAccessKeySecret"]?.toString() ?: ""
if (!customSystemPrompt.isNullOrBlank()) { if (!customSystemPrompt.isNullOrBlank()) {
systemPrompt = customSystemPrompt systemPrompt = customSystemPrompt
} else { } else {
@ -257,7 +263,10 @@ object AgentService : CoroutineScope {
region = config["azureSpeechRegion"]?.toString() ?: "", region = config["azureSpeechRegion"]?.toString() ?: "",
supportedLanguages = supportedLanguages, supportedLanguages = supportedLanguages,
audioSourceType = if (isExternalActive) AzureAsrHelper.AudioSourceType.EXTERNAL audioSourceType = if (isExternalActive) AzureAsrHelper.AudioSourceType.EXTERNAL
else AzureAsrHelper.AudioSourceType.MICROPHONE else AzureAsrHelper.AudioSourceType.MICROPHONE,
xunfeiAppId = config["xunfeiAppId"]?.toString() ?: "",
xunfeiAccessKeyId = config["xunfeiAccessKeyId"]?.toString() ?: "",
xunfeiAccessKeySecret = config["xunfeiAccessKeySecret"]?.toString() ?: ""
) )
if (asrInitSuccess) { if (asrInitSuccess) {
@ -306,6 +315,9 @@ object AgentService : CoroutineScope {
vipExptime = config["vipexptime"]?.toString()?.toIntOrNull() ?: vipExptime; vipExptime = config["vipexptime"]?.toString()?.toIntOrNull() ?: vipExptime;
navigationMode = config["navigationMode"]?.toString() ?: navigationMode navigationMode = config["navigationMode"]?.toString() ?: navigationMode
musicServiceType = config["musicServiceType"]?.toString() ?: "" musicServiceType = config["musicServiceType"]?.toString() ?: ""
xunfeiAppId = config["xunfeiAppId"]?.toString() ?: xunfeiAppId
xunfeiAccessKeyId = config["xunfeiAccessKeyId"]?.toString() ?: xunfeiAccessKeyId
xunfeiAccessKeySecret = config["xunfeiAccessKeySecret"]?.toString() ?: xunfeiAccessKeySecret
chatApiService.initialize( chatApiService.initialize(
config["openaiApiKey"]?.toString() ?: "", config["openaiApiKey"]?.toString() ?: "",
config["openaiBaseUrl"]?.toString() ?: "", config["openaiBaseUrl"]?.toString() ?: "",
@ -1407,7 +1419,10 @@ object AgentService : CoroutineScope {
subscriptionKey = this.azureSpeechKey, subscriptionKey = this.azureSpeechKey,
region = this.azureSpeechRegion, region = this.azureSpeechRegion,
supportedLanguages = languages.toTypedArray(), supportedLanguages = languages.toTypedArray(),
audioSourceType = audioSourceType audioSourceType = audioSourceType,
xunfeiAppId = this.xunfeiAppId,
xunfeiAccessKeyId = this.xunfeiAccessKeyId,
xunfeiAccessKeySecret = this.xunfeiAccessKeySecret
) ?: false ) ?: false
if (asrSuccess) { if (asrSuccess) {
recognizeCallback() recognizeCallback()
@ -1631,11 +1646,18 @@ object AgentService : CoroutineScope {
* 发送事件 * 发送事件
*/ */
private fun sendEvent(eventName: String, data: Map<String, Any>) { private fun sendEvent(eventName: String, data: Map<String, Any>) {
val shouldAttachAsrProvider = eventName == "recognizing" || eventName.startsWith("recognition_")
val finalData: Map<String, Any> = if (shouldAttachAsrProvider && !data.containsKey("provider")) {
val provider = azureAsrHelper?.getAsrProvider() ?: "unknown"
data.toMutableMap().apply { put("provider", provider) }
} else {
data
}
// 切换到主线程执行监听器回调,避免 UI 更新问题 // 切换到主线程执行监听器回调,避免 UI 更新问题
launch(Dispatchers.Main) { launch(Dispatchers.Main) {
listeners.forEach { listener -> listeners.forEach { listener ->
try { try {
listener.onEvent(eventName, data) listener.onEvent(eventName, finalData)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "向监听器发送事件失败", e) Log.e(TAG, "向监听器发送事件失败", e)
} }

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

@ -80,6 +80,9 @@ class AgentServicePlugin : FlutterPlugin, MethodCallHandler, EventChannel.Stream
config["isttsinterrupt"]?.toString()?.let { intent.putExtra("isttsinterrupt", it) } config["isttsinterrupt"]?.toString()?.let { intent.putExtra("isttsinterrupt", it) }
config["callingToolText"]?.toString()?.let { intent.putExtra("callingToolText", it) } config["callingToolText"]?.toString()?.let { intent.putExtra("callingToolText", it) }
config["insufficientIntegralText"]?.toString()?.let { intent.putExtra("insufficientIntegralText", it) } config["insufficientIntegralText"]?.toString()?.let { intent.putExtra("insufficientIntegralText", it) }
config["xunfeiAppId"]?.toString()?.let { intent.putExtra("xunfeiAppId", it) }
config["xunfeiAccessKeyId"]?.toString()?.let { intent.putExtra("xunfeiAccessKeyId", it) }
config["xunfeiAccessKeySecret"]?.toString()?.let { intent.putExtra("xunfeiAccessKeySecret", it) }
config["vipexptime"]?.toString()?.let { config["vipexptime"]?.toString()?.let {
intent.putExtra("vipexptime", it) intent.putExtra("vipexptime", it)
//打印日志 //打印日志

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

@ -71,6 +71,9 @@ class BleMediaService : Service(), CoroutineScope {
private const val APP_CALLING_TOOL_TEXT = "callingToolText" // 工具调用提示 private const val APP_CALLING_TOOL_TEXT = "callingToolText" // 工具调用提示
private const val APP_INSUFFICIENT_INTEGRAL_TEXT = "insufficientIntegralText" // 积分不足提示 private const val APP_INSUFFICIENT_INTEGRAL_TEXT = "insufficientIntegralText" // 积分不足提示
private const val KEY_VIP_EXPTIME = "vipexptime" // 会员到期时间 private const val KEY_VIP_EXPTIME = "vipexptime" // 会员到期时间
private const val KEY_XUNFEI_APP_ID = "xunfeiAppId" // 讯飞AppID
private const val KEY_XUNFEI_ACCESS_KEY_ID = "xunfeiAccessKeyId" // 讯飞AccessKeyID
private const val KEY_XUNFEI_ACCESS_KEY_SECRET = "xunfeiAccessKeySecret" // 讯飞AccessKeySecret
// 用于跟踪服务是否正在运行 // 用于跟踪服务是否正在运行
private val isRunning = AtomicBoolean(false) private val isRunning = AtomicBoolean(false)
@ -591,6 +594,9 @@ private var companionManager: BleCompanionManager? = null
it.getStringExtra(APP_INSUFFICIENT_INTEGRAL_TEXT)?.let { value -> config[APP_INSUFFICIENT_INTEGRAL_TEXT] = value } it.getStringExtra(APP_INSUFFICIENT_INTEGRAL_TEXT)?.let { value -> config[APP_INSUFFICIENT_INTEGRAL_TEXT] = value }
it.getStringExtra(KEY_VIP_EXPTIME)?.let { value -> config[KEY_VIP_EXPTIME] = value } it.getStringExtra(KEY_VIP_EXPTIME)?.let { value -> config[KEY_VIP_EXPTIME] = value }
it.getStringExtra("isttsinterrupt")?.let { value -> config["isttsinterrupt"] = value } it.getStringExtra("isttsinterrupt")?.let { value -> config["isttsinterrupt"] = value }
it.getStringExtra(KEY_XUNFEI_APP_ID)?.let { value -> config[KEY_XUNFEI_APP_ID] = value }
it.getStringExtra(KEY_XUNFEI_ACCESS_KEY_ID)?.let { value -> config[KEY_XUNFEI_ACCESS_KEY_ID] = value }
it.getStringExtra(KEY_XUNFEI_ACCESS_KEY_SECRET)?.let { value -> config[KEY_XUNFEI_ACCESS_KEY_SECRET] = value }
Log.d(TAG, "liwei-------vipexptime 3-1 ${ config[KEY_VIP_EXPTIME]}") Log.d(TAG, "liwei-------vipexptime 3-1 ${ config[KEY_VIP_EXPTIME]}")
// 提取 supportedLanguages 参数 // 提取 supportedLanguages 参数
it.getStringArrayListExtra(KEY_SUPPORTED_LANGUAGES)?.let { languages -> it.getStringArrayListExtra(KEY_SUPPORTED_LANGUAGES)?.let { languages ->
@ -655,6 +661,9 @@ private var companionManager: BleCompanionManager? = null
config[APP_CALLING_TOOL_TEXT] = getConfigString(prefs, APP_CALLING_TOOL_TEXT, "") config[APP_CALLING_TOOL_TEXT] = getConfigString(prefs, APP_CALLING_TOOL_TEXT, "")
config[APP_INSUFFICIENT_INTEGRAL_TEXT] = getConfigString(prefs, APP_INSUFFICIENT_INTEGRAL_TEXT, "") config[APP_INSUFFICIENT_INTEGRAL_TEXT] = getConfigString(prefs, APP_INSUFFICIENT_INTEGRAL_TEXT, "")
config[KEY_VIP_EXPTIME] = getConfigString(prefs, KEY_VIP_EXPTIME, "") config[KEY_VIP_EXPTIME] = getConfigString(prefs, KEY_VIP_EXPTIME, "")
config[KEY_XUNFEI_APP_ID] = getConfigString(prefs, KEY_XUNFEI_APP_ID, "")
config[KEY_XUNFEI_ACCESS_KEY_ID] = getConfigString(prefs, KEY_XUNFEI_ACCESS_KEY_ID, "")
config[KEY_XUNFEI_ACCESS_KEY_SECRET] = getConfigString(prefs, KEY_XUNFEI_ACCESS_KEY_SECRET, "")
Log.d(TAG, "liwei-------vipexptime 3-0 ${ config[KEY_VIP_EXPTIME]}") Log.d(TAG, "liwei-------vipexptime 3-0 ${ config[KEY_VIP_EXPTIME]}")
// 添加 supportedLanguages 参数处理 // 添加 supportedLanguages 参数处理
val supportedLanguagesStr = getConfigString(prefs, KEY_SUPPORTED_LANGUAGES, "") val supportedLanguagesStr = getConfigString(prefs, KEY_SUPPORTED_LANGUAGES, "")

30
local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift

@ -36,6 +36,9 @@ class AgentServiceImpl: NSObject {
private var azureSpeechKey: String = "" private var azureSpeechKey: String = ""
private var azureSpeechRegion: String = "" private var azureSpeechRegion: String = ""
private var xunfeiAppId: String = ""
private var xunfeiAccessKeyId: String = ""
private var xunfeiAccessKeySecret: String = ""
private var config: [String: Any] = [:] private var config: [String: Any] = [:]
// 添加音乐播放状态记录 // 添加音乐播放状态记录
@ -145,12 +148,17 @@ class AgentServiceImpl: NSObject {
} }
internal func sendEvent(name eventName: String, data: [String: Any]) { internal func sendEvent(name eventName: String, data: [String: Any]) {
var eventData = data
let shouldAttachAsrProvider = eventName == "recognizing" || eventName.hasPrefix("recognition_")
if shouldAttachAsrProvider && eventData["provider"] == nil {
eventData["provider"] = azureAsrHelper?.asrProvider() ?? "unknown"
}
listenersLock.lock() listenersLock.lock()
let currentListeners = self.listeners let currentListeners = self.listeners
listenersLock.unlock() listenersLock.unlock()
for listener in currentListeners { for listener in currentListeners {
listener.onEvent(eventName: eventName, data: data) listener.onEvent(eventName: eventName, data: eventData)
} }
} }
@ -252,6 +260,16 @@ class AgentServiceImpl: NSObject {
sendError("Azure语音区域缺失", code: "CONFIG_ERROR") sendError("Azure语音区域缺失", code: "CONFIG_ERROR")
return false return false
} }
if let xunfeiAppId = config["xunfeiAppId"] as? String {
self.xunfeiAppId = xunfeiAppId
}
if let xunfeiAccessKeyId = config["xunfeiAccessKeyId"] as? String {
self.xunfeiAccessKeyId = xunfeiAccessKeyId
}
if let xunfeiAccessKeySecret = config["xunfeiAccessKeySecret"] as? String {
self.xunfeiAccessKeySecret = xunfeiAccessKeySecret
}
//启动定位服务 //启动定位服务
NotificationCenter.default.post(name: .locationstartEvent, object: nil) NotificationCenter.default.post(name: .locationstartEvent, object: nil)
@ -298,7 +316,10 @@ class AgentServiceImpl: NSObject {
subscriptionKey: azureSpeechKey, subscriptionKey: azureSpeechKey,
region: azureSpeechRegion, region: azureSpeechRegion,
supportedLanguages: supportedLanguages, supportedLanguages: supportedLanguages,
audioSourceType: .microphone audioSourceType: .microphone,
xunfeiAppId: xunfeiAppId,
xunfeiAccessKeyId: xunfeiAccessKeyId,
xunfeiAccessKeySecret: xunfeiAccessKeySecret
), asrSuccess else { ), asrSuccess else {
sendError("初始化语音识别服务失败", code: "ASR_INIT_ERROR") sendError("初始化语音识别服务失败", code: "ASR_INIT_ERROR")
return false return false
@ -1459,7 +1480,10 @@ private func jsonToString(_ json: [String: Any]) -> String? {
subscriptionKey: azureSpeechKey, subscriptionKey: azureSpeechKey,
region: azureSpeechRegion, region: azureSpeechRegion,
supportedLanguages: languages, supportedLanguages: languages,
audioSourceType: .microphone audioSourceType: .microphone,
xunfeiAppId: xunfeiAppId,
xunfeiAccessKeyId: xunfeiAccessKeyId,
xunfeiAccessKeySecret: xunfeiAccessKeySecret
), asrSuccess else { ), asrSuccess else {
sendError("初始化语音识别服务失败", code: "ASR_INIT_ERROR") sendError("初始化语音识别服务失败", code: "ASR_INIT_ERROR")
return false return false

4
local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt

@ -48,6 +48,10 @@ class AzureAsrHelper(private val context: Context) {
private var xunfeiAccessKeyId: String = "" private var xunfeiAccessKeyId: String = ""
private var xunfeiAccessKeySecret: String = "" private var xunfeiAccessKeySecret: String = ""
fun getAsrProvider(): String {
return if (useXunfei) "xunfei" else "azure"
}
// 音频源配置 // 音频源配置
var audioSourceType = AudioSourceType.MICROPHONE var audioSourceType = AudioSourceType.MICROPHONE

8
local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt

@ -280,6 +280,7 @@ class AzureSpeechPlugin : BleService.Callback, FlutterPlugin {
mapOf( mapOf(
"type" to "result", "type" to "result",
"sessionid" to sessionid, "sessionid" to sessionid,
"provider" to azureAsrHelper.getAsrProvider(),
"text" to text, "text" to text,
"detectedLanguage" to detectedLanguage "detectedLanguage" to detectedLanguage
) )
@ -297,6 +298,7 @@ class AzureSpeechPlugin : BleService.Callback, FlutterPlugin {
mapOf( mapOf(
"type" to "recognizing", "type" to "recognizing",
"sessionid" to sessionid, "sessionid" to sessionid,
"provider" to azureAsrHelper.getAsrProvider(),
"text" to recognizing, "text" to recognizing,
"detectedLanguage" to detectedLanguage "detectedLanguage" to detectedLanguage
) )
@ -304,11 +306,11 @@ class AzureSpeechPlugin : BleService.Callback, FlutterPlugin {
} }
override fun onSessionStarted(sessionid:String) { override fun onSessionStarted(sessionid:String) {
sendAsrEvent(mapOf("type" to "sessionStarted","sessionid" to sessionid,)) sendAsrEvent(mapOf("type" to "sessionStarted","sessionid" to sessionid, "provider" to azureAsrHelper.getAsrProvider()))
} }
override fun onSessionStopped(sessionid:String) { override fun onSessionStopped(sessionid:String) {
sendAsrEvent(mapOf("type" to "sessionStopped","sessionid" to sessionid,)) sendAsrEvent(mapOf("type" to "sessionStopped","sessionid" to sessionid, "provider" to azureAsrHelper.getAsrProvider()))
} }
@ -318,6 +320,7 @@ class AzureSpeechPlugin : BleService.Callback, FlutterPlugin {
mapOf( mapOf(
"type" to "canceled", "type" to "canceled",
"sessionid" to sessionid, "sessionid" to sessionid,
"provider" to azureAsrHelper.getAsrProvider(),
"reason" to reason, "reason" to reason,
"errorDetails" to errorDetails "errorDetails" to errorDetails
) )
@ -331,6 +334,7 @@ class AzureSpeechPlugin : BleService.Callback, FlutterPlugin {
mapOf( mapOf(
"type" to "error", "type" to "error",
"sessionid" to sessionid, "sessionid" to sessionid,
"provider" to azureAsrHelper.getAsrProvider(),
"code" to code, "code" to code,
"message" to error "message" to error
) )

4
local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift

@ -80,6 +80,10 @@ public class AzureAsrHelper: NSObject {
// 音频处理 // 音频处理
public var audioStream: SimpleAudioReceiver? public var audioStream: SimpleAudioReceiver?
public func asrProvider() -> String {
return useXunfei ? "xunfei" : "azure"
}
/** /**
* 初始化Azure语音服务 * 初始化Azure语音服务
* *

14
local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureSpeechPlugin.swift

@ -224,6 +224,10 @@ internal func sendAsrEvent(_ event: [String: Any]) {
sendEvent(event, type: .asr) sendEvent(event, type: .asr)
} }
internal func currentAsrProvider() -> String {
return azureAsrHelper.asrProvider()
}
private func sendTtsEvent(_ event: [String: Any]) { private func sendTtsEvent(_ event: [String: Any]) {
sendEvent(event, type: .tts) sendEvent(event, type: .tts)
} }
@ -1289,6 +1293,7 @@ private class AsrCallbackWrapper: AzureAsrHelper.ContinuousRecognizeCallback {
plugin?.sendAsrEvent([ plugin?.sendAsrEvent([
"type": "result", "type": "result",
"sessionid": sessionid, "sessionid": sessionid,
"provider": plugin?.currentAsrProvider() ?? "",
"text": text, "text": text,
"detectedLanguage": detectedLanguage "detectedLanguage": detectedLanguage
]) ])
@ -1303,6 +1308,7 @@ private class AsrCallbackWrapper: AzureAsrHelper.ContinuousRecognizeCallback {
plugin?.sendAsrEvent([ plugin?.sendAsrEvent([
"type": "recognizing", "type": "recognizing",
"sessionid": sessionid, "sessionid": sessionid,
"provider": plugin?.currentAsrProvider() ?? "",
"text": text, "text": text,
"detectedLanguage": detectedLanguage "detectedLanguage": detectedLanguage
]) ])
@ -1314,7 +1320,8 @@ private class AsrCallbackWrapper: AzureAsrHelper.ContinuousRecognizeCallback {
func onSessionStarted(sessionid:String) { func onSessionStarted(sessionid:String) {
plugin?.sendAsrEvent([ plugin?.sendAsrEvent([
"type": "sessionStarted", "type": "sessionStarted",
"sessionid": sessionid "sessionid": sessionid,
"provider": plugin?.currentAsrProvider() ?? ""
]) ])
} }
@ -1324,7 +1331,8 @@ private class AsrCallbackWrapper: AzureAsrHelper.ContinuousRecognizeCallback {
func onSessionStopped(sessionid:String) { func onSessionStopped(sessionid:String) {
plugin?.sendAsrEvent([ plugin?.sendAsrEvent([
"type": "sessionStopped", "type": "sessionStopped",
"sessionid": sessionid "sessionid": sessionid,
"provider": plugin?.currentAsrProvider() ?? ""
]) ])
} }
@ -1337,6 +1345,7 @@ private class AsrCallbackWrapper: AzureAsrHelper.ContinuousRecognizeCallback {
plugin?.sendAsrEvent([ plugin?.sendAsrEvent([
"type": "canceled", "type": "canceled",
"sessionid": sessionid, "sessionid": sessionid,
"provider": plugin?.currentAsrProvider() ?? "",
"reason": reason, "reason": reason,
"errorDetails": errorDetails "errorDetails": errorDetails
]) ])
@ -1351,6 +1360,7 @@ private class AsrCallbackWrapper: AzureAsrHelper.ContinuousRecognizeCallback {
plugin?.sendAsrEvent([ plugin?.sendAsrEvent([
"type": "error", "type": "error",
"sessionid": sessionid, "sessionid": sessionid,
"provider": plugin?.currentAsrProvider() ?? "",
"code": errorCode, "code": errorCode,
"message": error "message": error
]) ])

Loading…
Cancel
Save