tjbot-ce 3.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.
Files changed (224) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +382 -0
  3. package/dist/camera/camera.d.ts +62 -0
  4. package/dist/camera/camera.d.ts.map +1 -0
  5. package/dist/camera/camera.js +155 -0
  6. package/dist/camera/camera.js.map +1 -0
  7. package/dist/camera/index.d.ts +18 -0
  8. package/dist/camera/index.d.ts.map +1 -0
  9. package/dist/camera/index.js +18 -0
  10. package/dist/camera/index.js.map +1 -0
  11. package/dist/config/config-types.d.ts +75 -0
  12. package/dist/config/config-types.d.ts.map +1 -0
  13. package/dist/config/config-types.generated.d.ts +495 -0
  14. package/dist/config/config-types.generated.d.ts.map +1 -0
  15. package/dist/config/config-types.generated.js +2 -0
  16. package/dist/config/config-types.generated.js.map +1 -0
  17. package/dist/config/config-types.js +175 -0
  18. package/dist/config/config-types.js.map +1 -0
  19. package/dist/config/index.d.ts +20 -0
  20. package/dist/config/index.d.ts.map +1 -0
  21. package/dist/config/index.js +19 -0
  22. package/dist/config/index.js.map +1 -0
  23. package/dist/config/tjbot-config.d.ts +98 -0
  24. package/dist/config/tjbot-config.d.ts.map +1 -0
  25. package/dist/config/tjbot-config.js +309 -0
  26. package/dist/config/tjbot-config.js.map +1 -0
  27. package/dist/config/vendor/colors.yaml +61 -0
  28. package/dist/config/vendor/model-registry.yaml +275 -0
  29. package/dist/config/vendor/tjbot-config.schema.yaml +792 -0
  30. package/dist/config/vendor/tjbot.default.toml +452 -0
  31. package/dist/led/index.d.ts +20 -0
  32. package/dist/led/index.d.ts.map +1 -0
  33. package/dist/led/index.js +20 -0
  34. package/dist/led/index.js.map +1 -0
  35. package/dist/led/led-common-anode.d.ts +38 -0
  36. package/dist/led/led-common-anode.d.ts.map +1 -0
  37. package/dist/led/led-common-anode.js +79 -0
  38. package/dist/led/led-common-anode.js.map +1 -0
  39. package/dist/led/led-neopixel-spi.d.ts +60 -0
  40. package/dist/led/led-neopixel-spi.d.ts.map +1 -0
  41. package/dist/led/led-neopixel-spi.js +216 -0
  42. package/dist/led/led-neopixel-spi.js.map +1 -0
  43. package/dist/led/led-neopixel-ws281x.js +186 -0
  44. package/dist/led/led-neopixel.d.ts +57 -0
  45. package/dist/led/led-neopixel.d.ts.map +1 -0
  46. package/dist/led/led-neopixel.js +235 -0
  47. package/dist/led/led-neopixel.js.map +1 -0
  48. package/dist/microphone/index.d.ts +18 -0
  49. package/dist/microphone/index.d.ts.map +1 -0
  50. package/dist/microphone/index.js +18 -0
  51. package/dist/microphone/index.js.map +1 -0
  52. package/dist/microphone/microphone.d.ts +65 -0
  53. package/dist/microphone/microphone.d.ts.map +1 -0
  54. package/dist/microphone/microphone.js +179 -0
  55. package/dist/microphone/microphone.js.map +1 -0
  56. package/dist/rpi-drivers/index.d.ts +22 -0
  57. package/dist/rpi-drivers/index.d.ts.map +1 -0
  58. package/dist/rpi-drivers/index.js +22 -0
  59. package/dist/rpi-drivers/index.js.map +1 -0
  60. package/dist/rpi-drivers/rpi-detect.d.ts +24 -0
  61. package/dist/rpi-drivers/rpi-detect.d.ts.map +1 -0
  62. package/dist/rpi-drivers/rpi-detect.js +49 -0
  63. package/dist/rpi-drivers/rpi-detect.js.map +1 -0
  64. package/dist/rpi-drivers/rpi-driver.d.ts +116 -0
  65. package/dist/rpi-drivers/rpi-driver.d.ts.map +1 -0
  66. package/dist/rpi-drivers/rpi-driver.js +261 -0
  67. package/dist/rpi-drivers/rpi-driver.js.map +1 -0
  68. package/dist/rpi-drivers/rpi3-driver.d.ts +47 -0
  69. package/dist/rpi-drivers/rpi3-driver.d.ts.map +1 -0
  70. package/dist/rpi-drivers/rpi3-driver.js +145 -0
  71. package/dist/rpi-drivers/rpi3-driver.js.map +1 -0
  72. package/dist/rpi-drivers/rpi4-driver.d.ts +35 -0
  73. package/dist/rpi-drivers/rpi4-driver.d.ts.map +1 -0
  74. package/dist/rpi-drivers/rpi4-driver.js +101 -0
  75. package/dist/rpi-drivers/rpi4-driver.js.map +1 -0
  76. package/dist/rpi-drivers/rpi5-driver.d.ts +33 -0
  77. package/dist/rpi-drivers/rpi5-driver.d.ts.map +1 -0
  78. package/dist/rpi-drivers/rpi5-driver.js +78 -0
  79. package/dist/rpi-drivers/rpi5-driver.js.map +1 -0
  80. package/dist/servo/index.d.ts +19 -0
  81. package/dist/servo/index.d.ts.map +1 -0
  82. package/dist/servo/index.js +19 -0
  83. package/dist/servo/index.js.map +1 -0
  84. package/dist/servo/servo-constants.d.ts +33 -0
  85. package/dist/servo/servo-constants.d.ts.map +1 -0
  86. package/dist/servo/servo-constants.js +34 -0
  87. package/dist/servo/servo-constants.js.map +1 -0
  88. package/dist/servo/servo-lgpio.d.ts +82 -0
  89. package/dist/servo/servo-lgpio.d.ts.map +1 -0
  90. package/dist/servo/servo-lgpio.js +178 -0
  91. package/dist/servo/servo-lgpio.js.map +1 -0
  92. package/dist/speaker/audio-player.d.ts +30 -0
  93. package/dist/speaker/audio-player.d.ts.map +1 -0
  94. package/dist/speaker/audio-player.js +68 -0
  95. package/dist/speaker/audio-player.js.map +1 -0
  96. package/dist/speaker/index.d.ts +18 -0
  97. package/dist/speaker/index.d.ts.map +1 -0
  98. package/dist/speaker/index.js +18 -0
  99. package/dist/speaker/index.js.map +1 -0
  100. package/dist/speaker/speaker.d.ts +53 -0
  101. package/dist/speaker/speaker.d.ts.map +1 -0
  102. package/dist/speaker/speaker.js +125 -0
  103. package/dist/speaker/speaker.js.map +1 -0
  104. package/dist/stt/backends/azure-stt.d.ts +32 -0
  105. package/dist/stt/backends/azure-stt.d.ts.map +1 -0
  106. package/dist/stt/backends/azure-stt.js +227 -0
  107. package/dist/stt/backends/azure-stt.js.map +1 -0
  108. package/dist/stt/backends/google-cloud-stt.d.ts +31 -0
  109. package/dist/stt/backends/google-cloud-stt.d.ts.map +1 -0
  110. package/dist/stt/backends/google-cloud-stt.js +371 -0
  111. package/dist/stt/backends/google-cloud-stt.js.map +1 -0
  112. package/dist/stt/backends/ibm-watson-stt.d.ts +32 -0
  113. package/dist/stt/backends/ibm-watson-stt.d.ts.map +1 -0
  114. package/dist/stt/backends/ibm-watson-stt.js +190 -0
  115. package/dist/stt/backends/ibm-watson-stt.js.map +1 -0
  116. package/dist/stt/backends/sherpa-onnx-stt.d.ts +117 -0
  117. package/dist/stt/backends/sherpa-onnx-stt.d.ts.map +1 -0
  118. package/dist/stt/backends/sherpa-onnx-stt.js +694 -0
  119. package/dist/stt/backends/sherpa-onnx-stt.js.map +1 -0
  120. package/dist/stt/index.d.ts +20 -0
  121. package/dist/stt/index.d.ts.map +1 -0
  122. package/dist/stt/index.js +21 -0
  123. package/dist/stt/index.js.map +1 -0
  124. package/dist/stt/stt-engine.d.ts +68 -0
  125. package/dist/stt/stt-engine.d.ts.map +1 -0
  126. package/dist/stt/stt-engine.js +99 -0
  127. package/dist/stt/stt-engine.js.map +1 -0
  128. package/dist/stt/stt-utils.d.ts +36 -0
  129. package/dist/stt/stt-utils.d.ts.map +1 -0
  130. package/dist/stt/stt-utils.js +112 -0
  131. package/dist/stt/stt-utils.js.map +1 -0
  132. package/dist/stt/stt.d.ts +52 -0
  133. package/dist/stt/stt.d.ts.map +1 -0
  134. package/dist/stt/stt.js +100 -0
  135. package/dist/stt/stt.js.map +1 -0
  136. package/dist/tjbot.d.ts +317 -0
  137. package/dist/tjbot.d.ts.map +1 -0
  138. package/dist/tjbot.js +736 -0
  139. package/dist/tjbot.js.map +1 -0
  140. package/dist/tts/backends/azure-tts.d.ts +30 -0
  141. package/dist/tts/backends/azure-tts.d.ts.map +1 -0
  142. package/dist/tts/backends/azure-tts.js +92 -0
  143. package/dist/tts/backends/azure-tts.js.map +1 -0
  144. package/dist/tts/backends/google-cloud-tts.d.ts +38 -0
  145. package/dist/tts/backends/google-cloud-tts.d.ts.map +1 -0
  146. package/dist/tts/backends/google-cloud-tts.js +116 -0
  147. package/dist/tts/backends/google-cloud-tts.js.map +1 -0
  148. package/dist/tts/backends/ibm-watson-tts.d.ts +42 -0
  149. package/dist/tts/backends/ibm-watson-tts.d.ts.map +1 -0
  150. package/dist/tts/backends/ibm-watson-tts.js +99 -0
  151. package/dist/tts/backends/ibm-watson-tts.js.map +1 -0
  152. package/dist/tts/backends/sherpa-onnx-tts.d.ts +80 -0
  153. package/dist/tts/backends/sherpa-onnx-tts.d.ts.map +1 -0
  154. package/dist/tts/backends/sherpa-onnx-tts.js +237 -0
  155. package/dist/tts/backends/sherpa-onnx-tts.js.map +1 -0
  156. package/dist/tts/index.d.ts +19 -0
  157. package/dist/tts/index.d.ts.map +1 -0
  158. package/dist/tts/index.js +20 -0
  159. package/dist/tts/index.js.map +1 -0
  160. package/dist/tts/tts-engine.d.ts +67 -0
  161. package/dist/tts/tts-engine.d.ts.map +1 -0
  162. package/dist/tts/tts-engine.js +109 -0
  163. package/dist/tts/tts-engine.js.map +1 -0
  164. package/dist/tts/tts.d.ts +47 -0
  165. package/dist/tts/tts.d.ts.map +1 -0
  166. package/dist/tts/tts.js +101 -0
  167. package/dist/tts/tts.js.map +1 -0
  168. package/dist/utils/colors.d.ts +39 -0
  169. package/dist/utils/colors.d.ts.map +1 -0
  170. package/dist/utils/colors.js +155 -0
  171. package/dist/utils/colors.js.map +1 -0
  172. package/dist/utils/constants.d.ts +41 -0
  173. package/dist/utils/constants.d.ts.map +1 -0
  174. package/dist/utils/constants.js +43 -0
  175. package/dist/utils/constants.js.map +1 -0
  176. package/dist/utils/credentials.d.ts +43 -0
  177. package/dist/utils/credentials.d.ts.map +1 -0
  178. package/dist/utils/credentials.js +121 -0
  179. package/dist/utils/credentials.js.map +1 -0
  180. package/dist/utils/errors.d.ts +26 -0
  181. package/dist/utils/errors.d.ts.map +1 -0
  182. package/dist/utils/errors.js +32 -0
  183. package/dist/utils/errors.js.map +1 -0
  184. package/dist/utils/index.d.ts +25 -0
  185. package/dist/utils/index.d.ts.map +1 -0
  186. package/dist/utils/index.js +23 -0
  187. package/dist/utils/index.js.map +1 -0
  188. package/dist/utils/logging.d.ts +44 -0
  189. package/dist/utils/logging.d.ts.map +1 -0
  190. package/dist/utils/logging.js +113 -0
  191. package/dist/utils/logging.js.map +1 -0
  192. package/dist/utils/model-registry.d.ts +142 -0
  193. package/dist/utils/model-registry.d.ts.map +1 -0
  194. package/dist/utils/model-registry.js +391 -0
  195. package/dist/utils/model-registry.js.map +1 -0
  196. package/dist/utils/utils.d.ts +33 -0
  197. package/dist/utils/utils.d.ts.map +1 -0
  198. package/dist/utils/utils.js +50 -0
  199. package/dist/utils/utils.js.map +1 -0
  200. package/dist/vision/backends/azure-vision.d.ts +33 -0
  201. package/dist/vision/backends/azure-vision.d.ts.map +1 -0
  202. package/dist/vision/backends/azure-vision.js +151 -0
  203. package/dist/vision/backends/azure-vision.js.map +1 -0
  204. package/dist/vision/backends/google-cloud-vision.d.ts +32 -0
  205. package/dist/vision/backends/google-cloud-vision.d.ts.map +1 -0
  206. package/dist/vision/backends/google-cloud-vision.js +193 -0
  207. package/dist/vision/backends/google-cloud-vision.js.map +1 -0
  208. package/dist/vision/backends/onnx.d.ts +116 -0
  209. package/dist/vision/backends/onnx.d.ts.map +1 -0
  210. package/dist/vision/backends/onnx.js +781 -0
  211. package/dist/vision/backends/onnx.js.map +1 -0
  212. package/dist/vision/index.d.ts +19 -0
  213. package/dist/vision/index.d.ts.map +1 -0
  214. package/dist/vision/index.js +20 -0
  215. package/dist/vision/index.js.map +1 -0
  216. package/dist/vision/vision-engine.d.ts +131 -0
  217. package/dist/vision/vision-engine.d.ts.map +1 -0
  218. package/dist/vision/vision-engine.js +97 -0
  219. package/dist/vision/vision-engine.js.map +1 -0
  220. package/dist/vision/vision.d.ts +48 -0
  221. package/dist/vision/vision.d.ts.map +1 -0
  222. package/dist/vision/vision.js +83 -0
  223. package/dist/vision/vision.js.map +1 -0
  224. package/package.json +124 -0
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Copyright 2026-present TJBot Contributors. All Rights Reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import fs from 'fs';
17
+ import path from 'path';
18
+ import { ModelRegistry, TJBotError } from '../../utils/index.js';
19
+ import { getLogger } from '../../utils/logging.js';
20
+ import { TTSEngine } from '../tts-engine.js';
21
+ const logger = getLogger(import.meta.url);
22
+ // Lazy require sherpa-onnx to avoid hard dependency issues
23
+ let sherpa;
24
+ /**
25
+ * Sherpa-ONNX Local Text-to-Speech Engine
26
+ *
27
+ * Offline speech synthesis using Sherpa-ONNX library with Piper voices.
28
+ * Models are automatically downloaded and cached in ~/.tjbot/models/sherpa-tts/
29
+ * @public
30
+ */
31
+ export class SherpaONNXTTSEngine extends TTSEngine {
32
+ registry = ModelRegistry.getInstance();
33
+ modelInfo;
34
+ modelPath;
35
+ ttsEngine;
36
+ /**
37
+ * Initialize the sherpa-onnx TTS engine.
38
+ * Pre-downloads the configured model.
39
+ */
40
+ async initialize() {
41
+ const config = this.config;
42
+ if (!config.model) {
43
+ throw new TJBotError('Sherpa-ONNX TTS model not specified. Provide model name in speak.backend.sherpa-onnx config.');
44
+ }
45
+ // Set environment variables to reduce noisy logging
46
+ if (!process.env.SHERPA_ONNX_LOG_LEVEL) {
47
+ process.env.SHERPA_ONNX_LOG_LEVEL = 'OFF';
48
+ }
49
+ // Load sherpa-onnx
50
+ if (!sherpa) {
51
+ const module = await import('sherpa-onnx-node');
52
+ // CommonJS module imported as ES module has exports in .default
53
+ sherpa = (module.default || module);
54
+ logger.debug('successfully loaded sherpa-onnx-node module');
55
+ }
56
+ // Load TTS model from registry
57
+ const modelName = config.model;
58
+ logger.info(`Loading TTS model: ${modelName}`);
59
+ this.modelInfo = await this.registry.loadModel(modelName);
60
+ this.modelPath = this.pathForModel();
61
+ // Load the TTS synthesizer
62
+ await this.setupSynthesizer();
63
+ logger.info('Sherpa-ONNX TTS engine initialized');
64
+ }
65
+ pathForModel() {
66
+ if (!this.modelInfo) {
67
+ throw new TJBotError('Model info not set. Ensure initialize() was called.');
68
+ }
69
+ // Resolve the model directory inside the local cache.
70
+ const modelCacheDir = this.registry.getModelCacheDirForType('tts');
71
+ const modelDir = path.join(modelCacheDir, this.modelInfo.folder);
72
+ const vitsDataDir = this.resolveVitsDataDir(modelDir);
73
+ // The voice model file is expected in the model directory.
74
+ const files = fs.readdirSync(modelDir).filter((f) => f.endsWith('.onnx'));
75
+ if (files.length === 0) {
76
+ throw new TJBotError(`No .onnx file found in model directory: ${modelDir}`);
77
+ }
78
+ const modelFile = path.join(modelDir, files[0]);
79
+ logger.debug(`Found TTS model file: ${modelFile} (vitsDataDir: ${vitsDataDir})`);
80
+ return modelFile;
81
+ }
82
+ /**
83
+ * Setup synthesizer based on model configuration
84
+ */
85
+ async setupSynthesizer() {
86
+ if (!this.modelInfo) {
87
+ throw new TJBotError('Model info not set. Ensure initialize() was called.');
88
+ }
89
+ if (!this.modelPath) {
90
+ throw new TJBotError('Model path not set. Ensure model is downloaded and initialize() was called.');
91
+ }
92
+ if (!sherpa) {
93
+ throw new TJBotError('Sherpa-ONNX module not loaded. Ensure initialize() was called.');
94
+ }
95
+ const modelFile = this.modelPath;
96
+ const modelDir = path.dirname(modelFile);
97
+ const vitsDataDir = this.resolveVitsDataDir(modelDir);
98
+ logger.debug(`using TTS model file: ${modelFile} (vitsDataDir: ${vitsDataDir})`);
99
+ this.ttsEngine = this.createOfflineTTS(modelFile, vitsDataDir);
100
+ }
101
+ /**
102
+ * Synthesize text to WAV audio using sherpa-onnx.
103
+ * Voice is configured at engine initialization time via config.
104
+ *
105
+ * @param text - Text to synthesize
106
+ * @returns WAV audio buffer
107
+ * @throws Error if not initialized or synthesis fails
108
+ */
109
+ async synthesize(text) {
110
+ if (!sherpa) {
111
+ throw new TJBotError('Sherpa-ONNX TTS service not initialized. Call initialize() first.');
112
+ }
113
+ if (!this.ttsEngine) {
114
+ throw new TJBotError('TTS engine not initialized. Call initialize() first.');
115
+ }
116
+ this.validateText(text);
117
+ logger.verbose(`Synthesizing speech with Sherpa-ONNX TTS (model=${this.config.model})`);
118
+ // Perform synthesis - pass parameters as object
119
+ const audio = this.ttsEngine.generate({
120
+ text,
121
+ sid: 0,
122
+ speed: 1.0,
123
+ });
124
+ // Convert audio data to WAV buffer
125
+ const wavBuffer = this.audioToWav(audio.samples, audio.sampleRate);
126
+ logger.debug(`Sherpa-ONNX TTS synthesis complete: ${wavBuffer.length} bytes`);
127
+ return wavBuffer;
128
+ }
129
+ /**
130
+ * Resolve the data directory for VITS models. Some models include
131
+ * a separate "espeak-ng-data" folder with necessary data files.
132
+ * If that folder exists, return its path. Otherwise, return
133
+ * the base model directory.
134
+ * @returns Path to the data directory to be used for VITS synthesis
135
+ */
136
+ resolveVitsDataDir(modelDir) {
137
+ const espeakNgDataDir = path.join(modelDir, 'espeak-ng-data');
138
+ return fs.existsSync(espeakNgDataDir) ? espeakNgDataDir : modelDir;
139
+ }
140
+ /**
141
+ * Setup synthesizer based on model configuration. Creates the OfflineTts instance with the appropriate config.
142
+ * @param modelFile The full path to the model file
143
+ * @param vitsDataDir The directory containing VITS data files (may be the same as modelDir or a subdirectory)
144
+ * @returns An instance of OfflineTts configured with the specified model
145
+ */
146
+ createOfflineTTS(modelFile, vitsDataDir) {
147
+ if (!sherpa) {
148
+ throw new TJBotError('Sherpa-ONNX module not loaded. Ensure initialize() was called.');
149
+ }
150
+ // Suppress sherpa-onnx console output
151
+ const originalLog = console.log;
152
+ const originalError = console.error;
153
+ console.log = () => { };
154
+ console.error = () => { };
155
+ const tokensPath = path.join(path.dirname(modelFile), 'tokens.txt');
156
+ if (!fs.existsSync(tokensPath)) {
157
+ throw new TJBotError(`Tokens file not found for model ${modelFile} at expected path: ${tokensPath}`);
158
+ }
159
+ let ttsEngine;
160
+ try {
161
+ // Use the camelCase config expected by sherpa-onnx-node bindings
162
+ const offlineTtsConfig = {
163
+ model: {
164
+ vits: {
165
+ model: modelFile,
166
+ tokens: tokensPath,
167
+ dataDir: vitsDataDir,
168
+ noiseScale: 0.667,
169
+ noiseScaleW: 0.8,
170
+ lengthScale: 1.0,
171
+ },
172
+ numThreads: 1,
173
+ provider: 'cpu',
174
+ debug: 0,
175
+ },
176
+ maxNumSentences: 1,
177
+ };
178
+ ttsEngine = new sherpa.OfflineTts(offlineTtsConfig);
179
+ }
180
+ finally {
181
+ console.log = originalLog;
182
+ console.error = originalError;
183
+ }
184
+ return ttsEngine;
185
+ }
186
+ /**
187
+ * Convert PCM samples to WAV format.
188
+ * Creates a proper WAV file with header and audio data.
189
+ *
190
+ * @param samples - PCM audio samples (typically as Float32Array)
191
+ * @param sampleRate - Sample rate in Hz (e.g., 22050)
192
+ * @returns WAV file as Buffer
193
+ */
194
+ audioToWav(samples, sampleRate) {
195
+ // Convert samples to 16-bit PCM
196
+ const pcm16 = this.float32ToPcm16(samples);
197
+ // Create WAV header
198
+ const channels = 1;
199
+ const bytesPerSample = 2;
200
+ const byteRate = sampleRate * channels * bytesPerSample;
201
+ const blockAlign = channels * bytesPerSample;
202
+ const header = Buffer.alloc(44);
203
+ // "RIFF" chunk descriptor
204
+ header.write('RIFF', 0, 4, 'ascii');
205
+ header.writeUInt32LE(36 + pcm16.length, 4);
206
+ header.write('WAVE', 8, 4, 'ascii');
207
+ // "fmt " subchunk
208
+ header.write('fmt ', 12, 4, 'ascii');
209
+ header.writeUInt32LE(16, 16); // Subchunk1Size (16 for PCM)
210
+ header.writeUInt16LE(1, 20); // AudioFormat (1 for PCM)
211
+ header.writeUInt16LE(channels, 22); // NumChannels
212
+ header.writeUInt32LE(sampleRate, 24); // SampleRate
213
+ header.writeUInt32LE(byteRate, 28); // ByteRate
214
+ header.writeUInt16LE(blockAlign, 32); // BlockAlign
215
+ header.writeUInt16LE(16, 34); // BitsPerSample
216
+ // "data" subchunk
217
+ const dataHeader = Buffer.alloc(8);
218
+ dataHeader.write('data', 0, 4, 'ascii');
219
+ dataHeader.writeUInt32LE(pcm16.length, 4);
220
+ return Buffer.concat([header, dataHeader, pcm16]);
221
+ }
222
+ /**
223
+ * Convert Float32 PCM samples to 16-bit PCM.
224
+ *
225
+ * @param float32Samples - Float32 audio samples (range -1.0 to 1.0)
226
+ * @returns 16-bit PCM samples as Buffer
227
+ */
228
+ float32ToPcm16(float32Samples) {
229
+ const output = new Int16Array(float32Samples.length);
230
+ for (let i = 0; i < float32Samples.length; i++) {
231
+ const sample = Math.max(-1, Math.min(1, float32Samples[i]));
232
+ output[i] = sample < 0 ? sample * 0x8000 : sample * 0x7fff;
233
+ }
234
+ return Buffer.from(output.buffer);
235
+ }
236
+ }
237
+ //# sourceMappingURL=sherpa-onnx-tts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sherpa-onnx-tts.js","sourceRoot":"","sources":["../../../src/tts/backends/sherpa-onnx-tts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright 2026-present TJBot Contributors. All Rights Reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ export { TTSController } from './tts.js';
17
+ export { createTTSEngine } from './tts-engine.js';
18
+ export type { TTSEngine } from './tts-engine.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tts/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGlD,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Copyright 2026-present TJBot Contributors. All Rights Reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ // TTS controller
17
+ export { TTSController } from './tts.js';
18
+ // TTS engine factory (async)
19
+ export { createTTSEngine } from './tts-engine.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tts/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,6BAA6B;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Copyright 2026-present TJBot Contributors. All Rights Reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { SpeakConfig, TTSEngineConfig } from '../config/index.js';
17
+ /**
18
+ * Abstract Text-to-Speech Engine Base Class
19
+ *
20
+ * Defines the interface for TTS backends (IBM Watson, sherpa-onnx, etc.)
21
+ * All implementations must extend this class and implement the required methods.
22
+ * @public
23
+ */
24
+ export declare abstract class TTSEngine {
25
+ protected config: TTSEngineConfig;
26
+ constructor(config?: TTSEngineConfig);
27
+ /**
28
+ * Initialize the TTS engine. Must be called before synthesize().
29
+ * @throws {TJBotError} if initialization fails
30
+ * @public
31
+ */
32
+ abstract initialize(): Promise<void>;
33
+ /**
34
+ * Clean up resources used by the TTS engine.
35
+ * Optional method for backends that need to release resources.
36
+ * @public
37
+ */
38
+ cleanup?(): Promise<void>;
39
+ /**
40
+ * Synthesize text to WAV audio.
41
+ * Both backends should validate input text and return audio as a Buffer in WAV format.
42
+ * Voice is configured at engine initialization time and cannot be changed per synthesis call.
43
+ * @param text - Text to synthesize
44
+ * @returns WAV audio buffer
45
+ * @throws {TJBotError} if synthesis fails
46
+ * @public
47
+ */
48
+ abstract synthesize(text: string): Promise<Buffer>;
49
+ /**
50
+ * Validates text input for synthesis.
51
+ * Checks for null/empty/whitespace-only input.
52
+ *
53
+ * @param text - Text to validate
54
+ * @throws Error if text is invalid
55
+ */
56
+ protected validateText(text: string): void;
57
+ }
58
+ /**
59
+ * Create a TTS engine instance based on the configuration.
60
+ * Uses dynamic imports to lazily load backend implementations only when needed.
61
+ * @param speakConfig - Configuration for the TTS engine with backend settings
62
+ * @returns {Promise<TTSEngine>} Initialized TTS engine instance
63
+ * @throws {TJBotError} if backend type is unknown or dependencies are not installed
64
+ * @public
65
+ */
66
+ export declare function createTTSEngine(speakConfig: SpeakConfig): Promise<TTSEngine>;
67
+ //# sourceMappingURL=tts-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tts-engine.d.ts","sourceRoot":"","sources":["../../src/tts/tts-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EACH,WAAW,EAGX,eAAe,EAElB,MAAM,oBAAoB,CAAC;AAG5B;;;;;;GAMG;AACH,8BAAsB,SAAS;IAC3B,SAAS,CAAC,MAAM,EAAE,eAAe,CAAC;gBAEtB,MAAM,CAAC,EAAE,eAAe;IAIpC;;;;OAIG;IACH,QAAQ,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAEpC;;;;OAIG;IACH,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;IAEzB;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAElD;;;;;;OAMG;IACH,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;CAK7C;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAoElF"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Copyright 2026-present TJBot Contributors. All Rights Reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { getTTSBackendConfig, } from '../config/index.js';
17
+ import { TJBotError } from '../utils/index.js';
18
+ /**
19
+ * Abstract Text-to-Speech Engine Base Class
20
+ *
21
+ * Defines the interface for TTS backends (IBM Watson, sherpa-onnx, etc.)
22
+ * All implementations must extend this class and implement the required methods.
23
+ * @public
24
+ */
25
+ export class TTSEngine {
26
+ config;
27
+ constructor(config) {
28
+ this.config = config ?? {};
29
+ }
30
+ /**
31
+ * Validates text input for synthesis.
32
+ * Checks for null/empty/whitespace-only input.
33
+ *
34
+ * @param text - Text to validate
35
+ * @throws Error if text is invalid
36
+ */
37
+ validateText(text) {
38
+ if (!text || typeof text !== 'string' || text.trim().length === 0) {
39
+ throw new TJBotError('Text input cannot be empty or whitespace-only');
40
+ }
41
+ }
42
+ }
43
+ /**
44
+ * Create a TTS engine instance based on the configuration.
45
+ * Uses dynamic imports to lazily load backend implementations only when needed.
46
+ * @param speakConfig - Configuration for the TTS engine with backend settings
47
+ * @returns {Promise<TTSEngine>} Initialized TTS engine instance
48
+ * @throws {TJBotError} if backend type is unknown or dependencies are not installed
49
+ * @public
50
+ */
51
+ export async function createTTSEngine(speakConfig) {
52
+ const backend = (speakConfig.backend?.type ?? 'local');
53
+ try {
54
+ if (backend === 'none') {
55
+ // Return a stub engine that throws on all synthesize calls
56
+ class NoneTTSEngine extends TTSEngine {
57
+ async initialize() {
58
+ // No-op for 'none' backend
59
+ }
60
+ async synthesize() {
61
+ throw new TJBotError('TTS is disabled. Configure a text-to-speech backend (local, ibm-watson-tts, google-cloud-tts, or azure-tts) to use speech synthesis.');
62
+ }
63
+ }
64
+ return new NoneTTSEngine();
65
+ }
66
+ if (backend === 'local') {
67
+ const module = await import('./backends/sherpa-onnx-tts.js');
68
+ if (!module?.SherpaONNXTTSEngine) {
69
+ throw new TJBotError('TTS backend "local" is unavailable (missing SherpaONNXTTSEngine export).');
70
+ }
71
+ const config = getTTSBackendConfig(speakConfig.backend, backend);
72
+ return new module.SherpaONNXTTSEngine(config);
73
+ }
74
+ if (backend === 'ibm-watson-tts') {
75
+ const module = await import('./backends/ibm-watson-tts.js');
76
+ if (!module?.IBMTTSEngine) {
77
+ throw new TJBotError('TTS backend "ibm-watson-tts" is unavailable (missing IBMTTSEngine export).');
78
+ }
79
+ const config = getTTSBackendConfig(speakConfig.backend, backend);
80
+ return new module.IBMTTSEngine(config);
81
+ }
82
+ if (backend === 'google-cloud-tts') {
83
+ const module = await import('./backends/google-cloud-tts.js');
84
+ if (!module?.GoogleCloudTTSEngine) {
85
+ throw new TJBotError('TTS backend "google-cloud-tts" is unavailable (missing GoogleCloudTTSEngine export).');
86
+ }
87
+ const config = getTTSBackendConfig(speakConfig.backend, backend);
88
+ return new module.GoogleCloudTTSEngine(config);
89
+ }
90
+ if (backend === 'azure-tts') {
91
+ const module = await import('./backends/azure-tts.js');
92
+ if (!module?.AzureTTSEngine) {
93
+ throw new TJBotError('TTS backend "azure-tts" is unavailable (missing AzureTTSEngine export).');
94
+ }
95
+ const config = getTTSBackendConfig(speakConfig.backend, backend);
96
+ return new module.AzureTTSEngine(config);
97
+ }
98
+ throw new TJBotError(`Unknown TTS backend type: ${backend}`);
99
+ }
100
+ catch (error) {
101
+ if (error instanceof TJBotError) {
102
+ throw error;
103
+ }
104
+ throw new TJBotError(`Failed to load TTS backend "${backend}". Ensure dependencies are installed.`, {
105
+ cause: error,
106
+ });
107
+ }
108
+ }
109
+ //# sourceMappingURL=tts-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tts-engine.js","sourceRoot":"","sources":["../../src/tts/tts-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Copyright 2025 IBM Corp. All Rights Reserved.
3
+ * Copyright 2026-present TJBot Contributors. All Rights Reserved.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { SpeakConfig } from '../config/config-types.js';
18
+ import { SpeakerController } from '../speaker/index.js';
19
+ /**
20
+ * TTS controller manages text-to-speech synthesis and engine lifecycle.
21
+ * TTS engine is eagerly initialized during setupSpeaker() and cached for reuse.
22
+
23
+ */
24
+ export declare class TTSController {
25
+ private ttsEngine?;
26
+ private speakerController;
27
+ private speakConfig?;
28
+ constructor(speakerController: SpeakerController);
29
+ /**
30
+ * Initialize the TTS backend
31
+ * Called during setupSpeaker to eagerly load TTS engine
32
+ * @param config Configuration object with backend, IBM settings, and Sherpa settings
33
+ */
34
+ initialize(config: SpeakConfig): Promise<void>;
35
+ /**
36
+ * Synthesize text to speech and play the audio.
37
+ * Lazily initializes the TTS engine on first call.
38
+ *
39
+ * @param text The text to speak
40
+ */
41
+ speak(text: string): Promise<void>;
42
+ /**
43
+ * Clean up TTS resources.
44
+ */
45
+ cleanup(): Promise<void>;
46
+ }
47
+ //# sourceMappingURL=tts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tts.d.ts","sourceRoot":"","sources":["../../src/tts/tts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAOxD;;;;GAIG;AACH,qBAAa,aAAa;IACtB,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,WAAW,CAAC,CAAc;gBAEtB,iBAAiB,EAAE,iBAAiB;IAKhD;;;;OAIG;IACG,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpD;;;;;OAKG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6CxC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAOjC"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Copyright 2025 IBM Corp. All Rights Reserved.
3
+ * Copyright 2026-present TJBot Contributors. All Rights Reserved.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import fs from 'fs';
18
+ import temp from 'temp';
19
+ import { TJBotError } from '../utils/errors.js';
20
+ import { getLogger } from '../utils/logging.js';
21
+ import { createTTSEngine } from './tts-engine.js';
22
+ const logger = getLogger(import.meta.url);
23
+ /**
24
+ * TTS controller manages text-to-speech synthesis and engine lifecycle.
25
+ * TTS engine is eagerly initialized during setupSpeaker() and cached for reuse.
26
+
27
+ */
28
+ export class TTSController {
29
+ ttsEngine;
30
+ speakerController;
31
+ speakConfig;
32
+ constructor(speakerController) {
33
+ this.ttsEngine = undefined;
34
+ this.speakerController = speakerController;
35
+ }
36
+ /**
37
+ * Initialize the TTS backend
38
+ * Called during setupSpeaker to eagerly load TTS engine
39
+ * @param config Configuration object with backend, IBM settings, and Sherpa settings
40
+ */
41
+ async initialize(config) {
42
+ this.speakConfig = config;
43
+ this.ttsEngine = await createTTSEngine(config);
44
+ await this.ttsEngine.initialize();
45
+ }
46
+ /**
47
+ * Synthesize text to speech and play the audio.
48
+ * Lazily initializes the TTS engine on first call.
49
+ *
50
+ * @param text The text to speak
51
+ */
52
+ async speak(text) {
53
+ if (this.ttsEngine === undefined) {
54
+ throw new TJBotError('TTS engine not initialized. Call initialize() before speaking.');
55
+ }
56
+ if (!text || text.trim().length === 0) {
57
+ throw new TJBotError('Text to speak cannot be empty');
58
+ }
59
+ try {
60
+ // Synthesize audio - voice is configured at engine initialization time
61
+ logger.verbose('Synthesizing speech...');
62
+ const audioBuffer = await this.ttsEngine.synthesize(text);
63
+ // Write to temporary file
64
+ const info = temp.openSync('tjbot');
65
+ logger.debug(`writing audio buffer to temp file: ${info.path}`);
66
+ const fd = fs.createWriteStream(info.path);
67
+ fd.write(audioBuffer);
68
+ // Wait for file to be written
69
+ const writePromise = new Promise((resolve, reject) => {
70
+ fd.on('close', () => resolve());
71
+ fd.on('error', () => reject());
72
+ });
73
+ fd.end();
74
+ await writePromise;
75
+ // Play the audio file
76
+ await this.speakerController.playAudio(info.path);
77
+ // Clean up temp file
78
+ try {
79
+ fs.unlinkSync(info.path);
80
+ }
81
+ catch (err) {
82
+ logger.error('Could not delete temp audio file:', err);
83
+ }
84
+ }
85
+ catch (error) {
86
+ logger.error('Error during speech synthesis:', error);
87
+ throw error;
88
+ }
89
+ }
90
+ /**
91
+ * Clean up TTS resources.
92
+ */
93
+ async cleanup() {
94
+ if (this.ttsEngine) {
95
+ logger.debug('TTSController cleanup');
96
+ await this.ttsEngine.cleanup?.();
97
+ this.ttsEngine = undefined;
98
+ }
99
+ }
100
+ }
101
+ //# sourceMappingURL=tts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tts.js","sourceRoot":"","sources":["../../src/tts/tts.ts"],"names":[],"mappings":"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"}