apix/backend/routers/references.py
Khoa.vo 0ef7e5475c
Some checks are pending
CI / build (18.x) (push) Waiting to run
CI / build (20.x) (push) Waiting to run
v3.0.0: Add FastAPI backend
- Add Python FastAPI backend with Pydantic validation
- Port WhiskClient and MetaAIClient to Python
- Create API routers for all endpoints
- Add Swagger/ReDoc documentation at /docs
- Update Dockerfile for multi-service container
- Add lib/api.ts frontend client
- Update README for V3
2026-01-13 07:46:32 +07:00

92 lines
3.3 KiB
Python

"""
References Router - Reference image upload
"""
from fastapi import APIRouter, HTTPException
from models.requests import ReferenceUploadRequest
from models.responses import ReferenceUploadResponse, ErrorResponse
from services.whisk_client import WhiskClient
import json
router = APIRouter(tags=["References"])
@router.post(
"/references/upload",
response_model=ReferenceUploadResponse,
responses={
400: {"model": ErrorResponse},
401: {"model": ErrorResponse},
500: {"model": ErrorResponse}
}
)
async def upload_reference(request: ReferenceUploadRequest):
"""
Upload a reference image for Whisk generation.
- **imageBase64**: Base64 encoded image data
- **mimeType**: Image MIME type (image/jpeg, image/png, image/webp, image/gif)
- **category**: Reference category (subject, scene, style)
- **cookies**: Whisk authentication cookies
"""
# Validate MIME type
allowed_types = ['image/jpeg', 'image/png', 'image/webp', 'image/gif']
if request.mimeType not in allowed_types:
raise HTTPException(
status_code=400,
detail=f"Unsupported file type: {request.mimeType}. Please use JPG, PNG, or WEBP."
)
# Normalize cookies
valid_cookies = request.cookies.strip()
is_json = False
trimmed = valid_cookies.strip()
if trimmed.startswith('[') or trimmed.startswith('{'):
is_json = True
try:
cookie_array = json.loads(trimmed)
if isinstance(cookie_array, list):
valid_cookies = "; ".join(
f"{c['name']}={c['value']}" for c in cookie_array
)
print(f"[API] Successfully parsed {len(cookie_array)} cookies from JSON.")
elif isinstance(cookie_array, dict) and 'name' in cookie_array and 'value' in cookie_array:
valid_cookies = f"{cookie_array['name']}={cookie_array['value']}"
except Exception as e:
print(f"[API] Failed to parse cookie JSON, falling back to raw value: {e}")
# Validate cookie format
if '=' not in valid_cookies:
raise HTTPException(
status_code=400,
detail='Invalid Cookie Format. Cookies must be in "name=value" format or a JSON list.'
)
print(f"[API] Uploading reference image ({request.category}, {request.mimeType})...")
print(f"[API] Using cookies (first 100 chars): {valid_cookies[:100]}...")
print(f"[API] Cookie was JSON: {is_json}")
try:
client = WhiskClient(valid_cookies)
# Remove data URI header if present
raw_base64 = request.imageBase64
if raw_base64.startswith('data:'):
raw_base64 = raw_base64.split(',', 1)[1] if ',' in raw_base64 else raw_base64
media_id = await client.upload_reference_image(
raw_base64,
request.mimeType,
request.category
)
if not media_id:
raise HTTPException(status_code=500, detail="Upload returned no ID")
return ReferenceUploadResponse(success=True, id=media_id)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
print(f"Reference Upload API failed: {e}")
raise HTTPException(status_code=500, detail=str(e))