debug: add pointCode fallback and console log
This commit is contained in:
@@ -781,6 +781,11 @@ export function ReviewPointsList({
|
||||
* 过滤评查点
|
||||
* 根据搜索文本和状态过滤条件筛选评查点
|
||||
*/
|
||||
// DEBUG: check pointCode
|
||||
if (reviewPoints.length > 0) {
|
||||
console.log('[DEBUG pointCode]', reviewPoints[0].pointName, 'pointCode:', reviewPoints[0].pointCode, 'keys:', Object.keys(reviewPoints[0]).filter(k => k.includes('ode') || k.includes('Code')));
|
||||
}
|
||||
|
||||
const filteredReviewPoints = reviewPoints.filter(point => {
|
||||
// 匹配搜索文本
|
||||
const matchesSearch = searchText === '' ||
|
||||
@@ -2745,8 +2750,10 @@ export function ReviewPointsList({
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
{/* <div className='flex flex-col'> */}
|
||||
<div className="flex items-center gap-2 max-w-[75%]">
|
||||
{reviewPoint.pointCode && (
|
||||
{reviewPoint.pointCode ? (
|
||||
<span className="text-[10px] font-mono bg-gray-100 text-gray-500 px-1 py-0.5 rounded flex-shrink-0">{reviewPoint.pointCode}</span>
|
||||
) : (
|
||||
<span className="text-[10px] font-mono bg-gray-100 text-gray-400 px-1 py-0.5 rounded flex-shrink-0">#{reviewPoint.pointId || reviewPoint.id}</span>
|
||||
)}
|
||||
<div className="review-point-title text-left text-blue-500 break-all">{reviewPoint.pointName}</div>
|
||||
{ reviewPoint.pointName === '签署乙方详细信息校验' && (
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
# 用户自定义合同类型 - 前后端对接文档
|
||||
|
||||
## 概述
|
||||
|
||||
为了优化 GraphRAG 抽取管道的规则加载,后端新增了 `attribute_type`(合同专属类型)参数支持。当指定该参数时,系统只加载 **通用 + 指定类型** 的评查点规则,大幅减少无关字段(816 → ~197),提升检索精度和抽取稳定性。
|
||||
|
||||
## 后端修改内容
|
||||
|
||||
### 1. 文档类型自动检测(`contract_server.py`)
|
||||
|
||||
**文件**: `services/documents/v2/contract_server.py`
|
||||
|
||||
**新增方法**: `_detect_attribute_type()`
|
||||
|
||||
```python
|
||||
@staticmethod
|
||||
def _detect_attribute_type(filename: str) -> Optional[str]:
|
||||
"""
|
||||
从文件名关键词检测合同专属子类型。
|
||||
|
||||
关键词表与 executor._CONTRACT_TYPE_KEYWORDS 保持一致。
|
||||
返回: "技术"/"租赁"/"买卖"/... 或 None
|
||||
"""
|
||||
_KEYWORDS = [
|
||||
("买卖", ["采购", "买卖", "购销", "供货", "购买"]),
|
||||
("租赁", ["租赁", "租用", "出租"]),
|
||||
("服务", ["服务", "咨询", "顾问"]),
|
||||
("委托", ["委托", "代理"]),
|
||||
("建设工程", ["建设工程", "施工", "装修", "装饰"]),
|
||||
("培训", ["培训", "教育", "教学"]),
|
||||
("技术", ["技术", "开发", "软件", "系统集成", "信息化"]),
|
||||
("赠与", ["赠与", "捐赠"]),
|
||||
("运输", ["运输", "物流", "配送", "搬运"]),
|
||||
("仓储", ["仓储", "存储", "保管"]),
|
||||
("合作", ["合作", "联营", "合资"]),
|
||||
("承揽", ["承揽", "加工", "定作"]),
|
||||
]
|
||||
if not filename:
|
||||
return None
|
||||
for type_code, keywords in _KEYWORDS:
|
||||
for kw in keywords:
|
||||
if kw in filename:
|
||||
return type_code
|
||||
return None
|
||||
```
|
||||
|
||||
**调用位置**: `extract()` 方法(约 L455)
|
||||
|
||||
```python
|
||||
# 确定合同专属子类型(用于精准加载规则)
|
||||
_attribute_type = self._detect_attribute_type(self.filename)
|
||||
if _attribute_type:
|
||||
log.document.info(
|
||||
f"[GraphRAG] doc={self.document_id} 合同子类型: {_attribute_type}"
|
||||
)
|
||||
|
||||
rag_result = await rag_service.extract(
|
||||
...
|
||||
attribute_type=_attribute_type,
|
||||
)
|
||||
```
|
||||
|
||||
### 2. GraphRAG 抽取服务支持(`rag_extraction_service.py`)
|
||||
|
||||
**文件**: `services/graph_rag/rag_extraction_service.py`
|
||||
|
||||
**修改点 1**: `extract()` 方法签名新增 `attribute_type` 参数(约 L175)
|
||||
|
||||
```python
|
||||
async def extract(
|
||||
self,
|
||||
...
|
||||
attribute_type: Optional[str] = None, # 新增参数
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Args:
|
||||
...
|
||||
attribute_type: 合同专属子类型(如"技术""租赁"),由上游指定,
|
||||
用于只加载 通用+该类型 的评查点规则,减少无关字段
|
||||
"""
|
||||
```
|
||||
|
||||
**修改点 2**: `_load_extraction_rules()` 方法新增类型过滤逻辑(约 L901)
|
||||
|
||||
```python
|
||||
# 指定了合同子类型时,只加载 通用+该类型(大幅减少无关字段)
|
||||
if attribute_type:
|
||||
_ep_filters["document_attribute_type"] = f"in.(通用,{attribute_type})"
|
||||
```
|
||||
|
||||
### 3. 支持的合同类型
|
||||
|
||||
| 类型代码 | 类型名称 | 关键词(文件名检测) |
|
||||
|---------|---------|---------------------|
|
||||
| `通用` | 通用类型 | 默认类型 |
|
||||
| `买卖` | 买卖合同 | 采购、买卖、购销、供货、购买 |
|
||||
| `租赁` | 租赁合同 | 租赁、租用、出租 |
|
||||
| `服务` | 服务合同 | 服务、咨询、顾问 |
|
||||
| `委托` | 委托合同 | 委托、代理 |
|
||||
| `建设工程` | 建设工程合同 | 建设工程、施工、装修、装饰 |
|
||||
| `培训` | 培训合同 | 培训、教育、教学 |
|
||||
| `技术` | 技术合同 | 技术、开发、软件、系统集成、信息化 |
|
||||
| `赠与` | 赠与合同 | 赠与、捐赠 |
|
||||
| `运输` | 运输合同 | 运输、物流、配送、搬运 |
|
||||
| `仓储` | 仓储合同 | 仓储、存储、保管 |
|
||||
| `合作` | 合作合同 | 合作、联营、合资 |
|
||||
| `承揽` | 承揽合同 | 承揽、加工、定作 |
|
||||
|
||||
## 前端对接指南
|
||||
|
||||
### 当前自动检测机制
|
||||
|
||||
**现状**: 后端已实现从**文件名**自动检测合同类型的逻辑。
|
||||
|
||||
例如:
|
||||
- `技术合同(去空格).docx` → 自动识别为 `技术` 类型
|
||||
- `房屋租赁合同.pdf` → 自动识别为 `租赁` 类型
|
||||
- `货物采购合同.docx` → 自动识别为 `买卖` 类型
|
||||
|
||||
### 前端手动指定合同类型(需后端额外支持)
|
||||
|
||||
**注意**: 当前后端尚未支持从 `upload_info` 中读取 `attribute_type` 参数。如需前端手动指定,需要进行以下额外修改:
|
||||
|
||||
#### 方案 A:修改上传接口传递 attribute_type
|
||||
|
||||
**1. 前端上传时传递参数**
|
||||
|
||||
```javascript
|
||||
// 示例:使用 FormData 上传
|
||||
const formData = new FormData();
|
||||
formData.append('file', fileBlob);
|
||||
|
||||
// 在 upload_info 中指定合同类型
|
||||
const uploadInfo = {
|
||||
type_id: 1, // 文档类型ID(1=合同)
|
||||
document_number: "HT2024001", // 合同编号
|
||||
attribute_type: "技术", // 👈 手动指定合同类型
|
||||
evaluation_level: "普通",
|
||||
remark: "测试合同"
|
||||
};
|
||||
formData.append('upload_info', JSON.stringify(uploadInfo));
|
||||
|
||||
// 调用上传接口
|
||||
const response = await fetch('/api/v2/documents/upload', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
},
|
||||
body: formData
|
||||
});
|
||||
```
|
||||
|
||||
**2. 后端需要额外修改的位置**
|
||||
|
||||
##### 2.1 修改 `contract_server.py` 的 `process_contract()` 方法
|
||||
|
||||
在约 L455 处,优先使用用户指定的类型:
|
||||
|
||||
```python
|
||||
# 确定合同专属子类型(用于精准加载规则)
|
||||
# 优先级:用户指定 > 文件名检测
|
||||
_attribute_type = None
|
||||
|
||||
# 1. 尝试从 upload_info 获取用户指定类型(需要传入)
|
||||
# if hasattr(self, 'upload_info') and self.upload_info:
|
||||
# _attribute_type = self.upload_info.get('attribute_type')
|
||||
|
||||
# 2. 文件名自动检测(当前已实现)
|
||||
if not _attribute_type:
|
||||
_attribute_type = self._detect_attribute_type(self.filename)
|
||||
|
||||
if _attribute_type:
|
||||
log.document.info(
|
||||
f"[GraphRAG] doc={self.document_id} 合同子类型: {_attribute_type} "
|
||||
f"({'用户指定' if hasattr(self, 'upload_info') and self.upload_info and self.upload_info.get('attribute_type') == _attribute_type else '文件名检测'})"
|
||||
)
|
||||
```
|
||||
|
||||
##### 2.2 修改 `tasks.py` 的 `process_contract_markdown()` 任务
|
||||
|
||||
在约 L1092 处,将 `attribute_type` 传递给 ContractMarkdownServer:
|
||||
|
||||
```python
|
||||
# 获取用户指定的合同类型(如果有的话)
|
||||
attribute_type = upload_info.get("attribute_type")
|
||||
|
||||
# 创建处理服务
|
||||
contract_server = ContractMarkdownServer(
|
||||
document_id=document_id,
|
||||
file_path=temp_path,
|
||||
filename=filename,
|
||||
template_id=template_id,
|
||||
user_area=user_area,
|
||||
user_role=user_role,
|
||||
attribute_type=attribute_type, # 👈 新增参数
|
||||
)
|
||||
```
|
||||
|
||||
##### 2.3 修改 `ContractMarkdownServer` 类
|
||||
|
||||
**文件**: `services/documents/v2/contract_markdown_server.py`
|
||||
|
||||
```python
|
||||
class ContractMarkdownServer:
|
||||
def __init__(
|
||||
self,
|
||||
...
|
||||
attribute_type: Optional[str] = None, # 新增参数
|
||||
):
|
||||
...
|
||||
self.attribute_type = attribute_type
|
||||
|
||||
async def process_contract(self):
|
||||
...
|
||||
# 在调用 ContractServer.extract() 时传递 attribute_type
|
||||
# (具体实现取决于 ContractMarkdownServer 如何调用 ContractServer)
|
||||
```
|
||||
|
||||
### API 接口说明
|
||||
|
||||
#### 上传文档接口
|
||||
|
||||
**URL**: `POST /api/v2/documents/upload`
|
||||
|
||||
**Content-Type**: `multipart/form-data`
|
||||
|
||||
**参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|-------|------|------|------|
|
||||
| `file` | File | 是 | 上传的文件(PDF/Word) |
|
||||
| `upload_info` | String(JSON) | 否 | 上传信息 JSON 字符串 |
|
||||
| `attachments` | File[] | 否 | 附件文件列表 |
|
||||
|
||||
**upload_info 结构**:
|
||||
|
||||
```json
|
||||
{
|
||||
"type_id": 1, // 文档类型ID:1=合同,2=案卷
|
||||
"document_number": "HT2024001", // 合同编号(可选)
|
||||
"attribute_type": "技术", // 合同专属类型(可选,待后端支持)
|
||||
"evaluation_level": "普通", // 评查级别(可选)
|
||||
"is_test_document": true, // 是否测试文档(可选)
|
||||
"remark": "备注信息" // 备注(可选)
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"result": {
|
||||
"document_id": 2751,
|
||||
"document_number": "HT2024001",
|
||||
"file_name": "技术合同(去空格).docx",
|
||||
"file_url": "documents/.../xxx.docx",
|
||||
"status": "Queued",
|
||||
"type_id": 1,
|
||||
"doc_type": "HT",
|
||||
"doc_type_description": "合同",
|
||||
"api_version": "v2",
|
||||
"is_test_document": true,
|
||||
"remark": "",
|
||||
"evaluation_level": "普通"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 可用的合同类型值(attribute_type)
|
||||
|
||||
前端下拉选项建议:
|
||||
|
||||
```javascript
|
||||
const CONTRACT_TYPES = [
|
||||
{ value: "通用", label: "通用合同" },
|
||||
{ value: "技术", label: "技术合同" },
|
||||
{ value: "租赁", label: "租赁合同" },
|
||||
{ value: "买卖", label: "买卖合同" },
|
||||
{ value: "服务", label: "服务合同" },
|
||||
{ value: "委托", label: "委托合同" },
|
||||
{ value: "建设工程", label: "建设工程合同" },
|
||||
{ value: "培训", label: "培训合同" },
|
||||
{ value: "赠与", label: "赠与合同" },
|
||||
{ value: "运输", label: "运输合同" },
|
||||
{ value: "仓储", label: "仓储合同" },
|
||||
{ value: "合作", label: "合作合同" },
|
||||
{ value: "承揽", label: "承揽合同" }
|
||||
];
|
||||
```
|
||||
|
||||
## 验证方式
|
||||
|
||||
### 1. 查看日志确认类型检测
|
||||
|
||||
上传文档后,查看日志确认合同类型识别:
|
||||
|
||||
```
|
||||
[DOCUMENT] [GraphRAG] doc=2751 合同子类型: 技术
|
||||
```
|
||||
|
||||
### 2. 查看规则加载情况
|
||||
|
||||
```
|
||||
[EXTRACTION] [RAG Rules] GROUP路径加载 197 个评查点 (过滤: 通用+技术), 子类型分布: {...}
|
||||
```
|
||||
|
||||
- **未指定类型**: 加载 816 个评查点(所有类型)
|
||||
- **指定类型**: 加载 ~197 个评查点(通用+指定类型)
|
||||
|
||||
### 3. 评查点过滤验证
|
||||
|
||||
某些专属评查点会根据类型过滤:
|
||||
|
||||
| 评查点 | 类型 | 行为 |
|
||||
|--------|------|------|
|
||||
| EP-089 技术内容-技术方案 | 技术 | 仅技术合同加载 |
|
||||
| EP-091 技术内容-技术指标 | 技术 | 仅技术合同加载 |
|
||||
| EP-020 违约责任条款完整性 | 通用 | 所有合同都加载 |
|
||||
|
||||
## 待实现功能(需后端额外开发)
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 文件名自动检测 | ✅ 已实现 | 后端从文件名关键词自动识别 |
|
||||
| 前端手动指定 | ⚠️ 待实现 | 需修改 `contract_server.py` 和 `tasks.py` |
|
||||
| 用户历史记录 | ❌ 未规划 | 记录用户常用合同类型,自动填充 |
|
||||
| AI 智能推荐 | ❌ 未规划 | 根据文档内容推荐合同类型 |
|
||||
|
||||
## 联系方式
|
||||
|
||||
如有疑问,请联系后端开发团队。
|
||||
+1442
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"plugin": ["superpowers@git+https://github.com/obra/superpowers.git"],
|
||||
"mcp": {
|
||||
"docauditai": {
|
||||
"type": "local",
|
||||
"command": [
|
||||
"npx",
|
||||
"@henkey/postgres-mcp-server",
|
||||
"--connection-string"
|
||||
]
|
||||
},
|
||||
"postgres-db": {
|
||||
"type": "local",
|
||||
"command": [
|
||||
"npx",
|
||||
"@henkey/postgres-mcp-server",
|
||||
"--connection-string",
|
||||
"postgresql://docauditai_admin:zhfw*123*@nas.7bm.co:54302/docauditai"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+27928
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user