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/Provider/Blackbox.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:
```
1: from __future__ import annotations
2: 
-import asyncio
-import aiohttp
3:+from aiohttp import ClientSession
4: import random
5: import string
6: import json
-import uuid
7: import re
-from typing import Optional, AsyncGenerator, Union
-
-from aiohttp import ClientSession, ClientResponseError
8:+import aiohttp
9: 
10: from ..typing import AsyncResult, Messages, ImageType
11: from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
12: from ..image import ImageResponse, to_data_uri
13: 
-
14: class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
15:     label = "Blackbox AI"
16:     url = "https://www.blackbox.ai"
19:     supports_stream = True
20:     supports_system_message = True
21:     supports_message_history = True
-
22:+    _last_validated_value = None
23:+    
24:     default_model = 'blackboxai'
-    image_models = ['ImageGeneration']
-    models = [
-        default_model,
-        'blackboxai-pro',
-        *image_models,
-        "llama-3.1-8b",
-        'llama-3.1-70b',
-        'llama-3.1-405b',
-        'gpt-4o',
-        'gemini-pro',
-        'gemini-1.5-flash',
-        'claude-sonnet-3.5',
-        'PythonAgent',
-        'JavaAgent',
-        'JavaScriptAgent',
-        'HTMLAgent',
-        'GoogleCloudAgent',
-        'AndroidDeveloper',
-        'SwiftDeveloper',
-        'Next.jsAgent',
-        'MongoDBAgent',
-        'PyTorchAgent',
-        'ReactAgent',
-        'XcodeAgent',
-        'AngularJSAgent',
-        'RepoMap',
-    ]
-
25:+    
26:+    image_models = ['Image Generation', 'repomap']
27:+   
28:+    userSelectedModel = ['gpt-4o', 'gemini-pro', 'claude-sonnet-3.5', 'blackboxai-pro']
29:+    
30:     agentMode = {
-        'ImageGeneration': {'mode': True, 'id': "ImageGenerationLV45LJp", 'name': "Image Generation"},
31:+        'Image Generation': {'mode': True, 'id': "ImageGenerationLV45LJp", 'name': "Image Generation"},
32:     }
-
33:+    
34:     trendingAgentMode = {
-        "blackboxai": {},
35:         "gemini-1.5-flash": {'mode': True, 'id': 'Gemini'},
36:         "llama-3.1-8b": {'mode': True, 'id': "llama-3.1-8b"},
37:         'llama-3.1-70b': {'mode': True, 'id': "llama-3.1-70b"},
-        'llama-3.1-405b': {'mode': True, 'id': "llama-3.1-405b"},
38:+	    'llama-3.1-405b': {'mode': True, 'id': "llama-3.1-405"},
39:+        #
40:+        'Python Agent': {'mode': True, 'id': "Python Agent"},
41:+        'Java Agent': {'mode': True, 'id': "Java Agent"},
42:+        'JavaScript Agent': {'mode': True, 'id': "JavaScript Agent"},
43:+        'HTML Agent': {'mode': True, 'id': "HTML Agent"},
44:+        'Google Cloud Agent': {'mode': True, 'id': "Google Cloud Agent"},
45:+        'Android Developer': {'mode': True, 'id': "Android Developer"},
46:+        'Swift Developer': {'mode': True, 'id': "Swift Developer"},
47:+        'Next.js Agent': {'mode': True, 'id': "Next.js Agent"},
48:+        'MongoDB Agent': {'mode': True, 'id': "MongoDB Agent"},
49:+        'PyTorch Agent': {'mode': True, 'id': "PyTorch Agent"},
50:+        'React Agent': {'mode': True, 'id': "React Agent"},
51:+        'Xcode Agent': {'mode': True, 'id': "Xcode Agent"},
52:+        'AngularJS Agent': {'mode': True, 'id': "AngularJS Agent"},
53:         'blackboxai-pro': {'mode': True, 'id': "BLACKBOXAI-PRO"},
-        'PythonAgent': {'mode': True, 'id': "Python Agent"},
-        'JavaAgent': {'mode': True, 'id': "Java Agent"},
-        'JavaScriptAgent': {'mode': True, 'id': "JavaScript Agent"},
-        'HTMLAgent': {'mode': True, 'id': "HTML Agent"},
-        'GoogleCloudAgent': {'mode': True, 'id': "Google Cloud Agent"},
-        'AndroidDeveloper': {'mode': True, 'id': "Android Developer"},
-        'SwiftDeveloper': {'mode': True, 'id': "Swift Developer"},
-        'Next.jsAgent': {'mode': True, 'id': "Next.js Agent"},
-        'MongoDBAgent': {'mode': True, 'id': "MongoDB Agent"},
-        'PyTorchAgent': {'mode': True, 'id': "PyTorch Agent"},
-        'ReactAgent': {'mode': True, 'id': "React Agent"},
-        'XcodeAgent': {'mode': True, 'id': "Xcode Agent"},
-        'AngularJSAgent': {'mode': True, 'id': "AngularJS Agent"},
-        'RepoMap': {'mode': True, 'id': "repomap"},
-    }
-
-    userSelectedModel = {
-        "gpt-4o": "gpt-4o",
-        "gemini-pro": "gemini-pro",
-        'claude-sonnet-3.5': "claude-sonnet-3.5",
-    }
-
-    model_prefixes = {
-        'gpt-4o': '@GPT-4o',
-        'gemini-pro': '@Gemini-PRO',
-        'claude-sonnet-3.5': '@Claude-Sonnet-3.5',
-        'PythonAgent': '@Python Agent',
-        'JavaAgent': '@Java Agent',
-        'JavaScriptAgent': '@JavaScript Agent',
-        'HTMLAgent': '@HTML Agent',
-        'GoogleCloudAgent': '@Google Cloud Agent',
-        'AndroidDeveloper': '@Android Developer',
-        'SwiftDeveloper': '@Swift Developer',
-        'Next.jsAgent': '@Next.js Agent',
-        'MongoDBAgent': '@MongoDB Agent',
-        'PyTorchAgent': '@PyTorch Agent',
-        'ReactAgent': '@React Agent',
-        'XcodeAgent': '@Xcode Agent',
-        'AngularJSAgent': '@AngularJS Agent',
-        'blackboxai-pro': '@BLACKBOXAI-PRO',
-        'ImageGeneration': '@Image Generation',
-    }
-
-    model_referers = {
-        "blackboxai": "/?model=blackboxai",
-        "gpt-4o": "/?model=gpt-4o",
-        "gemini-pro": "/?model=gemini-pro",
-        "claude-sonnet-3.5": "/?model=claude-sonnet-3.5"
54:+        #
55:+        'repomap': {'mode': True, 'id': "repomap"},
56:+        #
57:+        'Heroku Agent': {'mode': True, 'id': "Heroku Agent"},
58:+        'Godot Agent': {'mode': True, 'id': "Godot Agent"},
59:+        'Go Agent': {'mode': True, 'id': "Go Agent"},
60:+        'Gitlab Agent': {'mode': True, 'id': "Gitlab Agent"},
61:+        'Git Agent': {'mode': True, 'id': "Git Agent"},
62:+	    'Flask Agent': {'mode': True, 'id': "Flask Agent"},
63:+        'Firebase Agent': {'mode': True, 'id': "Firebase Agent"},
64:+        'FastAPI Agent': {'mode': True, 'id': "FastAPI Agent"},
65:+        'Erlang Agent': {'mode': True, 'id': "Erlang Agent"},
66:+        'Electron Agent': {'mode': True, 'id': "Electron Agent"},
67:+        'Docker Agent': {'mode': True, 'id': "Docker Agent"},
68:+        'DigitalOcean Agent': {'mode': True, 'id': "DigitalOcean Agent"},
69:+        'Bitbucket Agent': {'mode': True, 'id': "Bitbucket Agent"},
70:+        'Azure Agent': {'mode': True, 'id': "Azure Agent"},
71:+        'Flutter Agent': {'mode': True, 'id': "Flutter Agent"},
72:+        'Youtube Agent': {'mode': True, 'id': "Youtube Agent"},
73:+        'builder Agent': {'mode': True, 'id': "builder Agent"},
74:     }
75:+    
76:+    model_prefixes = {mode: f"@{value['id']}" for mode, value in trendingAgentMode.items() if mode not in ["gemini-1.5-flash", "llama-3.1-8b", "llama-3.1-70b", "llama-3.1-405b", "repomap"]}
77: 
78:+    
79:+    models = [default_model, *userSelectedModel, *list(agentMode.keys()), *list(trendingAgentMode.keys())]
80:+    
81:     model_aliases = {
82:         "gemini-flash": "gemini-1.5-flash",
83:         "claude-3.5-sonnet": "claude-sonnet-3.5",
-        "flux": "ImageGeneration",
84:+        "flux": "Image Generation",
85:     }
86: 
87:+    @classmethod
88:+    async def fetch_validated(cls):       
89:+        # If the key is already stored in memory, return it
90:+        if cls._last_validated_value:
91:+            return cls._last_validated_value
92:+
93:+        # If the key is not found, perform a search
94:+        async with aiohttp.ClientSession() as session:
95:+            try:
96:+                async with session.get(cls.url) as response:
97:+                    if response.status != 200:
98:+                        print("Failed to load the page.")
99:+                        return cls._last_validated_value
100:+                    
101:+                    page_content = await response.text()
102:+                    js_files = re.findall(r'static/chunks/\d{4}-[a-fA-F0-9]+\.js', page_content)
103:+
104:+                key_pattern = re.compile(r'w="([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})"')
105:+
106:+                for js_file in js_files:
107:+                    js_url = f"{cls.url}/_next/{js_file}"
108:+                    async with session.get(js_url) as js_response:
109:+                        if js_response.status == 200:
110:+                            js_content = await js_response.text()
111:+                            match = key_pattern.search(js_content)
112:+                            if match:
113:+                                validated_value = match.group(1)
114:+                                cls._last_validated_value = validated_value  # Keep in mind
115:+                                return validated_value
116:+            except Exception as e:
117:+                print(f"Error fetching validated value: {e}")
118:+
119:+        return cls._last_validated_value
120:+
121:+
122:+    @staticmethod
123:+    def generate_id(length=7):
124:+        characters = string.ascii_letters + string.digits
125:+        return ''.join(random.choice(characters) for _ in range(length))
126:+        
127:+    @classmethod
128:+    def add_prefix_to_messages(cls, messages: Messages, model: str) -> Messages:
129:+        prefix = cls.model_prefixes.get(model, "")
130:+        if not prefix:
131:+            return messages
132:+
133:+        new_messages = []
134:+        for message in messages:
135:+            new_message = message.copy()
136:+            if message['role'] == 'user':
137:+                new_message['content'] = (prefix + " " + message['content']).strip()
138:+            new_messages.append(new_message)
139:+
140:+        return new_messages
141:+
142:     @classmethod
143:     def get_model(cls, model: str) -> str:
144:         if model in cls.models:
148:         else:
149:             return cls.default_model
150: 
-    @staticmethod
-    def generate_random_string(length: int = 7) -> str:
-        characters = string.ascii_letters + string.digits
-        return ''.join(random.choices(characters, k=length))
-
-    @staticmethod
-    def generate_next_action() -> str:
-        return uuid.uuid4().hex
-
-    @staticmethod
-    def generate_next_router_state_tree() -> str:
-        router_state = [
-            "",
-            {
-                "children": [
-                    "(chat)",
-                    {
-                        "children": [
-                            "__PAGE__",
-                            {}
-                        ]
-                    }
-                ]
-            },
-            None,
-            None,
-            True
-        ]
-        return json.dumps(router_state)
-
-    @staticmethod
-    def clean_response(text: str) -> str:
-        pattern = r'^\$\@\$v=undefined-rv1\$\@\$'
-        cleaned_text = re.sub(pattern, '', text)
-        return cleaned_text
-
151:     @classmethod
152:     async def create_async_generator(
153:         cls,
154:         model: str,
155:         messages: Messages,
-        proxy: Optional[str] = None,
156:+        proxy: str = None,
157:+        web_search: bool = False,
158:         image: ImageType = None,
159:         image_name: str = None,
-        websearch: bool = False,
160:         **kwargs
-    ) -> AsyncGenerator[Union[str, ImageResponse], None]:
-        """
-        Creates an asynchronous generator for streaming responses from Blackbox AI.
-
-        Parameters:
-            model (str): Model to use for generating responses.
-            messages (Messages): Message history.
-            proxy (Optional[str]): Proxy URL, if needed.
-            image (ImageType): Image data to be processed, if any.
-            image_name (str): Name of the image file, if an image is provided.
-            websearch (bool): Enables or disables web search mode.
-            **kwargs: Additional keyword arguments.
161:+    ) -> AsyncResult:
162:+        model = cls.get_model(model)
163:+        message_id = cls.generate_id()
164:+        messages_with_prefix = cls.add_prefix_to_messages(messages, model)
165:+        validated_value = await cls.fetch_validated()
166: 
-        Yields:
-            Union[str, ImageResponse]: Segments of the generated response or ImageResponse objects.
-        """
-        
167:         if image is not None:
-            messages[-1]['data'] = {
168:+            messages_with_prefix[-1]['data'] = {
169:                 'fileText': '',
170:                 'imageBase64': to_data_uri(image),
171:                 'title': image_name
172:             }
-            messages[-1]['content'] = 'FILE:BB\n$#$\n\n$#$\n' + messages[-1]['content']
-        
-        model = cls.get_model(model)
-
-        chat_id = cls.generate_random_string()
-        next_action = cls.generate_next_action()
-        next_router_state_tree = cls.generate_next_router_state_tree()
-
-        agent_mode = cls.agentMode.get(model, {})
-        trending_agent_mode = cls.trendingAgentMode.get(model, {})
-
-        prefix = cls.model_prefixes.get(model, "")
-        
-        formatted_prompt = ""
-        for message in messages:
-            role = message.get('role', '').capitalize()
-            content = message.get('content', '')
-            if role and content:
-                formatted_prompt += f"{role}: {content}\n"
-        
-        if prefix:
-            formatted_prompt = f"{prefix} {formatted_prompt}".strip()
173: 
-        referer_path = cls.model_referers.get(model, f"/?model={model}")
-        referer_url = f"{cls.url}{referer_path}"
-
-        common_headers = {
174:+        headers = {
175:             'accept': '*/*',
176:             'accept-language': 'en-US,en;q=0.9',
177:             'cache-control': 'no-cache',
178:+            'content-type': 'application/json',
179:             'origin': cls.url,
180:             'pragma': 'no-cache',
181:             'priority': 'u=1, i',
-            'sec-ch-ua': '"Chromium";v="129", "Not=A?Brand";v="8"',
182:+            'referer': f'{cls.url}/',
183:+            'sec-ch-ua': '"Not?A_Brand";v="99", "Chromium";v="130"',
184:             'sec-ch-ua-mobile': '?0',
185:             'sec-ch-ua-platform': '"Linux"',
186:             'sec-fetch-dest': 'empty',
187:             'sec-fetch-mode': 'cors',
188:             'sec-fetch-site': 'same-origin',
-            'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) '
-                          'AppleWebKit/537.36 (KHTML, like Gecko) '
-                          'Chrome/129.0.0.0 Safari/537.36'
-        }
-
-        headers_api_chat = {
-            'Content-Type': 'application/json',
-            'Referer': referer_url
189:+            'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36'
190:         }
-        headers_api_chat_combined = {**common_headers, **headers_api_chat}
-
-        payload_api_chat = {
-            "messages": [
-                {
-                    "id": chat_id,
-                    "content": formatted_prompt,
-                    "role": "user",
-					"data": messages[-1].get('data')
-                }
-            ],
-            "id": chat_id,
191:+        
192:+        data = {
193:+            "messages": messages_with_prefix,
194:+            "id": message_id,
195:             "previewToken": None,
196:             "userId": None,
197:             "codeModelMode": True,
-            "agentMode": agent_mode,
-            "trendingAgentMode": trending_agent_mode,
198:+            "agentMode": cls.agentMode.get(model, {}) if model in cls.agentMode else {},
199:+            "trendingAgentMode": cls.trendingAgentMode.get(model, {}) if model in cls.trendingAgentMode else {},
200:             "isMicMode": False,
201:             "userSystemPrompt": None,
202:             "maxTokens": 1024,
209:             "clickedForceWebSearch": False,
210:             "visitFromDelta": False,
211:             "mobileClient": False,
-            "webSearchMode": websearch,
-            "userSelectedModel": cls.userSelectedModel.get(model, model)
212:+            "userSelectedModel": model if model in cls.userSelectedModel else None,
213:+            "webSearchMode": web_search,
214:+            "validated": validated_value,
215:         }
216: 
-        headers_chat = {
-            'Accept': 'text/x-component',
-            'Content-Type': 'text/plain;charset=UTF-8',
-            'Referer': f'{cls.url}/chat/{chat_id}?model={model}',
-            'next-action': next_action,
-            'next-router-state-tree': next_router_state_tree,
-            'next-url': '/'
-        }
-        headers_chat_combined = {**common_headers, **headers_chat}
-
-        data_chat = '[]'
-
-        async with ClientSession(headers=common_headers) as session:
-            try:
-                async with session.post(
-                    cls.api_endpoint,
-                    headers=headers_api_chat_combined,
-                    json=payload_api_chat,
-                    proxy=proxy
-                ) as response_api_chat:
-                    response_api_chat.raise_for_status()
-                    text = await response_api_chat.text()
-                    cleaned_response = cls.clean_response(text)
-
-                    if model in cls.image_models:
-                        match = re.search(r'!\[.*?\]\((https?://[^\)]+)\)', cleaned_response)
-                        if match:
-                            image_url = match.group(1)
-                            image_response = ImageResponse(images=image_url, alt="Generated Image")
-                            yield image_response
-                        else:
-                            yield cleaned_response
-                    else:
-                        if websearch:
-                            match = re.search(r'\$~~~\$(.*?)\$~~~\$', cleaned_response, re.DOTALL)
-                            if match:
-                                source_part = match.group(1).strip()
-                                answer_part = cleaned_response[match.end():].strip()
-                                try:
-                                    sources = json.loads(source_part)
-                                    source_formatted = "**Source:**\n"
-                                    for item in sources:
-                                        title = item.get('title', 'No Title')
-                                        link = item.get('link', '#')
-                                        position = item.get('position', '')
-                                        source_formatted += f"{position}. [{title}]({link})\n"
-                                    final_response = f"{answer_part}\n\n{source_formatted}"
-                                except json.JSONDecodeError:
-                                    final_response = f"{answer_part}\n\nSource information is unavailable."
-                            else:
-                                final_response = cleaned_response
-                        else:
-                            if '$~~~$' in cleaned_response:
-                                final_response = cleaned_response.split('$~~~$')[0].strip()
-                            else:
-                                final_response = cleaned_response
-
-                        yield final_response
-            except ClientResponseError as e:
-                error_text = f"Error {e.status}: {e.message}"
-                try:
-                    error_response = await e.response.text()
-                    cleaned_error = cls.clean_response(error_response)
-                    error_text += f" - {cleaned_error}"
-                except Exception:
-                    pass
-                yield error_text
-            except Exception as e:
-                yield f"Unexpected error during /api/chat request: {str(e)}"
-
-            chat_url = f'{cls.url}/chat/{chat_id}?model={model}'
-
-            try:
-                async with session.post(
-                    chat_url,
-                    headers=headers_chat_combined,
-                    data=data_chat,
-                    proxy=proxy
-                ) as response_chat:
-                    response_chat.raise_for_status()
-                    pass
-            except ClientResponseError as e:
-                error_text = f"Error {e.status}: {e.message}"
-                try:
-                    error_response = await e.response.text()
-                    cleaned_error = cls.clean_response(error_response)
-                    error_text += f" - {cleaned_error}"
-                except Exception:
-                    pass
-                yield error_text
-            except Exception as e:
-                yield f"Unexpected error during /chat/{chat_id} request: {str(e)}"
217:+        async with ClientSession(headers=headers) as session:
218:+            async with session.post(cls.api_endpoint, json=data, proxy=proxy) as response:
219:+                response.raise_for_status()
220:+                response_text = await response.text()
221:+                
222:+                if model in cls.image_models:
223:+                    image_matches = re.findall(r'!\[.*?\]\((https?://[^\)]+)\)', response_text)
224:+                    if image_matches:
225:+                        image_url = image_matches[0]
226:+                        image_response = ImageResponse(images=[image_url], alt="Generated Image")
227:+                        yield image_response
228:+                        return
229:+
230:+                response_text = re.sub(r'Generated by BLACKBOX.AI, try unlimited chat https://www.blackbox.ai', '', response_text, flags=re.DOTALL)
231:+                
232:+                json_match = re.search(r'\$~~~\$(.*?)\$~~~\$', response_text, re.DOTALL)
233:+                if json_match:
234:+                    search_results = json.loads(json_match.group(1))
235:+                    answer = response_text.split('$~~~$')[-1].strip()
236:+                    
237:+                    formatted_response = f"{answer}\n\n**Source:**"
238:+                    for i, result in enumerate(search_results, 1):
239:+                        formatted_response += f"\n{i}. {result['title']}: {result['link']}"
240:+                    
241:+                    yield formatted_response
242:+                else:
243:+                    yield response_text.strip()
```