from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from app.core.database import get_db from app.models.tryon import TryOnTask from app.models.wardrobe import WardrobeItem from app.schemas.tryon import TryOnTaskCreate, TryOnTaskResponse from app.api.deps import get_current_user from app.models.user import User from app.workers.tasks import run_tryon import uuid router = APIRouter() @router.post("/run", response_model=TryOnTaskResponse, status_code=status.HTTP_201_CREATED) def trigger_try_on( task_in: TryOnTaskCreate, db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): # 1. Determine selected garment IDs and validate ownership garment_ids = [] if task_in.garment_item_ids: garment_ids = task_in.garment_item_ids elif task_in.garment_item_id: garment_ids = [task_in.garment_item_id] if not garment_ids: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Vui lòng chọn ít nhất một trang phục để thử đồ." ) for gid in garment_ids: item = db.query(WardrobeItem).filter( WardrobeItem.id == gid, WardrobeItem.user_id == current_user.id ).first() if not item: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"Không tìm thấy vật phẩm quần áo phù hợp (ID: {gid})." ) person_image_url = None from app.models.body import BodyProfile if task_in.person_image_base64: try: import base64 header = "base64," b64_str = task_in.person_image_base64 if header in b64_str: b64_str = b64_str.split(header)[1] img_data = base64.b64decode(b64_str) from app.services.storage import storage_service filename = f"{uuid.uuid4()}.jpg" r2_path = f"users/{current_user.id}/body/{filename}" person_image_url = storage_service.upload_file(img_data, r2_path, "image/jpeg") # Save/Update persistently to user's BodyProfile profile = db.query(BodyProfile).filter(BodyProfile.user_id == current_user.id).first() if profile: profile.body_image_url = person_image_url else: profile = BodyProfile( user_id=current_user.id, gender="male", height_cm=170.0, weight_kg=60.0, body_image_url=person_image_url ) db.add(profile) db.commit() except Exception as e: import logging logging.error(f"Failed to upload try-on person image: {e}") else: # Load from saved profile profile = db.query(BodyProfile).filter(BodyProfile.user_id == current_user.id).first() if profile and profile.body_image_url: person_image_url = profile.body_image_url else: person_image_url = None task = TryOnTask( user_id=current_user.id, garment_item_id=garment_ids[0] if garment_ids else None, garment_item_ids=garment_ids, person_image_url=person_image_url, status="PENDING" ) db.add(task) db.commit() db.refresh(task) # Kích hoạt Celery Task tạo ảnh thử đồ qua image-gen API (bất đồng bộ) run_tryon.delay(str(task.id)) return task @router.get("/tasks", response_model=list[TryOnTaskResponse]) def list_try_on_tasks( limit: int = 50, db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): """Lịch sử các lần thử đồ của người dùng (mới nhất trước).""" tasks = ( db.query(TryOnTask) .filter(TryOnTask.user_id == current_user.id) .order_by(TryOnTask.created_at.desc()) .limit(limit) .all() ) return tasks @router.get("/tasks/{task_id}", response_model=TryOnTaskResponse) def get_try_on_task( task_id: uuid.UUID, db: Session = Depends(get_db), current_user: User = Depends(get_current_user) ): task = db.query(TryOnTask).filter( TryOnTask.id == task_id, TryOnTask.user_id == current_user.id ).first() if not task: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Không tìm thấy tác vụ thử đồ." ) return task