echogarden 1.6.2 → 1.7.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.
- package/data/schemas/options.json +30 -4
- package/dist/api/SourceSeparation.d.ts +3 -2
- package/dist/api/SourceSeparation.js +10 -8
- package/dist/api/SourceSeparation.js.map +1 -1
- package/dist/api/Synthesis.js +3 -1
- package/dist/api/Synthesis.js.map +1 -1
- package/dist/api/TextTranslation.d.ts +3 -1
- package/dist/api/TextTranslation.js +12 -6
- package/dist/api/TextTranslation.js.map +1 -1
- package/dist/build-tools/MakeTarballsForInstalledPackages.d.ts +1 -0
- package/dist/build-tools/MakeTarballsForInstalledPackages.js +20 -0
- package/dist/build-tools/MakeTarballsForInstalledPackages.js.map +1 -0
- package/dist/cli/CLI.js +4 -3
- package/dist/cli/CLI.js.map +1 -1
- package/dist/dsp/FFT.d.ts +2 -3
- package/dist/dsp/FFT.js +25 -23
- package/dist/dsp/FFT.js.map +1 -1
- package/dist/nlp/Segmentation.js +2 -1
- package/dist/nlp/Segmentation.js.map +1 -1
- package/dist/nlp/TextNormalizer.d.ts +2 -0
- package/dist/nlp/TextNormalizer.js +51 -0
- package/dist/nlp/TextNormalizer.js.map +1 -1
- package/dist/recognition/WhisperSTT.d.ts +2 -0
- package/dist/recognition/WhisperSTT.js +7 -6
- package/dist/recognition/WhisperSTT.js.map +1 -1
- package/dist/source-separation/MDXNetSourceSeparation.d.ts +20 -2
- package/dist/source-separation/MDXNetSourceSeparation.js +134 -76
- package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
- package/dist/subtitles/Subtitles.js +2 -1
- package/dist/subtitles/Subtitles.js.map +1 -1
- package/dist/synthesis/EspeakTTS.js +5 -5
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/dist/tests/Test.js +0 -1
- package/dist/tests/Test.js.map +1 -1
- package/dist/text-translation/GoogleTranslateTextTranslation.d.ts +9 -3
- package/dist/text-translation/GoogleTranslateTextTranslation.js +59 -29
- package/dist/text-translation/GoogleTranslateTextTranslation.js.map +1 -1
- package/dist/utilities/OnnxUtilities.d.ts +1 -0
- package/dist/utilities/OnnxUtilities.js +5 -5
- package/dist/utilities/OnnxUtilities.js.map +1 -1
- package/dist/utilities/PackageManager.js +3 -0
- package/dist/utilities/PackageManager.js.map +1 -1
- package/dist/utilities/StringUtilities.d.ts +28 -0
- package/dist/utilities/StringUtilities.js +150 -0
- package/dist/utilities/StringUtilities.js.map +1 -0
- package/dist/utilities/TarballMaker.d.ts +3 -4
- package/dist/utilities/TarballMaker.js +6 -19
- package/dist/utilities/TarballMaker.js.map +1 -1
- package/dist/utilities/Timeline.js +2 -1
- package/dist/utilities/Timeline.js.map +1 -1
- package/dist/utilities/Utilities.d.ts +1 -33
- package/dist/utilities/Utilities.js +3 -176
- package/dist/utilities/Utilities.js.map +1 -1
- package/dist/utilities/WebReader.js +1 -1
- package/dist/utilities/WebReader.js.map +1 -1
- package/dist/utilities/WikipediaReader.js +1 -1
- package/dist/utilities/WikipediaReader.js.map +1 -1
- package/dist/utilities/WindowedList.d.ts +10 -0
- package/dist/utilities/WindowedList.js +36 -0
- package/dist/utilities/WindowedList.js.map +1 -0
- package/docs/Engines.md +1 -1
- package/docs/Options.md +8 -2
- package/package.json +8 -9
- package/src/api/SourceSeparation.ts +15 -10
- package/src/api/Synthesis.ts +3 -1
- package/src/api/TextTranslation.ts +17 -9
- package/src/build-tools/MakeTarballsForInstalledPackages.ts +25 -0
- package/src/cli/CLI.ts +4 -3
- package/src/dsp/FFT.ts +30 -33
- package/src/nlp/Segmentation.ts +2 -1
- package/src/nlp/TextNormalizer.ts +60 -0
- package/src/recognition/WhisperSTT.ts +7 -6
- package/src/source-separation/MDXNetSourceSeparation.ts +183 -85
- package/src/subtitles/Subtitles.ts +2 -1
- package/src/synthesis/EspeakTTS.ts +5 -5
- package/src/tests/Test.ts +0 -4
- package/src/text-translation/GoogleTranslateTextTranslation.ts +91 -30
- package/src/utilities/OnnxUtilities.ts +7 -8
- package/src/utilities/PackageManager.ts +3 -0
- package/src/utilities/StringUtilities.ts +203 -0
- package/src/utilities/TarballMaker.ts +6 -23
- package/src/utilities/Timeline.ts +2 -1
- package/src/utilities/Utilities.ts +4 -237
- package/src/utilities/WebReader.ts +1 -1
- package/src/utilities/WikipediaReader.ts +1 -1
- package/src/utilities/WindowedList.ts +45 -0
|
@@ -1,35 +1,55 @@
|
|
|
1
1
|
import { request } from "gaxios"
|
|
2
2
|
import { Logger } from "../utilities/Logger.js"
|
|
3
|
-
import { Fragment, splitToFragments, splitToLines
|
|
3
|
+
import { Fragment, splitToFragments, splitToLines } from "../nlp/Segmentation.js"
|
|
4
4
|
import { TranslationPair } from "../api/TextTranslation.js"
|
|
5
5
|
import { getChromeOnWindowsHeaders, getChromeOnAndroidHeaders } from "../utilities/BrowserRequestHeaders.js"
|
|
6
|
-
import { logToStderr
|
|
6
|
+
import { logToStderr } from "../utilities/Utilities.js"
|
|
7
7
|
import { getShortLanguageCode } from "../utilities/Locale.js"
|
|
8
|
+
import { PlainTextOptions } from "../api/Common.js"
|
|
9
|
+
import { extendDeep } from "../utilities/ObjectUtilities.js"
|
|
10
|
+
import { splitAndPreserveSeparators } from "../utilities/StringUtilities.js"
|
|
8
11
|
|
|
9
12
|
const log = logToStderr
|
|
10
13
|
|
|
11
|
-
export async function translateText(
|
|
14
|
+
export async function translateText(
|
|
15
|
+
text: string,
|
|
16
|
+
sourceLanguage: string,
|
|
17
|
+
targetLanguage: string,
|
|
18
|
+
plainTextOptions: PlainTextOptions,
|
|
19
|
+
options: GoogleTranslateTextTranslationOptions) {
|
|
20
|
+
|
|
12
21
|
const logger = new Logger()
|
|
13
22
|
|
|
14
|
-
|
|
23
|
+
if (!supportsLanguage(sourceLanguage)) {
|
|
24
|
+
throw new Error(`Language code ${sourceLanguage} is not supported by the Google Translate engine. Supported language codes are ${supportedLanguageCodes.join(', ')}`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!supportsLanguage(targetLanguage)) {
|
|
28
|
+
throw new Error(`Language code ${sourceLanguage} is not supported by the Google Translate engine. Supported language codes are ${supportedLanguageCodes.join(', ')}`)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
options = extendDeep(defaultGoogleTranslateTextTranslationOptions, options)
|
|
32
|
+
|
|
33
|
+
const maxCharactersPerPart = options.maxCharactersPerPart!
|
|
15
34
|
|
|
16
|
-
|
|
17
|
-
|
|
35
|
+
const paragraphSeperatorPattern = plainTextOptions.paragraphBreaks === 'double' ? /(\r?\n)(\r?\n)+/g : /(\r?\n)+/g
|
|
36
|
+
|
|
37
|
+
const paragraphs = splitAndPreserveSeparators(text, paragraphSeperatorPattern)
|
|
18
38
|
|
|
19
39
|
const fragmentsForParagraph: Fragment[][] = []
|
|
20
40
|
|
|
21
41
|
for (const paragraph of paragraphs) {
|
|
22
|
-
const fragments = await splitToFragments(paragraph,
|
|
42
|
+
const fragments = await splitToFragments(paragraph, maxCharactersPerPart, getShortLanguageCode(sourceLanguage))
|
|
23
43
|
|
|
24
44
|
fragmentsForParagraph.push(fragments)
|
|
25
45
|
}
|
|
26
46
|
|
|
27
|
-
const
|
|
47
|
+
const parts: Fragment[][] = [[]]
|
|
28
48
|
|
|
29
|
-
function
|
|
49
|
+
function totalLengthOfLastPart() {
|
|
30
50
|
let total = 0
|
|
31
51
|
|
|
32
|
-
for (const fragment of
|
|
52
|
+
for (const fragment of parts[parts.length - 1]) {
|
|
33
53
|
total += fragment.length
|
|
34
54
|
}
|
|
35
55
|
|
|
@@ -42,14 +62,14 @@ export async function translateText(text: string, sourceLanguage: string, target
|
|
|
42
62
|
const fragments = fragmentsForParagraph[paragraphIndex]
|
|
43
63
|
|
|
44
64
|
for (const fragment of fragments) {
|
|
45
|
-
let
|
|
65
|
+
let lastPart = parts[parts.length - 1]
|
|
46
66
|
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
|
|
67
|
+
if (totalLengthOfLastPart() + fragment.length > maxCharactersPerPart) {
|
|
68
|
+
lastPart = []
|
|
69
|
+
parts.push(lastPart)
|
|
50
70
|
}
|
|
51
71
|
|
|
52
|
-
|
|
72
|
+
lastPart.push(fragment)
|
|
53
73
|
|
|
54
74
|
fragmentToParagraphIndex.set(fragment, paragraphIndex)
|
|
55
75
|
}
|
|
@@ -57,25 +77,25 @@ export async function translateText(text: string, sourceLanguage: string, target
|
|
|
57
77
|
|
|
58
78
|
const translatedFragmentsForParagraphs = paragraphs.map(_ => [] as string[])
|
|
59
79
|
|
|
60
|
-
for (let
|
|
61
|
-
const
|
|
80
|
+
for (let partIndex = 0; partIndex < parts.length; partIndex++) {
|
|
81
|
+
const part = parts[partIndex]
|
|
62
82
|
|
|
63
|
-
const
|
|
83
|
+
const joinedFragmentsInPart = part.map(x => x.text.replaceAll('|', ' ')).join(`\n|\n`)
|
|
64
84
|
|
|
65
|
-
logger.logTitledMessage(`\nTranslate part ${
|
|
85
|
+
logger.logTitledMessage(`\nTranslate part ${partIndex + 1} of ${parts.length}`, joinedFragmentsInPart.replaceAll('\n|\n', ''))
|
|
66
86
|
|
|
67
87
|
logger.start(`Request translation from Google Translate`)
|
|
68
|
-
const fragmentTranslationPair = await translateText_MobileWeb(
|
|
88
|
+
const fragmentTranslationPair = await translateText_MobileWeb(joinedFragmentsInPart, sourceLanguage, targetLanguage, options)
|
|
69
89
|
logger.end()
|
|
70
90
|
|
|
71
|
-
const
|
|
91
|
+
const translatedTextForPart = fragmentTranslationPair[0].translatedText
|
|
72
92
|
|
|
73
|
-
logger.logTitledMessage(`Translated part`, `"${
|
|
93
|
+
logger.logTitledMessage(`Translated part`, `"${translatedTextForPart.replaceAll(' | ', '\n') }"`)
|
|
74
94
|
|
|
75
|
-
const splitTranslation =
|
|
95
|
+
const splitTranslation = translatedTextForPart.split(`|`)
|
|
76
96
|
|
|
77
|
-
for (let fragmentIndex = 0; fragmentIndex <
|
|
78
|
-
const fragment =
|
|
97
|
+
for (let fragmentIndex = 0; fragmentIndex < part.length; fragmentIndex++) {
|
|
98
|
+
const fragment = part[fragmentIndex]
|
|
79
99
|
const translatedFragment = splitTranslation[fragmentIndex].trim()
|
|
80
100
|
|
|
81
101
|
const paragraphIndex = fragmentToParagraphIndex.get(fragment)!
|
|
@@ -87,18 +107,46 @@ export async function translateText(text: string, sourceLanguage: string, target
|
|
|
87
107
|
const translationPairs: TranslationPair[] = []
|
|
88
108
|
|
|
89
109
|
for (let paragraphIndex = 0; paragraphIndex < paragraphs.length; paragraphIndex++) {
|
|
110
|
+
const sourceParagraph = paragraphs[paragraphIndex]
|
|
111
|
+
const translatedParagraph = translatedFragmentsForParagraphs[paragraphIndex].join(' ')
|
|
112
|
+
|
|
113
|
+
let translatedParagraphWithWhitespace = ''
|
|
114
|
+
|
|
115
|
+
const sourceParagraphLeadingWhitespaceMatches = sourceParagraph.match(/^\s+/)
|
|
116
|
+
|
|
117
|
+
if (sourceParagraphLeadingWhitespaceMatches) {
|
|
118
|
+
translatedParagraphWithWhitespace += sourceParagraphLeadingWhitespaceMatches[0]
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
translatedParagraphWithWhitespace += translatedParagraph
|
|
122
|
+
|
|
123
|
+
const sourceParagraphTrailingWhitespaceMatches = sourceParagraph.match(/\s+$/)
|
|
124
|
+
|
|
125
|
+
if (sourceParagraphTrailingWhitespaceMatches) {
|
|
126
|
+
translatedParagraphWithWhitespace += sourceParagraphTrailingWhitespaceMatches[0]
|
|
127
|
+
}
|
|
128
|
+
|
|
90
129
|
translationPairs.push({
|
|
91
130
|
sourceText: paragraphs[paragraphIndex],
|
|
92
|
-
translatedText:
|
|
131
|
+
translatedText: translatedParagraphWithWhitespace,
|
|
93
132
|
})
|
|
94
133
|
}
|
|
95
134
|
|
|
96
|
-
const
|
|
135
|
+
const translatedParagraphs = translationPairs.map(pair => pair.translatedText)
|
|
136
|
+
|
|
137
|
+
const translatedText = translatedParagraphs.join('')
|
|
97
138
|
|
|
98
139
|
return { translationPairs, translatedText }
|
|
99
140
|
}
|
|
100
141
|
|
|
101
|
-
export async function translateText_MobileWeb(
|
|
142
|
+
export async function translateText_MobileWeb(
|
|
143
|
+
text: string,
|
|
144
|
+
sourceLanguage: string,
|
|
145
|
+
targetLanguage: string,
|
|
146
|
+
options: GoogleTranslateTextTranslationOptions) {
|
|
147
|
+
|
|
148
|
+
const tld = options.tld
|
|
149
|
+
|
|
102
150
|
const logger = new Logger()
|
|
103
151
|
|
|
104
152
|
logger.start(`Request translation from Google Translate`)
|
|
@@ -419,11 +467,11 @@ function normalizeLanguageCodeForGoogleTranslate(languageCode: string) {
|
|
|
419
467
|
}
|
|
420
468
|
|
|
421
469
|
export function supportsLanguage(langCode: string) {
|
|
422
|
-
return
|
|
470
|
+
return supportedLanguageCodes.includes(normalizeLanguageCodeForGoogleTranslate(langCode))
|
|
423
471
|
}
|
|
424
472
|
|
|
425
473
|
// 243 Languages supported
|
|
426
|
-
export const
|
|
474
|
+
export const supportedLanguageCodes = [
|
|
427
475
|
'ab', // Abkhaz
|
|
428
476
|
'ace', // Acehnese
|
|
429
477
|
'ach', // Acholi
|
|
@@ -464,6 +512,7 @@ export const supportedLanguages = [
|
|
|
464
512
|
'ch', // Chamorro
|
|
465
513
|
'ce', // Chechen
|
|
466
514
|
'ny', // Chichewa
|
|
515
|
+
'zh', // Chinese (same as zh-CN)
|
|
467
516
|
'zh-CN', // Chinese (Simplified)
|
|
468
517
|
'zh-TW', // Chinese (Traditional)
|
|
469
518
|
'chk', // Chuukese
|
|
@@ -505,6 +554,7 @@ export const supportedLanguages = [
|
|
|
505
554
|
'cnh', // Hakha Chin
|
|
506
555
|
'ha', // Hausa
|
|
507
556
|
'haw', // Hawaiian
|
|
557
|
+
'he', // Hebrew
|
|
508
558
|
'iw', // Hebrew
|
|
509
559
|
'hil', // Hiligaynon
|
|
510
560
|
'hi', // Hindi
|
|
@@ -520,6 +570,7 @@ export const supportedLanguages = [
|
|
|
520
570
|
'it', // Italian
|
|
521
571
|
'jam', // Jamaican Patois
|
|
522
572
|
'ja', // Japanese
|
|
573
|
+
'jv', // Javanese
|
|
523
574
|
'jw', // Javanese
|
|
524
575
|
'kac', // Jingpo
|
|
525
576
|
'kl', // Kalaallisut
|
|
@@ -668,3 +719,13 @@ export const supportedLanguages = [
|
|
|
668
719
|
'zap', // Zapotec
|
|
669
720
|
'zu', // Zulu
|
|
670
721
|
]
|
|
722
|
+
|
|
723
|
+
export interface GoogleTranslateTextTranslationOptions {
|
|
724
|
+
tld?: string
|
|
725
|
+
maxCharactersPerPart?: number
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
export const defaultGoogleTranslateTextTranslationOptions: GoogleTranslateTextTranslationOptions = {
|
|
729
|
+
tld: 'com',
|
|
730
|
+
maxCharactersPerPart: 2000,
|
|
731
|
+
}
|
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import type * as Onnx from 'onnxruntime-node'
|
|
2
2
|
|
|
3
3
|
export function getOnnxSessionOptions(options: OnnxSessionOptions) {
|
|
4
|
-
|
|
5
4
|
const onnxOptions: Onnx.InferenceSession.SessionOptions = {
|
|
6
5
|
executionProviders: ['cpu'],
|
|
7
6
|
logSeverityLevel: 3,
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
function dmlProviderAvailable() {
|
|
11
|
-
const platform = process.platform
|
|
12
|
-
const arch = process.arch
|
|
13
|
-
|
|
14
|
-
return platform === 'win32' && arch === 'x64'
|
|
15
|
-
}
|
|
16
|
-
|
|
17
9
|
if (options) {
|
|
18
10
|
if (options.executionProviders != null) {
|
|
19
11
|
let executionProviders = options.executionProviders.filter(provider => {
|
|
@@ -54,6 +46,13 @@ export function makeOnnxLikeFloat32Tensor(onnxTensor: Onnx.Tensor): OnnxLikeFloa
|
|
|
54
46
|
}
|
|
55
47
|
}
|
|
56
48
|
|
|
49
|
+
export function dmlProviderAvailable() {
|
|
50
|
+
const platform = process.platform
|
|
51
|
+
const arch = process.arch
|
|
52
|
+
|
|
53
|
+
return platform === 'win32' && arch === 'x64'
|
|
54
|
+
}
|
|
55
|
+
|
|
57
56
|
export interface OnnxLikeFloat32Tensor {
|
|
58
57
|
readonly data: Float32Array
|
|
59
58
|
readonly dims: number[]
|
|
@@ -157,6 +157,9 @@ const packageVersionTagResolutionLookup: { [packageName: string]: string } = {
|
|
|
157
157
|
'mdxnet-UVR_MDXNET_2_9682': '20240330',
|
|
158
158
|
'mdxnet-UVR_MDXNET_3_9662': '20240330',
|
|
159
159
|
'mdxnet-UVR_MDXNET_KARA': '20240330',
|
|
160
|
+
'mdxnet-UVR_MDXNET_Main': '20241008',
|
|
161
|
+
'mdxnet-Kim_Vocal_1': '20241008',
|
|
162
|
+
'mdxnet-Kim_Vocal_2': '20241008',
|
|
160
163
|
|
|
161
164
|
// whisper.cpp models
|
|
162
165
|
'whisper.cpp-tiny': '20240405',
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
export function includesAnyOf(str: string, substrings: string[]) {
|
|
2
|
+
return indexOfAnyOf(str, substrings) >= 0
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function indexOfAnyOf(str: string, substrings: string[]) {
|
|
6
|
+
for (const substring of substrings) {
|
|
7
|
+
const index = str.indexOf(substring)
|
|
8
|
+
|
|
9
|
+
if (index >= 0) {
|
|
10
|
+
return index
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return -1
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function startsWithAnyOf(str: string, prefixes: string[]) {
|
|
18
|
+
for (const prefix of prefixes) {
|
|
19
|
+
if (str.startsWith(prefix)) {
|
|
20
|
+
return true
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function formatHMS(timeHMS: { hours: number, minutes: number, seconds: number, milliseconds: number }, decimalSeparator = '.') {
|
|
28
|
+
return `${formatIntegerWithLeadingZeros(timeHMS.hours, 2)}:${formatIntegerWithLeadingZeros(timeHMS.minutes, 2)}:${formatIntegerWithLeadingZeros(timeHMS.seconds, 2)}${decimalSeparator}${formatIntegerWithLeadingZeros(timeHMS.milliseconds, 3)}`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function formatMS(timeMS: { minutes: number, seconds: number, milliseconds: number }, decimalSeparator = '.') {
|
|
32
|
+
return `${formatIntegerWithLeadingZeros(timeMS.minutes, 2)}:${formatIntegerWithLeadingZeros(timeMS.seconds, 2)}${decimalSeparator}${formatIntegerWithLeadingZeros(timeMS.milliseconds, 3)}`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function formatIntegerWithLeadingZeros(num: number, minDigitCount: number) {
|
|
36
|
+
num = Math.floor(num)
|
|
37
|
+
|
|
38
|
+
let numAsString = `${num}`
|
|
39
|
+
|
|
40
|
+
while (numAsString.length < minDigitCount) {
|
|
41
|
+
numAsString = `0${numAsString}`
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return numAsString
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function formatListWithQuotedElements(strings: string[], quoteSymbol = `'`) {
|
|
48
|
+
return strings.map(str => `${quoteSymbol}${str}${quoteSymbol}`).join(', ')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getUTF32Chars(str: string) {
|
|
52
|
+
const utf32chars: string[] = []
|
|
53
|
+
const mapping: number[] = []
|
|
54
|
+
|
|
55
|
+
let utf32Index = 0
|
|
56
|
+
|
|
57
|
+
for (const utf32char of str) {
|
|
58
|
+
utf32chars.push(utf32char)
|
|
59
|
+
|
|
60
|
+
for (let i = 0; i < utf32char.length; i++) {
|
|
61
|
+
mapping.push(utf32Index)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
utf32Index += 1
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
mapping.push(utf32Index)
|
|
68
|
+
|
|
69
|
+
return { utf32chars, mapping }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function containsInvalidCodepoint(str: string) {
|
|
73
|
+
for (const char of str) {
|
|
74
|
+
if (char.codePointAt(0) === 65533) {
|
|
75
|
+
return true
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
export function splitAndPreserveSeparators(text: string, separatorRegex: RegExp): string[] {
|
|
84
|
+
if (!separatorRegex.flags.includes('g')) {
|
|
85
|
+
throw new Error('RegExp must be global')
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Use the match method to find all matches for the separators
|
|
89
|
+
const matches = text.match(separatorRegex)
|
|
90
|
+
|
|
91
|
+
// If no matches are found, return the original text as a single element array
|
|
92
|
+
if (!matches) {
|
|
93
|
+
return [text]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Initialize the result array
|
|
97
|
+
const result: string[] = []
|
|
98
|
+
|
|
99
|
+
// Initialize the start position
|
|
100
|
+
let lastIndex = 0
|
|
101
|
+
|
|
102
|
+
// Iterate through the matches
|
|
103
|
+
matches.forEach(match => {
|
|
104
|
+
// Get the index of the current match
|
|
105
|
+
const matchIndex = text.indexOf(match, lastIndex)
|
|
106
|
+
|
|
107
|
+
// Add the substring before the match to the result, joined with the match itself
|
|
108
|
+
result.push(text.substring(lastIndex, matchIndex) + match)
|
|
109
|
+
|
|
110
|
+
// Update the last index to the end of the current match
|
|
111
|
+
lastIndex = matchIndex + match.length
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
// Add the remaining substring after the last match to the result
|
|
115
|
+
{
|
|
116
|
+
const remainingText = text.substring(lastIndex)
|
|
117
|
+
|
|
118
|
+
if (remainingText.length > 0) {
|
|
119
|
+
result.push(remainingText)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return result
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function getTokenRepetitionScore(tokens: string[] | number[]) {
|
|
127
|
+
const maxCycleLength = Math.floor(tokens.length / 2)
|
|
128
|
+
|
|
129
|
+
const matchLengthForCycleLength: number[] = [0]
|
|
130
|
+
|
|
131
|
+
for (let cycleLength = 1; cycleLength <= maxCycleLength; cycleLength++) {
|
|
132
|
+
let matchCount = 0
|
|
133
|
+
|
|
134
|
+
for (let leftIndex = cycleLength; leftIndex < tokens.length; leftIndex++) {
|
|
135
|
+
const referenceIndex = leftIndex - cycleLength
|
|
136
|
+
|
|
137
|
+
if (tokens[leftIndex] !== tokens[referenceIndex]) {
|
|
138
|
+
break
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
matchCount += 1
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const score = matchCount
|
|
145
|
+
|
|
146
|
+
matchLengthForCycleLength.push(score)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
let longestMatch = -Infinity
|
|
150
|
+
let longestCycleRepetition = -Infinity
|
|
151
|
+
|
|
152
|
+
for (let i = 1; i <= matchLengthForCycleLength.length; i++) {
|
|
153
|
+
const matchLength = matchLengthForCycleLength[i]
|
|
154
|
+
|
|
155
|
+
if (matchLength > longestMatch) {
|
|
156
|
+
longestMatch = matchLength
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const cycleCount = (matchLength / i) + 1
|
|
160
|
+
|
|
161
|
+
if (cycleCount > longestCycleRepetition) {
|
|
162
|
+
longestCycleRepetition = cycleCount
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return { longestMatch, longestCycleRepetition }
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export async function convertHtmlToText(html: string) {
|
|
170
|
+
const { htmlToText } = await import('html-to-text')
|
|
171
|
+
|
|
172
|
+
const text = htmlToText(html, {
|
|
173
|
+
wordwrap: false,
|
|
174
|
+
|
|
175
|
+
selectors: [
|
|
176
|
+
{ selector: 'a', options: { ignoreHref: true } },
|
|
177
|
+
{ selector: 'img', format: 'skip' },
|
|
178
|
+
{ selector: 'h1', options: { uppercase: false } },
|
|
179
|
+
{ selector: 'h2', options: { uppercase: false } },
|
|
180
|
+
{ selector: 'h3', options: { uppercase: false } },
|
|
181
|
+
{ selector: 'h4', options: { uppercase: false } },
|
|
182
|
+
{ selector: 'table', options: { uppercaseHeaderCells: false } }
|
|
183
|
+
]
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
return text || ''
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export function substituteCharactersUsingLookup(text: string, substitutionLookup: Record<string, string>) {
|
|
190
|
+
let resultText = ''
|
|
191
|
+
|
|
192
|
+
for (const char of text) {
|
|
193
|
+
const substitution = substitutionLookup[char]
|
|
194
|
+
|
|
195
|
+
if (substitution !== undefined) {
|
|
196
|
+
resultText += substitution
|
|
197
|
+
} else {
|
|
198
|
+
resultText += char
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return resultText
|
|
203
|
+
}
|
|
@@ -1,28 +1,11 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
import { createTarball } from './Compression.js'
|
|
3
|
-
import { ensureDir,
|
|
4
|
-
import { ensureAndGetPackagesDir } from './PackageManager.js'
|
|
3
|
+
import { ensureDir, move, readdir, stat } from './FileSystem.js'
|
|
5
4
|
import { appName } from '../api/Common.js'
|
|
6
5
|
import { getRandomHexString } from './Utilities.js'
|
|
7
6
|
import { getAppTempDir } from './PathUtilities.js'
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export async function makeTarballsForInstalledPackages(skipIfExists = false) {
|
|
12
|
-
const packagesDir = await ensureAndGetPackagesDir()
|
|
13
|
-
const packageList = await readdir(packagesDir)
|
|
14
|
-
|
|
15
|
-
for (const packageName of packageList) {
|
|
16
|
-
if (skipIfExists && existsSync(path.join(tarballDir, `${packageName}.tar.gz`))) {
|
|
17
|
-
continue
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const packagePath = path.join(packagesDir, packageName)
|
|
21
|
-
await createNamedTarball(packagePath, packageName)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export async function createNamedTarball(inputPath: string, name: string) {
|
|
8
|
+
export async function createNamedTarball(inputPath: string, name: string, tarballDir: string) {
|
|
26
9
|
const tempDir = getAppTempDir(appName)
|
|
27
10
|
await ensureDir(tempDir)
|
|
28
11
|
const tempFilename = path.join(tempDir, getRandomHexString(16))
|
|
@@ -34,7 +17,7 @@ export async function createNamedTarball(inputPath: string, name: string) {
|
|
|
34
17
|
await move(tempFilename, targetFilname)
|
|
35
18
|
}
|
|
36
19
|
|
|
37
|
-
export async function createTarballForEachDirIn(baseDir: string, namePrefix:
|
|
20
|
+
export async function createTarballForEachDirIn(baseDir: string, namePrefix: string, tarballDir: string) {
|
|
38
21
|
for (const dirName of await readdir(baseDir)) {
|
|
39
22
|
const dirPath = path.join(baseDir, dirName)
|
|
40
23
|
|
|
@@ -46,11 +29,11 @@ export async function createTarballForEachDirIn(baseDir: string, namePrefix: Str
|
|
|
46
29
|
|
|
47
30
|
const archiveName = `${namePrefix}-${dirName}`
|
|
48
31
|
|
|
49
|
-
await createNamedTarball(dirPath, archiveName)
|
|
32
|
+
await createNamedTarball(dirPath, archiveName, tarballDir)
|
|
50
33
|
}
|
|
51
34
|
}
|
|
52
35
|
|
|
53
|
-
export async function createTarballForEachFileIn(baseDir: string, namePrefix:
|
|
36
|
+
export async function createTarballForEachFileIn(baseDir: string, namePrefix: string, tarballDir: string) {
|
|
54
37
|
for (const filename of await readdir(baseDir)) {
|
|
55
38
|
const filenameWithoutExtension = path.parse(filename).name
|
|
56
39
|
|
|
@@ -64,6 +47,6 @@ export async function createTarballForEachFileIn(baseDir: string, namePrefix: St
|
|
|
64
47
|
|
|
65
48
|
const archiveName = `${namePrefix}-${filenameWithoutExtension}`
|
|
66
49
|
|
|
67
|
-
await createNamedTarball(filePath, archiveName)
|
|
50
|
+
await createNamedTarball(filePath, archiveName, tarballDir)
|
|
68
51
|
}
|
|
69
52
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ParagraphBreakType, WhitespaceProcessing } from '../api/Common.js'
|
|
2
2
|
import { applyWhitespaceProcessing, isWord, isWordOrSymbolWord, splitToParagraphs, splitToSentences, splitToWords } from '../nlp/Segmentation.js'
|
|
3
3
|
import { deepClone } from './ObjectUtilities.js'
|
|
4
|
-
import { getUTF32Chars,
|
|
4
|
+
import { getUTF32Chars, splitAndPreserveSeparators } from './StringUtilities.js'
|
|
5
|
+
import { roundToDigits } from './Utilities.js'
|
|
5
6
|
|
|
6
7
|
export function addTimeOffsetToTimeline(targetTimeline: Timeline, timeOffset: number) {
|
|
7
8
|
if (!targetTimeline) {
|