echogarden 2.10.2 → 3.0.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/LICENSE.MIT.md +7 -0
- package/README.md +9 -1
- package/data/lexicons/heteronyms.en.json +44 -10
- package/data/lexicons/words.en.json +726 -22
- package/data/schemas/options.json +91 -153
- package/dist/alignment/DTWMfccSequenceAlignment.js.map +1 -1
- package/dist/alignment/SemanticTextAlignment.d.ts +4 -2
- package/dist/alignment/SemanticTextAlignment.d.ts.map +1 -1
- package/dist/alignment/SemanticTextAlignment.js +7 -7
- package/dist/alignment/SemanticTextAlignment.js.map +1 -1
- package/dist/alignment/SpeechAlignment.d.ts +9 -10
- package/dist/alignment/SpeechAlignment.d.ts.map +1 -1
- package/dist/alignment/SpeechAlignment.js +23 -96
- package/dist/alignment/SpeechAlignment.js.map +1 -1
- package/dist/api/APIOptions.d.ts +1 -1
- package/dist/api/APIOptions.d.ts.map +1 -1
- package/dist/api/Alignment.d.ts +8 -6
- package/dist/api/Alignment.d.ts.map +1 -1
- package/dist/api/Alignment.js +31 -40
- package/dist/api/Alignment.js.map +1 -1
- package/dist/api/Common.d.ts +7 -0
- package/dist/api/Common.d.ts.map +1 -1
- package/dist/api/Common.js.map +1 -1
- package/dist/api/Denoising.d.ts +5 -2
- package/dist/api/Denoising.d.ts.map +1 -1
- package/dist/api/Denoising.js +15 -15
- package/dist/api/Denoising.js.map +1 -1
- package/dist/api/GlobalOptions.d.ts +2 -8
- package/dist/api/GlobalOptions.d.ts.map +1 -1
- package/dist/api/GlobalOptions.js +2 -13
- package/dist/api/GlobalOptions.js.map +1 -1
- package/dist/api/Recognition.d.ts +11 -12
- package/dist/api/Recognition.d.ts.map +1 -1
- package/dist/api/Recognition.js +32 -82
- package/dist/api/Recognition.js.map +1 -1
- package/dist/api/SourceSeparation.d.ts +7 -2
- package/dist/api/SourceSeparation.d.ts.map +1 -1
- package/dist/api/SourceSeparation.js +12 -10
- package/dist/api/SourceSeparation.js.map +1 -1
- package/dist/api/SpeechLanguageDetection.d.ts +11 -7
- package/dist/api/SpeechLanguageDetection.d.ts.map +1 -1
- package/dist/api/SpeechLanguageDetection.js +37 -30
- package/dist/api/SpeechLanguageDetection.js.map +1 -1
- package/dist/api/SpeechSearch.d.ts +4 -1
- package/dist/api/SpeechSearch.d.ts.map +1 -1
- package/dist/api/SpeechSearch.js.map +1 -1
- package/dist/api/SpeechTranslation.d.ts +10 -6
- package/dist/api/SpeechTranslation.d.ts.map +1 -1
- package/dist/api/SpeechTranslation.js +28 -26
- package/dist/api/SpeechTranslation.js.map +1 -1
- package/dist/api/Synthesis.d.ts +13 -8
- package/dist/api/Synthesis.d.ts.map +1 -1
- package/dist/api/Synthesis.js +67 -89
- package/dist/api/Synthesis.js.map +1 -1
- package/dist/api/TextLanguageDetection.d.ts +4 -2
- package/dist/api/TextLanguageDetection.d.ts.map +1 -1
- package/dist/api/TextLanguageDetection.js +4 -7
- package/dist/api/TextLanguageDetection.js.map +1 -1
- package/dist/api/TextTranslation.d.ts +4 -2
- package/dist/api/TextTranslation.d.ts.map +1 -1
- package/dist/api/TextTranslation.js +13 -24
- package/dist/api/TextTranslation.js.map +1 -1
- package/dist/api/TimelineTranslationAlignment.d.ts +6 -3
- package/dist/api/TimelineTranslationAlignment.d.ts.map +1 -1
- package/dist/api/TimelineTranslationAlignment.js +20 -11
- package/dist/api/TimelineTranslationAlignment.js.map +1 -1
- package/dist/api/TranscriptAndTranslationAlignment.d.ts +6 -4
- package/dist/api/TranscriptAndTranslationAlignment.d.ts.map +1 -1
- package/dist/api/TranscriptAndTranslationAlignment.js +11 -12
- package/dist/api/TranscriptAndTranslationAlignment.js.map +1 -1
- package/dist/api/TranslationAlignment.d.ts +6 -4
- package/dist/api/TranslationAlignment.d.ts.map +1 -1
- package/dist/api/TranslationAlignment.js +20 -21
- package/dist/api/TranslationAlignment.js.map +1 -1
- package/dist/api/VoiceActivityDetection.d.ts +9 -8
- package/dist/api/VoiceActivityDetection.d.ts.map +1 -1
- package/dist/api/VoiceActivityDetection.js +20 -43
- package/dist/api/VoiceActivityDetection.js.map +1 -1
- package/dist/audio/AudioBufferConversion.js.map +1 -1
- package/dist/audio/AudioPlayer.d.ts +1 -3
- package/dist/audio/AudioPlayer.d.ts.map +1 -1
- package/dist/audio/AudioPlayer.js +3 -188
- package/dist/audio/AudioPlayer.js.map +1 -1
- package/dist/audio/AudioUtilities.d.ts +2 -1
- package/dist/audio/AudioUtilities.d.ts.map +1 -1
- package/dist/audio/AudioUtilities.js +2 -2
- package/dist/audio/AudioUtilities.js.map +1 -1
- package/dist/build-tools/MakeTarballsForInstalledPackages.js +3 -3
- package/dist/build-tools/MakeTarballsForInstalledPackages.js.map +1 -1
- package/dist/cli/CLI.d.ts.map +1 -1
- package/dist/cli/CLI.js +139 -92
- package/dist/cli/CLI.js.map +1 -1
- package/dist/codecs/FFMpegTranscoder.d.ts +4 -3
- package/dist/codecs/FFMpegTranscoder.d.ts.map +1 -1
- package/dist/codecs/FFMpegTranscoder.js +16 -14
- package/dist/codecs/FFMpegTranscoder.js.map +1 -1
- package/dist/codecs/TIMITCodec.d.ts.map +1 -1
- package/dist/data-structures/DynamicTypedArray.d.ts.map +1 -1
- package/dist/data-structures/DynamicTypedArray.js.map +1 -1
- package/dist/data-structures/Queue.d.ts.map +1 -1
- package/dist/data-structures/WindowedList.d.ts.map +1 -1
- package/dist/data-structures/WindowedList.js.map +1 -1
- package/dist/denoising/NSNet2.d.ts +3 -2
- package/dist/denoising/NSNet2.d.ts.map +1 -1
- package/dist/denoising/NSNet2.js +4 -4
- package/dist/denoising/NSNet2.js.map +1 -1
- package/dist/denoising/RNNoise.d.ts +2 -1
- package/dist/denoising/RNNoise.d.ts.map +1 -1
- package/dist/denoising/RNNoise.js +10 -6
- package/dist/denoising/RNNoise.js.map +1 -1
- package/dist/dsp/BiquadFilter.d.ts.map +1 -1
- package/dist/dsp/DecayingPeakEstimator.d.ts.map +1 -1
- package/dist/dsp/DecayingPeakEstimator.js.map +1 -1
- package/dist/dsp/FFT.d.ts.map +1 -1
- package/dist/dsp/FFT.js +2 -1
- package/dist/dsp/FFT.js.map +1 -1
- package/dist/dsp/KWeightingFilter.d.ts.map +1 -1
- package/dist/dsp/KWeightingFilter.js.map +1 -1
- package/dist/dsp/LoudnessEstimator.d.ts.map +1 -1
- package/dist/dsp/LoudnessEstimator.js.map +1 -1
- package/dist/dsp/MFCC.d.ts +3 -2
- package/dist/dsp/MFCC.d.ts.map +1 -1
- package/dist/dsp/MFCC.js +4 -4
- package/dist/dsp/MFCC.js.map +1 -1
- package/dist/dsp/MelSpectrogram.d.ts +10 -8
- package/dist/dsp/MelSpectrogram.d.ts.map +1 -1
- package/dist/dsp/MelSpectrogram.js +31 -34
- package/dist/dsp/MelSpectrogram.js.map +1 -1
- package/dist/dsp/Rubberband.d.ts.map +1 -1
- package/dist/dsp/Rubberband.js +8 -3
- package/dist/dsp/Rubberband.js.map +1 -1
- package/dist/dsp/Sonic.d.ts.map +1 -1
- package/dist/dsp/Sonic.js +1 -1
- package/dist/dsp/Sonic.js.map +1 -1
- package/dist/dsp/SpeexResampler.d.ts.map +1 -1
- package/dist/dsp/SpeexResampler.js +1 -1
- package/dist/dsp/SpeexResampler.js.map +1 -1
- package/dist/encodings/Ascii.d.ts +1 -1
- package/dist/encodings/Ascii.d.ts.map +1 -1
- package/dist/encodings/Base64.js.map +1 -1
- package/dist/encodings/Utf16.d.ts.map +1 -1
- package/dist/encodings/Utf8.d.ts.map +1 -1
- package/dist/math/VectorMath.d.ts +1 -0
- package/dist/math/VectorMath.d.ts.map +1 -1
- package/dist/math/VectorMath.js +9 -5
- package/dist/math/VectorMath.js.map +1 -1
- package/dist/nlp/ChineseSegmentation.d.ts +1 -1
- package/dist/nlp/ChineseSegmentation.d.ts.map +1 -1
- package/dist/nlp/EspeakPhonemizer.d.ts +1 -1
- package/dist/nlp/EspeakPhonemizer.d.ts.map +1 -1
- package/dist/nlp/EspeakPhonemizer.js +2 -2
- package/dist/nlp/EspeakPhonemizer.js.map +1 -1
- package/dist/nlp/IPA.d.ts +2 -2
- package/dist/nlp/Segmentation.d.ts +1 -1
- package/dist/nlp/Segmentation.d.ts.map +1 -1
- package/dist/nlp/Segmentation.js +8 -4
- package/dist/nlp/Segmentation.js.map +1 -1
- package/dist/recognition/AmazonTranscribeSTT.d.ts +2 -1
- package/dist/recognition/AmazonTranscribeSTT.d.ts.map +1 -1
- package/dist/recognition/AmazonTranscribeSTT.js +3 -3
- package/dist/recognition/AmazonTranscribeSTT.js.map +1 -1
- package/dist/recognition/AzureCognitiveServicesSTT.d.ts +2 -1
- package/dist/recognition/AzureCognitiveServicesSTT.d.ts.map +1 -1
- package/dist/recognition/AzureCognitiveServicesSTT.js +4 -4
- package/dist/recognition/AzureCognitiveServicesSTT.js.map +1 -1
- package/dist/recognition/DeepgramSTT.d.ts +2 -1
- package/dist/recognition/DeepgramSTT.d.ts.map +1 -1
- package/dist/recognition/DeepgramSTT.js +12 -13
- package/dist/recognition/DeepgramSTT.js.map +1 -1
- package/dist/recognition/GoogleCloudSTT.d.ts +2 -1
- package/dist/recognition/GoogleCloudSTT.d.ts.map +1 -1
- package/dist/recognition/GoogleCloudSTT.js +11 -10
- package/dist/recognition/GoogleCloudSTT.js.map +1 -1
- package/dist/recognition/OpenAICloudSTT.d.ts +2 -1
- package/dist/recognition/OpenAICloudSTT.d.ts.map +1 -1
- package/dist/recognition/OpenAICloudSTT.js +6 -6
- package/dist/recognition/OpenAICloudSTT.js.map +1 -1
- package/dist/recognition/WhisperCommon.d.ts +9 -0
- package/dist/recognition/WhisperCommon.d.ts.map +1 -0
- package/dist/recognition/WhisperCommon.js +52 -0
- package/dist/recognition/WhisperCommon.js.map +1 -0
- package/dist/recognition/{WhisperCppSTT.d.ts → WhisperCppCliSTT.d.ts} +14 -16
- package/dist/recognition/WhisperCppCliSTT.d.ts.map +1 -0
- package/dist/recognition/{WhisperCppSTT.js → WhisperCppCliSTT.js} +55 -84
- package/dist/recognition/WhisperCppCliSTT.js.map +1 -0
- package/dist/recognition/WhisperSTT.d.ts +72 -85
- package/dist/recognition/WhisperSTT.d.ts.map +1 -1
- package/dist/recognition/WhisperSTT.js +384 -519
- package/dist/recognition/WhisperSTT.js.map +1 -1
- package/dist/server/Client.d.ts +2 -2
- package/dist/server/Client.d.ts.map +1 -1
- package/dist/server/Client.js.map +1 -1
- package/dist/server/Worker.d.ts +6 -7
- package/dist/server/Worker.d.ts.map +1 -1
- package/dist/server/Worker.js +42 -44
- package/dist/server/Worker.js.map +1 -1
- package/dist/source-separation/MDXNetSourceSeparation.d.ts +3 -2
- package/dist/source-separation/MDXNetSourceSeparation.d.ts.map +1 -1
- package/dist/source-separation/MDXNetSourceSeparation.js +10 -8
- package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
- package/dist/speech-embeddings/WavToVec2BertFeatureEmbeddings.d.ts +3 -2
- package/dist/speech-embeddings/WavToVec2BertFeatureEmbeddings.d.ts.map +1 -1
- package/dist/speech-embeddings/WavToVec2BertFeatureEmbeddings.js +5 -5
- package/dist/speech-embeddings/WavToVec2BertFeatureEmbeddings.js.map +1 -1
- package/dist/speech-language-detection/SileroLanguageDetection.d.ts +5 -3
- package/dist/speech-language-detection/SileroLanguageDetection.d.ts.map +1 -1
- package/dist/speech-language-detection/SileroLanguageDetection.js +8 -8
- package/dist/speech-language-detection/SileroLanguageDetection.js.map +1 -1
- package/dist/speech-search/DTWSpeechSearch.d.ts +2 -1
- package/dist/speech-search/DTWSpeechSearch.d.ts.map +1 -1
- package/dist/speech-search/DTWSpeechSearch.js +4 -4
- package/dist/speech-search/DTWSpeechSearch.js.map +1 -1
- package/dist/subtitles/Subtitles.d.ts +13 -1
- package/dist/subtitles/Subtitles.d.ts.map +1 -1
- package/dist/subtitles/Subtitles.js +22 -22
- package/dist/subtitles/Subtitles.js.map +1 -1
- package/dist/synthesis/AwsPollyTTS.d.ts +3 -2
- package/dist/synthesis/AwsPollyTTS.d.ts.map +1 -1
- package/dist/synthesis/AwsPollyTTS.js +5 -5
- package/dist/synthesis/AwsPollyTTS.js.map +1 -1
- package/dist/synthesis/AzureCognitiveServicesTTS.d.ts +2 -1
- package/dist/synthesis/AzureCognitiveServicesTTS.d.ts.map +1 -1
- package/dist/synthesis/AzureCognitiveServicesTTS.js +3 -3
- package/dist/synthesis/AzureCognitiveServicesTTS.js.map +1 -1
- package/dist/synthesis/CoquiServerTTS.d.ts +2 -1
- package/dist/synthesis/CoquiServerTTS.d.ts.map +1 -1
- package/dist/synthesis/CoquiServerTTS.js +7 -8
- package/dist/synthesis/CoquiServerTTS.js.map +1 -1
- package/dist/synthesis/DeepgramTTS.d.ts +2 -2
- package/dist/synthesis/DeepgramTTS.d.ts.map +1 -1
- package/dist/synthesis/DeepgramTTS.js +13 -13
- package/dist/synthesis/DeepgramTTS.js.map +1 -1
- package/dist/synthesis/ElevenLabsTTS.d.ts +3 -3
- package/dist/synthesis/ElevenLabsTTS.d.ts.map +1 -1
- package/dist/synthesis/ElevenLabsTTS.js +22 -21
- package/dist/synthesis/ElevenLabsTTS.js.map +1 -1
- package/dist/synthesis/EspeakTTS.d.ts +11 -9
- package/dist/synthesis/EspeakTTS.d.ts.map +1 -1
- package/dist/synthesis/EspeakTTS.js +118 -68
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/dist/synthesis/FliteTTS.d.ts +2 -2
- package/dist/synthesis/FliteTTS.d.ts.map +1 -1
- package/dist/synthesis/FliteTTS.js +2 -2
- package/dist/synthesis/FliteTTS.js.map +1 -1
- package/dist/synthesis/GnuSpeechTTS.d.ts +2 -2
- package/dist/synthesis/GnuSpeechTTS.d.ts.map +1 -1
- package/dist/synthesis/GnuSpeechTTS.js +1 -1
- package/dist/synthesis/GnuSpeechTTS.js.map +1 -1
- package/dist/synthesis/GoogleCloudTTS.d.ts +3 -2
- package/dist/synthesis/GoogleCloudTTS.d.ts.map +1 -1
- package/dist/synthesis/GoogleCloudTTS.js +15 -14
- package/dist/synthesis/GoogleCloudTTS.js.map +1 -1
- package/dist/synthesis/GoogleTranslateTTS.d.ts +3 -2
- package/dist/synthesis/GoogleTranslateTTS.d.ts.map +1 -1
- package/dist/synthesis/GoogleTranslateTTS.js +11 -11
- package/dist/synthesis/GoogleTranslateTTS.js.map +1 -1
- package/dist/synthesis/KokoroTTS.d.ts +4 -4
- package/dist/synthesis/KokoroTTS.d.ts.map +1 -1
- package/dist/synthesis/KokoroTTS.js +11 -10
- package/dist/synthesis/KokoroTTS.js.map +1 -1
- package/dist/synthesis/MicrosoftEdgeTTS.d.ts +4 -3
- package/dist/synthesis/MicrosoftEdgeTTS.d.ts.map +1 -1
- package/dist/synthesis/MicrosoftEdgeTTS.js +41 -20
- package/dist/synthesis/MicrosoftEdgeTTS.js.map +1 -1
- package/dist/synthesis/OpenAICloudTTS.d.ts +2 -2
- package/dist/synthesis/OpenAICloudTTS.d.ts.map +1 -1
- package/dist/synthesis/OpenAICloudTTS.js +6 -5
- package/dist/synthesis/OpenAICloudTTS.js.map +1 -1
- package/dist/synthesis/SamTTS.d.ts +2 -1
- package/dist/synthesis/SamTTS.d.ts.map +1 -1
- package/dist/synthesis/SamTTS.js +2 -2
- package/dist/synthesis/SamTTS.js.map +1 -1
- package/dist/synthesis/SapiTTS.d.ts +2 -2
- package/dist/synthesis/SapiTTS.d.ts.map +1 -1
- package/dist/synthesis/SapiTTS.js +2 -2
- package/dist/synthesis/SapiTTS.js.map +1 -1
- package/dist/synthesis/SvoxPicoTTS.d.ts +2 -2
- package/dist/synthesis/SvoxPicoTTS.d.ts.map +1 -1
- package/dist/synthesis/SvoxPicoTTS.js +3 -3
- package/dist/synthesis/SvoxPicoTTS.js.map +1 -1
- package/dist/synthesis/VitsTTS.d.ts +3 -3
- package/dist/synthesis/VitsTTS.d.ts.map +1 -1
- package/dist/synthesis/VitsTTS.js +14 -11
- package/dist/synthesis/VitsTTS.js.map +1 -1
- package/dist/text-translation/DeepLTextTranslation.d.ts +2 -2
- package/dist/text-translation/DeepLTextTranslation.d.ts.map +1 -1
- package/dist/text-translation/DeepLTextTranslation.js +10 -9
- package/dist/text-translation/DeepLTextTranslation.js.map +1 -1
- package/dist/text-translation/GoogleTranslateTextTranslation.d.ts +4 -4
- package/dist/text-translation/GoogleTranslateTextTranslation.d.ts.map +1 -1
- package/dist/text-translation/GoogleTranslateTextTranslation.js +20 -18
- package/dist/text-translation/GoogleTranslateTextTranslation.js.map +1 -1
- package/dist/text-translation/NLLBTextTranslation.d.ts +2 -2
- package/dist/text-translation/NLLBTextTranslation.d.ts.map +1 -1
- package/dist/text-translation/NLLBTextTranslation.js +4 -6
- package/dist/text-translation/NLLBTextTranslation.js.map +1 -1
- package/dist/typings/TypedArray.d.ts.map +1 -1
- package/dist/utilities/Compression.d.ts +4 -3
- package/dist/utilities/Compression.d.ts.map +1 -1
- package/dist/utilities/Compression.js +9 -9
- package/dist/utilities/Compression.js.map +1 -1
- package/dist/utilities/FileDownloader.d.ts +6 -3
- package/dist/utilities/FileDownloader.d.ts.map +1 -1
- package/dist/utilities/FileDownloader.js +25 -21
- package/dist/utilities/FileDownloader.js.map +1 -1
- package/dist/utilities/FileReader.d.ts.map +1 -1
- package/dist/utilities/FileReader.js.map +1 -1
- package/dist/utilities/FileSystem.js +1 -1
- package/dist/utilities/FileSystem.js.map +1 -1
- package/dist/utilities/FileWriter.d.ts.map +1 -1
- package/dist/utilities/FileWriter.js.map +1 -1
- package/dist/utilities/Hashing.d.ts.map +1 -1
- package/dist/utilities/Hashing.js.map +1 -1
- package/dist/utilities/Locale.js.map +1 -1
- package/dist/utilities/Logger.d.ts +17 -9
- package/dist/utilities/Logger.d.ts.map +1 -1
- package/dist/utilities/Logger.js +50 -35
- package/dist/utilities/Logger.js.map +1 -1
- package/dist/utilities/NpmUtilities.d.ts.map +1 -1
- package/dist/utilities/NpmUtilities.js +4 -5
- package/dist/utilities/NpmUtilities.js.map +1 -1
- package/dist/utilities/ObjectUtilities.js.map +1 -1
- package/dist/utilities/OpenPromise.d.ts.map +1 -1
- package/dist/utilities/OpenPromise.js.map +1 -1
- package/dist/utilities/PackageManager.d.ts +4 -1
- package/dist/utilities/PackageManager.d.ts.map +1 -1
- package/dist/utilities/PackageManager.js +37 -22
- package/dist/utilities/PackageManager.js.map +1 -1
- package/dist/utilities/PathUtilities.d.ts +2 -0
- package/dist/utilities/PathUtilities.d.ts.map +1 -1
- package/dist/utilities/PathUtilities.js +5 -2
- package/dist/utilities/PathUtilities.js.map +1 -1
- package/dist/utilities/RandomGenerator.d.ts.map +1 -1
- package/dist/utilities/SignalChannel.d.ts.map +1 -1
- package/dist/utilities/SmoothEstimator.d.ts.map +1 -1
- package/dist/utilities/SmoothEstimator.js.map +1 -1
- package/dist/utilities/StringBuilder.d.ts.map +1 -1
- package/dist/utilities/TarballMaker.d.ts +4 -3
- package/dist/utilities/TarballMaker.d.ts.map +1 -1
- package/dist/utilities/TarballMaker.js +6 -6
- package/dist/utilities/TarballMaker.js.map +1 -1
- package/dist/utilities/Timeline.js.map +1 -1
- package/dist/utilities/Timer.d.ts.map +1 -1
- package/dist/utilities/Utilities.d.ts +9 -7
- package/dist/utilities/Utilities.d.ts.map +1 -1
- package/dist/utilities/Utilities.js +49 -33
- package/dist/utilities/Utilities.js.map +1 -1
- package/dist/utilities/VirtualFileReadStream.d.ts.map +1 -1
- package/dist/utilities/WebReader.d.ts +2 -1
- package/dist/utilities/WebReader.d.ts.map +1 -1
- package/dist/utilities/WebReader.js +7 -6
- package/dist/utilities/WebReader.js.map +1 -1
- package/dist/utilities/WikipediaReader.d.ts +2 -1
- package/dist/utilities/WikipediaReader.d.ts.map +1 -1
- package/dist/utilities/WikipediaReader.js +1 -5
- package/dist/utilities/WikipediaReader.js.map +1 -1
- package/dist/voice-activity-detection/AdaptiveGateVAD.d.ts +2 -1
- package/dist/voice-activity-detection/AdaptiveGateVAD.d.ts.map +1 -1
- package/dist/voice-activity-detection/AdaptiveGateVAD.js +1 -1
- package/dist/voice-activity-detection/AdaptiveGateVAD.js.map +1 -1
- package/dist/voice-activity-detection/SileroVAD.d.ts.map +1 -1
- package/dist/voice-activity-detection/SileroVAD.js.map +1 -1
- package/dist/voice-activity-detection/WebRtcVAD.d.ts.map +1 -1
- package/dist/voice-activity-detection/WebRtcVAD.js +1 -1
- package/dist/voice-activity-detection/WebRtcVAD.js.map +1 -1
- package/docs/API.md +62 -17
- package/docs/CUDA.md +4 -3
- package/docs/Engines.md +8 -7
- package/docs/Licenses.md +0 -3
- package/docs/Options.md +27 -31
- package/docs/Server.md +1 -0
- package/docs/Tasklist.md +2 -1
- package/docs/Technical.md +2 -2
- package/package.json +45 -35
- package/src/alignment/SemanticTextAlignment.ts +14 -7
- package/src/alignment/SpeechAlignment.ts +47 -150
- package/src/api/APIOptions.ts +1 -1
- package/src/api/Alignment.ts +95 -61
- package/src/api/Common.ts +11 -0
- package/src/api/Denoising.ts +22 -17
- package/src/api/GlobalOptions.ts +4 -20
- package/src/api/Recognition.ts +106 -123
- package/src/api/SourceSeparation.ts +39 -21
- package/src/api/SpeechLanguageDetection.ts +77 -37
- package/src/api/SpeechSearch.ts +6 -1
- package/src/api/SpeechTranslation.ts +75 -38
- package/src/api/Synthesis.ts +220 -116
- package/src/api/TextLanguageDetection.ts +10 -12
- package/src/api/TextTranslation.ts +43 -26
- package/src/api/TimelineTranslationAlignment.ts +41 -13
- package/src/api/TranscriptAndTranslationAlignment.ts +28 -15
- package/src/api/TranslationAlignment.ts +53 -24
- package/src/api/VoiceActivityDetection.ts +33 -68
- package/src/audio/AudioPlayer.ts +4 -232
- package/src/audio/AudioUtilities.ts +9 -2
- package/src/build-tools/MakeTarballsForInstalledPackages.ts +4 -3
- package/src/cli/CLI.ts +209 -101
- package/src/codecs/FFMpegTranscoder.ts +18 -16
- package/src/denoising/NSNet2.ts +5 -4
- package/src/denoising/RNNoise.ts +14 -6
- package/src/dsp/FFT.ts +2 -1
- package/src/dsp/MFCC.ts +7 -5
- package/src/dsp/MelSpectrogram.ts +56 -36
- package/src/dsp/Rubberband.ts +10 -3
- package/src/dsp/Sonic.ts +2 -1
- package/src/dsp/SpeexResampler.ts +2 -1
- package/src/encodings/Ascii.ts +1 -1
- package/src/encodings/Base64.ts +1 -1
- package/src/math/VectorMath.ts +10 -6
- package/src/nlp/EspeakPhonemizer.ts +2 -2
- package/src/nlp/Segmentation.ts +9 -4
- package/src/recognition/AmazonTranscribeSTT.ts +4 -3
- package/src/recognition/AzureCognitiveServicesSTT.ts +5 -4
- package/src/recognition/DeepgramSTT.ts +16 -16
- package/src/recognition/GoogleCloudSTT.ts +14 -12
- package/src/recognition/OpenAICloudSTT.ts +12 -6
- package/src/recognition/WhisperCommon.ts +130 -0
- package/src/recognition/{WhisperCppSTT.ts → WhisperCppCliSTT.ts} +73 -133
- package/src/recognition/WhisperSTT.ts +569 -718
- package/src/server/Client.ts +4 -4
- package/src/server/Worker.ts +59 -59
- package/src/source-separation/MDXNetSourceSeparation.ts +15 -10
- package/src/speech-embeddings/WavToVec2BertFeatureEmbeddings.ts +7 -5
- package/src/speech-language-detection/SileroLanguageDetection.ts +18 -9
- package/src/speech-search/DTWSpeechSearch.ts +6 -5
- package/src/subtitles/Subtitles.ts +22 -22
- package/src/synthesis/AwsPollyTTS.ts +12 -5
- package/src/synthesis/AzureCognitiveServicesTTS.ts +11 -3
- package/src/synthesis/CoquiServerTTS.ts +8 -7
- package/src/synthesis/DeepgramTTS.ts +21 -15
- package/src/synthesis/ElevenLabsTTS.ts +33 -23
- package/src/synthesis/EspeakTTS.ts +145 -69
- package/src/synthesis/FliteTTS.ts +3 -3
- package/src/synthesis/GnuSpeechTTS.ts +2 -2
- package/src/synthesis/GoogleCloudTTS.ts +23 -14
- package/src/synthesis/GoogleTranslateTTS.ts +19 -11
- package/src/synthesis/KokoroTTS.ts +37 -14
- package/src/synthesis/MicrosoftEdgeTTS.ts +71 -23
- package/src/synthesis/OpenAICloudTTS.ts +7 -6
- package/src/synthesis/SamTTS.ts +3 -2
- package/src/synthesis/SapiTTS.ts +3 -3
- package/src/synthesis/SvoxPicoTTS.ts +4 -5
- package/src/synthesis/VitsTTS.ts +43 -15
- package/src/text-translation/DeepLTextTranslation.ts +12 -10
- package/src/text-translation/GoogleTranslateTextTranslation.ts +35 -21
- package/src/text-translation/NLLBTextTranslation.ts +5 -9
- package/src/typings/Fillers.d.ts +0 -60
- package/src/typings/TypedArray.ts +12 -1
- package/src/utilities/Compression.ts +10 -9
- package/src/utilities/FileDownloader.ts +38 -23
- package/src/utilities/FileSystem.ts +1 -1
- package/src/utilities/Logger.ts +59 -42
- package/src/utilities/NpmUtilities.ts +4 -6
- package/src/utilities/OpenPromise.ts +1 -2
- package/src/utilities/PackageManager.ts +53 -26
- package/src/utilities/PathUtilities.ts +6 -2
- package/src/utilities/TarballMaker.ts +7 -7
- package/src/utilities/Utilities.ts +58 -41
- package/src/utilities/WebReader.ts +11 -6
- package/src/utilities/WikipediaReader.ts +2 -8
- package/src/voice-activity-detection/AdaptiveGateVAD.ts +13 -8
- package/src/voice-activity-detection/WebRtcVAD.ts +1 -2
- package/tsconfig.json +53 -54
- package/dist/audio/AudioRecorder.d.ts +0 -4
- package/dist/audio/AudioRecorder.d.ts.map +0 -1
- package/dist/audio/AudioRecorder.js +0 -68
- package/dist/audio/AudioRecorder.js.map +0 -1
- package/dist/audio/SoxPath.d.ts +0 -2
- package/dist/audio/SoxPath.d.ts.map +0 -1
- package/dist/audio/SoxPath.js +0 -24
- package/dist/audio/SoxPath.js.map +0 -1
- package/dist/recognition/SileroSTT.d.ts +0 -30
- package/dist/recognition/SileroSTT.d.ts.map +0 -1
- package/dist/recognition/SileroSTT.js +0 -152
- package/dist/recognition/SileroSTT.js.map +0 -1
- package/dist/recognition/VoskSTT.d.ts +0 -11
- package/dist/recognition/VoskSTT.d.ts.map +0 -1
- package/dist/recognition/VoskSTT.js +0 -72
- package/dist/recognition/VoskSTT.js.map +0 -1
- package/dist/recognition/WhisperCppSTT.d.ts.map +0 -1
- package/dist/recognition/WhisperCppSTT.js.map +0 -1
- package/dist/synthesis/StreamlabsPollyTTS.d.ts +0 -12
- package/dist/synthesis/StreamlabsPollyTTS.d.ts.map +0 -1
- package/dist/synthesis/StreamlabsPollyTTS.js +0 -88
- package/dist/synthesis/StreamlabsPollyTTS.js.map +0 -1
- package/dist/utilities/BinaryUtilities.d.ts +0 -14
- package/dist/utilities/BinaryUtilities.d.ts.map +0 -1
- package/dist/utilities/BinaryUtilities.js +0 -113
- package/dist/utilities/BinaryUtilities.js.map +0 -1
- package/src/audio/AudioRecorder.ts +0 -91
- package/src/audio/SoxPath.ts +0 -31
- package/src/recognition/SileroSTT.ts +0 -222
- package/src/recognition/VoskSTT.ts +0 -112
- package/src/synthesis/StreamlabsPollyTTS.ts +0 -114
- package/src/utilities/BinaryUtilities.ts +0 -138
- /package/{LICENSE.md → LICENSE.GPLv3.md} +0 -0
|
@@ -1,40 +1,45 @@
|
|
|
1
1
|
import chalk from 'chalk'
|
|
2
|
-
import type * as Onnx from 'onnxruntime-node'
|
|
3
2
|
|
|
3
|
+
import { getRawAudioDuration, RawAudio } from '../audio/AudioUtilities.js'
|
|
4
|
+
import { formatLanguageCodeWithName, getShortLanguageCode, languageCodeToName } from '../utilities/Locale.js'
|
|
4
5
|
import { Logger } from '../utilities/Logger.js'
|
|
5
|
-
import { computeMelSpectrogramUsingFilterbanks, Filterbank } from '../dsp/MelSpectrogram.js'
|
|
6
|
-
import { clip, getIntegerRange, getTopKIndexes, splitFloat32Array, yieldToEventLoop } from '../utilities/Utilities.js'
|
|
7
|
-
import { indexOfMax, logOfVector, logSumExp, meanOfVector, medianOfVector, softmax, sumAndSumOfSquaresOfVector, sumOfSquaresOfVector, sumVector } from '../math/VectorMath.js'
|
|
8
|
-
|
|
9
|
-
import { alignDTWWindowed } from '../alignment/DTWSequenceAlignmentWindowed.js'
|
|
10
6
|
import { extendDeep } from '../utilities/ObjectUtilities.js'
|
|
11
7
|
import { Timeline, TimelineEntry } from '../utilities/Timeline.js'
|
|
12
|
-
|
|
13
|
-
import { getRawAudioDuration, RawAudio, sliceRawAudio } from '../audio/AudioUtilities.js'
|
|
14
|
-
import { readFileAsUtf8 } from '../utilities/FileSystem.js'
|
|
15
|
-
import { logLevelGreaterOrEqualTo, type LanguageDetectionResults } from '../api/API.js'
|
|
16
|
-
import { formatLanguageCodeWithName, getShortLanguageCode, languageCodeToName } from '../utilities/Locale.js'
|
|
17
|
-
import { loadPackage } from '../utilities/PackageManager.js'
|
|
18
|
-
import { XorShift32PRNG } from '../utilities/RandomGenerator.js'
|
|
19
|
-
import { detectSpeechLanguageByParts } from '../api/SpeechLanguageDetection.js'
|
|
8
|
+
|
|
20
9
|
import { type Tiktoken } from 'tiktoken/lite'
|
|
21
|
-
import {
|
|
22
|
-
import { medianOf5Filter } from '../math/MedianFilter.js'
|
|
23
|
-
import { getDeflateCompressionMetricsForString } from '../utilities/Compression.js'
|
|
24
|
-
import { dmlProviderAvailable, getOnnxSessionOptions, makeOnnxLikeFloat32Tensor, OnnxExecutionProvider, OnnxLikeFloat32Tensor } from '../utilities/OnnxUtilities.js'
|
|
10
|
+
import { XorShift32PRNG } from '../utilities/RandomGenerator.js'
|
|
25
11
|
import { murmurHash3_int32Input } from '../utilities/Hashing.js'
|
|
12
|
+
|
|
13
|
+
import { WhisperCppContext, WhisperCppContextOptions, CrossAttentionQKs, WhisperAlignmentHeadsPreset, whisperModelIdToTextLayerCount, whisperModelIdToAlignmentHeadsPreset, GgmlLogLevel } from '@echogarden/whisper.cpp-binding'
|
|
14
|
+
import { getDeflateCompressionMetricsForString } from '../utilities/Compression.js'
|
|
15
|
+
import { indexOfMax, meanOfVector, medianOfVector, softmax, sumAndSumOfSquaresOfVector, sumVector } from '../math/VectorMath.js'
|
|
16
|
+
import { loadPackage, LoadPackageCallbacks } from '../utilities/PackageManager.js'
|
|
17
|
+
import { joinPath, resolvePath } from '../utilities/PathUtilities.js'
|
|
18
|
+
import { readFileAsUtf8 } from '../utilities/FileSystem.js'
|
|
19
|
+
import { clip, concatUint8Arrays, getIntegerRange, getTopKIndexes, yieldToEventLoop } from '../utilities/Utilities.js'
|
|
26
20
|
import { containsInvalidCodepoint, getTokenRepetitionScore } from '../utilities/StringUtilities.js'
|
|
27
|
-
import {
|
|
21
|
+
import { alignDTWWindowed } from '../alignment/DTWSequenceAlignmentWindowed.js'
|
|
22
|
+
import { medianOf5Filter } from '../math/MedianFilter.js'
|
|
23
|
+
import { AlignmentPath } from '../alignment/SpeechAlignment.js'
|
|
24
|
+
import { includesPunctuation, isAllWhitespace, splitToWords } from '../nlp/Segmentation.js'
|
|
28
25
|
import { Timer } from '../utilities/Timer.js'
|
|
26
|
+
import { computeMelSpectrogramUsingFilterbank, Filterbank } from '../dsp/MelSpectrogram.js'
|
|
27
|
+
import { detectSpeechLanguageByParts, SpeechLanguageDetectionCallbacks } from '../api/SpeechLanguageDetection.js'
|
|
28
|
+
import { LanguageDetectionResults } from '../api/LanguageDetectionCommon.js'
|
|
29
|
+
import { RecognitionCallbacks } from '../api/Recognition.js'
|
|
30
|
+
import { AlignmentCallbacks } from '../api/Alignment.js'
|
|
31
|
+
import { OperationCallbacks } from '../api/Common.js'
|
|
32
|
+
import { WhisperModelId, WhisperQuantizedModelId, WhisperTask } from './WhisperCommon.js'
|
|
29
33
|
|
|
30
34
|
export async function recognize(
|
|
31
35
|
sourceRawAudio: RawAudio,
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
modelId: WhisperModelId,
|
|
37
|
+
modelPath: string,
|
|
38
|
+
libPath: string,
|
|
34
39
|
task: WhisperTask,
|
|
35
40
|
sourceLanguage: string,
|
|
36
41
|
options: WhisperOptions,
|
|
37
|
-
|
|
42
|
+
callbacks: RecognitionCallbacks) {
|
|
38
43
|
|
|
39
44
|
options = extendDeep(defaultWhisperOptions, options)
|
|
40
45
|
|
|
@@ -48,11 +53,11 @@ export async function recognize(
|
|
|
48
53
|
throw new Error(`The language ${formatLanguageCodeWithName(sourceLanguage)} is not supported by the Whisper engine.`)
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
if (isEnglishOnlyModel(
|
|
52
|
-
throw new Error(`The model '${
|
|
56
|
+
if (isEnglishOnlyModel(modelId) && sourceLanguage !== 'en') {
|
|
57
|
+
throw new Error(`The model '${modelId}' can only be used with English inputs. However, the given source language was ${languageCodeToName(sourceLanguage)}.`)
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
if (
|
|
60
|
+
if (modelId === 'large-v3-turbo' && task === 'translate') {
|
|
56
61
|
throw new Error(`The 'large-v3-turbo' model doesn't support translation tasks.`)
|
|
57
62
|
}
|
|
58
63
|
|
|
@@ -62,28 +67,26 @@ export async function recognize(
|
|
|
62
67
|
|
|
63
68
|
// Workaround issue with large-v3-turbo that produces invalid results when a prompt is passed to it.
|
|
64
69
|
// Always disable autoprompting for that model.
|
|
65
|
-
if (options.autoPromptParts &&
|
|
70
|
+
if (options.autoPromptParts && modelId === 'large-v3-turbo') {
|
|
66
71
|
options.autoPromptParts = false
|
|
67
72
|
}
|
|
68
73
|
|
|
69
|
-
// Select encoder ONNX provider
|
|
70
|
-
const encoderProviders: OnnxExecutionProvider[] =
|
|
71
|
-
options.encoderProvider ? [options.encoderProvider] : getDefaultEncoderProvidersForModel(modelName)
|
|
72
|
-
|
|
73
|
-
// Select decoder ONNX provider
|
|
74
|
-
const decoderProviders: OnnxExecutionProvider[] =
|
|
75
|
-
options.decoderProvider ? [options.decoderProvider] : getDefaultDecoderProvidersForModel(modelName)
|
|
76
|
-
|
|
77
74
|
const seed = options.seed
|
|
78
75
|
|
|
79
76
|
const whisper = new Whisper(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
decoderProviders,
|
|
77
|
+
modelId,
|
|
78
|
+
modelPath,
|
|
79
|
+
libPath,
|
|
84
80
|
seed)
|
|
85
81
|
|
|
86
|
-
const result = await whisper.recognize(
|
|
82
|
+
const result = await whisper.recognize(
|
|
83
|
+
sourceRawAudio,
|
|
84
|
+
task,
|
|
85
|
+
sourceLanguage,
|
|
86
|
+
options,
|
|
87
|
+
undefined,
|
|
88
|
+
callbacks,
|
|
89
|
+
)
|
|
87
90
|
|
|
88
91
|
return result
|
|
89
92
|
}
|
|
@@ -91,10 +94,12 @@ export async function recognize(
|
|
|
91
94
|
export async function align(
|
|
92
95
|
sourceRawAudio: RawAudio,
|
|
93
96
|
transcript: string,
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
modelId: WhisperModelId,
|
|
98
|
+
modelPath: string,
|
|
99
|
+
libPath: string,
|
|
96
100
|
sourceLanguage: string,
|
|
97
|
-
options: WhisperAlignmentOptions
|
|
101
|
+
options: WhisperAlignmentOptions,
|
|
102
|
+
callbacks: RecognitionCallbacks) {
|
|
98
103
|
|
|
99
104
|
options = extendDeep(defaultWhisperAlignmentOptions, options)
|
|
100
105
|
|
|
@@ -108,25 +113,24 @@ export async function align(
|
|
|
108
113
|
throw new Error(`The language ${formatLanguageCodeWithName(sourceLanguage)} is not supported by the Whisper engine.`)
|
|
109
114
|
}
|
|
110
115
|
|
|
111
|
-
if (isEnglishOnlyModel(
|
|
112
|
-
throw new Error(`The model '${
|
|
116
|
+
if (isEnglishOnlyModel(modelId) && sourceLanguage !== 'en') {
|
|
117
|
+
throw new Error(`The model '${modelId}' can only be used with English inputs. However, the given source language was ${languageCodeToName(sourceLanguage)}.`)
|
|
113
118
|
}
|
|
114
119
|
|
|
115
|
-
// Select encoder ONNX provider
|
|
116
|
-
const encoderProviders: OnnxExecutionProvider[] =
|
|
117
|
-
options.encoderProvider ? [options.encoderProvider] : getDefaultEncoderProvidersForModel(modelName)
|
|
118
|
-
|
|
119
|
-
// Select decoder ONNX provider
|
|
120
|
-
const decoderProviders: OnnxExecutionProvider[] =
|
|
121
|
-
options.decoderProvider ? [options.decoderProvider] : getDefaultDecoderProvidersForModel(modelName)
|
|
122
|
-
|
|
123
120
|
const whisper = new Whisper(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const timeline = await whisper.align(
|
|
121
|
+
modelId,
|
|
122
|
+
modelPath,
|
|
123
|
+
libPath,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
const timeline = await whisper.align(
|
|
127
|
+
sourceRawAudio,
|
|
128
|
+
transcript,
|
|
129
|
+
sourceLanguage,
|
|
130
|
+
'transcribe',
|
|
131
|
+
options,
|
|
132
|
+
callbacks,
|
|
133
|
+
)
|
|
130
134
|
|
|
131
135
|
return timeline
|
|
132
136
|
}
|
|
@@ -134,10 +138,12 @@ export async function align(
|
|
|
134
138
|
export async function alignEnglishTranslation(
|
|
135
139
|
sourceRawAudio: RawAudio,
|
|
136
140
|
translatedTranscript: string,
|
|
137
|
-
|
|
138
|
-
|
|
141
|
+
modelId: WhisperModelId,
|
|
142
|
+
modelPath: string,
|
|
143
|
+
libPath: string,
|
|
139
144
|
sourceLanguage: string,
|
|
140
|
-
options: WhisperAlignmentOptions
|
|
145
|
+
options: WhisperAlignmentOptions,
|
|
146
|
+
callbacks: AlignmentCallbacks) {
|
|
141
147
|
|
|
142
148
|
options = extendDeep(defaultWhisperAlignmentOptions, options)
|
|
143
149
|
|
|
@@ -151,38 +157,39 @@ export async function alignEnglishTranslation(
|
|
|
151
157
|
throw new Error(`The source language ${formatLanguageCodeWithName(sourceLanguage)} is not supported by the Whisper engine.`)
|
|
152
158
|
}
|
|
153
159
|
|
|
154
|
-
if (
|
|
160
|
+
if (modelId === 'large-v3-turbo') {
|
|
155
161
|
throw new Error(`The 'large-v3-turbo' model doesn't support translation tasks, so cannot be used for translation alignment.`)
|
|
156
162
|
}
|
|
157
163
|
|
|
158
|
-
if (isEnglishOnlyModel(
|
|
164
|
+
if (isEnglishOnlyModel(modelId)) {
|
|
159
165
|
throw new Error(`Translation alignment can only be done with multilingual models.`)
|
|
160
166
|
}
|
|
161
167
|
|
|
162
|
-
// Select encoder ONNX provider
|
|
163
|
-
const encoderProviders: OnnxExecutionProvider[] =
|
|
164
|
-
options.encoderProvider ? [options.encoderProvider] : getDefaultEncoderProvidersForModel(modelName)
|
|
165
|
-
|
|
166
|
-
// Select decoder ONNX provider
|
|
167
|
-
const decoderProviders: OnnxExecutionProvider[] =
|
|
168
|
-
options.decoderProvider ? [options.decoderProvider] : getDefaultDecoderProvidersForModel(modelName)
|
|
169
|
-
|
|
170
168
|
const whisper = new Whisper(
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const timeline = await whisper.align(
|
|
169
|
+
modelId,
|
|
170
|
+
modelPath,
|
|
171
|
+
libPath
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
const timeline = await whisper.align(
|
|
175
|
+
sourceRawAudio,
|
|
176
|
+
translatedTranscript,
|
|
177
|
+
sourceLanguage,
|
|
178
|
+
'translate',
|
|
179
|
+
options,
|
|
180
|
+
callbacks,
|
|
181
|
+
)
|
|
177
182
|
|
|
178
183
|
return timeline
|
|
179
184
|
}
|
|
180
185
|
|
|
181
186
|
export async function detectLanguage(
|
|
182
187
|
sourceRawAudio: RawAudio,
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
188
|
+
modelId: WhisperModelId,
|
|
189
|
+
modelPath: string,
|
|
190
|
+
libPath: string,
|
|
191
|
+
options: WhisperLanguageDetectionOptions,
|
|
192
|
+
callbacks: SpeechLanguageDetectionCallbacks) {
|
|
186
193
|
|
|
187
194
|
options = extendDeep(defaultWhisperLanguageDetectionOptions, options)
|
|
188
195
|
|
|
@@ -190,7 +197,7 @@ export async function detectLanguage(
|
|
|
190
197
|
throw new Error('Source audio must have a sample rate of 16000 Hz')
|
|
191
198
|
}
|
|
192
199
|
|
|
193
|
-
if (!isMultilingualModel(
|
|
200
|
+
if (!isMultilingualModel(modelId)) {
|
|
194
201
|
throw new Error(`Language detection is only supported with multilingual models.`)
|
|
195
202
|
}
|
|
196
203
|
|
|
@@ -198,165 +205,50 @@ export async function detectLanguage(
|
|
|
198
205
|
throw new Error(`Temperature cannot be negative`)
|
|
199
206
|
}
|
|
200
207
|
|
|
201
|
-
// Select encoder ONNX provider
|
|
202
|
-
const encoderProviders: OnnxExecutionProvider[] =
|
|
203
|
-
options.encoderProvider ? [options.encoderProvider] : getDefaultEncoderProvidersForModel(modelName)
|
|
204
|
-
|
|
205
|
-
// Select decoder ONNX provider
|
|
206
|
-
const decoderProviders: OnnxExecutionProvider[] =
|
|
207
|
-
options.decoderProvider ? [options.decoderProvider] : []
|
|
208
|
-
|
|
209
208
|
const whisper = new Whisper(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
209
|
+
modelId,
|
|
210
|
+
modelPath,
|
|
211
|
+
libPath,
|
|
212
|
+
)
|
|
214
213
|
|
|
215
214
|
async function detectLanguageForPart(partAudio: RawAudio) {
|
|
216
|
-
const
|
|
217
|
-
const partResults = await whisper.detectLanguage(audioFeatures, options.temperature!)
|
|
215
|
+
const partResults = await whisper.detectLanguage(partAudio, options, callbacks)
|
|
218
216
|
|
|
219
217
|
return partResults
|
|
220
218
|
}
|
|
221
219
|
|
|
222
|
-
const results = await detectSpeechLanguageByParts(
|
|
220
|
+
const results = await detectSpeechLanguageByParts(
|
|
221
|
+
sourceRawAudio,
|
|
222
|
+
detectLanguageForPart,
|
|
223
|
+
undefined,
|
|
224
|
+
undefined,
|
|
225
|
+
callbacks,
|
|
226
|
+
)
|
|
223
227
|
|
|
224
228
|
results.sort((entry1, entry2) => entry2.probability - entry1.probability)
|
|
225
229
|
|
|
226
230
|
return results
|
|
227
231
|
}
|
|
228
232
|
|
|
229
|
-
export async function detectVoiceActivity(
|
|
230
|
-
sourceRawAudio: RawAudio,
|
|
231
|
-
modelName: WhisperModelName,
|
|
232
|
-
modelDir: string,
|
|
233
|
-
options: WhisperVADOptions) {
|
|
234
|
-
|
|
235
|
-
options = extendDeep(defaultWhisperVADOptions, options)
|
|
236
|
-
|
|
237
|
-
if (sourceRawAudio.sampleRate !== 16000) {
|
|
238
|
-
throw new Error('Source audio must have a sample rate of 16000 Hz')
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (options.temperature! < 0) {
|
|
242
|
-
throw new Error(`Temperature cannot be negative`)
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const audioSamples = sourceRawAudio.audioChannels[0]
|
|
246
|
-
|
|
247
|
-
const partDuration = 5
|
|
248
|
-
const maxSamplesCountForPart = sourceRawAudio.sampleRate * partDuration
|
|
249
|
-
|
|
250
|
-
// Select encoder ONNX provider
|
|
251
|
-
const encoderProviders: OnnxExecutionProvider[] =
|
|
252
|
-
options.encoderProvider ? [options.encoderProvider] : getDefaultEncoderProvidersForModel(modelName)
|
|
253
|
-
|
|
254
|
-
// Select decoder ONNX provider
|
|
255
|
-
const decoderProviders: OnnxExecutionProvider[] =
|
|
256
|
-
options.decoderProvider ? [options.decoderProvider] : []
|
|
257
|
-
|
|
258
|
-
const whisper = new Whisper(
|
|
259
|
-
modelName,
|
|
260
|
-
modelDir,
|
|
261
|
-
encoderProviders,
|
|
262
|
-
decoderProviders)
|
|
263
|
-
|
|
264
|
-
const partProbabilities: Timeline = []
|
|
265
|
-
|
|
266
|
-
for (let sampleOffset = 0; sampleOffset < audioSamples.length; sampleOffset += maxSamplesCountForPart) {
|
|
267
|
-
const partSamples = sliceRawAudio(sourceRawAudio, sampleOffset, sampleOffset + maxSamplesCountForPart)
|
|
268
|
-
|
|
269
|
-
const samplesCountForPart = partSamples.audioChannels[0].length
|
|
270
|
-
|
|
271
|
-
const startTime = sampleOffset / sourceRawAudio.sampleRate
|
|
272
|
-
const endTime = (sampleOffset + samplesCountForPart) / sourceRawAudio.sampleRate
|
|
273
|
-
|
|
274
|
-
const encodedPartSamples = await whisper.encodeAudio(partSamples)
|
|
275
|
-
const probabilityForPart = await whisper.detectVoiceActivity(encodedPartSamples, options.temperature!)
|
|
276
|
-
|
|
277
|
-
partProbabilities.push({
|
|
278
|
-
type: 'segment',
|
|
279
|
-
text: '',
|
|
280
|
-
startTime,
|
|
281
|
-
endTime,
|
|
282
|
-
confidence: probabilityForPart,
|
|
283
|
-
})
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
return { partProbabilities }
|
|
287
|
-
}
|
|
288
|
-
|
|
289
233
|
export class Whisper {
|
|
290
234
|
isMultiligualModel: boolean
|
|
291
235
|
|
|
292
|
-
audioEncoder?: Onnx.InferenceSession
|
|
293
|
-
textDecoder?: Onnx.InferenceSession
|
|
294
|
-
|
|
295
236
|
tiktoken?: Tiktoken
|
|
237
|
+
context?: WhisperCppContext
|
|
296
238
|
|
|
297
|
-
|
|
298
|
-
endOfTextToken: number
|
|
299
|
-
startOfTextToken: number
|
|
300
|
-
|
|
301
|
-
languageTokensStart: number
|
|
302
|
-
languageTokensEnd: number
|
|
303
|
-
|
|
304
|
-
translateTaskToken: number
|
|
305
|
-
transcribeTaskToken: number
|
|
306
|
-
startOfPromptToken: number
|
|
307
|
-
nonSpeechToken: number
|
|
308
|
-
noTimestampsToken: number
|
|
309
|
-
|
|
310
|
-
timestampTokensStart: number
|
|
311
|
-
timestampTokensEnd: number
|
|
312
|
-
}
|
|
239
|
+
specialTokens: WhisperSpecialTokens
|
|
313
240
|
|
|
314
241
|
randomGen: XorShift32PRNG
|
|
315
242
|
|
|
316
243
|
constructor(
|
|
317
|
-
public readonly
|
|
318
|
-
public readonly
|
|
319
|
-
public readonly
|
|
320
|
-
public readonly decoderExecutionProviders: OnnxExecutionProvider[],
|
|
244
|
+
public readonly modelId: WhisperModelId,
|
|
245
|
+
public readonly modelPath: string,
|
|
246
|
+
public readonly libPath: string,
|
|
321
247
|
prngSeed = 1234) {
|
|
322
248
|
|
|
323
|
-
this.isMultiligualModel = isMultilingualModel(this.
|
|
249
|
+
this.isMultiligualModel = isMultilingualModel(this.modelId)
|
|
324
250
|
|
|
325
|
-
|
|
326
|
-
this.tokenConfig = {
|
|
327
|
-
endOfTextToken: 50257,
|
|
328
|
-
startOfTextToken: 50258,
|
|
329
|
-
|
|
330
|
-
languageTokensStart: 50259,
|
|
331
|
-
languageTokensEnd: 50358,
|
|
332
|
-
|
|
333
|
-
translateTaskToken: 50358,
|
|
334
|
-
transcribeTaskToken: 50359,
|
|
335
|
-
startOfPromptToken: 50361,
|
|
336
|
-
nonSpeechToken: 50362,
|
|
337
|
-
noTimestampsToken: 50363,
|
|
338
|
-
|
|
339
|
-
timestampTokensStart: 50364,
|
|
340
|
-
timestampTokensEnd: 50364 + 1501,
|
|
341
|
-
}
|
|
342
|
-
} else {
|
|
343
|
-
this.tokenConfig = {
|
|
344
|
-
endOfTextToken: 50256,
|
|
345
|
-
startOfTextToken: 50257,
|
|
346
|
-
|
|
347
|
-
languageTokensStart: 50258,
|
|
348
|
-
languageTokensEnd: 50358,
|
|
349
|
-
|
|
350
|
-
translateTaskToken: 50358,
|
|
351
|
-
transcribeTaskToken: 50359,
|
|
352
|
-
startOfPromptToken: 50360,
|
|
353
|
-
nonSpeechToken: 50361,
|
|
354
|
-
noTimestampsToken: 50362,
|
|
355
|
-
|
|
356
|
-
timestampTokensStart: 50363,
|
|
357
|
-
timestampTokensEnd: 50363 + 1501,
|
|
358
|
-
}
|
|
359
|
-
}
|
|
251
|
+
this.specialTokens = this.isMultiligualModel ? multilingualSpecialTokens : englishOnlySpecialTokens
|
|
360
252
|
|
|
361
253
|
this.randomGen = new XorShift32PRNG(murmurHash3_int32Input(prngSeed))
|
|
362
254
|
}
|
|
@@ -366,15 +258,15 @@ export class Whisper {
|
|
|
366
258
|
task: WhisperTask,
|
|
367
259
|
language: string,
|
|
368
260
|
options: WhisperOptions,
|
|
369
|
-
logitFilter
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
await this.initializeIfNeeded()
|
|
261
|
+
logitFilter: WhisperLogitFilter | undefined,
|
|
262
|
+
callbacks: RecognitionCallbacks) {
|
|
263
|
+
|
|
264
|
+
await this.initializeIfNeeded(options, callbacks)
|
|
373
265
|
|
|
374
|
-
const logger = new Logger()
|
|
266
|
+
const logger = new Logger(callbacks.logLevel)
|
|
375
267
|
|
|
376
268
|
options = extendDeep(defaultWhisperOptions, options)
|
|
377
|
-
options.model = this.
|
|
269
|
+
options.model = this.modelId
|
|
378
270
|
|
|
379
271
|
if (!options.timestampAccuracy) {
|
|
380
272
|
options.timestampAccuracy = this.defaultTimestampAccuracy
|
|
@@ -406,17 +298,21 @@ export class Whisper {
|
|
|
406
298
|
}
|
|
407
299
|
|
|
408
300
|
for (let audioOffset = 0; audioOffset < audioSamples.length;) {
|
|
301
|
+
callbacks?.abortSignal?.throwIfAborted()
|
|
302
|
+
|
|
409
303
|
const segmentStartTime = audioOffset / sampleRate
|
|
410
304
|
|
|
411
305
|
await logger.startAsync(`\nPrepare audio part at time position ${segmentStartTime.toFixed(2)}`, undefined, chalk.magentaBright)
|
|
412
306
|
|
|
413
|
-
const audioPartSamples = audioSamples.
|
|
307
|
+
const audioPartSamples = audioSamples.subarray(audioOffset, audioOffset + maxAudioSamplesPerPart)
|
|
414
308
|
const audioPartRawAudio: RawAudio = { audioChannels: [audioPartSamples], sampleRate }
|
|
415
309
|
const audioPartDuration = getRawAudioDuration(audioPartRawAudio)
|
|
416
310
|
|
|
417
311
|
logger.end()
|
|
418
312
|
|
|
419
|
-
|
|
313
|
+
await this.encodeSamples(audioPartSamples, false, options, callbacks)
|
|
314
|
+
|
|
315
|
+
await logger.startAsync(`Prepare prompt`)
|
|
420
316
|
|
|
421
317
|
const isFirstPart = audioOffset === 0
|
|
422
318
|
const isFinalPart = audioOffset + maxAudioSamplesPerPart >= audioSamples.length
|
|
@@ -430,9 +326,9 @@ export class Whisper {
|
|
|
430
326
|
promptTokens = promptTokens.slice(promptTokens.length - largestMaximumTokensPerPart)
|
|
431
327
|
}
|
|
432
328
|
|
|
433
|
-
initialTokens = [this.
|
|
329
|
+
initialTokens = [this.specialTokens.startOfPromptToken, ...promptTokens]
|
|
434
330
|
} else if (options.autoPromptParts && previousPartTextTokens.length > 0) {
|
|
435
|
-
initialTokens = [this.
|
|
331
|
+
initialTokens = [this.specialTokens.startOfPromptToken, ...previousPartTextTokens]
|
|
436
332
|
}
|
|
437
333
|
|
|
438
334
|
initialTokens = [...initialTokens, ...this.getTextStartTokens(language, task, !decodeTimestampTokens)]
|
|
@@ -450,13 +346,13 @@ export class Whisper {
|
|
|
450
346
|
decodedTokensInferenceTime: partTokensInferenceTime,
|
|
451
347
|
decodedTokensOverheadTime: partTokensOverheadTime,
|
|
452
348
|
} = await this.decodeTokens(
|
|
453
|
-
audioPartFeatures,
|
|
454
349
|
initialTokens,
|
|
455
350
|
audioPartDuration,
|
|
456
351
|
isFirstPart,
|
|
457
352
|
isFinalPart,
|
|
458
353
|
options,
|
|
459
354
|
wrappedLogitFilter,
|
|
355
|
+
callbacks,
|
|
460
356
|
)
|
|
461
357
|
|
|
462
358
|
const lastToken = partTokens[partTokens.length - 1]
|
|
@@ -477,36 +373,23 @@ export class Whisper {
|
|
|
477
373
|
|
|
478
374
|
await logger.startAsync(`Extract timeline for part (timestamp accuracy: ${options.timestampAccuracy!})`)
|
|
479
375
|
|
|
480
|
-
if (partTokens.length !== partTokensCrossAttentionQKs.length) {
|
|
481
|
-
throw new Error('Unexpected: partTokens.length !== partCrossAttentionQKs.length')
|
|
482
|
-
}
|
|
483
|
-
|
|
484
376
|
// Prepare tokens
|
|
485
377
|
partTokens = partTokens.slice(initialTokens.length)
|
|
486
378
|
partTokensConfidence = partTokensConfidence.slice(initialTokens.length)
|
|
487
379
|
partTokensCrossAttentionQKs = partTokensCrossAttentionQKs.slice(initialTokens.length)
|
|
488
380
|
|
|
489
|
-
// Find alignment path
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
if (options.timestampAccuracy === 'medium' || options.model === 'large-v3-turbo') {
|
|
493
|
-
alignmentHeads = this.alignmentHeadIndexes
|
|
494
|
-
} else if (options.timestampAccuracy === 'high') {
|
|
495
|
-
alignmentHeads = undefined
|
|
496
|
-
} else {
|
|
497
|
-
throw new Error(`Unsupported timestamp accuracy '${options.timestampAccuracy}', can only be 'medium' or 'high'.`)
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
const alignmentPath = await this.findAlignmentPathFromQKs(partTokensCrossAttentionQKs, partTokens, 0, segmentFrameCount, alignmentHeads)
|
|
381
|
+
// Find alignment path using the cross attention query-key tensors
|
|
382
|
+
const alignmentHeadsIndexesToUse = undefined
|
|
383
|
+
const alignmentPath = await this.findAlignmentPathFromCrossAttentionQKs(partTokensCrossAttentionQKs, partTokens, 0, segmentFrameCount, alignmentHeadsIndexesToUse)
|
|
501
384
|
|
|
502
385
|
// Generate timeline from alignment path
|
|
503
386
|
const partTimeline = await this.getTokenTimelineFromAlignmentPath(alignmentPath, partTokens, segmentStartTime, segmentEndTime, partTokensConfidence)
|
|
504
387
|
|
|
505
|
-
if (onPart) {
|
|
388
|
+
if (callbacks?.onPart) {
|
|
506
389
|
const partWordTimeline = this.tokenTimelineToWordTimeline(partTimeline, language)
|
|
507
390
|
const partTranscript = this.tokensToText(partTokens)
|
|
508
391
|
|
|
509
|
-
onPart(partTranscript, partTimeline, partWordTimeline)
|
|
392
|
+
callbacks.onPart(partTranscript, partTimeline, partWordTimeline)
|
|
510
393
|
}
|
|
511
394
|
|
|
512
395
|
// Add tokens to output
|
|
@@ -529,13 +412,13 @@ export class Whisper {
|
|
|
529
412
|
|
|
530
413
|
logger.end()
|
|
531
414
|
|
|
532
|
-
if (logLevelGreaterOrEqualTo('trace')) {
|
|
533
|
-
const
|
|
415
|
+
if (logger.logLevelGreaterOrEqualTo('trace')) {
|
|
416
|
+
const promptProcessingTime = partTokensDecodingTime[0]
|
|
534
417
|
const medianTokenDecodingTime = medianOfVector(partTokensDecodingTime.slice(1))
|
|
535
418
|
const medianTokenInferenceTime = medianOfVector(partTokensInferenceTime.slice(1))
|
|
536
419
|
const medianOverheadTime = medianOfVector(partTokensOverheadTime.slice(1))
|
|
537
420
|
|
|
538
|
-
logger.log(`${chalk.blueBright('Context')}: ${initialTokens.length + partTokens.length} tokens (${initialTokens.length} prompt, ${partTokens.length} decoded)\n${chalk.blueBright('Prompt
|
|
421
|
+
logger.log(`${chalk.blueBright('Context')}: ${initialTokens.length + partTokens.length} tokens (${initialTokens.length} prompt, ${partTokens.length} decoded)\n${chalk.blueBright('Prompt processing time')}: ${promptProcessingTime.toFixed(1)}ms\n${chalk.blueBright('Median token decode time')}: ${medianTokenDecodingTime.toFixed(1)}ms (${medianTokenInferenceTime.toFixed(1)}ms inference, ${medianOverheadTime.toFixed(2)}ms overhead)`, 'trace')
|
|
539
422
|
}
|
|
540
423
|
}
|
|
541
424
|
|
|
@@ -550,8 +433,12 @@ export class Whisper {
|
|
|
550
433
|
return { transcript, timeline, allDecodedTokens }
|
|
551
434
|
}
|
|
552
435
|
|
|
553
|
-
async align(rawAudio: RawAudio, transcript: string, sourceLanguage: string, task: 'transcribe' | 'translate', whisperAlignmentOptions: WhisperAlignmentOptions) {
|
|
554
|
-
await this.initializeTokenizerIfNeeded()
|
|
436
|
+
async align(rawAudio: RawAudio, transcript: string, sourceLanguage: string, task: 'transcribe' | 'translate', whisperAlignmentOptions: WhisperAlignmentOptions, callbacks: RecognitionCallbacks) {
|
|
437
|
+
await this.initializeTokenizerIfNeeded(callbacks)
|
|
438
|
+
|
|
439
|
+
const logger = new Logger(callbacks.logLevel)
|
|
440
|
+
|
|
441
|
+
logger.start(`Tokenize transcript`)
|
|
555
442
|
|
|
556
443
|
whisperAlignmentOptions = extendDeep(defaultWhisperAlignmentOptions, whisperAlignmentOptions)
|
|
557
444
|
|
|
@@ -580,7 +467,7 @@ export class Whisper {
|
|
|
580
467
|
|
|
581
468
|
// Initialize custom logit filter that allows only the transcript tokens to be decoded
|
|
582
469
|
// in order.
|
|
583
|
-
const endOfTextToken = this.
|
|
470
|
+
const endOfTextToken = this.specialTokens.endOfTextToken
|
|
584
471
|
|
|
585
472
|
const logitFilter: WhisperLogitFilter = (logits, decodedTokens, isFirstPart, isFinalPart) => {
|
|
586
473
|
const decodedTextTokens = decodedTokens.filter(token => this.isTextToken(token))
|
|
@@ -607,8 +494,14 @@ export class Whisper {
|
|
|
607
494
|
|
|
608
495
|
// Set options for alignment
|
|
609
496
|
const options: WhisperOptions = {
|
|
610
|
-
model: this.
|
|
497
|
+
model: this.modelId,
|
|
498
|
+
|
|
499
|
+
enableGPU: whisperAlignmentOptions.enableGPU,
|
|
500
|
+
threadCount: whisperAlignmentOptions.threadCount,
|
|
501
|
+
gpuDeviceIndex: whisperAlignmentOptions.gpuDeviceIndex,
|
|
502
|
+
|
|
611
503
|
temperature: 0.0,
|
|
504
|
+
|
|
612
505
|
prompt: undefined,
|
|
613
506
|
topCandidateCount: 1,
|
|
614
507
|
punctuationThreshold: Infinity,
|
|
@@ -620,13 +513,20 @@ export class Whisper {
|
|
|
620
513
|
endTokenThreshold: whisperAlignmentOptions.endTokenThreshold!,
|
|
621
514
|
includeEndTokenInCandidates: false,
|
|
622
515
|
timestampAccuracy: whisperAlignmentOptions.timestampAccuracy!,
|
|
623
|
-
encoderProvider: whisperAlignmentOptions.encoderProvider!,
|
|
624
|
-
decoderProvider: whisperAlignmentOptions.decoderProvider!,
|
|
625
516
|
seed: undefined,
|
|
626
517
|
}
|
|
627
518
|
|
|
519
|
+
logger.end()
|
|
520
|
+
|
|
628
521
|
// Recognize
|
|
629
|
-
const { timeline, allDecodedTokens } = await this.recognize(
|
|
522
|
+
const { timeline, allDecodedTokens } = await this.recognize(
|
|
523
|
+
rawAudio,
|
|
524
|
+
task,
|
|
525
|
+
sourceLanguage,
|
|
526
|
+
options,
|
|
527
|
+
logitFilter,
|
|
528
|
+
callbacks,
|
|
529
|
+
)
|
|
630
530
|
|
|
631
531
|
{
|
|
632
532
|
// If not all tokens were decoded, add the remaining ones to the timeline
|
|
@@ -675,44 +575,41 @@ export class Whisper {
|
|
|
675
575
|
return timeline
|
|
676
576
|
}
|
|
677
577
|
|
|
678
|
-
async detectLanguage(
|
|
578
|
+
async detectLanguage(
|
|
579
|
+
audioSamples: RawAudio,
|
|
580
|
+
options: WhisperLanguageDetectionOptions,
|
|
581
|
+
callbacks: SpeechLanguageDetectionCallbacks): Promise<LanguageDetectionResults> {
|
|
582
|
+
|
|
679
583
|
if (!this.isMultiligualModel) {
|
|
680
584
|
throw new Error('Language detection is only supported with multilingual models')
|
|
681
585
|
}
|
|
682
586
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
const logger = new Logger()
|
|
687
|
-
await logger.startAsync('Detect language with Whisper model')
|
|
688
|
-
|
|
689
|
-
const sotToken = this.tokenConfig.startOfTextToken
|
|
587
|
+
if (audioSamples.sampleRate !== 16000) {
|
|
588
|
+
throw new Error('Sample rate must be 16000 Hz')
|
|
589
|
+
}
|
|
690
590
|
|
|
691
|
-
|
|
692
|
-
|
|
591
|
+
if (audioSamples.audioChannels.length !== 1) {
|
|
592
|
+
throw new Error('Audio must be mono')
|
|
593
|
+
}
|
|
693
594
|
|
|
694
|
-
|
|
595
|
+
await this.initializeContextIfNeeded(options, { logLevel: callbacks.logLevel })
|
|
695
596
|
|
|
696
|
-
|
|
697
|
-
const
|
|
597
|
+
// Prepare and run decoder
|
|
598
|
+
const logger = new Logger(callbacks.logLevel)
|
|
599
|
+
await logger.startAsync('Detect language with Whisper model')
|
|
600
|
+
logger.log(``)
|
|
698
601
|
|
|
699
|
-
|
|
700
|
-
const offsetTensor = new Onnx.Tensor('int64', new BigInt64Array([BigInt(offset)]), [])
|
|
602
|
+
await this.encodeSamples(audioSamples.audioChannels[0], undefined, options, callbacks)
|
|
701
603
|
|
|
702
|
-
const
|
|
703
|
-
tokens: tokensTensor,
|
|
704
|
-
audio_features: audioFeatures,
|
|
705
|
-
kv_cache: kvCacheTensor,
|
|
706
|
-
offset: offsetTensor
|
|
707
|
-
}
|
|
604
|
+
const specialTokens = this.specialTokens
|
|
708
605
|
|
|
709
|
-
const
|
|
710
|
-
const logitsBuffer = decoderOutputs['logits'].data as Float32Array
|
|
606
|
+
const initialTokens = [specialTokens.startOfTextToken]
|
|
711
607
|
|
|
712
|
-
|
|
608
|
+
await this.context!.decodeTokens(initialTokens, 0, options.threadCount!);
|
|
713
609
|
|
|
714
|
-
const
|
|
715
|
-
const
|
|
610
|
+
const logits = this.context!.getLogits()
|
|
611
|
+
const languageTokensLogits = logits.subarray(specialTokens.languageTokensStart, specialTokens.languageTokensEnd)
|
|
612
|
+
const languageTokensProbabilities = softmax(languageTokensLogits, options.temperature)
|
|
716
613
|
|
|
717
614
|
const results: LanguageDetectionResults = []
|
|
718
615
|
|
|
@@ -732,72 +629,96 @@ export class Whisper {
|
|
|
732
629
|
return results
|
|
733
630
|
}
|
|
734
631
|
|
|
735
|
-
async
|
|
736
|
-
|
|
632
|
+
async encodeSamples(samples: Float32Array, useCustomMelConverter = false, options: WhisperOptions, callbacks: OperationCallbacks) {
|
|
633
|
+
const logger = new Logger(callbacks.logLevel)
|
|
737
634
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
await logger.startAsync('Detect voice activity with Whisper model')
|
|
635
|
+
if (useCustomMelConverter) {
|
|
636
|
+
await logger.startAsync('Extract Mel spectrogram from audio part')
|
|
741
637
|
|
|
742
|
-
|
|
638
|
+
// Compute Mel spectrogram
|
|
639
|
+
const sampleRate = 16000
|
|
640
|
+
const rawAudio: RawAudio = { audioChannels: [samples], sampleRate: 16000 }
|
|
743
641
|
|
|
744
|
-
|
|
745
|
-
|
|
642
|
+
const fftOrder = 400
|
|
643
|
+
const fftWindowSize = 400
|
|
644
|
+
const fftHopLength = 160
|
|
746
645
|
|
|
747
|
-
|
|
646
|
+
const melBandCount = this.melBandCount
|
|
647
|
+
const melFilterbank = this.melFilterbank
|
|
748
648
|
|
|
749
|
-
|
|
750
|
-
|
|
649
|
+
const maxAudioSamples = sampleRate * 30
|
|
650
|
+
const maxFrameCount = 3000
|
|
751
651
|
|
|
752
|
-
|
|
753
|
-
|
|
652
|
+
const { melSpectrogram } = await computeMelSpectrogramUsingFilterbank(
|
|
653
|
+
rawAudio,
|
|
654
|
+
fftOrder,
|
|
655
|
+
fftWindowSize,
|
|
656
|
+
fftHopLength,
|
|
657
|
+
melFilterbank,
|
|
658
|
+
undefined,
|
|
659
|
+
callbacks
|
|
660
|
+
)
|
|
754
661
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
662
|
+
const frameCount = Math.min(melSpectrogram.length, maxFrameCount)
|
|
663
|
+
|
|
664
|
+
// Flatten, transpose, apply logarithm, and normalize Mel spectrogram
|
|
665
|
+
await logger.startAsync('Process Mel spectrogram')
|
|
666
|
+
|
|
667
|
+
const flattenedLogMelSpectrogram = new Float32Array(frameCount * melBandCount)
|
|
668
|
+
|
|
669
|
+
let maxLogMel = -Infinity
|
|
761
670
|
|
|
762
|
-
|
|
763
|
-
|
|
671
|
+
for (let i = 0; i < melBandCount; i++) {
|
|
672
|
+
for (let j = 0; j < frameCount; j++) {
|
|
673
|
+
const mel = melSpectrogram[j][i]
|
|
674
|
+
const logMel = Math.log10(Math.max(mel, 1e-10))
|
|
764
675
|
|
|
765
|
-
|
|
676
|
+
if (logMel > maxLogMel) {
|
|
677
|
+
maxLogMel = logMel
|
|
678
|
+
}
|
|
766
679
|
|
|
767
|
-
|
|
680
|
+
flattenedLogMelSpectrogram[(i * frameCount) + j] = logMel
|
|
681
|
+
}
|
|
682
|
+
}
|
|
768
683
|
|
|
769
|
-
|
|
684
|
+
for (let i = 0; i < flattenedLogMelSpectrogram.length; i++) {
|
|
685
|
+
const logMel = flattenedLogMelSpectrogram[i]
|
|
686
|
+
const normalizedLogMel = (Math.max(logMel, maxLogMel - 8) + 4) / 4
|
|
687
|
+
|
|
688
|
+
flattenedLogMelSpectrogram[i] = normalizedLogMel
|
|
689
|
+
}
|
|
770
690
|
|
|
771
|
-
|
|
691
|
+
await logger.startAsync('Encode Mel spectrogram')
|
|
772
692
|
|
|
773
|
-
|
|
693
|
+
await this.context!.encodeLogMelSpectrogram(flattenedLogMelSpectrogram, melBandCount)
|
|
694
|
+
} else {
|
|
695
|
+
await logger.startAsync('Encode samples')
|
|
696
|
+
|
|
697
|
+
await this.context!.encodeSamples(samples, options.threadCount!)
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
logger.end()
|
|
774
701
|
}
|
|
775
702
|
|
|
776
703
|
// Decode tokens using the decoder model
|
|
777
704
|
async decodeTokens(
|
|
778
|
-
audioFeatures: Onnx.Tensor,
|
|
779
705
|
initialTokens: number[],
|
|
780
706
|
audioDuration: number,
|
|
781
707
|
isFirstPart: boolean,
|
|
782
708
|
isFinalPart: boolean,
|
|
783
709
|
options: WhisperOptions,
|
|
784
|
-
logitFilter
|
|
710
|
+
logitFilter: WhisperLogitFilter | undefined,
|
|
711
|
+
callbacks: RecognitionCallbacks) {
|
|
785
712
|
|
|
786
|
-
|
|
787
|
-
await this.initializeTokenizerIfNeeded()
|
|
788
|
-
await this.initializeDecoderSessionIfNeeded()
|
|
789
|
-
|
|
790
|
-
const logger = new Logger()
|
|
713
|
+
const logger = new Logger(callbacks.logLevel)
|
|
791
714
|
|
|
792
715
|
await logger.startAsync('Decode text tokens with Whisper decoder model')
|
|
793
716
|
|
|
794
717
|
options = extendDeep(defaultWhisperOptions, options)
|
|
795
718
|
|
|
796
|
-
const Onnx = await import('onnxruntime-node')
|
|
797
|
-
|
|
798
719
|
// Get token information
|
|
799
|
-
const endOfTextToken = this.
|
|
800
|
-
const timestampTokensStart = this.
|
|
720
|
+
const endOfTextToken = this.specialTokens.endOfTextToken
|
|
721
|
+
const timestampTokensStart = this.specialTokens.timestampTokensStart
|
|
801
722
|
|
|
802
723
|
const suppressedTextTokens = this.getSuppressedTextTokens()
|
|
803
724
|
const suppressedMetadataTokens = this.getSuppressedMetadataTokens()
|
|
@@ -808,15 +729,13 @@ export class Whisper {
|
|
|
808
729
|
|
|
809
730
|
// Initialize variables for decoding loop
|
|
810
731
|
let decodedTokens = initialTokens.slice()
|
|
811
|
-
const initialKvDimensions = this.getKvDimensions(1, decodedTokens.length)
|
|
812
|
-
let kvCacheTensor = new Onnx.Tensor('float32', new Float32Array(initialKvDimensions[0] * initialKvDimensions[1] * initialKvDimensions[2] * initialKvDimensions[3]), initialKvDimensions)
|
|
813
732
|
|
|
814
|
-
let decodedTokensTimestampLogits:
|
|
733
|
+
let decodedTokensTimestampLogits: Float32Array[] = []
|
|
815
734
|
let decodedTokensConfidence: number[] = []
|
|
816
|
-
let decodedTokensCrossAttentionQKs:
|
|
735
|
+
let decodedTokensCrossAttentionQKs: CrossAttentionQKs[] = []
|
|
817
736
|
|
|
818
737
|
for (let i = 0; i < decodedTokens.length; i++) {
|
|
819
|
-
decodedTokensTimestampLogits.push(new
|
|
738
|
+
decodedTokensTimestampLogits.push(new Float32Array(1501)) // Should the length be 1500 instead?
|
|
820
739
|
decodedTokensConfidence.push(1.0)
|
|
821
740
|
decodedTokensCrossAttentionQKs.push(undefined as any)
|
|
822
741
|
}
|
|
@@ -826,11 +745,15 @@ export class Whisper {
|
|
|
826
745
|
let bufferedTokensToPrint: number[] = []
|
|
827
746
|
|
|
828
747
|
// Define method to add a token to output
|
|
829
|
-
|
|
748
|
+
const addToken = (tokenToAdd: number, timestampLogits: Float32Array, confidence: number, crossAttentionQKs: CrossAttentionQKs) => {
|
|
830
749
|
decodedTokens.push(tokenToAdd)
|
|
831
750
|
decodedTokensTimestampLogits.push(timestampLogits)
|
|
832
751
|
decodedTokensConfidence.push(confidence)
|
|
833
752
|
decodedTokensCrossAttentionQKs.push(crossAttentionQKs)
|
|
753
|
+
|
|
754
|
+
if (callbacks?.onToken) {
|
|
755
|
+
callbacks.onToken(tokenToAdd, this.tokenToBytes(tokenToAdd))
|
|
756
|
+
}
|
|
834
757
|
}
|
|
835
758
|
|
|
836
759
|
const maxTokensPerPart = Math.min(options.maxTokensPerPart!, largestMaximumTokensPerPart)
|
|
@@ -842,6 +765,8 @@ export class Whisper {
|
|
|
842
765
|
|
|
843
766
|
// Start decoding loop
|
|
844
767
|
for (let decodedTokenCount = 0; decodedTokenCount < maxTokensPerPart; decodedTokenCount++) {
|
|
768
|
+
callbacks?.abortSignal?.throwIfAborted()
|
|
769
|
+
|
|
845
770
|
if (decodedTokenCount > 0) {
|
|
846
771
|
decodedTokensDecodingTime.push(tokenDecodingTimeTimer.getElapsedTimeAndRestart())
|
|
847
772
|
}
|
|
@@ -849,54 +774,24 @@ export class Whisper {
|
|
|
849
774
|
const isInitialState = decodedTokens.length === initialTokens.length
|
|
850
775
|
const atLeastOneTextTokenDecoded = decodedTokens.slice(initialTokens.length).some(token => this.isTextToken(token))
|
|
851
776
|
|
|
852
|
-
// If not in initial state, reshape KV Cache tensor to accomodate a new output token
|
|
853
|
-
if (!isInitialState) {
|
|
854
|
-
const dims = kvCacheTensor.dims
|
|
855
|
-
|
|
856
|
-
const currentKvCacheGroups = splitFloat32Array(kvCacheTensor.data as Float32Array, dims[2] * dims[3])
|
|
857
|
-
|
|
858
|
-
const reshapedKvCacheTensor = new Onnx.Tensor('float32', new Float32Array(dims[0] * dims[1] * (decodedTokens.length) * dims[3]), [dims[0], dims[1], decodedTokens.length, dims[3]])
|
|
859
|
-
const reshapedKvCacheGroups = splitFloat32Array(reshapedKvCacheTensor.data, decodedTokens.length * dims[3])
|
|
860
|
-
|
|
861
|
-
for (let i = 0; i < dims[0]; i++) {
|
|
862
|
-
reshapedKvCacheGroups[i].set(currentKvCacheGroups[i])
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
kvCacheTensor = reshapedKvCacheTensor
|
|
866
|
-
}
|
|
867
|
-
|
|
868
777
|
// Prepare values for decoder
|
|
869
778
|
const tokensToDecode = isInitialState ? decodedTokens : [decodedTokens[decodedTokens.length - 1]]
|
|
870
779
|
const offset = isInitialState ? 0 : decodedTokens.length
|
|
871
780
|
|
|
872
|
-
|
|
873
|
-
const
|
|
874
|
-
|
|
875
|
-
const decoderInputs = {
|
|
876
|
-
tokens: tokensTensor,
|
|
877
|
-
audio_features: audioFeatures,
|
|
878
|
-
kv_cache: kvCacheTensor,
|
|
879
|
-
offset: offsetTensor
|
|
880
|
-
}
|
|
781
|
+
//// Infer
|
|
782
|
+
const tokenInferenceTimer = new Timer()
|
|
881
783
|
|
|
882
|
-
|
|
883
|
-
const tokenInferenceTimeTimer = new Timer()
|
|
784
|
+
await this.context!.decodeTokens(tokensToDecode, offset, options.threadCount!)
|
|
884
785
|
|
|
885
|
-
|
|
786
|
+
decodedTokensInferenceTime.push(tokenInferenceTimer.elapsedTime)
|
|
886
787
|
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
kvCacheTensor = decoderOutputs['output_kv_cache'] as any
|
|
892
|
-
|
|
893
|
-
const crossAttentionQKsForTokenOnnx = decoderOutputs['cross_attention_qks']
|
|
894
|
-
const crossAttentionQKsForToken = makeOnnxLikeFloat32Tensor(crossAttentionQKsForTokenOnnx)
|
|
895
|
-
crossAttentionQKsForTokenOnnx.dispose()
|
|
788
|
+
// Get cross-attention QKs
|
|
789
|
+
//const getCrossAttentionQKsTimer = new Timer()
|
|
790
|
+
const tokenCrossAttentionQKs = await this.context!.getCrossAttentionQKs()
|
|
791
|
+
//getCrossAttentionQKsTimer.logAndRestart('getCrossAttentionQKs')
|
|
896
792
|
|
|
897
793
|
// Get logits
|
|
898
|
-
const
|
|
899
|
-
const allTokenLogits = Array.from(resultLogitsFloatArrays[resultLogitsFloatArrays.length - 1])
|
|
794
|
+
const allTokenLogits = this.context!.getLogits()
|
|
900
795
|
|
|
901
796
|
// Suppress metadata tokens in the suppression set
|
|
902
797
|
for (const suppressedTokenIndex of suppressedMetadataTokens) {
|
|
@@ -908,7 +803,7 @@ export class Whisper {
|
|
|
908
803
|
allTokenLogits[endOfTextToken] = -Infinity
|
|
909
804
|
}
|
|
910
805
|
|
|
911
|
-
const timestampTokenLogits = allTokenLogits.
|
|
806
|
+
const timestampTokenLogits = allTokenLogits.subarray(timestampTokensStart)
|
|
912
807
|
|
|
913
808
|
const decodeTimestampTokenIfNeeded = () => {
|
|
914
809
|
// Try to decode a timestamp token, if needed
|
|
@@ -921,7 +816,7 @@ export class Whisper {
|
|
|
921
816
|
// If this is the first token in the part, unconditionally decode a timestamp token
|
|
922
817
|
// for time 0.0
|
|
923
818
|
if (isInitialState) {
|
|
924
|
-
addToken(timestampTokensStart, timestampTokenLogits, 1.0,
|
|
819
|
+
addToken(timestampTokensStart, timestampTokenLogits, 1.0, tokenCrossAttentionQKs)
|
|
925
820
|
|
|
926
821
|
return true
|
|
927
822
|
}
|
|
@@ -937,26 +832,25 @@ export class Whisper {
|
|
|
937
832
|
}
|
|
938
833
|
|
|
939
834
|
// Derive token probabilities
|
|
940
|
-
const allTokenProbabilities = softmax(allTokenLogits
|
|
941
|
-
const
|
|
942
|
-
|
|
943
|
-
const nonTimestampTokenLogProbs = allTokenLogProbabilities.slice(0, timestampTokensStart)
|
|
835
|
+
const allTokenProbabilities = softmax(allTokenLogits, 1.0)
|
|
836
|
+
const nonTimestampTokenProbs = allTokenProbabilities.subarray(0, timestampTokensStart)
|
|
944
837
|
|
|
945
|
-
// Find highest non-timestamp token
|
|
946
|
-
const
|
|
947
|
-
const
|
|
838
|
+
// Find highest probability non-timestamp token
|
|
839
|
+
const indexOfMaxNonTimestampProb = indexOfMax(nonTimestampTokenProbs)
|
|
840
|
+
const valueOfMaxNonTimestampProb = nonTimestampTokenProbs[indexOfMaxNonTimestampProb]
|
|
841
|
+
const valueOfMaxNonTimestampLogProb = Math.log(valueOfMaxNonTimestampProb)
|
|
948
842
|
|
|
949
|
-
// Find highest timestamp token
|
|
950
|
-
const
|
|
951
|
-
const
|
|
843
|
+
// Find highest probability timestamp token
|
|
844
|
+
const timestampTokenProbs = allTokenProbabilities.subarray(timestampTokensStart)
|
|
845
|
+
const indexOfMaxTimestampProb = indexOfMax(timestampTokenProbs)
|
|
952
846
|
|
|
953
|
-
// Compute the log of the sum of
|
|
954
|
-
|
|
955
|
-
const
|
|
847
|
+
// Compute the log of the sum of probabilities of the timestamp tokens
|
|
848
|
+
const sumOfTimestampTokenProbs = sumVector(timestampTokenProbs)
|
|
849
|
+
const logSumOfTimestampTokenProbs = Math.log(sumOfTimestampTokenProbs)
|
|
956
850
|
|
|
957
851
|
// If the sum isn't greater than the log probability of the highest non-timestamp token,
|
|
958
852
|
// don't decode a timestamp
|
|
959
|
-
if (
|
|
853
|
+
if (logSumOfTimestampTokenProbs <= valueOfMaxNonTimestampLogProb) {
|
|
960
854
|
return false
|
|
961
855
|
}
|
|
962
856
|
|
|
@@ -969,15 +863,15 @@ export class Whisper {
|
|
|
969
863
|
const previousTokenTimestampLogits = decodedTokensTimestampLogits[decodedTokensTimestampLogits.length - 1]
|
|
970
864
|
const previousTokenConfidence = decodedTokensConfidence[decodedTokensConfidence.length - 1]
|
|
971
865
|
|
|
972
|
-
addToken(previousToken, previousTokenTimestampLogits, previousTokenConfidence,
|
|
866
|
+
addToken(previousToken, previousTokenTimestampLogits, previousTokenConfidence, tokenCrossAttentionQKs)
|
|
973
867
|
|
|
974
868
|
lastTimestampTokenIndex = decodedTokens.length
|
|
975
869
|
} else {
|
|
976
870
|
// Otherwise decode the highest probability timestamp
|
|
977
|
-
const timestampToken = timestampTokensStart +
|
|
871
|
+
const timestampToken = timestampTokensStart + indexOfMaxTimestampProb
|
|
978
872
|
const confidence = allTokenProbabilities[timestampToken]
|
|
979
873
|
|
|
980
|
-
addToken(timestampToken, timestampTokenLogits, confidence,
|
|
874
|
+
addToken(timestampToken, timestampTokenLogits, confidence, tokenCrossAttentionQKs)
|
|
981
875
|
}
|
|
982
876
|
|
|
983
877
|
return true
|
|
@@ -993,7 +887,7 @@ export class Whisper {
|
|
|
993
887
|
}
|
|
994
888
|
|
|
995
889
|
// Decode a non-timestamp token
|
|
996
|
-
let nonTimestampTokenLogits = allTokenLogits.slice(0, timestampTokensStart)
|
|
890
|
+
let nonTimestampTokenLogits: Float32Array<ArrayBufferLike> = allTokenLogits.slice(0, timestampTokensStart)
|
|
997
891
|
|
|
998
892
|
let shouldDecodeEndfOfTextToken = false
|
|
999
893
|
|
|
@@ -1029,7 +923,7 @@ export class Whisper {
|
|
|
1029
923
|
|
|
1030
924
|
// If filter caused all word token logits to be -Infinity, then there is no
|
|
1031
925
|
// other token to decode. Fall back to accept end-of-text
|
|
1032
|
-
if (nonTimestampTokenLogits.
|
|
926
|
+
if (nonTimestampTokenLogits.subarray(0, endOfTextToken).every(logit => logit === -Infinity)) {
|
|
1033
927
|
shouldDecodeEndfOfTextToken = true
|
|
1034
928
|
}
|
|
1035
929
|
} else {
|
|
@@ -1047,7 +941,7 @@ export class Whisper {
|
|
|
1047
941
|
// If end-of-text token should be decoded, then add it and break
|
|
1048
942
|
// out of the loop
|
|
1049
943
|
if (shouldDecodeEndfOfTextToken) {
|
|
1050
|
-
addToken(endOfTextToken, timestampTokenLogits, 1.0,
|
|
944
|
+
addToken(endOfTextToken, timestampTokenLogits, 1.0, tokenCrossAttentionQKs)
|
|
1051
945
|
|
|
1052
946
|
break
|
|
1053
947
|
}
|
|
@@ -1150,7 +1044,7 @@ export class Whisper {
|
|
|
1150
1044
|
const chosenToken = topCandidates[chosenCandidateRank].token
|
|
1151
1045
|
const chosenTokenConfidence = topCandidateProbabilities[chosenCandidateRank]
|
|
1152
1046
|
|
|
1153
|
-
addToken(chosenToken, timestampTokenLogits, chosenTokenConfidence,
|
|
1047
|
+
addToken(chosenToken, timestampTokenLogits, chosenTokenConfidence, tokenCrossAttentionQKs)
|
|
1154
1048
|
|
|
1155
1049
|
// If chosen token is the end-of-text token, break
|
|
1156
1050
|
if (chosenToken === endOfTextToken) {
|
|
@@ -1189,8 +1083,8 @@ export class Whisper {
|
|
|
1189
1083
|
|
|
1190
1084
|
decodedTokens = decodedTokens.slice(0, sliceEndTokenIndex)
|
|
1191
1085
|
decodedTokensTimestampLogits = decodedTokensTimestampLogits.slice(0, sliceEndTokenIndex)
|
|
1192
|
-
decodedTokensCrossAttentionQKs = decodedTokensCrossAttentionQKs.slice(0, sliceEndTokenIndex)
|
|
1193
1086
|
decodedTokensConfidence = decodedTokensConfidence.slice(0, sliceEndTokenIndex)
|
|
1087
|
+
decodedTokensCrossAttentionQKs = decodedTokensCrossAttentionQKs.slice(0, sliceEndTokenIndex)
|
|
1194
1088
|
|
|
1195
1089
|
decodedTokensDecodingTime = decodedTokensDecodingTime.slice(0, sliceEndTokenIndex)
|
|
1196
1090
|
decodedTokensInferenceTime = decodedTokensInferenceTime.slice(0, sliceEndTokenIndex)
|
|
@@ -1214,88 +1108,6 @@ export class Whisper {
|
|
|
1214
1108
|
}
|
|
1215
1109
|
}
|
|
1216
1110
|
|
|
1217
|
-
// Encode audio using the encoder model
|
|
1218
|
-
async encodeAudio(rawAudio: RawAudio) {
|
|
1219
|
-
await this.initializeEncoderSessionIfNeeded()
|
|
1220
|
-
|
|
1221
|
-
const Onnx = await import('onnxruntime-node')
|
|
1222
|
-
|
|
1223
|
-
const logger = new Logger()
|
|
1224
|
-
|
|
1225
|
-
const audioSamples = rawAudio.audioChannels[0]
|
|
1226
|
-
const sampleRate = rawAudio.sampleRate
|
|
1227
|
-
|
|
1228
|
-
const fftOrder = 400
|
|
1229
|
-
const fftWindowSize = 400
|
|
1230
|
-
const fftHopLength = 160
|
|
1231
|
-
|
|
1232
|
-
const filterbankCount = this.filterbankCount
|
|
1233
|
-
const filterbanks = this.filterbanks
|
|
1234
|
-
|
|
1235
|
-
const maxAudioSamples = sampleRate * 30
|
|
1236
|
-
const maxAudioFrames = 3000
|
|
1237
|
-
|
|
1238
|
-
if (sampleRate !== 16000) {
|
|
1239
|
-
throw new Error('Audio must have a sample rate of 16000 Hz')
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
if (audioSamples.length > maxAudioSamples) {
|
|
1243
|
-
throw new Error(`Audio part is longer than 30 seconds`)
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
await logger.startAsync('Extract Mel spectrogram from audio part')
|
|
1247
|
-
|
|
1248
|
-
// Pad audio samples to ensure that have a duration of 30 seconds
|
|
1249
|
-
const paddedAudioSamples = new Float32Array(maxAudioSamples)
|
|
1250
|
-
paddedAudioSamples.set(audioSamples, 0)
|
|
1251
|
-
|
|
1252
|
-
const rawAudioPart: RawAudio = { audioChannels: [paddedAudioSamples], sampleRate }
|
|
1253
|
-
|
|
1254
|
-
// Compute Mel spectrogram
|
|
1255
|
-
const { melSpectrogram } = await computeMelSpectrogramUsingFilterbanks(rawAudioPart, fftOrder, fftWindowSize, fftHopLength, filterbanks)
|
|
1256
|
-
|
|
1257
|
-
// Flatten, transpose, apply logarithm and normalize Mel spectrogram
|
|
1258
|
-
await logger.startAsync('Process Mel spectrogram')
|
|
1259
|
-
|
|
1260
|
-
const flattenedLogMelSpectrogram = new Float32Array(maxAudioFrames * filterbankCount)
|
|
1261
|
-
|
|
1262
|
-
let maxLogMel = -Infinity
|
|
1263
|
-
|
|
1264
|
-
for (let i = 0; i < filterbankCount; i++) {
|
|
1265
|
-
for (let j = 0; j < maxAudioFrames; j++) {
|
|
1266
|
-
const mel = melSpectrogram[j][i]
|
|
1267
|
-
const logMel = Math.log10(Math.max(mel, 1e-10))
|
|
1268
|
-
|
|
1269
|
-
if (logMel > maxLogMel) {
|
|
1270
|
-
maxLogMel = logMel
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
flattenedLogMelSpectrogram[(i * maxAudioFrames) + j] = logMel
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
for (let i = 0; i < flattenedLogMelSpectrogram.length; i++) {
|
|
1278
|
-
const logMel = flattenedLogMelSpectrogram[i]
|
|
1279
|
-
const normalizedLogMel = (Math.max(logMel, maxLogMel - 8) + 4) / 4
|
|
1280
|
-
|
|
1281
|
-
flattenedLogMelSpectrogram[i] = normalizedLogMel
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
|
-
// Run the encoder model
|
|
1285
|
-
await logger.startAsync('Encode Mel spectrogram with Whisper encoder model')
|
|
1286
|
-
|
|
1287
|
-
const inputTensor = new Onnx.Tensor('float32', flattenedLogMelSpectrogram, [1, filterbankCount, maxAudioFrames])
|
|
1288
|
-
|
|
1289
|
-
const encoderInputs = { mel: inputTensor }
|
|
1290
|
-
|
|
1291
|
-
const encoderOutputs = await this.audioEncoder!.run(encoderInputs)
|
|
1292
|
-
const encodedAudioFeatures = encoderOutputs['output']
|
|
1293
|
-
|
|
1294
|
-
logger.end()
|
|
1295
|
-
|
|
1296
|
-
return encodedAudioFeatures
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
1111
|
tokenTimelineToWordTimeline(tokenTimeline: Timeline, language: string): Timeline {
|
|
1300
1112
|
function isSeparatorCharacter(char: string) {
|
|
1301
1113
|
const nonSeparatingPunctuation = [`'`, `-`, `.`, `·`, `•`]
|
|
@@ -1304,7 +1116,7 @@ export class Whisper {
|
|
|
1304
1116
|
return false
|
|
1305
1117
|
}
|
|
1306
1118
|
|
|
1307
|
-
return
|
|
1119
|
+
return isAllWhitespace(char) || includesPunctuation(char)
|
|
1308
1120
|
}
|
|
1309
1121
|
|
|
1310
1122
|
function startsWithSeparatorCharacter(text: string) {
|
|
@@ -1410,6 +1222,7 @@ export class Whisper {
|
|
|
1410
1222
|
const tokenIndex = tokenMappingEntry.source
|
|
1411
1223
|
const token = tokens[tokenIndex]
|
|
1412
1224
|
const tokenConfidence = tokensConfidence ? tokensConfidence[tokenIndex] : undefined
|
|
1225
|
+
|
|
1413
1226
|
const tokenText = this.tokenToText(token, true)
|
|
1414
1227
|
|
|
1415
1228
|
let startTime = startTimeOffset + (tokenMappingEntry.dest * 0.02)
|
|
@@ -1437,41 +1250,48 @@ export class Whisper {
|
|
|
1437
1250
|
return tokenTimeline
|
|
1438
1251
|
}
|
|
1439
1252
|
|
|
1440
|
-
async
|
|
1441
|
-
|
|
1253
|
+
async findAlignmentPathFromCrossAttentionQKs(
|
|
1254
|
+
crossAttentionQKs: CrossAttentionQKs[],
|
|
1255
|
+
tokens: number[],
|
|
1256
|
+
partStartFrameIndex: number,
|
|
1257
|
+
partEndFrameIndex: number,
|
|
1258
|
+
alignmentHeadsIndexesToUse?: number[]) {
|
|
1442
1259
|
|
|
1443
|
-
|
|
1260
|
+
const partFrameCount = partEndFrameIndex - partStartFrameIndex
|
|
1261
|
+
|
|
1262
|
+
if (partFrameCount === 0 || tokens.length === 0 || crossAttentionQKs.length === 0 || crossAttentionQKs[0].data.length === 0) {
|
|
1444
1263
|
return []
|
|
1445
1264
|
}
|
|
1446
1265
|
|
|
1447
|
-
|
|
1448
|
-
const
|
|
1449
|
-
|
|
1450
|
-
const
|
|
1266
|
+
// crossAttentionQKs internal dimensions: [heads, tokens = 1, frames]
|
|
1267
|
+
const tokenCount = crossAttentionQKs.length
|
|
1268
|
+
|
|
1269
|
+
const headCount = Number(crossAttentionQKs[0].dimensions[0])
|
|
1270
|
+
const frameCount = Number(crossAttentionQKs[0].dimensions[2])
|
|
1451
1271
|
|
|
1452
|
-
if (!
|
|
1453
|
-
|
|
1272
|
+
if (!alignmentHeadsIndexesToUse) {
|
|
1273
|
+
alignmentHeadsIndexesToUse = getIntegerRange(0, headCount)
|
|
1454
1274
|
}
|
|
1455
1275
|
|
|
1456
|
-
//
|
|
1457
|
-
const attentionHeads: Float32Array[][] = [] //
|
|
1276
|
+
// Initialize attention head arrays
|
|
1277
|
+
const attentionHeads: Float32Array[][] = [] // dimensions: [heads, tokens, frames]
|
|
1458
1278
|
|
|
1459
|
-
for (const headIndex of
|
|
1460
|
-
const
|
|
1279
|
+
for (const headIndex of alignmentHeadsIndexesToUse) {
|
|
1280
|
+
const head: Float32Array[] = []
|
|
1461
1281
|
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
const startIndexInBuffer = bufferOffset + segmentStartFrame
|
|
1465
|
-
const endIndexInBuffer = bufferOffset + segmentEndFrame
|
|
1282
|
+
const startIndexInBuffer = headIndex * frameCount
|
|
1283
|
+
const endIndexInBuffer = startIndexInBuffer + partFrameCount
|
|
1466
1284
|
|
|
1467
|
-
|
|
1285
|
+
for (let tokenIndex = 0; tokenIndex < tokenCount; tokenIndex++) {
|
|
1286
|
+
const data = crossAttentionQKs[tokenIndex].data.subarray(startIndexInBuffer, endIndexInBuffer)
|
|
1468
1287
|
|
|
1469
|
-
|
|
1288
|
+
head.push(data)
|
|
1470
1289
|
}
|
|
1471
1290
|
|
|
1472
|
-
attentionHeads.push(
|
|
1291
|
+
attentionHeads.push(head)
|
|
1473
1292
|
}
|
|
1474
1293
|
|
|
1294
|
+
// Initialize settings
|
|
1475
1295
|
const applySoftmax = true
|
|
1476
1296
|
const normalize = true
|
|
1477
1297
|
const applyMedianFilter = true
|
|
@@ -1526,13 +1346,13 @@ export class Whisper {
|
|
|
1526
1346
|
}
|
|
1527
1347
|
}
|
|
1528
1348
|
|
|
1529
|
-
// Compute the mean of the selected attention heads for
|
|
1349
|
+
// Compute the mean of the selected attention heads for each frame
|
|
1530
1350
|
const frameMeansForToken: Float32Array[] = []
|
|
1531
1351
|
|
|
1532
1352
|
for (let tokenIndex = 0; tokenIndex < tokenCount; tokenIndex++) {
|
|
1533
|
-
const meansForFrames = new Float32Array(
|
|
1353
|
+
const meansForFrames = new Float32Array(partFrameCount)
|
|
1534
1354
|
|
|
1535
|
-
for (let frameIndex = 0; frameIndex <
|
|
1355
|
+
for (let frameIndex = 0; frameIndex < partFrameCount; frameIndex++) {
|
|
1536
1356
|
let sum = 0
|
|
1537
1357
|
|
|
1538
1358
|
for (const head of attentionHeads) {
|
|
@@ -1549,7 +1369,7 @@ export class Whisper {
|
|
|
1549
1369
|
|
|
1550
1370
|
// Anchor timestamp tokens timestamps to their original values, if enabled
|
|
1551
1371
|
if (anchorTimestampTokens) {
|
|
1552
|
-
const timestampTokensStart = this.
|
|
1372
|
+
const timestampTokensStart = this.specialTokens.timestampTokensStart
|
|
1553
1373
|
|
|
1554
1374
|
for (let tokenIndex = 0; tokenIndex < tokens.length; tokenIndex++) {
|
|
1555
1375
|
const token = tokens[tokenIndex]
|
|
@@ -1557,7 +1377,7 @@ export class Whisper {
|
|
|
1557
1377
|
if (this.isTimestampToken(token)) {
|
|
1558
1378
|
let timestampFrame = token - timestampTokensStart
|
|
1559
1379
|
|
|
1560
|
-
timestampFrame = clip(timestampFrame,
|
|
1380
|
+
timestampFrame = clip(timestampFrame, partStartFrameIndex, partEndFrameIndex - 1)
|
|
1561
1381
|
|
|
1562
1382
|
frameMeansForToken[tokenIndex][timestampFrame] = 100
|
|
1563
1383
|
}
|
|
@@ -1566,37 +1386,100 @@ export class Whisper {
|
|
|
1566
1386
|
|
|
1567
1387
|
// Perform DTW to align tokens indexes to frame indexes
|
|
1568
1388
|
const tokenIndexes = getIntegerRange(0, tokenCount)
|
|
1569
|
-
const frameIndexes = getIntegerRange(0,
|
|
1389
|
+
const frameIndexes = getIntegerRange(0, partFrameCount)
|
|
1570
1390
|
|
|
1571
1391
|
let { path } = alignDTWWindowed(tokenIndexes, frameIndexes, (tokenIndex, frameIndex) => {
|
|
1572
1392
|
return -frameMeansForToken[tokenIndex][frameIndex]
|
|
1573
|
-
},
|
|
1393
|
+
}, partFrameCount)
|
|
1574
1394
|
|
|
1575
|
-
path = path.map(entry => ({ source: entry.source, dest:
|
|
1395
|
+
path = path.map(entry => ({ source: entry.source, dest: partStartFrameIndex + entry.dest }))
|
|
1576
1396
|
|
|
1577
1397
|
return path
|
|
1578
1398
|
}
|
|
1579
1399
|
|
|
1580
|
-
async initializeIfNeeded() {
|
|
1581
|
-
await this.initializeTokenizerIfNeeded()
|
|
1582
|
-
await this.
|
|
1583
|
-
await this.initializeDecoderSessionIfNeeded()
|
|
1400
|
+
async initializeIfNeeded(options: WhisperOptions, callbacks: OperationCallbacks) {
|
|
1401
|
+
await this.initializeTokenizerIfNeeded(callbacks)
|
|
1402
|
+
await this.initializeContextIfNeeded(options, callbacks)
|
|
1584
1403
|
}
|
|
1585
1404
|
|
|
1586
|
-
async
|
|
1405
|
+
async initializeContextIfNeeded(options: WhisperOptions, callbacks: OperationCallbacks) {
|
|
1406
|
+
if (this.context) {
|
|
1407
|
+
return
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
const logger = new Logger(callbacks.logLevel)
|
|
1411
|
+
|
|
1412
|
+
const modelId = this.modelId
|
|
1413
|
+
const modelFilePath = this.modelPath
|
|
1414
|
+
const libPath = this.libPath
|
|
1415
|
+
|
|
1416
|
+
let libFilePath: string
|
|
1417
|
+
|
|
1418
|
+
if (process.platform === 'win32') {
|
|
1419
|
+
libFilePath = resolvePath(libPath, 'whisper.dll')
|
|
1420
|
+
} else if (process.platform === 'darwin') {
|
|
1421
|
+
libFilePath = resolvePath(libPath, 'libwhisper.0.dylib')
|
|
1422
|
+
} else if (process.platform === 'linux') {
|
|
1423
|
+
libFilePath = resolvePath(libPath, 'libwhisper.so.0')
|
|
1424
|
+
} else {
|
|
1425
|
+
throw new Error(`Unsupported platform`)
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
await logger.startAsync(`Load whisper.cpp model '${modelId}'`)
|
|
1429
|
+
|
|
1430
|
+
this.context = new WhisperCppContext()
|
|
1431
|
+
|
|
1432
|
+
let alignmentHeadsPreset: WhisperAlignmentHeadsPreset
|
|
1433
|
+
let alignmentHeadsTopCount = 0
|
|
1434
|
+
|
|
1435
|
+
if (options.timestampAccuracy == 'high') {
|
|
1436
|
+
alignmentHeadsPreset = WhisperAlignmentHeadsPreset.WHISPER_AHEADS_N_TOP_MOST
|
|
1437
|
+
alignmentHeadsTopCount = whisperModelIdToTextLayerCount[modelId]
|
|
1438
|
+
} else {
|
|
1439
|
+
alignmentHeadsPreset = whisperModelIdToAlignmentHeadsPreset[modelId]
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
const contextOptions: WhisperCppContextOptions = {
|
|
1443
|
+
libFilePath,
|
|
1444
|
+
modelFilePath,
|
|
1445
|
+
|
|
1446
|
+
// Force GPU option to be enabled for all GPU and CPU builds
|
|
1447
|
+
// The `enableGPU` option in `WhisperOptions` doesn't impact this
|
|
1448
|
+
enableGPU: true,
|
|
1449
|
+
|
|
1450
|
+
// Flash attention must be disabled for timestamp extraction to be possible
|
|
1451
|
+
// in the way it's done here
|
|
1452
|
+
enableFlashAttention: false,
|
|
1453
|
+
|
|
1454
|
+
// Device index is passed. Defaults to 0
|
|
1455
|
+
gpuDeviceIndex: options.gpuDeviceIndex!,
|
|
1456
|
+
|
|
1457
|
+
alignmentHeadsPreset,
|
|
1458
|
+
alignmentHeadsTopCount,
|
|
1459
|
+
|
|
1460
|
+
//logLevel: logger.logLevelGreaterOrEqualTo('trace') ? GgmlLogLevel.GGML_LOG_LEVEL_INFO : GgmlLogLevel.GGML_LOG_LEVEL_WARN,
|
|
1461
|
+
logLevel: GgmlLogLevel.GGML_LOG_LEVEL_WARN,
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
await this.context.initialize(contextOptions)
|
|
1465
|
+
|
|
1466
|
+
logger.end()
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
async initializeTokenizerIfNeeded(callbacks: LoadPackageCallbacks) {
|
|
1587
1470
|
if (this.tiktoken) {
|
|
1588
1471
|
return
|
|
1589
1472
|
}
|
|
1590
1473
|
|
|
1591
|
-
const logger = new Logger()
|
|
1474
|
+
const logger = new Logger(callbacks.logLevel)
|
|
1592
1475
|
await logger.startAsync('Load tokenizer data')
|
|
1593
1476
|
|
|
1594
|
-
const tiktokenModulePackagePath = await loadPackage('whisper-tiktoken-data')
|
|
1477
|
+
const tiktokenModulePackagePath = await loadPackage('whisper-tiktoken-data', callbacks)
|
|
1595
1478
|
|
|
1596
1479
|
const tiktokenDataFilePath = joinPath(tiktokenModulePackagePath, this.isMultiligualModel ? 'multilingual.tiktoken' : 'gpt2.tiktoken')
|
|
1597
1480
|
let tiktokenData = await readFileAsUtf8(tiktokenDataFilePath)
|
|
1598
1481
|
|
|
1599
|
-
const tokenConfig = this.
|
|
1482
|
+
const tokenConfig = this.specialTokens
|
|
1600
1483
|
|
|
1601
1484
|
const metadataTokens: Record<number, string> = {
|
|
1602
1485
|
[tokenConfig.endOfTextToken]: '[EndOfText]',
|
|
@@ -1616,7 +1499,7 @@ export class Whisper {
|
|
|
1616
1499
|
const languageTokenCount = tokenConfig.languageTokensEnd - tokenConfig.languageTokensStart
|
|
1617
1500
|
|
|
1618
1501
|
for (let i = 0; i < languageTokenCount; i++) {
|
|
1619
|
-
const tokenIndex = this.
|
|
1502
|
+
const tokenIndex = this.specialTokens.languageTokensStart + i
|
|
1620
1503
|
|
|
1621
1504
|
metadataTokens[tokenIndex] = `[Language_${i}]`
|
|
1622
1505
|
}
|
|
@@ -1624,7 +1507,7 @@ export class Whisper {
|
|
|
1624
1507
|
const timestampTokensCount = 1501
|
|
1625
1508
|
|
|
1626
1509
|
for (let i = 0; i <= timestampTokensCount; i++) {
|
|
1627
|
-
const tokenIndex = this.
|
|
1510
|
+
const tokenIndex = this.specialTokens.timestampTokensStart + i
|
|
1628
1511
|
const tokenTime = this.timestampTokenToSeconds(tokenIndex)
|
|
1629
1512
|
|
|
1630
1513
|
metadataTokens[tokenIndex] = `[Timestamp_${tokenTime.toFixed(2)}]`
|
|
@@ -1645,76 +1528,14 @@ export class Whisper {
|
|
|
1645
1528
|
logger.end()
|
|
1646
1529
|
}
|
|
1647
1530
|
|
|
1648
|
-
async initializeEncoderSessionIfNeeded() {
|
|
1649
|
-
if (this.audioEncoder) {
|
|
1650
|
-
return
|
|
1651
|
-
}
|
|
1652
|
-
|
|
1653
|
-
const logger = new Logger()
|
|
1654
|
-
|
|
1655
|
-
const onnxSessionOptions = getOnnxSessionOptions({ executionProviders: this.encoderExecutionProviders })
|
|
1656
|
-
|
|
1657
|
-
const onnxProvidersString = onnxSessionOptions.executionProviders!.length > 0 ? `${onnxSessionOptions.executionProviders!.join(', ')}` : `default`
|
|
1658
|
-
|
|
1659
|
-
await logger.startAsync(`Create encoder inference session for model '${this.modelName}' (ONNX provider: ${onnxProvidersString})`)
|
|
1660
|
-
|
|
1661
|
-
const encoderFilePath = joinPath(this.modelDir, 'encoder.onnx')
|
|
1662
|
-
|
|
1663
|
-
const Onnx = await import('onnxruntime-node')
|
|
1664
|
-
|
|
1665
|
-
this.audioEncoder = await Onnx.InferenceSession.create(encoderFilePath, onnxSessionOptions)
|
|
1666
|
-
|
|
1667
|
-
logger.end()
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
|
-
async initializeDecoderSessionIfNeeded() {
|
|
1671
|
-
if (this.textDecoder) {
|
|
1672
|
-
return
|
|
1673
|
-
}
|
|
1674
|
-
|
|
1675
|
-
const logger = new Logger()
|
|
1676
|
-
|
|
1677
|
-
const onnxSessionOptions = getOnnxSessionOptions({ executionProviders: this.decoderExecutionProviders })
|
|
1678
|
-
|
|
1679
|
-
const onnxProvidersString = onnxSessionOptions.executionProviders!.length > 0 ? `${onnxSessionOptions.executionProviders!.join(', ')}` : `default`
|
|
1680
|
-
|
|
1681
|
-
await logger.startAsync(`Create decoder inference session for model '${this.modelName}' (ONNX provider: ${onnxProvidersString})`)
|
|
1682
|
-
|
|
1683
|
-
const decoderFilePath = joinPath(this.modelDir, 'decoder.onnx')
|
|
1684
|
-
|
|
1685
|
-
const Onnx = await import('onnxruntime-node')
|
|
1686
|
-
|
|
1687
|
-
this.textDecoder = await Onnx.InferenceSession.create(decoderFilePath, onnxSessionOptions)
|
|
1688
|
-
|
|
1689
|
-
logger.end()
|
|
1690
|
-
}
|
|
1691
|
-
|
|
1692
|
-
getKvDimensions(groupCount: number, length: number) {
|
|
1693
|
-
const modelName = this.modelName
|
|
1694
|
-
|
|
1695
|
-
if (modelName === 'tiny' || modelName === 'tiny.en') {
|
|
1696
|
-
return [8, groupCount, length, 384]
|
|
1697
|
-
} else if (modelName === 'base' || modelName === 'base.en') {
|
|
1698
|
-
return [12, groupCount, length, 512]
|
|
1699
|
-
} else if (modelName === 'small' || modelName === 'small.en') {
|
|
1700
|
-
return [24, groupCount, length, 768]
|
|
1701
|
-
} else if (modelName === 'medium' || modelName === 'medium.en') {
|
|
1702
|
-
return [48, groupCount, length, 1024]
|
|
1703
|
-
} else if (modelName === 'large-v1' || modelName === 'large-v2' || modelName === 'large-v3' || modelName === 'large-v3-turbo') {
|
|
1704
|
-
return [64, groupCount, length, 1280]
|
|
1705
|
-
} else {
|
|
1706
|
-
throw new Error(`Unsupported model: ${modelName}`)
|
|
1707
|
-
}
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
1531
|
getTextStartTokens(language: string, task: WhisperTask, disableTimestamps = false) {
|
|
1711
|
-
const startOfTextToken = this.
|
|
1532
|
+
const startOfTextToken = this.specialTokens.startOfTextToken
|
|
1712
1533
|
|
|
1713
1534
|
let tokens: number[]
|
|
1714
1535
|
|
|
1715
1536
|
if (this.isMultiligualModel) {
|
|
1716
|
-
const languageToken = this.
|
|
1717
|
-
const taskToken = task === 'translate' ? this.
|
|
1537
|
+
const languageToken = this.specialTokens.languageTokensStart + languageIdLookup[language]
|
|
1538
|
+
const taskToken = task === 'translate' ? this.specialTokens.translateTaskToken : this.specialTokens.transcribeTaskToken
|
|
1718
1539
|
|
|
1719
1540
|
tokens = [startOfTextToken, languageToken, taskToken]
|
|
1720
1541
|
} else {
|
|
@@ -1722,7 +1543,7 @@ export class Whisper {
|
|
|
1722
1543
|
}
|
|
1723
1544
|
|
|
1724
1545
|
if (disableTimestamps) {
|
|
1725
|
-
tokens.push(this.
|
|
1546
|
+
tokens.push(this.specialTokens.noTimestampsToken)
|
|
1726
1547
|
}
|
|
1727
1548
|
|
|
1728
1549
|
return tokens
|
|
@@ -1732,6 +1553,18 @@ export class Whisper {
|
|
|
1732
1553
|
return this.tokensToText([token], includeMetadataTokens)
|
|
1733
1554
|
}
|
|
1734
1555
|
|
|
1556
|
+
tokenToBytes(token: number) {
|
|
1557
|
+
return this.tiktoken!.decode_single_token_bytes(token)
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
tokensToBytes(tokens: number[]) {
|
|
1561
|
+
const tokensBytes = tokens.map(token => this.tokenToBytes(token))
|
|
1562
|
+
|
|
1563
|
+
const concatenatedTokensBytes = concatUint8Arrays(tokensBytes)
|
|
1564
|
+
|
|
1565
|
+
return concatenatedTokensBytes
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1735
1568
|
tokensToText(tokens: number[], includeMetadataTokens = false) {
|
|
1736
1569
|
tokens.forEach(token => this.assertIsValidToken(token))
|
|
1737
1570
|
|
|
@@ -1743,13 +1576,13 @@ export class Whisper {
|
|
|
1743
1576
|
return ''
|
|
1744
1577
|
}
|
|
1745
1578
|
|
|
1746
|
-
|
|
1579
|
+
try {
|
|
1580
|
+
const decodedBytes = this.tiktoken!.decode(new Uint32Array(tokens))
|
|
1747
1581
|
|
|
1748
|
-
|
|
1582
|
+
const textDecoder = new TextDecoder()
|
|
1749
1583
|
|
|
1750
|
-
|
|
1584
|
+
const decodedString = textDecoder.decode(decodedBytes)
|
|
1751
1585
|
|
|
1752
|
-
try {
|
|
1753
1586
|
return decodedString
|
|
1754
1587
|
} catch {
|
|
1755
1588
|
return '[TOKENIZER_FAILED]'
|
|
@@ -1761,23 +1594,23 @@ export class Whisper {
|
|
|
1761
1594
|
}
|
|
1762
1595
|
|
|
1763
1596
|
isTextToken(token: number) {
|
|
1764
|
-
return token < this.
|
|
1597
|
+
return token < this.specialTokens.endOfTextToken
|
|
1765
1598
|
}
|
|
1766
1599
|
|
|
1767
1600
|
isMetadataToken(token: number) {
|
|
1768
|
-
return token >= this.
|
|
1601
|
+
return token >= this.specialTokens.endOfTextToken
|
|
1769
1602
|
}
|
|
1770
1603
|
|
|
1771
1604
|
isLanguageToken(token: number) {
|
|
1772
|
-
return token >= this.
|
|
1605
|
+
return token >= this.specialTokens.languageTokensStart && token < this.specialTokens.languageTokensEnd
|
|
1773
1606
|
}
|
|
1774
1607
|
|
|
1775
1608
|
isTimestampToken(token: number) {
|
|
1776
|
-
return token >= this.
|
|
1609
|
+
return token >= this.specialTokens.timestampTokensStart
|
|
1777
1610
|
}
|
|
1778
1611
|
|
|
1779
1612
|
isNonTimestampToken(token: number) {
|
|
1780
|
-
return token < this.
|
|
1613
|
+
return token < this.specialTokens.timestampTokensStart
|
|
1781
1614
|
}
|
|
1782
1615
|
|
|
1783
1616
|
timestampTokenToSeconds(timestampToken: number) {
|
|
@@ -1787,7 +1620,7 @@ export class Whisper {
|
|
|
1787
1620
|
throw new Error(`Invalid timestamp token: ${timestampToken}`)
|
|
1788
1621
|
}
|
|
1789
1622
|
|
|
1790
|
-
let seconds = (timestampToken - this.
|
|
1623
|
+
let seconds = (timestampToken - this.specialTokens.timestampTokensStart) * 0.02
|
|
1791
1624
|
seconds = clip(seconds, 0.0, 30.0)
|
|
1792
1625
|
|
|
1793
1626
|
return seconds
|
|
@@ -1795,7 +1628,7 @@ export class Whisper {
|
|
|
1795
1628
|
|
|
1796
1629
|
isValidToken(token: number) {
|
|
1797
1630
|
//return token < this.tokenConfig.timestampTokensEnd
|
|
1798
|
-
return token <= this.
|
|
1631
|
+
return token <= this.specialTokens.timestampTokensEnd
|
|
1799
1632
|
}
|
|
1800
1633
|
|
|
1801
1634
|
assertIsValidToken(token: number) {
|
|
@@ -1821,7 +1654,7 @@ export class Whisper {
|
|
|
1821
1654
|
throw new Error(`Invalid language token: ${languageToken}`)
|
|
1822
1655
|
}
|
|
1823
1656
|
|
|
1824
|
-
let languageIndex = languageToken - this.
|
|
1657
|
+
let languageIndex = languageToken - this.specialTokens.languageTokensStart
|
|
1825
1658
|
|
|
1826
1659
|
if (this.isEnglishOnlyModel) {
|
|
1827
1660
|
languageIndex += 1
|
|
@@ -1832,24 +1665,20 @@ export class Whisper {
|
|
|
1832
1665
|
return this.isMultiligualModel === false
|
|
1833
1666
|
}
|
|
1834
1667
|
|
|
1835
|
-
get
|
|
1836
|
-
return this.
|
|
1837
|
-
}
|
|
1838
|
-
|
|
1839
|
-
get filterbankCount() {
|
|
1840
|
-
return this.isLargeModel ? 128 : 80
|
|
1668
|
+
get isLargeV3Model() {
|
|
1669
|
+
return this.modelId.startsWith('large-v3')
|
|
1841
1670
|
}
|
|
1842
1671
|
|
|
1843
|
-
get
|
|
1844
|
-
return this.
|
|
1672
|
+
get melBandCount() {
|
|
1673
|
+
return this.isLargeV3Model ? 128 : 80
|
|
1845
1674
|
}
|
|
1846
1675
|
|
|
1847
|
-
get
|
|
1848
|
-
return
|
|
1676
|
+
get melFilterbank() {
|
|
1677
|
+
return this.isLargeV3Model ? melFilterbank128 : melFilterbanks80
|
|
1849
1678
|
}
|
|
1850
1679
|
|
|
1851
1680
|
get defaultTimestampAccuracy() {
|
|
1852
|
-
if (this.
|
|
1681
|
+
if (this.modelId.startsWith('tiny') || this.modelId.startsWith('base')) {
|
|
1853
1682
|
return 'high'
|
|
1854
1683
|
} else {
|
|
1855
1684
|
return 'medium'
|
|
@@ -1906,7 +1735,7 @@ export class Whisper {
|
|
|
1906
1735
|
const wordTokenData: WhisperTokenData[] = []
|
|
1907
1736
|
const nonWordTokenData: WhisperTokenData[] = []
|
|
1908
1737
|
|
|
1909
|
-
for (let i = 0; i < this.
|
|
1738
|
+
for (let i = 0; i < this.specialTokens.endOfTextToken; i++) {
|
|
1910
1739
|
const tokenText = this.tokenToText(i, false)
|
|
1911
1740
|
|
|
1912
1741
|
const isNonWordToken = /^[\s\p{Punctuation}\p{Symbol}]+$/u.test(tokenText)
|
|
@@ -1943,109 +1772,68 @@ export class Whisper {
|
|
|
1943
1772
|
}
|
|
1944
1773
|
}
|
|
1945
1774
|
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
} else {
|
|
1950
|
-
if (languageCode) {
|
|
1951
|
-
const shortLanguageCode = getShortLanguageCode(languageCode)
|
|
1775
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
1776
|
+
// Utility methods
|
|
1777
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
1952
1778
|
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
modelName = 'tiny'
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
|
-
|
|
1959
|
-
if (modelName.startsWith('large') && modelName !== 'large-v3-turbo') {
|
|
1960
|
-
throw new Error(`Models 'large-v1', 'large-v2', 'large-v3' are not currently supported by the integrated Whisper engine due to model size restrictions of onnxruntime-node. To use large models, you can either select large-v3-turbo use the whisper.cpp engine instead.`)
|
|
1961
|
-
}
|
|
1962
|
-
|
|
1963
|
-
const packageName = modelNameToPackageName[modelName]
|
|
1964
|
-
|
|
1965
|
-
const modelDir = await loadPackage(packageName)
|
|
1966
|
-
|
|
1967
|
-
return { modelName, modelDir }
|
|
1779
|
+
export function isMultilingualModel(modelId: WhisperModelId) {
|
|
1780
|
+
return !isEnglishOnlyModel(modelId)
|
|
1968
1781
|
}
|
|
1969
1782
|
|
|
1970
|
-
export function
|
|
1971
|
-
|
|
1972
|
-
const originalModelName = modelName
|
|
1973
|
-
modelName = modelName.slice(0, modelName.length - 3) as WhisperModelName
|
|
1974
|
-
|
|
1975
|
-
const logger = new Logger()
|
|
1976
|
-
logger.logTitledMessage(`Warning`, `The model '${originalModelName}' is English only and cannot be used to transcribe language '${languageCode}'. Using '${modelName}' instead.`, chalk.yellowBright, 'warning')
|
|
1977
|
-
}
|
|
1978
|
-
|
|
1979
|
-
return modelName
|
|
1783
|
+
export function isEnglishOnlyModel(modelId: WhisperModelId) {
|
|
1784
|
+
return modelId.endsWith('.en')
|
|
1980
1785
|
}
|
|
1981
1786
|
|
|
1982
|
-
export function
|
|
1983
|
-
|
|
1984
|
-
|
|
1787
|
+
export async function loadLibraryPackages(enableGPU: boolean | undefined, callbacks: LoadPackageCallbacks) {
|
|
1788
|
+
const arch = process.arch
|
|
1789
|
+
const platform = process.platform
|
|
1985
1790
|
|
|
1986
|
-
|
|
1987
|
-
return modelName.endsWith('.en')
|
|
1988
|
-
}
|
|
1791
|
+
let packageName: string
|
|
1989
1792
|
|
|
1990
|
-
|
|
1991
|
-
if (dmlProviderAvailable()) {
|
|
1992
|
-
return ['dml', 'cpu']
|
|
1993
|
-
} else {
|
|
1994
|
-
return []
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1793
|
+
const useMacOsGpuBuildByDefault = true
|
|
1997
1794
|
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
return ['dml', 'cpu']
|
|
1795
|
+
if (platform === 'win32' && arch === 'x64') {
|
|
1796
|
+
if (enableGPU) {
|
|
1797
|
+
packageName = 'whisper.cpp-lib-windows-x64-cublas-12.4.0'
|
|
2002
1798
|
} else {
|
|
2003
|
-
|
|
1799
|
+
packageName = 'whisper.cpp-lib-windows-x64-cpu'
|
|
2004
1800
|
}
|
|
1801
|
+
} else if (platform === 'win32' && arch === 'arm64') {
|
|
1802
|
+
packageName = 'whisper.cpp-lib-windows-arm64-cpu'
|
|
1803
|
+
} else if (platform === 'darwin' && arch === 'x64') {
|
|
1804
|
+
if (useMacOsGpuBuildByDefault || enableGPU) {
|
|
1805
|
+
packageName = 'whisper.cpp-lib-macos-universal'
|
|
1806
|
+
} else {
|
|
1807
|
+
packageName = 'whisper.cpp-lib-macos-universal-cpu-basic'
|
|
1808
|
+
}
|
|
1809
|
+
} else if (platform === 'darwin' && arch === 'arm64') {
|
|
1810
|
+
if (useMacOsGpuBuildByDefault || enableGPU) {
|
|
1811
|
+
packageName = 'whisper.cpp-lib-macos-universal'
|
|
1812
|
+
} else {
|
|
1813
|
+
packageName = 'whisper.cpp-lib-macos-universal-cpu-basic'
|
|
1814
|
+
}
|
|
1815
|
+
} else if (platform === 'linux' && arch === 'x64') {
|
|
1816
|
+
if (enableGPU) {
|
|
1817
|
+
packageName = 'whisper.cpp-lib-linux-x64-cublas-12.4.0'
|
|
1818
|
+
} else {
|
|
1819
|
+
packageName = 'whisper.cpp-lib-linux-x64-cpu'
|
|
1820
|
+
}
|
|
1821
|
+
} else if (platform === 'linux' && arch === 'arm64') {
|
|
1822
|
+
packageName = 'whisper.cpp-lib-linux-arm64-cpu'
|
|
2005
1823
|
} else {
|
|
2006
|
-
|
|
1824
|
+
throw new Error(`The platform and architecture combination ${platform} / ${arch} is not supported by the Whisper engine`)
|
|
2007
1825
|
}
|
|
2008
|
-
}
|
|
2009
1826
|
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
}
|
|
1827
|
+
const whisperCppLibPath = await loadPackage(packageName, callbacks)
|
|
1828
|
+
|
|
1829
|
+
const libPath = whisperCppLibPath
|
|
2014
1830
|
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
export type WhisperModelName =
|
|
2018
|
-
'tiny' |
|
|
2019
|
-
'tiny.en' |
|
|
2020
|
-
'base' |
|
|
2021
|
-
'base.en' |
|
|
2022
|
-
'small' |
|
|
2023
|
-
'small.en' |
|
|
2024
|
-
'medium' |
|
|
2025
|
-
'medium.en' |
|
|
2026
|
-
'large-v1' |
|
|
2027
|
-
'large-v2' |
|
|
2028
|
-
'large-v3' |
|
|
2029
|
-
'large-v3-turbo'
|
|
2030
|
-
|
|
2031
|
-
export type WhisperTask = 'transcribe' | 'translate' | 'detect-language'
|
|
2032
|
-
|
|
2033
|
-
export const modelNameToPackageName: { [modelName in WhisperModelName]: string } = {
|
|
2034
|
-
'tiny': 'whisper-tiny',
|
|
2035
|
-
'tiny.en': 'whisper-tiny.en',
|
|
2036
|
-
'base': 'whisper-base',
|
|
2037
|
-
'base.en': 'whisper-base.en',
|
|
2038
|
-
'small': 'whisper-small',
|
|
2039
|
-
'small.en': 'whisper-small.en',
|
|
2040
|
-
'medium': 'whisper-medium',
|
|
2041
|
-
'medium.en': 'whisper-medium.en',
|
|
2042
|
-
'large-v1': 'whisper-large-v1',
|
|
2043
|
-
'large-v2': 'whisper-large-v2',
|
|
2044
|
-
'large-v3': 'whisper-large-v3',
|
|
2045
|
-
'large-v3-turbo': 'whisper-large-v3-turbo-fp16',
|
|
1831
|
+
return { libPath }
|
|
2046
1832
|
}
|
|
2047
1833
|
|
|
2048
|
-
|
|
1834
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
1835
|
+
// Tables
|
|
1836
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
2049
1837
|
|
|
2050
1838
|
const languageIdLookup: { [s: string]: number } = {
|
|
2051
1839
|
'en': 0,
|
|
@@ -2150,7 +1938,7 @@ const languageIdLookup: { [s: string]: number } = {
|
|
|
2150
1938
|
//'yue': 99
|
|
2151
1939
|
}
|
|
2152
1940
|
|
|
2153
|
-
const
|
|
1941
|
+
const alignmentHeadsIndices: { [name in WhisperModelId]: number[] } = {
|
|
2154
1942
|
'tiny': [14, 18, 20, 21, 22, 23,],
|
|
2155
1943
|
'tiny.en': [6, 12, 17, 18, 19, 20, 21, 22,],
|
|
2156
1944
|
'base': [25, 34, 35, 39, 41, 42, 44, 46,],
|
|
@@ -2165,7 +1953,7 @@ const alignmentHeadsIndexes: { [name in WhisperModelName]: number[] } = {
|
|
|
2165
1953
|
'large-v3-turbo': [44, 51, 63, 66, 71, 74,],
|
|
2166
1954
|
}
|
|
2167
1955
|
|
|
2168
|
-
const
|
|
1956
|
+
const melFilterbanks80: Filterbank = [
|
|
2169
1957
|
/* 0 */ { startIndex: 1, weights: [0.02486259490251541,] },
|
|
2170
1958
|
|
|
2171
1959
|
/* 1 */ { startIndex: 1, weights: [0.001990821911022067, 0.022871771827340126,] },
|
|
@@ -2327,7 +2115,7 @@ const filterbanks_80: Filterbank[] = [
|
|
|
2327
2115
|
/* 79 */ { startIndex: 186, weights: [0.000366741674952209, 0.0008330700220540166, 0.0012993983691558242, 0.0017657268326729536, 0.0022320549469441175, 0.002698383294045925, 0.0031647118739783764, 0.003141313325613737, 0.002692554146051407, 0.0022437951993197203, 0.00179503601975739, 0.0013462770730257034, 0.000897518009878695, 0.0004487590049393475,] },
|
|
2328
2116
|
]
|
|
2329
2117
|
|
|
2330
|
-
const
|
|
2118
|
+
const melFilterbank128: Filterbank = [
|
|
2331
2119
|
/* 0 */ { startIndex: 1, weights: [0.012373986653983593,] },
|
|
2332
2120
|
|
|
2333
2121
|
/* 1 */ { startIndex: 1, weights: [0.030392564833164215,] },
|
|
@@ -2585,9 +2373,75 @@ const filterbanks_128: Filterbank[] = [
|
|
|
2585
2373
|
/* 127 */ { startIndex: 191, weights: [0.0004756950947921723, 0.0016171716852113605, 0.002758648479357362, 0.0039001251570880413, 0.005041601601988077, 0.004457120783627033, 0.003342840587720275, 0.0022285603918135166, 0.0011142801959067583,] },
|
|
2586
2374
|
]
|
|
2587
2375
|
|
|
2376
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
2377
|
+
// Types and constants
|
|
2378
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
2379
|
+
interface WhisperSpecialTokens {
|
|
2380
|
+
endOfTextToken: number
|
|
2381
|
+
startOfTextToken: number
|
|
2382
|
+
|
|
2383
|
+
languageTokensStart: number
|
|
2384
|
+
languageTokensEnd: number
|
|
2385
|
+
|
|
2386
|
+
translateTaskToken: number
|
|
2387
|
+
transcribeTaskToken: number
|
|
2388
|
+
startOfPromptToken: number
|
|
2389
|
+
nonSpeechToken: number
|
|
2390
|
+
noTimestampsToken: number
|
|
2391
|
+
|
|
2392
|
+
timestampTokensStart: number
|
|
2393
|
+
timestampTokensEnd: number
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2396
|
+
const multilingualSpecialTokens: WhisperSpecialTokens = {
|
|
2397
|
+
endOfTextToken: 50257,
|
|
2398
|
+
startOfTextToken: 50258,
|
|
2399
|
+
|
|
2400
|
+
languageTokensStart: 50259,
|
|
2401
|
+
languageTokensEnd: 50358,
|
|
2402
|
+
|
|
2403
|
+
translateTaskToken: 50358,
|
|
2404
|
+
transcribeTaskToken: 50359,
|
|
2405
|
+
startOfPromptToken: 50361,
|
|
2406
|
+
nonSpeechToken: 50362,
|
|
2407
|
+
noTimestampsToken: 50363,
|
|
2408
|
+
|
|
2409
|
+
timestampTokensStart: 50364,
|
|
2410
|
+
timestampTokensEnd: 50364 + 1501,
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
const englishOnlySpecialTokens: WhisperSpecialTokens = {
|
|
2414
|
+
endOfTextToken: 50256,
|
|
2415
|
+
startOfTextToken: 50257,
|
|
2416
|
+
|
|
2417
|
+
languageTokensStart: 50258,
|
|
2418
|
+
languageTokensEnd: 50358,
|
|
2419
|
+
|
|
2420
|
+
translateTaskToken: 50358,
|
|
2421
|
+
transcribeTaskToken: 50359,
|
|
2422
|
+
startOfPromptToken: 50360,
|
|
2423
|
+
nonSpeechToken: 50361,
|
|
2424
|
+
noTimestampsToken: 50362,
|
|
2425
|
+
|
|
2426
|
+
timestampTokensStart: 50363,
|
|
2427
|
+
timestampTokensEnd: 50363 + 1501,
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
export type WhisperLogitFilter = (logits: Float32Array, decodedTokens: number[], isFirstPart: boolean, isFinalPart: boolean) => Float32Array
|
|
2431
|
+
|
|
2432
|
+
export type WhisperTokenData = {
|
|
2433
|
+
id: number
|
|
2434
|
+
text: string
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2588
2437
|
// Recognition options
|
|
2589
2438
|
export interface WhisperOptions {
|
|
2590
|
-
model?:
|
|
2439
|
+
model?: WhisperQuantizedModelId
|
|
2440
|
+
|
|
2441
|
+
enableGPU?: boolean
|
|
2442
|
+
threadCount?: number
|
|
2443
|
+
gpuDeviceIndex?: number
|
|
2444
|
+
|
|
2591
2445
|
temperature?: number
|
|
2592
2446
|
prompt?: string
|
|
2593
2447
|
topCandidateCount?: number
|
|
@@ -2600,8 +2454,6 @@ export interface WhisperOptions {
|
|
|
2600
2454
|
endTokenThreshold?: number
|
|
2601
2455
|
includeEndTokenInCandidates?: boolean
|
|
2602
2456
|
timestampAccuracy?: WhisperTimestampAccuracy,
|
|
2603
|
-
encoderProvider?: OnnxExecutionProvider
|
|
2604
|
-
decoderProvider?: OnnxExecutionProvider
|
|
2605
2457
|
seed?: number
|
|
2606
2458
|
}
|
|
2607
2459
|
|
|
@@ -2609,6 +2461,11 @@ const largestMaximumTokensPerPart = 220
|
|
|
2609
2461
|
|
|
2610
2462
|
export const defaultWhisperOptions: WhisperOptions = {
|
|
2611
2463
|
model: undefined,
|
|
2464
|
+
|
|
2465
|
+
enableGPU: false,
|
|
2466
|
+
threadCount: 4,
|
|
2467
|
+
gpuDeviceIndex: 0,
|
|
2468
|
+
|
|
2612
2469
|
temperature: 0.1,
|
|
2613
2470
|
prompt: undefined,
|
|
2614
2471
|
topCandidateCount: 5,
|
|
@@ -2621,62 +2478,56 @@ export const defaultWhisperOptions: WhisperOptions = {
|
|
|
2621
2478
|
endTokenThreshold: 0.9,
|
|
2622
2479
|
includeEndTokenInCandidates: true,
|
|
2623
2480
|
timestampAccuracy: undefined,
|
|
2624
|
-
encoderProvider: undefined,
|
|
2625
|
-
decoderProvider: undefined,
|
|
2626
2481
|
seed: undefined,
|
|
2627
2482
|
}
|
|
2628
2483
|
|
|
2629
2484
|
// Alignment options
|
|
2630
2485
|
export interface WhisperAlignmentOptions {
|
|
2631
|
-
model?:
|
|
2486
|
+
model?: WhisperQuantizedModelId
|
|
2487
|
+
|
|
2488
|
+
enableGPU?: boolean
|
|
2489
|
+
threadCount?: number
|
|
2490
|
+
gpuDeviceIndex?: number
|
|
2491
|
+
|
|
2632
2492
|
endTokenThreshold?: number
|
|
2633
2493
|
maxTokensPerPart?: number
|
|
2634
2494
|
timestampAccuracy?: WhisperTimestampAccuracy,
|
|
2635
|
-
|
|
2636
|
-
encoderProvider?: OnnxExecutionProvider
|
|
2637
|
-
decoderProvider?: OnnxExecutionProvider
|
|
2638
2495
|
}
|
|
2639
2496
|
|
|
2640
2497
|
export const defaultWhisperAlignmentOptions: WhisperAlignmentOptions = {
|
|
2641
2498
|
model: undefined,
|
|
2499
|
+
|
|
2500
|
+
enableGPU: false,
|
|
2501
|
+
threadCount: 4,
|
|
2502
|
+
gpuDeviceIndex: 0,
|
|
2503
|
+
|
|
2642
2504
|
endTokenThreshold: 0.9,
|
|
2643
2505
|
maxTokensPerPart: largestMaximumTokensPerPart,
|
|
2644
2506
|
timestampAccuracy: undefined,
|
|
2645
|
-
|
|
2646
|
-
encoderProvider: undefined,
|
|
2647
|
-
decoderProvider: undefined,
|
|
2648
2507
|
}
|
|
2649
2508
|
|
|
2650
2509
|
// Language detection options
|
|
2651
2510
|
export interface WhisperLanguageDetectionOptions {
|
|
2652
|
-
model?:
|
|
2511
|
+
model?: WhisperQuantizedModelId
|
|
2512
|
+
|
|
2513
|
+
enableGPU?: boolean
|
|
2514
|
+
threadCount?: number
|
|
2515
|
+
gpuDeviceIndex?: number
|
|
2516
|
+
|
|
2653
2517
|
temperature?: number
|
|
2654
|
-
encoderProvider?: OnnxExecutionProvider
|
|
2655
|
-
decoderProvider?: OnnxExecutionProvider
|
|
2656
2518
|
}
|
|
2657
2519
|
|
|
2658
2520
|
export const defaultWhisperLanguageDetectionOptions: WhisperLanguageDetectionOptions = {
|
|
2659
2521
|
model: undefined,
|
|
2660
|
-
temperature: 1.0,
|
|
2661
|
-
encoderProvider: undefined,
|
|
2662
|
-
decoderProvider: undefined,
|
|
2663
|
-
}
|
|
2664
2522
|
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
temperature?: number
|
|
2669
|
-
encoderProvider?: OnnxExecutionProvider
|
|
2670
|
-
decoderProvider?: OnnxExecutionProvider
|
|
2671
|
-
}
|
|
2523
|
+
enableGPU: false,
|
|
2524
|
+
threadCount: 4,
|
|
2525
|
+
gpuDeviceIndex: 0,
|
|
2672
2526
|
|
|
2673
|
-
export const defaultWhisperVADOptions: WhisperVADOptions = {
|
|
2674
|
-
model: undefined,
|
|
2675
2527
|
temperature: 1.0,
|
|
2676
|
-
encoderProvider: undefined,
|
|
2677
|
-
decoderProvider: undefined,
|
|
2678
2528
|
}
|
|
2679
2529
|
|
|
2680
2530
|
export type WhisperTimestampAccuracy = 'medium' | 'high'
|
|
2681
2531
|
|
|
2682
|
-
export type WhisperPartCallback = (partTranscript: string, partTokenTimeline: Timeline, partWordTimeline: Timeline) => void
|
|
2532
|
+
export type WhisperPartCallback = (partTranscript: string, partTokenTimeline: Timeline, partWordTimeline: Timeline) => Promise<void>
|
|
2533
|
+
export type WhisperTokenCallback = (tokenId: number, tokenUtf8Bytes: Uint8Array) => Promise<void>
|