echogarden 3.0.5 → 3.2.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/lexicons/heteronyms.en.json +2 -2
- package/data/lexicons/words.en.json +120 -0
- package/dist/alignment/SemanticTextAlignment.js +2 -2
- package/dist/alignment/SemanticTextAlignment.js.map +1 -1
- package/dist/api/Alignment.js +2 -2
- package/dist/api/Alignment.js.map +1 -1
- package/dist/api/Synthesis.js +2 -2
- package/dist/api/Synthesis.js.map +1 -1
- package/dist/encodings/Ascii.d.ts +1 -3
- package/dist/encodings/Ascii.d.ts.map +1 -1
- package/dist/encodings/Ascii.js +13 -9
- package/dist/encodings/Ascii.js.map +1 -1
- package/dist/encodings/Base64.d.ts.map +1 -1
- package/dist/encodings/Base64.js +9 -0
- package/dist/encodings/Base64.js.map +1 -1
- package/dist/encodings/Hex.d.ts.map +1 -1
- package/dist/encodings/Hex.js +11 -2
- package/dist/encodings/Hex.js.map +1 -1
- package/dist/encodings/LEB128.d.ts +1 -15
- package/dist/encodings/LEB128.d.ts.map +1 -1
- package/dist/encodings/LEB128.js +1 -247
- package/dist/encodings/LEB128.js.map +1 -1
- package/dist/encodings/Utf16.d.ts +1 -3
- package/dist/encodings/Utf16.d.ts.map +1 -1
- package/dist/encodings/Utf16.js +13 -9
- package/dist/encodings/Utf16.js.map +1 -1
- package/dist/encodings/Utf32.d.ts.map +1 -1
- package/dist/encodings/Utf32.js +6 -0
- package/dist/encodings/Utf32.js.map +1 -1
- package/dist/encodings/Utf8.d.ts +9 -5
- package/dist/encodings/Utf8.d.ts.map +1 -1
- package/dist/encodings/Utf8.js +36 -78
- package/dist/encodings/Utf8.js.map +1 -1
- package/dist/nlp/Segmentation.d.ts +2 -8
- package/dist/nlp/Segmentation.d.ts.map +1 -1
- package/dist/nlp/Segmentation.js +42 -19
- package/dist/nlp/Segmentation.js.map +1 -1
- package/dist/nlp/TextNormalizer.d.ts.map +1 -1
- package/dist/nlp/TextNormalizer.js +29 -14
- package/dist/nlp/TextNormalizer.js.map +1 -1
- package/dist/recognition/AmazonTranscribeSTT.js +3 -3
- package/dist/recognition/AmazonTranscribeSTT.js.map +1 -1
- package/dist/synthesis/AzureCognitiveServicesTTS.js +1 -1
- package/dist/synthesis/AzureCognitiveServicesTTS.js.map +1 -1
- package/dist/synthesis/EspeakTTS.d.ts.map +1 -1
- package/dist/synthesis/EspeakTTS.js +15 -8
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/dist/synthesis/KokoroTTS.d.ts.map +1 -1
- package/dist/synthesis/KokoroTTS.js +0 -5
- package/dist/synthesis/KokoroTTS.js.map +1 -1
- package/dist/synthesis/MicrosoftEdgeTTS.js +1 -1
- package/dist/synthesis/MicrosoftEdgeTTS.js.map +1 -1
- package/dist/synthesis/VitsTTS.d.ts.map +1 -1
- package/dist/synthesis/VitsTTS.js +0 -5
- package/dist/synthesis/VitsTTS.js.map +1 -1
- package/dist/utilities/FileSystem.d.ts +12 -7
- package/dist/utilities/FileSystem.d.ts.map +1 -1
- package/dist/utilities/FileSystem.js +196 -79
- package/dist/utilities/FileSystem.js.map +1 -1
- package/dist/utilities/FileWriter.d.ts +1 -0
- package/dist/utilities/FileWriter.d.ts.map +1 -1
- package/dist/utilities/FileWriter.js +8 -1
- package/dist/utilities/FileWriter.js.map +1 -1
- package/dist/utilities/ObjectUtilities.d.ts.map +1 -1
- package/dist/utilities/ObjectUtilities.js +15 -13
- package/dist/utilities/ObjectUtilities.js.map +1 -1
- package/dist/utilities/PackageManager.js +2 -2
- package/dist/utilities/PackageManager.js.map +1 -1
- package/dist/utilities/PathUtilities.d.ts +1 -0
- package/dist/utilities/PathUtilities.d.ts.map +1 -1
- package/dist/utilities/PathUtilities.js +18 -0
- package/dist/utilities/PathUtilities.js.map +1 -1
- package/dist/utilities/StringUtilities.d.ts.map +1 -1
- package/dist/utilities/StringUtilities.js.map +1 -1
- package/dist/utilities/Timeline.js +2 -2
- package/dist/utilities/Timeline.js.map +1 -1
- package/dist/utilities/WikipediaReader.js +5 -5
- package/dist/utilities/WikipediaReader.js.map +1 -1
- package/package.json +13 -12
- package/src/alignment/SemanticTextAlignment.ts +2 -2
- package/src/api/Alignment.ts +2 -2
- package/src/api/Synthesis.ts +2 -2
- package/src/encodings/Ascii.ts +14 -10
- package/src/encodings/Base64.ts +9 -0
- package/src/encodings/Hex.ts +11 -2
- package/src/encodings/Utf16.ts +14 -10
- package/src/encodings/Utf32.ts +6 -0
- package/src/encodings/Utf8.ts +45 -82
- package/src/nlp/Segmentation.ts +53 -19
- package/src/nlp/TextNormalizer.ts +40 -16
- package/src/recognition/AmazonTranscribeSTT.ts +3 -3
- package/src/synthesis/AzureCognitiveServicesTTS.ts +1 -1
- package/src/synthesis/EspeakTTS.ts +17 -9
- package/src/synthesis/KokoroTTS.ts +0 -6
- package/src/synthesis/MicrosoftEdgeTTS.ts +1 -1
- package/src/synthesis/VitsTTS.ts +0 -6
- package/src/utilities/FileSystem.ts +224 -85
- package/src/utilities/FileWriter.ts +11 -1
- package/src/utilities/ObjectUtilities.ts +19 -15
- package/src/utilities/PackageManager.ts +2 -2
- package/src/utilities/PathUtilities.ts +19 -0
- package/src/utilities/StringUtilities.ts +0 -2
- package/src/utilities/Timeline.ts +2 -2
- package/src/utilities/WikipediaReader.ts +5 -5
- package/src/encodings/HtmlEscape.ts +0 -39
- package/src/encodings/LEB128.ts +0 -362
- package/src/utilities/StringBuilder.ts +0 -45
package/src/encodings/Utf8.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { EncodeIntoResult } from
|
|
1
|
+
import { EncodeIntoResult } from './TextEncodingsCommon.js'
|
|
2
2
|
|
|
3
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
4
|
+
// UTF-8 Encoding
|
|
5
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
3
6
|
export function encodeUtf8(text: string) {
|
|
4
7
|
const textEncoder = new TextEncoder()
|
|
5
8
|
|
|
@@ -14,104 +17,64 @@ export function encodeUtf8Into(text: string, outputArray: Uint8Array): EncodeInt
|
|
|
14
17
|
return result
|
|
15
18
|
}
|
|
16
19
|
|
|
17
|
-
export
|
|
18
|
-
|
|
20
|
+
export class ChunkedUtf8Encoder {
|
|
21
|
+
private readonly textEncoder = new TextEncoder()
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
private pendingHighSurrogate = ''
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
writeChunk(stringChunk: string): Uint8Array {
|
|
26
|
+
if (this.pendingHighSurrogate !== '') {
|
|
27
|
+
stringChunk = this.pendingHighSurrogate + stringChunk
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
this.pendingHighSurrogate = ''
|
|
30
|
+
}
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
}
|
|
32
|
+
const lastCodeUnit = stringChunk.charCodeAt(stringChunk.length - 1)
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
private readonly textDecoder = new TextDecoder('utf-8')
|
|
34
|
+
if (lastCodeUnit >= 0xD800 && lastCodeUnit <= 0xDBFF) {
|
|
35
|
+
this.pendingHighSurrogate = stringChunk[stringChunk.length - 1]
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
stringChunk = stringChunk.substring(0, stringChunk.length - 1)
|
|
38
|
+
}
|
|
37
39
|
|
|
38
|
-
this.
|
|
40
|
+
return this.textEncoder.encode(stringChunk)
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
finalize(): Uint8Array {
|
|
44
|
+
const result = this.textEncoder.encode(this.pendingHighSurrogate)
|
|
45
|
+
|
|
46
|
+
this.pendingHighSurrogate = ''
|
|
47
|
+
|
|
48
|
+
return result
|
|
43
49
|
}
|
|
44
50
|
}
|
|
45
51
|
|
|
46
|
-
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
function
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
} else if (charCode <= 0xffff) {
|
|
62
|
-
outputArray[writeOffset++] = 0xe0 | (charCode >>> 12)
|
|
63
|
-
outputArray[writeOffset++] = 0x80 | ((charCode >>> 6) & 63)
|
|
64
|
-
outputArray[writeOffset++] = 0x80 | (charCode & 63)
|
|
65
|
-
} else if (charCode <= 0x10ffff) {
|
|
66
|
-
outputArray[writeOffset++] = 0xf0 | (charCode >>> 18)
|
|
67
|
-
outputArray[writeOffset++] = 0x80 | ((charCode >>> 12) & 63)
|
|
68
|
-
outputArray[writeOffset++] = 0x80 | ((charCode >>> 6) & 63)
|
|
69
|
-
outputArray[writeOffset++] = 0x80 | (charCode & 63)
|
|
70
|
-
|
|
71
|
-
readOffset++
|
|
72
|
-
}
|
|
52
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
53
|
+
// UTF-8 Decoding
|
|
54
|
+
//////////////////////////////////////////////////////////////////////////////
|
|
55
|
+
export function decodeUtf8(utf8Bytes: Uint8Array) {
|
|
56
|
+
const maxChunkLength = 2 ** 24
|
|
57
|
+
|
|
58
|
+
const chunkedUtf8Decoder = new ChunkedUtf8Decoder()
|
|
59
|
+
|
|
60
|
+
let resultString = ''
|
|
61
|
+
|
|
62
|
+
for (let offset = 0; offset < utf8Bytes.length; offset += maxChunkLength) {
|
|
63
|
+
const utf8Chunk = utf8Bytes.subarray(offset, offset + maxChunkLength)
|
|
64
|
+
const stringChunk = chunkedUtf8Decoder.writeChunk(utf8Chunk)
|
|
65
|
+
|
|
66
|
+
resultString += stringChunk
|
|
73
67
|
}
|
|
74
68
|
|
|
75
|
-
return
|
|
69
|
+
return resultString
|
|
76
70
|
}
|
|
77
71
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
let readOffset = 0
|
|
82
|
-
|
|
83
|
-
while (readOffset < utf8Bytes.length) {
|
|
84
|
-
const leadByte = utf8Bytes[readOffset++]
|
|
85
|
-
|
|
86
|
-
let outputCodePoint: number
|
|
87
|
-
|
|
88
|
-
if (leadByte >>> 7 === 0) {
|
|
89
|
-
outputCodePoint = leadByte
|
|
90
|
-
} else if (leadByte >>> 5 === 6) {
|
|
91
|
-
outputCodePoint =
|
|
92
|
-
(leadByte & 31) << 6 |
|
|
93
|
-
(utf8Bytes[readOffset++] & 63)
|
|
94
|
-
} else if (leadByte >>> 4 === 14) {
|
|
95
|
-
outputCodePoint =
|
|
96
|
-
(leadByte & 15) << 12 |
|
|
97
|
-
(utf8Bytes[readOffset++] & 63) << 6 |
|
|
98
|
-
(utf8Bytes[readOffset++] & 63)
|
|
99
|
-
} else if (leadByte >>> 3 === 30) {
|
|
100
|
-
outputCodePoint =
|
|
101
|
-
(leadByte & 7) << 18 |
|
|
102
|
-
(utf8Bytes[readOffset++] & 63) << 12 |
|
|
103
|
-
(utf8Bytes[readOffset++] & 63) << 6 |
|
|
104
|
-
(utf8Bytes[readOffset++] & 63)
|
|
105
|
-
} else {
|
|
106
|
-
throw new Error(`Invalid UTF-8 stream: An invalid lead byte value encountered at position ${readOffset}`)
|
|
107
|
-
}
|
|
72
|
+
export class ChunkedUtf8Decoder {
|
|
73
|
+
private readonly textDecoder = new TextDecoder('utf-8')
|
|
108
74
|
|
|
109
|
-
|
|
110
|
-
|
|
75
|
+
writeChunk(chunk: Uint8Array) {
|
|
76
|
+
const decodedChunk = this.textDecoder.decode(chunk, { stream: true })
|
|
111
77
|
|
|
112
|
-
|
|
113
|
-
throw new Error(`UTF-8 decoding failed. Byte sequence is truncated.`)
|
|
78
|
+
return decodedChunk
|
|
114
79
|
}
|
|
115
|
-
|
|
116
|
-
return decodedString
|
|
117
80
|
}
|
package/src/nlp/Segmentation.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { sumArray, logToStderr } from '../utilities/Utilities.js'
|
|
2
2
|
import { getShortLanguageCode } from '../utilities/Locale.js'
|
|
3
3
|
import { ParagraphBreakType, WhitespaceProcessing } from '../api/Common.js'
|
|
4
|
-
import {
|
|
4
|
+
import { splitAndPreserveSeparators } from '../utilities/StringUtilities.js'
|
|
5
|
+
import { anyOf, buildRegExp, unicodeProperty, oneOrMore, possibly, codepoint, inputStart, inputEnd, whitespace } from 'regexp-composer'
|
|
5
6
|
|
|
6
7
|
import * as TextSegmentation from '@echogarden/text-segmentation'
|
|
7
8
|
import { splitChineseTextToWords_Jieba } from './ChineseSegmentation.js'
|
|
@@ -9,50 +10,81 @@ import { splitJapaneseTextToWords_Kuromoji } from './JapaneseSegmentation.js'
|
|
|
9
10
|
|
|
10
11
|
const log = logToStderr
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
const includesWordCharacterPattern = anyOf(unicodeProperty('Letter'), unicodeProperty('Number'))
|
|
14
|
+
const includesWordCharacterRegExp = buildRegExp(includesWordCharacterPattern)
|
|
13
15
|
|
|
14
16
|
// See: https://mathiasbynens.be/notes/es-unicode-property-escapes
|
|
15
|
-
export const emojiSequenceRegExp = /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/u
|
|
17
|
+
//export const emojiSequenceRegExp = /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/u
|
|
18
|
+
const includesEmojiSequencePattern = anyOf(
|
|
19
|
+
[unicodeProperty('Emoji_Modifier_Base'), possibly(unicodeProperty('Emoji_Modifier'))],
|
|
20
|
+
unicodeProperty('Emoji_Presentation'),
|
|
21
|
+
[unicodeProperty('Emoji'), codepoint('FE0F')]
|
|
22
|
+
)
|
|
23
|
+
const includesEmojiSequenceRegExp = buildRegExp(includesEmojiSequencePattern)
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
|
|
25
|
+
const symbolWordsList = [
|
|
26
|
+
'$', '€', '¢', '£', '¥', '©', '®', '™', '%', '&', '#', '~', '@', '+', '±', '÷',
|
|
27
|
+
'/', '\\', '^', '*', '×', '=', '≈', '¼', '½', '¾', '→', '≤', '≥', '∞'
|
|
28
|
+
]
|
|
19
29
|
|
|
20
|
-
|
|
21
|
-
|
|
30
|
+
const includesSymbolWordPattern = anyOf(...symbolWordsList)
|
|
31
|
+
const includesSymbolWordRegExp = buildRegExp(includesSymbolWordPattern)
|
|
32
|
+
|
|
33
|
+
const isAllSymbolWordsPattern = [inputStart, oneOrMore(includesSymbolWordPattern), inputEnd]
|
|
34
|
+
const isAllSymbolWordsRegExp = buildRegExp(isAllSymbolWordsPattern)
|
|
35
|
+
|
|
36
|
+
const includesWordCharacterOrEmojiPattern = anyOf(includesWordCharacterPattern, includesEmojiSequencePattern)
|
|
37
|
+
const includesWordCharacterOrEmojiRegExp = buildRegExp(includesWordCharacterOrEmojiPattern)
|
|
38
|
+
|
|
39
|
+
const includesWordCharacterOrEmojiOrIsAllSymbolWordPattern = anyOf(includesWordCharacterPattern, includesEmojiSequencePattern, isAllSymbolWordsPattern)
|
|
40
|
+
const includesWordCharacterOrEmojiOrIsAllSymbolWordRegExp = buildRegExp(includesWordCharacterOrEmojiOrIsAllSymbolWordPattern)
|
|
41
|
+
|
|
42
|
+
const includesPunctuationPattern = unicodeProperty('Punctuation')
|
|
43
|
+
const includesPunctuationRegExp = buildRegExp(includesPunctuationPattern)
|
|
44
|
+
|
|
45
|
+
const isAllPunctuationPattern = [inputStart, oneOrMore(includesPunctuationPattern), inputEnd]
|
|
46
|
+
const isAllPunctuationRegExp = buildRegExp(isAllPunctuationPattern)
|
|
47
|
+
|
|
48
|
+
const phraseSeparatorsList = [',', '、', ',', '،', ';', ';', ':', ':', '—']
|
|
49
|
+
const includesPhraseSeparatorsPattern = anyOf(...phraseSeparatorsList)
|
|
50
|
+
const includesPhraseSeparatorsRegExp = buildRegExp(includesPhraseSeparatorsPattern)
|
|
51
|
+
|
|
52
|
+
const isAllWhitespacePattern = [inputStart, oneOrMore(whitespace), inputEnd]
|
|
53
|
+
const isAllWhitespaceRegExp = buildRegExp(isAllWhitespacePattern)
|
|
22
54
|
|
|
23
55
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
24
56
|
// Predicates
|
|
25
57
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
26
58
|
export function isWordOrEmojiOrSymbolWord(str: string) {
|
|
27
|
-
return
|
|
59
|
+
return includesWordCharacterOrEmojiOrIsAllSymbolWordRegExp.test(str.trim())
|
|
28
60
|
}
|
|
29
61
|
|
|
30
62
|
export function isWordOrEmoji(str: string) {
|
|
31
|
-
return
|
|
63
|
+
return includesWordCharacterOrEmojiRegExp.test(str.trim())
|
|
32
64
|
}
|
|
33
65
|
|
|
34
66
|
export function isSymbolWord(str: string) {
|
|
35
|
-
return
|
|
67
|
+
return isAllSymbolWordsRegExp.test(str.trim())
|
|
36
68
|
}
|
|
37
69
|
|
|
38
|
-
export function
|
|
39
|
-
return
|
|
70
|
+
export function includesWordCharacter(str: string) {
|
|
71
|
+
return includesWordCharacterRegExp.test(str.trim())
|
|
40
72
|
}
|
|
41
73
|
|
|
42
74
|
export function includesPunctuation(str: string) {
|
|
43
|
-
return includesPunctuationRegExp.test(str
|
|
75
|
+
return includesPunctuationRegExp.test(str.trim())
|
|
44
76
|
}
|
|
45
77
|
|
|
46
78
|
export function isAllPunctuation(str: string) {
|
|
47
|
-
return isAllPunctuationRegExp.test(str
|
|
79
|
+
return isAllPunctuationRegExp.test(str.trim())
|
|
48
80
|
}
|
|
49
81
|
|
|
50
82
|
export function includesEmoji(str: string) {
|
|
51
|
-
return
|
|
83
|
+
return includesEmojiSequenceRegExp.test(str.trim())
|
|
52
84
|
}
|
|
53
85
|
|
|
54
86
|
export function isAllWhitespace(str: string) {
|
|
55
|
-
return
|
|
87
|
+
return isAllWhitespaceRegExp.test(str)
|
|
56
88
|
}
|
|
57
89
|
|
|
58
90
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -280,11 +312,13 @@ export class Word {
|
|
|
280
312
|
this.isSentenceFinalizer = isSentenceFinalizer
|
|
281
313
|
}
|
|
282
314
|
|
|
283
|
-
get containsOnlyPunctuation() { return !
|
|
315
|
+
get containsOnlyPunctuation() { return !isWordOrEmojiOrSymbolWord(this.text) }
|
|
284
316
|
|
|
285
|
-
get isSymbolWord() { return
|
|
317
|
+
get isSymbolWord() { return isSymbolWord(this.text) }
|
|
286
318
|
|
|
287
|
-
get isPhraseSeperator() {
|
|
319
|
+
get isPhraseSeperator() {
|
|
320
|
+
return this.containsOnlyPunctuation && includesPhraseSeparatorsRegExp.test(this.text)
|
|
321
|
+
}
|
|
288
322
|
|
|
289
323
|
get length() { return this.text.length }
|
|
290
324
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getShortLanguageCode } from '../utilities/Locale.js'
|
|
2
2
|
import { substituteCharactersUsingLookup } from '../utilities/StringUtilities.js'
|
|
3
|
-
import { anyOf, buildRegExp, charRange, inputEnd, inputStart, repeated, zeroOrMore } from 'regexp-composer'
|
|
3
|
+
import { anyOf, buildRegExp, charRange, inputEnd, inputStart, oneOrMore, repeated, unicodeProperty, zeroOrMore } from 'regexp-composer'
|
|
4
4
|
|
|
5
5
|
export function getNormalizedFragmentsForSpeech(
|
|
6
6
|
words: string[],
|
|
@@ -25,14 +25,24 @@ export function getNormalizedFragmentsForSpeech(
|
|
|
25
25
|
const nextNonWhitespaceWord = nextNonWhitespaceWords[0]
|
|
26
26
|
|
|
27
27
|
const originalWordIndex = nonWhitespaceWordOriginalIndex[wordIndex]
|
|
28
|
+
|
|
28
29
|
const isFollowedByWhitespace = words[originalWordIndex + 1]?.trim().length === 0
|
|
30
|
+
const isSpecialCharacterBeforeYear = ['(', ',', '©'].includes(words[originalWordIndex])
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
//const isWordPrecedingAYear = wordsPrecedingAYear.includes(lowerCaseWord)
|
|
33
|
+
const isWordPrecedingAYear =
|
|
34
|
+
isAllLettersOrApostropheRegExp.test(lowerCaseWord) || isSpecialCharacterBeforeYear
|
|
35
|
+
|
|
36
|
+
const followedByFourDigitYearPattern = fourDigitYearRegExp.test(nextNonWhitespaceWord)
|
|
33
37
|
|
|
34
|
-
|
|
38
|
+
const isWordPrecedingADecade = wordsPrecedingADecade.includes(lowerCaseWord)
|
|
39
|
+
const followedByFourDigitDecadePattern = fourDigitDecadeRegExp.test(nextNonWhitespaceWord)
|
|
35
40
|
|
|
41
|
+
if (isWordPrecedingAYear &&
|
|
42
|
+
(isFollowedByWhitespace || isSpecialCharacterBeforeYear) &&
|
|
43
|
+
followedByFourDigitYearPattern) {
|
|
44
|
+
|
|
45
|
+
// Normalize a four digit year pattern, e.g. 'in 1995'.
|
|
36
46
|
const normalizedString = normalizeFourDigitYearString(nextNonWhitespaceWord)
|
|
37
47
|
|
|
38
48
|
normalizedFragments.push(word)
|
|
@@ -43,11 +53,11 @@ export function getNormalizedFragmentsForSpeech(
|
|
|
43
53
|
|
|
44
54
|
wordIndex += 1
|
|
45
55
|
} else if (
|
|
46
|
-
|
|
56
|
+
isWordPrecedingADecade &&
|
|
47
57
|
isFollowedByWhitespace &&
|
|
48
|
-
|
|
58
|
+
followedByFourDigitDecadePattern) {
|
|
49
59
|
|
|
50
|
-
|
|
60
|
+
// Normalize a four digit decade pattern, e.g. 'the 1980s'.
|
|
51
61
|
|
|
52
62
|
const normalizedString = normalizeFourDigitDecadeString(nextNonWhitespaceWord)
|
|
53
63
|
|
|
@@ -58,7 +68,7 @@ export function getNormalizedFragmentsForSpeech(
|
|
|
58
68
|
referenceFragments.push(nextNonWhitespaceWord)
|
|
59
69
|
|
|
60
70
|
wordIndex += 1
|
|
61
|
-
} else if (
|
|
71
|
+
} else if (fourDigitYearRangeRegExp.test(words.slice(originalWordIndex, originalWordIndex + 3).join(''))) {
|
|
62
72
|
// Normalize a year range pattern, e.g. '1835-1896', ensure there are no spaces between words
|
|
63
73
|
normalizedFragments.push(normalizeFourDigitYearString(nonWhitespaceWords[wordIndex]))
|
|
64
74
|
referenceFragments.push(nonWhitespaceWords[wordIndex])
|
|
@@ -92,7 +102,7 @@ export function getNormalizedFragmentsForSpeech(
|
|
|
92
102
|
const referenceString = word
|
|
93
103
|
referenceFragments.push(referenceString)
|
|
94
104
|
}
|
|
95
|
-
} else if (
|
|
105
|
+
} else if (followingCurrencyRegExp.test(lowerCaseWord)) {
|
|
96
106
|
const currencyWord = currencySymbolsAsWords[currencySymbols.indexOf(lowerCaseWord[lowerCaseWord.length - 1])]
|
|
97
107
|
|
|
98
108
|
const normalizedString = `${word.substring(0, word.length - 1)} ${currencyWord}`
|
|
@@ -234,14 +244,14 @@ const wordsFollowingACurrency = [
|
|
|
234
244
|
|
|
235
245
|
const arabicNumeralPattern = charRange('0', '9')
|
|
236
246
|
|
|
237
|
-
const
|
|
247
|
+
const isNumberPattern = [
|
|
238
248
|
inputStart,
|
|
239
249
|
arabicNumeralPattern,
|
|
240
250
|
zeroOrMore(anyOf(arabicNumeralPattern, ',', '.')),
|
|
241
251
|
inputEnd
|
|
242
252
|
]
|
|
243
253
|
|
|
244
|
-
const
|
|
254
|
+
const isNumberRegExp = buildRegExp(isNumberPattern)
|
|
245
255
|
|
|
246
256
|
const precedingCurrencyPattern = [
|
|
247
257
|
inputStart,
|
|
@@ -261,13 +271,27 @@ const followingCurrencyPattern = [
|
|
|
261
271
|
inputEnd
|
|
262
272
|
]
|
|
263
273
|
|
|
264
|
-
const
|
|
274
|
+
const followingCurrencyRegExp = buildRegExp(followingCurrencyPattern)
|
|
265
275
|
|
|
266
276
|
const fourDigitYearPattern = [inputStart, repeated(4, arabicNumeralPattern), inputEnd]
|
|
267
|
-
const
|
|
277
|
+
const fourDigitYearRegExp = buildRegExp(fourDigitYearPattern)
|
|
268
278
|
|
|
269
279
|
const fourDigitDecadePattern = [inputStart, repeated(3, arabicNumeralPattern), '0s', inputEnd]
|
|
270
|
-
const
|
|
280
|
+
const fourDigitDecadeRegExp = buildRegExp(fourDigitDecadePattern)
|
|
271
281
|
|
|
272
282
|
const fourDigitYearRangePattern = [inputStart, repeated(4, arabicNumeralPattern), anyOf('-', '–'), repeated(4, arabicNumeralPattern), inputEnd]
|
|
273
|
-
const
|
|
283
|
+
const fourDigitYearRangeRegExp = buildRegExp(fourDigitYearRangePattern)
|
|
284
|
+
|
|
285
|
+
const isAllLettersPattern = [inputStart, oneOrMore(unicodeProperty('Letter')), inputEnd]
|
|
286
|
+
const isAllLettersRegExp = buildRegExp(isAllLettersPattern)
|
|
287
|
+
|
|
288
|
+
const isAllLettersOrApostrophePattern = [
|
|
289
|
+
inputStart,
|
|
290
|
+
|
|
291
|
+
unicodeProperty('Letter'),
|
|
292
|
+
zeroOrMore(anyOf(unicodeProperty('Letter'), `'`)),
|
|
293
|
+
|
|
294
|
+
inputEnd,
|
|
295
|
+
]
|
|
296
|
+
|
|
297
|
+
const isAllLettersOrApostropheRegExp = buildRegExp(isAllLettersOrApostrophePattern)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Item, LanguageCode, StartStreamTranscriptionCommandInput } from '@aws-sdk/client-transcribe-streaming'
|
|
2
|
-
import { wordCharacterRegExp } from '../nlp/Segmentation.js'
|
|
3
1
|
import * as FFMpegTranscoder from '../codecs/FFMpegTranscoder.js'
|
|
2
|
+
import { Item, LanguageCode, StartStreamTranscriptionCommandInput } from '@aws-sdk/client-transcribe-streaming'
|
|
3
|
+
import { isWordOrEmojiOrSymbolWord } from '../nlp/Segmentation.js'
|
|
4
4
|
import { Logger } from '../utilities/Logger.js'
|
|
5
5
|
import { Timeline } from '../utilities/Timeline.js'
|
|
6
6
|
import { RawAudio } from '../audio/AudioUtilities.js'
|
|
@@ -103,7 +103,7 @@ export async function recgonize(rawAudio: RawAudio, languageCode: string, region
|
|
|
103
103
|
for (const event of events) {
|
|
104
104
|
const text = event.Content!
|
|
105
105
|
|
|
106
|
-
if (!
|
|
106
|
+
if (!isWordOrEmojiOrSymbolWord(text)) {
|
|
107
107
|
continue
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -6,7 +6,7 @@ import { Logger } from '../utilities/Logger.js'
|
|
|
6
6
|
import { Timeline } from '../utilities/Timeline.js'
|
|
7
7
|
import { RawAudio, getRawAudioDuration } from '../audio/AudioUtilities.js'
|
|
8
8
|
import { concatUint8Arrays } from '../utilities/Utilities.js'
|
|
9
|
-
import { escapeHtml } from '
|
|
9
|
+
import { escapeHtml } from 'standard-html-escaper'
|
|
10
10
|
import { SynthesisCallbacks } from '../api/Synthesis.js'
|
|
11
11
|
|
|
12
12
|
export async function synthesize(
|
|
@@ -4,15 +4,15 @@ import { Logger } from '../utilities/Logger.js'
|
|
|
4
4
|
import { RawAudio, getEmptyRawAudio } from '../audio/AudioUtilities.js'
|
|
5
5
|
import { getNormalizedFragmentsForSpeech, simplifyPunctuationCharacters } from '../nlp/TextNormalizer.js'
|
|
6
6
|
import { ipaPhoneToKirshenbaum } from '../nlp/PhoneConversion.js'
|
|
7
|
-
import { isAllPunctuation,
|
|
7
|
+
import { isAllPunctuation, isWordOrEmoji, splitToWords, isWordOrEmojiOrSymbolWord } from '../nlp/Segmentation.js'
|
|
8
8
|
import { Lexicon, tryGetFirstLexiconSubstitution } from '../nlp/Lexicon.js'
|
|
9
9
|
import { phonemizeSentence } from '../nlp/EspeakPhonemizer.js'
|
|
10
10
|
import { Timeline, TimelineEntry } from '../utilities/Timeline.js'
|
|
11
11
|
import { extendDeep } from '../utilities/ObjectUtilities.js'
|
|
12
|
-
import { escapeHtml } from '
|
|
12
|
+
import { escapeHtml } from 'standard-html-escaper'
|
|
13
13
|
import * as TextSegmentation from '@echogarden/text-segmentation'
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import { OperationCallbacks, SynthesisCallbacks } from '../api/API.js'
|
|
16
16
|
import { loadPackage } from '../utilities/PackageManager.js'
|
|
17
17
|
|
|
18
18
|
import { wrapEmscriptenModuleHeap } from 'wasm-heap-manager'
|
|
@@ -73,11 +73,14 @@ export async function preprocessAndSynthesize(text: string, language: string, es
|
|
|
73
73
|
for (let i = 0; i < mergedWords.length; i++) {
|
|
74
74
|
const mergedWord = mergedWords[i]
|
|
75
75
|
|
|
76
|
-
// Convert isolated groups of vertical bars and em dashes to a comma
|
|
77
76
|
if (/^[\|│—─–]+$/.test(mergedWord)) {
|
|
77
|
+
// Convert isolated groups of vertical bars or em dashes to a comma
|
|
78
78
|
mergedWords[i] = ','
|
|
79
|
-
} else if (isAllPunctuation(mergedWord)) {
|
|
80
|
-
|
|
79
|
+
} else if (isAllPunctuation(mergedWord)) {
|
|
80
|
+
// Collapse repeated punctuation to up to 3 repetitions,
|
|
81
|
+
// Since otherwise eSpeak may go crazy.
|
|
82
|
+
|
|
83
|
+
mergedWords[i] = mergedWord.substring(0, Math.min(3, mergedWord.length))
|
|
81
84
|
}
|
|
82
85
|
}
|
|
83
86
|
|
|
@@ -102,7 +105,12 @@ export async function preprocessAndSynthesize(text: string, language: string, es
|
|
|
102
105
|
|
|
103
106
|
const { normalizedFragments, referenceFragments } = getNormalizedFragmentsForSpeech(words, nonWhitespaceWords, nonWhitespaceWordsOriginalIndex, language)
|
|
104
107
|
|
|
105
|
-
const simplifiedFragments = normalizedFragments.map(word =>
|
|
108
|
+
const simplifiedFragments = normalizedFragments.map(word => {
|
|
109
|
+
return simplifyPunctuationCharacters(word)
|
|
110
|
+
.toLocaleLowerCase()
|
|
111
|
+
.replaceAll('(', ',')
|
|
112
|
+
.replaceAll(')', ',')
|
|
113
|
+
})
|
|
106
114
|
|
|
107
115
|
if ([`'`].includes(simplifiedFragments[0])) {
|
|
108
116
|
normalizedFragments[0] = `()`
|
|
@@ -150,8 +158,8 @@ export async function preprocessAndSynthesize(text: string, language: string, es
|
|
|
150
158
|
{
|
|
151
159
|
const fragmentWordSequence = new TextSegmentation.WordSequence()
|
|
152
160
|
|
|
153
|
-
for (let fragment of
|
|
154
|
-
fragmentWordSequence.addWord(fragment, 0, !
|
|
161
|
+
for (let fragment of simplifiedFragments) {
|
|
162
|
+
fragmentWordSequence.addWord(fragment, 0, !isWordOrEmojiOrSymbolWord(fragment))
|
|
155
163
|
}
|
|
156
164
|
|
|
157
165
|
const wordEntries = referenceTimeline.flatMap(phraseEntry => phraseEntry.timeline!)
|
|
@@ -72,12 +72,6 @@ export class KokoroTTS {
|
|
|
72
72
|
const voicePrimaryLanguage = voice.languages[0]
|
|
73
73
|
const voicePrimaryLanguageShort = getShortLanguageCode(voicePrimaryLanguage)
|
|
74
74
|
|
|
75
|
-
sentenceText = //simplifyPunctuationCharacters(sentence.trim())
|
|
76
|
-
sentenceText
|
|
77
|
-
.replaceAll('(', ', ')
|
|
78
|
-
.replaceAll(')', ', ')
|
|
79
|
-
.replaceAll('—', ', ')
|
|
80
|
-
|
|
81
75
|
const simplifiedSentenceText = simplifyPunctuationCharacters(sentenceText.trim())
|
|
82
76
|
|
|
83
77
|
const voiceLanguage = voiceEntry.languages[0]
|
|
@@ -8,7 +8,7 @@ import { concatUint8Arrays, getRandomHexString, logToStderr, sha256AsHex } from
|
|
|
8
8
|
import { RawAudio, getEmptyRawAudio, getRawAudioDuration } from '../audio/AudioUtilities.js'
|
|
9
9
|
import { Timer } from '../utilities/Timer.js'
|
|
10
10
|
import { decodeUtf8, encodeUtf8 } from '../encodings/Utf8.js'
|
|
11
|
-
import { escapeHtml } from '
|
|
11
|
+
import { escapeHtml } from 'standard-html-escaper'
|
|
12
12
|
import { requestHttp } from 'easier-http-request'
|
|
13
13
|
import { VoiceListRequestCallbacks, SynthesisCallbacks } from '../api/API.js'
|
|
14
14
|
|
package/src/synthesis/VitsTTS.ts
CHANGED
|
@@ -72,12 +72,6 @@ export class VitsTTS {
|
|
|
72
72
|
|
|
73
73
|
lengthScale *= baseLengthScale
|
|
74
74
|
|
|
75
|
-
sentence = //simplifyPunctuationCharacters(sentence.trim())
|
|
76
|
-
sentence
|
|
77
|
-
.replaceAll('(', ', ')
|
|
78
|
-
.replaceAll(')', ', ')
|
|
79
|
-
.replaceAll('—', ', ')
|
|
80
|
-
|
|
81
75
|
const Espeak = await import('../synthesis/EspeakTTS.js')
|
|
82
76
|
|
|
83
77
|
logger.end()
|