Files
HaHafeng bbf98c4d5c fix(backend): Resolve PgBoss infinite loop issue and cleanup unused files
Backend fixes:
- Fix PgBoss task infinite loop on SAE (root cause: missing queue table constraints)
- Add singletonKey to prevent duplicate job enqueueing
- Add idempotency check in reviewWorker (skip completed tasks)
- Add optimistic locking in reviewService (atomic status update)

Frontend fixes:
- Add isSubmitting state to prevent duplicate submissions in RVW Dashboard
- Fix API baseURL in knowledgeBaseApi (relative path)

Cleanup (removed):
- Old frontend/ directory (migrated to frontend-v2)
- python-microservice/ (unused, replaced by extraction_service)
- Root package.json and node_modules (accidentally created)
- redcap-docker-dev/ (external dependency)
- Various temporary files and outdated docs in root

New documentation:
- docs/07-运维文档/01-PgBoss队列监控与维护.md
- docs/07-运维文档/02-故障预防检查清单.md
- docs/07-运维文档/03-数据库迁移注意事项.md

Database fix applied to RDS:
- Added PRIMARY KEY to platform_schema.queue
- Added 3 missing foreign key constraints

Tested: Local build passed, RDS constraints verified
2026-01-27 18:16:22 +08:00

1373 lines
31 KiB
Markdown
Raw Permalink 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.
# AI智能文献模块 - API设计规范
> **文档版本:** v3.0
> **创建日期:** 2025-10-29
> **维护者:** AI智能文献开发团队
> **最后更新:** 2025-11-23
> **更新说明:** 新增全文复筛API5个核心接口
---
## 📋 文档说明
本文档描述AI智能文献模块的API设计规范包括接口定义、请求响应格式、错误处理等。
**API基础信息**:
- **Base URL**: `http://localhost:3001` (开发环境)
- **API前缀**: `/api/v1/asl`
- **协议**: HTTP/HTTPS
- **数据格式**: JSON
- **认证方式**: JWT Token (测试阶段支持默认用户)
---
## 🔌 API设计原则
1. **RESTful设计**: 遵循RESTful API设计规范
2. **统一响应格式**: `{ success: boolean, data?: any, error?: string }`
3. **分页支持**: 列表接口支持分页参数
4. **版本控制**: API版本化管理 (`/api/v1/...`)
5. **错误处理**: 统一的HTTP状态码和错误消息
6. **模块化路由**: `/api/v1/asl/...` 独立路由空间
---
## 📡 核心API接口
### 1. 项目管理 (Projects)
#### 1.1 创建筛选项目
**接口**: `POST /api/v1/asl/projects`
**认证**: 需要 (测试阶段默认用户ID)
**说明**: 创建一个新的文献筛选项目
**请求体**:
```json
{
"projectName": "SGLT2抑制剂系统综述",
"picoCriteria": {
"P": "2型糖尿病成人患者",
"I": "SGLT2抑制剂empagliflozin、dapagliflozin等",
"C": "安慰剂或常规降糖疗法",
"O": "心血管结局MACE、心衰住院、心血管死亡",
"S": "随机对照试验 (RCT)"
},
"inclusionCriteria": "英文文献RCT研究2010年后发表",
"exclusionCriteria": "病例报告,综述,动物实验",
"screeningConfig": {
"models": ["deepseek-chat", "qwen-max"],
"temperature": 0
}
}
```
**响应示例**:
```json
{
"success": true,
"data": {
"id": "d67f0b9a-b035-4804-aca1-0bd672c27d81",
"userId": "asl-test-user-001",
"projectName": "SGLT2抑制剂系统综述",
"picoCriteria": {
"population": "2型糖尿病成人患者",
"intervention": "SGLT2抑制剂",
"comparison": "安慰剂或常规降糖疗法",
"outcome": "心血管结局",
"studyDesign": "随机对照试验 (RCT)"
},
"inclusionCriteria": "英文文献RCT研究2010年后发表",
"exclusionCriteria": "病例报告,综述,动物实验",
"status": "draft",
"screeningConfig": {
"models": ["deepseek-chat", "qwen-max"],
"temperature": 0
},
"createdAt": "2025-11-18T07:30:00.000Z",
"updatedAt": "2025-11-18T07:30:00.000Z"
}
}
```
**测试命令**:
```bash
curl -X POST http://localhost:3001/api/v1/asl/projects \
-H "Content-Type: application/json" \
-d '{
"projectName": "测试项目",
"picoCriteria": {
"population": "成人患者",
"intervention": "药物A",
"comparison": "安慰剂",
"outcome": "主要结局",
"studyDesign": "RCT"
},
"inclusionCriteria": "英文文献",
"exclusionCriteria": "综述"
}'
```
---
#### 1.2 获取项目列表
**接口**: `GET /api/v1/asl/projects`
**认证**: 需要
**说明**: 获取当前用户的所有筛选项目
**查询参数**: 无
**响应示例**:
```json
{
"success": true,
"data": [
{
"id": "d67f0b9a-b035-4804-aca1-0bd672c27d81",
"userId": "asl-test-user-001",
"projectName": "SGLT2抑制剂系统综述",
"picoCriteria": {...},
"status": "screening",
"createdAt": "2025-11-18T07:30:00.000Z",
"updatedAt": "2025-11-18T07:35:00.000Z",
"_count": {
"literatures": 3,
"screeningResults": 3
}
}
]
}
```
**测试命令**:
```bash
curl http://localhost:3001/api/v1/asl/projects
```
---
#### 1.3 获取项目详情
**接口**: `GET /api/v1/asl/projects/:projectId`
**认证**: 需要
**说明**: 获取指定项目的详细信息
**路径参数**:
- `projectId`: 项目ID (UUID)
**响应示例**:
```json
{
"success": true,
"data": {
"id": "d67f0b9a-b035-4804-aca1-0bd672c27d81",
"userId": "asl-test-user-001",
"projectName": "SGLT2抑制剂系统综述",
"picoCriteria": {
"population": "2型糖尿病成人患者",
"intervention": "SGLT2抑制剂",
"comparison": "安慰剂或常规降糖疗法",
"outcome": "心血管结局",
"studyDesign": "随机对照试验 (RCT)"
},
"inclusionCriteria": "英文文献RCT研究2010年后发表",
"exclusionCriteria": "病例报告,综述,动物实验",
"status": "screening",
"screeningConfig": {
"models": ["deepseek-chat", "qwen-max"],
"temperature": 0
},
"createdAt": "2025-11-18T07:30:00.000Z",
"updatedAt": "2025-11-18T07:35:00.000Z",
"_count": {
"literatures": 3,
"screeningResults": 3,
"screeningTasks": 1
}
}
}
```
**测试命令**:
```bash
curl http://localhost:3001/api/v1/asl/projects/{projectId}
```
---
#### 1.4 更新项目
**接口**: `PUT /api/v1/asl/projects/:projectId`
**认证**: 需要
**说明**: 更新项目信息
**路径参数**:
- `projectId`: 项目ID (UUID)
**请求体**(支持部分更新):
```json
{
"projectName": "更新后的项目名称",
"status": "screening",
"inclusionCriteria": "更新后的纳入标准"
}
```
**响应示例**:
```json
{
"success": true,
"data": {
"id": "d67f0b9a-b035-4804-aca1-0bd672c27d81",
"projectName": "更新后的项目名称",
"status": "screening",
...
}
}
```
**测试命令**:
```bash
curl -X PUT http://localhost:3001/api/v1/asl/projects/{projectId} \
-H "Content-Type: application/json" \
-d '{"status": "screening"}'
```
---
#### 1.5 删除项目
**接口**: `DELETE /api/v1/asl/projects/:projectId`
**认证**: 需要
**说明**: 删除项目及所有关联数据(级联删除)
**路径参数**:
- `projectId`: 项目ID (UUID)
**响应示例**:
```json
{
"success": true,
"message": "Project deleted successfully"
}
```
**测试命令**:
```bash
curl -X DELETE http://localhost:3001/api/v1/asl/projects/{projectId}
```
---
### 2. 文献管理 (Literatures)
#### 2.1 导入文献JSON格式
**接口**: `POST /api/v1/asl/literatures/import`
**认证**: 需要
**说明**: 批量导入文献JSON格式
**请求体**:
```json
{
"projectId": "d67f0b9a-b035-4804-aca1-0bd672c27d81",
"literatures": [
{
"pmid": "12345678",
"title": "Efficacy of SGLT2 inhibitors in type 2 diabetes",
"abstract": "Background: SGLT2 inhibitors are a new class...",
"authors": "Smith J, Jones A, Brown B",
"journal": "New England Journal of Medicine",
"publicationYear": 2020,
"doi": "10.1056/NEJMoa1234567"
},
{
"title": "Another study on SGLT2 inhibitors",
"abstract": "Objective: To evaluate...",
"authors": "Johnson M",
"journal": "The Lancet",
"publicationYear": 2019
}
]
}
```
**响应示例**:
```json
{
"success": true,
"data": {
"importedCount": 2
}
}
```
**字段说明**:
- `pmid`: PubMed ID (可选)
- `title`: 文献标题 (必填)
- `abstract`: 摘要 (必填)
- `authors`: 作者 (可选)
- `journal`: 期刊 (可选)
- `publicationYear`: 发表年份 (可选)
- `doi`: DOI (可选)
**测试命令**:
```bash
curl -X POST http://localhost:3001/api/v1/asl/literatures/import \
-H "Content-Type: application/json" \
-d '{
"projectId": "{projectId}",
"literatures": [
{
"title": "测试文献",
"abstract": "这是测试摘要"
}
]
}'
```
---
#### 2.2 导入文献Excel文件
**接口**: `POST /api/v1/asl/literatures/import-excel`
**认证**: 需要
**说明**: 从Excel文件批量导入文献
**请求类型**: `multipart/form-data`
**表单字段**:
- `file`: Excel文件 (.xlsx)
- `projectId`: 项目ID
**Excel格式要求**:
| 列名(中英文均可) | 必填 | 说明 |
|------------------|------|------|
| PMID / pmid / PMID编号 | 否 | PubMed ID |
| Title / title / 标题 | 是 | 文献标题 |
| Abstract / abstract / 摘要 | 是 | 摘要 |
| Authors / authors / 作者 | 否 | 作者 |
| Journal / journal / 期刊 | 否 | 期刊名称 |
| Year / year / 年份 | 否 | 发表年份 |
| DOI / doi | 否 | DOI |
**响应示例**:
```json
{
"success": true,
"data": {
"importedCount": 15,
"totalRows": 15
}
}
```
**测试命令**:
```bash
curl -X POST http://localhost:3001/api/v1/asl/literatures/import-excel \
-F "file=@literatures.xlsx" \
-F "projectId={projectId}"
```
---
#### 2.3 获取文献列表
**接口**: `GET /api/v1/asl/projects/:projectId/literatures`
**认证**: 需要
**说明**: 获取项目的文献列表(支持分页)
**路径参数**:
- `projectId`: 项目ID (UUID)
**查询参数**:
- `page`: 页码(默认: 1
- `limit`: 每页数量(默认: 50最大: 100
**响应示例**:
```json
{
"success": true,
"data": {
"literatures": [
{
"id": "lit-uuid-001",
"projectId": "d67f0b9a-b035-4804-aca1-0bd672c27d81",
"pmid": "12345678",
"title": "Efficacy of SGLT2 inhibitors...",
"abstract": "Background: SGLT2 inhibitors...",
"authors": "Smith J, Jones A",
"journal": "NEJM",
"publicationYear": 2020,
"doi": "10.1056/NEJMoa1234567",
"createdAt": "2025-11-18T07:32:00.000Z",
"screeningResults": [
{
"conflictStatus": "none",
"finalDecision": "include"
}
]
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 3,
"totalPages": 1
}
}
}
```
**测试命令**:
```bash
curl "http://localhost:3001/api/v1/asl/projects/{projectId}/literatures?page=1&limit=50"
```
---
#### 2.4 删除文献
**接口**: `DELETE /api/v1/asl/literatures/:literatureId`
**认证**: 需要
**说明**: 删除指定文献(级联删除筛选结果)
**路径参数**:
- `literatureId`: 文献ID (UUID)
**响应示例**:
```json
{
"success": true,
"message": "Literature deleted successfully"
}
```
**测试命令**:
```bash
curl -X DELETE http://localhost:3001/api/v1/asl/literatures/{literatureId}
```
---
### 3. 筛选任务管理 (Screening Tasks)
> **注意**: 以下接口为待实现功能Week 2计划
#### 3.1 启动筛选任务
**接口**: `POST /api/v1/asl/projects/:projectId/screening/start`
**认证**: 需要
**说明**: 启动AI筛选任务异步执行
**请求体**:
```json
{
"taskType": "title_abstract",
"models": ["deepseek-chat", "qwen-max"],
"concurrency": 3
}
```
**响应示例**:
```json
{
"success": true,
"data": {
"taskId": "task-uuid-001",
"status": "running",
"totalItems": 100,
"startedAt": "2025-11-18T08:00:00.000Z"
}
}
```
---
#### 3.2 获取筛选进度
**接口**: `GET /api/v1/asl/tasks/:taskId/progress`
**认证**: 需要
**说明**: 获取筛选任务进度
**响应示例**:
```json
{
"success": true,
"data": {
"taskId": "task-uuid-001",
"status": "running",
"totalItems": 100,
"processedItems": 45,
"successItems": 40,
"failedItems": 2,
"conflictItems": 3,
"progress": 45,
"estimatedEndAt": "2025-11-18T08:15:00.000Z"
}
}
```
---
#### 3.3 获取筛选结果
**接口**: `GET /api/v1/asl/projects/:projectId/results`
**认证**: 需要
**说明**: 获取筛选结果列表
**查询参数**:
- `page`: 页码(默认: 1
- `limit`: 每页数量(默认: 50
- `conflictOnly`: 只显示冲突项(布尔值)
- `finalDecision`: 筛选决策include / exclude / pending
**响应示例**:
```json
{
"success": true,
"data": {
"results": [
{
"id": "result-uuid-001",
"literatureId": "lit-uuid-001",
"literature": {
"title": "...",
"abstract": "..."
},
"dsConclusion": "include",
"qwenConclusion": "include",
"conflictStatus": "none",
"finalDecision": "include",
"createdAt": "2025-11-18T08:05:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 100,
"totalPages": 2
}
}
}
```
---
#### 3.4 审核冲突文献
**接口**: `POST /api/v1/asl/results/review`
**认证**: 需要
**说明**: 批量审核冲突文献
**请求体**:
```json
{
"projectId": "d67f0b9a-b035-4804-aca1-0bd672c27d81",
"reviews": [
{
"resultId": "result-uuid-001",
"finalDecision": "include"
},
{
"resultId": "result-uuid-002",
"finalDecision": "exclude",
"exclusionReason": "不符合PICO标准中的干预措施"
}
]
}
```
**响应示例**:
```json
{
"success": true,
"data": {
"reviewedCount": 2
}
}
```
---
### 4. 全文复筛管理 (Fulltext Screening)
> **状态**: ✅ Day 5实现中2025-11-23
#### 4.1 创建全文复筛任务
**接口**: `POST /api/v1/asl/fulltext-screening/tasks`
**认证**: 需要
**说明**: 创建全文复筛任务对标题初筛通过的文献进行12字段评估
**请求体**:
```json
{
"projectId": "proj-123",
"literatureIds": ["lit-001", "lit-002", "lit-003"],
"modelA": "deepseek-v3",
"modelB": "qwen-max",
"promptVersion": "v1.0.0"
}
```
**字段说明**:
- `projectId`: 项目ID必填
- `literatureIds`: 待筛选文献ID列表必填需要是标题初筛通过的文献
- `modelA`: 模型A名称可选默认: deepseek-v3
- `modelB`: 模型B名称可选默认: qwen-max
- `promptVersion`: Prompt版本可选默认: v1.0.0
**响应示例**:
```json
{
"success": true,
"data": {
"taskId": "fst-20251123-001",
"projectId": "proj-123",
"status": "pending",
"totalCount": 3,
"modelA": "deepseek-v3",
"modelB": "qwen-max",
"createdAt": "2025-11-23T10:00:00.000Z",
"message": "任务创建成功,正在后台处理"
}
}
```
**业务规则**:
1. 验证所有文献是否属于该项目
2. 检查文献是否有可用的PDF`pdfStatus === 'ready'`
3. 任务创建后立即返回,后台异步处理
4. 如果部分文献PDF未就绪仅处理PDF就绪的文献
**错误响应**:
```json
{
"success": false,
"error": "部分文献PDF未就绪无法开始全文复筛"
}
```
**测试命令**:
```bash
curl -X POST http://localhost:3001/api/v1/asl/fulltext-screening/tasks \
-H "Content-Type: application/json" \
-d '{
"projectId": "proj-123",
"literatureIds": ["lit-001", "lit-002"],
"modelA": "deepseek-v3",
"modelB": "qwen-max"
}'
```
---
#### 4.2 获取任务进度
**接口**: `GET /api/v1/asl/fulltext-screening/tasks/:taskId`
**认证**: 需要
**说明**: 获取全文复筛任务的详细进度信息
**路径参数**:
- `taskId`: 任务ID
**响应示例**:
```json
{
"success": true,
"data": {
"taskId": "fst-20251123-001",
"projectId": "proj-123",
"status": "processing",
"progress": {
"totalCount": 30,
"processedCount": 15,
"successCount": 13,
"failedCount": 1,
"degradedCount": 1,
"pendingCount": 15,
"progressPercent": 50
},
"statistics": {
"totalTokens": 450000,
"totalCost": 2.25,
"avgTimePerLit": 18500
},
"time": {
"startedAt": "2025-11-23T10:00:00.000Z",
"estimatedEndAt": "2025-11-23T10:12:30.000Z",
"elapsedSeconds": 270
},
"models": {
"modelA": "deepseek-v3",
"modelB": "qwen-max"
},
"updatedAt": "2025-11-23T10:04:30.000Z"
}
}
```
**字段说明**:
- `status`: 任务状态
- `pending`: 待处理
- `processing`: 处理中
- `completed`: 已完成
- `failed`: 失败
- `cancelled`: 已取消
- `successCount`: 双模型都成功的文献数
- `degradedCount`: 仅一个模型成功的文献数(降级模式)
- `failedCount`: 双模型都失败的文献数
- `totalCost`: 累计成本(单位:元)
**测试命令**:
```bash
curl http://localhost:3001/api/v1/asl/fulltext-screening/tasks/fst-20251123-001
```
---
#### 4.3 获取任务结果
**接口**: `GET /api/v1/asl/fulltext-screening/tasks/:taskId/results`
**认证**: 需要
**说明**: 获取全文复筛任务的详细结果,支持筛选和分页
**路径参数**:
- `taskId`: 任务ID
**查询参数**:
- `filter`: 结果筛选(可选)
- `all`: 全部(默认)
- `conflict`: 仅冲突项
- `pending`: 待审核
- `reviewed`: 已审核
- `page`: 页码(默认: 1
- `pageSize`: 每页数量(默认: 20最大: 100
- `sortBy`: 排序字段(可选: `priority`, `createdAt`
- `sortOrder`: 排序方向(`asc` | `desc`,默认: `desc`
**响应示例**:
```json
{
"success": true,
"data": {
"taskId": "fst-20251123-001",
"total": 30,
"filtered": 3,
"results": [
{
"resultId": "fsr-001",
"literatureId": "lit-001",
"literature": {
"pmid": "12345678",
"title": "Effect of SGLT2 inhibitors on cardiovascular outcomes",
"authors": "Smith JA, et al.",
"journal": "Lancet",
"year": 2023,
"doi": "10.1016/..."
},
"modelAResult": {
"modelName": "deepseek-v3",
"status": "success",
"fields": {
"field1_source": {
"assessment": "完整",
"evidence": "第一作者Smith JA, Lancet 2023",
"location": "第1页",
"confidence": 0.98
},
"field2_studyType": {
"assessment": "完整",
"evidence": "多中心随机对照试验",
"location": "Methods第2页",
"confidence": 0.95
},
"field5_population": {
"assessment": "完整",
"evidence": "纳入500例2型糖尿病患者年龄58±12岁",
"location": "Methods第3页",
"confidence": 0.92
},
"field9_outcomes": {
"assessment": "完整",
"evidence": "主要结局eGFR变化-15.2±3.5 ml/min vs -8.1±2.9 ml/min",
"location": "Results第5页表2",
"confidence": 0.96
}
},
"overall": {
"decision": "include",
"reason": "12字段完整关键数据可提取",
"dataQuality": "high",
"confidence": 0.94
},
"tokens": 15000,
"cost": 0.015
},
"modelBResult": {
"modelName": "qwen-max",
"status": "success",
"fields": { /* */ },
"overall": {
"decision": "include",
"confidence": 0.92
},
"tokens": 15200,
"cost": 0.061
},
"validation": {
"medicalLogicIssues": [],
"evidenceChainIssues": []
},
"conflict": {
"isConflict": false,
"severity": "none",
"conflictFields": [],
"overallConflict": false
},
"review": {
"finalDecision": null,
"reviewedBy": null,
"reviewedAt": null,
"reviewNotes": null,
"priority": 50
},
"processing": {
"isDegraded": false,
"degradedModel": null,
"processedAt": "2025-11-23T10:02:15.000Z"
}
},
{
"resultId": "fsr-002",
"literatureId": "lit-005",
"literature": { /* ... */ },
"modelAResult": {
"modelName": "deepseek-v3",
"status": "success",
"fields": {
"field9_outcomes": {
"assessment": "缺失",
"evidence": "未报告具体数值仅有P值",
"location": "Results第4页",
"confidence": 0.88
}
},
"overall": {
"decision": "exclude",
"reason": "关键字段field9数据不完整无法Meta分析",
"confidence": 0.85
}
},
"modelBResult": {
"overall": {
"decision": "include",
"reason": "虽然主要结局在Discussion报告但数据完整"
}
},
"conflict": {
"isConflict": true,
"severity": "high",
"conflictFields": ["field9"],
"overallConflict": true,
"details": {
"field9": {
"modelA": "缺失",
"modelB": "完整",
"importance": "critical"
}
}
},
"review": {
"finalDecision": null,
"priority": 95
}
}
],
"pagination": {
"page": 1,
"pageSize": 20,
"totalPages": 2
},
"summary": {
"totalResults": 30,
"conflictCount": 3,
"pendingReview": 3,
"reviewed": 27,
"avgPriority": 62
}
}
}
```
**12字段说明**:
- `field1_source`: 文献来源(作者、期刊、年份等)
- `field2_studyType`: 研究类型RCT、队列研究等
- `field3_studyDesign`: 研究设计细节
- `field4_diagnosis`: 疾病诊断标准
- `field5_population`: 人群特征(样本量、基线等)⭐
- `field6_baseline`: 基线数据⭐
- `field7_intervention`: 干预措施⭐
- `field8_control`: 对照措施
- `field9_outcomes`: 结局指标⭐⭐⭐ 最关键
- `field10_statistics`: 统计方法
- `field11_quality`: 质量评价(随机化、盲法等)⭐⭐
- `field12_other`: 其他信息
**测试命令**:
```bash
# 获取所有结果
curl "http://localhost:3001/api/v1/asl/fulltext-screening/tasks/fst-20251123-001/results"
# 仅获取冲突项
curl "http://localhost:3001/api/v1/asl/fulltext-screening/tasks/fst-20251123-001/results?filter=conflict"
# 分页查询
curl "http://localhost:3001/api/v1/asl/fulltext-screening/tasks/fst-20251123-001/results?page=2&pageSize=10"
```
---
#### 4.4 人工审核决策
**接口**: `PUT /api/v1/asl/fulltext-screening/results/:resultId/decision`
**认证**: 需要
**说明**: 对单个全文复筛结果进行人工审核决策
**路径参数**:
- `resultId`: 结果ID
**请求体**:
```json
{
"finalDecision": "exclude",
"exclusionReason": "关键字段field9结局指标数据不完整",
"reviewNotes": "虽然报告了P<0.05但缺少均值±SD无法用于Meta分析"
}
```
**字段说明**:
- `finalDecision`: 最终决策(必填)
- `include`: 纳入
- `exclude`: 排除
- `exclusionReason`: 排除原因(`finalDecision === 'exclude'` 时必填)
- `reviewNotes`: 审核备注(可选)
**响应示例**:
```json
{
"success": true,
"data": {
"resultId": "fsr-002",
"finalDecision": "exclude",
"exclusionReason": "关键字段field9结局指标数据不完整",
"reviewedBy": "user-001",
"reviewedAt": "2025-11-23T10:30:00.000Z"
}
}
```
**测试命令**:
```bash
curl -X PUT http://localhost:3001/api/v1/asl/fulltext-screening/results/fsr-002/decision \
-H "Content-Type: application/json" \
-d '{
"finalDecision": "exclude",
"exclusionReason": "结局指标数据不完整",
"reviewNotes": "缺少均值和标准差"
}'
```
---
#### 4.5 导出Excel
**接口**: `GET /api/v1/asl/fulltext-screening/tasks/:taskId/export`
**认证**: 需要
**说明**: 导出全文复筛结果为Excel文件3个Sheet
**路径参数**:
- `taskId`: 任务ID
**响应**:
- Content-Type: `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`
- Content-Disposition: `attachment; filename="fulltext_screening_results_{taskId}.xlsx"`
**Excel结构**:
**Sheet 1: 纳入文献列表**
| 列名 | 说明 |
|------|------|
| 序号 | 1, 2, 3... |
| PMID | PubMed ID |
| 文献来源 | 第一作者+年份 |
| 标题 | 文献标题 |
| 期刊 | 期刊名称 |
| 年份 | 发表年份 |
| DOI | DOI编号 |
| 最终决策 | 纳入 |
| 数据质量 | 高/中/低 |
| 可提取性 | 可提取/部分可提取/不可提取 |
| 模型一致性 | 一致/不一致 |
| 是否人工审核 | 是/否 |
**Sheet 2: 排除文献列表**
| 列名 | 说明 |
|------|------|
| 序号 | 1, 2, 3... |
| PMID | PubMed ID |
| 文献来源 | 第一作者+年份 |
| 标题 | 文献标题 |
| 排除原因 | 详细排除原因 |
| 排除字段 | field5, field9等 |
| 是否冲突 | 是/否 |
| 审核人 | 用户ID |
| 审核时间 | 2025-11-23 10:30 |
**Sheet 3: PRISMA统计**
| 统计项 | 数量 | 百分比 |
|--------|------|--------|
| 全文复筛总数 | 30 | 100% |
| 最终纳入 | 18 | 60% |
| 最终排除 | 12 | 40% |
| - 结局指标缺失/不完整 | 5 | 16.7% |
| - 人群特征不符 | 3 | 10% |
| - 干预措施不明确 | 2 | 6.7% |
| - 研究质量问题 | 1 | 3.3% |
| - 其他原因 | 1 | 3.3% |
| 模型冲突数 | 3 | 10% |
| 人工审核数 | 3 | 10% |
**成本统计额外Sheet**:
| 项目 | 值 |
|------|-----|
| 总Token数 | 450,000 |
| 总成本(元) | ¥2.25 |
| 平均成本/篇 | ¥0.075 |
| 模型组合 | DeepSeek-V3 + Qwen-Max |
| 处理时间 | 8分30秒 |
**测试命令**:
```bash
curl -O -J http://localhost:3001/api/v1/asl/fulltext-screening/tasks/fst-20251123-001/export
```
---
## 📋 响应格式规范
### 1. 成功响应
**格式**:
```json
{
"success": true,
"data": {
// 响应数据
}
}
```
**HTTP状态码**:
- `200` - 成功GET、PUT
- `201` - 创建成功POST
---
### 2. 错误响应
**格式**:
```json
{
"success": false,
"error": "错误描述"
}
```
或(详细错误):
```json
{
"error": "Missing required fields"
}
```
**常见HTTP状态码**:
- `400` - 请求参数错误
- `401` - 未授权
- `403` - 无权限
- `404` - 资源不存在
- `500` - 服务器内部错误
**错误示例**:
```json
// 400 - 参数错误
{
"error": "Missing required fields"
}
// 404 - 资源不存在
{
"error": "Project not found"
}
// 500 - 服务器错误
{
"error": "Failed to create project"
}
```
---
### 3. 分页响应
**格式**:
```json
{
"success": true,
"data": {
"items": [...], // 或 literatures、results 等
"pagination": {
"page": 1,
"limit": 50,
"total": 150,
"totalPages": 3
}
}
}
```
**分页参数**:
- `page`: 当前页码从1开始
- `limit`: 每页数量
- `total`: 总记录数
- `totalPages`: 总页数
---
## 🔐 认证授权
### 当前状态(测试模式)
**测试用户**:
- **用户ID**: `asl-test-user-001`
- **邮箱**: `asl-test@example.com`
- **权限**: 完全访问
**实现方式**:
- 优先从JWT中获取`userId`
- JWT不存在时使用默认测试用户ID
### 生产环境(待实现)
**认证流程**:
1. 用户登录获取JWT Token
2. 请求头携带Token: `Authorization: Bearer {token}`
3. 中间件验证Token并提取`userId`
4. 控制器使用`userId`查询用户数据
**中间件示例**:
```typescript
// 待实现
fastify.addHook('preHandler', async (request, reply) => {
const token = request.headers.authorization?.replace('Bearer ', '');
if (!token) {
return reply.status(401).send({ error: 'Unauthorized' });
}
const userId = await verifyJWT(token);
(request as any).userId = userId;
});
```
---
## 🧪 API测试
### 快速测试脚本
**测试所有API**:
```bash
cd AIclinicalresearch/backend
npx tsx scripts/test-asl-api.ts
```
**测试结果**:
```
🚀 开始测试 ASL 模块 API...
📍 测试 1/7: 健康检查 ✅
📍 测试 2/7: 创建筛选项目 ✅
📍 测试 3/7: 获取项目列表 ✅
📍 测试 4/7: 获取项目详情 ✅
📍 测试 5/7: 导入文献 ✅
📍 测试 6/7: 获取文献列表 ✅
📍 测试 7/7: 更新项目 ✅
═══════════════════════════════════
🎉 所有测试通过!(7/7 - 100%)
═══════════════════════════════════
```
### Postman集合
**导入说明**:
1. 创建新的Collection: `ASL API`
2. 设置环境变量:
- `base_url`: `http://localhost:3001`
- `api_prefix`: `/api/v1/asl`
3. 导入下方接口
**示例请求** (Postman):
```
POST {{base_url}}{{api_prefix}}/projects
Headers:
Content-Type: application/json
Body (raw JSON):
{
"projectName": "测试项目",
"picoCriteria": {...},
"inclusionCriteria": "英文文献",
"exclusionCriteria": "综述"
}
```
---
## 📊 性能指标
### 响应时间目标
| 接口类型 | 目标响应时间 | 说明 |
|---------|-------------|------|
| 单个查询 | < 100ms | 项目详情、文献详情 |
| 列表查询 | < 200ms | 项目列表、文献列表 |
| 创建/更新 | < 300ms | 创建项目、更新项目 |
| 批量导入 | < 2s | 导入100篇文献 |
| LLM筛选 | 4-6s/篇 | 双模型并行筛选 |
### 并发能力
- **API服务器**: 支持100+并发请求
- **LLM筛选**: 并发数为3可配置
- **数据库连接池**: 17个连接
---
## 🔄 版本历史
### v3.0 (2025-11-23)
- ✅ 新增全文复筛管理API5个接口
- 创建任务、获取进度、获取结果、人工审核、导出Excel
- ✅ 支持12字段详细评估
- ✅ 支持双模型对比和冲突检测
- ✅ 完整的Excel导出功能3 Sheets
- ✅ 调整文档结构5大模块
### v2.1 (2025-11-21)
- ✅ 新增统计API接口
- ✅ 更新PICOS格式说明
- ✅ 添加云原生架构标注
### v2.0 (2025-11-18)
- ✅ 实现10个核心API端点
- ✅ 完成项目管理功能
- ✅ 完成文献管理功能
- ✅ 添加测试脚本和文档
- ✅ 所有接口测试通过
### v1.0 (2025-10-29)
- 初始API设计规范
- 定义接口结构
---
## ⏳ 后续规划
### Week 2
- [ ] 实现筛选任务API (3个接口)
- [ ] 实现冲突审核API (2个接口)
- [ ] 添加SSE进度推送
- [ ] 集成异步任务队列
### Week 3-4
- [ ] 添加JWT认证中间件
- [ ] 实现权限控制
- [ ] 添加API限流
- [ ] 完善错误处理
---
---
### 5. 统计API (Statistics)
#### 5.1 获取项目统计数据(云原生:后端聚合)
**接口**: `GET /api/v1/asl/projects/:projectId/statistics`
**认证**: 需要
**说明**: 获取项目的筛选统计数据(总数、纳入率、排除率、排除原因分析等)
**路径参数**:
- `projectId`: 项目ID
**响应示例**:
```json
{
"success": true,
"data": {
"total": 199,
"included": 85,
"excluded": 90,
"pending": 24,
"conflict": 24,
"reviewed": 175,
"exclusionReasons": {
"P不匹配人群": 40,
"I不匹配干预": 25,
"S不匹配研究设计": 15,
"其他原因": 10
},
"includedRate": "42.7",
"excludedRate": "45.2",
"pendingRate": "12.1"
}
}
```
**特点**
- ✅ 云原生后端Prisma聚合查询6个并行查询
- ✅ 性能:<500ms199篇文献
- ✅ 减少网络传输从MB级降到KB级
**测试命令**:
```bash
curl http://localhost:3001/api/v1/asl/projects/55941145-bba0-4b15-bda4-f0a398d78208/statistics
```---**文档版本:** v3.0
**最后更新:** 2025-11-23Day 5: 全文复筛API
**维护者:** AI智能文献开发团队**本次更新**
- ✅ 新增全文复筛管理API5个核心接口
- ✅ 详细的12字段评估文档
- ✅ 双模型对比和冲突检测说明
- ✅ Excel导出格式规范
- ✅ 完整的请求/响应示例---## 📚 相关文档- [数据库设计文档](./01-数据库设计.md)
- [API测试报告](../../../backend/ASL-API-测试报告.md)
- [Week 1完成报告](../05-开发记录/2025-11-18-Week1完成报告.md)