121 lines
4.2 KiB
Python
121 lines
4.2 KiB
Python
|
|
import asyncio
|
||
|
|
import logging
|
||
|
|
from datetime import datetime, timezone
|
||
|
|
|
||
|
|
from fastapi import APIRouter, HTTPException, Query
|
||
|
|
|
||
|
|
from app.schemas.common import TaskDetail, TaskResponse, TaskStatus
|
||
|
|
from app.schemas.image_editing import (
|
||
|
|
ExpandRequest,
|
||
|
|
InpaintRequest,
|
||
|
|
RelightRequest,
|
||
|
|
StyleTransferRequest,
|
||
|
|
UpscaleCreativeRequest,
|
||
|
|
UpscalePrecisionRequest,
|
||
|
|
)
|
||
|
|
from app.services import freepik_client, task_tracker
|
||
|
|
|
||
|
|
logger = logging.getLogger(__name__)
|
||
|
|
|
||
|
|
router = APIRouter(prefix='/api/v1/edit', tags=['image-editing'])
|
||
|
|
|
||
|
|
|
||
|
|
async def _submit_and_respond(result: dict, sync: bool, metadata: dict) -> TaskResponse | TaskDetail:
|
||
|
|
data = result.get('data', result)
|
||
|
|
freepik_task_id = str(data.get('task_id') or data.get('id', ''))
|
||
|
|
if not freepik_task_id:
|
||
|
|
raise HTTPException(status_code=502, detail='No task_id in Freepik response')
|
||
|
|
|
||
|
|
internal_id = task_tracker.submit(freepik_task_id, metadata)
|
||
|
|
|
||
|
|
if not sync:
|
||
|
|
return TaskResponse(
|
||
|
|
task_id=internal_id,
|
||
|
|
status=TaskStatus.pending,
|
||
|
|
created_at=datetime.now(timezone.utc),
|
||
|
|
)
|
||
|
|
|
||
|
|
from app.config import settings
|
||
|
|
elapsed = 0
|
||
|
|
while elapsed < settings.task_poll_timeout_seconds:
|
||
|
|
await asyncio.sleep(2)
|
||
|
|
elapsed += 2
|
||
|
|
task = task_tracker.get_task(internal_id)
|
||
|
|
if not task:
|
||
|
|
raise HTTPException(status_code=500, detail='Task disappeared')
|
||
|
|
if task['status'] == TaskStatus.completed:
|
||
|
|
return TaskDetail(
|
||
|
|
task_id=internal_id,
|
||
|
|
status=TaskStatus.completed,
|
||
|
|
created_at=task['created_at'],
|
||
|
|
updated_at=task['updated_at'],
|
||
|
|
progress=1.0,
|
||
|
|
result_url=f'/api/v1/tasks/{internal_id}/result',
|
||
|
|
)
|
||
|
|
if task['status'] == TaskStatus.failed:
|
||
|
|
raise HTTPException(status_code=502, detail=task.get('error', 'Task failed'))
|
||
|
|
|
||
|
|
raise HTTPException(status_code=504, detail='Task did not complete in time')
|
||
|
|
|
||
|
|
|
||
|
|
@router.post('/upscale/creative', response_model=TaskResponse)
|
||
|
|
async def upscale_creative(request: UpscaleCreativeRequest, sync: bool = Query(False)):
|
||
|
|
result = await freepik_client.upscale_creative(
|
||
|
|
image=request.image,
|
||
|
|
prompt=request.prompt,
|
||
|
|
scale=request.scale,
|
||
|
|
creativity=request.creativity,
|
||
|
|
resemblance=request.resemblance,
|
||
|
|
)
|
||
|
|
return await _submit_and_respond(result, sync, {'operation': 'upscale-creative'})
|
||
|
|
|
||
|
|
|
||
|
|
@router.post('/upscale/precision', response_model=TaskResponse)
|
||
|
|
async def upscale_precision(request: UpscalePrecisionRequest, sync: bool = Query(False)):
|
||
|
|
result = await freepik_client.upscale_precision(
|
||
|
|
image=request.image,
|
||
|
|
scale=request.scale,
|
||
|
|
)
|
||
|
|
return await _submit_and_respond(result, sync, {'operation': 'upscale-precision'})
|
||
|
|
|
||
|
|
|
||
|
|
@router.post('/relight', response_model=TaskResponse)
|
||
|
|
async def relight(request: RelightRequest, sync: bool = Query(False)):
|
||
|
|
result = await freepik_client.relight_image(
|
||
|
|
image=request.image,
|
||
|
|
prompt=request.prompt,
|
||
|
|
light_source=request.light_source,
|
||
|
|
intensity=request.intensity,
|
||
|
|
)
|
||
|
|
return await _submit_and_respond(result, sync, {'operation': 'relight'})
|
||
|
|
|
||
|
|
|
||
|
|
@router.post('/style-transfer', response_model=TaskResponse)
|
||
|
|
async def style_transfer(request: StyleTransferRequest, sync: bool = Query(False)):
|
||
|
|
result = await freepik_client.style_transfer(
|
||
|
|
image=request.image,
|
||
|
|
style_reference=request.style_reference,
|
||
|
|
strength=request.strength,
|
||
|
|
)
|
||
|
|
return await _submit_and_respond(result, sync, {'operation': 'style-transfer'})
|
||
|
|
|
||
|
|
|
||
|
|
@router.post('/expand', response_model=TaskResponse)
|
||
|
|
async def expand(request: ExpandRequest, sync: bool = Query(False)):
|
||
|
|
result = await freepik_client.expand_image(
|
||
|
|
image=request.image,
|
||
|
|
prompt=request.prompt,
|
||
|
|
direction=request.direction,
|
||
|
|
)
|
||
|
|
return await _submit_and_respond(result, sync, {'operation': 'expand'})
|
||
|
|
|
||
|
|
|
||
|
|
@router.post('/inpaint', response_model=TaskResponse)
|
||
|
|
async def inpaint(request: InpaintRequest, sync: bool = Query(False)):
|
||
|
|
result = await freepik_client.inpaint(
|
||
|
|
image=request.image,
|
||
|
|
mask=request.mask,
|
||
|
|
prompt=request.prompt,
|
||
|
|
)
|
||
|
|
return await _submit_and_respond(result, sync, {'operation': 'inpaint'})
|