""" 文件上传接口 """ import os import uuid from datetime import datetime from fastapi import APIRouter, UploadFile, File, HTTPException, Request from fastapi.responses import FileResponse from loguru import logger from app.schemas import ApiResponse from app.config import settings router = APIRouter() # 上传目录 UPLOAD_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "uploads") os.makedirs(UPLOAD_DIR, exist_ok=True) @router.post("/upload", response_model=ApiResponse) async def upload_file(request: Request, file: UploadFile = File(...)): """ 上传文件并返回公开访问链接 - 接收前端上传的文件(如简历 PDF) - 保存到本地并生成公开链接 - 返回文件链接供 Coze 工作流使用 """ try: # 验证文件类型 if not file.filename.lower().endswith('.pdf'): raise HTTPException(status_code=400, detail="仅支持 PDF 格式") # 读取文件内容 content = await file.read() # 验证文件大小(最大 10MB) if len(content) > 10 * 1024 * 1024: raise HTTPException(status_code=400, detail="文件大小不能超过 10MB") # 生成唯一文件名 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") unique_id = uuid.uuid4().hex[:8] safe_filename = f"{timestamp}_{unique_id}.pdf" # 保存文件 file_path = os.path.join(UPLOAD_DIR, safe_filename) with open(file_path, "wb") as f: f.write(content) logger.info(f"File saved: {file_path}, size: {len(content)} bytes") # 生成公开访问链接 # 从请求中获取 host host = request.headers.get("host", "localhost:8000") scheme = request.headers.get("x-forwarded-proto", "http") file_url = f"{scheme}://{host}/api/files/{safe_filename}" logger.info(f"File URL: {file_url}") return ApiResponse( code=0, message="success", data={ "fileUrl": file_url, "fileName": file.filename, "fileSize": len(content), } ) except HTTPException: raise except Exception as e: logger.error(f"Upload error: {e}") raise HTTPException(status_code=500, detail=str(e)) @router.get("/files/{filename}") async def get_file(filename: str): """ 获取上传的文件(供 Coze 工作流访问) """ # 安全检查:防止路径遍历 if ".." in filename or "/" in filename or "\\" in filename: raise HTTPException(status_code=400, detail="Invalid filename") file_path = os.path.join(UPLOAD_DIR, filename) if not os.path.exists(file_path): raise HTTPException(status_code=404, detail="File not found") return FileResponse( file_path, media_type="application/pdf", filename=filename )