"""Style reference loader for Content Pipeline v2.
Loads JSON style examples from shared/project-docs/blog/style-examples/.
These examples teach the LLM the target voice and structure.
"""
import json
import os
from pathlib import Path
from typing import Optional
STYLE_EXAMPLES_DIR = Path("/home/hoffmann_admin/.openclaw/shared/project-docs/blog/style-examples")
def load_style_example(slug: str) -> Optional[dict]:
"""Load a style example by slug.
Looks for {slug}.json in the style-examples directory.
Returns None if not found.
"""
path = STYLE_EXAMPLES_DIR / f"{slug}.json"
if not path.exists():
return None
try:
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
except (json.JSONDecodeError, IOError):
return None
def list_style_examples() -> list[dict]:
"""List all available style examples.
Returns list of {slug, title, excerpt} dicts.
"""
if not STYLE_EXAMPLES_DIR.exists():
return []
examples = []
for path in sorted(STYLE_EXAMPLES_DIR.glob("*.json")):
try:
with open(path, "r", encoding="utf-8") as f:
data = json.load(f)
examples.append({
"slug": data.get("slug", path.stem),
"title": data.get("title", path.stem),
"excerpt": data.get("excerpt", "")[:200],
})
except (json.JSONDecodeError, IOError):
continue
return examples
def build_style_prompt(style_reference: Optional[str]) -> str:
"""Build a style injection prompt from a style reference.
If style_reference is None or not found, returns a generic prompt.
"""
if not style_reference:
return _default_style_prompt()
example = load_style_example(style_reference)
if not example:
return _default_style_prompt()
# Extract voice markers
voice = example.get("voice_markers", {})
structure = example.get("structure", {})
prompt_parts = [
"## Voice and Style Guide (from reference: {title})",
"",
"Write in first person. Use 'I' statements throughout.",
"Include specific timestamps and temporal markers (2 AM, yesterday, etc.)",
"Describe struggle honestly — what broke, what you tried, why it failed.",
"Mention the real cost: sleep lost, family disrupted, frustration felt.",
"End with reflection — what you learned, what you'd do differently.",
"",
"## Structural Template",
"",
]
if "hook" in structure:
prompt_parts.append(f"1. Hook: {structure['hook'].get('type', 'timestamp_location_crisis')}")
if "struggle" in structure:
s = structure["struggle"]
prompt_parts.append(f"2. Struggle: {s.get('attempts', 2)} failed attempts, escalating tension")
if "moment" in structure:
prompt_parts.append(f"3. The Moment: {structure['moment'].get('realization', 'The realization')}")
if "fix" in structure:
f = structure["fix"]
prompt_parts.append(f"4. The Fix: {f.get('solution', 'The solution')} (note caveats: {f.get('caveats', 'none')})")
if "reflection" in structure:
prompt_parts.append(f"5. Reflection: {structure['reflection'].get('lesson', 'The lesson learned')}")
prompt_parts.extend([
"",
"## Voice Markers to Emulate",
"",
f"- I-statements: ~{voice.get('i_statements', 8)} per article",
f"- Direct quotes: {', '.join(voice.get('quotes', ['Aundrea said...']))}",
f"- Cost mentions: {', '.join(voice.get('cost_mentions', ['sleep', 'time']))}",
"",
])
return "\n".join(prompt_parts).format(title=example.get("title", "Reference"))
def _default_style_prompt() -> str:
"""Default style prompt when no reference is available."""
return """## Voice and Style Guide
Write in first person. Use 'I' statements throughout.
Include specific timestamps and temporal markers.
Describe struggle honestly — what broke, what you tried, why it failed.
Mention the real cost: sleep lost, family disrupted, frustration felt.
End with reflection — what you learned, what you'd do differently.
Structural Template
- Hook: Start with a specific moment of crisis (timestamp + location)
- Struggle: 2-3 failed attempts, escalating tension
- The Moment: The realization or breakthrough
- The Fix: The solution, with honest caveats
- Reflection: What you learned, what you'd do differently
"""
def ensure_style_examples_dir():
"""Ensure the style examples directory exists."""
STYLE_EXAMPLES_DIR.mkdir(parents=True, exist_ok=True)
Initialize on import
ensure_style_examples_dir()