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:
2026-02-22 22:08:47 -05:00
parent 2100ca2312
commit 4f2449f79b
4 changed files with 167 additions and 16 deletions

View File

@@ -50,9 +50,16 @@ def process_book(bp, folder, context="", resume=False, interactive=False):
bp = planner.enrich(bp, folder, context)
with open(bp_path, "w") as f: json.dump(bp, f, indent=2)
# Ensure Persona Exists (Auto-create if missing)
# Ensure Persona Exists (Auto-create + Exp 6: Validate before accepting)
if 'author_details' not in bp['book_metadata'] or not bp['book_metadata']['author_details']:
bp['book_metadata']['author_details'] = style_persona.create_initial_persona(bp, folder)
max_persona_attempts = 3
for persona_attempt in range(1, max_persona_attempts + 1):
candidate_persona = style_persona.create_initial_persona(bp, folder)
is_valid, p_score = style_persona.validate_persona(bp, candidate_persona, folder)
if is_valid or persona_attempt == max_persona_attempts:
bp['book_metadata']['author_details'] = candidate_persona
break
utils.log("SYSTEM", f" -> Persona attempt {persona_attempt}/{max_persona_attempts} scored {p_score}/10. Regenerating...")
with open(bp_path, "w") as f: json.dump(bp, f, indent=2)
except Exception as _e:
utils.log("ERROR", f"Blueprint phase failed: {type(_e).__name__}: {_e}")
@@ -268,6 +275,21 @@ def process_book(bp, folder, context="", resume=False, interactive=False):
# Update Structured Story State (Item 9: Thread Tracking)
current_story_state = story_state.update_story_state(txt, ch['chapter_number'], current_story_state, folder)
# Exp 5: Mid-gen Consistency Snapshot (every 10 chapters)
if len(ms) > 0 and len(ms) % 10 == 0:
utils.log("EDITOR", f"--- Mid-gen consistency check after chapter {ch['chapter_number']} ({len(ms)} written) ---")
try:
consistency = story_editor.analyze_consistency(bp, ms, folder)
issues = consistency.get('issues', [])
if issues:
for issue in issues:
utils.log("EDITOR", f" ⚠️ {issue}")
c_score = consistency.get('score', 'N/A')
c_summary = consistency.get('summary', '')
utils.log("EDITOR", f" Consistency score: {c_score}/10 — {c_summary}")
except Exception as _ce:
utils.log("EDITOR", f" Mid-gen consistency check failed (non-blocking): {_ce}")
# Dynamic Pacing Check (every other chapter)
remaining = chapters[i+1:]
if remaining and len(remaining) >= 2 and i % 2 == 1: