From 02b5cbea76ba648610ee4dfef764d22541e91d31 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Tue, 3 Feb 2026 10:40:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(azure=5Fspeech):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=9A=E8=AF=AD=E8=A8=80=E8=87=AA=E5=8A=A8=E6=A3=80=E6=B5=8B?= =?UTF-8?q?=E6=97=B6=E9=80=89=E6=8B=A9=E6=9C=80=E4=BD=B3=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E8=AF=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 扩展自动语言检测功能,使其能够从支持的语言列表中选择最佳匹配的语言代码。当检测到中文时,优先选择 zh-CN,其次 zh-HK、zh-TW 或其他 zh- 变体;检测到英文时,优先选择 en-US 或其他 en- 变体。这确保了语音识别使用最准确的语言配置,提升了多语言场景下的识别准确性。 --- .../azure_speech/AzureAsrHelper.kt | 8 +- .../azure_speech/XunFeiAsrHelper.kt | 76 ++++++++++++++----- .../Sources/azure_speech/AzureAsrHelper.swift | 5 +- .../azure_speech/XunFeiAsrHelper.swift | 49 +++++++++--- 4 files changed, 107 insertions(+), 31 deletions(-) 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 a01e75561..1f6ac4e1e 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 @@ -325,7 +325,13 @@ class AzureAsrHelper(private val context: Context) { try { Log.d(tag, "startContinuousRecognition: ${audioStream.isContinuousRecognitionActive}") - xunFeiAsrHelper?.start(callback, currentLanguage, isAutoDetectLanguage, isRemoveFirstPunctuation) + xunFeiAsrHelper?.start( + callback, + currentLanguage, + supportedLanguages.toList(), + isAutoDetectLanguage, + isRemoveFirstPunctuation + ) this.audioSourceType = audioSourceType if (!audioStream.isContinuousRecognitionActive) { 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 4ebd748ff..039a2bafd 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 @@ -34,6 +34,7 @@ class XunFeiAsrHelper(private val context: Context) { private var lastIntermediateResult = "" private var currentLanguage = "zh-CN" + private var supportedLanguages: List = emptyList() private var isAutoDetectLanguage = false // 是否第去除一个文字的标点符号 @@ -58,7 +59,13 @@ class XunFeiAsrHelper(private val context: Context) { return appId.isNotBlank() && accessKeyId.isNotBlank() && accessKeySecret.isNotBlank() } - fun start(callback: AzureAsrHelper.ContinuousRecognizeCallback, language: String, isAutoDetect: Boolean, isRemoveFirstPunctuation: Boolean) { + fun start( + callback: AzureAsrHelper.ContinuousRecognizeCallback, + language: String, + supportedLanguages: List, + isAutoDetect: Boolean, + isRemoveFirstPunctuation: Boolean + ) { try { webSocket?.cancel() webSocket = null @@ -70,6 +77,7 @@ class XunFeiAsrHelper(private val context: Context) { lastIntermediateResult = "" currentLanguage = language + this.supportedLanguages = supportedLanguages isAutoDetectLanguage = isAutoDetect removeFirstPunctuation = isRemoveFirstPunctuation @@ -99,15 +107,7 @@ class XunFeiAsrHelper(private val context: Context) { override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { Log.d(tag, "WebSocket Closed: $code / $reason") if (currentSessionId.isNotEmpty() && lastIntermediateResult.isNotEmpty()) { - val detectedLanguage = if (isAutoDetectLanguage) { - if (lastIntermediateResult.contains(Regex("[\\u4e00-\\u9fa5]"))) { - "zh-CN" - } else { - "en-US" - } - } else { - currentLanguage - } + val detectedLanguage = selectDetectedLanguage(lastIntermediateResult) callback.onResult(currentSessionId, lastIntermediateResult, detectedLanguage) } callback.onSessionStopped(currentSessionId) @@ -219,15 +219,7 @@ class XunFeiAsrHelper(private val context: Context) { return } - val detectedLanguage = if (isAutoDetectLanguage) { - if (resultTextTemp.contains(Regex("[\\u4e00-\\u9fa5]"))) { - "zh-CN" - } else { - "en-US" - } - } else { - currentLanguage - } + val detectedLanguage = selectDetectedLanguage(resultTextTemp) if (st.optInt("type") == 0) { callback.onResult(currentSessionId, resultTextTemp, detectedLanguage) @@ -254,6 +246,52 @@ class XunFeiAsrHelper(private val context: Context) { } } + private fun normalizeLanguageCode(code: String): String { + val trimmed = code.trim() + if (trimmed.isEmpty()) return trimmed + + val parts = trimmed.split("-") + val lang = parts.getOrNull(0)?.lowercase() ?: trimmed.lowercase() + val region = parts.getOrNull(1)?.uppercase() + return if (region.isNullOrEmpty()) lang else "$lang-$region" + } + + private fun findSupportedExact(target: String): String? { + val targetNorm = normalizeLanguageCode(target) + return supportedLanguages.firstOrNull { normalizeLanguageCode(it) == targetNorm } + } + + private fun findSupportedPrefix(prefix: String): String? { + val p = prefix.lowercase() + return supportedLanguages.firstOrNull { normalizeLanguageCode(it).startsWith(p) } + } + + + private fun pickPreferredChineseLanguage(): String { + return findSupportedExact("zh-CN") + ?: findSupportedExact("zh-HK") + ?: findSupportedExact("zh-TW") + ?: findSupportedPrefix("zh") + ?: currentLanguage + } + + private fun pickPreferredEnglishLanguage(): String { + return findSupportedExact("en-US") + ?: findSupportedPrefix("en") + ?: currentLanguage + } + + // 选择检测到的语言 + // 如果开启了自动检测语言,根据文本内容判断是否为中文 + // 如果是中文,选择中文语言;否则选择英文语言 + // 如果未开启自动检测语言,返回当前语言 + private fun selectDetectedLanguage(text: String): String { + if (!isAutoDetectLanguage) return currentLanguage + + val hasChinese = text.contains(Regex("[\\u4e00-\\u9fa5]")) + return if (hasChinese) pickPreferredChineseLanguage() else pickPreferredEnglishLanguage() + } + private fun getWebSocketUrl(): String { val baseWsUrl = "wss://office-api-ast-dx.iflyaisol.com/ast/communicate/v1" diff --git a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift index e12d4ed03..fc8f112ca 100644 --- a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift +++ b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift @@ -490,7 +490,10 @@ public class AzureAsrHelper: NSObject { // 启动讯飞识别 xunFeiAsrHelper?.start( - callback: callback, language: currentLanguage, isAutoDetect: isAutoDetectLanguage, + callback: callback, + language: currentLanguage, + supportedLanguages: supportedLanguages, + isAutoDetect: isAutoDetectLanguage, isRemoveFirstPunctuation: isRemoveFirstPunctuation) // 创建代理回调,将音频数据转发给讯飞 diff --git a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/XunFeiAsrHelper.swift b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/XunFeiAsrHelper.swift index bc63bcaee..f17d356ad 100644 --- a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/XunFeiAsrHelper.swift +++ b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/XunFeiAsrHelper.swift @@ -23,6 +23,7 @@ class XunFeiAsrHelper: NSObject, URLSessionWebSocketDelegate { private var lastIntermediateResult = "" private var currentLanguage = "zh-CN" + private var supportedLanguages: [String] = [] private var isAutoDetectLanguage = false // 是否第去除一个文字的标点符号 @@ -47,11 +48,12 @@ class XunFeiAsrHelper: NSObject, URLSessionWebSocketDelegate { return !appId.isEmpty && !accessKeyId.isEmpty && !accessKeySecret.isEmpty } - func start(callback: AzureAsrHelper.ContinuousRecognizeCallback, language: String, isAutoDetect: Bool, isRemoveFirstPunctuation: Bool) { + func start(callback: AzureAsrHelper.ContinuousRecognizeCallback, language: String, supportedLanguages: [String], isAutoDetect: Bool, isRemoveFirstPunctuation: Bool) { stop() self.callback = callback self.currentLanguage = language + self.supportedLanguages = supportedLanguages self.isAutoDetectLanguage = isAutoDetect self.removeFirstPunctuation = isRemoveFirstPunctuation self.currentSessionId = UUID().uuidString @@ -268,16 +270,43 @@ class XunFeiAsrHelper: NSObject, URLSessionWebSocketDelegate { } } + private func normalizeLanguageCode(_ code: String) -> String { + let trimmed = code.trimmingCharacters(in: .whitespacesAndNewlines) + if trimmed.isEmpty { return trimmed } + let parts = trimmed.split(separator: "-") + let lang = parts.first?.lowercased() ?? trimmed.lowercased() + let region = parts.count > 1 ? parts[1].uppercased() : "" + return region.isEmpty ? lang : "\(lang)-\(region)" + } + + private func findSupportedExact(_ target: String) -> String? { + let targetNorm = normalizeLanguageCode(target) + return supportedLanguages.first { normalizeLanguageCode($0) == targetNorm } + } + + private func findSupportedPrefix(_ prefix: String) -> String? { + let p = prefix.lowercased() + return supportedLanguages.first { normalizeLanguageCode($0).hasPrefix(p) } + } + + private func pickPreferredChineseLanguage() -> String { + return findSupportedExact("zh-CN") + ?? findSupportedExact("zh-HK") + ?? findSupportedExact("zh-TW") + ?? findSupportedPrefix("zh") + ?? currentLanguage + } + + private func pickPreferredEnglishLanguage() -> String { + return findSupportedExact("en-US") + ?? findSupportedPrefix("en") + ?? currentLanguage + } + private func detectLanguage(from text: String) -> String { - if isAutoDetectLanguage { - if text.range(of: "[\\u4e00-\\u9fa5]", options: .regularExpression) != nil { - return "zh-CN" - } else { - return "en-US" - } - } else { - return currentLanguage - } + guard isAutoDetectLanguage else { return currentLanguage } + let hasChinese = text.range(of: "[\\u4e00-\\u9fa5]", options: .regularExpression) != nil + return hasChinese ? pickPreferredChineseLanguage() : pickPreferredEnglishLanguage() } private func getWebSocketUrl() -> String {