@zeewain/3d-avatar-sdk 1.2.2 → 1.2.4-0

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.
@@ -452,6 +452,7 @@ async function handleTextBroadcast(params: {
452
452
  voiceCode?: string;
453
453
  speed?: number;
454
454
  broadcastMotionString?: string;
455
+ isAppend?: boolean;
455
456
  }): Promise<void> {
456
457
  if (!sdk.value) return;
457
458
 
@@ -470,7 +471,7 @@ async function handleTextBroadcast(params: {
470
471
  motionPlayMode: 'random'
471
472
  };
472
473
 
473
- await sdk.value.startBroadcast(broadcastParams);
474
+ await sdk.value.startBroadcast(broadcastParams, params.isAppend);
474
475
  addLog('文本播报已开始', 'success');
475
476
  // ElMessage.success('文本播报已开始');
476
477
  } catch (error) {
@@ -488,6 +489,7 @@ async function handleAudioBroadcast(params: {
488
489
  speed?: number;
489
490
  audioText?: string;
490
491
  broadcastMotionString?: string;
492
+ isAppend?: boolean;
491
493
  }): Promise<void> {
492
494
  if (!sdk.value) return;
493
495
 
@@ -506,7 +508,7 @@ async function handleAudioBroadcast(params: {
506
508
  motionPlayMode: 'random'
507
509
  };
508
510
 
509
- await sdk.value.startBroadcast(broadcastParams);
511
+ await sdk.value.startBroadcast(broadcastParams, params.isAppend);
510
512
  addLog('音频播报已开始', 'success');
511
513
  ElMessage.success('音频播报已开始');
512
514
  } catch (error) {
@@ -115,15 +115,18 @@
115
115
  </div>
116
116
  </el-form-item>
117
117
  <el-form-item class="action-buttons">
118
- <el-button
119
- type="primary"
120
- icon="chat-dot-round"
121
- :loading="isTextLoading"
122
- :disabled="!sdkStatus.canBroadcast || !textFormData.text || !textFormData.voiceCode || !globalConfig.avatarCode"
123
- @click="handleTextBroadcast"
124
- >
125
- {{ isTextLoading ? '播报中...' : '执行文本播报' }}
126
- </el-button>
118
+ <div class="action-buttons-container">
119
+ <el-button
120
+ type="primary"
121
+ icon="chat-dot-round"
122
+ :loading="isTextLoading"
123
+ :disabled="!sdkStatus.canBroadcast || !textFormData.text || !textFormData.voiceCode || !globalConfig.avatarCode"
124
+ @click="handleTextBroadcast"
125
+ >
126
+ {{ isTextLoading ? '播报中...' : '执行文本播报' }}
127
+ </el-button>
128
+ <el-button @click="handleResetBroadcast">重置</el-button>
129
+ </div>
127
130
  </el-form-item>
128
131
  </el-form>
129
132
  </div>
@@ -181,15 +184,18 @@
181
184
  </el-form-item>
182
185
 
183
186
  <el-form-item class="action-buttons">
184
- <el-button
187
+ <div class="action-buttons-container">
188
+ <el-button
185
189
  type="primary"
186
190
  icon="headset"
187
191
  :loading="isAudioLoading"
188
192
  :disabled="!sdkStatus.canBroadcast || !audioFormData.audioUrl || !globalConfig.avatarCode"
189
193
  @click="handleAudioBroadcast"
190
- >
191
- {{ isAudioLoading ? '播报中...' : '执行音频播报' }}
192
- </el-button>
194
+ >
195
+ {{ isAudioLoading ? '播报中...' : '执行音频播报' }}
196
+ </el-button>
197
+ <el-button @click="handleResetBroadcast">重置</el-button>
198
+ </div>
193
199
  </el-form-item>
194
200
  </el-form>
195
201
  </div>
@@ -328,6 +334,7 @@ const isAudioLoading = ref(false);
328
334
  const pauseLoading = ref(false);
329
335
  const resumeLoading = ref(false);
330
336
  const stopLoading = ref(false);
337
+ const isStartBroadcast = ref(false);
331
338
 
332
339
  async function handleTextBroadcast() {
333
340
  const { text, volume, speed, voiceCode, broadcastMotionString } = textFormData;
@@ -345,11 +352,12 @@ async function handleTextBroadcast() {
345
352
  isTextLoading.value = true;
346
353
  result.value = `🔄 正在执行文本播报...\n📝 播报文本: ${text.substring(0, 30)}${text.length > 30 ? '...' : ''}\n🎤 音色编码: ${voiceCode}\n🔊 音量: ${volume}\n⚡ 语速: ${speed}\n\n📡 流式播报中,请等待服务器响应...`;
347
354
  try {
348
- emit('text-broadcast', { avatarCode, text, volume, speed, voiceCode, broadcastMotionString });
355
+ emit('text-broadcast', { avatarCode, text, volume, speed, voiceCode, broadcastMotionString, isAppend: isStartBroadcast.value });
356
+ isStartBroadcast.value = true;
349
357
  setTimeout(() => {
350
358
  isTextLoading.value = false;
351
359
  result.value = '✅ 文本播报请求已发送\n📋 请查看右侧日志面板获取详细信息\n\n📝 操作说明:\n- 播报将以流式方式进行\n- 可使用下方控制按钮暂停/继续/停止\n- 播报过程中会触发相应的事件回调';
352
- }, 1000);
360
+ }, 0);
353
361
  } catch (error: any) {
354
362
  isTextLoading.value = false;
355
363
  result.value = `❌ 播报失败: ${error.message}\n\n🔍 可能的原因:\n- 网络连接问题\n- 音色编码不存在\n- 服务器繁忙\n- 文本内容不符合要求`;
@@ -373,7 +381,8 @@ async function handleAudioBroadcast() {
373
381
  isAudioLoading.value = true;
374
382
  result.value = `🔄 正在执行音频播报...\n🎵 音频地址: ${audioUrl}\n📝 字幕文本: ${audioText || '无'}\n🔊 音量: ${volume}\n\n📡 正在验证音频文件并加载...`;
375
383
  try {
376
- emit('audio-broadcast', { avatarCode, audioText, audioUrl, volume, broadcastMotionString });
384
+ emit('audio-broadcast', { avatarCode, audioText, audioUrl, volume, broadcastMotionString, isAppend: isStartBroadcast.value });
385
+ isStartBroadcast.value = true;
377
386
  setTimeout(() => {
378
387
  isAudioLoading.value = false;
379
388
  result.value = '✅ 音频播报请求已发送\n📋 请查看右侧日志面板获取详细信息\n\n📝 操作说明:\n- 音频将直接驱动数字人口型\n- 支持MP3、WAV等格式\n- 可使用下方控制按钮进行控制';
@@ -429,7 +438,11 @@ function handleStopBroadcast() {
429
438
  result.value = `❌ 停止播报失败: ${error.message}\n\n🔍 可能的原因:\n- Unity通信异常\n- 播报服务未初始化\n- 系统资源异常`;
430
439
  }
431
440
  }
432
-
441
+
442
+ function handleResetBroadcast() {
443
+ isStartBroadcast.value = false;
444
+ }
445
+
433
446
  function clearResult() {
434
447
  result.value = '等待播报操作...\n\n新版SDK特性:\n- 支持流式播报,实时响应\n- 内置事件回调机制\n- token统一管理,无需重复传递\n- 支持音量和语速控制\n- 实时播报控制(暂停/恢复/停止)';
435
448
  }
@@ -502,10 +515,15 @@ function clearResult() {
502
515
  &.action-buttons {
503
516
  margin-bottom: 0;
504
517
  margin-top: 25px;
505
- .el-button {
518
+ .action-buttons-container {
506
519
  width: 100%;
507
- padding: 10px 0;
508
- font-weight: 500;
520
+ display: flex;
521
+ gap: 10px;
522
+ .el-button {
523
+ width: 100%;
524
+ padding: 10px 0;
525
+ font-weight: 500;
526
+ }
509
527
  }
510
528
  }
511
529
  .input-help {
@@ -9,6 +9,7 @@
9
9
  "include": [
10
10
  "package.json",
11
11
  "vite.config.ts",
12
- "vite/**/*.ts"
12
+ "vite/**/*.ts",
13
+ "plugins/**/*.ts"
13
14
  ]
14
15
  }
@@ -5,10 +5,12 @@ import vue from '@vitejs/plugin-vue';
5
5
  import AutoImport from 'unplugin-auto-import/vite';
6
6
  import Components from 'unplugin-vue-components/vite';
7
7
  import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
8
+ import createHtml from './plugins/html';
8
9
 
9
10
  // https://vitejs.dev/config/
10
11
  export default defineConfig(({ mode, command }) =>
11
12
  {
13
+ const isBuild = command === 'build';
12
14
  // 加载环境变量
13
15
  const env = loadEnv(mode, process.cwd(), '');
14
16
 
@@ -44,7 +46,8 @@ export default defineConfig(({ mode, command }) =>
44
46
  Components({
45
47
  resolvers: [ElementPlusResolver()],
46
48
  dts: true
47
- })
49
+ }),
50
+ createHtml(isBuild)
48
51
  ],
49
52
  resolve: {
50
53
  alias: {
package/dist/index.d.ts CHANGED
@@ -351,6 +351,8 @@ interface IAvatarSDKConfig {
351
351
  onProgress?: (progress: number) => void;
352
352
  /** 播报回调函数,可选 */
353
353
  broadcastCallbacks?: IBroadcastCallbacks;
354
+ /** 是否启用调试日志,默认为false */
355
+ enableDebugLog?: boolean;
354
356
  }
355
357
 
356
358
  /**
@@ -511,9 +513,10 @@ declare class ZEEAvatarSDK {
511
513
  /**
512
514
  * 开始播报
513
515
  * @param params 播报参数
516
+ * @param isAppend 是否追加播报
514
517
  * @returns Promise<void> 播报操作的Promise
515
518
  */
516
- startBroadcast(params: IBroadcastParams): Promise<void>;
519
+ startBroadcast(params: IBroadcastParams, isAppend?: boolean): Promise<void>;
517
520
  /**
518
521
  * 暂停播报
519
522
  * @param resetIdle 是否重置空闲状态
@@ -836,12 +839,20 @@ declare class AvatarService extends UnityBaseService<AvatarOperationType> implem
836
839
  declare class BroadcastService extends UnityBaseService<BroadcastOperationType> implements IBroadcastAPI {
837
840
  /** 事件回调函数集合 */
838
841
  private callbacks;
839
- /** 请求控制器,用于取消请求 */
840
- private activeController;
842
+ /** 播报任务队列 */
843
+ private taskQueue;
844
+ /** 任务序号计数器 */
845
+ private taskSequence;
846
+ /** 当前发送任务的序号 */
847
+ private currentSendingSequence;
841
848
  /** 是否正在生成音频 */
842
849
  private isGeneratingAudio;
843
850
  /** 是否已经收到音频 */
844
851
  private hasReceivedAudio;
852
+ /** 队列处理定时器 */
853
+ private queueProcessTimer;
854
+ /** 主请求控制器(兼容性保留) */
855
+ private activeController;
845
856
  /**
846
857
  * 构造函数
847
858
  * @param config - 播报服务配置
@@ -874,8 +885,9 @@ declare class BroadcastService extends UnityBaseService<BroadcastOperationType>
874
885
  /**
875
886
  * 开始播报
876
887
  * @param params - 播报参数
888
+ * @param isAppend - 是否追加播报
877
889
  * @returns Promise<void> 播报操作的Promise
878
- * @description 开始流式播报,支持文本转语音和自定义音频播报
890
+ * @description 开始流式播报,支持文本转语音和自定义音频播报。使用队列机制确保音频按序播报
879
891
  * @throws {SDKError} 当参数验证失败或播报失败时抛出错误
880
892
  * @example
881
893
  * ```typescript
@@ -889,17 +901,18 @@ declare class BroadcastService extends UnityBaseService<BroadcastOperationType>
889
901
  * isSubtitle: true
890
902
  * });
891
903
  *
892
- * // 自定义音频播报
904
+ * // 追加播报(会进入队列按序播报)
893
905
  * await broadcastService.startBroadcast({
894
- * type: BroadcastType.AUDIO,
906
+ * type: BroadcastType.TEXT,
895
907
  * humanCode: 'human001',
896
- * audioUrl: 'https://example.com/audio.mp3',
908
+ * text: '这是第二段内容',
909
+ * voiceCode: 'voice001',
897
910
  * volume: 0.8,
898
- * isSubtitle: false
899
- * });
911
+ * isSubtitle: true
912
+ * }, true);
900
913
  * ```
901
914
  */
902
- startBroadcast(params: IBroadcastParams): Promise<void>;
915
+ startBroadcast(params: IBroadcastParams, isAppend?: boolean): Promise<void>;
903
916
  /**
904
917
  * 暂停播报
905
918
  * @param resetIdle - 是否重置空闲状态
@@ -940,7 +953,7 @@ declare class BroadcastService extends UnityBaseService<BroadcastOperationType>
940
953
  /**
941
954
  * 获取播报状态
942
955
  * @returns 播报状态信息
943
- * @description 获取当前播报服务的状态信息
956
+ * @description 获取当前播报服务的状态信息,包括队列状态
944
957
  */
945
958
  getStatus(): {
946
959
  isActive: boolean;
@@ -948,12 +961,96 @@ declare class BroadcastService extends UnityBaseService<BroadcastOperationType>
948
961
  hasReceivedAudio: boolean;
949
962
  pendingCallbacks: number;
950
963
  hasController: boolean;
964
+ queueInfo?: {
965
+ totalTasks: number;
966
+ requestingTasks: number;
967
+ completedTasks: number;
968
+ failedTasks: number;
969
+ totalPendingResponses: number;
970
+ currentSendingSequence: number;
971
+ };
951
972
  };
952
973
  /**
953
974
  * 销毁播报服务
954
975
  * @description 清理所有资源和回调
955
976
  */
956
977
  destroy(): void;
978
+ /**
979
+ * 创建播报任务
980
+ * @param params - 播报参数
981
+ * @returns IBroadcastTask 播报任务对象
982
+ * @description 创建新的播报任务并分配唯一ID和序号
983
+ * @private
984
+ */
985
+ private createBroadcastTask;
986
+ /**
987
+ * 添加任务到队列
988
+ * @param task - 播报任务
989
+ * @description 将任务添加到队列并立即开始请求
990
+ * @private
991
+ */
992
+ private addTaskToQueue;
993
+ /**
994
+ * 处理队列
995
+ * @description 处理队列中的任务,发起请求生成音频
996
+ * @private
997
+ */
998
+ private processQueue;
999
+ /**
1000
+ * 队列处理步骤
1001
+ * @description 处理队列中的单个步骤,包括发起请求和发送音频
1002
+ * @private
1003
+ */
1004
+ private processQueueStep;
1005
+ /**
1006
+ * 开始任务请求
1007
+ * @param task - 播报任务
1008
+ * @description 为任务发起流式请求生成音频
1009
+ * @private
1010
+ */
1011
+ private startTaskRequest;
1012
+ /**
1013
+ * 处理任务响应
1014
+ * @param task - 播报任务
1015
+ * @param data - 响应数据
1016
+ * @description 处理任务的流式响应数据
1017
+ * @private
1018
+ */
1019
+ private handleTaskResponse;
1020
+ /**
1021
+ * 发送下一个响应
1022
+ * @param task - 播报任务
1023
+ * @description 发送任务中的第一个待发送响应到Unity,发送后立即删除
1024
+ * @private
1025
+ */
1026
+ private sendNextResponse;
1027
+ /**
1028
+ * 处理任务关闭
1029
+ * @param task - 播报任务
1030
+ * @description 处理任务的流式连接关闭
1031
+ * @private
1032
+ */
1033
+ private handleTaskClose;
1034
+ /**
1035
+ * 处理任务错误
1036
+ * @param task - 播报任务
1037
+ * @param error - 错误对象
1038
+ * @description 处理任务执行过程中的错误
1039
+ * @private
1040
+ */
1041
+ private handleTaskError;
1042
+ /**
1043
+ * 清理已完成的任务
1044
+ * @description 从队列中移除已完成、失败或取消的任务
1045
+ * @private
1046
+ */
1047
+ private cleanupCompletedTasks;
1048
+ /**
1049
+ * 取消所有任务
1050
+ * @description 取消队列中的所有任务
1051
+ * @private
1052
+ */
1053
+ private cancelAllTasks;
957
1054
  /** 全局回调函数名称 */
958
1055
  protected get callbackFunctionName(): string;
959
1056
  /**