From c4bf4e75a8b803af949ad231328c824f6863e3d3 Mon Sep 17 00:00:00 2001 From: aiueo-1234 <130837816+aiueo-1234@users.noreply.github.com> Date: Sat, 24 Feb 2024 15:02:30 +0900 Subject: [PATCH 01/15] =?UTF-8?q?=E4=BB=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Contracts/Services/IAnalyzerService.cs | 2 +- KoeBook.Core/Services/AnalyzerService.cs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 KoeBook.Core/Services/AnalyzerService.cs diff --git a/KoeBook.Core/Contracts/Services/IAnalyzerService.cs b/KoeBook.Core/Contracts/Services/IAnalyzerService.cs index 4cd1e2c..b917ff9 100644 --- a/KoeBook.Core/Contracts/Services/IAnalyzerService.cs +++ b/KoeBook.Core/Contracts/Services/IAnalyzerService.cs @@ -8,5 +8,5 @@ public interface IAnalyzerService /// 本の情報の取得・解析を行います /// /// 編集前の読み上げテキスト - ValueTask AnalyzeAsync(BookProperties bookProperties, CancellationToken cancellationToken); + ValueTask AnalyzeAsync(BookProperties bookProperties, string tempDirectory, string coverFilePath, CancellationToken cancellationToken); } diff --git a/KoeBook.Core/Services/AnalyzerService.cs b/KoeBook.Core/Services/AnalyzerService.cs new file mode 100644 index 0000000..a8f0535 --- /dev/null +++ b/KoeBook.Core/Services/AnalyzerService.cs @@ -0,0 +1,19 @@ +using KoeBook.Core.Contracts.Services; +using KoeBook.Core.Models; +using KoeBook.Epub.Service; + +namespace KoeBook.Core.Services; + +public class AnalyzerService(IScrapingService scrapingService, IEpubDocumentStoreService epubDocumentStoreService) : IAnalyzerService +{ + private readonly IScrapingService _scrapingService = scrapingService; + private readonly IEpubDocumentStoreService _epubDocumentStoreService = epubDocumentStoreService; + + public async ValueTask AnalyzeAsync(BookProperties bookProperties, string tempDirectory, string coverFilePath, CancellationToken cancellationToken) + { + var document = await _scrapingService.ScrapingAsync(bookProperties.Source, coverFilePath, bookProperties.Id, cancellationToken); + _epubDocumentStoreService.Register(document, cancellationToken); + + throw new NotImplementedException(); + } +} From 22f1ecf79f89ddc4497b6b05962d784506b34e93 Mon Sep 17 00:00:00 2001 From: herring101 <81513223+herring101@users.noreply.github.com> Date: Sat, 24 Feb 2024 21:18:52 +0900 Subject: [PATCH 02/15] chatgpt analyze --- .../Contracts/Services/ILlmAnalyzerService.cs | 8 + KoeBook.Core/EbookException.cs | 3 + KoeBook.Core/KoeBook.Core.csproj | 4 +- KoeBook.Core/Services/AnalyzerService.cs | 60 +++- .../Services/ChaGptAnalyzerService.cs | 330 ++++++++++++++++++ 5 files changed, 400 insertions(+), 5 deletions(-) create mode 100644 KoeBook.Core/Contracts/Services/ILlmAnalyzerService.cs create mode 100644 KoeBook.Core/Services/ChaGptAnalyzerService.cs diff --git a/KoeBook.Core/Contracts/Services/ILlmAnalyzerService.cs b/KoeBook.Core/Contracts/Services/ILlmAnalyzerService.cs new file mode 100644 index 0000000..ddf948b --- /dev/null +++ b/KoeBook.Core/Contracts/Services/ILlmAnalyzerService.cs @@ -0,0 +1,8 @@ +using KoeBook.Core.Models; + +namespace KoeBook.Core.Contracts.Services; + +public interface ILlmAnalyzerService +{ + ValueTask LlmAnalyzeScriptLinesAsync(BookProperties bookProperties, List scriptLines, List chunks, CancellationToken cancellationToken); +} diff --git a/KoeBook.Core/EbookException.cs b/KoeBook.Core/EbookException.cs index e7ef5a4..99d6d67 100644 --- a/KoeBook.Core/EbookException.cs +++ b/KoeBook.Core/EbookException.cs @@ -40,4 +40,7 @@ public enum ExceptionType [EnumMember(Value = "有効な Style Bert VITS のAPIルートを設定してください")] UnknownStyleBertVitsRoot, + + [EnumMember(Value = "GPT4による話者・スタイル設定に失敗しました")] + Gpt4TalkerAndStyleSettingFailed, } diff --git a/KoeBook.Core/KoeBook.Core.csproj b/KoeBook.Core/KoeBook.Core.csproj index f2fc1f9..92b37e0 100644 --- a/KoeBook.Core/KoeBook.Core.csproj +++ b/KoeBook.Core/KoeBook.Core.csproj @@ -1,4 +1,4 @@ - + net8.0 KoeBook.Core @@ -9,8 +9,8 @@ + - diff --git a/KoeBook.Core/Services/AnalyzerService.cs b/KoeBook.Core/Services/AnalyzerService.cs index a8f0535..0b50b9c 100644 --- a/KoeBook.Core/Services/AnalyzerService.cs +++ b/KoeBook.Core/Services/AnalyzerService.cs @@ -1,19 +1,73 @@ -using KoeBook.Core.Contracts.Services; +using System.Text; +using System.Text.RegularExpressions; +using KoeBook.Core.Contracts.Services; using KoeBook.Core.Models; +using KoeBook.Epub; using KoeBook.Epub.Service; namespace KoeBook.Core.Services; -public class AnalyzerService(IScrapingService scrapingService, IEpubDocumentStoreService epubDocumentStoreService) : IAnalyzerService +public class AnalyzerService(IScrapingService scrapingService, IEpubDocumentStoreService epubDocumentStoreService, ILlmAnalyzerService llmAnalyzerService) : IAnalyzerService { private readonly IScrapingService _scrapingService = scrapingService; private readonly IEpubDocumentStoreService _epubDocumentStoreService = epubDocumentStoreService; + private readonly ILlmAnalyzerService _llmAnalyzerService = llmAnalyzerService; + private Dictionary _rubyReplacements = new Dictionary(); public async ValueTask AnalyzeAsync(BookProperties bookProperties, string tempDirectory, string coverFilePath, CancellationToken cancellationToken) { var document = await _scrapingService.ScrapingAsync(bookProperties.Source, coverFilePath, bookProperties.Id, cancellationToken); _epubDocumentStoreService.Register(document, cancellationToken); - throw new NotImplementedException(); + var scriptLines = new List(); + foreach (var chapter in document.Chapters) + { + foreach (var section in chapter.Sections) + { + foreach (var element in section.Elements) + { + if (element is Paragraph paragraph) + { + var line = paragraph.Text; + // rubyタグがあればルビのdictionaryに登録 + var matches = Regex.Matches(line, "(.*?)(.*?)"); + foreach (Match match in matches) + { + var key = match.Groups[1].Value; + var value = match.Groups[2].Value; + if (!_rubyReplacements.ContainsKey(key)) + { + _rubyReplacements.Add(key, value); + } + } + // ルビを置換 + foreach (var replacement in _rubyReplacements) + { + line = line.Replace(replacement.Key, replacement.Value); + } + scriptLines.Add(new ScriptLine(paragraph, line, "", "")); + } + } + } + } + + // 800文字以上になったら1チャンクに分ける + var chunks = new List(); + var chunk = new StringBuilder(); + foreach (var line in scriptLines) + { + if (chunk.Length + line.Text.Length > 800) + { + chunks.Add(chunk.ToString()); + chunk.Clear(); + } + chunk.Append(line.Text); + } + if (chunk.Length > 0) chunks.Add(chunk.ToString()); + + // GPT4による話者、スタイル解析 + var bookScripts = await _llmAnalyzerService.LlmAnalyzeScriptLinesAsync(bookProperties, scriptLines, chunks, cancellationToken); + + return bookScripts; } } diff --git a/KoeBook.Core/Services/ChaGptAnalyzerService.cs b/KoeBook.Core/Services/ChaGptAnalyzerService.cs new file mode 100644 index 0000000..86b128f --- /dev/null +++ b/KoeBook.Core/Services/ChaGptAnalyzerService.cs @@ -0,0 +1,330 @@ +using System.Text; +using System.Text.RegularExpressions; +using KoeBook.Core.Contracts.Services; +using KoeBook.Core.Models; +using OpenAI.Interfaces; +using OpenAI.ObjectModels.RequestModels; + +namespace KoeBook.Core.Services; + +public partial class ChaGptAnalyzerService(IOpenAIService openAIService) : ILlmAnalyzerService +{ + private readonly IOpenAIService _openAiService = openAIService; + + public async ValueTask LlmAnalyzeScriptLinesAsync(BookProperties bookProperties, List scriptLines, List chunks, CancellationToken cancellationToken) + { + Queue summaryList = new(); + Queue characterList = new(); + for (int i = 0; i < chunks.Count; i++) + { + // 話者・スタイル解析 + var Task1 = CharacterStyleAnalysisAsync(scriptLines, chunks, summaryList.Peek(), characterList.Peek(), i, cancellationToken); + // 要約・キャラクターリスト解析 + var Task2 = SummaryCharacterListAnalysisAsync(scriptLines, chunks, summaryList.Peek(), characterList.Peek(), i, cancellationToken); + // WhenAllで非同期処理を待つ + await Task.WhenAll(Task1, Task2); + // 結果をキューに追加 + summaryList.Enqueue(Task2.Result.summary); + characterList.Enqueue(Task2.Result.characterList); + // 5個以上になったら古いものを削除 + if (summaryList.Count > 5) + { + summaryList.Dequeue(); + characterList.Dequeue(); + } + } + + // キャラクター名と声のマッピング + var characterVoiceMapping = await GetCharacterVoiceMappingAsync(characterList.Peek(), cancellationToken); + + var bookScripts = new BookScripts + ( + bookProperties, + new BookOptions + { + CharacterMapping = characterVoiceMapping + } + ) + { + ScriptLines = scriptLines + }; + return bookScripts; + } + + private async Task CharacterStyleAnalysisAsync(List scriptLines, + List chunks, + string summary, + string characterList, + int idx, + CancellationToken cancellationToken) + { + var completionResult = await _openAiService.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest + { + Messages = new List + { + ChatMessage.FromSystem($$""" + All Information + - Goal + - Information about this story + - Output Format + - Notes + + + # Goal + Set speaker name and style of target sentence + + + # Information about this story + 1. Summary so far + {{summary}} + + + 2. Character List + {{characterList}} + + + 3. Target Sentence + {{chunks[idx]}} + + + # Output Format + ``` + #### CharacterList + - name1 + - name2 + ... + + + #### Summery + - point1 + - point2 + - point3 + + + #### Talker and Style Setting + {SENTENCE}[{TALKER}:{STYLE}] + {SENTENCE}[{TALKER}:{STYLE}] + ... + {SENTENCE}[{TALKER}:{STYLE}] + ``` + STYLE = narration | neutral | laughing | happy | sad | cry | surprised | angry + assign the name of the speaker to {TALKER} if the sentence is dialogue, or use 'ナレーション' for narrative sentences. If the sentence is part of a monologue, use the name of the character who is speaking. + The {SENTENCE} should be a direct excerpt from the 'Target Sentence' section." + + + # **Notes** + ## **Separate Narration and lines.** Be careful as you often make mistakes!! + Input + ``` + 落ちてくる落ち葉を見て、清美は言った。 + 「悲しいね…。あなたとの思い出が、一枚一枚、地面に落ちていくみたい…。」 + ``` + Output + ``` + 落ちてくる落ち葉を見て、清美は言った。[ナレーション:narration] + 「悲しいね…。あなたとの思い出が、一枚一枚、地面に落ちていくみたい…。」[漆原清美:sad] + ``` + ## First person + Input + ``` + 俺は泣きながら勇気を振り絞って言った。 + 「お前は本当に、俺のことを愛してるのか?」 + ``` + Output + ``` + 俺は泣きながら勇気を振り絞って言った。[松原一馬:narration] + 「お前は本当に、俺のことを愛してるのか?」[松原一馬:cry] + ``` + ## What is not enclosed in brackets is basically narration style + Input + ``` + ファーラン王子はそっと、王のもとへ行き、王の耳元で何かを囁いた。 + そして、王は、その言葉を聞いて、驚いたような顔をした。 + アミダス王は立ち上がり、民衆の前で声を張り上げた。 + 「私は、この国を、息子ファーランに譲る!」 + ``` + Output + ``` + ファーラン王子はそっと、王のもとへ行き、王の耳元で何かを囁いた。[ナレーション:narration] + そして、王は、その言葉を聞いて、驚いたような顔をした。[ナレーション:narration] + アミダス王は立ち上がり、民衆の前で声を張り上げた。[ナレーション:narration] + 「私は、この国を、息子ファーランに譲る!」[アミダス王:neutral] + ``` + """ + ) + }, + Model = OpenAI.ObjectModels.Models.Gpt_4_0125_preview, + MaxTokens = 2000 + }); + if (completionResult.Successful) + { + var result = completionResult.Choices.First().Message.Content; + // "#### Talker and Style Setting"以下の文章を改行区切りでリスト化 + List output = new List(); + var lines = result.Split("\n"); + var start = false; + foreach (var line in lines) + { + if (start) + { + if (line.Contains("```")) + { + break; + } + output.Add(line); + } + if (line.Contains("#### Talker and Style Setting")) + { + start = true; + } + } + // パラグラフと対応するoutputをマッピング + for (int i = 0; i < output.Count; i++) + { + // {SENTENCE}[{TALKER}:{STYLE}]の形式になっているかチェック + var match = Regex.Match(output[i], @"(.+)\[(.+):(.+)]"); + if (match.Success) + { + var sentence = match.Groups[1].Value; + var talker = match.Groups[2].Value; + var style = match.Groups[3].Value; + if (sentence == scriptLines[idx + i].Text || Math.Abs(sentence.Length - scriptLines[idx + i].Text.Length) < 5) + { + scriptLines[idx + i].Character = talker; + scriptLines[idx + i].Style = style; + } + else + { + EbookException.Throw(ExceptionType.Gpt4TalkerAndStyleSettingFailed); + } + } + else + { + EbookException.Throw(ExceptionType.Gpt4TalkerAndStyleSettingFailed); + } + } + } + } + + private async Task<(string summary, string characterList)> SummaryCharacterListAnalysisAsync(List scriptLines, + List chunks, + string summary, + string characterList, + int idx, + CancellationToken cancellationToken) + { + var storyText = string.Join("\n", chunks.Skip(int.Max(0, idx - 4)).Take(4)); + var completionResult = await _openAiService.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest + { + Messages = new List + { + ChatMessage.FromSystem($$""" + All Information + - Goal + - Information about this story + - Output Format + + + # Goal + Make CharacterList and Summery of the story. + + + # Information about this story + 1. Character List + {{characterList}} + + + 2. Summary so far + {{summary}} + + + 3. Story + {{storyText}} + + + # Output Format (write name,description,summary in Japanese!!) + ``` + #### CharacterList + {name1} + - {description1} + - {description2} + ...(up to 10 descriptions) + + + {name2} + - {description1} + - {description2} + ... + ... + + + #### Summery of 5 points + - {summary1} + - {summary2} + ... + ``` + """) + }, + }); + if (completionResult.Successful) + { + var result = completionResult.Choices.First().Message.Content; + var lines = result.Split("\n"); + bool summaryStart = false; + bool characterListStart = false; + StringBuilder _summary = new(); + StringBuilder _characterList = new(); + + foreach (var line in lines) + { + if (line.Contains("#### CharacterList")) + { + characterListStart = true; + continue; + } + if (line.Contains("#### Summery of")) + { + summaryStart = true; + characterListStart = false; + continue; + } + if (characterListStart) + { + _characterList.AppendLine(line); + } + if (summaryStart) + { + if (line.Contains("```")) + { + break; + } + _summary.AppendLine(line); + } + } + + return (_summary.ToString(), _characterList.ToString()); + } + else + { + EbookException.Throw(ExceptionType.Gpt4TalkerAndStyleSettingFailed); + return default!; + } + } + + private async Task> GetCharacterVoiceMappingAsync(string characterList, CancellationToken cancellationToken) + { + //var completionResult = await _openAiService.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest + //{ + // Messages = new List + // { + // ChatMessage.FromSystem($$""" + // All Information + // - Goal + // - Information about this story + // - Output Format + // """) + // } + //} + return new Dictionary(); + } +} From a9cd34a51ef4b995c56c21bf715d222a240d9eb5 Mon Sep 17 00:00:00 2001 From: herring101 <81513223+herring101@users.noreply.github.com> Date: Sun, 25 Feb 2024 00:52:23 +0900 Subject: [PATCH 03/15] api key setting --- .../Services/ISecretSettingsService.cs | 4 +- KoeBook.Core/Services/MyOpenAiService.cs | 64 +++++++++++++++++++ .../Services/SercretSettingsService.cs | 10 ++- KoeBook/Services/ActivationService.cs | 4 ++ KoeBook/Services/LocalSettingsService.cs | 2 +- KoeBook/ViewModels/SettingsViewModel.cs | 16 ++--- KoeBook/Views/SettingsPage.xaml | 3 +- 7 files changed, 86 insertions(+), 17 deletions(-) create mode 100644 KoeBook.Core/Services/MyOpenAiService.cs diff --git a/KoeBook.Core/Contracts/Services/ISecretSettingsService.cs b/KoeBook.Core/Contracts/Services/ISecretSettingsService.cs index e575970..56adbf6 100644 --- a/KoeBook.Core/Contracts/Services/ISecretSettingsService.cs +++ b/KoeBook.Core/Contracts/Services/ISecretSettingsService.cs @@ -2,7 +2,9 @@ public interface ISecretSettingsService { - Task GetApiKeyAsync(string folderPath, CancellationToken cancellationToken); + string? ApiKey { get; } + + Task InitializeAsync(string folderPath, CancellationToken cancellationToken); Task SaveApiKeyAsync(string folderPath, string apiKey, CancellationToken cancellationToken); } diff --git a/KoeBook.Core/Services/MyOpenAiService.cs b/KoeBook.Core/Services/MyOpenAiService.cs new file mode 100644 index 0000000..e8c4793 --- /dev/null +++ b/KoeBook.Core/Services/MyOpenAiService.cs @@ -0,0 +1,64 @@ +using KoeBook.Core.Contracts.Services; +using OpenAI; +using OpenAI.Interfaces; +using OpenAI.Managers; + +namespace KoeBook.Core.Services; + +public class MyOpenAiService(ISecretSettingsService secretSettingsService, IHttpClientFactory httpClientFactory) : IOpenAIService +{ + private readonly ISecretSettingsService _secretSettingsService = secretSettingsService; + private readonly IHttpClientFactory _httpClientFactory = httpClientFactory; + + private string? _apiKey; + private OpenAIService? _openAiService; + + + public IModelService Models => GetOpenAiService()?.Models!; + + public ICompletionService Completions => GetOpenAiService()?.Completions!; + + public IEmbeddingService Embeddings => GetOpenAiService()?.Embeddings!; + + public OpenAI.Interfaces.IFileService Files => GetOpenAiService()?.Files!; + + public IFineTuneService FineTunes => GetOpenAiService()?.FineTunes!; + + public IFineTuningJobService FineTuningJob => GetOpenAiService()?.FineTuningJob!; + + public IModerationService Moderation => GetOpenAiService()?.Moderation!; + + public IImageService Image => GetOpenAiService()?.Image!; + + public IEditService Edit => GetOpenAiService()?.Edit!; + + public IChatCompletionService ChatCompletion => GetOpenAiService()?.ChatCompletion!; + + public IAudioService Audio => GetOpenAiService()?.Audio!; + + public void SetDefaultModelId(string modelId) + { + GetOpenAiService()?.SetDefaultModelId(modelId); + } + + private OpenAIService? GetOpenAiService() + { + if (_apiKey != _secretSettingsService.ApiKey) + { + if (string.IsNullOrEmpty(_secretSettingsService.ApiKey)) + { + _apiKey = _secretSettingsService.ApiKey; + return null; + } + var options = new OpenAiOptions + { + ApiKey = _secretSettingsService.ApiKey, + }; + var openAiService = new OpenAIService(options, _httpClientFactory.CreateClient()); + + _openAiService = openAiService; + _apiKey = _secretSettingsService.ApiKey; + } + return _openAiService; + } +} diff --git a/KoeBook.Core/Services/SercretSettingsService.cs b/KoeBook.Core/Services/SercretSettingsService.cs index da725be..ad64b4f 100644 --- a/KoeBook.Core/Services/SercretSettingsService.cs +++ b/KoeBook.Core/Services/SercretSettingsService.cs @@ -9,6 +9,8 @@ public class SecretSettingsService : ISecretSettingsService { private readonly byte[] _bytes; + public string? ApiKey { get; private set; } + public SecretSettingsService() { ulong value = 2546729043367843253ul; @@ -18,9 +20,9 @@ public SecretSettingsService() _bytes = BitConverter.GetBytes(value); } - public Task GetApiKeyAsync(string folderPath, CancellationToken cancellationToken) + public async Task InitializeAsync(string folderPath, CancellationToken cancellationToken) { - return Task.Run(async () => + ApiKey = await Task.Run(async () => { cancellationToken.ThrowIfCancellationRequested(); var path = Path.Combine(folderPath, "alt"); @@ -32,12 +34,14 @@ public SecretSettingsService() var result = ProtectedData.Unprotect(data, _bytes, DataProtectionScope.CurrentUser); return Encoding.UTF8.GetString(result); - }, cancellationToken); + }, cancellationToken).ConfigureAwait(false); + return ApiKey; } public Task SaveApiKeyAsync(string folderPath, string apiKey, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(apiKey); + ApiKey = apiKey; return Task.Run(async () => { cancellationToken.ThrowIfCancellationRequested(); diff --git a/KoeBook/Services/ActivationService.cs b/KoeBook/Services/ActivationService.cs index 7f021b2..97c72a8 100644 --- a/KoeBook/Services/ActivationService.cs +++ b/KoeBook/Services/ActivationService.cs @@ -14,6 +14,7 @@ public class ActivationService : IActivationService private readonly IEnumerable _activationHandlers; private readonly IThemeSelectorService _themeSelectorService; private readonly IApiRootSelectorService _apiRootSelectorService; + private readonly ISecretSettingsService _secretSettingsService; private readonly ISoundGenerationSelectorService _soundGenerationSelectorService; private UIElement? _shell = null; @@ -22,12 +23,14 @@ public ActivationService( IEnumerable activationHandlers, IThemeSelectorService themeSelectorService, IApiRootSelectorService apiRootSelectorService, + ISecretSettingsService secretSettingsService, ISoundGenerationSelectorService soundGenerationSelectorService) { _defaultHandler = defaultHandler; _activationHandlers = activationHandlers; _themeSelectorService = themeSelectorService; _apiRootSelectorService = apiRootSelectorService; + _secretSettingsService = secretSettingsService; _soundGenerationSelectorService = soundGenerationSelectorService; } @@ -72,6 +75,7 @@ private async Task InitializeAsync() { await _themeSelectorService.InitializeAsync().ConfigureAwait(false); await _apiRootSelectorService.InitializeAsync(default).ConfigureAwait(false); + await _secretSettingsService.InitializeAsync(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "KoeBook/ApplicationData"), default).ConfigureAwait(false); await _soundGenerationSelectorService.InitializeAsync(default).ConfigureAwait(false); await Task.CompletedTask; } diff --git a/KoeBook/Services/LocalSettingsService.cs b/KoeBook/Services/LocalSettingsService.cs index 3fe9bcf..295ed64 100644 --- a/KoeBook/Services/LocalSettingsService.cs +++ b/KoeBook/Services/LocalSettingsService.cs @@ -87,7 +87,7 @@ public async Task SaveSettingAsync(string key, T value) public async ValueTask GetApiKeyAsync(CancellationToken cancellationToken) { - return await _secretSettingsService.GetApiKeyAsync(_applicationDataFolder, cancellationToken).ConfigureAwait(false); + return await _secretSettingsService.InitializeAsync(_applicationDataFolder, cancellationToken).ConfigureAwait(false); } public async ValueTask SaveApiKeyAsync(string apiKey, CancellationToken cancellationToken) diff --git a/KoeBook/ViewModels/SettingsViewModel.cs b/KoeBook/ViewModels/SettingsViewModel.cs index b9aff31..384ce9f 100644 --- a/KoeBook/ViewModels/SettingsViewModel.cs +++ b/KoeBook/ViewModels/SettingsViewModel.cs @@ -16,6 +16,7 @@ public partial class SettingsViewModel : ObservableRecipient { private readonly IThemeSelectorService _themeSelectorService; private readonly IApiRootSelectorService _apiRootSelectorService; + private readonly ISecretSettingsService _secretSettingsService; private readonly ILocalSettingsService _localSettingsService; private readonly ISoundGenerationSelectorService _soundGenerationSelectorService; @@ -30,7 +31,7 @@ public int SelectedThemeIndex } [ObservableProperty] - private string _apiKey = string.Empty; + private string _apiKey; [ObservableProperty] [NotifyPropertyChangedFor(nameof(ApiKeyRevealMode))] @@ -50,11 +51,13 @@ public int SelectedThemeIndex public SettingsViewModel(IThemeSelectorService themeSelectorService, IApiRootSelectorService apiRootSelectorService, ISoundGenerationSelectorService soundGenerationSelectorService, - ILocalSettingsService localSettingsService) + ILocalSettingsService localSettingsService, + ISecretSettingsService secretSettingsService) { _themeSelectorService = themeSelectorService; _elementTheme = _themeSelectorService.Theme; - _localSettingsService = localSettingsService; + _secretSettingsService = secretSettingsService; + _apiKey = _secretSettingsService.ApiKey ?? string.Empty; _apiRootSelectorService = apiRootSelectorService; _styleBertVitsRoot = apiRootSelectorService.StyleBertVitsRoot; _soundGenerationSelectorService = soundGenerationSelectorService; @@ -87,13 +90,6 @@ static async void Core(IApiRootSelectorService service, ISoundGenerationSelector } } - public async void OnLoaded(object _, RoutedEventArgs __) - { - var key = await _localSettingsService.GetApiKeyAsync(default); - if (key is not null) - ApiKey = key; - } - private static string GetVersionDescription() { Version version; diff --git a/KoeBook/Views/SettingsPage.xaml b/KoeBook/Views/SettingsPage.xaml index 08a6af4..55990fe 100644 --- a/KoeBook/Views/SettingsPage.xaml +++ b/KoeBook/Views/SettingsPage.xaml @@ -7,8 +7,7 @@ xmlns:controls="using:CommunityToolkit.WinUI.Controls" xmlns:helpers="using:KoeBook.Helpers" xmlns:ui="using:CommunityToolkit.WinUI" - mc:Ignorable="d" - Loaded="{x:Bind ViewModel.OnLoaded}"> + mc:Ignorable="d"> From aee07f341412c2c1fbefcc4b0309b6bb8e254b5e Mon Sep 17 00:00:00 2001 From: herring101 <81513223+herring101@users.noreply.github.com> Date: Sun, 25 Feb 2024 01:01:54 +0900 Subject: [PATCH 04/15] analyzer mock --- KoeBook/Services/CoreMocks/AnalyzerServiceMock.cs | 2 +- KoeBook/Services/GenerationTaskRunnerService.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/KoeBook/Services/CoreMocks/AnalyzerServiceMock.cs b/KoeBook/Services/CoreMocks/AnalyzerServiceMock.cs index d54b1a8..51ed97a 100644 --- a/KoeBook/Services/CoreMocks/AnalyzerServiceMock.cs +++ b/KoeBook/Services/CoreMocks/AnalyzerServiceMock.cs @@ -10,7 +10,7 @@ public class AnalyzerServiceMock(IDisplayStateChangeService stateService) : IAna { private readonly IDisplayStateChangeService _stateService = stateService; - public async ValueTask AnalyzeAsync(BookProperties bookProperties, CancellationToken cancellationToken) + public async ValueTask AnalyzeAsync(BookProperties bookProperties, string tempDirectory, string coverFilePath, CancellationToken cancellationToken) { DisplayStateChanging stateChanging; if (bookProperties.SourceType == SourceType.Url) diff --git a/KoeBook/Services/GenerationTaskRunnerService.cs b/KoeBook/Services/GenerationTaskRunnerService.cs index 5669da4..5029174 100644 --- a/KoeBook/Services/GenerationTaskRunnerService.cs +++ b/KoeBook/Services/GenerationTaskRunnerService.cs @@ -50,7 +50,7 @@ private async ValueTask RunAsync(GenerationTask task) { try { - var scripts = await _analyzerService.AnalyzeAsync(new(task.Id, task.Source, task.SourceType), task.CancellationToken); + var scripts = await _analyzerService.AnalyzeAsync(new(task.Id, task.Source, task.SourceType), "", "", task.CancellationToken); task.BookScripts = scripts; task.State = GenerationState.Editting; task.Progress = 0; From 5030003ec412a98a3766525e6fa7e4e4b1d68c0c Mon Sep 17 00:00:00 2001 From: herring101 <81513223+herring101@users.noreply.github.com> Date: Sun, 25 Feb 2024 01:05:10 +0900 Subject: [PATCH 05/15] fix analyzeAsync --- KoeBook.Core/Services/AnalyzerService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KoeBook.Core/Services/AnalyzerService.cs b/KoeBook.Core/Services/AnalyzerService.cs index 0b50b9c..5771a14 100644 --- a/KoeBook.Core/Services/AnalyzerService.cs +++ b/KoeBook.Core/Services/AnalyzerService.cs @@ -16,7 +16,7 @@ public class AnalyzerService(IScrapingService scrapingService, IEpubDocumentStor public async ValueTask AnalyzeAsync(BookProperties bookProperties, string tempDirectory, string coverFilePath, CancellationToken cancellationToken) { - var document = await _scrapingService.ScrapingAsync(bookProperties.Source, coverFilePath, bookProperties.Id, cancellationToken); + var document = await _scrapingService.ScrapingAsync(bookProperties.Source, coverFilePath, tempDirectory, bookProperties.Id, cancellationToken); _epubDocumentStoreService.Register(document, cancellationToken); var scriptLines = new List(); From d8d9ca6c7dc8dbee2f98e4720f0c333a9c0ca092 Mon Sep 17 00:00:00 2001 From: herring101 <81513223+herring101@users.noreply.github.com> Date: Sun, 25 Feb 2024 01:40:35 +0900 Subject: [PATCH 06/15] characterMapping --- KoeBook.Core/Services/AnalyzerService.cs | 7 +- .../Services/ChaGptAnalyzerService.cs | 106 ++++++++++++++---- 2 files changed, 91 insertions(+), 22 deletions(-) diff --git a/KoeBook.Core/Services/AnalyzerService.cs b/KoeBook.Core/Services/AnalyzerService.cs index 5771a14..d52f748 100644 --- a/KoeBook.Core/Services/AnalyzerService.cs +++ b/KoeBook.Core/Services/AnalyzerService.cs @@ -7,7 +7,7 @@ namespace KoeBook.Core.Services; -public class AnalyzerService(IScrapingService scrapingService, IEpubDocumentStoreService epubDocumentStoreService, ILlmAnalyzerService llmAnalyzerService) : IAnalyzerService +public partial class AnalyzerService(IScrapingService scrapingService, IEpubDocumentStoreService epubDocumentStoreService, ILlmAnalyzerService llmAnalyzerService) : IAnalyzerService { private readonly IScrapingService _scrapingService = scrapingService; private readonly IEpubDocumentStoreService _epubDocumentStoreService = epubDocumentStoreService; @@ -30,7 +30,7 @@ public async ValueTask AnalyzeAsync(BookProperties bookProperties, { var line = paragraph.Text; // rubyタグがあればルビのdictionaryに登録 - var matches = Regex.Matches(line, "(.*?)(.*?)"); + var matches = MyRegex().Matches(input: line); foreach (Match match in matches) { var key = match.Groups[1].Value; @@ -70,4 +70,7 @@ public async ValueTask AnalyzeAsync(BookProperties bookProperties, return bookScripts; } + + [GeneratedRegex("(.*?)(.*?)")] + private static partial Regex MyRegex(); } diff --git a/KoeBook.Core/Services/ChaGptAnalyzerService.cs b/KoeBook.Core/Services/ChaGptAnalyzerService.cs index 86b128f..1d0e28c 100644 --- a/KoeBook.Core/Services/ChaGptAnalyzerService.cs +++ b/KoeBook.Core/Services/ChaGptAnalyzerService.cs @@ -35,7 +35,7 @@ public async ValueTask LlmAnalyzeScriptLinesAsync(BookProperties bo } // キャラクター名と声のマッピング - var characterVoiceMapping = await GetCharacterVoiceMappingAsync(characterList.Peek(), cancellationToken); + var characterVoiceMapping = await GetCharacterVoiceMappingAsync(scriptLines, characterList.Peek(), cancellationToken); var bookScripts = new BookScripts ( @@ -161,10 +161,11 @@ 3. Target Sentence var result = completionResult.Choices.First().Message.Content; // "#### Talker and Style Setting"以下の文章を改行区切りでリスト化 List output = new List(); - var lines = result.Split("\n"); + var lines = result?.Split("\n"); var start = false; - foreach (var line in lines) + for (var i = 0; i < lines?.Length; i++) { + var line = lines[i]; if (start) { if (line.Contains("```")) @@ -263,20 +264,23 @@ 3. Story - {summary2} ... ``` - """) + """), }, + Model = OpenAI.ObjectModels.Models.Gpt_4_0125_preview, + MaxTokens = 2000 }); if (completionResult.Successful) { var result = completionResult.Choices.First().Message.Content; - var lines = result.Split("\n"); + var lines = result?.Split("\n"); bool summaryStart = false; bool characterListStart = false; StringBuilder _summary = new(); StringBuilder _characterList = new(); - foreach (var line in lines) + for (var i = 0; i < lines?.Length; i++) { + var line = lines[i]; if (line.Contains("#### CharacterList")) { characterListStart = true; @@ -311,20 +315,82 @@ 3. Story } } - private async Task> GetCharacterVoiceMappingAsync(string characterList, CancellationToken cancellationToken) + private async Task> GetCharacterVoiceMappingAsync(List scriptLines, string characterDescription, CancellationToken cancellationToken) { - //var completionResult = await _openAiService.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest - //{ - // Messages = new List - // { - // ChatMessage.FromSystem($$""" - // All Information - // - Goal - // - Information about this story - // - Output Format - // """) - // } - //} - return new Dictionary(); + // キャラクター名一覧の取得 + var characterList = scriptLines.Select(x => "- " + x.Character).Distinct().ToList(); + var characterListString = string.Join("\n", characterList); + var completionResult = await _openAiService.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest + { + Messages = new List + { + ChatMessage.FromSystem($$""" + All Information + - Goal + - Character Description + - Character List + - Voice List + - Output Format + + #### Goal + Make a table of character names and voices + + #### Character Description + {{characterDescription}} + + #### Character List + {{characterListString}} + + #### Voice List + - ナレーション女 + - 女子小学生 + - 女子中高生 + - 成人女性 + - 老年女性 + - ナレーション男 + - 男子小学生 + - 男子中高生 + - 成人男性 + - 老年男性 + + #### Output Format + ``` + {character1} - {voice1} + {character2} - {voice2} + ... + ``` + """) + }, + Model = OpenAI.ObjectModels.Models.Gpt_4_0125_preview, + MaxTokens = 2000 + }); + if (completionResult.Successful) + { + var result = completionResult.Choices.First().Message.Content; + var lines = result?.Split("\n"); + Dictionary characterVoiceMapping = new(); + foreach (var match in from line in lines + let match = CharacterMappingRegex().Match(line) + select match) + { + if (match.Success) + { + characterVoiceMapping.Add(match.Groups[1].Value, match.Groups[2].Value); + } + else + { + EbookException.Throw(ExceptionType.Gpt4TalkerAndStyleSettingFailed); + } + } + return characterVoiceMapping; + } + else + { + EbookException.Throw(ExceptionType.Gpt4TalkerAndStyleSettingFailed); + return default!; + } } + + [GeneratedRegex(@"(.+) - (.+)")] + private static partial Regex CharacterMappingRegex(); } From 08bb4c1f26fdb9c8b78583b79fb8ef6e3ae79ec6 Mon Sep 17 00:00:00 2001 From: aiueo-1234 <130837816+aiueo-1234@users.noreply.github.com> Date: Sun, 25 Feb 2024 01:58:44 +0900 Subject: [PATCH 07/15] =?UTF-8?q?DI=E3=81=AB=E7=99=BB=E9=8C=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{ChaGptAnalyzerService.cs => ChatGptAnalyzerService.cs} | 2 +- KoeBook/App.xaml.cs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) rename KoeBook.Core/Services/{ChaGptAnalyzerService.cs => ChatGptAnalyzerService.cs} (99%) diff --git a/KoeBook.Core/Services/ChaGptAnalyzerService.cs b/KoeBook.Core/Services/ChatGptAnalyzerService.cs similarity index 99% rename from KoeBook.Core/Services/ChaGptAnalyzerService.cs rename to KoeBook.Core/Services/ChatGptAnalyzerService.cs index 1d0e28c..e6941d5 100644 --- a/KoeBook.Core/Services/ChaGptAnalyzerService.cs +++ b/KoeBook.Core/Services/ChatGptAnalyzerService.cs @@ -7,7 +7,7 @@ namespace KoeBook.Core.Services; -public partial class ChaGptAnalyzerService(IOpenAIService openAIService) : ILlmAnalyzerService +public partial class ChatGptAnalyzerService(IOpenAIService openAIService) : ILlmAnalyzerService { private readonly IOpenAIService _openAiService = openAIService; diff --git a/KoeBook/App.xaml.cs b/KoeBook/App.xaml.cs index 3458991..73d7f4c 100644 --- a/KoeBook/App.xaml.cs +++ b/KoeBook/App.xaml.cs @@ -92,6 +92,9 @@ public App() services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); // Views and ViewModels services.AddTransient(); From 2adf3103bd5787cd32b51b372509272f07483f6f Mon Sep 17 00:00:00 2001 From: aiueo-1234 <130837816+aiueo-1234@users.noreply.github.com> Date: Sun, 25 Feb 2024 02:00:05 +0900 Subject: [PATCH 08/15] =?UTF-8?q?=E3=83=95=E3=82=A9=E3=83=BC=E3=83=9E?= =?UTF-8?q?=E3=83=83=E3=83=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KoeBook.Core/Services/SercretSettingsService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KoeBook.Core/Services/SercretSettingsService.cs b/KoeBook.Core/Services/SercretSettingsService.cs index ad64b4f..9ae223a 100644 --- a/KoeBook.Core/Services/SercretSettingsService.cs +++ b/KoeBook.Core/Services/SercretSettingsService.cs @@ -9,7 +9,7 @@ public class SecretSettingsService : ISecretSettingsService { private readonly byte[] _bytes; - public string? ApiKey { get; private set; } + public string? ApiKey { get; private set; } public SecretSettingsService() { From 1de3c7cf543ad84ae1896eda21189974b0ef77e3 Mon Sep 17 00:00:00 2001 From: aiueo-1234 <130837816+aiueo-1234@users.noreply.github.com> Date: Sun, 25 Feb 2024 02:19:04 +0900 Subject: [PATCH 09/15] =?UTF-8?q?SettingsViewModel.cs=E3=81=AE=E3=82=B3?= =?UTF-8?q?=E3=83=B3=E3=82=B9=E3=83=88=E3=83=A9=E3=82=AF=E3=82=BF=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KoeBook/ViewModels/SettingsViewModel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/KoeBook/ViewModels/SettingsViewModel.cs b/KoeBook/ViewModels/SettingsViewModel.cs index 384ce9f..fe81b98 100644 --- a/KoeBook/ViewModels/SettingsViewModel.cs +++ b/KoeBook/ViewModels/SettingsViewModel.cs @@ -59,6 +59,7 @@ public SettingsViewModel(IThemeSelectorService themeSelectorService, _secretSettingsService = secretSettingsService; _apiKey = _secretSettingsService.ApiKey ?? string.Empty; _apiRootSelectorService = apiRootSelectorService; + _localSettingsService = localSettingsService; _styleBertVitsRoot = apiRootSelectorService.StyleBertVitsRoot; _soundGenerationSelectorService = soundGenerationSelectorService; _versionDescription = GetVersionDescription(); From 21ab9a1bcbe97f9d309659cd85ba6673f3b03934 Mon Sep 17 00:00:00 2001 From: aiueo-1234 <130837816+aiueo-1234@users.noreply.github.com> Date: Sun, 25 Feb 2024 02:49:44 +0900 Subject: [PATCH 10/15] =?UTF-8?q?DI=E3=81=AE=E8=BF=BD=E5=8A=A0=E3=81=A8Scr?= =?UTF-8?q?apingAsync=E3=81=AE=E3=82=A8=E3=83=A9=E3=83=BC=E5=87=A6?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KoeBook.Core/EbookException.cs | 3 +++ KoeBook.Core/Services/AnalyzerService.cs | 11 ++++++++++- KoeBook/App.xaml.cs | 4 ++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/KoeBook.Core/EbookException.cs b/KoeBook.Core/EbookException.cs index 99d6d67..e8590e8 100644 --- a/KoeBook.Core/EbookException.cs +++ b/KoeBook.Core/EbookException.cs @@ -43,4 +43,7 @@ public enum ExceptionType [EnumMember(Value = "GPT4による話者・スタイル設定に失敗しました")] Gpt4TalkerAndStyleSettingFailed, + + [EnumMember(Value = "webページの解析に失敗しました")] + WebScrapingFailed } diff --git a/KoeBook.Core/Services/AnalyzerService.cs b/KoeBook.Core/Services/AnalyzerService.cs index d52f748..08be95f 100644 --- a/KoeBook.Core/Services/AnalyzerService.cs +++ b/KoeBook.Core/Services/AnalyzerService.cs @@ -16,7 +16,16 @@ public partial class AnalyzerService(IScrapingService scrapingService, IEpubDocu public async ValueTask AnalyzeAsync(BookProperties bookProperties, string tempDirectory, string coverFilePath, CancellationToken cancellationToken) { - var document = await _scrapingService.ScrapingAsync(bookProperties.Source, coverFilePath, tempDirectory, bookProperties.Id, cancellationToken); + EpubDocument? document; + try + { + document = await _scrapingService.ScrapingAsync(bookProperties.Source, coverFilePath, tempDirectory, bookProperties.Id, cancellationToken); + } + catch (Exception ex) + { + EbookException.Throw(ExceptionType.WebScrapingFailed, "", ex); + return default; + } _epubDocumentStoreService.Register(document, cancellationToken); var scriptLines = new List(); diff --git a/KoeBook/App.xaml.cs b/KoeBook/App.xaml.cs index 73d7f4c..c828253 100644 --- a/KoeBook/App.xaml.cs +++ b/KoeBook/App.xaml.cs @@ -6,6 +6,8 @@ using KoeBook.Core.Contracts.Services; using KoeBook.Core.Services; using KoeBook.Core.Services.Mocks; +using KoeBook.Epub; +using KoeBook.Epub.Service; using KoeBook.Models; using KoeBook.Notifications; using KoeBook.Services; @@ -95,6 +97,8 @@ public App() services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + // TODO: 切り替えサービスを作成 + services.AddSingleton(); // Views and ViewModels services.AddTransient(); From 01372e7eaa95981dda6c2b6909540d5f7c4d38ef Mon Sep 17 00:00:00 2001 From: herring101 <81513223+herring101@users.noreply.github.com> Date: Sun, 25 Feb 2024 10:11:09 +0900 Subject: [PATCH 11/15] fix ruby replacement --- KoeBook.Core/Services/AnalyzerService.cs | 47 ++++++++++++++++++------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/KoeBook.Core/Services/AnalyzerService.cs b/KoeBook.Core/Services/AnalyzerService.cs index 08be95f..43f5531 100644 --- a/KoeBook.Core/Services/AnalyzerService.cs +++ b/KoeBook.Core/Services/AnalyzerService.cs @@ -39,21 +39,18 @@ public async ValueTask AnalyzeAsync(BookProperties bookProperties, { var line = paragraph.Text; // rubyタグがあればルビのdictionaryに登録 - var matches = MyRegex().Matches(input: line); - foreach (Match match in matches) + var rubyDict = ExtractRuby(line); + + foreach (var ruby in rubyDict) { - var key = match.Groups[1].Value; - var value = match.Groups[2].Value; - if (!_rubyReplacements.ContainsKey(key)) + if (!_rubyReplacements.ContainsKey(ruby.Key)) { - _rubyReplacements.Add(key, value); + _rubyReplacements.Add(ruby.Key, ruby.Value); } } // ルビを置換 - foreach (var replacement in _rubyReplacements) - { - line = line.Replace(replacement.Key, replacement.Value); - } + line = ReplaceBaseTextWithRuby(line, rubyDict); + scriptLines.Add(new ScriptLine(paragraph, line, "", "")); } } @@ -80,6 +77,32 @@ public async ValueTask AnalyzeAsync(BookProperties bookProperties, return bookScripts; } - [GeneratedRegex("(.*?)(.*?)")] - private static partial Regex MyRegex(); + private static Dictionary ExtractRuby(string text) + { + var rubyDict = new Dictionary(); + var rubyRegex = new Regex("(.*?)(.*?)"); + + foreach (Match match in rubyRegex.Matches(text)) + { + if (!rubyDict.ContainsKey(match.Groups[1].Value)) + { + rubyDict.Add(match.Groups[1].Value, match.Groups[2].Value); + } + } + + return rubyDict; + } + + private static string ReplaceBaseTextWithRuby(string text, Dictionary rubyDict) + { + // 元のテキストからルビタグをすべてルビテキストに置き換える + var resultText = text; + foreach (var pair in rubyDict) + { + var rubyTag = $"{pair.Key}{pair.Value}"; + resultText = resultText.Replace(rubyTag, pair.Value); + } + + return resultText; + } } From 43dc05581982f3c17b1de302208749ef9d701b46 Mon Sep 17 00:00:00 2001 From: aiueo-1234 <130837816+aiueo-1234@users.noreply.github.com> Date: Sun, 25 Feb 2024 12:14:41 +0900 Subject: [PATCH 12/15] =?UTF-8?q?=E3=82=AB=E3=83=90=E3=83=BC=E3=83=95?= =?UTF-8?q?=E3=82=A1=E3=82=A4=E3=83=AB=E3=81=AE=E5=AF=BE=E7=AD=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/AnalyzerService _CoverFileBytes.cs | 13 +++++++++++++ KoeBook.Core/Services/AnalyzerService.cs | 5 +++++ KoeBook/Services/GenerationTaskRunnerService.cs | 10 +++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 KoeBook.Core/Services/AnalyzerService _CoverFileBytes.cs diff --git a/KoeBook.Core/Services/AnalyzerService _CoverFileBytes.cs b/KoeBook.Core/Services/AnalyzerService _CoverFileBytes.cs new file mode 100644 index 0000000..ff1681e --- /dev/null +++ b/KoeBook.Core/Services/AnalyzerService _CoverFileBytes.cs @@ -0,0 +1,13 @@ +using System.Text; +using System.Text.RegularExpressions; +using KoeBook.Core.Contracts.Services; +using KoeBook.Core.Models; +using KoeBook.Epub; +using KoeBook.Epub.Service; + +namespace KoeBook.Core.Services; + +public partial class AnalyzerService +{ + public ReadOnlySpan CoverFile => [89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x0, 0x1, 0x90, 0x8, 0x6, 0x0, 0x0, 0x0, 0x14, 0x75, 0x5d, 0x7b, 0x0, 0x0, 0x0, 0x1, 0x73, 0x52, 0x47, 0x42, 0x0, 0xae, 0xce, 0x1c, 0xe9, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0x1d, 0x87, 0x0, 0x0, 0x1d, 0x87, 0x1, 0x8f, 0xe5, 0xf1, 0x65, 0x0, 0x0, 0x4, 0xfa, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0xed, 0xd4, 0x1, 0xd, 0x0, 0x0, 0xc, 0xc3, 0xa0, 0xfb, 0x37, 0xbd, 0xeb, 0x68, 0x2, 0x22, 0xb8, 0x1, 0x44, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x22, 0xb6, 0x7, 0x7c, 0x3f, 0x1a, 0x75, 0x8a, 0x71, 0x90, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82] +} diff --git a/KoeBook.Core/Services/AnalyzerService.cs b/KoeBook.Core/Services/AnalyzerService.cs index 43f5531..5c5b0c1 100644 --- a/KoeBook.Core/Services/AnalyzerService.cs +++ b/KoeBook.Core/Services/AnalyzerService.cs @@ -16,6 +16,11 @@ public partial class AnalyzerService(IScrapingService scrapingService, IEpubDocu public async ValueTask AnalyzeAsync(BookProperties bookProperties, string tempDirectory, string coverFilePath, CancellationToken cancellationToken) { + coverFilePath = Path.Combine(tempDirectory, "Cover.png"); + using var fs = File.Create(coverFilePath); + await fs.WriteAsync(CoverFile.ToArray(), cancellationToken); + await fs.FlushAsync(cancellationToken); + EpubDocument? document; try { diff --git a/KoeBook/Services/GenerationTaskRunnerService.cs b/KoeBook/Services/GenerationTaskRunnerService.cs index 5029174..0522457 100644 --- a/KoeBook/Services/GenerationTaskRunnerService.cs +++ b/KoeBook/Services/GenerationTaskRunnerService.cs @@ -50,7 +50,7 @@ private async ValueTask RunAsync(GenerationTask task) { try { - var scripts = await _analyzerService.AnalyzeAsync(new(task.Id, task.Source, task.SourceType), "", "", task.CancellationToken); + var scripts = await _analyzerService.AnalyzeAsync(new(task.Id, task.Source, task.SourceType), _tempFolder, "", task.CancellationToken); task.BookScripts = scripts; task.State = GenerationState.Editting; task.Progress = 0; @@ -59,8 +59,10 @@ private async ValueTask RunAsync(GenerationTask task) { var resultPath = await _epubGenService.GenerateEpubAsync(scripts, _tempFolder, task.CancellationToken); task.State = GenerationState.Completed; - task.Progress = 0; - task.MaximumProgress = 0; + task.Progress = 1; + task.MaximumProgress = 1; + var fileName = Path.GetFileName(resultPath); + File.Copy(resultPath, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),"KoeBook", fileName), true); } } catch (OperationCanceledException) @@ -88,6 +90,8 @@ public async void RunGenerateEpubAsync(GenerationTask task) task.State = GenerationState.Completed; task.Progress = 1; task.MaximumProgress = 1; + var fileName = Path.GetFileName(resultPath); + File.Copy(resultPath, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "KoeBook", fileName), true); } catch (OperationCanceledException) { From d65719d984d6a4c62d12db2194eaebb9a03f9004 Mon Sep 17 00:00:00 2001 From: aiueo-1234 <130837816+aiueo-1234@users.noreply.github.com> Date: Sun, 25 Feb 2024 12:18:23 +0900 Subject: [PATCH 13/15] =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- KoeBook.Core/Services/AnalyzerService _CoverFileBytes.cs | 2 +- KoeBook/Services/GenerationTaskRunnerService.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/KoeBook.Core/Services/AnalyzerService _CoverFileBytes.cs b/KoeBook.Core/Services/AnalyzerService _CoverFileBytes.cs index ff1681e..4edc65d 100644 --- a/KoeBook.Core/Services/AnalyzerService _CoverFileBytes.cs +++ b/KoeBook.Core/Services/AnalyzerService _CoverFileBytes.cs @@ -9,5 +9,5 @@ namespace KoeBook.Core.Services; public partial class AnalyzerService { - public ReadOnlySpan CoverFile => [89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x0, 0x1, 0x90, 0x8, 0x6, 0x0, 0x0, 0x0, 0x14, 0x75, 0x5d, 0x7b, 0x0, 0x0, 0x0, 0x1, 0x73, 0x52, 0x47, 0x42, 0x0, 0xae, 0xce, 0x1c, 0xe9, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0x1d, 0x87, 0x0, 0x0, 0x1d, 0x87, 0x1, 0x8f, 0xe5, 0xf1, 0x65, 0x0, 0x0, 0x4, 0xfa, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0xed, 0xd4, 0x1, 0xd, 0x0, 0x0, 0xc, 0xc3, 0xa0, 0xfb, 0x37, 0xbd, 0xeb, 0x68, 0x2, 0x22, 0xb8, 0x1, 0x44, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x22, 0xb6, 0x7, 0x7c, 0x3f, 0x1a, 0x75, 0x8a, 0x71, 0x90, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82] + public ReadOnlySpan CoverFile => [89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x1, 0x2c, 0x0, 0x0, 0x1, 0x90, 0x8, 0x6, 0x0, 0x0, 0x0, 0x14, 0x75, 0x5d, 0x7b, 0x0, 0x0, 0x0, 0x1, 0x73, 0x52, 0x47, 0x42, 0x0, 0xae, 0xce, 0x1c, 0xe9, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0x1d, 0x87, 0x0, 0x0, 0x1d, 0x87, 0x1, 0x8f, 0xe5, 0xf1, 0x65, 0x0, 0x0, 0x4, 0xfa, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0xed, 0xd4, 0x1, 0xd, 0x0, 0x0, 0xc, 0xc3, 0xa0, 0xfb, 0x37, 0xbd, 0xeb, 0x68, 0x2, 0x22, 0xb8, 0x1, 0x44, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x32, 0x84, 0x5, 0x64, 0x8, 0xb, 0xc8, 0x10, 0x16, 0x90, 0x21, 0x2c, 0x20, 0x43, 0x58, 0x40, 0x86, 0xb0, 0x80, 0xc, 0x61, 0x1, 0x19, 0xc2, 0x2, 0x22, 0xb6, 0x7, 0x7c, 0x3f, 0x1a, 0x75, 0x8a, 0x71, 0x90, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82]; } diff --git a/KoeBook/Services/GenerationTaskRunnerService.cs b/KoeBook/Services/GenerationTaskRunnerService.cs index 0522457..fe6f0fd 100644 --- a/KoeBook/Services/GenerationTaskRunnerService.cs +++ b/KoeBook/Services/GenerationTaskRunnerService.cs @@ -62,7 +62,7 @@ private async ValueTask RunAsync(GenerationTask task) task.Progress = 1; task.MaximumProgress = 1; var fileName = Path.GetFileName(resultPath); - File.Copy(resultPath, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),"KoeBook", fileName), true); + File.Copy(resultPath, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "KoeBook", fileName), true); } } catch (OperationCanceledException) From 504cb7b5bc500942cea2a730bb061c50df44bb17 Mon Sep 17 00:00:00 2001 From: herring101 <81513223+herring101@users.noreply.github.com> Date: Sun, 25 Feb 2024 12:20:29 +0900 Subject: [PATCH 14/15] GPT4 character and style Analyze --- KoeBook.Core/Services/AnalyzerService.cs | 2 +- .../Services/ChatGptAnalyzerService.cs | 97 +++++++++---------- 2 files changed, 46 insertions(+), 53 deletions(-) diff --git a/KoeBook.Core/Services/AnalyzerService.cs b/KoeBook.Core/Services/AnalyzerService.cs index 43f5531..7514cc1 100644 --- a/KoeBook.Core/Services/AnalyzerService.cs +++ b/KoeBook.Core/Services/AnalyzerService.cs @@ -67,7 +67,7 @@ public async ValueTask AnalyzeAsync(BookProperties bookProperties, chunks.Add(chunk.ToString()); chunk.Clear(); } - chunk.Append(line.Text); + chunk.AppendLine(line.Text); } if (chunk.Length > 0) chunks.Add(chunk.ToString()); diff --git a/KoeBook.Core/Services/ChatGptAnalyzerService.cs b/KoeBook.Core/Services/ChatGptAnalyzerService.cs index e6941d5..dd0d84e 100644 --- a/KoeBook.Core/Services/ChatGptAnalyzerService.cs +++ b/KoeBook.Core/Services/ChatGptAnalyzerService.cs @@ -1,37 +1,51 @@ using System.Text; using System.Text.RegularExpressions; using KoeBook.Core.Contracts.Services; +using KoeBook.Core.Helpers; using KoeBook.Core.Models; using OpenAI.Interfaces; using OpenAI.ObjectModels.RequestModels; namespace KoeBook.Core.Services; -public partial class ChatGptAnalyzerService(IOpenAIService openAIService) : ILlmAnalyzerService +public partial class ChatGptAnalyzerService(IOpenAIService openAIService, IDisplayStateChangeService displayStateChangeService) : ILlmAnalyzerService { private readonly IOpenAIService _openAiService = openAIService; + private readonly IDisplayStateChangeService _displayStateChangeService = displayStateChangeService; public async ValueTask LlmAnalyzeScriptLinesAsync(BookProperties bookProperties, List scriptLines, List chunks, CancellationToken cancellationToken) { + var progress = _displayStateChangeService.ResetProgress(bookProperties, GenerationState.Analyzing, chunks.Count); Queue summaryList = new(); Queue characterList = new(); + int currentLineIndex = 0; for (int i = 0; i < chunks.Count; i++) { // 話者・スタイル解析 - var Task1 = CharacterStyleAnalysisAsync(scriptLines, chunks, summaryList.Peek(), characterList.Peek(), i, cancellationToken); + var summary = ""; + var characters = ""; + if (summaryList.Count != 0) + { + summary = summaryList.Peek(); + characters = characterList.Peek(); + } + var Task1 = CharacterStyleAnalysisAsync(scriptLines, chunks, summary, characters, i, currentLineIndex, cancellationToken); // 要約・キャラクターリスト解析 - var Task2 = SummaryCharacterListAnalysisAsync(scriptLines, chunks, summaryList.Peek(), characterList.Peek(), i, cancellationToken); + var summary1 = ""; + var characters1 = ""; + if (summaryList.Count > 5) + { + summary1 = summaryList.Dequeue(); + characters1 = characterList.Dequeue(); + } + var Task2 = SummaryCharacterListAnalysisAsync(scriptLines, chunks, summary1, characters1, i, cancellationToken); // WhenAllで非同期処理を待つ await Task.WhenAll(Task1, Task2); + currentLineIndex += chunks[i].Split("\n").Length - 1; // 結果をキューに追加 summaryList.Enqueue(Task2.Result.summary); characterList.Enqueue(Task2.Result.characterList); - // 5個以上になったら古いものを削除 - if (summaryList.Count > 5) - { - summaryList.Dequeue(); - characterList.Dequeue(); - } + progress.UpdateProgress(i + 1); } // キャラクター名と声のマッピング @@ -56,8 +70,11 @@ private async Task CharacterStyleAnalysisAsync(List scriptLines, string summary, string characterList, int idx, + int currentLineIndex, CancellationToken cancellationToken) { + int count = 0; +RESTART: var completionResult = await _openAiService.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest { Messages = new List @@ -109,52 +126,27 @@ 3. Target Sentence ``` STYLE = narration | neutral | laughing | happy | sad | cry | surprised | angry assign the name of the speaker to {TALKER} if the sentence is dialogue, or use 'ナレーション' for narrative sentences. If the sentence is part of a monologue, use the name of the character who is speaking. - The {SENTENCE} should be a direct excerpt from the 'Target Sentence' section." + {SENTENCE} should be used as is from the first line of the "Target Sentence" section, without a line break. # **Notes** ## **Separate Narration and lines.** Be careful as you often make mistakes!! Input ``` - 落ちてくる落ち葉を見て、清美は言った。 + そうして、時が流れ少し肌寒い季節となった。木もすっかりやせ細っていて、黄金色の葉っぱが雪のように降っている。落ちてくる落ち葉を見て、清美は言った。 「悲しいね…。あなたとの思い出が、一枚一枚、地面に落ちていくみたい…。」 ``` Output ``` - 落ちてくる落ち葉を見て、清美は言った。[ナレーション:narration] + そうして、時が流れ少し肌寒い季節となった。木もすっかりやせ細っていて、黄金色の葉っぱが雪のように降っている。落ちてくる落ち葉を見て、清美は言った。[ナレーション:narration] 「悲しいね…。あなたとの思い出が、一枚一枚、地面に落ちていくみたい…。」[漆原清美:sad] ``` - ## First person - Input - ``` - 俺は泣きながら勇気を振り絞って言った。 - 「お前は本当に、俺のことを愛してるのか?」 - ``` - Output - ``` - 俺は泣きながら勇気を振り絞って言った。[松原一馬:narration] - 「お前は本当に、俺のことを愛してるのか?」[松原一馬:cry] - ``` - ## What is not enclosed in brackets is basically narration style - Input - ``` - ファーラン王子はそっと、王のもとへ行き、王の耳元で何かを囁いた。 - そして、王は、その言葉を聞いて、驚いたような顔をした。 - アミダス王は立ち上がり、民衆の前で声を張り上げた。 - 「私は、この国を、息子ファーランに譲る!」 - ``` - Output - ``` - ファーラン王子はそっと、王のもとへ行き、王の耳元で何かを囁いた。[ナレーション:narration] - そして、王は、その言葉を聞いて、驚いたような顔をした。[ナレーション:narration] - アミダス王は立ち上がり、民衆の前で声を張り上げた。[ナレーション:narration] - 「私は、この国を、息子ファーランに譲る!」[アミダス王:neutral] ``` """ ) }, - Model = OpenAI.ObjectModels.Models.Gpt_4_0125_preview, - MaxTokens = 2000 + Model = OpenAI.ObjectModels.Models.Gpt_4_turbo_preview, + MaxTokens = 4000 }); if (completionResult.Successful) { @@ -189,19 +181,20 @@ 3. Target Sentence var sentence = match.Groups[1].Value; var talker = match.Groups[2].Value; var style = match.Groups[3].Value; - if (sentence == scriptLines[idx + i].Text || Math.Abs(sentence.Length - scriptLines[idx + i].Text.Length) < 5) + if (sentence == scriptLines[currentLineIndex + i].Text || Math.Abs(sentence.Length - scriptLines[currentLineIndex + i].Text.Length) < 5) { - scriptLines[idx + i].Character = talker; - scriptLines[idx + i].Style = style; + scriptLines[currentLineIndex + i].Character = talker; + scriptLines[currentLineIndex + i].Style = style; } - else + else if (count > 3) { EbookException.Throw(ExceptionType.Gpt4TalkerAndStyleSettingFailed); } - } - else - { - EbookException.Throw(ExceptionType.Gpt4TalkerAndStyleSettingFailed); + else + { + count++; + goto RESTART; + } } } } @@ -259,15 +252,15 @@ 3. Story ... - #### Summery of 5 points + #### Summery of {{Math.Min(20,(idx+1)*5)}} points - {summary1} - {summary2} ... ``` """), }, - Model = OpenAI.ObjectModels.Models.Gpt_4_0125_preview, - MaxTokens = 2000 + Model = OpenAI.ObjectModels.Models.Gpt_4_turbo_preview, + MaxTokens = 4000 }); if (completionResult.Successful) { @@ -361,8 +354,8 @@ Make a table of character names and voices ``` """) }, - Model = OpenAI.ObjectModels.Models.Gpt_4_0125_preview, - MaxTokens = 2000 + Model = OpenAI.ObjectModels.Models.Gpt_4_turbo_preview, + MaxTokens = 4000 }); if (completionResult.Successful) { From 55410b4027de013aa5023e87d790ce19184babbf Mon Sep 17 00:00:00 2001 From: herring101 <81513223+herring101@users.noreply.github.com> Date: Sun, 25 Feb 2024 12:24:09 +0900 Subject: [PATCH 15/15] Update appsettings.json --- KoeBook/appsettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KoeBook/appsettings.json b/KoeBook/appsettings.json index 3c7ff82..5fbea09 100644 --- a/KoeBook/appsettings.json +++ b/KoeBook/appsettings.json @@ -4,7 +4,7 @@ "LocalSettingsFile": "LocalSettings.json" }, "MockOptions": { - "IAnalyzerService": true, + "IAnalyzerService": false, "IEpubGenerateService": false, "ISoundGenerationSelectorService": false, "ISoundGenerationService": false