2D 数字人虚拟人SDK ,可以通过语音完成对虚拟人实时驱动。
部署成本低: 无需客户提供技术团队进行配合,支持低成本快速部署在多种终端及大屏; 网络依赖小:可落地在地铁、银行、政务等多种场景的虚拟助理自助服务上; 功能多样化:可根据客户需求满足视频、媒体、客服、金融、广电等多个行业的多样化需求
提供定制形象的 AI 主播,智能客服等多场景形象租赁,支持客户快速部署和低成本运营; 专属形象定制:支持定制专属的虚拟助理形象,可选低成本或深度形象生成; 播报内容定制:支持定制专属的播报内容,应用在培训、播报等多种场景上; 实时互动问答:支持实时对话,也可定制专属问答库,可满足咨询查询、语音闲聊、虚拟陪伴、垂类场景的客服问答等需求。
项目 | 描述 |
---|---|
系统 | 支持 Android 7.0+ ( API Level 24 )到 Android 13 ( API Level 33 )系统。 |
CPU架构 | armeabi-v7a, arm64-v8a |
硬件要求 | 要求设备 CPU4 核极以上,内存 4G 及以上。可用存储空间 500MB 及以上。 |
网络 | 支持 WIF 及移动网络。如果使用云端问答库,设备带宽(用于数字人的实际带宽)期望 10mbps 及以上。 |
开发 IDE | Android Studio Giraffe \mid 2022.3.1 Patch 2 |
内存要求 | 可用于数字人的内存 >= 400MB |
联系客服,获取SDK包。
引入 sdk aar 包: duix_client_sdk_release_${version}.aar
app 目录新建 libs 目录,放入 aar 包,在 build.gradle 中增加配置如下
dependencies {
// duix_client_sdk_release_${version}.aar放到libs目录下(必选)
implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
// sdk 中使用到 exoplayer 处理音频(必选)
implementation 'com.google.android.exoplayer:exoplayer:2.14.2'
// 云端问答接口使用的SSE组件(非必选)
implementation 'com.squareup.okhttp3:okhttp-sse:4.10.0'
// 云端asr对接 (非必选)
implementation "org.java-websocket:Java-WebSocket:1.5.1"
...
}
权限要求, AndroidManifest.xml中,增加如下配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
</manifest>
在渲染页onCreate()阶段构建DUIX对象并添加回调事件
val duixOptions = DUIXOptions(appId, appKey, baseDir, modelDir)
duix = DUIX(mContext, duixOptions, mDUIXRender) { event, msg, info ->
when (event) {
ai.guiji.duix.sdk.client.Constant.CALLBACK_EVENT_INIT_READY -> {
initOK()
}
ai.guiji.duix.sdk.client.Constant.CALLBACK_EVENT_INIT_ERROR -> {
}
ai.guiji.duix.sdk.client.Constant.CALLBACK_EVENT_AUTH_EXPIRE -> {
runOnUiThread {
Toast.makeText(mContext, "会话过期: $msg", Toast.LENGTH_LONG).show()
}
}
// ...
}
}
// 异步回调结果
duix?.init()
启动参数说明:
参数 | 类型 | 描述 |
---|---|---|
appId | String | 平台申请 |
appKey | String | 平台申请 |
baseDir | String | 存放模型驱动的配置文件,需要自行管理. 可将压缩文件解压到外部存储并提供文件夹路径 |
modelDir | String | 存放模型文件的文件夹,需要自行管理. 可将压缩文件解压到外部存储并提供文件夹路径 |
DUIX对象构建说明:
参数 | 类型 | 描述 |
---|---|---|
context | Context | 系统上下文 |
duixOptions | DUIXOptions | 通过appId,appKey等构建的启动参数 |
render | RenderSink | 渲染数据接口,sdk提供了默认的渲染组件继承自该接口,也可以自己实现 |
callback | Callback | SDK处理的各种回调事件 |
参考demo LiveActivity示例
object : Callback {
fun onEvent(event: String, msg: String, info: Object) {
when (event) {
"init.ready" -> {
// SDK授权及模型初始化成功
}
"init.error" -> {
// 授权异常或初始化失败
Log.e(TAG, "init error: $msg")
}
// ...
}
}
}
使用RenderSink接口接受渲染帧数据,SDK中提供了该接口实现DUIXRenderer.java。也可以自己实现该接口自定义渲染。 其中RenderSink的定义如下:
/**
* 渲染管道,通过该接口返回渲染数据
*/
public interface RenderSink {
// frame中的buffer数据以bgr顺序排列
void onVideoFrame(ImageFrame imageFrame);
}
使用DUIXRenderer及DUIXTextureView控件简单实现渲染展示,该控件支持透明通道可以自由设置背景及前景:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
mDUIXRender =
DUIXRenderer(
mContext,
binding.glTextureView
)
binding.glTextureView.setEGLContextClientVersion(GL_CONTEXT_VERSION)
binding.glTextureView.setEGLConfigChooser(8, 8, 8, 8, 16, 0) // 透明
binding.glTextureView.isOpaque = false // 透明
binding.glTextureView.setRenderer(mDUIXRender)
binding.glTextureView.renderMode =
GLSurfaceView.RENDERMODE_WHEN_DIRTY // 一定要在设置完Render之后再调用
duix = DUIX(mContext, duixOptions, mDUIXRender) { event, msg, _ ->
}
// ...
}
在初始化成功后,可以播放音频以驱动形象
duix?.playAudio(wavPath)
参数说明:
参数 | 类型 | 描述 |
---|---|---|
wavPath | String | 16k采样率单通道的wav文件地址或https网络地址 |
音频播放状态及进度回调:
object : Callback {
fun onEvent(event: String, msg: String, info: Object) {
when (event) {
// ...
"play.start" -> {
// 开始播放音频
}
"play.end" -> {
// 完成播放音频
}
"play.error" -> {
// 音频播放异常
}
"play.progress" -> {
// 音频播放进度
}
"answer.result" -> {
// 大模型答疑返回结果(可能多次返回)
}
"answer.error" -> {
// 大模型答疑返回异常
}
"asr.result" -> {
// asr识别返回结果
}
"asr.error" -> {
// asr识别返回异常
}
"tts.result" -> {
// 文本合成返回结果
}
"tts.error" -> {
// 文本合成返回异常
}
}
}
}
当数字人正在播报时调用该接口终止播报。
函数定义:
boolean stopAudio();
调用示例如下:
duix?.stopAudio()
当模型中支持播放动作区间时可使用该函数播放多做区间,多个时随机播放。
函数定义:
void motion();
调用示例如下:
duix?.motion()
当需要进行语音识别相关的功能时,可使用相关接口。
函数定义:
// 启动ASR识别
boolean startAsr();
// 持续传输PCM(16k单通道16bit)音频数据
boolean sendRecord(byte[] audio);
// 关闭ASR识别
boolean stopAsr();
调用示例如下:
// 启动ASR识别
duix?.startAsr()
// 持续传输PCM(16k单通道)音频数据
duix?.sendRecord(buffer)
// 关闭ASR识别
duix?.stopAsr()
当需要进行云端问答相关功能时,可使用该接口。
函数定义:
boolean startAnswer(String conversationId, String question);
调用示例如下:
duix?.startAnswer(conversationId, question)
参数说明:
参数 | 类型 | 描述 |
---|---|---|
conversationId | String | 对话ID,在后台申请 |
question | String | 问题内容 |
当对接三方大模型接口,需要单独完成TTS语音合成需求,可使用该接口。
函数定义:
boolean tts(String conversationId, String content);
调用示例如下:
duix?.tts(conversationId, content)
参数说明:
参数 | 类型 | 描述 |
---|---|---|
conversationId | String | 对话ID,在后台申请 |
content | String | 合成文本 |
如果代码使用了混淆,请在proguard-rules.pro中配置:
-keep class com.btows.ncnntest.**{*; }
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
1. 添加TTS调用接口
1. 修复部分设备opengl默认float低精度导致无法正常显示数字人的问题。
1. 优化本地渲染。
1. 使用新的渲染模式,独立渲染线程。
1. 添加ASR语音识别相关接口
2. 添加问答相关接口
3. 添加数字人静默动作区间设置
1. 本地渲染数字人集成。