dippoo's picture
Sync all local changes: video routes, pod management, wavespeed, UI updates
e808ae1
raw
history blame
5.12 kB
"""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}