Popiai-skill仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

6.0 KiB

Phase 1: Text Analysis

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.


1.1 Chapter Splitting

Automatically identify chapter boundaries:

  • Common chapter markers: Chapter X, CHAPTER X, Part X, numbered headings, etc.
  • For Chinese text: 第X章, 第X节, etc.
  • If automatic identification fails, ask the user to specify the delimiter
  • Generate analysis/chapters.md recording each chapter's title and position range

1.2 Character & Dialogue Identification

Three sequential steps: regex pre-processing (deterministic) → character pre-identification (LLM) → LLM segmentation (speaker attribution).


Step A: Regex Pre-processing (MANDATORY script)

Executor: Bundled script — no LLM needed. Run it directly, do NOT rewrite it. Input: source/book.txt Output: analysis/chapter_{N}/preprocessed.txt — each line contains either pure narration or pure dialogue, never both.

python3 $AUDIOBOOK_SCRIPTS/preprocess_chapter.py <chapter_number>

This script is MANDATORY — do NOT skip it or write your own regex.


Step A2: Character Pre-identification (LLM)

Before segmenting, scan the full chapter text to build a character list. This gives the LLM global context for speaker attribution.

Executor: LLM via text_generation MCP tool. Input: preprocessed.txt from Step A. Output: analysis/characters.md — format see references/characters-example.md.

Prompt template for character identification:

Read the following chapter text and identify ALL speaking characters.

For each character, provide:
1. Name (as it appears in the text)
2. Gender (if determinable)
3. Brief description (role, relationship to other characters)
4. Example dialogue line (one quote from the text)

Rules:
- Only list characters who SPEAK (have quoted dialogue)
- The narrator is NOT a character
- If a character is referred to by multiple names/titles, note all variants
- Pay attention to attribution phrases like "X said", "X replied", "X asked"

Text:
{preprocessed_text}

Write analysis/characters.md with the results. This character list will be used in Step B for speaker attribution.


Step B: LLM Segmentation

Executor: LLM via text_generation MCP tool. Input: preprocessed.txt from Step A + characters.md from Step A2. Output: analysis/chapter_{N}/segments.json — format see references/segments-example.json.

The LLM's task is to:

  1. Mark each line as narration or dialogue (Step A already split them, but the LLM decides the type — e.g., a quoted letter may be narration)
  2. For dialogue lines, identify who is speaking using the character list from Step A2

Prompt template for segmentation:

You are segmenting a chapter for audiobook production.

Known characters in this chapter:
{characters_list}

For each line of the preprocessed text, output a JSON segment:
- Narration (anything outside quotes, or quoted non-speech like letters/signs):
  {"type": "narration", "voice": "narrator", "text": "..."}
- Dialogue (a character speaking):
  {"type": "dialogue", "voice": "<character name>", "character": "<character name>", "text": "..."}

Speaker identification rules:
- Use surrounding attribution ("张叔说", "she replied") to determine the speaker
- In alternating two-person conversations, track the turn-taking pattern
- If the previous line is narration containing a character name + speech verb, the next dialogue belongs to that character
- Mark unattributable dialogue as voice: "unknown", character: "unknown"
- Use the EXACT character name from the characters list above

Text to segment:
{preprocessed_text}

Attribution Validation (CRITICAL): After segmentation, verify all speaker attributions:

  1. Check against story context — who is speaking to whom?
  2. For 2-speaker conversations, verify the alternating pattern is consistent
  3. Correct any wrong attributions before proceeding

Output files:

  • analysis/chapter_{N}/segments.jsonIMPORTANT: write with Python json.dump(), not Bash echo/heredoc (Chinese curly quotes "" break hand-built JSON)

segments.json must include a voice field on EVERY segment:

  • Narration segments: "voice": "narrator"
  • Dialogue segments: "voice": "<character name>" (same value as the character field)
  • This voice field is the single source of truth for voice assignment in all downstream phases. See references/segments-example.json for the exact format.

Before writing, ensure directories exist:

from pathlib import Path
(BOOK_DIR / "analysis" / f"chapter_{N}").mkdir(parents=True, exist_ok=True)

Step C: Attribution Validation Script (MANDATORY)

After writing segments.json, run the bundled validation script to detect common attribution errors:

python3 $AUDIOBOOK_SCRIPTS/validate_segments.py <chapter_number>

The script checks: unknown speakers, missing voice/character fields, and flags runs of 3+ consecutive same-speaker dialogue for review.

This script is MANDATORY — run it after every segments.json is written. If ERRORs appear, fix the segments before proceeding to Phase 2.