From 1b07e3c3edaa55c68461f17e98a5c19dfec78b15 Mon Sep 17 00:00:00 2001 From: tanlongsheng <252620078@qq.com> Date: Mon, 15 Dec 2025 16:44:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=98=AF=E5=90=A6=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E7=AC=AC=E4=B8=80=E4=B8=AA=E6=A0=87=E7=82=B9=E7=AC=A6?= =?UTF-8?q?=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/services/asr_service.dart | 5 +- .../speech_impl/azure_asr_service.dart | 6 +- .../speech_impl/volcano_asr_api_service.dart | 5 +- .../speech_impl/volcano_asr_service.dart | 5 +- .../speech_impl/xunfei_asr_service.dart | 5 +- .../controllers/translation_controller.dart | 5 +- .../agent_service/AgentService.kt | 2 +- .../azure_speech/AzureAsrHelper.kt | 6 +- .../azure_speech/AzureSpeechPlugin.kt | 3 +- .../azure_speech/XunFeiAsrHelper.kt | 55 +++++++++++-------- 10 files changed, 62 insertions(+), 35 deletions(-) diff --git a/lib/data/services/asr_service.dart b/lib/data/services/asr_service.dart index 1a74af25c..35c263e34 100644 --- a/lib/data/services/asr_service.dart +++ b/lib/data/services/asr_service.dart @@ -20,8 +20,9 @@ abstract class AsrService { /// /// 返回一个包含识别事件的流 Future startContinuousRecognition( - bool audioSourceType, - ); + bool audioSourceType, { + bool isRemoveFirstPunctuation = true, + }); /// 停止连续语音识别 Future stopContinuousRecognition(); diff --git a/lib/data/services/speech_impl/azure_asr_service.dart b/lib/data/services/speech_impl/azure_asr_service.dart index 12e43489c..1eb84856b 100644 --- a/lib/data/services/speech_impl/azure_asr_service.dart +++ b/lib/data/services/speech_impl/azure_asr_service.dart @@ -191,7 +191,10 @@ class AzureAsrService extends GetxService implements AsrService { /// - 在 600ms 的冷却时间内再次调用会被防抖拦截并返回 false; /// - 首次或冷却期外调用会继续启动连续识别; /// - 若当前已处于连续识别中,会先调用停止后再启动。 - Future startContinuousRecognition(bool audioSourceType) async { + Future startContinuousRecognition( + bool audioSourceType, { + bool isRemoveFirstPunctuation = true, + }) async { // 防抖判断:短时间内重复调用直接拦截 final now = DateTime.now(); if (_lastStartAt != null && now.difference(_lastStartAt!) < _debounce) { @@ -212,6 +215,7 @@ class AzureAsrService extends GetxService implements AsrService { final bool result = await _channel.invokeMethod('startContinuousRecognition', { 'audioSourceType': audioSourceType, + 'isRemoveFirstPunctuation': isRemoveFirstPunctuation, }); if (!result) { diff --git a/lib/data/services/speech_impl/volcano_asr_api_service.dart b/lib/data/services/speech_impl/volcano_asr_api_service.dart index 80714696f..3e5711b38 100644 --- a/lib/data/services/speech_impl/volcano_asr_api_service.dart +++ b/lib/data/services/speech_impl/volcano_asr_api_service.dart @@ -862,7 +862,10 @@ class VolcanoAsrApiService implements AsrService { } @override - Future startContinuousRecognition(bool audioSourceType) { + Future startContinuousRecognition( + bool audioSourceType, { + bool isRemoveFirstPunctuation = true, + }) { // TODO: implement startContinuousRecognition throw UnimplementedError(); } diff --git a/lib/data/services/speech_impl/volcano_asr_service.dart b/lib/data/services/speech_impl/volcano_asr_service.dart index 3ed457c3b..ec36a0385 100644 --- a/lib/data/services/speech_impl/volcano_asr_service.dart +++ b/lib/data/services/speech_impl/volcano_asr_service.dart @@ -397,7 +397,10 @@ class VolcanoAsrService extends GetxService implements AsrService { } @override - Future startContinuousRecognition(bool audioSourceType) { + Future startContinuousRecognition( + bool audioSourceType, { + bool isRemoveFirstPunctuation = true, + }) { // TODO: implement startContinuousRecognition throw UnimplementedError(); } diff --git a/lib/data/services/speech_impl/xunfei_asr_service.dart b/lib/data/services/speech_impl/xunfei_asr_service.dart index 9dda44c97..284e50519 100644 --- a/lib/data/services/speech_impl/xunfei_asr_service.dart +++ b/lib/data/services/speech_impl/xunfei_asr_service.dart @@ -321,7 +321,10 @@ class XunfeiAsrService extends GetxService implements AsrService { } @override - Future startContinuousRecognition(bool audioSourceType) { + Future startContinuousRecognition( + bool audioSourceType, { + bool isRemoveFirstPunctuation = true, + }) { // TODO: implement startContinuousRecognition throw UnimplementedError(); } diff --git a/lib/modules/translation/controllers/translation_controller.dart b/lib/modules/translation/controllers/translation_controller.dart index b31f7dbe3..b7a06dc14 100644 --- a/lib/modules/translation/controllers/translation_controller.dart +++ b/lib/modules/translation/controllers/translation_controller.dart @@ -403,7 +403,10 @@ class TranslationController extends GetxController with WidgetsBindingObserver { if (_asrSessionStartTime == null) { await _initializeSession(); } - await _asrService.startContinuousRecognition(_audioSourceType); //开启识别 + await _asrService.startContinuousRecognition( + _audioSourceType, + isRemoveFirstPunctuation: false, + ); //开启识别 _startAsrActiveTracking(); //开启识别活动跟踪 if (isRecording.value) { if (isCreateRecord.value) { diff --git a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt index 7c8b56e4f..6a6dade10 100644 --- a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt +++ b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt @@ -642,7 +642,7 @@ object AgentService : CoroutineScope { if(isExternalActive){ isKeepResult = true } - azureAsrHelper?.startContinuousRecognition(audioSourceType) + azureAsrHelper?.startContinuousRecognition(audioSourceType, isRemoveFirstPunctuation = false) // 根据模式启动相应的空闲检测 startIdleCheckForMode(mode) diff --git a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt index 8be629ac1..e96133295 100644 --- a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt +++ b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt @@ -238,11 +238,13 @@ class AzureAsrHelper(private val context: Context) { * 开始连续语音识别 * @param audioSourceType 音频源类型 * @param audioDataCallback 音频数据回调 + * @param isRemoveFirstPunctuation 是否移除第一个标点符号 * @return 是否成功开始识别 */ fun startContinuousRecognition( audioSourceType: AudioSourceType = AudioSourceType.MICROPHONE, - audioDataCallback: SimpleAudioReceiver.AudioDataCallback? = null + audioDataCallback: SimpleAudioReceiver.AudioDataCallback? = null, + isRemoveFirstPunctuation: Boolean = true ): Boolean { Log.d(tag, "startContinuousRecognition:${audioStream.isContinuousRecognitionActive} ") @@ -285,7 +287,7 @@ class AzureAsrHelper(private val context: Context) { } try { - xunFeiAsrHelper?.start(callback, currentLanguage, isAutoDetectLanguage) + xunFeiAsrHelper?.start(callback, currentLanguage, isAutoDetectLanguage, isRemoveFirstPunctuation) this.audioSourceType = audioSourceType if (!audioStream.isContinuousRecognitionActive) { diff --git a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt index 09fc9ebe6..b072c4118 100644 --- a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt +++ b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt @@ -449,6 +449,7 @@ class AzureSpeechPlugin : BleService.Callback, FlutterPlugin { "startContinuousRecognition" -> { val useExternalAudio = call.argument("audioSourceType") ?: false + val removeFirstPunctuation = call.argument("isRemoveFirstPunctuation") ?: true // 确保事件通道已准备好 if (asrEventSink == null) { result.error( @@ -468,7 +469,7 @@ class AzureSpeechPlugin : BleService.Callback, FlutterPlugin { AzureAsrHelper.AudioSourceType.MICROPHONE } - val success = azureAsrHelper.startContinuousRecognition(audioSourceType) + val success = azureAsrHelper.startContinuousRecognition(audioSourceType, isRemoveFirstPunctuation = removeFirstPunctuation) result.success(true) } catch (e: Exception) { result.error("START_RECOGNITION_ERROR", e.message, null) diff --git a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/XunFeiAsrHelper.kt b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/XunFeiAsrHelper.kt index f1095bafe..9975fda83 100644 --- a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/XunFeiAsrHelper.kt +++ b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/XunFeiAsrHelper.kt @@ -30,7 +30,10 @@ class XunFeiAsrHelper(private val context: Context) { private var currentLanguage = "zh-CN" private var isAutoDetectLanguage = false - fun start(callback: AzureAsrHelper.ContinuousRecognizeCallback, language: String, isAutoDetect: Boolean) { + // 是否第去除一个文字的标点符号 + private var removeFirstPunctuation = true + + fun start(callback: AzureAsrHelper.ContinuousRecognizeCallback, language: String, isAutoDetect: Boolean, isRemoveFirstPunctuation: Boolean) { try { webSocket?.cancel() webSocket = null @@ -43,6 +46,7 @@ class XunFeiAsrHelper(private val context: Context) { currentLanguage = language isAutoDetectLanguage = isAutoDetect + removeFirstPunctuation = isRemoveFirstPunctuation val url = getWebSocketUrl() val request = Request.Builder().url(url).build() @@ -142,32 +146,35 @@ class XunFeiAsrHelper(private val context: Context) { for (k in 0 until ws.length()) { val kObj = ws.getJSONObject(k) val cw = kObj.optJSONArray("cw") ?: continue - // 如果resultTextTemp中第一个文字是标点符号,则去除第一个文字的标点符号 - for (l in 0 until cw.length()) { - val lObj = cw.getJSONObject(l) - val w = lObj.optString("w") - val wp = lObj.optString("wp") - - if (wp == "p") { - punctuationCount++ - if (resultTextTemp.isEmpty()) { - continue + if(removeFirstPunctuation) { + // 如果resultTextTemp中第一个文字是标点符号,则去除第一个文字的标点符号 + for (l in 0 until cw.length()) { + val lObj = cw.getJSONObject(l) + val w = lObj.optString("w") + val wp = lObj.optString("wp") + + if (wp == "p") { + punctuationCount++ + if (resultTextTemp.isEmpty()) { + continue + } + } else { + wordCount++ + } + resultTextTemp += w + } + } else { + // 不去除resultTextTemp第一个文字的标点符号 + for (l in 0 until cw.length()) { + val lObj = cw.getJSONObject(l) + resultTextTemp += lObj.optString("w") + if (lObj.optString("wp") == "p") { + punctuationCount++ + } else { + wordCount++ } - } else { - wordCount++ } - resultTextTemp += w } - // 不去除resultTextTemp第一个文字的标点符号 - // for (l in 0 until cw.length()) { - // val lObj = cw.getJSONObject(l) - // resultTextTemp += lObj.optString("w") - // if (lObj.optString("wp") == "p") { - // punctuationCount++ - // } else { - // wordCount++ - // } - // } } }