首页
/ graphify 视频与音频转录指南:把音视频内容转成可查询的知识图谱文档

graphify 视频与音频转录指南:把音视频内容转成可查询的知识图谱文档

2026-09-06 19:24:40作者:裘旻烁

本篇技术指南围绕 graphify 流水线中的 Step 2.5 展开,讲解当语料库中检测到视频/音频文件时,如何将其先转录为纯文本、再作为文档送入图谱构建流程。读完本文你将掌握 graphify 的“零额外 API 调用”转录策略、GRAPHIFY_WHISPER_PROMPT / GRAPHIFY_WHISPER_MODEL 两个环境变量的正确用法,以及底层 transcribe.py 的实现原理与缓存机制。

为什么视频必须先转录

graphify 的目标是把任意语料(代码、文档、SQL schema、配置、PDF)变成可查询的知识图谱,但视频(.mp4.mov)和纯音频(.mp3.wav无法被直接读取为文本。detect 阶段只负责把它们归类并统计数量,语义与关系抽取阶段处理不了原始媒体流。因此流水线设计了 Step 2.5:先把音视频转成 transcript(转录文本),再把转录结果当作 doc 文件,交给后续 Step 3 的结构化/语义抽取。

整个决策路径在 detect.py 中可见:当扩展名命中 VIDEO_EXTENSIONS 集合时,文件被归类为 FileType.VIDEOdetect.py),随后在技能流程里触发 Step 2.5。graphify-out/.graphify_detect.json 会给出类似下面的汇总:

Corpus: X files · ~Y words
  video:    N files (.mp4 .mp3 ...)

需要强调的触发条件有两个:

  1. 仅当 detect 返回的 video 文件数大于 0 时,才执行 Step 2.5;返回 0 则整段跳过;
  2. 若语料只有视频、没有其他任何文档或代码,则不能从语料中获取领域信息,直接使用通用兜底提示词:"Use proper punctuation and paragraph breaks."

核心策略:用一句领域提示词提升 Whisper 转录质量

转录质量的关键不在于调大模型,而在于给 Whisper 一个贴合语料领域的上下文提示(initial prompt)。graphify 的巧妙之处在于:宿主 Agent 本身就是语言模型,不必再发起一次独立的外部 LLM API 调用——直接从已有产出中现学现用。

具体做法是读取 graphify-out/.graphify_detect.json(若存在历史 analysis 文件则读 analysis),取出 god node(顶层主题节点)标签,由 Agent 自己写成一句领域提示句。原文档给出了两个典型例子:

  • 标签为 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.,这是 Whisper 输出带规范标点和段落的重要引导,也是语料无标签时的兜底文本。

这一策略在源码里同时存在自动与手动两条路径。若没有人显式指定,transcribe.py 中的 build_whisper_prompt(god_nodes) 会自动从最多 10 个 god node 中取前 5 个标签拼出提示句 "Technical discussion about <topics>. Use proper punctuation and paragraph breaks.";但只要设置了环境变量 GRAPHIFY_WHISPER_PROMPT,它就会被当作最高优先级覆盖(对应测试见 tests/test_transcribe.py)。

Step 1:编写并导出 Whisper 提示词

动手写提示词时按如下步骤:

  1. 静默读取 detect 输出或 analysis 中的 god node 标签(不要打印原始 JSON);
  2. 根据标签组成一句简短的领域提示(如上文两个例子);
  3. 若语料里只有视频,改用通用兜底提示词。

然后把它导出为环境变量 GRAPHIFY_WHISPER_PROMPT(环境变量在启动时需要明确 export),因为后续转录命令在子 Python 进程中执行,只有导出的变量才能被子进程继承。这也是使用中最高频的踩坑点:仅 GRAPHIFY_WHISPER_PROMPT="..." 赋值而不 export,子进程将读不到,退回到源码中的兜底 prompt。

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):graphify 把流水线专用的 Python 解释器路径提前写入该文件,用命令替换的方式调用,保证用的是安装好 graphify 及其可选依赖的那套 Python,而不是 python3 默认指向的任意解释器。
  • 读取 detect 结果detect.get('files', {}).get('video', []) 取出全部视频/音频文件路径。
  • 从环境变量取提示词os.environ.get('GRAPHIFY_WHISPER_PROMPT', 'Use proper punctuation and paragraph breaks.') 与源码中的 _FALLBACK_PROMPT 常量完全一致。
  • 必须用 Python 写 JSON,不能用 shell 重定向(如 > .graphify_transcripts.json):因为 transcribe_all / Whisper 会把进度信息打印到 stdout,一旦用 shell > 重定向就会把进度文本混入 JSON 造成文件损坏(这正是 issue #1392 的教训)。正确做法是把进度打到 stderr(上面的 print(..., file=sys.stderr)),JSON 则由 Python 侧 write_text 落盘。
  • JSON 写入使用 ensure_ascii=False,保留非 ASCII 字符(如中文、日文转录结果)的原始形态,方便下游抽取。

转录完成之后的收尾动作,原文档明确规定了三点:

  • graphify-out/.graphify_transcripts.json 读回转录文件路径;
  • 在 Step 3B 派发语义子代理之前,把这些 transcript 追加进 docs 文件清单;
  • 打印汇总行:Transcribed N video file(s) -> treating as docs
  • 若某个文件转录失败,打印警告并继续处理其余文件,不要中断整批任务。

底层实现:transcribe.py 如何工作

把命令交给 graphify.transcribe 后,内部逻辑(graphify/transcribe.py)决定了行为细节:

依赖与安装前置。 转录基于 faster-whisperfrom faster_whisper import WhisperModel);若未安装会抛出明确提示:pip install 'graphifyy[video]'transcribe.py)。从源码结构看,[video] 为可选的 extra 依赖,也就是说视频转录不是默认安装项,需要用户显式安装才能使用。

支持的媒体类型。 VIDEO_EXTENSIONS = {'.mp4', '.mov', '.webm', '.mkv', '.avi', '.m4v', '.mp3', '.wav', '.m4a', '.ogg'}transcribe.py),与 detect.py 中用于识别 video 文件的扩展名集合保持一致。

URL 支持。 URL_PREFIXES = ('http://', 'https://', 'www.')is_url() 会判断传入的是本地文件还是网络地址(transcribe.py)。对 URL(典型如 YouTube 链接),download_audio()yt-dlp 只下载音频流(format: bestaudio),文件名基于 URL 的 SHA-1 前 12 位哈希生成稳定名(yt_<hash>.<ext>),已下载过的音频会命中缓存直接复用(transcribe.py)。值得注意的是下载前会先调用 graphify.security.validate_url 校验 URL,用于拦截私有 IP、非法 scheme,再进行下载。graphify/ingest.py 中的 URL 摄入(url_type == "youtube")同样复用了 download_audio(见 ingest.py),说明 URL 下载是跨入口共用的能力。

转录参数与运行环境。 核心调用在 transcribe()transcribe.py):

  • 模型名从环境变量读取:_model_name() 返回 GRAPHIFY_WHISPER_MODEL,缺省为 "base"transcribe.py);
  • 使用 device="cpu", compute_type="int8",即默认纯 CPU + int8 量化推理,无需 GPU;
  • beam_size=5(beam search 宽度)用于提升解码质量;
  • 每行文本 strip() 后过滤空行,按行合并写入 .txt 转录文件;
  • 转录完成后打印语言、片段数等信息:transcript saved -> <path> (lang=<lang>, N segments)

缓存与强制重转。 transcript 目标路径是 <输出目录>/<文件名>.txt;若同名转录文件已存在且未传 force=Truetranscribe() 直接返回缓存路径,不再调用 Whisper(对应测试 tests/test_transcribe.py);force=True 则强制重新转录(tests/test_transcribe.py)。转录输出目录默认来自 graphify.paths.out_path("transcripts"),即 graphify 输出目录下的 transcripts/ 子目录。

批处理与容错。 transcribe_all() 顺序遍历整个文件列表:每个文件单独 try/except,某个文件失败只打印 warning: could not transcribe <vf>: <exc>,其余文件继续执行;空列表直接返回 []transcribe.py)。这从代码层面印证了原文档“失败则警告并继续”的行为约定。

Whisper 模型如何选择

原文档明确:Whisper 模型默认是 base。用户可以在初始命令中传入 --whisper-model <name>(例如在技能层的命令示例如 /graphify <path> --whisper-model medium,对应 skill-amp.md 的注释“use a larger Whisper model for better transcription accuracy”)。

当用户传入了自定义模型名,执行转录前必须:

export GRAPHIFY_WHISPER_MODEL=<name>   # must be exported, not just assigned

同样强调“必须 export 而非仅赋值”,因为转录代码在子 Python 进程中通过 os.environ.get("GRAPHIFY_WHISPER_MODEL", "base") 读取(transcribe.py)。

选型权衡可以这样把握:base 体积小、速度快,适合大多数演示与一般性内容;面对口音重、术语密集或低音质录音,可以升级到 mediumlarge 等更重模型换取准确率,代价是更长的 CPU 推理时间。graphify 采用纯本地 CPU 推理,不依赖外部语音 API,这也符合其“本地确定性解析、无需密钥”的整体设计取向。

对上游流程的衔接与约束

  • 触发与跳过是硬性规则:完整技能流程(见 skill-amp.md)在 Step 2.5 处明确引用本转录参考文档,并规定零视频文件时整段跳过;Step 2 汇总里视频类别也只在文件数非 0 时列出。
  • 转录产物进入文档通道:transcript 是 .txt 纯文本,会被当作 doc 文件参与 Step 3 的抽取(结构化与语义两条路径),进而贡献节点、边与 god node。换句话说,一个内含视频的语料最终仍会汇成同一张可查询知识图谱,而不是被排除在外。
  • 输出目录约定:流水线把中间产物写入 graphify-out/ 目录(.graphify_detect.json.graphify_python.graphify_transcripts.json 等),转录文本默认落在输出目录的 transcripts/ 子目录下。

小结:可落地的执行清单

把上述要点收敛为一份可直接照做的清单:

  1. detect 报告视频数 > 0 才进入 Step 2.5,否则跳过;
  2. 从 detect/analysis 的 god node 标签自拟一句领域提示(含 Use proper punctuation and paragraph breaks. 后缀);纯视频语料用通用兜底句;
  3. export GRAPHIFY_WHISPER_PROMPT="<提示句>",需要换模型时再 export GRAPHIFY_WHISPER_MODEL=<name>(默认 base);
  4. $(cat graphify-out/.graphify_python) 运行转录脚本,进度打到 stderr,JSON 由 Python 写盘,禁止 shell > 重定向;
  5. .graphify_transcripts.json 中的转录路径并入 docs 列表,交给 Step 3 抽取;
  6. 单文件失败仅告警不中断,批处理自动继续(transcribe_all 内建逐文件容错)。

这套流程让含音视频的语料与纯文本语料最终收敛到同一套“转文本 → 入图 → 可查询”的管线中,整个过程保持本地执行、无独立语音 API 调用。

登录后查看全文
热门项目推荐
相关项目推荐