Browse Source

fix: 修复语音识别标点处理及MCP连接稳定性问题

修复语音识别在非push_to_talk模式下未移除首标点的问题,提升听写体验
优化MCP客户端连接管理,增加心跳检测和连接状态主动检查,避免假死连接
移除调试日志语句,避免生产环境日志污染
newdev_shunjiawei
liwei1dao 9 months ago
parent
commit
20c35a3c7a
  1. 10
      lib/modules/translation/controllers/translation_controller.dart
  2. 2
      local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureTtsHelper.swift
  3. 91
      local_plugins/chat_api/ios/chat_api/Sources/chat_api/MCPClient.swift

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

@ -445,7 +445,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver {
}
await _asrService.startContinuousRecognition(
_audioSourceType,
isRemoveFirstPunctuation: false,
isRemoveFirstPunctuation: true,
mode: 'push_to_talk',
); //开启识别
_startAsrActiveTracking(); //开启识别活动跟踪
@ -1066,11 +1066,19 @@ class TranslationController extends GetxController with WidgetsBindingObserver {
/// 启动语音识别
Future<void> _startAsrService(String mode) async {
if (mode == 'push_to_talk') {
await _asrService.startContinuousRecognition(
_audioSourceType,
isRemoveFirstPunctuation: false,
mode: mode,
);
} else {
await _asrService.startContinuousRecognition(
_audioSourceType,
isRemoveFirstPunctuation: true,
mode: mode,
);
}
}
/// 完成识别启动

2
local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureTtsHelper.swift

@ -1455,7 +1455,7 @@ private func ensureAudioSessionQueueSpecificKeySet() {
*/
private func applyAudioSessionForTTS() -> Bool {
var success = true
os_log("liwei-------------TTS applyAudioSessionForTTS currentRecognitionMode:%{public}@", log: self.log, type: .info, currentRecognitionMode)
// os_log("liwei-------------TTS applyAudioSessionForTTS currentRecognitionMode:%{public}@", log: self.log, type: .info, currentRecognitionMode)
ensureAudioSessionQueueSpecificKeySet()
let applyBody = {
if self.isApplyingAudioSessionConfig { return }

91
local_plugins/chat_api/ios/chat_api/Sources/chat_api/MCPClient.swift

@ -36,9 +36,11 @@ public class MCPSubClient {
// 使用官方MCP Swift SDK
private var mcpClient: Client?
private var transport: CustomSseClientTransport?
private var tools: [Tool] = []
private var toolMaps: [[String: Any]] = []
private var isConnectedFlag = false
private let toolsLock = NSLock()
// 重连配置
private let maxRetryAttempts = 3
@ -52,6 +54,10 @@ public class MCPSubClient {
private let maxToolCallRetries = 3
private let toolCallTimeout: TimeInterval = 30.0
private let keepAliveInterval: TimeInterval = 25.0
private let keepAliveTimeout: TimeInterval = 8.0
private var keepAliveTask: Task<Void, Never>?
// 连接状态锁
private let connectionLock = NSLock()
@ -89,6 +95,7 @@ public class MCPSubClient {
}
}
)
self.transport = transport
// 3. 连接到服务器(添加超时)
try await withTimeout(seconds: 10) {
@ -106,6 +113,7 @@ public class MCPSubClient {
isConnectedFlag = true
retryCount = 0 // 重置重试计数
currentReconnectDelay = initialReconnectDelay // 重置延迟
startKeepAlive()
return true
@ -116,6 +124,9 @@ public class MCPSubClient {
}
private func processTools(_ toolList: [Tool]) {
toolsLock.lock()
defer { toolsLock.unlock() }
tools.removeAll()
toolMaps.removeAll()
@ -173,6 +184,13 @@ public class MCPSubClient {
/// 检查连接状态
/// 检查连接状态
public func checkConnection() async -> Bool {
if isConnectedFlag, let transport {
let isActive = await transport.isConnectionActive()
if !isActive {
isConnectedFlag = false
}
}
if !isConnectedFlag {
return await connect()
}
@ -339,14 +357,25 @@ public class MCPSubClient {
}
public func getToolMaps() -> [[String: Any]] {
toolsLock.lock()
defer { toolsLock.unlock() }
return toolMaps
}
public func containsTool(name: String) -> Bool {
toolsLock.lock()
defer { toolsLock.unlock() }
return tools.contains { $0.name == name }
}
public func close() async {
keepAliveTask?.cancel()
keepAliveTask = nil
reconnectTask?.cancel()
reconnectTask = nil
if let client = mcpClient {
await client.disconnect()
}
@ -359,9 +388,9 @@ public class MCPSubClient {
if isConnectedFlag {
print("[\(serverId)] 连接已断开,更新状态")
isConnectedFlag = false
// 启动重连逻辑
// startReconnection()
keepAliveTask?.cancel()
keepAliveTask = nil
startReconnection()
}
}
}
@ -369,7 +398,9 @@ public class MCPSubClient {
/// 启动重连
private func startReconnection() {
// 取消之前的重连任务
reconnectTask?.cancel()
if reconnectTask != nil {
return
}
reconnectTask = Task { [weak self] in
await self?.performReconnection()
@ -378,6 +409,8 @@ public class MCPSubClient {
/// 执行重连
private func performReconnection() async {
defer { reconnectTask = nil }
while retryCount < maxRetryAttempts && !Task.isCancelled {
retryCount += 1
@ -403,6 +436,8 @@ public class MCPSubClient {
private func handleConnectionError(_ error: Error) async {
print("[\(serverId)] 连接错误: \(error.localizedDescription)")
isConnectedFlag = false
keepAliveTask?.cancel()
keepAliveTask = nil
// 如果是MCP特定错误,可以进行特殊处理
if let mcpError = error as? MCPError {
@ -411,9 +446,49 @@ public class MCPSubClient {
}
// 如果还有重试机会,启动重连
// if retryCount < maxRetryAttempts {
// startReconnection()
// }
startReconnection()
}
private func startKeepAlive() {
keepAliveTask?.cancel()
keepAliveTask = Task { [weak self] in
guard let self else { return }
while !Task.isCancelled {
try? await Task.sleep(for: .seconds(self.keepAliveInterval))
if Task.isCancelled {
return
}
if !self.isConnectedFlag {
continue
}
if let transport = self.transport {
let isActive = await transport.isConnectionActive()
if !isActive {
await self.handleConnectionLost()
continue
}
}
guard let client = self.mcpClient else {
await self.handleConnectionError(MCPError.internalError("MCP client not initialized"))
continue
}
do {
let (toolList, _) = try await withTimeout(seconds: self.keepAliveTimeout) {
try await client.listTools()
}
self.processTools(toolList)
} catch {
await self.handleConnectionError(error)
}
}
}
}
/// 获取连接状态
@ -665,7 +740,7 @@ public class MCPClient {
}
public func isConnected() -> Bool {
return !subClients.isEmpty && subClients.values.allSatisfy { $0.getConnectionStatus() }
return !subClients.isEmpty && subClients.values.contains { $0.getConnectionStatus() }
}
public func disconnectAll() async {

Loading…
Cancel
Save