129 lines
3.7 KiB
Python
129 lines
3.7 KiB
Python
import uuid
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.api.deps import get_current_user
|
|
from app.database import get_db
|
|
from app.models.user import User
|
|
from app.models.brand import Brand
|
|
from app.models.trend_insight import TrendInsight
|
|
from app.schemas.trend_insight import (
|
|
TrendInsightRequest,
|
|
TrendInsightResponse,
|
|
TrendInsightList,
|
|
TrendSummary,
|
|
)
|
|
from app.services.trend.trend_analyzer_service import TrendAnalyzerService
|
|
|
|
router = APIRouter()
|
|
def _to_uuid(value: str | uuid.UUID) -> uuid.UUID:
|
|
if isinstance(value, uuid.UUID):
|
|
return value
|
|
return uuid.UUID(str(value))
|
|
|
|
|
|
async def _get_brand_with_access(
|
|
brand_id: uuid.UUID,
|
|
db: AsyncSession,
|
|
current_user: User,
|
|
) -> Brand:
|
|
stmt = select(Brand).where(
|
|
Brand.id == brand_id,
|
|
Brand.user_id == _to_uuid(current_user.id),
|
|
)
|
|
result = await db.execute(stmt)
|
|
brand = result.scalar_one_or_none()
|
|
|
|
if not brand:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="品牌不存在",
|
|
)
|
|
return brand
|
|
|
|
|
|
@router.post("/insight", response_model=TrendInsightResponse)
|
|
async def create_trend_insight(
|
|
request: TrendInsightRequest,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
await _get_brand_with_access(request.brand_id, db, current_user)
|
|
|
|
service = TrendAnalyzerService(db)
|
|
result = await service.analyze_trends(
|
|
brand_id=request.brand_id,
|
|
days=request.period_days,
|
|
platforms=request.platforms,
|
|
keywords=request.keywords,
|
|
)
|
|
|
|
if result.get("status") == "insufficient_data":
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=result.get("message", "数据不足"),
|
|
)
|
|
|
|
insight_id = uuid.UUID(result["insight_id"])
|
|
insight = await service.get_insight_by_id(insight_id)
|
|
if insight is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
detail="洞察创建失败",
|
|
)
|
|
return insight
|
|
|
|
|
|
@router.get("/brand/{brand_id}", response_model=TrendInsightList)
|
|
async def list_trend_insights(
|
|
brand_id: uuid.UUID,
|
|
skip: int = Query(0, ge=0),
|
|
limit: int = Query(20, ge=1, le=100),
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
await _get_brand_with_access(brand_id, db, current_user)
|
|
|
|
service = TrendAnalyzerService(db)
|
|
items, total = await service.get_insights(
|
|
brand_id=brand_id,
|
|
skip=skip,
|
|
limit=limit,
|
|
)
|
|
return TrendInsightList(items=items, total=total)
|
|
|
|
|
|
@router.get("/brand/{brand_id}/summary", response_model=TrendSummary)
|
|
async def get_trend_summary(
|
|
brand_id: uuid.UUID,
|
|
period_days: int = Query(30, ge=7, le=365),
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
await _get_brand_with_access(brand_id, db, current_user)
|
|
|
|
service = TrendAnalyzerService(db)
|
|
summary = await service.get_summary(
|
|
brand_id=brand_id,
|
|
days=period_days,
|
|
)
|
|
return TrendSummary(**summary)
|
|
|
|
|
|
@router.get("/{insight_id}", response_model=TrendInsightResponse)
|
|
async def get_trend_insight_detail(
|
|
insight_id: uuid.UUID,
|
|
current_user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
service = TrendAnalyzerService(db)
|
|
insight = await service.get_insight_by_id(insight_id)
|
|
if insight is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="洞察不存在",
|
|
)
|
|
return insight
|