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.
- package/data/schemas/options.json +16 -0
- package/dist/api/Alignment.js +2 -2
- package/dist/api/Alignment.js.map +1 -1
- package/dist/api/Recognition.js +2 -2
- package/dist/api/Recognition.js.map +1 -1
- package/dist/api/Synthesis.js +5 -4
- package/dist/api/Synthesis.js.map +1 -1
- package/dist/api/Translation.js +2 -2
- package/dist/api/Translation.js.map +1 -1
- package/dist/audio/AudioUtilities.d.ts +1 -0
- package/dist/audio/AudioUtilities.js +25 -7
- package/dist/audio/AudioUtilities.js.map +1 -1
- package/dist/cli/CLI.js +2 -2
- package/dist/cli/CLI.js.map +1 -1
- package/dist/recognition/WhisperSTT.js +2 -2
- package/dist/recognition/WhisperSTT.js.map +1 -1
- package/dist/subtitles/Subtitles.d.ts +10 -7
- package/dist/subtitles/Subtitles.js +268 -207
- package/dist/subtitles/Subtitles.js.map +1 -1
- package/docs/Options.md +4 -2
- package/package.json +7 -6
- package/src/alignment/DTWMfccSequenceAlignment.ts +43 -0
- package/src/alignment/DTWSequenceAlignment.ts +121 -0
- package/src/alignment/DTWSequenceAlignmentWindowed.ts +210 -0
- package/src/alignment/LevenshteinSequenceAlignment.ts +126 -0
- package/src/alignment/SpeechAlignment.ts +488 -0
- package/src/api/API.ts +12 -0
- package/src/api/APIOptions.ts +15 -0
- package/src/api/Alignment.ts +329 -0
- package/src/api/Common.ts +16 -0
- package/src/api/Denoising.ts +120 -0
- package/src/api/LanguageDetection.ts +286 -0
- package/src/api/Recognition.ts +344 -0
- package/src/api/Synthesis.ts +1735 -0
- package/src/api/Translation.ts +143 -0
- package/src/api/Vad.ts +172 -0
- package/src/audio/AudioBufferConversion.ts +248 -0
- package/src/audio/AudioPlayer.ts +358 -0
- package/src/audio/AudioRecorder.ts +91 -0
- package/src/audio/AudioUtilities.ts +392 -0
- package/src/audio/SoxPath.ts +24 -0
- package/src/cli/CLI.ts +1360 -0
- package/src/cli/CLIConfigFile.ts +91 -0
- package/src/cli/CLILauncher.ts +26 -0
- package/src/cli/CLIOptionsSchema.ts +54 -0
- package/src/cli/CLIParser.ts +41 -0
- package/src/cli/CLIStarter.ts +40 -0
- package/src/codecs/FFMpegTranscoder.ts +214 -0
- package/src/codecs/TIMITCodec.ts +17 -0
- package/src/codecs/WaveCodec.ts +260 -0
- package/src/denoising/RNNoise.ts +95 -0
- package/src/dsp/BiquadFilter.ts +488 -0
- package/src/dsp/FFT.ts +187 -0
- package/src/dsp/MFCC.ts +227 -0
- package/src/dsp/MelSpectogram.ts +145 -0
- package/src/dsp/Rubberband.ts +249 -0
- package/src/dsp/Sonic.ts +59 -0
- package/src/dsp/SpeexResampler.ts +79 -0
- package/src/math/VectorMath.ts +812 -0
- package/src/nlp/ChineseSegmentation.ts +68 -0
- package/src/nlp/CompromiseNLP.ts +113 -0
- package/src/nlp/EspeakPhonemizer.ts +168 -0
- package/src/nlp/IPA.ts +139 -0
- package/src/nlp/JapaneseSegmentation.ts +53 -0
- package/src/nlp/Lexicon.ts +119 -0
- package/src/nlp/PhoneConversion.ts +508 -0
- package/src/nlp/Segmentation.ts +237 -0
- package/src/nlp/TextNormalizer.ts +160 -0
- package/src/recognition/AmazonTranscribeSTT.ts +112 -0
- package/src/recognition/AzureCognitiveServicesSTT.ts +76 -0
- package/src/recognition/GoogleCloudSTT.ts +92 -0
- package/src/recognition/SileroSTT.ts +173 -0
- package/src/recognition/VoskSTT.ts +112 -0
- package/src/recognition/WhisperSTT.ts +1518 -0
- package/src/server/Client.ts +297 -0
- package/src/server/Server.ts +178 -0
- package/src/server/ServerStarter.ts +12 -0
- package/src/server/Worker.ts +400 -0
- package/src/server/WorkerStarter.ts +38 -0
- package/src/speech-language-detection/SileroLanguageDetection.ts +105 -0
- package/src/subtitles/Subtitles.ts +478 -0
- package/src/synthesis/AwsPollyTTS.ts +78 -0
- package/src/synthesis/AzureCognitiveServicesTTS.ts +146 -0
- package/src/synthesis/CoquiServerTTS.ts +29 -0
- package/src/synthesis/ElevenLabsTTS.ts +104 -0
- package/src/synthesis/EspeakTTS.ts +552 -0
- package/src/synthesis/FliteTTS.ts +387 -0
- package/src/synthesis/GoogleCloudTTS.ts +112 -0
- package/src/synthesis/GoogleTranslateTTS.ts +210 -0
- package/src/synthesis/MicrosoftEdgeTTS.ts +298 -0
- package/src/synthesis/SamTTS.ts +30 -0
- package/src/synthesis/SapiTTS.ts +222 -0
- package/src/synthesis/StreamlabsPollyTTS.ts +114 -0
- package/src/synthesis/SvoxPicoTTS.ts +318 -0
- package/src/synthesis/VitsTTS.ts +734 -0
- package/src/tests/Test.ts +24 -0
- package/src/text-language-detection/FastTextLanguageDetection.ts +53 -0
- package/src/text-language-detection/TinyLDLanguageDetection.ts +16 -0
- package/src/typings/Fillers.d.ts +41 -0
- package/src/utilities/BinaryArrayConversion.ts +159 -0
- package/src/utilities/Compression.ts +91 -0
- package/src/utilities/FileDownloader.ts +201 -0
- package/src/utilities/FileSystem.ts +265 -0
- package/src/utilities/Hashing.ts +230 -0
- package/src/utilities/Locale.ts +119 -0
- package/src/utilities/Logger.ts +72 -0
- package/src/utilities/NdArrayUtilities.ts +31 -0
- package/src/utilities/ObjectUtilities.ts +169 -0
- package/src/utilities/OpenPromise.ts +13 -0
- package/src/utilities/PackageManager.ts +97 -0
- package/src/utilities/Queue.ts +17 -0
- package/src/utilities/RandomGenerator.ts +237 -0
- package/src/utilities/SignalChannel.ts +22 -0
- package/src/utilities/TarballMaker.ts +68 -0
- package/src/utilities/Timeline.ts +231 -0
- package/src/utilities/Timer.ts +93 -0
- package/src/utilities/Utilities.ts +574 -0
- package/src/utilities/WasmMemoryManager.ts +516 -0
- package/src/utilities/WebReader.ts +55 -0
- package/src/utilities/WikipediaReader.ts +41 -0
- package/src/voice-activity-detection/SileroVAD.ts +86 -0
- package/src/voice-activity-detection/WebRtcVAD.ts +76 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import * as fsExtra from 'fs-extra/esm'
|
|
2
|
+
import gracefulFS from 'graceful-fs'
|
|
3
|
+
import * as os from 'node:os'
|
|
4
|
+
|
|
5
|
+
import path from 'node:path'
|
|
6
|
+
import { fileURLToPath } from 'node:url'
|
|
7
|
+
import { promisify } from 'node:util'
|
|
8
|
+
import { OpenPromise } from './OpenPromise.js'
|
|
9
|
+
import { getRandomHexString, sha256AsHex } from './Utilities.js'
|
|
10
|
+
import { appName } from '../api/Common.js'
|
|
11
|
+
|
|
12
|
+
export const readFile = promisify(gracefulFS.readFile)
|
|
13
|
+
//export const writeFile = promisify(gracefulFS.writeFile)
|
|
14
|
+
export const readdir = promisify(gracefulFS.readdir)
|
|
15
|
+
export const stat = promisify(gracefulFS.stat)
|
|
16
|
+
export const open = promisify(gracefulFS.open)
|
|
17
|
+
export const close = promisify(gracefulFS.close)
|
|
18
|
+
export const chmod = promisify(gracefulFS.chmod)
|
|
19
|
+
export const copyFile = promisify(gracefulFS.copyFile)
|
|
20
|
+
export const access = promisify(gracefulFS.access)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
export const createReadStream = gracefulFS.createReadStream
|
|
24
|
+
export const createWriteStream = gracefulFS.createWriteStream
|
|
25
|
+
export const existsSync = gracefulFS.existsSync
|
|
26
|
+
|
|
27
|
+
export const remove = fsExtra.remove
|
|
28
|
+
export const copy = fsExtra.copy
|
|
29
|
+
export const outputFile = fsExtra.outputFile
|
|
30
|
+
|
|
31
|
+
export async function readDirRecursive(dir: string, fileFilter?: (filePath: string) => boolean) {
|
|
32
|
+
if (!(await stat(dir)).isDirectory()) {
|
|
33
|
+
throw new Error(`'${dir}' is not a directory`)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const filenamesInDir = await readdir(dir)
|
|
37
|
+
const filesInDir = filenamesInDir.map(filename => path.join(dir, filename))
|
|
38
|
+
|
|
39
|
+
const result: string[] = []
|
|
40
|
+
const subDirectories: string[] = []
|
|
41
|
+
|
|
42
|
+
for (const filePath of filesInDir) {
|
|
43
|
+
if ((await stat(filePath)).isDirectory()) {
|
|
44
|
+
subDirectories.push(filePath)
|
|
45
|
+
} else {
|
|
46
|
+
if (fileFilter && !fileFilter(filePath)) {
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
result.push(filePath)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
for (const subDirectory of subDirectories) {
|
|
55
|
+
const filesInSubdirectory = await readDirRecursive(subDirectory, fileFilter)
|
|
56
|
+
result.push(...filesInSubdirectory)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return result
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function isFileIsUpToDate(filePath: string, timeRangeSeconds: number) {
|
|
63
|
+
const fileUpdateTime = (await stat(filePath)).mtime.valueOf()
|
|
64
|
+
|
|
65
|
+
const currentTime = (new Date()).valueOf()
|
|
66
|
+
|
|
67
|
+
const differenceInMilliseconds = currentTime - fileUpdateTime
|
|
68
|
+
|
|
69
|
+
const differenceInSeconds = differenceInMilliseconds / 1000
|
|
70
|
+
|
|
71
|
+
return differenceInSeconds <= timeRangeSeconds
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function getModuleRootDir() {
|
|
75
|
+
const currentScriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
76
|
+
return path.resolve(currentScriptDir, '..', '..')
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function resolveToModuleRootDir(relativePath: string) {
|
|
80
|
+
return path.resolve(getModuleRootDir(), relativePath)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function getLowercaseFileExtension(filename: string) {
|
|
84
|
+
const fileExtensionIndex = filename.lastIndexOf(".")
|
|
85
|
+
|
|
86
|
+
if (fileExtensionIndex == -1) {
|
|
87
|
+
return ""
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return filename.substring(fileExtensionIndex + 1).toLowerCase()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function computeFileSha256Hex(filePath: string) {
|
|
94
|
+
const resultOpenPromise = new OpenPromise<string>()
|
|
95
|
+
|
|
96
|
+
const crypto = await import('crypto')
|
|
97
|
+
const hash = crypto.createHash('sha256')
|
|
98
|
+
|
|
99
|
+
const readStream = createReadStream(filePath)
|
|
100
|
+
|
|
101
|
+
readStream.on('data', data => hash.update(data))
|
|
102
|
+
readStream.on('error', error => resultOpenPromise.reject(error))
|
|
103
|
+
readStream.on('end', () => resultOpenPromise.resolve(hash.digest('hex')))
|
|
104
|
+
|
|
105
|
+
return resultOpenPromise.promise
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function readAndParseJsonFile(jsonFilePath: string, useJson5 = false) {
|
|
109
|
+
const fileContent = await readFile(jsonFilePath, { encoding: "utf-8" })
|
|
110
|
+
|
|
111
|
+
if (useJson5) {
|
|
112
|
+
const { default: JSON5 } = await import('json5')
|
|
113
|
+
|
|
114
|
+
return JSON5.parse(fileContent)
|
|
115
|
+
} else {
|
|
116
|
+
return JSON.parse(fileContent)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export async function writeFile(filePath: string, data: string | NodeJS.ArrayBufferView, options?: fsExtra.WriteFileOptions) {
|
|
121
|
+
return outputFile(filePath, data, options)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function writeFileSafe(filePath: string, data: string | NodeJS.ArrayBufferView, options?: fsExtra.WriteFileOptions) {
|
|
125
|
+
const tempDir = getAppTempDir(appName)
|
|
126
|
+
const tempFilePath = path.join(tempDir, `${getRandomHexString(16)}.partial`)
|
|
127
|
+
|
|
128
|
+
await writeFile(tempFilePath, data, options)
|
|
129
|
+
|
|
130
|
+
await move(tempFilePath, filePath)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function getAppTempDir(appName: string) {
|
|
134
|
+
let tempDir: string
|
|
135
|
+
|
|
136
|
+
const platform = process.platform
|
|
137
|
+
const homeDir = os.homedir()
|
|
138
|
+
|
|
139
|
+
if (platform == "win32") {
|
|
140
|
+
tempDir = path.join(homeDir, "AppData", "Local", "Temp", appName)
|
|
141
|
+
} else if (platform == "darwin") {
|
|
142
|
+
tempDir = path.join(homeDir, "Library", "Caches", appName)
|
|
143
|
+
} else if (platform == "linux") {
|
|
144
|
+
tempDir = path.join(homeDir, ".cache", appName)
|
|
145
|
+
} else {
|
|
146
|
+
throw new Error(`Unsupport platform ${platform}`)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return tempDir
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function getAppDataDir(appName: string) {
|
|
153
|
+
let dataDir: string
|
|
154
|
+
|
|
155
|
+
const platform = process.platform
|
|
156
|
+
const homeDir = os.homedir()
|
|
157
|
+
|
|
158
|
+
if (platform == "win32") {
|
|
159
|
+
dataDir = path.join(homeDir, "AppData", "Local", appName)
|
|
160
|
+
} else if (platform == "darwin") {
|
|
161
|
+
dataDir = path.join(homeDir, "Library", "Application Support", appName)
|
|
162
|
+
} else if (platform == "linux") {
|
|
163
|
+
dataDir = path.join(homeDir, ".local", "share", appName)
|
|
164
|
+
} else {
|
|
165
|
+
throw new Error(`Unsupport platform ${platform}`)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return dataDir
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export async function chmodRecursive(rootPath: string, newMode: number) {
|
|
172
|
+
const rootPathStat = await stat(rootPath)
|
|
173
|
+
|
|
174
|
+
await chmod(rootPath, newMode)
|
|
175
|
+
|
|
176
|
+
if (rootPathStat.isDirectory()) {
|
|
177
|
+
const fileList = await readdir(rootPath)
|
|
178
|
+
|
|
179
|
+
for (const filename of fileList) {
|
|
180
|
+
const filePath = path.join(rootPath, filename)
|
|
181
|
+
|
|
182
|
+
await chmodRecursive(filePath, newMode)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export async function ensureDir(dirPath: string) {
|
|
188
|
+
dirPath = path.normalize(dirPath)
|
|
189
|
+
|
|
190
|
+
if (existsSync(dirPath)) {
|
|
191
|
+
const dirStats = await stat(dirPath)
|
|
192
|
+
|
|
193
|
+
if (!dirStats.isDirectory()) {
|
|
194
|
+
throw new Error(`The path '${dirPath}' exists but is not a directory.`)
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
return fsExtra.ensureDir(dirPath)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export async function move(source: string, dest: string) {
|
|
202
|
+
source = path.normalize(source)
|
|
203
|
+
dest = path.normalize(dest)
|
|
204
|
+
|
|
205
|
+
if (existsSync(dest)) {
|
|
206
|
+
const destPathExistsAndIsWritable = await existsAndIsWritable(dest)
|
|
207
|
+
|
|
208
|
+
if (!destPathExistsAndIsWritable) {
|
|
209
|
+
throw new Error(`The destination path '${dest}' exists but is not writable. There may be a permissions or locking issue.`)
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
const destDir = path.parse(dest).dir
|
|
213
|
+
const destDirIsWritable = await testDirectoryIsWritable(destDir)
|
|
214
|
+
|
|
215
|
+
if (!destDirIsWritable) {
|
|
216
|
+
throw new Error(`The directory ${destDir} is not writable. There may be a permissions issue.`)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return fsExtra.move(source, dest, { overwrite: true })
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export async function existsAndIsWritable(targetPath: string) {
|
|
224
|
+
try {
|
|
225
|
+
await access(targetPath, gracefulFS.constants.W_OK);
|
|
226
|
+
} catch {
|
|
227
|
+
return false
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return true
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export async function testDirectoryIsWritable(dir: string) {
|
|
234
|
+
const testFileName = path.join(dir, getRandomHexString(16))
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
await fsExtra.createFile(testFileName)
|
|
238
|
+
await remove(testFileName)
|
|
239
|
+
} catch (e) {
|
|
240
|
+
return false
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return true
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export async function copyFileAlternative(source: string, dest: string) {
|
|
247
|
+
return new Promise<void>((resolve, reject) => {
|
|
248
|
+
const readStream = createReadStream(source)
|
|
249
|
+
const writeStream = createWriteStream(dest)
|
|
250
|
+
|
|
251
|
+
readStream.on('error', (err: any) => {
|
|
252
|
+
reject(err)
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
writeStream.on('error', (err: any) => {
|
|
256
|
+
reject(err)
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
readStream.pipe(writeStream)
|
|
260
|
+
|
|
261
|
+
readStream.on('end', () => {
|
|
262
|
+
resolve()
|
|
263
|
+
})
|
|
264
|
+
})
|
|
265
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
export function knuthMultiplicative(bytes: Buffer) {
|
|
2
|
+
let hash = 0
|
|
3
|
+
|
|
4
|
+
for (const byte of bytes) {
|
|
5
|
+
hash += Math.imul(byte, 2654435761)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return hash
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function xorShift32Hash(bytes: Buffer) {
|
|
12
|
+
let s = 0
|
|
13
|
+
|
|
14
|
+
for (const byte of bytes) {
|
|
15
|
+
s += byte
|
|
16
|
+
|
|
17
|
+
s ^= s << 13
|
|
18
|
+
s ^= s >> 17
|
|
19
|
+
s ^= s << 5
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return s
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function jenkinsOneAtATime(bytes: Buffer) {
|
|
26
|
+
let hash = 0
|
|
27
|
+
|
|
28
|
+
for (const byte of bytes) {
|
|
29
|
+
hash += byte
|
|
30
|
+
hash += hash << 10
|
|
31
|
+
hash ^= hash >> 6
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
hash += hash << 3
|
|
35
|
+
hash ^= hash >> 11
|
|
36
|
+
hash += hash << 15
|
|
37
|
+
|
|
38
|
+
return hash >>> 0
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function FNV1a(bytes: Buffer) {
|
|
42
|
+
let hval = 2166136261 | 0
|
|
43
|
+
|
|
44
|
+
for (const byte of bytes) {
|
|
45
|
+
hval = Math.imul(hval ^ byte, 16777619)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return hval >>> 0
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function superFastHash(bytes: Buffer) {
|
|
52
|
+
let hash = bytes.length, tmp, p = 0
|
|
53
|
+
const len = bytes.length >>> 2
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < len; i++) {
|
|
56
|
+
hash += bytes[p] | bytes[p + 1] << 8
|
|
57
|
+
tmp = ((bytes[p + 2] | bytes[p + 3] << 8) << 11) ^ hash
|
|
58
|
+
hash = (hash << 16) ^ tmp
|
|
59
|
+
hash += hash >>> 11
|
|
60
|
+
p += 4
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
switch (bytes.length & 3) {
|
|
64
|
+
case 3:
|
|
65
|
+
hash += bytes[p] | bytes[p + 1] << 8
|
|
66
|
+
hash ^= hash << 16
|
|
67
|
+
hash ^= bytes[p + 2] << 18
|
|
68
|
+
hash += hash >>> 11
|
|
69
|
+
break
|
|
70
|
+
case 2:
|
|
71
|
+
hash += bytes[p] | bytes[p + 1] << 8
|
|
72
|
+
hash ^= hash << 11
|
|
73
|
+
hash += hash >>> 17
|
|
74
|
+
break
|
|
75
|
+
case 1:
|
|
76
|
+
hash += bytes[p]
|
|
77
|
+
hash ^= hash << 10
|
|
78
|
+
hash += hash >>> 1
|
|
79
|
+
break
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
hash ^= hash << 3
|
|
83
|
+
hash += hash >>> 5
|
|
84
|
+
hash ^= hash << 4
|
|
85
|
+
hash += hash >>> 17
|
|
86
|
+
hash ^= hash << 25
|
|
87
|
+
hash += hash >>> 6
|
|
88
|
+
|
|
89
|
+
return hash >>> 0
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function cyrb53Hash(bytes: Buffer, seed = 0) {
|
|
93
|
+
// https://github.com/bryc/code/blob/master/jshash/experimental/cyrb53.js
|
|
94
|
+
|
|
95
|
+
let h1 = 0xdeadbeef ^ seed
|
|
96
|
+
let h2 = 0x41c6ce57 ^ seed
|
|
97
|
+
|
|
98
|
+
for (const byte of bytes) {
|
|
99
|
+
h1 = Math.imul(h1 ^ byte, 2654435761)
|
|
100
|
+
h2 = Math.imul(h2 ^ byte, 1597334677)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909)
|
|
104
|
+
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909)
|
|
105
|
+
|
|
106
|
+
return (4294967296 * (2097151 & h2)) + (h1 >>> 0)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function djb2(bytes: Buffer) {
|
|
110
|
+
let hash = 5381
|
|
111
|
+
|
|
112
|
+
for (const byte of bytes) {
|
|
113
|
+
//hash += (hash << 5) + byte
|
|
114
|
+
hash += (hash * 33) + byte
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return hash >>> 0
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
export function murmurHash1(bytes: Buffer, seed = 0) {
|
|
122
|
+
// https://github.com/bryc/code/blob/master/jshash/hashes/murmurhash1.js
|
|
123
|
+
|
|
124
|
+
const length = bytes.length
|
|
125
|
+
|
|
126
|
+
const multiplier = 3332679571
|
|
127
|
+
const intIterationMaxIndex = length & -4
|
|
128
|
+
|
|
129
|
+
let hash = seed ^ Math.imul(length, multiplier)
|
|
130
|
+
let index = 0
|
|
131
|
+
|
|
132
|
+
for (; index < intIterationMaxIndex; index += 4) {
|
|
133
|
+
hash += bytes[index + 3] << 24 |
|
|
134
|
+
bytes[index + 2] << 16 |
|
|
135
|
+
bytes[index + 1] << 8 |
|
|
136
|
+
bytes[index]
|
|
137
|
+
|
|
138
|
+
hash = Math.imul(hash, multiplier)
|
|
139
|
+
hash ^= hash >>> 16
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
switch (length & 3) {
|
|
143
|
+
case 3: {
|
|
144
|
+
hash += bytes[index + 2] << 16
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
case 2: {
|
|
148
|
+
hash += bytes[index + 1] << 8
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
case 1: {
|
|
152
|
+
hash += bytes[index]
|
|
153
|
+
hash = Math.imul(hash, multiplier)
|
|
154
|
+
hash ^= hash >>> 16
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
hash = Math.imul(hash, multiplier)
|
|
159
|
+
hash ^= hash >>> 10
|
|
160
|
+
|
|
161
|
+
hash = Math.imul(hash, multiplier)
|
|
162
|
+
hash ^= hash >>> 17
|
|
163
|
+
|
|
164
|
+
return hash >>> 0
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function MurmurHash3(bytes: Buffer, seed = 0) {
|
|
168
|
+
// https://github.com/bryc/code/blob/master/jshash/hashes/murmurhash3.js
|
|
169
|
+
|
|
170
|
+
const p1 = 3432918353
|
|
171
|
+
const p2 = 461845907
|
|
172
|
+
const p3 = 2246822507
|
|
173
|
+
const p4 = 3266489909
|
|
174
|
+
|
|
175
|
+
const byteCount = bytes.length
|
|
176
|
+
|
|
177
|
+
const intIterationMaxIndex = byteCount & -4
|
|
178
|
+
|
|
179
|
+
let k = 0
|
|
180
|
+
let hash = seed | 0
|
|
181
|
+
let i = 0
|
|
182
|
+
|
|
183
|
+
for (; i < intIterationMaxIndex; i += 4) {
|
|
184
|
+
k = bytes[i + 3] << 24 | bytes[i + 2] << 16 | bytes[i + 1] << 8 | bytes[i]
|
|
185
|
+
|
|
186
|
+
k = Math.imul(k, p1)
|
|
187
|
+
|
|
188
|
+
k = k << 15 | k >>> 17
|
|
189
|
+
|
|
190
|
+
hash ^= Math.imul(k, p2)
|
|
191
|
+
|
|
192
|
+
hash = hash << 13 | hash >>> 19
|
|
193
|
+
|
|
194
|
+
hash = (Math.imul(hash, 5) + 3864292196) | 0 // |0 = prevent float
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
k = 0
|
|
198
|
+
|
|
199
|
+
switch (bytes.length & 3) {
|
|
200
|
+
case 3: {
|
|
201
|
+
k ^= bytes[i + 2] << 16
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
case 2: {
|
|
205
|
+
k ^= bytes[i + 1] << 8
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
case 1: {
|
|
209
|
+
k ^= bytes[i]
|
|
210
|
+
|
|
211
|
+
k = Math.imul(k, p1)
|
|
212
|
+
|
|
213
|
+
k = k << 15 | k >>> 17
|
|
214
|
+
|
|
215
|
+
hash ^= Math.imul(k, p2)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
hash ^= byteCount
|
|
220
|
+
|
|
221
|
+
hash ^= hash >>> 16
|
|
222
|
+
|
|
223
|
+
hash = Math.imul(hash, p3)
|
|
224
|
+
hash ^= hash >>> 13
|
|
225
|
+
|
|
226
|
+
hash = Math.imul(hash, p4)
|
|
227
|
+
hash ^= hash >>> 16
|
|
228
|
+
|
|
229
|
+
return hash >>> 0
|
|
230
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { readAndParseJsonFile, resolveToModuleRootDir } from "./FileSystem.js"
|
|
2
|
+
|
|
3
|
+
export function languageCodeToName(languageCode: string) {
|
|
4
|
+
const languageNames = new Intl.DisplayNames(['en'], { type: 'language' })
|
|
5
|
+
|
|
6
|
+
let translatedLanguageName: string | undefined
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
translatedLanguageName = languageNames.of(languageCode)
|
|
10
|
+
} catch (e) {
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return translatedLanguageName || "Unknown"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function formatLanguageCodeWithName(languageCode: string, styleId: 1 | 2 = 1) {
|
|
17
|
+
if (styleId == 1) {
|
|
18
|
+
return `${languageCodeToName(languageCode)} (${languageCode})`
|
|
19
|
+
} else {
|
|
20
|
+
return `${languageCode}, ${languageCodeToName(languageCode)}`
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function getShortLanguageCode(langCode: string) {
|
|
25
|
+
const dashIndex = langCode.indexOf("-")
|
|
26
|
+
|
|
27
|
+
if (dashIndex == -1) {
|
|
28
|
+
return langCode
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return langCode.substring(0, dashIndex).toLowerCase()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function normalizeLanguageCode(langCode: string) {
|
|
35
|
+
langCode = langCode.trim()
|
|
36
|
+
|
|
37
|
+
const parts = langCode.split("-")
|
|
38
|
+
|
|
39
|
+
const result = [parts[0].toLowerCase()]
|
|
40
|
+
|
|
41
|
+
for (let i = 1; i < parts.length; i++) {
|
|
42
|
+
result.push(parts[i].toUpperCase())
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return result.join("-")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const isoToLcidLookup = new Map<string, number>()
|
|
49
|
+
const lcidToIsoLookup = new Map<number, string[]>()
|
|
50
|
+
const lcidEntries: LCIDEntry[] = []
|
|
51
|
+
|
|
52
|
+
export async function isoToLcidLanguageCode(iso: string) {
|
|
53
|
+
await loadLcidLookupIfNeeded()
|
|
54
|
+
|
|
55
|
+
return isoToLcidLookup.get(iso)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function lcidToIsoLanguageCode(lcid: number) {
|
|
59
|
+
await loadLcidLookupIfNeeded()
|
|
60
|
+
|
|
61
|
+
return lcidToIsoLookup.get(lcid)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function loadLcidLookupIfNeeded() {
|
|
65
|
+
if (lcidEntries.length > 0) {
|
|
66
|
+
return lcidEntries
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const lcidLookup: LCIDLookup = await readAndParseJsonFile(resolveToModuleRootDir("data/tables/lcid-table.json"))
|
|
70
|
+
|
|
71
|
+
for (const isoName in lcidLookup) {
|
|
72
|
+
const lcidEntry = lcidLookup[isoName]
|
|
73
|
+
lcidEntries.push(lcidEntry)
|
|
74
|
+
|
|
75
|
+
const lcidValue = lcidEntry.LCID
|
|
76
|
+
|
|
77
|
+
isoToLcidLookup.set(isoName, lcidValue)
|
|
78
|
+
|
|
79
|
+
let entry = lcidToIsoLookup.get(lcidValue)
|
|
80
|
+
|
|
81
|
+
if (!entry) {
|
|
82
|
+
entry = []
|
|
83
|
+
lcidToIsoLookup.set(lcidValue, entry)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
entry.push(isoName)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return lcidEntries
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function getDefaultDialectForLanguageCodeIfPossible(langCode: string) {
|
|
93
|
+
const defaultDialect = defaultDialectForLanguageCode[langCode]
|
|
94
|
+
|
|
95
|
+
return defaultDialect || langCode
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export const defaultDialectForLanguageCode: { [lang: string]: string } = {
|
|
99
|
+
"en": "en-US",
|
|
100
|
+
"zh": "zh-CN",
|
|
101
|
+
"ar": "ar-EG",
|
|
102
|
+
"fr": "fr-FR",
|
|
103
|
+
"de": "de-DE",
|
|
104
|
+
"pt": "pt-BR",
|
|
105
|
+
"es": "es-ES",
|
|
106
|
+
"nl": "nl-NL"
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
type LCIDLookup = { [isoLangCode: string]: LCIDEntry }
|
|
110
|
+
|
|
111
|
+
export interface LCIDEntry {
|
|
112
|
+
"LCID": number
|
|
113
|
+
"Name": string
|
|
114
|
+
"TwoLetterISOLanguageName": string,
|
|
115
|
+
"ThreeLetterISOLanguageName": string,
|
|
116
|
+
"ThreeLetterWindowsLanguageName": string,
|
|
117
|
+
"EnglishName": string
|
|
118
|
+
"ANSICodePage": string
|
|
119
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import chalk from "chalk"
|
|
2
|
+
import { Timer } from "./Timer.js"
|
|
3
|
+
import { logToStderr, writeToStderr, yieldToEventLoop } from "./Utilities.js"
|
|
4
|
+
|
|
5
|
+
let currentActiveLogger: Logger | null = null
|
|
6
|
+
|
|
7
|
+
export class Logger {
|
|
8
|
+
private timer = new Timer()
|
|
9
|
+
active = false
|
|
10
|
+
|
|
11
|
+
start(title: string, titleColor = chalk.cyanBright) {
|
|
12
|
+
this.startAsync(title, false, titleColor)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async startAsync(title: string, yieldBeforeStart = true, titleColor = chalk.cyanBright) {
|
|
16
|
+
if (currentActiveLogger != null && currentActiveLogger != this) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
this.end()
|
|
21
|
+
|
|
22
|
+
if (yieldBeforeStart) {
|
|
23
|
+
await yieldToEventLoop()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
writeToStderr(`${titleColor(title)}.. `)
|
|
27
|
+
this.active = true
|
|
28
|
+
currentActiveLogger = this
|
|
29
|
+
this.timer.restart()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
end() {
|
|
33
|
+
if (this.active && currentActiveLogger == this) {
|
|
34
|
+
const elapsedTime = this.timer.elapsedTime
|
|
35
|
+
|
|
36
|
+
writeToStderr(`${elapsedTime.toFixed(1)}ms\n`)
|
|
37
|
+
currentActiveLogger = null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.active = false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
logDuration(message: any, startTime: number, titleColor = chalk.cyanBright) {
|
|
44
|
+
const duration = Timer.currentTime - startTime
|
|
45
|
+
|
|
46
|
+
this.log(`${titleColor(message)}: ${duration.toFixed(1)}ms`)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
logTitledMessage(title: string, content: string, titleColor = chalk.cyanBright) {
|
|
50
|
+
this.log(`${titleColor(title)}: ${content}`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
log(message: any) {
|
|
54
|
+
if (currentActiveLogger == this || currentActiveLogger == null) {
|
|
55
|
+
logToStderr(message)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
write(message: any) {
|
|
60
|
+
if (currentActiveLogger == this || currentActiveLogger == null) {
|
|
61
|
+
writeToStderr(message)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getTimestamp() {
|
|
66
|
+
return Timer.currentTime
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function resetActiveLogger() {
|
|
71
|
+
currentActiveLogger = null
|
|
72
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import ndarray from 'ndarray'
|
|
2
|
+
import ops from 'ndarray-ops'
|
|
3
|
+
import { medianFilter, softmax } from '../math/VectorMath.js'
|
|
4
|
+
|
|
5
|
+
export function ndarraySoftMax(vector: ndarray.NdArray, temperature = 1.0) {
|
|
6
|
+
const vectorAsArray = new Array(vector.shape[0])
|
|
7
|
+
|
|
8
|
+
for (let i = 0; i < vectorAsArray.length; i++) {
|
|
9
|
+
vectorAsArray[i] = vector.get(i)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const result = softmax(vectorAsArray, temperature)
|
|
13
|
+
|
|
14
|
+
for (let i = 0; i < vectorAsArray.length; i++) {
|
|
15
|
+
vector.set(i, result[i])
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function ndarrayMedianFilter(vector: ndarray.NdArray, width: number) {
|
|
20
|
+
const vectorAsArray = new Array(vector.shape[0])
|
|
21
|
+
|
|
22
|
+
for (let i = 0; i < vectorAsArray.length; i++) {
|
|
23
|
+
vectorAsArray[i] = vector.get(i)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const result = medianFilter(vectorAsArray, width)
|
|
27
|
+
|
|
28
|
+
for (let i = 0; i < vectorAsArray.length; i++) {
|
|
29
|
+
vector.set(i, result[i])
|
|
30
|
+
}
|
|
31
|
+
}
|