文件猎手 🔍
SLUG:
doc-hunter| 昵称: 文件猎手 | 全称: 路径扫描式多格式文件条件筛选器
概述
用户输入本地电脑的某个目录路径,给出一个自然语言查询条件。AI 自动递归扫描该目录下所有支持格式的文件(图片、PDF、Word、Excel、文本),提取每个文件的文本内容,根据条件筛选出匹配的文件,将匹配的文件本身回复到对话框中(而非仅列出文件名),同时输出筛选结果汇总表。
核心特点:
- 用户只需输入路径 + 条件,无需逐个上传文件
- 支持图片、PDF、Word(.docx)、Excel(.xlsx/.xls)、文本(.txt/.csv/.md/.log) 多种格式
- 匹配的文件通过
present_files直接回复到对话框 - 所有文件在本地处理,不上传外部服务器
触发词
- 文件猎手 / doc-hunter
- 文件筛选 / 条件筛选文件 / 按条件查找文件
- 多格式文件搜索 / 多格式文件查询
- 查找符合条件 / 帮我从这个路径找
- 筛选合同 / 筛选发票 / 筛选文档
- 文件条件过滤 / 批量文件检索
- 哪个文件满足 / 哪些文件符合条件
- 扫描路径 / 扫描目录找文件
环境准备(首次使用前执行一次)
1. 确定 Python 与脚本路径
| 变量 | 说明 | 典型路径(Windows) |
|------|------|---------------------|
| PYTHON | managed venv 的 Python 解释器 | ~/.workbuddy/binaries/python/envs/default/Scripts/python.exe |
| SKILL_DIR | 本技能安装目录 | ~/.workbuddy/skills/multi-format-file-filter |
| BATCH_SCRIPT | 批量扫描脚本 | $SKILL_DIR/scripts/batch_extract.py |
AI 应使用系统提示 "Available Runtimes" 中指定的 managed Python 路径。若路径不同,以系统提示为准。
2. 安装依赖
首次使用前,AI 执行以下命令安装依赖库:
<PYTHON> -m pip install pdfplumber python-docx openpyxl xlrd -q
| 库 | 用途 | |---|------| | pdfplumber | PDF 文本提取 | | python-docx | Word(.docx) 文本提取 | | openpyxl | Excel(.xlsx) 文本提取 | | xlrd | Excel(.xls) 文本提取 |
脚本内置自动安装逻辑:即使忘记预装,运行时检测到缺失也会自动 pip install。
3. 验证
<PYTHON> -c "import pdfplumber, docx, openpyxl, xlrd; print('All dependencies OK')"
消息协议
__DOC_HUNTER__ 消息
当弹窗按钮触发 sendPrompt('__DOC_HUNTER__' + JSON.stringify({path, condition})) 时,AI 收到的消息格式为:
__DOC_HUNTER__{"path":"D:\\contracts","condition":"合同金额大于10000元"}
AI 收到此消息后必须:
- 去掉
__DOC_HUNTER__前缀,解析 JSON - 提取
path(目录路径)和condition(查询条件) - 进入阶段二:扫描目录
直接对话输入
用户也可能直接在对话框中输入路径和条件,例如:
- "扫描 D:\contracts\ 找出合同金额大于10000元的文件"
- "帮我从 C:\Users\admin\Desktop\发票 里面找出发票金额超过5000元的"
AI 应从消息中识别:
- 路径:匹配
[A-Za-z]:[\\\/][^\s]+或/[^\s]+格式的路径 - 条件:路径之外的内容即为查询条件
识别成功后直接进入阶段二。
工作流程
阶段一:收集路径与查询条件
- AI 调用
read_me加载interactive模块。 - AI 调用
show_widget渲染弹窗(参考下方「弹窗参考代码」),包含:- 本地目录路径输入框
- 查询条件输入框
- **「开始扫描 ↗」**按钮(触发
sendPrompt('__DOC_HUNTER__' + JSON.stringify({path, condition})))
- 用户填写路径和条件,点击「开始扫描 ↗」按钮。
- AI 收到
__DOC_HUNTER__消息后,解析出 path 和 condition。
如果用户在触发技能时已给出路径和条件(如"文件猎手,扫描 D:\contracts 找金额大于10000元的"),则跳过弹窗,直接进入阶段二。
阶段二:扫描目录与批量提取文本
-
AI 验证路径是否存在(使用 Bash
ls检查)。- 若路径不存在,告知用户并请其重新输入。
-
AI 运行批量扫描脚本:
<PYTHON> "<SKILL_DIR>/scripts/batch_extract.py" "<用户输入的路径>" --output "output/doc_hunter_text/" -
脚本递归扫描目录,对每个文件:
- PDF / Word / Excel / 文本文件:自动提取文本
- 图片文件:仅记录路径,标记
status: "image_pending"
-
脚本输出 JSON 到 stdout,AI 解析 JSON 获取:
total_found:找到的文件总数summary:各格式文件数量统计files:文件数组,每个元素包含filename、filepath、ext、category、text、status、char_count
-
AI 向用户展示找到的文件清单,确认后继续。
阶段三:图片文字提取
对于 JSON 中 category == "image" 或 status == "image_pending" 的文件:
- AI 使用 Read 工具逐个读取图片文件(Read 工具支持图片,利用 AI 多模态能力提取文字)。
- 每读一张图片,AI 从图片中识别文字内容(如合同金额、发票号码、日期等)。
- 将提取的文字与 JSON 中其他文件的文本汇总,供阶段四使用。
注意: 如果图片数量较多(>10张),AI 应分批处理,每批 3-5 张,避免上下文过大。
阶段四:条件匹配
-
AI 汇总所有文件的文本内容(阶段二提取的 + 阶段三图片识别的)。
-
AI 根据用户的自然语言条件进行匹配判断:
数值比较条件:如"金额大于10000""数量少于5""总价在1000到5000之间" → AI 从文本中提取数值并进行比较。
关键词匹配条件:如"包含违约金条款""甲方为XX公司""签订日期在2024年" → AI 在文本中搜索匹配内容。
复合条件:如"金额大于10000且包含质保条款" → AI 同时满足多个条件。
-
对每个文件,判断是否满足条件,记录:
- 是否匹配(是/否)
- 匹配理由(引用原文中的关键语句,如"合同金额15,000元,大于10,000元")
阶段五:输出结果
-
AI 调用
show_widget渲染筛选结果汇总表(HTML 表格),格式如下:| 序号 | 文件名 | 格式 | 是否匹配 | 匹配理由 | |------|--------|------|---------|---------| | 1 | contract_A.pdf | PDF | ✅ 是 | 合同金额15,000元,大于10,000元 | | 2 | invoice_B.jpg | 图片 | ❌ 否 | 合同金额8,000元,不满足条件 |
-
AI 调用
present_files,将所有匹配的文件的完整路径传入files数组,将匹配文件本身回复到对话框中:present_files({ files: ["D:\\contracts\\contract_A.pdf", "D:\\contracts\\contract_C.docx"], explanation: "以下2个文件满足查询条件:合同金额大于10000元" }) -
如果没有任何文件匹配,明确告知用户"未找到符合条件的文件",并建议调整查询条件或扩大扫描范围。
弹窗参考代码
AI 首次触发技能时,使用 show_widget 渲染以下弹窗(加载 interactive 模块)。弹窗使用 read_me 返回的 CSS 变量适配主题。
<div style="font-family: -apple-system, sans-serif; max-width: 480px; margin: 0 auto; padding: 20px;">
<div style="text-align: center; margin-bottom: 20px;">
<div style="font-size: 36px; margin-bottom: 8px;">🔍</div>
<h2 style="margin: 0 0 4px; font-size: 18px;">文件猎手</h2>
<p style="margin: 0; font-size: 12px; opacity: 0.6;">输入本地路径和查询条件,AI 自动筛选文件</p>
</div>
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 12px; font-weight: 600; margin-bottom: 6px;">📁 本地目录路径</label>
<input type="text" id="dh_path" placeholder="如:D:\\contracts 或 C:\\Users\\admin\\Desktop\\发票"
style="width: 100%; padding: 10px 12px; border: 1px solid rgba(0,0,0,0.15); border-radius: 8px; font-size: 13px; box-sizing: border-box; background: rgba(0,0,0,0.02);" />
</div>
<div style="margin-bottom: 14px;">
<label style="display: block; font-size: 12px; font-weight: 600; margin-bottom: 6px;">🔎 查询条件</label>
<input type="text" id="dh_condition" placeholder="如:合同金额大于10000元"
style="width: 100%; padding: 10px 12px; border: 1px solid rgba(0,0,0,0.15); border-radius: 8px; font-size: 13px; box-sizing: border-box; background: rgba(0,0,0,0.02);" />
</div>
<button onclick="dh_start()"
style="width: 100%; padding: 11px; background: #4f7df3; color: white; border: none; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer;">
开始扫描 ↗
</button>
<div style="margin-top: 12px; padding: 10px; background: rgba(0,0,0,0.03); border-radius: 8px;">
<p style="margin: 0; font-size: 11px; opacity: 0.6; line-height: 1.6;">
📋 支持格式:图片(PNG/JPG/JPEG/GIF/BMP/WEBP)、PDF、Word(.docx)、Excel(.xlsx/.xls)、文本(.txt/.csv)<br/>
⚠️ 不支持旧版 .doc 格式,请先转换为 .docx
</p>
</div>
</div>
<script>
function dh_start() {
var p = document.getElementById('dh_path').value.trim();
var c = document.getElementById('dh_condition').value.trim();
if (!p) { alert('请输入本地目录路径'); return; }
if (!c) { alert('请输入查询条件'); return; }
sendPrompt('__DOC_HUNTER__' + JSON.stringify({path: p, condition: c}));
}
</script>
注意: 弹窗颜色需根据 IDE 主题(light/dark)调整。light 主题用浅色背景 + 深色文字;dark 主题用深色背景 + 浅色文字。使用 read_me 返回的 CSS 变量或内联适配。
脚本说明
scripts/batch_extract.py(主脚本)
批量扫描目录并提取文本,输出 JSON。
用法:
<PYTHON> "<SKILL_DIR>/scripts/batch_extract.py" "<目录路径>" --output "output/doc_hunter_text/" --max-files 200 --max-text-length 15000
输出 JSON 结构:
{
"directory": "D:\\contracts",
"total_found": 15,
"total_processed": 15,
"truncated": false,
"summary": { "image": 3, "pdf": 5, "word": 4, "excel": 2, "text": 1 },
"files": [
{
"filename": "contract_A.pdf",
"filepath": "D:\\contracts\\contract_A.pdf",
"ext": ".pdf",
"category": "pdf",
"text": "合同金额:15,000元...",
"status": "ok",
"char_count": 1200
},
{
"filename": "invoice_B.jpg",
"filepath": "D:\\contracts\\invoice_B.jpg",
"ext": ".jpg",
"category": "image",
"text": "",
"status": "image_pending",
"char_count": 0
}
]
}
参数说明:
--output:文本输出目录(可选,保存每个文件的 .txt 副本)--max-files:最大处理文件数(默认 200,防止超大目录卡死)--max-text-length:单个文件文本最大提取字符数(默认 15000,防止上下文溢出)
scripts/extract_text.py(单文件提取)
对单个文件提取文本。在 batch_extract.py 内部调用,也可单独使用。
用法:
<PYTHON> "<SKILL_DIR>/scripts/extract_text.py" "<文件路径>" --output "output/doc_hunter_text/"
注意事项
- 路径格式:Windows 路径使用反斜杠
\,在 JSON 和命令行中需注意转义。AI 在执行 Bash 命令时应使用正斜杠/或正确转义。 - 图片文字提取依赖 AI 多模态能力:对于手写体、模糊图片、复杂排版的图片,文字识别准确率可能下降。建议用户尽量使用清晰的扫描件。
- 不支持旧版 .doc 格式:请用户先将 .doc 文件另存为 .docx 格式。.doc 是二进制格式,python-docx 无法解析。
- 大文件处理:单个文件超过 50MB 时,文本提取可能较慢,请耐心等待。
- 扫描深度:脚本递归扫描所有子目录。如目录层级过深或文件过多(>200),仅处理前 200 个文件。可通过
--max-files参数调整。 - 文本截断:单个文件提取文本超过 15000 字符时自动截断,防止 AI 上下文溢出。可通过
--max-text-length参数调整。 - 查询条件建议:尽量给出明确的条件,如"金额大于10000元"优于"金额大的合同";数值条件优于模糊描述。
- 密码保护文件:不支持加密的 PDF、Word、Excel 文件,请用户先解除密码保护。
- 图片型 PDF:如果 PDF 是扫描件(图片型),pdfplumber 提取文本为空。AI 应在结果中标记此类文件为"文本为空(可能为扫描件)"。
- 隐私安全:所有文件在本地处理,不会上传到外部服务器。
快速排查
| 问题 | 可能原因 | 解决方法 |
|------|---------|---------|
| 脚本报错"目录不存在" | 路径拼写错误或权限不足 | 检查路径是否正确,确认目录存在且有读取权限 |
| PDF 文本提取为空 | PDF 为扫描件(图片型) | 标记为"可能为扫描件",建议用户转为图片格式处理 |
| Word 文本提取乱码 | 文档编码异常 | 尝试将 .docx 另存后重新扫描 |
| 图片文字识别不准确 | 图片模糊、倾斜、手写体 | 建议用户使用更清晰的扫描件 |
| 条件匹配结果不符合预期 | 查询条件表述不精确 | 尝试更精确的条件描述,如加上具体单位(元、万元) |
| 依赖库安装失败 | 网络问题或权限不足 | 手动执行:<PYTHON> -m pip install pdfplumber python-docx openpyxl xlrd |
| 找到 0 个文件 | 目录下无支持格式的文件 | 检查目录是否正确,确认文件格式在支持列表中 |
| 脚本输出 JSON 过大 | 文件过多或文本过长 | 使用 --max-files 和 --max-text-length 限制 |
支付宝付费改造契约(PAYSKILL)
本技能为付费技能(PAYSKILL)。调用遵循支付宝 AI 生意画像契约,由平台调度层执行 probe → pay → complete → ack 流程:
- probe(探测):平台调用前先探测是否已持有本技能的支付宝有效订阅 / 付费凭证。已付费则直接放行。
- 402 Payment-Needed:未付费时,脚本向标准输出返回 HTTP 状态
402与Payment-Needed标记,提示用户通过支付宝完成付费(pay),平台据此唤起付费页。 - complete(扣费确认):用户在支付宝完成扣费后,平台下发
Payment-Proof(付费凭证)。 - ack(验签放行):平台携带
Payment-Proof重试本次调用;scripts/payment_gate.py验签该凭证,确认有效后放行主流程。
订阅持久化与幂等:
- 付费状态缓存在本地
.pay_cache/state.json,避免每次调用重复付费(订阅持久化)。 - 同一
Payment-Proof在 24h 幂等窗口内仅生效一次,避免重复扣费。
现金流改造后的调用套路:
用户调用 → 平台 probe →
未付费:下发 402 Payment-Needed → 支付宝 pay → complete → 下发 Payment-Proof
已付费/携带 Proof:脚本 ack 验签 → 放行主流程
本契约由 SkillHUB 平台调度层解析,脚本本地仅处理
402/验签/持久化三环节;付费本体交给支付宝。
微信扫一扫