Files
AIclinicalresearch/第一周开发指南.md
2025-10-10 15:14:54 +08:00

901 lines
18 KiB
Markdown
Raw 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.
# 第一周开发指南Day 1-7
> **目标:** 搭建完整的开发环境,实现第一个功能(用户认证)
> **时间:** 7天
> **状态:** 🚀 准备就绪!
---
## ✅ 已完成准备工作
- [x] Docker Desktop 安装完毕
- [x] DeepSeek API Key 已申请
- [x] Qwen API Key 已申请
---
## 📅 本周计划
| 天数 | 任务 | 预计时间 |
|------|------|---------|
| Day 1 | 验证环境 + 创建项目结构 | 2小时 |
| Day 2 | 启动基础服务Docker | 1小时 |
| Day 3 | 搭建后端框架 | 3小时 |
| Day 4 | 搭建前端框架 | 3小时 |
| Day 5 | 实现用户认证(后端) | 4小时 |
| Day 6 | 实现登录界面(前端) | 4小时 |
| Day 7 | 测试联调 | 2小时 |
---
## 🎯 Day 1: 验证环境 + 创建项目结构
### 步骤1验证 Docker 安装
打开终端Windows用PowerShell或CMDmacOS用Terminal执行
```bash
# 检查 Docker 版本
docker --version
# 应输出类似Docker version 24.0.x
# 检查 Docker Compose 版本
docker-compose --version
# 应输出类似Docker Compose version v2.x.x
# 检查 Docker 是否运行
docker ps
# 应输出表头(即使没有容器运行)
```
**如果遇到错误:**
- Windows: 确保 Docker Desktop 已启动系统托盘有Docker图标
- macOS: 确保 Docker Desktop 已启动
---
### 步骤2创建项目目录结构
```bash
# 选择一个工作目录(比如 D:\Projects 或 ~/Projects
cd D:\Projects # Windows
# 或
cd ~/Projects # macOS/Linux
# 创建项目根目录
mkdir ai-clinical-research
cd ai-clinical-research
# 创建子目录
mkdir backend frontend config docs
# 验证目录结构
tree -L 1
# 或 Windows: dir
```
**预期结构:**
```
ai-clinical-research/
├── backend/ # 后端代码
├── frontend/ # 前端代码
├── config/ # 配置文件
└── docs/ # 文档
```
---
### 步骤3创建 docker-compose.yml
在项目根目录创建 `docker-compose.yml`
```yaml
version: '3.8'
services:
# PostgreSQL 数据库
postgres:
image: postgres:15-alpine
container_name: acr-postgres
environment:
POSTGRES_DB: ai_clinical_research
POSTGRES_USER: dev_user
POSTGRES_PASSWORD: dev_pass_2024
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dev_user -d ai_clinical_research"]
interval: 10s
timeout: 5s
retries: 5
# Redis 缓存
redis:
image: redis:7-alpine
container_name: acr-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
# Dify Sandbox沙箱环境Dify依赖
dify-sandbox:
image: langgenius/dify-sandbox:latest
container_name: acr-dify-sandbox
restart: unless-stopped
# Dify API
dify-api:
image: langgenius/dify-api:latest
container_name: acr-dify-api
environment:
# 数据库配置
DB_USERNAME: dify
DB_PASSWORD: dify_pass_2024
DB_HOST: dify-postgres
DB_PORT: 5432
DB_DATABASE: dify
# Redis配置
REDIS_HOST: dify-redis
REDIS_PORT: 6379
REDIS_DB: 0
# 应用配置
MODE: api
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
CONSOLE_WEB_URL: http://localhost
CONSOLE_API_URL: http://localhost:5001
SERVICE_API_URL: http://localhost:5001
APP_WEB_URL: http://localhost
# 文件存储(本地)
STORAGE_TYPE: local
STORAGE_LOCAL_PATH: /app/storage
# Vector Store向量数据库
VECTOR_STORE: qdrant
QDRANT_URL: http://dify-qdrant:6333
QDRANT_API_KEY: dify-qdrant-key
# Celery异步任务
CELERY_BROKER_URL: redis://dify-redis:6379/1
# 模型配置可选可在Web界面配置
# OPENAI_API_KEY: your-key-here
ports:
- "5001:5001"
volumes:
- dify_app_storage:/app/storage
depends_on:
- dify-postgres
- dify-redis
- dify-qdrant
- dify-sandbox
restart: unless-stopped
# Dify Worker后台任务处理
dify-worker:
image: langgenius/dify-api:latest
container_name: acr-dify-worker
environment:
MODE: worker
DB_USERNAME: dify
DB_PASSWORD: dify_pass_2024
DB_HOST: dify-postgres
DB_PORT: 5432
DB_DATABASE: dify
REDIS_HOST: dify-redis
REDIS_PORT: 6379
REDIS_DB: 0
CELERY_BROKER_URL: redis://dify-redis:6379/1
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
STORAGE_TYPE: local
STORAGE_LOCAL_PATH: /app/storage
VECTOR_STORE: qdrant
QDRANT_URL: http://dify-qdrant:6333
QDRANT_API_KEY: dify-qdrant-key
volumes:
- dify_app_storage:/app/storage
depends_on:
- dify-postgres
- dify-redis
- dify-qdrant
restart: unless-stopped
# Dify PostgreSQL
dify-postgres:
image: postgres:15-alpine
container_name: acr-dify-postgres
environment:
POSTGRES_DB: dify
POSTGRES_USER: dify
POSTGRES_PASSWORD: dify_pass_2024
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- dify_postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dify -d dify"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
# Dify Redis
dify-redis:
image: redis:7-alpine
container_name: acr-dify-redis
volumes:
- dify_redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
restart: unless-stopped
# Qdrant 向量数据库
dify-qdrant:
image: qdrant/qdrant:latest
container_name: acr-dify-qdrant
environment:
QDRANT__SERVICE__API_KEY: dify-qdrant-key
ports:
- "6333:6333"
volumes:
- dify_qdrant_data:/qdrant/storage
restart: unless-stopped
# Dify Web界面
dify-web:
image: langgenius/dify-web:latest
container_name: acr-dify-web
environment:
CONSOLE_API_URL: http://localhost:5001
APP_API_URL: http://localhost:5001
ports:
- "3000:3000"
depends_on:
- dify-api
restart: unless-stopped
volumes:
postgres_data:
redis_data:
dify_postgres_data:
dify_redis_data:
dify_qdrant_data:
dify_app_storage:
networks:
default:
name: acr-network
```
**保存文件:** `ai-clinical-research/docker-compose.yml`
---
### 步骤4创建 .gitignore
在项目根目录创建 `.gitignore`
```gitignore
# Node modules
node_modules/
*/node_modules/
# Environment variables
.env
.env.local
.env.*.local
*.env
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Build outputs
dist/
build/
*.log
# Database
*.sqlite
*.db
# API Keys重要
**/config/api-keys.json
backend/config/api-keys.json
```
---
### 步骤5创建 README.md
在项目根目录创建 `README.md`
```markdown
# AI科研助手
## 快速启动
### 启动所有服务
\`\`\`bash
docker-compose up -d
\`\`\`
### 查看服务状态
\`\`\`bash
docker-compose ps
\`\`\`
### 查看日志
\`\`\`bash
docker-compose logs -f
\`\`\`
### 停止所有服务
\`\`\`bash
docker-compose down
\`\`\`
## 访问地址
- 前端开发服务器: http://localhost:5173
- 后端API: http://localhost:3001
- Dify Web管理界面: http://localhost:3000
- Dify API: http://localhost:5001
- PostgreSQL: localhost:5432
- Redis: localhost:6379
## 开发文档
详见 `docs/` 目录
```
---
**✅ Day 1 完成检查清单:**
- [ ] Docker 命令验证通过
- [ ] 项目目录创建完成
- [ ] docker-compose.yml 创建完成
- [ ] .gitignore 创建完成
- [ ] README.md 创建完成
---
## 🎯 Day 2: 启动基础服务
### 步骤1启动 Docker 服务
```bash
# 确保在项目根目录
cd ai-clinical-research
# 启动所有服务首次启动会下载镜像需要5-10分钟
docker-compose up -d
# 查看启动日志
docker-compose logs -f
# 等待所有服务启动完成约2-3分钟
# 看到类似信息表示成功:
# acr-dify-api | INFO: Application startup complete.
# acr-dify-web | ready - started server on 0.0.0.0:3000
```
**注意:** 首次启动会下载Docker镜像约2GB请耐心等待。
---
### 步骤2验证服务状态
```bash
# 查看所有容器状态
docker-compose ps
# 应该看到所有服务都是 "Up" 状态
# NAME STATUS
# acr-postgres Up (healthy)
# acr-redis Up (healthy)
# acr-dify-postgres Up (healthy)
# acr-dify-redis Up (healthy)
# acr-dify-qdrant Up
# acr-dify-api Up
# acr-dify-worker Up
# acr-dify-web Up
```
---
### 步骤3访问 Dify Web 界面
1. 打开浏览器访问http://localhost:3000
2. 首次访问会要求创建管理员账号
3. 填写信息:
- 邮箱admin@example.com
- 密码Admin123!(自己设置一个)
- 确认密码Admin123!
4. 点击"创建账号"
**成功标志:** 进入Dify管理后台
---
### 步骤4获取 Dify API Key
1. 在Dify管理后台点击左侧 "设置" → "API密钥"
2. 点击 "创建密钥"
3. 复制生成的API Key类似`app-xxx...`
4. 保存到安全的地方(后面会用到)
---
### 步骤5测试数据库连接
```bash
# 测试 PostgreSQL业务数据库
docker exec -it acr-postgres psql -U dev_user -d ai_clinical_research -c "SELECT version();"
# 应输出 PostgreSQL 版本信息
# 测试 Redis
docker exec -it acr-redis redis-cli ping
# 应输出: PONG
# 测试 Dify API
curl http://localhost:5001/health
# 应输出: {"status":"ok"}
```
---
**✅ Day 2 完成检查清单:**
- [ ] 所有Docker容器启动成功
- [ ] Dify Web界面可访问
- [ ] Dify管理员账号创建完成
- [ ] Dify API Key获取完成
- [ ] 数据库连接测试通过
---
## 🎯 Day 3: 搭建后端框架
### 步骤1初始化后端项目
```bash
# 进入后端目录
cd backend
# 初始化 Node.js 项目
npm init -y
# 安装依赖
npm install fastify@4.26.0 \
@fastify/cors@9.0.0 \
@fastify/jwt@7.2.0 \
@prisma/client@5.10.0 \
bcryptjs@2.4.3 \
dotenv@16.4.0 \
ioredis@5.3.0 \
axios@1.6.0
# 安装开发依赖
npm install -D \
prisma@5.10.0 \
typescript@5.3.0 \
@types/node@20.11.0 \
@types/bcryptjs@2.4.6 \
tsx@4.7.0 \
nodemon@3.0.0
```
---
### 步骤2配置 TypeScript
创建 `backend/tsconfig.json`
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"moduleResolution": "node"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
```
---
### 步骤3配置环境变量
创建 `backend/.env`
```bash
# 数据库配置
DATABASE_URL="postgresql://dev_user:dev_pass_2024@localhost:5432/ai_clinical_research"
# Redis配置
REDIS_URL="redis://localhost:6379"
# JWT配置
JWT_SECRET="your-super-secret-jwt-key-change-this-in-production-2024"
JWT_EXPIRES_IN="7d"
# LLM API Keys
DEEPSEEK_API_KEY="你的DeepSeek API Key"
DASHSCOPE_API_KEY="你的Qwen API Key"
# Dify配置
DIFY_API_URL="http://localhost:5001"
DIFY_API_KEY="你在Day2获取的Dify API Key"
# 应用配置
NODE_ENV="development"
PORT=3001
```
**注意:** 把"你的XXX API Key"替换成你实际申请的Key
---
### 步骤4初始化 Prisma
```bash
# 初始化 Prisma
npx prisma init
# 这会创建 prisma/schema.prisma 文件
```
编辑 `backend/prisma/schema.prisma`
```prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// 用户表
model User {
id String @id @default(uuid())
email String @unique
password String
name String?
role String @default("user") // user, admin
status String @default("active") // active, inactive
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// 关联
projects Project[]
knowledgeBases KnowledgeBase[]
@@map("users")
}
// 项目/课题表
model Project {
id String @id @default(uuid())
userId String
name String
description String @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// 关联
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
conversations Conversation[]
@@map("projects")
}
// 对话表
model Conversation {
id String @id @default(uuid())
projectId String?
userId String
agentId String
title String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// 关联
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade)
messages Message[]
@@map("conversations")
}
// 消息表
model Message {
id String @id @default(uuid())
conversationId String
role String // user, assistant
content String @db.Text
createdAt DateTime @default(now())
// 关联
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
@@map("messages")
}
// 知识库表
model KnowledgeBase {
id String @id @default(uuid())
userId String
name String
description String?
difyDatasetId String // Dify中的知识库ID
fileCount Int @default(0)
totalSizeBytes BigInt @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// 关联
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
documents Document[]
@@map("knowledge_bases")
}
// 文档表
model Document {
id String @id @default(uuid())
kbId String
userId String
filename String
fileType String
fileSizeBytes BigInt
fileUrl String
difyDocumentId String
status String @default("uploading") // uploading, processing, completed, failed
progress Int @default(0)
errorMessage String?
segmentsCount Int?
tokensCount Int?
uploadedAt DateTime @default(now())
processedAt DateTime?
// 关联
knowledgeBase KnowledgeBase @relation(fields: [kbId], references: [id], onDelete: Cascade)
@@map("documents")
}
```
---
### 步骤5创建数据库表
```bash
# 生成 Prisma Client
npx prisma generate
# 创建数据库迁移
npx prisma migrate dev --name init
# 看到类似输出表示成功:
# ✔ Generated Prisma Client
# ✔ Your database is now in sync with your schema.
```
---
### 步骤6创建基础目录结构
```bash
# 在 backend 目录下创建
mkdir -p src/routes src/services src/config src/utils src/types
```
---
### 步骤7创建服务器入口文件
创建 `backend/src/server.ts`
```typescript
import Fastify from 'fastify';
import cors from '@fastify/cors';
import dotenv from 'dotenv';
// 加载环境变量
dotenv.config();
const server = Fastify({
logger: true
});
// 注册CORS
server.register(cors, {
origin: true // 开发环境允许所有来源
});
// 健康检查端点
server.get('/health', async (request, reply) => {
return { status: 'ok', timestamp: new Date().toISOString() };
});
// 测试端点
server.get('/api/test', async (request, reply) => {
return {
message: 'AI科研助手后端服务运行正常',
env: process.env.NODE_ENV,
timestamp: new Date().toISOString()
};
});
// 启动服务器
const start = async () => {
try {
const port = parseInt(process.env.PORT || '3001');
await server.listen({ port, host: '0.0.0.0' });
console.log(`🚀 服务器启动成功!`);
console.log(`📝 API地址: http://localhost:${port}`);
console.log(`🏥 健康检查: http://localhost:${port}/health`);
} catch (err) {
server.log.error(err);
process.exit(1);
}
};
start();
```
---
### 步骤8配置 package.json scripts
编辑 `backend/package.json`,添加 scripts
```json
{
"scripts": {
"dev": "tsx watch src/server.ts",
"build": "tsc",
"start": "node dist/server.js",
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate dev",
"prisma:studio": "prisma studio"
}
}
```
---
### 步骤9启动后端服务
```bash
# 启动开发服务器
npm run dev
# 看到类似输出表示成功:
# 🚀 服务器启动成功!
# 📝 API地址: http://localhost:3001
# 🏥 健康检查: http://localhost:3001/health
```
---
### 步骤10测试后端API
打开新的终端窗口:
```bash
# 测试健康检查
curl http://localhost:3001/health
# 测试API
curl http://localhost:3001/api/test
```
---
**✅ Day 3 完成检查清单:**
- [ ] 后端项目初始化完成
- [ ] 依赖安装完成
- [ ] TypeScript配置完成
- [ ] 环境变量配置完成
- [ ] Prisma数据库模型创建完成
- [ ] 数据库迁移成功
- [ ] 后端服务启动成功
- [ ] API测试通过
---
## 🎯 Day 4-7: 继续开发...
后续天数的详细步骤将在您完成Day 1-3后提供
---
## 📊 当前进度
```
✅ 环境准备: 100%
⏳ Day 1: 待开始
⏳ Day 2: 待开始
⏳ Day 3: 待开始
```
---
## 🆘 常见问题
### Q1: Docker 容器启动失败
```bash
# 查看日志
docker-compose logs [服务名]
# 重启服务
docker-compose restart [服务名]
# 完全重置
docker-compose down -v
docker-compose up -d
```
### Q2: 端口被占用
```bash
# Windows 查找占用端口的进程
netstat -ano | findstr :3001
# macOS/Linux
lsof -i :3001
# 修改端口(在 .env 中)
PORT=3002
```
### Q3: npm install 太慢
```bash
# 使用国内镜像
npm config set registry https://registry.npmmirror.com
```
---
## 🎉 准备开始!
**现在就开始 Day 1 吧!**
执行第一个命令:
```bash
docker --version
```
有任何问题随时告诉我!🚀