下载地址
https://www.zhengdianxue.com/wp-content/uploads/skills/org-07epl2hq--ajzq-equity-visual-report.zip将提示词发送给你的 AI 安装该 skills
请根据 https://skillhub.cn/install/skillhub.md,安装 @org-07epl2hq/ajzq-equity-visual-report。- 爱建证券企业深度研究可视化研报生成skill —— 把上市公司深度研究转成可视化研报视频。Use when the user asks to turn a company research note into a short vertical (9:16) visual research report with data animation and a so…
- 做成视频"
- , "
- 做个可视化研报"
- , "
- 每日认识一家公司"
- …(完整说明见下方「阅读全文」)
阅读全文 (展开查看完整说明)
概述
爱建证券 · 企业深度研究可视化研报生成 skill
把一份公司深度研究,变成一条 1080×1920 竖屏、约 3 分钟、带柔和女声旁白和数据动画 的可视化研报视频。
核心取舍:不用 AI 视频生成。原因是中文字符在生成模型里必崩、且要烧大量积分;改用 Chrome/Edge 无头渲染 HTML 动画 —— 中文排版 100% 可控、改字改数零成本、每期只需复制模板。
已落地 6 期:中成股份 000151、百花医药 600721、华天科技 002185、普源精电 688337、优利德 688628、万科A 000002。
〇、署名与合规口径
对外以「爱建证券」名义出片时统一按以下处理:
- 品牌条:画面底部 150px 品牌区写
爱建证券 企业深度研究+ 标的简称/代码 + 日期。 - 免责声明:末幕固定一句「以上仅为公开信息整理,不构成任何投资建议;数据截至 <日期>」,旁白里同步念一遍。
- 口径:所有引用数据必须带日期;多来源打架时画面只用一个口径,脚注标注来源。
- 内部自用/不带署名的版本,品牌条可留通用文案,但免责声明不得删。
一、什么时候用
- 用户说「做成视频」「出个短视频」「做个可视化研报」「每日认识一家公司」「做成和 XX 那期一样的」。
- 用户给了一份公司调研,要可视化成竖屏短视频(抖音 / 视频号口径)。
- 用户要给已有视频补旁白。
- 用户没给标的:「今天做一期」「随便来一家」「每日认识一家公司」→ 走 Step 0,从当天十大热门股自动选题。
不适用:横屏PPT式汇报、需要真人出镜、需要动态实物素材。
二、环境依赖
开跑前先自检一次,别录到一半才发现缺东西:
python scripts/check_env.py # 只检查
python scripts/check_env.py --fix # 自动补 Playwright 需要的 ffmpeg| 依赖 | 位置 / 安装 | 用途 |
|---|---|---|
| Python venv | C:Users<user>.workbuddybinariespythonenvsdefaultScriptspython.exe | 统一解释器 |
| edge-tts | pip install edge-tts(当前 7.2.8) | 神经网络语音 |
| playwright | pip install playwright | 无头录制 |
| pypdf | pip install pypdf | 解析财报 PDF(Step 2 兜底取数要用) |
| msedge | C:Program Files (x86)MicrosoftEdgeApplicationmsedge.exe | 渲染内核(比自带 Chromium 稳) |
| ffmpeg | <venv>Libsite-packagesimageio_ffmpegbinariesffmpeg-win-x86_64-v7.1.exe | 分离/转码/合成 |
| node (>=18) | C:Program Filesnodejsnode.exe | 跑内置 westock-data(选题器 + 取数都要用) |
| pypinyin(可选) | pip install pypinyin | 自动生成拼音 slug |
Playwright 的 ffmpeg:Playwright 录制需要它自己那份 ffmpeg,playwright install ffmpeg 会联网失败。check_env.py --fix 会直接把 imageio_ffmpeg 拷到 ~/.cache/ms-playwright/ffmpeg-1011/ffmpeg-win64.exe。手动版:
cp <venv>/Lib/site-packages/imageio_ffmpeg/binaries/ffmpeg-win-x86_64-v7.1.exe
~/.cache/ms-playwright/ffmpeg-1011/ffmpeg-win64.exe为什么不用 Windows SAPI:Add-Type 被安全策略拦截,本地 TTS 不可用。Edge 在线神经语音(zh-CN-XiaoxiaoNeural)质量更好且免费。
三、标准流程(7 步)
Step 0 · 选题(用户没给标的时必做)
用户没有指定公司时,不要反问「您想看哪家」,也不要凭记忆挑。直接跑选题器:
python scripts/pick_hot_topic.py # 列出当日十大热门股 + 默认推荐
python scripts/pick_hot_topic.py --json # 机读输出
python scripts/pick_hot_topic.py --pick sh603259 # 手动改选榜单里的某只它依次做三件事:
- 调内置 westock-data 的
hot stock(当日热搜股票榜;金融数据权威入口,禁止改用网页搜索)拉取全市场热度排序; - 过滤不可拍的标的:ETF/指数、ST/*ST、上市未满 5 日的新股(
N/C开头)→ 取前 10,即当天十大热门股; - 对照
references/episode-log.json(往期已做清单)去重,默认推荐「热度最高且没做过」的那只,同时给出拼音 slug 与下一轮换配色,末尾直接打印可执行的脚手架命令(见 Step 1)。
# 代码 名称 涨跌% 现价 slug
1 000002.SZ 万科A 7.35 4.38 wanke ←默认
2 000011.SZ 深物业A 9.97 12.24 shenwuyea
...
(已过滤 2 只:N力勤资源=上市未超5日新股;通信ETF富国=非个股)
推荐直接开跑:
python scripts/new_episode.py --slug wanke --code 000002.SZ --name 万科A --theme cyan依赖:
node(跑 westock-data,脚本会自动查找内置技能目录)+pypinyin(拼音 slug;缺失时退回<市场前缀><代码>,如sz000002)。必须回写:一期做完后执行
python scripts/pick_hot_topic.py --mark-done --slug wanke --code 000002.SZ --name 万科A --theme cyan,否则下一期会重复选题。热门 ≠ 好拍:Top10 若全是纯题材游资票,优先挑「热度靠前 + 有真实财务口径 + 有反差点」的那只,并在封面钩子里点破炒作与基本面的错配(参照优利德那期:公司自己发公告否认 67GHz 概念;万科那期:涨停当天公司公告称经营无重大变化)。
Step 1 · 起工程骨架
python scripts/new_episode.py --slug wanke --code 000002.SZ --name 万科A --theme blue自动创建 output/<slug>-video/ 并落好 narration.py index.html record.py quickcheck.py shots.py mix.py,路径与输出名全部替换完毕。
Step 2 · 采集数据(westock-data,禁止网页搜索)
这一步以前漏写了,导致每期都要重新摸索取数路径。 内置技能入口:
NODE="C:/Program Files/nodejs/node.exe"
WS="C:/Program Files/WorkBuddy/resources/app.asar.unpacked/resources/builtin-skills/westock-data/scripts/index.js"
"$NODE" "$WS" quote sz000002八幕需要什么、用什么命令取:
| 幕 | 要什么 | 命令 |
|---|---|---|
| 1 封面 | 现价/涨跌/振幅/量比/成交额/52周区间 | quote <code> |
| 2 档案 | 全称/上市日期/地域/企业性质/主营 | profile <code> |
| 2 档案 | 股东户数、前十大股东 | shareholder <code> |
| 3 反转 | 近 30 日走势、异动日期 | kline <code> --period day --limit 30 |
| 3 反转 | 事件标签 | events tags <code> |
| 3 反转 | 异动/风险公告原文(最出钩子的地方) | notice list <code> --type 0 --limit 20 → notice detail <公告ID> |
| 4 业务 | 分行业/分产品收入构成、毛利率 | 半年报 PDF(见下方兜底) |
| 5 财务 | 营收/归母/扣非多期 | finance <code> --type lrb --num 6 |
| 5 财务 | 资产负债率、货币资金、有息负债 | finance <code> --type zcfz --num 2 |
| 6 事件 | 关联交易、担保、借款进展 | notice list + notice detail |
| 7 估值 | 一致预期、目标价、评级 | consensus <code>、score <code> |
| — | 背景新闻 | news article <code> --limit 20 |
公告正文拿不到时的 PDF 兜底(高频坑):notice detail 对半年报、长公告经常返回空或截断。直接下 PDF:
http://file.finance.qq.com/finance/hs/pdf/<YYYY>/<MM>/<DD>/<公告ID数字>.PDF
# 公告 ID 形如 nos1225521951 → 取数字部分 1225521951,日期用公告披露日from pypdf import PdfReader
r = PdfReader('h1.pdf')
for i, pg in enumerate(r.pages[:60]):
t = pg.extract_text() or ''
if '营业收入构成' in t or '分行业' in t or '毛利率' in t:
print('命中页', i + 1)取数纪律:
- 每个上画面的数字都要能指到「哪份公告 / 哪个日期」,脚注写清。
- 同一指标两个来源打架时(毛利率、持股、市净率常发生),画面只用一个口径,脚注写来源+日期。
- 亏损股/周期底部股不要写 PE。用 PB、PS、每股净资产 vs 现价、EV/EBITDA。万科那期 PE 无意义,改用 PB 0.50 倍 + 每股净资产 8.56 元 vs 现价 4.31 元,更有说服力。
Step 3 · 写旁白(narration.py)
- 必须 8 条,与 8 个分镜一一对应。脚本启动时会拿
index.html里.scene的数量做硬断言,条数不对直接退出并提示。 - 禁止用相邻字符串隐式拼接写多句。那是 C 风格写法,Python 会把相邻字面量自动合并——漏一个逗号就变 9 条,声音和画面整体错位,而录制前完全看不出来。一幕想说多句就写成一个长字符串用「。」连接。
- 长度硬指标:汉字总量 560–620 字 ≈ 148–163 秒(实测基准 3.8 汉字/秒,
zh-CN-XiaoxiaoNeural@-8%)。脚本会在生成前先打印字数和预估时长,先自砍一轮再合成,别等录完才发现超。 - 数字一律写中文读法:「110.89 元」→「一百一十点八九元」;单位写「吉赫兹」「百分之」「倍」,不要写 GHz / %。
- 每段只讲一件事,句子短,避免从句套从句,TTS 断句才自然。
- 跑一次拿到真实时长:
python narration.py→ 输出TOTAL: xxx s。
音频目录不用手改。脚本按 LINES 内容 hash 自动选目录(文案没变就复用
audio,改了就新建audio2/audio3),并把当前目录写进_audio_dir.json,mix.py自动读取 —— 沙箱不让删旧文件,所以重录=换目录,这件事以前要手改两个文件,现在全自动。
Step 4 · 做画面(index.html)
八幕标准结构,可增删但建议保持:
| # | 幕 | 内容要点 |
|---|---|---|
| 1 | 封面 | 公司名 + 一句话钩子(最有反差的那个事实) |
| 2 | 档案 | 全称/市值/企业性质/实控人/员工/主营,六卡网格 |
| 3 | 核心反转 | 本期最大矛盾点(错配、折价、溢价…) |
| 4 | 业务 | 收入结构条形图 + 增长引擎 |
| 5 | 财务 | 柱状图 + 含金量指标 + 单季反转对照 |
| 6 | 事件/资本运作 | 并购、定增、大股东借款/担保、债务展期;写清金额、条件、对报表的影响 |
| 7 | 估值与风险 | 4 条风险 + 一致预期(亏损股用 PB/PS,不写 PE) |
| 8 | 三句话总结 | 结论 + 免责声明 |
第 6 幕不限于并购。万科那期就是「大股东输血 + 债务化险」,比硬套并购模板贴切得多。
排版红线:
- 字号下限 21px;画面四周留 76px 安全边距,底部 150px 让给品牌条。
- 每幕元素总高度控制在 1920−150 以内,底部不要留大片空白(补一张信息卡填满)—— 这是截图复查时最高频的问题。
- 长句别挤在一行:超过约 40 字就主动断行,或拆成两行不同字号。
- 动画延时用
--d:变量递增 0.06–0.1s,形成瀑布式入场。 - 数字要有「滚动」效果:
data-count="110.89" data-suffix=" 元"(脚本自带 countUp)。
Step 5 · 定时间轴(一键回填,别手改)
python mix.py # 算时间轴 + 合成 voice.wav
python <skill>/scripts/sync_timeline.py --dir . # 自动回填 4 个文件 5 处要回填的 5 处(以前手改,漏一处就是「画面切了声音没切」,录完 3.5 分钟才发现):
| 文件 | 字段 |
|---|---|
index.html | var DURS = [...] |
record.py | DURATION_MS = sum(DURS)+800 |
quickcheck.py | DURS = [...]、TARGETS = 起点+800 |
shots.py | TARGETS = 起点+2600 |
sync_timeline.py 会同时校验「音频段数 == 画面 .scene 数」,不一致直接拒绝回填。此时 silent.mp4 还没生成,mix.py 会跳过合并并提示,属正常。
Step 6 · 校验(别跳过)
python quickcheck.py # ~2.5min,打印每幕是否按时切换到 active
python shots.py # 同样 ~2.5min,但会在 frames/ 落 8 张关键帧,肉眼查版式两个可并行跑。shots.py 是这一版新增的 —— 光看 active 序号只能证明时间轴对,看截图才能发现「底部空一半」「柱高塌了」。
跑完必须逐张 Read frames/s1..s8.png。只看日志不算校验完。
Step 7 · 录制与合成
python record.py # ~3.5min,生成 silent.mp4
python mix.py # 二次运行:合成音轨 + 与视频合并 → <slug>_<code>_daily_vo.mp4验证:
ffmpeg -i out.mp4 -af volumedetect -f null - 2>&1 | grep -E "mean_volume|max_volume"
ffmpeg -y -ss 17 -i out.mp4 -frames:v 1 check.png # 抽查帧合格区间:mean ≈ −22 dB、max ≈ −5 dB,视频流 H.264 + yuv420p + 30fps,音频 AAC 48kHz 立体声。
四、配色轮换
每期换主色,避免视觉疲劳。new_episode.py --theme 已内置 5 套:
| theme | 主色 | 背景 | 已用 |
|---|---|---|---|
cyan | #9fe4f2 | #0b1620 | 华天科技 |
violet | #a78bfa | #120c22 | 普源精电 |
gold | #f0b45e | #1a1206 | 优利德 |
blue | #4f8ff7 | #0a1430 | 万科A |
green | #4fd1a5 | #0a1a14 | — |
涨跌色遵循 A 股惯例:涨红 #ff6b6b、跌绿 #2ecc9b(全主题统一,不用改)。
五、踩过的坑(照着躲)
- 无头渲染不支持渐变文字:
background-clip:text+ 渐变在无头截图里变纯黑。全部改实色。 - 负利润/负值柱 collapse:百分比高度不能为负,先做基准平移再算百分比。
- **沙箱禁
rm/unlink**(FAIL_CLOSED)**:想重录音频就换目录名。现在narration.py按文案 hash 自动选(audio→audio2→audio3`),别手改。 - bash 里替换长 Windows 路径会被静默吞掉反斜杠:批量改文件里的路径一律用 Python 内联脚本,别用 sed。
- Write 之后再 Edit 会报 "File has been modified since read":中间用脚本改过文件就得先 Read,或直接继续用 Python 替换。
- 单位混用:写稿时用「亿美元」查、写成「416 亿人民币」就会翻车。所有跨境数据当场折算并复核一遍。
- 多口径冲突必须标注:同一标的的不同来源持股/毛利率/市净率常打架(如 Unisem 持股 44% vs 58.94%)。画面只用一个口径,脚注写清来源与日期。
- 隐式拼接导致段数错位(本期新增):
LINES里两个相邻字符串会被 Python 合并,逗号写漏就少一段。一幕一句长字符串,脚本有断言兜底。 notice detail返回空:半年报和长公告经常取不到正文,直接下 PDF 用 pypdf 解析(见 Step 2 兜底方案)。- 亏损股写 PE 会闹笑话:PE 为负或几百倍时改用 PB / 每股净资产 / PS。
- 底部大片空白:每幕内容高度不足时补一张信息卡或再加一行注解,别让画面下半截空着。
- 画布(Ardot)不可用时不要硬等:
fetch_file_info返回NO_ADAPTER就重试 3 次、仍失败则停止设计路径,改走本流水线交付,并在回复里说明。本流水线不依赖任何画布工具。
六、选题死磕点
同一套模板,成片质量高低取决于这三点:
- 钩子要具体到反常识。「业绩增长」不算钩子;「涨停当晚,公司自己发公告泼冷水」才算。
- 要有对照组。拿本期公司与同系列前几家横向比(扣非占比、PB、季度增速),数字才有锚。
- 免责声明必写。每期结尾固定:「仅为公开信息整理,不构成投资建议」。
交付清单
每期结束后必须给出:
- 成品 MP4 路径、时长、体积、分辨率码率
- 八幕一句话脚本(用户改稿最快)
- 校验结果(8 幕 active 通过 + 音量数值)
- 已执行
--mark-done回写references/episode-log.json(避免下期重复选题)
附:脚本一览
| 脚本 | 作用 |
|---|---|
scripts/check_env.py [--fix] | 环境自检 + 自动补 Playwright 的 ffmpeg |
scripts/pick_hot_topic.py [--json|--pick|--mark-done] | 当日十大热门股选题 / 回写往期 |
scripts/new_episode.py | 生成一期工程骨架(含主题配色) |
scripts/sync_timeline.py --dir <工程目录> | 时间轴一键回填 4 文件 5 处 |