90 lines
3.2 KiB
Python
90 lines
3.2 KiB
Python
from datetime import date
|
|
from typing import Optional
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from sqlalchemy import select, func
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from ..database import get_db
|
|
from ..models.news import ProcessedNews
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
def _serialize(n: ProcessedNews) -> dict:
|
|
return {
|
|
"id": n.id,
|
|
"title_zh": n.title_zh,
|
|
"summary": n.summary,
|
|
"opinion": n.opinion,
|
|
"keywords": n.keywords or [],
|
|
"importance_score": n.importance_score,
|
|
"importance_reason": n.importance_reason,
|
|
"category": n.category,
|
|
"is_featured": n.is_featured,
|
|
"featured_rank": n.featured_rank,
|
|
"source_name": n.source_name or "",
|
|
"source_url": n.source_url or "",
|
|
"published_at": n.published_at.isoformat() if n.published_at else None,
|
|
"processed_at": n.processed_at.isoformat() if n.processed_at else None,
|
|
}
|
|
|
|
|
|
@router.get("/featured")
|
|
async def get_featured(
|
|
news_date: Optional[str] = Query(default=None, alias="date"),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
target = date.fromisoformat(news_date) if news_date else date.today()
|
|
stmt = (
|
|
select(ProcessedNews)
|
|
.where(ProcessedNews.is_featured == True)
|
|
.where(func.date(ProcessedNews.processed_at) == target)
|
|
.order_by(ProcessedNews.featured_rank)
|
|
)
|
|
result = await db.execute(stmt)
|
|
items = result.scalars().all()
|
|
return {"date": str(target), "items": [_serialize(n) for n in items]}
|
|
|
|
|
|
@router.get("")
|
|
async def get_news(
|
|
news_date: Optional[str] = Query(default=None, alias="date"),
|
|
category: Optional[str] = Query(default=None),
|
|
page: int = Query(default=1, ge=1),
|
|
page_size: int = Query(default=20, ge=1, le=100),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
target = date.fromisoformat(news_date) if news_date else date.today()
|
|
stmt = select(ProcessedNews).where(func.date(ProcessedNews.processed_at) == target)
|
|
if category:
|
|
stmt = stmt.where(ProcessedNews.category == category)
|
|
|
|
count_stmt = select(func.count()).select_from(stmt.subquery())
|
|
total = (await db.execute(count_stmt)).scalar_one()
|
|
|
|
stmt = stmt.order_by(ProcessedNews.importance_score.desc()).offset((page - 1) * page_size).limit(page_size)
|
|
result = await db.execute(stmt)
|
|
items = result.scalars().all()
|
|
|
|
return {"date": str(target), "total": total, "page": page, "items": [_serialize(n) for n in items]}
|
|
|
|
|
|
@router.get("/dates")
|
|
async def get_dates(db: AsyncSession = Depends(get_db)):
|
|
stmt = select(
|
|
func.date(ProcessedNews.processed_at).label("d"),
|
|
func.count(ProcessedNews.id).label("cnt"),
|
|
).group_by("d").order_by(func.date(ProcessedNews.processed_at).desc()).limit(30)
|
|
result = await db.execute(stmt)
|
|
return [{"date": str(row.d), "count": row.cnt} for row in result]
|
|
|
|
|
|
@router.get("/{news_id}")
|
|
async def get_news_detail(news_id: int, db: AsyncSession = Depends(get_db)):
|
|
stmt = select(ProcessedNews).where(ProcessedNews.id == news_id)
|
|
result = await db.execute(stmt)
|
|
news = result.scalar_one_or_none()
|
|
if not news:
|
|
raise HTTPException(status_code=404, detail="Not found")
|
|
return _serialize(news)
|