本文将向您详细介绍,如何借助服务端的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://help.aliyun.com/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();
相关文档
在开启通话后,挂断前,可以根据您的业务需求处理字幕、打断智能体讲话等,请参见基础功能。
该文章对您有帮助吗?