Split story context into wizard step
This commit is contained in:
parent
54bcd56df4
commit
01555136e7
@ -1131,7 +1131,7 @@ static void Phase21UEnforcesAliasAgeSemanticAndUiResetRules()
|
|||||||
Assert(!StoryIntelligenceIllustrationCompatibility.AssetCompatible("Hatchback", "SportsCar"), "Hatchback must not use sports-car art when demand generation is available.");
|
Assert(!StoryIntelligenceIllustrationCompatibility.AssetCompatible("Hatchback", "SportsCar"), "Hatchback must not use sports-car art when demand generation is available.");
|
||||||
|
|
||||||
var root = Path.Combine(AppContext.BaseDirectory, "../../../../PlotLine");
|
var root = Path.Combine(AppContext.BaseDirectory, "../../../../PlotLine");
|
||||||
var onboarding = File.ReadAllText(Path.Combine(root, "Views/Onboarding/StoryIntelligence.cshtml"));
|
var onboarding = File.ReadAllText(Path.Combine(root, "Views/Onboarding/StoryIntelligenceContext.cshtml"));
|
||||||
var adminController = File.ReadAllText(Path.Combine(root, "Controllers/AdminController.cs"));
|
var adminController = File.ReadAllText(Path.Combine(root, "Controllers/AdminController.cs"));
|
||||||
var adminDiagnostics = File.ReadAllText(Path.Combine(root, "Views/Admin/StoryIntelligenceDiagnostics.cshtml"));
|
var adminDiagnostics = File.ReadAllText(Path.Combine(root, "Views/Admin/StoryIntelligenceDiagnostics.cshtml"));
|
||||||
var program = File.ReadAllText(Path.Combine(root, "Program.cs"));
|
var program = File.ReadAllText(Path.Combine(root, "Program.cs"));
|
||||||
|
|||||||
@ -79,6 +79,13 @@ public sealed class OnboardingController(IOnboardingService onboarding, IOnboard
|
|||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("story-intelligence/context")]
|
||||||
|
public async Task<IActionResult> StoryIntelligenceContext()
|
||||||
|
{
|
||||||
|
var model = await storyIntelligence.GetOverviewAsync();
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("story-intelligence/book/{bookId:int}/continue")]
|
[HttpGet("story-intelligence/book/{bookId:int}/continue")]
|
||||||
public async Task<IActionResult> ContinueStoryIntelligence(int bookId)
|
public async Task<IActionResult> ContinueStoryIntelligence(int bookId)
|
||||||
{
|
{
|
||||||
@ -113,7 +120,7 @@ public sealed class OnboardingController(IOnboardingService onboarding, IOnboard
|
|||||||
if (job is null)
|
if (job is null)
|
||||||
{
|
{
|
||||||
TempData["OnboardingStoryIntelligenceError"] = "Review the manuscript scan before starting Story Intelligence.";
|
TempData["OnboardingStoryIntelligenceError"] = "Review the manuscript scan before starting Story Intelligence.";
|
||||||
return RedirectToAction(nameof(StoryIntelligence));
|
return RedirectToAction(nameof(StoryIntelligenceContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
return RedirectToAction(nameof(StoryIntelligenceProgress), new { batchId = job.BatchID });
|
return RedirectToAction(nameof(StoryIntelligenceProgress), new { batchId = job.BatchID });
|
||||||
|
|||||||
@ -68,7 +68,7 @@ public sealed class OnboardingStoryIntelligenceService(
|
|||||||
var missingTextCount = included.Count(chapter => string.IsNullOrWhiteSpace(chapter.Preview.ChapterText));
|
var missingTextCount = included.Count(chapter => string.IsNullOrWhiteSpace(chapter.Preview.ChapterText));
|
||||||
var primaryCharacterCount = preview.CharacterCandidates.Count(candidate => !string.Equals(candidate.Category, "Excluded", StringComparison.OrdinalIgnoreCase));
|
var primaryCharacterCount = preview.CharacterCandidates.Count(candidate => !string.Equals(candidate.Category, "Excluded", StringComparison.OrdinalIgnoreCase));
|
||||||
var characterPageCount = Math.Max(1, (int)Math.Ceiling(primaryCharacterCount / 10d));
|
var characterPageCount = Math.Max(1, (int)Math.Ceiling(primaryCharacterCount / 10d));
|
||||||
var totalWizardSteps = 7 + characterPageCount + 2;
|
var totalWizardSteps = 7 + characterPageCount + 3;
|
||||||
return new StoryIntelligenceOverviewViewModel
|
return new StoryIntelligenceOverviewViewModel
|
||||||
{
|
{
|
||||||
PreviewID = preview.PreviewID,
|
PreviewID = preview.PreviewID,
|
||||||
@ -79,7 +79,8 @@ public sealed class OnboardingStoryIntelligenceService(
|
|||||||
ApprovedChapterCount = included.Count,
|
ApprovedChapterCount = included.Count,
|
||||||
ApprovedWordCount = included.Sum(chapter => chapter.Preview.WordCount),
|
ApprovedWordCount = included.Sum(chapter => chapter.Preview.WordCount),
|
||||||
MissingChapterTextCount = missingTextCount,
|
MissingChapterTextCount = missingTextCount,
|
||||||
WizardCurrentStep = totalWizardSteps - 1,
|
WizardCurrentStep = totalWizardSteps - 2,
|
||||||
|
WizardContextStep = totalWizardSteps - 1,
|
||||||
WizardTotalSteps = totalWizardSteps,
|
WizardTotalSteps = totalWizardSteps,
|
||||||
ExistingBatchID = existingBatch?.BatchID,
|
ExistingBatchID = existingBatch?.BatchID,
|
||||||
CanStart = included.Count > 0 && missingTextCount == 0,
|
CanStart = included.Count > 0 && missingTextCount == 0,
|
||||||
|
|||||||
@ -128,6 +128,7 @@ public sealed class StoryIntelligenceOverviewViewModel
|
|||||||
public int ApprovedWordCount { get; init; }
|
public int ApprovedWordCount { get; init; }
|
||||||
public int MissingChapterTextCount { get; init; }
|
public int MissingChapterTextCount { get; init; }
|
||||||
public int WizardCurrentStep { get; init; } = 9;
|
public int WizardCurrentStep { get; init; } = 9;
|
||||||
|
public int WizardContextStep { get; init; } = 10;
|
||||||
public int WizardTotalSteps { get; init; } = 10;
|
public int WizardTotalSteps { get; init; } = 10;
|
||||||
public string? Message { get; init; }
|
public string? Message { get; init; }
|
||||||
public Guid? ExistingBatchID { get; init; }
|
public Guid? ExistingBatchID { get; init; }
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
@model StoryIntelligenceOverviewViewModel
|
@model StoryIntelligenceOverviewViewModel
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Story and portrait context";
|
ViewData["Title"] = "Ready to analyse manuscript";
|
||||||
}
|
}
|
||||||
|
|
||||||
<section class="onboarding-shell" aria-labelledby="story-intelligence-title">
|
<section class="onboarding-shell" aria-labelledby="story-intelligence-title">
|
||||||
@ -8,8 +8,8 @@
|
|||||||
<partial name="_OnboardingJourneyHeader" model="@(new OnboardingJourneyHeaderViewModel { CurrentStep = Model.WizardCurrentStep, TotalSteps = Model.WizardTotalSteps })" />
|
<partial name="_OnboardingJourneyHeader" model="@(new OnboardingJourneyHeaderViewModel { CurrentStep = Model.WizardCurrentStep, TotalSteps = Model.WizardTotalSteps })" />
|
||||||
<div class="onboarding-copy">
|
<div class="onboarding-copy">
|
||||||
<p class="eyebrow">Step @Model.WizardCurrentStep of @Model.WizardTotalSteps</p>
|
<p class="eyebrow">Step @Model.WizardCurrentStep of @Model.WizardTotalSteps</p>
|
||||||
<h1 id="story-intelligence-title">Story and Portrait Context</h1>
|
<h1 id="story-intelligence-title">Ready to Analyse Manuscript</h1>
|
||||||
<p>Set the context choices for this manuscript before the analysis starts.</p>
|
<p>Review the approved manuscript scope before setting final story and portrait context.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (TempData["OnboardingStoryIntelligenceError"] is string error)
|
@if (TempData["OnboardingStoryIntelligenceError"] is string error)
|
||||||
@ -70,83 +70,17 @@
|
|||||||
</section>
|
</section>
|
||||||
}
|
}
|
||||||
|
|
||||||
<form asp-action="StartStoryIntelligence" method="post" class="onboarding-analysis-setup">
|
<div class="onboarding-analysis-flow">
|
||||||
<div class="onboarding-analysis-setup__header">
|
<div><span>1</span><strong>Analyse chapters</strong></div>
|
||||||
<div>
|
<div><span>2</span><strong>Review scenes</strong></div>
|
||||||
<p class="eyebrow">Pre-analysis setup</p>
|
<div><span>3</span><strong>Review story entities</strong></div>
|
||||||
<h2>Context choices</h2>
|
<div><span>4</span><strong>Build database</strong></div>
|
||||||
<p>Explicit manuscript evidence always wins. These choices guide unresolved generated portraits and broad story context.</p>
|
</div>
|
||||||
</div>
|
|
||||||
<strong>Required before analysis</strong>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="onboarding-analysis-controls">
|
<div class="onboarding-actions">
|
||||||
<label>
|
<a class="btn btn-outline-secondary" asp-action="ScanReview" asp-route-previewId="@Model.PreviewID">Back to scan review</a>
|
||||||
Appearance baseline
|
<a class="btn btn-primary @(Model.CanStart ? string.Empty : "disabled")" asp-action="StoryIntelligenceContext" aria-disabled="@(!Model.CanStart)">Next</a>
|
||||||
<select class="form-select" name="appearancePreference">
|
</div>
|
||||||
<option value="@StoryMemoryAppearancePreferences.Balanced">Balanced diverse cast</option>
|
|
||||||
<option value="@StoryMemoryAppearancePreferences.ExplicitEvidenceOnly">Explicit evidence only</option>
|
|
||||||
<option value="@StoryMemoryAppearancePreferences.PredominantlyLight">Predominantly light-skinned cast</option>
|
|
||||||
<option value="@StoryMemoryAppearancePreferences.PredominantlyMedium">Predominantly medium-skinned cast</option>
|
|
||||||
<option value="@StoryMemoryAppearancePreferences.PredominantlyDark">Predominantly dark-skinned cast</option>
|
|
||||||
<option value="@StoryMemoryAppearancePreferences.CustomMix">Custom mix</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Primary character age group
|
|
||||||
<select class="form-select" name="primaryAgeGroup">
|
|
||||||
<option value="">No baseline</option>
|
|
||||||
<option value="Late teen / early 20s">Late teen / early 20s</option>
|
|
||||||
<option value="Young teen">Young teen</option>
|
|
||||||
<option value="Older teen">Older teen</option>
|
|
||||||
<option value="Young adult">Young adult</option>
|
|
||||||
<option value="Adult">Adult</option>
|
|
||||||
<option value="Middle-aged adult">Middle-aged adult</option>
|
|
||||||
<option value="Senior">Senior</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Era
|
|
||||||
<select class="form-select" name="storyEra">
|
|
||||||
<option value="">No baseline</option>
|
|
||||||
<option value="1980s">1980s</option>
|
|
||||||
<option value="1970s">1970s</option>
|
|
||||||
<option value="1990s">1990s</option>
|
|
||||||
<option value="2000s">2000s</option>
|
|
||||||
<option value="Contemporary">Contemporary</option>
|
|
||||||
<option value="Victorian">Victorian</option>
|
|
||||||
<option value="Medieval">Medieval</option>
|
|
||||||
<option value="Near future">Near future</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Location
|
|
||||||
<select class="form-select" name="storyLocation">
|
|
||||||
<option value="">No baseline</option>
|
|
||||||
<option value="UK">UK</option>
|
|
||||||
<option value="United States">United States</option>
|
|
||||||
<option value="Europe">Europe</option>
|
|
||||||
<option value="Urban">Urban</option>
|
|
||||||
<option value="Suburban">Suburban</option>
|
|
||||||
<option value="Rural">Rural</option>
|
|
||||||
<option value="Fantasy world">Fantasy world</option>
|
|
||||||
<option value="Science fiction setting">Science fiction setting</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="onboarding-analysis-flow">
|
|
||||||
<div><span>1</span><strong>Analyse chapters</strong></div>
|
|
||||||
<div><span>2</span><strong>Review scenes</strong></div>
|
|
||||||
<div><span>3</span><strong>Review story entities</strong></div>
|
|
||||||
<div><span>4</span><strong>Build database</strong></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="onboarding-actions">
|
|
||||||
<a class="btn btn-outline-secondary" asp-action="ScanReview" asp-route-previewId="@Model.PreviewID">Back to scan review</a>
|
|
||||||
<button class="btn btn-primary" type="submit" disabled="@(!Model.CanStart)">Save context and analyse manuscript</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="onboarding-actions onboarding-actions--secondary">
|
<div class="onboarding-actions onboarding-actions--secondary">
|
||||||
<form asp-action="SkipStoryIntelligence" method="post">
|
<form asp-action="SkipStoryIntelligence" method="post">
|
||||||
|
|||||||
107
PlotLine/Views/Onboarding/StoryIntelligenceContext.cshtml
Normal file
107
PlotLine/Views/Onboarding/StoryIntelligenceContext.cshtml
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
@model StoryIntelligenceOverviewViewModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Story and portrait context";
|
||||||
|
}
|
||||||
|
|
||||||
|
<section class="onboarding-shell" aria-labelledby="story-intelligence-context-title">
|
||||||
|
<div class="onboarding-panel onboarding-analysis-panel">
|
||||||
|
<partial name="_OnboardingJourneyHeader" model="@(new OnboardingJourneyHeaderViewModel { CurrentStep = Model.WizardContextStep, TotalSteps = Model.WizardTotalSteps })" />
|
||||||
|
<div class="onboarding-copy">
|
||||||
|
<p class="eyebrow">Step @Model.WizardContextStep of @Model.WizardTotalSteps</p>
|
||||||
|
<h1 id="story-intelligence-context-title">Story and Portrait Context</h1>
|
||||||
|
<p>Set the context choices for this manuscript before the analysis starts.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (TempData["OnboardingStoryIntelligenceError"] is string error)
|
||||||
|
{
|
||||||
|
<div class="alert alert-danger">@error</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (Model.ExistingBatchID.HasValue)
|
||||||
|
{
|
||||||
|
<section class="onboarding-story-card">
|
||||||
|
<h2>Analysis has already started</h2>
|
||||||
|
<p>You can continue reviewing progress for the approved chapters.</p>
|
||||||
|
<div class="onboarding-actions">
|
||||||
|
<a class="btn btn-primary" asp-action="StoryIntelligenceReview" asp-route-batchId="@Model.ExistingBatchID">Continue pipeline</a>
|
||||||
|
<form asp-action="ScanManuscript" method="post">
|
||||||
|
<button class="btn btn-outline-secondary" type="submit">Scan manuscript again</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<form asp-action="StartStoryIntelligence" method="post" class="onboarding-analysis-setup">
|
||||||
|
<div class="onboarding-analysis-setup__header">
|
||||||
|
<div>
|
||||||
|
<p class="eyebrow">Pre-analysis setup</p>
|
||||||
|
<h2>Context choices</h2>
|
||||||
|
<p>Explicit manuscript evidence always wins. These choices guide unresolved generated portraits and broad story context.</p>
|
||||||
|
</div>
|
||||||
|
<strong>Required before analysis</strong>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="onboarding-analysis-controls">
|
||||||
|
<label>
|
||||||
|
Appearance baseline
|
||||||
|
<select class="form-select" name="appearancePreference">
|
||||||
|
<option value="@StoryMemoryAppearancePreferences.Balanced">Balanced diverse cast</option>
|
||||||
|
<option value="@StoryMemoryAppearancePreferences.ExplicitEvidenceOnly">Explicit evidence only</option>
|
||||||
|
<option value="@StoryMemoryAppearancePreferences.PredominantlyLight">Predominantly light-skinned cast</option>
|
||||||
|
<option value="@StoryMemoryAppearancePreferences.PredominantlyMedium">Predominantly medium-skinned cast</option>
|
||||||
|
<option value="@StoryMemoryAppearancePreferences.PredominantlyDark">Predominantly dark-skinned cast</option>
|
||||||
|
<option value="@StoryMemoryAppearancePreferences.CustomMix">Custom mix</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Primary character age group
|
||||||
|
<select class="form-select" name="primaryAgeGroup">
|
||||||
|
<option value="">No baseline</option>
|
||||||
|
<option value="Late teen / early 20s">Late teen / early 20s</option>
|
||||||
|
<option value="Young teen">Young teen</option>
|
||||||
|
<option value="Older teen">Older teen</option>
|
||||||
|
<option value="Young adult">Young adult</option>
|
||||||
|
<option value="Adult">Adult</option>
|
||||||
|
<option value="Middle-aged adult">Middle-aged adult</option>
|
||||||
|
<option value="Senior">Senior</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Era
|
||||||
|
<select class="form-select" name="storyEra">
|
||||||
|
<option value="">No baseline</option>
|
||||||
|
<option value="1980s">1980s</option>
|
||||||
|
<option value="1970s">1970s</option>
|
||||||
|
<option value="1990s">1990s</option>
|
||||||
|
<option value="2000s">2000s</option>
|
||||||
|
<option value="Contemporary">Contemporary</option>
|
||||||
|
<option value="Victorian">Victorian</option>
|
||||||
|
<option value="Medieval">Medieval</option>
|
||||||
|
<option value="Near future">Near future</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Location
|
||||||
|
<select class="form-select" name="storyLocation">
|
||||||
|
<option value="">No baseline</option>
|
||||||
|
<option value="UK">UK</option>
|
||||||
|
<option value="United States">United States</option>
|
||||||
|
<option value="Europe">Europe</option>
|
||||||
|
<option value="Urban">Urban</option>
|
||||||
|
<option value="Suburban">Suburban</option>
|
||||||
|
<option value="Rural">Rural</option>
|
||||||
|
<option value="Fantasy world">Fantasy world</option>
|
||||||
|
<option value="Science fiction setting">Science fiction setting</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="onboarding-actions">
|
||||||
|
<a class="btn btn-outline-secondary" asp-action="StoryIntelligence">Back</a>
|
||||||
|
<button class="btn btn-primary" type="submit" disabled="@(!Model.CanStart)">Save context and analyse manuscript</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
@ -1,6 +1,6 @@
|
|||||||
@model OnboardingJourneyHeaderViewModel
|
@model OnboardingJourneyHeaderViewModel
|
||||||
@{
|
@{
|
||||||
var characterReviewStepCount = Math.Max(1, Model.TotalSteps - 9);
|
var characterReviewStepCount = Math.Max(1, Model.TotalSteps - 10);
|
||||||
var steps = Model.TotalSteps <= 10
|
var steps = Model.TotalSteps <= 10
|
||||||
? BuildDefaultSteps()
|
? BuildDefaultSteps()
|
||||||
: BuildDynamicSteps(characterReviewStepCount, Model.TotalSteps);
|
: BuildDynamicSteps(characterReviewStepCount, Model.TotalSteps);
|
||||||
@ -60,6 +60,7 @@
|
|||||||
steps.Add(new HeaderStep($"Characters {index}", 7 + index));
|
steps.Add(new HeaderStep($"Characters {index}", 7 + index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
steps.Add(new HeaderStep("Story Summary", totalSteps - 2));
|
||||||
steps.Add(new HeaderStep("Story Context", totalSteps - 1));
|
steps.Add(new HeaderStep("Story Context", totalSteps - 1));
|
||||||
steps.Add(new HeaderStep("Complete", totalSteps));
|
steps.Add(new HeaderStep("Complete", totalSteps));
|
||||||
return steps;
|
return steps;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user