后端初始化结构

This commit is contained in:
zly
2025-11-22 21:29:00 +08:00
parent 9fa602f21b
commit e68ad06829
26 changed files with 1350 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
# 项目信息
PROJECT_NAME=PBMDB API
VERSION=1.0.0
API_V1_STR=/api/v1
# 数据库配置
DATABASE_URL=postgresql://webws_admin:your_password_here@postgres:5432/webws_database
# 安全配置
SECRET_KEY=your-secret-key-here-change-in-production-use-at-least-32-chars
ACCESS_TOKEN_EXPIRE_MINUTES=10080
# CORS 配置
ALLOWED_ORIGINS=https://amiap.hzau.edu.cn,http://localhost:3000
# 文件上传配置
MAX_UPLOAD_SIZE=104857600
UPLOAD_DIR=/app/uploads
# 分页配置
DEFAULT_PAGE_SIZE=20
MAX_PAGE_SIZE=100

38
web/ws/backend/.gitignore vendored Normal file
View File

@@ -0,0 +1,38 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
env/
ENV/
*.egg-info/
dist/
build/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# 环境变量
.env
# 数据库
*.db
*.sqlite3
# 上传文件
uploads/
*.log
# 测试
.pytest_cache/
.coverage
htmlcov/
# Alembic
alembic/versions/*.pyc

View File

@@ -0,0 +1,314 @@
# 开发指南
## 快速开始
### 本地开发
```bash
# 1. 进入后端目录
cd /vol1/1000/docker_server/traefik/web/ws/backend
# 2. 使用启动脚本(自动创建虚拟环境、安装依赖)
./start.sh
# 或者手动启动
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
```
访问:
- API 文档: http://localhost:8000/docs
- 健康检查: http://localhost:8000/health
### Docker 开发
```bash
cd /vol1/1000/docker_server/traefik/web/ws
# 构建镜像
docker compose build backend
# 启动服务
docker compose up -d backend
# 查看日志
docker compose logs -f backend
# 进入容器
docker compose exec backend bash
```
## 开发流程
### 1. 添加新的 API 端点
**示例:添加实验数据 API**
```bash
# 1. 创建端点文件
touch app/api/v1/endpoints/experiments.py
```
```python
# app/api/v1/endpoints/experiments.py
from fastapi import APIRouter
router = APIRouter()
@router.get("/")
async def get_experiments():
"""获取实验列表"""
return {"experiments": []}
@router.get("/{experiment_id}")
async def get_experiment(experiment_id: str):
"""获取实验详情"""
return {"id": experiment_id}
```
```python
# 2. 在 app/api/v1/router.py 中注册
from app.api.v1.endpoints import experiments
api_router.include_router(
experiments.router,
prefix="/experiments",
tags=["experiments"]
)
```
### 2. 添加数据模型
```bash
# 创建模型文件
touch app/models/experiment.py
```
```python
# app/models/experiment.py
from sqlalchemy import Column, String, Integer, DateTime
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Experiment(Base):
__tablename__ = "experiments"
id = Column(Integer, primary_key=True)
name = Column(String(200))
description = Column(String(1000))
created_at = Column(DateTime)
```
### 3. 添加 Pydantic 模式
```bash
# 创建模式文件
touch app/schemas/experiment.py
```
```python
# app/schemas/experiment.py
from pydantic import BaseModel
from datetime import datetime
from typing import Optional
class ExperimentBase(BaseModel):
name: str
description: Optional[str] = None
class ExperimentCreate(ExperimentBase):
pass
class ExperimentResponse(ExperimentBase):
id: int
created_at: datetime
class Config:
from_attributes = True
```
### 4. 添加业务逻辑
```bash
# 创建服务文件
touch app/services/experiment_service.py
```
```python
# app/services/experiment_service.py
from sqlalchemy.orm import Session
from app.models.experiment import Experiment
from app.schemas.experiment import ExperimentCreate
async def create_experiment(db: Session, data: ExperimentCreate):
"""创建实验"""
experiment = Experiment(**data.dict())
db.add(experiment)
db.commit()
db.refresh(experiment)
return experiment
```
## 代码规范
### Python 风格
- 遵循 PEP 8 规范
- 使用类型提示
- 函数添加文档字符串
```python
async def get_strain_detail(strain_id: str) -> dict:
"""
获取菌种详情
Args:
strain_id: 菌种 ID
Returns:
dict: 菌种详细信息
Raises:
HTTPException: 菌种不存在时
"""
pass
```
### 命名规范
- 文件名:`snake_case.py`
- 类名:`PascalCase`
- 函数名:`snake_case`
- 常量:`UPPER_CASE`
### 目录组织
```
app/
├── api/v1/endpoints/ # 按功能模块组织
│ ├── strains.py # 菌种相关
│ ├── genes.py # 基因相关
│ └── upload.py # 上传相关
├── models/ # 数据库模型
├── schemas/ # 数据验证模式
└── services/ # 业务逻辑
```
## 测试
### 单元测试
```bash
# 安装测试依赖
pip install pytest pytest-asyncio httpx
# 运行测试
pytest
```
### API 测试
```bash
# 使用测试脚本
./test_api.sh
# 或使用 curl
curl http://localhost:8000/health
```
## 数据库迁移
```bash
# 安装 alembic
pip install alembic
# 初始化
alembic init alembic
# 创建迁移
alembic revision --autogenerate -m "Add experiments table"
# 执行迁移
alembic upgrade head
# 回滚
alembic downgrade -1
```
## 调试技巧
### 1. 日志输出
```python
import logging
logger = logging.getLogger(__name__)
@router.get("/debug")
async def debug_endpoint():
logger.info("Debug endpoint called")
logger.debug(f"Data: {data}")
return {"status": "ok"}
```
### 2. 断点调试
```python
# 使用 pdb
import pdb; pdb.set_trace()
# 或使用 breakpoint()
breakpoint()
```
### 3. 查看 SQL 查询
```python
# 在配置中启用 SQL 日志
DATABASE_URL = "postgresql://...?echo=true"
```
## 常见问题
### Q: 导入错误?
确保在项目根目录运行,并使用正确的 Python 路径:
```bash
export PYTHONPATH=/vol1/1000/docker_server/traefik/web/ws/backend:$PYTHONPATH
```
### Q: 数据库连接失败?
检查 `.env` 文件中的 `DATABASE_URL` 配置。
### Q: CORS 错误?
`app/core/config.py` 中添加允许的源。
## 部署检查清单
- [ ] 修改生产环境 `SECRET_KEY`
- [ ] 配置正确的 `DATABASE_URL`
- [ ] 更新 `ALLOWED_ORIGINS`
- [ ] 运行数据库迁移
- [ ] 测试所有 API 端点
- [ ] 配置日志记录
- [ ] 设置监控和告警
- [ ] 备份数据库
## 贡献流程
1. 创建功能分支
2. 开发并测试
3. 提交代码commit message 规范)
4. 提交 Pull Request
5. Code Review
6. 合并到主分支
## 联系方式
如有问题,请联系开发团队。

33
web/ws/backend/Dockerfile Normal file
View File

@@ -0,0 +1,33 @@
# FastAPI 后端 Dockerfile
FROM python:3.11-slim
# 设置工作目录
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y \
gcc \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# 复制依赖文件
COPY requirements.txt .
# 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY app/ ./app/
# 创建上传目录
RUN mkdir -p /app/uploads
# 暴露端口
EXPOSE 8000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1
# 启动命令
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

297
web/ws/backend/README.md Normal file
View File

@@ -0,0 +1,297 @@
# FastAPI 后端项目
PBMDB (Plant Beneficial Microbe Database) 农业有益微生物综合信息数据库后端 API 服务。
## 📁 项目结构
```
backend/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI 应用入口
│ ├── api/
│ │ ├── __init__.py
│ │ └── v1/
│ │ ├── __init__.py
│ │ ├── router.py # API 路由汇总
│ │ └── endpoints/
│ │ ├── __init__.py
│ │ ├── strains.py # 菌种资源 API
│ │ ├── genomes.py # 基因组学数据 API
│ │ ├── genes.py # 基因资源 API
│ │ ├── upload.py # 数据汇交上传 API
│ │ └── analysis.py # 智能分析 API
│ ├── core/
│ │ ├── __init__.py
│ │ ├── config.py # 应用配置
│ │ └── security.py # 认证安全
│ ├── models/ # SQLAlchemy 数据模型
│ │ └── __init__.py
│ ├── schemas/ # Pydantic 数据模式
│ │ └── __init__.py
│ └── services/ # 业务逻辑层
│ └── __init__.py
├── requirements.txt # Python 依赖
├── Dockerfile # Docker 构建文件
├── .env.example # 环境变量示例
└── README.md # 本文件
```
## 🚀 技术栈
- **FastAPI**: 现代、高性能 Python Web 框架
- **Uvicorn**: ASGI 服务器
- **SQLAlchemy**: ORM 数据库工具
- **PostgreSQL**: 关系型数据库
- **Pydantic**: 数据验证和设置管理
## 🎯 核心功能模块
### 1. 菌种资源 (`/api/v1/strains`)
- 菌种列表查询(分类、搜索、分页)
- 菌种详情展示
- 菌种分类树
### 2. 基因组学数据 (`/api/v1/genomes`)
- 基因组数据列表(基因组学/转录组学/其他组学)
- 基因组详情
- 物种分类树
### 3. 基因资源 (`/api/v1/genes`)
- 基因列表查询(功能分类)
- 基因详情
- 功能基因分类
### 4. 数据汇交 (`/api/v1/upload`)
- 基因组数据上传
- 宏基因组数据上传
- 原始测序数据上传
- 上传口令验证
- 上传状态查询
### 5. 智能分析 (`/api/v1/analysis`)
- 智能问答(基于知识图谱)
- 基因挖掘(序列比对)
- 菌株评估
- 知识图谱查询
- 分析任务状态查询
## ⚙️ 环境配置
### 1. 创建环境变量文件
```bash
cd /vol1/1000/docker_server/traefik/web/ws/backend
cp .env.example .env
```
编辑 `.env` 文件:
```bash
# 项目信息
PROJECT_NAME=PBMDB API
VERSION=1.0.0
# 数据库配置
DATABASE_URL=postgresql://webws_admin:your_password@postgres:5432/webws_database
# 安全配置
SECRET_KEY=your-secret-key-here-change-in-production
# CORS 配置
ALLOWED_ORIGINS=https://amiap.hzau.edu.cn,http://localhost:3000
# 文件上传配置
MAX_UPLOAD_SIZE=104857600
UPLOAD_DIR=/app/uploads
```
## 🏃 本地开发
### 使用虚拟环境
```bash
cd /vol1/1000/docker_server/traefik/web/ws/backend
# 创建虚拟环境
python3 -m venv venv
source venv/bin/activate
# 安装依赖
pip install -r requirements.txt
# 运行开发服务器
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
```
访问:
- API 文档: http://localhost:8000/docs
- ReDoc 文档: http://localhost:8000/redoc
- 健康检查: http://localhost:8000/health
## 🐳 Docker 部署
### 1. 更新 docker-compose.yml
`/vol1/1000/docker_server/traefik/web/ws/docker-compose.yml` 中添加后端服务:
```yaml
services:
# ... 现有服务 ...
backend:
build: ./backend
container_name: webws-backend
restart: unless-stopped
environment:
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
volumes:
- ./backend/uploads:/app/uploads
networks:
- frontend
depends_on:
- postgres
labels:
- "traefik.enable=true"
# HTTP 路由 - 重定向到 HTTPS
- "traefik.http.routers.webws-api-http.rule=Host(`amiap.hzau.edu.cn`) && PathPrefix(`/ABM/api`)"
- "traefik.http.routers.webws-api-http.entrypoints=web"
- "traefik.http.routers.webws-api-http.priority=100"
- "traefik.http.routers.webws-api-http.middlewares=redirect-to-https"
# HTTPS 路由
- "traefik.http.routers.webws-api-https.rule=Host(`amiap.hzau.edu.cn`) && PathPrefix(`/ABM/api`)"
- "traefik.http.routers.webws-api-https.entrypoints=websecure"
- "traefik.http.routers.webws-api-https.priority=100"
- "traefik.http.routers.webws-api-https.tls.certresolver=myresolver"
# StripPrefix 中间件(移除 /ABM/api 前缀)
- "traefik.http.routers.webws-api-https.middlewares=api-stripprefix"
- "traefik.http.middlewares.api-stripprefix.stripprefix.prefixes=/ABM/api"
- "traefik.http.services.webws-api.loadbalancer.server.port=8000"
```
### 2. 构建并启动
```bash
cd /vol1/1000/docker_server/traefik/web/ws
# 构建镜像
docker compose build backend
# 启动服务
docker compose up -d backend
# 查看日志
docker compose logs -f backend
```
## 📡 API 访问地址
部署后API 通过以下地址访问:
- **外部访问**: https://amiap.hzau.edu.cn/ABM/api/
- **API 文档**: https://amiap.hzau.edu.cn/ABM/api/docs
- **容器间访问**: http://webws-backend:8000/
## 🔧 路由说明
### URL 路径处理
由于使用了 Traefik `StripPrefix` 中间件,路径会自动处理:
**用户访问**: `https://amiap.hzau.edu.cn/ABM/api/strains/`
**FastAPI 接收**: `/api/v1/strains/` (已移除 `/ABM/api`)
### 路由优先级
```
Priority 100: /ABM/api/** → 后端 API 服务
Priority 47: /ABM/** → Nginx 静态文件服务
```
不会产生冲突Traefik 优先匹配更高优先级和更具体的路径。
## 📊 数据库迁移
### 使用 Alembic
```bash
# 进入容器
docker compose exec backend bash
# 初始化迁移(首次)
alembic init alembic
# 创建迁移
alembic revision --autogenerate -m "Initial migration"
# 执行迁移
alembic upgrade head
```
## 🧪 测试 API
### 使用 curl
```bash
# 健康检查
curl https://amiap.hzau.edu.cn/ABM/api/health
# 获取菌种列表
curl https://amiap.hzau.edu.cn/ABM/api/api/v1/strains/
# 获取基因组数据
curl https://amiap.hzau.edu.cn/ABM/api/api/v1/genomes/
```
### 使用 Swagger UI
访问 https://amiap.hzau.edu.cn/ABM/api/docs 进行交互式测试。
## 📝 开发指南
### 添加新的 API 端点
1.`app/api/v1/endpoints/` 下创建新文件
2. 定义路由和处理函数
3.`app/api/v1/router.py` 中注册路由
### 添加数据模型
1.`app/models/` 下创建 SQLAlchemy 模型
2.`app/schemas/` 下创建 Pydantic 模式
3. 运行数据库迁移
### 添加业务逻辑
`app/services/` 下创建服务层代码,保持控制器简洁。
## 🔒 安全注意事项
1. **生产环境**必须修改 `SECRET_KEY`
2. 使用环境变量管理敏感信息
3. 启用 HTTPS已配置
4. 实现完整的认证系统(待实现)
5. 添加请求频率限制
## 🚀 性能优化
1. 使用数据库连接池
2. 启用查询缓存Redis
3. 异步文件处理
4. 压缩响应数据
5. CDN 加速静态资源
## 📚 相关文档
- [FastAPI 官方文档](https://fastapi.tiangolo.com/)
- [Pydantic 文档](https://docs.pydantic.dev/)
- [SQLAlchemy 文档](https://docs.sqlalchemy.org/)
- [Uvicorn 文档](https://www.uvicorn.org/)
## 📞 联系方式
如有问题,请联系项目维护团队。

View File

View File

View File

View File

@@ -0,0 +1,112 @@
"""
智能分析 API
"""
from typing import Optional
from fastapi import APIRouter, BackgroundTasks, HTTPException
from pydantic import BaseModel
router = APIRouter()
class QuestionRequest(BaseModel):
"""智能问答请求"""
question: str
context: Optional[str] = None
class GeneMiningRequest(BaseModel):
"""基因挖掘请求"""
sequence: str
algorithm: str = "blast"
parameters: Optional[dict] = None
class StrainEvaluationRequest(BaseModel):
"""菌株评估请求"""
strain_id: str
evaluation_type: str # growth/resistance/etc
@router.post("/qa")
async def intelligent_qa(request: QuestionRequest):
"""
智能问答
基于知识图谱的智能问答系统
"""
# TODO: 集成 AI 模型进行问答
return {
"question": request.question,
"answer": "This is a placeholder answer. AI integration pending.",
"confidence": 0.0
}
@router.post("/gene-mining")
async def gene_mining(
background_tasks: BackgroundTasks,
request: GeneMiningRequest
):
"""
基因挖掘
通过序列比对等方法挖掘功能基因
"""
# TODO: 实现基因挖掘算法
# background_tasks.add_task(run_gene_mining, request)
return {
"status": "processing",
"task_id": "task_123",
"message": "Gene mining task started"
}
@router.post("/strain-evaluation")
async def strain_evaluation(
background_tasks: BackgroundTasks,
request: StrainEvaluationRequest
):
"""
菌株评估
评估菌株的各项指标和应用潜力
"""
# TODO: 实现菌株评估逻辑
return {
"status": "processing",
"task_id": "task_456",
"message": "Strain evaluation started"
}
@router.get("/knowledge-graph")
async def get_knowledge_graph(
entity: Optional[str] = None,
relationship: Optional[str] = None,
):
"""
知识图谱查询
查询微生物知识图谱
"""
# TODO: 实现知识图谱查询
return {
"nodes": [],
"edges": [],
"message": "Knowledge graph feature pending"
}
@router.get("/task/{task_id}")
async def get_analysis_task_status(task_id: str):
"""
查询分析任务状态
"""
# TODO: 从数据库或缓存查询任务状态
return {
"task_id": task_id,
"status": "completed",
"progress": 100,
"result": None
}

View File

@@ -0,0 +1,56 @@
"""
基因资源 API
"""
from typing import List, Optional
from fastapi import APIRouter, Query, HTTPException
router = APIRouter()
@router.get("/")
async def get_genes(
skip: int = Query(0, ge=0),
limit: int = Query(20, ge=1, le=100),
function_type: Optional[str] = None,
search: Optional[str] = None,
):
"""
获取基因列表
- **skip**: 跳过记录数
- **limit**: 返回记录数
- **function_type**: 功能类型 (抗逆/促生/杀虫/抗病/其他)
- **search**: 搜索关键词
"""
# TODO: 实现数据库查询
return {
"total": 0,
"items": [],
"skip": skip,
"limit": limit
}
@router.get("/{gene_id}")
async def get_gene_detail(gene_id: str):
"""
获取基因详情
"""
# TODO: 从数据库查询基因详细信息
raise HTTPException(status_code=404, detail="Gene not found")
@router.get("/functions/categories")
async def get_gene_functions():
"""
获取基因功能分类
"""
return {
"categories": [
{"id": 1, "name": "抗逆基因", "count": 0},
{"id": 2, "name": "促生基因", "count": 0},
{"id": 3, "name": "杀虫基因", "count": 0},
{"id": 4, "name": "抗病基因", "count": 0},
{"id": 5, "name": "其他功能基因", "count": 0},
]
}

View File

@@ -0,0 +1,51 @@
"""
基因组学数据 API
"""
from typing import List, Optional
from fastapi import APIRouter, Query, HTTPException
router = APIRouter()
@router.get("/")
async def get_genomes(
skip: int = Query(0, ge=0),
limit: int = Query(20, ge=1, le=100),
data_type: Optional[str] = None,
species: Optional[str] = None,
):
"""
获取基因组数据列表
- **skip**: 跳过记录数
- **limit**: 返回记录数
- **data_type**: 数据类型 (基因组学/转录组学/其他组学)
- **species**: 物种名称
"""
# TODO: 实现数据库查询
return {
"total": 0,
"items": [],
"skip": skip,
"limit": limit
}
@router.get("/{genome_id}")
async def get_genome_detail(genome_id: str):
"""
获取基因组详情
"""
# TODO: 从数据库查询基因组详细信息
raise HTTPException(status_code=404, detail="Genome not found")
@router.get("/species/tree")
async def get_species_tree():
"""
获取物种分类树
"""
# TODO: 返回物种分类树结构
return {
"tree": []
}

View File

@@ -0,0 +1,56 @@
"""
菌种资源 API
"""
from typing import List, Optional
from fastapi import APIRouter, Query, HTTPException
router = APIRouter()
@router.get("/")
async def get_strains(
skip: int = Query(0, ge=0),
limit: int = Query(20, ge=1, le=100),
category: Optional[str] = None,
search: Optional[str] = None,
):
"""
获取菌种列表
- **skip**: 跳过记录数
- **limit**: 返回记录数
- **category**: 菌种分类 (抗逆/促生/杀虫/抗病/食药用)
- **search**: 搜索关键词
"""
# TODO: 实现数据库查询
return {
"total": 0,
"items": [],
"skip": skip,
"limit": limit
}
@router.get("/{strain_id}")
async def get_strain_detail(strain_id: str):
"""
获取菌种详情
"""
# TODO: 从数据库查询菌种详细信息
raise HTTPException(status_code=404, detail="Strain not found")
@router.get("/categories/tree")
async def get_strain_categories():
"""
获取菌种分类树
"""
return {
"categories": [
{"id": 1, "name": "抗逆微生物", "count": 0},
{"id": 2, "name": "促生微生物", "count": 0},
{"id": 3, "name": "杀虫微生物", "count": 0},
{"id": 4, "name": "抗病微生物", "count": 0},
{"id": 5, "name": "食药用微生物", "count": 0},
]
}

View File

@@ -0,0 +1,107 @@
"""
数据汇交上传 API
"""
from typing import Optional
from fastapi import APIRouter, UploadFile, File, Form, HTTPException, BackgroundTasks
from app.core.security import verify_upload_key
router = APIRouter()
@router.post("/verify-key")
async def verify_key(key: str = Form(...)):
"""
验证上传口令
"""
is_valid = await verify_upload_key(key)
if not is_valid:
raise HTTPException(status_code=401, detail="Invalid upload key")
return {"status": "success", "message": "Key verified"}
@router.post("/genome")
async def upload_genome_data(
background_tasks: BackgroundTasks,
project_id: str = Form(...),
submitter_name: str = Form(...),
submitter_email: str = Form(...),
upload_key: str = Form(...),
file: Optional[UploadFile] = File(None),
):
"""
上传基因组数据
支持逐条提交和批量上传
"""
# 验证口令
if not await verify_upload_key(upload_key):
raise HTTPException(status_code=401, detail="Invalid upload key")
# TODO: 处理文件上传
if file:
# 异步保存文件
filename = file.filename
# background_tasks.add_task(save_file, file, filename)
# TODO: 保存到数据库
return {
"status": "success",
"message": "Data uploaded successfully",
"project_id": project_id
}
@router.post("/metagenome")
async def upload_metagenome_data(
background_tasks: BackgroundTasks,
project_id: str = Form(...),
submitter_name: str = Form(...),
upload_key: str = Form(...),
file: Optional[UploadFile] = File(None),
):
"""
上传宏基因组数据
"""
if not await verify_upload_key(upload_key):
raise HTTPException(status_code=401, detail="Invalid upload key")
# TODO: 实现宏基因组数据上传逻辑
return {
"status": "success",
"message": "Metagenome data uploaded",
"project_id": project_id
}
@router.post("/raw-data")
async def upload_raw_data(
background_tasks: BackgroundTasks,
project_id: str = Form(...),
upload_key: str = Form(...),
file: UploadFile = File(...),
):
"""
上传原始测序数据
"""
if not await verify_upload_key(upload_key):
raise HTTPException(status_code=401, detail="Invalid upload key")
# TODO: 实现原始数据上传逻辑
return {
"status": "success",
"message": "Raw data uploaded",
"filename": file.filename
}
@router.get("/status/{upload_id}")
async def get_upload_status(upload_id: str):
"""
查询上传状态
"""
# TODO: 从数据库查询上传状态
return {
"upload_id": upload_id,
"status": "processing",
"progress": 50
}

View File

@@ -0,0 +1,14 @@
"""
API v1 路由汇总
"""
from fastapi import APIRouter
from app.api.v1.endpoints import strains, genomes, genes, upload, analysis
api_router = APIRouter()
# 注册各模块路由
api_router.include_router(strains.router, prefix="/strains", tags=["strains"])
api_router.include_router(genomes.router, prefix="/genomes", tags=["genomes"])
api_router.include_router(genes.router, prefix="/genes", tags=["genes"])
api_router.include_router(upload.router, prefix="/upload", tags=["upload"])
api_router.include_router(analysis.router, prefix="/analysis", tags=["analysis"])

View File

View File

@@ -0,0 +1,43 @@
"""
应用配置
"""
from typing import List
from pydantic_settings import BaseSettings
from pydantic import AnyHttpUrl
class Settings(BaseSettings):
"""应用配置类"""
# 项目信息
PROJECT_NAME: str = "PBMDB API"
VERSION: str = "1.0.0"
API_V1_STR: str = "/api/v1"
# 数据库配置
DATABASE_URL: str = "postgresql://webws_admin:password@postgres:5432/webws_database"
# CORS 配置
ALLOWED_ORIGINS: List[str] = [
"https://amiap.hzau.edu.cn",
"http://localhost:3000", # 本地开发
]
# 安全配置
SECRET_KEY: str = "your-secret-key-here-change-in-production"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7 # 7 days
# 文件上传配置
MAX_UPLOAD_SIZE: int = 1024 * 1024 * 100 # 100MB
UPLOAD_DIR: str = "/app/uploads"
# 分页配置
DEFAULT_PAGE_SIZE: int = 20
MAX_PAGE_SIZE: int = 100
class Config:
env_file = ".env"
case_sensitive = True
settings = Settings()

View File

@@ -0,0 +1,39 @@
"""
安全认证模块
"""
from datetime import datetime, timedelta
from typing import Optional
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
security = HTTPBearer()
async def verify_token(
credentials: HTTPAuthorizationCredentials = Depends(security)
) -> dict:
"""
验证 Token
"""
token = credentials.credentials
# TODO: 实现 JWT token 验证逻辑
return {"user_id": "example"}
async def verify_upload_key(key: str) -> bool:
"""
验证上传口令
用于数据汇交功能
"""
# TODO: 从数据库或配置中验证口令
valid_keys = ["temp_key_123"] # 临时示例
return key in valid_keys
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
"""
创建访问令牌
"""
# TODO: 实现 JWT token 生成
return "temporary_token"

View File

@@ -0,0 +1,43 @@
"""
FastAPI 应用入口
"""
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.core.config import settings
from app.api.v1.router import api_router
app = FastAPI(
title=settings.PROJECT_NAME,
version=settings.VERSION,
description="PBMDB (Plant Beneficial Microbe Database) API",
docs_url="/docs",
redoc_url="/redoc",
)
# CORS 配置
app.add_middleware(
CORSMiddleware,
allow_origins=settings.ALLOWED_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 注册路由
app.include_router(api_router, prefix="/api/v1")
@app.get("/")
async def root():
"""健康检查端点"""
return {
"status": "ok",
"message": "PBMDB API is running",
"version": settings.VERSION
}
@app.get("/health")
async def health_check():
"""健康检查"""
return {"status": "healthy"}

View File

View File

View File

22
web/ws/backend/manage.py Normal file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.base')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,27 @@
# FastAPI 核心
fastapi>=0.104.0
uvicorn[standard]>=0.24.0
pydantic>=2.5.0
pydantic-settings>=2.1.0
# 数据库
sqlalchemy>=2.0.0
asyncpg>=0.29.0
alembic>=1.13.0
# 文件处理
aiofiles>=23.2.0
python-multipart>=0.0.6
# 认证
python-jose[cryptography]>=3.3.0
passlib[bcrypt]>=1.7.4
# 其他常用库
python-dateutil>=2.8.2
pytz>=2023.3
# 可选AI/ML 相关(按需取消注释)
# transformers>=4.35.0
# torch>=2.1.0
# scikit-learn>=1.3.0

41
web/ws/backend/start.sh Executable file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
# FastAPI 开发服务器启动脚本
set -e
echo "=========================================="
echo "启动 FastAPI 开发服务器"
echo "=========================================="
# 检查虚拟环境
if [ ! -d "venv" ]; then
echo "创建虚拟环境..."
python3 -m venv venv
fi
# 激活虚拟环境
echo "激活虚拟环境..."
source venv/bin/activate
# 安装依赖
echo "安装依赖..."
pip install -r requirements.txt
# 检查环境变量
if [ ! -f ".env" ]; then
echo "警告: .env 文件不存在,复制 .env.example..."
cp .env.example .env
echo "请编辑 .env 文件配置数据库等信息"
fi
# 启动服务器
echo ""
echo "=========================================="
echo "启动服务器..."
echo "=========================================="
echo "API 文档: http://localhost:8000/docs"
echo "健康检查: http://localhost:8000/health"
echo "=========================================="
echo ""
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

35
web/ws/backend/test_api.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/bin/bash
# FastAPI API 测试脚本
BASE_URL="https://amiap.hzau.edu.cn/ABM/api"
echo "=========================================="
echo "测试 PBMDB FastAPI 接口"
echo "=========================================="
echo -e "\n✓ 1. 健康检查..."
curl -s "${BASE_URL}/health" | jq '.' || echo "Failed"
echo -e "\n✓ 2. 根路径..."
curl -s "${BASE_URL}/" | jq '.' || echo "Failed"
echo -e "\n✓ 3. 获取菌种列表..."
curl -s "${BASE_URL}/api/v1/strains/" | jq '.' || echo "Failed"
echo -e "\n✓ 4. 获取菌种分类..."
curl -s "${BASE_URL}/api/v1/strains/categories/tree" | jq '.' || echo "Failed"
echo -e "\n✓ 5. 获取基因组列表..."
curl -s "${BASE_URL}/api/v1/genomes/" | jq '.' || echo "Failed"
echo -e "\n✓ 6. 获取基因列表..."
curl -s "${BASE_URL}/api/v1/genes/" | jq '.' || echo "Failed"
echo -e "\n✓ 7. 获取基因功能分类..."
curl -s "${BASE_URL}/api/v1/genes/functions/categories" | jq '.' || echo "Failed"
echo -e "\n=========================================="
echo "测试完成"
echo "=========================================="
echo "访问 API 文档: ${BASE_URL}/docs"
echo "=========================================="