PlotDirector/PlotLine/Services/StoryIntelligencePipelineStateService.cs

143 lines
6.0 KiB
C#

using PlotLine.Data;
using PlotLine.Models;
namespace PlotLine.Services;
public interface IStoryIntelligencePipelineStateService
{
Task<StoryIntelligenceBookPipelineState?> GetForBookAsync(int bookId, int userId);
Task<IReadOnlyList<StoryIntelligenceBookPipelineState>> ListForUserAsync(int userId);
Task<StoryIntelligenceBookPipelineState?> EnsureForBookAsync(int bookId, int userId);
Task RecordSceneImportAsync(int projectId, int bookId, int runId);
Task RecordCharacterImportAsync(int projectId, int bookId);
Task RecordLocationImportAsync(int projectId, int bookId);
Task RecordAssetImportAsync(int projectId, int bookId);
Task RecordRelationshipImportAsync(int projectId, int bookId);
Task<IReadOnlyList<StoryIntelligenceCommittedRunSummary>> ListCommittedRunsByBookAsync(int bookId, int userId);
}
public sealed class StoryIntelligencePipelineStateService(
IStoryIntelligencePipelineRepository pipelines,
ILogger<StoryIntelligencePipelineStateService> logger) : IStoryIntelligencePipelineStateService
{
public async Task<StoryIntelligenceBookPipelineState?> GetForBookAsync(int bookId, int userId)
=> await pipelines.GetByBookForUserAsync(bookId, userId)
?? await EnsureForBookAsync(bookId, userId);
public Task<IReadOnlyList<StoryIntelligenceBookPipelineState>> ListForUserAsync(int userId)
=> pipelines.ListForUserAsync(userId);
public async Task<StoryIntelligenceBookPipelineState?> EnsureForBookAsync(int bookId, int userId)
{
var existing = await pipelines.GetByBookForUserAsync(bookId, userId);
if (existing is not null)
{
return existing;
}
var committedRuns = await pipelines.ListCommittedRunsByBookAsync(bookId, userId);
if (committedRuns.Count == 0)
{
return null;
}
var latestRun = committedRuns.OrderByDescending(run => run.StoryIntelligenceRunID).First();
var created = await pipelines.UpsertAsync(new StoryIntelligenceBookPipelineSaveRequest
{
ProjectID = latestRun.ProjectID,
BookID = latestRun.BookID,
CurrentStage = StoryIntelligencePipelineStages.CharacterReview,
LastCompletedStage = StoryIntelligencePipelineStages.SceneImport,
CurrentReviewStage = StoryIntelligencePipelineStages.CharacterReview,
Status = StoryIntelligencePipelineStatuses.NeedsReview,
CompletedUtc = null,
LastRunID = latestRun.StoryIntelligenceRunID
});
logger.LogInformation(
"Created Story Intelligence pipeline state for existing imported book {BookID}. ProjectID={ProjectID} CurrentStage={CurrentStage}",
bookId,
created.ProjectID,
created.CurrentStage);
return created;
}
public async Task RecordSceneImportAsync(int projectId, int bookId, int runId)
{
await pipelines.UpsertAsync(new StoryIntelligenceBookPipelineSaveRequest
{
ProjectID = projectId,
BookID = bookId,
CurrentStage = StoryIntelligencePipelineStages.CharacterReview,
LastCompletedStage = StoryIntelligencePipelineStages.SceneImport,
CurrentReviewStage = StoryIntelligencePipelineStages.CharacterReview,
Status = StoryIntelligencePipelineStatuses.NeedsReview,
CompletedUtc = null,
LastRunID = runId
});
}
public async Task RecordCharacterImportAsync(int projectId, int bookId)
{
await pipelines.UpsertAsync(new StoryIntelligenceBookPipelineSaveRequest
{
ProjectID = projectId,
BookID = bookId,
CurrentStage = StoryIntelligencePipelineStages.LocationReview,
LastCompletedStage = StoryIntelligencePipelineStages.CharacterImport,
CurrentReviewStage = StoryIntelligencePipelineStages.LocationReview,
Status = StoryIntelligencePipelineStatuses.NeedsReview,
CompletedUtc = null,
LastRunID = null
});
}
public async Task RecordLocationImportAsync(int projectId, int bookId)
{
await pipelines.UpsertAsync(new StoryIntelligenceBookPipelineSaveRequest
{
ProjectID = projectId,
BookID = bookId,
CurrentStage = StoryIntelligencePipelineStages.AssetReview,
LastCompletedStage = StoryIntelligencePipelineStages.LocationImport,
CurrentReviewStage = StoryIntelligencePipelineStages.AssetReview,
Status = StoryIntelligencePipelineStatuses.NeedsReview,
CompletedUtc = null,
LastRunID = null
});
}
public async Task RecordAssetImportAsync(int projectId, int bookId)
{
await pipelines.UpsertAsync(new StoryIntelligenceBookPipelineSaveRequest
{
ProjectID = projectId,
BookID = bookId,
CurrentStage = StoryIntelligencePipelineStages.RelationshipReview,
LastCompletedStage = StoryIntelligencePipelineStages.AssetImport,
CurrentReviewStage = StoryIntelligencePipelineStages.RelationshipReview,
Status = StoryIntelligencePipelineStatuses.NeedsReview,
CompletedUtc = null,
LastRunID = null
});
}
public async Task RecordRelationshipImportAsync(int projectId, int bookId)
{
await pipelines.UpsertAsync(new StoryIntelligenceBookPipelineSaveRequest
{
ProjectID = projectId,
BookID = bookId,
CurrentStage = StoryIntelligencePipelineStages.Complete,
LastCompletedStage = StoryIntelligencePipelineStages.RelationshipImport,
CurrentReviewStage = null,
Status = StoryIntelligencePipelineStatuses.Complete,
CompletedUtc = DateTime.UtcNow,
LastRunID = null
});
}
public Task<IReadOnlyList<StoryIntelligenceCommittedRunSummary>> ListCommittedRunsByBookAsync(int bookId, int userId)
=> pipelines.ListCommittedRunsByBookAsync(bookId, userId);
}