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
1373 lines
31 KiB
Markdown
1373 lines
31 KiB
Markdown
# AI智能文献模块 - API设计规范
|
||
|
||
> **文档版本:** v3.0
|
||
> **创建日期:** 2025-10-29
|
||
> **维护者:** AI智能文献开发团队
|
||
> **最后更新:** 2025-11-23
|
||
> **更新说明:** 新增全文复筛API(5个核心接口)
|
||
|
||
---
|
||
|
||
## 📋 文档说明
|
||
|
||
本文档描述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)
|
||
- ✅ 新增全文复筛管理API(5个接口)
|
||
- 创建任务、获取进度、获取结果、人工审核、导出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个并行查询)
|
||
- ✅ 性能:<500ms(199篇文献)
|
||
- ✅ 减少网络传输:从MB级降到KB级
|
||
|
||
**测试命令**:
|
||
```bash
|
||
curl http://localhost:3001/api/v1/asl/projects/55941145-bba0-4b15-bda4-f0a398d78208/statistics
|
||
```---**文档版本:** v3.0
|
||
**最后更新:** 2025-11-23(Day 5: 全文复筛API)
|
||
**维护者:** AI智能文献开发团队**本次更新**:
|
||
- ✅ 新增全文复筛管理API(5个核心接口)
|
||
- ✅ 详细的12字段评估文档
|
||
- ✅ 双模型对比和冲突检测说明
|
||
- ✅ Excel导出格式规范
|
||
- ✅ 完整的请求/响应示例---## 📚 相关文档- [数据库设计文档](./01-数据库设计.md)
|
||
- [API测试报告](../../../backend/ASL-API-测试报告.md)
|
||
- [Week 1完成报告](../05-开发记录/2025-11-18-Week1完成报告.md)
|