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/api/__init__.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 and Changes 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:
```
14: from fastapi.encoders import jsonable_encoder
15: from fastapi.middleware.cors import CORSMiddleware
16: from pydantic import BaseModel
-from typing import Union, Optional
17:+from typing import Union, Optional, Iterator
18: 
19: import g4f
20: import g4f.debug
-from g4f.client import Client
21:+from g4f.client import Client, ChatCompletion, ChatCompletionChunk, ImagesResponse
22: from g4f.typing import Messages
23: from g4f.cookies import read_cookie_files
24: 
-def create_app():
25:+def create_app(g4f_api_key: str = None):
26:     app = FastAPI()
-    api = Api(app)
27:+
28:+    # Add CORS middleware
29:     app.add_middleware(
30:         CORSMiddleware,
31:         allow_origin_regex=".*",
33:         allow_methods=["*"],
34:         allow_headers=["*"],
35:     )
36:+
37:+    api = Api(app, g4f_api_key=g4f_api_key)
38:     api.register_routes()
39:     api.register_authorization()
40:     api.register_validation_exception_handler()
41:+
42:+    # Read cookie files if not ignored
43:     if not AppConfig.ignore_cookie_files:
44:         read_cookie_files()
-    return app
45: 
-def create_app_debug():
-    g4f.debug.logging = True
-    return create_app()
46:+    return app
47: 
-class ChatCompletionsForm(BaseModel):
48:+class ChatCompletionsConfig(BaseModel):
49:     messages: Messages
50:     model: str
51:     provider: Optional[str] = None
57:     web_search: Optional[bool] = None
58:     proxy: Optional[str] = None
59: 
-class ImagesGenerateForm(BaseModel):
-    model: Optional[str] = None
-    provider: Optional[str] = None
60:+class ImageGenerationConfig(BaseModel):
61:     prompt: str
-    response_format: Optional[str] = None
-    api_key: Optional[str] = None
-    proxy: Optional[str] = None
62:+    model: Optional[str] = None
63:+    response_format: str = "url"
64: 
-class AppConfig():
65:+class AppConfig:
66:     ignored_providers: Optional[list[str]] = None
67:     g4f_api_key: Optional[str] = None
68:     ignore_cookie_files: bool = False
73:         for key, value in data.items():
74:             setattr(cls, key, value)
75: 
76:+list_ignored_providers: list[str] = None
77:+
78:+def set_list_ignored_providers(ignored: list[str]):
79:+    global list_ignored_providers
80:+    list_ignored_providers = ignored
81:+
82: class Api:
-    def __init__(self, app: FastAPI) -> None:
83:+    def __init__(self, app: FastAPI, g4f_api_key=None) -> None:
84:         self.app = app
85:         self.client = Client()
86:+        self.g4f_api_key = g4f_api_key
87:         self.get_g4f_api_key = APIKeyHeader(name="g4f-api-key")
88: 
89:     def register_authorization(self):
90:         @self.app.middleware("http")
91:         async def authorization(request: Request, call_next):
-            if AppConfig.g4f_api_key and request.url.path in ["/v1/chat/completions", "/v1/completions"]:
92:+            if self.g4f_api_key and request.url.path in ["/v1/chat/completions", "/v1/completions", "/v1/images/generate"]:
93:                 try:
94:                     user_g4f_api_key = await self.get_g4f_api_key(request)
95:                 except HTTPException as e:
98:                             status_code=HTTP_401_UNAUTHORIZED,
99:                             content=jsonable_encoder({"detail": "G4F API key required"}),
100:                         )
-                if not secrets.compare_digest(AppConfig.g4f_api_key, user_g4f_api_key):
101:+                if not secrets.compare_digest(self.g4f_api_key, user_g4f_api_key):
102:                     return JSONResponse(
103:                         status_code=HTTP_403_FORBIDDEN,
104:                         content=jsonable_encoder({"detail": "Invalid G4F API key"}),
105:                     )
-            return await call_next(request)
106:+
107:+            response = await call_next(request)
108:+            return response
109: 
110:     def register_validation_exception_handler(self):
111:         @self.app.exception_handler(RequestValidationError)
112:         async def validation_exception_handler(request: Request, exc: RequestValidationError):
113:             details = exc.errors()
-            modified_details = [{
-                "loc": error["loc"],
-                "message": error["msg"],
-                "type": error["type"],
-            } for error in details]
114:+            modified_details = []
115:+            for error in details:
116:+                modified_details.append({
117:+                    "loc": error["loc"],
118:+                    "message": error["msg"],
119:+                    "type": error["type"],
120:+                })
121:             return JSONResponse(
122:                 status_code=HTTP_422_UNPROCESSABLE_ENTITY,
123:                 content=jsonable_encoder({"detail": modified_details}),
131:         @self.app.get("/v1")
132:         async def read_root_v1():
133:             return HTMLResponse('g4f API: Go to '
-                                '<a href="/v1/chat/completions">chat/completions</a> '
-                                'or <a href="/v1/models">models</a>.')
134:+                                '<a href="/v1/chat/completions">chat/completions</a>, '
135:+                                '<a href="/v1/models">models</a>, or '
136:+                                '<a href="/v1/images/generate">images/generate</a>.')
137: 
138:         @self.app.get("/v1/models")
139:         async def models():
-            model_list = {
-                model: g4f.models.ModelUtils.convert[model]
140:+            model_list = dict(
141:+                (model, g4f.models.ModelUtils.convert[model])
142:                 for model in g4f.Model.__all__()
-            }
143:+            )
144:             model_list = [{
145:                 'id': model_id,
146:                 'object': 'model',
147:                 'created': 0,
148:                 'owned_by': model.base_provider
149:             } for model_id, model in model_list.items()]
-            return JSONResponse({
-                "object": "list",
-                "data": model_list,
-            })
150:+            return JSONResponse(model_list)
151: 
152:         @self.app.get("/v1/models/{model_name}")
153:         async def model_info(model_name: str):
163:                 return JSONResponse({"error": "The model does not exist."})
164: 
165:         @self.app.post("/v1/chat/completions")
-        async def chat_completions(config: ChatCompletionsForm, request: Request = None, provider: str = None):
166:+        async def chat_completions(config: ChatCompletionsConfig, request: Request = None, provider: str = None):
167:             try:
168:                 config.provider = provider if config.provider is None else config.provider
169:                 if config.api_key is None and request is not None:
172:                         auth_header = auth_header.split(None, 1)[-1]
173:                         if auth_header and auth_header != "Bearer":
174:                             config.api_key = auth_header
-                # Use the asynchronous create method and await it
-                response = await self.client.chat.completions.async_create(
175:+
176:+                # Create the completion response
177:+                response = self.client.chat.completions.create(
178:                     **{
179:                         **AppConfig.defaults,
180:                         **config.dict(exclude_none=True),
181:                     },
182:                     ignored=AppConfig.ignored_providers
183:                 )
-                if not config.stream:
184:+
185:+                # Check if the response is synchronous or asynchronous
186:+                if isinstance(response, ChatCompletion):
187:+                    # Synchronous response
188:                     return JSONResponse(response.to_json())
189: 
190:+                if not config.stream:
191:+                    # If the response is an iterator but not streaming, collect the result
192:+                    response_list = list(response) if isinstance(response, Iterator) else [response]
193:+                    return JSONResponse(response_list[0].to_json())
194:+
195:+                # Streaming response
196:                 async def streaming():
197:                     try:
198:                         async for chunk in response:
203:                         logging.exception(e)
204:                         yield f'data: {format_exception(e, config)}\n\n'
205:                     yield "data: [DONE]\n\n"
206:+
207:                 return StreamingResponse(streaming(), media_type="text/event-stream")
208: 
209:             except Exception as e:
210:                 logging.exception(e)
211:                 return Response(content=format_exception(e, config), status_code=500, media_type="application/json")
212: 
-        @self.app.post("/v1/completions")
-        async def completions():
-            return Response(content=json.dumps({'info': 'Not working yet.'}, indent=4), media_type="application/json")
-
-        @self.app.post("/v1/images/generations")
-        async def images_generate(config: ImagesGenerateForm, request: Request = None, provider: str = None):
213:+        @self.app.post("/v1/images/generate")
214:+        async def generate_image(config: ImageGenerationConfig):
215:             try:
-                config.provider = provider if config.provider is None else config.provider
-                if config.api_key is None and request is not None:
-                    auth_header = request.headers.get("Authorization")
-                    if auth_header is not None:
-                        auth_header = auth_header.split(None, 1)[-1]
-                        if auth_header and auth_header != "Bearer":
-                            config.api_key = auth_header
-                # Use the asynchronous generate method and await it
-                response = await self.client.images.async_generate(
-                    **config.dict(exclude_none=True),
216:+                response: ImagesResponse = await self.client.images.async_generate(
217:+                    prompt=config.prompt,
218:+                    model=config.model,
219:+                    response_format=config.response_format
220:                 )
-                return JSONResponse(response.to_json())
221:+                # Convert Image objects to dictionaries
222:+                response_data = [image.to_dict() for image in response.data]
223:+                return JSONResponse({"data": response_data})
224:             except Exception as e:
225:                 logging.exception(e)
226:                 return Response(content=format_exception(e, config), status_code=500, media_type="application/json")
227: 
-def format_exception(e: Exception, config: ChatCompletionsForm) -> str:
228:+        @self.app.post("/v1/completions")
229:+        async def completions():
230:+            return Response(content=json.dumps({'info': 'Not working yet.'}, indent=4), media_type="application/json")
231:+
232:+def format_exception(e: Exception, config: Union[ChatCompletionsConfig, ImageGenerationConfig]) -> str:
233:     last_provider = g4f.get_last_provider(True)
234:     return json.dumps({
235:         "error": {"message": f"{e.__class__.__name__}: {e}"},
-        "model": last_provider.get("model") if last_provider else config.model,
-        "provider": last_provider.get("name") if last_provider else config.provider
236:+        "model": last_provider.get("model") if last_provider else getattr(config, 'model', None),
237:+        "provider": last_provider.get("name") if last_provider else getattr(config, 'provider', None)
238:     })
239: 
240: def run_api(
243:     bind: str = None,
244:     debug: bool = False,
245:     workers: int = None,
-    use_colors: bool = None
246:+    use_colors: bool = None,
247:+    g4f_api_key: str = None
248: ) -> None:
249:     print(f'Starting server... [g4f v-{g4f.version.utils.current_version}]' + (" (debug)" if debug else ""))
250:     if use_colors is None:
251:         use_colors = debug
252:     if bind is not None:
253:         host, port = bind.split(":")
254:+    if debug:
255:+        g4f.debug.logging = True
256:     uvicorn.run(
-        f"g4f.api:create_app{'_debug' if debug else ''}",
-        host=host, port=int(port),
-        workers=workers,
-        use_colors=use_colors,
-        factory=True,
257:+        "g4f.api:create_app", 
258:+        host=host, 
259:+        port=int(port), 
260:+        workers=workers, 
261:+        use_colors=use_colors, 
262:+        factory=True, 
263:         reload=debug
264:     )
```