1010from typing import Optional
1111
1212from urllib .parse import quote
13+ import aiohttp
1314import requests
1415from fastapi import APIRouter , Depends , HTTPException , Request , UploadFile
1516from fastapi .responses import FileResponse
2122)
2223from open_webui .constants import ERROR_MESSAGES
2324from open_webui .retrieval .web .utils import validate_url
24- from open_webui .env import ENABLE_FORWARD_USER_INFO_HEADERS
25+ from open_webui .env import AIOHTTP_CLIENT_SESSION_SSL , ENABLE_FORWARD_USER_INFO_HEADERS
26+ from open_webui .utils .session_pool import get_session
2527
2628from open_webui .models .chats import Chats
2729from open_webui .routers .files import upload_file_handler , get_file_content_by_id
@@ -313,12 +315,14 @@ def get_automatic1111_api_auth(request: Request):
313315async def verify_url (request : Request , user = Depends (get_admin_user )):
314316 if request .app .state .config .IMAGE_GENERATION_ENGINE == 'automatic1111' :
315317 try :
316- r = requests .get (
318+ session = await get_session ()
319+ async with session .get (
317320 url = f'{ request .app .state .config .AUTOMATIC1111_BASE_URL } /sdapi/v1/options' ,
318321 headers = {'authorization' : get_automatic1111_api_auth (request )},
319- )
320- r .raise_for_status ()
321- return True
322+ ssl = AIOHTTP_CLIENT_SESSION_SSL ,
323+ ) as r :
324+ r .raise_for_status ()
325+ return True
322326 except Exception :
323327 request .app .state .config .ENABLE_IMAGE_GENERATION = False
324328 raise HTTPException (status_code = 400 , detail = ERROR_MESSAGES .INVALID_URL )
@@ -327,12 +331,14 @@ async def verify_url(request: Request, user=Depends(get_admin_user)):
327331 if request .app .state .config .COMFYUI_API_KEY :
328332 headers = {'Authorization' : f'Bearer { request .app .state .config .COMFYUI_API_KEY } ' }
329333 try :
330- r = requests .get (
334+ session = await get_session ()
335+ async with session .get (
331336 url = f'{ request .app .state .config .COMFYUI_BASE_URL } /object_info' ,
332337 headers = headers ,
333- )
334- r .raise_for_status ()
335- return True
338+ ssl = AIOHTTP_CLIENT_SESSION_SSL ,
339+ ) as r :
340+ r .raise_for_status ()
341+ return True
336342 except Exception :
337343 request .app .state .config .ENABLE_IMAGE_GENERATION = False
338344 raise HTTPException (status_code = 400 , detail = ERROR_MESSAGES .INVALID_URL )
@@ -357,11 +363,13 @@ async def get_models(request: Request, user=Depends(get_verified_user)):
357363 elif request .app .state .config .IMAGE_GENERATION_ENGINE == 'comfyui' :
358364 # TODO - get models from comfyui
359365 headers = {'Authorization' : f'Bearer { request .app .state .config .COMFYUI_API_KEY } ' }
360- r = requests .get (
366+ session = await get_session ()
367+ async with session .get (
361368 url = f'{ request .app .state .config .COMFYUI_BASE_URL } /object_info' ,
362369 headers = headers ,
363- )
364- info = r .json ()
370+ ssl = AIOHTTP_CLIENT_SESSION_SSL ,
371+ ) as r :
372+ info = await r .json ()
365373
366374 workflow = json .loads (request .app .state .config .COMFYUI_WORKFLOW )
367375 model_node_id = None
@@ -399,11 +407,13 @@ async def get_models(request: Request, user=Depends(get_verified_user)):
399407 request .app .state .config .IMAGE_GENERATION_ENGINE == 'automatic1111'
400408 or request .app .state .config .IMAGE_GENERATION_ENGINE == ''
401409 ):
402- r = requests .get (
410+ session = await get_session ()
411+ async with session .get (
403412 url = f'{ request .app .state .config .AUTOMATIC1111_BASE_URL } /sdapi/v1/sd-models' ,
404413 headers = {'authorization' : get_automatic1111_api_auth (request )},
405- )
406- models = r .json ()
414+ ssl = AIOHTTP_CLIENT_SESSION_SSL ,
415+ ) as r :
416+ models = await r .json ()
407417 return list (
408418 map (
409419 lambda model : {'id' : model ['title' ], 'name' : model ['model_name' ]},
@@ -533,7 +543,7 @@ async def image_generations(
533543
534544 model = get_image_model (request )
535545
536- r = None
546+
537547 try :
538548 if request .app .state .config .IMAGE_GENERATION_ENGINE == 'openai' :
539549 headers = {
@@ -568,16 +578,15 @@ async def image_generations(
568578 ),
569579 }
570580
571- # Use asyncio.to_thread for the requests.post call
572- r = await asyncio .to_thread (
573- requests .post ,
581+ session = await get_session ()
582+ async with session .post (
574583 url = url ,
575584 json = data ,
576585 headers = headers ,
577- )
578-
579- r .raise_for_status ()
580- res = r .json ()
586+ ssl = AIOHTTP_CLIENT_SESSION_SSL ,
587+ ) as r :
588+ r .raise_for_status ()
589+ res = await r .json ()
581590
582591 images = []
583592
@@ -619,16 +628,15 @@ async def image_generations(
619628 model = f'{ model } :generateContent'
620629 data = {'contents' : [{'parts' : [{'text' : form_data .prompt }]}]}
621630
622- # Use asyncio.to_thread for the requests.post call
623- r = await asyncio .to_thread (
624- requests .post ,
631+ session = await get_session ()
632+ async with session .post (
625633 url = f'{ request .app .state .config .IMAGES_GEMINI_API_BASE_URL } /models/{ model } ' ,
626634 json = data ,
627635 headers = headers ,
628- )
629-
630- r .raise_for_status ()
631- res = r .json ()
636+ ssl = AIOHTTP_CLIENT_SESSION_SSL ,
637+ ) as r :
638+ r .raise_for_status ()
639+ res = await r .json ()
632640
633641 images = []
634642
@@ -727,15 +735,14 @@ async def image_generations(
727735 if request .app .state .config .AUTOMATIC1111_PARAMS :
728736 data = {** data , ** request .app .state .config .AUTOMATIC1111_PARAMS }
729737
730- # Use asyncio.to_thread for the requests.post call
731- r = await asyncio .to_thread (
732- requests .post ,
738+ session = await get_session ()
739+ async with session .post (
733740 url = f'{ request .app .state .config .AUTOMATIC1111_BASE_URL } /sdapi/v1/txt2img' ,
734741 json = data ,
735742 headers = {'authorization' : get_automatic1111_api_auth (request )},
736- )
737-
738- res = r .json ()
743+ ssl = AIOHTTP_CLIENT_SESSION_SSL ,
744+ ) as r :
745+ res = await r .json ()
739746 log .debug (f'res: { res } ' )
740747
741748 images = []
@@ -753,10 +760,8 @@ async def image_generations(
753760 return images
754761 except Exception as e :
755762 error = e
756- if r != None :
757- data = r .json ()
758- if 'error' in data :
759- error = data ['error' ]['message' ]
763+ if isinstance (e , aiohttp .ClientResponseError ):
764+ error = e .message
760765 raise HTTPException (status_code = 400 , detail = ERROR_MESSAGES .DEFAULT (error ))
761766
762767
@@ -798,11 +803,12 @@ async def load_url_image(data):
798803 if data .startswith ('http://' ) or data .startswith ('https://' ):
799804 # Validate URL to prevent SSRF attacks against local/private networks
800805 validate_url (data )
801- r = await asyncio .to_thread (requests .get , data )
802- r .raise_for_status ()
806+ session = await get_session ()
807+ async with session .get (data , ssl = AIOHTTP_CLIENT_SESSION_SSL ) as r :
808+ r .raise_for_status ()
803809
804- image_data = base64 .b64encode (r . content ).decode ('utf-8' )
805- return f'data:{ r .headers ["content-type" ]} ;base64,{ image_data } '
810+ image_data = base64 .b64encode (await r . read () ).decode ('utf-8' )
811+ return f'data:{ r .headers ["content-type" ]} ;base64,{ image_data } '
806812
807813 else :
808814 file_id = None
@@ -846,7 +852,7 @@ def get_image_file_item(base64_string, param_name='image'):
846852 ),
847853 )
848854
849- r = None
855+
850856 try :
851857 if request .app .state .config .IMAGE_EDIT_ENGINE == 'openai' :
852858 headers = {
@@ -883,17 +889,30 @@ def get_image_file_item(base64_string, param_name='image'):
883889 if request .app .state .config .IMAGES_EDIT_OPENAI_API_VERSION :
884890 url_search_params += f'?api-version={ request .app .state .config .IMAGES_EDIT_OPENAI_API_VERSION } '
885891
886- # Use asyncio.to_thread for the requests.post call
887- r = await asyncio .to_thread (
888- requests .post ,
892+ # Build multipart form data for aiohttp
893+ form = aiohttp .FormData ()
894+ for key , value in data .items ():
895+ if isinstance (value , dict ):
896+ form .add_field (key , json .dumps (value ))
897+ else :
898+ form .add_field (key , str (value ))
899+ for param_name , (filename , file_obj , content_type_val ) in files :
900+ form .add_field (
901+ param_name ,
902+ file_obj ,
903+ filename = filename ,
904+ content_type = content_type_val ,
905+ )
906+
907+ session = await get_session ()
908+ async with session .post (
889909 url = f'{ request .app .state .config .IMAGES_EDIT_OPENAI_API_BASE_URL } /images/edits{ url_search_params } ' ,
890910 headers = headers ,
891- files = files ,
892- data = data ,
893- )
894-
895- r .raise_for_status ()
896- res = r .json ()
911+ data = form ,
912+ ssl = AIOHTTP_CLIENT_SESSION_SSL ,
913+ ) as r :
914+ r .raise_for_status ()
915+ res = await r .json ()
897916
898917 images = []
899918 for image in res ['data' ]:
@@ -940,16 +959,15 @@ def get_image_file_item(base64_string, param_name='image'):
940959 ]
941960 )
942961
943- # Use asyncio.to_thread for the requests.post call
944- r = await asyncio .to_thread (
945- requests .post ,
962+ session = await get_session ()
963+ async with session .post (
946964 url = f'{ request .app .state .config .IMAGES_EDIT_GEMINI_API_BASE_URL } /models/{ model } ' ,
947965 json = data ,
948966 headers = headers ,
949- )
950-
951- r .raise_for_status ()
952- res = r .json ()
967+ ssl = AIOHTTP_CLIENT_SESSION_SSL ,
968+ ) as r :
969+ r .raise_for_status ()
970+ res = await r .json ()
953971
954972 images = []
955973 for image in res ['candidates' ]:
@@ -1048,13 +1066,7 @@ def get_image_file_item(base64_string, param_name='image'):
10481066 return images
10491067 except Exception as e :
10501068 error = e
1051- if r != None :
1052- data = r .text
1053- try :
1054- data = json .loads (data )
1055- if 'error' in data :
1056- error = data ['error' ]['message' ]
1057- except Exception :
1058- error = data
1069+ if isinstance (e , aiohttp .ClientResponseError ):
1070+ error = e .message
10591071
10601072 raise HTTPException (status_code = 400 , detail = ERROR_MESSAGES .DEFAULT (error ))
0 commit comments