# 本地合同助手 · ContractAI Desktop

> 基于 Electron + React + DeepSeek 的本地合同智能识别、台账管理与 Agent Harness 可观测原型

**当前版本：v1.1 Agent Harness Observability**

---

## 功能特性

### 核心业务能力

- **合同智能识别**：上传 PDF 或图片，通过 PyMuPDF 提取文本，经 DeepSeek 大模型解析甲方、乙方、金额、付款条款及行项目明细
- **人机协同校对（Human-in-the-loop）**：AI 识别结果在前端可视化展示，支持逐字段、逐行项目编辑后归档
- **本地合同台账**：合同数据以 JSON 文件本地持久化，支持增删改查、关键词搜索、多选批量删除
- **可配置 Excel 导出**：根据公司模板（字段开关 + 业务模块）动态生成导出列，行项目扁平化输出
- **批量文件处理**：多文件队列，识别保存后自动处理下一个，全部完成后一键合并导出 Excel
- **API Key 安全管理**：密钥经 AES-256-CBC + 机器 ID 绑定加密存储，支持托管模式、自带 Key（BYO）和自定义 API 端点三种推理模式
- **商业化授权**：内置 5 次免费试用，支持激活码（`CONTRACT-XXXX-XXXX-XXXX` 格式，有效期 1 年）

### v1.1 新增：Agent Harness Observability

- **`_meta` 观测数据**：每次 AI 调用后记录模型名、Token 用量（prompt/completion/total）、响应延迟、提取方式、fallback 状态
- **`_trace` 识别轨迹**：主进程记录端到端识别步骤时间线（授权检查 → 路径校验 → Python 启动 → 模型调用 → JSON 解析），识别失败也保留轨迹
- **`_evaluation` 质量评估**：字段完整率、必填字段缺失列表、金额有效性、置信等级（high / medium / low）
- **HarnessPanel 面板**：review 页内嵌可折叠解析详情面板，展示以上全部观测数据
- **Failure Taxonomy**：12 种标准化失败类型枚举（`key_missing`、`api_timeout`、`pdf_no_text` 等）

---

## 技术栈

| 层级 | 技术 | 说明 |
|------|------|------|
| 桌面壳 | Electron 30 | `contextIsolation: true`，`nodeIntegration: false` |
| 前端 UI | React 18 + Vite 5 | 端口 5173 |
| 样式 | Tailwind CSS 3 | PostCSS + Autoprefixer |
| 图标库 | lucide-react | — |
| Excel 导出 | xlsx-js-style | 含 Node polyfills |
| AI 推理 | DeepSeek Chat API | `deepseek-chat`，支持自定义端点 |
| PDF 文本提取 | PyMuPDF（fitz） | Python 侧 |
| HTTP 客户端 | requests | Python 侧，含超时与错误捕获 |
| 本地存储 | JSON 文件 | contracts.json / template.json |
| 安全加密 | Node.js crypto（AES-256-CBC）+ node-machine-id | API Key 存储 |

---

## 目录结构

```
contract-desktop-app/
├── electron/
│   ├── main.js                # 主进程：窗口、IPC、Python 子进程、_trace 构建
│   ├── preload.js             # contextBridge 暴露 electronAPI
│   └── utils/
│       ├── licenseService.js  # 试用计数与激活码校验
│       ├── secureStorage.js   # API Key AES 加密存储
│       ├── safeJson.js        # 安全原子读写 JSON
│       ├── writeQueue.js      # 串行写入队列，防并发覆盖
│       └── pathValidator.js   # 文件路径安全校验（含类型/大小）
├── src/
│   ├── main.jsx               # React 入口
│   ├── App.jsx                # 根组件
│   ├── ContractExtractor.jsx  # 核心主界面（上传/识别/校对/台账/导出）
│   ├── Settings.jsx           # 设置页（模板/推理模式/License/数据备份）
│   ├── HarnessPanel.jsx       # ✨ v1.1 Agent 解析详情面板（新增）
│   └── assets/images/         # 应用图标等静态资源
├── python/
│   └── ai_service.py          # AI 服务：PyMuPDF + DeepSeek + _meta 观测
├── data/
│   ├── contracts.json         # 合同台账主数据（含 _trace / _evaluation）
│   └── template.json          # 导出字段与业务模块配置
├── ARCHITECTURE.md            # 完整架构文档
├── AGENT_HARNESS_V1_1.md      # ✨ v1.1 Harness 技术规格（新增）
├── index.html
├── vite.config.mts
└── package.json
```

---

## 快速开始

### 环境要求

- **Node.js** ≥ 18
- **Python** ≥ 3.9（需创建虚拟环境 `.venv`）
- **DeepSeek API Key**（可在 [platform.deepseek.com](https://platform.deepseek.com) 获取）

### 安装依赖

```bash
# 安装 Node 依赖
npm install

# 创建 Python 虚拟环境并安装依赖
python -m venv .venv
.venv\Scripts\pip install pymupdf requests
```

### 开发运行

```bash
npm run dev
```

同时启动 Vite 开发服务器（端口 5173）和 Electron 主进程。

### 生产打包

```bash
# 构建前端
npm run build

# 打包 Windows 安装包（需先安装 electron-builder）
npm install --save-dev electron-builder
npm run build:win
```

打包产物输出至 `release/`，包含 `dist/`、`electron/`、`python/`、`data/`。

---

## 使用流程

```
上传 PDF / 图片（支持批量）
        ↓
授权检查（试用次数 / 激活码 / 自带 Key）
        ↓
路径安全校验（pathValidator）
        ↓
Python 子进程：PyMuPDF 提取文本
        ↓
DeepSeek API：结构化解析（甲方、乙方、金额、行项目…）
        ↓     ↘ AI 失败时：正则兜底（基于文件名）
前端 Review 界面：人工核对与编辑
        ↓     ↗ HarnessPanel 展示解析轨迹与质量评估
保存至本地 contracts.json（含 _trace / _evaluation）
        ↓
历史台账查看 / 搜索 / 批量管理
        ↓
按公司模板导出 Excel
```

---

## 推理模式配置

在「设置 → 使用方式」中可选择三种模式：

| 模式 | 说明 |
|------|------|
| **托管模式**（managed） | 使用内置的共享 API 配额，无需配置 Key |
| **自带 Key**（BYO） | 填入个人 DeepSeek API Key，本地 AES 加密存储 |
| **自定义 API**（custom_api） | 指定任意兼容 OpenAI 格式的 API 端点与 Key |

---

## v1.1 Agent Harness 说明

### HarnessPanel（review 页内嵌面板）

识别完成后，review 页右侧校对表单上方会出现**可折叠的"Agent 解析详情"面板**，展示：

| 区块 | 内容 |
|------|------|
| 模型与耗时 | 模型名、AI 响应延迟、Token 用量（prompt ↑ / completion ↓） |
| 解析来源 | 来源标签（DeepSeek AI / 正则兜底）、提取方式、文本长度、推理模式 |
| 质量评估 | 字段完整率进度条、缺失必填字段（中文）、明细行数、金额有效性、置信等级 |
| Trace 时间线 | 二级折叠，展示每个步骤的状态、耗时、traceId |

若数据不存在（如编辑旧合同），面板显示"当前记录暂无解析轨迹"。

### contracts.json 新增字段（向后兼容）

v1.1 保存的合同在原有字段基础上，新增两个可选字段：

```json
{
  "header": { "...原有字段不变..." },
  "lineItems": [ "...原有字段不变..." ],
  "_trace": {
    "traceId": "trc_1748000000000",
    "steps": [
      { "event": "license_checked", "label": "授权检查", "status": "success", "durationMs": 3 },
      { "event": "path_validated",  "label": "路径校验",  "status": "success", "durationMs": 11 },
      { "event": "python_finished", "label": "Python 执行完成", "status": "success", "durationMs": 4180 },
      "..."
    ],
    "summary": {
      "totalDurationMs": 4280,
      "model": "deepseek-chat",
      "totalTokens": 1270,
      "latencyMs": 3240,
      "fallbackUsed": false,
      "inferenceMode": "byo"
    }
  },
  "_evaluation": {
    "fieldCompleteness": 0.833,
    "missingRequiredFields": ["signDate"],
    "amountValid": true,
    "lineItemCount": 3,
    "confidenceLevel": "medium",
    "totalTokens": 1270,
    "usageAvailable": true,
    "humanEdited": false
  }
}
```

> **向后兼容**：旧合同无 `_trace`/`_evaluation` 字段，读取与展示均不受影响。

### Failure Taxonomy

系统使用统一的失败类型枚举标注每次识别失败原因：

| failureType | 触发场景 |
|-------------|---------|
| `license_denied` | 试用次数用完或激活码过期 |
| `key_missing` | 未配置 API Key |
| `path_invalid` | 文件路径不合法或文件不存在 |
| `file_type_rejected` | 上传了不支持的文件格式 |
| `python_crash` | Python 子进程异常退出 |
| `api_timeout` | DeepSeek API 请求超时（60s） |
| `api_http_error` | HTTP 4xx / 5xx 错误 |
| `pdf_no_text` | PDF 无文字层（扫描件），已退化为 fallback |
| `json_parse_failed` | 无法从输出中提取有效 JSON |
| `unknown` | 未分类异常 |

---

## 数据格式参考

### contracts.json

```json
{
  "meta": { "app": "ContractAI", "version": "1.5", "lastModified": "ISO时间" },
  "contracts": [
    {
      "header": {
        "id": "1748000000000",
        "externalNo": "HT-2025-001",
        "title": "采购合同",
        "partyA": "甲方公司",
        "partyB": "乙方公司",
        "signDate": "2025-01-01",
        "amount": 100000,
        "currency": "CNY",
        "paymentTerms": "货到付款",
        "contractStatus": "archived",
        "createdAt": "ISO时间",
        "updatedAt": "ISO时间"
      },
      "lineItems": [
        {
          "lineId": "1",
          "objectName": "物品名称",
          "spec": "规格型号",
          "unit": "个",
          "quantity": 10,
          "unitPrice": 1000.00,
          "lineTotal": 10000.00,
          "remark": "备注",
          "lineStatus": "draft"
        }
      ],
      "_trace": { "...识别轨迹（v1.1 新增，可选）..." },
      "_evaluation": { "...质量评估（v1.1 新增，可选）..." }
    }
  ]
}
```

### template.json

```json
{
  "fixedFieldToggles": {
    "contractNo": true,
    "title": true,
    "partyA": true,
    "partyB": true,
    "signDate": true,
    "amount": true,
    "currency": false,
    "paymentTerms": false
  },
  "enabledModules": ["project"]
}
```

---

## License 与授权

- **免费试用**：安装后可免费识别 **5 次**
- **激活码**：格式 `CONTRACT-XXXX-XXXX-XXXX`，激活后有效期 **1 年**
- 切换到「自带 Key」或「自定义 API」模式后，不消耗试用次数
- License 文件：`%APPDATA%/本地合同助手/license.json`
- API Key 加密文件：`%APPDATA%/本地合同助手/secure_config.json`

---

## 数据备份与恢复

在「设置 → 数据备份」中可以：

- **导出备份**：将 `contracts.json` 导出为本地 JSON 文件
- **导入合并**：追加备份文件中的新合同（重复 ID 自动跳过）
- **导入覆盖**：用备份文件完全替换当前数据（不可撤销）

---

## 开发说明

- 主进程与渲染进程通过 `contextBridge` 通信，所有 `electronAPI` 方法均定义于 `electron/preload.js`
- Python 子进程由主进程通过 `execFile` 调用，API Key 通过**环境变量**注入（不暴露于命令行或日志）
- v1.1 起，`ai_service.py` 返回的 JSON 新增顶层 `_meta` 字段；主进程 IPC handler 新增 `_trace` 字段；均向后兼容
- 写入操作经 `writeQueue` 串行化，`safeJson` 原子写入，防数据损坏

---

## 常见问题

**Q: 识别结果为空或报错？**  
A: 检查 `.venv` 是否正确创建并安装了 `pymupdf` 和 `requests`；检查 DeepSeek API Key 是否有效；查看 review 页 HarnessPanel 面板的失败类型提示。

**Q: HarnessPanel 显示"当前记录暂无解析轨迹"？**  
A: 这是正常的降级状态，通常出现在：编辑旧版本合同（v1.1 前保存的）、或识别链路在 trace 构建前就已失败。

**Q: Token 用量显示"不可用"？**  
A: 当 DeepSeek API 响应体不含 `usage` 字段时（部分自定义端点），`usageAvailable` 为 false，Token 显示"不可用"，不影响识别结果。

**Q: 扫描版 PDF 无法识别文字？**  
A: 当前使用 PyMuPDF 提取文字层，扫描件（纯图片 PDF）提取结果为空，AI 将以文件名为线索进行推断，HarnessPanel 将显示 `pdf_no_text` 失败类型和"Fallback"标签。

**Q: 如何自定义导出 Excel 的字段？**  
A: 进入「设置 → 公司模板」，勾选需要导出的字段和业务模块，保存后导出即生效。

---

## 路线图

- [x] v1.0：PDF 识别 → 人工校对 → 台账管理 → Excel 导出 → 安全存储
- [x] **v1.1：Agent Harness Observability（_meta / _trace / _evaluation / HarnessPanel / Failure Taxonomy）**
- [ ] v1.2：Human Delta（AI vs 用户修改对比）、Dashboard 聚合指标
- [ ] v2.0：SQLite 迁移、行项目标准化、历史价格比对、异常金额预警

---

## License

本项目为私有商业软件，未经授权禁止分发或商用。
