111 lines
4.2 KiB
Python
111 lines
4.2 KiB
Python
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status
|
|
from pydantic import ValidationError
|
|
from sqlalchemy import desc, select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.database import AsyncSessionLocal, get_db
|
|
from app.core.security import get_current_user
|
|
from app.models.reading import Reading
|
|
from app.models.uploaded_image import UploadedImage
|
|
from app.models.user import User
|
|
from app.schemas.quota import QuotaResponse
|
|
from app.schemas.reading import BaziInput, ReadingCreate, ReadingDetail, ReadingSummary
|
|
from app.services.image_service import ImageService
|
|
from app.services.quota_service import QuotaService
|
|
from app.services.reading_service import ReadingService
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
async def generate_reading_task(reading_id: str) -> None:
|
|
async with AsyncSessionLocal() as session:
|
|
await ReadingService().generate(session, reading_id)
|
|
|
|
|
|
@router.get("/quota", response_model=QuotaResponse)
|
|
async def get_reading_quota(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
|
|
return await QuotaService().get_quota(db, user.id)
|
|
|
|
|
|
@router.post("", response_model=ReadingDetail, status_code=status.HTTP_201_CREATED)
|
|
async def create_reading(
|
|
payload: ReadingCreate,
|
|
background_tasks: BackgroundTasks,
|
|
user: User = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
input_data = dict(payload.input_data)
|
|
image_id = payload.image_id
|
|
|
|
if payload.reading_type in {"palm", "face"}:
|
|
image_result = await db.execute(select(UploadedImage).where(UploadedImage.id == image_id, UploadedImage.user_id == user.id))
|
|
image = image_result.scalar_one_or_none()
|
|
if image is None:
|
|
raise HTTPException(status_code=404, detail="Image not found")
|
|
elif payload.reading_type == "bazi":
|
|
try:
|
|
input_data = BaziInput.model_validate(input_data).model_dump()
|
|
except ValidationError as exc:
|
|
raise HTTPException(status_code=422, detail=exc.errors()) from exc
|
|
|
|
await QuotaService().consume(db, user.id)
|
|
reading = Reading(
|
|
user_id=user.id,
|
|
reading_type=payload.reading_type,
|
|
image_id=image_id,
|
|
input_data=input_data,
|
|
status="pending",
|
|
)
|
|
db.add(reading)
|
|
await db.flush()
|
|
await db.refresh(reading)
|
|
await db.commit()
|
|
background_tasks.add_task(generate_reading_task, reading.id)
|
|
return reading
|
|
|
|
|
|
@router.get("", response_model=list[ReadingSummary])
|
|
async def list_readings(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
|
|
result = await db.execute(
|
|
select(Reading).where(Reading.user_id == user.id).order_by(desc(Reading.created_at)).limit(80)
|
|
)
|
|
readings = result.scalars().all()
|
|
return [
|
|
ReadingSummary(
|
|
id=reading.id,
|
|
reading_type=reading.reading_type,
|
|
status=reading.status,
|
|
created_at=reading.created_at,
|
|
overall_summary=(reading.report_data or {}).get("overall_summary") if reading.report_data else None,
|
|
)
|
|
for reading in readings
|
|
]
|
|
|
|
|
|
@router.get("/{reading_id}", response_model=ReadingDetail)
|
|
async def get_reading(reading_id: str, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
|
|
return await _get_owned_reading(db, reading_id, user.id)
|
|
|
|
|
|
@router.delete("/{reading_id}")
|
|
async def delete_reading(reading_id: str, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
|
|
reading = await _get_owned_reading(db, reading_id, user.id)
|
|
image = None
|
|
if reading.image_id:
|
|
image_result = await db.execute(select(UploadedImage).where(UploadedImage.id == reading.image_id))
|
|
image = image_result.scalar_one_or_none()
|
|
await db.delete(reading)
|
|
await db.flush()
|
|
if image:
|
|
ImageService().delete(image.storage_key)
|
|
await db.delete(image)
|
|
return {"status": "deleted"}
|
|
|
|
|
|
async def _get_owned_reading(db: AsyncSession, reading_id: str, user_id: str) -> Reading:
|
|
result = await db.execute(select(Reading).where(Reading.id == reading_id, Reading.user_id == user_id))
|
|
reading = result.scalar_one_or_none()
|
|
if reading is None:
|
|
raise HTTPException(status_code=404, detail="Reading not found")
|
|
return reading
|