Blueprint v2.3: AI-isms filter, Deep POV mandate, genre-specific writing rules
- story/style_persona.py: Expanded default ai_isms list with 20+ modern AI phrases (delved, mined, neon-lit, bustling, a wave of, etched in, etc.) and added filter_words (wondered, seemed, appeared, watched, observed, sensed) - story/editor.py: Stricter evaluate_chapter_quality rubric — added DEEP_POV_ENFORCEMENT block with automatic fail conditions for filter word density and summary mode; strengthened criterion 5 scoring thresholds - story/writer.py: Added get_genre_instructions() helper with genre-specific mandates for Thriller, Romance, Fantasy, Sci-Fi, Horror, Historical, and General Fiction; added DEEP_POV_MANDATE block banning summary mode and filter words; expanded AVOID AI-ISMS banned phrase list Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,7 +17,7 @@ def evaluate_chapter_quality(text, chapter_title, genre, model, folder):
|
||||
|
||||
prompt = f"""
|
||||
ROLE: Senior Literary Editor
|
||||
TASK: Critique chapter draft.
|
||||
TASK: Critique chapter draft. Apply STRICT scoring — do not inflate scores.
|
||||
|
||||
METADATA:
|
||||
- TITLE: {chapter_title}
|
||||
@@ -25,16 +25,21 @@ def evaluate_chapter_quality(text, chapter_title, genre, model, folder):
|
||||
|
||||
PROHIBITED_PATTERNS:
|
||||
- AI_ISMS: {ai_isms}
|
||||
- FILTER_WORDS: {fw_examples}
|
||||
- FILTER_WORDS: {fw_examples} — these are telling words that distance the reader from the scene.
|
||||
- CLICHES: White Room, As You Know Bob, Summary Mode, Anachronisms.
|
||||
- SYNTAX: Repetitive structure, Passive Voice, Adverb Reliance.
|
||||
|
||||
DEEP_POV_ENFORCEMENT (AUTOMATIC FAIL CONDITIONS):
|
||||
- FILTER_WORD_DENSITY: Scan the entire text for filter words (felt, saw, heard, realized, decided, noticed, knew, thought, wondered, seemed, appeared, watched, observed, sensed). If these words appear more than once per 120 words on average, criterion 5 MUST score 1-4 and the overall score CANNOT exceed 5.
|
||||
- SUMMARY_MODE: If any passage narrates events in summary rather than dramatizing them in real-time scene (e.g., "Over the next hour, they discussed...", "He had spent years..."), flag it. Summary mode in a scene that should be dramatized drops criterion 2 to 1-3 and the overall score CANNOT exceed 6.
|
||||
- TELLING_EMOTIONS: Phrases like "She felt sad," "He was angry," "She was nervous" — labeling emotions instead of showing them through physical action — are automatic criterion 5 failures. Each instance must be called out.
|
||||
|
||||
QUALITY_RUBRIC (1-10):
|
||||
1. ENGAGEMENT & TENSION: Does the story grip the reader from the first line? Is there conflict or tension in every scene?
|
||||
2. SCENE EXECUTION: Is the middle of the chapter fully fleshed out? Does it avoid "sagging" or summarizing key moments?
|
||||
2. SCENE EXECUTION: Is the middle of the chapter fully fleshed out? Does it avoid "sagging" or summarizing key moments? (Automatic 1-3 if summary mode detected.)
|
||||
3. VOICE & TONE: Is the narrative voice distinct? Does it match the genre?
|
||||
4. SENSORY IMMERSION: Does the text use sensory details effectively without being overwhelming?
|
||||
5. SHOW, DON'T TELL: Are emotions shown through physical reactions and subtext?
|
||||
5. SHOW, DON'T TELL / DEEP POV: STRICT ENFORCEMENT. Emotions must be rendered through physical reactions, micro-behaviours, and subtext — NOT named or labelled. Score 1-4 if filter word density is high. Score 1-2 if the chapter names emotions directly ("she felt," "he was angry") more than 3 times. Score 7-10 ONLY if the reader experiences the POV character's state without being told what it is.
|
||||
6. CHARACTER AGENCY: Do characters drive the plot through active choices?
|
||||
7. PACING: Does the chapter feel rushed? Does the ending land with impact, or does it cut off too abruptly?
|
||||
8. GENRE APPROPRIATENESS: Are introductions of characters, places, items, or actions consistent with the {genre} conventions?
|
||||
@@ -49,7 +54,8 @@ def evaluate_chapter_quality(text, chapter_title, genre, model, folder):
|
||||
- 9 (Bestseller): Exceptional quality, minor style tweaks only.
|
||||
- 7-8 (Professional): Good draft, solid structure, needs editing.
|
||||
- 6 (Passable): Average, has issues with pacing or voice. Needs heavy refinement.
|
||||
- 1-5 (Fail): Structural flaws, boring, or incoherent. Needs rewrite.
|
||||
- 1-5 (Fail): Structural flaws, summary mode detected, heavy filter word reliance, or incoherent. Needs full rewrite.
|
||||
- IMPORTANT: A score of 7+ CANNOT be awarded if filter word density is high or if any emotion is directly named/labelled.
|
||||
|
||||
OUTPUT_FORMAT (JSON):
|
||||
{{
|
||||
|
||||
@@ -10,10 +10,22 @@ def get_style_guidelines():
|
||||
"ai_isms": [
|
||||
'testament to', 'tapestry', 'shiver down spine', 'unspoken agreement',
|
||||
'palpable tension', 'a sense of', 'suddenly', 'in that moment',
|
||||
'symphony of', 'dance of', 'azure', 'cerulean'
|
||||
'symphony of', 'dance of', 'azure', 'cerulean',
|
||||
'delved', 'mined', 'neon-lit', 'bustling', 'weaved', 'intricately',
|
||||
'a reminder that', 'couldn\'t help but', 'it occurred to',
|
||||
'the air was thick with', 'etched in', 'a wave of', 'wash of emotion',
|
||||
'intertwined', 'navigate', 'realm', 'in the grand scheme',
|
||||
'at the end of the day', 'painting a picture', 'a dance between',
|
||||
'the weight of', 'visceral reminder', 'stark reminder',
|
||||
'a symphony', 'a mosaic', 'rich tapestry', 'whirlwind of',
|
||||
'his/her heart raced', 'time seemed to slow', 'the world fell away',
|
||||
'needless to say', 'it goes without saying', 'importantly',
|
||||
'it is worth noting', 'commendable', 'meticulous', 'pivotal',
|
||||
'in conclusion', 'overall', 'in summary', 'to summarize'
|
||||
],
|
||||
"filter_words": [
|
||||
'felt', 'saw', 'heard', 'realized', 'decided', 'noticed', 'knew', 'thought'
|
||||
'felt', 'saw', 'heard', 'realized', 'decided', 'noticed', 'knew', 'thought',
|
||||
'wondered', 'seemed', 'appeared', 'looked like', 'watched', 'observed', 'sensed'
|
||||
]
|
||||
}
|
||||
path = os.path.join(config.DATA_DIR, "style_guidelines.json")
|
||||
|
||||
@@ -6,6 +6,74 @@ from story.style_persona import get_style_guidelines
|
||||
from story.editor import evaluate_chapter_quality
|
||||
|
||||
|
||||
def get_genre_instructions(genre):
|
||||
"""Return genre-specific writing mandates to inject into the draft prompt."""
|
||||
g = genre.lower()
|
||||
if any(x in g for x in ['thriller', 'mystery', 'crime', 'suspense']):
|
||||
return (
|
||||
"GENRE_MANDATES (Thriller/Mystery):\n"
|
||||
"- Every scene must end on a hook: a revelation, reversal, or imminent threat.\n"
|
||||
"- Clues must be planted through detail, not narrated as clues.\n"
|
||||
"- Danger must feel visceral — use short, punchy sentences during action beats.\n"
|
||||
"- Internal monologue must reflect calculation and suspicion, not passive observation.\n"
|
||||
"- NEVER explain the mystery through the narrator — show the protagonist piecing it together."
|
||||
)
|
||||
elif any(x in g for x in ['romance', 'romantic']):
|
||||
return (
|
||||
"GENRE_MANDATES (Romance):\n"
|
||||
"- Show attraction through micro-actions: eye contact, proximity, hesitation, body heat.\n"
|
||||
"- NEVER tell the reader they feel attraction — render it through physical involuntary response.\n"
|
||||
"- Dialogue must carry subtext — what is NOT said is as important as what is said.\n"
|
||||
"- Every scene must shift the relationship dynamic (closer together or further apart).\n"
|
||||
"- The POV character's emotional wound must be present even in light-hearted scenes."
|
||||
)
|
||||
elif any(x in g for x in ['fantasy', 'epic', 'sword', 'magic']):
|
||||
return (
|
||||
"GENRE_MANDATES (Fantasy):\n"
|
||||
"- Introduce world-building through the POV character's reactions — not exposition dumps.\n"
|
||||
"- Magic and the fantastical must have visible cost or consequence — no deus ex machina.\n"
|
||||
"- Use concrete, grounded sensory details even in otherworldly settings.\n"
|
||||
"- Character motivation must be rooted in tangible personal stakes, not abstract prophecy or destiny.\n"
|
||||
"- NEVER use 'As you know Bob' exposition — characters who live in this world do not explain it to each other."
|
||||
)
|
||||
elif any(x in g for x in ['science fiction', 'sci-fi', 'scifi', 'space', 'cyberpunk']):
|
||||
return (
|
||||
"GENRE_MANDATES (Science Fiction):\n"
|
||||
"- Introduce technology through its sensory and social impact, not technical exposition.\n"
|
||||
"- The speculative premise must colour every scene — do not write contemporary fiction with sci-fi decoration.\n"
|
||||
"- Characters must treat their environment as natives, not tourists — no wonder at ordinary things.\n"
|
||||
"- Avoid anachronistic emotional or social responses inconsistent with the world's norms.\n"
|
||||
"- Themes (AI, surveillance, cloning) must emerge from plot choices and character conflict, not speeches."
|
||||
)
|
||||
elif any(x in g for x in ['horror', 'dark', 'gothic']):
|
||||
return (
|
||||
"GENRE_MANDATES (Horror):\n"
|
||||
"- Dread is built through implication — show what is wrong, never describe the monster directly.\n"
|
||||
"- Use the environment as an active hostile force — the setting must feel alive and threatening.\n"
|
||||
"- The POV character's psychology IS the true horror: isolation, doubt, paranoia.\n"
|
||||
"- Avoid jump-scare prose (sudden capitalised noises). Build sustained, crawling unease.\n"
|
||||
"- Sensory details must feel 'off' — wrong smells, sounds that don't belong, textures that repel."
|
||||
)
|
||||
elif any(x in g for x in ['historical', 'period', 'regency', 'victorian']):
|
||||
return (
|
||||
"GENRE_MANDATES (Historical Fiction):\n"
|
||||
"- Characters must think and speak with period-accurate worldviews — avoid modern anachronisms.\n"
|
||||
"- Historical detail must be woven into action and dialogue, never listed in descriptive passages.\n"
|
||||
"- Social hierarchy and constraint must feel like real, material limits on character choices.\n"
|
||||
"- Avoid modern idioms, slang, or metaphors that did not exist in the era.\n"
|
||||
"- The tension between historical inevitability and personal agency is the engine of the story."
|
||||
)
|
||||
else:
|
||||
return (
|
||||
"GENRE_MANDATES (General Fiction):\n"
|
||||
"- Every scene must change the character's situation, knowledge, or emotional state.\n"
|
||||
"- Conflict must be present in every scene — internal, interpersonal, or external.\n"
|
||||
"- Subtext: characters rarely say exactly what they mean — write the gap between intent and words.\n"
|
||||
"- The end of every chapter must be earned through causality, not arbitrary stopping.\n"
|
||||
"- Avoid coincidence as a plot driver — every event must have a clear cause."
|
||||
)
|
||||
|
||||
|
||||
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,
|
||||
@@ -137,6 +205,8 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None,
|
||||
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 ""
|
||||
|
||||
genre_mandates = get_genre_instructions(genre)
|
||||
|
||||
total_chapters = ls.get('chapters', '?')
|
||||
prompt = f"""
|
||||
ROLE: Fiction Writer
|
||||
@@ -163,19 +233,28 @@ def write_chapter(chap, bp, folder, prev_sum, tracking=None, prev_content=None,
|
||||
AUTHOR_VOICE:
|
||||
{persona_info}
|
||||
|
||||
{genre_mandates}
|
||||
|
||||
DEEP_POV_MANDATE (NON-NEGOTIABLE):
|
||||
- SUMMARY MODE IS BANNED. Every scene beat must be DRAMATIZED in real-time. Do NOT write "Over the next hour they discussed..." — write the actual exchange.
|
||||
- FILTER WORDS ARE BANNED: Do NOT write "She felt nervous," "He saw the door," "She realized she was late," "He noticed the knife." Instead, render the sensation directly: the reader must experience it, not be told about it.
|
||||
- BANNED FILTER WORDS: felt, saw, heard, realized, decided, noticed, knew, thought, wondered, seemed, appeared, watched, observed, sensed — remove all instances and rewrite to show the underlying experience.
|
||||
- EMOTION RENDERING: Never label an emotion. "She was terrified" → show the dry mouth, the locked knees, the way her vision narrowed to a single point. "He was angry" → show the jaw tightening, the controlled breath, the clipped syllables.
|
||||
- DEEP POV means: the reader is inside the POV character's skull at all times. The prose must feel like consciousness, not narration about a character.
|
||||
|
||||
INSTRUCTIONS:
|
||||
- Start with the Chapter Header formatted as Markdown H1 (e.g. '# Chapter X: Title'). Follow the 'Formatting Rules' for the header style.
|
||||
|
||||
- SENSORY ANCHORING: Start scenes by establishing Who, Where, and When immediately.
|
||||
- DEEP POV: Immerse the reader in the POV character's immediate experience. Filter descriptions through their specific worldview and emotional state.
|
||||
- SHOW, DON'T TELL: Focus on immediate action and internal reaction. Don't summarize feelings; show the physical manifestation of them.
|
||||
- DEEP POV: Immerse the reader in the POV character's immediate experience. Filter descriptions through their specific worldview and emotional state. (See DEEP_POV_MANDATE above.)
|
||||
- SHOW, DON'T TELL: Focus on immediate action and internal reaction. NEVER summarize feelings; show the physical manifestation of them.
|
||||
- CAUSALITY: Ensure events follow a "Because of X, Y happened" logic, not just "And then X, and then Y".
|
||||
- STAGING: When characters enter, describe their entrance. Don't let them just "appear" in dialogue.
|
||||
- SENSORY DETAILS: Use specific sensory details sparingly to ground the scene. Avoid stacking adjectives (e.g. "crisp white blouses, sharp legal briefs").
|
||||
- ACTIVE VOICE: Use active voice. Subject -> Verb -> Object. Avoid "was/were" constructions.
|
||||
- STRONG VERBS: Delete adverbs. Use specific verbs (e.g. "trudged" instead of "walked slowly").
|
||||
- NO INFO-DUMPS: Weave backstory into dialogue or action. Do not stop the story to explain history.
|
||||
- AVOID CLICHÉS: Avoid common AI tropes (e.g., 'shiver down spine', 'palpable tension', 'unspoken agreement', 'testament to', 'tapestry of', 'azure', 'cerulean').
|
||||
- AVOID AI-ISMS: Banned phrases — 'shiver down spine', 'palpable tension', 'unspoken agreement', 'testament to', 'tapestry of', 'azure', 'cerulean', 'delved', 'mined', 'bustling', 'neon-lit', 'a sense of', 'symphony of', 'the weight of'. Any of these appearing is an automatic quality failure.
|
||||
- MAINTAIN CONTINUITY: Pay close attention to the PREVIOUS CONTEXT. Characters must NOT know things that haven't happened yet or haven't been revealed to them.
|
||||
- CHARACTER INTERACTIONS: If characters are meeting for the first time in the summary, treat them as strangers.
|
||||
- SENTENCE VARIETY: Avoid repetitive sentence structures (e.g. starting multiple sentences with "He" or "She"). Vary sentence length to create rhythm.
|
||||
|
||||
Reference in New Issue
Block a user