@zeewain/3d-avatar-sdk 2.1.5 → 2.2.1

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.
@@ -1,2865 +1 @@
1
- (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ZEEAvatarSDKLib = {}));
5
- })(this, (function (exports) { 'use strict';
6
-
7
- /******************************************************************************
8
- Copyright (c) Microsoft Corporation.
9
-
10
- Permission to use, copy, modify, and/or distribute this software for any
11
- purpose with or without fee is hereby granted.
12
-
13
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
14
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
16
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
18
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19
- PERFORMANCE OF THIS SOFTWARE.
20
- ***************************************************************************** */
21
- /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
22
-
23
-
24
- function __awaiter(thisArg, _arguments, P, generator) {
25
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
26
- return new (P || (P = Promise))(function (resolve, reject) {
27
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
28
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
29
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
30
- step((generator = generator.apply(thisArg, _arguments || [])).next());
31
- });
32
- }
33
-
34
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
35
- var e = new Error(message);
36
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
37
- };
38
-
39
- /**
40
- * @fileoverview SDK简化错误码定义
41
- * @description 定义SDK的基本错误类型和错误码,保持简单实用
42
- */
43
- /**
44
- * 错误类别枚举
45
- * @enum {string}
46
- * @description 错误的主要分类
47
- */
48
- exports.ErrorCategory = void 0;
49
- (function (ErrorCategory) {
50
- /** 网络通信错误 */
51
- ErrorCategory["NETWORK"] = "NETWORK";
52
- /** 操作执行错误 */
53
- ErrorCategory["OPERATION"] = "OPERATION";
54
- /** 资源加载错误 */
55
- ErrorCategory["RESOURCE"] = "RESOURCE";
56
- /** 系统错误 */
57
- ErrorCategory["SYSTEM"] = "SYSTEM";
58
- /** 配置错误 */
59
- ErrorCategory["CONFIG"] = "CONFIG";
60
- })(exports.ErrorCategory || (exports.ErrorCategory = {}));
61
- /**
62
- * 网络错误码 (1xxx)
63
- * @enum {number}
64
- * @description 网络相关的错误码
65
- */
66
- exports.NetworkErrorCode = void 0;
67
- (function (NetworkErrorCode) {
68
- /** 网络连接失败 */
69
- NetworkErrorCode[NetworkErrorCode["CONNECTION_FAILED"] = 1001] = "CONNECTION_FAILED";
70
- /** 请求超时 */
71
- NetworkErrorCode[NetworkErrorCode["REQUEST_TIMEOUT"] = 1002] = "REQUEST_TIMEOUT";
72
- /** 服务错误 */
73
- NetworkErrorCode[NetworkErrorCode["SERVER_ERROR"] = 1003] = "SERVER_ERROR";
74
- /** 未授权访问 */
75
- NetworkErrorCode[NetworkErrorCode["UNAUTHORIZED"] = 1004] = "UNAUTHORIZED";
76
- })(exports.NetworkErrorCode || (exports.NetworkErrorCode = {}));
77
- /**
78
- * 操作错误码 (2xxx)
79
- * @enum {number}
80
- * @description 数字人操作相关的错误码
81
- */
82
- exports.OperationErrorCode = void 0;
83
- (function (OperationErrorCode) {
84
- /** Unity实例未初始化 */
85
- OperationErrorCode[OperationErrorCode["UNITY_NOT_INITIALIZED"] = 2001] = "UNITY_NOT_INITIALIZED";
86
- /** 数字人未加载 */
87
- OperationErrorCode[OperationErrorCode["AVATAR_NOT_LOADED"] = 2002] = "AVATAR_NOT_LOADED";
88
- /** 操作执行失败 */
89
- OperationErrorCode[OperationErrorCode["OPERATION_FAILED"] = 2003] = "OPERATION_FAILED";
90
- /** 操作超时 */
91
- OperationErrorCode[OperationErrorCode["OPERATION_TIMEOUT"] = 2004] = "OPERATION_TIMEOUT";
92
- /** 操作被取消 */
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";
100
- })(exports.OperationErrorCode || (exports.OperationErrorCode = {}));
101
- /**
102
- * 资源错误码 (3xxx)
103
- * @enum {number}
104
- * @description 资源加载相关的错误码
105
- */
106
- exports.ResourceErrorCode = void 0;
107
- (function (ResourceErrorCode) {
108
- /** 资源加载失败 */
109
- ResourceErrorCode[ResourceErrorCode["LOAD_FAILED"] = 3001] = "LOAD_FAILED";
110
- /** 资源文件损坏 */
111
- ResourceErrorCode[ResourceErrorCode["FILE_CORRUPTED"] = 3002] = "FILE_CORRUPTED";
112
- /** 资源不存在 */
113
- ResourceErrorCode[ResourceErrorCode["NOT_FOUND"] = 3003] = "NOT_FOUND";
114
- /** 资源格式不支持 */
115
- ResourceErrorCode[ResourceErrorCode["UNSUPPORTED_FORMAT"] = 3004] = "UNSUPPORTED_FORMAT";
116
- /** 资源版本不兼容 */
117
- ResourceErrorCode[ResourceErrorCode["VERSION_INCOMPATIBLE"] = 3005] = "VERSION_INCOMPATIBLE";
118
- })(exports.ResourceErrorCode || (exports.ResourceErrorCode = {}));
119
- /**
120
- * 系统错误码 (4xxx)
121
- * @enum {number}
122
- * @description 系统资源相关的错误码
123
- */
124
- exports.SystemErrorCode = void 0;
125
- (function (SystemErrorCode) {
126
- /** 内存不足 */
127
- SystemErrorCode[SystemErrorCode["OUT_OF_MEMORY"] = 4001] = "OUT_OF_MEMORY";
128
- /** GPU不支持 */
129
- SystemErrorCode[SystemErrorCode["GPU_NOT_SUPPORTED"] = 4002] = "GPU_NOT_SUPPORTED";
130
- /** WebGL不支持 */
131
- SystemErrorCode[SystemErrorCode["WEBGL_NOT_SUPPORTED"] = 4003] = "WEBGL_NOT_SUPPORTED";
132
- /** 浏览器不兼容 */
133
- SystemErrorCode[SystemErrorCode["BROWSER_NOT_COMPATIBLE"] = 4004] = "BROWSER_NOT_COMPATIBLE";
134
- })(exports.SystemErrorCode || (exports.SystemErrorCode = {}));
135
- /**
136
- * 配置错误码 (5xxx)
137
- * @enum {number}
138
- * @description 配置相关的错误码
139
- */
140
- exports.ConfigErrorCode = void 0;
141
- (function (ConfigErrorCode) {
142
- /** 配置参数无效 */
143
- ConfigErrorCode[ConfigErrorCode["INVALID_CONFIG"] = 5001] = "INVALID_CONFIG";
144
- /** 必需参数缺失 */
145
- ConfigErrorCode[ConfigErrorCode["MISSING_REQUIRED_PARAM"] = 5002] = "MISSING_REQUIRED_PARAM";
146
- /** 参数值超出范围 */
147
- ConfigErrorCode[ConfigErrorCode["PARAM_OUT_OF_RANGE"] = 5003] = "PARAM_OUT_OF_RANGE";
148
- /** JSON格式错误 */
149
- ConfigErrorCode[ConfigErrorCode["INVALID_JSON_FORMAT"] = 5004] = "INVALID_JSON_FORMAT";
150
- })(exports.ConfigErrorCode || (exports.ConfigErrorCode = {}));
151
- /**
152
- * 错误码信息映射表
153
- * @const {Record<SDKErrorCode, { category: ErrorCategory; message: string }>}
154
- * @description 错误码到错误信息的映射表
155
- */
156
- const ERROR_CODE_MAP = {
157
- // 网络错误
158
- [exports.NetworkErrorCode.CONNECTION_FAILED]: {
159
- category: exports.ErrorCategory.NETWORK,
160
- message: '网络连接失败'
161
- },
162
- [exports.NetworkErrorCode.REQUEST_TIMEOUT]: {
163
- category: exports.ErrorCategory.NETWORK,
164
- message: '请求超时'
165
- },
166
- [exports.NetworkErrorCode.SERVER_ERROR]: {
167
- category: exports.ErrorCategory.NETWORK,
168
- message: '服务器错误'
169
- },
170
- [exports.NetworkErrorCode.UNAUTHORIZED]: {
171
- category: exports.ErrorCategory.NETWORK,
172
- message: '未授权访问'
173
- },
174
- // 操作错误
175
- [exports.OperationErrorCode.UNITY_NOT_INITIALIZED]: {
176
- category: exports.ErrorCategory.OPERATION,
177
- message: 'Unity实例未初始化'
178
- },
179
- [exports.OperationErrorCode.AVATAR_NOT_LOADED]: {
180
- category: exports.ErrorCategory.OPERATION,
181
- message: '数字人未加载'
182
- },
183
- [exports.OperationErrorCode.OPERATION_FAILED]: {
184
- category: exports.ErrorCategory.OPERATION,
185
- message: '操作执行失败'
186
- },
187
- [exports.OperationErrorCode.OPERATION_TIMEOUT]: {
188
- category: exports.ErrorCategory.OPERATION,
189
- message: '操作超时'
190
- },
191
- [exports.OperationErrorCode.OPERATION_CANCELLED]: {
192
- category: exports.ErrorCategory.OPERATION,
193
- message: '操作被取消'
194
- },
195
- [exports.OperationErrorCode.BROADCAST_EQUITY_NOT_EXIST]: {
196
- category: exports.ErrorCategory.OPERATION,
197
- message: '用户权益额度不存在'
198
- },
199
- [exports.OperationErrorCode.BROADCAST_EQUITY_NOT_ENOUGH]: {
200
- category: exports.ErrorCategory.OPERATION,
201
- message: '用户权益额度不足'
202
- },
203
- [exports.OperationErrorCode.BROADCAST_EQUITY_FREEZE_FAILED]: {
204
- category: exports.ErrorCategory.OPERATION,
205
- message: '用户权益额度冻结失败'
206
- },
207
- // 资源错误
208
- [exports.ResourceErrorCode.LOAD_FAILED]: {
209
- category: exports.ErrorCategory.RESOURCE,
210
- message: '资源加载失败'
211
- },
212
- [exports.ResourceErrorCode.FILE_CORRUPTED]: {
213
- category: exports.ErrorCategory.RESOURCE,
214
- message: '资源文件损坏'
215
- },
216
- [exports.ResourceErrorCode.NOT_FOUND]: {
217
- category: exports.ErrorCategory.RESOURCE,
218
- message: '资源不存在'
219
- },
220
- [exports.ResourceErrorCode.UNSUPPORTED_FORMAT]: {
221
- category: exports.ErrorCategory.RESOURCE,
222
- message: '资源格式不支持'
223
- },
224
- [exports.ResourceErrorCode.VERSION_INCOMPATIBLE]: {
225
- category: exports.ErrorCategory.RESOURCE,
226
- message: '资源版本不兼容'
227
- },
228
- // 系统错误
229
- [exports.SystemErrorCode.OUT_OF_MEMORY]: {
230
- category: exports.ErrorCategory.SYSTEM,
231
- message: '内存不足'
232
- },
233
- [exports.SystemErrorCode.GPU_NOT_SUPPORTED]: {
234
- category: exports.ErrorCategory.SYSTEM,
235
- message: 'GPU不支持'
236
- },
237
- [exports.SystemErrorCode.WEBGL_NOT_SUPPORTED]: {
238
- category: exports.ErrorCategory.SYSTEM,
239
- message: 'WebGL不支持'
240
- },
241
- [exports.SystemErrorCode.BROWSER_NOT_COMPATIBLE]: {
242
- category: exports.ErrorCategory.SYSTEM,
243
- message: '浏览器不兼容'
244
- },
245
- // 配置错误
246
- [exports.ConfigErrorCode.INVALID_CONFIG]: {
247
- category: exports.ErrorCategory.CONFIG,
248
- message: '配置参数无效'
249
- },
250
- [exports.ConfigErrorCode.MISSING_REQUIRED_PARAM]: {
251
- category: exports.ErrorCategory.CONFIG,
252
- message: '必需参数缺失'
253
- },
254
- [exports.ConfigErrorCode.PARAM_OUT_OF_RANGE]: {
255
- category: exports.ErrorCategory.CONFIG,
256
- message: '参数值超出范围'
257
- },
258
- [exports.ConfigErrorCode.INVALID_JSON_FORMAT]: {
259
- category: exports.ErrorCategory.CONFIG,
260
- message: 'JSON格式错误'
261
- }
262
- };
263
- /**
264
- * 根据错误码获取错误信息
265
- * @param code - 错误码
266
- * @returns 错误信息对象,包含分类和消息
267
- */
268
- function getErrorInfo(code) {
269
- return ERROR_CODE_MAP[code] || {
270
- category: exports.ErrorCategory.SYSTEM,
271
- message: '未知错误'
272
- };
273
- }
274
-
275
- /**
276
- * @fileoverview SDK错误类
277
- * @description 简单的SDK错误类,用户可以通过try-catch捕获错误码
278
- */
279
- /**
280
- * SDK错误类
281
- * @class SDKError
282
- * @extends {Error}
283
- * @description SDK的统一错误类,包含错误码和错误类别
284
- */
285
- class SDKError extends Error {
286
- /**
287
- * 构造函数
288
- * @param code - 错误码
289
- * @param message - 自定义错误消息(可选,默认使用错误码对应的消息)
290
- * @param originalError - 原始错误对象(可选)
291
- */
292
- constructor(code, message, originalError) {
293
- const errorInfo = getErrorInfo(code);
294
- const finalMessage = message || errorInfo.message;
295
- super(finalMessage);
296
- this.name = 'SDKError';
297
- this.code = code;
298
- this.category = errorInfo.category;
299
- this.message = finalMessage;
300
- this.timestamp = Date.now();
301
- // 保留原始错误的堆栈信息
302
- if (originalError && originalError.stack) {
303
- this.stack = originalError.stack;
304
- }
305
- else if (Error.captureStackTrace) {
306
- Error.captureStackTrace(this, SDKError);
307
- }
308
- }
309
- /**
310
- * 获取错误的JSON表示
311
- * @returns 错误信息对象
312
- */
313
- toJSON() {
314
- return {
315
- name: this.name,
316
- code: this.code,
317
- category: this.category,
318
- message: this.message,
319
- timestamp: this.timestamp
320
- };
321
- }
322
- /**
323
- * 创建网络错误
324
- * @param code - 网络错误码
325
- * @param message - 自定义错误消息
326
- * @param originalError - 原始错误
327
- * @returns SDKError实例
328
- * @static
329
- */
330
- static createNetworkError(code, message, originalError) {
331
- return new SDKError(code, message, originalError);
332
- }
333
- /**
334
- * 创建操作错误
335
- * @param code - 操作错误码
336
- * @param message - 自定义错误消息
337
- * @param originalError - 原始错误
338
- * @returns SDKError实例
339
- * @static
340
- */
341
- static createOperationError(code, message, originalError) {
342
- return new SDKError(code, message, originalError);
343
- }
344
- /**
345
- * 创建资源错误
346
- * @param code - 资源错误码
347
- * @param message - 自定义错误消息
348
- * @param originalError - 原始错误
349
- * @returns SDKError实例
350
- * @static
351
- */
352
- static createResourceError(code, message, originalError) {
353
- return new SDKError(code, message, originalError);
354
- }
355
- /**
356
- * 创建系统错误
357
- * @param code - 系统错误码
358
- * @param message - 自定义错误消息
359
- * @param originalError - 原始错误
360
- * @returns SDKError实例
361
- * @static
362
- */
363
- static createSystemError(code, message, originalError) {
364
- return new SDKError(code, message, originalError);
365
- }
366
- /**
367
- * 创建配置错误
368
- * @param code - 配置错误码
369
- * @param message - 自定义错误消息
370
- * @param originalError - 原始错误
371
- * @returns SDKError实例
372
- * @static
373
- */
374
- static createConfigError(code, message, originalError) {
375
- return new SDKError(code, message, originalError);
376
- }
377
- /**
378
- * 根据Unity错误码创建错误
379
- * @param unityCode - Unity错误码
380
- * @param message - 错误消息
381
- * @returns SDKError实例
382
- * @static
383
- */
384
- static createFromUnityError(unityCode, message) {
385
- /** 错误类型编码 错误名称 描述说明 常见发生场景
386
- ERR - 100 资源加载失败 资源文件加载失败 AssetBundle加载失败、纹理 / 音频加载失败
387
- ERR - 200 网络通信错误 网络请求相关错误 下载超时、连接中断、服务器错误
388
- ERR - 300 配置参数错误 配置数据错误或缺失 JSON解析失败、参数缺失、路径错误
389
- ERR - 400 操作执行失败 特定操作执行失败 动画播放失败、装扮应用失败、合并失败
390
- ERR - 500 系统资源不足 系统资源限制问题 内存不足、GPU资源不足
391
- ERR - 600 状态冲突错误 当前状态不允许执行此操作 在非准备状态下执行操作
392
- ERR - 700 数据验证失败 数据验证或格式错误 许可证无效、数据校验失败
393
- ERR - 800 第三方依赖错误 外部依赖或服务问题 云服务不可用、SDK错误
394
- */
395
- switch (unityCode) {
396
- case 100:
397
- return new SDKError(exports.ResourceErrorCode.LOAD_FAILED, message);
398
- case 200:
399
- return new SDKError(exports.NetworkErrorCode.CONNECTION_FAILED, message);
400
- case 300:
401
- return new SDKError(exports.ConfigErrorCode.INVALID_CONFIG, message);
402
- case 400:
403
- return new SDKError(exports.OperationErrorCode.OPERATION_FAILED, message);
404
- case 500:
405
- return new SDKError(exports.SystemErrorCode.OUT_OF_MEMORY, message);
406
- case 600:
407
- return new SDKError(exports.OperationErrorCode.OPERATION_CANCELLED, message);
408
- case 700:
409
- return new SDKError(exports.ConfigErrorCode.INVALID_CONFIG, message);
410
- default:
411
- return new SDKError(3001, message || `Unity错误 (错误码: ${unityCode})`);
412
- }
413
- }
414
- }
415
-
416
- /**
417
- * Unity服务日志级别枚举
418
- * @enum {string}
419
- * @description 定义日志记录的级别
420
- */
421
- var LogLevel;
422
- (function (LogLevel) {
423
- LogLevel["DEBUG"] = "debug";
424
- LogLevel["INFO"] = "info";
425
- LogLevel["WARN"] = "warn";
426
- LogLevel["ERROR"] = "error";
427
- })(LogLevel || (LogLevel = {}));
428
- /**
429
- * 简单日志记录器实现
430
- * @class SimpleLogger
431
- * @implements {ISimpleLogger}
432
- * @description 提供基础的日志记录功能
433
- */
434
- class SimpleLogger {
435
- constructor(enableDebug = false) {
436
- this.enableDebug = enableDebug;
437
- }
438
- pad(num, len) {
439
- let s = String(num);
440
- while (s.length < len) {
441
- s = `0${s}`;
442
- }
443
- return s;
444
- }
445
- getTimestamp() {
446
- const now = new Date();
447
- const hours = this.pad(now.getHours(), 2);
448
- const minutes = this.pad(now.getMinutes(), 2);
449
- const seconds = this.pad(now.getSeconds(), 2);
450
- const milliseconds = this.pad(now.getMilliseconds(), 3).slice(0, 2);
451
- return `[${hours}:${minutes}:${seconds}.${milliseconds}]`;
452
- }
453
- debug(message, data) {
454
- if (this.enableDebug) {
455
- console.debug(`[SDK DEBUG]${this.getTimestamp()} ${message}`, data);
456
- }
457
- }
458
- info(message, data) {
459
- console.info(`[SDK INFO]${this.getTimestamp()} ${message}`, data);
460
- }
461
- warn(message, data) {
462
- console.warn(`[SDK WARN]${this.getTimestamp()} ${message}`, data);
463
- }
464
- error(message, error, data) {
465
- console.error(`[SDK ERROR]${this.getTimestamp()} ${message}`, error, error instanceof SDKError ? error.code : null, data);
466
- }
467
- }
468
-
469
- /**
470
- * @fileoverview Unity服务基础类型定义
471
- * @description 定义Unity服务的通用接口和类型,为所有Unity服务提供统一的基础类型
472
- */
473
- /**
474
- * Unity操作结果状态枚举
475
- * @enum {number}
476
- * @description 定义Unity操作的标准状态码
477
- */
478
- exports.UnityOperationStatus = void 0;
479
- (function (UnityOperationStatus) {
480
- /** 操作成功 */
481
- UnityOperationStatus[UnityOperationStatus["SUCCESS"] = 0] = "SUCCESS";
482
- /** 操作失败 */
483
- UnityOperationStatus[UnityOperationStatus["FAILURE"] = 1] = "FAILURE";
484
- /** 操作超时 */
485
- UnityOperationStatus[UnityOperationStatus["TIMEOUT"] = 2] = "TIMEOUT";
486
- /** 操作取消 */
487
- UnityOperationStatus[UnityOperationStatus["CANCELLED"] = 3] = "CANCELLED";
488
- })(exports.UnityOperationStatus || (exports.UnityOperationStatus = {}));
489
-
490
- /**
491
- * @fileoverview Unity服务抽象基类
492
- * @description 提供Unity服务的通用基础实现,包括回调管理、消息发送、错误处理等功能
493
- */
494
- /**
495
- * 默认Unity服务配置
496
- * @const {Partial<IUnityServiceConfig>}
497
- */
498
- const DEFAULT_CONFIG = {
499
- targetObjectName: 'AvatarSDK',
500
- timeout: 30000,
501
- enableDebugLog: false,
502
- maxRetries: 0
503
- };
504
- /**
505
- * Unity服务抽象基类
506
- * @abstract
507
- * @class UnityBaseService
508
- * @implements {IUnityCallbackManager<T>, IUnityMessageSender}
509
- * @description 为所有Unity服务提供通用的基础功能
510
- */
511
- class UnityBaseService {
512
- get uniqueCallbackName() {
513
- return `${this.callbackFunctionName}_${this.instanceId}`;
514
- }
515
- /**
516
- * 构造函数
517
- * @param config - Unity服务配置
518
- * @description 初始化基础服务,设置配置和注册全局回调
519
- */
520
- constructor(config) {
521
- /** 存储待处理的Promise解析函数 */
522
- this.pendingCallbacks = new Map();
523
- const finalConfig = Object.assign(Object.assign({}, DEFAULT_CONFIG), config);
524
- this.unityInstance = finalConfig.unityInstance;
525
- this.targetObjectName = finalConfig.targetObjectName;
526
- this.timeout = finalConfig.timeout || DEFAULT_CONFIG.timeout;
527
- this.maxRetries = finalConfig.maxRetries;
528
- this.instanceId = finalConfig.instanceId || 'default';
529
- this.logger = new SimpleLogger(finalConfig.enableDebugLog);
530
- this.initializeGlobalCallback();
531
- this.logger.debug('Unity service initialized', { config: finalConfig });
532
- }
533
- /**
534
- * 处理Unity回调
535
- * @param operation - 操作类型
536
- * @param code - 响应代码
537
- * @param message - 响应消息
538
- * @param data - 额外数据,支持可变数量的参数
539
- * @description 统一处理Unity的回调,管理Promise的解析和拒绝
540
- * @example
541
- * // Unity可能传递的不同参数结构:
542
- * // handleCallback('INIT', 0, 'Success', true, 'extra_data')
543
- * // handleCallback('BROADCAST', 0, 'Success', { isBroadcastCompleted: true })
544
- * // handleCallback('CAMERA', 0, 'Success', cameraData, screenCapture)
545
- */
546
- handleCallback(operation, code, message, data) {
547
- const dataObj = data ? JSON.parse(data) : undefined;
548
- this.logger.warn('[ Received Unity callback ]', { operation, code, message, data: dataObj, originalData: data });
549
- const callback = this.pendingCallbacks.get(operation);
550
- if (!callback) {
551
- this.logger.warn(`No pending callback for operation: ${operation}`);
552
- return;
553
- }
554
- // 清理超时定时器
555
- if (callback.timer) {
556
- clearTimeout(callback.timer);
557
- }
558
- // 构建响应对象,将data参数安全地合并到响应中
559
- const response = {
560
- success: code === exports.UnityOperationStatus.SUCCESS,
561
- message,
562
- errorCode: code,
563
- data: dataObj
564
- };
565
- try {
566
- if (code === exports.UnityOperationStatus.SUCCESS) {
567
- callback.resolve(response);
568
- this.logger.debug(`Operation '${operation}' completed successfully`);
569
- }
570
- else {
571
- const error = SDKError.createFromUnityError(code, `Unity operation '${operation}' failed: ${message}`);
572
- callback.reject(error);
573
- this.logger.error(`Operation '${operation}' failed`, error);
574
- }
575
- }
576
- catch (error) {
577
- this.logger.error(`Error handling callback for operation '${operation}'`, error);
578
- }
579
- finally {
580
- this.pendingCallbacks.delete(operation);
581
- }
582
- }
583
- /**
584
- * 设置回调Promise
585
- * @param operation - 操作类型
586
- * @returns Promise<IUnityCallbackResponse> 返回回调Promise
587
- * @description 创建Promise并设置超时处理
588
- */
589
- setupCallback(operation) {
590
- // 如果已存在相同操作的回调,先清理
591
- this.clearCallback(operation);
592
- return new Promise((resolve, reject) => {
593
- // 设置超时定时器
594
- const timer = setTimeout(() => {
595
- this.pendingCallbacks.delete(operation);
596
- const timeoutError = new SDKError(exports.OperationErrorCode.OPERATION_TIMEOUT, `Unity operation '${operation}' timed out after ${this.timeout}ms`);
597
- this.logger.error(`Operation '${operation}' timed out`, timeoutError);
598
- reject(timeoutError);
599
- }, this.timeout);
600
- this.pendingCallbacks.set(operation, {
601
- resolve,
602
- reject,
603
- timer,
604
- retries: 0
605
- });
606
- this.logger.debug(`Callback setup for operation '${operation}' with timeout ${this.timeout}ms`);
607
- });
608
- }
609
- /**
610
- * 清理指定操作的回调
611
- * @param operation - 操作类型
612
- * @description 清理指定操作的回调和定时器
613
- */
614
- clearCallback(operation) {
615
- const callback = this.pendingCallbacks.get(operation);
616
- if (callback) {
617
- if (callback.timer) {
618
- clearTimeout(callback.timer);
619
- }
620
- this.pendingCallbacks.delete(operation);
621
- this.logger.debug(`Cleared callback for operation '${operation}'`);
622
- }
623
- }
624
- /**
625
- * 清理所有待处理的回调
626
- * @description 清理所有待处理的回调和定时器,通常在服务销毁时调用
627
- */
628
- clearAllCallbacks() {
629
- // 使用 forEach 迭代 Map,避免 TS2549 错误
630
- this.pendingCallbacks.forEach((callback) => {
631
- if (callback.timer) {
632
- clearTimeout(callback.timer);
633
- }
634
- });
635
- this.pendingCallbacks.clear();
636
- this.logger.debug('Cleared all pending callbacks');
637
- }
638
- /**
639
- * 发送消息到Unity(同步)
640
- * @param methodName - Unity方法名
641
- * @param parameter - 参数对象,可选
642
- * @description 向Unity发送消息,自动处理参数序列化和错误处理
643
- * @throws {SDKError} 当Unity实例未初始化或发送失败时抛出错误
644
- */
645
- sendMessage(methodName, parameter) {
646
- if (!this.isUnityAvailable()) {
647
- throw new SDKError(exports.OperationErrorCode.UNITY_NOT_INITIALIZED, 'Unity实例未初始化');
648
- }
649
- try {
650
- this.logger.warn(`[ Sending message ]: ${this.targetObjectName}.${methodName}`, parameter);
651
- const paramString = parameter ? JSON.stringify(parameter) : '';
652
- this.unityInstance.SendMessage(this.targetObjectName, methodName, paramString);
653
- }
654
- catch (error) {
655
- const serviceError = new SDKError(exports.OperationErrorCode.OPERATION_FAILED, `Failed to send Unity message: ${methodName}`, error);
656
- this.logger.error(`Failed to send Unity message: ${methodName}`, serviceError);
657
- throw serviceError;
658
- }
659
- }
660
- /**
661
- * 发送异步消息到Unity并等待回调
662
- * @param methodName - Unity方法名
663
- * @param operation - 操作类型(用于回调标识)
664
- * @param parameter - 参数对象,可选
665
- * @returns Promise<IUnityCallbackResponse> 返回异步操作的Promise
666
- * @description 向Unity发送异步消息并等待回调响应
667
- * @throws {Error} 当Unity实例不可用或操作失败时抛出错误
668
- */
669
- sendAsyncMessage(methodName, operation, parameter) {
670
- return __awaiter(this, void 0, void 0, function* () {
671
- if (!this.isUnityAvailable()) {
672
- throw new SDKError(exports.OperationErrorCode.UNITY_NOT_INITIALIZED, 'Unity实例未初始化');
673
- }
674
- try {
675
- // 注册异步回调
676
- const callbackPromise = this.setupCallback(operation);
677
- // 添加回调相关信息到参数
678
- const fullParameter = Object.assign(Object.assign({}, parameter), { callbackFun: this.uniqueCallbackName, operationType: operation });
679
- // 发送消息到Unity
680
- this.sendMessage(methodName, fullParameter);
681
- // 等待回调或超时
682
- return yield callbackPromise;
683
- }
684
- catch (error) {
685
- // 清理回调
686
- this.clearCallback(operation);
687
- // 如果是需要重试的错误且还有重试次数
688
- if (this.maxRetries > 0 && error instanceof SDKError && error.code === exports.OperationErrorCode.OPERATION_TIMEOUT) {
689
- return yield this.retryOperation(operation, methodName, parameter);
690
- }
691
- throw error;
692
- }
693
- });
694
- }
695
- /**
696
- * 销毁服务
697
- * @description 清理所有资源和回调
698
- */
699
- destroy() {
700
- this.clearAllCallbacks();
701
- // 清理全局回调函数
702
- if (window[this.uniqueCallbackName]) {
703
- delete window[this.uniqueCallbackName];
704
- this.logger.debug(`Global callback unregistered: ${this.uniqueCallbackName}`);
705
- }
706
- this.logger.info('Unity service destroyed');
707
- }
708
- /**
709
- * 检查Unity实例是否可用
710
- * @returns boolean Unity实例是否可用
711
- * @description 检查Unity实例是否已初始化且可用
712
- */
713
- isUnityAvailable() {
714
- return this.unityInstance !== null && typeof this.unityInstance.SendMessage === 'function';
715
- }
716
- /**
717
- * 获取待处理回调数量
718
- * @returns number 待处理回调数量
719
- * @description 获取当前待处理的回调Promise数量
720
- */
721
- getPendingCallbackCount() {
722
- return this.pendingCallbacks.size;
723
- }
724
- /**
725
- * 初始化全局回调函数
726
- * @description 注册全局回调函数到window对象
727
- * @protected
728
- */
729
- initializeGlobalCallback() {
730
- window[this.uniqueCallbackName] = (operation, code, message, data) => {
731
- this.handleCallback(operation, code, message, data);
732
- };
733
- this.logger.warn(`Global callback registered: ${this.uniqueCallbackName}`);
734
- }
735
- /**
736
- * 重试操作
737
- * @param operation - 操作类型
738
- * @param methodName - Unity方法名
739
- * @param parameter - 参数
740
- * @returns Promise<IUnityCallbackResponse> 返回操作结果
741
- * @description 支持重试的异步操作
742
- * @protected
743
- */
744
- retryOperation(operation, methodName, parameter) {
745
- return __awaiter(this, void 0, void 0, function* () {
746
- let lastError = null;
747
- for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
748
- try {
749
- if (attempt > 0) {
750
- this.logger.debug(`Retrying operation '${operation}', attempt ${attempt}/${this.maxRetries}`);
751
- // 简单的延迟重试策略
752
- yield new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
753
- }
754
- return yield this.sendAsyncMessage(methodName, operation, parameter);
755
- }
756
- catch (error) {
757
- lastError = error;
758
- this.logger.warn(`Operation '${operation}' failed, attempt ${attempt + 1}/${this.maxRetries + 1}`, error);
759
- // 如果是超时错误且还有重试次数,继续重试
760
- if (error instanceof SDKError && error.code === exports.OperationErrorCode.OPERATION_TIMEOUT && attempt < this.maxRetries) {
761
- continue;
762
- }
763
- // 其他类型的错误或没有重试次数了,直接抛出
764
- if (!(error instanceof SDKError && error.code === exports.OperationErrorCode.OPERATION_TIMEOUT) || attempt >= this.maxRetries) {
765
- throw error;
766
- }
767
- }
768
- }
769
- throw lastError || new SDKError(exports.OperationErrorCode.OPERATION_TIMEOUT, `All retry attempts failed for operation: ${operation}`);
770
- });
771
- }
772
- }
773
-
774
- /**
775
- * @fileoverview Avatar API接口定义
776
- * @description 定义数字人控制API的核心接口、类型和枚举
777
- */
778
- /**
779
- * Avatar操作类型枚举
780
- * @enum {string}
781
- * @description 定义Avatar服务支持的操作类型
782
- */
783
- exports.AvatarOperationType = void 0;
784
- (function (AvatarOperationType) {
785
- AvatarOperationType["INITIALIZE_AVATAR"] = "initializeAvatar";
786
- AvatarOperationType["PLAY_MOTION"] = "playMotion";
787
- AvatarOperationType["GET_CURRENT_MOTION"] = "getCurrentMotion";
788
- AvatarOperationType["UNLOAD_AVATAR"] = "unloadAvatar";
789
- AvatarOperationType["SET_CAMERA"] = "setCamera";
790
- })(exports.AvatarOperationType || (exports.AvatarOperationType = {}));
791
- /**
792
- * Avatar摄像机类型枚举
793
- * @enum {string}
794
- * @description 定义Avatar支持的摄像机类型
795
- */
796
- exports.AvatarCameraType = void 0;
797
- (function (AvatarCameraType) {
798
- AvatarCameraType["WHOLE"] = "whole";
799
- AvatarCameraType["HALF"] = "half";
800
- AvatarCameraType["FACE"] = "face";
801
- })(exports.AvatarCameraType || (exports.AvatarCameraType = {}));
802
-
803
- /**
804
- * @fileoverview Avatar API重构实现模块
805
- * @description 提供数字人控制API的重构实现,继承Unity基础服务,包括数字人初始化、动作控制、摄像机设置等功能
806
- */
807
- /**
808
- * Avatar API实现类
809
- * @class AvatarService
810
- * @extends {UnityBaseService<AvatarOperationType>}
811
- * @implements {IAvatarAPI}
812
- * @description 数字人控制API的重构实现,继承Unity基础服务,负责与Unity引擎进行通信
813
- */
814
- class AvatarService extends UnityBaseService {
815
- /** 全局回调函数名称 */
816
- get callbackFunctionName() {
817
- return 'uniAvatarCallback';
818
- }
819
- /**
820
- * 构造函数
821
- * @param config - 可选的服务配置,用于覆盖默认配置
822
- * @description 初始化Avatar API,设置Unity实例和配置
823
- * @example
824
- * ```typescript
825
- * const avatarAPI = new AvatarAPIRefactored(unityInstance, {
826
- * timeout: 15000,
827
- * enableDebugLog: true,
828
- * maxRetries: 2
829
- * });
830
- * ```
831
- */
832
- constructor(config) {
833
- super(config);
834
- this.logger.info('Avatar API service initialized');
835
- }
836
- /**
837
- * 初始化数字人
838
- * @param avatarCode - 数字人编码
839
- * @param cameraType - 摄像机类型,默认为'whole'
840
- * @returns Promise<IAvatarCallbackResponse> 初始化操作的Promise
841
- * @description 通过数字人编码加载数字人模型,支持设置摄像机类型
842
- * @example
843
- * ```typescript
844
- * const result = await avatarAPI.initializeAvatar('avatar001', 'whole');
845
- * if (result.success) {
846
- * console.log('Avatar initialized successfully');
847
- * }
848
- * ```
849
- */
850
- initializeAvatar(avatarCode_1) {
851
- return __awaiter(this, arguments, void 0, function* (avatarCode, cameraType = exports.AvatarCameraType.WHOLE) {
852
- this.logger.info(`Initializing avatar: ${avatarCode} with camera type: ${cameraType}`);
853
- try {
854
- const result = yield this.sendAsyncMessage('InitializeAvatar', exports.AvatarOperationType.INITIALIZE_AVATAR, {
855
- avatarCode,
856
- cameraType
857
- });
858
- this.logger.info(`Avatar initialization ${result.success ? 'succeeded' : 'failed'}`);
859
- return result;
860
- }
861
- catch (error) {
862
- this.logger.error('Failed to initialize avatar', error);
863
- throw error;
864
- }
865
- });
866
- }
867
- handleCallback(operation, code, message, data) {
868
- super.handleCallback(operation, code, message, data);
869
- }
870
- /**
871
- * 播放数字人动作
872
- * @param clipCode - 动作编码
873
- * @returns Promise<IAvatarCallbackResponse> 播放操作的Promise
874
- * @description 播放指定的数字人动作
875
- * @example
876
- * ```typescript
877
- * const result = await avatarAPI.playMotion('motion001');
878
- * if (result.success) {
879
- * console.log(`Motion started`);
880
- * }
881
- * ```
882
- */
883
- playMotion(clipCode) {
884
- return __awaiter(this, void 0, void 0, function* () {
885
- this.logger.info(`Playing motion: ${clipCode}`);
886
- try {
887
- const result = yield this.sendAsyncMessage('PlayMotion', exports.AvatarOperationType.PLAY_MOTION, {
888
- clipCode
889
- });
890
- this.logger.info(`Motion play ${result.success ? 'succeeded' : 'failed'}`);
891
- return result;
892
- }
893
- catch (error) {
894
- this.logger.error('Failed to play motion', error);
895
- throw error;
896
- }
897
- });
898
- }
899
- /**
900
- * 获取当前播放的动作信息
901
- * @param getRemainingTime - 是否获取剩余时间
902
- * @returns Promise<IAvatarCallbackResponse> 获取操作的Promise
903
- * @description 获取当前数字人播放的动作编码和剩余时间
904
- * @example
905
- * ```typescript
906
- * const result = await avatarAPI.getCurrentMotion(true);
907
- * if (result.success) {
908
- * console.log(`Current motion: ${result.motionId}, remaining: ${result.motionRemainingTime}ms`);
909
- * }
910
- * ```
911
- */
912
- getCurrentMotion(getRemainingTime) {
913
- return __awaiter(this, void 0, void 0, function* () {
914
- var _a, _b;
915
- this.logger.info(`Getting current motion info, includeRemainingTime: ${getRemainingTime}`);
916
- try {
917
- const result = yield this.sendAsyncMessage('GetCurrentMotion', exports.AvatarOperationType.GET_CURRENT_MOTION, {
918
- getRemainingTime
919
- });
920
- this.logger.info('Current motion info retrieved', {
921
- motionId: (_a = result.data) === null || _a === void 0 ? void 0 : _a.motionId,
922
- remainingTime: (_b = result.data) === null || _b === void 0 ? void 0 : _b.motionRemainingTime
923
- });
924
- return result;
925
- }
926
- catch (error) {
927
- this.logger.error('Failed to get current motion info', error);
928
- throw error;
929
- }
930
- });
931
- }
932
- /**
933
- * 卸载数字人
934
- * @returns Promise<IAvatarCallbackResponse> 卸载操作的Promise
935
- * @description 卸载当前加载的数字人模型,释放相关资源
936
- * @example
937
- * ```typescript
938
- * const result = await avatarAPI.unloadAvatar();
939
- * if (result.success) {
940
- * console.log('Avatar unloaded successfully');
941
- * }
942
- * ```
943
- */
944
- unloadAvatar() {
945
- return __awaiter(this, void 0, void 0, function* () {
946
- this.logger.info('Unloading avatar');
947
- try {
948
- const result = yield this.sendAsyncMessage('UnloadAvatar', exports.AvatarOperationType.UNLOAD_AVATAR);
949
- this.logger.info(`Avatar unload ${result.success ? 'succeeded' : 'failed'}`);
950
- return result;
951
- }
952
- catch (error) {
953
- this.logger.error('Failed to unload avatar', error);
954
- throw error;
955
- }
956
- });
957
- }
958
- /**
959
- * 设置摄像机类型
960
- * @param cameraType - 摄像机类型
961
- * @returns Promise<IAvatarCallbackResponse> 设置操作的Promise
962
- * @description 设置数字人的摄像机类型和视角
963
- * @example
964
- * ```typescript
965
- * const result = await avatarAPI.setCamera('face');
966
- * if (result.success) {
967
- * console.log('Camera type set successfully');
968
- * }
969
- * ```
970
- */
971
- setCamera(cameraType) {
972
- return __awaiter(this, void 0, void 0, function* () {
973
- this.logger.info(`Setting camera type: ${cameraType}`);
974
- try {
975
- const result = yield this.sendAsyncMessage('SetCamera', exports.AvatarOperationType.SET_CAMERA, {
976
- cameraType
977
- });
978
- this.logger.info(`Camera type setting ${result.success ? 'succeeded' : 'failed'}`);
979
- return result;
980
- }
981
- catch (error) {
982
- this.logger.error('Failed to set camera type', error);
983
- throw error;
984
- }
985
- });
986
- }
987
- /**
988
- * 批量执行Avatar操作
989
- * @param operations - 操作数组
990
- * @returns Promise<IAvatarCallbackResponse[]> 返回所有操作的结果
991
- * @description 批量执行多个Avatar操作,支持串行或并行执行
992
- * @example
993
- * ```typescript
994
- * const results = await avatarAPI.batchExecute([
995
- * { method: 'playMotion', params: ['motion001'] },
996
- * { method: 'setCamera', params: ['bust'] }
997
- * ]);
998
- * ```
999
- */
1000
- batchExecute(operations) {
1001
- return __awaiter(this, void 0, void 0, function* () {
1002
- this.logger.info(`Executing batch operations: ${operations.length} items`);
1003
- const results = [];
1004
- for (const operation of operations) {
1005
- try {
1006
- // 使用类型断言来调用方法
1007
- const method = this[operation.method];
1008
- const result = yield method.apply(this, operation.params);
1009
- results.push(result);
1010
- }
1011
- catch (error) {
1012
- this.logger.error(`Batch operation failed: ${operation.method}`, error);
1013
- // 继续执行其他操作,但记录错误
1014
- results.push({
1015
- success: false,
1016
- message: `Batch operation failed: ${error.message}`,
1017
- errorCode: 1
1018
- });
1019
- }
1020
- }
1021
- this.logger.info(`Batch operations completed: ${results.filter(r => r.success).length}/${results.length} successful`);
1022
- return results;
1023
- });
1024
- }
1025
- }
1026
-
1027
- /**
1028
- * @fileoverview 环境配置管理模块
1029
- * @description 提供多环境配置管理和自动环境检测功能
1030
- */
1031
- /**
1032
- * 环境配置映射表
1033
- * @constant {Record<Environment, IEnvConfig>}
1034
- * @description 各环境的配置映射,包含不同环境的API地址
1035
- */
1036
- const ENV_MAP = {
1037
- /** 开发环境配置 */
1038
- dev: {
1039
- apiBaseUrl: 'https://dev.local.zeewain.com'
1040
- },
1041
- /** 测试环境配置 */
1042
- test: {
1043
- apiBaseUrl: 'https://test.local.zeewain.com'
1044
- },
1045
- /** 生产环境配置 */
1046
- prod: {
1047
- apiBaseUrl: 'https://ai.zeewain3d.com'
1048
- }
1049
- };
1050
- /**
1051
- * 获取指定环境的配置
1052
- * @param env - 环境类型,默认为'dev'
1053
- * @param withApiModule - 是否包含API模块路径
1054
- * @returns 返回对应环境的配置对象
1055
- * @example
1056
- * ```typescript
1057
- * const config = getEnvConfig('prod');
1058
- * console.log(config.apiBaseUrl); // https://ai.zeewain3d.com/api/dh-talker
1059
- * ```
1060
- */
1061
- function getEnvConfig(env = 'dev', withApiModule = true) {
1062
- const baseUrl = ENV_MAP[env];
1063
- if (baseUrl) {
1064
- return {
1065
- apiBaseUrl: `${baseUrl.apiBaseUrl}${withApiModule ? '/api' : ''}`
1066
- };
1067
- }
1068
- return null;
1069
- }
1070
-
1071
- /**
1072
- * @fileoverview SDK配置管理器
1073
- * @description 提供全局SDK配置管理,避免循环依赖问题
1074
- */
1075
- /**
1076
- * SDK配置管理器
1077
- * @class ConfigManager
1078
- * @description 管理SDK全局配置,提供配置访问接口
1079
- */
1080
- class ConfigManager {
1081
- /**
1082
- * 私有构造函数(单例模式)
1083
- */
1084
- constructor() {
1085
- /** SDK配置对象 */
1086
- this.config = null;
1087
- }
1088
- /**
1089
- * 获取配置管理器实例
1090
- * @returns ConfigManager 配置管理器实例
1091
- * @description 单例模式获取配置管理器
1092
- */
1093
- static getInstance() {
1094
- if (!ConfigManager.instance) {
1095
- ConfigManager.instance = new ConfigManager();
1096
- }
1097
- return ConfigManager.instance;
1098
- }
1099
- /**
1100
- * 设置SDK配置
1101
- * @param config - SDK配置对象
1102
- * @description 设置全局SDK配置
1103
- */
1104
- setConfig(config) {
1105
- this.config = Object.assign(Object.assign({}, config), { env: config.env || 'prod', containerId: config.containerId || 'unity-container' });
1106
- }
1107
- /**
1108
- * 更新SDK配置
1109
- * @param config - SDK配置对象
1110
- * @description 更新全局SDK配置
1111
- */
1112
- updateConfig(config) {
1113
- if (this.config) {
1114
- this.config = Object.assign(Object.assign({}, this.config), config);
1115
- }
1116
- }
1117
- /**
1118
- * 获取SDK配置
1119
- * @returns IAvatarSDKConfig | null SDK配置对象或null
1120
- * @description 获取当前SDK配置
1121
- */
1122
- getConfig() {
1123
- return this.config;
1124
- }
1125
- /**
1126
- * 获取API基础URL
1127
- * @param withApiModule 是否包含模块路径
1128
- * @returns string API基础URL
1129
- * @description 根据当前环境配置获取API基础URL
1130
- */
1131
- getApiBaseUrl(withApiModule = true) {
1132
- var _a, _b, _c, _d;
1133
- if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.env) === 'custom' && ((_b = this.config) === null || _b === void 0 ? void 0 : _b.apiUrl)) {
1134
- // 如果环境为自定义,则直接返回配置的API,无需添加模块路径
1135
- return `${this.config.apiUrl}${withApiModule ? '/api' : ''}`;
1136
- }
1137
- return ((_d = getEnvConfig(((_c = this.config) === null || _c === void 0 ? void 0 : _c.env) || 'prod', withApiModule)) === null || _d === void 0 ? void 0 : _d.apiBaseUrl) || '';
1138
- }
1139
- /**
1140
- * 重置配置
1141
- * @description 清空当前配置
1142
- */
1143
- reset() {
1144
- this.config = null;
1145
- }
1146
- }
1147
- /** 全局配置实例 */
1148
- ConfigManager.instance = null;
1149
-
1150
- /**
1151
- * @fileoverview Unity WebGL加载器模块
1152
- * @description 提供Unity WebGL应用的加载和初始化功能
1153
- */
1154
- /**
1155
- * Unity WebGL加载器类
1156
- * @class UnityLoader
1157
- * @description 负责Unity WebGL应用的加载、初始化和容器管理
1158
- */
1159
- class UnityLoader {
1160
- /**
1161
- * 构造函数
1162
- * @param config - Unity配置对象
1163
- * @description 初始化Unity加载器,设置默认容器ID
1164
- */
1165
- constructor() {
1166
- this.config = ConfigManager.getInstance().getConfig();
1167
- }
1168
- /**
1169
- * 初始化Unity实例
1170
- * @returns Promise<IUnityInstance> 返回Unity实例的Promise
1171
- * @description 完整的Unity初始化流程,包括容器创建、脚本加载和实例创建
1172
- * @throws {Error} 当Unity加载失败时抛出错误
1173
- */
1174
- init() {
1175
- return __awaiter(this, void 0, void 0, function* () {
1176
- // 创建容器
1177
- const container = this.createContainer();
1178
- // 加载UnityLoader脚本
1179
- yield this.loadUnityLoader();
1180
- // 创建并返回Unity实例
1181
- return yield this.createUnityInstance(container);
1182
- });
1183
- }
1184
- /**
1185
- * 创建Unity容器元素
1186
- * @returns HTMLElement 返回Unity容器元素
1187
- * @description 创建或获取Unity容器,设置基本样式,清理提示元素
1188
- * @private
1189
- */
1190
- createContainer() {
1191
- const container = document.getElementById(this.config.containerId);
1192
- if (!container) {
1193
- throw new TypeError(`Avatar container element with ID "${this.config.containerId}" not found`);
1194
- }
1195
- else if (!(container instanceof HTMLDivElement)) {
1196
- throw new TypeError('Avatar container element must be a div element');
1197
- }
1198
- container.style.position = 'relative';
1199
- return container;
1200
- }
1201
- /**
1202
- * 加载Unity WebGL加载器脚本
1203
- * @returns Promise<void> 加载操作的Promise
1204
- * @description 动态加载Unity WebGL加载器脚本,如果已存在则跳过
1205
- * @throws {Error} 当脚本加载失败或函数不存在时抛出错误
1206
- * @private
1207
- */
1208
- loadUnityLoader() {
1209
- return new Promise((resolve, reject) => {
1210
- // 检查是否已经加载了createUnityInstance函数
1211
- if (window.createUnityInstance) {
1212
- return resolve();
1213
- }
1214
- // 创建脚本元素
1215
- const script = document.createElement('script');
1216
- script.src = this.config.loaderUrl;
1217
- script.async = true;
1218
- script.crossOrigin = 'anonymous';
1219
- // 脚本加载成功回调
1220
- script.onload = () => {
1221
- if (typeof window.createUnityInstance === 'function') {
1222
- resolve();
1223
- }
1224
- else {
1225
- reject(new Error('createUnityInstance function not found'));
1226
- }
1227
- };
1228
- // 脚本加载失败回调
1229
- script.onerror = (error) => {
1230
- reject(new Error(`Failed to load UnityLoader: ${error}`));
1231
- };
1232
- // 将脚本添加到页面头部
1233
- document.head.appendChild(script);
1234
- });
1235
- }
1236
- /**
1237
- * 创建Unity实例
1238
- * @param container - Unity容器元素
1239
- * @param resolve - 成功回调函数
1240
- * @param reject - 失败回调函数
1241
- * @description 创建Canvas元素,配置移动设备适配,并初始化Unity实例
1242
- * @throws {Error} 当Unity实例创建失败时抛出错误
1243
- * @private
1244
- */
1245
- createUnityInstance(container) {
1246
- return __awaiter(this, void 0, void 0, function* () {
1247
- let canvas = container.querySelector('#unity-canvas');
1248
- // 避免重复创建
1249
- if (!canvas) {
1250
- canvas = document.createElement('canvas');
1251
- canvas.id = 'unity-canvas';
1252
- canvas.style.width = '100%';
1253
- canvas.style.height = '100%';
1254
- container.appendChild(canvas);
1255
- }
1256
- // 移动设备适配
1257
- if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
1258
- // 添加移动设备viewport元标签
1259
- const meta = document.createElement('meta');
1260
- meta.name = 'viewport';
1261
- meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';
1262
- document.head.appendChild(meta);
1263
- // 设置移动设备Canvas样式
1264
- canvas.style.width = '100%';
1265
- canvas.style.height = '100%';
1266
- canvas.style.position = 'fixed';
1267
- }
1268
- // 创建Unity实例
1269
- if (typeof window.createUnityInstance === 'function') {
1270
- const instance = yield window.createUnityInstance(canvas, {
1271
- dataUrl: this.config.dataUrl,
1272
- frameworkUrl: this.config.frameworkUrl,
1273
- codeUrl: this.config.codeUrl,
1274
- companyName: '广州紫为云科技有限公司',
1275
- productName: '数字人SDK',
1276
- productVersion: '1.0'
1277
- }, (progress) => {
1278
- // 调用进度回调
1279
- if (this.config.onProgress) {
1280
- this.config.onProgress(progress);
1281
- }
1282
- });
1283
- return instance;
1284
- }
1285
- else {
1286
- throw new TypeError('createUnityInstance is not defined on window.');
1287
- }
1288
- });
1289
- }
1290
- }
1291
-
1292
- async function getBytes(stream, onChunk) {
1293
- const reader = stream.getReader();
1294
- let result;
1295
- while (!(result = await reader.read()).done) {
1296
- onChunk(result.value);
1297
- }
1298
- }
1299
- function getLines(onLine) {
1300
- let buffer;
1301
- let position;
1302
- let fieldLength;
1303
- let discardTrailingNewline = false;
1304
- return function onChunk(arr) {
1305
- if (buffer === undefined) {
1306
- buffer = arr;
1307
- position = 0;
1308
- fieldLength = -1;
1309
- }
1310
- else {
1311
- buffer = concat(buffer, arr);
1312
- }
1313
- const bufLength = buffer.length;
1314
- let lineStart = 0;
1315
- while (position < bufLength) {
1316
- if (discardTrailingNewline) {
1317
- if (buffer[position] === 10) {
1318
- lineStart = ++position;
1319
- }
1320
- discardTrailingNewline = false;
1321
- }
1322
- let lineEnd = -1;
1323
- for (; position < bufLength && lineEnd === -1; ++position) {
1324
- switch (buffer[position]) {
1325
- case 58:
1326
- if (fieldLength === -1) {
1327
- fieldLength = position - lineStart;
1328
- }
1329
- break;
1330
- case 13:
1331
- discardTrailingNewline = true;
1332
- case 10:
1333
- lineEnd = position;
1334
- break;
1335
- }
1336
- }
1337
- if (lineEnd === -1) {
1338
- break;
1339
- }
1340
- onLine(buffer.subarray(lineStart, lineEnd), fieldLength);
1341
- lineStart = position;
1342
- fieldLength = -1;
1343
- }
1344
- if (lineStart === bufLength) {
1345
- buffer = undefined;
1346
- }
1347
- else if (lineStart !== 0) {
1348
- buffer = buffer.subarray(lineStart);
1349
- position -= lineStart;
1350
- }
1351
- };
1352
- }
1353
- function getMessages(onId, onRetry, onMessage) {
1354
- let message = newMessage();
1355
- const decoder = new TextDecoder();
1356
- return function onLine(line, fieldLength) {
1357
- if (line.length === 0) {
1358
- onMessage === null || onMessage === void 0 ? void 0 : onMessage(message);
1359
- message = newMessage();
1360
- }
1361
- else if (fieldLength > 0) {
1362
- const field = decoder.decode(line.subarray(0, fieldLength));
1363
- const valueOffset = fieldLength + (line[fieldLength + 1] === 32 ? 2 : 1);
1364
- const value = decoder.decode(line.subarray(valueOffset));
1365
- switch (field) {
1366
- case 'data':
1367
- message.data = message.data
1368
- ? message.data + '\n' + value
1369
- : value;
1370
- break;
1371
- case 'event':
1372
- message.event = value;
1373
- break;
1374
- case 'id':
1375
- onId(message.id = value);
1376
- break;
1377
- case 'retry':
1378
- const retry = parseInt(value, 10);
1379
- if (!isNaN(retry)) {
1380
- onRetry(message.retry = retry);
1381
- }
1382
- break;
1383
- }
1384
- }
1385
- };
1386
- }
1387
- function concat(a, b) {
1388
- const res = new Uint8Array(a.length + b.length);
1389
- res.set(a);
1390
- res.set(b, a.length);
1391
- return res;
1392
- }
1393
- function newMessage() {
1394
- return {
1395
- data: '',
1396
- event: '',
1397
- id: '',
1398
- retry: undefined,
1399
- };
1400
- }
1401
-
1402
- var __rest = (undefined && undefined.__rest) || function (s, e) {
1403
- var t = {};
1404
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
1405
- t[p] = s[p];
1406
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
1407
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
1408
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
1409
- t[p[i]] = s[p[i]];
1410
- }
1411
- return t;
1412
- };
1413
- const EventStreamContentType = 'text/event-stream';
1414
- const DefaultRetryInterval = 1000;
1415
- const LastEventId = 'last-event-id';
1416
- function fetchEventSource(input, _a) {
1417
- var { signal: inputSignal, headers: inputHeaders, onopen: inputOnOpen, onmessage, onclose, onerror, openWhenHidden, fetch: inputFetch } = _a, rest = __rest(_a, ["signal", "headers", "onopen", "onmessage", "onclose", "onerror", "openWhenHidden", "fetch"]);
1418
- return new Promise((resolve, reject) => {
1419
- const headers = Object.assign({}, inputHeaders);
1420
- if (!headers.accept) {
1421
- headers.accept = EventStreamContentType;
1422
- }
1423
- let curRequestController;
1424
- function onVisibilityChange() {
1425
- curRequestController.abort();
1426
- if (!document.hidden) {
1427
- create();
1428
- }
1429
- }
1430
- if (!openWhenHidden) {
1431
- document.addEventListener('visibilitychange', onVisibilityChange);
1432
- }
1433
- let retryInterval = DefaultRetryInterval;
1434
- let retryTimer = 0;
1435
- function dispose() {
1436
- document.removeEventListener('visibilitychange', onVisibilityChange);
1437
- window.clearTimeout(retryTimer);
1438
- curRequestController.abort();
1439
- }
1440
- inputSignal === null || inputSignal === void 0 ? void 0 : inputSignal.addEventListener('abort', () => {
1441
- dispose();
1442
- resolve();
1443
- });
1444
- const fetch = inputFetch !== null && inputFetch !== void 0 ? inputFetch : window.fetch;
1445
- const onopen = inputOnOpen !== null && inputOnOpen !== void 0 ? inputOnOpen : defaultOnOpen;
1446
- async function create() {
1447
- var _a;
1448
- curRequestController = new AbortController();
1449
- try {
1450
- const response = await fetch(input, Object.assign(Object.assign({}, rest), { headers, signal: curRequestController.signal }));
1451
- await onopen(response);
1452
- await getBytes(response.body, getLines(getMessages(id => {
1453
- if (id) {
1454
- headers[LastEventId] = id;
1455
- }
1456
- else {
1457
- delete headers[LastEventId];
1458
- }
1459
- }, retry => {
1460
- retryInterval = retry;
1461
- }, onmessage)));
1462
- onclose === null || onclose === void 0 ? void 0 : onclose();
1463
- dispose();
1464
- resolve();
1465
- }
1466
- catch (err) {
1467
- if (!curRequestController.signal.aborted) {
1468
- try {
1469
- const interval = (_a = onerror === null || onerror === void 0 ? void 0 : onerror(err)) !== null && _a !== void 0 ? _a : retryInterval;
1470
- window.clearTimeout(retryTimer);
1471
- retryTimer = window.setTimeout(create, interval);
1472
- }
1473
- catch (innerErr) {
1474
- dispose();
1475
- reject(innerErr);
1476
- }
1477
- }
1478
- }
1479
- }
1480
- create();
1481
- });
1482
- }
1483
- function defaultOnOpen(response) {
1484
- const contentType = response.headers.get('content-type');
1485
- if (!(contentType === null || contentType === void 0 ? void 0 : contentType.startsWith(EventStreamContentType))) {
1486
- throw new Error(`Expected content-type to be ${EventStreamContentType}, Actual: ${contentType}`);
1487
- }
1488
- }
1489
-
1490
- /**
1491
- * @fileoverview 流式播报服务接口定义
1492
- * @description 定义流式播报服务相关的类型、接口和枚举
1493
- */
1494
- /**
1495
- * 播报操作类型枚举
1496
- * @enum {string}
1497
- * @description 定义播报服务支持的操作类型
1498
- */
1499
- exports.BroadcastOperationType = void 0;
1500
- (function (BroadcastOperationType) {
1501
- BroadcastOperationType["START_BROADCAST"] = "startBroadcast";
1502
- BroadcastOperationType["PAUSE_BROADCAST"] = "pauseBroadcast";
1503
- BroadcastOperationType["RESUME_BROADCAST"] = "resumeBroadcast";
1504
- BroadcastOperationType["STOP_BROADCAST"] = "stopBroadcast";
1505
- BroadcastOperationType["APPEND_BROADCAST"] = "appendBroadcast";
1506
- })(exports.BroadcastOperationType || (exports.BroadcastOperationType = {}));
1507
- /**
1508
- * 播报类型枚举
1509
- * @enum {string}
1510
- * @description 定义播报的类型,支持文本转语音和自定义音频播报
1511
- */
1512
- exports.BroadcastType = void 0;
1513
- (function (BroadcastType) {
1514
- /** 文本智能体播报 */
1515
- BroadcastType["TEXT"] = "text";
1516
- /** 自定义音频智能体播报 */
1517
- BroadcastType["AUDIO"] = "audio";
1518
- })(exports.BroadcastType || (exports.BroadcastType = {}));
1519
-
1520
- /**
1521
- * @fileoverview 流式播报服务重构实现模块
1522
- * @description 提供流式播报服务的重构实现,继承Unity基础服务,支持文本转语音和自定义音频播报
1523
- */
1524
- /**
1525
- * 播报任务状态枚举
1526
- */
1527
- var BroadcastTaskStatus;
1528
- (function (BroadcastTaskStatus) {
1529
- /** 等待中(尚未开始请求) */
1530
- BroadcastTaskStatus["PENDING"] = "pending";
1531
- /** 请求中 */
1532
- BroadcastTaskStatus["REQUESTING"] = "requesting";
1533
- /** 已完成 */
1534
- BroadcastTaskStatus["COMPLETED"] = "completed";
1535
- /** 失败 */
1536
- BroadcastTaskStatus["FAILED"] = "failed";
1537
- /** 已取消 */
1538
- BroadcastTaskStatus["CANCELLED"] = "cancelled";
1539
- })(BroadcastTaskStatus || (BroadcastTaskStatus = {}));
1540
- /**
1541
- * 流式播报服务重构类
1542
- * @class BroadcastServiceRefactored
1543
- * @extends {UnityBaseService<BroadcastOperationType>}
1544
- * @description 提供流式播报服务的重构实现,继承Unity基础服务,支持文本转语音和自定义音频播报
1545
- */
1546
- class BroadcastService extends UnityBaseService {
1547
- /**
1548
- * 构造函数
1549
- * @param config - 播报服务配置
1550
- * @description 初始化播报服务,设置环境配置和回调函数
1551
- * @example
1552
- * ```typescript
1553
- * const broadcastService = new BroadcastServiceRefactored({
1554
- * unityInstance,
1555
- * callbacks: {
1556
- * onStart: () => console.log('Broadcast started'),
1557
- * onFinish: () => console.log('Broadcast finished'),
1558
- * onError: (error) => console.error('Broadcast error:', error)
1559
- * },
1560
- * timeout: 15000,
1561
- * enableDebugLog: true
1562
- * });
1563
- * ```
1564
- */
1565
- constructor(config) {
1566
- super(config);
1567
- /** 事件回调函数集合 */
1568
- this.callbacks = {};
1569
- /** 播报任务队列 */
1570
- this.taskQueue = [];
1571
- /** 任务序号计数器 */
1572
- this.taskSequence = 0;
1573
- /** 当前发送任务的序号 */
1574
- this.currentSendingSequence = 0;
1575
- /** 是否正在播报音频 */
1576
- this.isBroadcastingAudio = false;
1577
- /** 是否已经收到音频 */
1578
- this.hasReceivedAudio = false;
1579
- /** 队列处理定时器 */
1580
- this.queueProcessTimer = null;
1581
- /** 播报完成次数 */
1582
- this.broadcastCompletedCount = 0;
1583
- this.callbacks = config.callbacks || {};
1584
- this.logger.info('Broadcast service initialized', { config });
1585
- }
1586
- /**
1587
- * 处理Unity回调
1588
- * @param operation - 操作类型
1589
- * @param code - 响应代码
1590
- * @param message - 响应消息
1591
- * @param data - 额外数据,支持可变数量的参数
1592
- * @description 处理Unity的播报回调,并触发相应的事件回调
1593
- * @override
1594
- */
1595
- handleCallback(operation, code, message, data) {
1596
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
1597
- // 提取 isBroadcastCompleted 参数
1598
- const { isBroadcastCompleted } = JSON.parse(data || '{}');
1599
- // 先调用基类处理逻辑
1600
- super.handleCallback(operation, code, message, data);
1601
- // 触发对应的事件回调(仅在成功时)
1602
- if (code === 0) {
1603
- switch (operation) {
1604
- case exports.BroadcastOperationType.START_BROADCAST:
1605
- if (isBroadcastCompleted) {
1606
- this.broadcastCompletedCount++;
1607
- const status = this.getStatus();
1608
- // 判断是否所有任务都已完成:
1609
- // 1. 没有待请求的任务 (PENDING)
1610
- // 2. 没有正在请求的任务 (REQUESTING)
1611
- // 3. Unity播放完成次数等于已完成任务数
1612
- const isAllTasksCompleted = ((_a = status.queueInfo) === null || _a === void 0 ? void 0 : _a.pendingTasks) === 0
1613
- && ((_b = status.queueInfo) === null || _b === void 0 ? void 0 : _b.requestingTasks) === 0
1614
- && ((_c = status.queueInfo) === null || _c === void 0 ? void 0 : _c.completedTasks) === this.broadcastCompletedCount;
1615
- if (isAllTasksCompleted) {
1616
- // 重置状态、计数
1617
- this.isBroadcastingAudio = false;
1618
- this.hasReceivedAudio = false;
1619
- this.currentSendingSequence = 0;
1620
- // 清理已完成的任务
1621
- this.cleanupCompletedTasks();
1622
- this.logger.warn('Broadcast all completed');
1623
- }
1624
- // this.logger.warn('AAAAAA', { status: this.getStatus(), broadcastCompletedCount: this.broadcastCompletedCount });
1625
- (_e = (_d = this.callbacks).onFinish) === null || _e === void 0 ? void 0 : _e.call(_d);
1626
- }
1627
- break;
1628
- case exports.BroadcastOperationType.PAUSE_BROADCAST:
1629
- (_g = (_f = this.callbacks).onPause) === null || _g === void 0 ? void 0 : _g.call(_f);
1630
- this.logger.debug('Broadcast paused callback triggered');
1631
- break;
1632
- case exports.BroadcastOperationType.RESUME_BROADCAST:
1633
- (_j = (_h = this.callbacks).onResume) === null || _j === void 0 ? void 0 : _j.call(_h);
1634
- this.logger.debug('Broadcast resumed callback triggered');
1635
- break;
1636
- case exports.BroadcastOperationType.STOP_BROADCAST:
1637
- (_l = (_k = this.callbacks).onStop) === null || _l === void 0 ? void 0 : _l.call(_k);
1638
- this.logger.debug('Broadcast stopped callback triggered');
1639
- break;
1640
- }
1641
- }
1642
- else {
1643
- const error = SDKError.createFromUnityError(code, `Unity operation '${operation}' failed: ${message}`);
1644
- this.handleError(error);
1645
- }
1646
- }
1647
- /**
1648
- * 开始播报
1649
- * @param params - 播报参数
1650
- * @param isAppend - 是否追加播报
1651
- * @returns Promise<void> 播报操作的Promise
1652
- * @description 开始流式播报,支持文本转语音和自定义音频播报。使用队列机制确保音频按序播报
1653
- * @throws {SDKError} 当参数验证失败或播报失败时抛出错误
1654
- * @example
1655
- * ```typescript
1656
- * // 文本播报
1657
- * await broadcastService.startBroadcast({
1658
- * type: BroadcastType.TEXT,
1659
- * humanCode: 'human001',
1660
- * text: '你好,世界!',
1661
- * voiceCode: 'voice001',
1662
- * volume: 0.8,
1663
- * isSubtitle: true
1664
- * });
1665
- *
1666
- * // 追加播报(会进入队列按序播报)
1667
- * await broadcastService.startBroadcast({
1668
- * type: BroadcastType.TEXT,
1669
- * humanCode: 'human001',
1670
- * text: '这是第二段内容',
1671
- * voiceCode: 'voice001',
1672
- * volume: 0.8,
1673
- * isSubtitle: true
1674
- * }, true);
1675
- * ```
1676
- */
1677
- startBroadcast(params, isAppend) {
1678
- return __awaiter(this, void 0, void 0, function* () {
1679
- var _a, _b;
1680
- this.logger.info(`Starting broadcast: ${params.type}`, {
1681
- humanCode: params.humanCode,
1682
- text: params.text,
1683
- audioUrl: params.audioUrl,
1684
- isAppend,
1685
- queueLength: this.taskQueue.length
1686
- });
1687
- // 验证参数
1688
- this.validateBroadcastParams(params);
1689
- // 非追加模式下需要初始化播报
1690
- if (!isAppend) {
1691
- // 先停止当前播报并清空队列
1692
- yield this.stopBroadcast();
1693
- // 重置序号计数器
1694
- this.taskSequence = 0;
1695
- this.currentSendingSequence = 0;
1696
- // 通知Unity开始新任务(清空队列),这里不使用sendAsyncMessage,因为startBroadcast不需要等待完成,而是在任务播报完成后通过回调通知
1697
- this.sendMessage('StartBroadcast', {
1698
- callbackFun: this.uniqueCallbackName,
1699
- operationType: exports.BroadcastOperationType.START_BROADCAST,
1700
- motionList: params.motionList,
1701
- motionPlayMode: params.motionPlayMode
1702
- });
1703
- // 触发开始回调
1704
- (_b = (_a = this.callbacks).onStart) === null || _b === void 0 ? void 0 : _b.call(_a);
1705
- this.isBroadcastingAudio = true;
1706
- }
1707
- // 创建新的播报任务
1708
- const task = this.createBroadcastTask(params);
1709
- // 添加任务到队列
1710
- this.addTaskToQueue(task);
1711
- this.logger.debug('Broadcast task created and queued', {
1712
- taskId: task.id,
1713
- sequence: task.sequence,
1714
- isAppend
1715
- });
1716
- });
1717
- }
1718
- /**
1719
- * 暂停播报
1720
- * @param resetIdle - 是否重置空闲状态
1721
- * @returns Promise<void> 暂停操作的Promise
1722
- * @description 暂停当前正在播报的内容
1723
- * @example
1724
- * ```typescript
1725
- * await broadcastService.pauseBroadcast();
1726
- * ```
1727
- */
1728
- pauseBroadcast(resetIdle) {
1729
- return __awaiter(this, void 0, void 0, function* () {
1730
- this.logger.info('Pausing broadcast');
1731
- try {
1732
- yield this.sendAsyncMessage('PauseBroadcast', exports.BroadcastOperationType.PAUSE_BROADCAST, {
1733
- resetIdle
1734
- });
1735
- this.logger.info('Broadcast paused successfully');
1736
- }
1737
- catch (error) {
1738
- this.logger.error('Failed to pause broadcast', error);
1739
- throw error;
1740
- }
1741
- });
1742
- }
1743
- /**
1744
- * 继续播报
1745
- * @returns Promise<void> 继续操作的Promise
1746
- * @description 继续播报之前暂停的内容
1747
- * @example
1748
- * ```typescript
1749
- * await broadcastService.resumeBroadcast();
1750
- * ```
1751
- */
1752
- resumeBroadcast() {
1753
- return __awaiter(this, void 0, void 0, function* () {
1754
- this.logger.info('Resuming broadcast');
1755
- try {
1756
- yield this.sendAsyncMessage('ResumeBroadcast', exports.BroadcastOperationType.RESUME_BROADCAST, {});
1757
- this.logger.info('Broadcast resumed successfully');
1758
- }
1759
- catch (error) {
1760
- this.logger.error('Failed to resume broadcast', error);
1761
- throw error;
1762
- }
1763
- });
1764
- }
1765
- /**
1766
- * 停止播报
1767
- * @returns Promise<void> 停止操作的Promise
1768
- * @description 停止当前播报并清空播报队列
1769
- * @example
1770
- * ```typescript
1771
- * await broadcastService.stopBroadcast();
1772
- * ```
1773
- */
1774
- stopBroadcast() {
1775
- return __awaiter(this, void 0, void 0, function* () {
1776
- this.logger.info('Stopping broadcast and clearing queue', { queueLength: this.taskQueue.length });
1777
- // 取消所有队列中的任务
1778
- this.cancelAllTasks();
1779
- // 重置状态
1780
- this.isBroadcastingAudio = false;
1781
- this.hasReceivedAudio = false;
1782
- this.broadcastCompletedCount = 0;
1783
- try {
1784
- yield this.sendAsyncMessage('StopBroadcast', exports.BroadcastOperationType.STOP_BROADCAST, {});
1785
- this.logger.info('Broadcast stopped successfully');
1786
- }
1787
- catch (error) {
1788
- this.logger.error('Failed to stop broadcast', error);
1789
- throw error;
1790
- }
1791
- });
1792
- }
1793
- /**
1794
- * 更新回调函数
1795
- * @param callbacks - 新的回调函数配置
1796
- * @description 更新播报事件的回调函数
1797
- */
1798
- updateCallbacks(callbacks) {
1799
- this.callbacks = Object.assign(Object.assign({}, this.callbacks), callbacks);
1800
- this.logger.debug('Broadcast callbacks updated');
1801
- }
1802
- /**
1803
- * 获取播报状态
1804
- * @returns 播报状态信息
1805
- * @description 获取当前播报服务的状态信息,包括队列状态
1806
- */
1807
- getStatus() {
1808
- const pendingTasks = this.taskQueue.filter((t) => t.status === BroadcastTaskStatus.PENDING).length;
1809
- const completedTasks = this.taskQueue.filter((t) => t.status === BroadcastTaskStatus.COMPLETED).length;
1810
- const requestingTasks = this.taskQueue.filter((t) => t.status === BroadcastTaskStatus.REQUESTING).length;
1811
- const failedTasks = this.taskQueue.filter((t) => t.status === BroadcastTaskStatus.FAILED).length;
1812
- const totalPendingResponses = this.taskQueue.reduce((sum, t) => sum + t.pendingResponses.length, 0);
1813
- const currentSendingSequence = this.currentSendingSequence;
1814
- const isGeneratingAudio = pendingTasks + requestingTasks > 0;
1815
- return {
1816
- isActive: this.isBroadcastingAudio || isGeneratingAudio, // 是否正在播报音频或正在生成音频
1817
- isGeneratingAudio,
1818
- hasReceivedAudio: this.hasReceivedAudio,
1819
- queueInfo: {
1820
- totalTasks: this.taskQueue.length,
1821
- pendingTasks,
1822
- requestingTasks,
1823
- completedTasks,
1824
- failedTasks,
1825
- totalPendingResponses,
1826
- currentSendingSequence
1827
- }
1828
- };
1829
- }
1830
- /**
1831
- * 销毁播报服务
1832
- * @description 清理所有资源和回调
1833
- */
1834
- destroy() {
1835
- // 清理队列处理定时器
1836
- this.clearQueueProcessTimer();
1837
- // 取消所有任务
1838
- this.cancelAllTasks();
1839
- // 调用基类销毁方法
1840
- super.destroy();
1841
- this.logger.info('Broadcast service destroyed');
1842
- }
1843
- /**
1844
- * 创建播报任务
1845
- * @param params - 播报参数
1846
- * @returns IBroadcastTask 播报任务对象
1847
- * @description 创建新的播报任务并分配唯一ID和序号
1848
- * @private
1849
- */
1850
- createBroadcastTask(params) {
1851
- const typeText = params.type === exports.BroadcastType.TEXT ? 'TEXT' : 'AUDIO';
1852
- const typeInfo = params.type === exports.BroadcastType.TEXT ? params.text : params.audioUrl;
1853
- const task = {
1854
- id: `[${typeText}]-(${typeInfo})_${Math.random().toString(36).substring(2, 9)}`,
1855
- sequence: ++this.taskSequence,
1856
- params,
1857
- status: BroadcastTaskStatus.PENDING,
1858
- controller: new AbortController(),
1859
- pendingResponses: [],
1860
- isGenerationComplete: false,
1861
- createdAt: new Date()
1862
- };
1863
- this.logger.debug('Created broadcast task', { taskId: task.id, sequence: task.sequence });
1864
- return task;
1865
- }
1866
- /**
1867
- * 添加任务到队列
1868
- * @param task - 播报任务
1869
- * @description 将任务添加到队列,只有当没有正在请求的任务时才开始请求(串行请求模式)
1870
- * @private
1871
- */
1872
- addTaskToQueue(task) {
1873
- this.taskQueue.push(task);
1874
- this.logger.debug('Task added to queue', { taskId: task.id, params: task.params, queueLength: this.taskQueue.length });
1875
- // 检查是否有正在请求的任务
1876
- const hasRequestingTask = this.taskQueue.some((t) => t.status === BroadcastTaskStatus.REQUESTING);
1877
- // 只有当没有正在请求的任务时,才开始当前任务的请求
1878
- if (!hasRequestingTask) {
1879
- this.startTaskRequest(task);
1880
- }
1881
- else {
1882
- this.logger.debug('Task queued, waiting for previous task to complete', {
1883
- taskId: task.id,
1884
- pendingTasks: this.taskQueue.filter((t) => t.status === BroadcastTaskStatus.PENDING).length
1885
- });
1886
- }
1887
- // 开始处理队列
1888
- this.processTaskQueue();
1889
- }
1890
- /**
1891
- * 处理队列
1892
- * @description 处理队列中的任务响应,按序号发送给unity播放
1893
- * @private
1894
- */
1895
- processTaskQueue() {
1896
- // 启动队列处理定时器(如果尚未启动)
1897
- if (!this.queueProcessTimer) {
1898
- this.queueProcessTimer = setInterval(() => {
1899
- this.processTaskQueueStep();
1900
- }, 100); // 每100ms检查一次队列状态
1901
- }
1902
- // 立即处理一次
1903
- this.processTaskQueueStep();
1904
- }
1905
- /**
1906
- * 队列处理步骤
1907
- * @description 处理队列中的单个步骤,按序号发送给unity播放
1908
- * @private
1909
- */
1910
- processTaskQueueStep() {
1911
- // 按序号找到下一个要处理的任务(只处理已开始请求的任务,排除 PENDING 状态)
1912
- const nextTask = this.taskQueue.find((task) => task.sequence === this.currentSendingSequence + 1
1913
- && task.status !== BroadcastTaskStatus.PENDING
1914
- && task.pendingResponses.length > 0);
1915
- if (nextTask) {
1916
- this.sendNextResponse(nextTask);
1917
- }
1918
- else {
1919
- this.logger.debug('No next task to process', { currentSendingSequence: this.currentSendingSequence, taskQueue: this.taskQueue });
1920
- }
1921
- // 如果队列中没有需要处理的任务(PENDING 或 REQUESTING 状态),则停止定时器
1922
- const activeTasks = this.taskQueue.filter(task => task.status === BroadcastTaskStatus.PENDING
1923
- || task.status === BroadcastTaskStatus.REQUESTING);
1924
- if (activeTasks.length === 0) {
1925
- this.clearQueueProcessTimer();
1926
- }
1927
- }
1928
- /**
1929
- * 开始任务请求
1930
- * @param task - 播报任务
1931
- * @description 为任务发起流式请求生成音频
1932
- * @private
1933
- */
1934
- startTaskRequest(task) {
1935
- return __awaiter(this, void 0, void 0, function* () {
1936
- var _a;
1937
- task.status = BroadcastTaskStatus.REQUESTING;
1938
- this.logger.debug('Starting task request', { taskId: task.id });
1939
- try {
1940
- const apiUrl = `${ConfigManager.getInstance().getApiBaseUrl(true)}${this.getBroadcastApiPath(task.params.type)}`;
1941
- const requestBody = {
1942
- humanCode: task.params.humanCode,
1943
- speed: task.params.speed,
1944
- volume: task.params.volume >= 0 ? task.params.volume * 100 : undefined,
1945
- isSubtitle: task.params.isSubtitle,
1946
- audioDrivenVersion: ConfigManager.getInstance().getConfig().audioDrivenVersion
1947
- };
1948
- // 根据播报类型设置特定参数
1949
- if (task.params.type === exports.BroadcastType.TEXT) {
1950
- requestBody.text = task.params.text;
1951
- requestBody.voiceCode = task.params.voiceCode;
1952
- }
1953
- else if (task.params.type === exports.BroadcastType.AUDIO) {
1954
- requestBody.text = task.params.text;
1955
- requestBody.audioUrl = task.params.audioUrl;
1956
- }
1957
- // 发起流式请求
1958
- fetchEventSource(apiUrl, {
1959
- method: 'POST',
1960
- headers: {
1961
- 'Content-Type': 'application/json',
1962
- 'x_auth_token': ((_a = ConfigManager.getInstance().getConfig()) === null || _a === void 0 ? void 0 : _a.token) || ''
1963
- },
1964
- body: JSON.stringify(requestBody),
1965
- signal: task.controller.signal,
1966
- openWhenHidden: true,
1967
- /**
1968
- * 连接建立时的回调,用于检查 HTTP 状态码
1969
- * @param response - HTTP 响应对象
1970
- * @throws {SDKError} 当 HTTP 状态码异常时抛出对应的 SDKError
1971
- */
1972
- onopen: (response) => __awaiter(this, void 0, void 0, function* () {
1973
- // 检查 HTTP 状态码,处理 401 token 过期等异常
1974
- if (!response.ok) {
1975
- const error = this.createHttpError(response.status, response.statusText, task.id);
1976
- this.handleTaskError(task, error);
1977
- throw error;
1978
- }
1979
- }),
1980
- onmessage: (event) => {
1981
- this.handleTaskResponse(task, event.data);
1982
- },
1983
- onclose: () => {
1984
- this.handleTaskClose(task);
1985
- },
1986
- onerror: (error) => {
1987
- // 如果是 SDKError,说明已经在 onopen 中处理过了(HTTP 状态码错误),直接抛出
1988
- if (error instanceof SDKError) {
1989
- throw error;
1990
- }
1991
- // 其他错误(网络错误等)转换为 SDKError
1992
- this.logger.error('broadcast onerror', error);
1993
- const sdkError = this.convertToSDKError(error, task.id);
1994
- this.handleTaskError(task, sdkError);
1995
- throw sdkError;
1996
- }
1997
- });
1998
- }
1999
- catch (error) {
2000
- // 将所有异常统一转换为 SDKError
2001
- const sdkError = this.convertToSDKError(error, task.id);
2002
- this.handleTaskError(task, sdkError);
2003
- }
2004
- });
2005
- }
2006
- /**
2007
- * 处理任务响应
2008
- * @param task - 播报任务
2009
- * @param data - 响应数据
2010
- * @description 处理任务的流式响应数据
2011
- * @private
2012
- */
2013
- handleTaskResponse(task, data) {
2014
- try {
2015
- const response = JSON.parse(data);
2016
- // 错误处理
2017
- if (response.code !== 0) {
2018
- const error = this.createBroadcastError(response.code, response.message);
2019
- this.handleTaskError(task, error);
2020
- return;
2021
- }
2022
- // 处理音频数据
2023
- if (response.data) {
2024
- this.hasReceivedAudio = true;
2025
- // 自定义音频播报时,如果服务器未返回音频URL,使用传入的audioUrl
2026
- if (task.params.type === exports.BroadcastType.AUDIO && task.params.audioUrl && !response.data.voiceUrl) {
2027
- response.data.voiceUrl = task.params.audioUrl;
2028
- }
2029
- // 如果音频和口播文件是相对路径,则需要拼接API基础URL
2030
- const { voiceUrl, mouthShapeUrl } = response.data;
2031
- if (voiceUrl && !voiceUrl.startsWith('http')) {
2032
- response.data.voiceUrl = `${ConfigManager.getInstance().getApiBaseUrl(false)}${voiceUrl}`;
2033
- }
2034
- if (mouthShapeUrl && !mouthShapeUrl.startsWith('http')) {
2035
- response.data.mouthShapeUrl = `${ConfigManager.getInstance().getApiBaseUrl(false)}${mouthShapeUrl}`;
2036
- }
2037
- // 添加处理后的响应对象到待发送队列
2038
- task.pendingResponses.push(response);
2039
- this.logger.debug('Response added to task', { taskId: task.id, response, pendingCount: task.pendingResponses.length });
2040
- // 检查是否完成
2041
- if (response.data.done) {
2042
- task.isGenerationComplete = true;
2043
- this.logger.debug('Task generation completed', { taskId: task.id, totalResponses: task.pendingResponses.length });
2044
- }
2045
- }
2046
- }
2047
- catch (error) {
2048
- this.handleTaskError(task, new SDKError(exports.OperationErrorCode.OPERATION_FAILED, typeof error === 'string' ? error : (error.message || '播报服务错误')));
2049
- }
2050
- }
2051
- /**
2052
- * 发送下一个响应给unity播放
2053
- * @param task - 播报任务
2054
- * @description 发送任务的响应数组中的第一个待发送响应到Unity(按顺序发送),发送后立即删除
2055
- * @private
2056
- */
2057
- sendNextResponse(task) {
2058
- var _a;
2059
- if (task.pendingResponses.length === 0) {
2060
- return;
2061
- }
2062
- // 取出第一个待发送的响应
2063
- const response = task.pendingResponses.shift();
2064
- this.logger.debug('Sending response to Unity', {
2065
- taskId: task.id,
2066
- remainingResponses: task.pendingResponses.length,
2067
- voiceUrl: (_a = response.data) === null || _a === void 0 ? void 0 : _a.voiceUrl
2068
- });
2069
- // 发送响应到Unity,这里不使用sendAsyncMessage,因为appendBroadcast不需要等待完成,而是在任务播报完成后通过startBroadcast回调通知
2070
- this.sendMessage('AppendBroadcast', {
2071
- response,
2072
- callbackFun: this.uniqueCallbackName,
2073
- operationType: exports.BroadcastOperationType.APPEND_BROADCAST
2074
- });
2075
- // 如果任务已完成且没有更多待发送响应,标记任务完成并推进序号
2076
- if (task.isGenerationComplete && task.pendingResponses.length === 0) {
2077
- task.status = BroadcastTaskStatus.COMPLETED;
2078
- this.currentSendingSequence = task.sequence;
2079
- this.logger.debug('Task completed', { taskId: task.id });
2080
- }
2081
- }
2082
- /**
2083
- * 处理任务关闭
2084
- * @param task - 播报任务
2085
- * @description 处理任务的流式连接关闭,并启动下一个待处理任务的请求
2086
- * @private
2087
- */
2088
- handleTaskClose(task) {
2089
- this.logger.debug('Task stream closed', { taskId: task.id });
2090
- // 如果任务已经失败或取消,不再处理(已经在 handleTaskError 中处理过了)
2091
- if (task.status === BroadcastTaskStatus.FAILED || task.status === BroadcastTaskStatus.CANCELLED) {
2092
- return;
2093
- }
2094
- // 如果还没有标记为完成,则标记为完成
2095
- if (!task.isGenerationComplete && task.status === BroadcastTaskStatus.REQUESTING) {
2096
- task.isGenerationComplete = true;
2097
- }
2098
- // 当前任务请求完成后(流断开后),启动下一个待处理任务的请求
2099
- this.startNextPendingTask();
2100
- }
2101
- /**
2102
- * 处理任务错误
2103
- * @param task - 播报任务
2104
- * @param error - 错误对象
2105
- * @description 处理任务执行过程中的错误,防止重复触发错误回调,并启动下一个待处理任务
2106
- * @private
2107
- */
2108
- handleTaskError(task, error) {
2109
- var _a, _b;
2110
- // 如果任务已经是失败或取消状态,不再重复处理,防止回调被多次触发
2111
- if (task.status === BroadcastTaskStatus.FAILED || task.status === BroadcastTaskStatus.CANCELLED) {
2112
- return;
2113
- }
2114
- task.status = BroadcastTaskStatus.FAILED;
2115
- task.error = error;
2116
- this.logger.error(`Task failed - ${task.id}`, error);
2117
- // 触发错误回调(只触发一次)
2118
- (_b = (_a = this.callbacks).onError) === null || _b === void 0 ? void 0 : _b.call(_a, error);
2119
- // 流式播报场景:一个任务失败,取消并清空所有后续任务
2120
- this.cancelAllTasks();
2121
- // 重置播报状态
2122
- this.isBroadcastingAudio = false;
2123
- this.hasReceivedAudio = false;
2124
- this.currentSendingSequence = 0;
2125
- this.clearQueueProcessTimer();
2126
- this.logger.debug('Task failed, all tasks cancelled and broadcast state reset');
2127
- }
2128
- /**
2129
- * 清理已完成的任务
2130
- * @description 从队列中移除已完成、失败或取消的任务
2131
- * @private
2132
- */
2133
- cleanupCompletedTasks() {
2134
- const beforeLength = this.taskQueue.length;
2135
- this.taskQueue = this.taskQueue.filter(task => task.status !== BroadcastTaskStatus.COMPLETED
2136
- && task.status !== BroadcastTaskStatus.FAILED
2137
- && task.status !== BroadcastTaskStatus.CANCELLED);
2138
- const removedCount = beforeLength - this.taskQueue.length;
2139
- if (removedCount > 0) {
2140
- this.logger.debug('Cleaned up completed tasks', { removedCount, remainingTasks: this.taskQueue.length });
2141
- }
2142
- }
2143
- /**
2144
- * 取消所有任务
2145
- * @description 取消队列中的所有任务
2146
- * @private
2147
- */
2148
- cancelAllTasks() {
2149
- for (const task of this.taskQueue) {
2150
- if (task.status !== BroadcastTaskStatus.COMPLETED && task.status !== BroadcastTaskStatus.FAILED) {
2151
- task.controller.abort();
2152
- task.status = BroadcastTaskStatus.CANCELLED;
2153
- }
2154
- }
2155
- this.taskQueue = [];
2156
- this.taskSequence = 0;
2157
- this.currentSendingSequence = 0;
2158
- this.logger.debug('All tasks cancelled and queue cleared');
2159
- }
2160
- /** 全局回调函数名称 */
2161
- get callbackFunctionName() {
2162
- return 'uniBroadcastCallback';
2163
- }
2164
- /**
2165
- * 获取播报API路径
2166
- * @param type - 播报类型
2167
- * @returns string 返回对应的API路径
2168
- * @description 根据播报类型获取对应的API路径
2169
- * @throws {SDKError} 当播报类型未知时抛出错误
2170
- * @private
2171
- */
2172
- getBroadcastApiPath(type) {
2173
- switch (type) {
2174
- case exports.BroadcastType.TEXT:
2175
- return '/aiep-openapi/avatar-interaction/v1/broadcast/text';
2176
- case exports.BroadcastType.AUDIO:
2177
- return '/aiep-openapi/avatar-interaction/v1/broadcast/audio';
2178
- default:
2179
- throw new SDKError(exports.ConfigErrorCode.INVALID_CONFIG, `未知的播报类型: ${type}`);
2180
- }
2181
- }
2182
- /**
2183
- * 验证播报参数
2184
- * @param params - 播报参数
2185
- * @description 验证播报参数的有效性
2186
- * @throws {SDKError} 当参数验证失败时抛出错误
2187
- * @private
2188
- */
2189
- validateBroadcastParams(params) {
2190
- if (params.type === exports.BroadcastType.TEXT) {
2191
- if (!params.text || !params.voiceCode) {
2192
- throw new SDKError(exports.ConfigErrorCode.MISSING_REQUIRED_PARAM, '文本播报需要提供text和voiceCode参数');
2193
- }
2194
- }
2195
- else if (params.type === exports.BroadcastType.AUDIO) {
2196
- if (!params.audioUrl) {
2197
- throw new SDKError(exports.ConfigErrorCode.MISSING_REQUIRED_PARAM, '自定义音频播报需要提供audioUrl参数');
2198
- }
2199
- }
2200
- }
2201
- /**
2202
- * 处理错误
2203
- * @param error - 错误对象
2204
- * @description 统一处理播报过程中的错误
2205
- * @private
2206
- */
2207
- handleError(error) {
2208
- var _a, _b;
2209
- this.logger.error('Broadcast error occurred', error);
2210
- // 触发错误回调
2211
- (_b = (_a = this.callbacks).onError) === null || _b === void 0 ? void 0 : _b.call(_a, error);
2212
- }
2213
- /**
2214
- * 创建播报请求错误对象
2215
- * @param errorCode - 错误码
2216
- * @param errorMessage - 错误消息
2217
- * @returns SDKError 错误对象
2218
- * @description 根据错误码创建对应的 SDKError 对象
2219
- * @private
2220
- */
2221
- createBroadcastError(errorCode, errorMessage) {
2222
- // 用户权益额度不存在错误码 14001
2223
- // 用户权益额度不足错误码 14002
2224
- // 用户权益额度冻结失败 14003
2225
- switch (errorCode) {
2226
- case 14001:
2227
- return new SDKError(exports.OperationErrorCode.BROADCAST_EQUITY_NOT_EXIST, '用户权益额度不存在');
2228
- case 14002:
2229
- return new SDKError(exports.OperationErrorCode.BROADCAST_EQUITY_NOT_ENOUGH, '用户权益额度不足');
2230
- case 14003:
2231
- return new SDKError(exports.OperationErrorCode.BROADCAST_EQUITY_FREEZE_FAILED, '用户权益额度冻结失败');
2232
- default:
2233
- return new SDKError(exports.OperationErrorCode.OPERATION_FAILED, `${errorMessage}(${errorCode})` || `播报服务错误(${errorCode})`);
2234
- }
2235
- }
2236
- /**
2237
- * 启动下一个待处理任务的请求
2238
- * @description 在当前任务请求完成或失败后,检查并启动下一个待处理任务
2239
- * @private
2240
- */
2241
- startNextPendingTask() {
2242
- // 查找下一个待处理的任务(按序号排序,取第一个 PENDING 状态的任务)
2243
- const nextPendingTask = this.taskQueue
2244
- .filter((t) => t.status === BroadcastTaskStatus.PENDING)
2245
- .sort((a, b) => a.sequence - b.sequence)[0];
2246
- if (nextPendingTask) {
2247
- this.logger.debug('Starting next pending task', {
2248
- taskId: nextPendingTask.id,
2249
- sequence: nextPendingTask.sequence
2250
- });
2251
- this.startTaskRequest(nextPendingTask);
2252
- }
2253
- else {
2254
- this.logger.debug('No pending tasks to start');
2255
- }
2256
- }
2257
- /**
2258
- * 清理队列处理定时器
2259
- * @description 清理队列处理定时器
2260
- * @private
2261
- */
2262
- clearQueueProcessTimer() {
2263
- if (this.queueProcessTimer) {
2264
- clearInterval(this.queueProcessTimer);
2265
- this.queueProcessTimer = null;
2266
- this.logger.debug('Queue process timer cleared');
2267
- }
2268
- }
2269
- /**
2270
- * 根据 HTTP 状态码创建对应的 SDKError
2271
- * @param status - HTTP 状态码
2272
- * @param statusText - HTTP 状态文本
2273
- * @param taskId - 任务 ID(用于日志记录)
2274
- * @returns SDKError 实例
2275
- * @description 将 HTTP 错误状态码映射为对应的 SDKError
2276
- * @private
2277
- */
2278
- createHttpError(status, statusText, taskId) {
2279
- this.logger.warn(`HTTP error occurred - Task: ${taskId}, Status: ${status}`, { status, statusText });
2280
- switch (status) {
2281
- case 401:
2282
- // Token 过期或未授权
2283
- return new SDKError(exports.NetworkErrorCode.UNAUTHORIZED, `Token 已过期或无效,请重新授权 (HTTP ${status})`);
2284
- case 403:
2285
- // 禁止访问
2286
- return new SDKError(exports.NetworkErrorCode.UNAUTHORIZED, `无权限访问该资源 (HTTP ${status})`);
2287
- case 404:
2288
- // 资源不存在
2289
- return new SDKError(exports.NetworkErrorCode.SERVER_ERROR, `请求的资源不存在 (HTTP ${status})`);
2290
- case 500:
2291
- case 502:
2292
- case 503:
2293
- case 504:
2294
- // 服务器错误
2295
- return new SDKError(exports.NetworkErrorCode.SERVER_ERROR, `服务器错误,请稍后重试 (HTTP ${status})`);
2296
- default:
2297
- // 其他 HTTP 错误
2298
- return new SDKError(exports.NetworkErrorCode.CONNECTION_FAILED, `网络请求失败: ${statusText || 'Unknown Error'} (HTTP ${status})`);
2299
- }
2300
- }
2301
- /**
2302
- * 将任意错误转换为 SDKError
2303
- * @param error - 原始错误对象
2304
- * @param taskId - 任务 ID(用于日志记录)
2305
- * @returns SDKError 实例
2306
- * @description 统一将各种类型的错误转换为 SDKError,便于上层统一处理
2307
- * @private
2308
- */
2309
- convertToSDKError(error, taskId) {
2310
- // 如果已经是 SDKError,直接返回
2311
- if (error instanceof SDKError) {
2312
- return error;
2313
- }
2314
- // 如果是普通 Error 对象
2315
- if (error instanceof Error) {
2316
- // 检查是否是网络相关的错误
2317
- const errorMessage = error.message.toLowerCase();
2318
- if (errorMessage.includes('timeout') || errorMessage.includes('timed out')) {
2319
- return new SDKError(exports.NetworkErrorCode.REQUEST_TIMEOUT, `请求超时 - Task: ${taskId}`, error);
2320
- }
2321
- if (errorMessage.includes('network') || errorMessage.includes('fetch') || errorMessage.includes('connection')) {
2322
- // "Failed to fetch" 通常是 CORS 问题或 Token 过期(服务端返回 401 但未设置 CORS 头)
2323
- const hint = errorMessage.includes('failed to fetch')
2324
- ? '(可能是 Token 过期或 CORS 跨域问题,请检查 Token 是否有效)'
2325
- : '';
2326
- return new SDKError(exports.NetworkErrorCode.CONNECTION_FAILED, `网络请求失败 - Task: ${taskId}: ${error.message}${hint}`, error);
2327
- }
2328
- if (errorMessage.includes('abort') || errorMessage.includes('cancel')) {
2329
- return new SDKError(exports.OperationErrorCode.OPERATION_CANCELLED, `操作已取消 - Task: ${taskId}`, error);
2330
- }
2331
- // 默认作为操作失败处理
2332
- return new SDKError(exports.OperationErrorCode.OPERATION_FAILED, `播报任务执行失败 - Task: ${taskId}: ${error.message}`, error);
2333
- }
2334
- // 如果是字符串或其他类型
2335
- const errorMessage = String(error);
2336
- return new SDKError(exports.OperationErrorCode.OPERATION_FAILED, `播报任务执行失败 - Task: ${taskId}: ${errorMessage}`);
2337
- }
2338
- }
2339
-
2340
- /**
2341
- * @fileoverview 3D数字人SDK核心模块
2342
- * @description 提供数字人SDK的核心功能,包括Unity实例管理、Avatar API封装等
2343
- */
2344
- /**
2345
- * 数字人加载器类
2346
- * @class ZEEAvatarLoader
2347
- * @description 数字人SDK的核心加载器,负责Unity实例的初始化和管理
2348
- */
2349
- class ZEEAvatarLoader {
2350
- /**
2351
- * 构造函数
2352
- * @param config - Unity配置对象
2353
- * @description 初始化数字人加载器,创建Unity加载器实例
2354
- */
2355
- constructor() {
2356
- /** Avatar API实例 */
2357
- this.apiService = null;
2358
- /** Unity实例 */
2359
- this.unityInstance = null;
2360
- this.loader = new UnityLoader();
2361
- }
2362
- /**
2363
- * 初始化数字人SDK
2364
- * @returns Promise<IAvatarAPI> 返回Avatar API的Promise
2365
- * @description 完整的SDK初始化流程,包括Unity实例创建和Avatar API初始化
2366
- * @throws {Error} 当Unity初始化失败时抛出错误
2367
- * @example
2368
- * ```typescript
2369
- * const loader = new ZEEAvatarLoader({
2370
- * loaderUrl: 'path/to/webgl.loader.js',
2371
- * dataUrl: 'path/to/webgl.data.unityweb',
2372
- * frameworkUrl: 'path/to/webgl.framework.js.unityweb',
2373
- * codeUrl: 'path/to/webgl.wasm.unityweb',
2374
- * containerId: 'unity-container'
2375
- * });
2376
- *
2377
- * const avatarAPI = await loader.init();
2378
- * ```
2379
- */
2380
- init() {
2381
- return __awaiter(this, void 0, void 0, function* () {
2382
- this.unityInstance = yield this.loader.init();
2383
- this.initGlobalConfig();
2384
- // 向下兼容,后续版本不在使用该实例
2385
- this.apiService = new AvatarService({
2386
- unityInstance: this.unityInstance
2387
- });
2388
- return this.apiService;
2389
- });
2390
- }
2391
- /**
2392
- * 更新token
2393
- * @param token - 新的token
2394
- * @description 更新当前的token
2395
- */
2396
- updateToken(token) {
2397
- const currentConfig = ConfigManager.getInstance().getConfig();
2398
- if (currentConfig) {
2399
- ConfigManager.getInstance().setConfig(Object.assign(Object.assign({}, currentConfig), { token }));
2400
- this.initGlobalConfig();
2401
- }
2402
- }
2403
- /**
2404
- * 获取Avatar API实例
2405
- * @returns IAvatarAPI | null 返回Avatar API实例或null
2406
- * @description 获取当前的Avatar API实例,如果未初始化则返回null
2407
- */
2408
- getAPI() {
2409
- return this.apiService;
2410
- }
2411
- /**
2412
- * 获取Unity实例
2413
- * @returns IUnityInstance | null 返回Unity实例或null
2414
- * @description 获取当前的Unity实例,如果未初始化则返回null
2415
- */
2416
- getInstance() {
2417
- return this.unityInstance;
2418
- }
2419
- /**
2420
- * 获取容器ID
2421
- * @returns string 返回容器ID
2422
- * @description 获取Unity容器的DOM元素ID
2423
- */
2424
- getContainerId() {
2425
- return ConfigManager.getInstance().getConfig().containerId;
2426
- }
2427
- /**
2428
- * 销毁SDK实例
2429
- * @description 清理所有资源,包括Unity实例和DOM元素
2430
- * @example
2431
- * ```typescript
2432
- * loader.destroy();
2433
- * ```
2434
- */
2435
- destroy() {
2436
- if (this.unityInstance) {
2437
- // 移除DOM容器下的canvas元素
2438
- const container = document.getElementById(this.getContainerId());
2439
- if (container) {
2440
- const canvas = container.querySelector('#unity-canvas');
2441
- if (canvas) {
2442
- canvas.remove();
2443
- }
2444
- }
2445
- // 退出Unity实例
2446
- if (typeof this.unityInstance.Quit === 'function') {
2447
- this.unityInstance.Quit();
2448
- }
2449
- // 清理引用
2450
- this.unityInstance = null;
2451
- this.apiService = null;
2452
- }
2453
- // 重置配置管理器
2454
- ConfigManager.getInstance().reset();
2455
- }
2456
- /**
2457
- * 初始化全局配置
2458
- * @description 向Unity发送全局配置参数
2459
- * @protected
2460
- */
2461
- initGlobalConfig() {
2462
- const config = ConfigManager.getInstance().getConfig();
2463
- const { assetsFrom } = config;
2464
- const globalParams = {
2465
- token: config === null || config === void 0 ? void 0 : config.token,
2466
- apiBaseUrl: ConfigManager.getInstance().getApiBaseUrl(false),
2467
- idleMotionList: config === null || config === void 0 ? void 0 : config.idleMotionList
2468
- // 純AB包方案在SDK 2.1.0 中已弃用
2469
- // assetsUrl: config?.assetsUrl
2470
- };
2471
- this.unityInstance.SendMessage('AvatarSDK', 'InitializeConfig', JSON.stringify(globalParams));
2472
- console.warn('[ Send Unity message ]: AvatarSDK.InitializeConfig', globalParams);
2473
- //
2474
- if (assetsFrom !== 'cloud') {
2475
- const assetModuleParams = {
2476
- isZip: true,
2477
- assetBundlePath: config === null || config === void 0 ? void 0 : config.assetsUrl
2478
- };
2479
- this.unityInstance.SendMessage('AvatarSDK', 'InitAssetBundleModule', JSON.stringify(assetModuleParams));
2480
- console.warn('[ Send Unity message ]: AvatarSDK.InitAssetBundleModule', assetModuleParams);
2481
- }
2482
- }
2483
- }
2484
-
2485
- // 深拷贝
2486
- /**
2487
- * 比较两个版本号的前两位(major.minor)是否一致
2488
- * @param version1 版本号1,格式:x.x.x
2489
- * @param version2 版本号2,格式:x.x.x
2490
- * @returns boolean 如果前两位一致返回 true,否则返回 false
2491
- * @description 用于检查 SDK 版本与资源版本是否兼容
2492
- * @example
2493
- * compareVersionCompatibility('2.1.0', '2.1.5') // true
2494
- * compareVersionCompatibility('2.1.0', '2.2.0') // false
2495
- * compareVersionCompatibility('2.1.0', '3.0.0') // false
2496
- */
2497
- function compareVersionCompatibility(version1, version2) {
2498
- // 提取版本号的前两位(major.minor)
2499
- const getMajorMinor = (version) => {
2500
- const parts = version.split('.');
2501
- if (parts.length < 2) {
2502
- return version;
2503
- }
2504
- return `${parts[0]}.${parts[1]}`;
2505
- };
2506
- const v1MajorMinor = getMajorMinor(version1);
2507
- const v2MajorMinor = getMajorMinor(version2);
2508
- return v1MajorMinor === v2MajorMinor;
2509
- }
2510
-
2511
- /**
2512
- * @fileoverview SDK 版本号常量
2513
- * @description 此文件由构建脚本自动生成,请勿手动修改
2514
- */
2515
- /**
2516
- * SDK 版本号
2517
- * @const {string} SDK_VERSION
2518
- */
2519
- const SDK_VERSION = '2.1.5';
2520
-
2521
- /**
2522
- * @fileoverview 统一的3D数字人SDK入口类
2523
- * @description 提供统一的SDK接口,内部通过组合模式调用各个服务模块
2524
- */
2525
- /**
2526
- * 生成唯一标识符
2527
- * @returns string 唯一标识符
2528
- */
2529
- function generateUniqueId() {
2530
- return `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
2531
- }
2532
- /**
2533
- * 统一的3D数字人SDK类
2534
- * @class ZEEAvatarSDK
2535
- * @description 提供统一的SDK接口,简化用户使用体验,支持多实例
2536
- */
2537
- class ZEEAvatarSDK {
2538
- /**
2539
- * 构造函数
2540
- * @param config SDK配置对象
2541
- */
2542
- constructor(config) {
2543
- /** Unity加载器实例 */
2544
- this.loader = null;
2545
- /** Avatar服务实例 */
2546
- this.avatarService = null;
2547
- /** 播报服务实例 */
2548
- this.broadcastService = null;
2549
- /** Unity实例 */
2550
- this.unityInstance = null;
2551
- /** SDK初始化状态 */
2552
- this.isInitialized = false;
2553
- this.instanceId = generateUniqueId();
2554
- // 设置全局配置
2555
- ConfigManager.getInstance().setConfig(config);
2556
- // 设置日志
2557
- this.logger = new SimpleLogger(ConfigManager.getInstance().getConfig().enableDebugLog);
2558
- this.logger.info('SDK版本', SDK_VERSION);
2559
- }
2560
- /**
2561
- * 初始化数字人
2562
- * @param avatarCode 数字人编码
2563
- * @param cameraType 摄像机类型
2564
- * @returns Promise<IAvatarCallbackResponse> 初始化结果
2565
- * @description 统一的初始化方法,包含Unity实例初始化和数字人加载
2566
- */
2567
- initializeAvatar(avatarCode_1) {
2568
- return __awaiter(this, arguments, void 0, function* (avatarCode, cameraType = exports.AvatarCameraType.WHOLE) {
2569
- var _a;
2570
- if (this.isInitialized) {
2571
- throw new SDKError(exports.OperationErrorCode.OPERATION_FAILED, 'SDK已经初始化,请勿重复初始化');
2572
- }
2573
- try {
2574
- const config = ConfigManager.getInstance().getConfig();
2575
- // 1. 创建Unity加载器
2576
- this.loader = new ZEEAvatarLoader();
2577
- // 2. 初始化Unity实例
2578
- yield this.loader.init();
2579
- // 3. 获取Unity实例
2580
- this.unityInstance = this.loader.getInstance();
2581
- // 4. 创建带有唯一标识符的Avatar服务
2582
- this.avatarService = new AvatarService({
2583
- unityInstance: this.unityInstance,
2584
- instanceId: this.instanceId,
2585
- enableDebugLog: config.enableDebugLog,
2586
- timeout: config.operationTimeout
2587
- });
2588
- // 5. 创建带有唯一标识符的播报服务
2589
- this.broadcastService = new BroadcastService({
2590
- unityInstance: this.unityInstance,
2591
- instanceId: this.instanceId,
2592
- callbacks: config.broadcastCallbacks,
2593
- enableDebugLog: config.enableDebugLog,
2594
- timeout: config.operationTimeout
2595
- });
2596
- // 6. 初始化数字人
2597
- const result = yield this.avatarService.initializeAvatar(avatarCode, cameraType);
2598
- if (result.success) {
2599
- const audioDrivenVersion = (_a = result.data) === null || _a === void 0 ? void 0 : _a.audioDrivenVersion;
2600
- config.audioDrivenVersion = audioDrivenVersion;
2601
- this.logger.info('AudioDrivenVersion', audioDrivenVersion);
2602
- // 7. 检查资源版本兼容性
2603
- if (audioDrivenVersion) {
2604
- const isCompatible = compareVersionCompatibility(SDK_VERSION, audioDrivenVersion);
2605
- if (!isCompatible) {
2606
- // 销毁SDK实例
2607
- this.destroy();
2608
- throw new SDKError(exports.ResourceErrorCode.VERSION_INCOMPATIBLE, `资源版本不兼容: SDK版本为 ${SDK_VERSION},WebGL资源版本为 ${audioDrivenVersion},前两位版本号必须一致`);
2609
- }
2610
- this.logger.info('版本兼容性检查通过', `SDK: ${SDK_VERSION}, 资源: ${audioDrivenVersion}`);
2611
- }
2612
- this.isInitialized = true;
2613
- }
2614
- return result;
2615
- }
2616
- catch (error) {
2617
- throw new SDKError(exports.OperationErrorCode.OPERATION_FAILED, `数字人初始化失败: ${error instanceof Error ? error.message : String(error)}`);
2618
- }
2619
- });
2620
- }
2621
- /**
2622
- * 更新Token
2623
- * @param token 新的认证Token
2624
- * @description 更新全局Token配置
2625
- */
2626
- updateToken(token) {
2627
- ConfigManager.getInstance().updateConfig({ token });
2628
- // 如果loader已经初始化,也更新loader的token
2629
- if (this.loader) {
2630
- this.loader.updateToken(token);
2631
- }
2632
- }
2633
- // ===========================================
2634
- // Avatar API 方法
2635
- // ===========================================
2636
- /**
2637
- * 播放数字人动作
2638
- * @param clipCode 动作编码
2639
- * @returns Promise<IAvatarCallbackResponse> 播放结果
2640
- */
2641
- playMotion(clipCode) {
2642
- return __awaiter(this, void 0, void 0, function* () {
2643
- this.ensureInitialized();
2644
- return yield this.avatarService.playMotion(clipCode);
2645
- });
2646
- }
2647
- /**
2648
- * 获取当前播放的动作信息
2649
- * @param getRemainingTime 是否获取剩余时间
2650
- * @returns Promise<IAvatarCallbackResponse> 动作信息
2651
- */
2652
- getCurrentMotion() {
2653
- return __awaiter(this, arguments, void 0, function* (getRemainingTime = false) {
2654
- this.ensureInitialized();
2655
- return yield this.avatarService.getCurrentMotion(getRemainingTime);
2656
- });
2657
- }
2658
- /**
2659
- * 卸载数字人
2660
- * @returns Promise<IAvatarCallbackResponse> 卸载结果
2661
- */
2662
- unloadAvatar() {
2663
- return __awaiter(this, void 0, void 0, function* () {
2664
- this.ensureInitialized();
2665
- try {
2666
- const result = yield this.avatarService.unloadAvatar();
2667
- if (result.success) {
2668
- this.isInitialized = false;
2669
- }
2670
- return result;
2671
- }
2672
- catch (error) {
2673
- throw new SDKError(exports.OperationErrorCode.OPERATION_FAILED, `数字人卸载失败: ${error instanceof Error ? error.message : String(error)}`);
2674
- }
2675
- });
2676
- }
2677
- /**
2678
- * 设置摄像机类型
2679
- * @param cameraType 摄像机类型
2680
- * @returns Promise<IAvatarCallbackResponse> 设置结果
2681
- */
2682
- setCamera(cameraType) {
2683
- return __awaiter(this, void 0, void 0, function* () {
2684
- this.ensureInitialized();
2685
- return yield this.avatarService.setCamera(cameraType);
2686
- });
2687
- }
2688
- // ===========================================
2689
- // Broadcast API 方法
2690
- // ===========================================
2691
- /**
2692
- * 开始播报(适用于普通播报场景)
2693
- * @param params 播报参数
2694
- * @param isAppend 是否追加播报
2695
- * @returns Promise<void> 播报操作的Promise
2696
- */
2697
- startBroadcast(params, isAppend) {
2698
- return __awaiter(this, void 0, void 0, function* () {
2699
- this.ensureInitialized();
2700
- return yield this.broadcastService.startBroadcast(params, isAppend);
2701
- });
2702
- }
2703
- /**
2704
- * 开始流式播报(适用于ChatGPT等对话场景)
2705
- * @param params 播报参数
2706
- * @param forceRestart 是否强制重新开始(停止当前播报并开始新的)
2707
- * @returns Promise<void> 播报操作的Promise
2708
- * @description SDK内部自动维护播报状态,首次调用或空闲时使用 isAppend=false,后续调用自动使用 isAppend=true
2709
- */
2710
- startStreamBroadcast(params, forceRestart) {
2711
- return __awaiter(this, void 0, void 0, function* () {
2712
- this.ensureInitialized();
2713
- // 如果强制重新开始,先停止当前播报
2714
- if (forceRestart) {
2715
- const status = this.broadcastService.getStatus();
2716
- if (status.isActive) {
2717
- yield this.broadcastService.stopBroadcast();
2718
- }
2719
- // 强制重新开始时使用 isAppend=false
2720
- return yield this.broadcastService.startBroadcast(params, false);
2721
- }
2722
- // 检查当前播报状态
2723
- const status = this.broadcastService.getStatus();
2724
- // 如果当前正在播报或生成音频,使用追加模式
2725
- // 如果当前空闲,使用非追加模式开始新的播报
2726
- const isAppend = status.isActive;
2727
- this.logger.debug('startStreamBroadcast', { isActive: status.isActive, isAppend });
2728
- return yield this.broadcastService.startBroadcast(params, isAppend);
2729
- });
2730
- }
2731
- /**
2732
- * 暂停播报
2733
- * @param resetIdle 是否重置空闲状态
2734
- * @returns Promise<void> 暂停操作的Promise
2735
- */
2736
- pauseBroadcast(resetIdle) {
2737
- return __awaiter(this, void 0, void 0, function* () {
2738
- this.ensureInitialized();
2739
- return yield this.broadcastService.pauseBroadcast(resetIdle);
2740
- });
2741
- }
2742
- /**
2743
- * 恢复播报
2744
- * @returns Promise<void> 恢复操作的Promise
2745
- */
2746
- resumeBroadcast() {
2747
- return __awaiter(this, void 0, void 0, function* () {
2748
- this.ensureInitialized();
2749
- return yield this.broadcastService.resumeBroadcast();
2750
- });
2751
- }
2752
- /**
2753
- * 停止播报
2754
- * @returns Promise<void> 停止操作的Promise
2755
- */
2756
- stopBroadcast() {
2757
- return __awaiter(this, void 0, void 0, function* () {
2758
- this.ensureInitialized();
2759
- return yield this.broadcastService.stopBroadcast();
2760
- });
2761
- }
2762
- /**
2763
- * 更新播报回调函数
2764
- * @param callbacks 新的回调函数集合
2765
- */
2766
- updateBroadcastCallbacks(callbacks) {
2767
- this.ensureInitialized();
2768
- this.broadcastService.updateCallbacks(callbacks);
2769
- }
2770
- /**
2771
- * 获取播报状态
2772
- * @returns 播报状态信息
2773
- */
2774
- getBroadcastStatus() {
2775
- this.ensureInitialized();
2776
- return this.broadcastService.getStatus();
2777
- }
2778
- // ===========================================
2779
- // 生命周期管理
2780
- // ===========================================
2781
- /**
2782
- * 销毁SDK实例
2783
- * @description 清理所有资源,包括Unity实例和服务
2784
- */
2785
- destroy() {
2786
- try {
2787
- // 销毁播报服务
2788
- if (this.broadcastService) {
2789
- this.broadcastService.destroy();
2790
- this.broadcastService = null;
2791
- }
2792
- // 销毁Avatar服务
2793
- if (this.avatarService) {
2794
- this.avatarService.destroy();
2795
- this.avatarService = null;
2796
- }
2797
- // 销毁Unity加载器
2798
- if (this.loader) {
2799
- this.loader.destroy();
2800
- this.loader = null;
2801
- }
2802
- // 清理状态
2803
- this.unityInstance = null;
2804
- this.isInitialized = false;
2805
- }
2806
- catch (error) {
2807
- console.error('SDK销毁过程中发生错误:', error);
2808
- }
2809
- }
2810
- // ===========================================
2811
- // 工具方法
2812
- // ===========================================
2813
- /**
2814
- * 获取SDK实例唯一标识符
2815
- * @returns string 实例ID
2816
- */
2817
- getInstanceId() {
2818
- return this.instanceId;
2819
- }
2820
- /**
2821
- * 获取SDK初始化状态
2822
- * @returns boolean 是否已初始化
2823
- */
2824
- isSDKInitialized() {
2825
- return this.isInitialized;
2826
- }
2827
- /**
2828
- * 获取Avatar加载状态
2829
- * @returns boolean 是否已加载Avatar
2830
- */
2831
- isAvatarInitialized() {
2832
- return this.isInitialized;
2833
- }
2834
- /**
2835
- * 获取SDK配置
2836
- * @returns IAvatarSDKConfig 当前配置
2837
- */
2838
- getConfig() {
2839
- const config = ConfigManager.getInstance().getConfig();
2840
- return config ? Object.assign({}, config) : null;
2841
- }
2842
- // ===========================================
2843
- // 私有方法
2844
- // ===========================================
2845
- /**
2846
- * 确保SDK已初始化
2847
- * @private
2848
- */
2849
- ensureInitialized() {
2850
- if (!this.isInitialized) {
2851
- throw new SDKError(exports.OperationErrorCode.UNITY_NOT_INITIALIZED, 'Avatar尚未初始化,请先调用initializeAvatar()方法');
2852
- }
2853
- }
2854
- }
2855
-
2856
- exports.AvatarService = AvatarService;
2857
- exports.BroadcastService = BroadcastService;
2858
- exports.ERROR_CODE_MAP = ERROR_CODE_MAP;
2859
- exports.SDKError = SDKError;
2860
- exports.SDK_VERSION = SDK_VERSION;
2861
- exports.ZEEAvatarLoader = ZEEAvatarLoader;
2862
- exports.ZEEAvatarSDK = ZEEAvatarSDK;
2863
- exports.getErrorInfo = getErrorInfo;
2864
-
2865
- }));
1
+ !function(global,factory){"object"==typeof exports&&"undefined"!=typeof module?factory(exports):"function"==typeof define&&define.amd?define(["exports"],factory):factory((global="undefined"!=typeof globalThis?globalThis:global||self).ZEEAvatarSDKLib={})}(this,function(exports){"use strict";function __awaiter(thisArg,_arguments,P,generator){return new(P||(P=Promise))(function(resolve,reject){function fulfilled(value){try{step(generator.next(value))}catch(e){reject(e)}}function rejected(value){try{step(generator.throw(value))}catch(e){reject(e)}}function step(result){result.done?resolve(result.value):function adopt(value){return value instanceof P?value:new P(function(resolve){resolve(value)})}(result.value).then(fulfilled,rejected)}step((generator=generator.apply(thisArg,_arguments||[])).next())})}var ErrorCategory,NetworkErrorCode,OperationErrorCode,ResourceErrorCode,SystemErrorCode,ConfigErrorCode;"function"==typeof SuppressedError&&SuppressedError,exports.ErrorCategory=void 0,(ErrorCategory=exports.ErrorCategory||(exports.ErrorCategory={})).NETWORK="NETWORK",ErrorCategory.OPERATION="OPERATION",ErrorCategory.RESOURCE="RESOURCE",ErrorCategory.SYSTEM="SYSTEM",ErrorCategory.CONFIG="CONFIG",exports.NetworkErrorCode=void 0,(NetworkErrorCode=exports.NetworkErrorCode||(exports.NetworkErrorCode={}))[NetworkErrorCode.CONNECTION_FAILED=1001]="CONNECTION_FAILED",NetworkErrorCode[NetworkErrorCode.REQUEST_TIMEOUT=1002]="REQUEST_TIMEOUT",NetworkErrorCode[NetworkErrorCode.SERVER_ERROR=1003]="SERVER_ERROR",NetworkErrorCode[NetworkErrorCode.UNAUTHORIZED=1004]="UNAUTHORIZED",exports.OperationErrorCode=void 0,(OperationErrorCode=exports.OperationErrorCode||(exports.OperationErrorCode={}))[OperationErrorCode.UNITY_NOT_INITIALIZED=2001]="UNITY_NOT_INITIALIZED",OperationErrorCode[OperationErrorCode.AVATAR_NOT_LOADED=2002]="AVATAR_NOT_LOADED",OperationErrorCode[OperationErrorCode.OPERATION_FAILED=2003]="OPERATION_FAILED",OperationErrorCode[OperationErrorCode.OPERATION_TIMEOUT=2004]="OPERATION_TIMEOUT",OperationErrorCode[OperationErrorCode.OPERATION_CANCELLED=2005]="OPERATION_CANCELLED",OperationErrorCode[OperationErrorCode.BROADCAST_EQUITY_NOT_EXIST=2006]="BROADCAST_EQUITY_NOT_EXIST",OperationErrorCode[OperationErrorCode.BROADCAST_EQUITY_NOT_ENOUGH=2007]="BROADCAST_EQUITY_NOT_ENOUGH",OperationErrorCode[OperationErrorCode.BROADCAST_EQUITY_FREEZE_FAILED=2008]="BROADCAST_EQUITY_FREEZE_FAILED",exports.ResourceErrorCode=void 0,(ResourceErrorCode=exports.ResourceErrorCode||(exports.ResourceErrorCode={}))[ResourceErrorCode.LOAD_FAILED=3001]="LOAD_FAILED",ResourceErrorCode[ResourceErrorCode.FILE_CORRUPTED=3002]="FILE_CORRUPTED",ResourceErrorCode[ResourceErrorCode.NOT_FOUND=3003]="NOT_FOUND",ResourceErrorCode[ResourceErrorCode.UNSUPPORTED_FORMAT=3004]="UNSUPPORTED_FORMAT",ResourceErrorCode[ResourceErrorCode.VERSION_INCOMPATIBLE=3005]="VERSION_INCOMPATIBLE",exports.SystemErrorCode=void 0,(SystemErrorCode=exports.SystemErrorCode||(exports.SystemErrorCode={}))[SystemErrorCode.OUT_OF_MEMORY=4001]="OUT_OF_MEMORY",SystemErrorCode[SystemErrorCode.GPU_NOT_SUPPORTED=4002]="GPU_NOT_SUPPORTED",SystemErrorCode[SystemErrorCode.WEBGL_NOT_SUPPORTED=4003]="WEBGL_NOT_SUPPORTED",SystemErrorCode[SystemErrorCode.BROWSER_NOT_COMPATIBLE=4004]="BROWSER_NOT_COMPATIBLE",exports.ConfigErrorCode=void 0,(ConfigErrorCode=exports.ConfigErrorCode||(exports.ConfigErrorCode={}))[ConfigErrorCode.INVALID_CONFIG=5001]="INVALID_CONFIG",ConfigErrorCode[ConfigErrorCode.MISSING_REQUIRED_PARAM=5002]="MISSING_REQUIRED_PARAM",ConfigErrorCode[ConfigErrorCode.PARAM_OUT_OF_RANGE=5003]="PARAM_OUT_OF_RANGE",ConfigErrorCode[ConfigErrorCode.INVALID_JSON_FORMAT=5004]="INVALID_JSON_FORMAT";const ERROR_CODE_MAP={[exports.NetworkErrorCode.CONNECTION_FAILED]:{category:exports.ErrorCategory.NETWORK,message:"网络连接失败"},[exports.NetworkErrorCode.REQUEST_TIMEOUT]:{category:exports.ErrorCategory.NETWORK,message:"请求超时"},[exports.NetworkErrorCode.SERVER_ERROR]:{category:exports.ErrorCategory.NETWORK,message:"服务器错误"},[exports.NetworkErrorCode.UNAUTHORIZED]:{category:exports.ErrorCategory.NETWORK,message:"未授权访问"},[exports.OperationErrorCode.UNITY_NOT_INITIALIZED]:{category:exports.ErrorCategory.OPERATION,message:"Unity实例未初始化"},[exports.OperationErrorCode.AVATAR_NOT_LOADED]:{category:exports.ErrorCategory.OPERATION,message:"数字人未加载"},[exports.OperationErrorCode.OPERATION_FAILED]:{category:exports.ErrorCategory.OPERATION,message:"操作执行失败"},[exports.OperationErrorCode.OPERATION_TIMEOUT]:{category:exports.ErrorCategory.OPERATION,message:"操作超时"},[exports.OperationErrorCode.OPERATION_CANCELLED]:{category:exports.ErrorCategory.OPERATION,message:"操作被取消"},[exports.OperationErrorCode.BROADCAST_EQUITY_NOT_EXIST]:{category:exports.ErrorCategory.OPERATION,message:"用户权益额度不存在"},[exports.OperationErrorCode.BROADCAST_EQUITY_NOT_ENOUGH]:{category:exports.ErrorCategory.OPERATION,message:"用户权益额度不足"},[exports.OperationErrorCode.BROADCAST_EQUITY_FREEZE_FAILED]:{category:exports.ErrorCategory.OPERATION,message:"用户权益额度冻结失败"},[exports.ResourceErrorCode.LOAD_FAILED]:{category:exports.ErrorCategory.RESOURCE,message:"资源加载失败"},[exports.ResourceErrorCode.FILE_CORRUPTED]:{category:exports.ErrorCategory.RESOURCE,message:"资源文件损坏"},[exports.ResourceErrorCode.NOT_FOUND]:{category:exports.ErrorCategory.RESOURCE,message:"资源不存在"},[exports.ResourceErrorCode.UNSUPPORTED_FORMAT]:{category:exports.ErrorCategory.RESOURCE,message:"资源格式不支持"},[exports.ResourceErrorCode.VERSION_INCOMPATIBLE]:{category:exports.ErrorCategory.RESOURCE,message:"资源版本不兼容"},[exports.SystemErrorCode.OUT_OF_MEMORY]:{category:exports.ErrorCategory.SYSTEM,message:"内存不足"},[exports.SystemErrorCode.GPU_NOT_SUPPORTED]:{category:exports.ErrorCategory.SYSTEM,message:"GPU不支持"},[exports.SystemErrorCode.WEBGL_NOT_SUPPORTED]:{category:exports.ErrorCategory.SYSTEM,message:"WebGL不支持"},[exports.SystemErrorCode.BROWSER_NOT_COMPATIBLE]:{category:exports.ErrorCategory.SYSTEM,message:"浏览器不兼容"},[exports.ConfigErrorCode.INVALID_CONFIG]:{category:exports.ErrorCategory.CONFIG,message:"配置参数无效"},[exports.ConfigErrorCode.MISSING_REQUIRED_PARAM]:{category:exports.ErrorCategory.CONFIG,message:"必需参数缺失"},[exports.ConfigErrorCode.PARAM_OUT_OF_RANGE]:{category:exports.ErrorCategory.CONFIG,message:"参数值超出范围"},[exports.ConfigErrorCode.INVALID_JSON_FORMAT]:{category:exports.ErrorCategory.CONFIG,message:"JSON格式错误"}};function getErrorInfo(code){return ERROR_CODE_MAP[code]||{category:exports.ErrorCategory.SYSTEM,message:"未知错误"}}class SDKError extends Error{constructor(code,message,originalError){const errorInfo=getErrorInfo(code),finalMessage=message||errorInfo.message;super(finalMessage),this.name="SDKError",this.code=code,this.category=errorInfo.category,this.message=finalMessage,this.timestamp=Date.now(),originalError&&originalError.stack?this.stack=originalError.stack:Error.captureStackTrace&&Error.captureStackTrace(this,SDKError)}toJSON(){return{name:this.name,code:this.code,category:this.category,message:this.message,timestamp:this.timestamp}}static createNetworkError(code,message,originalError){return new SDKError(code,message,originalError)}static createOperationError(code,message,originalError){return new SDKError(code,message,originalError)}static createResourceError(code,message,originalError){return new SDKError(code,message,originalError)}static createSystemError(code,message,originalError){return new SDKError(code,message,originalError)}static createConfigError(code,message,originalError){return new SDKError(code,message,originalError)}static createFromUnityError(unityCode,message){switch(unityCode){case 100:return new SDKError(exports.ResourceErrorCode.LOAD_FAILED,message);case 200:return new SDKError(exports.NetworkErrorCode.CONNECTION_FAILED,message);case 300:case 700:return new SDKError(exports.ConfigErrorCode.INVALID_CONFIG,message);case 400:return new SDKError(exports.OperationErrorCode.OPERATION_FAILED,message);case 500:return new SDKError(exports.SystemErrorCode.OUT_OF_MEMORY,message);case 600:return new SDKError(exports.OperationErrorCode.OPERATION_CANCELLED,message);default:return new SDKError(3001,message||`Unity错误 (错误码: ${unityCode})`)}}}var LogLevel,UnityOperationStatus;!function(LogLevel){LogLevel.DEBUG="debug",LogLevel.INFO="info",LogLevel.WARN="warn",LogLevel.ERROR="error"}(LogLevel||(LogLevel={}));class SimpleLogger{constructor(enableDebug=!1){this.enableDebug=enableDebug}pad(num,len){let s=String(num);for(;s.length<len;)s=`0${s}`;return s}getTimestamp(){const now=new Date;return`[${this.pad(now.getHours(),2)}:${this.pad(now.getMinutes(),2)}:${this.pad(now.getSeconds(),2)}.${this.pad(now.getMilliseconds(),3).slice(0,2)}]`}debug(message,data){this.enableDebug&&console.debug(`[SDK DEBUG]${this.getTimestamp()} ${message}`,data)}info(message,data){console.info(`[SDK INFO]${this.getTimestamp()} ${message}`,data)}warn(message,data){console.warn(`[SDK WARN]${this.getTimestamp()} ${message}`,data)}error(message,error,data){console.error(`[SDK ERROR]${this.getTimestamp()} ${message}`,error,error instanceof SDKError?error.code:null,data)}}exports.UnityOperationStatus=void 0,(UnityOperationStatus=exports.UnityOperationStatus||(exports.UnityOperationStatus={}))[UnityOperationStatus.SUCCESS=0]="SUCCESS",UnityOperationStatus[UnityOperationStatus.FAILURE=1]="FAILURE",UnityOperationStatus[UnityOperationStatus.TIMEOUT=2]="TIMEOUT",UnityOperationStatus[UnityOperationStatus.CANCELLED=3]="CANCELLED";const DEFAULT_CONFIG={targetObjectName:"AvatarSDK",timeout:3e4,enableDebugLog:!1,maxRetries:0};class UnityBaseService{get uniqueCallbackName(){return`${this.callbackFunctionName}_${this.instanceId}`}constructor(config){this.pendingCallbacks=new Map;const finalConfig=Object.assign(Object.assign({},DEFAULT_CONFIG),config);this.unityInstance=finalConfig.unityInstance,this.targetObjectName=finalConfig.targetObjectName,this.timeout=finalConfig.timeout||DEFAULT_CONFIG.timeout,this.maxRetries=finalConfig.maxRetries,this.instanceId=finalConfig.instanceId||"default",this.logger=new SimpleLogger(finalConfig.enableDebugLog),this.initializeGlobalCallback(),this.logger.debug("Unity service initialized",{config:finalConfig})}handleCallback(operation,code,message,data){const dataObj=data?JSON.parse(data):void 0;this.logger.warn("[ Received Unity callback ]",{operation:operation,code:code,message:message,data:dataObj,originalData:data});const callback=this.pendingCallbacks.get(operation);if(!callback)return void this.logger.warn(`No pending callback for operation: ${operation}`);callback.timer&&clearTimeout(callback.timer);const response={success:code===exports.UnityOperationStatus.SUCCESS,message:message,errorCode:code,data:dataObj};try{if(code===exports.UnityOperationStatus.SUCCESS)callback.resolve(response),this.logger.debug(`Operation '${operation}' completed successfully`);else{const error=SDKError.createFromUnityError(code,`Unity operation '${operation}' failed: ${message}`);callback.reject(error),this.logger.error(`Operation '${operation}' failed`,error)}}catch(error){this.logger.error(`Error handling callback for operation '${operation}'`,error)}finally{this.pendingCallbacks.delete(operation)}}setupCallback(operation){return this.clearCallback(operation),new Promise((resolve,reject)=>{const timer=setTimeout(()=>{this.pendingCallbacks.delete(operation);const timeoutError=new SDKError(exports.OperationErrorCode.OPERATION_TIMEOUT,`Unity operation '${operation}' timed out after ${this.timeout}ms`);this.logger.error(`Operation '${operation}' timed out`,timeoutError),reject(timeoutError)},this.timeout);this.pendingCallbacks.set(operation,{resolve:resolve,reject:reject,timer:timer,retries:0}),this.logger.debug(`Callback setup for operation '${operation}' with timeout ${this.timeout}ms`)})}clearCallback(operation){const callback=this.pendingCallbacks.get(operation);callback&&(callback.timer&&clearTimeout(callback.timer),this.pendingCallbacks.delete(operation),this.logger.debug(`Cleared callback for operation '${operation}'`))}clearAllCallbacks(){this.pendingCallbacks.forEach(callback=>{callback.timer&&clearTimeout(callback.timer)}),this.pendingCallbacks.clear(),this.logger.debug("Cleared all pending callbacks")}sendMessage(methodName,parameter){if(!this.isUnityAvailable())throw new SDKError(exports.OperationErrorCode.UNITY_NOT_INITIALIZED,"Unity实例未初始化");try{this.logger.warn(`[ Sending message ]: ${this.targetObjectName}.${methodName}`,parameter);const paramString=parameter?JSON.stringify(parameter):"";this.unityInstance.SendMessage(this.targetObjectName,methodName,paramString)}catch(error){const serviceError=new SDKError(exports.OperationErrorCode.OPERATION_FAILED,`Failed to send Unity message: ${methodName}`,error);throw this.logger.error(`Failed to send Unity message: ${methodName}`,serviceError),serviceError}}sendAsyncMessage(methodName,operation,parameter){return __awaiter(this,void 0,void 0,function*(){if(!this.isUnityAvailable())throw new SDKError(exports.OperationErrorCode.UNITY_NOT_INITIALIZED,"Unity实例未初始化");try{const callbackPromise=this.setupCallback(operation),fullParameter=Object.assign(Object.assign({},parameter),{callbackFun:this.uniqueCallbackName,operationType:operation});return this.sendMessage(methodName,fullParameter),yield callbackPromise}catch(error){if(this.clearCallback(operation),this.maxRetries>0&&error instanceof SDKError&&error.code===exports.OperationErrorCode.OPERATION_TIMEOUT)return yield this.retryOperation(operation,methodName,parameter);throw error}})}destroy(){this.clearAllCallbacks(),window[this.uniqueCallbackName]&&(delete window[this.uniqueCallbackName],this.logger.debug(`Global callback unregistered: ${this.uniqueCallbackName}`)),this.logger.info("Unity service destroyed")}isUnityAvailable(){return null!==this.unityInstance&&"function"==typeof this.unityInstance.SendMessage}getPendingCallbackCount(){return this.pendingCallbacks.size}initializeGlobalCallback(){window[this.uniqueCallbackName]=(operation,code,message,data)=>{this.handleCallback(operation,code,message,data)},this.logger.warn(`Global callback registered: ${this.uniqueCallbackName}`)}retryOperation(operation,methodName,parameter){return __awaiter(this,void 0,void 0,function*(){let lastError=null;for(let attempt=0;attempt<=this.maxRetries;attempt++)try{return attempt>0&&(this.logger.debug(`Retrying operation '${operation}', attempt ${attempt}/${this.maxRetries}`),yield new Promise(resolve=>setTimeout(resolve,1e3*Math.pow(2,attempt)))),yield this.sendAsyncMessage(methodName,operation,parameter)}catch(error){if(lastError=error,this.logger.warn(`Operation '${operation}' failed, attempt ${attempt+1}/${this.maxRetries+1}`,error),error instanceof SDKError&&error.code===exports.OperationErrorCode.OPERATION_TIMEOUT&&attempt<this.maxRetries)continue;if(!(error instanceof SDKError&&error.code===exports.OperationErrorCode.OPERATION_TIMEOUT)||attempt>=this.maxRetries)throw error}throw lastError||new SDKError(exports.OperationErrorCode.OPERATION_TIMEOUT,`All retry attempts failed for operation: ${operation}`)})}}var AvatarOperationType,AvatarCameraType;exports.AvatarOperationType=void 0,(AvatarOperationType=exports.AvatarOperationType||(exports.AvatarOperationType={})).INITIALIZE_AVATAR="initializeAvatar",AvatarOperationType.PLAY_MOTION="playMotion",AvatarOperationType.GET_CURRENT_MOTION="getCurrentMotion",AvatarOperationType.UNLOAD_AVATAR="unloadAvatar",AvatarOperationType.SET_CAMERA="setCamera",exports.AvatarCameraType=void 0,(AvatarCameraType=exports.AvatarCameraType||(exports.AvatarCameraType={})).WHOLE="whole",AvatarCameraType.HALF="half",AvatarCameraType.FACE="face";class AvatarService extends UnityBaseService{get callbackFunctionName(){return"uniAvatarCallback"}constructor(config){super(config),this.logger.info("Avatar API service initialized")}initializeAvatar(avatarCode_1){return __awaiter(this,arguments,void 0,function*(avatarCode,cameraType=exports.AvatarCameraType.WHOLE){this.logger.info(`Initializing avatar: ${avatarCode} with camera type: ${cameraType}`);try{const result=yield this.sendAsyncMessage("InitializeAvatar",exports.AvatarOperationType.INITIALIZE_AVATAR,{avatarCode:avatarCode,cameraType:cameraType});return this.logger.info("Avatar initialization "+(result.success?"succeeded":"failed")),result}catch(error){throw this.logger.error("Failed to initialize avatar",error),error}})}handleCallback(operation,code,message,data){super.handleCallback(operation,code,message,data)}playMotion(clipCode){return __awaiter(this,void 0,void 0,function*(){this.logger.info(`Playing motion: ${clipCode}`);try{const result=yield this.sendAsyncMessage("PlayMotion",exports.AvatarOperationType.PLAY_MOTION,{clipCode:clipCode});return this.logger.info("Motion play "+(result.success?"succeeded":"failed")),result}catch(error){throw this.logger.error("Failed to play motion",error),error}})}getCurrentMotion(getRemainingTime){return __awaiter(this,void 0,void 0,function*(){var _a,_b;this.logger.info(`Getting current motion info, includeRemainingTime: ${getRemainingTime}`);try{const result=yield this.sendAsyncMessage("GetCurrentMotion",exports.AvatarOperationType.GET_CURRENT_MOTION,{getRemainingTime:getRemainingTime});return this.logger.info("Current motion info retrieved",{motionId:null===(_a=result.data)||void 0===_a?void 0:_a.motionId,remainingTime:null===(_b=result.data)||void 0===_b?void 0:_b.motionRemainingTime}),result}catch(error){throw this.logger.error("Failed to get current motion info",error),error}})}unloadAvatar(){return __awaiter(this,void 0,void 0,function*(){this.logger.info("Unloading avatar");try{const result=yield this.sendAsyncMessage("UnloadAvatar",exports.AvatarOperationType.UNLOAD_AVATAR);return this.logger.info("Avatar unload "+(result.success?"succeeded":"failed")),result}catch(error){throw this.logger.error("Failed to unload avatar",error),error}})}setCamera(cameraType){return __awaiter(this,void 0,void 0,function*(){this.logger.info(`Setting camera type: ${cameraType}`);try{const result=yield this.sendAsyncMessage("SetCamera",exports.AvatarOperationType.SET_CAMERA,{cameraType:cameraType});return this.logger.info("Camera type setting "+(result.success?"succeeded":"failed")),result}catch(error){throw this.logger.error("Failed to set camera type",error),error}})}batchExecute(operations){return __awaiter(this,void 0,void 0,function*(){this.logger.info(`Executing batch operations: ${operations.length} items`);const results=[];for(const operation of operations)try{const method=this[operation.method],result=yield method.apply(this,operation.params);results.push(result)}catch(error){this.logger.error(`Batch operation failed: ${operation.method}`,error),results.push({success:!1,message:`Batch operation failed: ${error.message}`,errorCode:1})}return this.logger.info(`Batch operations completed: ${results.filter(r=>r.success).length}/${results.length} successful`),results})}}const ENV_MAP={dev:{apiBaseUrl:"https://dev.local.zeewain.com"},test:{apiBaseUrl:"https://test.local.zeewain.com"},prod:{apiBaseUrl:"https://ai.zeewain3d.com"}};class ConfigManager{constructor(){this.config=null}static getInstance(){return ConfigManager.instance||(ConfigManager.instance=new ConfigManager),ConfigManager.instance}setConfig(config){this.config=Object.assign(Object.assign({},config),{env:config.env||"prod",containerId:config.containerId||"unity-container"})}updateConfig(config){this.config&&(this.config=Object.assign(Object.assign({},this.config),config))}getConfig(){return this.config}getApiBaseUrl(withApiModule=!0){var _a,_b,_c,_d;return"custom"===(null===(_a=this.config)||void 0===_a?void 0:_a.env)&&(null===(_b=this.config)||void 0===_b?void 0:_b.apiUrl)?`${this.config.apiUrl}${withApiModule?"/api":""}`:(null===(_d=function getEnvConfig(env="dev",withApiModule=!0){const baseUrl=ENV_MAP[env];return baseUrl?{apiBaseUrl:`${baseUrl.apiBaseUrl}${withApiModule?"/api":""}`}:null}((null===(_c=this.config)||void 0===_c?void 0:_c.env)||"prod",withApiModule))||void 0===_d?void 0:_d.apiBaseUrl)||""}reset(){this.config=null}}ConfigManager.instance=null;class UnityLoader{constructor(){this.config=ConfigManager.getInstance().getConfig()}init(){return __awaiter(this,void 0,void 0,function*(){const container=this.createContainer();return yield this.loadUnityLoader(),yield this.createUnityInstance(container)})}createContainer(){const container=document.getElementById(this.config.containerId);if(!container)throw new TypeError(`Avatar container element with ID "${this.config.containerId}" not found`);if(!(container instanceof HTMLDivElement))throw new TypeError("Avatar container element must be a div element");return container.style.position="relative",container}loadUnityLoader(){return new Promise((resolve,reject)=>{if(window.createUnityInstance)return resolve();const script=document.createElement("script");script.src=this.config.loaderUrl,script.async=!0,script.crossOrigin="anonymous",script.onload=()=>{"function"==typeof window.createUnityInstance?resolve():reject(new Error("createUnityInstance function not found"))},script.onerror=error=>{reject(new Error(`Failed to load UnityLoader: ${error}`))},document.head.appendChild(script)})}createUnityInstance(container){return __awaiter(this,void 0,void 0,function*(){let canvas=container.querySelector("#unity-canvas");if(canvas||(canvas=document.createElement("canvas"),canvas.id="unity-canvas",canvas.style.width="100%",canvas.style.height="100%",container.appendChild(canvas)),/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)){const meta=document.createElement("meta");meta.name="viewport",meta.content="width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes",document.head.appendChild(meta),canvas.style.width="100%",canvas.style.height="100%",canvas.style.position="fixed"}if("function"==typeof window.createUnityInstance){return yield window.createUnityInstance(canvas,{dataUrl:this.config.dataUrl,frameworkUrl:this.config.frameworkUrl,codeUrl:this.config.codeUrl,companyName:"广州紫为云科技有限公司",productName:"数字人SDK",productVersion:"1.0"},progress=>{this.config.onProgress&&this.config.onProgress(progress)})}throw new TypeError("createUnityInstance is not defined on window.")})}}function getLines(onLine){let buffer,position,fieldLength,discardTrailingNewline=!1;return function onChunk(arr){void 0===buffer?(buffer=arr,position=0,fieldLength=-1):buffer=function concat(a,b){const res=new Uint8Array(a.length+b.length);return res.set(a),res.set(b,a.length),res}(buffer,arr);const bufLength=buffer.length;let lineStart=0;for(;position<bufLength;){discardTrailingNewline&&(10===buffer[position]&&(lineStart=++position),discardTrailingNewline=!1);let lineEnd=-1;for(;position<bufLength&&-1===lineEnd;++position)switch(buffer[position]){case 58:-1===fieldLength&&(fieldLength=position-lineStart);break;case 13:discardTrailingNewline=!0;case 10:lineEnd=position}if(-1===lineEnd)break;onLine(buffer.subarray(lineStart,lineEnd),fieldLength),lineStart=position,fieldLength=-1}lineStart===bufLength?buffer=void 0:0!==lineStart&&(buffer=buffer.subarray(lineStart),position-=lineStart)}}var __rest=function(s,e){var t={};for(var p in s)Object.prototype.hasOwnProperty.call(s,p)&&e.indexOf(p)<0&&(t[p]=s[p]);if(null!=s&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(p=Object.getOwnPropertySymbols(s);i<p.length;i++)e.indexOf(p[i])<0&&Object.prototype.propertyIsEnumerable.call(s,p[i])&&(t[p[i]]=s[p[i]])}return t};function fetchEventSource(input,_a){var{signal:inputSignal,headers:inputHeaders,onopen:inputOnOpen,onmessage:onmessage,onclose:onclose,onerror:onerror,openWhenHidden:openWhenHidden,fetch:inputFetch}=_a,rest=__rest(_a,["signal","headers","onopen","onmessage","onclose","onerror","openWhenHidden","fetch"]);return new Promise((resolve,reject)=>{const headers=Object.assign({},inputHeaders);let curRequestController;function onVisibilityChange(){curRequestController.abort(),document.hidden||create()}headers.accept||(headers.accept="text/event-stream"),openWhenHidden||document.addEventListener("visibilitychange",onVisibilityChange);let retryInterval=1e3,retryTimer=0;function dispose(){document.removeEventListener("visibilitychange",onVisibilityChange),window.clearTimeout(retryTimer),curRequestController.abort()}null==inputSignal||inputSignal.addEventListener("abort",()=>{dispose(),resolve()});const fetch=null!=inputFetch?inputFetch:window.fetch,onopen=null!=inputOnOpen?inputOnOpen:defaultOnOpen;async function create(){var _a;curRequestController=new AbortController;try{const response=await fetch(input,Object.assign(Object.assign({},rest),{headers:headers,signal:curRequestController.signal}));await onopen(response),await async function getBytes(stream,onChunk){const reader=stream.getReader();let result;for(;!(result=await reader.read()).done;)onChunk(result.value)}(response.body,getLines(function getMessages(onId,onRetry,onMessage){let message={data:"",event:"",id:"",retry:void 0};const decoder=new TextDecoder;return function onLine(line,fieldLength){if(0===line.length)null==onMessage||onMessage(message),message={data:"",event:"",id:"",retry:void 0};else if(fieldLength>0){const field=decoder.decode(line.subarray(0,fieldLength)),valueOffset=fieldLength+(32===line[fieldLength+1]?2:1),value=decoder.decode(line.subarray(valueOffset));switch(field){case"data":message.data=message.data?message.data+"\n"+value:value;break;case"event":message.event=value;break;case"id":onId(message.id=value);break;case"retry":const retry=parseInt(value,10);isNaN(retry)||onRetry(message.retry=retry)}}}}(id=>{id?headers["last-event-id"]=id:delete headers["last-event-id"]},retry=>{retryInterval=retry},onmessage))),null==onclose||onclose(),dispose(),resolve()}catch(err){if(!curRequestController.signal.aborted)try{const interval=null!==(_a=null==onerror?void 0:onerror(err))&&void 0!==_a?_a:retryInterval;window.clearTimeout(retryTimer),retryTimer=window.setTimeout(create,interval)}catch(innerErr){dispose(),reject(innerErr)}}}create()})}function defaultOnOpen(response){const contentType=response.headers.get("content-type");if(!(null==contentType?void 0:contentType.startsWith("text/event-stream")))throw new Error(`Expected content-type to be text/event-stream, Actual: ${contentType}`)}var BroadcastOperationType,BroadcastType,BroadcastTaskStatus;exports.BroadcastOperationType=void 0,(BroadcastOperationType=exports.BroadcastOperationType||(exports.BroadcastOperationType={})).START_BROADCAST="startBroadcast",BroadcastOperationType.PAUSE_BROADCAST="pauseBroadcast",BroadcastOperationType.RESUME_BROADCAST="resumeBroadcast",BroadcastOperationType.STOP_BROADCAST="stopBroadcast",BroadcastOperationType.APPEND_BROADCAST="appendBroadcast",exports.BroadcastType=void 0,(BroadcastType=exports.BroadcastType||(exports.BroadcastType={})).TEXT="text",BroadcastType.AUDIO="audio",function(BroadcastTaskStatus){BroadcastTaskStatus.PENDING="pending",BroadcastTaskStatus.REQUESTING="requesting",BroadcastTaskStatus.COMPLETED="completed",BroadcastTaskStatus.FAILED="failed",BroadcastTaskStatus.CANCELLED="cancelled"}(BroadcastTaskStatus||(BroadcastTaskStatus={}));class BroadcastService extends UnityBaseService{constructor(config){super(config),this.callbacks={},this.taskQueue=[],this.taskSequence=0,this.currentSendingSequence=0,this.isBroadcastingAudio=!1,this.hasReceivedAudio=!1,this.queueProcessTimer=null,this.broadcastCompletedCount=0,this.callbacks=config.callbacks||{},this.logger.info("Broadcast service initialized",{config:config})}handleCallback(operation,code,message,data){var _a,_b,_c,_d,_e,_f,_g,_h,_j,_k,_l;const{isBroadcastCompleted:isBroadcastCompleted}=JSON.parse(data||"{}");if(super.handleCallback(operation,code,message,data),0===code)switch(operation){case exports.BroadcastOperationType.START_BROADCAST:if(isBroadcastCompleted){this.broadcastCompletedCount++;const status=this.getStatus();0===(null===(_a=status.queueInfo)||void 0===_a?void 0:_a.pendingTasks)&&0===(null===(_b=status.queueInfo)||void 0===_b?void 0:_b.requestingTasks)&&(null===(_c=status.queueInfo)||void 0===_c?void 0:_c.completedTasks)===this.broadcastCompletedCount&&(this.isBroadcastingAudio=!1,this.hasReceivedAudio=!1,this.currentSendingSequence=0,this.cleanupCompletedTasks(),this.logger.warn("Broadcast all completed")),null===(_e=(_d=this.callbacks).onFinish)||void 0===_e||_e.call(_d)}break;case exports.BroadcastOperationType.PAUSE_BROADCAST:null===(_g=(_f=this.callbacks).onPause)||void 0===_g||_g.call(_f),this.logger.debug("Broadcast paused callback triggered");break;case exports.BroadcastOperationType.RESUME_BROADCAST:null===(_j=(_h=this.callbacks).onResume)||void 0===_j||_j.call(_h),this.logger.debug("Broadcast resumed callback triggered");break;case exports.BroadcastOperationType.STOP_BROADCAST:null===(_l=(_k=this.callbacks).onStop)||void 0===_l||_l.call(_k),this.logger.debug("Broadcast stopped callback triggered")}else{const error=SDKError.createFromUnityError(code,`Unity operation '${operation}' failed: ${message}`);this.handleError(error)}}startBroadcast(params,isAppend){return __awaiter(this,void 0,void 0,function*(){var _a,_b;this.logger.info(`Starting broadcast: ${params.type}`,{humanCode:params.humanCode,text:params.text,audioUrl:params.audioUrl,isAppend:isAppend,queueLength:this.taskQueue.length}),this.validateBroadcastParams(params),isAppend||(yield this.stopBroadcast(),this.taskSequence=0,this.currentSendingSequence=0,this.sendMessage("StartBroadcast",{callbackFun:this.uniqueCallbackName,operationType:exports.BroadcastOperationType.START_BROADCAST,motionList:params.motionList,motionPlayMode:params.motionPlayMode}),null===(_b=(_a=this.callbacks).onStart)||void 0===_b||_b.call(_a),this.isBroadcastingAudio=!0);const task=this.createBroadcastTask(params);this.addTaskToQueue(task),this.logger.debug("Broadcast task created and queued",{taskId:task.id,sequence:task.sequence,isAppend:isAppend})})}pauseBroadcast(resetIdle){return __awaiter(this,void 0,void 0,function*(){this.logger.info("Pausing broadcast");try{yield this.sendAsyncMessage("PauseBroadcast",exports.BroadcastOperationType.PAUSE_BROADCAST,{resetIdle:resetIdle}),this.logger.info("Broadcast paused successfully")}catch(error){throw this.logger.error("Failed to pause broadcast",error),error}})}resumeBroadcast(){return __awaiter(this,void 0,void 0,function*(){this.logger.info("Resuming broadcast");try{yield this.sendAsyncMessage("ResumeBroadcast",exports.BroadcastOperationType.RESUME_BROADCAST,{}),this.logger.info("Broadcast resumed successfully")}catch(error){throw this.logger.error("Failed to resume broadcast",error),error}})}stopBroadcast(){return __awaiter(this,void 0,void 0,function*(){this.logger.info("Stopping broadcast and clearing queue",{queueLength:this.taskQueue.length}),this.cancelAllTasks(),yield new Promise(resolve=>setTimeout(resolve,100)),this.isBroadcastingAudio=!1,this.hasReceivedAudio=!1,this.broadcastCompletedCount=0;try{yield this.sendAsyncMessage("StopBroadcast",exports.BroadcastOperationType.STOP_BROADCAST,{}),this.logger.info("Broadcast stopped successfully")}catch(error){throw this.logger.error("Failed to stop broadcast",error),error}})}updateCallbacks(callbacks){this.callbacks=Object.assign(Object.assign({},this.callbacks),callbacks),this.logger.debug("Broadcast callbacks updated")}getStatus(){const pendingTasks=this.taskQueue.filter(t=>t.status===BroadcastTaskStatus.PENDING).length,requestingTasks=this.taskQueue.filter(t=>t.status===BroadcastTaskStatus.REQUESTING).length,completedTasks=this.taskQueue.filter(t=>t.status===BroadcastTaskStatus.COMPLETED).length,failedTasks=this.taskQueue.filter(t=>t.status===BroadcastTaskStatus.FAILED).length,totalPendingResponses=this.taskQueue.reduce((sum,t)=>sum+t.pendingResponses.length,0),currentSendingSequence=this.currentSendingSequence,isGeneratingAudio=pendingTasks+requestingTasks>0;return{isActive:this.isBroadcastingAudio||isGeneratingAudio,isGeneratingAudio:isGeneratingAudio,hasReceivedAudio:this.hasReceivedAudio,queueInfo:{totalTasks:this.taskQueue.length,pendingTasks:pendingTasks,requestingTasks:requestingTasks,completedTasks:completedTasks,failedTasks:failedTasks,totalPendingResponses:totalPendingResponses,currentSendingSequence:currentSendingSequence}}}destroy(){this.clearQueueProcessTimer(),this.cancelAllTasks(),super.destroy(),this.logger.info("Broadcast service destroyed")}createBroadcastTask(params){const task={id:`[${params.type===exports.BroadcastType.TEXT?"TEXT":"AUDIO"}]-(${params.type===exports.BroadcastType.TEXT?params.text:params.audioUrl})_${Math.random().toString(36).substring(2,9)}`,sequence:++this.taskSequence,params:params,status:BroadcastTaskStatus.PENDING,controller:new AbortController,pendingResponses:[],isGenerationComplete:!1,createdAt:new Date};return this.logger.debug("Created broadcast task",{taskId:task.id,sequence:task.sequence}),task}addTaskToQueue(task){this.taskQueue.push(task),this.logger.debug("Task added to queue",{taskId:task.id,params:task.params,queueLength:this.taskQueue.length});this.taskQueue.some(t=>t.status===BroadcastTaskStatus.REQUESTING)?this.logger.debug("Task queued, waiting for previous task to complete",{taskId:task.id,pendingTasks:this.taskQueue.filter(t=>t.status===BroadcastTaskStatus.PENDING).length}):this.startTaskRequest(task),this.processTaskQueue()}processTaskQueue(){this.queueProcessTimer||(this.queueProcessTimer=setInterval(()=>{this.processTaskQueueStep()},100)),this.processTaskQueueStep()}processTaskQueueStep(){const nextTask=this.taskQueue.find(task=>task.sequence===this.currentSendingSequence+1&&task.status!==BroadcastTaskStatus.PENDING&&task.pendingResponses.length>0);nextTask?this.sendNextResponse(nextTask):this.logger.debug("No next task to process",{currentSendingSequence:this.currentSendingSequence,taskQueue:this.taskQueue});0===this.taskQueue.filter(task=>task.status===BroadcastTaskStatus.PENDING||task.status===BroadcastTaskStatus.REQUESTING).length&&this.clearQueueProcessTimer()}startTaskRequest(task){return __awaiter(this,void 0,void 0,function*(){var _a;task.status=BroadcastTaskStatus.REQUESTING,this.logger.debug("Starting task request",{taskId:task.id});try{const apiUrl=`${ConfigManager.getInstance().getApiBaseUrl(!0)}${this.getBroadcastApiPath(task.params.type)}`,requestBody={humanCode:task.params.humanCode,speed:task.params.speed,volume:task.params.volume>=0?100*task.params.volume:void 0,isSubtitle:task.params.isSubtitle,audioDrivenVersion:ConfigManager.getInstance().getConfig().audioDrivenVersion};task.params.type===exports.BroadcastType.TEXT?(requestBody.text=task.params.text,requestBody.voiceCode=task.params.voiceCode):task.params.type===exports.BroadcastType.AUDIO&&(requestBody.text=task.params.text,requestBody.audioUrl=task.params.audioUrl),fetchEventSource(apiUrl,{method:"POST",headers:{"Content-Type":"application/json",x_auth_token:(null===(_a=ConfigManager.getInstance().getConfig())||void 0===_a?void 0:_a.token)||""},body:JSON.stringify(requestBody),signal:task.controller.signal,openWhenHidden:!0,onopen:response=>__awaiter(this,void 0,void 0,function*(){if(!response.ok){const error=this.createHttpError(response.status,response.statusText,task.id);throw this.handleTaskError(task,error),error}}),onmessage:event=>{this.handleTaskResponse(task,event.data)},onclose:()=>{this.handleTaskClose(task)},onerror:error=>{if(error instanceof SDKError)throw error;this.logger.error("broadcast onerror",error);const sdkError=this.convertToSDKError(error,task.id);throw this.handleTaskError(task,sdkError),sdkError}})}catch(error){const sdkError=this.convertToSDKError(error,task.id);this.handleTaskError(task,sdkError)}})}handleTaskResponse(task,data){try{const response=JSON.parse(data);if(0!==response.code){const error=this.createBroadcastError(response.code,response.message);return void this.handleTaskError(task,error)}if(response.data){this.hasReceivedAudio=!0,task.params.type===exports.BroadcastType.AUDIO&&task.params.audioUrl&&!response.data.voiceUrl&&(response.data.voiceUrl=task.params.audioUrl);const{voiceUrl:voiceUrl,mouthShapeUrl:mouthShapeUrl}=response.data;voiceUrl&&!voiceUrl.startsWith("http")&&(response.data.voiceUrl=`${ConfigManager.getInstance().getApiBaseUrl(!1)}${voiceUrl}`),mouthShapeUrl&&!mouthShapeUrl.startsWith("http")&&(response.data.mouthShapeUrl=`${ConfigManager.getInstance().getApiBaseUrl(!1)}${mouthShapeUrl}`),task.pendingResponses.push(response),this.logger.debug("Response added to task",{taskId:task.id,response:response,pendingCount:task.pendingResponses.length}),response.data.done&&(task.isGenerationComplete=!0,this.logger.debug("Task generation completed",{taskId:task.id,totalResponses:task.pendingResponses.length}))}}catch(error){this.handleTaskError(task,new SDKError(exports.OperationErrorCode.OPERATION_FAILED,"string"==typeof error?error:error.message||"播报服务错误"))}}sendNextResponse(task){var _a;if(0===task.pendingResponses.length)return;const response=task.pendingResponses.shift();this.logger.debug("Sending response to Unity",{taskId:task.id,remainingResponses:task.pendingResponses.length,voiceUrl:null===(_a=response.data)||void 0===_a?void 0:_a.voiceUrl}),this.sendMessage("AppendBroadcast",{response:response,callbackFun:this.uniqueCallbackName,operationType:exports.BroadcastOperationType.APPEND_BROADCAST}),task.isGenerationComplete&&0===task.pendingResponses.length&&(task.status=BroadcastTaskStatus.COMPLETED,this.currentSendingSequence=task.sequence,this.logger.debug("Task completed",{taskId:task.id}))}handleTaskClose(task){return __awaiter(this,void 0,void 0,function*(){this.logger.debug("Task stream closed",{taskId:task.id}),task.status!==BroadcastTaskStatus.FAILED&&task.status!==BroadcastTaskStatus.CANCELLED&&(task.isGenerationComplete||task.status!==BroadcastTaskStatus.REQUESTING||(task.isGenerationComplete=!0),this.startNextPendingTask())})}handleTaskError(task,error){var _a,_b;task.status!==BroadcastTaskStatus.FAILED&&task.status!==BroadcastTaskStatus.CANCELLED&&(task.status=BroadcastTaskStatus.FAILED,task.error=error,this.logger.error(`Task failed - ${task.id}`,error),null===(_b=(_a=this.callbacks).onError)||void 0===_b||_b.call(_a,error),this.cancelAllTasks(),this.isBroadcastingAudio=!1,this.hasReceivedAudio=!1,this.currentSendingSequence=0,this.clearQueueProcessTimer(),this.logger.debug("Task failed, all tasks cancelled and broadcast state reset"))}cleanupCompletedTasks(){const beforeLength=this.taskQueue.length;this.taskQueue=this.taskQueue.filter(task=>task.status!==BroadcastTaskStatus.COMPLETED&&task.status!==BroadcastTaskStatus.FAILED&&task.status!==BroadcastTaskStatus.CANCELLED);const removedCount=beforeLength-this.taskQueue.length;removedCount>0&&this.logger.debug("Cleaned up completed tasks",{removedCount:removedCount,remainingTasks:this.taskQueue.length})}cancelAllTasks(){for(const task of this.taskQueue)task.status===BroadcastTaskStatus.REQUESTING?(task.controller.abort(),task.status=BroadcastTaskStatus.CANCELLED,this.logger.debug("Task aborted",{taskId:task.id,previousStatus:"requesting"})):task.status===BroadcastTaskStatus.PENDING&&(task.status=BroadcastTaskStatus.CANCELLED,this.logger.debug("Task cancelled",{taskId:task.id,previousStatus:"pending"}));this.taskQueue=[],this.taskSequence=0,this.currentSendingSequence=0,this.logger.debug("All tasks cancelled and queue cleared")}get callbackFunctionName(){return"uniBroadcastCallback"}getBroadcastApiPath(type){switch(type){case exports.BroadcastType.TEXT:return"/aiep-openapi/avatar-interaction/v1/broadcast/text";case exports.BroadcastType.AUDIO:return"/aiep-openapi/avatar-interaction/v1/broadcast/audio";default:throw new SDKError(exports.ConfigErrorCode.INVALID_CONFIG,`未知的播报类型: ${type}`)}}validateBroadcastParams(params){if(params.type===exports.BroadcastType.TEXT){if(!params.text||!params.voiceCode)throw new SDKError(exports.ConfigErrorCode.MISSING_REQUIRED_PARAM,"文本播报需要提供text和voiceCode参数")}else if(params.type===exports.BroadcastType.AUDIO&&!params.audioUrl)throw new SDKError(exports.ConfigErrorCode.MISSING_REQUIRED_PARAM,"自定义音频播报需要提供audioUrl参数")}handleError(error){var _a,_b;this.logger.error("Broadcast error occurred",error),null===(_b=(_a=this.callbacks).onError)||void 0===_b||_b.call(_a,error)}createBroadcastError(errorCode,errorMessage){switch(errorCode){case 14001:return new SDKError(exports.OperationErrorCode.BROADCAST_EQUITY_NOT_EXIST,"用户权益额度不存在");case 14002:return new SDKError(exports.OperationErrorCode.BROADCAST_EQUITY_NOT_ENOUGH,"用户权益额度不足");case 14003:return new SDKError(exports.OperationErrorCode.BROADCAST_EQUITY_FREEZE_FAILED,"用户权益额度冻结失败");default:return new SDKError(exports.OperationErrorCode.OPERATION_FAILED,`${errorMessage}(${errorCode})`||`播报服务错误(${errorCode})`)}}startNextPendingTask(){const nextPendingTask=this.taskQueue.filter(t=>t.status===BroadcastTaskStatus.PENDING).sort((a,b)=>a.sequence-b.sequence)[0];nextPendingTask?(this.logger.debug("Starting next pending task",{taskId:nextPendingTask.id,sequence:nextPendingTask.sequence}),this.startTaskRequest(nextPendingTask)):this.logger.debug("No pending tasks to start")}clearQueueProcessTimer(){this.queueProcessTimer&&(clearInterval(this.queueProcessTimer),this.queueProcessTimer=null,this.logger.debug("Queue process timer cleared"))}createHttpError(status,statusText,taskId){switch(this.logger.warn(`HTTP error occurred - Task: ${taskId}, Status: ${status}`,{status:status,statusText:statusText}),status){case 401:return new SDKError(exports.NetworkErrorCode.UNAUTHORIZED,`Token 已过期或无效,请重新授权 (HTTP ${status})`);case 403:return new SDKError(exports.NetworkErrorCode.UNAUTHORIZED,`无权限访问该资源 (HTTP ${status})`);case 404:return new SDKError(exports.NetworkErrorCode.SERVER_ERROR,`请求的资源不存在 (HTTP ${status})`);case 500:case 502:case 503:case 504:return new SDKError(exports.NetworkErrorCode.SERVER_ERROR,`服务器错误,请稍后重试 (HTTP ${status})`);default:return new SDKError(exports.NetworkErrorCode.CONNECTION_FAILED,`网络请求失败: ${statusText||"Unknown Error"} (HTTP ${status})`)}}convertToSDKError(error,taskId){if(error instanceof SDKError)return error;if(error instanceof Error){const errorMessage=error.message.toLowerCase();if(errorMessage.includes("timeout")||errorMessage.includes("timed out"))return new SDKError(exports.NetworkErrorCode.REQUEST_TIMEOUT,`请求超时 - Task: ${taskId}`,error);if(errorMessage.includes("network")||errorMessage.includes("fetch")||errorMessage.includes("connection")){const hint=errorMessage.includes("failed to fetch")?"(可能是 Token 过期或 CORS 跨域问题,请检查 Token 是否有效)":"";return new SDKError(exports.NetworkErrorCode.CONNECTION_FAILED,`网络请求失败 - Task: ${taskId}: ${error.message}${hint}`,error)}return errorMessage.includes("abort")||errorMessage.includes("cancel")?new SDKError(exports.OperationErrorCode.OPERATION_CANCELLED,`操作已取消 - Task: ${taskId}`,error):new SDKError(exports.OperationErrorCode.OPERATION_FAILED,`播报任务执行失败 - Task: ${taskId}: ${error.message}`,error)}const errorMessage=String(error);return new SDKError(exports.OperationErrorCode.OPERATION_FAILED,`播报任务执行失败 - Task: ${taskId}: ${errorMessage}`)}}class ZEEAvatarLoader{constructor(){this.apiService=null,this.unityInstance=null,this.loader=new UnityLoader}init(){return __awaiter(this,void 0,void 0,function*(){return this.unityInstance=yield this.loader.init(),this.initGlobalConfig(),this.apiService=new AvatarService({unityInstance:this.unityInstance}),this.apiService})}updateToken(token){const currentConfig=ConfigManager.getInstance().getConfig();currentConfig&&(ConfigManager.getInstance().setConfig(Object.assign(Object.assign({},currentConfig),{token:token})),this.initGlobalConfig())}getAPI(){return this.apiService}getInstance(){return this.unityInstance}getContainerId(){return ConfigManager.getInstance().getConfig().containerId}destroy(){if(this.unityInstance){const container=document.getElementById(this.getContainerId());if(container){const canvas=container.querySelector("#unity-canvas");canvas&&canvas.remove()}"function"==typeof this.unityInstance.Quit&&this.unityInstance.Quit(),this.unityInstance=null,this.apiService=null}ConfigManager.getInstance().reset()}initGlobalConfig(){const config=ConfigManager.getInstance().getConfig(),{assetsFrom:assetsFrom}=config,globalParams={token:null==config?void 0:config.token,apiBaseUrl:ConfigManager.getInstance().getApiBaseUrl(!1),idleMotionList:null==config?void 0:config.idleMotionList};if(this.unityInstance.SendMessage("AvatarSDK","InitializeConfig",JSON.stringify(globalParams)),console.warn("[ Send Unity message ]: AvatarSDK.InitializeConfig",globalParams),"cloud"!==assetsFrom){const assetModuleParams={isZip:!0,assetBundlePath:null==config?void 0:config.assetsUrl};this.unityInstance.SendMessage("AvatarSDK","InitAssetBundleModule",JSON.stringify(assetModuleParams)),console.warn("[ Send Unity message ]: AvatarSDK.InitAssetBundleModule",assetModuleParams)}}}exports.AvatarService=AvatarService,exports.BroadcastService=BroadcastService,exports.ERROR_CODE_MAP=ERROR_CODE_MAP,exports.SDKError=SDKError,exports.SDK_VERSION="2.2.1",exports.ZEEAvatarLoader=ZEEAvatarLoader,exports.ZEEAvatarSDK=class ZEEAvatarSDK{constructor(config){var _a;this.loader=null,this.avatarService=null,this.broadcastService=null,this.unityInstance=null,this.isInitialized=!1,this.instanceId=function generateUniqueId(){return`${Date.now()}_${Math.random().toString(36).substring(2,9)}`}(),ConfigManager.getInstance().setConfig(config),this.logger=new SimpleLogger(null===(_a=ConfigManager.getInstance().getConfig().enableDebugLog)||void 0===_a||_a),this.logger.info("SDK版本","2.2.1")}initializeAvatar(avatarCode_1){return __awaiter(this,arguments,void 0,function*(avatarCode,cameraType=exports.AvatarCameraType.WHOLE){var _a;if(this.isInitialized)throw new SDKError(exports.OperationErrorCode.OPERATION_FAILED,"SDK已经初始化,请勿重复初始化");try{const config=ConfigManager.getInstance().getConfig();this.loader=new ZEEAvatarLoader,yield this.loader.init(),this.unityInstance=this.loader.getInstance(),this.avatarService=new AvatarService({unityInstance:this.unityInstance,instanceId:this.instanceId,enableDebugLog:config.enableDebugLog,timeout:config.operationTimeout}),this.broadcastService=new BroadcastService({unityInstance:this.unityInstance,instanceId:this.instanceId,callbacks:config.broadcastCallbacks,enableDebugLog:config.enableDebugLog,timeout:config.operationTimeout});const result=yield this.avatarService.initializeAvatar(avatarCode,cameraType);if(result.success){const audioDrivenVersion=null===(_a=result.data)||void 0===_a?void 0:_a.audioDrivenVersion;if(config.audioDrivenVersion=audioDrivenVersion,this.logger.info("AudioDrivenVersion",audioDrivenVersion),audioDrivenVersion){if(!function compareVersionCompatibility(version1,version2){const getMajorMinor=version=>{const parts=version.split(".");return parts.length<2?version:`${parts[0]}.${parts[1]}`};return getMajorMinor(version1)===getMajorMinor(version2)}("2.2.1",audioDrivenVersion))throw this.destroy(),new SDKError(exports.ResourceErrorCode.VERSION_INCOMPATIBLE,`资源版本不兼容: SDK版本为 2.2.1,WebGL资源版本为 ${audioDrivenVersion},前两位版本号必须一致`);this.logger.info("版本兼容性检查通过",`SDK: 2.2.1, 资源: ${audioDrivenVersion}`)}this.isInitialized=!0}return result}catch(error){throw new SDKError(exports.OperationErrorCode.OPERATION_FAILED,`数字人初始化失败: ${error instanceof Error?error.message:String(error)}`)}})}updateToken(token){ConfigManager.getInstance().updateConfig({token:token}),this.loader&&this.loader.updateToken(token)}playMotion(clipCode){return __awaiter(this,void 0,void 0,function*(){return this.ensureInitialized(),yield this.avatarService.playMotion(clipCode)})}getCurrentMotion(){return __awaiter(this,arguments,void 0,function*(getRemainingTime=!1){return this.ensureInitialized(),yield this.avatarService.getCurrentMotion(getRemainingTime)})}unloadAvatar(){return __awaiter(this,void 0,void 0,function*(){this.ensureInitialized();try{const result=yield this.avatarService.unloadAvatar();return result.success&&(this.isInitialized=!1),result}catch(error){throw new SDKError(exports.OperationErrorCode.OPERATION_FAILED,`数字人卸载失败: ${error instanceof Error?error.message:String(error)}`)}})}setCamera(cameraType){return __awaiter(this,void 0,void 0,function*(){return this.ensureInitialized(),yield this.avatarService.setCamera(cameraType)})}startBroadcast(params,isAppend){return __awaiter(this,void 0,void 0,function*(){return this.ensureInitialized(),yield this.broadcastService.startBroadcast(params,isAppend)})}startStreamBroadcast(params,forceRestart){return __awaiter(this,void 0,void 0,function*(){this.ensureInitialized();const status=this.broadcastService.getStatus(),isAppend=status.isActive;return this.logger.debug("startStreamBroadcast",{isActive:status.isActive,isAppend:isAppend}),yield this.broadcastService.startBroadcast(params,!forceRestart&&isAppend)})}pauseBroadcast(resetIdle){return __awaiter(this,void 0,void 0,function*(){return this.ensureInitialized(),yield this.broadcastService.pauseBroadcast(resetIdle)})}resumeBroadcast(){return __awaiter(this,void 0,void 0,function*(){return this.ensureInitialized(),yield this.broadcastService.resumeBroadcast()})}stopBroadcast(){return __awaiter(this,void 0,void 0,function*(){return this.ensureInitialized(),yield this.broadcastService.stopBroadcast()})}updateBroadcastCallbacks(callbacks){this.ensureInitialized(),this.broadcastService.updateCallbacks(callbacks)}getBroadcastStatus(){return this.ensureInitialized(),this.broadcastService.getStatus()}destroy(){try{this.broadcastService&&(this.broadcastService.destroy(),this.broadcastService=null),this.avatarService&&(this.avatarService.destroy(),this.avatarService=null),this.loader&&(this.loader.destroy(),this.loader=null),this.unityInstance=null,this.isInitialized=!1}catch(error){console.error("SDK销毁过程中发生错误:",error)}}getInstanceId(){return this.instanceId}isSDKInitialized(){return this.isInitialized}isAvatarInitialized(){return this.isInitialized}getConfig(){const config=ConfigManager.getInstance().getConfig();return config?Object.assign({},config):null}ensureInitialized(){if(!this.isInitialized)throw new SDKError(exports.OperationErrorCode.UNITY_NOT_INITIALIZED,"Avatar尚未初始化,请先调用initializeAvatar()方法")}},exports.getErrorInfo=getErrorInfo});