Files
Auto-Finance/README.md
2026-06-12 12:06:06 +08:00

16 KiB
Raw Blame History

财务报销自动化

自动从 PDF 发票或图片中提取信息,生成发票汇总表与易耗品出库单,并可选在财务系统中自动填报报销单。

支持发票类型区分:系统自动识别高铁票、酒店住宿等差旅发票与普通发票。差旅发票不生成易耗品出库单,走差旅报销流程;普通发票生成出库单,走普通报销流程。

项目结构

├── pyproject.toml                  # 项目配置(依赖、工具链)
├── uv.lock                         # 依赖锁定文件
├── Makefile                        # 任务脚本(跨平台)
├── tasks.py                        # 任务脚本Windows 兼容)
├── .pre-commit-config.yaml         # pre-commit 钩子配置
├── .env.example                    # 环境变量示例SSO 地址、LLM 配置等)
├── config.example.json             # 用户配置示例
├── 易耗品、出库单.doc              # 易耗品出库单 Word 模板
├── src/
│   ├── __init__.py                 # 包初始化 / 日志器
│   ├── config.py                   # 配置加载
│   ├── bot.py                      # 浏览器自动填报
│   ├── pipeline.py                 # CLI 流程编排
│   ├── main.py                     # CLI 入口
│   ├── doc/                        # 文档处理模块
│   │   ├── extractor.py            # 编排入口:串联 PDF 读取 → LLM 提取 → 分类
│   │   ├── pdf.py                  # PDF 图片渲染PyMuPDF供多模态 LLM 使用)
│   │   ├── llm_extractor.py        # LLM 信息提取
│   │   ├── matcher.py              # 数据匹配与校验
│   │   ├── invoice.py              # 发票类型常量、分类逻辑、CSV 读写工具
│   │   ├── fill_consumable_doc.py  # 将 CSV 填入易耗品出库单Word COM
│   │   ├── prompt.py               # LLM 提示词模板
│   │   └── prompts/                # 提示词模板文件
│   └── web/
│       ├── app.py                  # Web 服务入口
│       ├── templates/
│       │   ├── index.html          # PC 端主页
│       │   └── mobile_upload.html  # 移动端扫码上传
│       ├── static/
│       │   ├── css/                # 样式文件
│       │   └── js/                 # 前端脚本
│       └── uploads/                # 按会话隔离的上传与产物目录
├── scripts/                        # CLI 数据目录
│   ├── data/                       # 发票源文件、config.json 与 .invoice_cache 缓存
│   └── test_*.py                   # 测试脚本
├── tests/                          # 测试目录
├── docs/                           # 用户文档API 说明、操作指南等)
├── images/                         # 浏览器调试截图
└── *.pdf / *.jpg / *.png           # 发票 PDF 或图片CLI 模式,放在 scripts/data/

数据流

flowchart TB
    PDF[PDF 发票 / 图片] --> Extract[extractor 多模态提取]
    Extract --> Cache[(.invoice_cache/*.json)]

    Cache --> Classify{发票类型分类}
    Classify -->|差旅发票| Travel[高铁票 / 酒店住宿]
    Classify -->|普通发票| General[普通发票]
    Classify -->|支付记录| Payment[支付截图]
    Classify -->|申请单| Application[出差事前申请单]

    Travel --> Matcher[matcher 金额匹配]
    Payment --> Matcher
    Matcher --> MatchResult[(match_result.json)]

    Cache --> TravelLLM[LLM 差旅信息提取]
    MatchResult --> TravelLLM
    TravelLLM --> TravelInfo[(travel_info.json)]

    Cache --> NormalLLM[LLM 普通发票信息提取]
    MatchResult --> NormalLLM
    NormalLLM --> NormalInfo[(normal_info.json)]

    TravelInfo -->|差旅基本信息| Bot_T[bot/travel.py<br/>差旅填报流程]
    TravelInfo -->|报销明细| Bot_T
    TravelInfo -->|支付方式| Bot_T
    TravelInfo -->|补助清单| Bot_T
    TravelInfo -->|附件清单| Bot_T
    Bot_T --> Submit_T[差旅报销提交]

    NormalInfo -->|报销说明| Bot_G[bot/normal.py<br/>普通填报流程]
    NormalInfo -->|发票总数/金额| Bot_G
    NormalInfo -->|支付方式| Bot_G
    NormalInfo -->|附件清单| Bot_G
    Bot_G --> Submit_G[普通报销提交]

    General --> CSV[(invoice_summary.csv)]
    CSV --> Fill[fill_consumable_doc]
    Fill --> Doc[易耗品、出库单.doc]

关键中间产物

文件 生成阶段 作用
.invoice_cache/*.json extractor 提取 单张发票/支付记录/申请单的结构化数据
match_result.json matcher 匹配 支付截图与发票的关联关系(按金额匹配)
travel_info.json LLM 差旅信息提取 综合发票缓存 + 匹配结果,生成差旅报销所需的全部结构化数据
normal_info.json LLM 普通发票信息提取 综合普通发票 + 匹配结果,生成普通报销所需的全部结构化数据
invoice_summary.csv extractor 提取 普通发票汇总(用于生成易耗品出库单)

bot 模块架构

bot/ 包负责浏览器自动化填报,仅接收已提取的信息并执行填报操作,不承担信息提取职责:

模块 职责
bot/base.py BaseBot 基类:浏览器生命周期、登录、导航、截图
bot/travel.py 差旅填报流程:基本信息 → 差旅明细 → 支付方式 → 补助清单 → 附件上传
bot/normal.py 普通填报流程:基本信息 → 总明细 → 支付方式 → 附件上传
bot/__init__.py 入口函数:run_bot() / run_bot_web(),负责类型判断和流程路由

环境要求

  • Python 3.12+
  • uv 包管理器(安装指南
  • Windows易耗品出库单填写依赖 Microsoft Word + COM仅 Windows 可用)

快速开始

1. 安装依赖

# 同步所有依赖(运行时 + 开发工具)
make install
# Windows 上等效命令:
python tasks.py install

项目使用 uv 管理依赖,所有包版本锁定在 uv.lock 中,确保可复现。

依赖 用途
PyMuPDF PDF 图片渲染(供多模态 LLM 使用)
llama-index LLM 信息提取(发票识别、差旅信息提取)
playwright 财务系统浏览器自动化
flask Web 服务
pywin32 填写 Word 出库单(fill_consumable_doc

2. 准备数据CLI 模式)

将发票 PDF 或图片(.jpg.png.webp.bmp)放在 scripts/data/ 目录下。

3. 配置

编辑 scripts/config.json(参考 config.example.json

{
    "username": "你的工号",
    "password": "你的密码",
    "default_name": "默认报销人姓名",
    "default_card_no": "默认公务卡号",
    "default_person_id": "默认人员编号",
    "consumable_storage": "物料存储地"
}
字段 说明
username / password 信息门户登录凭据
default_name 默认报销人姓名
default_card_no 默认公务卡号
default_person_id 默认人员编号(工号)
consumable_storage 出库单「存放地点」列默认值(默认: 躬行楼 C205

服务端配置SSO 地址、报销系统 URL、LLM 参数)通过环境变量提供,有默认值,一般无需修改:

环境变量 默认值 说明
SSO_LOGIN_URL https://tyrz.fynu.edu.cn/sso/login SSO 登录地址
PORTAL_URL https://tyrz.fynu.edu.cn/oshall 统一信息平台地址
REIMBURSE_URL http://210.45.32.214:8081 报销系统地址
REIMBURSE_PAGE /expen/common/common?v=4.0 普通报销页面路径
TRAVEL_PAGE /expen/travel/travel?v=4.0 差旅报销页面路径
LLM_MODEL qwen-vl-max LLM 模型名称
LLM_API_BASE http://localhost:8080/v1 LLM API 地址
LLM_API_KEY lm-studio LLM API 密钥

4. 运行CLI

# 全流程(发票提取 → 浏览器填报)
make run
# Windows 等效:
python tasks.py run

# 仅执行某一步
uv run python src/main.py --step invoice    # 仅发票提取
uv run python src/main.py --step submit     # 仅浏览器填报

# 覆盖配置中的登录凭据
uv run python src/main.py -u 工号 -p 密码

5. 填写易耗品出库单CLI

需已生成 invoice_summary.csv,且本机已安装 Microsoft Word

uv run python -m src.doc.fill_consumable_doc
uv run python -m src.doc.fill_consumable_doc --csv invoice_summary.csv --doc "易耗品、出库单.doc"
uv run python -m src.doc.fill_consumable_doc --config scripts/config.json  # 指定配置文件
uv run python -m src.doc.fill_consumable_doc --no-backup   # 不生成 .doc.bak 备份

填写规则概要:

  • 表头「日期」使用填写当天的日期(非发票开票日期)
  • spec_model 解析品名、规格、单位、数量、单价;card_amount 写入金额列
  • 单价/金额保留两位小数;表格内统一为 宋体五号10.5 磅)
  • 存放地点取自 consumable_storage(默认: 躬行楼 C205);购货人/领用人签字、备注保持空白

执行步骤说明

步骤 命令 说明
发票提取 --step invoice 扫描 scripts/data/ 目录的 PDF 和图片,生成 invoice_summary.csv
浏览器填报 --step submit 登录信息门户 → 报销系统 → 自动填单、上传附件

全流程执行时数据在内存中流转CSV 为参考产物。分步执行时,缓存数据会自动成为下一步的输入。

缓存机制

系统使用 JSON 缓存作为数据中转站,串联整个处理流程:

源文件 (PDF/图片) → LLM 多模态提取 → JSON 缓存 → 匹配/分类/填报
缓存文件 说明
<文件名>.json 每个源文件的 LLM 提取结果(发票信息、支付记录等)
match_result.json 发票与支付记录的匹配结果
travel_info.json 差旅信息(事由、地点、时间等)提取结果

缓存位置CLI 模式为 scripts/data/.invoice_cache/Web 模式为 src/web/uploads/<session_id>/.invoice_cache/。缓存文件与源文件同名(如 发票1.pdf 对应 .invoice_cache/发票1.json),后续步骤(金额匹配、发票分类、浏览器填报)均从缓存读取结构化数据。删除缓存后下次处理会重新提取。

CSV 字段说明

发票级别 CSVinvoice_summary.csv)使用英文列名:

列名 说明
index 行号
invoice_type 发票类型:train / hotel / general
invoice_number 电子发票号码
invoice_date 开票日期
item_name 货物或应税劳务名称
spec_model 规格型号(差旅发票为出发站→到达站)
total_amount 发票含税金额
seller_name 销方名称
departure / arrival 出发站 / 到达站(高铁票专用)
train_no / ride_date / seat_class 车次 / 乘车日期 / 座位等级(高铁票专用)
person_name 人员姓名
card_date / card_no / card_amount 刷卡日期 / 公务卡号 / 刷卡金额
remark 备注
person_id 工号

Web 服务

提供浏览器界面:上传文件 → 自动处理 → 在线编辑 → 下载产物 → 可选提交财务系统。

uv run python src/web/app.py

访问 http://localhost:5000

推荐使用流程

  1. 上传 PDF 或图片(或上传已有 CSV
  2. 填写配置(账号、密码、姓名、公务卡号、存放地点等),可上传 config.json 一键填充
  3. 点击 开始处理 — 完成发票提取、生成 CSV系统自动识别发票类型并分类统计
  4. 普通发票:自动生成 易耗品、出库单.doc,可下载
  5. 差旅发票(高铁票/酒店住宿):跳过出库单生成,直接进入差旅报销流程
  6. 在表格中核对、修改发票数据(提交财务系统前会自动保存)
  7. 确认无误后点击 提交到财务系统

处理流程

上传 PDF 或图片 → LLM 识别文档类型 → 结构化提取 → 分类处理

系统通过 LLM 多模态识别自动判断每张文档的类型,无需手动指定:

文档类型 处理方式 状态
发票(高铁票/酒店住宿/普通发票) 提取发票信息 → 金额匹配 → 分类 已实现
支付记录(刷卡截图) 提取刷卡信息 → 与发票匹配 已实现
出差事前申请单 提取出差事由、地点、时间 已实现
飞机票 同高铁票处理流程 计划中

功能一览

功能 说明
发票提取 上传 PDF 或图片后自动完成
发票类型自动分类 高铁票/酒店住宿/普通发票,自动分流处理
易耗品出库单 仅普通发票自动生成 Word差旅发票跳过
表格在线编辑 处理完成后可修改 CSV 各字段;保存后重新生成出库单
财务系统填报 单独按钮触发,处理阶段不会自动提交
实时日志 SSE 推送处理进度
配置上传 支持上传 config.json 填充表单
手机扫码上传 二维码打开移动端页面拍照上传PC 端轮询同步

Web 端浏览器填报以无头模式运行。未上传 PDF 或图片时,填报阶段会跳过附件上传。 出库单生成需要 Windows + Word + pywin32若失败页面会显示具体原因CSV 等其它产物仍可正常使用。

会话产物

每次上传生成独立会话,产物存放在 src/web/uploads/<session_id>/

产物 说明
invoice_summary.csv 发票汇总数据(含 LLM 识别结果)
payment_records.csv 支付记录级别数据(含匹配结果)
travel_applications.json 出差事前申请单数据JSON 格式)
易耗品、出库单.doc 自动填写的出库单(仅普通发票)
config.json 当次会话配置
session.log 处理日志
result.json 处理结果
.invoice_cache/ LLM 提取结果缓存JSON 格式,避免重复处理)

会话缓存机制与 CLI 模式相同,缓存目录中的 JSON 数据是后续匹配、分类和填报的唯一数据来源。

接口说明见 API.md

开发任务

项目提供统一的任务脚本,支持跨平台使用:

任务 Makefile tasks.py 说明
安装依赖 make install python tasks.py install 同步依赖 + 安装 pre-commit
代码检查 make check python tasks.py check Ruff lint + 格式化 + MyPy 类型检查 + deptry 依赖检查
运行测试 make test python tasks.py test pytest + 覆盖率报告
运行 CLI make run python tasks.py run 执行全流程
清理缓存 make clean python tasks.py clean 删除虚拟环境和缓存

代码质量

项目配置了完整的代码质量工具链:

  • Ruff — 快速 lint 检查和代码格式化(替代 flake8 + isort + black
  • MyPy — 严格模式类型检查(strict = true
  • deptry — 检测未声明、未使用、过时依赖
  • pre-commit — 提交前自动运行 Ruff 检查和格式化

所有检查通过后方可提交代码。

注意事项

  • 浏览器填报时会打开或使用 Chromium请勿手动干扰自动化流程
  • 调试截图保存在 images/ 目录
  • 项目根目录需保留 易耗品、出库单.doc 模板Web 每次从模板复制到会话目录再填写,不修改原模板
  • scripts/config.json 含敏感信息,请勿提交到公开仓库
  • 发票类型区分:差旅发票(高铁票/酒店住宿)不会生成易耗品出库单,差旅报销填报流程已完整实现(含差旅信息提取、明细录入、支付方式、补助清单、附件上传)