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,231 @@
1
+ import { ParagraphBreakType, WhitespaceProcessing } from "../api/Common.js"
2
+ import { isWordOrSymbolWord, splitToParagraphs, splitToSentences } from "../nlp/Segmentation.js"
3
+ import { deepClone } from "./ObjectUtilities.js"
4
+ import { getUTF32Chars, roundToDigits } from "./Utilities.js"
5
+
6
+ export function addTimeOffsetToTimeline(targetTimeline: Timeline, timeOffset: number) {
7
+ if (!targetTimeline) {
8
+ return targetTimeline
9
+ }
10
+
11
+ const newTimeline = deepClone(targetTimeline)
12
+
13
+ for (const segmentTimelineEntry of newTimeline) {
14
+ segmentTimelineEntry.startTime = Math.max(segmentTimelineEntry.startTime + timeOffset, 0)
15
+ segmentTimelineEntry.endTime = Math.max(segmentTimelineEntry.endTime + timeOffset, 0)
16
+
17
+ if (segmentTimelineEntry.timeline) {
18
+ segmentTimelineEntry.timeline = addTimeOffsetToTimeline(segmentTimelineEntry.timeline, timeOffset)
19
+ }
20
+ }
21
+
22
+ return newTimeline
23
+ }
24
+
25
+ export function multiplyTimelineByFactor(targetTimeline: Timeline, factor: number) {
26
+ const newTimeline = deepClone(targetTimeline)
27
+
28
+ for (const segmentTimelineEntry of newTimeline) {
29
+ segmentTimelineEntry.startTime = segmentTimelineEntry.startTime * factor
30
+ segmentTimelineEntry.endTime = segmentTimelineEntry.endTime * factor
31
+
32
+ if (segmentTimelineEntry.timeline) {
33
+ segmentTimelineEntry.timeline = multiplyTimelineByFactor(segmentTimelineEntry.timeline, factor)
34
+ }
35
+ }
36
+
37
+ return newTimeline
38
+ }
39
+
40
+ export function roundTimelineProperties(targetTimeline: Timeline, decimalDigits = 2) {
41
+ const roundedTimeline = deepClone(targetTimeline)
42
+
43
+ for (const entry of roundedTimeline) {
44
+ if (entry.startTime) {
45
+ entry.startTime = roundToDigits(entry.startTime, decimalDigits)
46
+ }
47
+
48
+ if (entry.endTime) {
49
+ entry.endTime = roundToDigits(entry.endTime, decimalDigits)
50
+ }
51
+
52
+ if (entry.confidence) {
53
+ entry.confidence = roundToDigits(entry.confidence, decimalDigits)
54
+ }
55
+
56
+ if (entry.timeline) {
57
+ entry.timeline = roundTimelineProperties(entry.timeline)
58
+ }
59
+ }
60
+
61
+ return roundedTimeline
62
+ }
63
+
64
+ export async function wordTimelineToSegmentSentenceTimeline(wordTimeline: Timeline, transcript: string, language: string, paragraphBreaks: ParagraphBreakType = 'double', whitespace: WhitespaceProcessing = 'collapse') {
65
+ const paragraphs = await splitToParagraphs(transcript, paragraphBreaks, whitespace)
66
+
67
+ const segments = paragraphs
68
+ .map(segment =>
69
+ splitToSentences(segment, language).map(sentence =>
70
+ sentence.trim()))
71
+
72
+ let text = ""
73
+ const charIndexToSentenceEntryMapping: TimelineEntry[] = []
74
+
75
+ const segmentTimeline: Timeline = []
76
+
77
+ for (const segment of segments) {
78
+ const sentencesInSegment: Timeline = []
79
+
80
+ const segmentEntry: TimelineEntry = {
81
+ type: "segment",
82
+ text: "",
83
+ startTime: -1,
84
+ endTime: -1,
85
+ timeline: sentencesInSegment
86
+ }
87
+
88
+ for (const sentence of segment) {
89
+ const sentenceEntry: TimelineEntry = {
90
+ type: "sentence",
91
+ text: sentence,
92
+ startTime: -1,
93
+ endTime: -1,
94
+ timeline: []
95
+ }
96
+
97
+ for (const char of sentence + " ") {
98
+ text += char
99
+ charIndexToSentenceEntryMapping.push(sentenceEntry)
100
+ }
101
+
102
+ sentencesInSegment.push(sentenceEntry)
103
+ }
104
+
105
+ segmentTimeline.push(segmentEntry)
106
+ }
107
+
108
+ let wordSearchStartOffset = 0
109
+
110
+ for (let wordIndex = 0; wordIndex < wordTimeline.length; wordIndex++) {
111
+ const wordEntry = wordTimeline[wordIndex]
112
+ const wordText = wordEntry.text
113
+
114
+ if (!isWordOrSymbolWord(wordText)) {
115
+ continue
116
+ }
117
+
118
+ const indexOfWordInText = text.indexOf(wordText, wordSearchStartOffset)
119
+
120
+ if (indexOfWordInText == -1) {
121
+ throw new Error(`Couldn't find the word '${wordText}' in the text at start position ${wordSearchStartOffset}`)
122
+ }
123
+
124
+ const targetSentenceEntry = charIndexToSentenceEntryMapping[indexOfWordInText]
125
+ targetSentenceEntry.timeline!.push(wordEntry)
126
+
127
+ wordSearchStartOffset = indexOfWordInText + wordText.length
128
+ }
129
+
130
+ const newSegmentTimeline: Timeline = []
131
+
132
+ for (const segmentEntry of segmentTimeline) {
133
+ const oldSentenceTimeline = segmentEntry.timeline!
134
+
135
+ const newSentenceTimeline: Timeline = []
136
+
137
+ for (const sentenceEntry of oldSentenceTimeline) {
138
+ const wordTimeline = sentenceEntry.timeline
139
+
140
+ if (!wordTimeline || wordTimeline.length == 0) {
141
+ continue
142
+ }
143
+
144
+ sentenceEntry.startTime = wordTimeline[0].startTime
145
+ sentenceEntry.endTime = wordTimeline[wordTimeline.length - 1].endTime
146
+
147
+ newSentenceTimeline.push(sentenceEntry)
148
+ }
149
+
150
+ if (newSentenceTimeline.length == 0) {
151
+ continue
152
+ }
153
+
154
+ segmentEntry.text = newSentenceTimeline.map(sentenceEntry => sentenceEntry.text).join(" ")
155
+
156
+ segmentEntry.startTime = newSentenceTimeline[0].startTime
157
+ segmentEntry.endTime = newSentenceTimeline[newSentenceTimeline.length - 1].endTime
158
+
159
+ newSegmentTimeline.push(segmentEntry)
160
+ }
161
+
162
+ return { segmentTimeline: newSegmentTimeline }
163
+ }
164
+
165
+ export function addWordTextOffsetsToTimeline(timeline: Timeline, text: string, currentOffset = 0) {
166
+ const { mapping } = getUTF32Chars(text)
167
+
168
+ for (const entry of timeline) {
169
+ if (entry.type == 'word') {
170
+ let word = entry.text
171
+
172
+ word = word.trim().replaceAll(/\s+/g, ' ')
173
+
174
+ const wordParts = word.split(' ')
175
+
176
+ let startOffset: number | undefined
177
+ let endOffset: number | undefined
178
+
179
+ for (let i = 0; i < wordParts.length; i++) {
180
+ let wordPart = wordParts[i]
181
+
182
+ let wordPartOffset = text.indexOf(wordPart, currentOffset)
183
+
184
+ if (wordPartOffset == -1) {
185
+ continue
186
+ }
187
+
188
+ currentOffset = wordPartOffset + wordParts[i].length
189
+
190
+ if (i == 0) {
191
+ startOffset = wordPartOffset
192
+ }
193
+
194
+ endOffset = currentOffset
195
+ }
196
+
197
+ entry.startOffsetUtf16 = startOffset
198
+ entry.endOffsetUtf16 = endOffset
199
+
200
+ entry.startOffsetUtf32 = startOffset != undefined ? mapping[startOffset] : undefined
201
+ entry.endOffsetUtf32 = endOffset != undefined ? mapping[endOffset] : undefined
202
+ } else if (entry.timeline) {
203
+ currentOffset = addWordTextOffsetsToTimeline(entry.timeline, text, currentOffset)
204
+ }
205
+ }
206
+
207
+ return currentOffset
208
+ }
209
+
210
+ export type TimelineEntryType = "segment" | "paragraph" | "sentence" | "clause" | "phrase" | "word" | "token" | "letter" | "phone" | "subphone"
211
+
212
+ export type TimelineEntry = {
213
+ type: TimelineEntryType
214
+
215
+ text: string,
216
+
217
+ startTime: number,
218
+ endTime: number,
219
+
220
+ startOffsetUtf16?: number
221
+ endOffsetUtf16?: number
222
+
223
+ startOffsetUtf32?: number
224
+ endOffsetUtf32?: number
225
+
226
+ confidence?: number
227
+
228
+ timeline?: Timeline
229
+ }
230
+
231
+ export type Timeline = TimelineEntry[]
@@ -0,0 +1,93 @@
1
+ import { roundToDigits, writeToStderr } from "./Utilities.js"
2
+
3
+ declare const chrome: any
4
+ declare const process: any
5
+
6
+ export class Timer {
7
+ startTime = 0
8
+
9
+ constructor() {
10
+ this.restart()
11
+ }
12
+
13
+ restart() {
14
+ this.startTime = Timer.currentTime
15
+ }
16
+
17
+ get elapsedTime(): number {
18
+ // Elapsed time (milliseconds)
19
+ return Timer.currentTime - this.startTime
20
+ }
21
+
22
+ get elapsedTimeSeconds(): number {
23
+ // Elapsed time (seconds)
24
+ return this.elapsedTime / 1000
25
+ }
26
+
27
+ getElapsedTimeAndRestart(): number {
28
+ const elapsedTime = this.elapsedTime
29
+ this.restart()
30
+ return elapsedTime
31
+ }
32
+
33
+ logAndRestart(title: string, timePrecision = 3): number {
34
+ const elapsedTime = this.elapsedTime
35
+
36
+ //
37
+ const message = `${title}: ${roundToDigits(elapsedTime, timePrecision)}ms`
38
+ writeToStderr(message)
39
+ //
40
+
41
+ this.restart()
42
+
43
+ return elapsedTime
44
+ }
45
+
46
+ static get currentTime(): number {
47
+ if (!this.timestampFunc) {
48
+ this.createGlobalTimestampFunction()
49
+ }
50
+
51
+ return this.timestampFunc()
52
+ }
53
+
54
+ static get microsecondTimestamp(): number {
55
+ return Math.floor(Timer.currentTime * 1000)
56
+ }
57
+
58
+ private static createGlobalTimestampFunction() {
59
+ if (typeof process === "object" && typeof process.hrtime === "function") {
60
+ let baseTimestamp = 0
61
+
62
+ this.timestampFunc = () => {
63
+ const nodeTimeStamp = process.hrtime()
64
+ const millisecondTime = (nodeTimeStamp[0] * 1000) + (nodeTimeStamp[1] / 1000000)
65
+
66
+ return baseTimestamp + millisecondTime
67
+ }
68
+
69
+ baseTimestamp = Date.now() - this.timestampFunc()
70
+ }
71
+ else if (typeof chrome === "object" && chrome.Interval) {
72
+ const baseTimestamp = Date.now()
73
+
74
+ const chromeIntervalObject = new chrome.Interval()
75
+ chromeIntervalObject.start()
76
+
77
+ this.timestampFunc = () => baseTimestamp + chromeIntervalObject.microseconds() / 1000
78
+ }
79
+ else if (typeof performance === "object" && performance.now) {
80
+ const baseTimestamp = Date.now() - performance.now()
81
+
82
+ this.timestampFunc = () => baseTimestamp + performance.now()
83
+ }
84
+ else if (Date.now) {
85
+ this.timestampFunc = () => Date.now()
86
+ }
87
+ else {
88
+ this.timestampFunc = () => (new Date()).getTime()
89
+ }
90
+ }
91
+
92
+ private static timestampFunc: () => number
93
+ }