From 4b878aa9204f7a0a47536f7a96825e9ff646e374 Mon Sep 17 00:00:00 2001 From: niksedk Date: Thu, 13 Apr 2023 19:38:08 +0200 Subject: [PATCH] Add download of Whisper CTranslate2 models (multi file) --- .../AudioToText/WhisperCTranslate2Model.cs | 123 +++++++++++++++++ src/libse/AudioToText/WhisperCppModel.cs | 27 ++-- src/libse/AudioToText/WhisperHelper.cs | 10 ++ src/libse/AudioToText/WhisperModel.cs | 34 ++--- .../Forms/AudioToText/WhisperAudioToText.cs | 34 +++-- .../WhisperModelDownload.Designer.cs | 23 +++- .../Forms/AudioToText/WhisperModelDownload.cs | 126 +++++++++++------- 7 files changed, 266 insertions(+), 111 deletions(-) create mode 100644 src/libse/AudioToText/WhisperCTranslate2Model.cs diff --git a/src/libse/AudioToText/WhisperCTranslate2Model.cs b/src/libse/AudioToText/WhisperCTranslate2Model.cs new file mode 100644 index 000000000..9489a1dde --- /dev/null +++ b/src/libse/AudioToText/WhisperCTranslate2Model.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Nikse.SubtitleEdit.Core.AudioToText +{ + public class WhisperCTranslate2Model : IWhisperModel + { + public string[] Urls { get; set; } + public string Size { get; set; } + public string Name { get; set; } + public bool AlreadyDownloaded { get; set; } + public long Bytes { get; set; } + + public override string ToString() + { + return $"{(AlreadyDownloaded ? "* " : string.Empty)}{Name} ({Size})"; + } + + private readonly string[] _fileNames = { "model.bin", "config.json", "vocabulary.txt", "tokenizer.json" }; + + public string ModelFolder => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".cache", "whisper-ctranslate2"); + + public void CreateModelFolder() + { + var cacheFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".cache"); + if (!Directory.Exists(cacheFolder)) + { + Directory.CreateDirectory(cacheFolder); + } + + if (!Directory.Exists(ModelFolder)) + { + Directory.CreateDirectory(ModelFolder); + } + } + + // See https://github.com/jordimas/whisper-ctranslate2/blob/main/src/whisper_ctranslate2/models.py + public WhisperModel[] Models => new[] + { + new WhisperModel + { + Name = "tiny.en", + Size = "74 MB", + Urls = MakeUrls("https://huggingface.co/datasets/jordimas/whisper-ct2-v2/resolve/main/c4d1be0a2003ce00bb721abd23e7a34925a6f0c0d21d5c416f11c763ee7f7b15.tiny-en/"), + Folder = "c4d1be0a2003ce00bb721abd23e7a34925a6f0c0d21d5c416f11c763ee7f7b15.tiny-en", + }, + new WhisperModel + { + Name = "tiny", + Size = "74 MB", + Urls = MakeUrls("https://huggingface.co/datasets/jordimas/whisper-ct2-v2/resolve/main/dc6a7765cdc8ae7822b1c3068a2f966eddc2549eda7e67406cae915a8c19430c.tiny/"), + Folder = "dc6a7765cdc8ae7822b1c3068a2f966eddc2549eda7e67406cae915a8c19430c.tiny", + }, + new WhisperModel + { + Name = "base.en", + Size = "142 MB", + Urls = MakeUrls("https://huggingface.co/datasets/jordimas/whisper-ct2-v2/resolve/main/2ca96777261aeadd48e30bc5f26fd3ee462f4921dbc1f38dfd826a67c761c9b2.base-en/"), + Folder = "2ca96777261aeadd48e30bc5f26fd3ee462f4921dbc1f38dfd826a67c761c9b2.base-en", + }, + new WhisperModel + { + Name = "base", + Size = "142 MB", + Urls = MakeUrls("https://huggingface.co/datasets/jordimas/whisper-ct2-v2/resolve/main/d7c4df31737340263ce37933bda1e77a38367dbb09cda7433ce1ee0c58ce1a60.base/"), + Folder = "d7c4df31737340263ce37933bda1e77a38367dbb09cda7433ce1ee0c58ce1a60.base", + }, + new WhisperModel + { + Name = "small.en", + Size = "472 MB", + Urls = MakeUrls("https://huggingface.co/datasets/jordimas/whisper-ct2-v2/resolve/main/e2c14bb0f6a8a69afe12fbe1d82fa0c41494d4bde9615bdf399da5665f43cbc4.small-en/"), + Folder = "e2c14bb0f6a8a69afe12fbe1d82fa0c41494d4bde9615bdf399da5665f43cbc4.small-en", + }, + new WhisperModel + { + Name = "small", + Size = "472 MB", + Urls = MakeUrls("https://huggingface.co/datasets/jordimas/whisper-ct2-v2/resolve/main/936cd99363be80fa388c0c5006e846d8cd42834c6cf8156a7c300723a3bf929f.small/"), + Folder = "936cd99363be80fa388c0c5006e846d8cd42834c6cf8156a7c300723a3bf929f.small", + }, + new WhisperModel + { + Name = "medium", + Size = "1.5 GB", + Urls = MakeUrls("https://huggingface.co/datasets/jordimas/whisper-ct2-v2/resolve/main/d8b91e278db3041c3b41bf879716281edf5cfa7b0025823cc174b5429877d2bc.medium/"), + Folder = "d8b91e278db3041c3b41bf879716281edf5cfa7b0025823cc174b5429877d2bc.medium", + }, + new WhisperModel + { + Name = "medium.en", + Size = "1.5 GB", + Urls = MakeUrls("https://huggingface.co/datasets/jordimas/whisper-ct2-v2/resolve/main/22d42d3e69ce9149bfd52c07d357e4cb72b992fb602805d6bb39f331400d6742.mediu-en/"), + Folder = "22d42d3e69ce9149bfd52c07d357e4cb72b992fb602805d6bb39f331400d6742.mediu-en", + }, + //new WhisperModel - large-v1 + //{ + // Name = "large", + // Size = "2.1 GB", + // Urls = "MakeUrls("https://huggingface.co/datasets/jordimas/whisper-ct2-v2/resolve/main/ea44e7a9609bd21a604b28880b85fc7dc2c373876c627a7553ce5440a8c406c1.large/"), + //}, + new WhisperModel + { + Name = "large", // large-v2 + Size = "2.9 GB", + Urls = MakeUrls("https://huggingface.co/datasets/jordimas/whisper-ct2-v2/resolve/main/ff9f410b63b3d996274c895f6209e9b9ab01d497815b21c2d35ae336ab7d7f20.large-v2/"), + Folder = "ff9f410b63b3d996274c895f6209e9b9ab01d497815b21c2d35ae336ab7d7f20.large-v2", + }, + }; + + private string[] MakeUrls(string baseUrl) + { + var result = new List(); + foreach (var fileName in _fileNames) + { + result.Add(baseUrl.TrimEnd('/') + "/" + fileName); + } + + return result.ToArray(); + } + } +} diff --git a/src/libse/AudioToText/WhisperCppModel.cs b/src/libse/AudioToText/WhisperCppModel.cs index 0797b2e45..79f8e6b1c 100644 --- a/src/libse/AudioToText/WhisperCppModel.cs +++ b/src/libse/AudioToText/WhisperCppModel.cs @@ -27,64 +27,55 @@ namespace Nikse.SubtitleEdit.Core.AudioToText { Name = "tiny.en", Size = "74 MB", - UrlSecondary = "https://ggml.ggerganov.com/ggml-model-whisper-tiny.en.bin", - UrlPrimary = "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin", + Urls = new []{ "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin" }, }, new WhisperModel { Name = "tiny", Size = "74 MB", - UrlSecondary = "https://ggml.ggerganov.com/ggml-model-whisper-tiny.bin", - UrlPrimary = "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-tiny.bin", + Urls = new []{ "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-tiny.bin" }, }, new WhisperModel { Name = "base.en", Size = "141 MB", - UrlSecondary = "https://ggml.ggerganov.com/ggml-model-whisper-base.en.bin", - UrlPrimary = "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin", + Urls = new []{ "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin" }, }, new WhisperModel { Name = "base", Size = "141 MB", - UrlSecondary = "https://ggml.ggerganov.com/ggml-model-whisper-base.bin", - UrlPrimary = "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-base.bin", + Urls = new []{ "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-base.bin" }, }, new WhisperModel { Name = "small.en", Size = "465 MB", - UrlSecondary = "https://ggml.ggerganov.com/ggml-model-whisper-small.en.bin", - UrlPrimary = "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-small.en.bin", + Urls = new []{ "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-small.en.bin" }, }, new WhisperModel { Name = "small", Size = "465 MB", - UrlSecondary = "https://ggml.ggerganov.com/ggml-model-whisper-small.bin", - UrlPrimary = "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-small.bin", + Urls = new []{ "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-small.bin" }, }, new WhisperModel { Name = "medium.en", Size = "1.42 GB", - UrlSecondary = "https://ggml.ggerganov.com/ggml-model-whisper-medium.en.bin", - UrlPrimary = "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-medium.en.bin", + Urls = new []{ "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-medium.en.bin" }, }, new WhisperModel { Name = "medium", Size = "1.42 GB", - UrlSecondary = "https://ggml.ggerganov.com/ggml-model-whisper-medium.bin", - UrlPrimary = "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-medium.bin", + Urls = new []{ "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-medium.bin" }, }, new WhisperModel { Name = "large", Size = "2.88 GB", - UrlSecondary = "https://ggml.ggerganov.com/ggml-model-whisper-large.bin", - UrlPrimary = "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-large.bin", + Urls = new []{ "https://huggingface.co/datasets/ggerganov/whisper.cpp/resolve/main/ggml-large.bin" }, }, }; } diff --git a/src/libse/AudioToText/WhisperHelper.cs b/src/libse/AudioToText/WhisperHelper.cs index d6dad53e8..6ade308b0 100644 --- a/src/libse/AudioToText/WhisperHelper.cs +++ b/src/libse/AudioToText/WhisperHelper.cs @@ -14,6 +14,11 @@ namespace Nikse.SubtitleEdit.Core.AudioToText return new WhisperCppModel(); } + if (Configuration.Settings.Tools.WhisperChoice == WhisperChoice.CTranslate2) + { + return new WhisperCTranslate2Model(); + } + return new WhisperModel(); } @@ -25,6 +30,11 @@ namespace Nikse.SubtitleEdit.Core.AudioToText return ".bin"; } + if (Configuration.Settings.Tools.WhisperChoice == WhisperChoice.CTranslate2) + { + return string.Empty; + } + return ".pt"; } diff --git a/src/libse/AudioToText/WhisperModel.cs b/src/libse/AudioToText/WhisperModel.cs index 8d4ee13ee..77ec15e3c 100644 --- a/src/libse/AudioToText/WhisperModel.cs +++ b/src/libse/AudioToText/WhisperModel.cs @@ -5,10 +5,10 @@ namespace Nikse.SubtitleEdit.Core.AudioToText { public class WhisperModel : IWhisperModel { - public string UrlPrimary { get; set; } - public string UrlSecondary { get; set; } + public string[] Urls { get; set; } public string Size { get; set; } public string Name { get; set; } + public string Folder { get; set; } public bool AlreadyDownloaded { get; set; } public long Bytes { get; set; } @@ -40,71 +40,61 @@ namespace Nikse.SubtitleEdit.Core.AudioToText { Name = "tiny.en", Size = "74 MB", - UrlPrimary = "https://openaipublic.azureedge.net/main/whisper/models/d3dd57d32accea0b295c96e26691aa14d8822fac7d9d27d5dc00b4ca2826dd03/tiny.en.pt", - UrlSecondary = "https://openaipublic.azureedge.net/main/whisper/models/d3dd57d32accea0b295c96e26691aa14d8822fac7d9d27d5dc00b4ca2826dd03/tiny.en.pt", + Urls = new []{ "https://openaipublic.azureedge.net/main/whisper/models/d3dd57d32accea0b295c96e26691aa14d8822fac7d9d27d5dc00b4ca2826dd03/tiny.en.pt" }, }, new WhisperModel { Name = "tiny", Size = "74 MB", - UrlPrimary = "https://openaipublic.azureedge.net/main/whisper/models/65147644a518d12f04e32d6f3b26facc3f8dd46e5390956a9424a650c0ce22b9/tiny.pt", - UrlSecondary = "https://openaipublic.azureedge.net/main/whisper/models/65147644a518d12f04e32d6f3b26facc3f8dd46e5390956a9424a650c0ce22b9/tiny.pt", + Urls = new []{ "https://openaipublic.azureedge.net/main/whisper/models/65147644a518d12f04e32d6f3b26facc3f8dd46e5390956a9424a650c0ce22b9/tiny.pt" }, }, new WhisperModel { Name = "base.en", Size = "142 MB", - UrlPrimary = "https://openaipublic.azureedge.net/main/whisper/models/25a8566e1d0c1e2231d1c762132cd20e0f96a85d16145c3a00adf5d1ac670ead/base.en.pt", - UrlSecondary = "https://openaipublic.azureedge.net/main/whisper/models/25a8566e1d0c1e2231d1c762132cd20e0f96a85d16145c3a00adf5d1ac670ead/base.en.pt", + Urls = new []{ "https://openaipublic.azureedge.net/main/whisper/models/25a8566e1d0c1e2231d1c762132cd20e0f96a85d16145c3a00adf5d1ac670ead/base.en.pt" }, }, new WhisperModel { Name = "base", Size = "142 MB", - UrlPrimary = "https://openaipublic.azureedge.net/main/whisper/models/ed3a0b6b1c0edf879ad9b11b1af5a0e6ab5db9205f891f668f8b0e6c6326e34e/base.pt", - UrlSecondary = "https://openaipublic.azureedge.net/main/whisper/models/ed3a0b6b1c0edf879ad9b11b1af5a0e6ab5db9205f891f668f8b0e6c6326e34e/base.pt", + Urls = new []{ "https://openaipublic.azureedge.net/main/whisper/models/ed3a0b6b1c0edf879ad9b11b1af5a0e6ab5db9205f891f668f8b0e6c6326e34e/base.pt" }, }, new WhisperModel { Name = "small.en", Size = "472 MB", - UrlPrimary = "https://openaipublic.azureedge.net/main/whisper/models/f953ad0fd29cacd07d5a9eda5624af0f6bcf2258be67c92b79389873d91e0872/small.en.pt", - UrlSecondary = "https://openaipublic.azureedge.net/main/whisper/models/f953ad0fd29cacd07d5a9eda5624af0f6bcf2258be67c92b79389873d91e0872/small.en.pt", + Urls = new []{ "https://openaipublic.azureedge.net/main/whisper/models/f953ad0fd29cacd07d5a9eda5624af0f6bcf2258be67c92b79389873d91e0872/small.en.pt" }, }, new WhisperModel { Name = "small", Size = "472 MB", - UrlPrimary = "https://openaipublic.azureedge.net/main/whisper/models/9ecf779972d90ba49c06d968637d720dd632c55bbf19d441fb42bf17a411e794/small.pt", - UrlSecondary = "https://openaipublic.azureedge.net/main/whisper/models/9ecf779972d90ba49c06d968637d720dd632c55bbf19d441fb42bf17a411e794/small.pt", + Urls = new []{ "https://openaipublic.azureedge.net/main/whisper/models/9ecf779972d90ba49c06d968637d720dd632c55bbf19d441fb42bf17a411e794/small.pt" }, }, new WhisperModel { Name = "medium", Size = "1.5 GB", - UrlPrimary = "https://openaipublic.azureedge.net/main/whisper/models/345ae4da62f9b3d59415adc60127b97c714f32e89e936602e85993674d08dcb1/medium.pt", - UrlSecondary = "https://openaipublic.azureedge.net/main/whisper/models/345ae4da62f9b3d59415adc60127b97c714f32e89e936602e85993674d08dcb1/medium.pt", + Urls = new []{ "https://openaipublic.azureedge.net/main/whisper/models/345ae4da62f9b3d59415adc60127b97c714f32e89e936602e85993674d08dcb1/medium.pt" }, }, new WhisperModel { Name = "medium.en", Size = "1.5 GB", - UrlPrimary = "https://openaipublic.azureedge.net/main/whisper/models/d7440d1dc186f76616474e0ff0b3b6b879abc9d1a4926b7adfa41db2d497ab4f/medium.en.pt", - UrlSecondary = "https://openaipublic.azureedge.net/main/whisper/models/d7440d1dc186f76616474e0ff0b3b6b879abc9d1a4926b7adfa41db2d497ab4f/medium.en.pt", + Urls = new []{ "https://openaipublic.azureedge.net/main/whisper/models/d7440d1dc186f76616474e0ff0b3b6b879abc9d1a4926b7adfa41db2d497ab4f/medium.en.pt" }, }, //new WhisperModel - large-v1 //{ // Name = "large", // Size = "2.1 GB", - // UrlPrimary = "https://openaipublic.azureedge.net/main/whisper/models/e4b87e7e0bf463eb8e6956e646f1e277e901512310def2c24bf0e11bd3c28e9a/large.pt", - // UrlSecondary = "https://openaipublic.azureedge.net/main/whisper/models/e4b87e7e0bf463eb8e6956e646f1e277e901512310def2c24bf0e11bd3c28e9a/large.pt", + // Urls = new []{ "https://openaipublic.azureedge.net/main/whisper/models/e4b87e7e0bf463eb8e6956e646f1e277e901512310def2c24bf0e11bd3c28e9a/large.pt" }, //}, new WhisperModel { Name = "large", // large-v2 Size = "2.9 GB", - UrlPrimary = "https://openaipublic.azureedge.net/main/whisper/models/81f7c96c852ee8fc832187b0132e569d6c3065a3252ed18e56effd0b6a73e524/large-v2.pt", - UrlSecondary = "https://openaipublic.azureedge.net/main/whisper/models/81f7c96c852ee8fc832187b0132e569d6c3065a3252ed18e56effd0b6a73e524/large-v2.pt", + Urls = new []{ "https://openaipublic.azureedge.net/main/whisper/models/81f7c96c852ee8fc832187b0132e569d6c3065a3252ed18e56effd0b6a73e524/large-v2.pt" }, }, }; } diff --git a/src/ui/Forms/AudioToText/WhisperAudioToText.cs b/src/ui/Forms/AudioToText/WhisperAudioToText.cs index 8de424f17..18ef480da 100644 --- a/src/ui/Forms/AudioToText/WhisperAudioToText.cs +++ b/src/ui/Forms/AudioToText/WhisperAudioToText.cs @@ -14,7 +14,6 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; -using Vosk; namespace Nikse.SubtitleEdit.Forms.AudioToText { @@ -166,8 +165,6 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText comboBoxCharsPerSub.Visible = Configuration.Settings.Tools.WhisperChoice == WhisperChoice.Cpp; labelCharsPerSub.Left = comboBoxCharsPerSub.Left - labelCharsPerSub.Width - 9; labelCharsPerSub.Visible = Configuration.Settings.Tools.WhisperChoice == WhisperChoice.Cpp; - - buttonDownload.Enabled = Configuration.Settings.Tools.WhisperChoice != WhisperChoice.CTranslate2; } public static void FillModels(ComboBox comboBoxModels, string lastDownloadedModel) @@ -175,16 +172,26 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText var whisperModel = WhisperHelper.GetWhisperModel(); var modelsFolder = whisperModel.ModelFolder; var selectName = string.IsNullOrEmpty(lastDownloadedModel) ? Configuration.Settings.Tools.WhisperModel : lastDownloadedModel; + + if (!Directory.Exists(modelsFolder)) + { + whisperModel.CreateModelFolder(); + } + comboBoxModels.Items.Clear(); if (Configuration.Settings.Tools.WhisperChoice == WhisperChoice.CTranslate2) { foreach (var model in whisperModel.Models) { - comboBoxModels.Items.Add(model); - if (model.Name == selectName) + var path = Path.Combine(modelsFolder, model.Folder, "model.bin"); + if (File.Exists(path)) { - comboBoxModels.SelectedIndex = comboBoxModels.Items.Count - 1; + comboBoxModels.Items.Add(model); + if (model.Name == selectName) + { + comboBoxModels.SelectedIndex = comboBoxModels.Items.Count - 1; + } } } @@ -196,11 +203,6 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText return; } - if (!Directory.Exists(modelsFolder)) - { - whisperModel.CreateModelFolder(); - } - var models = new List(); foreach (var fileName in Directory.GetFiles(modelsFolder)) { @@ -1317,7 +1319,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText checkBoxTranslateToEnglish.Enabled = comboBoxLanguages.Text.ToLowerInvariant() != "english"; } - private void whisperPhpOriginalToolStripMenuItem_Click(object sender, EventArgs e) + private void WhisperPhpOriginalChoose() { Configuration.Settings.Tools.WhisperChoice = WhisperChoice.OpenAI; @@ -1348,12 +1350,6 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText Init(); } - private void whisperCppCToolStripMenuItem_Click(object sender, EventArgs e) - { - Configuration.Settings.Tools.WhisperChoice = WhisperChoice.Cpp; - Init(); - } - private void removeTemporaryFilesToolStripMenuItem_Click(object sender, EventArgs e) { Configuration.Settings.Tools.WhisperDeleteTempFiles = !Configuration.Settings.Tools.WhisperDeleteTempFiles; @@ -1433,7 +1429,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText if (comboBoxWhisperEngine.Text == WhisperChoice.OpenAI) { - whisperPhpOriginalToolStripMenuItem_Click(null, null); + WhisperPhpOriginalChoose(); } else if (comboBoxWhisperEngine.Text == WhisperChoice.Cpp) { diff --git a/src/ui/Forms/AudioToText/WhisperModelDownload.Designer.cs b/src/ui/Forms/AudioToText/WhisperModelDownload.Designer.cs index 8cb6813bb..ad9a0511d 100644 --- a/src/ui/Forms/AudioToText/WhisperModelDownload.Designer.cs +++ b/src/ui/Forms/AudioToText/WhisperModelDownload.Designer.cs @@ -33,13 +33,14 @@ this.buttonCancel = new System.Windows.Forms.Button(); this.comboBoxModels = new System.Windows.Forms.ComboBox(); this.textBoxError = new System.Windows.Forms.TextBox(); + this.labelFileName = new System.Windows.Forms.Label(); this.SuspendLayout(); // // labelPleaseWait // this.labelPleaseWait.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.labelPleaseWait.AutoSize = true; - this.labelPleaseWait.Location = new System.Drawing.Point(12, 92); + this.labelPleaseWait.Location = new System.Drawing.Point(12, 111); this.labelPleaseWait.Name = "labelPleaseWait"; this.labelPleaseWait.Size = new System.Drawing.Size(70, 13); this.labelPleaseWait.TabIndex = 3; @@ -61,7 +62,7 @@ this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.buttonCancel.ImeMode = System.Windows.Forms.ImeMode.NoControl; - this.buttonCancel.Location = new System.Drawing.Point(362, 87); + this.buttonCancel.Location = new System.Drawing.Point(362, 106); this.buttonCancel.Name = "buttonCancel"; this.buttonCancel.Size = new System.Drawing.Size(75, 23); this.buttonCancel.TabIndex = 4; @@ -83,18 +84,29 @@ this.textBoxError.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxError.Location = new System.Drawing.Point(15, 69); + this.textBoxError.Location = new System.Drawing.Point(97, 86); this.textBoxError.Multiline = true; this.textBoxError.Name = "textBoxError"; this.textBoxError.ReadOnly = true; - this.textBoxError.Size = new System.Drawing.Size(422, 12); + this.textBoxError.Size = new System.Drawing.Size(340, 14); this.textBoxError.TabIndex = 2; // + // labelFileName + // + this.labelFileName.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.labelFileName.AutoSize = true; + this.labelFileName.Location = new System.Drawing.Point(12, 86); + this.labelFileName.Name = "labelFileName"; + this.labelFileName.Size = new System.Drawing.Size(52, 13); + this.labelFileName.TabIndex = 5; + this.labelFileName.Text = "File name"; + // // WhisperModelDownload // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(449, 120); + this.ClientSize = new System.Drawing.Size(449, 139); + this.Controls.Add(this.labelFileName); this.Controls.Add(this.textBoxError); this.Controls.Add(this.comboBoxModels); this.Controls.Add(this.labelPleaseWait); @@ -122,5 +134,6 @@ private System.Windows.Forms.Button buttonCancel; private System.Windows.Forms.ComboBox comboBoxModels; private System.Windows.Forms.TextBox textBoxError; + private System.Windows.Forms.Label labelFileName; } } \ No newline at end of file diff --git a/src/ui/Forms/AudioToText/WhisperModelDownload.cs b/src/ui/Forms/AudioToText/WhisperModelDownload.cs index 3a7808a98..312842759 100644 --- a/src/ui/Forms/AudioToText/WhisperModelDownload.cs +++ b/src/ui/Forms/AudioToText/WhisperModelDownload.cs @@ -3,6 +3,7 @@ using Nikse.SubtitleEdit.Core.Common; using Nikse.SubtitleEdit.Logic; using System; using System.IO; +using System.Linq; using System.Threading; using System.Windows.Forms; @@ -13,7 +14,6 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText public bool AutoClose { get; internal set; } public WhisperModel LastDownloadedModel { get; private set; } private readonly CancellationTokenSource _cancellationTokenSource; - private bool _error; private string _downloadFileName; public WhisperModelDownload() @@ -29,7 +29,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText var selectedIndex = 0; foreach (var downloadModel in WhisperHelper.GetWhisperModel().Models) { - var fileName = MakeDownloadFileName(downloadModel); + var fileName = MakeDownloadFileName(downloadModel, downloadModel.Urls[0]); downloadModel.AlreadyDownloaded = File.Exists(fileName); comboBoxModels.Items.Add(downloadModel); @@ -41,6 +41,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText comboBoxModels.SelectedIndex = selectedIndex; labelPleaseWait.Text = string.Empty; + labelFileName.Text = string.Empty; textBoxError.Visible = false; _cancellationTokenSource = new CancellationTokenSource(); } @@ -66,14 +67,18 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText } LastDownloadedModel = (WhisperModel)comboBoxModels.Items[comboBoxModels.SelectedIndex]; - var url = _error ? LastDownloadedModel.UrlSecondary : LastDownloadedModel.UrlPrimary; + MultiFileDownload(); + } + + private void MultiFileDownload() + { + var currentDownloadUrl = string.Empty; try { labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait; buttonDownload.Enabled = false; Refresh(); Cursor = Cursors.WaitCursor; - var httpClient = HttpClientHelper.MakeHttpClient(); var folder = WhisperHelper.GetWhisperModel().ModelFolder; if (!Directory.Exists(folder)) @@ -81,52 +86,90 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText WhisperHelper.GetWhisperModel().CreateModelFolder(); } - _downloadFileName = MakeDownloadFileName(LastDownloadedModel) + ".$$$"; - using (var downloadStream = new FileStream(_downloadFileName, FileMode.Create, FileAccess.Write)) + if (!string.IsNullOrEmpty(LastDownloadedModel.Folder)) { - var downloadTask = httpClient.DownloadAsync(url, downloadStream, new Progress((progress) => + folder = Path.Combine(folder, LastDownloadedModel.Folder); + if (!Directory.Exists(folder)) { - var pct = (int)Math.Round(progress * 100.0, MidpointRounding.AwayFromZero); - labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait + " " + pct + "%"; - }), _cancellationTokenSource.Token); - - while (!downloadTask.IsCompleted && !downloadTask.IsCanceled) - { - Application.DoEvents(); + Directory.CreateDirectory(folder); } - - if (downloadTask.IsCanceled) - { - DialogResult = DialogResult.Cancel; - labelPleaseWait.Refresh(); - try - { - File.Delete(_downloadFileName); - } - catch - { - // ignore - } - return; - } - - CompleteDownload(downloadStream); } + + foreach (var url in LastDownloadedModel.Urls) + { + var httpClient = HttpClientHelper.MakeHttpClient(); + currentDownloadUrl = url; + _downloadFileName = MakeDownloadFileName(LastDownloadedModel, url) + ".$$$"; + labelFileName.Text = url.Split('/').Last(); + using (var downloadStream = new FileStream(_downloadFileName, FileMode.Create, FileAccess.Write)) + { + var downloadTask = httpClient.DownloadAsync(url, downloadStream, new Progress((progress) => + { + var pct = (int)Math.Round(progress * 100.0, MidpointRounding.AwayFromZero); + labelPleaseWait.Text = LanguageSettings.Current.General.PleaseWait + " " + pct + "%"; + }), _cancellationTokenSource.Token); + + while (!downloadTask.IsCompleted && !downloadTask.IsCanceled) + { + Application.DoEvents(); + } + + if (downloadTask.IsCanceled) + { + DialogResult = DialogResult.Cancel; + labelPleaseWait.Refresh(); + try + { + File.Delete(_downloadFileName); + } + catch + { + // ignore + } + return; + } + + CompleteDownload(downloadStream); + } + } + + Cursor = Cursors.Default; + labelPleaseWait.Text = string.Empty; + + if (AutoClose) + { + DialogResult = DialogResult.OK; + return; + } + + buttonDownload.Enabled = true; + labelPleaseWait.Text = string.Format(LanguageSettings.Current.SettingsFfmpeg.XDownloadOk, "Whisper model"); } catch (Exception exception) { labelPleaseWait.Text = string.Empty; buttonDownload.Enabled = true; Cursor = Cursors.Default; - MessageBox.Show($"Unable to download {url}!" + Environment.NewLine + Environment.NewLine + + MessageBox.Show($"Unable to download {currentDownloadUrl}!" + Environment.NewLine + Environment.NewLine + exception.Message + Environment.NewLine + Environment.NewLine + exception.StackTrace); - _error = true; } } - private static string MakeDownloadFileName(WhisperModel model) + private static string MakeDownloadFileName(WhisperModel model, string url) { - return Path.Combine(WhisperHelper.GetWhisperModel().ModelFolder, model.Name + WhisperHelper.ModelExtension()); + var path = WhisperHelper.GetWhisperModel().ModelFolder; + if (!string.IsNullOrEmpty(model.Folder)) + { + path = Path.Combine(path, model.Folder); + } + + if (model.Urls.Length > 1) + { + var arr = url.Split('/'); + return Path.Combine(path, arr.Last()); + } + + return Path.Combine(path, model.Name + WhisperHelper.ModelExtension()); } private void buttonCancel_Click(object sender, EventArgs e) @@ -157,18 +200,7 @@ namespace Nikse.SubtitleEdit.Forms.AudioToText Application.DoEvents(); File.Move(_downloadFileName, newFileName); - - Cursor = Cursors.Default; - labelPleaseWait.Text = string.Empty; - - if (AutoClose) - { - DialogResult = DialogResult.OK; - return; - } - - buttonDownload.Enabled = true; - labelPleaseWait.Text = string.Format(LanguageSettings.Current.SettingsFfmpeg.XDownloadOk, "Whisper model"); + labelFileName.Text = string.Empty; } } }