(
request: Request,
message: ImageTaskRequest,
timeout_seconds: int = 600,
poll_interval_seconds: float = 0.5,
)
| 122 | poll_interval_seconds: float = 0.5, |
| 123 | ): |
| 124 | if timeout_seconds <= 0: |
| 125 | raise HTTPException(status_code=400, detail="timeout_seconds must be > 0") |
| 126 | if poll_interval_seconds <= 0: |
| 127 | raise HTTPException(status_code=400, detail="poll_interval_seconds must be > 0") |
| 128 | |
| 129 | task_id = None |
| 130 | try: |
| 131 | if hasattr(message, "image_path") and message.image_path and message.image_path.startswith("http"): |
| 132 | if not await validate_url_async(message.image_path): |
| 133 | raise HTTPException(status_code=400, detail=f"Image URL is not accessible: {message.image_path}") |
| 134 | if hasattr(message, "image_mask_path") and message.image_mask_path and message.image_mask_path.startswith("http"): |
| 135 | if not await validate_url_async(message.image_mask_path): |
| 136 | raise HTTPException(status_code=400, detail=f"Image mask URL is not accessible: {message.image_mask_path}") |
| 137 | if hasattr(message, "presigned_url") and message.presigned_url: |
| 138 | if not message.presigned_url.startswith(("http://", "https://")): |
| 139 | raise HTTPException(status_code=400, detail=f"Invalid presigned_url: {message.presigned_url}") |
| 140 | |
| 141 | message._prefer_memory_result = True |
| 142 | task_id = task_manager.create_task(message) |
| 143 | message.task_id = task_id |
| 144 | |
| 145 | wait_task = asyncio.create_task(_wait_task_and_stream_result(task_id, timeout_seconds, poll_interval_seconds)) |
| 146 | disconnect_task = asyncio.create_task(_watch_client_disconnect(request, task_id)) |
| 147 | |
| 148 | done, pending = await asyncio.wait({wait_task, disconnect_task}, return_when=asyncio.FIRST_COMPLETED) |
| 149 | for pending_task in pending: |
| 150 | pending_task.cancel() |
| 151 | |
| 152 | if disconnect_task in done: |
| 153 | if not wait_task.done(): |
| 154 | wait_task.cancel() |
| 155 | raise HTTPException(status_code=499, detail=f"Client disconnected, task {task_id} cancelled") |
| 156 | |
| 157 | result_png = wait_task.result() |
| 158 | upload_result = await _upload_sync_result_if_needed(message, result_png) |
| 159 | if upload_result is not None: |
| 160 | return upload_result |
| 161 | return _build_png_response(result_png) |
| 162 | |
| 163 | except asyncio.CancelledError: |
| 164 | if task_id: |
| 165 | task_manager.cancel_task(task_id) |
| 166 | raise |
| 167 | |
| 168 | except RuntimeError as e: |
| 169 | if getattr(e, "original_error_type", "") == "ValueError": |
| 170 | raise HTTPException(status_code=413, detail=str(e)) |
| 171 | raise HTTPException(status_code=503, detail=str(e)) |
| 172 | except HTTPException: |
| 173 | raise |
| 174 | except Exception as e: |
| 175 | logger.error(f"Failed to run sync image task: {e}") |
| 176 | raise HTTPException(status_code=500, detail=str(e)) |
| 177 | |
| 178 | |
| 179 | @router.post("/form", response_model=TaskResponse) |
| 180 | async def create_image_task_form( |
| 181 | request: Request, |
nothing calls this directly
no test coverage detected