Skip to content

Commit

Permalink
Merge pull request #26 from OUCC/herring/claudia
Browse files Browse the repository at this point in the history
Claudeでの解析
  • Loading branch information
aiueo-1234 authored Apr 30, 2024
2 parents ab1eef1 + 49e0aae commit 9ca7a6c
Show file tree
Hide file tree
Showing 14 changed files with 313 additions and 55 deletions.
20 changes: 2 additions & 18 deletions Epub/KoeBook.Epub/Services/AnalyzerService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
using KoeBook.Core;
using KoeBook.Core.Contracts.Services;
Expand Down Expand Up @@ -67,23 +66,8 @@ public async ValueTask<BookScripts> AnalyzeAsync(BookProperties bookProperties,
}).Where(l => !string.IsNullOrEmpty(l.Text))
.ToArray();

// 800文字以上になったら1チャンクに分ける
var chunks = new List<string>();
var chunk = new StringBuilder();
foreach (var line in scriptLines)
{
if (chunk.Length + line.Text.Length > 800)
{
chunks.Add(chunk.ToString());
chunk.Clear();
}
chunk.AppendLine(line.Text);
}
if (chunk.Length > 0) chunks.Add(chunk.ToString());

// GPT4による話者、スタイル解析
var bookScripts = await _llmAnalyzerService.LlmAnalyzeScriptLinesAsync(bookProperties, [.. scriptLines], chunks, cancellationToken);

// LLMによる話者、スタイル解析
var bookScripts = await _llmAnalyzerService.LlmAnalyzeScriptLinesAsync(bookProperties, scriptLines, cancellationToken)!;
return bookScripts;
}

Expand Down
8 changes: 8 additions & 0 deletions KoeBook.Core/Contracts/Services/IClaudeService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Claudia;

namespace KoeBook.Core.Contracts.Services;

public interface IClaudeService
{
IMessages? Messages { get; }
}
2 changes: 1 addition & 1 deletion KoeBook.Core/Contracts/Services/ILlmAnalyzerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ namespace KoeBook.Core.Contracts.Services;

public interface ILlmAnalyzerService
{
ValueTask<BookScripts> LlmAnalyzeScriptLinesAsync(BookProperties bookProperties, List<ScriptLine> scriptLines, List<string> chunks, CancellationToken cancellationToken);
ValueTask<BookScripts> LlmAnalyzeScriptLinesAsync(BookProperties bookProperties, ScriptLine[] scriptLines, CancellationToken cancellationToken);
}
6 changes: 6 additions & 0 deletions KoeBook.Core/EbookException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ public enum ExceptionType
[EnumMember(Value = "GPT4による話者・スタイル設定に失敗しました")]
Gpt4TalkerAndStyleSettingFailed,

[EnumMember(Value = "APIキーが設定されていません")]
ApiKeyNotSet,

[EnumMember(Value = "Claudeによる話者・スタイル設定に失敗しました")]
ClaudeTalkerAndStyleSettingFailed,

[EnumMember(Value = "webページの解析に失敗しました")]
WebScrapingFailed,

Expand Down
3 changes: 2 additions & 1 deletion KoeBook.Core/KoeBook.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Betalgo.OpenAI" Version="7.4.6" />
<PackageReference Include="Betalgo.OpenAI" Version="8.1.1" />
<PackageReference Include="Claudia" Version="1.2.0" />
<PackageReference Include="FastEnum" Version="1.8.0" />
<PackageReference Include="NAudio" Version="2.2.1" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
Expand Down
6 changes: 4 additions & 2 deletions KoeBook.Core/Models/BookScripts.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace KoeBook.Core.Models;
using System.Collections.Immutable;

namespace KoeBook.Core.Models;

/// <summary>
/// 本の読み上げ情報
Expand All @@ -15,5 +17,5 @@ public class BookScripts(BookProperties bookProperties, BookOptions options)
/// <summary>
/// 読み上げテキストの配列
/// </summary>
public required IReadOnlyList<ScriptLine> ScriptLines { get; set; }
public required ImmutableArray<ScriptLine> ScriptLines { get; set; }
}
57 changes: 35 additions & 22 deletions KoeBook.Core/Services/ChatGptAnalyzerService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Text;
using System.Collections.Immutable;
using System.Text;
using System.Text.RegularExpressions;
using KoeBook.Core.Contracts.Services;
using KoeBook.Core.Helpers;
Expand All @@ -13,8 +14,20 @@ public partial class ChatGptAnalyzerService(IOpenAIService openAIService, IDispl
private readonly IOpenAIService _openAiService = openAIService;
private readonly IDisplayStateChangeService _displayStateChangeService = displayStateChangeService;

public async ValueTask<BookScripts> LlmAnalyzeScriptLinesAsync(BookProperties bookProperties, List<ScriptLine> scriptLines, List<string> chunks, CancellationToken cancellationToken)
public async ValueTask<BookScripts> LlmAnalyzeScriptLinesAsync(BookProperties bookProperties, ScriptLine[] scriptLines, CancellationToken cancellationToken)
{
var chunks = new List<string>();
var chunk = new StringBuilder();
foreach (var line in scriptLines)
{
if (chunk.Length + line.Text.Length > 800)
{
chunks.Add(chunk.ToString());
chunk.Clear();
}
chunk.AppendLine(line.Text);
}
if (chunk.Length > 0) chunks.Add(chunk.ToString());
var progress = _displayStateChangeService.ResetProgress(bookProperties, GenerationState.Analyzing, chunks.Count);
Queue<string> summaryList = new();
Queue<string> characterList = new();
Expand All @@ -38,7 +51,7 @@ public async ValueTask<BookScripts> LlmAnalyzeScriptLinesAsync(BookProperties bo
summary1 = summaryList.Dequeue();
characters1 = characterList.Dequeue();
}
var Task2 = SummaryCharacterListAnalysisAsync(scriptLines, chunks, summary1, characters1, i, cancellationToken);
var Task2 = SummaryCharacterListAnalysisAsync(chunks, summary1, characters1, i, cancellationToken);
// WhenAllで非同期処理を待つ
await Task.WhenAll(Task1, Task2);
currentLineIndex += chunks[i].Split("\n").Length - 1;
Expand All @@ -60,12 +73,12 @@ public async ValueTask<BookScripts> LlmAnalyzeScriptLinesAsync(BookProperties bo
}
)
{
ScriptLines = scriptLines
ScriptLines = [.. scriptLines]
};
return bookScripts;
}

private async Task CharacterStyleAnalysisAsync(List<ScriptLine> scriptLines,
private async Task CharacterStyleAnalysisAsync(ScriptLine[] scriptLines,
List<string> chunks,
string summary,
string characterList,
Expand All @@ -77,8 +90,8 @@ private async Task CharacterStyleAnalysisAsync(List<ScriptLine> scriptLines,
RESTART:
var completionResult = await _openAiService.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest
{
Messages = new List<ChatMessage>
{
Messages =
[
ChatMessage.FromSystem($$"""
All Information
- Goal
Expand Down Expand Up @@ -144,15 +157,15 @@ 3. Target Sentence
```
"""
)
},
],
Model = OpenAI.ObjectModels.Models.Gpt_4_turbo_preview,
MaxTokens = 4000
});
}, cancellationToken: cancellationToken);
if (completionResult.Successful)
{
var result = completionResult.Choices.First().Message.Content;
// "#### Talker and Style Setting"以下の文章を改行区切りでリスト化
List<string> output = new List<string>();
var output = new List<string>();
var lines = result?.Split("\n");
var start = false;
for (var i = 0; i < lines?.Length; i++)
Expand Down Expand Up @@ -200,7 +213,7 @@ 3. Target Sentence
}
}

private async Task<(string summary, string characterList)> SummaryCharacterListAnalysisAsync(List<ScriptLine> scriptLines,
private async Task<(string summary, string characterList)> SummaryCharacterListAnalysisAsync(
List<string> chunks,
string summary,
string characterList,
Expand All @@ -210,8 +223,8 @@ 3. Target Sentence
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>
{
Messages =
[
ChatMessage.FromSystem($$"""
All Information
- Goal
Expand Down Expand Up @@ -252,16 +265,16 @@ 3. Story
...
#### Summery of {{Math.Min(20,(idx+1)*5)}} points
#### Summery of {{Math.Min(20, (idx + 1) * 5)}} points
- {summary1}
- {summary2}
...
```
"""),
},
],
Model = OpenAI.ObjectModels.Models.Gpt_4_turbo_preview,
MaxTokens = 4000
});
}, cancellationToken: cancellationToken);
if (completionResult.Successful)
{
var result = completionResult.Choices.First().Message.Content;
Expand Down Expand Up @@ -308,15 +321,15 @@ 3. Story
}
}

private async Task<Dictionary<string, string>> GetCharacterVoiceMappingAsync(List<ScriptLine> scriptLines, string characterDescription, CancellationToken cancellationToken)
private async Task<Dictionary<string, string>> GetCharacterVoiceMappingAsync(ScriptLine[] scriptLines, string characterDescription, CancellationToken cancellationToken)
{
// キャラクター名一覧の取得
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>
{
Messages =
[
ChatMessage.FromSystem($$"""
All Information
- Goal
Expand Down Expand Up @@ -353,15 +366,15 @@ Make a table of character names and voices
...
```
""")
},
],
Model = OpenAI.ObjectModels.Models.Gpt_4_turbo_preview,
MaxTokens = 4000
});
}, cancellationToken: cancellationToken);
if (completionResult.Successful)
{
var result = completionResult.Choices.First().Message.Content;
var lines = result?.Split("\n");
Dictionary<string, string> characterVoiceMapping = new();
Dictionary<string, string> characterVoiceMapping = [];
foreach (var match in from line in lines
let match = CharacterMappingRegex().Match(line)
select match)
Expand Down
Loading

0 comments on commit 9ca7a6c

Please sign in to comment.