Skip to content

Commit

Permalink
Merge pull request #43 from OUCC/herring/story_gen
Browse files Browse the repository at this point in the history
story generator
  • Loading branch information
miyaji255 authored May 1, 2024
2 parents bd35040 + 1acdb32 commit 5273779
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
8 changes: 8 additions & 0 deletions KoeBook.Core/Contracts/Services/ILlmStoryGeneratorService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using KoeBook.Core.Models;

namespace KoeBook.Core.Contracts.Services;

internal interface ILlmStoryGeneratorService
{
ValueTask<string> GenerateStoryAsync(StoryGenre storyGenre, string premise, CancellationToken cancellationToken);
}
69 changes: 69 additions & 0 deletions KoeBook.Core/Services/ClaudeStoryGeneratorService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using KoeBook.Core.Contracts.Services;
using KoeBook.Core.Models;

namespace KoeBook.Core.Services;

internal class ClaudeStoryGeneratorService(IClaudeService claudeService) : ILlmStoryGeneratorService
{
private readonly IClaudeService _claudeService = claudeService;

public async ValueTask<string> GenerateStoryAsync(StoryGenre storyGenre, string premise, CancellationToken cancellationToken)
{
if (_claudeService.Messages is null)
{
throw new EbookException(ExceptionType.ApiKeyNotSet);
}
try
{
var storyXml = await _claudeService.Messages.CreateAsync(new()
{
Model = Claudia.Models.Claude3Opus,
MaxTokens = 4000,
Temperature = 0.4,
Messages = [new()
{
Role = "user",
Content = CreateStoryPrompt(storyGenre, premise)
}]
},
cancellationToken: cancellationToken
);
return storyXml.ToString();
}
catch (OperationCanceledException) { throw; }
catch (Exception e)
{
throw new EbookException(ExceptionType.ClaudeTalkerAndStyleSettingFailed, innerException: e);
}
}

private string CreateStoryPrompt(StoryGenre storyGenre, string premise)
{
return $"""
You are a highly capable AI novelist that can write compelling 2500-character short stories and novellas in fluent, natural Japanese based on a given theme or plot points.

When crafting the story, please focus on the following:
- Use dialogue extensively to advance the plot while revealing characters' personalities, motivations and relationships
- Write witty, revealing conversations authentic to each character's voice
- Vary dialogue tags and phrases to convey nuanced speech
- Aim to create a polished story where characters' distinct voices come through in the dialogue, within the 2500-character limit
- Words beyond the general vocabulary and proper nouns that are easily misread are given ruby. Not necessary for simple vocabulary.

Please generate the full story in Japanese in a single output follow this example:
<?xml version="1.0" encoding="UTF-8"?>
<Book>
<Title>境界線の向こう側</Title>
<Content>
<Section>
<Paragraph><Text>高校2年の夏、バレー部のエースで</Text><Ruby><Rb>端正</Rb><Rt>たんせい</Rt></Ruby><Text>な顔立ちの山田祐樹は、バスケ部のキャプテンで凛とした佇まいの田中麻衣に密かに想いを寄せていた。しかし、両者の部活仲間たちの目を</Text><Ruby><Rb>憚</Rb><Rt>はばか</Rt></Ruby><Text>り、互いに素振りも見せずにいた。</Text></Paragraph>
</Section>
</Content>
</Book>

Based on this prompt, please generate a ~2500-character Japanese story from the specified theme or plot points provided.

theme: {storyGenre.Genre}
premise: {premise}
""";
}
}

0 comments on commit 5273779

Please sign in to comment.