Spaces:
Running
Running
File size: 5,116 Bytes
ed37502 e808ae1 ed37502 e808ae1 ed37502 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | """Catalog API routes — query and manage generated images."""
from __future__ import annotations
from pathlib import Path
from fastapi import APIRouter, HTTPException
from fastapi.responses import FileResponse
from content_engine.models.schemas import ImageResponse
router = APIRouter(prefix="/api", tags=["catalog"])
_catalog = None
def init_routes(catalog):
"""Initialize route dependencies."""
global _catalog
_catalog = catalog
@router.get("/images", response_model=list[ImageResponse])
async def list_images(
character_id: str | None = None,
content_rating: str | None = None,
template_id: str | None = None,
is_approved: bool | None = None,
is_published: bool | None = None,
pose: str | None = None,
outfit: str | None = None,
emotion: str | None = None,
limit: int = 50,
offset: int = 0,
):
"""Search and list generated images with optional filters."""
if _catalog is None:
raise HTTPException(503, "Catalog not initialized")
images = await _catalog.search(
character_id=character_id,
content_rating=content_rating,
template_id=template_id,
is_approved=is_approved,
is_published=is_published,
pose=pose,
outfit=outfit,
emotion=emotion,
limit=limit,
offset=offset,
)
return [
ImageResponse(
id=img.id,
character_id=img.character_id,
template_id=img.template_id,
content_rating=img.content_rating,
file_path=img.file_path,
seed=img.seed,
pose=img.pose,
outfit=img.outfit,
emotion=img.emotion,
camera_angle=img.camera_angle,
lighting=img.lighting,
scene=img.scene,
quality_score=img.quality_score,
is_approved=img.is_approved,
is_published=img.is_published,
created_at=img.created_at,
)
for img in images
]
@router.get("/images/{image_id}", response_model=ImageResponse)
async def get_image(image_id: str):
"""Get a single image by ID."""
if _catalog is None:
raise HTTPException(503, "Catalog not initialized")
img = await _catalog.get_image(image_id)
if img is None:
raise HTTPException(404, f"Image not found: {image_id}")
return ImageResponse(
id=img.id,
character_id=img.character_id,
template_id=img.template_id,
content_rating=img.content_rating,
file_path=img.file_path,
seed=img.seed,
pose=img.pose,
outfit=img.outfit,
emotion=img.emotion,
camera_angle=img.camera_angle,
lighting=img.lighting,
scene=img.scene,
quality_score=img.quality_score,
is_approved=img.is_approved,
is_published=img.is_published,
created_at=img.created_at,
)
@router.get("/images/{image_id}/file")
async def serve_image_file(image_id: str):
"""Serve the actual image file for display in the UI."""
if _catalog is None:
raise HTTPException(503, "Catalog not initialized")
img = await _catalog.get_image(image_id)
if img is None:
raise HTTPException(404, f"Image not found: {image_id}")
file_path = Path(img.file_path)
if not file_path.exists():
raise HTTPException(404, f"Image file not found on disk")
ext = file_path.suffix.lower()
media_type = "video/mp4" if ext == ".mp4" else "video/webm" if ext == ".webm" else "image/png"
return FileResponse(
file_path,
media_type=media_type,
headers={"Cache-Control": "public, max-age=3600"},
)
@router.get("/images/{image_id}/download")
async def download_image_file(image_id: str):
"""Download the image file as an attachment."""
if _catalog is None:
raise HTTPException(503, "Catalog not initialized")
img = await _catalog.get_image(image_id)
if img is None:
raise HTTPException(404, f"Image not found: {image_id}")
file_path = Path(img.file_path)
if not file_path.exists():
raise HTTPException(404, "Image file not found on disk")
return FileResponse(
file_path,
media_type="image/png",
filename=file_path.name,
)
@router.post("/images/{image_id}/approve")
async def approve_image(image_id: str):
"""Mark an image as approved for publishing."""
if _catalog is None:
raise HTTPException(503, "Catalog not initialized")
success = await _catalog.approve_image(image_id)
if not success:
raise HTTPException(404, f"Image not found: {image_id}")
return {"status": "approved", "image_id": image_id}
@router.delete("/images/{image_id}")
async def delete_image(image_id: str):
"""Delete an image from the catalog and disk."""
if _catalog is None:
raise HTTPException(503, "Catalog not initialized")
success = await _catalog.delete_image(image_id)
if not success:
raise HTTPException(404, f"Image not found: {image_id}")
return {"status": "deleted", "image_id": image_id}
|