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,574 @@
1
+ import * as readline from 'node:readline'
2
+ import { IncomingMessage } from 'node:http'
3
+ import { inspect } from 'node:util'
4
+
5
+ import { RandomGenerator } from './RandomGenerator.js'
6
+ import { randomUUID, randomBytes } from 'node:crypto'
7
+
8
+ const log = logToStderr
9
+
10
+ export function concatFloat32Arrays(arrays: Float32Array[]) {
11
+ return concatTypedArrays<Float32Array>(Float32Array, arrays)
12
+ }
13
+
14
+ function concatTypedArrays<R>(ArrayConstructor: any, arrays: any[]) {
15
+ let totalLength = 0
16
+
17
+ for (const arr of arrays) {
18
+ totalLength += arr.length
19
+ }
20
+
21
+ const result = new ArrayConstructor(totalLength)
22
+
23
+ let offset = 0
24
+
25
+ for (const arr of arrays) {
26
+ result.set(arr, offset)
27
+ offset += arr.length
28
+ }
29
+
30
+ return <R>result
31
+ }
32
+
33
+ export function shuffleArray<T>(array: T[], randomGen: RandomGenerator) {
34
+ return shuffleArrayInPlace(array.slice(), randomGen)
35
+ }
36
+
37
+ export function shuffleArrayInPlace<T>(array: T[], randomGen: RandomGenerator) {
38
+ const vectorCount = array.length
39
+
40
+ for (let i = 0; i < vectorCount - 1; i++) {
41
+ const value = array[i]
42
+ const targetIndex = randomGen.getIntInRange(i + 1, vectorCount)
43
+
44
+ array[i] = array[targetIndex]
45
+ array[targetIndex] = value
46
+ }
47
+
48
+ return array
49
+ }
50
+
51
+ export function simplifyPunctuationCharacters(text: string) {
52
+ return text
53
+ .replaceAll(`“`, `"`)
54
+ .replaceAll(`”`, `"`)
55
+ .replaceAll(`„`, `"`)
56
+ .replaceAll(`ߵ`, `"`)
57
+ .replaceAll(`ߴ`, `"`)
58
+ .replaceAll(`«`, `"`)
59
+ .replaceAll(`»`, `"`)
60
+
61
+ .replaceAll(`’`, `'`)
62
+ .replaceAll(`ʼ`, `'`)
63
+ .replaceAll(`ʼ`, `'`)
64
+ .replaceAll(`'`, `'`)
65
+ .replaceAll(`,`, `,`)
66
+ .replaceAll(`、`, `,`)
67
+ .replaceAll(`:`, `:`)
68
+ .replaceAll(`;`, `;`)
69
+ .replaceAll(`。`, `.`)
70
+ }
71
+
72
+ export function writeToStderr(message: any) {
73
+ process.stderr.write(message)
74
+ }
75
+
76
+ export function printToStderr(message: any) {
77
+ if (typeof message == 'string') {
78
+ writeToStderr(message)
79
+ } else {
80
+ writeToStderr(objToString(message))
81
+ }
82
+ }
83
+
84
+ export function logToStderr(message: any) {
85
+ printToStderr(message)
86
+ writeToStderr("\n")
87
+ }
88
+
89
+ export function objToString(obj: any) {
90
+ const formattedString = inspect(obj, {
91
+ showHidden: false,
92
+ depth: null,
93
+ colors: false,
94
+ maxArrayLength: null,
95
+ maxStringLength: null,
96
+ compact: 5,
97
+ })
98
+
99
+ return formattedString
100
+ }
101
+
102
+ export function getRandomHexString(charCount = 32, upperCase = false) {
103
+ if (charCount % 2 !== 0) {
104
+ throw new Error(`'charCount' must be an even number`)
105
+ }
106
+
107
+ let hex = randomBytes(charCount / 2).toString("hex")
108
+
109
+ if (upperCase) {
110
+ hex = hex.toUpperCase()
111
+ }
112
+
113
+ return hex
114
+ }
115
+
116
+ export function getRandomUUID(dashes = true) {
117
+ let uuid = randomUUID() as string
118
+
119
+ if (dashes == false) {
120
+ uuid = uuid.replaceAll("-", "")
121
+ }
122
+
123
+ return uuid
124
+ }
125
+
126
+ export function sumArray<T>(arr: Array<T>, valueGetter: (item: T) => number) {
127
+ let sum = 0
128
+
129
+ for (let i = 0; i < arr.length; i++) {
130
+ sum += valueGetter(arr[i])
131
+ }
132
+
133
+ return sum
134
+ }
135
+
136
+ export function includesAnyOf(str: string, substrings: string[]) {
137
+ return indexOfAnyOf(str, substrings) >= 0
138
+ }
139
+
140
+ export function indexOfAnyOf(str: string, substrings: string[]) {
141
+ for (const substring of substrings) {
142
+ const index = str.indexOf(substring)
143
+
144
+ if (index >= 0) {
145
+ return index
146
+ }
147
+ }
148
+
149
+ return -1
150
+ }
151
+
152
+ export function startsWithAnyOf(str: string, prefixes: string[]) {
153
+ for (const prefix of prefixes) {
154
+ if (str.startsWith(prefix)) {
155
+ return true
156
+ }
157
+ }
158
+
159
+ return false
160
+ }
161
+
162
+ export function roundToDigits(val: number, digits = 3) {
163
+ const multiplier = 10 ** digits
164
+ return Math.round(val * multiplier) / multiplier
165
+ }
166
+
167
+ export function delay(timeMs: number) {
168
+ return new Promise((resolve) => {
169
+ setTimeout(resolve, timeMs)
170
+ })
171
+ }
172
+
173
+ export function yieldToEventLoop() {
174
+ return new Promise((resolve) => {
175
+ setImmediate(resolve)
176
+ })
177
+ }
178
+
179
+ export function printMatrix(matrix: Float32Array[]) {
180
+ const rowCount = matrix.length
181
+
182
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
183
+ log(matrix[rowIndex].join(", "))
184
+ }
185
+ }
186
+
187
+ export function stringifyAndFormatJson(obj: any) {
188
+ return JSON.stringify(obj, undefined, 4)
189
+ }
190
+
191
+ export function secondsToHMS(totalSeconds: number) {
192
+ let remainingSeconds = totalSeconds
193
+
194
+ const hours = Math.floor(remainingSeconds / 60 / 60)
195
+ remainingSeconds -= hours * 60 * 60
196
+
197
+ const minutes = Math.floor(remainingSeconds / 60)
198
+ remainingSeconds -= minutes * 60
199
+
200
+ const seconds = Math.floor(remainingSeconds)
201
+ remainingSeconds -= seconds
202
+
203
+ const milliseconds = Math.floor(remainingSeconds * 1000)
204
+
205
+ return { hours, minutes, seconds, milliseconds }
206
+ }
207
+
208
+ export function secondsToMS(totalSeconds: number) {
209
+ const { hours, minutes, seconds, milliseconds } = secondsToHMS(totalSeconds)
210
+
211
+ return { minutes: (hours * 60) + minutes, seconds, milliseconds }
212
+ }
213
+
214
+ export function formatHMS(timeHMS: { hours: number, minutes: number, seconds: number, milliseconds: number }, decimalSeparator = ".") {
215
+ return `${formatIntegerWithLeadingZeros(timeHMS.hours, 2)}:${formatIntegerWithLeadingZeros(timeHMS.minutes, 2)}:${formatIntegerWithLeadingZeros(timeHMS.seconds, 2)}${decimalSeparator}${formatIntegerWithLeadingZeros(timeHMS.milliseconds, 3)}`
216
+ }
217
+
218
+ export function formatMS(timeMS: { minutes: number, seconds: number, milliseconds: number }, decimalSeparator = ".") {
219
+ return `${formatIntegerWithLeadingZeros(timeMS.minutes, 2)}:${formatIntegerWithLeadingZeros(timeMS.seconds, 2)}${decimalSeparator}${formatIntegerWithLeadingZeros(timeMS.milliseconds, 3)}`
220
+ }
221
+
222
+ export function formatIntegerWithLeadingZeros(num: number, minDigitCount: number) {
223
+ num = Math.floor(num)
224
+
225
+ let numAsString = `${num}`
226
+
227
+ while (numAsString.length < minDigitCount) {
228
+ numAsString = `0${numAsString}`
229
+ }
230
+
231
+ return numAsString
232
+ }
233
+
234
+ export function intsInRange(start: number, end: number) {
235
+ const result: number[] = []
236
+
237
+ for (let i = start; i < end; i++) {
238
+ result.push(i)
239
+ }
240
+
241
+ return result
242
+ }
243
+
244
+ export function randomIntsInRange(count: number, min: number, max: number) {
245
+ const randomArray: number[] = []
246
+
247
+ for (let i = 0; i < count; i++) {
248
+ randomArray.push(randomIntInRange(min, max))
249
+ }
250
+
251
+ return randomArray
252
+ }
253
+
254
+ export function randomIntInRange(min: number, max: number) {
255
+ return Math.floor(randomFloatInRange(min, max))
256
+ }
257
+
258
+ export function randomFloatsInRange(count: number, min = 0.0, max = 1.0) {
259
+ const randomVector: number[] = []
260
+
261
+ for (let i = 0; i < count; i++) {
262
+ randomVector.push(randomFloatInRange(min, max))
263
+ }
264
+
265
+ return randomVector
266
+ }
267
+
268
+ export function randomFloatInRange(min: number, max: number) {
269
+ return min + Math.random() * (max - min)
270
+ }
271
+
272
+ export function serializeMapToObject<V>(map: Map<string, V>) {
273
+ const obj: { [key: string]: V } = {}
274
+
275
+ for (const [key, value] of map) {
276
+ obj[key] = value
277
+ }
278
+
279
+ return obj
280
+ }
281
+
282
+ export function deserializeObjectToMap<V>(obj: { [key: string]: V }) {
283
+ const map = new Map<string, V>()
284
+
285
+ for (const key in obj) {
286
+ map.set(key, obj[key])
287
+ }
288
+
289
+ return map
290
+ }
291
+
292
+ export function waitTimeout(timeout = 0) {
293
+ return new Promise<void>((resolve) => setTimeout(() => {
294
+ resolve()
295
+ }, timeout))
296
+ }
297
+
298
+ export function waitImmediate() {
299
+ return new Promise<void>((resolve) => setImmediate(() => {
300
+ resolve()
301
+ }))
302
+ }
303
+
304
+ export function waitNextTick() {
305
+ return new Promise<void>((resolve) => process.nextTick(() => resolve()))
306
+ }
307
+
308
+ export function setupUnhandledExceptionListeners() {
309
+ process.on('unhandledRejection', (e: any) => {
310
+ log(`Unhandled promise rejection:\n ${e}`)
311
+ process.exit(1)
312
+ })
313
+
314
+ process.on('uncaughtException', function (e) {
315
+ log(`Uncaught exception:\n ${e}`)
316
+ process.exit(1)
317
+ })
318
+ }
319
+
320
+ export function setupProgramTerminationListeners(cleanupFunc?: () => void) {
321
+ function exitProcess(exitCode = 0) {
322
+ if (cleanupFunc) {
323
+ cleanupFunc()
324
+ }
325
+
326
+ process.exit(exitCode)
327
+ }
328
+
329
+ process.on('SIGINT', () => exitProcess(0))
330
+ process.on('SIGQUIT', () => exitProcess(0))
331
+ process.on('SIGTERM', () => exitProcess(0))
332
+
333
+ if (process.stdin.isTTY) {
334
+ readline.emitKeypressEvents(process.stdin)
335
+
336
+ process.stdin.setRawMode(true)
337
+
338
+ process.stdin.on('keypress', (str, key) => {
339
+ if (key.name == 'escape') {
340
+ exitProcess(0)
341
+ }
342
+
343
+ if (key.ctrl == true && key.name == 'c') {
344
+ exitProcess(0)
345
+ }
346
+ })
347
+ }
348
+ }
349
+
350
+ export function clip(num: number, min: number, max: number) {
351
+ return Math.max(min, Math.min(max, num))
352
+ }
353
+
354
+ export function readBinaryIncomingMessage(incomingMessage: IncomingMessage) {
355
+ return new Promise<Buffer>((resolve, reject) => {
356
+ const chunks: Buffer[] = []
357
+
358
+ incomingMessage.on("data", (chunk) => {
359
+ chunks.push(Buffer.from(chunk))
360
+ })
361
+
362
+ incomingMessage.on("end", () => {
363
+ resolve(Buffer.concat(chunks))
364
+ })
365
+
366
+ incomingMessage.on("error", (e) => {
367
+ reject(e)
368
+ })
369
+ })
370
+ }
371
+
372
+ export function splitFloat32Array(nums: Float32Array, partSize: number): Float32Array[] {
373
+ const result: Float32Array[] = []
374
+
375
+ for (let offset = 0; offset < nums.length; offset += partSize) {
376
+ result.push(nums.subarray(offset, offset + partSize))
377
+ }
378
+
379
+ return result
380
+ }
381
+
382
+ export async function sha256AsHex(input: string) {
383
+ const crypto = await import('crypto')
384
+ const hash = crypto.createHash('sha256').update(input).digest('hex')
385
+
386
+ return hash
387
+ }
388
+
389
+ export async function commandExists(command: string) {
390
+ const { default: commandExists } = await import("command-exists")
391
+
392
+ try {
393
+ await commandExists(command)
394
+ return true
395
+ } catch {
396
+ return false
397
+ }
398
+ }
399
+
400
+ export async function convertHtmlToText(html: string) {
401
+ const { convert } = await import('html-to-text')
402
+
403
+ const text = convert(html, {
404
+ wordwrap: null,
405
+
406
+ selectors: [
407
+ { selector: 'a', options: { ignoreHref: true } },
408
+ { selector: 'img', format: 'skip' },
409
+ { selector: 'h1', options: { uppercase: false } },
410
+ { selector: 'h2', options: { uppercase: false } },
411
+ { selector: 'h3', options: { uppercase: false } },
412
+ { selector: 'h4', options: { uppercase: false } },
413
+ { selector: 'table', options: { uppercaseHeaderCells: false } }
414
+ ]
415
+ })
416
+
417
+ return text || ""
418
+ }
419
+
420
+ export function formatListWithQuotedElements(strings: string[], quoteSymbol = `'`) {
421
+ return strings.map(str => `${quoteSymbol}${str}${quoteSymbol}`).join(", ")
422
+ }
423
+
424
+ export async function resolveModuleMainPath(moduleName: string) {
425
+ const { resolve } = await import('import-meta-resolve')
426
+ const { fileURLToPath } = await import('url')
427
+
428
+ return fileURLToPath(await resolve(moduleName, import.meta.url))
429
+ }
430
+
431
+ export function getWithDefault<T>(value: T | undefined, defaultValue: T) {
432
+ if (value === undefined) {
433
+ return defaultValue
434
+ } else {
435
+ return value
436
+ }
437
+ }
438
+
439
+ export function splitFilenameOnExtendedExtension(filenameWithExtension: string) {
440
+ let splitPoint = filenameWithExtension.length
441
+
442
+ for (let i = filenameWithExtension.length - 1; i >= 0; i--) {
443
+ if (filenameWithExtension[i] == ".") {
444
+ if (/^[a-zA-Z0-9\.]+$/.test(filenameWithExtension.slice(i + 1))) {
445
+ splitPoint = i
446
+
447
+ continue
448
+ } else {
449
+ break
450
+ }
451
+ }
452
+ }
453
+
454
+ const name = filenameWithExtension.slice(0, splitPoint)
455
+ const ext = filenameWithExtension.slice(splitPoint + 1)
456
+
457
+ return [name, ext]
458
+ }
459
+
460
+ export function getUTF32Chars(str: string) {
461
+ const utf32chars: string[] = []
462
+ const mapping: number[] = []
463
+
464
+ let utf32Index = 0
465
+
466
+ for (const utf32char of str) {
467
+ utf32chars.push(utf32char)
468
+
469
+ for (let i = 0; i < utf32char.length; i++) {
470
+ mapping.push(utf32Index)
471
+ }
472
+
473
+ utf32Index += 1
474
+ }
475
+
476
+ mapping.push(utf32Index)
477
+
478
+ return { utf32chars, mapping }
479
+ }
480
+
481
+ export function getRepetitionScoreRelativeToFirstSubstring(tokens: string[] | number[]) {
482
+ const maxOrder = Math.floor(tokens.length)
483
+
484
+ const matchCountForOrder: number[] = []
485
+
486
+ for (let i = 0; i <= maxOrder; i++) {
487
+ matchCountForOrder.push(0)
488
+ }
489
+
490
+ for (let offset = 0; offset < tokens.length; offset++) {
491
+ for (let order = 1; order <= maxOrder; order++) {
492
+ const referenceToken = tokens[-1 + order]
493
+ const targetToken = tokens[offset + order]
494
+
495
+ if (targetToken == referenceToken) {
496
+ matchCountForOrder[order] += 1
497
+ } else {
498
+ break
499
+ }
500
+ }
501
+ }
502
+
503
+ const scores = matchCountForOrder.map((count, index) => count * index)
504
+
505
+ let maxScoreOrder = -1
506
+ let maxScore = -Infinity
507
+
508
+ for (let i = 1; i <= matchCountForOrder.length; i++) {
509
+ const score = scores[i]
510
+
511
+ if (score > maxScore) {
512
+ maxScoreOrder = i
513
+ maxScore = score
514
+ }
515
+ }
516
+
517
+ return { maxScore, maxScoreOrder }
518
+ }
519
+
520
+ export function getConsecutiveRepetitionScoreRelativeToFirstSubstring(tokens: string[] | number[]) {
521
+ function countRepetitionForLength(len: number) {
522
+ let count = 0
523
+
524
+ for (let offset = len; offset < tokens.length; offset += len) {
525
+ for (let i = 0; i < len; i++) {
526
+ if (tokens[i] != tokens[offset + i]) {
527
+ return count
528
+ }
529
+ }
530
+
531
+ count += 1
532
+ }
533
+
534
+ return count
535
+ }
536
+
537
+ const maxLength = Math.floor(tokens.length / 2)
538
+
539
+ const repeatCountForLength: number[] = []
540
+
541
+ for (let i = 0; i <= maxLength; i++) {
542
+ repeatCountForLength.push(0)
543
+ }
544
+
545
+ for (let targetLen = 1; targetLen <= maxLength; targetLen++) {
546
+ repeatCountForLength[targetLen] = countRepetitionForLength(targetLen)
547
+ }
548
+
549
+ const scores = repeatCountForLength.map((count, index) => count * index)
550
+
551
+ let maxScoreLength = -1
552
+ let maxScore = -Infinity
553
+
554
+ for (let i = 1; i <= repeatCountForLength.length; i++) {
555
+ const score = scores[i]
556
+
557
+ if (score > maxScore) {
558
+ maxScoreLength = i
559
+ maxScore = score
560
+ }
561
+ }
562
+
563
+ return { maxScore, maxScoreLength, repeatCountForLength }
564
+ }
565
+
566
+ export async function resolveModuleScriptPath(moduleName: string) {
567
+ const { resolve } = await import('import-meta-resolve')
568
+
569
+ const scriptPath = await resolve(moduleName, import.meta.url)
570
+
571
+ const { fileURLToPath } = await import('url')
572
+
573
+ return fileURLToPath(scriptPath)
574
+ }