Extracted remaining 4 endpoint groups: - create.py: 7 endpoints (create, 3xtemplates, providers, estimate-cost, platform-specs) - transform.py: 4 endpoints (image-to-video, talking-avatar, estimate-cost, video serving) - compress.py: 5 endpoints (compress, batch, estimate, formats, presets) - convert.py: 4 endpoints (convert-format, batch, supported, recommendations) Legacy router is now empty (only imports + empty router definition). All 33 routes preserved. Package is fully modular.
159 lines
6.3 KiB
Python
159 lines
6.3 KiB
Python
"""Compression Studio endpoints."""
|
|
|
|
from typing import Dict, Any
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
|
|
from .models import (
|
|
CompressImageRequest, CompressImageResponse,
|
|
CompressBatchRequest, CompressBatchResponse,
|
|
CompressionEstimateRequest, CompressionEstimateResponse,
|
|
CompressionFormatsResponse, CompressionPresetsResponse,
|
|
)
|
|
from .deps import get_studio_manager, _require_user_id
|
|
from services.image_studio import ImageStudioManager
|
|
from middleware.auth_middleware import get_current_user
|
|
from utils.logger_utils import get_service_logger
|
|
|
|
logger = get_service_logger("api.image_studio")
|
|
router = APIRouter(tags=["image-studio"])
|
|
|
|
|
|
@router.post("/compress", response_model=CompressImageResponse, summary="Compress an image")
|
|
async def compress_image(
|
|
request: CompressImageRequest,
|
|
current_user: Dict[str, Any] = Depends(get_current_user),
|
|
studio_manager: ImageStudioManager = Depends(get_studio_manager),
|
|
):
|
|
"""Compress an image with specified quality and format settings."""
|
|
try:
|
|
user_id = _require_user_id(current_user, "image compression")
|
|
logger.info(f"[Compression] Request from user {user_id}: format={request.format}, quality={request.quality}")
|
|
|
|
from services.image_studio.compression_service import CompressionRequest as ServiceRequest
|
|
|
|
compression_request = ServiceRequest(
|
|
image_base64=request.image_base64,
|
|
quality=request.quality,
|
|
format=request.format,
|
|
target_size_kb=request.target_size_kb,
|
|
strip_metadata=request.strip_metadata,
|
|
progressive=request.progressive,
|
|
optimize=request.optimize,
|
|
)
|
|
|
|
result = await studio_manager.compress_image(compression_request, user_id=user_id)
|
|
|
|
return CompressImageResponse(
|
|
success=result.success,
|
|
image_base64=result.image_base64,
|
|
original_size_kb=result.original_size_kb,
|
|
compressed_size_kb=result.compressed_size_kb,
|
|
compression_ratio=result.compression_ratio,
|
|
format=result.format,
|
|
width=result.width,
|
|
height=result.height,
|
|
quality_used=result.quality_used,
|
|
metadata_stripped=result.metadata_stripped,
|
|
)
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"[Compression] ❌ Error: {str(e)}", exc_info=True)
|
|
raise HTTPException(status_code=500, detail=f"Image compression failed: {e}")
|
|
|
|
|
|
@router.post("/compress/batch", response_model=CompressBatchResponse, summary="Compress multiple images")
|
|
async def compress_batch(
|
|
request: CompressBatchRequest,
|
|
current_user: Dict[str, Any] = Depends(get_current_user),
|
|
studio_manager: ImageStudioManager = Depends(get_studio_manager),
|
|
):
|
|
"""Compress multiple images with the same or individual settings."""
|
|
try:
|
|
user_id = _require_user_id(current_user, "batch compression")
|
|
logger.info(f"[Compression] Batch request from user {user_id}: {len(request.images)} images")
|
|
|
|
from services.image_studio.compression_service import CompressionRequest as ServiceRequest
|
|
|
|
compression_requests = [
|
|
ServiceRequest(
|
|
image_base64=img.image_base64,
|
|
quality=img.quality,
|
|
format=img.format,
|
|
target_size_kb=img.target_size_kb,
|
|
strip_metadata=img.strip_metadata,
|
|
progressive=img.progressive,
|
|
optimize=img.optimize,
|
|
)
|
|
for img in request.images
|
|
]
|
|
|
|
results = await studio_manager.compress_batch(compression_requests, user_id=user_id)
|
|
|
|
successful = sum(1 for r in results if r.success)
|
|
failed = len(results) - successful
|
|
|
|
return CompressBatchResponse(
|
|
success=failed == 0,
|
|
results=[
|
|
CompressImageResponse(
|
|
success=r.success,
|
|
image_base64=r.image_base64,
|
|
original_size_kb=r.original_size_kb,
|
|
compressed_size_kb=r.compressed_size_kb,
|
|
compression_ratio=r.compression_ratio,
|
|
format=r.format,
|
|
width=r.width,
|
|
height=r.height,
|
|
quality_used=r.quality_used,
|
|
metadata_stripped=r.metadata_stripped,
|
|
)
|
|
for r in results
|
|
],
|
|
total_images=len(results),
|
|
successful=successful,
|
|
failed=failed,
|
|
)
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"[Compression] ❌ Batch error: {str(e)}", exc_info=True)
|
|
raise HTTPException(status_code=500, detail=f"Batch compression failed: {e}")
|
|
|
|
|
|
@router.post("/compress/estimate", response_model=CompressionEstimateResponse, summary="Estimate compression results")
|
|
async def estimate_compression(
|
|
request: CompressionEstimateRequest,
|
|
current_user: Dict[str, Any] = Depends(get_current_user),
|
|
studio_manager: ImageStudioManager = Depends(get_studio_manager),
|
|
):
|
|
"""Estimate compression results without actually compressing the image."""
|
|
try:
|
|
result = await studio_manager.estimate_compression(
|
|
request.image_base64,
|
|
request.format,
|
|
request.quality,
|
|
)
|
|
return CompressionEstimateResponse(**result)
|
|
except Exception as e:
|
|
logger.error(f"[Compression] ❌ Estimate error: {str(e)}", exc_info=True)
|
|
raise HTTPException(status_code=500, detail=f"Compression estimation failed: {e}")
|
|
|
|
|
|
@router.get("/compress/formats", response_model=CompressionFormatsResponse, summary="Get supported compression formats")
|
|
async def get_compression_formats(
|
|
studio_manager: ImageStudioManager = Depends(get_studio_manager),
|
|
):
|
|
"""Get list of supported compression formats with their capabilities."""
|
|
formats = studio_manager.get_compression_formats()
|
|
return CompressionFormatsResponse(formats=formats)
|
|
|
|
|
|
@router.get("/compress/presets", response_model=CompressionPresetsResponse, summary="Get compression presets")
|
|
async def get_compression_presets(
|
|
studio_manager: ImageStudioManager = Depends(get_studio_manager),
|
|
):
|
|
"""Get predefined compression presets for common use cases."""
|
|
presets = studio_manager.get_compression_presets()
|
|
return CompressionPresetsResponse(presets=presets)
|