Blueprint v2.0: Pre-Flight Beat Expansion (Director's Treatment)

Implement Section 3 of the AI Context Optimization Blueprint: before each
chapter draft, model_logic expands sparse scene_beats into a structured
Director's Treatment covering staging, sensory anchors, emotional shifts,
and subtext per beat. This treatment is injected into the writer prompt,
giving the model a detailed scene blueprint to dramatize rather than infer,
reducing rewrite attempts and improving first-draft quality scores.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-21 00:15:43 -05:00
parent f71a04c03c
commit 0667c31413

View File

@@ -6,6 +6,38 @@ from story.style_persona import get_style_guidelines
from story.editor import evaluate_chapter_quality
def expand_beats_to_treatment(beats, pov_char, genre, folder):
"""Expand sparse scene beats into a Director's Treatment using a fast model.
This pre-flight step gives the writer detailed staging and emotional direction,
reducing rewrites by preventing skipped beats and flat pacing."""
if not beats:
return None
prompt = f"""
ROLE: Story Director
TASK: Expand the following sparse scene beats into a concise "Director's Treatment".
GENRE: {genre}
POV_CHARACTER: {pov_char or 'Protagonist'}
SCENE_BEATS: {json.dumps(beats)}
For EACH beat, provide 3-4 sentences covering:
1. STAGING: Where are characters physically? How do they enter/exit the scene?
2. SENSORY ANCHOR: One specific sensory detail (sound, smell, texture) to ground the beat.
3. EMOTIONAL SHIFT: What is the POV character's internal state at the START vs END of this beat?
4. SUBTEXT: What does the POV character want vs. what they actually do or say?
OUTPUT: Prose treatment only. Do NOT write the chapter prose itself.
"""
try:
response = ai_models.model_logic.generate_content(prompt)
utils.log_usage(folder, ai_models.model_logic.name, response.usage_metadata)
utils.log("WRITER", " -> Beat expansion complete.")
return response.text
except Exception as e:
utils.log("WRITER", f" -> Beat expansion failed: {e}. Using raw beats.")
return None
def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None, next_chapter_hint=""):
pacing = chap.get('pacing', 'Standard')
est_words = chap.get('estimated_words', 'Flexible')
@@ -101,6 +133,10 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None,
trunc_content = utils.truncate_to_tokens(prev_content, 1000)
prev_context_block = f"\nPREVIOUS CHAPTER TEXT (Last ~1000 Tokens — For Immediate Continuity):\n{trunc_content}\n"
utils.log("WRITER", f" -> Expanding beats to Director's Treatment...")
treatment = expand_beats_to_treatment(chap.get('beats', []), pov_char, genre, folder)
treatment_block = f"\n DIRECTORS_TREATMENT (Staged expansion of the beats — use this as your scene blueprint; DRAMATIZE every moment, do NOT summarize):\n{treatment}\n" if treatment else ""
total_chapters = ls.get('chapters', '?')
prompt = f"""
ROLE: Fiction Writer
@@ -168,6 +204,7 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None,
- CHARACTERS: {json.dumps(chars_for_writer)}
{char_visuals}
- SCENE_BEATS: {json.dumps(chap['beats'])}
{treatment_block}
OUTPUT: Markdown text.
"""