@zeewain/3d-avatar-sdk 1.2.2 → 1.2.4-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +213 -9
- package/dist/examples/test-vue2/package.json +1 -1
- package/dist/examples/test-vue3/index.html +1 -0
- package/dist/examples/test-vue3/package.json +3 -1
- package/dist/examples/test-vue3/plugins/html.ts +38 -0
- package/dist/examples/test-vue3/pnpm-lock.yaml +291 -90
- package/dist/examples/test-vue3/src/App.vue +4 -2
- package/dist/examples/test-vue3/src/components/BroadcastAPI.vue +38 -20
- package/dist/examples/test-vue3/tsconfig.node.json +2 -1
- package/dist/examples/test-vue3/vite.config.ts +4 -1
- package/dist/index.d.ts +108 -11
- package/dist/index.es5.js +400 -155
- package/dist/index.es5.umd.js +400 -155
- package/dist/index.esm.js +349 -137
- package/dist/index.umd.cjs +349 -137
- package/package.json +1 -1
package/dist/index.umd.cjs
CHANGED
|
@@ -1025,6 +1025,7 @@
|
|
|
1025
1025
|
/**
|
|
1026
1026
|
* 获取指定环境的配置
|
|
1027
1027
|
* @param env - 环境类型,默认为'dev'
|
|
1028
|
+
* @param withApiModule - 是否包含API模块路径
|
|
1028
1029
|
* @returns 返回对应环境的配置对象
|
|
1029
1030
|
* @example
|
|
1030
1031
|
* ```typescript
|
|
@@ -1032,11 +1033,11 @@
|
|
|
1032
1033
|
* console.log(config.apiBaseUrl); // https://aiip.zeewain.com/api/dh-talker
|
|
1033
1034
|
* ```
|
|
1034
1035
|
*/
|
|
1035
|
-
function getEnvConfig(env = 'dev',
|
|
1036
|
+
function getEnvConfig(env = 'dev', withApiModule = true) {
|
|
1036
1037
|
const baseUrl = ENV_MAP[env];
|
|
1037
1038
|
if (baseUrl) {
|
|
1038
1039
|
return {
|
|
1039
|
-
apiBaseUrl: `${baseUrl.apiBaseUrl}${
|
|
1040
|
+
apiBaseUrl: `${baseUrl.apiBaseUrl}${withApiModule ? '/api' : ''}`
|
|
1040
1041
|
};
|
|
1041
1042
|
}
|
|
1042
1043
|
return null;
|
|
@@ -1106,17 +1107,17 @@
|
|
|
1106
1107
|
}
|
|
1107
1108
|
/**
|
|
1108
1109
|
* 获取API基础URL
|
|
1109
|
-
* @param
|
|
1110
|
+
* @param withApiModule 是否包含模块路径
|
|
1110
1111
|
* @returns string API基础URL
|
|
1111
1112
|
* @description 根据当前环境配置获取API基础URL
|
|
1112
1113
|
*/
|
|
1113
|
-
getApiBaseUrl(
|
|
1114
|
+
getApiBaseUrl(withApiModule = true) {
|
|
1114
1115
|
var _a, _b, _c, _d;
|
|
1115
1116
|
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.env) === 'custom' && ((_b = this.config) === null || _b === void 0 ? void 0 : _b.apiUrl)) {
|
|
1116
1117
|
// 如果环境为自定义,则直接返回配置的API,无需添加模块路径
|
|
1117
|
-
return this.config.apiUrl
|
|
1118
|
+
return `${this.config.apiUrl}${withApiModule ? '/api' : ''}`;
|
|
1118
1119
|
}
|
|
1119
|
-
return ((_d = getEnvConfig(((_c = this.config) === null || _c === void 0 ? void 0 : _c.env) || 'prod',
|
|
1120
|
+
return ((_d = getEnvConfig(((_c = this.config) === null || _c === void 0 ? void 0 : _c.env) || 'prod', withApiModule)) === null || _d === void 0 ? void 0 : _d.apiBaseUrl) || '';
|
|
1120
1121
|
}
|
|
1121
1122
|
/**
|
|
1122
1123
|
* 获取自定义API URL
|
|
@@ -1512,6 +1513,20 @@
|
|
|
1512
1513
|
* @fileoverview 流式播报服务重构实现模块
|
|
1513
1514
|
* @description 提供流式播报服务的重构实现,继承Unity基础服务,支持文本转语音和自定义音频播报
|
|
1514
1515
|
*/
|
|
1516
|
+
/**
|
|
1517
|
+
* 播报任务状态枚举
|
|
1518
|
+
*/
|
|
1519
|
+
var BroadcastTaskStatus;
|
|
1520
|
+
(function (BroadcastTaskStatus) {
|
|
1521
|
+
/** 请求中 */
|
|
1522
|
+
BroadcastTaskStatus["REQUESTING"] = "requesting";
|
|
1523
|
+
/** 已完成 */
|
|
1524
|
+
BroadcastTaskStatus["COMPLETED"] = "completed";
|
|
1525
|
+
/** 失败 */
|
|
1526
|
+
BroadcastTaskStatus["FAILED"] = "failed";
|
|
1527
|
+
/** 已取消 */
|
|
1528
|
+
BroadcastTaskStatus["CANCELLED"] = "cancelled";
|
|
1529
|
+
})(BroadcastTaskStatus || (BroadcastTaskStatus = {}));
|
|
1515
1530
|
/**
|
|
1516
1531
|
* 流式播报服务重构类
|
|
1517
1532
|
* @class BroadcastServiceRefactored
|
|
@@ -1541,12 +1556,20 @@
|
|
|
1541
1556
|
super(config);
|
|
1542
1557
|
/** 事件回调函数集合 */
|
|
1543
1558
|
this.callbacks = {};
|
|
1544
|
-
/**
|
|
1545
|
-
this.
|
|
1559
|
+
/** 播报任务队列 */
|
|
1560
|
+
this.taskQueue = [];
|
|
1561
|
+
/** 任务序号计数器 */
|
|
1562
|
+
this.taskSequence = 0;
|
|
1563
|
+
/** 当前发送任务的序号 */
|
|
1564
|
+
this.currentSendingSequence = 0;
|
|
1546
1565
|
/** 是否正在生成音频 */
|
|
1547
1566
|
this.isGeneratingAudio = false;
|
|
1548
1567
|
/** 是否已经收到音频 */
|
|
1549
1568
|
this.hasReceivedAudio = false;
|
|
1569
|
+
/** 队列处理定时器 */
|
|
1570
|
+
this.queueProcessTimer = null;
|
|
1571
|
+
/** 主请求控制器(兼容性保留) */
|
|
1572
|
+
this.activeController = null;
|
|
1550
1573
|
this.callbacks = config.callbacks || {};
|
|
1551
1574
|
this.logger.info('Broadcast service initialized', { config });
|
|
1552
1575
|
}
|
|
@@ -1595,8 +1618,9 @@
|
|
|
1595
1618
|
/**
|
|
1596
1619
|
* 开始播报
|
|
1597
1620
|
* @param params - 播报参数
|
|
1621
|
+
* @param isAppend - 是否追加播报
|
|
1598
1622
|
* @returns Promise<void> 播报操作的Promise
|
|
1599
|
-
* @description
|
|
1623
|
+
* @description 开始流式播报,支持文本转语音和自定义音频播报。使用队列机制确保音频按序播报
|
|
1600
1624
|
* @throws {SDKError} 当参数验证失败或播报失败时抛出错误
|
|
1601
1625
|
* @example
|
|
1602
1626
|
* ```typescript
|
|
@@ -1610,130 +1634,54 @@
|
|
|
1610
1634
|
* isSubtitle: true
|
|
1611
1635
|
* });
|
|
1612
1636
|
*
|
|
1613
|
-
* //
|
|
1637
|
+
* // 追加播报(会进入队列按序播报)
|
|
1614
1638
|
* await broadcastService.startBroadcast({
|
|
1615
|
-
* type: BroadcastType.
|
|
1639
|
+
* type: BroadcastType.TEXT,
|
|
1616
1640
|
* humanCode: 'human001',
|
|
1617
|
-
*
|
|
1641
|
+
* text: '这是第二段内容',
|
|
1642
|
+
* voiceCode: 'voice001',
|
|
1618
1643
|
* volume: 0.8,
|
|
1619
|
-
* isSubtitle:
|
|
1620
|
-
* });
|
|
1644
|
+
* isSubtitle: true
|
|
1645
|
+
* }, true);
|
|
1621
1646
|
* ```
|
|
1622
1647
|
*/
|
|
1623
|
-
startBroadcast(params) {
|
|
1648
|
+
startBroadcast(params, isAppend) {
|
|
1624
1649
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1625
1650
|
var _a, _b;
|
|
1626
|
-
this.logger.info(`Starting broadcast: ${params.type}`, {
|
|
1651
|
+
this.logger.info(`Starting broadcast: ${params.type}`, {
|
|
1652
|
+
humanCode: params.humanCode,
|
|
1653
|
+
isAppend,
|
|
1654
|
+
queueLength: this.taskQueue.length
|
|
1655
|
+
});
|
|
1627
1656
|
// 验证参数
|
|
1628
1657
|
this.validateBroadcastParams(params);
|
|
1629
|
-
//
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
this.hasReceivedAudio = false;
|
|
1644
|
-
this.activeController = null;
|
|
1645
|
-
});
|
|
1646
|
-
// 通知Unity开始新任务(清空队列)
|
|
1647
|
-
this.sendMessage('StartBroadcast', {
|
|
1648
|
-
callbackFun: this.uniqueCallbackName,
|
|
1649
|
-
operationType: exports.BroadcastOperationType.START_BROADCAST,
|
|
1650
|
-
motionList: params.motionList,
|
|
1651
|
-
motionPlayMode: params.motionPlayMode
|
|
1652
|
-
});
|
|
1653
|
-
try {
|
|
1654
|
-
const apiUrl = `${ConfigManager.getInstance().getApiBaseUrl(true)}${this.getBroadcastApiPath(params.type)}`;
|
|
1655
|
-
const requestBody = {
|
|
1656
|
-
humanCode: params.humanCode,
|
|
1657
|
-
speed: params.speed,
|
|
1658
|
-
volume: params.volume >= 0 ? params.volume * 100 : undefined, // 转换为百分比
|
|
1659
|
-
isSubtitle: params.isSubtitle
|
|
1660
|
-
};
|
|
1661
|
-
// 根据播报类型设置特定参数
|
|
1662
|
-
if (params.type === exports.BroadcastType.TEXT) {
|
|
1663
|
-
requestBody.text = params.text;
|
|
1664
|
-
requestBody.voiceCode = params.voiceCode;
|
|
1665
|
-
}
|
|
1666
|
-
else if (params.type === exports.BroadcastType.AUDIO) {
|
|
1667
|
-
requestBody.text = params.text;
|
|
1668
|
-
requestBody.audioUrl = params.audioUrl;
|
|
1669
|
-
}
|
|
1670
|
-
this.logger.debug('Sending broadcast request', { apiUrl, requestBody });
|
|
1658
|
+
// 非追加模式下需要初始化播报
|
|
1659
|
+
if (!isAppend) {
|
|
1660
|
+
// 先停止当前播报并清空队列
|
|
1661
|
+
yield this.stopBroadcast();
|
|
1662
|
+
// 重置序号计数器
|
|
1663
|
+
this.taskSequence = 0;
|
|
1664
|
+
this.currentSendingSequence = 0;
|
|
1665
|
+
// 通知Unity开始新任务(清空队列)
|
|
1666
|
+
this.sendMessage('StartBroadcast', {
|
|
1667
|
+
callbackFun: this.uniqueCallbackName,
|
|
1668
|
+
operationType: exports.BroadcastOperationType.START_BROADCAST,
|
|
1669
|
+
motionList: params.motionList,
|
|
1670
|
+
motionPlayMode: params.motionPlayMode
|
|
1671
|
+
});
|
|
1671
1672
|
// 触发开始回调
|
|
1672
1673
|
(_b = (_a = this.callbacks).onStart) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
1673
1674
|
this.isGeneratingAudio = true;
|
|
1674
|
-
// 发起流式播报请求
|
|
1675
|
-
yield fetchEventSource(apiUrl, {
|
|
1676
|
-
method: 'POST',
|
|
1677
|
-
headers: {
|
|
1678
|
-
'Content-Type': 'application/json',
|
|
1679
|
-
'x_auth_token': ConfigManager.getInstance().getToken()
|
|
1680
|
-
},
|
|
1681
|
-
body: JSON.stringify(requestBody),
|
|
1682
|
-
signal: this.activeController.signal,
|
|
1683
|
-
openWhenHidden: true,
|
|
1684
|
-
onmessage: (event) => {
|
|
1685
|
-
const response = JSON.parse(event.data);
|
|
1686
|
-
// 错误处理
|
|
1687
|
-
if (response.code !== 0) {
|
|
1688
|
-
this.handleBroadcastError(response.code);
|
|
1689
|
-
return;
|
|
1690
|
-
}
|
|
1691
|
-
// 流式播报
|
|
1692
|
-
if (response.data) {
|
|
1693
|
-
// 未完成播报时,更新任务ID
|
|
1694
|
-
if (!response.data.done) {
|
|
1695
|
-
this.hasReceivedAudio = true;
|
|
1696
|
-
}
|
|
1697
|
-
// 自定义音频播报时,如果服务器未返回音频URL,使用传入的audioUrl
|
|
1698
|
-
if (params.type === exports.BroadcastType.AUDIO && params.audioUrl && !response.data.voiceUrl) {
|
|
1699
|
-
response.data.voiceUrl = params.audioUrl;
|
|
1700
|
-
}
|
|
1701
|
-
// 如果有音频URL,发送到Unity
|
|
1702
|
-
if (response.data.voiceUrl) {
|
|
1703
|
-
this.sendMessage('AppendBroadcast', {
|
|
1704
|
-
response,
|
|
1705
|
-
callbackFun: this.uniqueCallbackName,
|
|
1706
|
-
operationType: exports.BroadcastOperationType.APPEND_BROADCAST
|
|
1707
|
-
});
|
|
1708
|
-
}
|
|
1709
|
-
if (response.data.done) {
|
|
1710
|
-
this.isGeneratingAudio = false;
|
|
1711
|
-
this.hasReceivedAudio = false;
|
|
1712
|
-
this.activeController = null;
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
|
-
},
|
|
1716
|
-
onclose: () => {
|
|
1717
|
-
var _a;
|
|
1718
|
-
// 如果不是由abort触发的关闭,需要处理
|
|
1719
|
-
if (this.isGeneratingAudio) {
|
|
1720
|
-
(_a = this.activeController) === null || _a === void 0 ? void 0 : _a.abort();
|
|
1721
|
-
}
|
|
1722
|
-
// 流结束时调用完成回调
|
|
1723
|
-
this.logger.debug('Broadcast stream closed');
|
|
1724
|
-
},
|
|
1725
|
-
onerror: (error) => {
|
|
1726
|
-
this.logger.error('Broadcast stream error', error);
|
|
1727
|
-
const sdkError = new SDKError(exports.OperationErrorCode.OPERATION_FAILED, '服务出错了', error);
|
|
1728
|
-
this.handleError(sdkError);
|
|
1729
|
-
// 必须抛出错误,否则会循环重试请求
|
|
1730
|
-
throw new Error(`服务出错了${sdkError.message}`);
|
|
1731
|
-
}
|
|
1732
|
-
});
|
|
1733
|
-
}
|
|
1734
|
-
catch (error) {
|
|
1735
|
-
this.handleError(error);
|
|
1736
1675
|
}
|
|
1676
|
+
// 创建新的播报任务
|
|
1677
|
+
const task = this.createBroadcastTask(params);
|
|
1678
|
+
// 添加任务到队列
|
|
1679
|
+
this.addTaskToQueue(task);
|
|
1680
|
+
this.logger.debug('Broadcast task created and queued', {
|
|
1681
|
+
taskId: task.id,
|
|
1682
|
+
sequence: task.sequence,
|
|
1683
|
+
isAppend
|
|
1684
|
+
});
|
|
1737
1685
|
});
|
|
1738
1686
|
}
|
|
1739
1687
|
/**
|
|
@@ -1794,12 +1742,12 @@
|
|
|
1794
1742
|
*/
|
|
1795
1743
|
stopBroadcast() {
|
|
1796
1744
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1797
|
-
this.logger.info('Stopping broadcast');
|
|
1798
|
-
//
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1745
|
+
this.logger.info('Stopping broadcast and clearing queue', { queueLength: this.taskQueue.length });
|
|
1746
|
+
// 取消所有队列中的任务
|
|
1747
|
+
this.cancelAllTasks();
|
|
1748
|
+
// 重置状态
|
|
1749
|
+
this.isGeneratingAudio = false;
|
|
1750
|
+
this.hasReceivedAudio = false;
|
|
1803
1751
|
try {
|
|
1804
1752
|
yield this.sendAsyncMessage('StopBroadcast', exports.BroadcastOperationType.STOP_BROADCAST, {});
|
|
1805
1753
|
this.logger.info('Broadcast stopped successfully');
|
|
@@ -1822,15 +1770,23 @@
|
|
|
1822
1770
|
/**
|
|
1823
1771
|
* 获取播报状态
|
|
1824
1772
|
* @returns 播报状态信息
|
|
1825
|
-
* @description
|
|
1773
|
+
* @description 获取当前播报服务的状态信息,包括队列状态
|
|
1826
1774
|
*/
|
|
1827
1775
|
getStatus() {
|
|
1828
1776
|
return {
|
|
1829
|
-
isActive: this.
|
|
1777
|
+
isActive: this.taskQueue.length > 0 || this.isGeneratingAudio,
|
|
1830
1778
|
isGeneratingAudio: this.isGeneratingAudio,
|
|
1831
1779
|
hasReceivedAudio: this.hasReceivedAudio,
|
|
1832
1780
|
pendingCallbacks: this.getPendingCallbackCount(),
|
|
1833
|
-
hasController: this.activeController !== null
|
|
1781
|
+
hasController: this.activeController !== null,
|
|
1782
|
+
queueInfo: {
|
|
1783
|
+
totalTasks: this.taskQueue.length,
|
|
1784
|
+
requestingTasks: this.taskQueue.filter((t) => t.status === BroadcastTaskStatus.REQUESTING).length,
|
|
1785
|
+
completedTasks: this.taskQueue.filter((t) => t.status === BroadcastTaskStatus.COMPLETED).length,
|
|
1786
|
+
failedTasks: this.taskQueue.filter((t) => t.status === BroadcastTaskStatus.FAILED).length,
|
|
1787
|
+
totalPendingResponses: this.taskQueue.reduce((sum, t) => sum + t.pendingResponses.length, 0),
|
|
1788
|
+
currentSendingSequence: this.currentSendingSequence
|
|
1789
|
+
}
|
|
1834
1790
|
};
|
|
1835
1791
|
}
|
|
1836
1792
|
/**
|
|
@@ -1838,15 +1794,268 @@
|
|
|
1838
1794
|
* @description 清理所有资源和回调
|
|
1839
1795
|
*/
|
|
1840
1796
|
destroy() {
|
|
1841
|
-
//
|
|
1842
|
-
if (this.
|
|
1843
|
-
this.
|
|
1844
|
-
this.
|
|
1797
|
+
// 清理队列处理定时器
|
|
1798
|
+
if (this.queueProcessTimer) {
|
|
1799
|
+
clearInterval(this.queueProcessTimer);
|
|
1800
|
+
this.queueProcessTimer = null;
|
|
1845
1801
|
}
|
|
1802
|
+
// 取消所有任务
|
|
1803
|
+
this.cancelAllTasks();
|
|
1846
1804
|
// 调用基类销毁方法
|
|
1847
1805
|
super.destroy();
|
|
1848
1806
|
this.logger.info('Broadcast service destroyed');
|
|
1849
1807
|
}
|
|
1808
|
+
/**
|
|
1809
|
+
* 创建播报任务
|
|
1810
|
+
* @param params - 播报参数
|
|
1811
|
+
* @returns IBroadcastTask 播报任务对象
|
|
1812
|
+
* @description 创建新的播报任务并分配唯一ID和序号
|
|
1813
|
+
* @private
|
|
1814
|
+
*/
|
|
1815
|
+
createBroadcastTask(params) {
|
|
1816
|
+
const task = {
|
|
1817
|
+
id: `broadcast_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
|
|
1818
|
+
sequence: ++this.taskSequence,
|
|
1819
|
+
params,
|
|
1820
|
+
status: BroadcastTaskStatus.REQUESTING,
|
|
1821
|
+
controller: new AbortController(),
|
|
1822
|
+
pendingResponses: [],
|
|
1823
|
+
isGenerationComplete: false,
|
|
1824
|
+
createdAt: new Date()
|
|
1825
|
+
};
|
|
1826
|
+
this.logger.debug('Created broadcast task', { taskId: task.id, sequence: task.sequence });
|
|
1827
|
+
return task;
|
|
1828
|
+
}
|
|
1829
|
+
/**
|
|
1830
|
+
* 添加任务到队列
|
|
1831
|
+
* @param task - 播报任务
|
|
1832
|
+
* @description 将任务添加到队列并立即开始请求
|
|
1833
|
+
* @private
|
|
1834
|
+
*/
|
|
1835
|
+
addTaskToQueue(task) {
|
|
1836
|
+
this.taskQueue.push(task);
|
|
1837
|
+
this.logger.debug('Task added to queue', { taskId: task.id, queueLength: this.taskQueue.length });
|
|
1838
|
+
// 立即开始该任务的请求
|
|
1839
|
+
this.startTaskRequest(task);
|
|
1840
|
+
// 开始处理队列
|
|
1841
|
+
this.processQueue();
|
|
1842
|
+
}
|
|
1843
|
+
/**
|
|
1844
|
+
* 处理队列
|
|
1845
|
+
* @description 处理队列中的任务,发起请求生成音频
|
|
1846
|
+
* @private
|
|
1847
|
+
*/
|
|
1848
|
+
processQueue() {
|
|
1849
|
+
// 启动队列处理定时器(如果尚未启动)
|
|
1850
|
+
if (!this.queueProcessTimer) {
|
|
1851
|
+
this.queueProcessTimer = setInterval(() => {
|
|
1852
|
+
this.processQueueStep();
|
|
1853
|
+
}, 100); // 每100ms检查一次队列状态
|
|
1854
|
+
}
|
|
1855
|
+
// 立即处理一次
|
|
1856
|
+
this.processQueueStep();
|
|
1857
|
+
}
|
|
1858
|
+
/**
|
|
1859
|
+
* 队列处理步骤
|
|
1860
|
+
* @description 处理队列中的单个步骤,包括发起请求和发送音频
|
|
1861
|
+
* @private
|
|
1862
|
+
*/
|
|
1863
|
+
processQueueStep() {
|
|
1864
|
+
// 按序号找到下一个要处理的任务
|
|
1865
|
+
const nextTask = this.taskQueue.find((task) => task.sequence === this.currentSendingSequence + 1
|
|
1866
|
+
&& task.pendingResponses.length > 0);
|
|
1867
|
+
if (nextTask) {
|
|
1868
|
+
this.sendNextResponse(nextTask);
|
|
1869
|
+
}
|
|
1870
|
+
// 清理已完成的任务
|
|
1871
|
+
this.cleanupCompletedTasks();
|
|
1872
|
+
// 如果队列为空,停止定时器
|
|
1873
|
+
if (this.taskQueue.length === 0 && this.queueProcessTimer) {
|
|
1874
|
+
clearInterval(this.queueProcessTimer);
|
|
1875
|
+
this.queueProcessTimer = null;
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
/**
|
|
1879
|
+
* 开始任务请求
|
|
1880
|
+
* @param task - 播报任务
|
|
1881
|
+
* @description 为任务发起流式请求生成音频
|
|
1882
|
+
* @private
|
|
1883
|
+
*/
|
|
1884
|
+
startTaskRequest(task) {
|
|
1885
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1886
|
+
task.status = BroadcastTaskStatus.REQUESTING;
|
|
1887
|
+
this.logger.debug('Starting task request', { taskId: task.id });
|
|
1888
|
+
try {
|
|
1889
|
+
const apiUrl = `${ConfigManager.getInstance().getApiBaseUrl(true)}${this.getBroadcastApiPath(task.params.type)}`;
|
|
1890
|
+
const requestBody = {
|
|
1891
|
+
humanCode: task.params.humanCode,
|
|
1892
|
+
speed: task.params.speed,
|
|
1893
|
+
volume: task.params.volume >= 0 ? task.params.volume * 100 : undefined,
|
|
1894
|
+
isSubtitle: task.params.isSubtitle
|
|
1895
|
+
};
|
|
1896
|
+
// 根据播报类型设置特定参数
|
|
1897
|
+
if (task.params.type === exports.BroadcastType.TEXT) {
|
|
1898
|
+
requestBody.text = task.params.text;
|
|
1899
|
+
requestBody.voiceCode = task.params.voiceCode;
|
|
1900
|
+
}
|
|
1901
|
+
else if (task.params.type === exports.BroadcastType.AUDIO) {
|
|
1902
|
+
requestBody.text = task.params.text;
|
|
1903
|
+
requestBody.audioUrl = task.params.audioUrl;
|
|
1904
|
+
}
|
|
1905
|
+
// 发起流式请求
|
|
1906
|
+
fetchEventSource(apiUrl, {
|
|
1907
|
+
method: 'POST',
|
|
1908
|
+
headers: {
|
|
1909
|
+
'Content-Type': 'application/json',
|
|
1910
|
+
'x_auth_token': ConfigManager.getInstance().getToken()
|
|
1911
|
+
},
|
|
1912
|
+
body: JSON.stringify(requestBody),
|
|
1913
|
+
signal: task.controller.signal,
|
|
1914
|
+
openWhenHidden: true,
|
|
1915
|
+
onmessage: (event) => {
|
|
1916
|
+
this.handleTaskResponse(task, event.data);
|
|
1917
|
+
},
|
|
1918
|
+
onclose: () => {
|
|
1919
|
+
this.handleTaskClose(task);
|
|
1920
|
+
},
|
|
1921
|
+
onerror: (error) => {
|
|
1922
|
+
this.handleTaskError(task, error);
|
|
1923
|
+
throw new Error(`Task ${task.id} request failed: ${error}`);
|
|
1924
|
+
}
|
|
1925
|
+
});
|
|
1926
|
+
}
|
|
1927
|
+
catch (error) {
|
|
1928
|
+
this.handleTaskError(task, error);
|
|
1929
|
+
}
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
/**
|
|
1933
|
+
* 处理任务响应
|
|
1934
|
+
* @param task - 播报任务
|
|
1935
|
+
* @param data - 响应数据
|
|
1936
|
+
* @description 处理任务的流式响应数据
|
|
1937
|
+
* @private
|
|
1938
|
+
*/
|
|
1939
|
+
handleTaskResponse(task, data) {
|
|
1940
|
+
try {
|
|
1941
|
+
const response = JSON.parse(data);
|
|
1942
|
+
// 错误处理
|
|
1943
|
+
if (response.code !== 0) {
|
|
1944
|
+
this.handleBroadcastError(response.code);
|
|
1945
|
+
return;
|
|
1946
|
+
}
|
|
1947
|
+
// 处理音频数据
|
|
1948
|
+
if (response.data && response.data.voiceUrl) {
|
|
1949
|
+
// 自定义音频播报时,如果服务器未返回音频URL,使用传入的audioUrl
|
|
1950
|
+
if (task.params.type === exports.BroadcastType.AUDIO && task.params.audioUrl && !response.data.voiceUrl) {
|
|
1951
|
+
response.data.voiceUrl = task.params.audioUrl;
|
|
1952
|
+
}
|
|
1953
|
+
// 添加处理后的响应对象到待发送队列
|
|
1954
|
+
task.pendingResponses.push(response);
|
|
1955
|
+
this.logger.debug('Response added to task', { taskId: task.id, pendingCount: task.pendingResponses.length });
|
|
1956
|
+
}
|
|
1957
|
+
// 检查是否完成
|
|
1958
|
+
if (response.data && response.data.done) {
|
|
1959
|
+
task.isGenerationComplete = true;
|
|
1960
|
+
this.logger.debug('Task generation completed', { taskId: task.id, totalResponses: task.pendingResponses.length });
|
|
1961
|
+
// 任务完成生成,保持REQUESTING状态直到所有响应发送完毕
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
catch (error) {
|
|
1965
|
+
this.handleTaskError(task, error);
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
/**
|
|
1969
|
+
* 发送下一个响应
|
|
1970
|
+
* @param task - 播报任务
|
|
1971
|
+
* @description 发送任务中的第一个待发送响应到Unity,发送后立即删除
|
|
1972
|
+
* @private
|
|
1973
|
+
*/
|
|
1974
|
+
sendNextResponse(task) {
|
|
1975
|
+
var _a;
|
|
1976
|
+
if (task.pendingResponses.length === 0) {
|
|
1977
|
+
return;
|
|
1978
|
+
}
|
|
1979
|
+
// 取出第一个待发送的响应
|
|
1980
|
+
const response = task.pendingResponses.shift();
|
|
1981
|
+
this.logger.debug('Sending response to Unity', {
|
|
1982
|
+
taskId: task.id,
|
|
1983
|
+
remainingResponses: task.pendingResponses.length,
|
|
1984
|
+
voiceUrl: (_a = response.data) === null || _a === void 0 ? void 0 : _a.voiceUrl
|
|
1985
|
+
});
|
|
1986
|
+
// 发送响应到Unity
|
|
1987
|
+
this.sendMessage('AppendBroadcast', {
|
|
1988
|
+
response,
|
|
1989
|
+
callbackFun: this.uniqueCallbackName,
|
|
1990
|
+
operationType: exports.BroadcastOperationType.APPEND_BROADCAST
|
|
1991
|
+
});
|
|
1992
|
+
// 如果任务已完成且没有更多待发送响应,标记任务完成并推进序号
|
|
1993
|
+
if (task.isGenerationComplete && task.pendingResponses.length === 0) {
|
|
1994
|
+
task.status = BroadcastTaskStatus.COMPLETED;
|
|
1995
|
+
this.currentSendingSequence = task.sequence;
|
|
1996
|
+
this.logger.debug('Task completed', { taskId: task.id });
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
/**
|
|
2000
|
+
* 处理任务关闭
|
|
2001
|
+
* @param task - 播报任务
|
|
2002
|
+
* @description 处理任务的流式连接关闭
|
|
2003
|
+
* @private
|
|
2004
|
+
*/
|
|
2005
|
+
handleTaskClose(task) {
|
|
2006
|
+
this.logger.debug('Task stream closed', { taskId: task.id });
|
|
2007
|
+
// 如果还没有标记为完成,则标记为完成
|
|
2008
|
+
if (!task.isGenerationComplete && task.status === BroadcastTaskStatus.REQUESTING) {
|
|
2009
|
+
task.isGenerationComplete = true;
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
/**
|
|
2013
|
+
* 处理任务错误
|
|
2014
|
+
* @param task - 播报任务
|
|
2015
|
+
* @param error - 错误对象
|
|
2016
|
+
* @description 处理任务执行过程中的错误
|
|
2017
|
+
* @private
|
|
2018
|
+
*/
|
|
2019
|
+
handleTaskError(task, error) {
|
|
2020
|
+
var _a, _b;
|
|
2021
|
+
task.status = BroadcastTaskStatus.FAILED;
|
|
2022
|
+
task.error = error;
|
|
2023
|
+
this.logger.error(`Task failed - ${task.id}`, error);
|
|
2024
|
+
// 触发错误回调
|
|
2025
|
+
(_b = (_a = this.callbacks).onError) === null || _b === void 0 ? void 0 : _b.call(_a, error);
|
|
2026
|
+
}
|
|
2027
|
+
/**
|
|
2028
|
+
* 清理已完成的任务
|
|
2029
|
+
* @description 从队列中移除已完成、失败或取消的任务
|
|
2030
|
+
* @private
|
|
2031
|
+
*/
|
|
2032
|
+
cleanupCompletedTasks() {
|
|
2033
|
+
const beforeLength = this.taskQueue.length;
|
|
2034
|
+
this.taskQueue = this.taskQueue.filter(task => task.status !== BroadcastTaskStatus.COMPLETED
|
|
2035
|
+
&& task.status !== BroadcastTaskStatus.FAILED
|
|
2036
|
+
&& task.status !== BroadcastTaskStatus.CANCELLED);
|
|
2037
|
+
const removedCount = beforeLength - this.taskQueue.length;
|
|
2038
|
+
if (removedCount > 0) {
|
|
2039
|
+
this.logger.debug('Cleaned up completed tasks', { removedCount, remainingTasks: this.taskQueue.length });
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
/**
|
|
2043
|
+
* 取消所有任务
|
|
2044
|
+
* @description 取消队列中的所有任务
|
|
2045
|
+
* @private
|
|
2046
|
+
*/
|
|
2047
|
+
cancelAllTasks() {
|
|
2048
|
+
for (const task of this.taskQueue) {
|
|
2049
|
+
if (task.status !== BroadcastTaskStatus.COMPLETED && task.status !== BroadcastTaskStatus.FAILED) {
|
|
2050
|
+
task.controller.abort();
|
|
2051
|
+
task.status = BroadcastTaskStatus.CANCELLED;
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
this.taskQueue = [];
|
|
2055
|
+
this.taskSequence = 0;
|
|
2056
|
+
this.currentSendingSequence = 0;
|
|
2057
|
+
this.logger.debug('All tasks cancelled and queue cleared');
|
|
2058
|
+
}
|
|
1850
2059
|
/** 全局回调函数名称 */
|
|
1851
2060
|
get callbackFunctionName() {
|
|
1852
2061
|
return 'uniBroadcastCallback';
|
|
@@ -2135,13 +2344,15 @@
|
|
|
2135
2344
|
// 4. 创建带有唯一标识符的Avatar服务
|
|
2136
2345
|
this.avatarService = new AvatarService({
|
|
2137
2346
|
unityInstance: this.unityInstance,
|
|
2138
|
-
instanceId: this.instanceId
|
|
2347
|
+
instanceId: this.instanceId,
|
|
2348
|
+
enableDebugLog: this.config.enableDebugLog
|
|
2139
2349
|
});
|
|
2140
2350
|
// 5. 创建带有唯一标识符的播报服务
|
|
2141
2351
|
this.broadcastService = new BroadcastService({
|
|
2142
2352
|
unityInstance: this.unityInstance,
|
|
2143
2353
|
instanceId: this.instanceId,
|
|
2144
|
-
callbacks: this.config.broadcastCallbacks
|
|
2354
|
+
callbacks: this.config.broadcastCallbacks,
|
|
2355
|
+
enableDebugLog: this.config.enableDebugLog
|
|
2145
2356
|
});
|
|
2146
2357
|
// 6. 初始化数字人
|
|
2147
2358
|
const result = yield this.avatarService.initializeAvatar(avatarCode, cameraType);
|
|
@@ -2229,12 +2440,13 @@
|
|
|
2229
2440
|
/**
|
|
2230
2441
|
* 开始播报
|
|
2231
2442
|
* @param params 播报参数
|
|
2443
|
+
* @param isAppend 是否追加播报
|
|
2232
2444
|
* @returns Promise<void> 播报操作的Promise
|
|
2233
2445
|
*/
|
|
2234
|
-
startBroadcast(params) {
|
|
2446
|
+
startBroadcast(params, isAppend) {
|
|
2235
2447
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2236
2448
|
this.ensureInitialized();
|
|
2237
|
-
return yield this.broadcastService.startBroadcast(params);
|
|
2449
|
+
return yield this.broadcastService.startBroadcast(params, isAppend);
|
|
2238
2450
|
});
|
|
2239
2451
|
}
|
|
2240
2452
|
/**
|