本文將向您詳細介紹,如何藉助服務端的OpenAPI發起智能體呼叫。
情境說明
當您的業務需要即時監控或記錄每一次通話時,可以通過服務端OpenAPI:GenerateAIAgentCall - 產生AI智能體通話執行個體介面來發起通話,該介面需要的服務端來發起,並把發起後的結果下發給用戶端,用戶端再通過返回的資訊進入通話。
商務程序
APP在啟動AI智能體後,便可調用call()進入通話,在通話過程中,可以調用AICallKit的API實現智能體的即時字幕、打斷等互動功能。AICallKit依賴於即時音視頻能力,因此在內部已實現AliVCSDK_ARTC SDK的相關功能。如果您的業務情境還需要用到直播與點播能力,可以使用音視頻終端組合SDK,例如AliVCSDK_Standard或AliVCSDK_InteractiveLive,具體組合方式,請參考SDK選擇與下載。
服務端流程
服務端提供啟動通話的介面,例如generateAIAgentCall介面,核心實現是接收來自用戶端的請求,調用OpenAPI:GenerateAIAgentCall - 產生AI智能體通話執行個體,再把結果透傳給端側。
// 示範如果調用GenerateAIAgentCall
// This file is auto-generated, don't edit it. Thanks.
package com.aliyun.rtc;
import com.alibaba.fastjson.JSON;
import com.aliyun.ice20201109.models.GenerateAIAgentCallResponse;
import com.aliyun.tea.*;
public class SampleGenerateaiagentcall {
/**
* <b>description</b> :
* <p>使用AK&SK初始化帳號Client</p>
* @return Client
*
* @throws Exception
*/
public static com.aliyun.ice20201109.Client createClient() throws Exception {
// 工程代碼泄露可能會導致 AccessKey 泄露,並威脅帳號下所有資源的安全性。以下程式碼範例僅供參考。
// 建議使用更安全的 STS 方式,更多鑒權訪問方式請參見:https://www.alibabacloud.com/help/document_detail/378657.html。
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// 必填,請確保代碼運行環境設定了環境變數 ALIBABA_CLOUD_ACCESS_KEY_ID。
.setAccessKeyId("YourAccessKeyId")
// 必填,請確保代碼運行環境設定了環境變數 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
.setAccessKeySecret("YourAccessKeySecret");
// Endpoint 請參考 https://api.aliyun.com/product/ICE
config.endpoint = "ice.cn-shanghai.aliyuncs.com";
return new com.aliyun.ice20201109.Client(config);
}
public static void main(String[] args) throws Exception {
generateAIAgentCall();
}
public static void generateAIAgentCall() throws Exception {
com.aliyun.ice20201109.Client client = createClient();
com.aliyun.ice20201109.models.AIAgentTemplateConfig.AIAgentTemplateConfigVoiceChat AIAgentTemplateConfigVoiceChat = new com.aliyun.ice20201109.models.AIAgentTemplateConfig.AIAgentTemplateConfigVoiceChat()
.setGreeting("你好!");
com.aliyun.ice20201109.models.AIAgentTemplateConfig AIAgentTemplateConfig = new com.aliyun.ice20201109.models.AIAgentTemplateConfig()
.setVoiceChat(AIAgentTemplateConfigVoiceChat);
com.aliyun.ice20201109.models.GenerateAIAgentCallRequest generateAIAgentCallRequest = new com.aliyun.ice20201109.models.GenerateAIAgentCallRequest()
.setAIAgentId("YOUR_AIAGENTID")
.setTemplateConfig(AIAgentTemplateConfig);
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
// 複製代碼運行請自行列印 API 的傳回值
GenerateAIAgentCallResponse resp = client.generateAIAgentCallWithOptions(generateAIAgentCallRequest, runtime);
System.out.println(JSON.toJSONString(resp));
} catch (TeaException error) {
// 此處僅做列印展示,請謹慎對待異常處理,在工程專案中切勿直接忽略異常。
// 錯誤 message
System.out.println(error.getMessage());
// 診斷地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此處僅做列印展示,請謹慎對待異常處理,在工程專案中切勿直接忽略異常。
// 錯誤 message
System.out.println(error.getMessage());
// 診斷地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
}
用戶端流程
步驟一:用戶端建立並初始化通話引擎
通過AICallKit SDK建立並初始化通話引擎的程式碼範例如下:
Android
ARTCAICallEngine mARTCAICallEngine = null;
// 建立engine執行個體
void initEngine(Context context, String userId) {
// 初始化
// context -> Android Context
// userId -> 進入rtc頻道的使用者id
mARTCAICallEngine = new ARTCAICallEngineImpl(context, userId);
// 指定智能體的類型:純語音、數字人、視覺理解
ARTCAICallEngine.ARTCAICallAgentType aiAgentType = VoiceAgent;
mARTCAICallEngine.setAICallAgentType(aiAgentType);
// 如果是數字人類型,則需要配置數字人顯示的視圖容器
if (aiAgentType == AvatarAgent) {
ViewGroup avatarlayer;
engine.setAgentView(
avatarlayer,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
}
// 如果是視覺理解類型,則需要配置本地視頻預覽顯示的視圖容器
else if (aiAgentType == VisionAgent) {
ViewGroup previewLayer;
engine.setLocalView(previewLayer,
new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
} else if (aiAgentType == VideoAgent) {
ARTCAICallEngine.ARTCAICallVideoCanvas remoteCanvas = new ARTCAICallEngine.ARTCAICallVideoCanvas();
remoteCanvas.zOrderOnTop = false;
remoteCanvas.zOrderMediaOverlay = false;
ViewGroup avatarlayer;
engine.setAgentView(
avatarlayer,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT),
remoteCanvas);
ViewGroup previewLayer;
engine.setLocalView(previewLayer,
new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
}
}
// 設定回調
void initCallback() {
mARTCAICallEngine.setEngineCallback(mCallEngineCallbackWrapper);
}
// 回調處理(僅樣本部分核心的回調操作)
ARTCAICallEngine.IARTCAICallEngineCallback mCallEngineCallbackWrapper = new ARTCAICallEngine.IARTCAICallEngineCallback() {
@Override
public void onErrorOccurs(ARTCAICallEngine.AICallErrorCode errorCode) {
// 發生了錯誤,結束通話
mARTCAICallEngine.handup();
}
@Override
public void onCallBegin() {
// 通話開始(入會)
}
@Override
public void onCallEnd() {
// 通話結束(離會)
}
@Override
public void onAICallEngineRobotStateChanged(ARTCAICallEngine.ARTCAICallRobotState oldRobotState,
ARTCAICallEngine.ARTCAICallRobotState newRobotState) {
// 機器人狀態同步
}
@Override
public void onUserSpeaking(boolean isSpeaking) {
// 使用者說話回調
}
@Override
public void onUserAsrSubtitleNotify(String text, boolean isSentenceEnd, int sentenceId) {
// 同步ASR識別使用者的話
}
@Override
public void onAIAgentSubtitleNotify(String text, boolean end, int userAsrSentenceId) {
// 同步智能體回應的話
}
@Override
public void onNetworkStatusChanged(String uid, ARTCAICallEngine.ARTCAICallNetworkQuality quality) {
// 網路狀態回調
}
@Override
public void onVoiceVolumeChanged(String uid, int volume) {
// 音量變化
}
@Override
public void onVoiceIdChanged(String voiceId) {
// 當前通話的音色發生了改變
}
@Override
public void onVoiceInterrupted(boolean enable) {
// 當前通話的語音打斷設定改變
}
@Override
public void onAgentVideoAvailable(boolean available) {
// 智能體視頻是否可用(推流)
}
@Override
public void onAgentAudioAvailable(boolean available) {
// 智能體音頻是否可用(推流)
}
@Override
public void onAgentAvatarFirstFrameDrawn() {
// 數字人首視訊框架渲染
}
@Override
public void onUserOnLine(String uid) {
// 使用者上線回調
}
};iOS
// 建立engine執行個體
let engine = ARTCAICallEngineFactory.createEngine()
let agentType: ARTCAICallAgentType
// 初始化engine執行個體
public func setup() {
// 設定回調
self.engine.delegate = self
// 如果是數字人類型,則需要配置數字人顯示的視圖配置
if self.agentType == .AvatarAgent {
let agentViewConfig = ARTCAICallViewConfig(view: self.avatarAgentView)
self.engine.setAgentViewConfig(viewConfig: agentViewConfig)
}
// 如果是視覺理解類型,則需要配置本地視頻預覽配置
else if self.agentType == .VisionAgent {
let cameraViewConfig = ARTCAICallViewConfig(view: self.cameraView)
self.engine.setLocalViewConfig(viewConfig: cameraViewConfig)
}
// 如果是視訊通話類型,則需要配置數字人顯示的視圖配置+本地視頻預覽配置
else if self.agentType == .VisionAgent {
let agentViewConfig = ARTCAICallViewConfig(view: self.avatarAgentView)
self.engine.setAgentViewConfig(viewConfig: agentViewConfig)
let cameraViewConfig = ARTCAICallViewConfig(view: self.cameraView)
self.engine.setLocalViewConfig(viewConfig: cameraViewConfig)
}
}
// 回調處理(僅樣本不分核心的回調操作)
public func onErrorOccurs(code: ARTCAICallErrorCode) {
// 發生了錯誤
self.engine.handup()
}
public func onCallBegin() {
// 通話開始
}
public func onCallEnd() {
// 通話結束
}
public func onAgentStateChanged(state: ARTCAICallAgentState) {
// 智能體狀態改變
}
public func onUserSubtitleNotify(text: String, isSentenceEnd: Bool, sentenceId: Int) {
// 使用者提問被智能體識別結果的通知
}
public func onVoiceAgentSubtitleNotify(text: String, isSentenceEnd: Bool, userAsrSentenceId: Int) {
// 智能體回答結果通知
}
public func onVoiceIdChanged(voiceId: String) {
// 當前通話的音色發生了改變
}
public func onVoiceInterrupted(enable: Bool) {
// 當前通話的語音打斷是否啟用
}Web
// 引入SDK
import AICallEngine, { AICallErrorCode, AICallAgentState, AICallAgentType } from 'aliyun-auikit-aicall';
// 建立engine執行個體
const engine = new AICallEngine();
// 其他功能調用樣本,請參考API說明
// 回調處理(僅樣本不分核心的回調操作)
engine.on('errorOccurred', (code) => {
// 發生了錯誤
engine.handup();
});
engine.on('callBegin', () => {
// 通話開始
});
engine.on('callEnd', () => {
// 通話結束
});
engine.on('agentStateChanged', (state) => {
// 智能體狀態改變
});
engine.on('userSubtitleNotify', (subtitle) => {
// 使用者提問被智能體識別結果的通知
});
engine.on('agentSubtitleNotify', (subtitle) => {
// 智能體回答結果通知
});
engine.on('voiceIdChanged', (voiceId) => {
// 當前通話的音色發生了改變
});
engine.on('voiceInterruptChanged', (enable) => {
// 當前通話的語音打斷是否啟用
});
// 初始化
await engine.init(agentType);步驟二:進入通話
通過AICallKit SDK進入通話的程式碼範例如下:
Android
// 啟動智能體後,開始通話
void call() {
// 設定engine的啟動參數
ARTCAICallEngine.ARTCAICallConfig artcaiCallConfig = new ARTCAICallEngine.ARTCAICallConfig();
// 如果有臨時的智能體ID,可以配置
artcaiCallConfig.agentId = aiAgentId;
artcaiCallConfig.region = "cn-shanghai";//智能體地區,必填
artcaiCallConfig.agentType = VoiceAgent;//定智能體的類型:純語音、數字人、視覺理解、視訊通話
mARTCAICallEngine.init(artcaiCallConfig);
// 從服務端擷取到aIAgentInstanceId、rtcAuthToken、aIAgentUserId、channelId
String aIAgentInstanceId = “XXX”;
String rtcAuthToken = "XXX";
String aIAgentUserId = "XXX";
String channelId = "XXX";
mARTCAICallEngine.call(rtcAuthToken, aIAgentInstanceId,
aIAgentUserId, channelId);
}iOS
public func call() {
// 從服務端擷取到agent_instance_id、rtc_auth_token、ai_agent_user_id、channel_id
let agentInfo = ARTCAICallAgentInfo(agentType: self.agentType, channelId: channel_id, uid: ai_agent_user_id, instanceId: agent_instance_id)
self.engine.call(userId: self.userId, token: rtc_auth_token, agentInfo: agentInfo) { [weak self] error in
if let error = error {
// 處理錯誤
}
else {
// 成功通話
}
}
}Web
const userId = 'xxx'; // 當前發起通話的使用者的uid
// 從服務端擷取 agentInfo
// 您需要部署自己的 AppServer,訪問 GenerateAIAgentCall 介面產生AI智能體通話執行個體
// 其中的傳回值即為 agentInfo
// agentInfo.instanceId 智能體執行個體ID
// agentInfo.channelId: ARTC頻道ID
// agentInfo.userId: ARTC使用者ID
// agentInfo.rtcToken: ARTC入會Token
// agentInfo.reqId: 請求ID
const agentInfo = await fetchAgentInfo();
// 可以與 fetchAgentInfo 平行處理, agentType 為智能體類型,參考 AICallAgentType
await engine.init(agentType);
try {
// 啟動智能體後,開始通話
engine.call(userId, agentInfo);
} catch (error) {}步驟三:掛斷通話
通過AICallKit SDK掛斷通話的程式碼範例如下:
Android
// 結束通話
void handup() {
mARTCAICallEngine.handup();
}iOS
public func handup() {
// 結束通話
self.engine.handup()
}Web
// 結束通話,在需要時調用
engine.handup();相關文檔
在開啟通話後,掛斷前,可以根據您的業務需求處理字幕、打斷智能體講話等,請參見基礎功能。