SuperAPI AI Directory

wjs-voicedrop-reading-aloud

Writing & research

View repository

Updated 10-15 23:32

About this skill

wjs-voicedrop-reading-aloud

Text → audiobook mp3. Not read literally, but firstarranged: different kinds of content get different voices, voice instructions are added at key turning points, then synthesized with Volcano Engine Doubao seed-tts-2.0.

Synthesis tool:~/code/volcano-tts/tts.py(first source ~/code/.env)。

Iron rules

  1. Never feed text with 【】/[ ] annotations directly to the bare API — the bare API will read the annotations out verbatim (confirmed by testing). Always go through tts.py, which splits the annotations into segments and converts them into context_texts voice instructions.
  2. Only 2.0 voices can be used (_uranus_bigtts suffix) — moon/mars/tob voices throw an error under the seed-tts-2.0 resource resource ID is mismatched。
  3. Before synthesis, show the user the arranged reading script(unless the user says to just produce it) — arrangement is re-creation, and the voice assignment and instructions are worth confirming. Skip this step in headless/automated scenarios.

Workflow

1. Get the content and read it through carefully

  • Plain text/file: read directly.
  • URL: WebFetch; for SPA pages (such as docs.volcengine.com), use the browse skill to render and then get the body text.
  • VoiceDrop article: the voicedrop MCP's read_article。

While reading through, mark: body narration / direct quotes (quotation marks, blockquote) / plain-language gripes and inner monologue / data, lists, tables / headings and sections.

2. Arrange and rewrite into a reading script

This is the core step; it isrewritingnot transcription:

  • Remove all visual residue: markdown symbols, links, image captions, footnote numbers.
  • Rewrite tables, lists, and data into spoken sentences ("three reasons: first...").
  • Do not read headings word for word; fold them into transition sentences, or carry them with a pause + breath.
  • Change long sentences that are too formal into colloquial ones, but keep the author's word style.
  • Assign voices by the nature of the content(see the voice table): one main voice runs through the body; quotes switch to a quote voice; gripes/plain language switch to an interjection voice. Voice switching is a "format signal" for listeners, equivalent to a quote block visually.
  • Do not switch voices frequently: generally cap it at 2~3 voices, and switch only where the nature of the content truly changes.

3. Add voice instructions (sparingly)

Add before the sentence [心理活动、细腻表情、肢体动作等描述], such as [放慢,一字一顿,点出要害]。

  • Add only where needed: emotional turns, rhythm changes, emphasis, imitation of a quote's tone. Add none to straightforward passages; rely on global instructions as a fallback.
  • Empirical density: at most one every 3~5 sentences; a calm narrative passage can have none at all.
  • Each annotation is a segment split (one API call + splice point); splitting too finely makes the speech flow disjointed.
  • Write annotations as performance cues addressed to the reader (inner activity/expression/action are all fine), not as explanations addressed to the listener.
  • Instructions must be dramatic and emotional to be effective(tested): the model follows emotion/voice-type instructions very strongly (crying tone, whisper, excited shouting, like a judge pronouncing a sentence, changes on the order of +50% duration), and follows subtle stage directions ("the tone sinks", "with a trace of regret") and mechanically precise instructions ("pause for one second", "slow down by half") very weakly. In wording, err on the side of exaggeration: "please press the voice down to near a whisper, lean close to the mic, as if revealing a secret" is far better than "lower the voice".

4. Reading script format (tts.py --script)

# 注释行
@voice narrator zh_male_yuanboxiaoshu_uranus_bigtts
@voice quote zh_male_yizhipiannan_uranus_bigtts
@voice casual zh_male_fanjuanqingnian_uranus_bigtts

@narrator
[语气平静从容,像老朋友聊天]先讲一个真事。……他公开断言:

@quote
[带着当年的笃定与体面]股价已经站上了一个永久的高原。

@narrator
几天后,市场开始了最惨烈的下跌。

@casual
[像随口吐槽]这人判断力真差。

5. Synthesis and acceptance

source ~/code/.env
python3 ~/code/volcano-tts/tts.py -f script.txt --script -o out.mp3 \
  -i "这是一段有声书朗读,自然口语化,像讲故事,不要播音腔"
  • -i Global instructions are mandatory, setting the overall tone;--speech-rate、--subtitle(word-level timestamps) as needed.
  • Acceptance:afinfo out.mp3 Check whether the duration matches the word count (Chinese is about 4-5 characters/second); if this is the first time you've modified a tool or you have doubts, use ~/.claude/skills/wjs-transcribing-audio/scripts/volc_asr_stream.py to spot-check a passage and confirm the annotations are not being read aloud.
  • Use SendUserFile to send the mp3 to the user.

Voice list (tested and available, all support voice instructions)

Purpose voice_type Name
Main narration voice (male, default) zh_male_yuanboxiaoshu_uranus_bigtts 渊博小叔
Main narration voice (female, alternative) zh_female_zhixingnv_uranus_bigtts 知性女声
Narration (conversational/podcast feel) zh_male_shenyeboke_uranus_bigtts 深夜播客
Commentary tone zh_male_cixingjieshuonan_uranus_bigtts 磁性解说男声
Quotations/famous quotes/translations zh_male_yizhipiannan_uranus_bigtts 译制片男
Plain speech/roasting/inner monologue zh_female_shuangkuaisisi_uranus_bigtts 爽快思思(用户定:大白话用女声,与男声旁白区分)
Plain speech (male alternative) zh_male_fanjuanqingnian_uranus_bigtts 反卷青年
General female voice zh_female_vv_uranus_bigtts Vivi

More 2.0 voices:https://www.volcengine.com/docs/6561/1257544 (only recognizes the _uranus_bigtts suffix).

Common pitfalls

  • Instructions silently fail (everything sounds the same) → three confirmed pitfalls,tts.py all fixed: ① context_texts/section_id must be embedded in additions(JSON string); if placed at the top level of req_params , it is silently ignored; ② context_texts when multiple are passed, only the first takes effect—in-segment instructions must be on their own line and cannot be listed side by side with global ones (a global one placed first will override all in-segment ones); ③ paraphrasing packaging ("read according to this instruction: X") dilutes the effect; sending the annotated original text directly is strongest. When in doubt, use the "extremely slow crying tone" instruction for an A/B duration comparison (should be +25% or more); baseline synthesis is deterministic (the same sentence with the same parameters has exactly the same duration); a difference of less than 5% means it did not take effect.
  • Annotations are read aloud → you forgot to use tts.py 's annotation parsing, or used a bracket format it does not recognize (supports 【】 and [ ])。
  • resource ID is mismatched with speaker related resource → a non-2.0 voice was used.
  • Obvious sense of broken tone in the middle of the output → annotations split segments too finely; merge annotations and reduce switching.
  • Hearing "asterisk" or "hashtag" → the orchestration step did not clean markdown thoroughly (tts.py does not enable markdown filtering; it relies on clearing during orchestration).