qt-human 2.1.0-alpha.9 → 2.2.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1 +1,550 @@
1
- # 全特数字人
1
+ # Human 数字人接口使用文档
2
+
3
+ ## 简介
4
+
5
+ Human 是一个用于控制和管理数字人的核心类,提供了丰富的功能来操作数字人的行为、语音和交互。该类继承自 Emittery,支持事件监听机制。
6
+
7
+ ## 安装依赖
8
+
9
+ ```bash
10
+ $ yarn add qt-human
11
+ # 或
12
+ $ npm i qt-human
13
+ ```
14
+
15
+ ## 初始化配置
16
+
17
+ ### 基础配置
18
+
19
+ ```typescript
20
+ const config: QuanTe.Configuration = {
21
+ // 必填:授权token
22
+ token: string;
23
+
24
+ // 可选:模型容器,可以是DOM ID或HTMLElement
25
+ // 如果为空时表示只加载模型并不渲染
26
+ container?: string | HTMLElement;
27
+
28
+ // 可选:数字人ID
29
+ characterId?: string;
30
+
31
+ // 可选:音频配置
32
+ audio?: {
33
+ volumn?: number; // 音量大小,默认1.0
34
+ };
35
+
36
+ // 可选:服务配置
37
+ server?: {
38
+ api?: string; // API接口地址
39
+ wss?: string; // WebSocket服务地址
40
+ questionApiParams?: { // 问答接口参数
41
+ model?: 'quan' | 'charglm-3' | 'qwen1.5' | 'glm-4' | 'openai' | 'echo';
42
+ stream?: boolean;
43
+ sentence?: boolean;
44
+ max_tokens?: number;
45
+ temperature?: number;
46
+ };
47
+ text2SpeachApiParams?: { // 语音合成参数
48
+ role?: 'woman' | 'man' | 'xiaoxiao' | 'yunxiao' | 'yunhao';
49
+ speed?: number;
50
+ model?: 'gpt-sovits' | 'xunfei' | 'paddle' | 'paddle2' | 'azure';
51
+ viseme?: 'azure' | 'ovr' | 'a2f' | 'qt' | 'none' | 'a2f3d';
52
+ smooth_method?: number;
53
+ smooth_interations?: number;
54
+ }
55
+ };
56
+
57
+ // 可选:模型配置
58
+ modelConfig?: {
59
+ name?: string;
60
+ camera?: {
61
+ fov?: number;
62
+ };
63
+ };
64
+
65
+ // 可选:加载提示元素
66
+ loading?: string | HTMLElement;
67
+
68
+ // 可选:是否在加载完成后销毁loading
69
+ loadingDestory?: boolean;
70
+
71
+ // 可选:其他配置选项
72
+ options?: {
73
+ fps?: number; // 帧率,默认30
74
+ };
75
+
76
+ // 可选:模式,nomal 普通模式(默认), voice 语音控制, only_render 只渲染模型
77
+ mode?: 'voice' | 'nomal' | 'only_render';
78
+ // 语音交互模式配置
79
+ voiceModeConfig?: {
80
+ // 录音能量值,范围:0~100
81
+ level?: number
82
+ }
83
+ }
84
+ ```
85
+
86
+ ## 主要方法
87
+
88
+ ### setCharacter
89
+
90
+ 显示/切换数字人
91
+
92
+ ```typescript
93
+ setCharacter(characterId: string, configuration?: Partial<QuanTe.Configuration>): Promise<boolean>
94
+ ```
95
+
96
+ - `characterId`: 数字人ID
97
+ - `configuration`: 可选的配置参数
98
+ - 返回值: Promise<boolean> - 设置是否成功
99
+
100
+ ### speak
101
+
102
+ 让数字人说一段话
103
+
104
+ ```typescript
105
+ speak(text: string, callback?: Function, opt?: {[key: string]: any}): Promise<boolean>
106
+ ```
107
+
108
+ - `text`: 要说的文本内容
109
+ - `callback`: 可选的回调函数
110
+ - `opt`: 可选配置,如 `{ split: false }` 控制是否分段
111
+ - 返回值: Promise<boolean> - 说话是否成功
112
+
113
+ ### ask
114
+
115
+ 进行 AI 问答
116
+
117
+ ```typescript
118
+ ask(params: QuanTe.API.AskParams, callback: (msgs: IResultData<QuanTe.API.ChatMessage[]>) => void): Promise<QuanTe.Result<QuanTe.API.AskResponse>>
119
+ ```
120
+
121
+ - `params`: 问答参数
122
+
123
+ ```typescript
124
+ {
125
+ message: Array<{
126
+ // user: 用户提问,assistant:系统回答
127
+ role: 'user' | 'assistant';
128
+ // 内容
129
+ content: string;
130
+ }>;
131
+ // 会话ID
132
+ conversation_id?: string;
133
+ // 接口响应模式,streaming: 流式,blocking:非流式
134
+ response_mode?: 'streaming' | 'blocking';
135
+ // 上传文件
136
+ files?: Array<{
137
+ type: 'image';
138
+ // remote_url:远程网络地址, local_file:本地图片
139
+ transfer_method: 'remote_url' | 'local_file';
140
+ // 图片地址
141
+ url: string;
142
+ }>;
143
+ }
144
+ ```
145
+
146
+ - `callback`: 回调函数,接收问答结果
147
+
148
+ ### muteAudio
149
+
150
+ 控制音频静音
151
+
152
+ ```typescript
153
+ muteAudio(isMute: boolean = true)
154
+ ```
155
+
156
+ - `isMute`: true 表示静音,false 表示取消静音
157
+
158
+ ### muteAction
159
+
160
+ 控制动作禁用
161
+
162
+ ```typescript
163
+ muteAction(isMute: boolean = true)
164
+ ```
165
+
166
+ - `isMute`: true 表示禁用动作,false 表示取消禁用
167
+
168
+ ### startVoice2Text
169
+
170
+ 开始录音转文本
171
+
172
+ ```typescript
173
+ startVoice2Text(callback: (data: QuanTe.Recorder.Voice2Text) => void): Promise<QuanTe.Result<QuanTe.Recorder.PermissionResult>>
174
+ ```
175
+
176
+ - `callback`: 回调函数,接收语音转文本结果
177
+ - 返回值: Promise<QuanTe.Result<QuanTe.Recorder.PermissionResult>>
178
+
179
+ ### stopVoice2Text
180
+
181
+ 结束录音转文本
182
+
183
+ ```typescript
184
+ stopVoice2Text(): Promise<QuanTe.Result<null>>
185
+ ```
186
+
187
+ - 返回值: Promise<QuanTe.Result<null>>
188
+
189
+ ### stop
190
+
191
+ 停止语音和口型动作
192
+
193
+ ```typescript
194
+ stop(): Promise<boolean>
195
+ ```
196
+
197
+ - 返回值: Promise<boolean> - 停止是否成功
198
+
199
+ ### speakByAudioShapes
200
+
201
+ 根据音频地址和口型数据说话
202
+
203
+ ```typescript
204
+ speakByAudioShapes(uris: string[], shapes: Array<number[][]>): Promise<boolean>
205
+ ```
206
+
207
+ - `uris`: 音频资源地址数组
208
+ - `shapes`: 口型数据数组
209
+ - 返回值: Promise<boolean> - 说话是否成功
210
+
211
+ ### updateToken
212
+
213
+ 更新授权token
214
+
215
+ ```typescript
216
+ updateToken(token: string): void
217
+ ```
218
+
219
+ - `token`: 新的授权token
220
+
221
+ ### setAngleView
222
+
223
+ 切换视角
224
+
225
+ ```typescript
226
+ setAngleView({ camera, controls }: {
227
+ camera: QuanTe.Model.TCamera & { duration?: number },
228
+ controls: QuanTe.Model.OrbitControl & { duration?: number }
229
+ }): void
230
+ ```
231
+
232
+ - `camera`: 相机配置
233
+ - `controls`: 轨道控制器配置
234
+
235
+ ### playAction
236
+
237
+ 执行动画
238
+
239
+ ```typescript
240
+ playAction(code: string, opts: QuanTe.PlayActionOptions = {}): Promise<void>
241
+ ```
242
+
243
+ - `code`: 动画代码
244
+ - `opts`: 动画选项
245
+
246
+ ```typescript
247
+ {
248
+ loop?: THREE.AnimationActionLoopStyles;
249
+ repetitions?: number;
250
+ }
251
+ ```
252
+
253
+ ### getModelInfo
254
+
255
+ 获取模型信息
256
+
257
+ ```typescript
258
+ getModelInfo(): ModelInfo | null
259
+ ```
260
+
261
+ - 返回值: ModelInfo | null - 模型信息对象或null
262
+
263
+ ## 事件监听
264
+
265
+ Human 类支持以下事件,可以通过 `EmitEvent` 枚举来使用:
266
+
267
+ ```typescript
268
+ import { EmitEvent } from 'qt-human'
269
+
270
+ // 数字人加载进度
271
+ human.on(EmitEvent.HUMAN_LOAD_PROGRESS, (data: {
272
+ code: string, // 加载阶段:'download' | 'loaded'
273
+ progress: number, // 当前进度
274
+ total: number // 总进度
275
+ }) => {})
276
+
277
+ // 数字人准备就绪
278
+ human.on(EmitEvent.HUMAN_READY, () => {})
279
+
280
+ // 数字人错误
281
+ human.on(EmitEvent.HUMAN_ERROR, (data: {
282
+ code: string, // 错误代码
283
+ uri: string // 相关资源地址
284
+ }) => {})
285
+
286
+ // 音频播放
287
+ human.on(EmitEvent.AUDIO_PLAY, () => {})
288
+
289
+ // 音频暂停
290
+ human.on(EmitEvent.AUDIO_PAUSE, () => {})
291
+
292
+ // 动作待执行
293
+ human.on(EmitEvent.HUMAN_ACTION_PENDING, (actions: string[]) => {})
294
+
295
+ // 语音唤醒
296
+ human.on(EmitEvent.VOICE_WAKE, (data: any) => {})
297
+
298
+ // 语音休眠
299
+ human.on(EmitEvent.VOICE_SLEEP, (data: any) => {})
300
+
301
+ // 语音打断
302
+ human.on(EmitEvent.VOICE_INTERRUPT, (data: any) => {})
303
+ ```
304
+
305
+ ### EmitEvent 事件说明
306
+
307
+ | 事件名称 | 说明 | 触发时机 | 事件数据 |
308
+ |---------|------|---------|---------|
309
+ | HUMAN_LOAD_PROGRESS | 数字人加载进度 | 模型加载过程中 | `{ code: 'download' \| 'loaded', progress: number, total: number }` |
310
+ | HUMAN_READY | 数字人准备就绪 | 模型加载完成,可以开始交互 | `void` |
311
+ | HUMAN_ERROR | 数字人错误 | 发生错误时 | `{ code: string, uri: string }` |
312
+ | AUDIO_PLAY | 音频播放 | 开始播放音频时 | `void` |
313
+ | AUDIO_PAUSE | 音频暂停 | 音频暂停时 | `void` |
314
+ | HUMAN_ACTION_PENDING | 动作待执行 | 有待执行的动作时 | `string[]` |
315
+ | VOICE_WAKE | 语音唤醒 | 语音交互被唤醒时 | `any` |
316
+ | VOICE_SLEEP | 语音休眠 | 语音交互进入休眠状态时 | `any` |
317
+ | VOICE_INTERRUPT | 语音打断 | 语音交互被用户打断时 | `any` |
318
+ | WAKE_RECORDER_START | 唤醒录音开始 | 语音交互被唤醒并开始录音时 | `any` |
319
+ | WAKE_RECORDER_STOP | 唤醒状态下结束录音 | 语音交互被唤醒并结束音时 | `any` |
320
+ | VOICE2TEXT | 语音转文本 | 语音识别结果返回时 | `{ is_final: boolean, text: string, wav_name: string }` |
321
+ | CORE_BUNDLES_LOADED | 模型加载完成 | 模型加载完成 | QuanTe.Loader.LoaderResponse[] 所有模型数据 |
322
+ | RECORDER_MESSAGE | 录音消息 | 开始录音 | pcm 录音数据 |
323
+ | RECORDER_START | 开始录音 | 当录音能量值达到15时 | |
324
+ | RECORDER_STOP | 结束录音 | 0.8秒内未收到能量值超过15时 | |
325
+ | RECORDER_SENDING | 录音中 | 每次发送websocket时 | |
326
+ | ASRTEXT | 语音转文本消息 | 收到 ASR 服务数据 | 文本数据 |
327
+
328
+ ### 事件使用示例
329
+
330
+ ```typescript
331
+ import Human, { EmitEvent } from 'qt-human'
332
+
333
+ const human = new Human({
334
+ token: 'your-token',
335
+ container: 'container-id'
336
+ });
337
+
338
+ // 监听加载进度
339
+ human.on(EmitEvent.HUMAN_LOAD_PROGRESS, (data) => {
340
+ console.log(`加载进度: ${data.progress}/${data.total}`);
341
+ });
342
+
343
+ // 监听准备就绪
344
+ human.on(EmitEvent.HUMAN_READY, () => {
345
+ console.log('数字人已准备就绪,可以开始交互');
346
+ });
347
+
348
+ // 监听错误
349
+ human.on(EmitEvent.HUMAN_ERROR, (error) => {
350
+ console.error('发生错误:', error);
351
+ });
352
+
353
+ // 监听音频状态
354
+ human.on(EmitEvent.AUDIO_PLAY, () => {
355
+ console.log('开始播放音频');
356
+ });
357
+
358
+ human.on(EmitEvent.AUDIO_PAUSE, () => {
359
+ console.log('音频已暂停');
360
+ });
361
+
362
+ // 监听语音交互状态
363
+ human.on(EmitEvent.VOICE_WAKE, () => {
364
+ console.log('语音交互已唤醒');
365
+ });
366
+
367
+ human.on(EmitEvent.VOICE_SLEEP, () => {
368
+ console.log('语音交互已休眠');
369
+ });
370
+
371
+ human.on(EmitEvent.VOICE_INTERRUPT, () => {
372
+ console.log('语音交互被用户打断');
373
+ });
374
+ ```
375
+
376
+ ## 使用示例
377
+
378
+ ```typescript
379
+ import Human, { EmitEvent } from 'qt-human'
380
+ import type { QuanTe } from 'qt-human'
381
+
382
+ // 创建数字人实例
383
+ const human = new Human({
384
+ token: 'your-token',
385
+ container: 'container-id'
386
+ });
387
+
388
+ // 监听事件
389
+ human.on(EmitEvent.HUMAN_READY, () => {
390
+ console.log('数字人准备就绪');
391
+ });
392
+
393
+ // characterId: 数字人ID, 请登录 qtworld 平台复制数字人ID
394
+ human.setCharacter('characterId');
395
+
396
+ // 让数字人说话
397
+ human.speak('你好,我是数字人');
398
+
399
+ // AI问答
400
+ human.ask({
401
+ // 请求id,非必填
402
+ reqId: 'abcdefg',
403
+ message: [{ role: 'user', content: '你好' }]
404
+ }, (msgs: IResultData<QuanTe.API.ChatMessage[]>) => {
405
+ // 大模型流式推送结果
406
+ console.log(msgs);
407
+ }).then((result: QuanTe.Result<QuanTe.API.AskResponse>) => {
408
+ // 所有语音播放结束后返回bs等数据
409
+ console.log('result....', result)
410
+ });
411
+
412
+ // 控制音频
413
+ human.muteAudio(true); // 静音
414
+ human.muteAudio(false); // 取消静音
415
+
416
+ // 开始录音
417
+ human.startVoice2Text((data: QuanTe.Recorder.Voice2Text) => {
418
+ // 语音转文本内容
419
+ console.log(data)
420
+ })
421
+ // 结束录音语音转文本
422
+ human.stopVoice2Text()
423
+
424
+ // 通过 audio 和 bs 数据驱动数字人说话
425
+ human.speakByAudioShapes(['https://xxx/audio.wav', 'https://xxx/audio2.wav'], [[[...52个数据],[...52个数据]], [[...52个数据]]])
426
+
427
+ // 停止(停止语音、动作、口型动画、接口请求和待执行的任务队列等)并执行待机动画
428
+ human.stop()
429
+
430
+ // 销毁实例
431
+ human.destroy();
432
+
433
+ ```
434
+
435
+ ## 语音交互模式的使用
436
+
437
+ ```typescript
438
+ import Human, { EmitEvent } from 'qt-human'
439
+
440
+ // 1、创建数字人对象并设置语音模式
441
+ const human = new Human({
442
+ token: 'your-token',
443
+ container: 'container-id',
444
+ mode: 'voice'
445
+ });
446
+
447
+ // 数字人准备就绪
448
+ human.on(EmitEvent.HUMAN_READY, () => {
449
+ // 2、开启语音交互
450
+ human.openVoiceInteraction({
451
+ // 唤醒词
452
+ wakeWords: ['小全小全', '你好小全'],
453
+ // 退出词(休眠)
454
+ exitWords: ['退出', '关闭'],
455
+ // 打断词
456
+ interruptWorlds: ['停止', '返回']
457
+ })
458
+ });
459
+ ```
460
+
461
+ ## 注意事项
462
+
463
+ 1. 使用前必须配置有效的 token
464
+ 2. 部分方法需要等待模型加载完成(HUMAN_READY 事件触发后)才能调用
465
+ 3. 注意及时销毁实例以释放资源
466
+ 4. 音频和动作控制可以根据需要随时切换
467
+ 5. 建议在组件销毁时调用 destroy() 方法清理资源
468
+
469
+ ## 获取 characterId 和 token
470
+
471
+ - characterId
472
+ 创建 Human 对象时所需的 characterId 请登录 qtworld 平台获取,[qtworld 地址: https://ai.quantekeji.com/platform/login](https://ai.quantekeji.com/platform/login)
473
+ - token
474
+ 获取 token 请调用数字人授权接口
475
+
476
+ ## 数字人授权接口
477
+
478
+ ### 接口说明
479
+ 获取数字人访问令牌(token),用于初始化 Human 对象。
480
+
481
+ ### 请求信息
482
+ - 请求方式:POST
483
+ - 接口地址:`https://ai.quantekeji.com/platform-api/human-auth/get-token`
484
+
485
+ ### 请求参数
486
+ ```typescript
487
+ {
488
+ // 应用秘钥(不要将秘钥保存在前端)
489
+ secretKey: string;
490
+
491
+ // 访问者ID(需要唯一)
492
+ visitorId: string;
493
+
494
+ // 访问者名称
495
+ visitorName: string;
496
+ }
497
+ ```
498
+
499
+ ### 响应参数
500
+ ```typescript
501
+ {
502
+ // 状态码:0 表示成功
503
+ code: number;
504
+
505
+ // 返回数据:JWT-TOKEN
506
+ data: string;
507
+
508
+ // 响应消息
509
+ msg: string;
510
+ }
511
+ ```
512
+
513
+ ### 使用示例
514
+
515
+ ```typescript
516
+ // 使用 axios 发起请求
517
+ import axios from 'axios';
518
+
519
+ async function getToken() {
520
+ try {
521
+ const response = await axios.post('https://ai.quantekeji.com/platform-api/human-auth/get-token', {
522
+ secretKey: 'your-secret-key',
523
+ visitorId: 'unique-visitor-id',
524
+ visitorName: 'visitor-name'
525
+ });
526
+
527
+ if (response.data.code === 0) {
528
+ const token = response.data.data;
529
+ // 使用获取到的 token 初始化 Human 对象
530
+ const human = new Human({
531
+ token,
532
+ container: 'container-id'
533
+ });
534
+ }
535
+ } catch (error) {
536
+ console.error('获取 token 失败:', error);
537
+ }
538
+ }
539
+ ```
540
+
541
+ ### 注意事项
542
+ 1. secretKey 是敏感信息,不要在前端代码中直接存储,在 [qtworld](https://ai.quantekeji.com/platform/login) 平台个人中心获取
543
+ 2. visitorId 需要保证唯一性,建议使用用户ID或其他唯一标识
544
+ 3. token 有效期通常为 2 小时,过期后需要重新获取
545
+ 4. 建议在服务端调用此接口,避免暴露 secretKey
546
+ 5. 获取到 token 后,请妥善保存,用于初始化 Human 对象
547
+
548
+
549
+
550
+