""" 文件上传 API """ from fastapi import APIRouter, HTTPException, status from pydantic import BaseModel from typing import Optional from datetime import datetime from app.services.oss import generate_upload_policy, get_file_url from app.config import settings router = APIRouter(prefix="/upload", tags=["文件上传"]) class UploadPolicyRequest(BaseModel): """获取上传凭证请求""" file_type: str = "general" # script, video, image, general file_name: Optional[str] = None class UploadPolicyResponse(BaseModel): """上传凭证响应""" access_key_id: str policy: str signature: str host: str dir: str expire: int max_size_mb: int class FileUploadedRequest(BaseModel): """文件上传完成回调""" file_key: str file_name: str file_size: int file_type: str class FileUploadedResponse(BaseModel): """文件上传完成响应""" url: str file_key: str file_name: str file_size: int file_type: str @router.post("/policy", response_model=UploadPolicyResponse) async def get_upload_policy( request: UploadPolicyRequest, ): """ 获取 OSS 直传凭证 前端使用此凭证直接上传文件到阿里云 OSS,无需经过后端。 文件类型说明: - script: 脚本文档 (docx, pdf, xlsx, txt, pptx) - video: 视频文件 (mp4, mov, webm) - image: 图片文件 (jpg, png, gif) - general: 通用文件 """ # 根据文件类型设置上传目录 now = datetime.now() base_dir = f"uploads/{now.year}/{now.month:02d}" if request.file_type == "script": upload_dir = f"{base_dir}/scripts/" elif request.file_type == "video": upload_dir = f"{base_dir}/videos/" elif request.file_type == "image": upload_dir = f"{base_dir}/images/" else: upload_dir = f"{base_dir}/files/" try: policy = generate_upload_policy( max_size_mb=settings.MAX_FILE_SIZE_MB, expire_seconds=3600, upload_dir=upload_dir, ) except ValueError as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e), ) return UploadPolicyResponse( access_key_id=policy["accessKeyId"], policy=policy["policy"], signature=policy["signature"], host=policy["host"], dir=policy["dir"], expire=policy["expire"], max_size_mb=settings.MAX_FILE_SIZE_MB, ) @router.post("/complete", response_model=FileUploadedResponse) async def file_uploaded( request: FileUploadedRequest, ): """ 文件上传完成回调 前端上传完成后调用此接口,获取文件的完整 URL。 """ url = get_file_url(request.file_key) return FileUploadedResponse( url=url, file_key=request.file_key, file_name=request.file_name, file_size=request.file_size, file_type=request.file_type, )