Files
algorithm/backend/app/routes/data_management.py
2026-02-18 09:36:18 +08:00

362 lines
12 KiB
Python
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.

"""数据管理路由,提供输入数据、输出结果和元数据的管理功能"""
from fastapi import APIRouter, HTTPException, status, Depends, UploadFile, File, Form
from typing import List, Dict, Any, Optional
from pydantic import BaseModel
from sqlalchemy.orm import Session
import json
from app.services.data_manager import data_manager
from app.models.database import get_db
from app.dependencies import get_current_active_user, get_current_active_user_optional
router = APIRouter(prefix="/data", tags=["data-management"])
class SaveInputDataRequest(BaseModel):
"""保存输入数据请求"""
algorithm_id: str
input_data: Dict[str, Any]
class SaveOutputDataRequest(BaseModel):
"""保存输出数据请求"""
algorithm_id: str
call_id: str
output_data: Dict[str, Any]
class GetDataFilters(BaseModel):
"""数据搜索过滤条件"""
user_id: Optional[str] = None
algorithm_id: Optional[str] = None
date_from: Optional[str] = None
date_to: Optional[str] = None
limit: int = 100
@router.post("/input")
async def save_input_data(
request: SaveInputDataRequest,
current_user: dict = Depends(get_current_active_user)
):
"""保存输入数据"""
# 检查用户权限
if current_user.get("role") not in ["admin", "user"] or current_user.get("id") != request.user_id:
if current_user.get("role") != "admin":
raise HTTPException(status_code=403, detail="Insufficient permissions")
data_id = data_manager.save_input_data(
user_id=current_user.get("id"),
algorithm_id=request.algorithm_id,
input_data=request.input_data
)
if data_id:
return {
"success": True,
"data_id": data_id,
"message": "Input data saved successfully"
}
else:
raise HTTPException(status_code=500, detail="Failed to save input data")
@router.post("/output")
async def save_output_data(
request: SaveOutputDataRequest,
current_user: dict = Depends(get_current_active_user)
):
"""保存输出结果数据"""
# 检查用户权限
if current_user.get("role") not in ["admin", "user"]:
raise HTTPException(status_code=403, detail="Insufficient permissions")
data_id = data_manager.save_output_data(
user_id=current_user.get("id"),
algorithm_id=request.algorithm_id,
call_id=request.call_id,
output_data=request.output_data
)
if data_id:
return {
"success": True,
"data_id": data_id,
"message": "Output data saved successfully"
}
else:
raise HTTPException(status_code=500, detail="Failed to save output data")
@router.get("/input/{data_id}")
async def get_input_data(
data_id: str,
current_user: dict = Depends(get_current_active_user)
):
"""获取输入数据"""
data = data_manager.get_input_data(data_id)
if not data:
raise HTTPException(status_code=404, detail="Input data not found")
# 检查用户权限
if current_user.get("role") != "admin" and data.get("user_id") != current_user.get("id"):
raise HTTPException(status_code=403, detail="Insufficient permissions")
return data
@router.get("/output/{data_id}")
async def get_output_data(
data_id: str,
current_user: dict = Depends(get_current_active_user)
):
"""获取输出结果数据"""
data = data_manager.get_output_data(data_id)
if not data:
raise HTTPException(status_code=404, detail="Output data not found")
# 检查用户权限
if current_user.get("role") != "admin" and data.get("user_id") != current_user.get("id"):
raise HTTPException(status_code=403, detail="Insufficient permissions")
return data
@router.get("/inputs/user")
async def get_user_inputs(
algorithm_id: Optional[str] = None,
limit: int = 100,
current_user: dict = Depends(get_current_active_user)
):
"""获取用户的历史输入数据"""
# 检查用户权限
if current_user.get("role") != "admin" and current_user.get("id") != current_user.get("id"):
if current_user.get("role") != "admin":
raise HTTPException(status_code=403, detail="Insufficient permissions")
inputs = data_manager.get_user_inputs(
user_id=current_user.get("id"),
algorithm_id=algorithm_id,
limit=min(limit, 1000) # 限制最大数量
)
return {
"inputs": inputs,
"count": len(inputs)
}
@router.get("/outputs/user")
async def get_user_outputs(
algorithm_id: Optional[str] = None,
limit: int = 100,
current_user: dict = Depends(get_current_active_user)
):
"""获取用户的历史输出数据"""
# 检查用户权限
if current_user.get("role") != "admin" and current_user.get("id") != current_user.get("id"):
if current_user.get("role") != "admin":
raise HTTPException(status_code=403, detail="Insufficient permissions")
outputs = data_manager.get_user_outputs(
user_id=current_user.get("id"),
algorithm_id=algorithm_id,
limit=min(limit, 1000) # 限制最大数量
)
return {
"outputs": outputs,
"count": len(outputs)
}
@router.post("/media/upload")
async def upload_media_file(
file: UploadFile = File(...),
algorithm_id: str = Form(...)
):
"""上传媒体文件(如图片、视频等)- 公开API不需要认证"""
if not algorithm_id:
raise HTTPException(status_code=400, detail="algorithm_id is required")
# 读取文件内容
file_content = await file.read()
# 保存到数据管理器(使用匿名用户)
file_path = data_manager.save_media_file(
user_id="anonymous",
algorithm_id=algorithm_id,
file_content=file_content,
file_name=file.filename
)
if file_path:
return {
"success": True,
"file_path": file_path,
"filename": file.filename,
"size": len(file_content),
"message": "Media file uploaded successfully"
}
else:
raise HTTPException(status_code=500, detail="Failed to upload media file")
@router.get("/media/{file_path:path}")
async def get_media_file(
file_path: str,
current_user: Optional[dict] = Depends(get_current_active_user_optional)
):
"""获取媒体文件"""
# results 目录下的文件公开访问
if file_path.startswith("results/"):
content = data_manager.get_media_file(file_path)
if content:
# 从完整路径中提取文件名来获取正确的MIME类型
import mimetypes
filename = file_path.split('/')[-1]
content_type, _ = mimetypes.guess_type(filename)
if content_type is None:
content_type = "application/octet-stream"
from fastapi.responses import Response
return Response(content=content, media_type=content_type)
else:
raise HTTPException(status_code=404, detail="Media file not found")
# 其他文件需要用户权限
if current_user is None:
raise HTTPException(status_code=401, detail="Not authenticated")
if current_user.get("role") != "admin" and not file_path.startswith(f"media/{current_user.get('id')}/"):
raise HTTPException(status_code=403, detail="Insufficient permissions")
content = data_manager.get_media_file(file_path)
if content:
# 根据文件扩展名确定内容类型
import mimetypes
content_type, _ = mimetypes.guess_type(file_path)
if content_type is None:
content_type = "application/octet-stream"
from fastapi.responses import Response
return Response(content=content, media_type=content_type)
else:
raise HTTPException(status_code=404, detail="Media file not found")
@router.post("/snapshots/create")
async def create_data_snapshot(
call_id: str,
current_user: dict = Depends(get_current_active_user),
db: Session = Depends(get_db)
):
"""创建数据快照"""
from app.models.models import AlgorithmCall
# 获取调用记录
call_record = db.query(AlgorithmCall).filter(AlgorithmCall.id == call_id).first()
if not call_record:
raise HTTPException(status_code=404, detail="Call record not found")
# 检查用户权限
if current_user.get("role") != "admin" and call_record.user_id != current_user.get("id"):
raise HTTPException(status_code=403, detail="Insufficient permissions")
# 创建快照
snapshot = data_manager.create_data_snapshot(call_record)
if snapshot:
return {
"success": True,
"snapshot": snapshot,
"message": "Data snapshot created successfully"
}
else:
raise HTTPException(status_code=500, detail="Failed to create data snapshot")
@router.post("/search")
async def search_data_by_metadata(
filters: GetDataFilters,
current_user: dict = Depends(get_current_active_user)
):
"""根据元数据搜索数据"""
# 检查用户权限 - 用户只能搜索自己的数据,管理员可以搜索所有数据
if current_user.get("role") != "admin":
if filters.user_id and filters.user_id != current_user.get("id"):
raise HTTPException(status_code=403, detail="Insufficient permissions")
# 如果没有指定用户ID则默认搜索当前用户的数据
if not filters.user_id:
filters.user_id = current_user.get("id")
results = data_manager.search_data_by_metadata(filters.dict())
return {
"results": results,
"count": len(results)
}
@router.delete("/user-data")
async def delete_user_data(
current_user: dict = Depends(get_current_active_user)
):
"""删除用户的所有数据"""
# 检查用户权限
if current_user.get("role") != "admin" and current_user.get("id") != current_user.get("id"):
if current_user.get("role") != "admin":
raise HTTPException(status_code=403, detail="Insufficient permissions")
success = data_manager.delete_user_data(current_user.get("id"))
if success:
return {
"success": True,
"message": "User data deleted successfully"
}
else:
raise HTTPException(status_code=500, detail="Failed to delete user data")
@router.get("/statistics")
async def get_data_statistics(
current_user: dict = Depends(get_current_active_user)
):
"""获取数据统计信息"""
# 这里返回基本的数据统计信息
# 在实际实现中,可能会从数据库和存储系统中收集更详细的统计信息
from sqlalchemy import func
from app.models.models import AlgorithmCall
db = next(get_db())
# 统计调用次数
total_calls = db.query(func.count(AlgorithmCall.id)).scalar()
# 统计当前用户调用次数
user_calls = db.query(func.count(AlgorithmCall.id)).filter(
AlgorithmCall.user_id == current_user.get("id")
).scalar()
# 管理员可以看到全部统计,普通用户只能看到自己的统计
if current_user.get("role") == "admin":
stats = {
"total_calls": total_calls,
"user_calls": user_calls,
"total_users": 0, # 在实际实现中,从用户表统计
"storage_used": "N/A", # 在实际实现中,从存储系统获取
"timestamp": "now"
}
else:
stats = {
"user_calls": user_calls,
"storage_used_by_user": "N/A", # 在实际实现中,从存储系统获取
"timestamp": "now"
}
return stats