Your task is to review pull requests. Instructions:
- Provide the response in following JSON format: {"reviews": [{"line": <line_number>, "body": "<review comment>"}]}
- Do not give positive comments or compliments.
- Provide comments and suggestions ONLY if there is something to improve, otherwise "reviews" should be an empty array.
- Write the comment in GitHub Markdown format.
- Use the given description only for the overall context and only comment the code.
- IMPORTANT: NEVER suggest adding comments to the code.

Review the following code diff in the file "g4f/gui/server/api.py" and take the pull request title and description into account when writing the response.
  
Pull request title: [pull] main from xtekky:main
Pull request description:
---
See [Commits](/Martintianzy/gpt4free/pull/130/commits) and [Changes](/Martintianzy/gpt4free/pull/130/files) for more details.

-----
Created by [<img src="https://prod.download/pull-18h-svg" valign="bottom"/> **pull[bot]**](https://github.com/wei/pull)

_Can you help keep this open source service alive? **[💖 Please sponsor : )](https://prod.download/pull-pr-sponsor)**_
---

Each line is prefixed by its number. Code to review:
```
2: 
3: import logging
4: import os
-import os.path
5: import uuid
6: import asyncio
7: import time
8: from aiohttp import ClientSession
-from typing import Iterator, Optional
9:+from typing import Iterator, Optional, AsyncIterator, Union
10: from flask import send_from_directory
11: 
12: from g4f import version, models
19: from g4f.providers.base_provider import ProviderModelMixin, FinishReason
20: from g4f.providers.conversation import BaseConversation
21: 
-conversations: dict[dict[str, BaseConversation]] = {}
22:+logger = logging.getLogger(__name__)
23:+
24:+# Define the directory for generated images
25: images_dir = "./generated_images"
26: 
27:+# Function to ensure the images directory exists
28:+def ensure_images_dir():
29:+    if not os.path.exists(images_dir):
30:+        os.makedirs(images_dir)
31:+
32:+conversations: dict[dict[str, BaseConversation]] = {}
33:+
34: 
35: class Api:
36:     @staticmethod
37:     def get_models() -> list[str]:
-        """
-        Return a list of all models.
-
-        Fetches and returns a list of all available models in the system.
-
-        Returns:
-            List[str]: A list of model names.
-        """
38:         return models._all_models
39: 
40:     @staticmethod
82: 
83:     @staticmethod
84:     def get_providers() -> list[str]:
-        """
-        Return a list of all working providers.
-        """
85:         return {
86:             provider.__name__: (
87:                 provider.label if hasattr(provider, "label") else provider.__name__
96: 
97:     @staticmethod
98:     def get_version():
-        """
-        Returns the current and latest version of the application.
-
-        Returns:
-            dict: A dictionary containing the current and latest version.
-        """
99:         try:
100:             current_version = version.utils.current_version
101:         except VersionNotFoundError:
106:         }
107: 
108:     def serve_images(self, name):
109:+        ensure_images_dir()
110:         return send_from_directory(os.path.abspath(images_dir), name)
111: 
112:     def _prepare_conversation_kwargs(self, json_data: dict, kwargs: dict):
-        """
-        Prepares arguments for chat completion based on the request data.
-
-        Reads the request and prepares the necessary arguments for handling 
-        a chat completion request.
-
-        Returns:
-            dict: Arguments prepared for chat completion.
-        """
113:         model = json_data.get('model') or models.default
114:         provider = json_data.get('provider')
115:         messages = json_data['messages']
117:         if api_key is not None:
118:             kwargs["api_key"] = api_key
119:         if json_data.get('web_search'):
-            if provider in ("Bing", "HuggingChat"):
120:+            if provider:
121:                 kwargs['web_search'] = True
122:             else:
123:                 from .internet import get_search_message
142:             result = ChatCompletion.create(**kwargs)
143:             first = True
144:             if isinstance(result, ImageResponse):
-                # Якщо результат є ImageResponse, обробляємо його як одиночний елемент
145:                 if first:
146:                     first = False
147:                     yield self._format_json("provider", get_last_provider(True))
148:                 yield self._format_json("content", str(result))
149:             else:
-                # Якщо результат є ітерабельним, обробляємо його як раніше
150:                 for chunk in result:
151:                     if first:
152:                         first = False
157:                         conversations[provider][conversation_id] = chunk
158:                         yield self._format_json("conversation", conversation_id)
159:                     elif isinstance(chunk, Exception):
-                        logging.exception(chunk)
160:+                        logger.exception(chunk)
161:                         yield self._format_json("message", get_error_message(chunk))
162:                     elif isinstance(chunk, ImagePreview):
163:                         yield self._format_json("preview", chunk.to_string())
164:                     elif isinstance(chunk, ImageResponse):
-                        # Обробка ImageResponse
165:                         images = asyncio.run(self._copy_images(chunk.get_list(), chunk.options.get("cookies")))
166:                         yield self._format_json("content", str(ImageResponse(images, chunk.alt)))
167:                     elif not isinstance(chunk, FinishReason):
168:                         yield self._format_json("content", str(chunk))
169:         except Exception as e:
-            logging.exception(e)
170:+            logger.exception(e)
171:             yield self._format_json('error', get_error_message(e))
172: 
-    # Додайте цей метод до класу Api
173:     async def _copy_images(self, images: list[str], cookies: Optional[Cookies] = None):
174:+        ensure_images_dir()
175:         async with ClientSession(
176:             connector=get_connector(None, os.environ.get("G4F_PROXY")),
177:             cookies=cookies
192:             return await asyncio.gather(*[copy_image(image) for image in images])
193: 
194:     def _format_json(self, response_type: str, content):
-        """
-        Formats and returns a JSON response.
-
-        Args:
-            response_type (str): The type of the response.
-            content: The content to be included in the response.
-
-        Returns:
-            str: A JSON formatted string.
-        """
195:         return {
196:             'type': response_type,
197:             response_type: content
199: 
200: 
201: def get_error_message(exception: Exception) -> str:
-    """
-    Generates a formatted error message from an exception.
-
-    Args:
-        exception (Exception): The exception to format.
-
-    Returns:
-        str: A formatted error message string.
-    """
202:     message = f"{type(exception).__name__}: {exception}"
203:     provider = get_last_provider()
204:     if provider is None:
```