第一章 工具的工作流程
1. 系统概述
1.1 系统是做什么的?
账单识别工具是一个自动化账单处理系统,能够:
- 读取律师事务所的PDF账单
- 自动识别账单中的文字和表格
- 提取关键信息(日期、金额、律师工时等)
- 保存到数据库供后续查询和导出
1.2 支持的账单类型
| 账单类型 | 律所名称 | 货币 | 特点 |
|---|---|---|---|
| QE账单 | Quinn Emanuel(奎恩伊曼纽尔) | 人民币 (¥) | 包含折扣和增值税 |
| Steptoe账单 | Steptoe & Johnson | 美元 ($) | 通常无折扣 |
1.3 系统架构
1 | flowchart TB |
2. 完整流程概览
2.1 端到端流程图
1 | sequenceDiagram |
2.2 处理时间线
1 | gantt |
3. 上传阶段
3.1 上传流程
1 | flowchart TD |
4. 任务管理
4.1 任务状态
1 | stateDiagram-v2 |
4.2 并发处理
系统支持同时处理多个账单:
1 | flowchart LR |
并发数量:
- 默认:同时处理 3个 账单
- 可配置:1-10个(在设置中调整)
- 建议:根据电脑性能调整
4.3 进度显示
系统会实时显示处理进度:
| 阶段 | 说明 | 进度占比 |
|---|---|---|
| 🔄 加载模型 | 准备AI模型 | 10% |
| 📐 识别布局 | 分析页面结构 | 25% |
| 🔍 检测文本 | 定位文字位置 | 15% |
| 📝 识别文字 | 提取文字内容 | 30% |
| 📊 识别表格 | 提取表格数据 | 10% |
| ✅ 提取数据 | 整理结构化信息 | 10% |
5. PDF预处理
5.1 为什么需要预处理?
律师账单PDF通常有很多页,但并非所有页面都包含关键信息。预处理的目的是:
- 🎯 只提取关键页面,跳过冗余内容
- ⚡ 加快识别速度
- 💰 节省API调用成本(在线模式)
5.2 预处理流程
1 | flowchart TD |
5.3 账单类型识别
系统通过关键词自动识别账单类型:
| 账单类型 | 识别关键词 | 货币 |
|---|---|---|
| 🏢 QE账单 | “quinn emanuel” | ¥ 人民币 |
| 🏛️ Steptoe账单 | “www.steptoe.com“ | $ 美元 |
5.4 有效页面提取规则
QE账单提取规则
1 | flowchart LR |
提取逻辑:
- 找到 “Statement Detail“ → 该页及之前的页面保留
- 找到 “Fee Summary“ → 该页及之后的页面保留
- 中间的详细工时页面跳过
Steptoe账单提取规则
1 | flowchart LR |
提取逻辑:
- 找到 “FEE DETAIL“ → 该页及之前的页面保留
- 找到 “EXPENSE DETAIL“ → 该页及之后的页面保留
- 中间的详细工时页面跳过
6. 智能识别
系统提供两种识别模式,可在设置中切换:
6.1 识别模式对比
| 特性 | 🖥️ 本地模型 | ☁️ 在线模型 |
|---|---|---|
| 网络要求 | 无需网络 | 需要网络 |
| 识别速度 | 较快 | 取决于网络 |
| 识别准确度 | 良好 | 优秀 |
| 成本 | 免费 | 按次收费 |
| 首次启动 | 慢(需加载模型) | 快 |
| 适用场景 | 离线环境、批量处理 | 高精度要求 |
6.2 识别模式选择流程
1 | flowchart TD |
6.3 本地模型识别
6.3.1 使用的AI技术
本地模型使用 Marker 开源工具,内部集成多个AI模型:
1 | mindmap |
6.3.2 识别阶段
1 | gantt |
阶段说明:
- 加载模型 (10%): 首次使用时加载AI模型到内存
- 识别布局 (25%): 分析页面结构,区分标题、正文、表格
- OCR检测 (5%): 检查可能的识别错误
- 检测边界 (10%): 定位每个文字的位置
- 识别文字 (30%): 使用OCR识别文字内容
- 识别表格 (10%): 重建表格结构
- 生成结果 (10%): 整理为Markdown格式
6.3.3 模型缓存机制
1 | flowchart TD |
优势:
- ✅ 首次识别较慢(需加载模型)
- ✅ 后续识别很快(模型已在内存)
- ✅ 节省时间和资源
6.4 在线模型识别
6.4.1 工作原理
1 | flowchart TD |
6.4.2 识别阶段
1 | gantt |
阶段说明:
- 读取PDF (5%): 读取PDF文件
- 转换图片 (15%): 将每页转为高清图片
- 上传图片 (10%): 发送到AI服务器
- AI分析 (40%): 在线AI识别(耗时最长)
- 下载结果 (10%): 接收识别结果
- 解析响应 (10%): 解析返回的数据
- 提取数据 (10%): 提取结构化信息
6.4.3 API配置
使用在线模型需要配置:
| 配置项 | 说明 | 示例 |
|---|---|---|
| API Endpoint | 服务器地址 | https://api.openai.com/v1 |
| API Key | 访问密钥 | sk-xxxxx |
| Model | 模型名称 | gpt-4o |
支持的API:
- OpenAI GPT-4 Vision
- 其他兼容OpenAI格式的视觉API
7. 数据提取
7.1 提取流程
1 | flowchart TD |
7.2 提取的数据字段
7.2.1 QE账单字段
1 | mindmap |
7.2.2 Steptoe账单字段
1 | mindmap |
7.3 数据字段对比
| 字段 | QE账单 | Steptoe账单 | 说明 |
|---|---|---|---|
| 账单日期 | ✅ | ✅ | 账单开具日期 |
| 费用总额 | ✅ Fees | ✅ Total Fees | 律师费总计 |
| 折扣 | ✅ 10% Discount | ❌ 通常无 | 优惠折扣 |
| 净费用 | ✅ Net Billed Fees | ✅ 计算得出 | 扣除折扣后 |
| 增值税 | ✅ VAT 6.77% | ❌ 无 | 中国税费 |
| 开支 | ✅ Total Expenses | ✅ Total Expenses | 其他费用 |
| 应付总额 | ✅ Total Due | ✅ Total Amount Due | 最终金额 |
| 律师明细 | ✅ Fee Summary | ✅ FEE SUMMARY | 工时明细表 |
7.4 日期识别
系统支持多种日期格式:
| 格式 | 示例 | 说明 |
|---|---|---|
| DD Month YYYY | 18 November 2025 |
日 月 年 |
| DD Mon YYYY | 18 Nov 2025 |
日 月缩写 年 |
| Month DD, YYYY | November 18, 2025 |
月 日, 年 |
月份识别:
- 支持完整月份名:January, February, March…
- 支持缩写:Jan, Feb, Mar…
- 不区分大小写
7.5 金额识别
系统能识别各种金额格式:
| 格式 | 示例 | 说明 |
|---|---|---|
| 带货币符号 | CNY1,673,658.15 |
人民币 |
| 带货币符号 | $27,108.00 |
美元 |
| 带千位分隔符 | 1,673,658.15 |
逗号分隔 |
| 无分隔符 | 1673658.15 |
纯数字 |
处理规则:
- 自动移除货币符号(¥、$、CNY、USD)
- 自动移除千位分隔符(,)
- 保留小数点后两位
7.6 表格提取
QE账单表格示例
| 律师姓名 | 缩写 | 职位 | 工时 | 费率 | 金额 |
|---|---|---|---|---|---|
| Zhang San | Z.S. | Associate | 10.5 | ¥1,200 | ¥12,600 |
| Li Si | L.S. | Partner | 5.0 | ¥2,500 | ¥12,500 |
| Wang Wu | W.W. | Associate | 8.0 | ¥1,200 | ¥9,600 |
Steptoe账单表格示例
| 律师姓名 | 职位 | 工时 | 费率 | 金额 |
|---|---|---|---|---|
| Levin, M.L. | Partner | 9.30 | $1,290.00 | $11,997.00 |
| Harris, D.C. | Associate | 14.60 | $1,035.00 | $15,111.00 |
提取内容:
- 律师姓名
- 职位(Partner/Associate等)
- 工作小时数
- 小时费率
- 总金额
8. 数据保存
8.1 数据库结构
1 | erDiagram |
8.2 状态流转
1 | stateDiagram-v2 |
8.3 保存时机
1 | sequenceDiagram |
8.4 数据完整性保证
1 | flowchart TD |
总结
完整流程回顾
1 | flowchart TB |
核心优势
| 特性 | 说明 |
|---|---|
| 自动化 | 无需手工录入,自动提取所有信息 |
| 智能化 | AI自动识别账单类型和关键信息 |
| 高效率 | 支持并发处理,批量识别 |
| 防重复 | MD5指纹技术,自动去重 |
| 灵活性 | 支持本地/在线两种识别模式 |
| 可追溯 | 保留原始PDF和识别结果 |
| 结构化 | 数据规范存储,便于查询和导出 |
第二章 代码工作
(一)系统启动与界面交互
- 入口:
main.py是程序的启动点。它使用webview库创建了一个窗口,加载web/index.html作为前端界面,并将 Python 后端的api对象暴露给前端 JavaScript 调用。 - 前后端桥梁:
src/api.py定义了Api类。前端通过pywebview.api.upload_files()等方法直接调用后端的 Python 函数,实现了文件选择、任务提交等功能。
(二)任务管理与并发
上传文件后,系统并不会阻塞主界面,而是将任务放入后台队列。
- 任务调度:
src/task_manager.py中的TaskManager类维护了一个任务队列 (self.queue)。 - 并发处理:它启动了多个工作线程(Worker Threads),默认数量是 3 个(
max_workers=3)。这意味着工具可以同时并行处理 3 个账单识别任务,提高效率。 - 流程控制:工作线程不断从队列取任务,调用
self.process_bill(bill_id, file_path)开始处理单个账单。
(三)第一阶段:PDF 预处理
这是节省 Token和提速的关键步骤。系统不会把整个几十页的 PDF 都扔给 AI,而是先自己“看”一遍。
核心代码:
src/pdf_preprocessor.py中的PDFPreprocessor类。步骤 1:类型识别
- 代码:
_detect_bill_type - 逻辑:它使用
fitz(PyMuPDF) 读取 PDF 文本。如果发现 “quinn emanuel” 字符串,就标记为BillType.QE;如果发现 “www.steptoe.com“,就标记为BillType.STEPTOE。
- 代码:
步骤 2:有效页面提取
- 代码:
extract_valid_pages_to_pdf - QE 规则 (
_extract_qe_pages):找到包含 “Statement Detail” 的页面作为起点,找到 “Fee Summary” 的页面作为终点。只提取这中间的页面。 - Steptoe 规则 (
_extract_steptoe_pages):提取 “FEE DETAIL” 到 “EXPENSE DETAIL” 之间的页面。 - 结果:生成一个新的、只包含核心表格的精简版 PDF,通常只有几页。
- 代码:
(四)第二阶段:AI 智能识别
根据设置,它会走两条路之一。
核心逻辑由 src/bill_parser.py 中的 BillParser 类调度。
路径 A:在线模型
- 核心代码:
src/online_parser.py中的OnlineBillParser类。 - 流程:
- 转图片:
_pdf_to_images_base64方法将精简后的 PDF 每一页转为高清图片。 - 构建 Prompt:使用预定义的
SYSTEM_PROMPT,明确指示 AI:“你是一个专业的账单解析助手… 保留所有表格结构,使用标准 Markdown 表格语法”。 - 调用 API:
_call_vision_api方法将图片和提示词发送给 OpenAI 兼容接口(如 GPT-4o),获取返回的 Markdown 文本。
- 转图片:
路径 B:本地模型
- 核心代码:
src/bill_parser.py中的_parse_local方法。 - 技术:使用开源库
marker。代码中通过converter(actual_pdf_path)调用本地模型,将 PDF 转换为 Markdown。
(五)第三阶段:数据提取
AI 返回的是 Markdown 文本,系统需要通过 正则表达式将其转化为结构化数据(JSON)。
QE 账单提取器:
- 代码:
src/parsers/qe_parser.py。 - 总额提取:使用正则
r'\|\s*Fees\s*\|\s*CNY\s*([\d,]+\.\d{2})\s*\|'提取表格中的 Fees。 - 折扣提取:提取 “10% Discount” 对应的负数金额。
- 表格提取:
_parse_fee_summary方法解析类似| Attorney | Title | Hours | Rate | Amount |的 Markdown 表格行,将其转为 Python 字典列表。
- 代码:
Steptoe 账单提取器:
- 代码:
src/parsers/steptoe_parser.py。 - 难点处理:Steptoe 的表头里常有换行符(如
Total<br>Fees),正则设计了兼容逻辑:r'.*Total\s*<br>\s*Fees...'。
- 代码:
(六)数据保存 (Data Storage)
最后,提取出的干净数据被存入 SQLite 数据库。
- 核心代码:
src/database.py。 - 逻辑:
Database.update_bill():更新账单的主表信息(总金额、折扣、日期等)。Database.save_bill_details():将律师工时明细表存入bill_details表中。
总结图示
1 | [用户上传] -> main.py (UI) -> api.py |
第三章 开发过程:Cursor 辅助的全栈开发



- 工具链:项目使用 Cursor 进行开发,结合了 Python(后端处理)和 pywebview(前端界面)。
- **AI 的角色 (Cursor Agent)**:
- 代码生成:负责生成繁琐的样板代码,例如
src/task_manager.py中的线程管理逻辑。 - 正则编写:在
src/parsers/qe_parser.py中,复杂的正则表达式(如匹配多样的日期格式r'(\d{1,2})\s+([A-Za-z]+)\s+(\d{4})')通常由 AI 初步生成,再由人工微调。 - 环境调试:帮助解决
pdf2image和fitz(PyMuPDF) 等库的依赖冲突问题。
- 代码生成:负责生成繁琐的样板代码,例如
整个系统架构分为三个阶段,每个阶段的人工与 AI 参与度不同:
第一阶段:PDF 预处理(人工逻辑主导)
开发背景:直接用 AI 处理几十页的 PDF 成本太高且速度慢,电脑跑不动
人工工作:
- 定义规则:定义了什么是“有效页面”。例如,对于 QE 账单,人工规定只提取从 “Statement Detail” 到 “Fee Summary” 之间的页面。
- 特征提取:在 PDF 文本中搜索特定关键词(如 “quinn emanuel”)来判断账单类型。
AI 工作:将上述逻辑落地成代码
第二阶段:核心识别(AI 能力主导)
开发背景:传统的 OCR 难以处理跨页表格和复杂排版。
人工工作:
- Prompt 工程:在
src/online_parser.py中,编写了严格的系统提示词(SYSTEM_PROMPT),强制 AI “保留所有表格结构,使用标准 Markdown 表格语法”,并禁止输出废话。 - 架构设计:设计了“在线模型”和“本地模型”两套策略的切换逻辑。
- Prompt 工程:在
AI 工作
- 在线模式:调用多模态大模型,利用视觉能力将图片形式的表格转换为 Markdown 文本。
- 本地模式:集成开源的
Marker模型,进行本地的 OCR 和布局分析。
第三阶段:数据结构化(人工与 AI 协作)
开发背景:AI 输出的 Markdown 是文本,需要转为数据库可存储的结构化数据。
- AI 工作:辅助编写正则表达式,用于从 Markdown 表格中提取“律师”“工时”“费率”等字段。
- 人工工作:
- 兜底逻辑:编写代码处理异常情况。例如,
SteptoeBillParser中处理表头包含<br>换行符的特殊情况,需要人工观察数据规律并调整逻辑。 - 数据清洗:编写逻辑移除金额中的货币符号(
CNY,$)和千位分隔符。
- 兜底逻辑:编写代码处理异常情况。例如,