1实现原理 · 为什么它能做到
核心知识是 2.5 时代的两大变故:不再接受 voice_label(要改用自然语言 instruction ≤200 字 + 文本内联 () 韵律指令),且审查更严(死/消失/敏感政治词触发 censorship_block)。
**What `stepaudio-2.5-tts` will NOT accept** — `voice_label` parameter. Error: `voice_label is not supported for v2 models`. This is the #1 migration gotcha from step-tts-2.
脚本请求 /v1/audio/speech:JSON body(model/input/voice/response_format/speed/volume + 可选 instruction),Authorization Bearer,成功直接落盘 mp3 字节。
body: dict[str, Any] = { "model": MODEL, "input": text, "voice": voice, "response_format": response_format, "speed": speed, "volume": volume, }
instruction 长度硬校验 + 内联 () 韵律由文本透传:句内 (试探着问)/(轻声)/(停顿一下) 等括号内容被模型消费为表演指令、不朗读。
if instruction: if len(instruction) > 200: return {"ok": False, "status": 0, "err": f"instruction too long: {len(instruction)} > 200 chars"}
censorship_block 的逐行降级:检测 'censorship_block'/'blocked' 标记失败行,批量模式记录跳过 ID 继续,不整批中断。
censored = "censorship_block" in raw or "blocked" in raw.lower()
批处理:--batch 读 JSONL({id, text, instruction?} 每行一个对象),逐行合成到 --out-dir/<id>.mp3,行间 sleep delay-ms 防限流。
out_path = args.out_dir / f"{line_id}.mp3" if result["ok"]: out_path.write_bytes(result["audio_bytes"])
非破坏性 A/B 是设计不变式:重生成语料写并行目录(voice/zh_v25/)绝不覆盖生产语料;ab_compare.sh 用 ffprobe/stat 对比两目录 mp3 的大小与时长出 markdown 表。
1. **Non-destructive A/B output** — when regenerating a corpus with a new model, write to a parallel directory (`voice/zh_v25/`), never overwrite the production corpus.
2核心能力
3外部依赖
| Kind | Dependency / Endpoint |
|---|---|
| network | api.stepfun.com(StepAudio TTS 端点) |
| network | platform.stepfun.com(取 key/定价/voice 文档,仅指引) |
| cli | python3(stdlib urllib,无第三方包) |
| cli | ffprobe(ffmpeg,ab_compare 用) |
4管控建议与判定依据
- scripts/: 执行本地脚本或命令: daymade-audio/stepfun-tts/scripts/tts_generate.py
- 网络端点: 声明外部网络访问: POST https://api.stepfun.com/v1/audio/speech(请求体含待合成文本 + instruction + Auth
- 本地工作目录: 文件读写与工件输出: tts_generate.py 写 --out(单句)或 --out-dir/<id>.mp3(批量,mkdir parents)到用户指定路径
5第二遍独立确认
- [ok] 端点/body/模型名(/v1/audio/speech + stepaudio-2.5-tts) — tts_generate.py API_URL/MODEL 常量与 body dict 逐字存在;api_reference.md 同。
- [ok] voice_label 拒绝处理(迁移 gotcha) — 脚本对 raw 含 'voice_label is not supported' 时追加 HINT 文案;SKILL.md 错误表同描述。
- [ok] instruction ≤200 硬校验 — synthesize() 内 'if len(instruction) > 200: return {ok: False, status: 0, err: ...}' 存在,超长不发请求。
- [ok] censorship 逐行降级(不整批失败) — censored 列表单独收集、failed 汇总、循环 continue;main 返回码只按 failed 定。
- [ok] API key 解析(env → CLAUDE_PLUGIN_DATA/config.json) — load_api_key 顺序与 asr 版一致(env 优先、config 兜底、fail-fast)。
- [ok] A/B 脚本无网络、本地文件对比 — ab_compare.sh 仅 comm/stat/ffprobe;--noproxy/网络 token 零命中。
- [ok] 功能声明 vs 夸大检查(voice cloning 未验证声明) — known_issues.md 第 56 行明确 'Zero-shot voice cloning (9.9 元/音色) … was not verified in this skill's test pass'——SKILL.md 也未把克隆列为核心能力,无夸大。
- [ok] 元数据(license/stars/commit) — 仓库级 MIT、stars=1385、pushed_at=2026-09-09T12:33:29Z;本地 HEAD==pin d5c4678cb5d4fd6acc9c922690df035dbd33d247。
6结论
f7fa276a8ae68d1a…