diff --git a/PlotLine/Services/StoryIntelligenceExperiencePrototypeData.cs b/PlotLine/Services/StoryIntelligenceExperiencePrototypeData.cs index 8a731bb..7d8c3f9 100644 --- a/PlotLine/Services/StoryIntelligenceExperiencePrototypeData.cs +++ b/PlotLine/Services/StoryIntelligenceExperiencePrototypeData.cs @@ -156,6 +156,7 @@ public static class StoryIntelligenceExperiencePrototypeData => new() { Id = id, + ChapterLabel = $"Chapter {Math.Max(1, chapters)}", SceneNumber = number, Title = title, Summary = summary, @@ -167,6 +168,7 @@ public static class StoryIntelligenceExperiencePrototypeData ChapterTotal = 5, ScenesAnalysed = number, SceneTotal = sceneTotal, + ElapsedTime = $"{Math.Max(1, number * 2)}m", EstimatedRemaining = remaining, PovCharacterId = pov, Location = location, diff --git a/PlotLine/Services/StoryIntelligenceVisualisationSnapshotService.cs b/PlotLine/Services/StoryIntelligenceVisualisationSnapshotService.cs index 22b2f17..c3d3580 100644 --- a/PlotLine/Services/StoryIntelligenceVisualisationSnapshotService.cs +++ b/PlotLine/Services/StoryIntelligenceVisualisationSnapshotService.cs @@ -135,6 +135,7 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( Scenes = scenes }; + StabiliseCharacterIllustrations(model); await illustrationLibrary.ApplyApprovedIllustrationsAsync(model); logger.LogInformation("Built Story Intelligence visualisation snapshot for run {RunId} in {ElapsedMs}ms.", runId, stopwatch.ElapsedMilliseconds); return model; @@ -183,10 +184,13 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( var sourceChapterCount = (await sources.ListChaptersAsync(session.BookID)).Count; var bookChapterTotal = Math.Max(1, Math.Max(sourceChapterCount, runSnapshots.Count)); var overallProgressPercent = BookProgress(runSnapshots, bookChapterTotal, isTerminal: false); - var completedChapterRuns = runSnapshots.Count(snapshot => IsTerminal(snapshot.Run.Status)); - var isTerminal = runSnapshots.All(snapshot => IsTerminal(snapshot.Run.Status)) - && string.Equals(session.Status, StoryIntelligencePipelineStatuses.Complete, StringComparison.OrdinalIgnoreCase); - overallProgressPercent = BookProgress(runSnapshots, bookChapterTotal, isTerminal); + var completedChapterRuns = runSnapshots.Count(snapshot => IsSuccessfulTerminal(snapshot.Run.Status)); + var isTerminal = runSnapshots.All(snapshot => IsTerminal(snapshot.Run.Status)); + var isSuccessfullyComplete = runSnapshots.All(snapshot => IsSuccessfulTerminal(snapshot.Run.Status)); + overallProgressPercent = BookProgress(runSnapshots, bookChapterTotal, isSuccessfullyComplete); + var overallElapsed = SessionElapsed(runSnapshots); + var overallRemaining = isTerminal ? "Ready to review" : EstimateSessionRemaining(runSnapshots, parsedScenes, totalScenes); + var overallStage = isSuccessfullyComplete ? "Analysis Complete" : isTerminal ? "Analysis stopped" : BackendStageDisplay(activeSnapshot.Run); var scenes = new List(); var nextSceneNumber = 1; foreach (var snapshot in runSnapshots) @@ -202,8 +206,9 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( overallChaptersAnalysed: completedChapterRuns, overallChapterTotal: bookChapterTotal, overallProgressPercent: overallProgressPercent, - overallStage: OverallStage(session, activeSnapshot.Run), - overallRemaining: EstimateSessionRemaining(runSnapshots, parsedScenes, totalScenes), + overallStage: overallStage, + overallElapsed: overallElapsed, + overallRemaining: overallRemaining, continuousSceneNumbering: true, overallTerminal: isTerminal) .ToList(); @@ -226,12 +231,13 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( ChangeToken = SessionChangeToken(session, runSnapshots), IsTerminal = isTerminal, SnapshotMessage = SessionSnapshotMessage(session, runSnapshots), - Diagnostics = BuildSessionDiagnostics(session, runSnapshots, activeSnapshot, current, parsedScenes, totalPersistedResults, overallProgressPercent), + Diagnostics = BuildSessionDiagnostics(session, runSnapshots, activeSnapshot, current, parsedScenes, totalPersistedResults, totalScenes, overallProgressPercent), ProjectName = DisplayTitle(session.ProjectName, "Untitled project"), BookTitle = DisplayTitle(session.BookDisplayTitle, "Untitled book"), Scenes = scenes }; + StabiliseCharacterIllustrations(model); await illustrationLibrary.ApplyApprovedIllustrationsAsync(model); logger.LogInformation("Built Story Intelligence import session visualisation snapshot for session {ImportSessionId} in {ElapsedMs}ms.", importSessionId, stopwatch.ElapsedMilliseconds); return model; @@ -249,6 +255,7 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( int? overallChapterTotal = null, int? overallProgressPercent = null, string? overallStage = null, + string? overallElapsed = null, string? overallRemaining = null, bool continuousSceneNumbering = false, bool overallTerminal = false) @@ -265,6 +272,7 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( yield return new StoryIntelligenceExperienceSceneState { Id = $"scene-result-{item.Result.SceneResultID}", + ChapterLabel = ChapterLabel(run, item), SceneNumber = sceneNumber, Title = SceneTitle(scene, item.Result, sceneNumber), Summary = Trim(FirstConfigured(scene.Summary?.Short, scene.Summary?.Detailed, run.CurrentMessage, "Scene analysed."), 180), @@ -279,8 +287,9 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( ChapterTotal = Math.Max(1, overallChapterTotal ?? run.SourceChapterCount ?? ChapterCount(completed)), ScenesAnalysed = overallCompletedScenes ?? completedScenes, SceneTotal = Math.Max(1, overallTotalScenes ?? totalScenes), + ElapsedTime = overallElapsed ?? EstimateElapsed(run), EstimatedRemaining = overallRemaining ?? EstimateRemaining(run, completedScenes, totalScenes), - PovCharacterId = CharacterId(scene.PointOfView?.CharacterName), + PovCharacterId = CharacterId(ResolveNarratorName(scene) ?? scene.PointOfView?.CharacterName), Location = BuildLocation(scene), Characters = BuildCharacters(scene), Assets = BuildAssets(scene), @@ -297,6 +306,7 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( => new() { Id = $"run-{run.StoryIntelligenceRunID}-waiting", + ChapterLabel = run.ChapterNumber.HasValue ? $"Chapter {run.ChapterNumber:0.##}" : "Chapter", SceneNumber = 1, Title = run.Status is StoryIntelligenceRunStatuses.Failed ? "Analysis failed" : "Waiting for analysed scenes", Summary = FirstConfigured(run.ErrorMessage, run.CurrentMessage, "No scene analysis results have been persisted yet."), @@ -308,6 +318,7 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( ChapterTotal = Math.Max(1, run.SourceChapterCount ?? 1), ScenesAnalysed = run.CompletedScenes ?? 0, SceneTotal = Math.Max(1, run.TotalDetectedScenes ?? 1), + ElapsedTime = EstimateElapsed(run), EstimatedRemaining = EstimateRemaining(run, run.CompletedScenes ?? 0, run.TotalDetectedScenes ?? 0), Location = PendingLocation(), LatestDiscoveries = run.ErrorMessage is null ? [] : [$"Run failed: {Trim(run.ErrorMessage, 90)}"], @@ -326,7 +337,8 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( private static IReadOnlyList BuildCharacters(SceneIntelligenceScene scene) { - var povName = Clean(scene.PointOfView?.CharacterName); + var narratorResolution = ResolveNarratorName(scene); + var povName = Clean(narratorResolution ?? scene.PointOfView?.CharacterName); var states = new List(); var reservedCodes = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var group in (scene.Characters ?? []) @@ -334,6 +346,11 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( .GroupBy(character => Clean(character.Name), StringComparer.OrdinalIgnoreCase) .Take(5)) { + if (!string.IsNullOrWhiteSpace(narratorResolution) && IsGenericNarratorName(group.Key)) + { + continue; + } + var character = group.OrderByDescending(item => item.Confidence ?? 0).First(); var isPov = !string.IsNullOrWhiteSpace(povName) && string.Equals(group.Key, povName, StringComparison.OrdinalIgnoreCase); var libraryCode = CharacterLibraryCode(group.Key, character, scene, reservedCodes); @@ -368,6 +385,62 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( return states.OrderByDescending(character => character.Weight).ToList(); } + private static string? ResolveNarratorName(SceneIntelligenceScene scene) + { + var povName = Clean(scene.PointOfView?.CharacterName); + if (!IsGenericNarratorName(povName)) + { + return null; + } + + var evidence = string.Join(' ', new[] + { + scene.PointOfView?.Evidence, + scene.Summary?.Short, + scene.Summary?.Detailed, + scene.ScenePurpose?.ObservedFunction + }.Where(value => !string.IsNullOrWhiteSpace(value))); + + var namedCharacters = (scene.Characters ?? []) + .Where(character => !string.IsNullOrWhiteSpace(character.Name)) + .Select(character => Clean(character.Name)) + .Where(name => !IsGenericNarratorName(name)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + foreach (var name in namedCharacters) + { + if (ContainsIdentityEvidence(evidence, name)) + { + return name; + } + } + + return namedCharacters.Count == 1 ? namedCharacters[0] : null; + } + + private static bool ContainsIdentityEvidence(string evidence, string name) + { + if (string.IsNullOrWhiteSpace(evidence) || string.IsNullOrWhiteSpace(name)) + { + return false; + } + + var lowerEvidence = evidence.ToLowerInvariant(); + var lowerName = name.ToLowerInvariant(); + return lowerEvidence.Contains($"narrated by {lowerName}", StringComparison.Ordinal) + || lowerEvidence.Contains($"narrator is {lowerName}", StringComparison.Ordinal) + || lowerEvidence.Contains($"i am {lowerName}", StringComparison.Ordinal) + || lowerEvidence.Contains($"i'm {lowerName}", StringComparison.Ordinal) + || lowerEvidence.Contains($"my name is {lowerName}", StringComparison.Ordinal); + } + + private static bool IsGenericNarratorName(string? name) + { + var value = Clean(name).ToLowerInvariant(); + return value is "narrator" or "i" or "me" or "my" or "myself" or "first person narrator" or "unnamed narrator"; + } + private static StoryIntelligenceExperienceLocationState BuildLocation(SceneIntelligenceScene scene) { var location = (scene.Locations ?? []) @@ -646,7 +719,7 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( var active = snapshots.FirstOrDefault(snapshot => !IsTerminal(snapshot.Run.Status)); if (active is not null) { - return FirstConfigured(active.Run.CurrentMessage, $"Analysing chapter {active.Run.ChapterNumber:0.##}."); + return BackendStageDisplay(active.Run); } return string.Equals(session.Status, StoryIntelligencePipelineStatuses.Complete, StringComparison.OrdinalIgnoreCase) @@ -658,13 +731,34 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( { if (snapshot.Run.TotalDetectedScenes.HasValue) { - var completed = Math.Clamp(snapshot.Run.CompletedScenes ?? snapshot.Completed.Count, 0, snapshot.Run.TotalDetectedScenes.Value); - return $"Scene {completed:N0} of {snapshot.Run.TotalDetectedScenes.Value:N0}"; + var scene = Math.Clamp((snapshot.Run.CompletedScenes ?? snapshot.Completed.Count) + (IsTerminal(snapshot.Run.Status) ? 0 : 1), 1, snapshot.Run.TotalDetectedScenes.Value); + return $"Scene {scene:N0} of {snapshot.Run.TotalDetectedScenes.Value:N0}"; } return snapshot.Current is null ? "Waiting" : $"Scene {SceneSortNumber(snapshot.Current):0.##}"; } + private static string BackendStageDisplay(StoryIntelligenceSavedRun run) + { + var stage = FirstConfigured(run.CurrentStage, run.Status); + var sceneText = run.TotalDetectedScenes.HasValue + ? $"Scene {Math.Clamp((run.CompletedScenes ?? 0) + (IsTerminal(run.Status) ? 0 : 1), 1, Math.Max(1, run.TotalDetectedScenes.Value)):N0}" + : "current scene"; + var chapterText = run.ChapterNumber.HasValue ? $"Chapter {run.ChapterNumber:0.##} " : string.Empty; + return stage switch + { + StoryIntelligenceFailureStages.SceneIntelligence => $"Analysing {chapterText}{sceneText}", + StoryIntelligencePipelineStages.CharacterImport or StoryIntelligencePipelineStages.CharacterReview => "Analysing Characters", + StoryIntelligencePipelineStages.RelationshipImport or StoryIntelligencePipelineStages.RelationshipReview => "Building Relationships", + StoryIntelligencePipelineStages.AssetImport or StoryIntelligencePipelineStages.AssetReview => "Analysing Assets", + StoryIntelligencePipelineStages.LocationImport or StoryIntelligencePipelineStages.LocationReview => "Analysing Locations", + StoryIntelligenceFailureStages.DomainImport or StoryIntelligencePipelineStages.KnowledgeImport or StoryIntelligencePipelineStages.KnowledgeReview => "Inferring Knowledge", + StoryIntelligenceFailureStages.Persistence => "Building Continuity", + _ when stage.Contains("Scene", StringComparison.OrdinalIgnoreCase) => $"Analysing {chapterText}{sceneText}", + _ => FirstConfigured(run.CurrentMessage, stage, $"Analysing {chapterText}{sceneText}") + }; + } + private static StoryIntelligenceExperienceSnapshotDiagnostics BuildSessionDiagnostics( StoryIntelligenceBookPipelineState session, IReadOnlyList snapshots, @@ -672,6 +766,7 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( ParsedSceneResult? current, int parsedScenes, int totalPersistedResults, + int totalScenes, int overallProgressPercent) { var failed = snapshots.Sum(snapshot => snapshot.Parsed.Count(item => item.Scene is null)); @@ -679,6 +774,7 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( return new() { RequestedMode = "real", + CurrentImportId = session.StoryIntelligenceBookPipelineID, RequestedImportSessionId = session.StoryIntelligenceBookPipelineID, ResolvedImportSessionId = session.StoryIntelligenceBookPipelineID, ActiveChapterRunId = activeSnapshot.Run.StoryIntelligenceRunID, @@ -686,6 +782,10 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( OverallBookProgress = overallProgressPercent, CurrentChapter = activeSnapshot.Run.ChapterNumber.HasValue ? $"Chapter {activeSnapshot.Run.ChapterNumber:0.##}" : "Chapter unknown", CurrentScene = CurrentSceneText(activeSnapshot), + CompletedScenes = parsedScenes, + TotalScenes = totalScenes, + ProgressSource = "ImportSession", + CurrentBackendStage = BackendStageDisplay(activeSnapshot.Run), SnapshotSource = "Real", RunStatus = SessionStatus(session, snapshots), PersistedCompletedSceneCount = snapshots.Sum(snapshot => snapshot.Run.CompletedScenes ?? snapshot.Completed.Count), @@ -722,8 +822,12 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( OverallBookProgress = Progress(run, run.CompletedScenes ?? completed.Count, Math.Max(run.TotalDetectedScenes ?? 0, results.Count)), CurrentChapter = run.ChapterNumber.HasValue ? $"Chapter {run.ChapterNumber:0.##}" : "Chapter unknown", CurrentScene = run.TotalDetectedScenes.HasValue - ? $"Scene {Math.Clamp(run.CompletedScenes ?? completed.Count, 0, run.TotalDetectedScenes.Value):N0} of {run.TotalDetectedScenes.Value:N0}" + ? $"Scene {Math.Clamp((run.CompletedScenes ?? completed.Count) + (IsTerminal(run.Status) ? 0 : 1), 1, run.TotalDetectedScenes.Value):N0} of {run.TotalDetectedScenes.Value:N0}" : (current is null ? "Waiting" : $"Scene {SceneSortNumber(current):0.##}"), + CompletedScenes = run.CompletedScenes ?? completed.Count, + TotalScenes = Math.Max(run.TotalDetectedScenes ?? 0, results.Count), + ProgressSource = "ChapterRun", + CurrentBackendStage = BackendStageDisplay(run), SnapshotSource = "Real", RunStatus = run.Status, PersistedCompletedSceneCount = run.CompletedScenes ?? 0, @@ -750,9 +854,36 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( _ => FirstConfigured(run.CurrentMessage, "Analysis snapshot is updating.") }; + private static void StabiliseCharacterIllustrations(StoryIntelligenceExperiencePrototypeViewModel model) + { + var firstAssignments = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var scene in model.Scenes.OrderBy(scene => scene.SceneNumber)) + { + foreach (var character in scene.Characters) + { + if (string.IsNullOrWhiteSpace(character.Id)) + { + continue; + } + + if (firstAssignments.TryGetValue(character.Id, out var assignment)) + { + character.LibraryCode = assignment.LibraryCode; + character.ImagePath = assignment.ImagePath; + continue; + } + + firstAssignments[character.Id] = (character.LibraryCode, character.ImagePath); + } + } + } + private static bool IsTerminal(string status) => status is StoryIntelligenceRunStatuses.Completed or StoryIntelligenceRunStatuses.CompletedWithWarnings or StoryIntelligenceRunStatuses.Failed or StoryIntelligenceRunStatuses.Cancelled; + private static bool IsSuccessfulTerminal(string status) + => status is StoryIntelligenceRunStatuses.Completed or StoryIntelligenceRunStatuses.CompletedWithWarnings; + private static int SceneNumber(ParsedSceneResult item) => item.Scene?.SceneReference?.SceneNumber.HasValue == true ? Convert.ToInt32(item.Scene.SceneReference.SceneNumber.Value) : item.Result.TemporarySceneNumber; @@ -764,11 +895,46 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( => item.Scene?.SceneReference?.SceneNumber ?? item.Result.TemporarySceneNumber; private static string SceneTitle(SceneIntelligenceScene scene, StoryIntelligenceSavedSceneResult result, int sceneNumber) - => FirstConfigured(scene.SceneReference?.SourceLabel, result.SourceLabel, scene.Summary?.Short, $"Scene {sceneNumber:N0}"); + => CompactSceneTitle(FirstConfigured(scene.SceneReference?.SourceLabel, result.SourceLabel, scene.Summary?.Short, $"Scene {sceneNumber:N0}"), sceneNumber); + + private static string CompactSceneTitle(string title, int sceneNumber) + { + var value = Clean(title); + if (string.IsNullOrWhiteSpace(value)) + { + return $"Scene {sceneNumber:N0}"; + } + + var sceneMarker = $"scene {sceneNumber}".ToLowerInvariant(); + var lower = value.ToLowerInvariant(); + var markerIndex = lower.IndexOf(sceneMarker, StringComparison.Ordinal); + if (markerIndex > 0) + { + value = value[markerIndex..].Trim(' ', '-', ':', '|'); + } + + var separators = new[] { " - ", " | ", ": " }; + foreach (var separator in separators) + { + var parts = value.Split(separator, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + if (parts.Length >= 3) + { + return Trim(parts[^1], 72); + } + } + + return Trim(value, 72); + } private static string TimelineLabel(SceneIntelligenceScene scene, StoryIntelligenceSavedSceneResult result) => FirstConfigured(scene.TimelineClues?.FirstOrDefault()?.AbsoluteDate, scene.Setting?.DateOrTimeReference, result.SourceLabel, "Known scene"); + private static string ChapterLabel(StoryIntelligenceSavedRun run, ParsedSceneResult item) + { + var chapter = item.Scene?.SceneReference?.ChapterNumber ?? run.ChapterNumber; + return chapter.HasValue ? $"Chapter {chapter:0.##}" : "Chapter"; + } + private static int Progress(StoryIntelligenceSavedRun run, int completedScenes, int totalScenes) { if (IsTerminal(run.Status) && run.Status is not StoryIntelligenceRunStatuses.Failed) @@ -817,7 +983,7 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( private static decimal ChapterProgress(RunSnapshot snapshot) { - if (IsTerminal(snapshot.Run.Status)) + if (IsSuccessfulTerminal(snapshot.Run.Status)) { return 1m; } @@ -853,6 +1019,19 @@ public sealed class StoryIntelligenceVisualisationSnapshotService( return FormatDuration(averageMs * (totalScenes - completedScenes)); } + private static string EstimateElapsed(StoryIntelligenceSavedRun run) + { + var elapsedMs = run.TotalDurationMs ?? Math.Max(0, Convert.ToInt64((DateTime.UtcNow - run.StartedUtc).TotalMilliseconds)); + return FormatDuration(elapsedMs); + } + + private static string SessionElapsed(IReadOnlyList snapshots) + { + var elapsedMs = snapshots.Sum(snapshot => snapshot.Run.TotalDurationMs + ?? Math.Max(0, Convert.ToInt64((DateTime.UtcNow - snapshot.Run.StartedUtc).TotalMilliseconds))); + return FormatDuration(elapsedMs); + } + private static string FormatDuration(long milliseconds) { var duration = TimeSpan.FromMilliseconds(Math.Max(0, milliseconds)); diff --git a/PlotLine/ViewModels/StoryIntelligenceExperiencePrototypeViewModels.cs b/PlotLine/ViewModels/StoryIntelligenceExperiencePrototypeViewModels.cs index 904bc33..0f335d2 100644 --- a/PlotLine/ViewModels/StoryIntelligenceExperiencePrototypeViewModels.cs +++ b/PlotLine/ViewModels/StoryIntelligenceExperiencePrototypeViewModels.cs @@ -20,6 +20,7 @@ public sealed class StoryIntelligenceExperiencePrototypeViewModel public sealed class StoryIntelligenceExperienceSnapshotDiagnostics { public string RequestedMode { get; init; } = string.Empty; + public int? CurrentImportId { get; init; } public int? RequestedImportSessionId { get; init; } public int? ResolvedImportSessionId { get; init; } public int? ActiveChapterRunId { get; init; } @@ -27,6 +28,10 @@ public sealed class StoryIntelligenceExperienceSnapshotDiagnostics public int OverallBookProgress { get; init; } public string CurrentChapter { get; init; } = string.Empty; public string CurrentScene { get; init; } = string.Empty; + public int CompletedScenes { get; init; } + public int TotalScenes { get; init; } + public string ProgressSource { get; init; } = string.Empty; + public string CurrentBackendStage { get; init; } = string.Empty; public string SnapshotSource { get; init; } = string.Empty; public string RunStatus { get; init; } = string.Empty; public int PersistedCompletedSceneCount { get; init; } @@ -54,6 +59,7 @@ public sealed class StoryIntelligenceExperienceRunOption public sealed class StoryIntelligenceExperienceSceneState { public string Id { get; init; } = string.Empty; + public string ChapterLabel { get; init; } = string.Empty; public int SceneNumber { get; init; } public string Title { get; init; } = string.Empty; public string Summary { get; init; } = string.Empty; @@ -65,6 +71,7 @@ public sealed class StoryIntelligenceExperienceSceneState public int ChapterTotal { get; init; } public int ScenesAnalysed { get; init; } public int SceneTotal { get; init; } + public string ElapsedTime { get; init; } = string.Empty; public string EstimatedRemaining { get; init; } = string.Empty; public string PovCharacterId { get; init; } = string.Empty; public StoryIntelligenceExperienceLocationState Location { get; init; } = new(); diff --git a/PlotLine/Views/Development/StoryIntelligenceExperience.cshtml b/PlotLine/Views/Development/StoryIntelligenceExperience.cshtml index c2956a6..868f5cc 100644 --- a/PlotLine/Views/Development/StoryIntelligenceExperience.cshtml +++ b/PlotLine/Views/Development/StoryIntelligenceExperience.cshtml @@ -46,9 +46,9 @@
    - @statusLabel - @Model.ProjectName - @Model.BookTitle + @statusLabel + @Model.ProjectName + @Model.BookTitle Preparing Scene 1
    @@ -68,7 +68,7 @@ @if (!string.IsNullOrWhiteSpace(Model.SnapshotMessage)) { -