echogarden 0.12.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (334) hide show
  1. package/README.md +15 -14
  2. package/data/schemas/options.json +398 -111
  3. package/dist/alignment/DTWMfccSequenceAlignment.d.ts +1 -1
  4. package/dist/alignment/DTWMfccSequenceAlignment.js +8 -8
  5. package/dist/alignment/DTWSequenceAlignment.d.ts +1 -1
  6. package/dist/alignment/DTWSequenceAlignment.js +1 -1
  7. package/dist/alignment/DTWSequenceAlignmentWindowed.d.ts +1 -1
  8. package/dist/alignment/DTWSequenceAlignmentWindowed.js +2 -2
  9. package/dist/alignment/LevenshteinSequenceAlignment.d.ts +1 -1
  10. package/dist/alignment/LevenshteinSequenceAlignment.js +1 -1
  11. package/dist/alignment/SpeechAlignment.d.ts +9 -10
  12. package/dist/alignment/SpeechAlignment.js +136 -105
  13. package/dist/alignment/SpeechAlignment.js.map +1 -1
  14. package/dist/api/API.d.ts +13 -12
  15. package/dist/api/API.js +14 -13
  16. package/dist/api/API.js.map +1 -1
  17. package/dist/api/APIOptions.d.ts +5 -4
  18. package/dist/api/Alignment.d.ts +15 -9
  19. package/dist/api/Alignment.js +88 -74
  20. package/dist/api/Alignment.js.map +1 -1
  21. package/dist/api/Common.js +1 -1
  22. package/dist/api/Denoising.d.ts +6 -6
  23. package/dist/api/Denoising.js +23 -23
  24. package/dist/api/Denoising.js.map +1 -1
  25. package/dist/api/LanguageDetection.d.ts +19 -12
  26. package/dist/api/LanguageDetection.js +88 -38
  27. package/dist/api/LanguageDetection.js.map +1 -1
  28. package/dist/api/Recognition.d.ts +16 -6
  29. package/dist/api/Recognition.js +129 -55
  30. package/dist/api/Recognition.js.map +1 -1
  31. package/dist/api/SourceSeparation.d.ts +17 -0
  32. package/dist/api/SourceSeparation.js +61 -0
  33. package/dist/api/SourceSeparation.js.map +1 -0
  34. package/dist/api/Synthesis.d.ts +18 -18
  35. package/dist/api/Synthesis.js +191 -164
  36. package/dist/api/Synthesis.js.map +1 -1
  37. package/dist/api/Translation.d.ts +19 -8
  38. package/dist/api/Translation.js +132 -35
  39. package/dist/api/Translation.js.map +1 -1
  40. package/dist/api/Vad.d.ts +10 -5
  41. package/dist/api/Vad.js +76 -38
  42. package/dist/api/Vad.js.map +1 -1
  43. package/dist/audio/AudioBufferConversion.d.ts +1 -1
  44. package/dist/audio/AudioBufferConversion.js +4 -4
  45. package/dist/audio/AudioPlayer.d.ts +1 -1
  46. package/dist/audio/AudioPlayer.js +26 -26
  47. package/dist/audio/AudioPlayer.js.map +1 -1
  48. package/dist/audio/AudioRecorder.d.ts +1 -1
  49. package/dist/audio/AudioRecorder.js +5 -5
  50. package/dist/audio/AudioUtilities.d.ts +13 -9
  51. package/dist/audio/AudioUtilities.js +86 -24
  52. package/dist/audio/AudioUtilities.js.map +1 -1
  53. package/dist/cli/CLI.d.ts +3 -3
  54. package/dist/cli/CLI.js +271 -162
  55. package/dist/cli/CLI.js.map +1 -1
  56. package/dist/cli/CLIConfigFile.js +8 -8
  57. package/dist/cli/CLILauncher.js +6 -6
  58. package/dist/cli/CLIOptionsSchema.js +2 -2
  59. package/dist/cli/CLIParser.js +5 -5
  60. package/dist/cli/CLIStarter.js +4 -4
  61. package/dist/codecs/FFMpegTranscoder.d.ts +2 -2
  62. package/dist/codecs/FFMpegTranscoder.js +37 -37
  63. package/dist/codecs/FFMpegTranscoder.js.map +1 -1
  64. package/dist/codecs/TIMITCodec.js +5 -5
  65. package/dist/codecs/WaveCodec.d.ts +1 -1
  66. package/dist/codecs/WaveCodec.js +22 -22
  67. package/dist/denoising/RNNoise.d.ts +1 -1
  68. package/dist/denoising/RNNoise.js +9 -9
  69. package/dist/dsp/BiquadFilter.d.ts +3 -2
  70. package/dist/dsp/BiquadFilter.js +18 -11
  71. package/dist/dsp/BiquadFilter.js.map +1 -1
  72. package/dist/dsp/DecayingPeakEstimator.d.ts +16 -0
  73. package/dist/dsp/DecayingPeakEstimator.js +23 -0
  74. package/dist/dsp/DecayingPeakEstimator.js.map +1 -0
  75. package/dist/dsp/FFT.d.ts +8 -4
  76. package/dist/dsp/FFT.js +76 -30
  77. package/dist/dsp/FFT.js.map +1 -1
  78. package/dist/dsp/KWeightingFilter.d.ts +9 -0
  79. package/dist/dsp/KWeightingFilter.js +40 -0
  80. package/dist/dsp/KWeightingFilter.js.map +1 -0
  81. package/dist/dsp/LoudnessEstimator.d.ts +21 -0
  82. package/dist/dsp/LoudnessEstimator.js +47 -0
  83. package/dist/dsp/LoudnessEstimator.js.map +1 -0
  84. package/dist/dsp/MFCC.d.ts +2 -2
  85. package/dist/dsp/MFCC.js +15 -15
  86. package/dist/dsp/MelSpectogram.d.ts +1 -1
  87. package/dist/dsp/MelSpectogram.js +6 -6
  88. package/dist/dsp/Rubberband.d.ts +11 -11
  89. package/dist/dsp/Rubberband.js +27 -27
  90. package/dist/dsp/Sonic.d.ts +1 -1
  91. package/dist/dsp/Sonic.js +3 -3
  92. package/dist/dsp/SpeexResampler.d.ts +1 -1
  93. package/dist/dsp/SpeexResampler.js +2 -2
  94. package/dist/math/VectorMath.d.ts +12 -8
  95. package/dist/math/VectorMath.js +35 -32
  96. package/dist/math/VectorMath.js.map +1 -1
  97. package/dist/nlp/ChineseSegmentation.js +2 -2
  98. package/dist/nlp/CompromiseNLP.js +3 -3
  99. package/dist/nlp/EspeakPhonemizer.js +30 -30
  100. package/dist/nlp/IPA.js +20 -20
  101. package/dist/nlp/JapaneseSegmentation.js +6 -6
  102. package/dist/nlp/Lexicon.d.ts +1 -1
  103. package/dist/nlp/Lexicon.js +7 -7
  104. package/dist/nlp/Segmentation.d.ts +3 -0
  105. package/dist/nlp/Segmentation.js +21 -14
  106. package/dist/nlp/Segmentation.js.map +1 -1
  107. package/dist/nlp/TextNormalizer.js +16 -16
  108. package/dist/recognition/AmazonTranscribeSTT.d.ts +2 -2
  109. package/dist/recognition/AmazonTranscribeSTT.js +13 -14
  110. package/dist/recognition/AmazonTranscribeSTT.js.map +1 -1
  111. package/dist/recognition/AzureCognitiveServicesSTT.js +5 -6
  112. package/dist/recognition/AzureCognitiveServicesSTT.js.map +1 -1
  113. package/dist/recognition/GoogleCloudSTT.d.ts +3 -3
  114. package/dist/recognition/GoogleCloudSTT.js +18 -18
  115. package/dist/recognition/OpenAICloudSTT.d.ts +19 -0
  116. package/dist/recognition/OpenAICloudSTT.js +81 -0
  117. package/dist/recognition/OpenAICloudSTT.js.map +1 -0
  118. package/dist/recognition/SileroSTT.d.ts +2 -2
  119. package/dist/recognition/SileroSTT.js +25 -25
  120. package/dist/recognition/VoskSTT.d.ts +2 -2
  121. package/dist/recognition/VoskSTT.js +8 -8
  122. package/dist/recognition/WhisperCppSTT.d.ts +88 -0
  123. package/dist/recognition/WhisperCppSTT.js +332 -0
  124. package/dist/recognition/WhisperCppSTT.js.map +1 -0
  125. package/dist/recognition/WhisperSTT.d.ts +49 -25
  126. package/dist/recognition/WhisperSTT.js +626 -481
  127. package/dist/recognition/WhisperSTT.js.map +1 -1
  128. package/dist/server/Client.d.ts +1 -1
  129. package/dist/server/Client.js +22 -22
  130. package/dist/server/Server.js +9 -9
  131. package/dist/server/Server.js.map +1 -1
  132. package/dist/server/Worker.d.ts +22 -22
  133. package/dist/server/Worker.js +36 -36
  134. package/dist/server/Worker.js.map +1 -1
  135. package/dist/server/WorkerStarter.js +2 -2
  136. package/dist/source-separation/MDXNetSourceSeparation.d.ts +11 -0
  137. package/dist/source-separation/MDXNetSourceSeparation.js +161 -0
  138. package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -0
  139. package/dist/speech-language-detection/SileroLanguageDetection.d.ts +1 -1
  140. package/dist/speech-language-detection/SileroLanguageDetection.js +7 -7
  141. package/dist/subtitles/Subtitles.d.ts +10 -0
  142. package/dist/subtitles/Subtitles.js +2 -2
  143. package/dist/subtitles/Subtitles.js.map +1 -1
  144. package/dist/synthesis/AwsPollyTTS.d.ts +1 -1
  145. package/dist/synthesis/AwsPollyTTS.js +12 -12
  146. package/dist/synthesis/AzureCognitiveServicesTTS.js +7 -7
  147. package/dist/synthesis/CoquiServerTTS.js +10 -10
  148. package/dist/synthesis/CoquiServerTTS.js.map +1 -1
  149. package/dist/synthesis/ElevenlabsTTS.d.ts +23 -0
  150. package/dist/synthesis/ElevenlabsTTS.js +103 -0
  151. package/dist/synthesis/ElevenlabsTTS.js.map +1 -0
  152. package/dist/synthesis/EspeakTTS.d.ts +6 -5
  153. package/dist/synthesis/EspeakTTS.js +81 -69
  154. package/dist/synthesis/EspeakTTS.js.map +1 -1
  155. package/dist/synthesis/FliteTTS.d.ts +3 -3
  156. package/dist/synthesis/FliteTTS.js +154 -154
  157. package/dist/synthesis/FliteTTS.js.map +1 -1
  158. package/dist/synthesis/GoogleCloudTTS.d.ts +3 -3
  159. package/dist/synthesis/GoogleCloudTTS.js +17 -17
  160. package/dist/synthesis/GoogleCloudTTS.js.map +1 -1
  161. package/dist/synthesis/GoogleTranslateTTS.d.ts +1 -1
  162. package/dist/synthesis/GoogleTranslateTTS.js +103 -103
  163. package/dist/synthesis/MicrosoftEdgeTTS.d.ts +2 -2
  164. package/dist/synthesis/MicrosoftEdgeTTS.js +74 -74
  165. package/dist/synthesis/OpenAICloudTTS.d.ts +13 -0
  166. package/dist/synthesis/OpenAICloudTTS.js +169 -0
  167. package/dist/synthesis/OpenAICloudTTS.js.map +1 -0
  168. package/dist/synthesis/SamTTS.js +3 -3
  169. package/dist/synthesis/SapiTTS.d.ts +3 -3
  170. package/dist/synthesis/SapiTTS.js +26 -26
  171. package/dist/synthesis/StreamlabsPollyTTS.d.ts +2 -2
  172. package/dist/synthesis/StreamlabsPollyTTS.js +27 -27
  173. package/dist/synthesis/SvoxPicoTTS.d.ts +2 -2
  174. package/dist/synthesis/SvoxPicoTTS.js +65 -65
  175. package/dist/synthesis/SvoxPicoTTS.js.map +1 -1
  176. package/dist/synthesis/VitsTTS.d.ts +3 -3
  177. package/dist/synthesis/VitsTTS.js +378 -378
  178. package/dist/synthesis/VitsTTS.js.map +1 -1
  179. package/dist/tests/Test.js +2 -2
  180. package/dist/utilities/Compression.d.ts +5 -0
  181. package/dist/utilities/Compression.js +29 -13
  182. package/dist/utilities/Compression.js.map +1 -1
  183. package/dist/utilities/FileDownloader.d.ts +1 -1
  184. package/dist/utilities/FileDownloader.js +16 -16
  185. package/dist/utilities/FileSystem.js +7 -7
  186. package/dist/utilities/Locale.d.ts +7 -7
  187. package/dist/utilities/Locale.js +15 -15
  188. package/dist/utilities/Logger.js +3 -3
  189. package/dist/utilities/ObjectUtilities.js +19 -19
  190. package/dist/utilities/OpenPromise.js +2 -2
  191. package/dist/utilities/OpenPromise.js.map +1 -1
  192. package/dist/utilities/PackageManager.js +31 -0
  193. package/dist/utilities/PackageManager.js.map +1 -1
  194. package/dist/utilities/PathUtilities.js +8 -8
  195. package/dist/utilities/RandomGenerator.js +2 -2
  196. package/dist/utilities/SmoothEstimator.d.ts +8 -0
  197. package/dist/utilities/SmoothEstimator.js +25 -0
  198. package/dist/utilities/SmoothEstimator.js.map +1 -0
  199. package/dist/utilities/TarballMaker.js +8 -8
  200. package/dist/utilities/Timeline.d.ts +3 -2
  201. package/dist/utilities/Timeline.js +11 -11
  202. package/dist/utilities/Timeline.js.map +1 -1
  203. package/dist/utilities/Timer.js +4 -4
  204. package/dist/utilities/Utilities.d.ts +4 -0
  205. package/dist/utilities/Utilities.js +38 -15
  206. package/dist/utilities/Utilities.js.map +1 -1
  207. package/dist/utilities/WasmMemoryManager.js +7 -7
  208. package/dist/utilities/WebReader.js +23 -23
  209. package/dist/utilities/WikipediaReader.js +2 -2
  210. package/dist/voice-activity-detection/AdaptiveGateVAD.d.ts +28 -0
  211. package/dist/voice-activity-detection/AdaptiveGateVAD.js +138 -0
  212. package/dist/voice-activity-detection/AdaptiveGateVAD.js.map +1 -0
  213. package/dist/voice-activity-detection/SileroVAD.d.ts +1 -1
  214. package/dist/voice-activity-detection/SileroVAD.js +5 -5
  215. package/dist/voice-activity-detection/SileroVAD.js.map +1 -1
  216. package/dist/voice-activity-detection/WebRtcVAD.d.ts +1 -1
  217. package/dist/voice-activity-detection/WebRtcVAD.js +4 -4
  218. package/docs/API.md +29 -11
  219. package/docs/CLI.md +31 -7
  220. package/docs/Contributing.md +38 -0
  221. package/docs/Development.md +93 -19
  222. package/docs/Engines.md +28 -16
  223. package/docs/Licenses.md +4 -1
  224. package/docs/Options.md +158 -78
  225. package/docs/Releases.md +262 -0
  226. package/docs/Server.md +7 -7
  227. package/docs/Tasklist.md +95 -76
  228. package/docs/Technical.md +4 -4
  229. package/package.json +13 -14
  230. package/src/alignment/DTWMfccSequenceAlignment.ts +9 -9
  231. package/src/alignment/DTWSequenceAlignment.ts +2 -2
  232. package/src/alignment/DTWSequenceAlignmentWindowed.ts +3 -3
  233. package/src/alignment/LevenshteinSequenceAlignment.ts +2 -2
  234. package/src/alignment/SpeechAlignment.ts +204 -119
  235. package/src/api/API.ts +14 -13
  236. package/src/api/APIOptions.ts +12 -11
  237. package/src/api/Alignment.ts +147 -90
  238. package/src/api/Common.ts +1 -1
  239. package/src/api/Denoising.ts +28 -28
  240. package/src/api/LanguageDetection.ts +135 -48
  241. package/src/api/Recognition.ts +198 -59
  242. package/src/api/SourceSeparation.ts +99 -0
  243. package/src/api/Synthesis.ts +217 -181
  244. package/src/api/Translation.ts +193 -40
  245. package/src/api/Vad.ts +110 -41
  246. package/src/audio/AudioBufferConversion.ts +4 -4
  247. package/src/audio/AudioPlayer.ts +27 -27
  248. package/src/audio/AudioRecorder.ts +5 -5
  249. package/src/audio/AudioUtilities.ts +107 -24
  250. package/src/cli/CLI.ts +313 -164
  251. package/src/cli/CLIConfigFile.ts +8 -8
  252. package/src/cli/CLILauncher.ts +6 -6
  253. package/src/cli/CLIOptionsSchema.ts +2 -2
  254. package/src/cli/CLIParser.ts +5 -5
  255. package/src/cli/CLIStarter.ts +4 -4
  256. package/src/codecs/FFMpegTranscoder.ts +38 -38
  257. package/src/codecs/TIMITCodec.ts +5 -5
  258. package/src/codecs/WaveCodec.ts +22 -22
  259. package/src/denoising/RNNoise.ts +9 -9
  260. package/src/dsp/BiquadFilter.ts +19 -11
  261. package/src/dsp/DecayingPeakEstimator.ts +35 -0
  262. package/src/dsp/FFT.ts +103 -35
  263. package/src/dsp/KWeightingFilter.ts +43 -0
  264. package/src/dsp/LoudnessEstimator.ts +74 -0
  265. package/src/dsp/MFCC.ts +15 -15
  266. package/src/dsp/MelSpectogram.ts +7 -7
  267. package/src/dsp/Rubberband.ts +38 -38
  268. package/src/dsp/Sonic.ts +4 -4
  269. package/src/dsp/SpeexResampler.ts +2 -2
  270. package/src/math/VectorMath.ts +42 -33
  271. package/src/nlp/ChineseSegmentation.ts +3 -3
  272. package/src/nlp/CompromiseNLP.ts +3 -3
  273. package/src/nlp/EspeakPhonemizer.ts +30 -30
  274. package/src/nlp/IPA.ts +20 -20
  275. package/src/nlp/JapaneseSegmentation.ts +6 -6
  276. package/src/nlp/Lexicon.ts +8 -8
  277. package/src/nlp/Segmentation.ts +23 -14
  278. package/src/nlp/TextNormalizer.ts +16 -16
  279. package/src/recognition/AmazonTranscribeSTT.ts +16 -17
  280. package/src/recognition/AzureCognitiveServicesSTT.ts +8 -6
  281. package/src/recognition/GoogleCloudSTT.ts +21 -21
  282. package/src/recognition/OpenAICloudSTT.ts +142 -0
  283. package/src/recognition/SileroSTT.ts +26 -26
  284. package/src/recognition/VoskSTT.ts +10 -10
  285. package/src/recognition/WhisperCppSTT.ts +555 -0
  286. package/src/recognition/WhisperSTT.ts +760 -507
  287. package/src/server/Client.ts +23 -23
  288. package/src/server/Server.ts +9 -9
  289. package/src/server/Worker.ts +53 -53
  290. package/src/server/WorkerStarter.ts +2 -2
  291. package/src/source-separation/MDXNetSourceSeparation.ts +228 -0
  292. package/src/speech-language-detection/SileroLanguageDetection.ts +8 -8
  293. package/src/subtitles/Subtitles.ts +3 -3
  294. package/src/synthesis/AwsPollyTTS.ts +14 -14
  295. package/src/synthesis/AzureCognitiveServicesTTS.ts +10 -10
  296. package/src/synthesis/CoquiServerTTS.ts +10 -10
  297. package/src/synthesis/ElevenlabsTTS.ts +137 -0
  298. package/src/synthesis/EspeakTTS.ts +90 -71
  299. package/src/synthesis/FliteTTS.ts +157 -157
  300. package/src/synthesis/GoogleCloudTTS.ts +19 -19
  301. package/src/synthesis/GoogleTranslateTTS.ts +104 -104
  302. package/src/synthesis/MicrosoftEdgeTTS.ts +80 -80
  303. package/src/synthesis/OpenAICloudTTS.ts +196 -0
  304. package/src/synthesis/SamTTS.ts +3 -3
  305. package/src/synthesis/SapiTTS.ts +29 -29
  306. package/src/synthesis/StreamlabsPollyTTS.ts +29 -29
  307. package/src/synthesis/SvoxPicoTTS.ts +67 -67
  308. package/src/synthesis/VitsTTS.ts +380 -380
  309. package/src/tests/Test.ts +4 -4
  310. package/src/utilities/Compression.ts +34 -13
  311. package/src/utilities/FileDownloader.ts +19 -19
  312. package/src/utilities/FileSystem.ts +7 -7
  313. package/src/utilities/Locale.ts +22 -22
  314. package/src/utilities/Logger.ts +4 -4
  315. package/src/utilities/ObjectUtilities.ts +19 -19
  316. package/src/utilities/OpenPromise.ts +2 -2
  317. package/src/utilities/PackageManager.ts +40 -0
  318. package/src/utilities/PathUtilities.ts +8 -8
  319. package/src/utilities/RandomGenerator.ts +3 -3
  320. package/src/utilities/SmoothEstimator.ts +35 -0
  321. package/src/utilities/TarballMaker.ts +9 -9
  322. package/src/utilities/Timeline.ts +15 -13
  323. package/src/utilities/Timer.ts +4 -4
  324. package/src/utilities/Utilities.ts +49 -15
  325. package/src/utilities/WasmMemoryManager.ts +7 -7
  326. package/src/utilities/WebReader.ts +23 -23
  327. package/src/utilities/WikipediaReader.ts +2 -2
  328. package/src/voice-activity-detection/AdaptiveGateVAD.ts +202 -0
  329. package/src/voice-activity-detection/SileroVAD.ts +5 -5
  330. package/src/voice-activity-detection/WebRtcVAD.ts +5 -5
  331. package/dist/synthesis/ElevenLabsTTS.d.ts +0 -8
  332. package/dist/synthesis/ElevenLabsTTS.js +0 -82
  333. package/dist/synthesis/ElevenLabsTTS.js.map +0 -1
  334. package/src/synthesis/ElevenLabsTTS.ts +0 -104
@@ -0,0 +1,555 @@
1
+ import { spawn } from 'node:child_process'
2
+ import { RawAudio, encodeRawAudioToWave, getRawAudioDuration } from '../audio/AudioUtilities.js'
3
+ import { Logger } from '../utilities/Logger.js'
4
+ import { type WhisperTask, type WhisperModelName } from './WhisperSTT.js'
5
+ import { getRandomHexString } from '../utilities/Utilities.js'
6
+ import { Timeline, TimelineEntryType } from '../utilities/Timeline.js'
7
+ import { tryParseTimeRangePatternWithHours } from '../subtitles/Subtitles.js'
8
+ import { getAppTempDir } from '../utilities/PathUtilities.js'
9
+ import { appName } from '../api/Common.js'
10
+ import path from 'node:path'
11
+ import { readAndParseJsonFile, remove } from '../utilities/FileSystem.js'
12
+ import { splitToLines } from '../nlp/Segmentation.js'
13
+ import { extendDeep } from '../utilities/ObjectUtilities.js'
14
+ import { formatLanguageCodeWithName, getShortLanguageCode } from '../utilities/Locale.js'
15
+ import { loadPackage } from '../utilities/PackageManager.js'
16
+ import { detectSpeechLanguageByParts } from '../api/LanguageDetection.js'
17
+
18
+ export async function recognize(
19
+ sourceRawAudio: RawAudio,
20
+ task: WhisperTask,
21
+ sourceLanguage: string | undefined,
22
+ modelName: WhisperModelName,
23
+ modelPath: string,
24
+ options: WhisperCppOptions) {
25
+
26
+ return new Promise<RecognitionResult>(async (resolve, reject) => {
27
+ const logger = new Logger()
28
+
29
+ if (sourceRawAudio.sampleRate != 16000) {
30
+ throw new Error('Source audio must have a sample rate of 16000 Hz')
31
+ }
32
+
33
+ options = extendDeep(defaultWhisperCppOptions, options)
34
+
35
+ let buildKind: WhisperCppBuild
36
+ let executablePath: string
37
+
38
+ if (options.executablePath) {
39
+ buildKind = 'custom'
40
+
41
+ executablePath = options.executablePath
42
+
43
+ if (options.enableGPU == null) {
44
+ options.enableGPU = true
45
+ }
46
+ } else {
47
+ if (options.build) {
48
+ buildKind = options.build
49
+
50
+ if (options.enableGPU == null) {
51
+ options.enableGPU = buildKind.startsWith('cublas-')
52
+ } else if (options.enableGPU === true && !buildKind.startsWith('cublas-')) {
53
+ throw new Error('GPU support is only available for CUDA builds')
54
+ }
55
+ } else {
56
+ if (options.enableGPU) {
57
+ buildKind = 'cublas-11.8.0'
58
+ } else {
59
+ buildKind = 'cpu'
60
+ }
61
+ }
62
+
63
+ executablePath = await loadExecutablePackage(buildKind)
64
+ }
65
+
66
+
67
+ logger.start(`Recognize with command-line whisper.cpp (build: ${buildKind}, model: ${options.model || modelName})`)
68
+ logger.log('')
69
+ logger.log('')
70
+
71
+ const sourceAsWave = encodeRawAudioToWave(sourceRawAudio)
72
+
73
+ const tempDirPath = getAppTempDir(appName)
74
+ const outJsonFilePathWithoutExtension = path.join(tempDirPath, `${getRandomHexString(16)}`)
75
+ const outJsonFilePath = `${outJsonFilePathWithoutExtension}.json`
76
+
77
+ const args: string[] = [
78
+ '--output-json-full',
79
+
80
+ '--output-file',
81
+ outJsonFilePathWithoutExtension,
82
+
83
+ '--model',
84
+ modelPath,
85
+
86
+ '--language',
87
+ sourceLanguage || 'auto',
88
+
89
+ '--threads',
90
+ `${options.threadCount!}`,
91
+
92
+ '--processors',
93
+ `${options.splitCount!}`,
94
+
95
+ '--best-of',
96
+ `${options.topCandidateCount!}`,
97
+
98
+ '--beam-size',
99
+ `${options.beamCount!}`,
100
+
101
+ '--entropy-thold',
102
+ `${options.repetitionThreshold!}`
103
+ ]
104
+
105
+ if (options.prompt) {
106
+ args.push(
107
+ '--prompt',
108
+ options.prompt,
109
+ )
110
+ }
111
+
112
+ if (!options.enableGPU) {
113
+ args.push(
114
+ '--no-gpu'
115
+ )
116
+ }
117
+
118
+ if (options.enableDTW) {
119
+ args.push(
120
+ '--max-len',
121
+ '0',
122
+
123
+ '--dtw',
124
+ modelName.replaceAll('-', '.'),
125
+ )
126
+ } else {
127
+ args.push(
128
+ '--max-len',
129
+ '0',
130
+ )
131
+ }
132
+
133
+ if (task === 'translate') {
134
+ args.push('--translate')
135
+ } else if (task === 'detect-language') {
136
+ args.push('--detect-language')
137
+ }
138
+
139
+ const argsString = args.join(' ')
140
+
141
+ const process = spawn(executablePath, [...args, '-'])
142
+
143
+ const stdoutLines: string[] = []
144
+ let stderrOutput = ''
145
+
146
+ process.stdout.setEncoding('utf8')
147
+ process.stdout.on('data', (str: string) => {
148
+ if (task === 'detect-language') {
149
+ return
150
+ }
151
+
152
+ const parts = splitToLines(str)
153
+ .map(line => line.trim())
154
+ .filter(line => line.length > 0)
155
+
156
+ logger.log(parts.join('\n'))
157
+
158
+ stdoutLines.push(...parts)
159
+ })
160
+
161
+ process.stderr.setEncoding('utf8')
162
+ process.stderr.on('data', (str: string) => {
163
+ if (options.verbose) {
164
+ logger.log(str)
165
+ }
166
+
167
+ stderrOutput += str
168
+ })
169
+
170
+ process.on('error', (e) => {
171
+ reject(e)
172
+ })
173
+
174
+ process.on('close', async (exitCode) => {
175
+ logger.end()
176
+
177
+ if (exitCode === 0) {
178
+ const parsedStdOut = parseStdOutLinesToTimeline(stdoutLines, 'word')
179
+
180
+ const resultObject: WhisperCppVerboseResult = await readAndParseJsonFile(outJsonFilePath)
181
+ await remove(outJsonFilePath)
182
+
183
+ if (task === 'detect-language') {
184
+ resolve({ timeline: [], transcript: '', language: resultObject.result.language })
185
+ } else {
186
+ const parsedResultObject = await parseResultObject(resultObject, modelName, getRawAudioDuration(sourceRawAudio), options.enableDTW!)
187
+
188
+ resolve(parsedResultObject)
189
+ }
190
+ } else {
191
+ reject(`whisper.cpp exited with code ${exitCode}`)
192
+
193
+ logger.log(stderrOutput)
194
+ }
195
+ })
196
+
197
+ //writeToStdinInChunks(process, sourceAsWave, 2 ** 10)
198
+ process.stdin.end(sourceAsWave)
199
+ })
200
+ }
201
+
202
+ export async function detectLanguage(sourceRawAudio: RawAudio, modelName: WhisperModelName, modelPath: string) {
203
+ if (sourceRawAudio.sampleRate != 16000) {
204
+ throw new Error('Source audio must have a sampling rate of 16000')
205
+ }
206
+
207
+ async function detectLanguageForPart(partAudio: RawAudio) {
208
+ const { language } = await recognize(
209
+ partAudio,
210
+ 'detect-language',
211
+ undefined,
212
+ modelName,
213
+ modelPath,
214
+ {},
215
+ )
216
+
217
+ const partResults = [{
218
+ language: language!,
219
+ languageName: formatLanguageCodeWithName(language!),
220
+ probability: 1.0,
221
+ }]
222
+
223
+ return partResults
224
+ }
225
+
226
+ const results = await detectSpeechLanguageByParts(sourceRawAudio, detectLanguageForPart)
227
+
228
+ results.sort((entry1, entry2) => entry2.probability - entry1.probability)
229
+
230
+ return results
231
+ }
232
+
233
+ async function parseResultObject(resultObject: WhisperCppVerboseResult, modelName: WhisperModelName, totalDuration: number, enableDTW: boolean): Promise<RecognitionResult> {
234
+ const { Whisper } = await import('../recognition/WhisperSTT.js')
235
+
236
+ const whisper = new Whisper(modelName, '')
237
+ await whisper.initializeTokenizerIfNeeded()
238
+
239
+ const tokenTimeline: Timeline = []
240
+
241
+ let currentCorrectionTimeOffset = 0
242
+
243
+ for (let segmentIndex = 0; segmentIndex < resultObject.transcription.length; segmentIndex++) {
244
+ const segmentObject = resultObject.transcription[segmentIndex]
245
+
246
+ const tokens = segmentObject.tokens
247
+
248
+ for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex++) {
249
+ const tokenObject = tokens[tokenIndex]
250
+
251
+ if (tokenIndex === 0 && tokenObject.text === '[_BEG_]' && tokenObject.offsets.from === 0) {
252
+ currentCorrectionTimeOffset = segmentObject.offsets.from / 1000
253
+ }
254
+
255
+ const tokenId = tokenObject.id
256
+ const tokenText = whisper.tokenToText(tokenId, true)
257
+ const tokenConfidence = tokenObject.p
258
+
259
+ let startTime: number
260
+ let endTime: number
261
+
262
+ if (enableDTW) {
263
+ const nextTokenEntry = tokens[tokenIndex + 1]
264
+
265
+ const tokenEntryDtwStartTime = tokenObject.t_dtw / 100
266
+ const nextTokenEntryDtwStartTime = nextTokenEntry ? nextTokenEntry.t_dtw / 100 : totalDuration
267
+
268
+ startTime = Math.max(tokenEntryDtwStartTime, 0)
269
+ endTime = nextTokenEntryDtwStartTime
270
+ } else {
271
+ startTime = tokenObject.offsets.from / 1000
272
+ endTime = tokenObject.offsets.to / 1000
273
+ }
274
+
275
+ startTime += currentCorrectionTimeOffset
276
+ endTime += currentCorrectionTimeOffset
277
+
278
+ tokenTimeline.push({
279
+ type: 'token',
280
+ text: tokenText,
281
+ id: tokenId,
282
+ startTime,
283
+ endTime,
284
+ confidence: tokenConfidence
285
+ })
286
+ }
287
+ }
288
+
289
+ const allTokenIds = tokenTimeline.map(entry => entry.id!)
290
+ const transcript = whisper.tokensToText(allTokenIds).trim()
291
+
292
+ let timeline = whisper.tokenTimelineToWordTimeline(tokenTimeline)
293
+
294
+ return {
295
+ transcript,
296
+ timeline,
297
+ language: resultObject.result.language
298
+ }
299
+ }
300
+
301
+ function parseStdOutLinesToTimeline(lines: string[], entryType: TimelineEntryType): RecognitionResult {
302
+ let transcript = ''
303
+ const timeline: Timeline = []
304
+
305
+ for (const line of lines) {
306
+ const openingSquareBracketIndex = line.indexOf('[')
307
+ const closingSquareBracketIndex = line.indexOf(']', openingSquareBracketIndex + 1)
308
+
309
+ const timeRangeString = line.substring(openingSquareBracketIndex + 1, closingSquareBracketIndex)
310
+
311
+ const { startTime, endTime, succeeded } = tryParseTimeRangePatternWithHours(timeRangeString)
312
+
313
+ if (!succeeded) {
314
+ continue
315
+ }
316
+
317
+ const text = line.substring(closingSquareBracketIndex + 1 + 2)
318
+
319
+ if (text.length === 0) {
320
+ continue
321
+ }
322
+
323
+ transcript += text
324
+
325
+ if (timeline.length === 0 || text.startsWith(' ')) {
326
+ timeline.push({
327
+ type: entryType,
328
+ text: text.trim(),
329
+ startTime: startTime,
330
+ endTime: endTime,
331
+ })
332
+ } else {
333
+ const previousEntry = timeline[timeline.length - 1]
334
+
335
+ previousEntry.text += text
336
+ previousEntry.endTime = endTime
337
+ }
338
+ }
339
+
340
+ return { transcript, timeline }
341
+ }
342
+
343
+ export async function loadModelPackage(modelId: WhisperCppModelId | undefined, languageCode: string | undefined) {
344
+ if (modelId === 'large') {
345
+ modelId = 'large-v2'
346
+ }
347
+
348
+ if (modelId) {
349
+ const modelName = getModelNameFromModelId(modelId)
350
+
351
+ if (languageCode != 'en' && modelName.endsWith('.en')) {
352
+ throw new Error(`The English-only model '${modelName}' cannot be used with a non-English language '${languageCode}'.`)
353
+ }
354
+ } else {
355
+ if (languageCode) {
356
+ const shortLanguageCode = getShortLanguageCode(languageCode)
357
+
358
+ modelId = shortLanguageCode == 'en' ? 'base.en' : 'base'
359
+ } else {
360
+ modelId = 'base'
361
+ }
362
+ }
363
+
364
+ const packageName = `whisper.cpp-${modelId}`
365
+ const modelDir = await loadPackage(packageName)
366
+ const modelPath = path.join(modelDir, `ggml-${modelId}.bin`)
367
+ const modelName = getModelNameFromModelId(modelId)
368
+
369
+ return { modelName, modelPath }
370
+ }
371
+
372
+ export type WhisperCppBuild = 'cpu' | 'cublas-11.8.0' | 'cublas-12.4.0' | 'custom'
373
+
374
+ export async function loadExecutablePackage(buildKind: WhisperCppBuild) {
375
+ if (buildKind === 'custom') {
376
+ throw new Error(`A 'custom' build kind requires providing a custom path to the whisper.cpp binary in the 'executablePath' option.`)
377
+ }
378
+
379
+ const platform = process.platform
380
+ const arch = process.arch
381
+
382
+ let packageName: string
383
+
384
+ if (buildKind.startsWith('cublas-')) {
385
+ if (platform === 'win32' && arch === 'x64') {
386
+ packageName = `whisper.cpp-binaries-windows-x64-${buildKind}-latest-patched`
387
+ } else {
388
+ throw new Error(`GPU builds (NVIDIA CUDA only) are currently only available as packages for Windows x64. Please specify a custom path to the binary in the 'executablePath' option.`)
389
+ }
390
+ } else if (buildKind === 'cpu') {
391
+ if (platform === 'win32' && arch === 'x64') {
392
+ packageName = `whisper.cpp-binaries-windows-x64-cpu-latest-patched`
393
+ } else if (platform === 'linux' && arch === 'x64') {
394
+ packageName = `whisper.cpp-binaries-linux-x64-cpu-latest-patched`
395
+ } else {
396
+ throw new Error(`Couldn't find a matching whisper.cpp binary package. Please specify a custom path to the binary in the 'executablePath' option.`)
397
+ }
398
+ } else {
399
+ throw new Error(`Unknown build kind '${buildKind}'`)
400
+ }
401
+
402
+ const packagePath = await loadPackage(packageName)
403
+
404
+ let filename = 'main'
405
+
406
+ if (platform === 'win32') {
407
+ filename += '.exe'
408
+ }
409
+
410
+ return path.join(packagePath, filename)
411
+ }
412
+
413
+ function getModelNameFromModelId(modelId: WhisperCppModelId): WhisperModelName {
414
+ let lastDashIndex = modelId.lastIndexOf('-')
415
+
416
+ if (modelId.startsWith('large-v') && lastDashIndex === 5) {
417
+ lastDashIndex = -1
418
+ }
419
+
420
+ let modelName: string
421
+
422
+ if (lastDashIndex >= 0) {
423
+ modelName = modelId.substring(0, lastDashIndex) as WhisperModelName
424
+ } else {
425
+ modelName = modelId
426
+ }
427
+
428
+ return modelName as WhisperModelName
429
+ }
430
+
431
+ export interface WhisperCppVerboseResult {
432
+ model: {
433
+ type: string
434
+ multilingual: boolean
435
+
436
+ ftype: number
437
+ mels: number
438
+ vocab: number
439
+
440
+ text: {
441
+ ctx: number
442
+ state: number
443
+ head: number
444
+ layer: number
445
+ }
446
+
447
+ audio: {
448
+ ctx: number
449
+ state: number
450
+ head: number
451
+ layer: number
452
+ }
453
+ }
454
+
455
+ params: {
456
+ language: string
457
+ model: string
458
+ translate: boolean
459
+ }
460
+
461
+ result: {
462
+ language: string
463
+ }
464
+
465
+ systeminfo: string
466
+
467
+ transcription: {
468
+ text: string
469
+ timestamps: { from: string, to: string }
470
+ offsets: { from: number, to: number }
471
+
472
+ tokens: {
473
+ text: string
474
+ timestamps: { from: string, to: string }
475
+ offsets: { from: number, to: number }
476
+
477
+ t_dtw: number
478
+ p: number
479
+ id: number
480
+ }[]
481
+ }[]
482
+ }
483
+
484
+ interface RecognitionResult {
485
+ transcript: string
486
+ timeline: Timeline
487
+ language?: string
488
+ }
489
+
490
+ export interface WhisperCppOptions {
491
+ build?: WhisperCppBuild
492
+ executablePath?: string
493
+ enableGPU?: boolean
494
+
495
+ model?: WhisperCppModelId
496
+
497
+ threadCount?: number,
498
+ splitCount?: number,
499
+
500
+ topCandidateCount?: number
501
+ beamCount?: number
502
+ repetitionThreshold?: number
503
+
504
+ prompt?: string
505
+
506
+ enableDTW?: boolean
507
+
508
+ verbose?: boolean
509
+ }
510
+
511
+ export const defaultWhisperCppOptions: WhisperCppOptions = {
512
+ build: undefined,
513
+ executablePath: undefined,
514
+
515
+ model: undefined,
516
+
517
+ threadCount: 4,
518
+ splitCount: 1,
519
+ enableGPU: undefined,
520
+
521
+ topCandidateCount: 5,
522
+ beamCount: 5,
523
+ repetitionThreshold: 2.4,
524
+
525
+ prompt: undefined,
526
+
527
+ enableDTW: false,
528
+
529
+ verbose: false,
530
+ }
531
+
532
+ export type WhisperCppModelId =
533
+ 'tiny' |
534
+ 'tiny-q5_1' |
535
+ 'tiny.en' |
536
+ 'tiny.en-q5_1' |
537
+ 'tiny.en-q8_0' |
538
+ 'base' |
539
+ 'base-q5_1' |
540
+ 'base.en' |
541
+ 'base.en-q5_1' |
542
+ 'small' |
543
+ 'small-q5_1' |
544
+ 'small.en' |
545
+ 'small.en-q5_1' |
546
+ 'medium' |
547
+ 'medium-q5_0' |
548
+ 'medium.en' |
549
+ 'medium.en-q5_0' |
550
+ 'large' |
551
+ 'large-v1' |
552
+ 'large-v2' |
553
+ 'large-v2-q5_0' |
554
+ 'large-v3' |
555
+ 'large-v3-q5_0'