4.5 KiB
Phase 2: Text Rewriting (Adding Pause Markers)
Script Setup (Run Once Per Session)
export AUDIOBOOK_SCRIPTS=$(python3 -c "
import json, os
from pathlib import Path
audiobook_root = Path(os.getcwd()) / '.audiobook'
hits = list(audiobook_root.glob('*/.audiobook-state.json')) if audiobook_root.exists() else []
if not hits:
print('ERROR: state file not found — run Phase 0 first'); exit(1)
data = json.loads(hits[0].read_text())
val = data.get('skillScriptsPath', '').strip()
if not val:
print('ERROR: skillScriptsPath missing from state — re-run Phase 0'); exit(1)
if not Path(val).is_dir():
print(f'ERROR: skillScriptsPath does not exist: {val}'); exit(1)
print(val)
")
echo "AUDIOBOOK_SCRIPTS=$AUDIOBOOK_SCRIPTS"
A clean path (no ERROR) means scripts are ready. If you see skillScriptsPath missing from state, derive the path from the <location> entry for the audiobook skill in your available_skills list (strip file:// and /SKILL.md, append /scripts) and patch the state file — same procedure as Phase 3/4.
Input / Output
- Input:
analysis/chapter_{N}/segments.jsonfrom Phase 1 (each segment is already unambiguously narration or dialogue). - Output:
scripts/chapter_{N}.md— the same segments with<#X#>pause markers inserted. Seereferences/chapter-script-example.mdfor the complete format.
Pause Marker Syntax
Use the TTS engine's native <#X#> pause syntax, where X is pause duration in seconds (supports decimals).
CRITICAL: The format is <#0.5#>, NOT <#0.5s#>. Never add s after the number. The s suffix causes TTS to read the marker as literal text instead of pausing, resulting in audio 3x longer than expected.
- Correct:
<#0.5#>,<#1.2#>,<#0.25#> - WRONG:
<#0.5s#>,<#1.2s#>,<#0.25s#> - WRONG:
<#0.3-0.5#>,<#0.5~0.8#>— never use ranges, pick one value
Pause Rules
Narration (includes attribution phrases like "she said," — these are narration segments per Phase 1):
| Scenario | Marker Example | Description |
|---|---|---|
| Normal period/full stop | <#0.6#> |
Natural inter-sentence pause |
| Paragraph end | <#1.5#> |
Paragraph transition |
| Scene change | <#2#> |
Environment/time transition |
| Ellipsis | <#1.2#> |
Dramatic pause effect |
| Exclamation/question mark | <#0.4#> |
Slightly shorter than period, maintains emotional continuity |
| Comma | <#0.25#> |
Light breath (only add in long sentences) |
| After attribution phrase | <#0.3#> |
Pause at end of "he said," before the next segment begins |
Dialogue:
| Scenario | Marker Example | Description |
|---|---|---|
| End of dialogue line | <#0.4#> |
Brief pause after line |
| Dialogue to narration transition | <#0.8#> |
From dialogue back to narration |
| Between dialogue lines (same scene) | <#0.6#> |
Two characters alternating |
| Hesitation within dialogue | <#0.8#> |
Character's inner hesitation |
Output Format
Phase 2 has two sub-steps:
- LLM adds pause markers to segment text (update
segments.jsonin-place with<#X#>markers) - Python script generates
chapter_N.mdfrom the updatedsegments.json— this guaranteesvoice:headers come directly from data, not LLM generation
Sub-step 1: LLM adds pause markers
Read segments.json, add <#X#> pause markers to each segment's text field according to the Pause Rules above, and write the updated segments back to the same file.
Do NOT generate chapter_N.md directly. Only update the text field in segments.json.
Sub-step 1.5: Validate pause markers (MANDATORY script)
After adding pause markers, run validation to catch and auto-fix malformed markers:
python3 $AUDIOBOOK_SCRIPTS/validate_pause_markers.py <chapter_number>
The script auto-fixes common LLM mistakes:
<#0.6>→<#0.6#>(missing closing#)<#0.6s#>→<#0.6#>(spuriousssuffix)<# 0.6 #>→<#0.6#>(whitespace around number)<#0.3-0.5#>→<#0.4#>(range → average)
If unfixable markers remain, the script exits with error — fix manually before proceeding.
Sub-step 2: Generate chapter script
After pause markers are validated, run the bundled script to generate chapter_N.md:
python3 $AUDIOBOOK_SCRIPTS/generate_chapter_script.py <chapter_number>
The script reads segments.json and writes chapter_N.md with voice: headers directly from the voice field — no LLM generation involved.
This script is MANDATORY — do NOT skip it or write chapter_N.md by hand.