echogarden 2.5.0 → 2.5.2

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.
@@ -1,11 +1,16 @@
1
1
  import { getShortLanguageCode } from '../utilities/Locale.js'
2
2
  import { substituteCharactersUsingLookup } from '../utilities/StringUtilities.js'
3
3
 
4
- export function getNormalizedFragmentsForSpeech(words: string[], language: string) {
4
+ export function getNormalizedFragmentsForSpeech(
5
+ words: string[],
6
+ nonWhitespaceWords: string[],
7
+ nonWhitespaceWordOriginalIndex: number[],
8
+ language: string) {
9
+
5
10
  language = getShortLanguageCode(language)
6
11
 
7
12
  if (language != 'en') {
8
- return { normalizedFragments: [...words], referenceFragments: [...words] }
13
+ return { normalizedFragments: [...nonWhitespaceWords], referenceFragments: [...nonWhitespaceWords] }
9
14
  }
10
15
 
11
16
  const numberPattern = /^[0-9][0-9\,\.]*$/
@@ -41,73 +46,79 @@ export function getNormalizedFragmentsForSpeech(words: string[], language: strin
41
46
  const normalizedFragments: string[] = []
42
47
  const referenceFragments: string[] = []
43
48
 
44
- for (let wordIndex = 0; wordIndex < words.length; wordIndex++) {
45
- const word = words[wordIndex]
49
+ for (let wordIndex = 0; wordIndex < nonWhitespaceWords.length; wordIndex++) {
50
+ const word = nonWhitespaceWords[wordIndex]
46
51
  const lowerCaseWord = word.toLowerCase()
47
52
 
48
- const nextWords = words.slice(wordIndex + 1)
49
- const nextWord = nextWords[0]
53
+ const nextNonWhitespaceWords = nonWhitespaceWords.slice(wordIndex + 1)
54
+ const nextNonWhitespaceWord = nextNonWhitespaceWords[0]
55
+
56
+ const originalWordIndex = nonWhitespaceWordOriginalIndex[wordIndex]
57
+ const isFollowedByWhitespace = words[originalWordIndex + 1]?.trim().length === 0
50
58
 
51
59
  if ( // Normalize a four digit year pattern, e.g. 'in 1995'.
52
60
  wordsPrecedingAYear.includes(lowerCaseWord) &&
53
- fourDigitYearPattern.test(nextWord)) {
61
+ isFollowedByWhitespace &&
62
+ fourDigitYearPattern.test(nextNonWhitespaceWord)) {
54
63
 
55
- const normalizedString = normalizeFourDigitYearString(nextWord)
64
+ const normalizedString = normalizeFourDigitYearString(nextNonWhitespaceWord)
56
65
 
57
66
  normalizedFragments.push(word)
58
67
  referenceFragments.push(word)
59
68
 
60
69
  normalizedFragments.push(normalizedString)
61
- referenceFragments.push(nextWord)
70
+ referenceFragments.push(nextNonWhitespaceWord)
62
71
 
63
72
  wordIndex += 1
64
73
  } else if ( // Normalize a four digit decade pattern, e.g. 'the 1980s'.
65
74
  wordsPrecedingADecade.includes(lowerCaseWord) &&
66
- fourDigitDecadePattern.test(nextWord)) {
75
+ isFollowedByWhitespace &&
76
+ fourDigitDecadePattern.test(nextNonWhitespaceWord)) {
67
77
 
68
- const normalizedString = normalizeFourDigitDecadeString(nextWord)
78
+ const normalizedString = normalizeFourDigitDecadeString(nextNonWhitespaceWord)
69
79
 
70
80
  normalizedFragments.push(word)
71
81
  referenceFragments.push(word)
72
82
 
73
83
  normalizedFragments.push(normalizedString)
74
- referenceFragments.push(nextWord)
84
+ referenceFragments.push(nextNonWhitespaceWord)
75
85
 
76
86
  wordIndex += 1
77
- } else if ( // Normalize a year range pattern, e.g. '1835-1896'
78
- fourDigitYearRangePattern.test(words.slice(wordIndex, wordIndex + 3).join(''))) {
87
+ } else if ( // Normalize a year range pattern, e.g. '1835-1896', ensure there are no spaces between words
88
+ fourDigitYearRangePattern.test(words.slice(originalWordIndex, originalWordIndex + 3).join(''))) {
79
89
 
80
- normalizedFragments.push(normalizeFourDigitYearString(words[wordIndex]))
81
- referenceFragments.push(words[wordIndex])
90
+ normalizedFragments.push(normalizeFourDigitYearString(nonWhitespaceWords[wordIndex]))
91
+ referenceFragments.push(nonWhitespaceWords[wordIndex])
82
92
 
83
93
  normalizedFragments.push('to')
84
- referenceFragments.push(words[wordIndex + 1])
94
+ referenceFragments.push(nonWhitespaceWords[wordIndex + 1])
85
95
 
86
- normalizedFragments.push(normalizeFourDigitYearString(words[wordIndex + 2]))
87
- referenceFragments.push(words[wordIndex + 2])
96
+ normalizedFragments.push(normalizeFourDigitYearString(nonWhitespaceWords[wordIndex + 2]))
97
+ referenceFragments.push(nonWhitespaceWords[wordIndex + 2])
88
98
 
89
99
  wordIndex += 2
90
100
  } else if ( // Normalize a currency pattern, e.g. '$53.1 million', '€3.53'
91
101
  symbolsPrecedingACurrency.includes(lowerCaseWord) &&
92
- numberPattern.test(nextWord)) {
102
+ !isFollowedByWhitespace &&
103
+ numberPattern.test(nextNonWhitespaceWord)) {
93
104
 
94
105
  let currencyWord = symbolsPrecedingACurrencyAsWords[symbolsPrecedingACurrency.indexOf(lowerCaseWord)]
95
106
 
96
- if (wordsSucceedingACurrency.includes(nextWords[1].toLowerCase())) {
97
- const normalizedString = `${nextWord} ${nextWords[1]} ${currencyWord}`
107
+ if (wordsSucceedingACurrency.includes(nextNonWhitespaceWords[1]?.toLowerCase())) {
108
+ const normalizedString = `${nextNonWhitespaceWord} ${nextNonWhitespaceWords[1]} ${currencyWord}`
98
109
 
99
110
  normalizedFragments.push(normalizedString)
100
111
 
101
- const referenceString = `${word}${nextWord} ${nextWords[1]}`
112
+ const referenceString = `${word}${nextNonWhitespaceWord} ${nextNonWhitespaceWords[1]}`
102
113
  referenceFragments.push(referenceString)
103
114
 
104
115
  wordIndex += 2
105
116
  } else {
106
- const normalizedString = `${nextWord} ${currencyWord}`
117
+ const normalizedString = `${nextNonWhitespaceWord} ${currencyWord}`
107
118
 
108
119
  normalizedFragments.push(normalizedString)
109
120
 
110
- const referenceString = `${word}${nextWord}`
121
+ const referenceString = `${word}${nextNonWhitespaceWord}`
111
122
  referenceFragments.push(referenceString)
112
123
 
113
124
  wordIndex += 1
@@ -40,30 +40,45 @@ export async function preprocessAndSynthesize(text: string, language: string, es
40
40
  let words = await splitToWords(text, language)
41
41
 
42
42
  // Merge repeating non-words to a single word to work around eSpeak bug
43
- const wordsWithMerges: string[] = []
43
+ {
44
+ const wordsWithMerges: string[] = []
44
45
 
45
- for (let i = 0; i < words.length; i++) {
46
- const currentWord = words[i]
47
- const previousWord = words[i - 1]
46
+ for (let i = 0; i < words.length; i++) {
47
+ const currentWord = words[i]
48
+ const previousWord = words[i - 1]
48
49
 
49
- if (
50
- i > 0 &&
51
- currentWord === previousWord &&
52
- !['[', ']'].includes(currentWord) && // Work around eSpeak-NG marker bug with repeating squared brackets
53
- !wordCharacterPattern.test(currentWord)) {
50
+ if (
51
+ i > 0 &&
52
+ currentWord === previousWord &&
53
+ !['[', ']'].includes(currentWord) && // Work around eSpeak-NG marker bug with repeating squared brackets
54
+ !wordCharacterPattern.test(currentWord)) {
54
55
 
55
- wordsWithMerges[wordsWithMerges.length - 1] += currentWord
56
- } else {
57
- wordsWithMerges.push(currentWord)
56
+ wordsWithMerges[wordsWithMerges.length - 1] += currentWord
57
+ } else {
58
+ wordsWithMerges.push(currentWord)
59
+ }
58
60
  }
61
+
62
+ words = wordsWithMerges
59
63
  }
60
64
 
61
- words = wordsWithMerges
65
+ // Remove words containing only whitespace
66
+ const nonWhitespaceWords: string[] = []
67
+ const nonWhitespaceWordsOriginalIndex: number[] = []
62
68
 
63
- // Trim words and remove words containing only whitespace
64
- words = words.map(word => word.trim()).filter(word => word !== '')
69
+ {
70
+ for (let i = 0; i < words.length; i++) {
71
+ const word = words[i]
72
+ const wordIsWhitespace = word.trim().length === 0
73
+
74
+ if (!wordIsWhitespace) {
75
+ nonWhitespaceWords.push(word)
76
+ nonWhitespaceWordsOriginalIndex.push(i)
77
+ }
78
+ }
79
+ }
65
80
 
66
- const { normalizedFragments, referenceFragments } = getNormalizedFragmentsForSpeech(words, language)
81
+ const { normalizedFragments, referenceFragments } = getNormalizedFragmentsForSpeech(words, nonWhitespaceWords, nonWhitespaceWordsOriginalIndex, language)
67
82
 
68
83
  const simplifiedFragments = normalizedFragments.map(word => simplifyPunctuationCharacters(word).toLocaleLowerCase())
69
84