| from fastapi import APIRouter, File, UploadFile, HTTPException, Form |
| from fastapi.responses import StreamingResponse |
| from app.services.image_generation_service import generate_image_from_files_and_prompt |
| from app.services.prompt_factory import LIFESTYLE_TRYON_PROMPT_TEMPLATE |
| from app.schemas.common_schemas import ModelSchema, CameraSchema,GarmentType |
| import io |
| from typing import List, Annotated |
|
|
| router = APIRouter() |
|
|
| @router.post("/tryon", tags=["TRY-ON"]) |
| async def tryon( |
| garment_type: Annotated[str, Form()], |
| model_gender: Annotated[str, Form()], |
| model_age_range: Annotated[str, Form()], |
| model_body_shape: Annotated[str, Form()], |
| model_race_ethnicity: Annotated[str, Form()], |
| model_pose: Annotated[str, Form()], |
| camera_view_angle: Annotated[str, Form()], |
| camera_distance_meters: Annotated[float, Form()], |
| camera_focal_length_mm: Annotated[float, Form()], |
| camera_aperture_f_number: Annotated[float, Form()], |
| camera_lighting_condition: Annotated[str, Form()], |
| camera_background: Annotated[str, Form()], |
| garment_images: List[UploadFile] = File(..., description="Exactly one image of the garments (e.g., dress /bag/shoes).", min_items=1, max_items=1), |
| ): |
| """ |
| Generate a try-on image based on garment images, model characteristics, and camera settings. |
| """ |
| try: |
| garment=GarmentType(garment_type=garment_type) |
| model_attributes = ModelSchema( |
| gender=model_gender, |
| age_range=model_age_range, |
| body_shape=model_body_shape, |
| race_ethnicity=model_race_ethnicity, |
| pose=model_pose |
| ) |
| camera_settings = CameraSchema( |
| view_angle=camera_view_angle, |
| distance_meters=camera_distance_meters, |
| focal_length_mm=camera_focal_length_mm, |
| aperture_f_number=camera_aperture_f_number, |
| lighting_condition=camera_lighting_condition, |
| background=camera_background |
| ) |
| except Exception as e: |
| raise HTTPException(status_code=400, detail=f"Invalid model or camera attributes: {e}") |
|
|
| |
| if not garment_images or len(garment_images) != 1: |
| raise HTTPException(status_code=400, detail="Exactly one garment images are required for outfit match.") |
|
|
| image_bytes_list = [] |
| for image_file in garment_images: |
| if not image_file.content_type.startswith("image/"): |
| raise HTTPException(status_code=400, detail=f"Invalid file type for garment: {image_file.filename}. Must be an image.") |
| content = await image_file.read() |
| image_bytes_list.append((content, image_file.filename)) |
| |
| prompt=LIFESTYLE_TRYON_PROMPT_TEMPLATE.format( |
| garment_type=garment.garment_type, |
| model_gender=model_attributes.gender, |
| model_age_range=model_attributes.age_range, |
| model_race_ethnicity=model_attributes.race_ethnicity, |
| model_body_shape=model_attributes.body_shape, |
| model_pose=model_attributes.pose, |
| camera_view_angle=camera_settings.view_angle, |
| camera_distance_meters=camera_settings.distance_meters, |
| camera_focal_length_mm=camera_settings.focal_length_mm, |
| camera_aperture_f_number=camera_settings.aperture_f_number, |
| camera_lighting_condition=camera_settings.lighting_condition, |
| camera_background=camera_settings.background |
| ) |
|
|
| generated_image_data = await generate_image_from_files_and_prompt( |
| image_files=image_bytes_list, |
| prompt=prompt |
| ) |
|
|
| if generated_image_data: |
| return StreamingResponse(io.BytesIO(generated_image_data), media_type="image/png") |
| else: |
| raise HTTPException(status_code=500, detail="Failed to generate image. Check service logs.") |
|
|