feat: Implement ai_blueprint_v2.md — Exp 5, 6 & 7 (persona validation, mid-gen consistency, two-pass drafting)
Exp 6 — Iterative Persona Validation (story/style_persona.py + cli/engine.py): - Added validate_persona(): generates ~200-word sample in persona voice, scores 1–10 via lightweight voice-quality prompt; accepts if ≥ 7/10 - cli/engine.py retries create_initial_persona() up to 3× until validation passes - Expected: -20% Phase 3 voice-drift rewrites Exp 5 — Mid-gen Consistency Snapshots (cli/engine.py): - analyze_consistency() called every 10 chapters inside the writing loop - Issues logged as ⚠️ warnings; non-blocking; score and summary emitted - Expected: -30% post-generation continuity error rate Exp 7 — Two-Pass Drafting (story/writer.py): - After Flash rough draft, Pro model (model_logic) polishes prose against a strict checklist: filter words, deep POV, active voice, AI-isms, chapter hook - max_attempts reduced 3 → 2 since polished prose needs fewer rewrite cycles - Expected: +0.3 HQS with no increase in per-chapter cost Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -362,7 +362,51 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None,
|
||||
utils.log("WRITER", f"⚠️ Failed Ch {chap['chapter_number']}: {e}")
|
||||
return f"## Chapter {chap['chapter_number']} Failed\n\nError: {e}"
|
||||
|
||||
max_attempts = 3
|
||||
# Exp 7: Two-Pass Drafting — Polish the rough draft with the logic (Pro) model
|
||||
# before evaluation. Produces cleaner prose with fewer rewrite cycles.
|
||||
if current_text:
|
||||
utils.log("WRITER", f" -> Two-pass polish (Pro model)...")
|
||||
guidelines = get_style_guidelines()
|
||||
fw_list = '", "'.join(guidelines['filter_words'])
|
||||
polish_prompt = f"""
|
||||
ROLE: Senior Fiction Editor
|
||||
TASK: Polish this rough draft into publication-ready prose.
|
||||
|
||||
AUTHOR_VOICE:
|
||||
{persona_info}
|
||||
|
||||
GENRE: {genre}
|
||||
TARGET_WORDS: ~{est_words}
|
||||
BEATS (must all be covered): {json.dumps(chap.get('beats', []))}
|
||||
|
||||
POLISH_CHECKLIST:
|
||||
1. FILTER_REMOVAL: Remove all filter words [{fw_list}] — rewrite each to show the sensation directly.
|
||||
2. DEEP_POV: Ensure the reader is inside the POV character's experience at all times — no external narration.
|
||||
3. ACTIVE_VOICE: Replace all 'was/were + -ing' constructions with active alternatives.
|
||||
4. SENTENCE_VARIETY: No two consecutive sentences starting with the same word. Vary length for rhythm.
|
||||
5. STRONG_VERBS: Delete adverbs; replace with precise verbs.
|
||||
6. NO_AI_ISMS: Remove: 'testament to', 'tapestry', 'palpable tension', 'azure', 'cerulean', 'bustling', 'a sense of'.
|
||||
7. CHAPTER_HOOK: Ensure the final paragraph ends on unresolved tension, a question, or a threat.
|
||||
8. PRESERVE: Keep all narrative beats, approximate word count (±15%), and chapter header.
|
||||
|
||||
ROUGH_DRAFT:
|
||||
{current_text}
|
||||
|
||||
OUTPUT: Complete polished chapter in Markdown.
|
||||
"""
|
||||
try:
|
||||
resp_polish = ai_models.model_logic.generate_content(polish_prompt)
|
||||
utils.log_usage(folder, ai_models.model_logic.name, resp_polish.usage_metadata)
|
||||
polished = resp_polish.text
|
||||
if polished:
|
||||
polished_words = len(polished.split())
|
||||
utils.log("WRITER", f" -> Polished: {polished_words:,} words.")
|
||||
current_text = polished
|
||||
except Exception as e:
|
||||
utils.log("WRITER", f" -> Polish pass failed: {e}. Proceeding with raw draft.")
|
||||
|
||||
# Reduced from 3 → 2 attempts since polish pass already refines prose before evaluation
|
||||
max_attempts = 2
|
||||
SCORE_AUTO_ACCEPT = 8
|
||||
# Adaptive passing threshold: lenient for early setup chapters, strict for climax/resolution.
|
||||
# chapter_position=0.0 → setup (SCORE_PASSING=6.5), chapter_position=1.0 → climax (7.5)
|
||||
|
||||
Reference in New Issue
Block a user