echogarden 0.11.12 → 0.11.13

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 (122) hide show
  1. package/data/schemas/options.json +16 -0
  2. package/dist/api/Alignment.js +2 -2
  3. package/dist/api/Alignment.js.map +1 -1
  4. package/dist/api/Recognition.js +2 -2
  5. package/dist/api/Recognition.js.map +1 -1
  6. package/dist/api/Synthesis.js +5 -4
  7. package/dist/api/Synthesis.js.map +1 -1
  8. package/dist/api/Translation.js +2 -2
  9. package/dist/api/Translation.js.map +1 -1
  10. package/dist/audio/AudioUtilities.d.ts +1 -0
  11. package/dist/audio/AudioUtilities.js +25 -7
  12. package/dist/audio/AudioUtilities.js.map +1 -1
  13. package/dist/cli/CLI.js +2 -2
  14. package/dist/cli/CLI.js.map +1 -1
  15. package/dist/recognition/WhisperSTT.js +2 -2
  16. package/dist/recognition/WhisperSTT.js.map +1 -1
  17. package/dist/subtitles/Subtitles.d.ts +10 -7
  18. package/dist/subtitles/Subtitles.js +268 -207
  19. package/dist/subtitles/Subtitles.js.map +1 -1
  20. package/docs/Options.md +4 -2
  21. package/package.json +7 -6
  22. package/src/alignment/DTWMfccSequenceAlignment.ts +43 -0
  23. package/src/alignment/DTWSequenceAlignment.ts +121 -0
  24. package/src/alignment/DTWSequenceAlignmentWindowed.ts +210 -0
  25. package/src/alignment/LevenshteinSequenceAlignment.ts +126 -0
  26. package/src/alignment/SpeechAlignment.ts +488 -0
  27. package/src/api/API.ts +12 -0
  28. package/src/api/APIOptions.ts +15 -0
  29. package/src/api/Alignment.ts +329 -0
  30. package/src/api/Common.ts +16 -0
  31. package/src/api/Denoising.ts +120 -0
  32. package/src/api/LanguageDetection.ts +286 -0
  33. package/src/api/Recognition.ts +344 -0
  34. package/src/api/Synthesis.ts +1735 -0
  35. package/src/api/Translation.ts +143 -0
  36. package/src/api/Vad.ts +172 -0
  37. package/src/audio/AudioBufferConversion.ts +248 -0
  38. package/src/audio/AudioPlayer.ts +358 -0
  39. package/src/audio/AudioRecorder.ts +91 -0
  40. package/src/audio/AudioUtilities.ts +392 -0
  41. package/src/audio/SoxPath.ts +24 -0
  42. package/src/cli/CLI.ts +1360 -0
  43. package/src/cli/CLIConfigFile.ts +91 -0
  44. package/src/cli/CLILauncher.ts +26 -0
  45. package/src/cli/CLIOptionsSchema.ts +54 -0
  46. package/src/cli/CLIParser.ts +41 -0
  47. package/src/cli/CLIStarter.ts +40 -0
  48. package/src/codecs/FFMpegTranscoder.ts +214 -0
  49. package/src/codecs/TIMITCodec.ts +17 -0
  50. package/src/codecs/WaveCodec.ts +260 -0
  51. package/src/denoising/RNNoise.ts +95 -0
  52. package/src/dsp/BiquadFilter.ts +488 -0
  53. package/src/dsp/FFT.ts +187 -0
  54. package/src/dsp/MFCC.ts +227 -0
  55. package/src/dsp/MelSpectogram.ts +145 -0
  56. package/src/dsp/Rubberband.ts +249 -0
  57. package/src/dsp/Sonic.ts +59 -0
  58. package/src/dsp/SpeexResampler.ts +79 -0
  59. package/src/math/VectorMath.ts +812 -0
  60. package/src/nlp/ChineseSegmentation.ts +68 -0
  61. package/src/nlp/CompromiseNLP.ts +113 -0
  62. package/src/nlp/EspeakPhonemizer.ts +168 -0
  63. package/src/nlp/IPA.ts +139 -0
  64. package/src/nlp/JapaneseSegmentation.ts +53 -0
  65. package/src/nlp/Lexicon.ts +119 -0
  66. package/src/nlp/PhoneConversion.ts +508 -0
  67. package/src/nlp/Segmentation.ts +237 -0
  68. package/src/nlp/TextNormalizer.ts +160 -0
  69. package/src/recognition/AmazonTranscribeSTT.ts +112 -0
  70. package/src/recognition/AzureCognitiveServicesSTT.ts +76 -0
  71. package/src/recognition/GoogleCloudSTT.ts +92 -0
  72. package/src/recognition/SileroSTT.ts +173 -0
  73. package/src/recognition/VoskSTT.ts +112 -0
  74. package/src/recognition/WhisperSTT.ts +1518 -0
  75. package/src/server/Client.ts +297 -0
  76. package/src/server/Server.ts +178 -0
  77. package/src/server/ServerStarter.ts +12 -0
  78. package/src/server/Worker.ts +400 -0
  79. package/src/server/WorkerStarter.ts +38 -0
  80. package/src/speech-language-detection/SileroLanguageDetection.ts +105 -0
  81. package/src/subtitles/Subtitles.ts +478 -0
  82. package/src/synthesis/AwsPollyTTS.ts +78 -0
  83. package/src/synthesis/AzureCognitiveServicesTTS.ts +146 -0
  84. package/src/synthesis/CoquiServerTTS.ts +29 -0
  85. package/src/synthesis/ElevenLabsTTS.ts +104 -0
  86. package/src/synthesis/EspeakTTS.ts +552 -0
  87. package/src/synthesis/FliteTTS.ts +387 -0
  88. package/src/synthesis/GoogleCloudTTS.ts +112 -0
  89. package/src/synthesis/GoogleTranslateTTS.ts +210 -0
  90. package/src/synthesis/MicrosoftEdgeTTS.ts +298 -0
  91. package/src/synthesis/SamTTS.ts +30 -0
  92. package/src/synthesis/SapiTTS.ts +222 -0
  93. package/src/synthesis/StreamlabsPollyTTS.ts +114 -0
  94. package/src/synthesis/SvoxPicoTTS.ts +318 -0
  95. package/src/synthesis/VitsTTS.ts +734 -0
  96. package/src/tests/Test.ts +24 -0
  97. package/src/text-language-detection/FastTextLanguageDetection.ts +53 -0
  98. package/src/text-language-detection/TinyLDLanguageDetection.ts +16 -0
  99. package/src/typings/Fillers.d.ts +41 -0
  100. package/src/utilities/BinaryArrayConversion.ts +159 -0
  101. package/src/utilities/Compression.ts +91 -0
  102. package/src/utilities/FileDownloader.ts +201 -0
  103. package/src/utilities/FileSystem.ts +265 -0
  104. package/src/utilities/Hashing.ts +230 -0
  105. package/src/utilities/Locale.ts +119 -0
  106. package/src/utilities/Logger.ts +72 -0
  107. package/src/utilities/NdArrayUtilities.ts +31 -0
  108. package/src/utilities/ObjectUtilities.ts +169 -0
  109. package/src/utilities/OpenPromise.ts +13 -0
  110. package/src/utilities/PackageManager.ts +97 -0
  111. package/src/utilities/Queue.ts +17 -0
  112. package/src/utilities/RandomGenerator.ts +237 -0
  113. package/src/utilities/SignalChannel.ts +22 -0
  114. package/src/utilities/TarballMaker.ts +68 -0
  115. package/src/utilities/Timeline.ts +231 -0
  116. package/src/utilities/Timer.ts +93 -0
  117. package/src/utilities/Utilities.ts +574 -0
  118. package/src/utilities/WasmMemoryManager.ts +516 -0
  119. package/src/utilities/WebReader.ts +55 -0
  120. package/src/utilities/WikipediaReader.ts +41 -0
  121. package/src/voice-activity-detection/SileroVAD.ts +86 -0
  122. package/src/voice-activity-detection/WebRtcVAD.ts +76 -0
@@ -0,0 +1,173 @@
1
+ import { indexOfMax } from "../math/VectorMath.js"
2
+ import { wordCharacterPattern } from '../nlp/Segmentation.js'
3
+ import Onnx from 'onnxruntime-node'
4
+ import { Logger } from '../utilities/Logger.js'
5
+ import { logToStderr } from "../utilities/Utilities.js"
6
+ import { Timeline } from "../utilities/Timeline.js"
7
+ import { RawAudio, getRawAudioDuration } from "../audio/AudioUtilities.js"
8
+ import { readAndParseJsonFile, readFile } from "../utilities/FileSystem.js"
9
+ import path from "path"
10
+
11
+ const log = logToStderr
12
+
13
+ export async function recognize(rawAudio: RawAudio, modelDirectory: string) {
14
+ const logger = new Logger()
15
+ logger.start("Create ONNX inference session")
16
+
17
+ const modelPath = path.join(modelDirectory, "model.onnx")
18
+ const labelsPath = path.join(modelDirectory, "labels.json")
19
+
20
+ const labels: string[] = await readAndParseJsonFile(labelsPath)
21
+
22
+ const onnxOptions: Onnx.InferenceSession.SessionOptions = {
23
+ logSeverityLevel: 3
24
+ }
25
+
26
+ const recognition = await Onnx.InferenceSession.create(modelPath, onnxOptions)
27
+
28
+ logger.start("Prepare input data")
29
+
30
+ const audioSamples = rawAudio.audioChannels[0]
31
+
32
+ const inputTensor = new Onnx.Tensor('float32', audioSamples, [1, audioSamples.length])
33
+
34
+ const inputs = { input: inputTensor }
35
+
36
+ logger.start("Recognize with silero model")
37
+
38
+ const results = await recognition.run(inputs)
39
+
40
+ const rawResultValues = results["output"].data as Float32Array
41
+
42
+ const tokenResults: Float32Array[] = []
43
+
44
+ for (let i = 0; i < rawResultValues.length; i += labels.length) {
45
+ tokenResults.push(rawResultValues.subarray(i, i + labels.length))
46
+ }
47
+
48
+ const tokens: string[] = []
49
+
50
+ for (const tokenResult of tokenResults) {
51
+ const bestCandidateIndex = indexOfMax(new Array(...tokenResult))
52
+ tokens.push(labels[bestCandidateIndex])
53
+ }
54
+
55
+ //log(tokens.join("|"))
56
+
57
+ const result = processTokens(tokens, getRawAudioDuration(rawAudio))
58
+
59
+ logger.end()
60
+
61
+ return result
62
+ }
63
+
64
+ function processTokens(tokens: string[], totalDuration: number) {
65
+ const tokenCount = tokens.length
66
+
67
+ const decodedTokens: string[] = []
68
+ let tokenGroupIndexes: number[][] = [[]]
69
+
70
+ for (let i = 0; i < tokenCount; i++) {
71
+ const token = tokens[i]
72
+
73
+ if (token == "2") {
74
+ if (decodedTokens.length > 0) {
75
+ const previousDecodedToken = decodedTokens[decodedTokens.length - 1]
76
+ decodedTokens.push("$")
77
+ decodedTokens.push(previousDecodedToken)
78
+
79
+ tokenGroupIndexes[tokenGroupIndexes.length - 1].push(i)
80
+ } else {
81
+ decodedTokens.push(" ")
82
+ tokenGroupIndexes.push([])
83
+ }
84
+
85
+ continue
86
+ }
87
+
88
+ if (token == "_") {
89
+ continue
90
+ }
91
+
92
+ decodedTokens.push(token)
93
+
94
+ if (token == " ") {
95
+ tokenGroupIndexes.push([])
96
+ } else {
97
+ tokenGroupIndexes[tokenGroupIndexes.length - 1].push(i)
98
+ }
99
+ }
100
+
101
+ let decodedString = ""
102
+
103
+ for (let i = 0; i < decodedTokens.length; i++) {
104
+ const currentToken = decodedTokens[i]
105
+ const previousToken = decodedTokens[i - 1]
106
+
107
+ if (currentToken != "$" && (previousToken != currentToken || previousToken == undefined)) {
108
+ decodedString += currentToken
109
+ }
110
+ }
111
+
112
+ decodedString = decodedString.trim()
113
+
114
+ tokenGroupIndexes = tokenGroupIndexes.filter(group => group.length > 0)
115
+
116
+ if (tokenGroupIndexes.length > 0) {
117
+ let currentCorrection = Math.min(tokenGroupIndexes[0][0], 1.5)
118
+
119
+ for (let i = 0; i < tokenGroupIndexes.length; i++) {
120
+ const group = tokenGroupIndexes[i]
121
+
122
+ if (group.length == 1) {
123
+ group.push(group[0])
124
+ }
125
+
126
+ group[0] -= currentCorrection
127
+
128
+ if (i == tokenGroupIndexes.length - 1) {
129
+ currentCorrection = Math.min(tokenCount - i, 1.5)
130
+ } else {
131
+ currentCorrection = Math.min((tokenGroupIndexes[i + 1][0] - group[group.length - 1]) / 2, 1.5)
132
+ }
133
+
134
+ group[group.length - 1] += currentCorrection
135
+ }
136
+ }
137
+
138
+ const words = decodedString.split(" ")
139
+
140
+ const timeMultiplier = totalDuration / tokenCount
141
+
142
+ const timeline: Timeline = []
143
+
144
+ for (let i = 0; i < words.length; i++) {
145
+ const text = words[i]
146
+
147
+ if (!wordCharacterPattern.test(text)) {
148
+ continue
149
+ }
150
+
151
+ const group = tokenGroupIndexes[i]
152
+ const startTime = group[0] * timeMultiplier
153
+ const endTime = group[group.length - 1] * timeMultiplier
154
+
155
+ timeline.push({
156
+ type: "word",
157
+ text: text,
158
+ startTime,
159
+ endTime,
160
+ })
161
+ }
162
+
163
+ timeline[timeline.length - 1].endTime = totalDuration
164
+
165
+ return { transcript: decodedString, timeline }
166
+ }
167
+
168
+ export const languageCodeToPackageName: { [languageCode: string]: string } = {
169
+ "en": "silero-en-v5",
170
+ "es": "silero-es-v1",
171
+ "de": "silero-de-v1",
172
+ "uk": "silero-ua-v3",
173
+ }
@@ -0,0 +1,112 @@
1
+ import * as FFMpegTranscoder from "../codecs/FFMpegTranscoder.js"
2
+ import * as AudioBufferConversion from '../audio/AudioBufferConversion.js'
3
+ import { Logger } from "../utilities/Logger.js"
4
+ import { logToStderr } from "../utilities/Utilities.js"
5
+ import { Timeline } from "../utilities/Timeline.js"
6
+ import { RawAudio } from "../audio/AudioUtilities.js"
7
+
8
+ const log = logToStderr
9
+
10
+ export async function recognizeFile(filename: string, modelPath: string, verbose = true) {
11
+ const rawAudio = await FFMpegTranscoder.decodeToChannels(filename, 16000, 1)
12
+ return recognize(rawAudio, modelPath, verbose)
13
+ }
14
+
15
+ export async function recognize(rawAudio: RawAudio, modelPath: string, verbose = true) {
16
+ const logger = new Logger()
17
+ logger.start("Initialize vosk recognizer")
18
+
19
+ const audioChannels = rawAudio.audioChannels
20
+ const sampleRate = rawAudio.sampleRate
21
+
22
+ let Vosk = await import('@echogarden/vosk')
23
+
24
+ Vosk.setLogLevel(-1)
25
+
26
+ const model = await new Vosk.Model(modelPath)
27
+
28
+ const recognizer = new Vosk.Recognizer({ model, sampleRate })
29
+
30
+ recognizer.setMaxAlternatives(0)
31
+ recognizer.setWords(true)
32
+ recognizer.setPartialWords(true)
33
+
34
+ logger.start("Recognize with vosk")
35
+
36
+ const recognitionStartTimestamp = logger.getTimestamp()
37
+
38
+ const pcmAudio = AudioBufferConversion.encodeToAudioBuffer(audioChannels, 16)
39
+ const trailingSilence = Buffer.alloc(sampleRate * 4)
40
+ const pcmAudioWithTrailingSilence = Buffer.concat([pcmAudio, trailingSilence])
41
+ const pcmAudioByteCount = pcmAudioWithTrailingSilence.length
42
+
43
+ const maxChunkSize = sampleRate * 2.0
44
+
45
+ let previousResultText = ""
46
+
47
+ for (let readOffset = 0; readOffset < pcmAudioByteCount; readOffset += maxChunkSize) {
48
+ const chunkSize = Math.min(maxChunkSize, pcmAudioByteCount - readOffset)
49
+
50
+ const chunk = pcmAudioWithTrailingSilence.subarray(readOffset, readOffset + chunkSize)
51
+
52
+ const speechEnded = await recognizer.acceptWaveformAsync(chunk)
53
+
54
+ if (verbose) {
55
+ const partialResultText = recognizer.partialResult().partial
56
+
57
+ if (partialResultText != previousResultText) {
58
+ //logger.log(partialResultText)
59
+ //logger.log("")
60
+
61
+ previousResultText = partialResultText
62
+ }
63
+ }
64
+ }
65
+
66
+ //const speechEnded = await recognizer.acceptWaveformAsync(pcmAudioWithTrailingSilence)
67
+
68
+ const result = recognizer.finalResult()
69
+
70
+ recognizer.reset()
71
+ recognizer.free()
72
+ model.free()
73
+
74
+ const transcript: string = result.text
75
+ const events: VoskRecognitionEvent[] = result.result
76
+
77
+ if (events.length == 0) {
78
+ return { transcript, timeline: [] }
79
+ }
80
+
81
+ const timeline: Timeline = []
82
+
83
+ for (let i = 0; i < events.length; i++) {
84
+ const event = events[i]
85
+
86
+ const eventText = event.word
87
+ const eventStart = event.start
88
+ const eventEnd = event.end
89
+ const eventConfidence = event.conf
90
+
91
+ timeline.push({
92
+ type: "word",
93
+ text: eventText,
94
+ startTime: eventStart,
95
+ endTime: eventEnd,
96
+ confidence: eventConfidence
97
+ })
98
+ }
99
+
100
+ //logger.logDuration(`Recognition with vosk`, recognitionStartTimestamp)
101
+
102
+ logger.end()
103
+
104
+ return { transcript, timeline }
105
+ }
106
+
107
+ type VoskRecognitionEvent = {
108
+ word: string
109
+ start: number
110
+ end: number
111
+ conf: number
112
+ }