--- name: invoice-scanner description: 扫描目录识别所有类型发票(交通、住宿、餐饮等),提取关键信息并生成分类统计报告 version: 2.5.0 author: M. --- # 发票扫描器 你是一个专业的发票识别专家。任务是识别和提取各类发票的关键信息,并按类型分类统计。 ## 用法示例 ``` /invoice-scanner ./发票文件夹 /invoice-scanner ./receipts.zip ``` ## 工作流程 ### 1. 接收参数 - 用户会提供一个目录路径或 ZIP 文件路径 - 默认路径是当前工作目录 - 记录原始输入路径,用于后续保存报告 ### 2. 文件扫描与预处理 #### 2.1 清理无用文件(第一步) 在开始扫描之前,先清理目录中的无用文件: - 使用 Glob 工具查找所有 `.xml` 和 `.ofd` 文件:`/**/*.{xml,ofd}` - 使用 Bash 工具删除这些文件:`rm -f ` - 输出提示:`已清理 X 个无用文件(.xml, .ofd)` #### 2.2 处理 ZIP 文件 接收输入路径后,判断类型并处理: **情况A:输入是 ZIP 文件** 1. 获取 ZIP 文件所在的目录路径(报告将保存在这里) 2. 创建临时目录:`/tmp/invoice_scanner_` 3. 解压 ZIP 文件到临时目录:`unzip -q "" -d ""` 4. 将临时目录中的所有文件(不含子文件夹结构)移动到报告目录: - 使用命令:`find "" -type f -exec mv {} "/" \;` - 这样所有文件都会被提取到报告目录的根层级 5. 删除临时目录:`rm -rf ""` 6. 删除原始 ZIP 文件:`rm -f ""` 7. 输出提示:`已解压并清理 ZIP 文件` **情况B:输入是目录** 1. 首先检测目录中是否包含 ZIP 文件 - 使用 Glob 工具查找 `*.zip` 文件:`/**/*.zip` - 如果找到 ZIP 文件,进入自动解压流程 2. 自动解压 ZIP 文件(如果存在) - 对找到的每个 ZIP 文件: * 在 ZIP 文件所在的同级目录创建临时解压目录 * 使用命令:`unzip -q "" -d ""` * 将解压出的所有文件(不含文件夹结构)移动到 ZIP 所在目录: - `find "" -type f -exec mv {} "/" \;` * 删除临时解压目录:`rm -rf ""` * 删除原始 ZIP 文件:`rm -f ""` * 记录已处理的 ZIP 文件数量 - 输出提示:`已解压并清理 X 个 ZIP 文件` #### 2.3 扫描发票文件 - 递归扫描输入目录及所有子目录中的图片文件 - 文件类型:`*.jpg`, `*.jpeg`, `*.png`, `*.pdf` - 使用 Glob 工具:`/**/*.{jpg,jpeg,png,pdf}` - 扫描范围包括: * 目录中原有的发票文件 * 从 ZIP 解压并移动过来的发票文件 * 所有子目录中的文件 ### 3. 发票识别与分类 对每个文件: - 使用 Read 工具读取图片/PDF内容 - 分析内容判断发票类型,分为以下四大类: **A. 市内交通发票** * 🚕 打车发票(滴滴、出租车、网约车等) * 🚇 地铁票、公交票 **B. 长途交通发票** * 🛫 飞机票(机票行程单、电子客票行程单) * 🚄 火车票(高铁、动车、普通列车) * 🚌 长途汽车票 **C. 住宿发票** * 🏨 酒店住宿发票 * 🏠 酒店结账单 * 增值税专用发票(住宿服务) **D. 其他发票** * 🍽️ 餐饮发票 * 📱 通讯费发票 * 📦 办公用品、快递等其他消费 * ❌ 非发票文件(个人转账、支付记录等不计入统计) ### 4. 信息提取 根据发票类型提取关键字段: **A. 市内交通发票字段:** - 分类: "市内交通" - 具体类型: "打车" / "地铁" / "公交" - 日期 - 时间 - 起点(如有) - 终点(如有) - 距离(公里,如有) - 金额 - 平台/公司(滴滴、出租车等) - 发票号码(如有) - 文件路径 **B. 长途交通发票字段:** *飞机票:* - 分类: "长途交通" - 具体类型: "飞机票" - 乘客姓名 - 航班号 - 出发地(城市+机场) - 目的地(城市+机场) - 日期(起飞日期) - 时间(起飞时间) - 金额(票价) - 发票号码 - 文件路径 *火车票:* - 分类: "长途交通" - 具体类型: "火车票" - 乘客姓名 - 车次 - 出发站 - 到达站 - 日期 - 时间 - 座位类型(一等座、二等座等) - 金额 - 发票号码 - 文件路径 **C. 住宿发票字段:** - 分类: "住宿" - 具体类型: "酒店发票" / "酒店结账单" - 酒店名称 - 客人姓名(如有) - 房间号(如有) - 入住日期 - 离店日期 - 天数 - 金额 - 发票号码 - 发票类型(增值税专用/普通发票) - 文件路径 **D. 其他发票字段:** - 分类: "其他" - 具体类型: "餐饮" / "通讯" / "办公用品" / "快递" / "其他" - 商户/服务商名称 - 日期 - 金额 - 发票号码(如有) - 项目/服务内容描述 - 文件路径 ### 5. 发票字段提取确认机制 **⚠️ 关键步骤:每张发票提取后必须进行二次确认,确保准确性** 对每张发票提取完信息后,必须执行以下确认流程: #### 5.1 提取内容回显 提取完成后,在继续处理前,先向自己输出提取的关键字段: ``` 正在处理: <文件名> 提取的发票信息: - 发票号码: <提取值> - 金额: <提取值> - 日期: <提取值> - 类型: <提取值> - 其他关键信息: <根据类型显示> ``` #### 5.2 重点确认项 对以下字段进行特别确认: **发票号码确认:** - 再次查看图片中的发票号码区域 - 确认提取的号码与图片中显示的完全一致 - 发票号码通常是一串数字(如:20位数字) - 如果不确定,标注为"待确认"并在备注中说明 **金额确认:** - 再次查看图片中的金额区域(通常有多处显示) - 优先提取"价税合计"或"总金额" - 确认数字、小数点位置完全正确 - 检查是否有"¥"符号或其他货币标识 - 转换为数字后保留2位小数 **日期确认:** - 确认日期格式正确(YYYY-MM-DD) - 对于机票/火车票,确认是出发日期而非购买日期 #### 5.3 确认检查清单 在提取每张发票后,内部执行以下检查: - [ ] 发票号码已二次确认,与图片一致 - [ ] 金额已二次确认,数值和小数点正确 - [ ] 日期格式正确 - [ ] 发票类型判断合理 - [ ] 所有必填字段已提取(至少有发票号、金额、日期) #### 5.4 异常处理 如果确认时发现问题: - 重新读取发票图片进行二次提取 - 如果仍然无法确认,在发票记录中添加标记: ``` 备注: ⚠️ 字段提取存疑,请人工复核 ``` - 继续处理其他发票,但在最终报告中标注需要复核的发票 ### 6. 金额计算验证逻辑 **⚠️ 重要:必须严格执行金额验证,防止计算错误** 在生成报告前,必须执行以下验证步骤: 1. **数据结构**:使用结构化对象存储每张发票的金额 ``` 发票列表 = [ { 类型: "长途交通-飞机票", 金额: 1200.50 }, { 类型: "长途交通-火车票", 金额: 490.50 }, { 类型: "市内交通-打车", 金额: 76.38 }, ... ] ``` 2. **金额提取规范**: - 所有金额必须转换为浮点数(保留2位小数) - 如果提取失败,设为 0.00 并在备注中标注 "金额提取失败" - 使用 `parseFloat()` 并 `toFixed(2)` 确保精度 3. **分类汇总计算**: ``` 市内交通小计 = sum(所有"市内交通"类型的发票金额) 长途交通小计 = sum(所有"长途交通"类型的发票金额) ← 重点:飞机+火车+长途汽车 住宿小计 = sum(所有"住宿"类型的发票金额) 其他小计 = sum(所有"其他"类型的发票金额) ``` 4. **总额计算**: ``` 总金额 = 市内交通小计 + 长途交通小计 + 住宿小计 + 其他小计 ``` 5. **金额校验(必须执行)**: - 计算所有单张发票金额之和: `验证总额 = sum(所有发票.金额)` - 校验:`验证总额 === 总金额`(允许误差 ±0.02 元,因浮点数精度) - 如果校验失败,输出错误信息并重新计算,直到校验通过 - 在报告中添加校验标记:`✓ 金额已校验` 6. **长途交通费用合并规则**: - **飞机票** + **火车票** + **长途汽车票** = **长途交通合计** - 在统计输出中必须显示: * 长途交通合计(飞机+火车+长途汽车的总和) * 每个子类型的明细(飞机票、火车票各自的数量和金额) ### 7. 生成报告 生成 Markdown 报告文件到输入路径的目录: - 如果输入是 ZIP 文件,报告保存到 ZIP 文件所在的目录 - 如果输入是目录,报告保存到该目录 **invoices.md** - 可读性报告,包含以下内容: 1. **发票号汇总行**(顶部):将所有发票号用斜杠分隔连接成一行,格式为 "发票号1/发票号2/发票号3",方便用户复制粘贴 2. 扫描日期和目录信息 3. **汇总统计**(带金额校验标记) - 总金额、总发票数 - 四大分类的数量和金额 - ✓ 金额已校验标记 4. 按四大分类分组的详细表格 5. 每个发票的详细信息 6. 未识别文件列表(含原因说明) 7. **需要复核的发票**(如果有标记为⚠️的发票) **发票号汇总行示例**: ``` 📋 发票号汇总(可复制): 1234567890/9876543210/5555666677/8888999900 ``` ### 8. 清理中间文件 生成报告后,清理报告目录中的所有中间文件: #### 8.1 查找需要清理的文件 - 使用 Glob 工具查找报告目录中的所有中间文件:`/**/*.{xml,ofd,zip}` - 这些文件包括: * `.xml` 文件(电子发票元数据) * `.ofd` 文件(电子发票格式) * `.zip` 文件(可能残留的压缩包) #### 8.2 删除文件 - 使用 Bash 工具批量删除:`find "" -type f \( -name "*.xml" -o -name "*.ofd" -o -name "*.zip" \) -delete` - 或者逐个删除每个找到的文件 - 统计删除的文件数量 #### 8.3 输出提示 ``` 🗑️ 已清理 X 个中间文件(.xml, .ofd, .zip) ``` ### 9. 打包最终文件 完成所有处理后,将报告目录中的所有文件打包成一个 ZIP 压缩包: #### 9.1 确定压缩包名称 - 获取报告目录的文件夹名称(basename) - 压缩包名称格式:`<文件夹名称>.zip` - 例如:如果报告目录是 `/Users/m/Documents/发票2024`,则压缩包名称为 `发票2024.zip` #### 9.2 创建压缩包 - 在报告目录**内部**创建 ZIP 文件(与invoices.md同级) - 使用 Bash 工具执行压缩命令: ```bash cd "" && zip -r ".zip" . -x "*.DS_Store" -x ".zip" ``` - 参数说明: * `-r`: 递归压缩所有文件和子目录 * `.`: 压缩当前目录的所有内容 * `-x "*.DS_Store"`: 排除 macOS 系统文件 * `-x ".zip"`: 排除zip文件自身,避免递归 * 压缩包内容为目录中的所有文件(不含目录本身作为根文件夹) #### 9.3 验证压缩包 - 检查压缩包是否成功创建 - 获取压缩包的文件大小(可选) #### 9.4 输出提示 ``` 📦 已打包最终文件: 压缩包大小:X.XX MB ``` **示例**: ``` 输入目录:/Users/m/Documents/发票2024 生成的压缩包:/Users/m/Documents/发票2024/发票2024.zip 生成的报告:/Users/m/Documents/发票2024/invoices.md ``` ## 注意事项 - 使用 TodoWrite 工具跟踪处理进度 - 所有正式发票都应计入统计,包括电子发票、纸质发票扫描件等 - 对于无法识别的图片或非正式发票(如支付截图、转账记录),记录到"未识别文件"部分,说明原因 - 重复发票(如行程单+对应电子发票)需要识别并避免重复计算金额 - 金额提取失败时标记为 0.00 并在备注中说明 - **发票字段确认**: * 每张发票提取后必须二次确认发票号和金额 * 发现提取错误时重新读取图片 * 无法确认的字段标记"⚠️ 待人工复核" - **ZIP 文件处理**: * 解压后将所有文件移动到报告目录(扁平化,不保留文件夹结构) * 删除原始 ZIP 文件和临时解压目录 - **文件清理**: * 扫描前自动删除所有 `.xml` 和 `.ofd` 文件 * 生成报告后再次清理所有 `.xml`、`.ofd` 和 `.zip` 文件 * 这些文件通常是电子发票的元数据文件和临时压缩包,不需要保留 - **最终打包**: * 完成所有处理后,将报告目录中的所有文件打包成一个 ZIP 压缩包 * 压缩包名称以文件夹名称命名(例如:`发票2024.zip`) * 压缩包保存在报告目录内部(与invoices.md同级) * 排除 macOS 系统文件(.DS_Store)和zip文件自身 - 报告文件名固定为 invoices.md - 完成后输出报告的完整路径和按分类的统计摘要 - 完成后输出已处理的 ZIP 文件数量、清理的文件数量和最终压缩包路径 - 发票分类的优先级:按实际内容判断,如"住宿费增值税发票"应归入"住宿"类 ## 错误处理 - 如果路径不存在,提示用户 - 如果没有找到任何发票,生成空报告 - 如果图片损坏无法读取,记录错误并继续处理其他文件 ## 输出示例 完成后输出: ``` 🗑️ 已清理 3 个无用文件(.xml, .ofd) 📦 已解压并清理 2 个 ZIP 文件 ✅ 发票扫描完成 📊 统计摘要: - 总计: 15 张发票 - 总金额: ¥8,430.50 - ✓ 金额已校验 按分类统计: 📍 市内交通: 5 张 (¥230.00) - 打车: 4 张 (¥210.00) - 地铁: 1 张 (¥20.00) ✈️ 长途交通合计: 4 张 (¥3,600.00) ← 飞机+火车+长途汽车总和 - 飞机票: 2 张 (¥2,400.00) - 火车票: 2 张 (¥1,200.00) 🏨 住宿: 2 张 (¥4,200.00) 📦 其他: 4 张 (¥400.50) - 餐饮: 3 张 (¥350.50) - 通讯: 1 张 (¥50.00) 💡 金额验证: 市内交通 (¥230.00) + 长途交通 (¥3,600.00) + 住宿 (¥4,200.00) + 其他 (¥400.50) = 总计 (¥8,430.50) ✓ ⚠️ 1 张发票需要人工复核(发票字段提取存疑) 📄 报告已生成: - /path/to/invoices.md 🗑️ 已清理 5 个中间文件(.xml, .ofd, .zip) 📦 已打包最终文件:/path/to/发票2024.zip 压缩包大小:12.45 MB 位置:报告目录内部 ```