debug: add pointCode fallback and console log

This commit is contained in:
2026-03-23 20:11:53 +08:00
parent 2fe773909e
commit daca126ee2
5 changed files with 29733 additions and 1 deletions
+8 -1
View File
@@ -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 === '签署乙方详细信息校验' && (
+332
View File
@@ -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, // 文档类型ID1=合同)
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 智能推荐 | ❌ 未规划 | 根据文档内容推荐合同类型 |
## 联系方式
如有疑问,请联系后端开发团队。
File diff suppressed because it is too large Load Diff
+23
View File
@@ -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"
]
}
}
}
+27928
View File
File diff suppressed because it is too large Load Diff