Initial commit
This commit is contained in:
188
backend/app/api/routes/intent.py
Normal file
188
backend/app/api/routes/intent.py
Normal file
@@ -0,0 +1,188 @@
|
||||
"""
|
||||
意图编制 API 路由
|
||||
"""
|
||||
|
||||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select
|
||||
from pydantic import BaseModel
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from app.database import get_db
|
||||
from app.models.intent import Intent, AICheckRecord
|
||||
from planner.planning_agent.input_pipeline import parse_intent_file
|
||||
import tempfile
|
||||
|
||||
router = APIRouter(prefix="/intent", tags=["意图编制"])
|
||||
|
||||
|
||||
# ============ Pydantic Schemas ============
|
||||
|
||||
class IntentCreate(BaseModel):
|
||||
"""创建意图请求"""
|
||||
title: str
|
||||
content: Optional[str] = None
|
||||
status: str = "draft"
|
||||
|
||||
|
||||
class IntentUpdate(BaseModel):
|
||||
"""更新意图请求"""
|
||||
title: Optional[str] = None
|
||||
content: Optional[str] = None
|
||||
status: Optional[str] = None
|
||||
|
||||
|
||||
class IntentResponse(BaseModel):
|
||||
"""意图响应"""
|
||||
id: int
|
||||
title: str
|
||||
content: Optional[str]
|
||||
status: str
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class IntentListResponse(BaseModel):
|
||||
"""意图列表响应"""
|
||||
total: int
|
||||
items: List[IntentResponse]
|
||||
|
||||
|
||||
# ============ API Endpoints ============
|
||||
|
||||
@router.post("", response_model=IntentResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_intent(
|
||||
intent_data: IntentCreate,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""创建新意图"""
|
||||
intent = Intent(
|
||||
title=intent_data.title,
|
||||
content=intent_data.content,
|
||||
status=intent_data.status
|
||||
)
|
||||
db.add(intent)
|
||||
await db.commit()
|
||||
await db.refresh(intent)
|
||||
return intent
|
||||
|
||||
|
||||
@router.get("", response_model=IntentListResponse)
|
||||
async def list_intents(
|
||||
skip: int = 0,
|
||||
limit: int = 20,
|
||||
status_filter: Optional[str] = None,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""获取意图列表"""
|
||||
query = select(Intent)
|
||||
|
||||
if status_filter:
|
||||
query = query.where(Intent.status == status_filter)
|
||||
|
||||
query = query.order_by(Intent.updated_at.desc())
|
||||
|
||||
# 获取总数
|
||||
count_query = select(Intent)
|
||||
if status_filter:
|
||||
count_query = count_query.where(Intent.status == status_filter)
|
||||
result = await db.execute(count_query)
|
||||
total = len(result.scalars().all())
|
||||
|
||||
# 获取分页数据
|
||||
query = query.offset(skip).limit(limit)
|
||||
result = await db.execute(query)
|
||||
items = result.scalars().all()
|
||||
|
||||
return IntentListResponse(total=total, items=items)
|
||||
|
||||
|
||||
@router.get("/{intent_id}", response_model=IntentResponse)
|
||||
async def get_intent(
|
||||
intent_id: int,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""获取单个意图"""
|
||||
result = await db.execute(select(Intent).where(Intent.id == intent_id))
|
||||
intent = result.scalar_one_or_none()
|
||||
|
||||
if not intent:
|
||||
raise HTTPException(status_code=404, detail="意图不存在")
|
||||
|
||||
return intent
|
||||
|
||||
|
||||
@router.put("/{intent_id}", response_model=IntentResponse)
|
||||
async def update_intent(
|
||||
intent_id: int,
|
||||
intent_data: IntentUpdate,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""更新意图"""
|
||||
result = await db.execute(select(Intent).where(Intent.id == intent_id))
|
||||
intent = result.scalar_one_or_none()
|
||||
|
||||
if not intent:
|
||||
raise HTTPException(status_code=404, detail="意图不存在")
|
||||
|
||||
if intent_data.title is not None:
|
||||
intent.title = intent_data.title
|
||||
if intent_data.content is not None:
|
||||
intent.content = intent_data.content
|
||||
if intent_data.status is not None:
|
||||
intent.status = intent_data.status
|
||||
|
||||
intent.updated_at = datetime.utcnow()
|
||||
|
||||
await db.commit()
|
||||
await db.refresh(intent)
|
||||
return intent
|
||||
|
||||
|
||||
@router.delete("/{intent_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_intent(
|
||||
intent_id: int,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
"""删除意图"""
|
||||
result = await db.execute(select(Intent).where(Intent.id == intent_id))
|
||||
intent = result.scalar_one_or_none()
|
||||
|
||||
if not intent:
|
||||
raise HTTPException(status_code=404, detail="意图不存在")
|
||||
|
||||
await db.delete(intent)
|
||||
await db.commit()
|
||||
return None
|
||||
|
||||
|
||||
@router.post("/parse-file")
|
||||
async def parse_intent_file_endpoint(file: UploadFile = File(...)):
|
||||
"""解析意图编制导入文件(pdf/图片走 MinerU,文本直接读取)"""
|
||||
if not file.filename:
|
||||
raise HTTPException(status_code=400, detail="未提供文件")
|
||||
|
||||
suffix = Path(file.filename).suffix.lower()
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
tmp_path = Path(tmp_dir) / file.filename
|
||||
content = await file.read()
|
||||
tmp_path.write_bytes(content)
|
||||
|
||||
try:
|
||||
result = parse_intent_file(str(tmp_path))
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
return {
|
||||
"filename": file.filename,
|
||||
"suffix": suffix,
|
||||
"title": result.get("title", ""),
|
||||
"content": result.get("content", ""),
|
||||
"raw_result": result.get("raw_result"),
|
||||
}
|
||||
Reference in New Issue
Block a user