Files
Auto-Finance/docs/API.md
2026-06-09 16:25:20 +08:00

526 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
last_reviewed: 2026-06-09
---
# 财务报销自动化 — API 文档
> 基础地址: `http://localhost:5000`
> 启动: `uv run python src/web/app.py`
## 总览
| # | 方法 | 路径 | 说明 |
|---|------|------|------|
| 1 | GET | `/` | PC 端主页 |
| 2 | POST | `/api/session` | 创建会话 |
| 3 | POST | `/api/upload/<session_id>` | 上传文件PDF/图片) |
| 4 | POST | `/api/upload-csv/<session_id>` | 上传 CSV 发票数据 |
| 5 | GET | `/api/files/<session_id>` | 列出会话目录中的文件 |
| 6 | POST | `/api/process/<session_id>` | 启动处理(提取+LLM识别+出库单) |
| 7 | GET | `/api/logs/<session_id>` | SSE 日志流 |
| 8 | GET | `/api/download/<session_id>/<filename>` | 下载生成的文件 |
| 9 | GET | `/api/data/<session_id>` | 获取发票数据JSON |
| 10 | POST | `/api/save/<session_id>` | 保存编辑后的发票数据 |
| 11 | POST | `/api/submit-financial/<session_id>` | 提交到财务系统 |
| 12 | GET | `/mobile/<session_id>` | 移动端上传页面 |
| 13 | POST | `/api/mobile-upload/<session_id>` | 移动端上传图片 |
---
## 会话与目录
- 调用 `POST /api/session` 获得 `session_id`
- 该会话下所有文件存放在 `src/web/uploads/<session_id>/`
- 典型产物:`invoice_summary.csv``易耗品、出库单.doc``config.json``session.log``result.json`
---
## 接口详情
### 1. 创建会话
```
POST /api/session
```
**响应:**
```json
{ "session_id": "a1b2c3d4e5f6" }
```
---
### 2. 上传文件PDF/图片)
```
POST /api/upload/<session_id>
Content-Type: multipart/form-data
```
| 字段 | 类型 | 说明 |
|------|------|------|
| file | File | PDF 发票或支付截图 |
**响应(成功):**
```json
{ "ok": true, "filename": "1. 电容一批.pdf" }
```
**响应(失败):**
```json
{ "error": "未选择文件" }
```
HTTP `400`
---
### 3. 上传 CSV 发票数据
```
POST /api/upload-csv/<session_id>
Content-Type: multipart/form-data
```
| 字段 | 类型 | 说明 |
|------|------|------|
| file | File | 发票汇总 CSV |
**响应(成功):**
```json
{ "ok": true, "filename": "invoice_summary.csv" }
```
> 上传 CSV 后可跳过 PDF 提取和 LLM 识别,直接进入处理/编辑流程。
---
### 4. 列出会话文件
```
GET /api/files/<session_id>
```
**响应:**
```json
{
"pdfs": ["1. 电容一批.pdf"],
"images": ["payment_01.jpg"]
}
```
`images` 包含扩展名:`.png``.jpg``.jpeg``.bmp``.webp`
---
### 5. 启动管道处理
```
POST /api/process/<session_id>
Content-Type: application/json
```
**请求体:**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| mode | string | 否 | `"pdf"` / `"csv"` / `"auto"`(默认 `auto` |
| username | string | 否 | 财务系统工号 |
| password | string | 否 | 登录密码 |
| default_name | string | 否 | 默认报销人姓名 |
| default_card_no | string | 否 | 默认公务卡号 |
| default_person_id | string | 否 | 默认人员编号 |
| consumable_storage | string | 否 | 出库单存放地点;未填则用 `config.json` 中的值 |
**mode 行为:**
| mode | 行为 |
|------|------|
| `auto` | 仅有 CSV、无 PDF → CSV 模式;否则 → PDF 提取 + LLM 识别 |
| `csv` | 使用已上传 CSV跳过提取与 LLM 识别 |
| `pdf` | 执行 PDF 提取 + LLM 识别 |
**处理内容PDF 模式):**
1. 从会话目录 PDF 提取发票信息 → `invoice_summary.csv`
2. 对支付截图多模态 LLM 识别,回填刷卡字段
3. 根据发票类型自动分类:差旅发票(高铁票/酒店住宿)不生成出库单;普通发票从模板复制并自动填写
配置会写入 `src/web/uploads/<session_id>/config.json`
**响应(立即):**
```json
{ "status": "started" }
```
处理在后台线程执行,进度与结果通过 `GET /api/logs/<session_id>`SSE获取。
**SSE 完成时 `result` 示例(成功):**
```json
{
"ok": true,
"elapsed": "45.2s",
"invoice_count": 4,
"csv_url": "/api/download/<session_id>/invoice_summary.csv",
"travel_count": 2,
"general_count": 2,
"doc_url": "/api/download/<session_id>/%E6%98%93%E8%80%97%E5%93%81%E3%80%81%E5%87%BA%E5%BA%93%E5%8D%95.doc",
"doc_ok": true
}
```
**纯差旅发票(跳过出库单生成):**
```json
{
"ok": true,
"invoice_count": 3,
"csv_url": "/api/download/<session_id>/invoice_summary.csv",
"travel_count": 3,
"general_count": 0,
"doc_ok": null,
"doc_skipped": true,
"doc_message": "差旅发票无需生成易耗品出库单"
}
```
**出库单生成失败时CSV 等仍可能成功):**
```json
{
"ok": true,
"invoice_count": 4,
"csv_url": "/api/download/<session_id>/invoice_summary.csv",
"travel_count": 2,
"general_count": 2,
"doc_ok": false,
"doc_error": "服务器未安装 pywin32无法生成 Word 出库单"
}
```
**字段说明:**
| 字段 | 类型 | 说明 |
|------|------|------|
| `travel_count` | int | 差旅发票数量(高铁票/酒店住宿) |
| `general_count` | int | 普通发票数量 |
| `doc_ok` | bool/null | `true`=成功,`false`=失败,`null`=已跳过(纯差旅发票) |
| `doc_skipped` | bool | 是否因纯差旅发票而跳过出库单生成 |
| `doc_message` | string | 跳过时的提示信息 |
---
### 6. SSE 日志流
```
GET /api/logs/<session_id>
Accept: text/event-stream
```
**日志行格式:**
```
data: 2026-05-26 12:00:01 [INFO ] extractor: 正在提取发票...
```
**结束消息:**
```json
{
"type": "done",
"result": { }
}
```
`result` 结构取决于触发来源:
| 来源 | 典型字段 |
|------|----------|
| `/api/process` | `ok`, `elapsed`, `invoice_count`, `csv_url`, `travel_count`, `general_count`, `doc_url`, `doc_ok`, `doc_skipped`, `doc_error` |
| `/api/submit-financial` | `ok`, `submit_ok`, `submit_error` |
> SSE 超时时间为 10 分钟600 秒)。
---
### 7. 下载文件
```
GET /api/download/<session_id>/<filename>
```
**响应:** 文件二进制流,带 `Content-Disposition: attachment` 与 UTF-8 文件名。
| 扩展名 | Content-Type |
|--------|----------------|
| `.csv` | `text/csv; charset=utf-8` |
| `.doc` | `application/msword` |
| 其它 | `application/octet-stream` |
**常见文件名:**
| 文件名 | 说明 |
|--------|------|
| `invoice_summary.csv` | 发票汇总(含 LLM 识别结果) |
| `易耗品、出库单.doc` | 自动填写的出库单 |
| 用户上传的 CSV 名 | CSV 快捷模式下的原始文件 |
**错误:**
```json
{ "error": "文件不存在" }
```
HTTP `404``filename` 仅允许会话目录内的文件名(防止路径穿越)。
---
### 8. 获取发票数据
```
GET /api/data/<session_id>
```
**响应:**
```json
{
"csv_filename": "invoice_summary.csv",
"fields": [
"序号", "发票号码", "开票日期", "项目名称", "规格型号",
"价税合计", "销售方名称", "人员姓名", "刷卡日期",
"公务卡号", "刷卡金额", "备注", "工号"
],
"data": [
{
"__row": 0,
"序号": "1",
"发票号码": "26442000005432755951",
"价税合计": "2900.00"
}
]
}
```
- `fields`:列顺序
- `data[].__row`:内部行索引(保存时不需要提交,服务端按数组顺序写回)
**错误:** `404` 未找到 CSV`500` 读取失败。
---
### 9. 保存编辑后的发票数据
```
POST /api/save/<session_id>
Content-Type: application/json
```
**请求体:**
```json
{
"csv_filename": "invoice_summary.csv",
"data": [
{
"序号": "1",
"发票号码": "26442000005432755951",
"开票日期": "2026/05/18",
"项目名称": "...",
"规格型号": "...",
"价税合计": "2900.00",
"销售方名称": "...",
"人员姓名": "",
"刷卡日期": "2026/04/28",
"公务卡号": "",
"刷卡金额": "2850.00",
"备注": "",
"工号": "202407021"
}
]
}
```
**响应(成功):**
```json
{
"ok": true,
"doc_ok": true,
"doc_url": "/api/download/<session_id>/%E6%98%93%E8%80%97%E5%93%81%E3%80%81%E5%87%BA%E5%BA%93%E5%8D%95.doc"
}
```
保存后会根据最新 CSV **重新生成** 出库单 Word与会话 `config.json` 中的 `consumable_storage` 等配置一致)。
**纯差旅发票跳过出库单:**
```json
{
"ok": true,
"doc_ok": null,
"doc_skipped": true
}
```
**出库单生成失败:**
```json
{
"ok": true,
"doc_ok": false,
"doc_error": "出库单模板不存在,请将模板放在项目根目录"
}
```
---
### 10. 提交到财务系统
```
POST /api/submit-financial/<session_id>
```
**前置条件:**
- 会话目录存在 `config.json`(由 `/api/process` 写入),否则返回 `400`
- 存在可用的发票 CSV通常为 `invoice_summary.csv`
**说明:**
- 前端一般在提交前调用 `/api/save` 保存表格修改
- 本接口**不会**自动执行发票提取或 LLM 识别
- 根据发票类型选择填报模式:纯差旅发票走差旅报销流程,含普通发票走普通报销流程
**响应(立即):**
```json
{ "status": "started" }
```
**SSE 完成示例:**
```json
{
"type": "done",
"result": {
"ok": true,
"submit_ok": true
}
}
```
失败时 `submit_ok: false``submit_error` 为错误描述。
---
### 11. 移动端上传页面
```
GET /mobile/<session_id>
```
返回移动端 HTML 页面。扫码上传的图片与 PC 端共用同一会话目录PC 通过轮询 `GET /api/files/<session_id>` 同步文件列表。
---
### 12. 移动端上传图片
```
POST /api/mobile-upload/<session_id>
Content-Type: multipart/form-data
```
| 字段 | 类型 | 说明 |
|------|------|------|
| file | File | 图片文件 |
逻辑与 `POST /api/upload/<session_id>` 相同。
---
## 错误码汇总
| HTTP | 场景 |
|------|------|
| 400 | 参数缺失、未找到配置等 |
| 404 | `session_id` 不存在、文件不存在 |
| 500 | CSV 读取失败等内部错误 |
统一错误体:
```json
{ "error": "错误描述" }
```
---
## 发票类型分类
系统自动将发票分为两类,影响出库单生成和后续报销流程:
| 类型 | 判断依据 | 出库单 | 报销流程 |
|------|----------|--------|----------|
| 差旅发票 | 高铁票、酒店住宿等 | 不生成 | 差旅报销 |
| 普通发票 | 其他(办公用品、耗材等) | 自动生成 | 普通报销 |
`/api/process``/api/save` 的响应中 `travel_count` / `general_count` 即为分类统计。
---
## 端到端流程
```mermaid
sequenceDiagram
participant PC as PC 端
participant Server as Server
participant Mobile as 移动端
participant Word as Word COM
PC->>Server: POST /api/session
Server-->>PC: session_id
PC->>Server: POST /api/upload/{sid}
PC->>Server: POST /api/process/{sid}
Note over Server: PDF 提取 + LLM 识别 + 写 config.json
alt 含普通发票
Server->>Word: 从模板复制并填写出库单
else 纯差旅发票
Note over Server: 跳过出库单生成
end
Server-->>PC: SSE done (csv_url, doc_url, ...)
PC->>Server: GET /api/data/{sid}
Server-->>PC: fields + data
PC->>Server: POST /api/save/{sid}
Note over Server: 更新 CSV重新生成出库单
Server-->>PC: doc_url
PC->>Server: GET /api/download/{sid}/易耗品、出库单.doc
PC->>Server: POST /api/submit-financial/{sid}
Note over Server: Playwright 浏览器填报
Server-->>PC: SSE done (submit_ok)
Mobile->>Server: POST /api/mobile-upload/{sid}
PC->>Server: GET /api/files/{sid} (轮询)
```
---
## 相关 CLI
不经过 Web、在本地直接填写出库单
```bash
uv run python -m src.doc.fill_consumable_doc --csv invoice_summary.csv --doc "易耗品、出库单.doc"
```
详见 [README.md](./README.md)。