本文介绍了如何使用阿里云百炼大模型服务提供的实时多模交互移动端 Android SDK,包括SDK下载安装、关键接口及代码示例。
MultiModalDialog SDK是阿里云通义团队提供的支持音视频端到端多模实时交互的SDK。通过SDK对接通义大模型以及后端多种Agent,能够支持用户接入语音对话、天气、音乐、新闻等多种能力,并支持视频和图像的大模型对话能力。
多模态实时交互服务架构
前提条件
开通阿里云百炼实时多模交互应用,获取Workspace ID、APP ID和API Key。
下载SDK和 Demo bailian-multi-modal-android-sdk-1.0.4.1.zip并配置必要的环境、依赖。
导入示例代码,按照调用流程接入SDK。
您可以直接运行压缩包中的 APK 测试程序,填入上方三个必要参数,即可进行测试。
SDK接入
交互数据链路说明
SDK支持Websocket和RTC 两个链路与服务端交互,多模交互支持AudioOnly和AudioAndVideo 两种模式:
音频交互:推荐使用Websocket 连接,连接速度较快,性能要求较低。
WS 链路音频格式说明:
上行:支持 pcm 和 opus 格式音频进行语音识别。
下行:支持 pcm 和 mp3 音频流。
音视频交互:仅支持RTC 传输方式连接进行交互,提供端到端的音视频多模交互能力。
RTC 链路音频格式说明:
上行:支持 pcm 传入 SDK,传输采用 opus 格式。
下行:支持从 SDK 获取 pcm,传输采用 opus 格式。
交互模式说明
SDK支持 Push2Talk、 Tap2Talk和Duplex(全双工)三种交互模式。
Push2Talk: 长按说话,抬起结束的收音方式。
Tap2Talk: 点击开始说话,自动判断用户说话结束的收音方式。
Duplex: 全双工交互,连接开始后支持任意时刻开始说话,支持语音打断。
调用说明
SDK及其调用Demo。
SDK引用
导入依赖库。
app/src/main/libs
convsdk-release_*.aar //阿里云VoiceChatSDK
multimodal_dialog_sdk.aar // 阿里云多模对话SDK
com.aliyun.aio:AliVCSDK_ARTC // 阿里云RTC SDK
其他DemoAPP引入的依赖:
参考
app/build.gradle
implementation libs.androidbootstrap implementation libs.okhttp implementation libs.okio //Android OKHttp3应用要增加一个收入IO的okio包 implementation libs.http.logging.interceptor implementation libs.core.ktx //导入视频云sdk implementation libs.alivcsdk.artc
关键参数
参数名称 | 是否必须 | 值 | 说明 |
url | 是 | String | 请求的服务端地址。 Websocket链路地址:wss://dashscope.aliyuncs.com/api-ws/v1/inference RTC链路地址: https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation |
api_key | 是 | String | 百炼服务接入API Key 请您在百炼平台创建API_KEY,移动端为了安全考虑,您也可以在服务端接入短时Token,并下发给客户端使用。 |
workspace_id | 是 | String | 百炼管控台,工作空间id。 |
app_id | 是 | String | 您在管控台创建的应用id。 |
chain_mode | 是 | String | RTC/Websocket。 |
Demo简介
EntranceActivity 入口页面,需要修改url/api_key/app_id等信息。
可以通过页面选择使用RTC或者Websocket请求链路。
可以通过页面选择对话使用Tap2Talk或者Duplex等模式。
MultimodalDialogActivity,对话交互实现类。
Demo页面中引用TYAudioRecorder 作为录音输入,您可以替换为自己的实现。
Demo页面使用AudioPlayer作为音频播放输出,您可以选择使用自己的实现类。
Demo在音频交互模式下,支持VQA(图生文)功能,即通过语音说“拍照识别xxx”,触发服务下发拍照意图。之后:
您可以将本地拍照并上传OSS(或其他内容服务生成公共链接),触发单张图片的识别和对话。
您也可以直接上传图片的base64请求服务或者图片的对话结果。
Demo在VideoAndAudio音视频交互模式下,目前通过外部采集的方式输入图像序列,方便眼镜等IoT设备的采集和视频对话接入。
接口设计
MultimodalDialog 对话入口类
MultiModalDialog
初始化对话类,传入必要的全局参数。
/** * 初始化 * @param context: 上下文 * @param url: 服务器地址 * @param chainMode: 链路模式 * @param workspaceId: 工作空间id * @param appId: 应用id * @param dialogMode: 对话模式 * */ fun MultiModalDialog( context: Context, url: String?, chainMode: ChainMode?, workspaceId: String?, appId: String?, dialogMode: DialogMode? )
createConversation
创建会话。
/** * 初始化成功后,启动对话流程 * @param params 初始化参数 * @param chatCallback 主回调,除了初始化过程的所有消息,都会从这里透出给上层 */ fun createConversation(@NonNull MultiModalRequestParam params,chatCallback: IConversationCallback)
start
开始对话。
/** * 连接,启动对话 */ fun start()
stop
结束对话。
/** * 断开,结束对话 */ fun stop()
destroy
/** * 销毁实例 */ fun destroy()
setConversationTimeout
设置超时时间。
/** * 设置对话超时时间,当服务未在指定时间内检出用户说话,上报timeout事件 * @param timeout 超时时间,单位ms */ fun setConversationTimeout(timeout: Long)
interrupt
打断交互。
/** * 打断AI说话 */ fun interrupt()
startSpeech
通知服务端开始上传音频,注意需要在Listening状态才可以调用。只需要在Push2Talk模式下调用。
/** * 通知服务端开始上传音频,注意需要在Listening状态才可以调用。 * 只需要在Push2Talk模式下调用。 */ fun startSpeech()
sendAudioData
通知服务端上传音频。
/** * 通知服务端上传音频。 * @param audioData 音频帧数据 */ fun sendAudioData(audioData: ByteArray?)
stopSpeech
通知服务端结束上传音频。只需要在Push2Talk模式下调用。
/** * 通知服务端结束上传音频。只需要在Push2Talk模式下调用。 * Push2Talk 用户结束说话 */ fun stopSpeech()
requestToRespond
请求服务端回答指定问题or做TTS播放出来。
/** * 请求服务端回答指定问题or做TTS播放出来 * @param type: transcript 表示直接把文本转语音,prompt 表示把文本送大模型回答 * @param text:对应的文本 * @param params: 额外参数 */ fun requestToRespond(type: String, text: String, params: JSONObject)
其他接口。
/** * 当前配置是否是全双工模式 */ fun isDuplexMode(): Boolean /** * Push2Talk 用户取消说话 */ fun cancelSpeech() /** * 发送语音回复结束 * */ fun sendResponseEnded() /** * 发送语音回复开始 * */ fun sendResponseStarted() /** * 推送视频帧 * * @param videoFrame 视频帧 * @param callback: 送帧结果回调 */ fun sendVideoFrame(videoFrame: TYVideoFrame,callback: IVideoChatPushFrameCallback)
关键参数枚举
参数 | 值 | 说明 |
ChainMode | Websocket | 仅支持AudioOnly |
RTC | 支持AudioOnly和AudioAndVideo两种交互 | |
DialogMode | TAP2TALK | 手动开始,自动结束 |
PUSH2TALK | 手动开始,手动结束 | |
DUPLEX | 全双工交互 |
MultiModalRequestParam 端云交互参数详情
请求开始会话消息。服务收到Start消息后,向客户端发送Started消息。
一级参数 | 二级参数 | 三级参数 | 四级参数 | 类型 | 是否必选 | 说明 |
task_group | 任务组名称,固定为"aigc" | |||||
task | 任务名称,固定为"multimodal-generation" | |||||
function | 调用功能,固定为"generation" | |||||
model | 阿里云百炼模型名称,固定为"multimodal-dialog" | |||||
input | directive | string | 是 | 指令名称:Start | ||
workspace_id | string | 是 | 客户在阿里云百炼业务空间ID(Workspace ID),可在百炼管控台“业务空间详情”中查看,目前仅支持主账号默认工作空间 | |||
app_id | string | 是 | 客户创建的应用ID(APP ID),可在多模态交互管控台“我的应用”页面查看 | |||
dialog_id | string | 否 | 服务生成的对话ID,只有在希望继续之前的对话时传入 | |||
parameters | upstream | type | string | 是 | 上行类型: AudioOnly 仅语音通话 | |
mode | string | 否 | 客户端使用的模式,可选项:
默认tap2talk | |||
audio_format | string | 否 | 音频格式,支持pcm,opus,raw-opus,默认为pcm 注意:opus格式的每一包数据都需要单独ogg封装 | |||
sample_rate | int | 否 | 语音识别的采样率,支持范围:
默认为16000 | |||
downstream | voice | string | 否 | 合成语音的音色,支持范围取决于用户在管控台选择的tts模型 | ||
sample_rate | int | 否 | 合成语音的采样率,支持范围:
默认为24000 | |||
audio_format | string | 否 | 音频格式,支持pcm,opus,mp3,raw-opus,默认为pcm 注意:opus格式下发的每一包数据都有单独ogg封装 | |||
frame_size | int | 否 | 合成音频的帧大小,取值范围:
默认值为60,单位ms 只在合成音频格式为opus或raw-opus时生效 | |||
volume | int | 否 | 合成音频的音量,取值范围0-100,默认50 | |||
speech_rate | int | 否 | 合成音频的语速,取值范围50-200,表示默认语速的50%-200%,默认100 | |||
pitch_rate | int | 否 | 合成音频的声调,取值范围50-200,默认100 | |||
intermediate_text | string | 否 | 控制返回给用户哪些中间文本:
可以设置多种,以逗号分隔,默认为transcript | |||
transmit_rate_limit | int | 否 | 下发音频发送速率限制,单位:字节每秒 | |||
client_info | user_id | string | 是 | 终端用户ID,客户根据自己业务规则生成,用来针对不同终端用户实现定制化功能 | ||
device | uuid | string | 否 | 客户端全局唯一的ID,需要用户自己生成,传入SDK | ||
network | ip | string | 否 | 调用方公网IP | ||
location | latitude | string | 否 | 调用方纬度信息,在需要客户端精确位置的业务场景提交 | ||
longitude | string | 否 | 调用方经度信息,在需要客户端精确位置的业务场景提交 | |||
city_name | string | 否 | 调用方所在城市,指明客户端粗略位置 | |||
biz_params | user_defined_params | object | 否 | 其他需要透传给agent的参数 | ||
user_defined_tokens | object | 否 | 透传agent所需鉴权信息 | |||
user_prompt_params | object | 否 | 用于设置用户自定义prompt中的变量 | |||
user_query_params | object | 否 | 用于设置用户自定义query中的变量 |
示例如下:
{
"header": {
"action":"run-task",
"task_id": "9B32878******************3D053",
"streaming":"duplex"
},
"payload": {
"task_group":"aigc",
"task":"multimodal-generation",
"function":"generation",
"model":"multimodal-dialog",
"input":{
"directive": "Start",
"workspace_id": "llm-***********",
"app_id": "****************"
},
"parameters":{
"upstream":{
"type": "AudioOnly",
"mode": "duplex"
},
"downstream":{
"voice": "longxiaochun_v2",
"sample_rate": 24000
},
"client_info":{
"user_id": "bin********207",
"device":{
"uuid": "432k*********k449"
},
"network":{
"ip": "10.0.0.9"
},
"location":{
"city_name": "北京市"
}
},
"biz_params":{
"user_defined_params": {
"agentIdA": {
"name": "value"
}
},
"user_prompt_params": {
"name": "value"
},
"user_query_params": {
"name": "value"
}
}
}
}
}
IConversationCallback (回调接口)
/**
* 对话启动结果,鉴权、客户端加入通道成功后,会回调该消息
*/
fun onStartResult(isSuccess: Boolean, errorInfo: TYError?)
/**
* 主动打断的回调,包括手动打断和语音打断
*/
fun onInterruptResult(isSuccess: Boolean, errorInfo: TYError?)
/**
* 对话准备完成,多端(客户端/VoiceChat/视频理解)均加入通道后,会回调该消息,此时才能调用业务接口
*/
fun onReadyToSpeech()
/**
* 状态切换回调
* 包含DIALOG_IDLE,DIALOG_LISTENING,DIALOG_RESPONDING,DIALOG_THINKING
*/
fun onConvStateChangedCallback(state: DialogState)
/**
* 音量强度回调
* @param audioType 参考 {@link Constant.TYVolumeSourceType}
* @param audioLevel 0-100
*/
fun onConvSoundLevelCallback(audioLevel: Float, audioType: Constant.TYVolumeSourceType)
/**
* 超出用户有效输入超时时间的超时时间,收到此事件,用户需要重新启动或者结束对话
* @param timeout 超时时间
*/
fun onSpeechTimeout(timeout: Long)
/**
* 回路音频,用于客户端AEC回声消除
* @param bytes 音频数据
*/
fun onPlaybackAudioData(bytes: ByteArray)
/**
* 对话过程中的异常信息
* @param errorInfo 异常信息
*/
fun onErrorReceived(errorInfo: TYError)
/**
* 对话过程中的事件信息
* @param errorInfo 事件信息
*/
fun onConvEventCallback(var1: ConvEvent?)
/**
* 运行过程中回调关键日志信息给上层
* @param level 日志级别,参考Android.Log
* @param type 日志类型
* @param debugInfo 日志信息
*/
fun onDebugInfoTrack(level: Int, type: Constant.TYDebugInfoType, debugInfo: String)
onConvEventCallback AI对话 Response详情
EVENT_HUMAN_SPEAKING_DETAIL
语音识别内容
SpeechContent - response
一级参数
二级参数
三级参数
类型
是否必选
说明
output
event
string
是
事件名称:SpeechContent
dialog_id
string
是
对话id
text
string
是
用户语音识别出的文本,流式全量输出
finished
bool
是
输出是否结束
{ "header": { "request_id": "9B32878******************3D053", "service_id": "368208df", "status_code": 200, "status_name": "Success", "status_message": "Success.", "attributes":{ "user_id":"1234557879x" } }, "payload": { "output":{ "event": "SpeechContent", "dialog_id": "b39398c9dd8147********35cdea81f7", "text": "一二三", "finished": false }, "usage":{ "invoke":10, "model_x":10 } } }
EVENT_RESPONDING_DETAIL
大模型的返回文本
output
finished
bool
是
输出是否结束
dialog_id
string
是
对话id
event
string
是
消息类型
text
string
否
LLM大模型返回的文本结果
spoken
string
否
LLM大模型返回的播放内容的文本,可能跟 text 字段有所不同。
extra_info
object
否
其他扩展信息,目前支持:
commands: 命令字符串
agent_info: 智能体信息
tool_calls: 插件返回的信息
dialog_debug: 对话debug信息
timestamps: 链路中各节点时间戳
示例:
{ "header": { "event":"result-generated", "task_id": "9B32878******************3D053" }, "payload": { "output":{ "event": "RequestAccepted", "dialog_id": "b39398c9dd8147********35cdea81f7", "text": "您输入了数字序列“12345”。如果您有关于这些数字的问题或者需要我用它们来完成某项任务,请告诉我更多的细节,我会尽力帮助您。", "spoken": "您输入了数字序列“12345”。如果您有关于这些数字的问题或者需要我用它们来完成某项任务,请告诉我更多的细节,我会尽力帮助您。", "finished": true, "extra_info": { "commands": "[{\"name\":\"VOLUME_SET\",\"params\":[{\"name\":\"series\",\"normValue\":\"70\",\"value\":\"70\"}]}]", "tool_result": [{ "id": "", "type": "function", "function": { "name": "function_name", "arguments": "{\"id\": \"123\", \"name\": \"test\"}", "outputs": "函数调用结果", "status": { "code": 200, "message": "Success." } } }] } }, "usage":{ "invoke":10, "model_x":10 } } }
异常处理
onErrorReceived - response
百炼错误
错误码(Code) | 错误信息(Message) | 说明 |
403 | AccessDenied.Unpurchased | Access to model denied. Please make sure you are eligible for using the model. 用户必须开通百炼服务 |
403 | Model.AccessDenied | 只支持从默认业务空间调用 |
ResponseTimeout | {"header":{"task_id":"899*******499","event":"task-failed","error_code":"ResponseTimeout","error_message":"Response timeout!","attributes":{}},"payload":{}} 百炼网关要求服务端和客户端必须持续通信,如果超过1分钟没有交互则会超时报错。 | |
InternalError | {"header":{"task_id":"899*******499","event":"task-failed","error_code":"InternalError","error_message":"Internal server error!","attributes":{}},"payload":{}} 百炼网关要求服务端和客户端必须持续通信,如果超过1分钟没有交互则会超时报错。 |
多模态错误
(1)断连错误
出现以下错误时,错误码在header的status_code里,会话连接会断开,需要检查出错原因重新建连。
错误码(Code) | 错误信息(Message) | 说明 |
421 | InvalidParameter | type of directive payload is error, please choose transcript or prompt 参数错误,RequestToRespond请求的参数type错误,只能支持以下两种: (1)transcript 表示直接把文本转语音 (2)prompt 表示把文本送大模型回答 |
其他的参数错误 ,status_message 信息都有具体的提示说明。 | ||
422 | DirectiveNotSupported | 不支持的指令,请检查指令名称。 |
432 | AppConfigError | 获取到的百炼应用的配置有问题,参考status_message 里的具体信息修改。 |
433 | BillingAuthError | 未开通百炼多模态交互服务,或使用了错误账号。 |
444 | ClientAudioTimeout | Waiting for client audio timed out. 服务端长时间收不到客户端的音频输入。 |
449 | TooManyInterrupt | 用户短时间内发送过多RequestToRespond或RequestToSpeek 打断正常交互,通常是调用程序bug导致。 |
451 | NoSpeechRecognized | 服务没有识别到用户讲话,通常是push2talk模式下,用户发送了SendSpeech后,没有说话就又发送了StopSpeech指令。其他模式下也有极少数情况是由背景噪音引起。 |
(2)普通错误
出现以下错误时,错误码在payload的error_code里,连接不会断开,可以继续发送请求。
错误码(Code) | 错误信息(Message) | 说明 |
424 | AudioFormatError | 输入音频的格式不合规,ASR无法正常解析音频。 |
425 | NoInputAudioError | 没有获取到有效的输入音频数据,ASR无法识别。 |
426 | InvalidTtsVoice | tts voice error , need cosyvoice-v2 voice. 参数错误,选择的音色不是cosyvoice-v2支持的音色。 (1)cosyvoice-v2支持的官方音色参考音色列表。 (2)复刻音色,确认音色状态为“OK”后才能使用。查询指定音色。 |
tts voice error , need qwen-tts-realtime voice. 参数错误,选择的音色不是qwen-tts-realtime支持的音色。 qwen-tts-realtime支持的官方音色参考实时语音合成-通义千问。 | ||
500 | InternalSynthesizerError | Internal synthesizer error tts问题,提供dialogId给voicechat开发同学进行具体排查。 |
500 | InternalAsrError | Internal asr error asr问题,提供dialogId给voicechat开发同学进行具体排查。 |
500 | InternalLLMError | Internal LLM error llm问题,提供dialogId给voicechat开发同学进行具体排查。 |
500 | LLMTimeoutError | LLM response timeout llm问题,提供dialogId给voicechat开发同学进行具体排查。 |
RTC连接错误码
错误码 | 错误名称 | 说明 |
1001 | ERROR_CODE_AUTH_FAILED | RTC鉴权错误 |
1002 | ERROR_CODE_JOIN_CHANNEL_FAILED | RTC加入channel出错 |
1003 | ERROR_CODE_NETWORK_DISCONNECT | RTC网络断连 |
1004 | ERROR_CODE_CHANNEL_ERROR | RTC连接错误 |
调用时序
全双工交互
半双工交互
更多SDK接口使用说明
双工交互
移动端Android SDK支持Duplex 双工交互模式。 在双工交互模式下,SDK支持在播放语音合成回复的同时,输入录音数据。当用户在此时说话时,服务会自动打断当前播报数据返回 (客户端播放器缓存需要应用层处理),并开始新的回复。
双工交互需要实现回声消除(AEC,Acoustic Echo Cancellation),Android SDK内置了回声消除算法。当您需要使用双工交互时,仍需要您进行必要的配置。
输入麦克风录音音频
请将实时录音获取的音频数据通过如下接口传入SDK。
multiModalDialog.sendAudioData(data);
输入参考通道音频
请将实时播放的音频数据通过如下接口传入SDK。注意传入数据需要保证与当前播放数据一致。
multiModalDialog.sendRefData(data);
VQA交互
VQA 是在对话过程中通过发送图片实现图片+语音的多模交互的功能。
核心过程是语音或者文本请求拍照意图触发"visual_qa"拍照指令。
当客户端通过回调函数onConvEventCallback
收到拍照指令后, 发送图片链接或者base64数据(支持小于180KB的图片)。
处理"visual_qa" command和上传拍照。
private void executeCmd(String cmd,String dialogId,String taskId){
String cmdName = null;
String cmdParamValue = null;
try {
cmdName = new JSONArray(cmd).getJSONObject(0).getString("name");
}catch (Exception ex) {
ex.printStackTrace();
}
switch (cmdName){
case "visual_qa":
JSONObject extraObject = new JSONObject();
extraObject.put("images", imagesArray);
multimodalConversation.requestToRespond(type, text, extraObject.toString());
break:
......
}
//上传拍照
public static JSONArray getMockOSSImage() {
JSONObject imageObject = new JSONObject();
JSONArray images = new JSONArray();
try{
if (vqaUseUrl){
imageObject.put("type", "url");
imageObject.put("value", "https://help-static-aliyun-doc.aliyuncs.com/assets/img/zh-CN/7043267371/p909896.png");
}else {
imageObject.put("type", "base64");
imageObject.put("value", getLocalImageBase64());
}
images.put(imageObject);
}catch (Exception e){
e.printStackTrace();
}
return images;
}
通过 RTC 链路请求LiveAI
LiveAI (视频通话)是百炼多模交互提供的官方Agent。通过Android 全功能版本SDK, 您可以在应用中实现视频通话的功能。 本 SDK 内置了 RTC 协议,实现音视频双工的实时交互。
LiveAI调用时序
关键代码示例
完整代码请参考 "前提条件" 章节下载的 Android Demo。
//1. 设置交互类型为AudioAndVideo
MultiModalRequestParam.UpStream.builder().mode("duplex").type("AudioAndVideo").build();
//2. 在建联后发送voicechat_video_channel 请求
private void startVideoMode() {
if (isVideoMode) return;
try {
MultiModalRequestParam updateParams = MultiModalRequestParam.builder().build();
JSONObject videoObj = new JSONObject();
videoObj.put("action", "connect");
videoObj.put("type", "voicechat_video_channel");
List<JSONObject> videos = new ArrayList<>();
videos.add(videoObj);
updateParams.setBizParams(MultiModalRequestParam.BizParams.builder()
.videos(videos).build());
multiModalDialog.requestToRespond("prompt", "", updateParams.getParametersAsJson());
multiModalDialog.setVideoContainer(videoContainer, uiHandler);
isVideoMode = true;
runOnUiThread(() -> videoContainer.setVisibility(View.VISIBLE));
} catch (JSONException e) {
Log.e(TAG, "启动视频模式失败", e);
}
}
//3. 开始音视频交互。处理交互流程。注意 demo 中Constant.ChainMode.RTC 类型的处理。
private void handleOutputStarted() {
if (!isRtcUseInternalAudio()) {
audioPlayer.pause(true);
audioPlayer.play();
}
if (authParams.getChainMode() == Constant.ChainMode.RTC) {
//RTC 模式下,tts 合成数据速度为正常比例
multiModalDialog.sendResponseStarted();
}
}
private void handleOutputCompleted() {
Log.d(TAG, "输出完成");
if (authParams.getChainMode() != Constant.ChainMode.RTC) {
multiModalDialog.sendResponseEnded();
audioPlayer.isFinishSend(true);
}
}
通过 Websocket 链路请求LiveAI
LiveAI (视频通话)是百炼多模交互提供的官方Agent。通过Android 全功能版本SDK, 您也可以在Websocket链路中通过自行录制视频帧的方式来调用视频通话功能。
注意:通过 Websocket 调用 LiveAI发送图片只支持base64编码,每张图片的大小在180K以下。
LiveAI调用时序
关键代码示例
请注意参照如下的调用流程实现 通过Websocket 协议调用 LiveAI。
//1. 设置交互类型为AudioAndVideo
MultiModalRequestParam.UpStream.builder().mode("duplex").type("AudioAndVideo").build();
//2. 在建联后发送voicechat_video_channel 请求
private void startVideoMode() {
if (isVideoMode) return;
try {
MultiModalRequestParam updateParams = MultiModalRequestParam.builder().build();
JSONObject videoObj = new JSONObject();
videoObj.put("action", "connect");
videoObj.put("type", "voicechat_video_channel");
List<JSONObject> videos = new ArrayList<>();
videos.add(videoObj);
updateParams.setBizParams(MultiModalRequestParam.BizParams.builder()
.videos(videos).build());
multiModalDialog.requestToRespond("prompt", "", updateParams.getParametersAsJson());
multiModalDialog.setVideoContainer(videoContainer, uiHandler);
isVideoMode = true;
runOnUiThread(() -> videoContainer.setVisibility(View.VISIBLE));
} catch (JSONException e) {
Log.e(TAG, "启动视频模式失败", e);
}
}
//3. 每 500ms 提交一张视频帧照片数据,注意图片尺寸小于 180KB。
/**
* DEMO 流程未调用。演示在 websocket 链路中实现 liveAI
* 启动视频帧流,每 500ms 发送一次图片帧
*/
private void startVideoFrameStreaming() {
Thread videoStreamingThread = new Thread(() -> {
try {
while ( !Thread.currentThread().isInterrupted()) {
Thread.sleep(500);
JSONObject extraObject = new JSONObject();
extraObject.put("images", getMockOSSImage());
multiModalDialog.updateInfo(extraObject);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (JSONException e) {
throw new RuntimeException(e);
}
});
videoStreamingThread.setDaemon(true);
videoStreamingThread.setName("LiveAI-VideoStreaming");
videoStreamingThread.start();
}
/**
* build images list request
* */
private static JSONArray getMockOSSImage() {
JSONObject imageObject = new JSONObject();
JSONArray images = new JSONArray();
try{
imageObject.put("type", "base64");
imageObject.put("value", getLocalImageBase64());
images.put(imageObject);
}catch (Exception e){
e.printStackTrace();
}
return images;
}
//read local image to base64
private static String getLocalImageBase64(){
return "";
}
文本合成TTS
SDK支持通过文本直接请求服务端合成音频。
您需要在客户端处于Listening状态下发送requestToRespond
请求。
若当前状态非Listening,需要先调用Interrupt
接口打断当前播报。
conversation.requestToRespond("transcript","幸福是一种技能,是你摒弃了外在多余欲望后的内心平和。",null);
自定义提示词变量和传值
在管控台项目【提示词】配置自定义变量。
如下图示例,定义了一个user_name
字段代表用户昵称。并将变量user_name
以占位符形式${user_name} 插入到Prompt 中。
在代码中设置变量。
如下示例,设置"user_name" = "大米"
。
//在请求参数构建中传入biz_params.user_prompt_params
HashMap<String, String> userPromptParams = new HashMap<>();
userPromptParams.put("user_name", "大米");
MultiModalRequestParam.BizParams bizParams = MultiModalRequestParam.BizParams
.builder()
.userPromptParams(userPromptParams)
.build();
请求回复