Phase 20AE – Unify Story Intelligence Review Pipeline & Remove Placeholder Scene Architecture
This commit is contained in:
parent
5b4c78c040
commit
fba73186c1
@ -433,7 +433,7 @@ public sealed class StoryIntelligenceResultRepository(ISqlConnectionFactory conn
|
|||||||
return new StoryIntelligenceImportCommitResult
|
return new StoryIntelligenceImportCommitResult
|
||||||
{
|
{
|
||||||
Success = false,
|
Success = false,
|
||||||
Message = readiness.BlockReason ?? "This chapter contains existing authored scenes."
|
Message = readiness.BlockReason ?? "This chapter already contains scenes."
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,9 +442,6 @@ public sealed class StoryIntelligenceResultRepository(ISqlConnectionFactory conn
|
|||||||
{
|
{
|
||||||
var item = orderedScenes[index];
|
var item = orderedScenes[index];
|
||||||
var operation = "preparing scene";
|
var operation = "preparing scene";
|
||||||
var replacePlaceholder = readiness.HasUntouchedDefaultPlaceholder
|
|
||||||
&& readiness.PlaceholderSceneID.HasValue
|
|
||||||
&& index == 0;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -462,7 +459,7 @@ public sealed class StoryIntelligenceResultRepository(ISqlConnectionFactory conn
|
|||||||
"dbo.Scene_Save",
|
"dbo.Scene_Save",
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
SceneID = replacePlaceholder ? readiness.PlaceholderSceneID : null,
|
SceneID = (int?)null,
|
||||||
ChapterID = request.ChapterID,
|
ChapterID = request.ChapterID,
|
||||||
SceneNumber = Convert.ToDecimal(item.TemporarySceneNumber),
|
SceneNumber = Convert.ToDecimal(item.TemporarySceneNumber),
|
||||||
SceneTitle = sceneTitle,
|
SceneTitle = sceneTitle,
|
||||||
@ -587,9 +584,7 @@ public sealed class StoryIntelligenceResultRepository(ISqlConnectionFactory conn
|
|||||||
}
|
}
|
||||||
|
|
||||||
var notes = new List<string>();
|
var notes = new List<string>();
|
||||||
notes.Add(readiness.HasUntouchedDefaultPlaceholder
|
notes.Add("Committed into empty chapter.");
|
||||||
? "Replaced untouched default placeholder scene."
|
|
||||||
: "Committed into empty chapter.");
|
|
||||||
notes.AddRange(request.Warnings.Where(warning => !string.IsNullOrWhiteSpace(warning)));
|
notes.AddRange(request.Warnings.Where(warning => !string.IsNullOrWhiteSpace(warning)));
|
||||||
notes.AddRange(commitWarnings.Where(warning => !string.IsNullOrWhiteSpace(warning)));
|
notes.AddRange(commitWarnings.Where(warning => !string.IsNullOrWhiteSpace(warning)));
|
||||||
|
|
||||||
|
|||||||
@ -417,8 +417,6 @@ public sealed class StoryIntelligenceChapterImportReadiness
|
|||||||
{
|
{
|
||||||
public int ActiveSceneCount { get; init; }
|
public int ActiveSceneCount { get; init; }
|
||||||
public bool CanCommit { get; init; }
|
public bool CanCommit { get; init; }
|
||||||
public bool HasUntouchedDefaultPlaceholder { get; init; }
|
|
||||||
public int? PlaceholderSceneID { get; init; }
|
|
||||||
public string CommitMode { get; init; } = string.Empty;
|
public string CommitMode { get; init; } = string.Empty;
|
||||||
public string? BlockReason { get; init; }
|
public string? BlockReason { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -247,7 +247,9 @@ public sealed class OnboardingStoryIntelligenceService(
|
|||||||
CommitMessage = commit?.Notes,
|
CommitMessage = commit?.Notes,
|
||||||
Blockers = confirmation?.Blockers ?? [],
|
Blockers = confirmation?.Blockers ?? [],
|
||||||
Warnings = confirmation?.Warnings ?? [],
|
Warnings = confirmation?.Warnings ?? [],
|
||||||
Scenes = BuildScenePreviews(sceneResults)
|
Scenes = confirmation is null
|
||||||
|
? []
|
||||||
|
: BuildScenePreviews(confirmation.Scenes)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,19 +408,17 @@ public sealed class OnboardingStoryIntelligenceService(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IReadOnlyList<StoryIntelligenceOnboardingScenePreviewViewModel> BuildScenePreviews(IReadOnlyList<StoryIntelligenceSavedSceneResult> sceneResults)
|
private static IReadOnlyList<StoryIntelligenceOnboardingScenePreviewViewModel> BuildScenePreviews(IReadOnlyList<StoryIntelligenceSceneImportItem> importScenes)
|
||||||
=> sceneResults
|
=> importScenes
|
||||||
.OrderBy(scene => scene.TemporarySceneNumber)
|
.OrderBy(scene => scene.TemporarySceneNumber)
|
||||||
.Select(scene => new { Result = scene, Parsed = TryReadScene(scene.ParsedJson) })
|
|
||||||
.Where(scene => scene.Parsed is not null)
|
|
||||||
.Select(scene => new StoryIntelligenceOnboardingScenePreviewViewModel
|
.Select(scene => new StoryIntelligenceOnboardingScenePreviewViewModel
|
||||||
{
|
{
|
||||||
SceneNumber = scene.Result.TemporarySceneNumber,
|
SceneNumber = scene.TemporarySceneNumber,
|
||||||
Summary = Trim(FirstConfigured(scene.Parsed?.Summary?.Short, scene.Parsed?.Summary?.Detailed, $"Scene {scene.Result.TemporarySceneNumber:N0}")!, 180),
|
Summary = Trim(FirstConfigured(scene.ParsedScene.Summary?.Short, scene.ParsedScene.Summary?.Detailed, $"Scene {scene.TemporarySceneNumber:N0}")!, 180),
|
||||||
Pov = FirstConfigured(scene.Parsed?.PointOfView?.CharacterName, scene.Parsed?.PointOfView?.NarrativeMode),
|
Pov = FirstConfigured(scene.ParsedScene.PointOfView?.CharacterName, scene.ParsedScene.PointOfView?.NarrativeMode),
|
||||||
Setting = BuildSetting(scene.Parsed?.Setting),
|
Setting = BuildSetting(scene.ParsedScene.Setting),
|
||||||
Confidence = scene.Parsed?.Summary?.Confidence ?? scene.Parsed?.Setting?.Confidence,
|
Confidence = scene.ParsedScene.Summary?.Confidence ?? scene.ParsedScene.Setting?.Confidence,
|
||||||
HasWarnings = scene.Result.ValidationWarningsCount > 0
|
HasWarnings = false
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
|||||||
@ -129,11 +129,7 @@ public sealed class StoryIntelligenceImportCommitService(
|
|||||||
: null;
|
: null;
|
||||||
if (readiness is not null && !readiness.CanCommit)
|
if (readiness is not null && !readiness.CanCommit)
|
||||||
{
|
{
|
||||||
blockers.Add(readiness.BlockReason ?? "This chapter contains existing authored scenes.");
|
blockers.Add(readiness.BlockReason ?? "This chapter already contains scenes.");
|
||||||
}
|
|
||||||
else if (readiness?.HasUntouchedDefaultPlaceholder == true)
|
|
||||||
{
|
|
||||||
warnings.Add("This chapter contains only the default empty scene. It will be replaced by Scene 1 from the import.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingCommit is not null && string.Equals(existingCommit.Status, StoryIntelligenceImportCommitStatuses.Completed, StringComparison.OrdinalIgnoreCase))
|
if (existingCommit is not null && string.Equals(existingCommit.Status, StoryIntelligenceImportCommitStatuses.Completed, StringComparison.OrdinalIgnoreCase))
|
||||||
@ -169,7 +165,7 @@ public sealed class StoryIntelligenceImportCommitService(
|
|||||||
var parsed = TryReadScene(sceneResult);
|
var parsed = TryReadScene(sceneResult);
|
||||||
if (parsed is null)
|
if (parsed is null)
|
||||||
{
|
{
|
||||||
warnings.Add($"Suggested scene {sceneResult.TemporarySceneNumber:N0} was skipped because its parsed JSON could not be read.");
|
warnings.Add($"Scene {sceneResult.TemporarySceneNumber:N0} could not be prepared automatically and needs review.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +174,7 @@ public sealed class StoryIntelligenceImportCommitService(
|
|||||||
|
|
||||||
if (importScenes.Count == 0)
|
if (importScenes.Count == 0)
|
||||||
{
|
{
|
||||||
blockers.Add("No valid scene intelligence results are available to import.");
|
blockers.Add("No scenes are ready to create for this chapter.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var projectName = run.ProjectID.HasValue ? (await projects.GetAsync(run.ProjectID.Value))?.ProjectName ?? $"Project {run.ProjectID.Value:N0}" : "None";
|
var projectName = run.ProjectID.HasValue ? (await projects.GetAsync(run.ProjectID.Value))?.ProjectName ?? $"Project {run.ProjectID.Value:N0}" : "None";
|
||||||
@ -200,13 +196,13 @@ public sealed class StoryIntelligenceImportCommitService(
|
|||||||
BookTitle = bookTitle,
|
BookTitle = bookTitle,
|
||||||
ChapterLabel = chapterLabel,
|
ChapterLabel = chapterLabel,
|
||||||
ExistingSceneCount = readiness?.ActiveSceneCount ?? 0,
|
ExistingSceneCount = readiness?.ActiveSceneCount ?? 0,
|
||||||
HasUntouchedDefaultPlaceholder = readiness?.HasUntouchedDefaultPlaceholder == true,
|
|
||||||
CommitMode = readiness?.CommitMode ?? string.Empty,
|
CommitMode = readiness?.CommitMode ?? string.Empty,
|
||||||
ScenesToCreate = importScenes.Count,
|
ScenesToCreate = importScenes.Count,
|
||||||
MetricsToImport = importScenes.Sum(scene => scene.Metrics.Count),
|
MetricsToImport = importScenes.Sum(scene => scene.Metrics.Count),
|
||||||
MetricNames = importScenes.SelectMany(scene => scene.Metrics.Select(metric => metric.MetricName)).Distinct(StringComparer.OrdinalIgnoreCase).OrderBy(name => name).ToList(),
|
MetricNames = importScenes.SelectMany(scene => scene.Metrics.Select(metric => metric.MetricName)).Distinct(StringComparer.OrdinalIgnoreCase).OrderBy(name => name).ToList(),
|
||||||
Warnings = warnings,
|
Warnings = warnings,
|
||||||
Blockers = blockers
|
Blockers = blockers,
|
||||||
|
Scenes = importScenes
|
||||||
},
|
},
|
||||||
importScenes,
|
importScenes,
|
||||||
timeModeId,
|
timeModeId,
|
||||||
|
|||||||
29
PlotLine/Sql/125_Phase20AE_RemoveDefaultScenePlaceholder.sql
Normal file
29
PlotLine/Sql/125_Phase20AE_RemoveDefaultScenePlaceholder.sql
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
SET ANSI_NULLS ON;
|
||||||
|
GO
|
||||||
|
SET QUOTED_IDENTIFIER ON;
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF OBJECT_ID(N'dbo.TR_Chapters_CreateDefaultScene', N'TR') IS NOT NULL
|
||||||
|
DROP TRIGGER dbo.TR_Chapters_CreateDefaultScene;
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE OR ALTER PROCEDURE dbo.StoryIntelligenceImportCommit_GetChapterReadiness
|
||||||
|
@ChapterID int
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
DECLARE @ActiveSceneCount int;
|
||||||
|
|
||||||
|
SELECT @ActiveSceneCount = COUNT(1)
|
||||||
|
FROM dbo.Scenes
|
||||||
|
WHERE ChapterID = @ChapterID
|
||||||
|
AND IsArchived = 0;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
@ActiveSceneCount AS ActiveSceneCount,
|
||||||
|
CAST(CASE WHEN @ActiveSceneCount = 0 THEN 1 ELSE 0 END AS bit) AS CanCommit,
|
||||||
|
CAST(CASE WHEN @ActiveSceneCount = 0 THEN N'EmptyChapter' ELSE N'Blocked' END AS nvarchar(80)) AS CommitMode,
|
||||||
|
CAST(CASE WHEN @ActiveSceneCount = 0 THEN NULL ELSE N'This chapter already contains scenes.' END AS nvarchar(300)) AS BlockReason;
|
||||||
|
END;
|
||||||
|
GO
|
||||||
@ -304,13 +304,13 @@ public sealed class StoryIntelligenceImportConfirmationViewModel
|
|||||||
public string BookTitle { get; init; } = string.Empty;
|
public string BookTitle { get; init; } = string.Empty;
|
||||||
public string ChapterLabel { get; init; } = string.Empty;
|
public string ChapterLabel { get; init; } = string.Empty;
|
||||||
public int ExistingSceneCount { get; init; }
|
public int ExistingSceneCount { get; init; }
|
||||||
public bool HasUntouchedDefaultPlaceholder { get; init; }
|
|
||||||
public string CommitMode { get; init; } = string.Empty;
|
public string CommitMode { get; init; } = string.Empty;
|
||||||
public int ScenesToCreate { get; init; }
|
public int ScenesToCreate { get; init; }
|
||||||
public int MetricsToImport { get; init; }
|
public int MetricsToImport { get; init; }
|
||||||
public IReadOnlyList<string> MetricNames { get; init; } = [];
|
public IReadOnlyList<string> MetricNames { get; init; } = [];
|
||||||
public IReadOnlyList<string> Warnings { get; init; } = [];
|
public IReadOnlyList<string> Warnings { get; init; } = [];
|
||||||
public IReadOnlyList<string> Blockers { get; init; } = [];
|
public IReadOnlyList<string> Blockers { get; init; } = [];
|
||||||
|
public IReadOnlyList<StoryIntelligenceSceneImportItem> Scenes { get; init; } = [];
|
||||||
public bool HasCompletedCommit => ExistingCommit is not null
|
public bool HasCompletedCommit => ExistingCommit is not null
|
||||||
&& string.Equals(ExistingCommit.Status, StoryIntelligenceImportCommitStatuses.Completed, StringComparison.OrdinalIgnoreCase);
|
&& string.Equals(ExistingCommit.Status, StoryIntelligenceImportCommitStatuses.Completed, StringComparison.OrdinalIgnoreCase);
|
||||||
public bool CanCommit => Blockers.Count == 0 && !HasCompletedCommit;
|
public bool CanCommit => Blockers.Count == 0 && !HasCompletedCommit;
|
||||||
|
|||||||
@ -54,13 +54,6 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (Model.HasUntouchedDefaultPlaceholder)
|
|
||||||
{
|
|
||||||
<div class="alert alert-info">
|
|
||||||
This chapter contains only the default empty scene. It will be replaced by Scene 1 from the import.
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Project</dt>
|
<dt>Project</dt>
|
||||||
<dd>@Model.ProjectName</dd>
|
<dd>@Model.ProjectName</dd>
|
||||||
@ -78,10 +71,10 @@
|
|||||||
<dd>@(Model.MetricNames.Count == 0 ? "None" : string.Join(", ", Model.MetricNames))</dd>
|
<dd>@(Model.MetricNames.Count == 0 ? "None" : string.Join(", ", Model.MetricNames))</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
@if (Model.ExistingSceneCount > 0 && !Model.HasUntouchedDefaultPlaceholder)
|
@if (Model.ExistingSceneCount > 0)
|
||||||
{
|
{
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
This chapter already has authored scenes. The current import mode will not merge, replace, or overwrite authored scene content.
|
This chapter already has scenes. The current import mode will not merge, replace, or overwrite scene content.
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -156,7 +156,7 @@
|
|||||||
StoryIntelligenceRunStatuses.Pending => "Waiting",
|
StoryIntelligenceRunStatuses.Pending => "Waiting",
|
||||||
StoryIntelligenceRunStatuses.Running => "Reading",
|
StoryIntelligenceRunStatuses.Running => "Reading",
|
||||||
StoryIntelligenceRunStatuses.Completed => "Ready to create",
|
StoryIntelligenceRunStatuses.Completed => "Ready to create",
|
||||||
StoryIntelligenceRunStatuses.CompletedWithWarnings => "Ready with notes",
|
StoryIntelligenceRunStatuses.CompletedWithWarnings => "Ready",
|
||||||
StoryIntelligenceRunStatuses.Failed => "Needs review",
|
StoryIntelligenceRunStatuses.Failed => "Needs review",
|
||||||
StoryIntelligenceRunStatuses.Cancelled => "Cancelled",
|
StoryIntelligenceRunStatuses.Cancelled => "Cancelled",
|
||||||
_ => "Waiting"
|
_ => "Waiting"
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
var isAdmin = !string.IsNullOrWhiteSpace(userEmail)
|
var isAdmin = !string.IsNullOrWhiteSpace(userEmail)
|
||||||
&& adminEmails.Any(email => string.Equals(email, userEmail, StringComparison.OrdinalIgnoreCase));
|
&& adminEmails.Any(email => string.Equals(email, userEmail, StringComparison.OrdinalIgnoreCase));
|
||||||
var chaptersNeedingReview = Model.Chapters.Count(NeedsReview);
|
var chaptersNeedingReview = Model.Chapters.Count(NeedsReview);
|
||||||
var warningsCount = Model.Chapters.Sum(chapter => chapter.Warnings.Count + chapter.Blockers.Count + (chapter.FailedScenes ?? 0));
|
var warningsCount = Model.Chapters.Sum(chapter => NeedsReviewCount(chapter));
|
||||||
}
|
}
|
||||||
|
|
||||||
<section class="onboarding-shell" aria-labelledby="story-review-title">
|
<section class="onboarding-shell" aria-labelledby="story-review-title">
|
||||||
@ -55,7 +55,7 @@
|
|||||||
<strong>@FormatCost(Model.TotalEstimatedCostUSD)</strong>
|
<strong>@FormatCost(Model.TotalEstimatedCostUSD)</strong>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>Warnings requiring review</span>
|
<span>Needs review</span>
|
||||||
<strong>@warningsCount.ToString("N0")</strong>
|
<strong>@warningsCount.ToString("N0")</strong>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -68,27 +68,27 @@
|
|||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">Chapter @chapter.ChapterNumber</p>
|
<p class="eyebrow">Chapter @chapter.ChapterNumber</p>
|
||||||
<h2>@chapter.ChapterTitle</h2>
|
<h2>@chapter.ChapterTitle</h2>
|
||||||
<p>@((chapter.TotalDetectedScenes ?? 0).ToString("N0")) scene@(chapter.TotalDetectedScenes == 1 ? string.Empty : "s") detected / confidence @FormatConfidence(chapter.AverageConfidence)</p>
|
<p>@DetectedCount(chapter).ToString("N0") scene@(DetectedCount(chapter) == 1 ? string.Empty : "s") detected / @ReadyCount(chapter).ToString("N0") ready to create</p>
|
||||||
</div>
|
</div>
|
||||||
<strong class="@StatusClass(chapter)">@FriendlyStatus(chapter)</strong>
|
<strong class="@StatusClass(chapter)">@FriendlyStatus(chapter)</strong>
|
||||||
</summary>
|
</summary>
|
||||||
|
|
||||||
<div class="story-review-scene-panel">
|
<div class="story-review-scene-panel">
|
||||||
<div>
|
<div>
|
||||||
<span>Scenes found</span>
|
<span>Detected scenes</span>
|
||||||
<strong>@((chapter.TotalDetectedScenes ?? 0).ToString("N0"))</strong>
|
<strong>@DetectedCount(chapter).ToString("N0")</strong>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>Scenes ready</span>
|
<span>Ready</span>
|
||||||
<strong>@((chapter.CompletedScenes ?? 0).ToString("N0"))</strong>
|
<strong>@ReadyCount(chapter).ToString("N0")</strong>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>Needs review</span>
|
<span>Needs review</span>
|
||||||
<strong>@(((chapter.FailedScenes ?? 0) + chapter.Blockers.Count).ToString("N0"))</strong>
|
<strong>@NeedsReviewCount(chapter).ToString("N0")</strong>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>Confidence</span>
|
<span>Rejected</span>
|
||||||
<strong>@FormatConfidence(chapter.AverageConfidence)</strong>
|
<strong>@RejectedCount(chapter).ToString("N0")</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -104,7 +104,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
@foreach (var warning in chapter.Warnings)
|
@foreach (var warning in chapter.Warnings)
|
||||||
{
|
{
|
||||||
<li>@warning</li>
|
<li>@AuthorMessage(warning)</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -117,7 +117,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
@foreach (var blocker in chapter.Blockers)
|
@foreach (var blocker in chapter.Blockers)
|
||||||
{
|
{
|
||||||
<li>@blocker</li>
|
<li>@AuthorMessage(blocker)</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -125,7 +125,7 @@
|
|||||||
|
|
||||||
@if (!string.IsNullOrWhiteSpace(chapter.ErrorMessage))
|
@if (!string.IsNullOrWhiteSpace(chapter.ErrorMessage))
|
||||||
{
|
{
|
||||||
<p class="story-review-note story-review-note--warning">@chapter.ErrorMessage</p>
|
<p class="story-review-note story-review-note--warning">@AuthorMessage(chapter.ErrorMessage)</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="story-scene-preview-list">
|
<div class="story-scene-preview-list">
|
||||||
@ -174,7 +174,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="alert alert-info">
|
<section class="alert alert-info">
|
||||||
Scene creation uses the existing PlotDirector import safeguards. Default empty Scene 1 placeholders can be replaced, duplicate imports are blocked, and failures roll back safely.
|
Scene creation uses PlotDirector import safeguards. Duplicate imports are blocked, and failures roll back safely.
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="onboarding-actions">
|
<div class="onboarding-actions">
|
||||||
@ -200,10 +200,21 @@
|
|||||||
@functions {
|
@functions {
|
||||||
private static bool NeedsReview(StoryIntelligenceOnboardingChapterViewModel chapter)
|
private static bool NeedsReview(StoryIntelligenceOnboardingChapterViewModel chapter)
|
||||||
=> chapter.IsFailed
|
=> chapter.IsFailed
|
||||||
|| (chapter.FailedScenes ?? 0) > 0
|
|
||||||
|| chapter.Blockers.Count > 0
|
|| chapter.Blockers.Count > 0
|
||||||
|
|| NeedsReviewCount(chapter) > 0
|
||||||
|| (!chapter.CanCommit && !chapter.HasCompletedCommit && chapter.IsRunComplete);
|
|| (!chapter.CanCommit && !chapter.HasCompletedCommit && chapter.IsRunComplete);
|
||||||
|
|
||||||
|
private static int DetectedCount(StoryIntelligenceOnboardingChapterViewModel chapter)
|
||||||
|
=> Math.Max(chapter.TotalDetectedScenes ?? 0, ReadyCount(chapter) + Math.Max(chapter.FailedScenes ?? 0, 0));
|
||||||
|
|
||||||
|
private static int ReadyCount(StoryIntelligenceOnboardingChapterViewModel chapter)
|
||||||
|
=> chapter.HasCompletedCommit ? chapter.ScenesCreated : chapter.Scenes.Count;
|
||||||
|
|
||||||
|
private static int RejectedCount(StoryIntelligenceOnboardingChapterViewModel chapter) => 0;
|
||||||
|
|
||||||
|
private static int NeedsReviewCount(StoryIntelligenceOnboardingChapterViewModel chapter)
|
||||||
|
=> Math.Max(0, DetectedCount(chapter) - ReadyCount(chapter) - RejectedCount(chapter));
|
||||||
|
|
||||||
private static string FriendlyStatus(StoryIntelligenceOnboardingChapterViewModel chapter)
|
private static string FriendlyStatus(StoryIntelligenceOnboardingChapterViewModel chapter)
|
||||||
{
|
{
|
||||||
if (chapter.HasCompletedCommit)
|
if (chapter.HasCompletedCommit)
|
||||||
@ -213,18 +224,18 @@
|
|||||||
|
|
||||||
if (chapter.CanCommit)
|
if (chapter.CanCommit)
|
||||||
{
|
{
|
||||||
return chapter.Warnings.Count > 0 ? "Ready with notes" : "Ready to create";
|
return "Ready";
|
||||||
}
|
}
|
||||||
|
|
||||||
return chapter.Status switch
|
return chapter.Status switch
|
||||||
{
|
{
|
||||||
StoryIntelligenceRunStatuses.Pending => "Waiting",
|
StoryIntelligenceRunStatuses.Pending => "Waiting",
|
||||||
StoryIntelligenceRunStatuses.Running => "Reading",
|
StoryIntelligenceRunStatuses.Running => "Reading",
|
||||||
StoryIntelligenceRunStatuses.Completed => "Needs attention",
|
StoryIntelligenceRunStatuses.Completed => "Cannot import",
|
||||||
StoryIntelligenceRunStatuses.CompletedWithWarnings => "Needs attention",
|
StoryIntelligenceRunStatuses.CompletedWithWarnings => "Cannot import",
|
||||||
StoryIntelligenceRunStatuses.Failed => "Needs review",
|
StoryIntelligenceRunStatuses.Failed => "Needs review",
|
||||||
StoryIntelligenceRunStatuses.Cancelled => "Cancelled",
|
StoryIntelligenceRunStatuses.Cancelled => "Cancelled",
|
||||||
_ => "Needs attention"
|
_ => "Needs review"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,6 +258,31 @@
|
|||||||
|
|
||||||
private static string Display(string? value) => string.IsNullOrWhiteSpace(value) ? "Not detected" : value;
|
private static string Display(string? value) => string.IsNullOrWhiteSpace(value) ? "Not detected" : value;
|
||||||
|
|
||||||
|
private static string AuthorMessage(string? value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
return "This chapter needs review before scenes can be created.";
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = value.Trim();
|
||||||
|
if (message.Contains("JSON", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| message.Contains("parsed", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| message.Contains("parser", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| message.Contains("deserial", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return "One or more scene suggestions could not be prepared automatically and need review.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.Contains("existing authored scenes", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| message.Contains("already contains scenes", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return "This chapter already contains scenes. Choose an empty chapter before creating scenes from this analysis.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
private static string FormatConfidence(decimal? confidence)
|
private static string FormatConfidence(decimal? confidence)
|
||||||
=> confidence.HasValue ? $"{Math.Clamp(confidence.Value, 0m, 1m):P0}" : "Not available";
|
=> confidence.HasValue ? $"{Math.Clamp(confidence.Value, 0m, 1m):P0}" : "Not available";
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user