Browse Source

feat(azure_speech): 支持多语言自动检测时选择最佳匹配语言

扩展自动语言检测功能,使其能够从支持的语言列表中选择最佳匹配的语言代码。当检测到中文时,优先选择 zh-CN,其次 zh-HK、zh-TW 或其他 zh- 变体;检测到英文时,优先选择 en-US 或其他 en- 变体。这确保了语音识别使用最准确的语言配置,提升了多语言场景下的识别准确性。
newdev_shunjiawei
lxm 8 months ago
parent
commit
02b5cbea76
  1. 8
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt
  2. 76
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/XunFeiAsrHelper.kt
  3. 5
      local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift
  4. 47
      local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/XunFeiAsrHelper.swift

8
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 { try {
Log.d(tag, "startContinuousRecognition: ${audioStream.isContinuousRecognitionActive}") Log.d(tag, "startContinuousRecognition: ${audioStream.isContinuousRecognitionActive}")
xunFeiAsrHelper?.start(callback, currentLanguage, isAutoDetectLanguage, isRemoveFirstPunctuation) xunFeiAsrHelper?.start(
callback,
currentLanguage,
supportedLanguages.toList(),
isAutoDetectLanguage,
isRemoveFirstPunctuation
)
this.audioSourceType = audioSourceType this.audioSourceType = audioSourceType
if (!audioStream.isContinuousRecognitionActive) { if (!audioStream.isContinuousRecognitionActive) {

76
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 lastIntermediateResult = ""
private var currentLanguage = "zh-CN" private var currentLanguage = "zh-CN"
private var supportedLanguages: List<String> = emptyList()
private var isAutoDetectLanguage = false private var isAutoDetectLanguage = false
// 是否第去除一个文字的标点符号 // 是否第去除一个文字的标点符号
@ -58,7 +59,13 @@ class XunFeiAsrHelper(private val context: Context) {
return appId.isNotBlank() && accessKeyId.isNotBlank() && accessKeySecret.isNotBlank() 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<String>,
isAutoDetect: Boolean,
isRemoveFirstPunctuation: Boolean
) {
try { try {
webSocket?.cancel() webSocket?.cancel()
webSocket = null webSocket = null
@ -70,6 +77,7 @@ class XunFeiAsrHelper(private val context: Context) {
lastIntermediateResult = "" lastIntermediateResult = ""
currentLanguage = language currentLanguage = language
this.supportedLanguages = supportedLanguages
isAutoDetectLanguage = isAutoDetect isAutoDetectLanguage = isAutoDetect
removeFirstPunctuation = isRemoveFirstPunctuation removeFirstPunctuation = isRemoveFirstPunctuation
@ -99,15 +107,7 @@ class XunFeiAsrHelper(private val context: Context) {
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
Log.d(tag, "WebSocket Closed: $code / $reason") Log.d(tag, "WebSocket Closed: $code / $reason")
if (currentSessionId.isNotEmpty() && lastIntermediateResult.isNotEmpty()) { if (currentSessionId.isNotEmpty() && lastIntermediateResult.isNotEmpty()) {
val detectedLanguage = if (isAutoDetectLanguage) { val detectedLanguage = selectDetectedLanguage(lastIntermediateResult)
if (lastIntermediateResult.contains(Regex("[\\u4e00-\\u9fa5]"))) {
"zh-CN"
} else {
"en-US"
}
} else {
currentLanguage
}
callback.onResult(currentSessionId, lastIntermediateResult, detectedLanguage) callback.onResult(currentSessionId, lastIntermediateResult, detectedLanguage)
} }
callback.onSessionStopped(currentSessionId) callback.onSessionStopped(currentSessionId)
@ -219,15 +219,7 @@ class XunFeiAsrHelper(private val context: Context) {
return return
} }
val detectedLanguage = if (isAutoDetectLanguage) { val detectedLanguage = selectDetectedLanguage(resultTextTemp)
if (resultTextTemp.contains(Regex("[\\u4e00-\\u9fa5]"))) {
"zh-CN"
} else {
"en-US"
}
} else {
currentLanguage
}
if (st.optInt("type") == 0) { if (st.optInt("type") == 0) {
callback.onResult(currentSessionId, resultTextTemp, detectedLanguage) 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 { private fun getWebSocketUrl(): String {
val baseWsUrl = "wss://office-api-ast-dx.iflyaisol.com/ast/communicate/v1" val baseWsUrl = "wss://office-api-ast-dx.iflyaisol.com/ast/communicate/v1"

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

@ -490,7 +490,10 @@ public class AzureAsrHelper: NSObject {
// 启动讯飞识别 // 启动讯飞识别
xunFeiAsrHelper?.start( xunFeiAsrHelper?.start(
callback: callback, language: currentLanguage, isAutoDetect: isAutoDetectLanguage, callback: callback,
language: currentLanguage,
supportedLanguages: supportedLanguages,
isAutoDetect: isAutoDetectLanguage,
isRemoveFirstPunctuation: isRemoveFirstPunctuation) isRemoveFirstPunctuation: isRemoveFirstPunctuation)
// 创建代理回调,将音频数据转发给讯飞 // 创建代理回调,将音频数据转发给讯飞

47
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 lastIntermediateResult = ""
private var currentLanguage = "zh-CN" private var currentLanguage = "zh-CN"
private var supportedLanguages: [String] = []
private var isAutoDetectLanguage = false private var isAutoDetectLanguage = false
// 是否第去除一个文字的标点符号 // 是否第去除一个文字的标点符号
@ -47,11 +48,12 @@ class XunFeiAsrHelper: NSObject, URLSessionWebSocketDelegate {
return !appId.isEmpty && !accessKeyId.isEmpty && !accessKeySecret.isEmpty 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() stop()
self.callback = callback self.callback = callback
self.currentLanguage = language self.currentLanguage = language
self.supportedLanguages = supportedLanguages
self.isAutoDetectLanguage = isAutoDetect self.isAutoDetectLanguage = isAutoDetect
self.removeFirstPunctuation = isRemoveFirstPunctuation self.removeFirstPunctuation = isRemoveFirstPunctuation
self.currentSessionId = UUID().uuidString self.currentSessionId = UUID().uuidString
@ -268,16 +270,43 @@ class XunFeiAsrHelper: NSObject, URLSessionWebSocketDelegate {
} }
} }
private func detectLanguage(from text: String) -> String { private func normalizeLanguageCode(_ code: String) -> String {
if isAutoDetectLanguage { let trimmed = code.trimmingCharacters(in: .whitespacesAndNewlines)
if text.range(of: "[\\u4e00-\\u9fa5]", options: .regularExpression) != nil { if trimmed.isEmpty { return trimmed }
return "zh-CN" let parts = trimmed.split(separator: "-")
} else { let lang = parts.first?.lowercased() ?? trimmed.lowercased()
return "en-US" let region = parts.count > 1 ? parts[1].uppercased() : ""
return region.isEmpty ? lang : "\(lang)-\(region)"
} }
} else {
return currentLanguage 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 {
guard isAutoDetectLanguage else { return currentLanguage }
let hasChinese = text.range(of: "[\\u4e00-\\u9fa5]", options: .regularExpression) != nil
return hasChinese ? pickPreferredChineseLanguage() : pickPreferredEnglishLanguage()
} }
private func getWebSocketUrl() -> String { private func getWebSocketUrl() -> String {

Loading…
Cancel
Save