diff --git a/iOS/AgoraEntScenarios/AppDelegate.swift b/iOS/AgoraEntScenarios/AppDelegate.swift index 6da8308108..265de961a2 100644 --- a/iOS/AgoraEntScenarios/AppDelegate.swift +++ b/iOS/AgoraEntScenarios/AppDelegate.swift @@ -37,6 +37,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { isDebugMode = false } + AppContext.shared.isDebugMode = isDebugMode AppContext.shared.appId = KeyCenter.AppId AppContext.shared.certificate = KeyCenter.Certificate ?? "" AppContext.shared.hostUrl = KeyCenter.HostUrl @@ -51,6 +52,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { AppContext.shared.hyAPIKey = KeyCenter.HyAPIKey ?? "" AppContext.shared.hyAPISecret = KeyCenter.HyAPISecret ?? "" + AppContext.shared.aichatAgentHost = isDebugMode ? KeyCenter.AIChatAgentServerDevUrl : KeyCenter.AIChatAgentServerUrl + AGResourceManagerContext.shared.displayLogClosure = { text in asyncToMainThread { CommonLogger.default_info(text, tag: "ResourceManager") diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Assets/AIChat.bundle/en.lproj/Localizable.strings b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Assets/AIChat.bundle/en.lproj/Localizable.strings index 54ea35a76f..1de181683b 100644 Binary files a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Assets/AIChat.bundle/en.lproj/Localizable.strings and b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Assets/AIChat.bundle/en.lproj/Localizable.strings differ diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Assets/AIChat.bundle/zh-Hans.lproj/Localizable.strings b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Assets/AIChat.bundle/zh-Hans.lproj/Localizable.strings index a8fc8c946a..910c7ebcb5 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Assets/AIChat.bundle/zh-Hans.lproj/Localizable.strings +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Assets/AIChat.bundle/zh-Hans.lproj/Localizable.strings @@ -1,3 +1,5 @@ "aichat_common_greeting"="今天有什么能帮到你?"; "aichat_custom_greeting"="今天有什么想要聊聊的?"; + +"aichat_interrupt_success"="打断成功!我在听,请讲"; diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Implement/AIChatBotImplement.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Implement/AIChatBotImplement.swift index 135d8ff846..f416df7be9 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Implement/AIChatBotImplement.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Implement/AIChatBotImplement.swift @@ -295,7 +295,7 @@ extension AIChatBotImplement: AIChatBotServiceProtocol { public class AIChatUserAgentDeleteNetworkModel: AUINetworkModel { - public var username = VLUserCenter.user.id + public var username = AppContext.shared.getAIChatUid() public var toDeleteUsername = "" { didSet { @@ -305,10 +305,10 @@ public class AIChatUserAgentDeleteNetworkModel: AUINetworkModel { public override init() { super.init() - self.host = "https://ai-chat-service-staging.sh3t.agoralab.co" + self.host = AppContext.shared.aichatAgentHost // AppContext.shared.hostUrl self.method = .delete - self.interfaceName = "/v1/projects/\(AppContext.shared.appId)/chat/users/\(VLUserCenter.user.id)/toDeleteAgent/" + self.interfaceName = "/v1/projects/\(AppContext.shared.appId)/chat/users/\(AppContext.shared.getAIChatUid())/toDeleteAgent/" } public override func parse(data: Data?) throws -> Any? { @@ -331,11 +331,11 @@ public class AIChatUserCreateNetworkModel: AUINetworkModel { public var userType: UInt32 = 0 //0普通用户 1 agent机器人 2群组用户 - public var username = VLUserCenter.user.id + public var username = AppContext.shared.getAIChatUid() public override init() { super.init() - self.host = "https://ai-chat-service-staging.sh3t.agoralab.co" + self.host = AppContext.shared.aichatAgentHost // AppContext.shared.hostUrl self.method = .post self.interfaceName = "/v1/projects/\(AppContext.shared.appId)/chat/users" @@ -368,13 +368,13 @@ public class AIChatUpdateUserInfoNetworkModel: AUINetworkModel { public var ext = "" - public var username = VLUserCenter.user.id + public var username = AppContext.shared.getAIChatUid() public var birth = "female-chengshu" public override init() { super.init() - self.host = "https://ai-chat-service-staging.sh3t.agoralab.co" + self.host = AppContext.shared.aichatAgentHost // AppContext.shared.hostUrl self.method = .put self.interfaceName = "/v1/projects/\(AppContext.shared.appId)/chat/metadata/user/" @@ -410,16 +410,14 @@ public class AIChatAddFriendNetworkModel: AUINetworkModel { public var friendId = "" { didSet { - self.interfaceName = "/v1/projects/\(AppContext.shared.appId)/chat/users/\(VLUserCenter.user.id)/contacts/users/\(self.friendId)" + self.interfaceName = "/v1/projects/\(AppContext.shared.appId)/chat/users/\(AppContext.shared.getAIChatUid())/contacts/users/\(self.friendId)" } } public override init() { super.init() - self.host = "https://ai-chat-service-staging.sh3t.agoralab.co" + self.host = AppContext.shared.aichatAgentHost } - - } @@ -428,7 +426,7 @@ public class AIChatTTSNetworkModel: AUINetworkModel { public var voiceId: String = "" public override init() { super.init() - self.host = "https://ai-chat-service-staging.sh3t.agoralab.co" + self.host = AppContext.shared.aichatAgentHost self.interfaceName = "/v1/projects/\(AppContext.shared.appId)/voice/tts" } diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Implement/AIChatImplement.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Implement/AIChatImplement.swift index 701dc6279a..2653419c65 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Implement/AIChatImplement.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Implement/AIChatImplement.swift @@ -114,7 +114,7 @@ public class AIChatImplement: NSObject { } func login(token: String,completion: @escaping (Error?) -> Void) { - AgoraChatClient.shared().login(withUsername: VLUserCenter.user.id, agoraToken: token) { [weak self] (userID, error) in + AgoraChatClient.shared().login(withUsername: AppContext.shared.getAIChatUid(), agoraToken: token) { [weak self] (userID, error) in SVProgressHUD.dismiss() if error != nil { if error?.code == .userAlreadyLoginSame { @@ -204,7 +204,7 @@ extension AIChatImplement: AgoraChatManagerDelegate { class AIChatTokenGenerator: AUINetworkModel { - var uid = VLUserCenter.user.id + var uid = AppContext.shared.getAIChatUid() var expire = UInt32(60*60*24) @@ -213,7 +213,7 @@ class AIChatTokenGenerator: AUINetworkModel { override init() { super.init() self.method = .post - self.host = "https://ai-chat-service-staging.sh3t.agoralab.co" + self.host = AppContext.shared.aichatAgentHost self.interfaceName = "/v1/projects/\(AppContext.shared.appId)/chat/token" } diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Models/AIChatAgentNetworkModel.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Models/AIChatAgentNetworkModel.swift index bc575834df..2fab4268e7 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Models/AIChatAgentNetworkModel.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Models/AIChatAgentNetworkModel.swift @@ -11,7 +11,7 @@ import AgoraCommon class AIChatAgentNetworkModel: AUINetworkModel { override init() { super.init() - self.host = AppContext.agentServerUrl + self.host = AppContext.agentServerUrl() } } diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Models/AIChatViewModel.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Models/AIChatViewModel.swift index dc6bfc07d0..76b7ab71cd 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Models/AIChatViewModel.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Models/AIChatViewModel.swift @@ -30,7 +30,7 @@ public class AIChatViewModel: NSObject { public private(set) var bots: [AIChatBotProfileProtocol] = [] - private let sttChannelId = "aiChat_\(VLUserCenter.user.id)_\(UUID().uuidString)".md5() ?? "" + private let sttChannelId = "aiChat_\(AppContext.shared.getAIChatUid())_\(UUID().uuidString)".md5() ?? "" private var selectedBotId = "" diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Service/AIChatAgentService.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Service/AIChatAgentService.swift index 3d4bbd2f57..346091ed4c 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Service/AIChatAgentService.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Service/AIChatAgentService.swift @@ -29,7 +29,7 @@ class AIChatAgentService: NSObject { greeting: String?, context: [[String:Any]]?, completion: AgentRequestCompletion?) { - let uid = VLUserCenter.user.id + let uid = AppContext.shared.getAIChatUid() let model = AIChatAgentStartModel(appId: appId, channelName: channelName) model.uid = NSNumber(string: uid ) model.prompt = prompt @@ -57,7 +57,7 @@ class AIChatAgentService: NSObject { } func stopAgent(completion: AgentRequestCompletion?) { - let uid = VLUserCenter.user.id + let uid = AppContext.shared.getAIChatUid() let model = AIChatAgentStopModel(appId: appId, channelName: channelName) model.request { error, data in completion?(nil, error) diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Service/AIChatRTCService.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Service/AIChatRTCService.swift index 6fe42bf6eb..7f697d5015 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Service/AIChatRTCService.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Service/AIChatRTCService.swift @@ -37,10 +37,13 @@ class AIChatRTCService: NSObject { rtcKit.setDefaultAudioRouteToSpeakerphone(true) rtcKit.muteLocalAudioStream(true) rtcKit.muteLocalAudioStream(true) - rtcKit.setParameters ("{\"che.audio.sf.nsEnable\":1}") - rtcKit.setParameters ("{\"che.audio.sf.ainsToLoadFlag\" :1}") - rtcKit.setParameters ("{\"che.audio.sf.nsngAlgRoute\":12}") - rtcKit.setParameters ("{\"che.audio.sf.nsngPredefAgg\" :10}") + rtcKit.setParameters("{\"che.audio.sf.enabled\":true}") + rtcKit.setParameters("{\"che.audio.sf.ainlpToLoadFlag\":1}") + rtcKit.setParameters("{\"che.audio.sf.nlpAlgRoute\":1}") + rtcKit.setParameters("{\"che.audio.sf.ainsToLoadFlag\":1}") + rtcKit.setParameters("{\"che.audio.sf.nsngAlgRoute\":12}") + rtcKit.setParameters("{\"che.audio.sf.ainsModelPref\":11}") + rtcKit.setParameters("{\"che.audio.sf.ainlpModelPref\":11}") rtcKit.setAudioScenario(.gameStreaming) rtcKit.setAudioProfile(.default) self.rtcKit = rtcKit @@ -49,14 +52,14 @@ class AIChatRTCService: NSObject { extension AIChatRTCService: AIChatRTCServiceProtocol { func addDelegate(channelName: String, delegate: AgoraRtcEngineDelegate) { - let uid = Int(VLUserCenter.user.id) ?? 0 + let uid = Int(AppContext.shared.getAIChatUid()) ?? 0 aichatPrint("addDelegate[\(channelName)] uid:\(uid)", context: "AIChatRTCService") let connection = AgoraRtcConnection(channelId: channelName, localUid: uid) rtcKit?.addDelegateEx(delegate, connection: connection) } func removeDelegate(channelName: String, delegate: AgoraRtcEngineDelegate) { - let uid = Int(VLUserCenter.user.id) ?? 0 + let uid = Int(AppContext.shared.getAIChatUid()) ?? 0 aichatPrint("removeDelegate[\(channelName)] uid:\(uid)", context: "AIChatRTCService") let connection = AgoraRtcConnection(channelId: channelName, localUid: uid) rtcKit?.removeDelegateEx(delegate, connection: connection) @@ -71,7 +74,7 @@ extension AIChatRTCService: AIChatRTCServiceProtocol { option.autoSubscribeAudio = false option.clientRoleType = .audience - let uid = Int(VLUserCenter.user.id) ?? 0 + let uid = Int(AppContext.shared.getAIChatUid()) ?? 0 let connection = AgoraRtcConnection(channelId: channelName, localUid: uid) let ret = rtcKit.joinChannelEx(byToken: token, connection: connection, @@ -83,7 +86,7 @@ extension AIChatRTCService: AIChatRTCServiceProtocol { } func updateRole(channelName: String, role: AgoraClientRole) { - let uid = Int(VLUserCenter.user.id) ?? 0 + let uid = Int(AppContext.shared.getAIChatUid()) ?? 0 aichatPrint("updateRole[\(channelName)] role:\(role.rawValue)", context: "AIChatRTCService") let connection = AgoraRtcConnection(channelId: channelName, localUid: uid) @@ -103,7 +106,7 @@ extension AIChatRTCService: AIChatRTCServiceProtocol { } func muteLocalAudioStream(channelName: String, isMute: Bool) { - let uid = Int(VLUserCenter.user.id) ?? 0 + let uid = Int(AppContext.shared.getAIChatUid()) ?? 0 aichatPrint("muteAudio[\(channelName)] isMute:\(isMute)", context: "AIChatRTCService") let connection = AgoraRtcConnection(channelId: channelName, localUid: uid) rtcKit?.muteLocalAudioStreamEx(isMute, connection: connection) @@ -111,7 +114,7 @@ extension AIChatRTCService: AIChatRTCServiceProtocol { func leaveChannel(channelName: String) { aichatPrint("leaveChannel[\(channelName)]", context: "AIChatRTCService") - let uid = Int(VLUserCenter.user.id) ?? 0 + let uid = Int(AppContext.shared.getAIChatUid()) ?? 0 let connection = AgoraRtcConnection(channelId: channelName, localUid: uid) rtcKit?.leaveChannelEx(connection) dataStreamIdMap[channelName] = nil @@ -132,7 +135,7 @@ extension AIChatRTCService: AIChatRTCServiceProtocol { let config = AgoraDataStreamConfig() var result: Int32 = 0 - let uid = Int(VLUserCenter.user.id) ?? 0 + let uid = Int(AppContext.shared.getAIChatUid()) ?? 0 let connection = AgoraRtcConnection(channelId: channelName, localUid: uid) var dataStreamId = dataStreamIdMap[channelName] ?? 0 if dataStreamId == 0 { diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Service/AppContext+AIChat.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Service/AppContext+AIChat.swift index 22b469f300..10dc380a45 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Service/AppContext+AIChat.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/AIChatAPI/Service/AppContext+AIChat.swift @@ -44,11 +44,21 @@ class AIChatLogger: NSObject { } extension AppContext { - static var agentServerUrl = "https://ai-chat-service-staging.sh3t.agoralab.co" + static private var _agentServerUrl: String? static private var _rtcService: AIChatRTCService? static private var _audioTextConvertorService: AIChatAudioTextConvertorService? static private var _speechManager:SpeechManager? + static func agentServerUrl() -> String { + if let url = _agentServerUrl { + return url + } + + let url = AppContext.shared.aichatAgentHost + _agentServerUrl = url + return url + } + static func rtcService() -> AIChatRTCService? { if let service = _rtcService { return service @@ -77,6 +87,7 @@ extension AppContext { } static func destory() { + _agentServerUrl = nil _rtcService?.destory() _rtcService = nil @@ -85,4 +96,9 @@ extension AppContext { _speechManager = nil } + + func getAIChatUid() -> String { + let uid = Int(VLUserCenter.user.id) ?? 0 + return "\(isDebugMode ? uid + 1000000 : uid)" + } } diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/ChatBotViewController.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/ChatBotViewController.swift index 159f563208..32016d3eb4 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/ChatBotViewController.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/ChatBotViewController.swift @@ -111,7 +111,7 @@ final class ChatBotViewController: UIViewController { welcomeText = AIChatBotImplement.commonBotWelcomeMessage[id] ?? welcomeText } } - let welcomeMessage = AgoraChatMessage(conversationID: bot.botId, from: bot.botId, to: VLUserCenter.user.id, body: AgoraChatTextMessageBody(text: welcomeText), ext: nil) + let welcomeMessage = AgoraChatMessage(conversationID: bot.botId, from: bot.botId, to: AppContext.shared.getAIChatUid(), body: AgoraChatTextMessageBody(text: welcomeText), ext: nil) welcomeMessage.direction = .receive conversation?.insert(welcomeMessage, error: nil) } diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/CreateIntelligenceViewController.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/CreateIntelligenceViewController.swift index ab1392f2c5..4bbb4eadb6 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/CreateIntelligenceViewController.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/CreateIntelligenceViewController.swift @@ -334,7 +334,7 @@ extension CreateIntelligenceViewController: UITextFieldDelegate { let alertMessage = AgoraChatMessage(conversationID: bot.botId, body: AgoraChatCustomMessageBody(event: "AIChat_alert_message", customExt: nil), ext: ["something":"智能体创建成功"]) self.createClosure?(bot) conversation?.insert(alertMessage, error: nil) - let welcomeMessage = AgoraChatMessage(conversationID: bot.botId, from: bot.botId, to: VLUserCenter.user.id, body: AgoraChatTextMessageBody(text: "您好,我是\(bot.botName),很高兴为您服务。"), ext: nil) + let welcomeMessage = AgoraChatMessage(conversationID: bot.botId, from: bot.botId, to: AppContext.shared.getAIChatUid(), body: AgoraChatTextMessageBody(text: "您好,我是\(bot.botName),很高兴为您服务。"), ext: nil) welcomeMessage.direction = .receive conversation?.insert(welcomeMessage, error: nil) DispatchQueue.main.async { diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/CreateIntelligentGroupViewController.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/CreateIntelligentGroupViewController.swift index 38ef0ae0e8..01b0a5bab5 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/CreateIntelligentGroupViewController.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/CreateIntelligentGroupViewController.swift @@ -126,7 +126,7 @@ class CreateIntelligentGroupViewController: UIViewController { func fillItems() { self.items.removeAll() self.items.append(contentsOf: [ - AIChatGroupUserProfile(id: VLUserCenter.user.id, name: VLUserCenter.user.name, avatar: VLUserCenter.user.headUrl, type: .normal), + AIChatGroupUserProfile(id: AppContext.shared.getAIChatUid(), name: VLUserCenter.user.name, avatar: VLUserCenter.user.headUrl, type: .normal), AIChatGroupUserProfile(id: "6", name: "添加智能体", avatar: "", type: .add) ]) self.collectionView.reloadData() @@ -185,7 +185,7 @@ class CreateIntelligentGroupViewController: UIViewController { let bot = AIChatBotProfile() bot.botId = userId bot.botName = self.nameTextField.text ?? "" - if let botIcon = self.items.filter{$0.type == .normal && VLUserCenter.user.id != $0.id}.first?.avatar { + if let botIcon = self.items.filter{$0.type == .normal && AppContext.shared.getAIChatUid() != $0.id}.first?.avatar { bot.botIcon = VLUserCenter.user.headUrl+","+botIcon } DispatchQueue.main.async { @@ -233,7 +233,7 @@ extension CreateIntelligentGroupViewController: UICollectionViewDataSource,UICol case .add: self.addUser() case .remove: self.removeUser() case .normal: - if VLUserCenter.user.id != item.id { + if AppContext.shared.getAIChatUid() != item.id { self.items.remove(at: indexPath.row) collectionView.reloadData() } @@ -399,7 +399,7 @@ class IntelligenceCell: UICollectionViewCell { } else { self.symbol.image = nil - if item.id == VLUserCenter.user.id { + if item.id == AppContext.shared.getAIChatUid() { self.removeBadge.isHidden = true } else { self.removeBadge.isHidden = false diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/GroupManagerViewController.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/GroupManagerViewController.swift index 8c08019b75..ed7128826b 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/GroupManagerViewController.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/GroupManagerViewController.swift @@ -187,7 +187,7 @@ class GroupManagerViewController: UIViewController { func fillItems() { self.items.removeAll() self.items.append(contentsOf: [ - AIChatGroupUserProfile(id: VLUserCenter.user.id, name: VLUserCenter.user.name, avatar: VLUserCenter.user.headUrl, type: .normal) + AIChatGroupUserProfile(id: AppContext.shared.getAIChatUid(), name: VLUserCenter.user.name, avatar: VLUserCenter.user.headUrl, type: .normal) ]) let (name,ids) = self.service.groupInfo(groupId: self.groupId) self.nameTextField.text = name diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/VoiceChatViewController.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/VoiceChatViewController.swift index 8f68886227..a3ac3720f6 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/VoiceChatViewController.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Controllers/VoiceChatViewController.swift @@ -16,13 +16,28 @@ enum VoiceChatKey { } private let kMaxStopTriggerCount = 10 +private let smallButton = CGSize(width: 48, height: 48) +private let bigButton = CGSize(width: 70, height: 70) class VoiceChatViewController: UIViewController { private var bot: AIChatBotProfileProtocol private var context: [[String:Any]]? private var pingTimer: Timer? private var localStopTriggerCount: Int = 0 private var remoteStopTriggerCount: Int = 0 - private lazy var agentChannelName = "aiChat_\(VLUserCenter.user.id)_\("\(bot.botId)_\(UUID().uuidString)".md5() ?? "")" + private lazy var agentChannelName = "aiChat_\(AppContext.shared.getAIChatUid())_\("\(bot.botId)_\(UUID().uuidString)".md5() ?? "")" + + private var isLocalWaveStop: Bool = true { + didSet { + if isLocalWaveStop { + self.localStopTriggerCount = 0 + self.waveformView.stopAPng() + } else { + self.localStopTriggerCount = 0 + self.waveformView.startAPng() + } + } + } + private lazy var agentService: AIChatAgentService = { let appId = AppContext.shared.appId let service = AIChatAgentService(channelName: agentChannelName, appId: appId) @@ -113,8 +128,8 @@ class VoiceChatViewController: UIViewController { private let micButton: UIButton = { let button = UIButton() - button.setImage(UIImage(named: "voice_mic_on", in: .chatAIBundle, with: nil)?.withRenderingMode(.alwaysOriginal), for: .normal) - button.setImage(UIImage(named: "voice_mic_off", in: .chatAIBundle, with: nil)?.withRenderingMode(.alwaysOriginal), for: .selected) + button.setImage(UIImage(named: "voice_mic_on", in: .chatAIBundle, with: nil)?.byResize(to: smallButton), for: .normal) + button.setImage(UIImage(named: "voice_mic_off", in: .chatAIBundle, with: nil)?.byResize(to: smallButton), for: .selected) button.tintColor = .blue button.addTarget(self, action: #selector(micButtonAction(_:)), for: .touchUpInside) return button @@ -122,15 +137,15 @@ class VoiceChatViewController: UIViewController { private let stopButton: UIButton = { let button = UIButton() - button.setImage(UIImage(named: "voice_stop_btn", in: .chatAIBundle, with: nil)?.withRenderingMode(.alwaysOriginal), for: .normal) - button.setImage(UIImage(named: "voice_stop_btn_dis", in: .chatAIBundle, with: nil)?.withRenderingMode(.alwaysOriginal), for: .selected) + button.setImage(UIImage(named: "voice_stop_btn", in: .chatAIBundle, with: nil)?.byResize(to: bigButton), for: .normal) + button.setImage(UIImage(named: "voice_stop_btn_dis", in: .chatAIBundle, with: nil)?.byResize(to: bigButton), for: .selected) button.addTarget(self, action: #selector(stopButtonAction(_:)), for: .touchUpInside) return button }() private let hangupButton: UIButton = { let button = UIButton() - button.setImage(UIImage(named: "voice_close_btn", in: .chatAIBundle, with: nil)?.withRenderingMode(.alwaysOriginal), for: .normal) + button.setImage(UIImage(named: "voice_close_btn", in: .chatAIBundle, with: nil)?.byResize(to: smallButton), for: .normal) button.tintColor = .red button.addTarget(self, action: #selector(hangupButtonAction), for: .touchUpInside) @@ -158,8 +173,8 @@ class VoiceChatViewController: UIViewController { aichatPrint("viewDidLoad", context: "VoiceChatViewController") let greeting = bot.type == .common ? "aichat_common_greeting".toSceneLocalization() : "aichat_custom_greeting".toSceneLocalization() - startAgent(greeting: greeting as String) setupRtc() + startAgent(greeting: greeting as String) setupUI() } @@ -184,6 +199,12 @@ class VoiceChatViewController: UIViewController { @objc private func micButtonAction(_ button: UIButton) { button.isSelected = !button.isSelected AppContext.rtcService()?.muteLocalAudioStream(channelName: agentChannelName, isMute: button.isSelected) + + UIImpactFeedbackGenerator.feedback(with: .medium) + + if button.isSelected { + self.isLocalWaveStop = true + } } @objc private func stopButtonAction(_ button: UIButton) { @@ -194,13 +215,19 @@ class VoiceChatViewController: UIViewController { AIChatLogger.info("interruptAgent start", context: VoiceChatKey.voiceChatContext) agentService.interruptAgent { msg, error in AIChatLogger.info("interrupt agent completion: \(error?.localizedDescription ?? "success")", context: VoiceChatKey.voiceChatContext) + if let error = error {return} + ToastView.show(text: "aichat_interrupt_success".toSceneLocalization() as String) } + + UIImpactFeedbackGenerator.feedback(with: .medium) } @objc private func hangupButtonAction() { aichatPrint("hangupButtonAction", context: "VoiceChatViewController") destoryPingTimer() stopAgent() + + UIImpactFeedbackGenerator.feedback(with: .medium) } private func stopAgent() { @@ -334,12 +361,18 @@ class VoiceChatViewController: UIViewController { micButton.centerYAnchor.constraint(equalTo: stopButton.centerYAnchor), micButton.trailingAnchor.constraint(equalTo: stopButton.leadingAnchor, constant: -54), + micButton.widthAnchor.constraint(equalToConstant: smallButton.width), + micButton.heightAnchor.constraint(equalToConstant: smallButton.height), stopButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -75), stopButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), + stopButton.widthAnchor.constraint(equalToConstant: bigButton.width), + stopButton.heightAnchor.constraint(equalToConstant: bigButton.height), hangupButton.centerYAnchor.constraint(equalTo: stopButton.centerYAnchor), - hangupButton.leadingAnchor.constraint(equalTo: stopButton.trailingAnchor, constant: 54) + hangupButton.leadingAnchor.constraint(equalTo: stopButton.trailingAnchor, constant: 54), + hangupButton.widthAnchor.constraint(equalTo: micButton.widthAnchor), + hangupButton.heightAnchor.constraint(equalTo: micButton.heightAnchor), ]) let switchState = true//(UserDefaults.standard.object(forKey: VoiceChatKey.voiceSwitchKey) as? Bool) ?? true @@ -370,11 +403,6 @@ extension VoiceChatViewController: AgoraRtcEngineDelegate { aichatWarn("didOccurError: \(errorCode.rawValue)", context: "VoiceChatViewController") } - func rtcEngine(_ engine: AgoraRtcEngineKit, receiveStreamMessageFromUid uid: UInt, streamId: Int, data: Data) { - let message = String.init(data: data, encoding: .utf8) ?? "" - aichatPrint("receiveDataStreamMessageFromUid: \(uid) \(message)") - } - public func rtcEngine(_ engine: AgoraRtcEngineKit, reportAudioVolumeIndicationOfSpeakers speakers: [AgoraRtcAudioVolumeInfo], totalVolume: Int) { // guard speakers.count > 0, totalVolume >= 10 else {return} DispatchQueue.main.async { @@ -383,13 +411,13 @@ extension VoiceChatViewController: AgoraRtcEngineDelegate { // show bottom wave animation // aichatPrint("local speaker.volume: \(speaker.volume)") if speaker.volume > 10 { - self.localStopTriggerCount = 0 - self.waveformView.startAPng() + self.isLocalWaveStop = false } else { self.localStopTriggerCount += 1 if self.localStopTriggerCount > kMaxStopTriggerCount, self.waveformView.playAPNG { - self.waveformView.stopAPng() - self.localStopTriggerCount = 0 + self.isLocalWaveStop = true + } else if self.micButton.isSelected { + self.isLocalWaveStop = true } } } else { diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Core/Foundation/Impact+AIChat.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Core/Foundation/Impact+AIChat.swift new file mode 100644 index 0000000000..6a6888359e --- /dev/null +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Core/Foundation/Impact+AIChat.swift @@ -0,0 +1,16 @@ +// +// Impact+AIChat.swift +// AIChat +// +// Created by wushengtao on 2024/10/18. +// + +import Foundation + +extension UIImpactFeedbackGenerator { + static func feedback(with style: UIImpactFeedbackGenerator.FeedbackStyle) { + let feedbackGenerator = UIImpactFeedbackGenerator(style: style) + feedbackGenerator.prepare() + feedbackGenerator.impactOccurred() + } +} diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Views/AIChatMessagesList.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Views/AIChatMessagesList.swift index cb671b2a8f..9b7530e73a 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Views/AIChatMessagesList.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Views/AIChatMessagesList.swift @@ -691,22 +691,16 @@ extension AIChatMessagesList: IAIChatMessagesListDriver { self.chatView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none) self.chatView.endUpdates() self.chatView.scrollToRow(at: IndexPath(row: index, section: 0), at: .bottom, animated: true) - self.feedback(with: .light) + UIImpactFeedbackGenerator.feedback(with: .light) if finished { self.inputBar.setEnableState() - self.feedback(with: .medium) + UIImpactFeedbackGenerator.feedback(with: .medium) } break } } self.calculateTableViewLimitHeight() } - - func feedback(with style: UIImpactFeedbackGenerator.FeedbackStyle) { - let feedbackGenerator = UIImpactFeedbackGenerator(style: style) - feedbackGenerator.prepare() - feedbackGenerator.impactOccurred() - } private func insertTypingMessage(to: String) { let entity = MessageEntity() diff --git a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Views/LongPressButton.swift b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Views/LongPressButton.swift index 2bc3fee5ac..e49b700125 100644 --- a/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Views/LongPressButton.swift +++ b/iOS/AgoraEntScenarios/Common/API/AIChat/AIChat/Classes/Views/LongPressButton.swift @@ -53,7 +53,7 @@ class LongPressButton: UIButton { self.currentState = .start self.startLocation = gesture.location(in: self) self.longPressCallback?(.start, .none) - self.feedback(with: .heavy) + UIImpactFeedbackGenerator.feedback(with: .heavy) case .changed: guard let startLocation = self.startLocation else { return } let currentLocation = gesture.location(in: self) @@ -77,12 +77,6 @@ class LongPressButton: UIButton { } } - func feedback(with style: UIImpactFeedbackGenerator.FeedbackStyle) { - let feedbackGenerator = UIImpactFeedbackGenerator(style: style) - feedbackGenerator.prepare() - feedbackGenerator.impactOccurred() - } - private func getDirection(from start: CGPoint, to end: CGPoint) -> MoveDirection { let deltaX = end.x - start.x let deltaY = end.y - start.y diff --git a/iOS/AgoraEntScenarios/Context/AppContext.swift b/iOS/AgoraEntScenarios/Context/AppContext.swift index e2a09d393f..6555b513e3 100644 --- a/iOS/AgoraEntScenarios/Context/AppContext.swift +++ b/iOS/AgoraEntScenarios/Context/AppContext.swift @@ -167,4 +167,6 @@ import Bugly public var hyAppId: String = "" public var hyAPISecret: String = "" public var hyAPIKey: String = "" + + public var aichatAgentHost: String = "" } diff --git a/iOS/AgoraEntScenarios/KeyCenter.swift b/iOS/AgoraEntScenarios/KeyCenter.swift index 949de54f76..3fc35978e0 100644 --- a/iOS/AgoraEntScenarios/KeyCenter.swift +++ b/iOS/AgoraEntScenarios/KeyCenter.swift @@ -85,6 +85,15 @@ class KeyCenter: NSObject { //dynamic resource manifest download url static var DynamicResourceUrl: String? = nil + + //hy key + static var HyAppId: String? = nil + static var HyAPISecret: String? = nil + static var HyAPIKey: String? = nil + + //ai chat host url + static var AIChatAgentServerDevUrl = "https://ai-chat-service-staging.sh3t.agoralab.co" + static var AIChatAgentServerUrl = "https://ai-chat-service.apprtc.cn" static var HostUrl: String = "https://gateway-fulldemo.shengwang.cn/" static var baseServerUrlDev: String? = "https://service-staging.agora.io/"