echogarden 1.4.4 → 1.6.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.
Files changed (240) hide show
  1. package/data/schemas/options.json +310 -25
  2. package/dist/alignment/DTWMfccSequenceAlignment.d.ts +1 -1
  3. package/dist/alignment/DTWMfccSequenceAlignment.js +5 -5
  4. package/dist/alignment/DTWSequenceAlignmentWindowed.js +1 -3
  5. package/dist/alignment/DTWSequenceAlignmentWindowed.js.map +1 -1
  6. package/dist/alignment/{TextAlignment.d.ts → SemanticTextAlignment.d.ts} +4 -2
  7. package/dist/alignment/SemanticTextAlignment.js +336 -0
  8. package/dist/alignment/SemanticTextAlignment.js.map +1 -0
  9. package/dist/alignment/SpeechAlignment.d.ts +4 -3
  10. package/dist/alignment/SpeechAlignment.js +130 -39
  11. package/dist/alignment/SpeechAlignment.js.map +1 -1
  12. package/dist/api/API.d.ts +7 -3
  13. package/dist/api/API.js +7 -2
  14. package/dist/api/API.js.map +1 -1
  15. package/dist/api/APIOptions.d.ts +4 -1
  16. package/dist/api/Alignment.d.ts +1 -1
  17. package/dist/api/Alignment.js +13 -5
  18. package/dist/api/Alignment.js.map +1 -1
  19. package/dist/api/LanguageDetectionCommon.d.ts +6 -0
  20. package/dist/api/LanguageDetectionCommon.js +2 -0
  21. package/dist/api/LanguageDetectionCommon.js.map +1 -0
  22. package/dist/api/Recognition.js.map +1 -1
  23. package/dist/api/{LanguageDetection.d.ts → SpeechLanguageDetection.d.ts} +1 -25
  24. package/dist/api/{LanguageDetection.js → SpeechLanguageDetection.js} +1 -68
  25. package/dist/api/SpeechLanguageDetection.js.map +1 -0
  26. package/dist/api/{Translation.js → SpeechTranslation.js} +3 -3
  27. package/dist/api/SpeechTranslation.js.map +1 -0
  28. package/dist/api/Synthesis.d.ts +0 -1
  29. package/dist/api/Synthesis.js +4 -4
  30. package/dist/api/TextLanguageDetection.d.ts +21 -0
  31. package/dist/api/TextLanguageDetection.js +67 -0
  32. package/dist/api/TextLanguageDetection.js.map +1 -0
  33. package/dist/api/TextTranslation.d.ts +25 -0
  34. package/dist/api/TextTranslation.js +101 -0
  35. package/dist/api/TextTranslation.js.map +1 -0
  36. package/dist/api/TimelineTranslationAlignment.d.ts +23 -0
  37. package/dist/api/TimelineTranslationAlignment.js +92 -0
  38. package/dist/api/TimelineTranslationAlignment.js.map +1 -0
  39. package/dist/api/TranscriptAndTranslationAlignment.d.ts +35 -0
  40. package/dist/api/TranscriptAndTranslationAlignment.js +78 -0
  41. package/dist/api/TranscriptAndTranslationAlignment.js.map +1 -0
  42. package/dist/api/TranslationAlignment.d.ts +4 -3
  43. package/dist/api/TranslationAlignment.js +9 -8
  44. package/dist/api/TranslationAlignment.js.map +1 -1
  45. package/dist/api/VoiceActivityDetection.js +16 -1
  46. package/dist/api/VoiceActivityDetection.js.map +1 -1
  47. package/dist/audio/AudioBufferConversion.d.ts +0 -1
  48. package/dist/audio/AudioPlayer.d.ts +0 -1
  49. package/dist/audio/AudioPlayer.js +62 -41
  50. package/dist/audio/AudioPlayer.js.map +1 -1
  51. package/dist/audio/AudioUtilities.d.ts +0 -1
  52. package/dist/cli/CLI.d.ts +28 -7
  53. package/dist/cli/CLI.js +265 -37
  54. package/dist/cli/CLI.js.map +1 -1
  55. package/dist/codecs/FFMpegTranscoder.d.ts +0 -1
  56. package/dist/codecs/FFMpegTranscoder.js +7 -0
  57. package/dist/codecs/FFMpegTranscoder.js.map +1 -1
  58. package/dist/codecs/TIMITCodec.d.ts +0 -1
  59. package/dist/codecs/WaveCodec.d.ts +0 -1
  60. package/dist/dsp/FFT.d.ts +1 -1
  61. package/dist/dsp/FFT.js +6 -0
  62. package/dist/dsp/FFT.js.map +1 -1
  63. package/dist/dsp/KWeightingFilter.js +1 -1
  64. package/dist/dsp/KWeightingFilter.js.map +1 -1
  65. package/dist/dsp/MelSpectogram.d.ts +3 -2
  66. package/dist/dsp/MelSpectogram.js +14 -8
  67. package/dist/dsp/MelSpectogram.js.map +1 -1
  68. package/dist/math/VectorMath.d.ts +9 -9
  69. package/dist/math/VectorMath.js +10 -10
  70. package/dist/math/VectorMath.js.map +1 -1
  71. package/dist/nlp/ChineseSegmentation.js +4 -4
  72. package/dist/nlp/ChineseSegmentation.js.map +1 -1
  73. package/dist/nlp/Segmentation.d.ts +2 -2
  74. package/dist/nlp/Segmentation.js +20 -13
  75. package/dist/nlp/Segmentation.js.map +1 -1
  76. package/dist/recognition/OpenAICloudSTT.d.ts +2 -1
  77. package/dist/recognition/OpenAICloudSTT.js +30 -19
  78. package/dist/recognition/OpenAICloudSTT.js.map +1 -1
  79. package/dist/recognition/SileroSTT.d.ts +0 -1
  80. package/dist/recognition/WhisperCppSTT.d.ts +3 -3
  81. package/dist/recognition/WhisperCppSTT.js +21 -9
  82. package/dist/recognition/WhisperCppSTT.js.map +1 -1
  83. package/dist/recognition/WhisperSTT.d.ts +9 -6
  84. package/dist/recognition/WhisperSTT.js +227 -46
  85. package/dist/recognition/WhisperSTT.js.map +1 -1
  86. package/dist/server/Client.d.ts +3 -4
  87. package/dist/server/Client.js.map +1 -1
  88. package/dist/server/Worker.d.ts +3 -3
  89. package/dist/server/Worker.js +3 -2
  90. package/dist/server/Worker.js.map +1 -1
  91. package/dist/source-separation/MDXNetSourceSeparation.d.ts +0 -1
  92. package/dist/source-separation/MDXNetSourceSeparation.js +1 -1
  93. package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
  94. package/dist/speech-embeddings/WavToVec2BertFeatureEmbeddings.d.ts +12 -0
  95. package/dist/speech-embeddings/WavToVec2BertFeatureEmbeddings.js +68 -0
  96. package/dist/speech-embeddings/WavToVec2BertFeatureEmbeddings.js.map +1 -0
  97. package/dist/speech-language-detection/SileroLanguageDetection.d.ts +1 -2
  98. package/dist/speech-language-detection/SileroLanguageDetection.js +1 -1
  99. package/dist/speech-language-detection/SileroLanguageDetection.js.map +1 -1
  100. package/dist/subtitles/Subtitles.js +2 -2
  101. package/dist/subtitles/Subtitles.js.map +1 -1
  102. package/dist/synthesis/GoogleCloudTTS.d.ts +0 -1
  103. package/dist/synthesis/GoogleTranslateTTS.d.ts +0 -1
  104. package/dist/synthesis/GoogleTranslateTTS.js +6 -21
  105. package/dist/synthesis/GoogleTranslateTTS.js.map +1 -1
  106. package/dist/synthesis/StreamlabsPollyTTS.d.ts +0 -1
  107. package/dist/synthesis/VitsTTS.d.ts +0 -1
  108. package/dist/synthesis/VitsTTS.js +30 -0
  109. package/dist/synthesis/VitsTTS.js.map +1 -1
  110. package/dist/tests/Test.js +0 -31
  111. package/dist/tests/Test.js.map +1 -1
  112. package/dist/text-language-detection/FastTextLanguageDetection.d.ts +1 -1
  113. package/dist/text-language-detection/FastTextLanguageDetection.js.map +1 -1
  114. package/dist/text-language-detection/TinyLDLanguageDetection.d.ts +1 -1
  115. package/dist/text-language-detection/TinyLDLanguageDetection.js.map +1 -1
  116. package/dist/text-translation/DeepLTextTranslation.d.ts +2 -0
  117. package/dist/text-translation/DeepLTextTranslation.js +67 -0
  118. package/dist/text-translation/DeepLTextTranslation.js.map +1 -0
  119. package/dist/text-translation/GoogleTranslateTextTranslation.d.ts +10 -0
  120. package/dist/text-translation/GoogleTranslateTextTranslation.js +554 -0
  121. package/dist/text-translation/GoogleTranslateTextTranslation.js.map +1 -0
  122. package/dist/text-translation/NLLBTextTranslation.d.ts +2 -1
  123. package/dist/text-translation/NLLBTextTranslation.js +249 -19
  124. package/dist/text-translation/NLLBTextTranslation.js.map +1 -1
  125. package/dist/utilities/BinaryArrayConversion.d.ts +0 -1
  126. package/dist/utilities/BrowserRequestHeaders.d.ts +6 -0
  127. package/dist/utilities/BrowserRequestHeaders.js +52 -0
  128. package/dist/utilities/BrowserRequestHeaders.js.map +1 -0
  129. package/dist/utilities/BufferFileReadStream.d.ts +20 -0
  130. package/dist/utilities/BufferFileReadStream.js +81 -0
  131. package/dist/utilities/BufferFileReadStream.js.map +1 -0
  132. package/dist/utilities/DynamicUint8Array.d.ts +9 -0
  133. package/dist/utilities/DynamicUint8Array.js +31 -0
  134. package/dist/utilities/DynamicUint8Array.js.map +1 -0
  135. package/dist/utilities/FileSystem.d.ts +0 -2
  136. package/dist/utilities/Hashing.d.ts +3 -10
  137. package/dist/utilities/Hashing.js +10 -127
  138. package/dist/utilities/Hashing.js.map +1 -1
  139. package/dist/utilities/LEB128.d.ts +15 -5
  140. package/dist/utilities/LEB128.js +199 -119
  141. package/dist/utilities/LEB128.js.map +1 -1
  142. package/dist/utilities/LPVarInt.d.ts +11 -0
  143. package/dist/utilities/LPVarInt.js +187 -0
  144. package/dist/utilities/LPVarInt.js.map +1 -0
  145. package/dist/utilities/Locale.d.ts +1 -1
  146. package/dist/utilities/Locale.js +1 -1
  147. package/dist/utilities/OnnxUtilities.d.ts +1 -2
  148. package/dist/utilities/PVarInt.d.ts +4 -0
  149. package/dist/utilities/PVarInt.js +166 -0
  150. package/dist/utilities/PVarInt.js.map +1 -0
  151. package/dist/utilities/PackageManager.js +48 -25
  152. package/dist/utilities/PackageManager.js.map +1 -1
  153. package/dist/utilities/RandomGenerator.d.ts +3 -17
  154. package/dist/utilities/RandomGenerator.js +12 -81
  155. package/dist/utilities/RandomGenerator.js.map +1 -1
  156. package/dist/utilities/Timeline.d.ts +2 -0
  157. package/dist/utilities/Timeline.js +129 -20
  158. package/dist/utilities/Timeline.js.map +1 -1
  159. package/dist/utilities/Utilities.d.ts +1 -3
  160. package/dist/utilities/Utilities.js +30 -3
  161. package/dist/utilities/Utilities.js.map +1 -1
  162. package/dist/utilities/VarInt.d.ts +4 -0
  163. package/dist/utilities/VarInt.js +166 -0
  164. package/dist/utilities/VarInt.js.map +1 -0
  165. package/dist/utilities/VirtualFileReadStream.d.ts +20 -0
  166. package/dist/utilities/VirtualFileReadStream.js +79 -0
  167. package/dist/utilities/VirtualFileReadStream.js.map +1 -0
  168. package/dist/utilities/WebReader.js +7 -23
  169. package/dist/utilities/WebReader.js.map +1 -1
  170. package/dist/voice-activity-detection/SileroVAD.d.ts +0 -1
  171. package/docs/API.md +105 -3
  172. package/docs/CLI.md +51 -1
  173. package/docs/Engines.md +32 -3
  174. package/docs/Options.md +53 -12
  175. package/docs/Tasklist.md +1 -13
  176. package/package.json +20 -24
  177. package/src/alignment/DTWMfccSequenceAlignment.ts +5 -5
  178. package/src/alignment/DTWSequenceAlignmentWindowed.ts +1 -3
  179. package/src/alignment/SemanticTextAlignment.ts +467 -0
  180. package/src/alignment/SpeechAlignment.ts +214 -56
  181. package/src/api/API.ts +18 -2
  182. package/src/api/APIOptions.ts +14 -1
  183. package/src/api/Alignment.ts +31 -9
  184. package/src/api/LanguageDetectionCommon.ts +7 -0
  185. package/src/api/Recognition.ts +2 -0
  186. package/src/api/{LanguageDetection.ts → SpeechLanguageDetection.ts} +1 -119
  187. package/src/api/{Translation.ts → SpeechTranslation.ts} +2 -2
  188. package/src/api/Synthesis.ts +4 -4
  189. package/src/api/TextLanguageDetection.ts +116 -0
  190. package/src/api/TextTranslation.ts +177 -0
  191. package/src/api/TimelineTranslationAlignment.ts +162 -0
  192. package/src/api/TranscriptAndTranslationAlignment.ts +164 -0
  193. package/src/api/TranslationAlignment.ts +12 -10
  194. package/src/api/VoiceActivityDetection.ts +24 -3
  195. package/src/audio/AudioPlayer.ts +2 -0
  196. package/src/cli/CLI.ts +376 -40
  197. package/src/codecs/FFMpegTranscoder.ts +6 -0
  198. package/src/dsp/FFT.ts +8 -2
  199. package/src/dsp/KWeightingFilter.ts +1 -1
  200. package/src/dsp/MelSpectogram.ts +17 -8
  201. package/src/math/VectorMath.ts +15 -15
  202. package/src/nlp/ChineseSegmentation.ts +6 -4
  203. package/src/nlp/Segmentation.ts +18 -13
  204. package/src/recognition/OpenAICloudSTT.ts +47 -29
  205. package/src/recognition/WhisperCppSTT.ts +26 -11
  206. package/src/recognition/WhisperSTT.ts +364 -49
  207. package/src/server/Client.ts +3 -2
  208. package/src/server/Worker.ts +3 -2
  209. package/src/source-separation/MDXNetSourceSeparation.ts +1 -1
  210. package/src/speech-embeddings/WavToVec2BertFeatureEmbeddings.ts +107 -0
  211. package/src/speech-language-detection/SileroLanguageDetection.ts +2 -1
  212. package/src/subtitles/Subtitles.ts +2 -2
  213. package/src/synthesis/GoogleTranslateTTS.ts +7 -21
  214. package/src/synthesis/VitsTTS.ts +31 -3
  215. package/src/tests/Test.ts +1 -38
  216. package/src/text-language-detection/FastTextLanguageDetection.ts +1 -1
  217. package/src/text-language-detection/TinyLDLanguageDetection.ts +1 -1
  218. package/src/text-translation/DeepLTextTranslation.ts +88 -0
  219. package/src/text-translation/GoogleTranslateTextTranslation.ts +667 -0
  220. package/src/text-translation/NLLBTextTranslation.ts +261 -21
  221. package/src/typings/Fillers.d.ts +25 -2
  222. package/src/utilities/BrowserRequestHeaders.ts +59 -0
  223. package/src/utilities/DynamicUint8Array.ts +39 -0
  224. package/src/utilities/Hashing.ts +14 -167
  225. package/src/utilities/LEB128.ts +273 -148
  226. package/src/utilities/LPVarInt.ts +292 -0
  227. package/src/utilities/Locale.ts +1 -1
  228. package/src/utilities/OnnxUtilities.ts +1 -1
  229. package/src/utilities/PackageManager.ts +51 -30
  230. package/src/utilities/RandomGenerator.ts +12 -113
  231. package/src/utilities/Timeline.ts +162 -23
  232. package/src/utilities/Utilities.ts +40 -3
  233. package/src/utilities/VirtualFileReadStream.ts +109 -0
  234. package/src/utilities/WebReader.ts +9 -23
  235. package/dist/alignment/TextAlignment.js +0 -156
  236. package/dist/alignment/TextAlignment.js.map +0 -1
  237. package/dist/api/LanguageDetection.js.map +0 -1
  238. package/dist/api/Translation.js.map +0 -1
  239. package/src/alignment/TextAlignment.ts +0 -234
  240. /package/dist/api/{Translation.d.ts → SpeechTranslation.d.ts} +0 -0
@@ -15,7 +15,7 @@ import { loadLexiconsForLanguage } from '../nlp/Lexicon.js'
15
15
  import * as API from './API.js'
16
16
  import { Timeline, TimelineEntry, addTimeOffsetToTimeline, multiplyTimelineByFactor } from '../utilities/Timeline.js'
17
17
  import { getAppDataDir, ensureDir, existsSync, isFileIsUpToDate, readAndParseJsonFile, writeFileSafe } from '../utilities/FileSystem.js'
18
- import { formatLanguageCodeWithName, getShortLanguageCode, normalizeLanguageCode, defaultDialectForLanguageCode, parseLangIdentifier, normalizeIdentifierToLangaugeCode } from '../utilities/Locale.js'
18
+ import { formatLanguageCodeWithName, getShortLanguageCode, normalizeLanguageCode, defaultDialectForLanguageCode, parseLangIdentifier, normalizeIdentifierToLanguageCode } from '../utilities/Locale.js'
19
19
  import { loadPackage } from '../utilities/PackageManager.js'
20
20
  import { EngineMetadata, appName } from './Common.js'
21
21
  import { shouldCancelCurrentTask } from '../server/Worker.js'
@@ -332,7 +332,7 @@ async function synthesizeSegment(text: string, options: SynthesisOptions) {
332
332
  let language: string
333
333
 
334
334
  if (options.language) {
335
- language = await normalizeIdentifierToLangaugeCode(options.language)
335
+ language = await normalizeIdentifierToLanguageCode(options.language)
336
336
  } else {
337
337
  language = selectedVoice.languages[0]
338
338
  }
@@ -1556,7 +1556,7 @@ export async function requestVoiceList(options: VoiceListRequestOptions): Promis
1556
1556
  voiceList = await loadVoiceList()
1557
1557
  }
1558
1558
 
1559
- const languageCode = await normalizeIdentifierToLangaugeCode(options.language || '')
1559
+ const languageCode = await normalizeIdentifierToLanguageCode(options.language || '')
1560
1560
 
1561
1561
  if (languageCode) {
1562
1562
  let filteredVoiceList = voiceList.filter(voice => voice.languages.includes(languageCode))
@@ -1619,7 +1619,7 @@ export interface RequestVoiceListResult {
1619
1619
  }
1620
1620
 
1621
1621
  export async function selectBestOfflineEngineForLanguage(language: string): Promise<SynthesisEngine> {
1622
- language = await normalizeIdentifierToLangaugeCode(language)
1622
+ language = await normalizeIdentifierToLanguageCode(language)
1623
1623
 
1624
1624
  const VitsTTS = await import('../synthesis/VitsTTS.js')
1625
1625
 
@@ -0,0 +1,116 @@
1
+ import { extendDeep } from '../utilities/ObjectUtilities.js'
2
+
3
+ import { Logger } from '../utilities/Logger.js'
4
+
5
+ import * as API from './API.js'
6
+ import { logToStderr } from '../utilities/Utilities.js'
7
+ import { languageCodeToName } from '../utilities/Locale.js'
8
+ import { LanguageDetectionResults } from './LanguageDetectionCommon.js'
9
+
10
+ const log = logToStderr
11
+
12
+ export async function detectTextLanguage(input: string, options: TextLanguageDetectionOptions): Promise<TextLanguageDetectionResult> {
13
+ const logger = new Logger()
14
+
15
+ options = extendDeep(defaultTextLanguageDetectionOptions, options)
16
+
17
+ const defaultLanguage = options.defaultLanguage!
18
+ const fallbackThresholdProbability = options.fallbackThresholdProbability!
19
+
20
+ let detectedLanguageProbabilities: LanguageDetectionResults
21
+
22
+ logger.start(`Initialize ${options.engine} module`)
23
+
24
+ switch (options.engine) {
25
+ case 'tinyld': {
26
+ const { detectLanguage } = await import('../text-language-detection/TinyLDLanguageDetection.js')
27
+
28
+ logger.start('Detect text language using tinyld')
29
+
30
+ detectedLanguageProbabilities = await detectLanguage(input)
31
+
32
+ break
33
+ }
34
+
35
+ case 'fasttext': {
36
+ const { detectLanguage } = await import('../text-language-detection/FastTextLanguageDetection.js')
37
+
38
+ logger.start('Detect text language using FastText')
39
+
40
+ detectedLanguageProbabilities = await detectLanguage(input)
41
+
42
+ break
43
+ }
44
+
45
+ default: {
46
+ throw new Error(`Engine '${options.engine}' is not supported`)
47
+ }
48
+ }
49
+
50
+ let detectedLanguage: string
51
+
52
+ if (detectedLanguageProbabilities.length == 0 ||
53
+ detectedLanguageProbabilities[0].probability < fallbackThresholdProbability) {
54
+
55
+ detectedLanguage = defaultLanguage
56
+ } else {
57
+ detectedLanguage = detectedLanguageProbabilities[0].language
58
+ }
59
+
60
+ logger.end()
61
+
62
+ return {
63
+ detectedLanguage,
64
+ detectedLanguageName: languageCodeToName(detectedLanguage),
65
+ detectedLanguageProbabilities
66
+ }
67
+ }
68
+
69
+ /////////////////////////////////////////////////////////////////////////////////////////////
70
+ // Types
71
+ /////////////////////////////////////////////////////////////////////////////////////////////
72
+
73
+ export interface TextLanguageDetectionResult {
74
+ detectedLanguage: string
75
+ detectedLanguageName: string
76
+ detectedLanguageProbabilities: LanguageDetectionResults
77
+ }
78
+
79
+ export type LanguageDetectionGroupResults = LanguageDetectionGroupResultsEntry[]
80
+ export interface LanguageDetectionGroupResultsEntry {
81
+ languageGroup: string
82
+ probability: number
83
+ }
84
+
85
+ export type TextLanguageDetectionEngine = 'tinyld' | 'fasttext'
86
+
87
+ export interface TextLanguageDetectionOptions {
88
+ engine?: TextLanguageDetectionEngine
89
+ defaultLanguage?: string
90
+ fallbackThresholdProbability?: number
91
+ }
92
+
93
+ /////////////////////////////////////////////////////////////////////////////////////////////
94
+ // Constants
95
+ /////////////////////////////////////////////////////////////////////////////////////////////
96
+
97
+ export const defaultTextLanguageDetectionOptions: TextLanguageDetectionOptions = {
98
+ engine: 'tinyld',
99
+ defaultLanguage: 'en',
100
+ fallbackThresholdProbability: 0.05,
101
+ }
102
+
103
+ export const textLanguageDetectionEngines: API.EngineMetadata[] = [
104
+ {
105
+ id: 'tinyld',
106
+ name: 'TinyLD',
107
+ description: 'A simple language detection library.',
108
+ type: 'local'
109
+ },
110
+ {
111
+ id: 'fasttext',
112
+ name: 'FastText',
113
+ description: 'A library for word representations and sentence classification by Facebook research.',
114
+ type: 'local'
115
+ },
116
+ ]
@@ -0,0 +1,177 @@
1
+ import chalk from 'chalk'
2
+ import { formatLanguageCodeWithName, normalizeIdentifierToLanguageCode, parseLangIdentifier } from '../utilities/Locale.js'
3
+ import { Logger } from '../utilities/Logger.js'
4
+ import { extendDeep } from '../utilities/ObjectUtilities.js'
5
+ import * as API from './API.js'
6
+
7
+ export async function translateText(inputText: string, options: TextTranslationOptions): Promise<TextTranslationResult> {
8
+ const logger = new Logger()
9
+
10
+ const startTimestamp = logger.getTimestamp()
11
+
12
+ options = extendDeep(defaultTextTranslationOptions, options)
13
+
14
+ if (options.sourceLanguage) {
15
+ const languageData = await parseLangIdentifier(options.sourceLanguage)
16
+
17
+ options.sourceLanguage = languageData.Name
18
+
19
+ logger.end()
20
+ logger.logTitledMessage('Source language specified', formatLanguageCodeWithName(options.sourceLanguage))
21
+ } else {
22
+ logger.start('No source language specified. Detect text language')
23
+ const { detectedLanguage } = await API.detectTextLanguage(inputText, options.languageDetection || {})
24
+
25
+ options.sourceLanguage = detectedLanguage
26
+
27
+ logger.end()
28
+ logger.logTitledMessage('Source language detected', formatLanguageCodeWithName(detectedLanguage))
29
+ }
30
+
31
+ options.targetLanguage = await normalizeIdentifierToLanguageCode(options.targetLanguage!)
32
+
33
+ logger.logTitledMessage('Target language', formatLanguageCodeWithName(options.targetLanguage))
34
+
35
+ logger.start(`Load ${options.engine} module`)
36
+
37
+ let translationPairs: TranslationPair[]
38
+
39
+ switch (options.engine) {
40
+ case 'nllb': {
41
+ const NLLBTextTranslation = await import('../text-translation/NLLBTextTranslation.js')
42
+
43
+ logger.end()
44
+
45
+ logger.logTitledMessage(`Warning`, `The nllb engine is currently an early prototype implementation and doesn't work correctly.`, chalk.yellow, 'warning')
46
+
47
+ translationPairs = await NLLBTextTranslation.translateText(inputText, options.sourceLanguage, options.targetLanguage)
48
+
49
+ break
50
+ }
51
+
52
+ case 'google-translate': {
53
+ const GoogleTranslateTextTranslation = await import('../text-translation/GoogleTranslateTextTranslation.js')
54
+
55
+ logger.end()
56
+
57
+ translationPairs = await GoogleTranslateTextTranslation.translateText(inputText, options.sourceLanguage, options.targetLanguage)
58
+
59
+ break
60
+ }
61
+
62
+ case 'deepl': {
63
+ const DeepLTextTranslation = await import('../text-translation/DeepLTextTranslation.js')
64
+
65
+ logger.end()
66
+
67
+ logger.logTitledMessage(`Warning`, `The deepl engine is currently an early prototype implementation and doesn't work correctly.`, chalk.yellow, 'warning')
68
+
69
+ translationPairs = await DeepLTextTranslation.translateText(inputText, options.sourceLanguage, options.targetLanguage)
70
+
71
+ break
72
+ }
73
+
74
+ default: {
75
+ throw new Error(`'${options.engine}' is not a supported text translation engine.`)
76
+ }
77
+ }
78
+
79
+ const translatedText = translationPairs.map(pair => {
80
+ const translated = pair.translatedText
81
+
82
+ if (translated.endsWith(' ') || translated.endsWith('\n')) {
83
+ return pair.translatedText
84
+ } else {
85
+ return pair.translatedText + ' '
86
+ }
87
+ }).join('').trim()
88
+
89
+ logger.end()
90
+
91
+ logger.log('')
92
+ logger.logDuration(`Total text translation time`, startTimestamp, chalk.magentaBright)
93
+
94
+ return {
95
+ text: inputText,
96
+ translatedText,
97
+
98
+ translationPairs,
99
+
100
+ sourceLanguage: options.sourceLanguage!,
101
+ targetLanguage: options.targetLanguage!,
102
+ }
103
+ }
104
+
105
+ export interface TextTranslationOptions {
106
+ engine?: TextTranslationEngine
107
+
108
+ sourceLanguage?: string
109
+ targetLanguage?: string
110
+
111
+ languageDetection?: API.TextLanguageDetectionOptions
112
+
113
+ nllb?: {
114
+ },
115
+
116
+ googleTranslate?: {
117
+ },
118
+
119
+ deepl?: {
120
+ },
121
+ }
122
+
123
+ export interface TextTranslationResult {
124
+ text: string
125
+ translatedText: string
126
+
127
+ translationPairs: TranslationPair[]
128
+
129
+ sourceLanguage: string
130
+ targetLanguage: string
131
+ }
132
+
133
+ export type TextTranslationEngine = 'nllb' | 'google-translate' | 'deepl'
134
+
135
+ export interface TranslationPair {
136
+ sourceText: string
137
+ translatedText: string
138
+ }
139
+
140
+ export const defaultTextTranslationOptions: TextTranslationOptions = {
141
+ engine: 'google-translate',
142
+
143
+ sourceLanguage: undefined,
144
+ targetLanguage: 'en',
145
+
146
+ languageDetection: undefined,
147
+
148
+ nllb: {
149
+ },
150
+
151
+ googleTranslate: {
152
+ },
153
+
154
+ deepl: {
155
+ },
156
+ }
157
+
158
+ export const textTranslationEngines: API.EngineMetadata[] = [
159
+ {
160
+ id: 'nllb',
161
+ name: 'NLLB',
162
+ description: 'No Language Left Behind (NLLB) is a deep learning machine translation model by Facebook Research (early prototype implementation).',
163
+ type: 'local'
164
+ },
165
+ {
166
+ id: 'google-translate',
167
+ name: 'Google Translate',
168
+ description: 'Unoffical text translation API used by the Google Translate web interface.',
169
+ type: 'cloud'
170
+ },
171
+ {
172
+ id: 'deepl',
173
+ name: 'DeepL',
174
+ description: 'Unoffical text translation API used by the DeepL web interface (early prototype implementation).',
175
+ type: 'cloud'
176
+ },
177
+ ]
@@ -0,0 +1,162 @@
1
+ import chalk from 'chalk'
2
+ import { AudioSourceParam, RawAudio, ensureRawAudio } from '../audio/AudioUtilities.js'
3
+ import { SubtitlesConfig } from '../subtitles/Subtitles.js'
4
+ import { formatLanguageCodeWithName, getShortLanguageCode, parseLangIdentifier } from '../utilities/Locale.js'
5
+ import { Logger } from '../utilities/Logger.js'
6
+ import { extendDeep } from '../utilities/ObjectUtilities.js'
7
+ import { Timeline, addWordTextOffsetsToTimeline, wordTimelineToSegmentSentenceTimeline } from '../utilities/Timeline.js'
8
+ import * as API from './API.js'
9
+
10
+ export async function alignTimelineTranslation(inputTimeline: Timeline, translatedTranscript: string, options: TimelineTranslationAlignmentOptions): Promise<TimelineTranslationAlignmentResult> {
11
+ const logger = new Logger()
12
+
13
+ const startTimestamp = logger.getTimestamp()
14
+
15
+ options = extendDeep(defaultTimelineTranslationAlignmentOptions, options)
16
+
17
+ let rawAudio: RawAudio | undefined
18
+
19
+ if (options.audio) {
20
+ rawAudio = await ensureRawAudio(options.audio)
21
+ }
22
+
23
+ let sourceLanguage = options.sourceLanguage
24
+
25
+ if (options.sourceLanguage) {
26
+ const languageData = await parseLangIdentifier(options.sourceLanguage)
27
+
28
+ sourceLanguage = languageData.Name
29
+
30
+ logger.end()
31
+ logger.logTitledMessage('Source language specified', formatLanguageCodeWithName(sourceLanguage))
32
+ } else {
33
+ logger.start('No source language specified. Detect source language')
34
+
35
+ const timelineText = inputTimeline.map(entry => entry.text).join(' ')
36
+ const { detectedLanguage } = await API.detectTextLanguage(timelineText, options.languageDetection || {})
37
+
38
+ sourceLanguage = detectedLanguage
39
+
40
+ logger.end()
41
+ logger.logTitledMessage('Source language detected', formatLanguageCodeWithName(detectedLanguage))
42
+ }
43
+
44
+ let targetLanguage: string
45
+
46
+ if (options.targetLanguage) {
47
+ const languageData = await parseLangIdentifier(options.targetLanguage)
48
+
49
+ targetLanguage = languageData.Name
50
+
51
+ logger.end()
52
+ logger.logTitledMessage('Target language specified', formatLanguageCodeWithName(targetLanguage))
53
+ } else {
54
+ logger.start('No target language specified. Detect target language')
55
+ const { detectedLanguage } = await API.detectTextLanguage(translatedTranscript, options.languageDetection || {})
56
+
57
+ targetLanguage = detectedLanguage
58
+
59
+ logger.end()
60
+ logger.logTitledMessage('Target language detected', formatLanguageCodeWithName(detectedLanguage))
61
+ }
62
+
63
+ logger.start(`Load ${options.engine} module`)
64
+
65
+ let mappedWordTimeline: Timeline
66
+
67
+ switch (options.engine) {
68
+ case 'e5': {
69
+ const { alignTimelineToTextSemantically, e5SupportedLanguages } = await import('../alignment/SemanticTextAlignment.js')
70
+
71
+ const shortSourceLanguageCode = getShortLanguageCode(sourceLanguage)
72
+ if (!e5SupportedLanguages.includes(shortSourceLanguageCode)) {
73
+ throw new Error(`Source language ${formatLanguageCodeWithName(sourceLanguage)} is not supported by the E5 embedding model.`)
74
+ }
75
+
76
+ const shortTargetLanguageCode = getShortLanguageCode(targetLanguage)
77
+ if (!e5SupportedLanguages.includes(shortTargetLanguageCode)) {
78
+ throw new Error(`Target language ${formatLanguageCodeWithName(targetLanguage)} is not supported by the E5 embedding model.`)
79
+ }
80
+
81
+ logger.end()
82
+
83
+ mappedWordTimeline = await alignTimelineToTextSemantically(
84
+ inputTimeline,
85
+ translatedTranscript,
86
+ targetLanguage)
87
+
88
+ break
89
+ }
90
+
91
+ default: {
92
+ throw new Error(`Unsupported engine: ${options.engine}`)
93
+ }
94
+ }
95
+
96
+ logger.start(`Postprocess timeline`)
97
+
98
+ addWordTextOffsetsToTimeline(mappedWordTimeline, translatedTranscript)
99
+
100
+ const { segmentTimeline: mappedTimeline } = await wordTimelineToSegmentSentenceTimeline(mappedWordTimeline, translatedTranscript, targetLanguage)
101
+
102
+ logger.end()
103
+ logger.logDuration(`Total timeline translation alignment time`, startTimestamp, chalk.magentaBright)
104
+
105
+ logger.end()
106
+
107
+ return {
108
+ timeline: mappedTimeline,
109
+ wordTimeline: mappedWordTimeline,
110
+
111
+ sourceLanguage,
112
+ targetLanguage,
113
+
114
+ rawAudio,
115
+ }
116
+ }
117
+
118
+ // Types
119
+ export interface TimelineTranslationAlignmentResult {
120
+ timeline: Timeline
121
+ wordTimeline: Timeline
122
+
123
+ sourceLanguage?: string
124
+ targetLanguage: string
125
+
126
+ rawAudio?: RawAudio
127
+ }
128
+
129
+ export interface TimelineTranslationAlignmentOptions {
130
+ engine?: 'e5'
131
+
132
+ sourceLanguage?: string
133
+ targetLanguage?: string
134
+
135
+ audio?: AudioSourceParam
136
+
137
+ languageDetection?: API.TextLanguageDetectionOptions
138
+
139
+ subtitles?: SubtitlesConfig
140
+
141
+ e5?: {
142
+ model: 'small-fp16'
143
+ }
144
+ }
145
+
146
+ // Constants
147
+ const defaultTimelineTranslationAlignmentOptions: TimelineTranslationAlignmentOptions = {
148
+ engine: 'e5',
149
+
150
+ sourceLanguage: undefined,
151
+ targetLanguage: undefined,
152
+
153
+ audio: undefined,
154
+
155
+ languageDetection: undefined,
156
+
157
+ subtitles: undefined,
158
+
159
+ e5: {
160
+ model: 'small-fp16',
161
+ }
162
+ }
@@ -0,0 +1,164 @@
1
+ import { extendDeep } from '../utilities/ObjectUtilities.js'
2
+
3
+ import { logToStderr } from '../utilities/Utilities.js'
4
+ import { AudioSourceParam, RawAudio } from '../audio/AudioUtilities.js'
5
+ import { Logger } from '../utilities/Logger.js'
6
+
7
+ import * as API from './API.js'
8
+ import { Timeline } from '../utilities/Timeline.js'
9
+ import chalk from 'chalk'
10
+ import { type SubtitlesConfig } from '../subtitles/Subtitles.js'
11
+
12
+ const log = logToStderr
13
+
14
+ export async function alignTranscriptAndTranslation(input: AudioSourceParam, transcript: string, translatedTranscript: string, options: TranscriptAndTranslationAlignmentOptions): Promise<TranscriptAndTranslationAlignmentResult> {
15
+ const logger = new Logger()
16
+
17
+ const startTimestamp = logger.getTimestamp()
18
+
19
+ options = extendDeep(defaultTranscriptAndTranslationAlignmentOptions, options)
20
+
21
+ if (options.sourceLanguage && !options.alignment?.language) {
22
+ options.alignment = extendDeep(options.alignment || {}, { language: options.sourceLanguage })
23
+ }
24
+
25
+ if (options.targetLanguage && !options.timelineAlignment?.targetLanguage) {
26
+ options.timelineAlignment = extendDeep(options.timelineAlignment || {}, { targetLanguage: options.targetLanguage })
27
+ }
28
+
29
+ let alignmentResult: API.AlignmentResult
30
+ let timelineAlignmentResult: API.TimelineTranslationAlignmentResult
31
+
32
+ switch (options.engine) {
33
+ case 'two-stage': {
34
+ logger.logTitledMessage(`Start stage 1`, `Align speech to transcript`, chalk.magentaBright)
35
+ logger.end()
36
+
37
+ alignmentResult = await API.align(input, transcript, options.alignment || {})
38
+
39
+ logger.log(``)
40
+ logger.logTitledMessage(`Start stage 2`, `Align timeline to translated transcript`, chalk.magentaBright)
41
+ logger.end()
42
+
43
+ timelineAlignmentResult = await API.alignTimelineTranslation(alignmentResult.timeline, translatedTranscript, options.timelineAlignment || {})
44
+
45
+ break
46
+ }
47
+
48
+ default: {
49
+ throw new Error(`Engine '${options.engine}' is not supported`)
50
+ }
51
+ }
52
+
53
+ logger.end()
54
+
55
+ logger.log(``)
56
+ logger.logDuration(`Total transcript and translation alignment time`, startTimestamp, chalk.magentaBright)
57
+
58
+ return {
59
+ timeline: alignmentResult.timeline,
60
+ wordTimeline: alignmentResult.wordTimeline,
61
+
62
+ translatedTimeline: timelineAlignmentResult.timeline,
63
+ translatedWordTimeline: timelineAlignmentResult.wordTimeline,
64
+
65
+ transcript,
66
+ translatedTranscript,
67
+
68
+ sourceLanguage: alignmentResult.language,
69
+ targetLanguage: timelineAlignmentResult.targetLanguage,
70
+
71
+ inputRawAudio: alignmentResult.inputRawAudio,
72
+ isolatedRawAudio: alignmentResult.isolatedRawAudio,
73
+ backgroundRawAudio: alignmentResult.backgroundRawAudio,
74
+ }
75
+ }
76
+
77
+ export interface TranscriptAndTranslationAlignmentResult {
78
+ timeline: Timeline
79
+ wordTimeline: Timeline
80
+
81
+ translatedTimeline: Timeline
82
+ translatedWordTimeline: Timeline
83
+
84
+ transcript: string
85
+ translatedTranscript: string
86
+
87
+ sourceLanguage: string
88
+ targetLanguage: string
89
+
90
+ inputRawAudio: RawAudio
91
+ isolatedRawAudio?: RawAudio
92
+ backgroundRawAudio?: RawAudio
93
+ }
94
+
95
+ export type TranscriptAndTranslationAlignmentEngine = 'two-stage'
96
+
97
+ export interface TranscriptAndTranslationAlignmentOptions {
98
+ engine?: TranscriptAndTranslationAlignmentEngine
99
+
100
+ sourceLanguage?: string
101
+ targetLanguage?: string
102
+
103
+ isolate?: boolean
104
+
105
+ crop?: boolean
106
+
107
+ alignment?: API.AlignmentOptions
108
+
109
+ timelineAlignment?: API.TimelineTranslationAlignmentOptions
110
+
111
+ languageDetection?: API.TextLanguageDetectionOptions
112
+
113
+ vad?: API.VADOptions
114
+
115
+ plainText?: API.PlainTextOptions
116
+
117
+ subtitles?: SubtitlesConfig
118
+
119
+ sourceSeparation?: API.SourceSeparationOptions
120
+ }
121
+
122
+ export const defaultTranscriptAndTranslationAlignmentOptions: TranscriptAndTranslationAlignmentOptions = {
123
+ engine: 'two-stage',
124
+
125
+ sourceLanguage: undefined,
126
+ targetLanguage: undefined,
127
+
128
+ isolate: false,
129
+
130
+ crop: true,
131
+
132
+ alignment: {
133
+ },
134
+
135
+ timelineAlignment: {
136
+ },
137
+
138
+ languageDetection: {
139
+ },
140
+
141
+ plainText: {
142
+ paragraphBreaks: 'double',
143
+ whitespace: 'collapse'
144
+ },
145
+
146
+ subtitles: {
147
+ },
148
+
149
+ vad: {
150
+ engine: 'adaptive-gate'
151
+ },
152
+
153
+ sourceSeparation: {
154
+ },
155
+ }
156
+
157
+ export const TranscriptAndTranslationAlignmentEngines: API.EngineMetadata[] = [
158
+ {
159
+ id: 'two-stage',
160
+ name: 'Two-stage translation alignment',
161
+ description: 'Applies two-stage translation alignment to the spoken audio. First stage aligns the speech to the native language transcript. Second stage aligns the resulting timeline with the translated transcript.',
162
+ type: 'local'
163
+ }
164
+ ]