graphify 的视频转写机制:Whisper 集成、God-Node 领域提示与 Step 2.5 流水线
【免费下载链接】graphifyTurn any codebase, with its docs, SQL schemas, configs, and PDFs, into a queryable knowledge graph. A /graphify skill for Claude Code, Cursor, Codex, and Gemini CLI: local deterministic AST parsing, every edge explained, no vector store.项目地址: https://gitcode.com/GitHub_Trending/graph/graphify
本文以 Claude 技能参考文档 transcribe.md 为核心,完整拆解 graphify 把视频/音频语料纳入知识图谱的 Step 2.5 环节:从detect检测到video文件,到由 god node 标签生成 Whisper 领域提示(domain hint),再到执行本地 faster-whisper 转写、产出.txt文稿并回流到文档抽取流程的全过程。读完你可以掌握两个环境变量的正确用法(export而非赋值)、避免 JSON 输出被 stdout 进度污染的经典陷阱(#1392),并能对照 graphify/transcribe.py 源码理解缓存、URL 下载与容错机制的实现细节。
Step 2.5 在流水线中的定位:仅在检测到视频时触发
graphify 的构建流水线中,转写是一个"按需加载"的分支步骤。技能主文档 graphify/skill.md 明确规定:
Skip this step entirely if
detectreturned zerovideofiles. When the corpus has video or audio, seereferences/transcribe.mdto transcribe them to text first, then treat the transcripts as doc files in Step 3.
也就是说,语料库里没有任何视频文件时,Agent 根本不会读取 transcribe 参考文档——这是原文档开宗明义的第一句约束。它的触发链是:
- Step 2 的
detect按扩展名把语料分类,视频/音频文件归入video桶(判定表见 graphify/detect.py 中的VIDEO_EXTENSIONS:.mp4 .mov .webm .mkv .avi .m4v .mp3 .wav .m4a .ogg,与 graphify/transcribe.py#L11 中的集合保持一致),结果写入graphify-out/.graphify_detect.json; - 若
video列表非空,进入 Step 2.5:先把视频转成文本,再在 Step 3 中把文稿当作普通文档参与语义抽取; - 同一份参考文档也被复制到其他平台技能目录下(如 graphify/skills/codex/references/transcribe.md),各平台技能的行为是等价的。
领域提示(domain hint):让 god nodes 免费指导 Whisper 的 initial_prompt
参考文档给出的核心策略是:不额外调用任何 API。你自己(编码 Agent)本来就是一个语言模型,直接读取 god node 标签,亲手写一句领域提示,再把它作为 Whisper 的initial_prompt传入即可。
数据来源。god node 标签来自graphify-out/.graphify_detect.json(首次运行)或上一次运行留下的分析文件。god nodes 本身由 graphify/analyze.py#L109-L130 的god_nodes(G, top_n=10)计算:按度(degree)降序取前 10 个真实实体,并排除文件级 hub 节点、概念节点与 JSON 键噪声节点——这些是语料库中"连接最多的核心抽象",天然适合作为话题锚点。
提示的写法。原文档给出两个示范:
- 标签为
transformer, attention, encoder, decoder→"Machine learning research on transformer architectures and attention mechanisms. Use proper punctuation and paragraph breaks." - 标签为
kubernetes, deployment, pod, helm→"DevOps discussion about Kubernetes deployments and Helm charts. Use proper punctuation and paragraph breaks."
兜底规则。如果语料库只有视频文件、没有任何其他文档或代码可供推断领域,直接使用通用兜底提示:
"Use proper punctuation and paragraph breaks."这个字符串在源码中就是_FALLBACK_PROMPT常量(graphify/transcribe.py#L16),保证文档与实现一致。
环境变量传递与源码印证。提示必须命名为GRAPHIFY_WHISPER_PROMPT并且必须export(不是 shell 里的普通变量赋值),因为转写是在一个子 Python 进程中运行的,只有导出的环境变量才对子进程可见。这一点在源码里有双重印证:
- graphify/transcribe.py#L95-L115 的
build_whisper_prompt()会优先检查os.environ.get("GRAPHIFY_WHISPER_PROMPT"),一旦存在就短路掉基于 god node 的自动拼装;测试用例test_build_whisper_prompt_env_override(见 tests/test_transcribe.py#L40-L44)专门验证了这个短路行为; - 未设置时,
build_whisper_prompt()会取前 10 个 god node 标签中的前 5 个拼成"Technical discussion about {topics}. Use proper punctuation and paragraph breaks."作为次级默认。
执行转写:参考文档给出的完整命令
原文档 Step 2 的完整可复制命令如下,建议原样保留使用:
export GRAPHIFY_WHISPER_MODEL=base # or whatever --whisper-model the user passed (must be exported) export GRAPHIFY_WHISPER_PROMPT="<the one-sentence domain hint you composed in Step 1>" $(cat graphify-out/.graphify_python) -c " import json, os, sys from pathlib import Path from graphify.transcribe import transcribe_all detect = json.loads(Path('graphify-out/.graphify_detect.json').read_text(encoding=\"utf-8\")) video_files = detect.get('files', {}).get('video', []) prompt = os.environ.get('GRAPHIFY_WHISPER_PROMPT', 'Use proper punctuation and paragraph breaks.') transcript_paths = transcribe_all(video_files, initial_prompt=prompt) # Write the JSON from Python (NOT a shell '>' redirect): transcribe_all/Whisper # print progress to stdout, which would otherwise corrupt the JSON file (#1392). Path('graphify-out/.graphify_transcripts.json').write_text(json.dumps(transcript_paths, ensure_ascii=False), encoding=\"utf-8\") print(f'Transcribed {len(transcript_paths)} file(s)', file=sys.stderr) "命令中每个细节都有出处,逐条说明:
| 要素 | 作用 | 源码/文档依据 |
|---|---|---|
$(cat graphify-out/.graphify_python) | 使用 Step 1 解析出的、真正装有 graphify 依赖的解释器路径,而不是假设的python3 | graphify/skill-agents.md#L98 写入该文件 |
detect.get('files', {}).get('video', []) | 从 detect 输出中取出视频文件列表 | graphify-out/.graphify_detect.json结构 |
GRAPHIFY_WHISPER_PROMPT | 子进程读取的领域提示,缺省时回退到兜底提示 | graphify/transcribe.py#L106 |
GRAPHIFY_WHISPER_MODEL | 选择 Whisper 模型,默认base | graphify/transcribe.py#L14-L20:_model_name()读环境变量,缺省_DEFAULT_MODEL = "base" |
用 Python 写 JSON 而非 shell>重定向 | transcribe_all/Whisper 会向 stdout 打印进度,重定向会把进度混进 JSON 文件导致其损坏 | 文档中标注的 #1392 回归 |
print(..., file=sys.stderr) | 计数信息走 stderr,同样保护 JSON 通道 | 同上 |
模型选择。默认base;如果用户在命令中传了--whisper-model <name>(例如 graphify/skill.md#L21 示范的/graphify <path> --whisper-model medium),则必须export GRAPHIFY_WHISPER_MODEL=<name>后再执行上面的命令——再次强调是export而非赋值。
转写完成后:文稿如何回流到 Step 3
参考文档对"转写之后"的动作有明确约定:
- 从
graphify-out/.graphify_transcripts.json读回所有文稿路径; - 在派发 Step 3B 的语义子 Agent 之前,把这些路径并入文档(docs)清单——从此它们与
.md文档享受同等待遇; - 打印
Transcribed N video file(s) -> treating as docs告知用户数量; - 若某个文件转写失败,打印警告并继续处理其余文件,不让单点失败中断整条流水线。
最后一条容错语义由 graphify/transcribe.py#L166-L186 的transcribe_all()实现:它逐个调用transcribe(),except Exception时打印warning: could not transcribe ...并跳过,最终只返回成功项的路径列表;空输入直接返回[]。对应的测试test_transcribe_all_skips_failed(tests/test_transcribe.py#L136-L147)验证了"失败即跳过、不抛异常"的行为。
深入 transcribe.py:缓存、URL 下载与本地推理参数
参考文档只描述了调用面,而 graphify/transcribe.py 的实现面还有几个值得了解的机制:
输出与缓存。文稿默认写入graphify-out/transcripts/目录(_TRANSCRIPTS_DIR经由 graphify/paths.py#L295-L301 的out_path("transcripts")解析,尊重GRAPHIFY_OUT覆盖)。文件名取音频文件的 stem 加.txt;若该文件已存在且未传force=True,transcribe()直接返回缓存路径,完全不加载 Whisper 模型。测试test_transcribe_uses_cache与test_transcribe_force_reruns分别覆盖了"命中缓存"与force强制重转两条路径。
本地确定性推理。转写使用faster-whisper,固定参数WhisperModel(model_name, device="cpu", compute_type="int8"),转写时beam_size=5并传入initial_prompt(graphify/transcribe.py#L150-L155)。从源码结构看,这是一个纯 CPU + int8 量化配置——与 graphify "本地、无向量库、确定性"的整体立场一致,不需要 GPU 或云端 ASR 服务。
URL 支持。若输入不是文件路径而是http://、https://、www.开头的 URL,transcribe()会先经download_audio()用 yt-dlp 只拉音频流:以 URL 的 SHA-1 前 12 位生成稳定文件名yt_<hash>.<ext>,命中已有缓存则直接复用;下载前还会调用graphify.security的validate_url()拦截私有 IP 与非法 scheme(graphify/transcribe.py#L50-L92)。
依赖安装。视频能力是可选依赖,在 pyproject.toml 中声明为videoextra:faster-whisper(要求 Python ≥ 3.11)与yt-dlp>=2026.6.9。若未安装,_get_whisper()/_get_yt_dlp()会抛出带安装提示的ImportError:pip install 'graphifyy[video]';test_transcribe_missing_faster_whisper验证了该异常会向上传播而不是静默吞掉。
小结:这条参考文档的工程价值
transcribe.md 篇幅不长,但每一行都是踩过坑的约定:
- 条件加载——没有视频的语料永远不读它,避免无关上下文稀释 Agent 注意力;
- 零额外 API 的领域提示——god node 标签 → 一句话 domain hint → Whisper
initial_prompt,测试test_build_whisper_prompt_returns_topic_string确认了"不发 LLM 请求"的拼装逻辑; - 两个必须
export的环境变量——GRAPHIFY_WHISPER_PROMPT(可选,缺省回退兜底提示)与GRAPHIFY_WHISPER_MODEL(默认base); - JSON 输出走 Python、进度走 stderr——#1392 的教训被固化进了命令注释;
- 失败不阻塞——
transcribe_all的逐文件容错保证单个坏文件不拖垮整个图构建。
想继续深入,可以从 tests/test_transcribe.py 的全部用例出发逐条对照源码,或查看 graphify/skill.md 中 Step 2 → Step 2.5 → Step 3 的完整调度关系。
【免费下载链接】graphifyTurn any codebase, with its docs, SQL schemas, configs, and PDFs, into a queryable knowledge graph. A /graphify skill for Claude Code, Cursor, Codex, and Gemini CLI: local deterministic AST parsing, every edge explained, no vector store.项目地址: https://gitcode.com/GitHub_Trending/graph/graphify
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考