echogarden 0.1.9 → 0.2.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 +8 -2
- package/data/lexicons/{heteronyms.json → heteronyms.en.json} +22 -1
- package/data/schemas/options.json +29 -1
- package/dist/api/APIOptions.d.ts +2 -0
- package/dist/api/Alignment.d.ts +4 -8
- package/dist/api/Alignment.js.map +1 -1
- package/dist/api/Recognition.d.ts +4 -8
- package/dist/api/Recognition.js +2 -1
- package/dist/api/Recognition.js.map +1 -1
- package/dist/api/Synthesis.d.ts +8 -5
- package/dist/api/Synthesis.js +28 -8
- package/dist/api/Synthesis.js.map +1 -1
- package/dist/api/Translation.d.ts +4 -8
- package/dist/api/Translation.js.map +1 -1
- package/dist/audio/AudioPlayer.d.ts +2 -1
- package/dist/audio/AudioPlayer.js +31 -7
- package/dist/audio/AudioPlayer.js.map +1 -1
- package/dist/cli/CLI.d.ts +1 -1
- package/dist/cli/CLI.js +42 -11
- package/dist/cli/CLI.js.map +1 -1
- package/dist/cli/CLILauncher.js +1 -5
- package/dist/cli/CLILauncher.js.map +1 -1
- package/dist/cli/CLIStarter.js +31 -2
- package/dist/cli/CLIStarter.js.map +1 -1
- package/dist/server/Client.d.ts +22 -0
- package/dist/server/Client.js +246 -0
- package/dist/server/Client.js.map +1 -0
- package/dist/server/Server.d.ts +10 -1
- package/dist/server/Server.js +98 -14
- package/dist/server/Server.js.map +1 -1
- package/dist/server/ServerStarter.d.ts +1 -0
- package/dist/server/ServerStarter.js +10 -0
- package/dist/server/ServerStarter.js.map +1 -0
- package/dist/server/Worker.d.ts +57 -0
- package/dist/server/Worker.js +143 -0
- package/dist/server/Worker.js.map +1 -0
- package/dist/synthesis/EspeakTTS.js +5 -6
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/dist/synthesis/FliteTTS.d.ts +1 -1
- package/dist/synthesis/FliteTTS.js +4 -4
- package/dist/synthesis/FliteTTS.js.map +1 -1
- package/dist/synthesis/MicrosoftEdgeTTS.js +4 -8
- package/dist/synthesis/MicrosoftEdgeTTS.js.map +1 -1
- package/dist/synthesis/VitsTTS.d.ts +2 -2
- package/dist/synthesis/VitsTTS.js +36 -42
- package/dist/synthesis/VitsTTS.js.map +1 -1
- package/dist/utilities/FileDownloader.js.map +1 -1
- package/dist/utilities/Locale.js +2 -1
- package/dist/utilities/Locale.js.map +1 -1
- package/dist/utilities/Queue.d.ts +8 -0
- package/dist/utilities/Queue.js +14 -0
- package/dist/utilities/Queue.js.map +1 -0
- package/dist/utilities/SignalChannel.d.ts +6 -0
- package/dist/utilities/SignalChannel.js +18 -0
- package/dist/utilities/SignalChannel.js.map +1 -0
- package/dist/utilities/Utilities.d.ts +2 -1
- package/dist/utilities/Utilities.js +14 -7
- package/dist/utilities/Utilities.js.map +1 -1
- package/docs/CLI.md +0 -1
- package/docs/Engines.md +1 -1
- package/docs/Roadmap.md +7 -9
- package/docs/Technical.md +3 -1
- package/package.json +14 -13
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { WebSocket } from 'ws';
|
|
2
|
+
import { encode as encodeMsgPack, decode as decodeMsgPack } from 'msgpack-lite';
|
|
3
|
+
import { getRandomHexString, logToStderr } from '../utilities/Utilities.js';
|
|
4
|
+
import { OpenPromise } from '../utilities/OpenPromise.js';
|
|
5
|
+
import { Worker as WorkerThread } from 'node:worker_threads';
|
|
6
|
+
import { resolveToModuleRootDir } from '../utilities/FileSystem.js';
|
|
7
|
+
import { playAudioWithTimeline } from '../audio/AudioPlayer.js';
|
|
8
|
+
const log = logToStderr;
|
|
9
|
+
export class Client {
|
|
10
|
+
sendMessage;
|
|
11
|
+
responseListeners = new Map();
|
|
12
|
+
constructor(sourceChannel) {
|
|
13
|
+
if (sourceChannel instanceof WebSocket) {
|
|
14
|
+
sourceChannel.on("message", (messageData, isBinary) => {
|
|
15
|
+
if (!isBinary) {
|
|
16
|
+
log(`Received an unexpected string WebSocket message: '${messageData.toString("utf-8")}'`);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
let incomingMessage;
|
|
20
|
+
try {
|
|
21
|
+
incomingMessage = decodeMsgPack(messageData);
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
log(`Failed to decode incoming message. Reason: ${e}`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
this.onMessage(incomingMessage);
|
|
28
|
+
});
|
|
29
|
+
this.sendMessage = (outgoingMessage) => {
|
|
30
|
+
const encodedMessage = encodeMsgPack(outgoingMessage);
|
|
31
|
+
sourceChannel.send(encodedMessage);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
else if (sourceChannel instanceof WorkerThread) {
|
|
35
|
+
sourceChannel.on("message", (message) => {
|
|
36
|
+
this.onMessage(message);
|
|
37
|
+
});
|
|
38
|
+
sourceChannel.on("error", (e) => {
|
|
39
|
+
throw e;
|
|
40
|
+
});
|
|
41
|
+
this.sendMessage = (outgoingMessage) => {
|
|
42
|
+
sourceChannel.postMessage(outgoingMessage);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
throw new Error(`Invalid source: not a WebSocket or WorkerThread object`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async synthesizeSegments(segments, options, onSegment, onSentence) {
|
|
50
|
+
const requestOpenPromise = new OpenPromise();
|
|
51
|
+
const requestMessage = {
|
|
52
|
+
messageType: "SynthesizeSegmentsRequest",
|
|
53
|
+
segments,
|
|
54
|
+
options
|
|
55
|
+
};
|
|
56
|
+
function onResponse(responseMessage) {
|
|
57
|
+
if (responseMessage.messageType == "SynthesizeSegmentsResponse") {
|
|
58
|
+
requestOpenPromise.resolve(responseMessage);
|
|
59
|
+
}
|
|
60
|
+
else if (responseMessage.messageType == "SynthesisSegmentEvent" && onSegment) {
|
|
61
|
+
onSegment(responseMessage);
|
|
62
|
+
}
|
|
63
|
+
else if (responseMessage.messageType == "SynthesisSentenceEvent" && onSentence) {
|
|
64
|
+
onSentence(responseMessage);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function onError(e) {
|
|
68
|
+
requestOpenPromise.reject(e);
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
this.sendRequest(requestMessage, onResponse, onError);
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
onError(e);
|
|
75
|
+
}
|
|
76
|
+
return requestOpenPromise.promise;
|
|
77
|
+
}
|
|
78
|
+
async requestVoiceList(options) {
|
|
79
|
+
const requestOpenPromise = new OpenPromise();
|
|
80
|
+
const requestMessage = {
|
|
81
|
+
messageType: "VoiceListRequest",
|
|
82
|
+
options
|
|
83
|
+
};
|
|
84
|
+
function onResponse(responseMessage) {
|
|
85
|
+
if (responseMessage.messageType == "VoiceListResponse") {
|
|
86
|
+
requestOpenPromise.resolve(responseMessage);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function onError(e) {
|
|
90
|
+
requestOpenPromise.reject(e);
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
this.sendRequest(requestMessage, onResponse, onError);
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
onError(e);
|
|
97
|
+
}
|
|
98
|
+
return requestOpenPromise.promise;
|
|
99
|
+
}
|
|
100
|
+
async recognize(inputRawAudio, options) {
|
|
101
|
+
const requestOpenPromise = new OpenPromise();
|
|
102
|
+
const requestMessage = {
|
|
103
|
+
messageType: "RecognitionRequest",
|
|
104
|
+
inputRawAudio,
|
|
105
|
+
options
|
|
106
|
+
};
|
|
107
|
+
function onResponse(responseMessage) {
|
|
108
|
+
if (responseMessage.messageType == "RecognitionResponse") {
|
|
109
|
+
requestOpenPromise.resolve(responseMessage);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function onError(e) {
|
|
113
|
+
requestOpenPromise.reject(e);
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
this.sendRequest(requestMessage, onResponse, onError);
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
onError(e);
|
|
120
|
+
}
|
|
121
|
+
return requestOpenPromise.promise;
|
|
122
|
+
}
|
|
123
|
+
async align(inputRawAudio, transcript, options) {
|
|
124
|
+
const requestOpenPromise = new OpenPromise();
|
|
125
|
+
const requestMessage = {
|
|
126
|
+
messageType: "AlignmentRequest",
|
|
127
|
+
inputRawAudio,
|
|
128
|
+
transcript,
|
|
129
|
+
options
|
|
130
|
+
};
|
|
131
|
+
function onResponse(responseMessage) {
|
|
132
|
+
if (responseMessage.messageType == "AlignmentResponse") {
|
|
133
|
+
requestOpenPromise.resolve(responseMessage);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function onError(e) {
|
|
137
|
+
requestOpenPromise.reject(e);
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
this.sendRequest(requestMessage, onResponse, onError);
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
onError(e);
|
|
144
|
+
}
|
|
145
|
+
return requestOpenPromise.promise;
|
|
146
|
+
}
|
|
147
|
+
async translateSpeech(inputRawAudio, options) {
|
|
148
|
+
const requestOpenPromise = new OpenPromise();
|
|
149
|
+
const requestMessage = {
|
|
150
|
+
messageType: "SpeechTranslationRequest",
|
|
151
|
+
inputRawAudio,
|
|
152
|
+
options
|
|
153
|
+
};
|
|
154
|
+
function onResponse(responseMessage) {
|
|
155
|
+
if (responseMessage.messageType == "SpeechTranslationResponse") {
|
|
156
|
+
requestOpenPromise.resolve(responseMessage);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function onError(e) {
|
|
160
|
+
requestOpenPromise.reject(e);
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
this.sendRequest(requestMessage, onResponse, onError);
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
onError(e);
|
|
167
|
+
}
|
|
168
|
+
return requestOpenPromise.promise;
|
|
169
|
+
}
|
|
170
|
+
sendRequest(request, onResponse, onErrorResponse) {
|
|
171
|
+
const requestId = getRandomHexString();
|
|
172
|
+
request = {
|
|
173
|
+
requestId,
|
|
174
|
+
...request
|
|
175
|
+
};
|
|
176
|
+
this.sendMessage(request);
|
|
177
|
+
function onResponseMessage(message) {
|
|
178
|
+
if (message.messageType == "Error") {
|
|
179
|
+
onErrorResponse(message.error);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
onResponse(message);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
this.responseListeners.set(requestId, onResponseMessage);
|
|
186
|
+
}
|
|
187
|
+
onMessage(incomingMessage) {
|
|
188
|
+
const requestId = incomingMessage.requestId;
|
|
189
|
+
if (!requestId) {
|
|
190
|
+
log("Received a WebSocket message without a request ID");
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const listener = this.responseListeners.get(requestId);
|
|
194
|
+
if (listener) {
|
|
195
|
+
listener(incomingMessage);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
export async function runClientWebSocketTest(serverPort, secure) {
|
|
200
|
+
const ws = new WebSocket(`${secure ? "wss" : "ws"}://localhost:${serverPort}`, {
|
|
201
|
+
rejectUnauthorized: false
|
|
202
|
+
});
|
|
203
|
+
ws.on("open", async () => {
|
|
204
|
+
const client = new Client(ws);
|
|
205
|
+
const voiceListResult = await client.requestVoiceList({
|
|
206
|
+
engine: "pico"
|
|
207
|
+
});
|
|
208
|
+
log(voiceListResult);
|
|
209
|
+
const synthesisResult1 = await client.synthesizeSegments(["Hello world! How are you?", "Do you like turtles?"], {}, async (eventData) => {
|
|
210
|
+
log("onSegment (call 1)");
|
|
211
|
+
}, async (eventData) => {
|
|
212
|
+
log("onSentence (call 1)");
|
|
213
|
+
});
|
|
214
|
+
//log(synthesisResult1.timeline)
|
|
215
|
+
const wordTimeline = synthesisResult1.timeline.flatMap(segmentEntry => segmentEntry.timeline).flatMap(sentenceEntry => sentenceEntry.timeline);
|
|
216
|
+
const transcript = synthesisResult1.timeline.map(segmenEntry => segmenEntry.text).join("\n\n");
|
|
217
|
+
await playAudioWithTimeline(synthesisResult1.synthesizedAudio, wordTimeline, transcript);
|
|
218
|
+
await client.synthesizeSegments(["Hey! What's up?", "See ya."], {}, async (eventData) => {
|
|
219
|
+
log("onSegment (call 2)");
|
|
220
|
+
}, async (eventData) => {
|
|
221
|
+
log("onSentence (call 2)");
|
|
222
|
+
});
|
|
223
|
+
//log(synthesisResult2)
|
|
224
|
+
//ws.close()
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
export async function runClientWorkerThreadTest() {
|
|
228
|
+
const worker = new WorkerThread(resolveToModuleRootDir("dist/server/Worker.js"));
|
|
229
|
+
const client = new Client(worker);
|
|
230
|
+
const voiceListResult = await client.requestVoiceList({
|
|
231
|
+
engine: "pico"
|
|
232
|
+
});
|
|
233
|
+
log(voiceListResult);
|
|
234
|
+
await client.synthesizeSegments(["Hello world! How are you?", "Do you like turtles?"], {}, async (eventData) => {
|
|
235
|
+
log("onSegment (call 1)");
|
|
236
|
+
}, async (eventData) => {
|
|
237
|
+
log("onSentence (call 1)");
|
|
238
|
+
});
|
|
239
|
+
//log(synthesisResult1)
|
|
240
|
+
await client.synthesizeSegments(["Hey! What's up?", "See ya."], {}, async (eventData) => {
|
|
241
|
+
log("onSegment (call 2)");
|
|
242
|
+
}, async (eventData) => {
|
|
243
|
+
log("onSentence (call 2)");
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=Client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Client.js","sourceRoot":"","sources":["../../src/server/Client.ts"],"names":[],"mappings":"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"}
|
package/dist/server/Server.d.ts
CHANGED
|
@@ -1 +1,10 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare function startWebSocketServer(serverOptions: ServerOptions, onStarted: (options: ServerOptions) => void): Promise<void>;
|
|
2
|
+
export interface ServerOptions {
|
|
3
|
+
port?: number;
|
|
4
|
+
secure?: boolean;
|
|
5
|
+
certPath?: string;
|
|
6
|
+
keyPath?: string;
|
|
7
|
+
deflate?: boolean;
|
|
8
|
+
maxPayload?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const defaultServerOptions: ServerOptions;
|
package/dist/server/Server.js
CHANGED
|
@@ -1,18 +1,102 @@
|
|
|
1
|
-
import { WebSocketServer } from 'ws';
|
|
2
|
-
import { encode as encodeMsgPack } from 'msgpack-lite';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
2
|
+
import { encode as encodeMsgPack, decode as decodeMsgPack } from 'msgpack-lite';
|
|
3
|
+
import { Worker } from 'node:worker_threads';
|
|
4
|
+
import { logToStderr } from '../utilities/Utilities.js';
|
|
5
|
+
import { OpenPromise } from '../utilities/OpenPromise.js';
|
|
6
|
+
import { resolveToModuleRootDir, readFile, existsSync } from '../utilities/FileSystem.js';
|
|
7
|
+
import { extendDeep } from '../utilities/ObjectUtilities.js';
|
|
8
|
+
const log = logToStderr;
|
|
9
|
+
export async function startWebSocketServer(serverOptions, onStarted) {
|
|
10
|
+
serverOptions = extendDeep(defaultServerOptions, serverOptions);
|
|
11
|
+
const wsServerOptions = {
|
|
12
|
+
perMessageDeflate: serverOptions.deflate,
|
|
13
|
+
maxPayload: serverOptions.maxPayload
|
|
14
|
+
};
|
|
15
|
+
if (serverOptions.secure) {
|
|
16
|
+
if (!serverOptions.certPath || !existsSync(serverOptions.certPath)) {
|
|
17
|
+
throw new Error(`No valid certificate file path was given`);
|
|
18
|
+
}
|
|
19
|
+
if (!serverOptions.keyPath || !existsSync(serverOptions.keyPath)) {
|
|
20
|
+
throw new Error(`No valid key file path was given`);
|
|
21
|
+
}
|
|
22
|
+
const { createServer } = await import('https');
|
|
23
|
+
const httpsServer = createServer({
|
|
24
|
+
cert: await readFile(serverOptions.certPath),
|
|
25
|
+
key: await readFile(serverOptions.keyPath)
|
|
13
26
|
});
|
|
14
|
-
|
|
27
|
+
httpsServer.listen(serverOptions.port);
|
|
28
|
+
wsServerOptions.server = httpsServer;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
wsServerOptions.port = serverOptions.port;
|
|
32
|
+
}
|
|
33
|
+
const wss = new WebSocketServer(wsServerOptions);
|
|
34
|
+
const requestIdToWebSocket = new Map();
|
|
35
|
+
const worker = new Worker(resolveToModuleRootDir("dist/server/Worker.js"));
|
|
36
|
+
worker.on("message", (message) => {
|
|
37
|
+
if (!message.requestId) {
|
|
38
|
+
throw new Error("Worker message doesn't have a request ID");
|
|
39
|
+
}
|
|
40
|
+
const ws = requestIdToWebSocket.get(message.requestId);
|
|
41
|
+
if (!ws || ws.readyState != WebSocket.OPEN) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const encodedWorkerMessage = encodeMsgPack(message);
|
|
45
|
+
ws.send(encodedWorkerMessage);
|
|
15
46
|
});
|
|
47
|
+
const serverOpenPromise = new OpenPromise;
|
|
48
|
+
wss.on("listening", () => {
|
|
49
|
+
log(`Started Echogarden WebSocket server on port ${serverOptions.port}`);
|
|
50
|
+
onStarted(serverOptions);
|
|
51
|
+
});
|
|
52
|
+
wss.on("close", () => {
|
|
53
|
+
serverOpenPromise.resolve();
|
|
54
|
+
});
|
|
55
|
+
wss.on('connection', async (ws, req) => {
|
|
56
|
+
log(`Accepted incoming connection from ${req.socket.remoteAddress}`);
|
|
57
|
+
ws.on('message', (messageData, isBinary) => {
|
|
58
|
+
if (!isBinary) {
|
|
59
|
+
log(`Received an unexpected string WebSocket message: '${messageData.toString("utf-8")}'`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
let incomingMessage;
|
|
63
|
+
try {
|
|
64
|
+
incomingMessage = decodeMsgPack(messageData);
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
log(`Failed to decode binary WebSocket message. Reason: ${e}`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const requestId = incomingMessage.requestId;
|
|
71
|
+
if (!requestId) {
|
|
72
|
+
log("Received a WebSocket message without a request ID");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
requestIdToWebSocket.set(requestId, ws);
|
|
76
|
+
worker.postMessage(incomingMessage);
|
|
77
|
+
});
|
|
78
|
+
ws.on('error', (e) => {
|
|
79
|
+
log(e);
|
|
80
|
+
});
|
|
81
|
+
ws.on("close", () => {
|
|
82
|
+
const keysToDelete = [];
|
|
83
|
+
requestIdToWebSocket.forEach((value, key) => {
|
|
84
|
+
if (value == ws) {
|
|
85
|
+
keysToDelete.push(key);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
keysToDelete.forEach(key => requestIdToWebSocket.delete(key));
|
|
89
|
+
log(`Incoming connection from ${req.socket.remoteAddress} was closed`);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
return serverOpenPromise.promise;
|
|
16
93
|
}
|
|
17
|
-
|
|
94
|
+
export const defaultServerOptions = {
|
|
95
|
+
port: 4000,
|
|
96
|
+
secure: false,
|
|
97
|
+
certPath: undefined,
|
|
98
|
+
keyPath: undefined,
|
|
99
|
+
deflate: true,
|
|
100
|
+
maxPayload: 1000 * 1000000 // 1GB
|
|
101
|
+
};
|
|
18
102
|
//# sourceMappingURL=Server.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Server.js","sourceRoot":"","sources":["../../src/server/Server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"Server.js","sourceRoot":"","sources":["../../src/server/Server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { logToStderr, setupProgramTerminationListeners, setupUnhandledExceptionListeners } from '../utilities/Utilities.js';
|
|
2
|
+
import { startWebSocketServer } from './Server.js';
|
|
3
|
+
const log = logToStderr;
|
|
4
|
+
setupUnhandledExceptionListeners();
|
|
5
|
+
setupProgramTerminationListeners(() => {
|
|
6
|
+
log('');
|
|
7
|
+
});
|
|
8
|
+
await startWebSocketServer({}, (options) => {
|
|
9
|
+
});
|
|
10
|
+
//# sourceMappingURL=ServerStarter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ServerStarter.js","sourceRoot":"","sources":["../../src/server/ServerStarter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,gCAAgC,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAA;AAC3H,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAElD,MAAM,GAAG,GAAG,WAAW,CAAA;AAEvB,gCAAgC,EAAE,CAAA;AAElC,gCAAgC,CAAC,GAAG,EAAE;IACrC,GAAG,CAAC,EAAE,CAAC,CAAA;AACR,CAAC,CAAC,CAAA;AAEF,MAAM,oBAAoB,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE;AAC3C,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { RequestVoiceListResult, SynthesisOptions, SynthesisSegmentEventData, SynthesizeSegmentsResult, VoiceListRequestOptions } from "../api/Synthesis.js";
|
|
2
|
+
import { RawAudio } from "../audio/AudioUtilities.js";
|
|
3
|
+
import { RecognitionOptions, RecognitionResult } from "../api/Recognition.js";
|
|
4
|
+
import { AlignmentOptions, AlignmentResult } from "../api/Alignment.js";
|
|
5
|
+
import { SpeechTranslationOptions, SpeechTranslationResult } from "../api/Translation.js";
|
|
6
|
+
export declare function processMessage(message: WorkerRequestMessage, postMessage: PostMessageFunc): Promise<void>;
|
|
7
|
+
export interface SynthesizeSegmentsRequestMessage extends WorkerMessageBase {
|
|
8
|
+
messageType: "SynthesizeSegmentsRequest";
|
|
9
|
+
segments: string[];
|
|
10
|
+
options: SynthesisOptions;
|
|
11
|
+
}
|
|
12
|
+
export interface SynthesizeSegmentsResponseMessage extends WorkerMessageBase, SynthesizeSegmentsResult {
|
|
13
|
+
messageType: "SynthesizeSegmentsResponse";
|
|
14
|
+
}
|
|
15
|
+
export interface SynthesisSegmentEventMessage extends WorkerMessageBase, SynthesisSegmentEventData {
|
|
16
|
+
messageType: "SynthesisSegmentEvent";
|
|
17
|
+
}
|
|
18
|
+
export interface SynthesisSentenceEventMessage extends WorkerMessageBase, SynthesisSegmentEventData {
|
|
19
|
+
messageType: "SynthesisSentenceEvent";
|
|
20
|
+
}
|
|
21
|
+
export interface VoiceListRequestMessage extends WorkerMessageBase {
|
|
22
|
+
messageType: "VoiceListRequest";
|
|
23
|
+
options: VoiceListRequestOptions;
|
|
24
|
+
}
|
|
25
|
+
export interface VoiceListResponseMessage extends WorkerMessageBase, RequestVoiceListResult {
|
|
26
|
+
messageType: "VoiceListResponse";
|
|
27
|
+
}
|
|
28
|
+
export interface RecognitionRequestMessage extends WorkerMessageBase {
|
|
29
|
+
messageType: "RecognitionRequest";
|
|
30
|
+
inputRawAudio: RawAudio;
|
|
31
|
+
options: RecognitionOptions;
|
|
32
|
+
}
|
|
33
|
+
export interface RecognitionResponseMessage extends WorkerMessageBase, RecognitionResult {
|
|
34
|
+
messageType: "RecognitionResponse";
|
|
35
|
+
}
|
|
36
|
+
export interface AlignmentRequestMessage extends WorkerMessageBase {
|
|
37
|
+
messageType: "AlignmentRequest";
|
|
38
|
+
inputRawAudio: RawAudio;
|
|
39
|
+
transcript: string;
|
|
40
|
+
options: AlignmentOptions;
|
|
41
|
+
}
|
|
42
|
+
export interface AlignmentResponseMessage extends WorkerMessageBase, AlignmentResult {
|
|
43
|
+
messageType: "AlignmentResponse";
|
|
44
|
+
}
|
|
45
|
+
export interface SpeechTranslationRequestMessage extends WorkerMessageBase {
|
|
46
|
+
messageType: "SpeechTranslationRequest";
|
|
47
|
+
inputRawAudio: RawAudio;
|
|
48
|
+
options: SpeechTranslationOptions;
|
|
49
|
+
}
|
|
50
|
+
export interface SpeechTranslationResponseMessage extends WorkerMessageBase, SpeechTranslationResult {
|
|
51
|
+
messageType: "SpeechTranslationResponse";
|
|
52
|
+
}
|
|
53
|
+
export type WorkerRequestMessage = SynthesizeSegmentsRequestMessage | VoiceListRequestMessage | RecognitionRequestMessage | AlignmentRequestMessage | SpeechTranslationRequestMessage;
|
|
54
|
+
export interface WorkerMessageBase {
|
|
55
|
+
messageType: string;
|
|
56
|
+
}
|
|
57
|
+
export type PostMessageFunc = (response: any) => void;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { requestVoiceList, synthesizeSegments } from "../api/Synthesis.js";
|
|
2
|
+
import { Queue } from "../utilities/Queue.js";
|
|
3
|
+
import { isMainThread, parentPort } from 'node:worker_threads';
|
|
4
|
+
import { logToStderr } from "../utilities/Utilities.js";
|
|
5
|
+
import { recognize } from "../api/Recognition.js";
|
|
6
|
+
import { align } from "../api/Alignment.js";
|
|
7
|
+
import { translateSpeech } from "../api/Translation.js";
|
|
8
|
+
const log = logToStderr;
|
|
9
|
+
function startIfInWorkerThread() {
|
|
10
|
+
if (isMainThread || !parentPort) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const messageQueue = new Queue();
|
|
14
|
+
let isProcessing = false;
|
|
15
|
+
async function processQueueIfIdle() {
|
|
16
|
+
if (isProcessing) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
isProcessing = true;
|
|
20
|
+
while (!messageQueue.isEmpty) {
|
|
21
|
+
const incomingMessage = messageQueue.dequeue();
|
|
22
|
+
const requestId = incomingMessage.requestId;
|
|
23
|
+
function postMessage(outgoingMessage) {
|
|
24
|
+
parentPort?.postMessage({
|
|
25
|
+
requestId,
|
|
26
|
+
...outgoingMessage,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
await processMessage(incomingMessage, postMessage);
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
log(`${e}`);
|
|
34
|
+
parentPort?.postMessage({
|
|
35
|
+
requestId,
|
|
36
|
+
messageType: "Error",
|
|
37
|
+
error: e
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
isProcessing = false;
|
|
42
|
+
}
|
|
43
|
+
parentPort.on("message", (message) => {
|
|
44
|
+
messageQueue.enqueue(message);
|
|
45
|
+
processQueueIfIdle();
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
export async function processMessage(message, postMessage) {
|
|
49
|
+
switch (message.messageType) {
|
|
50
|
+
case "SynthesizeSegmentsRequest": {
|
|
51
|
+
await processSynthesizeSegmentsRequest(message, postMessage);
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
case "VoiceListRequest": {
|
|
55
|
+
await processVoiceListRequest(message, postMessage);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case "RecognitionRequest": {
|
|
59
|
+
await processRecognitionRequest(message, postMessage);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case "AlignmentRequest": {
|
|
63
|
+
await processAlignmentRequest(message, postMessage);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
case "SpeechTranslationRequest": {
|
|
67
|
+
await processSpeechTranslationRequest(message, postMessage);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
default: {
|
|
71
|
+
throw new Error(`Invalid message type: ${message.messageType}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
76
|
+
// Synthesis operations
|
|
77
|
+
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
78
|
+
async function processSynthesizeSegmentsRequest(message, postMessage) {
|
|
79
|
+
async function onSegment(eventData) {
|
|
80
|
+
const responseMessage = {
|
|
81
|
+
messageType: "SynthesisSegmentEvent",
|
|
82
|
+
...eventData
|
|
83
|
+
};
|
|
84
|
+
postMessage(responseMessage);
|
|
85
|
+
}
|
|
86
|
+
async function onSentence(eventData) {
|
|
87
|
+
const responseMessage = {
|
|
88
|
+
messageType: "SynthesisSentenceEvent",
|
|
89
|
+
...eventData
|
|
90
|
+
};
|
|
91
|
+
postMessage(responseMessage);
|
|
92
|
+
}
|
|
93
|
+
const result = await synthesizeSegments(message.segments, message.options, onSegment, onSentence);
|
|
94
|
+
const responseMessage = {
|
|
95
|
+
messageType: "SynthesizeSegmentsResponse",
|
|
96
|
+
...result
|
|
97
|
+
};
|
|
98
|
+
postMessage(responseMessage);
|
|
99
|
+
}
|
|
100
|
+
async function processVoiceListRequest(message, postMessage) {
|
|
101
|
+
const result = await requestVoiceList(message.options);
|
|
102
|
+
const responseMessage = {
|
|
103
|
+
messageType: "VoiceListResponse",
|
|
104
|
+
...result
|
|
105
|
+
};
|
|
106
|
+
postMessage(responseMessage);
|
|
107
|
+
}
|
|
108
|
+
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
109
|
+
// Recognition operations
|
|
110
|
+
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
111
|
+
async function processRecognitionRequest(message, postMessage) {
|
|
112
|
+
const result = await recognize(message.inputRawAudio, message.options);
|
|
113
|
+
const responseMessage = {
|
|
114
|
+
messageType: "RecognitionResponse",
|
|
115
|
+
...result
|
|
116
|
+
};
|
|
117
|
+
postMessage(responseMessage);
|
|
118
|
+
}
|
|
119
|
+
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
120
|
+
// Alignment operations
|
|
121
|
+
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
122
|
+
async function processAlignmentRequest(message, postMessage) {
|
|
123
|
+
const result = await align(message.inputRawAudio, message.transcript, message.options);
|
|
124
|
+
const responseMessage = {
|
|
125
|
+
messageType: "AlignmentResponse",
|
|
126
|
+
...result
|
|
127
|
+
};
|
|
128
|
+
postMessage(responseMessage);
|
|
129
|
+
}
|
|
130
|
+
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
131
|
+
// Speech translation operations
|
|
132
|
+
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
133
|
+
async function processSpeechTranslationRequest(message, postMessage) {
|
|
134
|
+
const result = await translateSpeech(message.inputRawAudio, message.options);
|
|
135
|
+
const responseMessage = {
|
|
136
|
+
messageType: "SpeechTranslationResponse",
|
|
137
|
+
...result
|
|
138
|
+
};
|
|
139
|
+
postMessage(responseMessage);
|
|
140
|
+
}
|
|
141
|
+
// Start worker if running in worker thread
|
|
142
|
+
startIfInWorkerThread();
|
|
143
|
+
//# sourceMappingURL=Worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Worker.js","sourceRoot":"","sources":["../../src/server/Worker.ts"],"names":[],"mappings":"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"}
|