@zeewain/3d-avatar-sdk 1.2.0 → 1.2.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.
Files changed (55) hide show
  1. package/README.md +6 -5
  2. package/dist/assets/Build/webgl.data.unityweb +0 -0
  3. package/dist/assets/Build/webgl.framework.js.unityweb +0 -0
  4. package/dist/assets/Build/webgl.wasm.unityweb +0 -0
  5. package/dist/examples/test-umd/index.html +762 -0
  6. package/dist/examples/test-vue2/.eslintignore +45 -0
  7. package/dist/examples/test-vue2/.eslintrc.js +174 -0
  8. package/dist/examples/test-vue2/.stylelintignore +50 -0
  9. package/dist/examples/test-vue2/.stylelintrc.js +79 -0
  10. package/dist/examples/test-vue2/README.md +139 -0
  11. package/dist/examples/test-vue2/babel.config.js +14 -0
  12. package/dist/examples/test-vue2/package.json +53 -0
  13. package/dist/examples/test-vue2/pnpm-lock.yaml +8776 -0
  14. package/dist/examples/test-vue2/public/index.html +19 -0
  15. package/dist/examples/test-vue2/setup.js +170 -0
  16. package/dist/examples/test-vue2/src/App.vue +943 -0
  17. package/dist/examples/test-vue2/src/components/BroadcastAPI.vue +666 -0
  18. package/dist/examples/test-vue2/src/components/CameraAPI.vue +414 -0
  19. package/dist/examples/test-vue2/src/components/GlobalConfig.vue +200 -0
  20. package/dist/examples/test-vue2/src/components/InfoCards.vue +294 -0
  21. package/dist/examples/test-vue2/src/components/InitAPI.vue +334 -0
  22. package/dist/examples/test-vue2/src/components/LogPanel.vue +249 -0
  23. package/dist/examples/test-vue2/src/components/MotionControlAPI.vue +400 -0
  24. package/dist/examples/test-vue2/src/components/UnityPreview.vue +201 -0
  25. package/dist/examples/test-vue2/src/main.js +16 -0
  26. package/dist/examples/test-vue2/vue.config.js +41 -0
  27. package/dist/examples/test-vue3/.eslintrc +3 -0
  28. package/dist/examples/test-vue3/.stylelintignore +3 -0
  29. package/dist/examples/test-vue3/.stylelintrc +48 -0
  30. package/dist/examples/test-vue3/README.md +236 -0
  31. package/dist/examples/test-vue3/env.d.ts +8 -0
  32. package/dist/examples/test-vue3/index.html +95 -0
  33. package/dist/examples/test-vue3/package.json +55 -0
  34. package/dist/examples/test-vue3/pnpm-lock.yaml +4636 -0
  35. package/dist/examples/test-vue3/setup.js +167 -0
  36. package/dist/examples/test-vue3/src/App.vue +962 -0
  37. package/dist/examples/test-vue3/src/components/BroadcastAPI.vue +636 -0
  38. package/dist/examples/test-vue3/src/components/CameraAPI.vue +376 -0
  39. package/dist/examples/test-vue3/src/components/GlobalConfig.vue +213 -0
  40. package/dist/examples/test-vue3/src/components/InfoCards.vue +288 -0
  41. package/dist/examples/test-vue3/src/components/InitAPI.vue +339 -0
  42. package/dist/examples/test-vue3/src/components/LogPanel.vue +236 -0
  43. package/dist/examples/test-vue3/src/components/MotionControlAPI.vue +373 -0
  44. package/dist/examples/test-vue3/src/components/UnityPreview.vue +189 -0
  45. package/dist/examples/test-vue3/src/main.ts +12 -0
  46. package/dist/examples/test-vue3/src/types.ts +9 -0
  47. package/dist/examples/test-vue3/tsconfig.json +44 -0
  48. package/dist/examples/test-vue3/tsconfig.node.json +14 -0
  49. package/dist/examples/test-vue3/vite.config.ts +75 -0
  50. package/dist/index.d.ts +142 -132
  51. package/dist/index.es5.js +93 -41
  52. package/dist/index.es5.umd.js +93 -41
  53. package/dist/index.esm.js +101 -42
  54. package/dist/index.umd.cjs +101 -42
  55. package/package.json +4 -3
package/dist/index.esm.js CHANGED
@@ -63,7 +63,7 @@ var NetworkErrorCode;
63
63
  NetworkErrorCode[NetworkErrorCode["CONNECTION_FAILED"] = 1001] = "CONNECTION_FAILED";
64
64
  /** 请求超时 */
65
65
  NetworkErrorCode[NetworkErrorCode["REQUEST_TIMEOUT"] = 1002] = "REQUEST_TIMEOUT";
66
- /** 服务器错误 */
66
+ /** 服务错误 */
67
67
  NetworkErrorCode[NetworkErrorCode["SERVER_ERROR"] = 1003] = "SERVER_ERROR";
68
68
  /** 未授权访问 */
69
69
  NetworkErrorCode[NetworkErrorCode["UNAUTHORIZED"] = 1004] = "UNAUTHORIZED";
@@ -85,6 +85,12 @@ var OperationErrorCode;
85
85
  OperationErrorCode[OperationErrorCode["OPERATION_TIMEOUT"] = 2004] = "OPERATION_TIMEOUT";
86
86
  /** 操作被取消 */
87
87
  OperationErrorCode[OperationErrorCode["OPERATION_CANCELLED"] = 2005] = "OPERATION_CANCELLED";
88
+ /** 用户权益额度不存在 */
89
+ OperationErrorCode[OperationErrorCode["BROADCAST_EQUITY_NOT_EXIST"] = 2006] = "BROADCAST_EQUITY_NOT_EXIST";
90
+ /** 用户权益额度不足 */
91
+ OperationErrorCode[OperationErrorCode["BROADCAST_EQUITY_NOT_ENOUGH"] = 2007] = "BROADCAST_EQUITY_NOT_ENOUGH";
92
+ /** 用户权益额度冻结失败 */
93
+ OperationErrorCode[OperationErrorCode["BROADCAST_EQUITY_FREEZE_FAILED"] = 2008] = "BROADCAST_EQUITY_FREEZE_FAILED";
88
94
  })(OperationErrorCode || (OperationErrorCode = {}));
89
95
  /**
90
96
  * 资源错误码 (3xxx)
@@ -178,6 +184,18 @@ const ERROR_CODE_MAP = {
178
184
  category: ErrorCategory.OPERATION,
179
185
  message: '操作被取消'
180
186
  },
187
+ [OperationErrorCode.BROADCAST_EQUITY_NOT_EXIST]: {
188
+ category: ErrorCategory.OPERATION,
189
+ message: '用户权益额度不存在'
190
+ },
191
+ [OperationErrorCode.BROADCAST_EQUITY_NOT_ENOUGH]: {
192
+ category: ErrorCategory.OPERATION,
193
+ message: '用户权益额度不足'
194
+ },
195
+ [OperationErrorCode.BROADCAST_EQUITY_FREEZE_FAILED]: {
196
+ category: ErrorCategory.OPERATION,
197
+ message: '用户权益额度冻结失败'
198
+ },
181
199
  // 资源错误
182
200
  [ResourceErrorCode.LOAD_FAILED]: {
183
201
  category: ErrorCategory.RESOURCE,
@@ -474,7 +492,7 @@ class UnityBaseService {
474
492
  */
475
493
  handleCallback(operation, code, message, data) {
476
494
  const dataObj = data ? JSON.parse(data) : undefined;
477
- this.logger.warn('[ Received Unity callback ]', { operation, code, message, data: dataObj });
495
+ this.logger.warn('[ Received Unity callback ]', { operation, code, message, data: dataObj, originalData: data });
478
496
  const callback = this.pendingCallbacks.get(operation);
479
497
  if (!callback) {
480
498
  this.logger.warn(`No pending callback for operation: ${operation}`);
@@ -721,7 +739,7 @@ class SimpleLogger {
721
739
  console.warn(`[Unity Warning] ${message}`, data);
722
740
  }
723
741
  error(message, error, data) {
724
- console.error(`[Unity Error] ${message}`, error, data);
742
+ console.error(`[Unity Error] ${message}`, error, error instanceof SDKError ? error.code : null, data);
725
743
  }
726
744
  }
727
745
 
@@ -772,7 +790,6 @@ class AvatarService extends UnityBaseService {
772
790
  }
773
791
  /**
774
792
  * 构造函数
775
- * @param unityInstance - Unity实例对象
776
793
  * @param config - 可选的服务配置,用于覆盖默认配置
777
794
  * @description 初始化Avatar API,设置Unity实例和配置
778
795
  * @example
@@ -1090,6 +1107,7 @@ class ConfigManager {
1090
1107
  getApiBaseUrl(withModule = true) {
1091
1108
  var _a, _b, _c, _d;
1092
1109
  if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.env) === 'custom' && ((_b = this.config) === null || _b === void 0 ? void 0 : _b.apiUrl)) {
1110
+ // 如果环境为自定义,则直接返回配置的API,无需添加模块路径
1093
1111
  return this.config.apiUrl;
1094
1112
  }
1095
1113
  return ((_d = getEnvConfig(((_c = this.config) === null || _c === void 0 ? void 0 : _c.env) || 'prod', withModule)) === null || _d === void 0 ? void 0 : _d.apiBaseUrl) || '';
@@ -1157,16 +1175,12 @@ class UnityLoader {
1157
1175
  createContainer() {
1158
1176
  const container = document.getElementById(this.config.containerId);
1159
1177
  if (!container) {
1160
- throw new Error(`Container element with ID "${this.config.containerId}" not found`);
1178
+ throw new TypeError(`Avatar container element with ID "${this.config.containerId}" not found`);
1161
1179
  }
1162
- container.style.width = '100%';
1163
- container.style.height = '100%';
1164
- container.style.position = 'relative';
1165
- // 移除容器提示元素
1166
- const containerTip = document.getElementById('unity-container-tip');
1167
- if (containerTip) {
1168
- containerTip.remove();
1180
+ else if (!(container instanceof HTMLDivElement)) {
1181
+ throw new TypeError('Avatar container element must be a div element');
1169
1182
  }
1183
+ container.style.position = 'relative';
1170
1184
  return container;
1171
1185
  }
1172
1186
  /**
@@ -1215,12 +1229,15 @@ class UnityLoader {
1215
1229
  */
1216
1230
  createUnityInstance(container) {
1217
1231
  return __awaiter(this, void 0, void 0, function* () {
1218
- // 创建Canvas元素
1219
- const canvas = document.createElement('canvas');
1220
- canvas.id = 'unity-canvas';
1221
- canvas.style.width = '100%';
1222
- canvas.style.height = '100%';
1223
- container.appendChild(canvas);
1232
+ let canvas = container.querySelector('#unity-canvas');
1233
+ // 避免重复创建
1234
+ if (!canvas) {
1235
+ canvas = document.createElement('canvas');
1236
+ canvas.id = 'unity-canvas';
1237
+ canvas.style.width = '100%';
1238
+ canvas.style.height = '100%';
1239
+ container.appendChild(canvas);
1240
+ }
1224
1241
  // 移动设备适配
1225
1242
  if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
1226
1243
  // 添加移动设备viewport元标签
@@ -1545,23 +1562,29 @@ class BroadcastService extends UnityBaseService {
1545
1562
  // 触发对应的事件回调(仅在成功时)
1546
1563
  if (code === 0) {
1547
1564
  switch (operation) {
1565
+ case BroadcastOperationType.START_BROADCAST:
1566
+ if (isBroadcastCompleted) {
1567
+ (_b = (_a = this.callbacks).onFinish) === null || _b === void 0 ? void 0 : _b.call(_a);
1568
+ }
1569
+ break;
1548
1570
  case BroadcastOperationType.PAUSE_BROADCAST:
1549
- (_b = (_a = this.callbacks).onPause) === null || _b === void 0 ? void 0 : _b.call(_a);
1571
+ (_d = (_c = this.callbacks).onPause) === null || _d === void 0 ? void 0 : _d.call(_c);
1550
1572
  this.logger.debug('Broadcast paused callback triggered');
1551
1573
  break;
1552
1574
  case BroadcastOperationType.RESUME_BROADCAST:
1553
- (_d = (_c = this.callbacks).onResume) === null || _d === void 0 ? void 0 : _d.call(_c);
1575
+ (_f = (_e = this.callbacks).onResume) === null || _f === void 0 ? void 0 : _f.call(_e);
1554
1576
  this.logger.debug('Broadcast resumed callback triggered');
1555
1577
  break;
1556
1578
  case BroadcastOperationType.STOP_BROADCAST:
1557
- (_f = (_e = this.callbacks).onStop) === null || _f === void 0 ? void 0 : _f.call(_e);
1558
- if (isBroadcastCompleted) {
1559
- (_h = (_g = this.callbacks).onFinish) === null || _h === void 0 ? void 0 : _h.call(_g);
1560
- }
1579
+ (_h = (_g = this.callbacks).onStop) === null || _h === void 0 ? void 0 : _h.call(_g);
1561
1580
  this.logger.debug('Broadcast stopped callback triggered');
1562
1581
  break;
1563
1582
  }
1564
1583
  }
1584
+ else {
1585
+ const error = SDKError.createFromUnityError(code, `Unity operation '${operation}' failed: ${message}`);
1586
+ this.handleError(error);
1587
+ }
1565
1588
  }
1566
1589
  /**
1567
1590
  * 开始播报
@@ -1622,7 +1645,7 @@ class BroadcastService extends UnityBaseService {
1622
1645
  motionPlayMode: params.motionPlayMode
1623
1646
  });
1624
1647
  try {
1625
- const apiUrl = `${this.getApiBaseUrl()}${this.getBroadcastApiPath(params.type)}`;
1648
+ const apiUrl = `${ConfigManager.getInstance().getApiBaseUrl(true)}${this.getBroadcastApiPath(params.type)}`;
1626
1649
  const requestBody = {
1627
1650
  humanCode: params.humanCode,
1628
1651
  speed: params.speed,
@@ -1656,7 +1679,7 @@ class BroadcastService extends UnityBaseService {
1656
1679
  const response = JSON.parse(event.data);
1657
1680
  // 错误处理
1658
1681
  if (response.code !== 0) {
1659
- this.handleError(new SDKError(NetworkErrorCode.SERVER_ERROR, response.message || '未知服务器错误'));
1682
+ this.handleBroadcastError(response.code);
1660
1683
  return;
1661
1684
  }
1662
1685
  // 流式播报
@@ -1695,7 +1718,10 @@ class BroadcastService extends UnityBaseService {
1695
1718
  },
1696
1719
  onerror: (error) => {
1697
1720
  this.logger.error('Broadcast stream error', error);
1698
- this.handleError(new SDKError(OperationErrorCode.OPERATION_FAILED, '播报流错误', error));
1721
+ const sdkError = new SDKError(OperationErrorCode.OPERATION_FAILED, '服务出错了', error);
1722
+ this.handleError(sdkError);
1723
+ // 必须抛出错误,否则会循环重试请求
1724
+ throw new Error(`服务出错了${sdkError.message}`);
1699
1725
  }
1700
1726
  });
1701
1727
  }
@@ -1819,16 +1845,6 @@ class BroadcastService extends UnityBaseService {
1819
1845
  get callbackFunctionName() {
1820
1846
  return 'uniBroadcastCallback';
1821
1847
  }
1822
- /**
1823
- * 获取API基础URL
1824
- * @returns string 返回当前环境的API基础URL
1825
- * @description 根据当前环境配置获取API基础URL
1826
- * @private
1827
- */
1828
- getApiBaseUrl() {
1829
- const configManager = ConfigManager.getInstance();
1830
- return configManager.getApiBaseUrl();
1831
- }
1832
1848
  /**
1833
1849
  * 获取播报API路径
1834
1850
  * @param type - 播报类型
@@ -1838,10 +1854,19 @@ class BroadcastService extends UnityBaseService {
1838
1854
  * @private
1839
1855
  */
1840
1856
  getBroadcastApiPath(type) {
1857
+ const env = ConfigManager.getInstance().getEnv();
1841
1858
  switch (type) {
1842
1859
  case BroadcastType.TEXT:
1860
+ // 临时处理,开发和测试环境使用新接口
1861
+ if (env === 'dev' || env === 'test') {
1862
+ return '/aiep-openapi/avatar-interaction/v1/broadcast/text';
1863
+ }
1843
1864
  return '/dh-talker/user/agent/broadcast/text';
1844
1865
  case BroadcastType.AUDIO:
1866
+ // 临时处理,开发和测试环境使用新接口
1867
+ if (env === 'dev' || env === 'test') {
1868
+ return '/aiep-openapi/avatar-interaction/v1/broadcast/audio';
1869
+ }
1845
1870
  return '/dh-talker/user/agent/broadcast/customAudio';
1846
1871
  default:
1847
1872
  throw new SDKError(ConfigErrorCode.INVALID_CONFIG, `未知的播报类型: ${type}`);
@@ -1883,6 +1908,31 @@ class BroadcastService extends UnityBaseService {
1883
1908
  // 触发错误回调
1884
1909
  (_b = (_a = this.callbacks).onError) === null || _b === void 0 ? void 0 : _b.call(_a, error);
1885
1910
  }
1911
+ /**
1912
+ * 处理播报错误
1913
+ * @param errorCode - 错误码
1914
+ * @description 处理播报过程中的错误
1915
+ * @private
1916
+ */
1917
+ handleBroadcastError(errorCode) {
1918
+ // 用户权益额度不存在错误码 14001
1919
+ // 用户权益额度不足错误码 14002
1920
+ // 用户权益额度冻结失败 14003
1921
+ switch (errorCode) {
1922
+ case 14001:
1923
+ this.handleError(new SDKError(OperationErrorCode.BROADCAST_EQUITY_NOT_EXIST, '用户权益额度不存在'));
1924
+ break;
1925
+ case 14002:
1926
+ this.handleError(new SDKError(OperationErrorCode.BROADCAST_EQUITY_NOT_ENOUGH, '用户权益额度不足'));
1927
+ break;
1928
+ case 14003:
1929
+ this.handleError(new SDKError(OperationErrorCode.BROADCAST_EQUITY_FREEZE_FAILED, '用户权益额度冻结失败'));
1930
+ break;
1931
+ default:
1932
+ this.handleError(new SDKError(OperationErrorCode.OPERATION_FAILED, '播报服务错误'));
1933
+ break;
1934
+ }
1935
+ }
1886
1936
  }
1887
1937
 
1888
1938
  /**
@@ -1984,10 +2034,13 @@ class ZEEAvatarLoader {
1984
2034
  */
1985
2035
  destroy() {
1986
2036
  if (this.unityInstance) {
1987
- // 移除DOM容器
2037
+ // 移除DOM容器下的canvas元素
1988
2038
  const container = document.getElementById(this.getContainerId());
1989
2039
  if (container) {
1990
- container.remove();
2040
+ const canvas = container.querySelector('#unity-canvas');
2041
+ if (canvas) {
2042
+ canvas.remove();
2043
+ }
1991
2044
  }
1992
2045
  // 退出Unity实例
1993
2046
  if (typeof this.unityInstance.Quit === 'function') {
@@ -2006,7 +2059,12 @@ class ZEEAvatarLoader {
2006
2059
  * @protected
2007
2060
  */
2008
2061
  initGlobalConfig() {
2009
- const params = Object.assign(Object.assign({}, ConfigManager.getInstance().getConfig()), { token: ConfigManager.getInstance().getToken(), apiBaseUrl: ConfigManager.getInstance().getApiBaseUrl(false) });
2062
+ const params = {
2063
+ token: ConfigManager.getInstance().getToken(),
2064
+ apiBaseUrl: ConfigManager.getInstance().getApiBaseUrl(false),
2065
+ idleMotionList: ConfigManager.getInstance().getConfig().idleMotionList,
2066
+ assetsUrl: ConfigManager.getInstance().getConfig().assetsUrl
2067
+ };
2010
2068
  console.warn('[ Send Unity message ]: AvatarSDK.InitializeConfig', params);
2011
2069
  this.unityInstance.SendMessage('AvatarSDK', 'InitializeConfig', JSON.stringify(params));
2012
2070
  }
@@ -2076,7 +2134,8 @@ class ZEEAvatarSDK {
2076
2134
  // 5. 创建带有唯一标识符的播报服务
2077
2135
  this.broadcastService = new BroadcastService({
2078
2136
  unityInstance: this.unityInstance,
2079
- instanceId: this.instanceId
2137
+ instanceId: this.instanceId,
2138
+ callbacks: this.config.broadcastCallbacks
2080
2139
  });
2081
2140
  // 6. 初始化数字人
2082
2141
  const result = yield this.avatarService.initializeAvatar(avatarCode, cameraType);
@@ -2291,7 +2350,7 @@ class ZEEAvatarSDK {
2291
2350
  */
2292
2351
  ensureInitialized() {
2293
2352
  if (!this.isInitialized) {
2294
- throw new SDKError(OperationErrorCode.UNITY_NOT_INITIALIZED, 'SDK未初始化,请先调用initializeAvatar()方法');
2353
+ throw new SDKError(OperationErrorCode.UNITY_NOT_INITIALIZED, 'Avatar尚未初始化,请先调用initializeAvatar()方法');
2295
2354
  }
2296
2355
  }
2297
2356
  }
@@ -69,7 +69,7 @@
69
69
  NetworkErrorCode[NetworkErrorCode["CONNECTION_FAILED"] = 1001] = "CONNECTION_FAILED";
70
70
  /** 请求超时 */
71
71
  NetworkErrorCode[NetworkErrorCode["REQUEST_TIMEOUT"] = 1002] = "REQUEST_TIMEOUT";
72
- /** 服务器错误 */
72
+ /** 服务错误 */
73
73
  NetworkErrorCode[NetworkErrorCode["SERVER_ERROR"] = 1003] = "SERVER_ERROR";
74
74
  /** 未授权访问 */
75
75
  NetworkErrorCode[NetworkErrorCode["UNAUTHORIZED"] = 1004] = "UNAUTHORIZED";
@@ -91,6 +91,12 @@
91
91
  OperationErrorCode[OperationErrorCode["OPERATION_TIMEOUT"] = 2004] = "OPERATION_TIMEOUT";
92
92
  /** 操作被取消 */
93
93
  OperationErrorCode[OperationErrorCode["OPERATION_CANCELLED"] = 2005] = "OPERATION_CANCELLED";
94
+ /** 用户权益额度不存在 */
95
+ OperationErrorCode[OperationErrorCode["BROADCAST_EQUITY_NOT_EXIST"] = 2006] = "BROADCAST_EQUITY_NOT_EXIST";
96
+ /** 用户权益额度不足 */
97
+ OperationErrorCode[OperationErrorCode["BROADCAST_EQUITY_NOT_ENOUGH"] = 2007] = "BROADCAST_EQUITY_NOT_ENOUGH";
98
+ /** 用户权益额度冻结失败 */
99
+ OperationErrorCode[OperationErrorCode["BROADCAST_EQUITY_FREEZE_FAILED"] = 2008] = "BROADCAST_EQUITY_FREEZE_FAILED";
94
100
  })(exports.OperationErrorCode || (exports.OperationErrorCode = {}));
95
101
  /**
96
102
  * 资源错误码 (3xxx)
@@ -184,6 +190,18 @@
184
190
  category: exports.ErrorCategory.OPERATION,
185
191
  message: '操作被取消'
186
192
  },
193
+ [exports.OperationErrorCode.BROADCAST_EQUITY_NOT_EXIST]: {
194
+ category: exports.ErrorCategory.OPERATION,
195
+ message: '用户权益额度不存在'
196
+ },
197
+ [exports.OperationErrorCode.BROADCAST_EQUITY_NOT_ENOUGH]: {
198
+ category: exports.ErrorCategory.OPERATION,
199
+ message: '用户权益额度不足'
200
+ },
201
+ [exports.OperationErrorCode.BROADCAST_EQUITY_FREEZE_FAILED]: {
202
+ category: exports.ErrorCategory.OPERATION,
203
+ message: '用户权益额度冻结失败'
204
+ },
187
205
  // 资源错误
188
206
  [exports.ResourceErrorCode.LOAD_FAILED]: {
189
207
  category: exports.ErrorCategory.RESOURCE,
@@ -480,7 +498,7 @@
480
498
  */
481
499
  handleCallback(operation, code, message, data) {
482
500
  const dataObj = data ? JSON.parse(data) : undefined;
483
- this.logger.warn('[ Received Unity callback ]', { operation, code, message, data: dataObj });
501
+ this.logger.warn('[ Received Unity callback ]', { operation, code, message, data: dataObj, originalData: data });
484
502
  const callback = this.pendingCallbacks.get(operation);
485
503
  if (!callback) {
486
504
  this.logger.warn(`No pending callback for operation: ${operation}`);
@@ -727,7 +745,7 @@
727
745
  console.warn(`[Unity Warning] ${message}`, data);
728
746
  }
729
747
  error(message, error, data) {
730
- console.error(`[Unity Error] ${message}`, error, data);
748
+ console.error(`[Unity Error] ${message}`, error, error instanceof SDKError ? error.code : null, data);
731
749
  }
732
750
  }
733
751
 
@@ -778,7 +796,6 @@
778
796
  }
779
797
  /**
780
798
  * 构造函数
781
- * @param unityInstance - Unity实例对象
782
799
  * @param config - 可选的服务配置,用于覆盖默认配置
783
800
  * @description 初始化Avatar API,设置Unity实例和配置
784
801
  * @example
@@ -1096,6 +1113,7 @@
1096
1113
  getApiBaseUrl(withModule = true) {
1097
1114
  var _a, _b, _c, _d;
1098
1115
  if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.env) === 'custom' && ((_b = this.config) === null || _b === void 0 ? void 0 : _b.apiUrl)) {
1116
+ // 如果环境为自定义,则直接返回配置的API,无需添加模块路径
1099
1117
  return this.config.apiUrl;
1100
1118
  }
1101
1119
  return ((_d = getEnvConfig(((_c = this.config) === null || _c === void 0 ? void 0 : _c.env) || 'prod', withModule)) === null || _d === void 0 ? void 0 : _d.apiBaseUrl) || '';
@@ -1163,16 +1181,12 @@
1163
1181
  createContainer() {
1164
1182
  const container = document.getElementById(this.config.containerId);
1165
1183
  if (!container) {
1166
- throw new Error(`Container element with ID "${this.config.containerId}" not found`);
1184
+ throw new TypeError(`Avatar container element with ID "${this.config.containerId}" not found`);
1167
1185
  }
1168
- container.style.width = '100%';
1169
- container.style.height = '100%';
1170
- container.style.position = 'relative';
1171
- // 移除容器提示元素
1172
- const containerTip = document.getElementById('unity-container-tip');
1173
- if (containerTip) {
1174
- containerTip.remove();
1186
+ else if (!(container instanceof HTMLDivElement)) {
1187
+ throw new TypeError('Avatar container element must be a div element');
1175
1188
  }
1189
+ container.style.position = 'relative';
1176
1190
  return container;
1177
1191
  }
1178
1192
  /**
@@ -1221,12 +1235,15 @@
1221
1235
  */
1222
1236
  createUnityInstance(container) {
1223
1237
  return __awaiter(this, void 0, void 0, function* () {
1224
- // 创建Canvas元素
1225
- const canvas = document.createElement('canvas');
1226
- canvas.id = 'unity-canvas';
1227
- canvas.style.width = '100%';
1228
- canvas.style.height = '100%';
1229
- container.appendChild(canvas);
1238
+ let canvas = container.querySelector('#unity-canvas');
1239
+ // 避免重复创建
1240
+ if (!canvas) {
1241
+ canvas = document.createElement('canvas');
1242
+ canvas.id = 'unity-canvas';
1243
+ canvas.style.width = '100%';
1244
+ canvas.style.height = '100%';
1245
+ container.appendChild(canvas);
1246
+ }
1230
1247
  // 移动设备适配
1231
1248
  if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
1232
1249
  // 添加移动设备viewport元标签
@@ -1551,23 +1568,29 @@
1551
1568
  // 触发对应的事件回调(仅在成功时)
1552
1569
  if (code === 0) {
1553
1570
  switch (operation) {
1571
+ case exports.BroadcastOperationType.START_BROADCAST:
1572
+ if (isBroadcastCompleted) {
1573
+ (_b = (_a = this.callbacks).onFinish) === null || _b === void 0 ? void 0 : _b.call(_a);
1574
+ }
1575
+ break;
1554
1576
  case exports.BroadcastOperationType.PAUSE_BROADCAST:
1555
- (_b = (_a = this.callbacks).onPause) === null || _b === void 0 ? void 0 : _b.call(_a);
1577
+ (_d = (_c = this.callbacks).onPause) === null || _d === void 0 ? void 0 : _d.call(_c);
1556
1578
  this.logger.debug('Broadcast paused callback triggered');
1557
1579
  break;
1558
1580
  case exports.BroadcastOperationType.RESUME_BROADCAST:
1559
- (_d = (_c = this.callbacks).onResume) === null || _d === void 0 ? void 0 : _d.call(_c);
1581
+ (_f = (_e = this.callbacks).onResume) === null || _f === void 0 ? void 0 : _f.call(_e);
1560
1582
  this.logger.debug('Broadcast resumed callback triggered');
1561
1583
  break;
1562
1584
  case exports.BroadcastOperationType.STOP_BROADCAST:
1563
- (_f = (_e = this.callbacks).onStop) === null || _f === void 0 ? void 0 : _f.call(_e);
1564
- if (isBroadcastCompleted) {
1565
- (_h = (_g = this.callbacks).onFinish) === null || _h === void 0 ? void 0 : _h.call(_g);
1566
- }
1585
+ (_h = (_g = this.callbacks).onStop) === null || _h === void 0 ? void 0 : _h.call(_g);
1567
1586
  this.logger.debug('Broadcast stopped callback triggered');
1568
1587
  break;
1569
1588
  }
1570
1589
  }
1590
+ else {
1591
+ const error = SDKError.createFromUnityError(code, `Unity operation '${operation}' failed: ${message}`);
1592
+ this.handleError(error);
1593
+ }
1571
1594
  }
1572
1595
  /**
1573
1596
  * 开始播报
@@ -1628,7 +1651,7 @@
1628
1651
  motionPlayMode: params.motionPlayMode
1629
1652
  });
1630
1653
  try {
1631
- const apiUrl = `${this.getApiBaseUrl()}${this.getBroadcastApiPath(params.type)}`;
1654
+ const apiUrl = `${ConfigManager.getInstance().getApiBaseUrl(true)}${this.getBroadcastApiPath(params.type)}`;
1632
1655
  const requestBody = {
1633
1656
  humanCode: params.humanCode,
1634
1657
  speed: params.speed,
@@ -1662,7 +1685,7 @@
1662
1685
  const response = JSON.parse(event.data);
1663
1686
  // 错误处理
1664
1687
  if (response.code !== 0) {
1665
- this.handleError(new SDKError(exports.NetworkErrorCode.SERVER_ERROR, response.message || '未知服务器错误'));
1688
+ this.handleBroadcastError(response.code);
1666
1689
  return;
1667
1690
  }
1668
1691
  // 流式播报
@@ -1701,7 +1724,10 @@
1701
1724
  },
1702
1725
  onerror: (error) => {
1703
1726
  this.logger.error('Broadcast stream error', error);
1704
- this.handleError(new SDKError(exports.OperationErrorCode.OPERATION_FAILED, '播报流错误', error));
1727
+ const sdkError = new SDKError(exports.OperationErrorCode.OPERATION_FAILED, '服务出错了', error);
1728
+ this.handleError(sdkError);
1729
+ // 必须抛出错误,否则会循环重试请求
1730
+ throw new Error(`服务出错了${sdkError.message}`);
1705
1731
  }
1706
1732
  });
1707
1733
  }
@@ -1825,16 +1851,6 @@
1825
1851
  get callbackFunctionName() {
1826
1852
  return 'uniBroadcastCallback';
1827
1853
  }
1828
- /**
1829
- * 获取API基础URL
1830
- * @returns string 返回当前环境的API基础URL
1831
- * @description 根据当前环境配置获取API基础URL
1832
- * @private
1833
- */
1834
- getApiBaseUrl() {
1835
- const configManager = ConfigManager.getInstance();
1836
- return configManager.getApiBaseUrl();
1837
- }
1838
1854
  /**
1839
1855
  * 获取播报API路径
1840
1856
  * @param type - 播报类型
@@ -1844,10 +1860,19 @@
1844
1860
  * @private
1845
1861
  */
1846
1862
  getBroadcastApiPath(type) {
1863
+ const env = ConfigManager.getInstance().getEnv();
1847
1864
  switch (type) {
1848
1865
  case exports.BroadcastType.TEXT:
1866
+ // 临时处理,开发和测试环境使用新接口
1867
+ if (env === 'dev' || env === 'test') {
1868
+ return '/aiep-openapi/avatar-interaction/v1/broadcast/text';
1869
+ }
1849
1870
  return '/dh-talker/user/agent/broadcast/text';
1850
1871
  case exports.BroadcastType.AUDIO:
1872
+ // 临时处理,开发和测试环境使用新接口
1873
+ if (env === 'dev' || env === 'test') {
1874
+ return '/aiep-openapi/avatar-interaction/v1/broadcast/audio';
1875
+ }
1851
1876
  return '/dh-talker/user/agent/broadcast/customAudio';
1852
1877
  default:
1853
1878
  throw new SDKError(exports.ConfigErrorCode.INVALID_CONFIG, `未知的播报类型: ${type}`);
@@ -1889,6 +1914,31 @@
1889
1914
  // 触发错误回调
1890
1915
  (_b = (_a = this.callbacks).onError) === null || _b === void 0 ? void 0 : _b.call(_a, error);
1891
1916
  }
1917
+ /**
1918
+ * 处理播报错误
1919
+ * @param errorCode - 错误码
1920
+ * @description 处理播报过程中的错误
1921
+ * @private
1922
+ */
1923
+ handleBroadcastError(errorCode) {
1924
+ // 用户权益额度不存在错误码 14001
1925
+ // 用户权益额度不足错误码 14002
1926
+ // 用户权益额度冻结失败 14003
1927
+ switch (errorCode) {
1928
+ case 14001:
1929
+ this.handleError(new SDKError(exports.OperationErrorCode.BROADCAST_EQUITY_NOT_EXIST, '用户权益额度不存在'));
1930
+ break;
1931
+ case 14002:
1932
+ this.handleError(new SDKError(exports.OperationErrorCode.BROADCAST_EQUITY_NOT_ENOUGH, '用户权益额度不足'));
1933
+ break;
1934
+ case 14003:
1935
+ this.handleError(new SDKError(exports.OperationErrorCode.BROADCAST_EQUITY_FREEZE_FAILED, '用户权益额度冻结失败'));
1936
+ break;
1937
+ default:
1938
+ this.handleError(new SDKError(exports.OperationErrorCode.OPERATION_FAILED, '播报服务错误'));
1939
+ break;
1940
+ }
1941
+ }
1892
1942
  }
1893
1943
 
1894
1944
  /**
@@ -1990,10 +2040,13 @@
1990
2040
  */
1991
2041
  destroy() {
1992
2042
  if (this.unityInstance) {
1993
- // 移除DOM容器
2043
+ // 移除DOM容器下的canvas元素
1994
2044
  const container = document.getElementById(this.getContainerId());
1995
2045
  if (container) {
1996
- container.remove();
2046
+ const canvas = container.querySelector('#unity-canvas');
2047
+ if (canvas) {
2048
+ canvas.remove();
2049
+ }
1997
2050
  }
1998
2051
  // 退出Unity实例
1999
2052
  if (typeof this.unityInstance.Quit === 'function') {
@@ -2012,7 +2065,12 @@
2012
2065
  * @protected
2013
2066
  */
2014
2067
  initGlobalConfig() {
2015
- const params = Object.assign(Object.assign({}, ConfigManager.getInstance().getConfig()), { token: ConfigManager.getInstance().getToken(), apiBaseUrl: ConfigManager.getInstance().getApiBaseUrl(false) });
2068
+ const params = {
2069
+ token: ConfigManager.getInstance().getToken(),
2070
+ apiBaseUrl: ConfigManager.getInstance().getApiBaseUrl(false),
2071
+ idleMotionList: ConfigManager.getInstance().getConfig().idleMotionList,
2072
+ assetsUrl: ConfigManager.getInstance().getConfig().assetsUrl
2073
+ };
2016
2074
  console.warn('[ Send Unity message ]: AvatarSDK.InitializeConfig', params);
2017
2075
  this.unityInstance.SendMessage('AvatarSDK', 'InitializeConfig', JSON.stringify(params));
2018
2076
  }
@@ -2082,7 +2140,8 @@
2082
2140
  // 5. 创建带有唯一标识符的播报服务
2083
2141
  this.broadcastService = new BroadcastService({
2084
2142
  unityInstance: this.unityInstance,
2085
- instanceId: this.instanceId
2143
+ instanceId: this.instanceId,
2144
+ callbacks: this.config.broadcastCallbacks
2086
2145
  });
2087
2146
  // 6. 初始化数字人
2088
2147
  const result = yield this.avatarService.initializeAvatar(avatarCode, cameraType);
@@ -2297,7 +2356,7 @@
2297
2356
  */
2298
2357
  ensureInitialized() {
2299
2358
  if (!this.isInitialized) {
2300
- throw new SDKError(exports.OperationErrorCode.UNITY_NOT_INITIALIZED, 'SDK未初始化,请先调用initializeAvatar()方法');
2359
+ throw new SDKError(exports.OperationErrorCode.UNITY_NOT_INITIALIZED, 'Avatar尚未初始化,请先调用initializeAvatar()方法');
2301
2360
  }
2302
2361
  }
2303
2362
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zeewain/3d-avatar-sdk",
3
3
  "type": "module",
4
- "version": "1.2.0",
4
+ "version": "1.2.2",
5
5
  "description": "SDK for ZEE Avatar WebGL integration",
6
6
  "author": "ZEEWain",
7
7
  "license": "MIT",
@@ -76,12 +76,13 @@
76
76
  "cross-env": "^7.0.3",
77
77
  "del-cli": "^5.1.0",
78
78
  "eslint": "^8.22.0",
79
+ "fs-extra": "^11.3.0",
80
+ "glob": "^11.0.3",
81
+ "minimatch": "^10.0.3",
79
82
  "release-it": "^17.6.0",
80
83
  "rollup": "^4.12.0",
81
84
  "rollup-plugin-copy": "^3.5.0",
82
85
  "rollup-plugin-dts": "^6.1.0",
83
- "rollup-plugin-livereload": "^2.0.5",
84
- "rollup-plugin-serve": "^3.0.0",
85
86
  "tslib": "^2.6.2",
86
87
  "typescript": "^5.8.3"
87
88
  },