SuperAPI AI Directory

blog-narrator

Frontend & websites

View repository

Updated 10-15 21:52

About this skill

Blog Narrator
Markdown → parse_md → { 预览 HTML | split → gen → (match) → merge → 配音 HTML }

Purpose

Export blog Markdown as line-by-line reveal HTML suitable for presentations

  • Right arrow key reveals line by line, left arrow key goes back
  • Initially only the title is shown and centered; when entering a new ## 标题 the previous section is cleared, keeping only the title and the current section
  • With pre-recorded audio version:Shift mute,Ctrl re-read the current line

Mode selection

If the user has not explicitly stated whether they want "preview" or "TTS", you must use the Ask tool to ask before generating.

Dependencies

Python packages:

pip install esflow edge-tts

System binaries (audio decoding):

brew install ffmpeg          # macOS
sudo apt install ffmpeg      # Debian/Ubuntu
  • Preview / split / merge: Python 3 standard library
  • gen:edge-tts
  • match(alternative alignment):onnxruntime、numpy, model downloaded on first use to scripts/models/

Images:(/pics/...) relative to cwd; can be overridden with BLOG_NARRATOR_IMAGE_BASE .

Quick start

# 轻量预览(无预录音,体积小,验证排版)
python3 scripts/run.py preview input.md output.html [--rate 1.15] [--open]

# TTS 分段配音(一次跑完 split→gen→(match)→merge)
python3 scripts/run.py tts input.md work_dir [--voice xiaoxiao|xiaoyi] [--rate 1.175] [--open]

Default behavior: preview writes output.html; TTS writes work_dir/{stem}_voice.html,--open and automatically opens the browser.

Artifact forms

Mode Audio source Size Use case
Preview HTML Browser SpeechSynthesis reading (no pre-recorded audio), includes a voice panel that can be clicked to play Small Quickly verify layout, live presentation fallback
TTS HTML edge-tts pre-recorded audio embedded as base64,work_dir/audio/N.mp3 as the segmentation source Large Offline presentations, stable voice

Both artifacts are self-contained single files, both with a voice panel (Shift mute,Ctrl re-read the current line). The difference is only in the audio source: preview relies on browser synthesis with zero dependencies, TTS embeds pre-recorded audio.

  • Working directory(TTS mode):
work_dir/
  src.md            # 原始 Markdown 副本
  srt.md            # 分段清单(## [N] 标记)
  audio/            # 1.mp3, 2.mp3, …
  {stem}_voice.html # 合成产物
  .esflow-jobs/     # esflow 运行状态(--from 续跑用)

Flow structure

esflow DAG orchestration (scripts/flow.py declaration,scripts/nodes/ each node):

parse_md ──→ export_preview         (mode=preview)
        └──→ split → gen → match → merge   (mode=tts)

Single flow with two paths, the subcommand determines mode, and the node accept skips accordingly:

Node Responsibility
parse_md strip frontmatter/divider → HTML + extract title/paragraph text
export_preview Only mode=preview, generate lightweight HTML
split Only mode=tts, write work_dir/src.md + srt.md + audio/
gen Edge TTS segmented synthesis audio/N.mp3
match Condition:audio/ when there are non- N.mp3 named files, ASR alignment and renaming
merge Synthesize HTML with embedded base64 audio

match when skipped merge still runs——merge directly reads split.audio_dir, does not depend on match artifacts. No TO_AGENT breakpoint, runs to completion in one go.

Debug a single node: in the skill root directory esflow run scripts/ --node <节点 id>(upstream reuses from job artifacts).

Resume: after replacing audio, run only match+merge

Standard TTS flow gen always produces N.mp3,match automatically skipped. Tomanually replace/supplement audio(e.g., use a custom voice for flowcharts, code snippets):

# 1. 先正常跑一次,拿到 job 目录
python3 scripts/run.py tts input.md work_dir

# 2. 手动改 audio/:替换某些 N.mp3,或按 srt.md 段号放入网页 TTS 下载的音频(可非 N.mp3 命名)

# 3. 从 match 续跑(上游 split/gen 从 job 目录加载,不重跑)
python3 scripts/run.py tts input.md work_dir --from match --job-dir work_dir/.esflow-jobs/blog-narrator/<job时间戳>

match uses ASR to recognize non-named audio and rename it to N.mp3,merge Re-synthesize HTML.--from You can also specify merge to only re-synthesize.

Parameters

preview subcommand

Parameter Description
input Input Markdown
output Output HTML path
--rate Default speech rate, default 1.15
--open Open browser after generation

tts subcommand

Parameter Description
input Input Markdown
work_dir Working directory (stores src.md/srt.md/audio/artifacts)
--voice Voice xiaoxiao/xiaoyi, default xiaoxiao
--rate Speech rate, default 1.175
--open Open browser after generation
--from NODE Resume from the specified node for that node and downstream, upstream loaded from --job-dir loaded
--job-dir DIR --from Required when resuming, points to the previous job directory

Exception handling

Situation Behavior
Input file does not exist Precheck failed, exit code 3
--voice Invalid bad_voice error, exit code 3
--rate Not a number bad_rate error, exit code 3
edge-tts synthesis failed Single segment failure skipped, log ⚠️ 失败, does not interrupt the whole
match Missing onnxruntime no_onnxruntime error, exit code 1
--from Not configured --job-dir exit code 3

Agent usage guide

Use this skill when the user mentions "blog to presentation", "line-by-line reveal HTML", or "blog voiceover":

  1. First use Ask to confirm the mode: preview or TTS
  2. Preview:python3 scripts/run.py preview <input.md> <output.html> --open
  3. TTS:python3 scripts/run.py tts <input.md> <work_dir> --open
  4. If the user wants to replace certain audio: guide them to use --from match --job-dir <上次job> resume
  5. Confirm the product HTML path and report it back to the user

Modification rules

  • Core library (MD→HTML, stage, ASR):scripts/narrator_core.py
  • DAG declaration:scripts/flow.py; node implementation:scripts/nodes/
  • CLI and envelope:scripts/run.py、scripts/common.py