speechflow 1.7.1 → 2.0.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.
- package/CHANGELOG.md +24 -0
- package/README.md +388 -120
- package/etc/claude.md +5 -5
- package/etc/speechflow.yaml +2 -2
- package/package.json +3 -3
- package/speechflow-cli/dst/speechflow-main-api.js.map +1 -1
- package/speechflow-cli/dst/speechflow-main-cli.js +1 -0
- package/speechflow-cli/dst/speechflow-main-cli.js.map +1 -1
- package/speechflow-cli/dst/speechflow-main-graph.d.ts +1 -0
- package/speechflow-cli/dst/speechflow-main-graph.js +30 -9
- package/speechflow-cli/dst/speechflow-main-graph.js.map +1 -1
- package/speechflow-cli/dst/speechflow-main-nodes.js +1 -0
- package/speechflow-cli/dst/speechflow-main-nodes.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.js +1 -0
- package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-compressor.js +7 -9
- package/speechflow-cli/dst/speechflow-node-a2a-compressor.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-expander-wt.js +1 -0
- package/speechflow-cli/dst/speechflow-node-a2a-expander-wt.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-expander.js +8 -9
- package/speechflow-cli/dst/speechflow-node-a2a-expander.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-filler.js +2 -0
- package/speechflow-cli/dst/speechflow-node-a2a-filler.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gender.js +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gender.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-meter.js +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-pitch.js +11 -9
- package/speechflow-cli/dst/speechflow-node-a2a-pitch.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-rnnoise-wt.js +1 -0
- package/speechflow-cli/dst/speechflow-node-a2a-rnnoise-wt.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-speex.js +4 -2
- package/speechflow-cli/dst/speechflow-node-a2a-speex.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-vad.js +19 -22
- package/speechflow-cli/dst/speechflow-node-a2a-vad.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-wav.js +31 -4
- package/speechflow-cli/dst/speechflow-node-a2a-wav.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.d.ts +0 -1
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.js +2 -11
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-google.d.ts +16 -0
- package/speechflow-cli/dst/speechflow-node-a2t-google.js +314 -0
- package/speechflow-cli/dst/speechflow-node-a2t-google.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-a2t-openai.js +6 -1
- package/speechflow-cli/dst/speechflow-node-a2t-openai.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-amazon.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-amazon.js +27 -7
- package/speechflow-cli/dst/speechflow-node-t2a-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js +5 -3
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-google.d.ts +15 -0
- package/speechflow-cli/dst/speechflow-node-t2a-google.js +215 -0
- package/speechflow-cli/dst/speechflow-node-t2a-google.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-t2a-kokoro.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js +27 -6
- package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-openai.d.ts +15 -0
- package/speechflow-cli/dst/speechflow-node-t2a-openai.js +192 -0
- package/speechflow-cli/dst/speechflow-node-t2a-openai.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-t2a-supertonic.d.ts +17 -0
- package/speechflow-cli/dst/speechflow-node-t2a-supertonic.js +619 -0
- package/speechflow-cli/dst/speechflow-node-t2a-supertonic.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-t2t-amazon.js +0 -2
- package/speechflow-cli/dst/speechflow-node-t2t-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-deepl.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-google.js.map +1 -1
- package/speechflow-cli/dst/{speechflow-node-t2t-transformers.d.ts → speechflow-node-t2t-opus.d.ts} +1 -3
- package/speechflow-cli/dst/speechflow-node-t2t-opus.js +161 -0
- package/speechflow-cli/dst/speechflow-node-t2t-opus.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-t2t-profanity.d.ts +11 -0
- package/speechflow-cli/dst/speechflow-node-t2t-profanity.js +118 -0
- package/speechflow-cli/dst/speechflow-node-t2t-profanity.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-t2t-punctuation.d.ts +13 -0
- package/speechflow-cli/dst/speechflow-node-t2t-punctuation.js +220 -0
- package/speechflow-cli/dst/speechflow-node-t2t-punctuation.js.map +1 -0
- package/speechflow-cli/dst/{speechflow-node-t2t-openai.d.ts → speechflow-node-t2t-spellcheck.d.ts} +2 -2
- package/speechflow-cli/dst/{speechflow-node-t2t-openai.js → speechflow-node-t2t-spellcheck.js} +48 -100
- package/speechflow-cli/dst/speechflow-node-t2t-spellcheck.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js +8 -8
- package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-summary.d.ts +16 -0
- package/speechflow-cli/dst/speechflow-node-t2t-summary.js +241 -0
- package/speechflow-cli/dst/speechflow-node-t2t-summary.js.map +1 -0
- package/speechflow-cli/dst/{speechflow-node-t2t-ollama.d.ts → speechflow-node-t2t-translate.d.ts} +2 -2
- package/speechflow-cli/dst/{speechflow-node-t2t-transformers.js → speechflow-node-t2t-translate.js} +53 -115
- package/speechflow-cli/dst/speechflow-node-t2t-translate.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-x2x-filter.js +2 -0
- package/speechflow-cli/dst/speechflow-node-x2x-filter.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-exec.d.ts +12 -0
- package/speechflow-cli/dst/speechflow-node-xio-exec.js +224 -0
- package/speechflow-cli/dst/speechflow-node-xio-exec.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-xio-file.d.ts +1 -0
- package/speechflow-cli/dst/speechflow-node-xio-file.js +78 -67
- package/speechflow-cli/dst/speechflow-node-xio-file.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-mqtt.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-vban.d.ts +17 -0
- package/speechflow-cli/dst/speechflow-node-xio-vban.js +330 -0
- package/speechflow-cli/dst/speechflow-node-xio-vban.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-xio-webrtc.d.ts +39 -0
- package/speechflow-cli/dst/speechflow-node-xio-webrtc.js +502 -0
- package/speechflow-cli/dst/speechflow-node-xio-webrtc.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-xio-websocket.js +9 -9
- package/speechflow-cli/dst/speechflow-node-xio-websocket.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-audio.js +8 -5
- package/speechflow-cli/dst/speechflow-util-audio.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-error.d.ts +1 -0
- package/speechflow-cli/dst/speechflow-util-error.js +5 -0
- package/speechflow-cli/dst/speechflow-util-error.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-llm.d.ts +35 -0
- package/speechflow-cli/dst/speechflow-util-llm.js +363 -0
- package/speechflow-cli/dst/speechflow-util-llm.js.map +1 -0
- package/speechflow-cli/dst/speechflow-util-queue.js +2 -1
- package/speechflow-cli/dst/speechflow-util-queue.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util.d.ts +1 -0
- package/speechflow-cli/dst/speechflow-util.js +2 -0
- package/speechflow-cli/dst/speechflow-util.js.map +1 -1
- package/speechflow-cli/etc/oxlint.jsonc +2 -1
- package/speechflow-cli/package.json +35 -18
- package/speechflow-cli/src/lib.d.ts +5 -0
- package/speechflow-cli/src/speechflow-main-api.ts +16 -16
- package/speechflow-cli/src/speechflow-main-cli.ts +1 -0
- package/speechflow-cli/src/speechflow-main-graph.ts +38 -14
- package/speechflow-cli/src/speechflow-main-nodes.ts +1 -0
- package/speechflow-cli/src/speechflow-node-a2a-compressor-wt.ts +1 -0
- package/speechflow-cli/src/speechflow-node-a2a-compressor.ts +8 -10
- package/speechflow-cli/src/speechflow-node-a2a-expander-wt.ts +1 -0
- package/speechflow-cli/src/speechflow-node-a2a-expander.ts +9 -10
- package/speechflow-cli/src/speechflow-node-a2a-filler.ts +2 -0
- package/speechflow-cli/src/speechflow-node-a2a-gender.ts +3 -3
- package/speechflow-cli/src/speechflow-node-a2a-meter.ts +2 -2
- package/speechflow-cli/src/speechflow-node-a2a-pitch.ts +11 -9
- package/speechflow-cli/src/speechflow-node-a2a-rnnoise-wt.ts +1 -0
- package/speechflow-cli/src/speechflow-node-a2a-rnnoise.ts +1 -1
- package/speechflow-cli/src/speechflow-node-a2a-speex.ts +5 -3
- package/speechflow-cli/src/speechflow-node-a2a-vad.ts +20 -23
- package/speechflow-cli/src/speechflow-node-a2a-wav.ts +31 -4
- package/speechflow-cli/src/speechflow-node-a2t-amazon.ts +6 -18
- package/speechflow-cli/src/speechflow-node-a2t-google.ts +315 -0
- package/speechflow-cli/src/speechflow-node-a2t-openai.ts +12 -7
- package/speechflow-cli/src/speechflow-node-t2a-amazon.ts +32 -10
- package/speechflow-cli/src/speechflow-node-t2a-elevenlabs.ts +6 -4
- package/speechflow-cli/src/speechflow-node-t2a-google.ts +203 -0
- package/speechflow-cli/src/speechflow-node-t2a-kokoro.ts +33 -10
- package/speechflow-cli/src/speechflow-node-t2a-openai.ts +176 -0
- package/speechflow-cli/src/speechflow-node-t2a-supertonic.ts +710 -0
- package/speechflow-cli/src/speechflow-node-t2t-amazon.ts +3 -4
- package/speechflow-cli/src/speechflow-node-t2t-deepl.ts +2 -2
- package/speechflow-cli/src/speechflow-node-t2t-google.ts +1 -1
- package/speechflow-cli/src/speechflow-node-t2t-opus.ts +137 -0
- package/speechflow-cli/src/speechflow-node-t2t-profanity.ts +93 -0
- package/speechflow-cli/src/speechflow-node-t2t-punctuation.ts +201 -0
- package/speechflow-cli/src/speechflow-node-t2t-spellcheck.ts +188 -0
- package/speechflow-cli/src/speechflow-node-t2t-subtitle.ts +8 -8
- package/speechflow-cli/src/speechflow-node-t2t-summary.ts +229 -0
- package/speechflow-cli/src/speechflow-node-t2t-translate.ts +181 -0
- package/speechflow-cli/src/speechflow-node-x2x-filter.ts +2 -0
- package/speechflow-cli/src/speechflow-node-xio-exec.ts +211 -0
- package/speechflow-cli/src/speechflow-node-xio-file.ts +91 -80
- package/speechflow-cli/src/speechflow-node-xio-mqtt.ts +2 -2
- package/speechflow-cli/src/speechflow-node-xio-vban.ts +325 -0
- package/speechflow-cli/src/speechflow-node-xio-webrtc.ts +535 -0
- package/speechflow-cli/src/speechflow-node-xio-websocket.ts +9 -9
- package/speechflow-cli/src/speechflow-util-audio.ts +10 -5
- package/speechflow-cli/src/speechflow-util-error.ts +9 -0
- package/speechflow-cli/src/speechflow-util-llm.ts +367 -0
- package/speechflow-cli/src/speechflow-util-queue.ts +3 -3
- package/speechflow-cli/src/speechflow-util.ts +2 -0
- package/speechflow-ui-db/package.json +9 -9
- package/speechflow-ui-st/package.json +9 -9
- package/speechflow-cli/dst/speechflow-node-t2t-ollama.js +0 -293
- package/speechflow-cli/dst/speechflow-node-t2t-ollama.js.map +0 -1
- package/speechflow-cli/dst/speechflow-node-t2t-openai.js.map +0 -1
- package/speechflow-cli/dst/speechflow-node-t2t-transformers.js.map +0 -1
- package/speechflow-cli/src/speechflow-node-t2t-ollama.ts +0 -281
- package/speechflow-cli/src/speechflow-node-t2t-openai.ts +0 -247
- package/speechflow-cli/src/speechflow-node-t2t-transformers.ts +0 -247
|
@@ -2,8 +2,8 @@ import SpeechFlowNode from "./speechflow-node";
|
|
|
2
2
|
export default class SpeechFlowNodeT2AElevenlabs extends SpeechFlowNode {
|
|
3
3
|
static name: string;
|
|
4
4
|
private elevenlabs;
|
|
5
|
-
private closing;
|
|
6
5
|
private resampler;
|
|
6
|
+
private closing;
|
|
7
7
|
constructor(id: string, cfg: {
|
|
8
8
|
[id: string]: any;
|
|
9
9
|
}, opts: {
|
|
@@ -57,8 +57,8 @@ class SpeechFlowNodeT2AElevenlabs extends speechflow_node_1.default {
|
|
|
57
57
|
static name = "t2a-elevenlabs";
|
|
58
58
|
/* internal state */
|
|
59
59
|
elevenlabs = null;
|
|
60
|
-
closing = false;
|
|
61
60
|
resampler = null;
|
|
61
|
+
closing = false;
|
|
62
62
|
/* construct node */
|
|
63
63
|
constructor(id, cfg, opts, args) {
|
|
64
64
|
super(id, cfg, opts, args);
|
|
@@ -153,8 +153,8 @@ class SpeechFlowNodeT2AElevenlabs extends speechflow_node_1.default {
|
|
|
153
153
|
maxRetries: 10
|
|
154
154
|
});
|
|
155
155
|
};
|
|
156
|
-
/* establish resampler from ElevenLabs's
|
|
157
|
-
output to our standard audio sample rate (48KHz) */
|
|
156
|
+
/* establish resampler from ElevenLabs's tier-dependent
|
|
157
|
+
output sample rate to our standard audio sample rate (48KHz) */
|
|
158
158
|
this.resampler = new speex_resampler_1.default(1, maxSampleRate, this.config.audioSampleRate, 7);
|
|
159
159
|
/* create transform stream and connect it to the ElevenLabs API */
|
|
160
160
|
const self = this;
|
|
@@ -168,6 +168,8 @@ class SpeechFlowNodeT2AElevenlabs extends speechflow_node_1.default {
|
|
|
168
168
|
callback(new Error("stream already destroyed"));
|
|
169
169
|
else if (Buffer.isBuffer(chunk.payload))
|
|
170
170
|
callback(new Error("invalid chunk payload type"));
|
|
171
|
+
else if (chunk.payload === "")
|
|
172
|
+
callback();
|
|
171
173
|
else {
|
|
172
174
|
let processTimeout = setTimeout(() => {
|
|
173
175
|
processTimeout = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speechflow-node-t2a-elevenlabs.js","sourceRoot":"","sources":["../src/speechflow-node-t2a-elevenlabs.ts"],"names":[],"mappings":";AAAA;;;;EAIE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEF,6BAA6B;AAC7B,8DAAgC;AAEhC,6BAA6B;AAC7B,sEAA6D;AAC7D,2CAA8C;AAC9C,iCAAyC;AACzC,sEAAmD;AAEnD,6BAA6B;AAC7B,wEAAmE;AACnE,wDAAmE;AAEnE,gEAAgE;AAChE,MAAqB,2BAA4B,SAAQ,yBAAc;IACnE,kCAAkC;IAC3B,MAAM,CAAC,IAAI,GAAG,gBAAgB,CAAA;IAErC,sBAAsB;IACd,UAAU,GAAuC,IAAI,CAAA;IACrD,
|
|
1
|
+
{"version":3,"file":"speechflow-node-t2a-elevenlabs.js","sourceRoot":"","sources":["../src/speechflow-node-t2a-elevenlabs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import SpeechFlowNode from "./speechflow-node";
|
|
2
|
+
export default class SpeechFlowNodeT2AGoogle extends SpeechFlowNode {
|
|
3
|
+
static name: string;
|
|
4
|
+
private client;
|
|
5
|
+
private resampler;
|
|
6
|
+
private closing;
|
|
7
|
+
constructor(id: string, cfg: {
|
|
8
|
+
[id: string]: any;
|
|
9
|
+
}, opts: {
|
|
10
|
+
[id: string]: any;
|
|
11
|
+
}, args: any[]);
|
|
12
|
+
status(): Promise<{}>;
|
|
13
|
+
open(): Promise<void>;
|
|
14
|
+
close(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
** SpeechFlow - Speech Processing Flow Graph
|
|
4
|
+
** Copyright (c) 2024-2025 Dr. Ralf S. Engelschall <rse@engelschall.com>
|
|
5
|
+
** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
+
};
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
/* standard dependencies */
|
|
45
|
+
const node_stream_1 = __importDefault(require("node:stream"));
|
|
46
|
+
/* external dependencies */
|
|
47
|
+
const GoogleTTS = __importStar(require("@google-cloud/text-to-speech"));
|
|
48
|
+
const luxon_1 = require("luxon");
|
|
49
|
+
const speex_resampler_1 = __importDefault(require("speex-resampler"));
|
|
50
|
+
const arktype = __importStar(require("arktype"));
|
|
51
|
+
/* internal dependencies */
|
|
52
|
+
const speechflow_node_1 = __importDefault(require("./speechflow-node"));
|
|
53
|
+
const util = __importStar(require("./speechflow-util"));
|
|
54
|
+
/* SpeechFlow node for Google Cloud text-to-speech conversion */
|
|
55
|
+
class SpeechFlowNodeT2AGoogle extends speechflow_node_1.default {
|
|
56
|
+
/* declare official node name */
|
|
57
|
+
static name = "t2a-google";
|
|
58
|
+
/* internal state */
|
|
59
|
+
client = null;
|
|
60
|
+
resampler = null;
|
|
61
|
+
closing = false;
|
|
62
|
+
/* construct node */
|
|
63
|
+
constructor(id, cfg, opts, args) {
|
|
64
|
+
super(id, cfg, opts, args);
|
|
65
|
+
/* declare node configuration parameters */
|
|
66
|
+
this.configure({
|
|
67
|
+
key: { type: "string", val: process.env.SPEECHFLOW_GOOGLE_KEY ?? "" },
|
|
68
|
+
voice: { type: "string", pos: 0, val: "en-US-Neural2-J" },
|
|
69
|
+
language: { type: "string", pos: 1, val: "en-US" },
|
|
70
|
+
speed: { type: "number", pos: 2, val: 1.0, match: (n) => n >= 0.25 && n <= 4.0 },
|
|
71
|
+
pitch: { type: "number", pos: 3, val: 0.0, match: (n) => n >= -20.0 && n <= 20.0 }
|
|
72
|
+
});
|
|
73
|
+
/* validate API key */
|
|
74
|
+
if (this.params.key === "")
|
|
75
|
+
throw new Error("Google Cloud API credentials JSON key is required");
|
|
76
|
+
/* declare node input/output format */
|
|
77
|
+
this.input = "text";
|
|
78
|
+
this.output = "audio";
|
|
79
|
+
}
|
|
80
|
+
/* one-time status of node */
|
|
81
|
+
async status() {
|
|
82
|
+
return {};
|
|
83
|
+
}
|
|
84
|
+
/* open node */
|
|
85
|
+
async open() {
|
|
86
|
+
/* clear destruction flag */
|
|
87
|
+
this.closing = false;
|
|
88
|
+
/* instantiate Google TTS client */
|
|
89
|
+
const data = util.run("Google Cloud API credentials key", () => JSON.parse(this.params.key));
|
|
90
|
+
const credentials = util.importObject("Google Cloud API credentials key", data, arktype.type({
|
|
91
|
+
project_id: "string",
|
|
92
|
+
private_key: "string",
|
|
93
|
+
client_email: "string"
|
|
94
|
+
}));
|
|
95
|
+
this.client = new GoogleTTS.TextToSpeechClient({
|
|
96
|
+
credentials: {
|
|
97
|
+
private_key: credentials.private_key,
|
|
98
|
+
client_email: credentials.client_email
|
|
99
|
+
},
|
|
100
|
+
projectId: credentials.project_id
|
|
101
|
+
});
|
|
102
|
+
/* establish resampler from Google TTS's output sample rate
|
|
103
|
+
to our standard audio sample rate (48KHz) */
|
|
104
|
+
const googleSampleRate = 24000; /* Google TTS outputs 24kHz for LINEAR16 */
|
|
105
|
+
this.resampler = new speex_resampler_1.default(1, googleSampleRate, this.config.audioSampleRate, 7);
|
|
106
|
+
/* perform text-to-speech operation with Google Cloud TTS API */
|
|
107
|
+
const textToSpeech = async (text) => {
|
|
108
|
+
this.log("info", `Google TTS: send text "${text}"`);
|
|
109
|
+
const [response] = await this.client.synthesizeSpeech({
|
|
110
|
+
input: { text },
|
|
111
|
+
voice: {
|
|
112
|
+
languageCode: this.params.language,
|
|
113
|
+
name: this.params.voice
|
|
114
|
+
},
|
|
115
|
+
audioConfig: {
|
|
116
|
+
audioEncoding: "LINEAR16",
|
|
117
|
+
sampleRateHertz: googleSampleRate,
|
|
118
|
+
speakingRate: this.params.speed,
|
|
119
|
+
pitch: this.params.pitch
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
if (!response.audioContent)
|
|
123
|
+
throw new Error("no audio content returned from Google TTS");
|
|
124
|
+
/* convert response to buffer */
|
|
125
|
+
const buffer = Buffer.isBuffer(response.audioContent)
|
|
126
|
+
? response.audioContent
|
|
127
|
+
: Buffer.from(response.audioContent);
|
|
128
|
+
this.log("info", `Google TTS: received audio (buffer length: ${buffer.byteLength})`);
|
|
129
|
+
/* resample from Google's sample rate to our standard rate */
|
|
130
|
+
const bufferResampled = this.resampler.processChunk(buffer);
|
|
131
|
+
this.log("info", `Google TTS: forwarding resampled audio (buffer length: ${bufferResampled.byteLength})`);
|
|
132
|
+
return bufferResampled;
|
|
133
|
+
};
|
|
134
|
+
/* create transform stream and connect it to the Google TTS API */
|
|
135
|
+
const self = this;
|
|
136
|
+
this.stream = new node_stream_1.default.Transform({
|
|
137
|
+
writableObjectMode: true,
|
|
138
|
+
readableObjectMode: true,
|
|
139
|
+
decodeStrings: false,
|
|
140
|
+
highWaterMark: 1,
|
|
141
|
+
async transform(chunk, encoding, callback) {
|
|
142
|
+
if (self.closing)
|
|
143
|
+
callback(new Error("stream already destroyed"));
|
|
144
|
+
else if (Buffer.isBuffer(chunk.payload))
|
|
145
|
+
callback(new Error("invalid chunk payload type"));
|
|
146
|
+
else if (chunk.payload === "")
|
|
147
|
+
callback();
|
|
148
|
+
else {
|
|
149
|
+
let processTimeout = setTimeout(() => {
|
|
150
|
+
processTimeout = null;
|
|
151
|
+
callback(new Error("Google TTS API timeout"));
|
|
152
|
+
}, 60 * 1000);
|
|
153
|
+
const clearProcessTimeout = () => {
|
|
154
|
+
if (processTimeout !== null) {
|
|
155
|
+
clearTimeout(processTimeout);
|
|
156
|
+
processTimeout = null;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
try {
|
|
160
|
+
if (self.closing) {
|
|
161
|
+
clearProcessTimeout();
|
|
162
|
+
callback(new Error("stream destroyed during processing"));
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const buffer = await textToSpeech(chunk.payload);
|
|
166
|
+
if (self.closing) {
|
|
167
|
+
clearProcessTimeout();
|
|
168
|
+
callback(new Error("stream destroyed during processing"));
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
/* calculate actual audio duration from PCM buffer size */
|
|
172
|
+
const durationMs = util.audioBufferDuration(buffer, self.config.audioSampleRate, self.config.audioBitDepth) * 1000;
|
|
173
|
+
/* create new chunk with recalculated timestamps */
|
|
174
|
+
const chunkNew = chunk.clone();
|
|
175
|
+
chunkNew.type = "audio";
|
|
176
|
+
chunkNew.payload = buffer;
|
|
177
|
+
chunkNew.timestampEnd = luxon_1.Duration.fromMillis(chunkNew.timestampStart.toMillis() + durationMs);
|
|
178
|
+
clearProcessTimeout();
|
|
179
|
+
this.push(chunkNew);
|
|
180
|
+
callback();
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
clearProcessTimeout();
|
|
184
|
+
callback(util.ensureError(error, "Google TTS processing failed"));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
final(callback) {
|
|
189
|
+
callback();
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/* close node */
|
|
194
|
+
async close() {
|
|
195
|
+
/* indicate closing */
|
|
196
|
+
this.closing = true;
|
|
197
|
+
/* shutdown stream */
|
|
198
|
+
if (this.stream !== null) {
|
|
199
|
+
await util.destroyStream(this.stream);
|
|
200
|
+
this.stream = null;
|
|
201
|
+
}
|
|
202
|
+
/* destroy resampler */
|
|
203
|
+
if (this.resampler !== null)
|
|
204
|
+
this.resampler = null;
|
|
205
|
+
/* destroy Google TTS client */
|
|
206
|
+
if (this.client !== null) {
|
|
207
|
+
await this.client.close().catch((error) => {
|
|
208
|
+
this.log("warning", `error closing Google TTS client: ${error}`);
|
|
209
|
+
});
|
|
210
|
+
this.client = null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
exports.default = SpeechFlowNodeT2AGoogle;
|
|
215
|
+
//# sourceMappingURL=speechflow-node-t2a-google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speechflow-node-t2a-google.js","sourceRoot":"","sources":["../src/speechflow-node-t2a-google.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import SpeechFlowNode from "./speechflow-node";
|
|
|
2
2
|
export default class SpeechFlowNodeT2AKokoro extends SpeechFlowNode {
|
|
3
3
|
static name: string;
|
|
4
4
|
private kokoro;
|
|
5
|
-
private closing;
|
|
6
5
|
private resampler;
|
|
6
|
+
private closing;
|
|
7
7
|
constructor(id: string, cfg: {
|
|
8
8
|
[id: string]: any;
|
|
9
9
|
}, opts: {
|
|
@@ -45,6 +45,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
const node_stream_1 = __importDefault(require("node:stream"));
|
|
46
46
|
/* external dependencies */
|
|
47
47
|
const kokoro_js_1 = require("kokoro-js");
|
|
48
|
+
const luxon_1 = require("luxon");
|
|
48
49
|
const speex_resampler_1 = __importDefault(require("speex-resampler"));
|
|
49
50
|
/* internal dependencies */
|
|
50
51
|
const speechflow_node_1 = __importDefault(require("./speechflow-node"));
|
|
@@ -55,8 +56,8 @@ class SpeechFlowNodeT2AKokoro extends speechflow_node_1.default {
|
|
|
55
56
|
static name = "t2a-kokoro";
|
|
56
57
|
/* internal state */
|
|
57
58
|
kokoro = null;
|
|
58
|
-
closing = false;
|
|
59
59
|
resampler = null;
|
|
60
|
+
closing = false;
|
|
60
61
|
/* construct node */
|
|
61
62
|
constructor(id, cfg, opts, args) {
|
|
62
63
|
super(id, cfg, opts, args);
|
|
@@ -144,8 +145,7 @@ class SpeechFlowNodeT2AKokoro extends speechflow_node_1.default {
|
|
|
144
145
|
buffer1.writeInt16LE(sample * 0x7FFF, i * 2);
|
|
145
146
|
}
|
|
146
147
|
/* resample audio samples from PCM/I16/24Khz to PCM/I16/48KHz */
|
|
147
|
-
|
|
148
|
-
return buffer2;
|
|
148
|
+
return this.resampler.processChunk(buffer1);
|
|
149
149
|
};
|
|
150
150
|
/* create transform stream and connect it to the Kokoro API */
|
|
151
151
|
const self = this;
|
|
@@ -159,18 +159,39 @@ class SpeechFlowNodeT2AKokoro extends speechflow_node_1.default {
|
|
|
159
159
|
callback(new Error("stream already destroyed"));
|
|
160
160
|
else if (Buffer.isBuffer(chunk.payload))
|
|
161
161
|
callback(new Error("invalid chunk payload type"));
|
|
162
|
+
else if (chunk.payload === "")
|
|
163
|
+
callback();
|
|
162
164
|
else {
|
|
165
|
+
let processTimeout = setTimeout(() => {
|
|
166
|
+
processTimeout = null;
|
|
167
|
+
callback(new Error("Kokoro TTS timeout"));
|
|
168
|
+
}, 60 * 1000);
|
|
169
|
+
const clearProcessTimeout = () => {
|
|
170
|
+
if (processTimeout !== null) {
|
|
171
|
+
clearTimeout(processTimeout);
|
|
172
|
+
processTimeout = null;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
163
175
|
text2speech(chunk.payload).then((buffer) => {
|
|
164
|
-
if (self.closing)
|
|
165
|
-
|
|
176
|
+
if (self.closing) {
|
|
177
|
+
clearProcessTimeout();
|
|
178
|
+
callback(new Error("stream destroyed during processing"));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
166
181
|
self.log("info", `Kokoro: received audio (buffer length: ${buffer.byteLength})`);
|
|
182
|
+
/* calculate actual audio duration from PCM buffer size */
|
|
183
|
+
const durationMs = util.audioBufferDuration(buffer, self.config.audioSampleRate, self.config.audioBitDepth) * 1000;
|
|
184
|
+
/* create new chunk with recalculated timestamps */
|
|
167
185
|
const chunkNew = chunk.clone();
|
|
168
186
|
chunkNew.type = "audio";
|
|
169
187
|
chunkNew.payload = buffer;
|
|
188
|
+
chunkNew.timestampEnd = luxon_1.Duration.fromMillis(chunkNew.timestampStart.toMillis() + durationMs);
|
|
189
|
+
clearProcessTimeout();
|
|
170
190
|
this.push(chunkNew);
|
|
171
191
|
callback();
|
|
172
192
|
}).catch((error) => {
|
|
173
|
-
|
|
193
|
+
clearProcessTimeout();
|
|
194
|
+
callback(util.ensureError(error, "Kokoro processing failed"));
|
|
174
195
|
});
|
|
175
196
|
}
|
|
176
197
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speechflow-node-t2a-kokoro.js","sourceRoot":"","sources":["../src/speechflow-node-t2a-kokoro.ts"],"names":[],"mappings":";AAAA;;;;EAIE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEF,6BAA6B;AAC7B,8DAAgC;AAEhC,6BAA6B;AAC7B,yCAAsC;AACtC,sEAA4C;AAE5C,6BAA6B;AAC7B,wEAAmE;AACnE,wDAAmE;AAEnE,4DAA4D;AAC5D,MAAqB,uBAAwB,SAAQ,yBAAc;IAC/D,kCAAkC;IAC3B,MAAM,CAAC,IAAI,GAAG,YAAY,CAAA;IAEjC,sBAAsB;IACd,MAAM,
|
|
1
|
+
{"version":3,"file":"speechflow-node-t2a-kokoro.js","sourceRoot":"","sources":["../src/speechflow-node-t2a-kokoro.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import SpeechFlowNode from "./speechflow-node";
|
|
2
|
+
export default class SpeechFlowNodeT2AOpenAI extends SpeechFlowNode {
|
|
3
|
+
static name: string;
|
|
4
|
+
private openai;
|
|
5
|
+
private resampler;
|
|
6
|
+
private closing;
|
|
7
|
+
constructor(id: string, cfg: {
|
|
8
|
+
[id: string]: any;
|
|
9
|
+
}, opts: {
|
|
10
|
+
[id: string]: any;
|
|
11
|
+
}, args: any[]);
|
|
12
|
+
status(): Promise<{}>;
|
|
13
|
+
open(): Promise<void>;
|
|
14
|
+
close(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
** SpeechFlow - Speech Processing Flow Graph
|
|
4
|
+
** Copyright (c) 2024-2025 Dr. Ralf S. Engelschall <rse@engelschall.com>
|
|
5
|
+
** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
+
};
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
/* standard dependencies */
|
|
45
|
+
const node_stream_1 = __importDefault(require("node:stream"));
|
|
46
|
+
/* external dependencies */
|
|
47
|
+
const openai_1 = __importDefault(require("openai"));
|
|
48
|
+
const luxon_1 = require("luxon");
|
|
49
|
+
const speex_resampler_1 = __importDefault(require("speex-resampler"));
|
|
50
|
+
/* internal dependencies */
|
|
51
|
+
const speechflow_node_1 = __importDefault(require("./speechflow-node"));
|
|
52
|
+
const util = __importStar(require("./speechflow-util"));
|
|
53
|
+
/* SpeechFlow node for OpenAI text-to-speech conversion */
|
|
54
|
+
class SpeechFlowNodeT2AOpenAI extends speechflow_node_1.default {
|
|
55
|
+
/* declare official node name */
|
|
56
|
+
static name = "t2a-openai";
|
|
57
|
+
/* internal state */
|
|
58
|
+
openai = null;
|
|
59
|
+
resampler = null;
|
|
60
|
+
closing = false;
|
|
61
|
+
/* construct node */
|
|
62
|
+
constructor(id, cfg, opts, args) {
|
|
63
|
+
super(id, cfg, opts, args);
|
|
64
|
+
/* declare node configuration parameters */
|
|
65
|
+
this.configure({
|
|
66
|
+
key: { type: "string", val: process.env.SPEECHFLOW_OPENAI_KEY },
|
|
67
|
+
api: { type: "string", val: "https://api.openai.com/v1", match: /^https?:\/\/.+/ },
|
|
68
|
+
voice: { type: "string", val: "alloy", pos: 0, match: /^(?:alloy|echo|fable|onyx|nova|shimmer)$/ },
|
|
69
|
+
model: { type: "string", val: "tts-1", pos: 1, match: /^(?:tts-1|tts-1-hd)$/ },
|
|
70
|
+
speed: { type: "number", val: 1.0, pos: 2, match: (n) => n >= 0.25 && n <= 4.0 }
|
|
71
|
+
});
|
|
72
|
+
/* sanity check parameters */
|
|
73
|
+
if (!this.params.key)
|
|
74
|
+
throw new Error("OpenAI API key not configured");
|
|
75
|
+
/* declare node input/output format */
|
|
76
|
+
this.input = "text";
|
|
77
|
+
this.output = "audio";
|
|
78
|
+
}
|
|
79
|
+
/* one-time status of node */
|
|
80
|
+
async status() {
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
83
|
+
/* open node */
|
|
84
|
+
async open() {
|
|
85
|
+
/* clear destruction flag */
|
|
86
|
+
this.closing = false;
|
|
87
|
+
/* establish OpenAI API connection */
|
|
88
|
+
this.openai = new openai_1.default({
|
|
89
|
+
baseURL: this.params.api,
|
|
90
|
+
apiKey: this.params.key,
|
|
91
|
+
timeout: 60000
|
|
92
|
+
});
|
|
93
|
+
/* establish resampler from OpenAI's 24Khz PCM output
|
|
94
|
+
to our standard audio sample rate (48KHz) */
|
|
95
|
+
this.resampler = new speex_resampler_1.default(1, 24000, this.config.audioSampleRate, 7);
|
|
96
|
+
/* perform text-to-speech operation with OpenAI API */
|
|
97
|
+
const textToSpeech = async (text) => {
|
|
98
|
+
this.log("info", `OpenAI TTS: send text "${text}"`);
|
|
99
|
+
const response = await this.openai.audio.speech.create({
|
|
100
|
+
model: this.params.model,
|
|
101
|
+
voice: this.params.voice,
|
|
102
|
+
input: text,
|
|
103
|
+
response_format: "pcm",
|
|
104
|
+
speed: this.params.speed
|
|
105
|
+
});
|
|
106
|
+
/* convert response to buffer (PCM 24kHz, 16-bit, little-endian) */
|
|
107
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
108
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
109
|
+
this.log("info", `OpenAI TTS: received audio (buffer length: ${buffer.byteLength})`);
|
|
110
|
+
/* resample from 24kHz to 48kHz */
|
|
111
|
+
const bufferResampled = this.resampler.processChunk(buffer);
|
|
112
|
+
this.log("info", `OpenAI TTS: forwarding resampled audio (buffer length: ${bufferResampled.byteLength})`);
|
|
113
|
+
return bufferResampled;
|
|
114
|
+
};
|
|
115
|
+
/* create transform stream and connect it to the OpenAI API */
|
|
116
|
+
const self = this;
|
|
117
|
+
this.stream = new node_stream_1.default.Transform({
|
|
118
|
+
writableObjectMode: true,
|
|
119
|
+
readableObjectMode: true,
|
|
120
|
+
decodeStrings: false,
|
|
121
|
+
highWaterMark: 1,
|
|
122
|
+
async transform(chunk, encoding, callback) {
|
|
123
|
+
if (self.closing)
|
|
124
|
+
callback(new Error("stream already destroyed"));
|
|
125
|
+
else if (Buffer.isBuffer(chunk.payload))
|
|
126
|
+
callback(new Error("invalid chunk payload type"));
|
|
127
|
+
else if (chunk.payload === "")
|
|
128
|
+
callback();
|
|
129
|
+
else {
|
|
130
|
+
let processTimeout = setTimeout(() => {
|
|
131
|
+
processTimeout = null;
|
|
132
|
+
callback(new Error("OpenAI TTS API timeout"));
|
|
133
|
+
}, 60 * 1000);
|
|
134
|
+
const clearProcessTimeout = () => {
|
|
135
|
+
if (processTimeout !== null) {
|
|
136
|
+
clearTimeout(processTimeout);
|
|
137
|
+
processTimeout = null;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
try {
|
|
141
|
+
if (self.closing) {
|
|
142
|
+
clearProcessTimeout();
|
|
143
|
+
callback(new Error("stream destroyed during processing"));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const buffer = await textToSpeech(chunk.payload);
|
|
147
|
+
if (self.closing) {
|
|
148
|
+
clearProcessTimeout();
|
|
149
|
+
callback(new Error("stream destroyed during processing"));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
/* calculate actual audio duration from PCM buffer size */
|
|
153
|
+
const durationMs = util.audioBufferDuration(buffer, self.config.audioSampleRate, self.config.audioBitDepth) * 1000;
|
|
154
|
+
/* create new chunk with recalculated timestamps */
|
|
155
|
+
const chunkNew = chunk.clone();
|
|
156
|
+
chunkNew.type = "audio";
|
|
157
|
+
chunkNew.payload = buffer;
|
|
158
|
+
chunkNew.timestampEnd = luxon_1.Duration.fromMillis(chunkNew.timestampStart.toMillis() + durationMs);
|
|
159
|
+
clearProcessTimeout();
|
|
160
|
+
this.push(chunkNew);
|
|
161
|
+
callback();
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
clearProcessTimeout();
|
|
165
|
+
callback(util.ensureError(error, "OpenAI TTS processing failed"));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
final(callback) {
|
|
170
|
+
callback();
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/* close node */
|
|
175
|
+
async close() {
|
|
176
|
+
/* indicate closing */
|
|
177
|
+
this.closing = true;
|
|
178
|
+
/* shutdown stream */
|
|
179
|
+
if (this.stream !== null) {
|
|
180
|
+
await util.destroyStream(this.stream);
|
|
181
|
+
this.stream = null;
|
|
182
|
+
}
|
|
183
|
+
/* destroy resampler */
|
|
184
|
+
if (this.resampler !== null)
|
|
185
|
+
this.resampler = null;
|
|
186
|
+
/* destroy OpenAI API */
|
|
187
|
+
if (this.openai !== null)
|
|
188
|
+
this.openai = null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
exports.default = SpeechFlowNodeT2AOpenAI;
|
|
192
|
+
//# sourceMappingURL=speechflow-node-t2a-openai.js.map
|