Phase 20AP.1 – Asset Intelligence Review and Import

This commit is contained in:
Nick Beckley 2026-07-09 21:09:48 +01:00
parent 11de81abed
commit d44217162c
4 changed files with 66 additions and 28 deletions

View File

@ -60,7 +60,9 @@ public sealed class StoryIntelligenceBookPipelineState
public DateTime CreatedUtc { get; init; } public DateTime CreatedUtc { get; init; }
public DateTime UpdatedUtc { get; init; } public DateTime UpdatedUtc { get; init; }
public bool IsComplete => string.Equals(Status, StoryIntelligencePipelineStatuses.Complete, StringComparison.OrdinalIgnoreCase); public bool IsComplete
=> string.Equals(Status, StoryIntelligencePipelineStatuses.Complete, StringComparison.OrdinalIgnoreCase)
&& string.Equals(LastCompletedStage, StoryIntelligencePipelineStages.AssetImport, StringComparison.OrdinalIgnoreCase);
} }
public sealed class StoryIntelligenceBookPipelineSaveRequest public sealed class StoryIntelligenceBookPipelineSaveRequest

View File

@ -525,31 +525,32 @@ public sealed class OnboardingStoryIntelligenceService(
.ToList() .ToList()
}; };
if (state.IsComplete) var characterStageComplete = HasCompletedStage(state, StoryIntelligencePipelineStages.CharacterImport)
{ || state.CurrentStage is StoryIntelligencePipelineStages.LocationReview
batch.CharacterStageComplete = true; or StoryIntelligencePipelineStages.LocationImport
batch.LocationStageComplete = true; or StoryIntelligencePipelineStages.AssetReview
batch.AssetStageComplete = true; or StoryIntelligencePipelineStages.AssetImport
} or StoryIntelligencePipelineStages.Complete;
else if (state.CurrentStage is StoryIntelligencePipelineStages.AssetReview or StoryIntelligencePipelineStages.AssetImport) var locationStageComplete = HasCompletedStage(state, StoryIntelligencePipelineStages.LocationImport)
{ || state.CurrentStage is StoryIntelligencePipelineStages.AssetReview
batch.CharacterStageComplete = true; or StoryIntelligencePipelineStages.AssetImport
batch.LocationStageComplete = true; or StoryIntelligencePipelineStages.Complete;
} var assetStageComplete = HasCompletedStage(state, StoryIntelligencePipelineStages.AssetImport);
else if (state.CurrentStage is StoryIntelligencePipelineStages.LocationReview or StoryIntelligencePipelineStages.LocationImport)
{ batch.CharacterStageComplete = characterStageComplete;
batch.CharacterStageComplete = true; batch.LocationStageComplete = locationStageComplete;
} batch.AssetStageComplete = assetStageComplete;
await batchStore.SaveAsync(batch); await batchStore.SaveAsync(batch);
var route = state.CurrentStage switch var route = assetStageComplete
? StoryIntelligenceResumeRoutes.Complete
: locationStageComplete
? StoryIntelligenceResumeRoutes.Assets
: characterStageComplete
? StoryIntelligenceResumeRoutes.Locations
: state.CurrentStage switch
{ {
StoryIntelligencePipelineStages.Complete => StoryIntelligenceResumeRoutes.Complete,
StoryIntelligencePipelineStages.AssetReview => StoryIntelligenceResumeRoutes.Assets,
StoryIntelligencePipelineStages.AssetImport => StoryIntelligenceResumeRoutes.Assets,
StoryIntelligencePipelineStages.LocationReview => StoryIntelligenceResumeRoutes.Locations,
StoryIntelligencePipelineStages.LocationImport => StoryIntelligenceResumeRoutes.Locations,
StoryIntelligencePipelineStages.CharacterReview => StoryIntelligenceResumeRoutes.Characters, StoryIntelligencePipelineStages.CharacterReview => StoryIntelligenceResumeRoutes.Characters,
StoryIntelligencePipelineStages.CharacterImport => StoryIntelligenceResumeRoutes.Characters, StoryIntelligencePipelineStages.CharacterImport => StoryIntelligenceResumeRoutes.Characters,
StoryIntelligencePipelineStages.SceneReview => StoryIntelligenceResumeRoutes.SceneReview, StoryIntelligencePipelineStages.SceneReview => StoryIntelligenceResumeRoutes.SceneReview,
@ -560,6 +561,9 @@ public sealed class OnboardingStoryIntelligenceService(
return new OnboardingStoryIntelligenceResumeTarget(batch.BatchID, route); return new OnboardingStoryIntelligenceResumeTarget(batch.BatchID, route);
} }
private static bool HasCompletedStage(StoryIntelligenceBookPipelineState state, string stage)
=> string.Equals(state.LastCompletedStage, stage, StringComparison.OrdinalIgnoreCase);
private async Task<(UserOnboardingState State, ManuscriptScanPreview Preview, ManuscriptScanReviewDecision Review, OnboardingManuscriptBuildResult? Build, OnboardingWizardViewModel Wizard)?> GetContextAsync(int userId) private async Task<(UserOnboardingState State, ManuscriptScanPreview Preview, ManuscriptScanReviewDecision Review, OnboardingManuscriptBuildResult? Build, OnboardingWizardViewModel Wizard)?> GetContextAsync(int userId)
{ {
var state = await onboardingRepository.GetAsync(userId); var state = await onboardingRepository.GetAsync(userId);

View File

@ -269,8 +269,12 @@ public sealed class StoryIntelligenceService(
return state.CurrentReviewStage switch return state.CurrentReviewStage switch
{ {
StoryIntelligencePipelineStages.AssetReview => "Waiting for Asset Review",
StoryIntelligencePipelineStages.LocationReview => "Waiting for Location Review",
StoryIntelligencePipelineStages.CharacterReview => "Waiting for Character Review", StoryIntelligencePipelineStages.CharacterReview => "Waiting for Character Review",
StoryIntelligencePipelineStages.SceneReview => "Needs Scene Review", StoryIntelligencePipelineStages.SceneReview => "Needs Scene Review",
_ when StoryIntelligenceReadyForAssets(state) => "Waiting for Asset Review",
_ when StoryIntelligenceReadyForLocations(state) => "Waiting for Location Review",
_ => string.Equals(state.Status, StoryIntelligencePipelineStatuses.InProgress, StringComparison.OrdinalIgnoreCase) _ => string.Equals(state.Status, StoryIntelligencePipelineStatuses.InProgress, StringComparison.OrdinalIgnoreCase)
? "Story Intelligence In Progress" ? "Story Intelligence In Progress"
: "Story Intelligence Needs Review" : "Story Intelligence Needs Review"
@ -282,11 +286,25 @@ public sealed class StoryIntelligenceService(
? "All currently available Story Intelligence stages are complete." ? "All currently available Story Intelligence stages are complete."
: state.CurrentReviewStage switch : state.CurrentReviewStage switch
{ {
StoryIntelligencePipelineStages.AssetReview => "Review detected assets and decide what to create or link.",
StoryIntelligencePipelineStages.LocationReview => "Review detected locations and decide what to create or link.",
StoryIntelligencePipelineStages.CharacterReview => "Review detected characters and decide what to create or link.", StoryIntelligencePipelineStages.CharacterReview => "Review detected characters and decide what to create or link.",
StoryIntelligencePipelineStages.SceneReview => "Review prepared scenes before creating them.", StoryIntelligencePipelineStages.SceneReview => "Review prepared scenes before creating them.",
_ when StoryIntelligenceReadyForAssets(state) => "Review detected assets and decide what to create or link.",
_ when StoryIntelligenceReadyForLocations(state) => "Review detected locations and decide what to create or link.",
_ => "Continue from the next Story Intelligence stage." _ => "Continue from the next Story Intelligence stage."
}; };
private static bool StoryIntelligenceReadyForAssets(StoryIntelligenceBookPipelineState state)
=> string.Equals(state.LastCompletedStage, StoryIntelligencePipelineStages.LocationImport, StringComparison.OrdinalIgnoreCase)
|| state.CurrentStage is StoryIntelligencePipelineStages.AssetReview or StoryIntelligencePipelineStages.AssetImport
|| (string.Equals(state.CurrentStage, StoryIntelligencePipelineStages.Complete, StringComparison.OrdinalIgnoreCase)
&& !string.Equals(state.LastCompletedStage, StoryIntelligencePipelineStages.AssetImport, StringComparison.OrdinalIgnoreCase));
private static bool StoryIntelligenceReadyForLocations(StoryIntelligenceBookPipelineState state)
=> string.Equals(state.LastCompletedStage, StoryIntelligencePipelineStages.CharacterImport, StringComparison.OrdinalIgnoreCase)
|| state.CurrentStage is StoryIntelligencePipelineStages.LocationReview or StoryIntelligencePipelineStages.LocationImport;
private static string FormatElapsed(TimeSpan elapsed) private static string FormatElapsed(TimeSpan elapsed)
=> elapsed.TotalMinutes < 1 => elapsed.TotalMinutes < 1
? $"{Math.Max(0, (int)elapsed.TotalSeconds)} sec" ? $"{Math.Max(0, (int)elapsed.TotalSeconds)} sec"

View File

@ -200,9 +200,23 @@
return pipeline.CurrentReviewStage switch return pipeline.CurrentReviewStage switch
{ {
StoryIntelligencePipelineStages.AssetReview => "Review detected assets and decide what to create or link.",
StoryIntelligencePipelineStages.LocationReview => "Review detected locations and decide what to create or link.",
StoryIntelligencePipelineStages.CharacterReview => "Scene creation is complete. Review detected characters to continue building the story database.", StoryIntelligencePipelineStages.CharacterReview => "Scene creation is complete. Review detected characters to continue building the story database.",
StoryIntelligencePipelineStages.SceneReview => "Review prepared scenes before creating them in PlotDirector.", StoryIntelligencePipelineStages.SceneReview => "Review prepared scenes before creating them in PlotDirector.",
_ when StoryIntelligenceReadyForAssets(pipeline) => "Review detected assets and decide what to create or link.",
_ when StoryIntelligenceReadyForLocations(pipeline) => "Review detected locations and decide what to create or link.",
_ => "PlotDirector will resume from the next Story Intelligence stage." _ => "PlotDirector will resume from the next Story Intelligence stage."
}; };
} }
private static bool StoryIntelligenceReadyForAssets(StoryIntelligenceBookPipelineState pipeline)
=> string.Equals(pipeline.LastCompletedStage, StoryIntelligencePipelineStages.LocationImport, StringComparison.OrdinalIgnoreCase)
|| pipeline.CurrentStage is StoryIntelligencePipelineStages.AssetReview or StoryIntelligencePipelineStages.AssetImport
|| (string.Equals(pipeline.CurrentStage, StoryIntelligencePipelineStages.Complete, StringComparison.OrdinalIgnoreCase)
&& !string.Equals(pipeline.LastCompletedStage, StoryIntelligencePipelineStages.AssetImport, StringComparison.OrdinalIgnoreCase));
private static bool StoryIntelligenceReadyForLocations(StoryIntelligenceBookPipelineState pipeline)
=> string.Equals(pipeline.LastCompletedStage, StoryIntelligencePipelineStages.CharacterImport, StringComparison.OrdinalIgnoreCase)
|| pipeline.CurrentStage is StoryIntelligencePipelineStages.LocationReview or StoryIntelligencePipelineStages.LocationImport;
} }