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
@@ -9,9 +9,10 @@ import { ParagraphBreakType, WhitespaceProcessing } from '../api/Common.js'
9
9
  const log = logToStderr
10
10
 
11
11
  export const wordCharacterPattern = /[\p{Letter}\p{Number}]/u
12
- export const phraseSeparators = [",", ";", ":"]
13
- export const sentenceSeparators = [".", "?", "!"]
14
- export const symbolWords = ["$", "€", "¢", "£", "¥", "©", "®", "™", "%", "&", "#", "~", "@", "+", "±", "÷", "/", "*", "=", "¼", "½", "¾"]
12
+ export const punctuationPattern = /[\p{Punctuation}]/u
13
+ export const phraseSeparators = [',', ';', ':']
14
+ export const sentenceSeparators = ['.', '?', '!']
15
+ export const symbolWords = ['$', '€', '¢', '£', '¥', '©', '®', '™', '%', '&', '#', '~', '@', '+', '±', '÷', '/', '*', '=', '¼', '½', '¾']
15
16
 
16
17
  export function isWordOrSymbolWord(str: string) {
17
18
  return isWord(str) || symbolWords.includes(str)
@@ -22,6 +23,10 @@ export function isWord(str: string) {
22
23
  return wordCharacterPattern.test(str) || symbolWords.includes(str)
23
24
  }
24
25
 
26
+ export function isPunctuation(str: string) {
27
+ return punctuationPattern.test(str)
28
+ }
29
+
25
30
  export class Sentence {
26
31
  phrases: Phrase[] = []
27
32
 
@@ -29,7 +34,7 @@ export class Sentence {
29
34
 
30
35
  get length() { return sumArray(this.phrases, (phrase) => phrase.length) }
31
36
 
32
- get text() { return this.phrases.reduce<string>((result, phrase) => result + phrase.text, "") }
37
+ get text() { return this.phrases.reduce<string>((result, phrase) => result + phrase.text, '') }
33
38
  }
34
39
 
35
40
  export class Phrase {
@@ -37,7 +42,7 @@ export class Phrase {
37
42
 
38
43
  get length() { return sumArray(this.words, (word) => word.length) }
39
44
 
40
- get text() { return this.words.reduce<string>((result, word) => result + word.text, "") }
45
+ get text() { return this.words.reduce<string>((result, word) => result + word.text, '') }
41
46
 
42
47
  get lastWord() {
43
48
  if (this.words.length == 0) {
@@ -75,7 +80,7 @@ export class Fragment {
75
80
 
76
81
  get length() { return sumArray(this.segments, (phrase) => phrase.length) }
77
82
 
78
- get text() { return this.segments.reduce<string>((result, segment) => result + segment.text, "") }
83
+ get text() { return this.segments.reduce<string>((result, segment) => result + segment.text, '') }
79
84
 
80
85
  get isEmpty() { return this.length == 0 }
81
86
 
@@ -196,17 +201,17 @@ export async function parse(text: string, langCode: string) {
196
201
  }
197
202
 
198
203
  export function splitToSentences(text: string, langCode: string): string[] {
199
- const shortLangCode = getShortLanguageCode(langCode || "")
204
+ const shortLangCode = getShortLanguageCode(langCode || '')
200
205
 
201
206
  return CldrSegmentation.sentenceSplit(text, CldrSegmentation.suppressions[shortLangCode])
202
207
  }
203
208
 
204
209
  export async function splitToWords(text: string, langCode: string): Promise<string[]> {
205
- const shortLangCode = getShortLanguageCode(langCode || "")
210
+ const shortLangCode = getShortLanguageCode(langCode || '')
206
211
 
207
- if (shortLangCode == "zh" || shortLangCode == "cmn") {
212
+ if (shortLangCode == 'zh' || shortLangCode == 'cmn') {
208
213
  return splitChineseTextToWords_Jieba(text, undefined, true)
209
- } else if (shortLangCode == "ja") {
214
+ } else if (shortLangCode == 'ja') {
210
215
  return splitJapaneseTextToWords_Kuromoji(text)
211
216
  } else {
212
217
  return CldrSegmentation.wordSplit(text, CldrSegmentation.suppressions[shortLangCode])
@@ -224,10 +229,10 @@ export function splitToParagraphs(text: string, paragraphBreaks: ParagraphBreakT
224
229
  throw new Error(`Invalid paragraph break type: ${paragraphBreaks}`)
225
230
  }
226
231
 
227
- if (whitespace == "removeLineBreaks") {
228
- paragraphs = paragraphs.map(p => p.replaceAll(/(\r?\n)+/g, " "))
229
- } else if (whitespace == "collapse") {
230
- paragraphs = paragraphs.map(p => p.replaceAll(/\s+/g, " "))
232
+ if (whitespace == 'removeLineBreaks') {
233
+ paragraphs = paragraphs.map(p => p.replaceAll(/(\r?\n)+/g, ' '))
234
+ } else if (whitespace == 'collapse') {
235
+ paragraphs = paragraphs.map(p => p.replaceAll(/\s+/g, ' '))
231
236
  }
232
237
 
233
238
  paragraphs = paragraphs.map(p => p.trim())
@@ -235,3 +240,7 @@ export function splitToParagraphs(text: string, paragraphBreaks: ParagraphBreakT
235
240
 
236
241
  return paragraphs
237
242
  }
243
+
244
+ export function splitToLines(text: string) {
245
+ return text.split(/\r?\n/g)
246
+ }
@@ -1,9 +1,9 @@
1
- import { getShortLanguageCode } from "../utilities/Locale.js"
1
+ import { getShortLanguageCode } from '../utilities/Locale.js'
2
2
 
3
3
  export function getNormalizedFragmentsForSpeech(words: string[], language: string) {
4
4
  language = getShortLanguageCode(language)
5
5
 
6
- if (language != "en") {
6
+ if (language != 'en') {
7
7
  return { normalizedFragments: [...words], referenceFragments: [...words] }
8
8
  }
9
9
 
@@ -15,26 +15,26 @@ export function getNormalizedFragmentsForSpeech(words: string[], language: strin
15
15
  const fourDigitYearRangePattern = /^[0-9][0-9][0-9][0-9][\-\–][0-9][0-9][0-9][0-9]$/
16
16
 
17
17
  const wordsPrecedingAYear = [
18
- "in", "the", "a", "to", "of", "since", "from", "between", "by", "until", "around", "before", "after",
19
- "his", "her", "year", "years", "during", "copyright", "©", "early", "mid", "late",
20
- "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december",
21
- "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"
18
+ 'in', 'the', 'a', 'to', 'of', 'since', 'from', 'between', 'by', 'until', 'around', 'before', 'after',
19
+ 'his', 'her', 'year', 'years', 'during', 'copyright', '©', 'early', 'mid', 'late',
20
+ 'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december',
21
+ 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'
22
22
  ]
23
23
 
24
24
  const wordsPrecedingADecade = [
25
- "the", "in", "early", "mid", "late", "a"
25
+ 'the', 'in', 'early', 'mid', 'late', 'a'
26
26
  ]
27
27
 
28
28
  const symbolsPrecedingACurrency = [
29
- "$", "", "£", "¥"
29
+ '$', '', '£', '¥'
30
30
  ]
31
31
 
32
32
  const symbolsPrecedingACurrencyAsWords = [
33
- "dollars", "euros", "pounds", "yen"
33
+ 'dollars', 'euros', 'pounds', 'yen'
34
34
  ]
35
35
 
36
36
  const wordsSucceedingACurrency = [
37
- "million", "billion", "trillion"
37
+ 'million', 'billion', 'trillion'
38
38
  ]
39
39
 
40
40
  const normalizedFragments: string[] = []
@@ -47,7 +47,7 @@ export function getNormalizedFragmentsForSpeech(words: string[], language: strin
47
47
  const nextWords = words.slice(wordIndex + 1)
48
48
  const nextWord = nextWords[0]
49
49
 
50
- if ( // Normalize a four digit year pattern, e.g. "in 1995".
50
+ if ( // Normalize a four digit year pattern, e.g. 'in 1995'.
51
51
  wordsPrecedingAYear.includes(lowerCaseWord) &&
52
52
  fourDigitYearPattern.test(nextWord)) {
53
53
 
@@ -60,7 +60,7 @@ export function getNormalizedFragmentsForSpeech(words: string[], language: strin
60
60
  referenceFragments.push(nextWord)
61
61
 
62
62
  wordIndex += 1
63
- } else if ( // Normalize a four digit decade pattern, e.g. "the 1980s".
63
+ } else if ( // Normalize a four digit decade pattern, e.g. 'the 1980s'.
64
64
  wordsPrecedingADecade.includes(lowerCaseWord) &&
65
65
  fourDigitDecadePattern.test(nextWord)) {
66
66
 
@@ -73,20 +73,20 @@ export function getNormalizedFragmentsForSpeech(words: string[], language: strin
73
73
  referenceFragments.push(nextWord)
74
74
 
75
75
  wordIndex += 1
76
- } else if ( // Normalize a year range pattern, e.g. "1835-1896"
77
- fourDigitYearRangePattern.test(words.slice(wordIndex, wordIndex + 3).join(""))) {
76
+ } else if ( // Normalize a year range pattern, e.g. '1835-1896'
77
+ fourDigitYearRangePattern.test(words.slice(wordIndex, wordIndex + 3).join(''))) {
78
78
 
79
79
  normalizedFragments.push(normalizeFourDigitYearString(words[wordIndex]))
80
80
  referenceFragments.push(words[wordIndex])
81
81
 
82
- normalizedFragments.push("to")
82
+ normalizedFragments.push('to')
83
83
  referenceFragments.push(words[wordIndex + 1])
84
84
 
85
85
  normalizedFragments.push(normalizeFourDigitYearString(words[wordIndex + 2]))
86
86
  referenceFragments.push(words[wordIndex + 2])
87
87
 
88
88
  wordIndex += 2
89
- } else if ( // Normalize a currency pattern, e.g. "$53.1 million", "€3.53"
89
+ } else if ( // Normalize a currency pattern, e.g. '$53.1 million', '€3.53'
90
90
  symbolsPrecedingACurrency.includes(lowerCaseWord) &&
91
91
  numberPattern.test(nextWord)) {
92
92
 
@@ -1,17 +1,17 @@
1
- import type { Item, LanguageCode, StartStreamTranscriptionCommandInput } from "@aws-sdk/client-transcribe-streaming"
2
- import { wordCharacterPattern } from "../nlp/Segmentation.js"
3
- import * as FFMpegTranscoder from "../codecs/FFMpegTranscoder.js"
4
- import { Logger } from "../utilities/Logger.js"
5
- import { Timeline } from "../utilities/Timeline.js"
6
- import { RawAudio } from "../audio/AudioUtilities.js"
1
+ import type { Item, LanguageCode, StartStreamTranscriptionCommandInput } from '@aws-sdk/client-transcribe-streaming'
2
+ import { wordCharacterPattern } from '../nlp/Segmentation.js'
3
+ import * as FFMpegTranscoder from '../codecs/FFMpegTranscoder.js'
4
+ import { Logger } from '../utilities/Logger.js'
5
+ import { Timeline } from '../utilities/Timeline.js'
6
+ import { RawAudio } from '../audio/AudioUtilities.js'
7
7
 
8
8
  export async function recgonize(rawAudio: RawAudio, languageCode: string, region: string, accessKeyId: string, secretAccessKey: string) {
9
- const flac16Khz16bitMonoAudio = await FFMpegTranscoder.encodeFromChannels(rawAudio, { format: "flac", sampleRate: 16000, sampleFormat: "s16", channelCount: 1 })
9
+ const flac16Khz16bitMonoAudio = await FFMpegTranscoder.encodeFromChannels(rawAudio, { format: 'flac', sampleRate: 16000, sampleFormat: 's16', channelCount: 1 })
10
10
 
11
11
  const logger = new Logger()
12
- logger.start("Initialize Amazon Transcribe streaming client module")
12
+ logger.start('Initialize Amazon Transcribe streaming client module')
13
13
 
14
- const streamingTranscribeSdk = await import("@aws-sdk/client-transcribe-streaming")
14
+ const streamingTranscribeSdk = await import('@aws-sdk/client-transcribe-streaming')
15
15
 
16
16
  const streamingTranscribeClient = new streamingTranscribeSdk.TranscribeStreamingClient({
17
17
  region,
@@ -23,7 +23,6 @@ export async function recgonize(rawAudio: RawAudio, languageCode: string, region
23
23
 
24
24
  const audioStream = async function* () {
25
25
  const chunkSize = 2 ** 12
26
- //const audioSamples = encodeToAudioBuffer(rawAudio.audioChannels, 16, SampleFormat.PCM)
27
26
 
28
27
  for (let i = 0; i < flac16Khz16bitMonoAudio.length; i += chunkSize) {
29
28
  const chunk = flac16Khz16bitMonoAudio.subarray(i, i + chunkSize)
@@ -35,17 +34,17 @@ export async function recgonize(rawAudio: RawAudio, languageCode: string, region
35
34
  const params: StartStreamTranscriptionCommandInput = {
36
35
  LanguageCode: languageCode as LanguageCode,
37
36
  MediaSampleRateHertz: rawAudio.sampleRate,
38
- MediaEncoding: "flac",
37
+ MediaEncoding: 'flac',
39
38
  AudioStream: audioStream(),
40
39
  }
41
40
 
42
- logger.start("Request recognition from Amazon Transcribe..")
41
+ logger.start('Request recognition from Amazon Transcribe')
43
42
 
44
43
  const command = new streamingTranscribeSdk.StartStreamTranscriptionCommand(params)
45
44
 
46
45
  const response = await streamingTranscribeClient.send(command)
47
46
 
48
- let transcript = ""
47
+ let transcript = ''
49
48
  let events: Item[] = []
50
49
 
51
50
  for await (const event of response.TranscriptResultStream!) {
@@ -73,13 +72,13 @@ export async function recgonize(rawAudio: RawAudio, languageCode: string, region
73
72
 
74
73
  if (firstResult.IsPartial === false) {
75
74
  events = [...events, ...firstAlternative.Items!]
76
- transcript += " " + firstAlternative.Transcript!
75
+ transcript += ' ' + firstAlternative.Transcript!
77
76
  }
78
77
  }
79
78
 
80
- logger.start("Process result")
79
+ logger.start('Process result')
81
80
 
82
- transcript = transcript.replace(/ +/g, " ").trim()
81
+ transcript = transcript.replace(/ +/g, ' ').trim()
83
82
 
84
83
  const timeline: Timeline = []
85
84
 
@@ -98,7 +97,7 @@ export async function recgonize(rawAudio: RawAudio, languageCode: string, region
98
97
 
99
98
  timeline.push(
100
99
  {
101
- type: "word",
100
+ type: 'word',
102
101
  text,
103
102
  startTime,
104
103
  endTime,
@@ -1,16 +1,17 @@
1
1
  import * as SpeechSDK from 'microsoft-cognitiveservices-speech-sdk'
2
2
 
3
- import { RawAudio, encodeWaveBuffer } from '../audio/AudioUtilities.js'
3
+ import { RawAudio, encodeRawAudioToWave } from '../audio/AudioUtilities.js'
4
4
  import { Logger } from '../utilities/Logger.js'
5
5
  import { Timeline } from '../utilities/Timeline.js'
6
6
 
7
7
  export async function recognize(rawAudio: RawAudio, subscriptionKey: string, serviceRegion: string, languageCode: string, profanity: SpeechSDK.ProfanityOption = SpeechSDK.ProfanityOption.Raw) {
8
8
  const logger = new Logger()
9
- logger.start("Request recognition from Azure Cognitive Services")
9
+
10
+ logger.start('Request recognition from Azure Cognitive Services')
10
11
 
11
12
  const result = await requestRecognition(rawAudio, subscriptionKey, serviceRegion, languageCode)
12
13
 
13
- logger.start("Process result")
14
+ logger.start('Process result')
14
15
 
15
16
  const transcript = result.text
16
17
 
@@ -25,7 +26,7 @@ export async function recognize(rawAudio: RawAudio, subscriptionKey: string, ser
25
26
  const endTime = (wordEntry.Offset + wordEntry.Duration) / 10000000
26
27
 
27
28
  timeline.push({
28
- type: "word",
29
+ type: 'word',
29
30
  text,
30
31
  startTime,
31
32
  endTime
@@ -38,8 +39,7 @@ export async function recognize(rawAudio: RawAudio, subscriptionKey: string, ser
38
39
  }
39
40
 
40
41
  async function requestRecognition(rawAudio: RawAudio, subscriptionKey: string, serviceRegion: string, languageCode: string, profanity: SpeechSDK.ProfanityOption = SpeechSDK.ProfanityOption.Raw) {
41
- //const encodedAudio = await FFMpegTranscoder.encodeFromChannels(rawAudio, { format: "wav", sampleRate: 16000, sampleFormat: "s16", channelCount: 1 });
42
- const encodedAudio = encodeWaveBuffer(rawAudio)
42
+ const encodedAudio = encodeRawAudioToWave(rawAudio)
43
43
 
44
44
  return new Promise<SpeechSDK.SpeechRecognitionResult>((resolve, reject) => {
45
45
  const audioFormat = SpeechSDK.AudioStreamFormat.getWaveFormat(16000, 16, 1, SpeechSDK.AudioFormatTag.PCM)
@@ -65,11 +65,13 @@ async function requestRecognition(rawAudio: RawAudio, subscriptionKey: string, s
65
65
  recognizer.recognizeOnceAsync(
66
66
  (result) => {
67
67
  recognizer.close()
68
+
68
69
  resolve(result)
69
70
  },
70
71
 
71
72
  (error) => {
72
73
  recognizer.close()
74
+
73
75
  reject(error)
74
76
  })
75
77
  })
@@ -1,21 +1,21 @@
1
- import { request } from "gaxios"
1
+ import { request } from 'gaxios'
2
2
 
3
- import * as FFMpegTranscoder from "../codecs/FFMpegTranscoder.js"
4
- import { Logger } from "../utilities/Logger.js"
5
- import { Timeline } from "../utilities/Timeline.js"
6
- import { RawAudio } from "../audio/AudioUtilities.js"
3
+ import * as FFMpegTranscoder from '../codecs/FFMpegTranscoder.js'
4
+ import { Logger } from '../utilities/Logger.js'
5
+ import { Timeline } from '../utilities/Timeline.js'
6
+ import { RawAudio } from '../audio/AudioUtilities.js'
7
7
 
8
- export type AudioEncoding = "LINEAR16" | "FLAC" | "MULAW" | "AMR" | "AMR" | "AMR_WB" | "OGG_OPUS" | "SPEEX_WITH_HEADER_BYTE" | "MP3" | "WEBM_OPUS"
8
+ export type AudioEncoding = 'LINEAR16' | 'FLAC' | 'MULAW' | 'AMR' | 'AMR' | 'AMR_WB' | 'OGG_OPUS' | 'SPEEX_WITH_HEADER_BYTE' | 'MP3' | 'WEBM_OPUS'
9
9
 
10
- export async function recognize(rawAudio: RawAudio, apiKey: string, languageCode = "en-US") {
11
- const flac16Khz16bitMonoAudio = await FFMpegTranscoder.encodeFromChannels(rawAudio, { format: "flac", sampleRate: 16000, sampleFormat: "s16", channelCount: 1 })
10
+ export async function recognize(rawAudio: RawAudio, apiKey: string, languageCode = 'en-US') {
11
+ const flac16Khz16bitMonoAudio = await FFMpegTranscoder.encodeFromChannels(rawAudio, { format: 'flac', sampleRate: 16000, sampleFormat: 's16', channelCount: 1 })
12
12
 
13
13
  const logger = new Logger()
14
- logger.start("Request recognition from Google Cloud")
14
+ logger.start('Request recognition from Google Cloud')
15
15
 
16
16
  const requestBody = {
17
17
  config: {
18
- encoding: "FLAC",
18
+ encoding: 'FLAC',
19
19
  sampleRateHertz: 16000,
20
20
  audioChannelCount: 1,
21
21
  languageCode,
@@ -25,35 +25,35 @@ export async function recognize(rawAudio: RawAudio, apiKey: string, languageCode
25
25
  enableWordTimeOffsets: true,
26
26
  enableWordConfidence: true,
27
27
  enableAutomaticPunctuation: true,
28
- model: "latest_long",
28
+ model: 'latest_long',
29
29
  useEnhanced: true
30
30
  },
31
31
 
32
32
  audio: {
33
- content: flac16Khz16bitMonoAudio.toString("base64")
33
+ content: flac16Khz16bitMonoAudio.toString('base64')
34
34
  }
35
35
  }
36
36
 
37
37
  const response = await request<any>({
38
- method: "POST",
38
+ method: 'POST',
39
39
 
40
40
  url: `https://speech.googleapis.com/v1p1beta1/speech:recognize`,
41
41
 
42
42
  params: {
43
- "key": apiKey
43
+ 'key': apiKey
44
44
  },
45
45
 
46
46
  headers: {
47
- "User-Agent": ""
47
+ 'User-Agent': ''
48
48
  },
49
49
 
50
50
  data: requestBody,
51
51
 
52
52
 
53
- responseType: "json"
53
+ responseType: 'json'
54
54
  })
55
55
 
56
- logger.start("Parse response body")
56
+ logger.start('Parse response body')
57
57
 
58
58
  const result = parseResponseBody(response.data)
59
59
 
@@ -65,7 +65,7 @@ export async function recognize(rawAudio: RawAudio, apiKey: string, languageCode
65
65
  function parseResponseBody(responseBody: any) {
66
66
  const results = responseBody.results
67
67
 
68
- let transcript = ""
68
+ let transcript = ''
69
69
  const timeline: Timeline = []
70
70
 
71
71
  for (const result of results) {
@@ -79,10 +79,10 @@ function parseResponseBody(responseBody: any) {
79
79
 
80
80
  for (const wordEvent of firstAlternative.words) {
81
81
  timeline.push({
82
- type: "word",
82
+ type: 'word',
83
83
  text: wordEvent.word,
84
- startTime: parseFloat(wordEvent.startTime.replace("s","")),
85
- endTime: parseFloat(wordEvent.endTime.replace("s", "")),
84
+ startTime: parseFloat(wordEvent.startTime.replace('s','')),
85
+ endTime: parseFloat(wordEvent.endTime.replace('s', '')),
86
86
  confidence: wordEvent.confidence
87
87
  })
88
88
  }
@@ -0,0 +1,142 @@
1
+ import { RawAudio } from '../audio/AudioUtilities.js';
2
+ import * as FFMpegTranscoder from '../codecs/FFMpegTranscoder.js'
3
+ import { Logger } from '../utilities/Logger.js';
4
+ import { extendDeep } from '../utilities/ObjectUtilities.js';
5
+ import { Timeline, TimelineEntry } from '../utilities/Timeline.js';
6
+
7
+ export async function recognize(rawAudio: RawAudio, languageCode: string, options: OpenAICloudSTTOptions, task: Task = 'transcribe') {
8
+ const logger = new Logger()
9
+
10
+ logger.start('Load OpenAI module')
11
+
12
+ options = extendDeep(defaultOpenAICloudSTTOptions, options)
13
+
14
+ const { default: OpenAI } = await import('openai')
15
+ const openai = new OpenAI(options)
16
+
17
+ logger.start('Encode audio to send')
18
+ const ffmpegOptions = FFMpegTranscoder.getDefaultFFMpegOptionsForSpeech('mp3')
19
+ const encodedAudio = await FFMpegTranscoder.encodeFromChannels(rawAudio, ffmpegOptions)
20
+ const audioAsWaveBlob = new FileLikeBlob([encodedAudio], 'audio', Date.now(), { type: 'audio/mpeg' })
21
+
22
+ logger.start('Request recognition from OpenAI Cloud API')
23
+
24
+ let response: VerboseResponse
25
+
26
+ if (task =='transcribe') {
27
+ response = await openai.audio.transcriptions.create({
28
+ file: audioAsWaveBlob,
29
+ model: options.model!,
30
+ language: languageCode,
31
+ prompt: options.prompt,
32
+ response_format: 'verbose_json',
33
+ temperature: options.temperature,
34
+ timestamp_granularities: ['word', 'segment']
35
+ }) as VerboseResponse
36
+ } else if (task == 'translate') {
37
+ response = await openai.audio.translations.create({
38
+ file: audioAsWaveBlob,
39
+ model: options.model!,
40
+ prompt: options.prompt,
41
+ response_format: 'verbose_json',
42
+ temperature: options.temperature,
43
+ }) as VerboseResponse
44
+ } else {
45
+ throw new Error(`Invalid task`)
46
+ }
47
+
48
+ const transcript = response.text
49
+
50
+ let timeline: Timeline
51
+
52
+ if (response.words) {
53
+ timeline = response.words.map<TimelineEntry>(entry => ({
54
+ type: 'word',
55
+ text: entry.word,
56
+ startTime: entry.start,
57
+ endTime: entry.end
58
+ }))
59
+ } else {
60
+ timeline = response.segments.map<TimelineEntry>(entry => ({
61
+ type: 'segment',
62
+ text: entry.text,
63
+ startTime: entry.start,
64
+ endTime: entry.end
65
+ }))
66
+ }
67
+
68
+ logger.end()
69
+
70
+ return { transcript, timeline }
71
+ }
72
+
73
+ class FileLikeBlob extends Blob {
74
+ constructor(
75
+ public readonly parts: BlobPart[],
76
+ public readonly name: string,
77
+ public readonly lastModified: number,
78
+ options: BlobPropertyBag,
79
+ ) {
80
+ super(parts, options)
81
+ }
82
+ }
83
+
84
+ export interface OpenAICloudSTTOptions {
85
+ model?: 'whisper-1'
86
+
87
+ apiKey?: string
88
+ organization?: string
89
+ baseURL?: string
90
+
91
+ temperature?: number
92
+ prompt?: string
93
+
94
+ timeout?: number
95
+ maxRetries?: number
96
+ }
97
+
98
+ export const defaultOpenAICloudSTTOptions: OpenAICloudSTTOptions = {
99
+ apiKey: undefined,
100
+ organization: undefined,
101
+ baseURL: undefined,
102
+
103
+ model: 'whisper-1',
104
+ temperature: 0,
105
+ prompt: undefined,
106
+
107
+ timeout: undefined,
108
+ maxRetries: 10,
109
+ }
110
+
111
+ interface VerboseResponse {
112
+ task: string
113
+ language: string
114
+ duration: number
115
+
116
+ text: string
117
+
118
+ segments: {
119
+ text: string
120
+
121
+ start: number
122
+ end: number
123
+
124
+ id: number
125
+ no_speech_prob: number
126
+ compression_ratio: number
127
+ avg_logprob: number
128
+ seek: number
129
+ temperature: number
130
+
131
+ tokens: number[]
132
+ }[]
133
+
134
+ words: {
135
+ word: string
136
+
137
+ start: number
138
+ end: number
139
+ }[]
140
+ }
141
+
142
+ type Task = 'transcribe' | 'translate'