PlotDirector/PlotLine/Data/StoryIntelligenceResultRepository.cs

171 lines
6.7 KiB
C#

using System.Data;
using Dapper;
using PlotLine.Models;
namespace PlotLine.Data;
public interface IStoryIntelligenceResultRepository
{
Task<int> SaveAsync(StoryIntelligenceRunSaveRequest request);
Task<IReadOnlyList<StoryIntelligenceSavedRunListItem>> ListRunsAsync();
Task<StoryIntelligenceSavedRun?> GetRunAsync(int runId);
Task<StoryIntelligenceSavedChapterResult?> GetChapterResultAsync(int runId);
Task<IReadOnlyList<StoryIntelligenceSavedSceneResult>> ListSceneResultsAsync(int runId);
}
public sealed class StoryIntelligenceResultRepository(ISqlConnectionFactory connectionFactory) : IStoryIntelligenceResultRepository
{
public async Task<int> SaveAsync(StoryIntelligenceRunSaveRequest request)
{
using var connection = connectionFactory.CreateConnection();
connection.Open();
using var transaction = connection.BeginTransaction();
try
{
var runId = await connection.QuerySingleAsync<int>(
"dbo.StoryIntelligenceRun_Save",
new
{
request.UserID,
request.ProjectID,
request.BookID,
request.Status,
request.SourceType,
request.SourceFileName,
request.SourceFileSizeBytes,
request.SourceWordCount,
request.SourceCharacterCount,
request.SourceChapterCount,
request.SourceDetectedImagesCount,
request.SourceDetectedTablesCount,
request.SourceDetectedFootnotesCount,
request.SourceDetectedCommentsCount,
request.PromptVersion,
request.Model,
request.StartedUtc,
request.CompletedUtc,
request.FailureStage,
request.TotalInputTokens,
request.TotalOutputTokens,
request.TotalTokens,
request.TotalDurationMs,
request.EstimatedCostGBP,
request.EstimatedCostUSD,
request.PromptVersionsSummary,
request.ErrorMessage,
request.ErrorDetail
},
transaction,
commandType: CommandType.StoredProcedure);
int? chapterResultId = null;
if (request.ChapterResult is not null)
{
var chapter = request.ChapterResult;
chapterResultId = await connection.QuerySingleAsync<int>(
"dbo.StoryIntelligenceChapterResult_Save",
new
{
StoryIntelligenceRunID = runId,
chapter.ProjectID,
chapter.BookID,
chapter.ChapterID,
chapter.ChapterNumber,
chapter.SourceLabel,
chapter.PromptVersion,
chapter.Model,
chapter.RawResponseJson,
chapter.OutputTextJson,
chapter.ParsedJson,
chapter.ValidationErrorsCount,
chapter.ValidationWarningsCount,
chapter.InputTokens,
chapter.OutputTokens,
chapter.TotalTokens,
chapter.DurationMs
},
transaction,
commandType: CommandType.StoredProcedure);
}
foreach (var scene in request.SceneResults)
{
await connection.ExecuteAsync(
"dbo.StoryIntelligenceSceneResult_Save",
new
{
StoryIntelligenceRunID = runId,
ChapterResultID = chapterResultId,
scene.ProjectID,
scene.BookID,
scene.ChapterID,
scene.SceneID,
scene.TemporarySceneNumber,
scene.StartParagraph,
scene.EndParagraph,
scene.SourceLabel,
scene.PromptVersion,
scene.Model,
scene.RawResponseJson,
scene.OutputTextJson,
scene.ParsedJson,
scene.ValidationErrorsCount,
scene.ValidationWarningsCount,
scene.InputTokens,
scene.OutputTokens,
scene.TotalTokens,
scene.DurationMs
},
transaction,
commandType: CommandType.StoredProcedure);
}
transaction.Commit();
return runId;
}
catch
{
transaction.Rollback();
throw;
}
}
public async Task<IReadOnlyList<StoryIntelligenceSavedRunListItem>> ListRunsAsync()
{
using var connection = connectionFactory.CreateConnection();
var rows = await connection.QueryAsync<StoryIntelligenceSavedRunListItem>(
"dbo.StoryIntelligenceRun_ListAdmin",
commandType: CommandType.StoredProcedure);
return rows.ToList();
}
public async Task<StoryIntelligenceSavedRun?> GetRunAsync(int runId)
{
using var connection = connectionFactory.CreateConnection();
return await connection.QuerySingleOrDefaultAsync<StoryIntelligenceSavedRun>(
"dbo.StoryIntelligenceRun_GetAdmin",
new { StoryIntelligenceRunID = runId },
commandType: CommandType.StoredProcedure);
}
public async Task<StoryIntelligenceSavedChapterResult?> GetChapterResultAsync(int runId)
{
using var connection = connectionFactory.CreateConnection();
return await connection.QuerySingleOrDefaultAsync<StoryIntelligenceSavedChapterResult>(
"dbo.StoryIntelligenceChapterResult_GetByRun",
new { StoryIntelligenceRunID = runId },
commandType: CommandType.StoredProcedure);
}
public async Task<IReadOnlyList<StoryIntelligenceSavedSceneResult>> ListSceneResultsAsync(int runId)
{
using var connection = connectionFactory.CreateConnection();
var rows = await connection.QueryAsync<StoryIntelligenceSavedSceneResult>(
"dbo.StoryIntelligenceSceneResult_ListByRun",
new { StoryIntelligenceRunID = runId },
commandType: CommandType.StoredProcedure);
return rows.ToList();
}
}