@@ -30,11 +30,7 @@ async def _wait_task_and_stream_result(task_id: str, timeout_seconds: int, poll_
3030 if status == TaskStatus .COMPLETED .value :
3131 result_png = task_manager .get_task_result_png (task_id )
3232 if result_png :
33- return Response (
34- content = result_png ,
35- media_type = "image/png" ,
36- headers = {"Content-Disposition" : 'inline; filename="result.png"' },
37- )
33+ return result_png
3834 raise HTTPException (status_code = 500 , detail = f"Task completed but no in-memory image found: { task_id } " )
3935
4036 if status == TaskStatus .FAILED .value :
@@ -50,6 +46,39 @@ async def _wait_task_and_stream_result(task_id: str, timeout_seconds: int, poll_
5046 await asyncio .sleep (poll_interval_seconds )
5147
5248
49+ def _build_png_response (result_png : bytes ) -> Response :
50+ return Response (
51+ content = result_png ,
52+ media_type = "image/png" ,
53+ headers = {"Content-Disposition" : 'inline; filename="result.png"' },
54+ )
55+
56+
57+ async def _upload_sync_result_if_needed (message : ImageTaskRequest , result_png : bytes ):
58+ presigned_url = (getattr (message , "presigned_url" , "" ) or "" ).strip ()
59+ if not presigned_url :
60+ return None
61+
62+ services = get_services ()
63+ assert services .file_service is not None , "File service is not initialized"
64+
65+ try :
66+ await services .file_service .upload_to_presigned_url (
67+ presigned_url = presigned_url ,
68+ file_content = result_png ,
69+ content_type = "image/png" ,
70+ )
71+ except ValueError as e :
72+ raise HTTPException (status_code = 502 , detail = f"Failed to upload sync result to presigned URL: { str (e )} " )
73+
74+ return {
75+ "task_id" : message .task_id ,
76+ "task_status" : "completed" ,
77+ "uploaded_to_presigned_url" : True ,
78+ "presigned_url" : presigned_url ,
79+ }
80+
81+
5382async def _watch_client_disconnect (request : Request , task_id : str , poll_interval_seconds : float = 0.2 ) -> bool :
5483 while True :
5584 if await request .is_disconnected ():
@@ -105,6 +134,9 @@ async def create_image_task_sync(
105134 if hasattr (message , "image_mask_path" ) and message .image_mask_path and message .image_mask_path .startswith ("http" ):
106135 if not await validate_url_async (message .image_mask_path ):
107136 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 } " )
108140
109141 message .prefer_memory_result = True
110142 task_id = task_manager .create_task (message )
@@ -124,7 +156,11 @@ async def create_image_task_sync(
124156 await asyncio .gather (wait_task , return_exceptions = True )
125157 raise HTTPException (status_code = 499 , detail = f"Client disconnected, task { task_id } cancelled" )
126158
127- return wait_task .result ()
159+ result_png = wait_task .result ()
160+ upload_result = await _upload_sync_result_if_needed (message , result_png )
161+ if upload_result is not None :
162+ return upload_result
163+ return _build_png_response (result_png )
128164
129165 except asyncio .CancelledError :
130166 if task_id :
0 commit comments