@mingxy/ocosay 1.0.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 +556 -0
- package/TECH_PLAN.md +352 -0
- package/__mocks__/@opencode-ai/plugin.ts +32 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +95 -0
- package/dist/config.js.map +1 -0
- package/dist/core/backends/afplay-backend.d.ts +33 -0
- package/dist/core/backends/afplay-backend.d.ts.map +1 -0
- package/dist/core/backends/afplay-backend.js +144 -0
- package/dist/core/backends/afplay-backend.js.map +1 -0
- package/dist/core/backends/aplay-backend.d.ts +33 -0
- package/dist/core/backends/aplay-backend.d.ts.map +1 -0
- package/dist/core/backends/aplay-backend.js +142 -0
- package/dist/core/backends/aplay-backend.js.map +1 -0
- package/dist/core/backends/base.d.ts +94 -0
- package/dist/core/backends/base.d.ts.map +1 -0
- package/dist/core/backends/base.js +6 -0
- package/dist/core/backends/base.js.map +1 -0
- package/dist/core/backends/index.d.ts +29 -0
- package/dist/core/backends/index.d.ts.map +1 -0
- package/dist/core/backends/index.js +114 -0
- package/dist/core/backends/index.js.map +1 -0
- package/dist/core/backends/naudiodon-backend.d.ts +52 -0
- package/dist/core/backends/naudiodon-backend.d.ts.map +1 -0
- package/dist/core/backends/naudiodon-backend.js +123 -0
- package/dist/core/backends/naudiodon-backend.js.map +1 -0
- package/dist/core/backends/powershell-backend.d.ts +34 -0
- package/dist/core/backends/powershell-backend.d.ts.map +1 -0
- package/dist/core/backends/powershell-backend.js +154 -0
- package/dist/core/backends/powershell-backend.js.map +1 -0
- package/dist/core/player.d.ts +97 -0
- package/dist/core/player.d.ts.map +1 -0
- package/dist/core/player.js +268 -0
- package/dist/core/player.js.map +1 -0
- package/dist/core/speaker.d.ts +97 -0
- package/dist/core/speaker.d.ts.map +1 -0
- package/dist/core/speaker.js +218 -0
- package/dist/core/speaker.js.map +1 -0
- package/dist/core/stream-player.d.ts +107 -0
- package/dist/core/stream-player.d.ts.map +1 -0
- package/dist/core/stream-player.js +272 -0
- package/dist/core/stream-player.js.map +1 -0
- package/dist/core/stream-reader.d.ts +86 -0
- package/dist/core/stream-reader.d.ts.map +1 -0
- package/dist/core/stream-reader.js +172 -0
- package/dist/core/stream-reader.js.map +1 -0
- package/dist/core/streaming-synthesizer.d.ts +51 -0
- package/dist/core/streaming-synthesizer.d.ts.map +1 -0
- package/dist/core/streaming-synthesizer.js +103 -0
- package/dist/core/streaming-synthesizer.js.map +1 -0
- package/dist/core/types.d.ts +141 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +37 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +179 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +151 -0
- package/dist/plugin.js.map +1 -0
- package/dist/providers/base.d.ts +55 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +95 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/minimax.d.ts +84 -0
- package/dist/providers/minimax.d.ts.map +1 -0
- package/dist/providers/minimax.js +387 -0
- package/dist/providers/minimax.js.map +1 -0
- package/dist/tools/tts.d.ts +147 -0
- package/dist/tools/tts.d.ts.map +1 -0
- package/dist/tools/tts.js +232 -0
- package/dist/tools/tts.js.map +1 -0
- package/jest.config.js +15 -0
- package/package.json +49 -0
- package/src/config.ts +121 -0
- package/src/core/backends/afplay-backend.ts +162 -0
- package/src/core/backends/aplay-backend.ts +160 -0
- package/src/core/backends/base.ts +117 -0
- package/src/core/backends/index.ts +128 -0
- package/src/core/backends/naudiodon-backend.ts +164 -0
- package/src/core/backends/powershell-backend.ts +173 -0
- package/src/core/player.ts +322 -0
- package/src/core/speaker.ts +283 -0
- package/src/core/stream-player.ts +326 -0
- package/src/core/stream-reader.ts +190 -0
- package/src/core/streaming-synthesizer.ts +123 -0
- package/src/core/types.ts +185 -0
- package/src/index.ts +233 -0
- package/src/plugin.ts +166 -0
- package/src/providers/base.ts +150 -0
- package/src/providers/minimax.ts +515 -0
- package/src/tools/tts.ts +277 -0
- package/src/types/naudiodon.d.ts +19 -0
- package/tests/__mocks__/@opencode-ai/plugin.ts +32 -0
- package/tests/backends.test.ts +831 -0
- package/tests/index.test.ts +201 -0
- package/tests/integration-test.d.ts +6 -0
- package/tests/integration-test.d.ts.map +1 -0
- package/tests/integration-test.js +84 -0
- package/tests/integration-test.js.map +1 -0
- package/tests/integration-test.ts +93 -0
- package/tests/p1-fixes.test.ts +160 -0
- package/tests/plugin.test.ts +311 -0
- package/tests/provider.test.d.ts +2 -0
- package/tests/provider.test.d.ts.map +1 -0
- package/tests/provider.test.js +69 -0
- package/tests/provider.test.js.map +1 -0
- package/tests/provider.test.ts +87 -0
- package/tests/speaker.test.d.ts +2 -0
- package/tests/speaker.test.d.ts.map +1 -0
- package/tests/speaker.test.js +63 -0
- package/tests/speaker.test.js.map +1 -0
- package/tests/speaker.test.ts +232 -0
- package/tests/stream-player.test.ts +303 -0
- package/tests/stream-reader.test.ts +269 -0
- package/tests/streaming-synthesizer.test.ts +225 -0
- package/tests/tts-tools.test.ts +270 -0
- package/tests/types.test.d.ts +2 -0
- package/tests/types.test.d.ts.map +1 -0
- package/tests/types.test.js +61 -0
- package/tests/types.test.js.map +1 -0
- package/tests/types.test.ts +63 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StreamReader - 流式文本缓冲与句子边界检测
|
|
3
|
+
*
|
|
4
|
+
* 功能:
|
|
5
|
+
* - 订阅 TuiEventBus 的 message.part.delta 事件
|
|
6
|
+
* - 缓冲区满或遇到句子结束符时触发 textReady 事件
|
|
7
|
+
* - 支持超时强制发送
|
|
8
|
+
*/
|
|
9
|
+
import { EventEmitter } from 'events';
|
|
10
|
+
import { StreamState, TTSError } from './types';
|
|
11
|
+
export declare class StreamReader extends EventEmitter {
|
|
12
|
+
private bufferSize;
|
|
13
|
+
private bufferTimeout;
|
|
14
|
+
private state;
|
|
15
|
+
private buffer;
|
|
16
|
+
private sessionID?;
|
|
17
|
+
private messageID?;
|
|
18
|
+
private partID?;
|
|
19
|
+
private timeoutHandle?;
|
|
20
|
+
constructor(bufferSize?: number, bufferTimeout?: number);
|
|
21
|
+
/**
|
|
22
|
+
* 启动流式监听
|
|
23
|
+
* 将状态从 IDLE 切换到 BUFFERING,开始监听事件
|
|
24
|
+
*/
|
|
25
|
+
start(): void;
|
|
26
|
+
/**
|
|
27
|
+
* 处理 message.part.delta 事件
|
|
28
|
+
*/
|
|
29
|
+
handleDelta(sessionID: string, messageID: string, partID: string, delta: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* 处理流结束
|
|
32
|
+
*/
|
|
33
|
+
handleEnd(): void;
|
|
34
|
+
/**
|
|
35
|
+
* 处理错误
|
|
36
|
+
*/
|
|
37
|
+
handleError(error: TTSError): void;
|
|
38
|
+
/**
|
|
39
|
+
* 重置缓冲器
|
|
40
|
+
*/
|
|
41
|
+
reset(): void;
|
|
42
|
+
/**
|
|
43
|
+
* 判断是否应该刷新缓冲区
|
|
44
|
+
* 条件:
|
|
45
|
+
* 1. 包含句子结束符(任何长度)
|
|
46
|
+
* 2. 缓冲区长度 >= bufferSize
|
|
47
|
+
*/
|
|
48
|
+
private shouldFlush;
|
|
49
|
+
/**
|
|
50
|
+
* 刷新缓冲区,发送textReady事件
|
|
51
|
+
*/
|
|
52
|
+
private flushBuffer;
|
|
53
|
+
/**
|
|
54
|
+
* 重置超时计时器
|
|
55
|
+
*/
|
|
56
|
+
private resetTimeout;
|
|
57
|
+
/**
|
|
58
|
+
* 清除超时计时器
|
|
59
|
+
*/
|
|
60
|
+
private clearTimeout;
|
|
61
|
+
/**
|
|
62
|
+
* 获取当前状态
|
|
63
|
+
*/
|
|
64
|
+
getState(): StreamState;
|
|
65
|
+
/**
|
|
66
|
+
* 检查流是否处于活跃状态
|
|
67
|
+
*/
|
|
68
|
+
isActive(): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* 获取当前缓冲区内容
|
|
71
|
+
*/
|
|
72
|
+
getBuffer(): string;
|
|
73
|
+
/**
|
|
74
|
+
* 获取当前会话ID
|
|
75
|
+
*/
|
|
76
|
+
getSessionID(): string | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* 获取当前消息ID
|
|
79
|
+
*/
|
|
80
|
+
getMessageID(): string | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* 获取当前分块ID
|
|
83
|
+
*/
|
|
84
|
+
getPartID(): string | undefined;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=stream-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-reader.d.ts","sourceRoot":"","sources":["../../src/core/stream-reader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAgB,MAAM,SAAS,CAAA;AAE7D,qBAAa,YAAa,SAAQ,YAAY;IAS1C,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,aAAa;IATvB,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,SAAS,CAAC,CAAQ;IAC1B,OAAO,CAAC,SAAS,CAAC,CAAQ;IAC1B,OAAO,CAAC,MAAM,CAAC,CAAQ;IACvB,OAAO,CAAC,aAAa,CAAC,CAAgB;gBAG5B,UAAU,GAAE,MAAW,EACvB,aAAa,GAAE,MAAa;IAKtC;;;OAGG;IACH,KAAK,IAAI,IAAI;IAOb;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAiBtF;;OAEG;IACH,SAAS,IAAI,IAAI;IAYjB;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAOlC;;OAEG;IACH,KAAK,IAAI,IAAI;IASb;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IAanB;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB;;OAEG;IACH,OAAO,CAAC,YAAY;IAOpB;;OAEG;IACH,QAAQ,IAAI,WAAW;IAIvB;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,SAAS;IAIlC;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,SAAS;IAIlC;;OAEG;IACH,SAAS,IAAI,MAAM,GAAG,SAAS;CAGhC"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StreamReader - 流式文本缓冲与句子边界检测
|
|
3
|
+
*
|
|
4
|
+
* 功能:
|
|
5
|
+
* - 订阅 TuiEventBus 的 message.part.delta 事件
|
|
6
|
+
* - 缓冲区满或遇到句子结束符时触发 textReady 事件
|
|
7
|
+
* - 支持超时强制发送
|
|
8
|
+
*/
|
|
9
|
+
import { EventEmitter } from 'events';
|
|
10
|
+
import { StreamState } from './types';
|
|
11
|
+
export class StreamReader extends EventEmitter {
|
|
12
|
+
bufferSize;
|
|
13
|
+
bufferTimeout;
|
|
14
|
+
state = StreamState.IDLE;
|
|
15
|
+
buffer = '';
|
|
16
|
+
sessionID;
|
|
17
|
+
messageID;
|
|
18
|
+
partID;
|
|
19
|
+
timeoutHandle;
|
|
20
|
+
constructor(bufferSize = 30, bufferTimeout = 2000) {
|
|
21
|
+
super();
|
|
22
|
+
this.bufferSize = bufferSize;
|
|
23
|
+
this.bufferTimeout = bufferTimeout;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 启动流式监听
|
|
27
|
+
* 将状态从 IDLE 切换到 BUFFERING,开始监听事件
|
|
28
|
+
*/
|
|
29
|
+
start() {
|
|
30
|
+
if (this.state === StreamState.IDLE) {
|
|
31
|
+
this.state = StreamState.BUFFERING;
|
|
32
|
+
this.emit('streamStart');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 处理 message.part.delta 事件
|
|
37
|
+
*/
|
|
38
|
+
handleDelta(sessionID, messageID, partID, delta) {
|
|
39
|
+
if (this.state === StreamState.IDLE) {
|
|
40
|
+
this.state = StreamState.BUFFERING;
|
|
41
|
+
this.sessionID = sessionID;
|
|
42
|
+
this.messageID = messageID;
|
|
43
|
+
this.partID = partID;
|
|
44
|
+
this.emit('streamStart');
|
|
45
|
+
}
|
|
46
|
+
this.buffer += delta;
|
|
47
|
+
this.resetTimeout();
|
|
48
|
+
if (this.shouldFlush()) {
|
|
49
|
+
this.flushBuffer();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 处理流结束
|
|
54
|
+
*/
|
|
55
|
+
handleEnd() {
|
|
56
|
+
if (this.state === StreamState.ENDED) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (this.buffer.length > 0) {
|
|
60
|
+
this.flushBuffer();
|
|
61
|
+
}
|
|
62
|
+
this.state = StreamState.ENDED;
|
|
63
|
+
this.clearTimeout();
|
|
64
|
+
this.emit('streamEnd');
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 处理错误
|
|
68
|
+
*/
|
|
69
|
+
handleError(error) {
|
|
70
|
+
this.clearTimeout();
|
|
71
|
+
this.state = StreamState.IDLE;
|
|
72
|
+
this.buffer = '';
|
|
73
|
+
this.emit('streamError', error);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 重置缓冲器
|
|
77
|
+
*/
|
|
78
|
+
reset() {
|
|
79
|
+
this.state = StreamState.IDLE;
|
|
80
|
+
this.buffer = '';
|
|
81
|
+
this.sessionID = undefined;
|
|
82
|
+
this.messageID = undefined;
|
|
83
|
+
this.partID = undefined;
|
|
84
|
+
this.clearTimeout();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 判断是否应该刷新缓冲区
|
|
88
|
+
* 条件:
|
|
89
|
+
* 1. 包含句子结束符(任何长度)
|
|
90
|
+
* 2. 缓冲区长度 >= bufferSize
|
|
91
|
+
*/
|
|
92
|
+
shouldFlush() {
|
|
93
|
+
// 句子结束标记:。!?.!?……(中文句号、感叹号、问号、省略号)
|
|
94
|
+
const sentenceEnd = /[。!?.!?]|……/;
|
|
95
|
+
if (sentenceEnd.test(this.buffer)) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
// 缓冲区达到阈值
|
|
99
|
+
if (this.buffer.length >= this.bufferSize) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 刷新缓冲区,发送textReady事件
|
|
106
|
+
*/
|
|
107
|
+
flushBuffer() {
|
|
108
|
+
const text = this.buffer.trim();
|
|
109
|
+
if (text.length > 0) {
|
|
110
|
+
this.emit('textReady', text);
|
|
111
|
+
}
|
|
112
|
+
this.buffer = '';
|
|
113
|
+
this.resetTimeout();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 重置超时计时器
|
|
117
|
+
*/
|
|
118
|
+
resetTimeout() {
|
|
119
|
+
this.clearTimeout();
|
|
120
|
+
this.timeoutHandle = setTimeout(() => {
|
|
121
|
+
if (this.buffer.length > 0) {
|
|
122
|
+
this.flushBuffer();
|
|
123
|
+
}
|
|
124
|
+
}, this.bufferTimeout);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 清除超时计时器
|
|
128
|
+
*/
|
|
129
|
+
clearTimeout() {
|
|
130
|
+
if (this.timeoutHandle) {
|
|
131
|
+
clearTimeout(this.timeoutHandle);
|
|
132
|
+
this.timeoutHandle = undefined;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 获取当前状态
|
|
137
|
+
*/
|
|
138
|
+
getState() {
|
|
139
|
+
return this.state;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 检查流是否处于活跃状态
|
|
143
|
+
*/
|
|
144
|
+
isActive() {
|
|
145
|
+
return this.state === StreamState.BUFFERING;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 获取当前缓冲区内容
|
|
149
|
+
*/
|
|
150
|
+
getBuffer() {
|
|
151
|
+
return this.buffer;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* 获取当前会话ID
|
|
155
|
+
*/
|
|
156
|
+
getSessionID() {
|
|
157
|
+
return this.sessionID;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* 获取当前消息ID
|
|
161
|
+
*/
|
|
162
|
+
getMessageID() {
|
|
163
|
+
return this.messageID;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* 获取当前分块ID
|
|
167
|
+
*/
|
|
168
|
+
getPartID() {
|
|
169
|
+
return this.partID;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=stream-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-reader.js","sourceRoot":"","sources":["../../src/core/stream-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StreamingSynthesizer - 流式合成器
|
|
3
|
+
*
|
|
4
|
+
* 功能:
|
|
5
|
+
* - 接收 StreamReader 发来的文本(通过 synthesize 方法)
|
|
6
|
+
* - 调用 TTSProvider 的流式合成接口
|
|
7
|
+
* - 将返回的音频 chunk 传递给下游(StreamPlayer)
|
|
8
|
+
*
|
|
9
|
+
* 数据流:
|
|
10
|
+
* StreamReader.textReady → StreamingSynthesizer.synthesize() → StreamPlayer (边收边播)
|
|
11
|
+
*/
|
|
12
|
+
import { EventEmitter } from 'events';
|
|
13
|
+
import { TTSError, StreamingSynthesizerOptions } from './types';
|
|
14
|
+
export interface StreamingSynthesizerEvents {
|
|
15
|
+
on(event: 'chunk', handler: (chunk: Buffer) => void): void;
|
|
16
|
+
on(event: 'error', handler: (error: TTSError) => void): void;
|
|
17
|
+
on(event: 'done', handler: () => void): void;
|
|
18
|
+
}
|
|
19
|
+
export declare class StreamingSynthesizer extends EventEmitter {
|
|
20
|
+
private options;
|
|
21
|
+
private audioChunks;
|
|
22
|
+
constructor(options: StreamingSynthesizerOptions);
|
|
23
|
+
/**
|
|
24
|
+
* 发送文本片段进行合成
|
|
25
|
+
* 调用 provider.speak() 并处理返回的音频流
|
|
26
|
+
*/
|
|
27
|
+
synthesize(text: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* 处理 AudioResult,根据 audioData 类型进行相应处理
|
|
30
|
+
*/
|
|
31
|
+
private processAudioResult;
|
|
32
|
+
/**
|
|
33
|
+
* 处理 ReadableStream,逐chunk emit
|
|
34
|
+
*/
|
|
35
|
+
private processReadableStream;
|
|
36
|
+
/**
|
|
37
|
+
* emit chunk 并累积
|
|
38
|
+
*/
|
|
39
|
+
private emitChunk;
|
|
40
|
+
/**
|
|
41
|
+
* 重置状态
|
|
42
|
+
* 清空累积的音频数据
|
|
43
|
+
*/
|
|
44
|
+
reset(): void;
|
|
45
|
+
/**
|
|
46
|
+
* 获取累积的音频数据
|
|
47
|
+
* 返回所有已接收的 chunk
|
|
48
|
+
*/
|
|
49
|
+
getAudioChunks(): Buffer[];
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=streaming-synthesizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming-synthesizer.d.ts","sourceRoot":"","sources":["../../src/core/streaming-synthesizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,EAAe,QAAQ,EAAgB,2BAA2B,EAAe,MAAM,SAAS,CAAA;AAEvG,MAAM,WAAW,0BAA0B;IACzC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAA;IAC1D,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAA;IAC5D,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;CAC7C;AAED,qBAAa,oBAAqB,SAAQ,YAAY;IAGxC,OAAO,CAAC,OAAO;IAF3B,OAAO,CAAC,WAAW,CAAe;gBAEd,OAAO,EAAE,2BAA2B;IAIxD;;;OAGG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B7C;;OAEG;YACW,kBAAkB;IAUhC;;OAEG;YACW,qBAAqB;IAqBnC;;OAEG;IACH,OAAO,CAAC,SAAS;IAKjB;;;OAGG;IACH,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACH,cAAc,IAAI,MAAM,EAAE;CAG3B"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StreamingSynthesizer - 流式合成器
|
|
3
|
+
*
|
|
4
|
+
* 功能:
|
|
5
|
+
* - 接收 StreamReader 发来的文本(通过 synthesize 方法)
|
|
6
|
+
* - 调用 TTSProvider 的流式合成接口
|
|
7
|
+
* - 将返回的音频 chunk 传递给下游(StreamPlayer)
|
|
8
|
+
*
|
|
9
|
+
* 数据流:
|
|
10
|
+
* StreamReader.textReady → StreamingSynthesizer.synthesize() → StreamPlayer (边收边播)
|
|
11
|
+
*/
|
|
12
|
+
import { EventEmitter } from 'events';
|
|
13
|
+
import { TTSError } from './types';
|
|
14
|
+
export class StreamingSynthesizer extends EventEmitter {
|
|
15
|
+
options;
|
|
16
|
+
audioChunks = [];
|
|
17
|
+
constructor(options) {
|
|
18
|
+
super();
|
|
19
|
+
this.options = options;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 发送文本片段进行合成
|
|
23
|
+
* 调用 provider.speak() 并处理返回的音频流
|
|
24
|
+
*/
|
|
25
|
+
async synthesize(text) {
|
|
26
|
+
if (!text || text.trim().length === 0) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const result = await this.options.provider.speak(text, {
|
|
31
|
+
model: 'stream',
|
|
32
|
+
voice: this.options.voice,
|
|
33
|
+
speed: this.options.speed,
|
|
34
|
+
volume: this.options.volume,
|
|
35
|
+
pitch: this.options.pitch
|
|
36
|
+
});
|
|
37
|
+
await this.processAudioResult(result);
|
|
38
|
+
this.emit('done');
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
const ttsError = error instanceof TTSError
|
|
42
|
+
? error
|
|
43
|
+
: new TTSError(error instanceof Error ? error.message : 'Synthesis failed', 'UNKNOWN', this.options.provider.name, error);
|
|
44
|
+
this.emit('error', ttsError);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 处理 AudioResult,根据 audioData 类型进行相应处理
|
|
49
|
+
*/
|
|
50
|
+
async processAudioResult(result) {
|
|
51
|
+
if (result.isStream && result.audioData instanceof ReadableStream) {
|
|
52
|
+
// 流式数据:ReadableStream
|
|
53
|
+
await this.processReadableStream(result.audioData);
|
|
54
|
+
}
|
|
55
|
+
else if (Buffer.isBuffer(result.audioData)) {
|
|
56
|
+
// 非流式数据:Buffer
|
|
57
|
+
this.emitChunk(result.audioData);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 处理 ReadableStream,逐chunk emit
|
|
62
|
+
*/
|
|
63
|
+
async processReadableStream(stream) {
|
|
64
|
+
const reader = stream.getReader();
|
|
65
|
+
try {
|
|
66
|
+
while (true) {
|
|
67
|
+
const { done, value } = await reader.read();
|
|
68
|
+
if (done) {
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
if (value) {
|
|
72
|
+
const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
73
|
+
this.emitChunk(chunk);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
reader.releaseLock();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* emit chunk 并累积
|
|
83
|
+
*/
|
|
84
|
+
emitChunk(chunk) {
|
|
85
|
+
this.audioChunks.push(chunk);
|
|
86
|
+
this.emit('chunk', chunk);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 重置状态
|
|
90
|
+
* 清空累积的音频数据
|
|
91
|
+
*/
|
|
92
|
+
reset() {
|
|
93
|
+
this.audioChunks = [];
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 获取累积的音频数据
|
|
97
|
+
* 返回所有已接收的 chunk
|
|
98
|
+
*/
|
|
99
|
+
getAudioChunks() {
|
|
100
|
+
return [...this.audioChunks];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=streaming-synthesizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming-synthesizer.js","sourceRoot":"","sources":["../../src/core/streaming-synthesizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTS Core Types
|
|
3
|
+
* 核心类型定义
|
|
4
|
+
*/
|
|
5
|
+
export declare enum TTSErrorCode {
|
|
6
|
+
NETWORK = "NETWORK",
|
|
7
|
+
AUTH = "AUTH",
|
|
8
|
+
QUOTA = "QUOTA",
|
|
9
|
+
INVALID_VOICE = "INVALID_VOICE",
|
|
10
|
+
INVALID_PARAMS = "INVALID_PARAMS",
|
|
11
|
+
PLAYER_ERROR = "PLAYER_ERROR",
|
|
12
|
+
UNKNOWN = "UNKNOWN"
|
|
13
|
+
}
|
|
14
|
+
export declare class TTSError extends Error {
|
|
15
|
+
constructor(message: string, code: TTSErrorCode, provider: string, details?: unknown);
|
|
16
|
+
code: TTSErrorCode;
|
|
17
|
+
provider: string;
|
|
18
|
+
details?: unknown;
|
|
19
|
+
}
|
|
20
|
+
export interface Voice {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
language?: string;
|
|
24
|
+
gender?: 'male' | 'female' | 'neutral';
|
|
25
|
+
previewUrl?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface TTSCapabilities {
|
|
28
|
+
speak: true;
|
|
29
|
+
voiceClone?: boolean;
|
|
30
|
+
stream?: boolean;
|
|
31
|
+
voiceList?: boolean;
|
|
32
|
+
sync?: boolean;
|
|
33
|
+
async?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export type SynthesisModel = 'sync' | 'async' | 'stream';
|
|
36
|
+
export interface SpeakOptions {
|
|
37
|
+
voice?: string;
|
|
38
|
+
model?: SynthesisModel;
|
|
39
|
+
speed?: number;
|
|
40
|
+
volume?: number;
|
|
41
|
+
pitch?: number;
|
|
42
|
+
sourceVoice?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface AudioResult {
|
|
45
|
+
audioData: Buffer | ReadableStream;
|
|
46
|
+
sampleRate?: number;
|
|
47
|
+
channels?: number;
|
|
48
|
+
duration?: number;
|
|
49
|
+
format: string;
|
|
50
|
+
isStream: boolean;
|
|
51
|
+
}
|
|
52
|
+
export type TTSEvent = 'start' | 'end' | 'error' | 'progress' | 'pause' | 'resume' | 'stop';
|
|
53
|
+
export interface SpeakerEvents {
|
|
54
|
+
on(event: 'start', handler: (text: string) => void): void;
|
|
55
|
+
on(event: 'end', handler: (text: string) => void): void;
|
|
56
|
+
on(event: 'error', handler: (error: TTSError) => void): void;
|
|
57
|
+
on(event: 'progress', handler: (progress: {
|
|
58
|
+
current: number;
|
|
59
|
+
total: number;
|
|
60
|
+
}) => void): void;
|
|
61
|
+
on(event: 'pause', handler: () => void): void;
|
|
62
|
+
on(event: 'resume', handler: () => void): void;
|
|
63
|
+
on(event: 'stop', handler: () => void): void;
|
|
64
|
+
off(event: TTSEvent, handler: Function): void;
|
|
65
|
+
}
|
|
66
|
+
export interface TTSProvider {
|
|
67
|
+
name: string;
|
|
68
|
+
capabilities: TTSCapabilities;
|
|
69
|
+
initialize(): Promise<void>;
|
|
70
|
+
destroy(): Promise<void>;
|
|
71
|
+
speak(text: string, options?: SpeakOptions): Promise<AudioResult>;
|
|
72
|
+
pause(): Promise<void>;
|
|
73
|
+
resume(): Promise<void>;
|
|
74
|
+
stop(): Promise<void>;
|
|
75
|
+
listVoices(): Promise<Voice[]>;
|
|
76
|
+
getCapabilities(): TTSCapabilities;
|
|
77
|
+
}
|
|
78
|
+
export interface GlobalConfig {
|
|
79
|
+
defaultProvider: string;
|
|
80
|
+
defaultModel?: SynthesisModel;
|
|
81
|
+
defaultVoice?: string;
|
|
82
|
+
}
|
|
83
|
+
export interface ProviderConfig {
|
|
84
|
+
enabled?: boolean;
|
|
85
|
+
apiKey?: string;
|
|
86
|
+
[key: string]: unknown;
|
|
87
|
+
}
|
|
88
|
+
export interface OcosayConfig {
|
|
89
|
+
enabled?: boolean;
|
|
90
|
+
autoPlay?: boolean;
|
|
91
|
+
autoRead?: boolean;
|
|
92
|
+
streamMode?: boolean;
|
|
93
|
+
streamBufferSize?: number;
|
|
94
|
+
streamBufferTimeout?: number;
|
|
95
|
+
provider?: string;
|
|
96
|
+
ttsModel?: string;
|
|
97
|
+
baseURL?: string;
|
|
98
|
+
speed?: number;
|
|
99
|
+
volume?: number;
|
|
100
|
+
pitch?: number;
|
|
101
|
+
}
|
|
102
|
+
export declare enum StreamState {
|
|
103
|
+
IDLE = "idle",
|
|
104
|
+
BUFFERING = "buffering",
|
|
105
|
+
STREAMING = "streaming",
|
|
106
|
+
ENDED = "ended"
|
|
107
|
+
}
|
|
108
|
+
export interface OcosayStreamConfig {
|
|
109
|
+
enabled: boolean;
|
|
110
|
+
autoPlay: boolean;
|
|
111
|
+
autoRead: boolean;
|
|
112
|
+
streamMode: boolean;
|
|
113
|
+
streamBufferSize: number;
|
|
114
|
+
streamBufferTimeout: number;
|
|
115
|
+
provider: string;
|
|
116
|
+
voiceId?: string;
|
|
117
|
+
ttsModel?: string;
|
|
118
|
+
baseURL?: string;
|
|
119
|
+
speed?: number;
|
|
120
|
+
volume?: number;
|
|
121
|
+
pitch?: number;
|
|
122
|
+
apiKey?: string;
|
|
123
|
+
}
|
|
124
|
+
export interface StreamReaderEvents {
|
|
125
|
+
onTextReady: (text: string) => void;
|
|
126
|
+
onStreamStart: () => void;
|
|
127
|
+
onStreamEnd: () => void;
|
|
128
|
+
onStreamError: (error: TTSError) => void;
|
|
129
|
+
}
|
|
130
|
+
export interface StreamingSynthesizerOptions {
|
|
131
|
+
provider: TTSProvider;
|
|
132
|
+
voice?: string;
|
|
133
|
+
speed?: number;
|
|
134
|
+
volume?: number;
|
|
135
|
+
pitch?: number;
|
|
136
|
+
}
|
|
137
|
+
export interface StreamPlayerOptions {
|
|
138
|
+
format?: 'mp3' | 'wav' | 'flac';
|
|
139
|
+
onProgress?: (bytesReceived: number) => void;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,oBAAY,YAAY;IACtB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,KAAK,UAAU;IACf,aAAa,kBAAkB;IAC/B,cAAc,mBAAmB;IACjC,YAAY,iBAAiB;IAC7B,OAAO,YAAY;CACpB;AAED,qBAAa,QAAS,SAAQ,KAAK;gBAE/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,OAAO;IASnB,IAAI,EAAE,YAAY,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAA;IACtC,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,IAAI,CAAA;IACX,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;AAExD,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,cAAc,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,GAAG,cAAc,CAAA;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,MAAM,QAAQ,GAChB,OAAO,GACP,KAAK,GACL,OAAO,GACP,UAAU,GACV,OAAO,GACP,QAAQ,GACR,MAAM,CAAA;AAEV,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAA;IACzD,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAA;IACvD,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAA;IAC5D,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,IAAI,CAAA;IAC5F,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;IAC7C,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;IAC9C,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;IAC5C,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAA;CAC9C;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,eAAe,CAAA;IAE7B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAExB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IACjE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACrB,UAAU,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,CAAA;IAE9B,eAAe,IAAI,eAAe,CAAA;CACnC;AAMD,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,cAAc,CAAA;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAMD,oBAAY,WAAW;IACrB,IAAI,SAAS;IACb,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,KAAK,UAAU;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;IACnB,gBAAgB,EAAE,MAAM,CAAA;IACxB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,aAAa,EAAE,MAAM,IAAI,CAAA;IACzB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,aAAa,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAA;CACzC;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,WAAW,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAA;IAC/B,UAAU,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7C"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTS Core Types
|
|
3
|
+
* 核心类型定义
|
|
4
|
+
*/
|
|
5
|
+
export var TTSErrorCode;
|
|
6
|
+
(function (TTSErrorCode) {
|
|
7
|
+
TTSErrorCode["NETWORK"] = "NETWORK";
|
|
8
|
+
TTSErrorCode["AUTH"] = "AUTH";
|
|
9
|
+
TTSErrorCode["QUOTA"] = "QUOTA";
|
|
10
|
+
TTSErrorCode["INVALID_VOICE"] = "INVALID_VOICE";
|
|
11
|
+
TTSErrorCode["INVALID_PARAMS"] = "INVALID_PARAMS";
|
|
12
|
+
TTSErrorCode["PLAYER_ERROR"] = "PLAYER_ERROR";
|
|
13
|
+
TTSErrorCode["UNKNOWN"] = "UNKNOWN";
|
|
14
|
+
})(TTSErrorCode || (TTSErrorCode = {}));
|
|
15
|
+
export class TTSError extends Error {
|
|
16
|
+
constructor(message, code, provider, details) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'TTSError';
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.provider = provider;
|
|
21
|
+
this.details = details;
|
|
22
|
+
}
|
|
23
|
+
code;
|
|
24
|
+
provider;
|
|
25
|
+
details;
|
|
26
|
+
}
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// 流式朗读相关类型
|
|
29
|
+
// ============================================================================
|
|
30
|
+
export var StreamState;
|
|
31
|
+
(function (StreamState) {
|
|
32
|
+
StreamState["IDLE"] = "idle";
|
|
33
|
+
StreamState["BUFFERING"] = "buffering";
|
|
34
|
+
StreamState["STREAMING"] = "streaming";
|
|
35
|
+
StreamState["ENDED"] = "ended";
|
|
36
|
+
})(StreamState || (StreamState = {}));
|
|
37
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAN,IAAY,YAQX;AARD,WAAY,YAAY;IACtB,mCAAmB,CAAA;IACnB,6BAAa,CAAA;IACb,+BAAe,CAAA;IACf,+CAA+B,CAAA;IAC/B,iDAAiC,CAAA;IACjC,6CAA6B,CAAA;IAC7B,mCAAmB,CAAA;AACrB,CAAC,EARW,YAAY,KAAZ,YAAY,QAQvB;AAED,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC,YACE,OAAe,EACf,IAAkB,EAClB,QAAgB,EAChB,OAAiB;QAEjB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,UAAU,CAAA;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IACxB,CAAC;IAED,IAAI,CAAc;IAClB,QAAQ,CAAQ;IAChB,OAAO,CAAU;CAClB;AA0GD,+EAA+E;AAC/E,WAAW;AACX,+EAA+E;AAE/E,MAAM,CAAN,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,4BAAa,CAAA;IACb,sCAAuB,CAAA;IACvB,sCAAuB,CAAA;IACvB,8BAAe,CAAA;AACjB,CAAC,EALW,WAAW,KAAX,WAAW,QAKtB"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { handleToolCall } from './tools/tts';
|
|
2
|
+
import { MiniMaxConfig } from './providers/minimax';
|
|
3
|
+
import { Speaker } from './core/speaker';
|
|
4
|
+
import { StreamReader } from './core/stream-reader';
|
|
5
|
+
import { StreamingSynthesizer } from './core/streaming-synthesizer';
|
|
6
|
+
import { StreamPlayer } from './core/stream-player';
|
|
7
|
+
export declare const pluginInfo: {
|
|
8
|
+
name: string;
|
|
9
|
+
version: string;
|
|
10
|
+
description: string;
|
|
11
|
+
author: string;
|
|
12
|
+
license: string;
|
|
13
|
+
};
|
|
14
|
+
export interface InitializeOptions {
|
|
15
|
+
defaultProvider?: string;
|
|
16
|
+
defaultModel?: 'sync' | 'async' | 'stream';
|
|
17
|
+
defaultVoice?: string;
|
|
18
|
+
providers?: {
|
|
19
|
+
minimax?: MiniMaxConfig;
|
|
20
|
+
};
|
|
21
|
+
autoRead?: boolean;
|
|
22
|
+
streamBufferSize?: number;
|
|
23
|
+
streamBufferTimeout?: number;
|
|
24
|
+
}
|
|
25
|
+
export declare function initialize(config?: InitializeOptions): Promise<void>;
|
|
26
|
+
export declare function getSpeaker(): Speaker;
|
|
27
|
+
export declare function isStreamEnabled(): boolean;
|
|
28
|
+
export declare function isAutoReadEnabled(): boolean;
|
|
29
|
+
export declare function getStreamStatus(): {
|
|
30
|
+
isActive: boolean;
|
|
31
|
+
bytesWritten: number;
|
|
32
|
+
state: string;
|
|
33
|
+
};
|
|
34
|
+
export declare function getStreamReader(): StreamReader | undefined;
|
|
35
|
+
export declare function getStreamingSynthesizer(): StreamingSynthesizer | undefined;
|
|
36
|
+
export declare function getStreamPlayer(): StreamPlayer | undefined;
|
|
37
|
+
export declare function destroy(): Promise<void>;
|
|
38
|
+
export { handleToolCall };
|
|
39
|
+
export declare const toolNames: string[];
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE5C,OAAO,EAAmB,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACpE,OAAO,EAAE,OAAO,EAAkB,MAAM,gBAAgB,CAAA;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAEnD,eAAO,MAAM,UAAU;;;;;;CAMtB,CAAA;AASD,MAAM,WAAW,iBAAiB;IAChC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE;QACV,OAAO,CAAC,EAAE,aAAa,CAAA;KACxB,CAAA;IACD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,wBAAsB,UAAU,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB1E;AAsFD,wBAAgB,UAAU,IAAI,OAAO,CASpC;AAED,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,wBAAgB,eAAe,IAAI;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAS5F;AAED,wBAAgB,eAAe,IAAI,YAAY,GAAG,SAAS,CAE1D;AAED,wBAAgB,uBAAuB,IAAI,oBAAoB,GAAG,SAAS,CAE1E;AAED,wBAAgB,eAAe,IAAI,YAAY,GAAG,SAAS,CAE1D;AAED,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CA6B7C;AAED,OAAO,EAAE,cAAc,EAAE,CAAA;AACzB,eAAO,MAAM,SAAS,UAWrB,CAAA"}
|