init the project
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# PRD 上传与解析接口
|
||||
|
||||
import logging
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from fastapi import APIRouter, UploadFile, File, HTTPException
|
||||
|
||||
from server.services.prd_manager.service import prd_service
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
|
||||
ALLOWED_EXTENSIONS = {".md", ".txt", ".docx", ".pdf"}
|
||||
_parse_executor = ThreadPoolExecutor(max_workers=2)
|
||||
|
||||
|
||||
@router.post("/upload")
|
||||
async def upload_prd(file: UploadFile = File(...)):
|
||||
"""上传 PRD 文件,立即返回 PRD ID,后台异步解析"""
|
||||
ext = "." + file.filename.rsplit(".", 1)[-1].lower() if "." in file.filename else ""
|
||||
if ext not in ALLOWED_EXTENSIONS:
|
||||
raise HTTPException(400, f"不支持的文件格式: {ext},支持: {', '.join(ALLOWED_EXTENSIONS)}")
|
||||
|
||||
content = await file.read()
|
||||
if len(content) == 0:
|
||||
raise HTTPException(400, "文件为空")
|
||||
|
||||
try:
|
||||
# Quick: save and return immediately
|
||||
prd_version = await prd_service.upload_quick(file.filename, content)
|
||||
|
||||
# Background: parse async (image analysis may take 60s+)
|
||||
_parse_executor.submit(_parse_in_background, prd_version["prd_id"], file.filename, content)
|
||||
|
||||
return {
|
||||
"prd_id": prd_version["prd_id"],
|
||||
"filename": prd_version["filename"],
|
||||
"status": "parsing",
|
||||
"uploaded_at": prd_version["uploaded_at"],
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error("PRD upload failed: %s", e)
|
||||
raise HTTPException(500, f"上传失败: {e}")
|
||||
|
||||
|
||||
def _parse_in_background(prd_id: str, filename: str, content: bytes):
|
||||
"""Run full parsing (text + images + vision analysis) in background thread."""
|
||||
import asyncio
|
||||
try:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.run_until_complete(prd_service.parse_async(prd_id, filename, content))
|
||||
except Exception as e:
|
||||
logger.error("Background parse failed for %s: %s", prd_id, e)
|
||||
prd_service.set_status(prd_id, "error", str(e))
|
||||
|
||||
|
||||
@router.get("/{prd_id}/status")
|
||||
async def get_prd_status(prd_id: str):
|
||||
"""获取 PRD 解析状态"""
|
||||
status = await prd_service.get_status(prd_id)
|
||||
if not status:
|
||||
raise HTTPException(404, "PRD not found")
|
||||
return status
|
||||
|
||||
|
||||
@router.get("/{prd_id}")
|
||||
async def get_prd(prd_id: str):
|
||||
"""获取 PRD 详情与版本"""
|
||||
prd = await prd_service.get_prd(prd_id)
|
||||
if not prd:
|
||||
raise HTTPException(404, "PRD not found")
|
||||
return {
|
||||
"prd_id": prd["prd_id"],
|
||||
"filename": prd["filename"],
|
||||
"status": prd.get("status", "ready"),
|
||||
"full_text": prd.get("full_text", ""),
|
||||
"sections": prd.get("sections", []),
|
||||
"images": prd.get("images", []),
|
||||
"uploaded_at": prd["uploaded_at"],
|
||||
}
|
||||
Reference in New Issue
Block a user