Json-Python-Server/app/api/routes/upload.py

125 lines
3.8 KiB
Python
Raw Permalink Normal View History

2026-01-29 18:18:32 +08:00
"""
文件上传路由
"""
import logging
import os
import shutil
from datetime import datetime
from pathlib import Path
from typing import Optional
from fastapi import APIRouter, UploadFile, File, Form, HTTPException, status
from pydantic import BaseModel
from app.core.config import settings
logger = logging.getLogger(__name__)
router = APIRouter()
class UploadResponse(BaseModel):
"""上传响应模型"""
success: bool
filename: str
file_type: str
original_filename: str
task_description: str
message: Optional[str] = None
class UploadImageResponse(BaseModel):
"""上传图片响应模型"""
success: bool
filename: str
file_type: str
original_filename: str
original_image: str
task_description: str
message: str
def allowed_file(filename: str) -> bool:
"""检查文件是否被允许"""
if '.' not in filename:
return False
ext = filename.rsplit('.', 1)[1].lower()
return ext in settings.ALLOWED_EXTENSIONS
@router.post("/upload", response_model=UploadResponse, summary="上传CSV或图片文件")
async def upload_file(
file: UploadFile = File(...),
task_description: str = Form(default="时间序列数据分析")
) -> dict:
"""
上传数据文件CSV 或图片
- **file**: CSV 或图片文件 (PNG, JPG, BMP, TIFF)
- **task_description**: 分析任务描述
"""
try:
logger.info(f"=== 上传请求开始 ===")
logger.info(f"文件名: {file.filename}")
logger.info(f"任务描述: {task_description}")
# 检查文件名
if not file.filename:
logger.error("文件名为空")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="没有选择文件"
)
# 检查文件类型
if not allowed_file(file.filename):
logger.error(f"不支持的文件类型: {file.filename}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"不支持的文件类型。允许的类型: {', '.join(settings.ALLOWED_EXTENSIONS)}"
)
# 获取文件扩展名
file_ext = file.filename.rsplit('.', 1)[1].lower()
# 生成文件名
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
new_filename = f"upload_{timestamp}_{file.filename}"
# 保存文件
file_path = settings.get_upload_path(new_filename)
logger.info(f"保存文件到: {file_path}")
content = await file.read()
with open(file_path, 'wb') as f:
f.write(content)
logger.info(f"文件保存成功,大小: {len(content)} bytes")
# 处理不同的文件类型
if file_ext == 'csv':
logger.info("处理 CSV 文件")
return {
"success": True,
"filename": new_filename,
"file_type": "csv",
"original_filename": file.filename,
"task_description": task_description
}
else:
logger.warning(f"不支持的文件类型: {file_ext}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"目前只支持 CSV 文件。您上传的是: {file_ext}"
)
except HTTPException:
raise
except Exception as e:
logger.error(f"上传处理异常: {str(e)}", exc_info=True)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=str(e)
)