|
|
|
@ -60,6 +60,8 @@ class AgentServiceImpl: NSObject { |
|
|
|
|
|
|
|
// 会话ID,用于区分不同聊天上下文 |
|
|
|
private let agentId = "default_agent" |
|
|
|
//工具调用提示 |
|
|
|
public var callingTool = "" |
|
|
|
|
|
|
|
private var isInitialized: Bool = false |
|
|
|
private var isRecognizing: Bool = false |
|
|
|
@ -162,6 +164,11 @@ class AgentServiceImpl: NSObject { |
|
|
|
// os_log("initialize: config=%{public}@", log: logger, type: .info, config) |
|
|
|
|
|
|
|
self.config = config |
|
|
|
|
|
|
|
if let callingTool = config["callingTool"] as? String { |
|
|
|
self.callingTool = callingTool |
|
|
|
} |
|
|
|
|
|
|
|
if let serverurl = config["serverurl"] as? String { |
|
|
|
self.serverurl = serverurl |
|
|
|
} |
|
|
|
@ -642,7 +649,7 @@ audioStream.saveAudioDataTo(data: audioData) |
|
|
|
os_log("添加用户消息", log: logger, type: .info) |
|
|
|
|
|
|
|
addToHistoryMessages(chatApiService.createUserMessage(content: displayText)) |
|
|
|
|
|
|
|
currsessionId = sessionid |
|
|
|
let callback = ChatApiStreamCallback( |
|
|
|
agentService: self, |
|
|
|
speakResponse: speakResponse, |
|
|
|
@ -650,11 +657,10 @@ audioStream.saveAudioDataTo(data: audioData) |
|
|
|
hasImage: hasImage, |
|
|
|
imagePath: imagePath |
|
|
|
) |
|
|
|
currsessionId = sessionid |
|
|
|
azureTtsHelper?.startspeak(sessionid: currsessionId) |
|
|
|
azureTtsHelper?.startspeak(sessionid: sessionid) |
|
|
|
os_log("设置回调并调用sendMessageStream", log: logger, type: .info) |
|
|
|
chatApiService.setStreamCallback(currsessionId,callback) |
|
|
|
chatApiService.sendMessageStream(currsessionId,messages: messages) |
|
|
|
chatApiService.setStreamCallback(sessionid,callback) |
|
|
|
chatApiService.sendMessageStream(sessionid,messages: messages) |
|
|
|
audioPlayer?.playAwaitSound() |
|
|
|
os_log("sendMessageStream调用完成", log: logger, type: .info) |
|
|
|
} |
|
|
|
@ -1613,6 +1619,7 @@ class ChatApiStreamCallback: StreamCallback { |
|
|
|
private var iscard = false; |
|
|
|
private var reply = true; //是否回复 |
|
|
|
private var broadcast = true //是否播发 |
|
|
|
private var iscallingTool = true; //是否调用工具 |
|
|
|
|
|
|
|
init(agentService: AgentServiceImpl, speakResponse: Bool, displayText: String, hasImage: Bool,imagePath:String) { |
|
|
|
self.agentService = agentService |
|
|
|
@ -1627,45 +1634,46 @@ class ChatApiStreamCallback: StreamCallback { |
|
|
|
func onUsage(_ sessionid: String,_ prompt_tokens: Int?,_ completion_tokens: Int?,_ total_tokens: Int?){ |
|
|
|
|
|
|
|
} |
|
|
|
func onToken(_ sessionId:String,_ token: String) { |
|
|
|
func onToken(_ sessionid:String,_ token: String) { |
|
|
|
do { |
|
|
|
// print("liwei--------------- AI Call onToken! sessionId:\(sessionId) token:\(token)") |
|
|
|
guard let agentService = try agentService else { return } |
|
|
|
if (sessionId != agentService.currsessionId) { |
|
|
|
guard let agentService = try agentService else { return } |
|
|
|
// print("liwei--------------- AI Call onToken! sessionId:\(sessionid) currsessionId:\(agentService.currsessionId) token:\(token)") |
|
|
|
if (sessionid != agentService.currsessionId) { |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
responseBuilder += token |
|
|
|
|
|
|
|
if speakResponse && reply && broadcast{ |
|
|
|
try agentService.azureTtsHelper?.speakStream(sessionid:sessionId,token) |
|
|
|
try agentService.azureTtsHelper?.speakStream(sessionid:sessionid,token) |
|
|
|
// 在开始流式TTS时立即停止气泡音 |
|
|
|
} |
|
|
|
if (reply && token != "") { |
|
|
|
try agentService.sendEvent(name: "assistant_token", data: ["token": token]) |
|
|
|
try agentService.sendEvent(name: "assistant_token", data: ["sessionid":sessionid,"token": token]) |
|
|
|
} |
|
|
|
}catch { |
|
|
|
print("liwei--------------- AI Call onToken 异常: \(error)") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func onComplete(_ sessionId:String) { |
|
|
|
func onComplete(_ sessionid:String) { |
|
|
|
do { |
|
|
|
guard let agentService = try agentService else { return } |
|
|
|
|
|
|
|
if sessionId == agentService.currsessionId { |
|
|
|
if sessionid == agentService.currsessionId { |
|
|
|
// 停止等待音效 |
|
|
|
agentService.audioPlayer?.stopAwaitSound() |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if speakResponse && reply && broadcast && sessionId == agentService.currsessionId{ |
|
|
|
agentService.azureTtsHelper?.flushStream(sessionid:sessionId) |
|
|
|
if speakResponse && reply && broadcast && sessionid == agentService.currsessionId{ |
|
|
|
agentService.azureTtsHelper?.flushStream(sessionid:sessionid) |
|
|
|
} |
|
|
|
|
|
|
|
let response = responseBuilder |
|
|
|
|
|
|
|
var responseData: [String: Any] = [ |
|
|
|
"sessionid":sessionid, |
|
|
|
"text": response, |
|
|
|
"userInput": displayText |
|
|
|
] |
|
|
|
@ -1684,8 +1692,9 @@ class ChatApiStreamCallback: StreamCallback { |
|
|
|
try agentService.addToHistoryMessages(assistantMessage) |
|
|
|
} |
|
|
|
// 保存聊天记录 |
|
|
|
try agentService.saveChatMessage(sessionId: sessionId,userMessage: displayText, assistantMessage: response, metadata: metadata,userMetadata:toJSONString(userMetadata)) |
|
|
|
try agentService.saveChatMessage(sessionId: sessionid,userMessage: displayText, assistantMessage: response, metadata: metadata,userMetadata:toJSONString(userMetadata)) |
|
|
|
agentService.isAiStreaming = false |
|
|
|
iscallingTool = true |
|
|
|
os_log("设置AI流式状态为false", log: agentService.logger, type: .info) |
|
|
|
}catch{ |
|
|
|
print("liwei--------------- AI Call onComplete 异常: \(error)") |
|
|
|
@ -1693,20 +1702,21 @@ class ChatApiStreamCallback: StreamCallback { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
func onError(_ sessionId:String,_ error: Error) { |
|
|
|
func onError(_ sessionid:String,_ error: Error) { |
|
|
|
do { |
|
|
|
guard let agentService = try agentService else { return } |
|
|
|
|
|
|
|
if sessionId == agentService.currsessionId { |
|
|
|
if sessionid == agentService.currsessionId { |
|
|
|
// 停止等待音效 |
|
|
|
agentService.audioPlayer?.stopAwaitSound() |
|
|
|
} |
|
|
|
|
|
|
|
os_log("ChatAPI错误: %{public}@", log: agentService.logger, type: .error, error.localizedDescription) |
|
|
|
if (sessionId != agentService.currsessionId) { |
|
|
|
if (sessionid != agentService.currsessionId) { |
|
|
|
return |
|
|
|
} |
|
|
|
try agentService.sendEvent(name: "error", data: [ |
|
|
|
"sessionid":sessionid, |
|
|
|
"code": "AI_ERROR", |
|
|
|
"message": error.localizedDescription |
|
|
|
]) |
|
|
|
@ -1719,27 +1729,34 @@ class ChatApiStreamCallback: StreamCallback { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
func onFunctionCall(_ sessionId:String,_ functionCall: [String: Any]) { |
|
|
|
func onFunctionCall(_ sessionid:String,_ functionCall: [String: Any]) { |
|
|
|
do { |
|
|
|
guard let agentService = try agentService else { return } |
|
|
|
if (sessionId != agentService.currsessionId) { |
|
|
|
if (sessionid != agentService.currsessionId) { |
|
|
|
return |
|
|
|
} |
|
|
|
let name = functionCall["name"] as? String ?? "" |
|
|
|
os_log("收到函数调用: %{public}@", log: agentService.logger, type: .info, name) |
|
|
|
let arguments = functionCall["arguments"] as? String ?? "" |
|
|
|
os_log("收到函数调用:%{public}@", log: agentService.logger, type: .info, functionCall) |
|
|
|
print("onFunctionCall=functionCall\(functionCall)") |
|
|
|
|
|
|
|
if (name == "exit_interaction") { |
|
|
|
// 关闭编码器 (设备侧) |
|
|
|
BleService.shared.closeCodec() |
|
|
|
agentService.stopRecognition() |
|
|
|
} |
|
|
|
BleService.shared.closeCodec() |
|
|
|
agentService.stopRecognition() |
|
|
|
} |
|
|
|
|
|
|
|
try agentService.sendEvent(name: "function_call", data: [ |
|
|
|
"sessionid":sessionid, |
|
|
|
"name": name, |
|
|
|
"arguments": functionCall |
|
|
|
"arguments": arguments |
|
|
|
]) |
|
|
|
|
|
|
|
|
|
|
|
if (iscallingTool) { |
|
|
|
os_log("收到函数调用: callingTool:%{public}@", log: agentService.logger, type: .info, agentService.callingTool) |
|
|
|
agentService.azureTtsHelper?.speakStream(sessionid: sessionid,agentService.callingTool) |
|
|
|
iscallingTool = false |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}catch{ |
|
|
|
@ -1748,7 +1765,7 @@ class ChatApiStreamCallback: StreamCallback { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
func onFunctionCallResult(_ sessionId:String,_ functionCall: [String: Any], _ functionCallResult: [String: Any]) { |
|
|
|
func onFunctionCallResult(_ sessionid:String,_ functionCall: [String: Any], _ functionCallResult: [String: Any]) { |
|
|
|
do { |
|
|
|
guard let agentService = agentService else { return } |
|
|
|
|
|
|
|
@ -1763,6 +1780,8 @@ class ChatApiStreamCallback: StreamCallback { |
|
|
|
iscard = !(resultmap["iscard"] as? Bool ?? false) |
|
|
|
if (iscard){ |
|
|
|
agentService.sendEvent(name: "function_call_result", data: [ |
|
|
|
"sessionid":sessionid, |
|
|
|
"function_name": name, |
|
|
|
"function_call": functionCall, |
|
|
|
"result": functionCallResult, |
|
|
|
"meta":metadata, |
|
|
|
@ -2066,7 +2085,7 @@ class AudioPlayer { |
|
|
|
extension AgentServiceImpl: AzureAsrHelper.ContinuousRecognizeCallback { |
|
|
|
func onResult(sessionid:String ,_ text: String, _ detectedLanguage: String) { |
|
|
|
if !text.isEmpty && isKeepResult { |
|
|
|
var data: [String: Any] = ["text": text] |
|
|
|
var data: [String: Any] = ["sessionid":sessionid,"text": text] |
|
|
|
if !detectedLanguage.isEmpty { |
|
|
|
data["language"] = detectedLanguage |
|
|
|
} |
|
|
|
@ -2093,7 +2112,7 @@ extension AgentServiceImpl: AzureAsrHelper.ContinuousRecognizeCallback { |
|
|
|
restartIdleCheck() |
|
|
|
} |
|
|
|
|
|
|
|
var data: [String: Any] = ["text": recognizing] |
|
|
|
var data: [String: Any] = ["sessionid":sessionid,"text": recognizing] |
|
|
|
if !detectedLanguage.isEmpty { |
|
|
|
data["language"] = detectedLanguage |
|
|
|
} |
|
|
|
@ -2106,7 +2125,7 @@ extension AgentServiceImpl: AzureAsrHelper.ContinuousRecognizeCallback { |
|
|
|
} |
|
|
|
|
|
|
|
func onSessionStarted(sessionid:String) { |
|
|
|
sendEvent(name: "recognition_started", data: ["status": "started"]) |
|
|
|
sendEvent(name: "recognition_started", data: ["sessionid":sessionid,"status": "started"]) |
|
|
|
isRecognizing = true |
|
|
|
hasSpeechDetected = false |
|
|
|
// 新增:会话真正启动,复位"启动中"状态 |
|
|
|
@ -2127,7 +2146,7 @@ extension AgentServiceImpl: AzureAsrHelper.ContinuousRecognizeCallback { |
|
|
|
} |
|
|
|
|
|
|
|
func onSessionStopped(sessionid:String) { |
|
|
|
sendEvent(name: "recognition_stopped", data: ["status": "stopped"]) |
|
|
|
sendEvent(name: "recognition_stopped", data: ["sessionid":sessionid,"status": "stopped"]) |
|
|
|
isRecognizing = false |
|
|
|
hasSpeechDetected = false |
|
|
|
stopIdleCheck() |
|
|
|
@ -2137,7 +2156,7 @@ extension AgentServiceImpl: AzureAsrHelper.ContinuousRecognizeCallback { |
|
|
|
} |
|
|
|
|
|
|
|
func onCanceled(sessionid:String ,_ reason: String, _ errorDetails: String) { |
|
|
|
var data: [String: Any] = [:] |
|
|
|
var data: [String: Any] = ["sessionid":sessionid] |
|
|
|
if !reason.isEmpty { |
|
|
|
data["reason"] = reason |
|
|
|
} |
|
|
|
@ -2154,7 +2173,7 @@ extension AgentServiceImpl: AzureAsrHelper.ContinuousRecognizeCallback { |
|
|
|
} |
|
|
|
|
|
|
|
func onError(sessionid:String ,_ errorCode: Int, _ error: String) { |
|
|
|
let data: [String: Any] = ["message": error.isEmpty ? "未知错误" : error] |
|
|
|
let data: [String: Any] = ["sessionid":sessionid,"message": error.isEmpty ? "未知错误" : error] |
|
|
|
sendEvent(name: "error", data: data) |
|
|
|
isRecognizing = false |
|
|
|
// 新增:出错时复位"启动中/待停止"状态 |
|
|
|
|