feat(aia): Complete AIA V2.0 with universal streaming capabilities
Major Changes: - Add StreamingService with OpenAI Compatible format - Upgrade Chat component V2 with Ant Design X integration - Implement AIA module with 12 intelligent agents - Update API routes to unified /api/v1 prefix - Update system documentation Backend (~1300 lines): - common/streaming: OpenAI Compatible adapter - modules/aia: 12 agents, conversation service, streaming integration - Update route versions (RVW, PKB to v1) Frontend (~3500 lines): - modules/aia: AgentHub + ChatWorkspace (100% prototype restoration) - shared/Chat: AIStreamChat, ThinkingBlock, useAIStream Hook - Update API endpoints to v1 Documentation: - AIA module status guide - Universal capabilities catalog - System overview updates - All module documentation sync Tested: Stream response verified, authentication working Status: AIA V2.0 core completed (85%)
This commit is contained in:
@@ -1,65 +1,52 @@
|
||||
# 标题摘要初筛模块 - 详细开发计划(MVP阶段)
|
||||
|
||||
> **文档版本:** V3.0
|
||||
> **创建日期:** 2025-11-16
|
||||
> **开发周期:** 4 周
|
||||
> **负责团队:** ASL 开发组
|
||||
# æ ‡é¢˜æ‘˜è¦<EFBFBD>åˆ<EFBFBD>ç›æ¨¡å<EFBFBD>— - 详细开å<E282AC>‘计划(MVP阶段ï¼?
|
||||
> **文档版本�* V3.0
|
||||
> **创建日期�* 2025-11-16
|
||||
> **å¼€å<EFBFBD>‘周期:** 4 å‘?
|
||||
> **负责团队ï¼?* ASL å¼€å<E282AC>‘组
|
||||
> **最å<E282AC>Žæ›´æ–°ï¼š** 2025-11-16
|
||||
> **⭐ 重要:基于真实架构(Frontend-v2 + Backend增量演进 + asl_schema)**
|
||||
> **â?é‡<C3A9>è¦<C3A8>:基于真实架构(Frontend-v2 + Backend增é‡<EFBFBD>演进 + asl_schemaï¼?*
|
||||
|
||||
---
|
||||
|
||||
## 📋 模å<C2A1>—概述
|
||||
|
||||
标题摘要初筛是 ASL 模块的第一个核心功能,也是 MVP 阶段的唯一交付功能。
|
||||
|
||||
æ ‡é¢˜æ‘˜è¦<EFBFBD>åˆ<EFBFBD>ç›æ˜?ASL 模å<C2A1>—çš„ç¬¬ä¸€ä¸ªæ ¸å¿ƒåŠŸèƒ½ï¼Œä¹Ÿæ˜¯ MVP 阶段的唯一交付功能ã€?
|
||||
### 功能范围
|
||||
|
||||
1. **设置与启动视图**:PICO 标准展示、Excel 文献导入、启动筛选任务
|
||||
2. **审核工作台视图**:双模型判断对比、冲突标记、人工复核
|
||||
3. **初筛结果视图**:统计概览、PRISMA 排除总结、结果导出
|
||||
|
||||
1. **设置与å<EFBFBD>¯åŠ¨è§†å›?*:PICO æ ‡å‡†å±•ç¤ºã€<C3A3>Excel 文献导入ã€<C3A3>å<EFBFBD>¯åЍç›é€‰ä»»åŠ?2. **å®¡æ ¸å·¥ä½œå<C593>°è§†å›?*:å<C5A1>Œæ¨¡åž‹åˆ¤æ–对比ã€<C3A3>冲çª<C3A7>æ ‡è®°ã€<C3A3>人工å¤<C3A5>æ ?3. **åˆ<C3A5>ç›ç»“果视图**:统计概览ã€<C3A3>PRISMA 排除总结ã€<C3A3>结果导å‡?
|
||||
### æŠ€æœ¯æ ˆ
|
||||
|
||||
| 层级 | 技术 | 说明 |
|
||||
| 层级 | 技�| 说明 |
|
||||
|------|------|------|
|
||||
| **å‰<C3A5>端** | React 19 + TypeScript + Ant Design 5 + xlsx | Frontend-v2æž¶æž„ |
|
||||
| **å<>Žç«¯** | Node.js + Fastify + TypeScript + Prisma | Backend/modules/asl/ |
|
||||
| **LLM** | DeepSeek-V3 + Qwen3-72B | å¤<C3A5>用 common/llm/adapters/ |
|
||||
| **数据库** | PostgreSQL 15 (asl_schema) | Schema隔离 |
|
||||
| **æ•°æ<EFBFBD>®åº?* | PostgreSQL 15 (asl_schema) | Schema隔离 |
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 架构前提(已完成)
|
||||
|
||||
### ✅ Frontend-v2 架构(Week 2 Day 6-7 完成)
|
||||
```
|
||||
## ðŸ<EFBFBD>—ï¸?æž¶æž„å‰<C3A5>æ<EFBFBD><C3A6>(已完æˆ<C3A6>ï¼?
|
||||
### âœ?Frontend-v2 架构(Week 2 Day 6-7 完æˆ<C3A6>ï¼?```
|
||||
frontend-v2/src/
|
||||
├── framework/layout/
|
||||
│ ├── MainLayout.tsx # ✅ 顶部导航布局
|
||||
│ └── TopNavigation.tsx # ✅ 6个模块导航
|
||||
├── framework/modules/
|
||||
│ ├── moduleRegistry.ts # ✅ 模块注册中心
|
||||
│ └── types.ts # ✅ ModuleDefinition接口
|
||||
� ├── MainLayout.tsx # �顶部导航布局
|
||||
â”? └── TopNavigation.tsx # âœ?6个模å<C2A1>—导èˆ?├── framework/modules/
|
||||
â”? ├── moduleRegistry.ts # âœ?模å<C2A1>—注册ä¸å¿ƒ
|
||||
â”? └── types.ts # âœ?ModuleDefinition接å<C2A5>£
|
||||
└── modules/asl/
|
||||
└── index.tsx # 🚧 占位页面(待替换)
|
||||
```
|
||||
└── index.tsx # 🚧 å<> ä½<C3A4>页é<C2B5>¢ï¼ˆå¾…替æ<C2BF>¢ï¼?```
|
||||
|
||||
### ✅ Backend 架构(Week 2 Day 8-9 完成)
|
||||
```
|
||||
### âœ?Backend 架构(Week 2 Day 8-9 完æˆ<EFBFBD>ï¼?```
|
||||
backend/src/
|
||||
├── common/llm/adapters/ # ✅ LLMFactory可复用
|
||||
├── common/utils/jsonParser.js # ✅ JSON解析可复用
|
||||
└── modules/
|
||||
├── common/llm/adapters/ # âœ?LLMFactoryå<EFBFBD>¯å¤<EFBFBD>ç”?├── common/utils/jsonParser.js # âœ?JSONè§£æž<C3A6>å<EFBFBD>¯å¤<C3A5>ç”?└── modules/
|
||||
└── asl/ # 🚧 空目录(待创建)
|
||||
```
|
||||
|
||||
### ✅ Database Schema(Week 1 完成)
|
||||
```prisma
|
||||
### âœ?Database Schema(Week 1 完æˆ<EFBFBD>ï¼?```prisma
|
||||
// backend/prisma/schema.prisma
|
||||
datasource db {
|
||||
schemas = [
|
||||
"asl_schema", # ✅ 已预留,待定义表结构
|
||||
"asl_schema", # �已预留,待定义表结构
|
||||
// ...其他9个Schema
|
||||
]
|
||||
}
|
||||
@@ -67,70 +54,58 @@ datasource db {
|
||||
|
||||
---
|
||||
|
||||
## 🌥️ 云原生开发注意事项(2025-11-16 新增)
|
||||
|
||||
> **⭐ 重要更新**:本模块开发需遵循阿里云 Serverless 部署架构要求
|
||||
> **详细规范**:[云原生开发规范](../../../04-开发规范/08-云原生开发规范.md)
|
||||
> **部署指南**:[云原生部署架构指南](../../../09-架构实施/03-云原生部署架构指南.md)
|
||||
|
||||
### 🎯 本地开发 + 云端部署双兼容策略
|
||||
## 🌥ï¸?云原生开å<E282AC>‘注æ„<C3A6>事项(2025-11-16 新增ï¼?
|
||||
> **â?é‡<C3A9>è¦<C3A8>æ›´æ–°**:本模å<C2A1>—å¼€å<E282AC>‘需é<E282AC>µå¾ªé˜¿é‡Œäº?Serverless 部署架构è¦<C3A8>求
|
||||
> **详细规范**:[云原生开å<E282AC>‘规范](../../../04-å¼€å<E282AC>‘è§„èŒ?08-云原生开å<E282AC>‘è§„èŒ?md)
|
||||
> **部署指å<E280A1>—**:[云原生部署架构指å<E280A1>—](../../../09-架构实施/03-云原生部署架构指å<E280A1>?md)
|
||||
|
||||
### 🎯 本地开å<E282AC>?+ 云端部署å<C2B2>Œå…¼å®¹ç–ç•?
|
||||
| 环境 | å˜å‚¨æ–¹å¼<C3A5> | é…<C3A9>ç½® | 说明 |
|
||||
|------|---------|------|------|
|
||||
| **本地开发** | LocalAdapter | `STORAGE_TYPE=local` | 文件存储到 `./uploads/` |
|
||||
| **本地开å<EFBFBD>?* | LocalAdapter | `STORAGE_TYPE=local` | 文件å˜å‚¨åˆ?`./uploads/` |
|
||||
| **生产环境** | OSSAdapter | `STORAGE_TYPE=oss` | 文件å˜å‚¨åˆ°é˜¿é‡Œäº‘ OSS |
|
||||
|
||||
**核心原则**:
|
||||
- ✅ **Excel导入**:内存解析(`xlsx.read(buffer)`),不落盘
|
||||
- ✅ **PDF上传**(V1.0):使用 `StorageFactory`,本地/OSS自动切换
|
||||
- ✅ **异步任务**:LLM筛选任务必须异步处理(> 10秒任务)
|
||||
- ✅ **环境变量**:所有配置从 `.env` 读取
|
||||
- ✅ **数据库连接池**:使用全局 `prisma` 实例,不新建连接
|
||||
|
||||
### ❌ 禁止的做法
|
||||
**æ ¸å¿ƒåŽŸåˆ™**ï¼?- âœ?**Excel导入**:内å˜è§£æž<C3A6>(`xlsx.read(buffer)`),ä¸<C3A4>è<EFBFBD>½ç›?- âœ?**PDFä¸Šä¼ **(V1.0):使用 `StorageFactory`,本åœ?OSS自动切æ<E280A1>¢
|
||||
- âœ?**异æ¥ä»»åŠ¡**:LLMç›é€‰ä»»åŠ¡å¿…é¡»å¼‚æ¥å¤„ç<E2809E>†ï¼ˆ> 10秒任务)
|
||||
- âœ?**环境å<C692>˜é‡<C3A9>**:所有é…<C3A9>置从 `.env` 读å<C2BB>–
|
||||
- âœ?**æ•°æ<C2B0>®åº“è¿žæŽ¥æ± **:使用全局 `prisma` 实例,ä¸<C3A4>新建连接
|
||||
|
||||
### â<>?ç¦<C3A7>æ¢çš„å<E2809E>šæ³?
|
||||
| ç¦<C3A7>æ¢æ“<C3A6>作 | æ£ç¡®å<C2AE>𿳕 | åŽŸå› |
|
||||
|---------|---------|------|
|
||||
| `fs.writeFileSync('./temp.xlsx')` | `xlsx.read(buffer)` 内å˜è§£æž<C3A6> | Serverless容器é‡<C3A9>å<EFBFBD>¯ä¸¢å¤±æ–‡ä»¶ |
|
||||
| `new PrismaClient()` 每次新建连接 | 使用全局 `prisma` 实例 | 避免连接数暴增 |
|
||||
| 硬编码 `apiKey = 'sk-xxx'` | `process.env.LLM_API_KEY` | 配置管理混乱 |
|
||||
| 同步处理1000条文献筛选 | 异步任务 + 进度轮询 | 超过30秒超时限制 |
|
||||
|
||||
### ✅ MVP阶段开发检查清单
|
||||
|
||||
在提交代码前,请确认:
|
||||
| `new PrismaClient()` æ¯<C3A6>次新建连接 | 使用全局 `prisma` 实例 | é<>¿å…<C3A5>连接数暴å¢?|
|
||||
| 硬编ç ?`apiKey = 'sk-xxx'` | `process.env.LLM_API_KEY` | é…<EFBFBD>置管ç<EFBFBD>†æ··ä¹± |
|
||||
| å<EFBFBD>Œæ¥å¤„ç<EFBFBD>†1000æ<EFBFBD>¡æ–‡çŒ®ç›é€?| 异æ¥ä»»åŠ¡ + 进度轮询 | 超过30ç§’è¶…æ—¶é™<C3A9>åˆ?|
|
||||
|
||||
### âœ?MVP阶段开å<E282AC>‘检查清å<E280A6>?
|
||||
在æ<EFBFBD><EFBFBD>交代ç <EFBFBD>å‰<EFBFBD>,请确认ï¼?
|
||||
- [ ] Excel导入是å<C2AF>¦ä½¿ç”¨å†…å˜è§£æž<C3A6>(`xlsx.read(buffer)`)?
|
||||
- [ ] 是å<C2AF>¦ä½¿ç”¨å…¨å±€ `prisma` 实例(`import { prisma } from '@/config/database'`)?
|
||||
- [ ] 是å<C2AF>¦æ‰€æœ‰é…<C3A9>置都从环境å<C692>˜é‡<C3A9>读å<C2BB>–?
|
||||
- [ ] LLMç›é€‰ä»»åŠ¡æ˜¯å<C2AF>¦å¼‚æ¥å¤„ç<E2809E>†ï¼ˆ`POST /screening/start` ç«‹å<E280B9>³è¿”回taskId)?
|
||||
- [ ] 是否预留了 OSS 字段(`pdfUrl`, `pdfOssKey`, `pdfFileSize`)?
|
||||
- [ ] 是å<C2AF>¦é¢„ç•™äº?OSS å—æ®µï¼ˆ`pdfUrl`, `pdfOssKey`, `pdfFileSize`)?
|
||||
- [ ] 是å<C2AF>¦ä½¿ç”¨å˜å‚¨æŠ½è±¡å±‚(`StorageFactory.create()`)?
|
||||
|
||||
**预留字段说明**:
|
||||
- MVP阶段仅做标题摘要筛选,不处理PDF
|
||||
**é¢„ç•™å—æ®µè¯´æ˜Ž**ï¼?- MVP阶段仅å<E280A6>šæ ‡é¢˜æ‘˜è¦<C3A8>ç›é€‰ï¼Œä¸<C3A4>处ç<E2809E>†PDF
|
||||
- V1.0阶段实现全文PDFç›é€‰æ—¶ï¼Œä½¿ç”¨é¢„留的OSSå—æ®µ
|
||||
|
||||
---
|
||||
|
||||
## 📅 四周开发计划
|
||||
|
||||
## 📅 四周开å<E282AC>‘计åˆ?
|
||||
```
|
||||
Week 1: 数据库Schema + 后端API框架 + 存储抽象层
|
||||
Week 2: LLM筛选核心 + 异步批处理逻辑
|
||||
Week 3: 前端模块开发 + 审核工作台(内存解析Excel)
|
||||
Week 4: 结果展示 + 导出 + 集成测试
|
||||
Week 1: æ•°æ<EFBFBD>®åº“Schema + å<>Žç«¯API框架 + å˜å‚¨æŠ½è±¡å±?Week 2: LLMç›é€‰æ ¸å¿?+ å¼‚æ¥æ‰¹å¤„ç<E2809E>†é€»è¾‘
|
||||
Week 3: å‰<C3A5>端模å<C2A1>—å¼€å<E282AC>?+ å®¡æ ¸å·¥ä½œå<C593>°ï¼ˆå†…å˜è§£æž<C3A6>Excelï¼?Week 4: 结果展示 + 导出 + 集æˆ<C3A6>测试
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗓️ Week 1: 数据库Schema与后端API框架
|
||||
## 🗓ï¸?Week 1: æ•°æ<EFBFBD>®åº“Schema与å<EFBFBD>Žç«¯API框架
|
||||
|
||||
### Day 1: Prisma Schema 设计
|
||||
|
||||
#### 任务1: 设计 asl_schema 表结构
|
||||
|
||||
**在 `backend/prisma/schema.prisma` 中添加:**
|
||||
#### 任务1: 设计 asl_schema 表结�
|
||||
**åœ?`backend/prisma/schema.prisma` 䏿·»åŠ ï¼š**
|
||||
|
||||
```prisma
|
||||
// ==================== ASL ç›é€‰é¡¹ç›®è¡¨ ====================
|
||||
@@ -144,15 +119,12 @@ model AslScreeningProject {
|
||||
// PICOæ ‡å‡†
|
||||
picoCriteria Json @map("pico_criteria") // { population, intervention, comparison, outcome, studyDesign }
|
||||
|
||||
// 筛选标准
|
||||
inclusionCriteria String @map("inclusion_criteria") @db.Text
|
||||
// ç›é€‰æ ‡å‡? inclusionCriteria String @map("inclusion_criteria") @db.Text
|
||||
exclusionCriteria String @map("exclusion_criteria") @db.Text
|
||||
|
||||
// 状态
|
||||
status String @default("draft") // draft, screening, completed
|
||||
// 状� status String @default("draft") // draft, screening, completed
|
||||
|
||||
// 筛选配置
|
||||
screeningConfig Json? @map("screening_config") // { models: ["deepseek", "qwen"], temperature: 0 }
|
||||
// ç›é€‰é…<EFBFBD>ç½? screeningConfig Json? @map("screening_config") // { models: ["deepseek", "qwen"], temperature: 0 }
|
||||
|
||||
// å…³è<C2B3>”
|
||||
literatures AslLiterature[]
|
||||
@@ -168,7 +140,7 @@ model AslScreeningProject {
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
// ==================== ASL 文献条目表 ====================
|
||||
// ==================== ASL 文献æ<EFBFBD>¡ç›®è¡?====================
|
||||
model AslLiterature {
|
||||
id String @id @default(uuid())
|
||||
projectId String @map("project_id")
|
||||
@@ -183,8 +155,7 @@ model AslLiterature {
|
||||
publicationYear Int? @map("publication_year")
|
||||
doi String?
|
||||
|
||||
// 云原生存储字段(V1.0 阶段使用,MVP阶段预留)
|
||||
pdfUrl String? @map("pdf_url") // PDF访问URL
|
||||
// 云原生å˜å‚¨å—段(V1.0 阶段使用,MVP阶段预留ï¼? pdfUrl String? @map("pdf_url") // PDF访问URL
|
||||
pdfOssKey String? @map("pdf_oss_key") // OSSå˜å‚¨Keyï¼ˆç”¨äºŽåˆ é™¤ï¼‰
|
||||
pdfFileSize Int? @map("pdf_file_size") // 文件大å°<C3A5>(å—节)
|
||||
|
||||
@@ -241,23 +212,19 @@ model AslScreeningResult {
|
||||
qwenSEvidence String? @map("qwen_s_evidence") @db.Text
|
||||
qwenReason String? @map("qwen_reason") @db.Text
|
||||
|
||||
// 冲突状态
|
||||
conflictStatus String @default("none") @map("conflict_status") // "none" | "conflict" | "resolved"
|
||||
// 冲çª<EFBFBD>状æ€? conflictStatus String @default("none") @map("conflict_status") // "none" | "conflict" | "resolved"
|
||||
conflictFields Json? @map("conflict_fields") // ["P", "I", "conclusion"]
|
||||
|
||||
// 最终决策
|
||||
finalDecision String? @map("final_decision") // "include" | "exclude" | "pending"
|
||||
// 最终决ç? finalDecision String? @map("final_decision") // "include" | "exclude" | "pending"
|
||||
finalDecisionBy String? @map("final_decision_by") // userId
|
||||
finalDecisionAt DateTime? @map("final_decision_at")
|
||||
exclusionReason String? @map("exclusion_reason") @db.Text
|
||||
|
||||
// AI处理状态
|
||||
aiProcessingStatus String @default("pending") @map("ai_processing_status") // "pending" | "processing" | "completed" | "failed"
|
||||
// AI处ç<EFBFBD>†çжæ€? aiProcessingStatus String @default("pending") @map("ai_processing_status") // "pending" | "processing" | "completed" | "failed"
|
||||
aiProcessedAt DateTime? @map("ai_processed_at")
|
||||
aiErrorMessage String? @map("ai_error_message") @db.Text
|
||||
|
||||
// 可追溯信息
|
||||
promptVersion String @default("v1.0.0") @map("prompt_version")
|
||||
// å<EFBFBD>¯è¿½æº¯ä¿¡æ<EFBFBD>? promptVersion String @default("v1.0.0") @map("prompt_version")
|
||||
rawOutput Json? @map("raw_output") // 原始LLM输出(备份)
|
||||
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
@@ -305,54 +272,48 @@ model AslScreeningTask {
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
// ==================== 用户表关联(添加到User模型)====================
|
||||
// 在 platform_schema 的 User 模型中添加:
|
||||
// ==================== 用户表关è<EFBFBD>”ï¼ˆæ·»åŠ åˆ°User模型ï¼?===================
|
||||
// åœ?platform_schema çš?User æ¨¡åž‹ä¸æ·»åŠ ï¼š
|
||||
// aslProjects AslScreeningProject[] @relation("AslProjects")
|
||||
```
|
||||
|
||||
**执行迁移:**
|
||||
**执行è¿<EFBFBD>ç§»ï¼?*
|
||||
```bash
|
||||
cd backend
|
||||
npx prisma migrate dev --name add_asl_screening_tables
|
||||
npx prisma generate
|
||||
```
|
||||
|
||||
**验收标准**:
|
||||
- ✅ 数据库表创建成功(4张表)
|
||||
- ✅ Prisma Client 生成成功
|
||||
- ✅ 可查询 asl_schema 表
|
||||
|
||||
**éªŒæ”¶æ ‡å‡†**ï¼?- âœ?æ•°æ<C2B0>®åº“表创建æˆ<C3A6>功ï¼?å¼ è¡¨ï¼?- âœ?Prisma Client 生æˆ<C3A6>æˆ<C3A6>功
|
||||
- âœ?å<>¯æŸ¥è¯?asl_schema è¡?
|
||||
---
|
||||
|
||||
### Day 2: å<>Žç«¯ç›®å½•结构创建
|
||||
|
||||
> **⭐ 前置条件(2025-11-17 更新)**:平台基础设施已完成实施 ✅
|
||||
> **完成状态**:8个核心模块,100%测试通过
|
||||
> **â?å‰<C3A5>ç½®æ<C2AE>¡ä»¶ï¼?025-11-17 æ›´æ–°ï¼?*:平å<C2B3>°åŸºç¡€è®¾æ–½å·²å®Œæˆ<C3A6>实æ–?âœ?
|
||||
> **完æˆ<C3A6>状æ€?*ï¼?ä¸ªæ ¸å¿ƒæ¨¡å<C2A1>—,100%测试通过
|
||||
> **完æˆ<C3A6>报告**:[å¹³å<C2B3>°åŸºç¡€è®¾æ–½å®žæ–½å®Œæˆ<C3A6>报告](../../../08-项目管ç<C2A1>†/03-æ¯<C3A6>周计划/2025-11-17-å¹³å<C2B3>°åŸºç¡€è®¾æ–½å®žæ–½å®Œæˆ<C3A6>报告.md)
|
||||
> **使用指å<E280A1>—**:[backend/src/common/README.md](../../../../backend/src/common/README.md)
|
||||
|
||||
#### 平台已提供的8个核心模块(无需ASL模块实现)
|
||||
|
||||
#### å¹³å<EFBFBD>°å·²æ<EFBFBD><EFBFBD>供的8ä¸ªæ ¸å¿ƒæ¨¡å<EFBFBD>—ï¼ˆæ— éœ€ASL模å<EFBFBD>—实现ï¼?
|
||||
**å¹³å<C2B3>°åŸºç¡€è®¾æ–½è·¯å¾„**:`backend/src/common/`
|
||||
|
||||
| # | 模å<C2A1>— | 使用方å¼<C3A5> | 功能说明 |
|
||||
|---|------|---------|---------|
|
||||
| 1 | **存储服务** | `import { storage } from '@/common/storage'` | 文件上传下载(本地/OSS切换) |
|
||||
| 1 | **å˜å‚¨æœ<EFBFBD>务** | `import { storage } from '@/common/storage'` | æ–‡ä»¶ä¸Šä¼ ä¸‹è½½ï¼ˆæœ¬åœ?OSS切æ<E280A1>¢ï¼?|
|
||||
| 2 | **日志系统** | `import { logger } from '@/common/logging'` | 结构化JSON日志 |
|
||||
| 3 | **ç¼“å˜æœ<C3A6>务** | `import { cache } from '@/common/cache'` | 内å˜/Redisç¼“å˜ |
|
||||
| 4 | **异步任务** | `import { jobQueue } from '@/common/jobs'` | 长时间任务处理 |
|
||||
| 5 | **健康检查** | `import { registerHealthRoutes } from '@/common/health'` | SAE健康检查 |
|
||||
| 6 | **监控指标** | `import { Metrics } from '@/common/monitoring'` | 性能监控和告警 |
|
||||
| 4 | **异æ¥ä»»åŠ¡** | `import { jobQueue } from '@/common/jobs'` | 长时间任务处ç<E2809E>?|
|
||||
| 5 | **å<EFBFBD>¥åº·æ£€æŸ?* | `import { registerHealthRoutes } from '@/common/health'` | SAEå<EFBFBD>¥åº·æ£€æŸ?|
|
||||
| 6 | **ç›‘æŽ§æŒ‡æ ‡** | `import { Metrics } from '@/common/monitoring'` | 性能监控和告è?|
|
||||
| 7 | **æ•°æ<C2B0>®åº“è¿žæŽ¥æ± ** | `import { prisma } from '@/config/database'` | 全局Prisma实例 |
|
||||
| 8 | **环境é…<C3A9>ç½®** | `import { env } from '@/config/env'` | 统一é…<C3A9>置管ç<C2A1>† |
|
||||
|
||||
**存储服务使用示例**:
|
||||
```typescript
|
||||
**å˜å‚¨æœ<EFBFBD>务使用示例**ï¼?```typescript
|
||||
// ASL模å<C2A1>—直接使用(一行代ç <C3A7>)
|
||||
import { storage } from '@/common/storage'
|
||||
|
||||
// 上传文件(不关心本地还是OSS)
|
||||
const url = await storage.upload('asl/literature/123.pdf', pdfBuffer)
|
||||
// ä¸Šä¼ æ–‡ä»¶ï¼ˆä¸<EFBFBD>关心本地还是OSSï¼?const url = await storage.upload('asl/literature/123.pdf', pdfBuffer)
|
||||
|
||||
// 下载文件
|
||||
const buffer = await storage.download('asl/literature/123.pdf')
|
||||
@@ -361,26 +322,18 @@ const buffer = await storage.download('asl/literature/123.pdf')
|
||||
await storage.delete('asl/literature/123.pdf')
|
||||
```
|
||||
|
||||
**支持的部署环境**:
|
||||
- ✅ 本地开发:LocalAdapter(文件存储到 `./uploads/`)
|
||||
- ✅ 云端SaaS:OSSAdapter(文件存储到阿里云OSS)
|
||||
- ✅ 私有化部署:LocalAdapter(文件存储到服务器)
|
||||
- ✅ 单机版:LocalAdapter(文件存储到用户本地)
|
||||
|
||||
**环境切换**:修改一个环境变量即可
|
||||
```bash
|
||||
# 本地开发
|
||||
STORAGE_TYPE=local
|
||||
**支æŒ<EFBFBD>的部署环å¢?*ï¼?- âœ?本地开å<E282AC>‘:LocalAdapter(文件å˜å‚¨åˆ° `./uploads/`ï¼?- âœ?云端SaaS:OSSAdapter(文件å˜å‚¨åˆ°é˜¿é‡Œäº‘OSSï¼?- âœ?ç§<C3A7>有化部署:LocalAdapter(文件å˜å‚¨åˆ°æœ<C3A6>务器)
|
||||
- âœ?å<>•机版:LocalAdapter(文件å˜å‚¨åˆ°ç”¨æˆ·æœ¬åœ°ï¼?
|
||||
**环境切æ<E280A1>¢**:修改一个环境å<C692>˜é‡<C3A9>å<EFBFBD>³å<C2B3>?```bash
|
||||
# 本地开å<E282AC>?STORAGE_TYPE=local
|
||||
|
||||
# 生产环境
|
||||
STORAGE_TYPE=oss
|
||||
```
|
||||
|
||||
**核心优势**:
|
||||
- ✅ ASL模块无需关心基础设施实现细节
|
||||
- ✅ 代码零改动切换环境(本地 ↔ 云端)
|
||||
- ✅ 所有业务模块(AIA/PKB/DC等)复用同一套基础设施
|
||||
- ✅ 统一维护、统一升级、统一监控
|
||||
**æ ¸å¿ƒä¼˜åŠ¿**ï¼?- âœ?ASL模å<C2A1>—æ— éœ€å…³å¿ƒåŸºç¡€è®¾æ–½å®žçŽ°ç»†èŠ‚
|
||||
- âœ?代ç <C3A7>零改动切æ<E280A1>¢çŽ¯å¢ƒï¼ˆæœ¬åœ° â†?云端ï¼?- âœ?所有业务模å<C2A1>—(AIA/PKB/DCç‰ï¼‰å¤<C3A5>用å<C2A8>Œä¸€å¥—基础设施
|
||||
- âœ?统一维护ã€<C3A3>统一å<E282AC>‡çº§ã€<C3A3>统一监控
|
||||
|
||||
---
|
||||
|
||||
@@ -402,7 +355,7 @@ touch types/screening.types.ts
|
||||
|
||||
#### 任务2: 创建路由文件
|
||||
|
||||
**`backend/src/modules/asl/routes/index.ts`:**
|
||||
**`backend/src/modules/asl/routes/index.ts`ï¼?*
|
||||
```typescript
|
||||
import { FastifyInstance } from 'fastify'
|
||||
import * as projectController from '../controllers/projectController.js'
|
||||
@@ -413,9 +366,8 @@ import * as screeningController from '../controllers/screeningController.js'
|
||||
* ASL 模å<C2A1>—路由注册
|
||||
*
|
||||
* @description
|
||||
* - 注册到 /api/v1/asl 前缀
|
||||
* - 参考 legacy/routes/ 的风格
|
||||
*
|
||||
* - 注册åˆ?/api/v1/asl å‰<EFBFBD>ç¼€
|
||||
* - å<EFBFBD>‚è€?legacy/routes/ 的风æ ? *
|
||||
* @version Week 3 Day 2
|
||||
*/
|
||||
export async function aslRoutes(fastify: FastifyInstance) {
|
||||
@@ -430,8 +382,7 @@ export async function aslRoutes(fastify: FastifyInstance) {
|
||||
fastify.post('/projects/:projectId/literatures/import', literatureController.importLiteratures)
|
||||
fastify.get('/projects/:projectId/literatures', literatureController.listLiteratures)
|
||||
|
||||
// 筛选管理
|
||||
fastify.post('/projects/:projectId/screening/start', screeningController.startScreening)
|
||||
// ç›é€‰ç®¡ç<EFBFBD>? fastify.post('/projects/:projectId/screening/start', screeningController.startScreening)
|
||||
fastify.get('/projects/:projectId/screening/results', screeningController.getScreeningResults)
|
||||
fastify.put('/screening/results/:resultId', screeningController.updateScreeningResult)
|
||||
fastify.post('/screening/results/batch-update', screeningController.batchUpdateResults)
|
||||
@@ -440,21 +391,19 @@ export async function aslRoutes(fastify: FastifyInstance) {
|
||||
}
|
||||
```
|
||||
|
||||
**验收标准**:
|
||||
- ✅ 目录结构清晰
|
||||
- ✅ 路由文件创建完成
|
||||
- ✅ **可正常使用平台服务**:
|
||||
- ✅ `import { storage } from '@/common/storage'` 可用
|
||||
- ✅ `import { logger } from '@/common/logging'` 可用
|
||||
- ✅ `import { prisma } from '@/config/database'` 可用
|
||||
- ✅ `import { jobQueue } from '@/common/jobs'` 可用
|
||||
- ✅ `import { cache } from '@/common/cache'` 可用
|
||||
**éªŒæ”¶æ ‡å‡†**ï¼?- âœ?目录结构清晰
|
||||
- âœ?路由文件创建完æˆ<C3A6>
|
||||
- âœ?**å<>¯æ£å¸¸ä½¿ç”¨å¹³å<C2B3>°æœ<C3A6>åŠ?*ï¼? - âœ?`import { storage } from '@/common/storage'` å<>¯ç”¨
|
||||
- âœ?`import { logger } from '@/common/logging'` å<>¯ç”¨
|
||||
- âœ?`import { prisma } from '@/config/database'` å<>¯ç”¨
|
||||
- âœ?`import { jobQueue } from '@/common/jobs'` å<>¯ç”¨
|
||||
- âœ?`import { cache } from '@/common/cache'` å<>¯ç”¨
|
||||
|
||||
---
|
||||
|
||||
### Day 3: 在 index.ts 中注册ASL路由
|
||||
### Day 3: åœ?index.ts 䏿³¨å†ŒASL路由
|
||||
|
||||
**`backend/src/index.ts`(修改):**
|
||||
**`backend/src/index.ts`(修改)�*
|
||||
```typescript
|
||||
// ============================================
|
||||
// ã€<C3A3>新架构】ASL 模å<C2A1>— - Week 3 新增
|
||||
@@ -466,22 +415,19 @@ import { aslRoutes } from './modules/asl/routes/index.js';
|
||||
// 注册 ASL 模å<C2A1>—路由
|
||||
await fastify.register(aslRoutes, { prefix: '/api/v1/asl' });
|
||||
|
||||
console.log('✅ ASL 路由已注册到 /api/v1/asl/*');
|
||||
console.log('�ASL 路由已注册到 /api/v1/asl/*');
|
||||
```
|
||||
|
||||
**验收标准**:
|
||||
- ✅ 后端启动成功
|
||||
- ✅ 访问 `http://localhost:3001/api/v1/asl/projects` 返回 200(即使是空列表)
|
||||
**éªŒæ”¶æ ‡å‡†**ï¼?- âœ?å<>Žç«¯å<C2AF>¯åЍæˆ<C3A6>功
|
||||
- âœ?访问 `http://localhost:3001/api/v1/asl/projects` 返回 200(å<CB86>³ä½¿æ˜¯ç©ºåˆ—表)
|
||||
|
||||
---
|
||||
|
||||
## 🗓️ Week 2: LLM筛选核心
|
||||
|
||||
### Day 4-5: LLM筛选服务实现
|
||||
|
||||
## 🗓ï¸?Week 2: LLMç›é€‰æ ¸å¿?
|
||||
### Day 4-5: LLMç›é€‰æœ<C3A6>务实çŽ?
|
||||
#### 任务1: 定义 JSON Schema
|
||||
|
||||
**`backend/src/modules/asl/schemas/screening.schema.ts`:**
|
||||
**`backend/src/modules/asl/schemas/screening.schema.ts`ï¼?*
|
||||
```typescript
|
||||
export const screeningOutputSchema = {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
@@ -541,12 +487,10 @@ export const screeningOutputSchema = {
|
||||
};
|
||||
```
|
||||
|
||||
#### 任务2: 创建提示词模板
|
||||
|
||||
**`backend/prompts/asl/screening/v1.0.0-basic.txt`:**
|
||||
#### 任务2: 创建æ<C2BA><C3A6>示è¯<C3A8>模æ<C2A1>?
|
||||
**`backend/prompts/asl/screening/v1.0.0-basic.txt`ï¼?*
|
||||
```
|
||||
你是一位医学文献筛选专家。请根据以下 PICO 标准判断这篇文献是否应该纳入系统评价。
|
||||
|
||||
ä½ æ˜¯ä¸€ä½<EFBFBD>åŒ»å¦æ–‡çŒ®ç›é€‰ä¸“å®¶ã€‚è¯·æ ¹æ<EFBFBD>®ä»¥ä¸‹ PICO æ ‡å‡†åˆ¤æ–这篇文献是å<C2AF>¦åº”该纳入系统评价ã€?
|
||||
# PICO æ ‡å‡†
|
||||
- **Population (ç ”ç©¶å¯¹è±¡)**: {{population}}
|
||||
- **Intervention (干预措施)**: {{intervention}}
|
||||
@@ -560,18 +504,16 @@ export const screeningOutputSchema = {
|
||||
# æŽ’é™¤æ ‡å‡†
|
||||
{{exclusionCriteria}}
|
||||
|
||||
# 待筛选文献
|
||||
**标题**: {{title}}
|
||||
# å¾…ç›é€‰æ–‡çŒ?**æ ‡é¢˜**: {{title}}
|
||||
|
||||
**摘è¦<C3A8>**: {{abstract}}
|
||||
|
||||
# 输出è¦<C3A8>求
|
||||
|
||||
请严格按照以下 JSON Schema 输出结果,输出纯JSON(不要包含任何其他文字):
|
||||
|
||||
è¯·ä¸¥æ ¼æŒ‰ç…§ä»¥ä¸?JSON Schema 输出结果,输出纯JSON(ä¸<C3A4>è¦<C3A8>包å<E280A6>«ä»»ä½•å…¶ä»–æ–‡å—)ï¼?
|
||||
{
|
||||
"decision": "include/exclude/uncertain",
|
||||
"reason": "判断理由(10-500字)",
|
||||
"reason": "判æ–ç<EFBFBD>†ç”±ï¼?0-500å—)",
|
||||
"confidence": 0.95,
|
||||
"pico": {
|
||||
"population": "match/partial/mismatch",
|
||||
@@ -589,16 +531,13 @@ export const screeningOutputSchema = {
|
||||
}
|
||||
|
||||
# 注æ„<C3A6>事项
|
||||
1. decision 只能是 "include"(纳入)、"exclude"(排除)或 "uncertain"(不确定)
|
||||
2. reason 必须具体说明判断依据
|
||||
3. confidence 为 0-1 之间的数值
|
||||
4. pico 字段逐项评估匹配程度
|
||||
1. decision å<EFBFBD>ªèƒ½æ˜?"include"(纳入)ã€?exclude"(排除)æˆ?"uncertain"(ä¸<C3A4>确定ï¼?2. reason 必须具体说明判æ–ä¾<C3A4>æ<EFBFBD>®
|
||||
3. confidence ä¸?0-1 之间的数å€?4. pico å—æ®µé€<C3A9>项评估匹é…<C3A9>程度
|
||||
5. evidences å—æ®µæ<C2B5><C3A6>å<EFBFBD>–原文ä¸çš„关键çŸè¯ä½œä¸ºè¯<C3A8>æ<EFBFBD>®
|
||||
```
|
||||
|
||||
#### 任务3: 实现 LLM 筛选服务
|
||||
|
||||
**`backend/src/modules/asl/services/llmScreeningService.ts`:**
|
||||
#### 任务3: 实现 LLM ç›é€‰æœ<C3A6>åŠ?
|
||||
**`backend/src/modules/asl/services/llmScreeningService.ts`ï¼?*
|
||||
```typescript
|
||||
import { LLMFactory } from '../../../common/llm/adapters/LLMFactory.js';
|
||||
import { parseJSON } from '../../../common/utils/jsonParser.js';
|
||||
@@ -615,23 +554,18 @@ const ajv = new Ajv();
|
||||
const validateSchema = ajv.compile(screeningOutputSchema);
|
||||
|
||||
/**
|
||||
* LLM 筛选服务
|
||||
*
|
||||
* LLM ç›é€‰æœ<EFBFBD>åŠ? *
|
||||
* @description
|
||||
* - å¤<C3A5>用 common/llm/adapters/LLMFactory.ts
|
||||
* - 双模型并行调用(DeepSeek + Qwen)
|
||||
* - JSON Schema 验证
|
||||
* - 冲突检测
|
||||
*
|
||||
* - å<EFBFBD>Œæ¨¡åž‹å¹¶è¡Œè°ƒç”¨ï¼ˆDeepSeek + Qwenï¼? * - JSON Schema 验è¯<C3A8>
|
||||
* - 冲çª<EFBFBD>检æµ? *
|
||||
* @version Week 3 Day 4-5
|
||||
*/
|
||||
class LLMScreeningService {
|
||||
/**
|
||||
* 双模型并行筛选
|
||||
*/
|
||||
* å<EFBFBD>Œæ¨¡åž‹å¹¶è¡Œç›é€? */
|
||||
async dualModelScreening(literature: any, protocol: any) {
|
||||
// 构建提示词
|
||||
const prompt = this.buildPrompt(literature, protocol);
|
||||
// 构建æ<EFBFBD><EFBFBD>示è¯? const prompt = this.buildPrompt(literature, protocol);
|
||||
|
||||
// 并行调用两个模型
|
||||
const [resultA, resultB] = await Promise.all([
|
||||
@@ -643,8 +577,7 @@ class LLMScreeningService {
|
||||
const decisionA = await this.parseModelOutput(resultA.content, 'deepseek');
|
||||
const decisionB = await this.parseModelOutput(resultB.content, 'qwen');
|
||||
|
||||
// 一致性判断
|
||||
const { consensus, conflictFields } = this.compareDecisions(decisionA, decisionB);
|
||||
// 一致性判� const { consensus, conflictFields } = this.compareDecisions(decisionA, decisionB);
|
||||
|
||||
// 自动分æµ<C3A6>
|
||||
const needReview = this.shouldReview(consensus, decisionA, decisionB);
|
||||
@@ -660,8 +593,7 @@ class LLMScreeningService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用LLM模型(复用common/llm)
|
||||
*/
|
||||
* 调用LLM模型(å¤<EFBFBD>用common/llmï¼? */
|
||||
private async callModel(modelName: string, prompt: string) {
|
||||
const llm = LLMFactory.createLLM(modelName);
|
||||
|
||||
@@ -669,19 +601,16 @@ class LLMScreeningService {
|
||||
messages: [
|
||||
{ role: 'user', content: prompt }
|
||||
],
|
||||
temperature: 0, // 确定性输出
|
||||
max_tokens: 1000
|
||||
temperature: 0, // 确定性输� max_tokens: 1000
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建提示词
|
||||
*/
|
||||
* 构建æ<EFBFBD><EFBFBD>示è¯? */
|
||||
private buildPrompt(literature: any, protocol: any): string {
|
||||
// 读取提示词模板
|
||||
const templatePath = path.resolve(__dirname, '../../../../prompts/asl/screening/v1.0.0-basic.txt');
|
||||
// 读å<EFBFBD>–æ<EFBFBD><EFBFBD>示è¯<EFBFBD>模æ<EFBFBD>? const templatePath = path.resolve(__dirname, '../../../../prompts/asl/screening/v1.0.0-basic.txt');
|
||||
let template = fs.readFileSync(templatePath, 'utf-8');
|
||||
|
||||
// 替æ<C2BF>¢å<C2A2>˜é‡<C3A9>
|
||||
@@ -702,13 +631,12 @@ class LLMScreeningService {
|
||||
* è§£æž<C3A6>模型输出
|
||||
*/
|
||||
private async parseModelOutput(content: string, modelName: string) {
|
||||
// 使用JSON解析器(复用common/utils)
|
||||
const parsed = parseJSON(content);
|
||||
// 使用JSONè§£æž<EFBFBD>器(å¤<EFBFBD>用common/utilsï¼? const parsed = parseJSON(content);
|
||||
|
||||
// JSON Schema 验è¯<C3A8>
|
||||
const valid = validateSchema(parsed);
|
||||
if (!valid) {
|
||||
console.error('JSON Schema验证失败:', validateSchema.errors);
|
||||
console.error('JSON Schema验è¯<C3A8>失败ï¼?, validateSchema.errors);
|
||||
throw new Error(`模型${modelName}è¾“å‡ºæ ¼å¼<C3A5>ä¸<C3A4>符å<C2A6>ˆSchema`);
|
||||
}
|
||||
|
||||
@@ -724,18 +652,15 @@ class LLMScreeningService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 对比两个模型的决策
|
||||
*/
|
||||
* 对比两个模型的决ç? */
|
||||
private compareDecisions(decisionA: any, decisionB: any) {
|
||||
const conflicts: string[] = [];
|
||||
|
||||
// 比较最终决策
|
||||
if (decisionA.decision !== decisionB.decision) {
|
||||
// 比较最终决ç? if (decisionA.decision !== decisionB.decision) {
|
||||
conflicts.push('decision');
|
||||
}
|
||||
|
||||
// 比较PICO各维度
|
||||
if (decisionA.pico.population !== decisionB.pico.population) conflicts.push('P');
|
||||
// 比较PICOå<EFBFBD>„ç»´åº? if (decisionA.pico.population !== decisionB.pico.population) conflicts.push('P');
|
||||
if (decisionA.pico.intervention !== decisionB.pico.intervention) conflicts.push('I');
|
||||
if (decisionA.pico.comparison !== decisionB.pico.comparison) conflicts.push('C');
|
||||
if (decisionA.pico.outcome !== decisionB.pico.outcome) conflicts.push('O');
|
||||
@@ -749,27 +674,24 @@ class LLMScreeningService {
|
||||
* 自动分æµ<C3A6>规则
|
||||
*/
|
||||
private shouldReview(consensus: string, decisionA: any, decisionB: any): boolean {
|
||||
// 规则1:冲突 → 必须复核
|
||||
// 规则1:冲çª?â†?å¿…é¡»å¤<C3A5>æ ¸
|
||||
if (consensus === 'conflict') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 规则2:低置信度 → 需要复核
|
||||
const avgConfidence = (decisionA.confidence + decisionB.confidence) / 2;
|
||||
// 规则2:低置信åº?â†?需è¦<C3A8>å¤<C3A5>æ ? const avgConfidence = (decisionA.confidence + decisionB.confidence) / 2;
|
||||
if (avgConfidence < 0.7) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 规则3:高置信度 + 一致 → 自动通过
|
||||
// 规则3:高置信�+ 一��自动通过
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量筛选
|
||||
*/
|
||||
* 批é‡<EFBFBD>ç›é€? */
|
||||
async batchScreening(literatures: any[], protocol: any, progressCallback?: (progress: number) => void) {
|
||||
const batchSize = 15; // 每批15篇
|
||||
const results = [];
|
||||
const batchSize = 15; // æ¯<EFBFBD>批15ç¯? const results = [];
|
||||
|
||||
for (let i = 0; i < literatures.length; i += batchSize) {
|
||||
const batch = literatures.slice(i, i + batchSize);
|
||||
@@ -781,8 +703,7 @@ class LLMScreeningService {
|
||||
|
||||
results.push(...batchResults);
|
||||
|
||||
// 推送进度
|
||||
const progress = Math.round(((i + batch.length) / literatures.length) * 100);
|
||||
// 推é€<EFBFBD>è¿›åº? const progress = Math.round(((i + batch.length) / literatures.length) * 100);
|
||||
progressCallback?.(progress);
|
||||
}
|
||||
|
||||
@@ -793,20 +714,16 @@ class LLMScreeningService {
|
||||
export const llmScreeningService = new LLMScreeningService();
|
||||
```
|
||||
|
||||
**验收标准**:
|
||||
- ✅ LLM双模型调用成功
|
||||
- ✅ JSON Schema验证通过率 > 95%
|
||||
- ✅ 冲突检测准确
|
||||
|
||||
**éªŒæ”¶æ ‡å‡†**ï¼?- âœ?LLMå<4D>Œæ¨¡åž‹è°ƒç”¨æˆ<C3A6>åŠ?- âœ?JSON Schema验è¯<C3A8>通过çŽ?> 95%
|
||||
- âœ?冲çª<C3A7>检测准ç¡?
|
||||
---
|
||||
|
||||
## 🗓️ Week 3: 前端模块开发
|
||||
|
||||
## 🗓ï¸?Week 3: å‰<EFBFBD>端模å<EFBFBD>—å¼€å<EFBFBD>?
|
||||
### Day 6-7: å‰<C3A5>端模å<C2A1>—结构创建
|
||||
|
||||
#### 任务1: 更新模å<C2A1>—定义
|
||||
|
||||
**`frontend-v2/src/modules/asl/index.tsx`(修改):**
|
||||
**`frontend-v2/src/modules/asl/index.tsx`(修改)�*
|
||||
```typescript
|
||||
import { lazy } from 'react'
|
||||
import { ModuleDefinition } from '@/framework/modules/types'
|
||||
@@ -827,7 +744,7 @@ const ASLModule: ModuleDefinition = {
|
||||
path: '/literature',
|
||||
icon: FileSearchOutlined,
|
||||
component: lazy(() => import('./routes')),
|
||||
placeholder: false, // ✅ 改为 false
|
||||
placeholder: false, // �改为 false
|
||||
requiredVersion: 'advanced',
|
||||
description: 'AI驱动的文献ç›é€‰å’Œåˆ†æž<C3A6>系统',
|
||||
}
|
||||
@@ -850,7 +767,7 @@ touch api/index.ts
|
||||
|
||||
#### 任务3: 实现路由é…<C3A9>ç½®
|
||||
|
||||
**`frontend-v2/src/modules/asl/routes.tsx`:**
|
||||
**`frontend-v2/src/modules/asl/routes.tsx`ï¼?*
|
||||
```typescript
|
||||
import { lazy } from 'react'
|
||||
import { Routes, Route, Navigate } from 'react-router-dom'
|
||||
@@ -865,9 +782,7 @@ const ScreeningResults = lazy(() => import('./pages/ScreeningResults'))
|
||||
*
|
||||
* @description
|
||||
* - /literature - 项目列表
|
||||
* - /literature/project/:id/settings - 设置与启动
|
||||
* - /literature/project/:id/workbench - 审核工作台
|
||||
* - /literature/project/:id/results - 初筛结果
|
||||
* - /literature/project/:id/settings - 设置与å<EFBFBD>¯åŠ? * - /literature/project/:id/workbench - å®¡æ ¸å·¥ä½œå<C593>? * - /literature/project/:id/results - åˆ<C3A5>ç›ç»“æžœ
|
||||
*
|
||||
* @version Week 3 Day 6
|
||||
*/
|
||||
@@ -885,9 +800,7 @@ export default function ASLRoutes() {
|
||||
}
|
||||
```
|
||||
|
||||
**验收标准**:
|
||||
- ✅ 顶部导航显示"AI智能文献"(不再是占位)
|
||||
- ✅ 点击后进入项目列表页(即使是空列表)
|
||||
**éªŒæ”¶æ ‡å‡†**ï¼?- âœ?顶部导航显示"AI智能文献"(ä¸<C3A4>å†<C3A5>是å<C2AF> ä½<C3A4>ï¼?- âœ?点击å<C2BB>Žè¿›å…¥é¡¹ç›®åˆ—表页(å<CB86>³ä½¿æ˜¯ç©ºåˆ—表)
|
||||
|
||||
---
|
||||
|
||||
@@ -895,39 +808,29 @@ export default function ASLRoutes() {
|
||||
|
||||
(由于篇幅é™<EFBFBD>åˆ¶ï¼Œæ ¸å¿ƒå®žçŽ°ä»£ç <EFBFBD>请å<EFBFBD>‚考任务分解文档)
|
||||
|
||||
**验收标准**:
|
||||
- ✅ Excel上传功能正常
|
||||
- ✅ 审核工作台可展示筛选结果
|
||||
- ✅ 双视图模态框可弹出
|
||||
|
||||
**éªŒæ”¶æ ‡å‡†**ï¼?- âœ?Excelä¸Šä¼ åŠŸèƒ½æ£å¸¸
|
||||
- âœ?å®¡æ ¸å·¥ä½œå<C593>°å<C2B0>¯å±•示ç›é€‰ç»“æž?- âœ?å<>Œè§†å›¾æ¨¡æ€<C3A6>框å<E280A0>¯å¼¹å‡?
|
||||
---
|
||||
|
||||
## 🗓️ Week 4: 集成测试与验收
|
||||
|
||||
### Day 11-14: 端到端测试
|
||||
|
||||
(详细测试计划见任务分解文档)
|
||||
|
||||
**验收标准**:
|
||||
- ✅ 完整流程:上传 → 筛选 → 复核 → 导出
|
||||
- ✅ 准确率 ≥ 85%
|
||||
- ✅ 性能达标(100篇 < 10分钟)
|
||||
|
||||
## 🗓ï¸?Week 4: 集æˆ<EFBFBD>测试与验æ”?
|
||||
### Day 11-14: 端到端测�
|
||||
(详细测试计划è§<EFBFBD>任务分解文档ï¼?
|
||||
**éªŒæ”¶æ ‡å‡†**ï¼?- âœ?完整æµ<C3A6>程:上ä¼?â†?ç›é€?â†?å¤<C3A5>æ ¸ â†?导出
|
||||
- �准确��85%
|
||||
- âœ?æ€§èƒ½è¾¾æ ‡ï¼?00ç¯?< 10分钟ï¼?
|
||||
---
|
||||
|
||||
## 📚 相关文档
|
||||
|
||||
- [å¼€å<EFBFBD>‘里程碑](./01-å¼€å<E282AC>‘里程碑.md)
|
||||
- [任务分解(Todo List)](./03-任务分解.md)
|
||||
- [质量保障策略](../02-技术设计/06-质量保障与可追溯策略.md)
|
||||
- [技术选型](../02-技术设计/07-文献处理技术选型.md)
|
||||
- [API设计规范](../02-技术设计/02-API设计规范.md)
|
||||
- [è´¨é‡<EFBFBD>ä¿<EFBFBD>éšœç–ç•¥](../02-技术设è®?06-è´¨é‡<C3A9>ä¿<C3A4>障与å<C5BD>¯è¿½æº¯ç–ç•¥.md)
|
||||
- [技术选型](../02-技术设è®?07-文献处ç<E2809E>†æŠ€æœ¯é€‰åž‹.md)
|
||||
- [API设计规范](../02-技术设�02-API设计规范.md)
|
||||
- [å‰<EFBFBD>å<EFBFBD>Žç«¯æ¨¡å<EFBFBD>—化架构设计-V2](../../../00-系统总体设计/å‰<C3A5>å<EFBFBD>Žç«¯æ¨¡å<C2A1>—化架构设计-V2.md)
|
||||
|
||||
---
|
||||
|
||||
**更新日志**:
|
||||
- 2025-11-18: V3.1 更新,补充平台基础设施完成状态(8个核心模块)
|
||||
- 2025-11-16: V3.0 重写,基于真实架构(Frontend-v2 + Backend + asl_schema)
|
||||
- 2025-11-16: V2.0 重写,详细到每天的任务和代码示例
|
||||
- 2025-10-29: V1.0 创建,初始版本
|
||||
**更新日志**ï¼?- 2025-11-18: V3.1 更新,补充平å<C2B3>°åŸºç¡€è®¾æ–½å®Œæˆ<C3A6>状æ€<C3A6>(8ä¸ªæ ¸å¿ƒæ¨¡å<C2A1>—)
|
||||
- 2025-11-16: V3.0 é‡<C3A9>写,基于真实架构(Frontend-v2 + Backend + asl_schemaï¼?- 2025-11-16: V2.0 é‡<C3A9>写,详细到æ¯<C3A6>天的任务和代ç <C3A7>示例
|
||||
- 2025-10-29: V1.0 创建,åˆ<EFBFBD>始版æœ?
|
||||
Reference in New Issue
Block a user