98 lines
3.0 KiB
Python
98 lines
3.0 KiB
Python
"""
|
||
文件上传接口
|
||
"""
|
||
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
|
||
)
|