deckflow-lite 的 C1「拆包器」:把异构输入拆成统一的 Parse Bundle——parse-manifest.json(统一 JSON 信封)+ document.md(五类元素的 markdown 形态)+ assets/(哈希命名的二进制资产)。只拆包,不改写、不裁剪、不解读。
本文档即完整的使用说明。合约与分层设计的内部文档不随仓库发布。
pipx install deckflow-extract约 4MB,全部是纯 Python wheel,装完即可解析全部受支持格式。 没有二进制依赖,因此跨平台体积恒定、可离线安装、Python 新版本发布当天就能用。
重引擎按需获取,不必在安装时决定:
deckflow-extract install --list # 可安装能力、体积、当前状态
deckflow-extract install pdf # 56MB:PDF 表格识别与完整图片提取
deckflow-extract install pptx # 37MB:PPTX shape/bbox 级定位
deckflow-extract install web # 21MB:网页正文抽取质量
deckflow-extract install ocr # 107MB:本地 OCR(必须显式指定)
deckflow-extract install cloud # 3MB:云端解析所需的 deckops SDK
deckflow-extract uninstall pdf # 卸载即删目录引擎装进独立的 sidecar 目录(默认 ~/.deckflow/parse/engines/<能力>/<python 标签>),不污染主环境。传统装法完全保留,Docker / CI / 内网离线可以一次装齐:
pipx install "deckflow-extract[local]" # = [pdf,pptx,web]本工具永不隐式安装任何东西:默认只给建议,只有显式 deckflow-extract install 或 --upgrade auto 才会真的下载。
仓库内直接运行(开发模式):
PYTHONPATH=src python3 -m deckflow_extract probe层 = 用户为这个引擎付出的代价,与产出质量无关(质量单独记在 manifest 的 fidelity 里):
| 层 | 代价 | 例子 |
|---|---|---|
| L0 内置 | 0 | pypdf、mammoth、openpyxl、xlrd、stdlib OOXML/ODF/EPUB/iWork 读取器 |
| L1 宿主 | 0,但不保证存在 | Keynote.app(osascript 导出)、LibreOffice、textutil、sips、tesseract |
| L2 按需 | 磁盘 + 一次下载 | pymupdf4llm、python-pptx、readability-lxml |
| L3 云端 | SDK(3MB)+ API key + 上传 + 配额 | deckops SDK 驱动的任务 API |
L0 是地板:任何机器、任何受支持格式都能产出一个合规的 Parse Bundle,或一条结构化的补救建议。没有 L1/L2/L3 也能跑完整条 deckflow-lite 流程。
路由不是「层越低越优先」:可用的引擎意味着代价已付清,所以在可用引擎里选保真度最高的;云端因为按次计费,默认永远排最后。
deckflow-extract formats # 完整能力表(每格式的引擎阶梯与当前状态)
deckflow-extract formats --extensions # 扁平扩展名列表,供 glob 使用
deckflow-extract formats --available # 只列当前机器上可用的文档 pdf docx doc rtf odt epub pages md txt、演示 pptx ppt key odp、表格 xlsx xls csv ods numbers、网页 url html、图片 image svg heic、结构化文本 json yaml。
音视频与压缩包明确不支持,但会被识别并返回 unsupported-format,不会退化成 unknown-input-type。
# 环境探测:格式能力表 + 宿主工具 + 已安装引擎 + 云端配置
deckflow-extract probe
# 解析一个输入 → Parse Bundle 目录(stdout 恰好一行 JSON)
deckflow-extract parse ./report.pdf --out ./report.parse
deckflow-extract parse ./book.xlsx --out ./book.parse
deckflow-extract parse ./deck.key --out ./keynote.parse
deckflow-extract parse https://example.com/post --out ./post.parse
deckflow-extract parse ./notes.md --out ./notes.parse --archive zip
# 云端模式(上传并计入配额)
deckflow-extract install cloud # 一次性:装 3MB 的 deckops SDK
deckflow-extract auth login # 浏览器登录;凭据与 deckhtml 共用
deckflow-extract parse ./deck.pptx --out ./deck.parse --mode cloud云端覆盖 pdf / pptx / docx / key / url 五类输入——这是服务端解析器实际支持的集合;其余格式没有云端路径,--mode cloud 会返回 no-cloud-path 并提示改走本地。
两个工具连的是同一个 Deckflow API,用的是同一套凭据,所以读写同一个文件:~/.deckflow/credentials。
装了 deckhtml 并登录过,这里不需要再配置一次;反过来也一样,在这里登录,deckhtml 立刻可用。
deckflow-extract auth login # 浏览器登录,存下 token
deckflow-extract auth status # 当前用的是哪个凭据、来自哪里
deckflow-extract auth logout # 清掉存下的 token / api key
printf '%s\n' "$DECKFLOW_API_KEY" | \
deckflow-extract config set api-key --stdin # 推荐:secret 不进入进程参数
deckflow-extract config set api-key <key> # 兼容写法
deckflow-extract config set space-id <id> # 可选;不设则首次调用时向服务端查询
deckflow-extract config show # 已脱敏命令名与键名刻意和 deckhtml auth login / deckhtml config set api-key 一致——同一个文件,不该有两套词汇。
| 形态 | 来自 | 请求头 | 会过期 |
|---|---|---|---|
token |
浏览器登录(auth login) |
X-Auth-Token |
会 |
apiKey |
空间的 worker secret(config set api-key) |
Authorization: Bearer |
不会 |
任意一种存在即视为已配置。只认 apiKey 是 0.2.x 的 bug:浏览器登录过的用户明明有可用凭据,却被告知未配置。
在终端里(stdin 与 stderr 都是 TTY)用 token 跑云端解析,遇到 401 会像 deckhtml 一样重新打开登录页,拿到新 token 后自动重试。
在非交互环境(agent 子进程、CI)不会——直接返回 unauthorized,hint 里写明跑 deckflow-extract auth login。中途弹浏览器再阻塞五分钟等一个没人会完成的回调,比一个干净的错误糟得多。这和 --upgrade ask 在无 TTY 时退化成 never 是同一条规则。
配了 apiKey 时也不会自动重登:worker secret 不能靠登录续期,而在用户显式配置的 key 旁边悄悄存一个 token,会让下一次解析换一个身份跑——那不是刷新,是替换。
- 环境变量:
DECKFLOW_API_KEY/DECKFLOW_TOKEN/DECKFLOW_SPACE_ID/DECKFLOW_API_BASE(DECKOPS_*同义) - 共用文件
~/.deckflow/credentials - 都没有 → 未配置,云端引擎不进路由
环境变量永远压过文件。 想要一次「保证不出网」的运行,光把变量摘掉已经不够了——还要设 DECKFLOW_NO_STORED_CREDENTIALS=1,否则存下的凭据会把刚摘掉的东西又补回来。deckflow-core 的 parse 已经这么做。
文件位置可以用 DECKFLOW_CONFIG_DIR(或 deckhtml 的 DECKHTML_CONFIG_DIR)改写,两个工具都认。
DeckHTML 的 sanitizeConfig 只保留它自己那 6 个键,遇到别的会重写文件。所以这里只写它认识的键(apiKey / token / spaceId / apiBase),并且每次写之前重新读一遍再合并——webhook 和 retentionHours 是它的,不能被我们的一次 config set 抹掉。本工具自己的状态放在 DECKFLOW_EXTRACT_HOME 下,不进这个文件。
常用参数:--mode auto|local|cloud、--upgrade never|ask|auto(默认 ask,环境变量 DECKFLOW_UPGRADE 等价)、--prefer local|cloud、--max-pages、--max-table-rows、--ocr auto、--strict。
每次 parse 的 stdout 与 parse-manifest.json 都带同一份评估结果:
| 字段 | 含义 |
|---|---|
tier / fidelity |
用了哪一层、拿到的质量向量(text / structure / tables / images / notes / provenance) |
gaps[] |
源文件里有但这次没提出来的东西,含 detected/extracted 与 confidence(exact 来自容器枚举,heuristic 来自文本推断) |
decision |
usable + recommended(accept / install / host / cloud / input)+ reason |
recommendations[] |
每个选项的 capability、收益、代价与是否需要重跑;不可用的选项也会列出并给出 blocked_by,但不内嵌调用方命令 |
engine_acquisition |
显式 --upgrade auto 的安装、自检与最终选中引擎结果;失败但 fallback 可用时状态为 repairable |
两条不变量:usable 为真时一定有一条 accept(用户永远可以「就用现在的结果」),没有任何一层能修复的缺口不会产生建议(比如图表内的数据系列,只写 diagnostic)。
skill 侧的读法:status == "parsed" 且 recommended == "accept" 就静默继续;recommended 是其他值时把 priority: high 的选项连同 accept 一起呈现给用户;needs-input 才必须问。
状态机与 deckflow-lite 一致:parsed / repairable / needs-input / blocked,默认退出码恒为 0(读 JSON 判断),--strict 时非 parsed 即非零。缺依赖不再是阻塞态——除非 L0 确实产不出内容,否则永远先出 Bundle 再给建议。
cd deckflow-extract/tests && python3 -m unittest discover包含体积闸(base 依赖闭包必须是纯 Python 且 ≤10MB)、L0 地板测试、探测精度测试(标为 exact 的计数必须与真值完全相等)与决策矩阵测试。未安装的重引擎测试会跳过。