Initial commit: AI Interview System
This commit is contained in:
97
backend/app/routers/upload.py
Normal file
97
backend/app/routers/upload.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""
|
||||
文件上传接口
|
||||
"""
|
||||
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
|
||||
)
|
||||
Reference in New Issue
Block a user