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}";
+ 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