Human 是一个用于控制和管理数字人的核心类,提供了丰富的功能来操作数字人的行为、语音和交互。该类继承自 Emittery,支持事件监听机制。
$ yarn add qt-human
# 或
$ npm i qt-human
const config: QuanTe.Configuration = {
// 必填:授权token
token: string;
// 可选:模型容器,可以是DOM ID或HTMLElement
// 如果为空时表示只加载模型并不渲染
container?: string | HTMLElement;
// 可选:数字人ID
characterId?: string;
// 可选:音频配置
audio?: {
volumn?: number; // 音量大小,默认1.0
};
// 可选:服务配置
server?: {
api?: string; // API接口地址
wss?: string; // WebSocket服务地址
questionApiParams?: { // 问答接口参数
model?: 'quan' | 'charglm-3' | 'qwen1.5' | 'glm-4' | 'openai' | 'echo';
stream?: boolean;
sentence?: boolean;
max_tokens?: number;
temperature?: number;
};
text2SpeachApiParams?: { // 语音合成参数
role?: 'woman' | 'man' | 'xiaoxiao' | 'yunxiao' | 'yunhao';
speed?: number;
model?: 'gpt-sovits' | 'xunfei' | 'paddle' | 'paddle2' | 'azure';
viseme?: 'azure' | 'ovr' | 'a2f' | 'qt' | 'none' | 'a2f3d';
smooth_method?: number;
smooth_interations?: number;
}
};
// 可选:模型配置
modelConfig?: {
name?: string;
camera?: {
fov?: number;
};
};
// 可选:加载提示元素
loading?: string | HTMLElement;
// 可选:是否在加载完成后销毁loading
loadingDestory?: boolean;
// 可选:其他配置选项
options?: {
fps?: number; // 帧率,默认30
};
// 可选:模式,nomal 普通模式(默认), voice 语音控制, only_render 只渲染模型
mode?: 'voice' | 'nomal' | 'only_render';
// 语音交互模式配置
voiceModeConfig?: {
// 录音能量值,范围:0~100
level?: number
}
}
显示/切换数字人
setCharacter(characterId: string, configuration?: Partial<QuanTe.Configuration>): Promise<boolean>
-
characterId
: 数字人ID -
configuration
: 可选的配置参数 - 返回值: Promise - 设置是否成功
让数字人说一段话
speak(text: string, callback?: Function, opt?: {[key: string]: any}): Promise<boolean>
-
text
: 要说的文本内容 -
callback
: 可选的回调函数 -
opt
: 可选配置,如{ split: false }
控制是否分段 - 返回值: Promise - 说话是否成功
进行 AI 问答
ask(params: QuanTe.API.AskParams, callback: (msgs: IResultData<QuanTe.API.ChatMessage[]>) => void): Promise<QuanTe.Result<QuanTe.API.AskResponse>>
-
params
: 问答参数{ message: Array<{ // user: 用户提问,assistant:系统回答 role: 'user' | 'assistant'; // 内容 content: string; }>; // 会话ID conversation_id?: string; // 接口响应模式,streaming: 流式,blocking:非流式 response_mode?: 'streaming' | 'blocking'; // 上传文件 files?: Array<{ type: 'image'; // remote_url:远程网络地址, local_file:本地图片 transfer_method: 'remote_url' | 'local_file'; // 图片地址 url: string; }>; }
-
callback
: 回调函数,接收问答结果
控制音频静音
muteAudio(isMute: boolean = true)
-
isMute
: true 表示静音,false 表示取消静音
控制动作禁用
muteAction(isMute: boolean = true)
-
isMute
: true 表示禁用动作,false 表示取消禁用
开始录音转文本
startVoice2Text(callback: (data: QuanTe.Recorder.Voice2Text) => void): Promise<QuanTe.Result<QuanTe.Recorder.PermissionResult>>
-
callback
: 回调函数,接收语音转文本结果 - 返回值: Promise<QuanTe.Result<QuanTe.Recorder.PermissionResult>>
结束录音转文本
stopVoice2Text(): Promise<QuanTe.Result<null>>
- 返回值: Promise<QuanTe.Result>
停止语音和口型动作
stop(): Promise<boolean>
- 返回值: Promise - 停止是否成功
根据音频地址和口型数据说话
speakByAudioShapes(uris: string[], shapes: Array<number[][]>): Promise<boolean>
-
uris
: 音频资源地址数组 -
shapes
: 口型数据数组 - 返回值: Promise - 说话是否成功
更新授权token
updateToken(token: string): void
-
token
: 新的授权token
切换视角
setAngleView({ camera, controls }: {
camera: QuanTe.Model.TCamera & { duration?: number },
controls: QuanTe.Model.OrbitControl & { duration?: number }
}): void
-
camera
: 相机配置 -
controls
: 轨道控制器配置
执行动画
playAction(code: string, opts: QuanTe.PlayActionOptions = {}): Promise<void>
-
code
: 动画代码 -
opts
: 动画选项{ loop?: THREE.AnimationActionLoopStyles; repetitions?: number; }
获取模型信息
getModelInfo(): ModelInfo | null
- 返回值: ModelInfo | null - 模型信息对象或null
Human 类支持以下事件,可以通过 EmitEvent
枚举来使用:
import { EmitEvent } from 'qt-human'
// 数字人加载进度
human.on(EmitEvent.HUMAN_LOAD_PROGRESS, (data: {
code: string, // 加载阶段:'download' | 'loaded'
progress: number, // 当前进度
total: number // 总进度
}) => {})
// 数字人准备就绪
human.on(EmitEvent.HUMAN_READY, () => {})
// 数字人错误
human.on(EmitEvent.HUMAN_ERROR, (data: {
code: string, // 错误代码
uri: string // 相关资源地址
}) => {})
// 音频播放
human.on(EmitEvent.AUDIO_PLAY, () => {})
// 音频暂停
human.on(EmitEvent.AUDIO_PAUSE, () => {})
// 动作待执行
human.on(EmitEvent.HUMAN_ACTION_PENDING, (actions: string[]) => {})
// 语音唤醒
human.on(EmitEvent.VOICE_WAKE, (data: any) => {})
// 语音休眠
human.on(EmitEvent.VOICE_SLEEP, (data: any) => {})
// 语音打断
human.on(EmitEvent.VOICE_INTERRUPT, (data: any) => {})
事件名称 | 说明 | 触发时机 | 事件数据 |
---|---|---|---|
HUMAN_LOAD_PROGRESS | 数字人加载进度 | 模型加载过程中 | { code: 'download' | 'loaded', progress: number, total: number } |
HUMAN_READY | 数字人准备就绪 | 模型加载完成,可以开始交互 | void |
HUMAN_ERROR | 数字人错误 | 发生错误时 | { code: string, uri: string } |
AUDIO_PLAY | 音频播放 | 开始播放音频时 | void |
AUDIO_PAUSE | 音频暂停 | 音频暂停时 | void |
HUMAN_ACTION_PENDING | 动作待执行 | 有待执行的动作时 | string[] |
VOICE_WAKE | 语音唤醒 | 语音交互被唤醒时 | any |
VOICE_SLEEP | 语音休眠 | 语音交互进入休眠状态时 | any |
VOICE_INTERRUPT | 语音打断 | 语音交互被用户打断时 | any |
WAKE_RECORDER_START | 唤醒录音开始 | 语音交互被唤醒并开始录音时 | any |
WAKE_RECORDER_STOP | 唤醒状态下结束录音 | 语音交互被唤醒并结束音时 | any |
VOICE2TEXT | 语音转文本 | 语音识别结果返回时 | { is_final: boolean, text: string, wav_name: string } |
CORE_BUNDLES_LOADED | 模型加载完成 | 模型加载完成 | QuanTe.Loader.LoaderResponse[] 所有模型数据 |
RECORDER_MESSAGE | 录音消息 | 开始录音 | pcm 录音数据 |
RECORDER_START | 开始录音 | 当录音能量值达到15时 | |
RECORDER_STOP | 结束录音 | 0.8秒内未收到能量值超过15时 | |
RECORDER_SENDING | 录音中 | 每次发送websocket时 | |
ASRTEXT | 语音转文本消息 | 收到 ASR 服务数据 | 文本数据 |
import Human, { EmitEvent } from 'qt-human'
const human = new Human({
token: 'your-token',
container: 'container-id'
});
// 监听加载进度
human.on(EmitEvent.HUMAN_LOAD_PROGRESS, (data) => {
console.log(`加载进度: ${data.progress}/${data.total}`);
});
// 监听准备就绪
human.on(EmitEvent.HUMAN_READY, () => {
console.log('数字人已准备就绪,可以开始交互');
});
// 监听错误
human.on(EmitEvent.HUMAN_ERROR, (error) => {
console.error('发生错误:', error);
});
// 监听音频状态
human.on(EmitEvent.AUDIO_PLAY, () => {
console.log('开始播放音频');
});
human.on(EmitEvent.AUDIO_PAUSE, () => {
console.log('音频已暂停');
});
// 监听语音交互状态
human.on(EmitEvent.VOICE_WAKE, () => {
console.log('语音交互已唤醒');
});
human.on(EmitEvent.VOICE_SLEEP, () => {
console.log('语音交互已休眠');
});
human.on(EmitEvent.VOICE_INTERRUPT, () => {
console.log('语音交互被用户打断');
});
import Human, { EmitEvent } from 'qt-human'
import type { QuanTe } from 'qt-human'
// 创建数字人实例
const human = new Human({
token: 'your-token',
container: 'container-id'
});
// 监听事件
human.on(EmitEvent.HUMAN_READY, () => {
console.log('数字人准备就绪');
});
// characterId: 数字人ID, 请登录 qtworld 平台复制数字人ID
human.setCharacter('characterId');
// 让数字人说话
human.speak('你好,我是数字人');
// AI问答
human.ask({
// 请求id,非必填
reqId: 'abcdefg',
message: [{ role: 'user', content: '你好' }]
}, (msgs: IResultData<QuanTe.API.ChatMessage[]>) => {
// 大模型流式推送结果
console.log(msgs);
}).then((result: QuanTe.Result<QuanTe.API.AskResponse>) => {
// 所有语音播放结束后返回bs等数据
console.log('result....', result)
});
// 控制音频
human.muteAudio(true); // 静音
human.muteAudio(false); // 取消静音
// 开始录音
human.startVoice2Text((data: QuanTe.Recorder.Voice2Text) => {
// 语音转文本内容
console.log(data)
})
// 结束录音语音转文本
human.stopVoice2Text()
// 通过 audio 和 bs 数据驱动数字人说话
human.speakByAudioShapes(['https://xxx/audio.wav', 'https://xxx/audio2.wav'], [[[...52个数据],[...52个数据]], [[...52个数据]]])
// 停止(停止语音、动作、口型动画、接口请求和待执行的任务队列等)并执行待机动画
human.stop()
// 销毁实例
human.destroy();
import Human, { EmitEvent } from 'qt-human'
// 1、创建数字人对象并设置语音模式
const human = new Human({
token: 'your-token',
container: 'container-id',
mode: 'voice'
});
// 数字人准备就绪
human.on(EmitEvent.HUMAN_READY, () => {
// 2、开启语音交互
human.openVoiceInteraction({
// 唤醒词
wakeWords: ['小全小全', '你好小全'],
// 退出词(休眠)
exitWords: ['退出', '关闭'],
// 打断词
interruptWorlds: ['停止', '返回']
})
});
- 使用前必须配置有效的 token
- 部分方法需要等待模型加载完成(HUMAN_READY 事件触发后)才能调用
- 注意及时销毁实例以释放资源
- 音频和动作控制可以根据需要随时切换
- 建议在组件销毁时调用 destroy() 方法清理资源
- characterId
创建 Human 对象时所需的 characterId 请登录 qtworld 平台获取,qtworld 地址: https://ai.quantekeji.com/platform/login - token
获取 token 请调用数字人授权接口
获取数字人访问令牌(token),用于初始化 Human 对象。
- 请求方式:POST
- 接口地址:
https://ai.quantekeji.com/platform-api/human-auth/get-token
{
// 应用秘钥(不要将秘钥保存在前端)
secretKey: string;
// 访问者ID(需要唯一)
visitorId: string;
// 访问者名称
visitorName: string;
}
{
// 状态码:0 表示成功
code: number;
// 返回数据:JWT-TOKEN
data: string;
// 响应消息
msg: string;
}
// 使用 axios 发起请求
import axios from 'axios';
async function getToken() {
try {
const response = await axios.post('https://ai.quantekeji.com/platform-api/human-auth/get-token', {
secretKey: 'your-secret-key',
visitorId: 'unique-visitor-id',
visitorName: 'visitor-name'
});
if (response.data.code === 0) {
const token = response.data.data;
// 使用获取到的 token 初始化 Human 对象
const human = new Human({
token,
container: 'container-id'
});
}
} catch (error) {
console.error('获取 token 失败:', error);
}
}
- secretKey 是敏感信息,不要在前端代码中直接存储,在 qtworld 平台个人中心获取
- visitorId 需要保证唯一性,建议使用用户ID或其他唯一标识
- token 有效期通常为 2 小时,过期后需要重新获取
- 建议在服务端调用此接口,避免暴露 secretKey
- 获取到 token 后,请妥善保存,用于初始化 Human 对象