Imported from zhchxiao123/cloud-service-kg-podcast (
.agents/skills/podcast-script/SKILL.md). Install upstream withnpx skills add zhchxiao123/cloud-service-kg-podcast --skill podcast-script. Copyright stays with the author.
播客脚本生成
生成双人播客对话脚本(host + guest),输出带幻灯片编号注解的 JSON,供 /podcast-voice 合成音频、供 /podcast-video 计算幻灯片切换时机。
想象你认识的那些最好的播客——主持人和嘉宾之间的来回充满真实的生命力,两个人都有真实的存在感。这就是目标质量。host 不是只念问题的机器,guest 不是只背事实的复读机——他们是两个好奇的人,真正在一起把一件事想清楚。
项目目录管理
所有产物统一存放在:
<当前工作空间>/podcast-projects/<项目名>/v<N>/podcast-script.json
<当前工作空间> 是调用此技能时所在的目录。播客视频流水线中的所有技能建议在同一个目录下调用,确保 podcast-projects/ 始终在同一位置。
确定项目: 扫描 podcast-projects/ 目录,找到含 slide-outline.json 的项目,向用户确认后继续。
自动版本: 读取 <项目名>/current.txt:
podcast-script.json已存在于当前版本 → 创建 vN+1/ 目录,复制现有产物,再写入新脚本,更新current.txtpodcast-script.json不存在 → 直接写入当前版本,成功后更新current.txt
前置检查
在生成脚本前确认以下各项,缺少信息时的标准问法见文末反问清单:
- 项目已确认(通过目录扫描或用户指定)
- 有内容来源:
slide-outline.json存在(推荐),或用户提供了文章/关键词 - 若使用大纲,验证大纲格式合法(含
slides数组,每项有slide、type、speaker_notes、depth字段)
两种工作模式
大纲对齐模式(优先,当存在 slide-outline.json 时)
大纲里的讨论提示是专门为对话设计的,比从零生成更精准。幻灯片上展示了什么结论,对话应当解释这些结论背后的"为什么"和"怎么做"——不是照读。
规则:
- 幻灯片的讨论提示是该幻灯片的主要内容来源,对话必须覆盖其中提到的所有角度
- 根据
depth分配对话轮次:short→ 1-2 轮,medium→ 3-4 轮,long→ 5-6 轮 depth: "long"的幻灯片必须有真实的对立观点或追问,不能全程点头认同cover/toc/section类型控制在 1-2 轮(开场/过渡),不要过度展开- 每个对话轮次加
"slide": N,严格递增,与大纲slide字段一一对应
字数预期(确保内容充实):
- 8-10 张幻灯片 → 至少 1500 中文字
- 11-12 张幻灯片 → 至少 2000 中文字
- 有 3 张以上
depth: "long"→ 可达 3000 字,不要截断
独立生成模式(当没有大纲时)
从关键词或文章直接生成,此时不输出 "slide" 字段。对话结构遵循四段弧线:
- 开场(10-15%):hook + 嘉宾第一观点(要让人觉得"这个角度没听过")
- 核心(50-60%):2-4 个话题,每个深入展开,不浅尝
- 互动(15-20%):真实分歧、追问、反驳——至少 2 次实质性交锋
- 收尾(10-15%):洞见结晶 + 开放性问题或行动建议
TTS 文本归一化
text 字段直接进 TTS 引擎,任何出现在非句末位置的 . 都会被误判为句号,导致音频断句错乱甚至合成长 silence。所有数字点/IP/版本号/包名都必须用中文「点」替换。脚本写完必须做归一化扫描。
强制替换规则
| 模式 | 原始示例 | 中文输出 | 英文输出 |
|---|---|---|---|
| 完整版本号 | v1.1.1 或 1.2.3 |
v1点1点1 |
v1 dot 1 dot 1 |
| 两点版本号(最常见) | 1.0 / v1.0 |
1点0 / v1点0 |
1 dot 0 / v1 dot 0 |
| IP 地址 | 192.168.1.1 |
192点168点1点1 |
192 dot 168 dot 1 dot 1 |
| dotted 包名/域名 | com.example.app |
com点example点app |
com dot example dot app |
| URL / 邮箱 | foo.bar/x |
foo点bar点x |
foo dot bar dot x |
| 省略号 | … 或 ... |
保留(句末)或 …… |
同 |
| 百分号小数 | 3.5% / 0.99% |
保留,TTS 能读 | n/a |
| 量级小数 | 3.5倍 / $9.99 |
保留,TTS 能读 | n/a |
关键问题:脚本里出现任何
\d+\.\d+都必须替换,单点版本号最容易遗漏(1点0比1.0更安全;不带 v 前缀也要替换)。
ASCII 引号陷阱
ASCII 直引号 ' 和 ' 在 OMLX TTS 的某些组合下导致 503。建议替换为:
- 显式短引用 → 中文「」:
'课程'→「课程」 - 强调短语 → 直接去掉引号不替换
全角标点偏好(中文播客建议)
| ASCII | 中文替代 |
|---|---|
, |
, |
.(句末) |
。 |
: |
: |
; |
; |
! |
! |
? |
? |
TTS 对全角标点的断句更稳。如果大纲/脚本生成已经用全角,跳过这步。
何时跑归一化
- 生成脚本后立即扫描:跑
<skill-dir>/scripts/normalize_text.py podcast-script.json自动扫描并列出每个违规位置。 - 用
--write修复:自动把1.0 → 1点0、ASCII 引号 →「」应用回文件。 - TTS 阶段再扫一次:omlx-podcast-tts 自己也会扫(见该 skill 校验),但它只会报错失败,不会自动修。脚本阶段就要修对。
- 单点版本号最易漏:脚本写完后用
\d+\.\d+全局 grep 一次。
输出格式
{
"title": "具体的、有吸引力的集标题",
"script": [
{"role": "host", "text": "开场...", "slide": 1},
{"role": "guest", "text": "嘉宾回应...", "slide": 1},
{"role": "host", "text": "进入主题...", "slide": 2},
{"role": "guest", "text": "深入分析...", "slide": 2}
]
}
role只用"host"或"guest",这两个值直接映射到 TTS 声道- 每个 turn 是一人连续说话直到对方接话的内容
- 典型 turn 长度:2-6 句;长段独白和单句回应都是正常的,取决于内容节奏
"slide"编号严格递增,不允许回跳(比如从 slide 3 回到 slide 2)
产物校验
写入文件前逐项验证:
-
script数组非空 - TTS 归一化扫描(每条
text都要过):- 单点/多点版本号:
\d+\.\d+(包括1.0、v1.2.3),必须已替换为「数字+点+数字」 - IP 地址:
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} - dotted 包名/域名:
[a-z0-9]+(\.[a-z0-9]+){2,} - ASCII 引号
'/'在中文对话里:替换为「」或删除 - 例外:纯小数带单位(
3.5倍、0.99%、$9.99、100.5元)不需转化
- 单点/多点版本号:
- 归一化脚本:把扫描结果列出每个违规位置,要求人工或自动替换后才能进入下一步
大纲对齐模式额外验证:
- 每个 turn 都有
role、text、slide三个字段 -
slide值严格递增,不跳号,不回退 -
slide最大值不超过大纲的total_slides - 字数达到对应幻灯片数量的预期下限
-
depth: "long"的幻灯片对应的对话轮次 ≥ 5 轮
独立生成模式额外验证:
- 不含
slide字段 - 总字数 ≥ 1500 中文字
反问清单
| 缺失情况 | 标准反问 |
|---|---|
| 无大纲也无其他输入 | "请提供内容来源:大纲路径、文章内容,或播客主题关键词。" |
| 大纲格式不合法 | "大纲文件缺少必要字段(<字段名>),请先重新运行 /podcast-outline 生成合法大纲。" |
| 用户未指定项目 | "请告诉我要继续哪个播客项目,或新建一个项目名称。" |
| 用户想调整某段对话 | 确认具体的幻灯片编号和修改方向,局部重写该 slide 的对话轮次,不重新生成整份脚本 |