Niansuh commited on
Commit
0cf9628
·
verified ·
1 Parent(s): 2117a04

Create blackbox.py

Browse files
Files changed (1) hide show
  1. blackbox.py +285 -0
blackbox.py ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/blackbox.py
2
+
3
+ import asyncio
4
+ import aiohttp
5
+ import random
6
+ import string
7
+ import json
8
+ import uuid
9
+ import re
10
+ from typing import Optional, AsyncGenerator, Union
11
+
12
+ from aiohttp import ClientSession, ClientResponseError
13
+
14
+ from .typing import Messages, ImageType
15
+ from .image import to_image, ImageResponse
16
+
17
+ class Blackbox:
18
+ url = "https://www.blackbox.ai"
19
+ api_endpoint = "https://www.blackbox.ai/api/chat"
20
+ working = True
21
+ supports_stream = True
22
+ supports_system_message = True
23
+ supports_message_history = True
24
+
25
+ default_model = 'blackboxai'
26
+ image_models = ['ImageGeneration']
27
+ models = [
28
+ default_model,
29
+ 'blackboxai-pro',
30
+ *image_models,
31
+ "llama-3.1-8b",
32
+ 'llama-3.1-70b',
33
+ 'llama-3.1-405b',
34
+ 'gpt-4o',
35
+ 'gemini-pro',
36
+ 'gemini-1.5-flash',
37
+ 'claude-sonnet-3.5',
38
+ 'PythonAgent',
39
+ 'JavaAgent',
40
+ 'JavaScriptAgent',
41
+ 'HTMLAgent',
42
+ 'GoogleCloudAgent',
43
+ 'AndroidDeveloper',
44
+ 'SwiftDeveloper',
45
+ 'Next.jsAgent',
46
+ 'MongoDBAgent',
47
+ 'PyTorchAgent',
48
+ 'ReactAgent',
49
+ 'XcodeAgent',
50
+ 'AngularJSAgent',
51
+ ]
52
+
53
+ agentMode = {
54
+ 'ImageGeneration': {'mode': True, 'id': "ImageGenerationLV45LJp", 'name': "Image Generation"},
55
+ 'Niansuh': {'mode': True, 'id': "NiansuhAIk1HgESy", 'name': "Niansuh"},
56
+ }
57
+
58
+ trendingAgentMode = {
59
+ "blackboxai": {},
60
+ "gemini-1.5-flash": {'mode': True, 'id': 'Gemini'},
61
+ "llama-3.1-8b": {'mode': True, 'id': "llama-3.1-8b"},
62
+ 'llama-3.1-70b': {'mode': True, 'id': "llama-3.1-70b"},
63
+ 'llama-3.1-405b': {'mode': True, 'id': "llama-3.1-405b"},
64
+ 'blackboxai-pro': {'mode': True, 'id': "BLACKBOXAI-PRO"},
65
+ 'PythonAgent': {'mode': True, 'id': "Python Agent"},
66
+ 'JavaAgent': {'mode': True, 'id': "Java Agent"},
67
+ 'JavaScriptAgent': {'mode': True, 'id': "JavaScript Agent"},
68
+ 'HTMLAgent': {'mode': True, 'id': "HTML Agent"},
69
+ 'GoogleCloudAgent': {'mode': True, 'id': "Google Cloud Agent"},
70
+ 'AndroidDeveloper': {'mode': True, 'id': "Android Developer"},
71
+ 'SwiftDeveloper': {'mode': True, 'id': "Swift Developer"},
72
+ 'Next.jsAgent': {'mode': True, 'id': "Next.js Agent"},
73
+ 'MongoDBAgent': {'mode': True, 'id': "MongoDB Agent"},
74
+ 'PyTorchAgent': {'mode': True, 'id': "PyTorch Agent"},
75
+ 'ReactAgent': {'mode': True, 'id': "React Agent"},
76
+ 'XcodeAgent': {'mode': True, 'id': "Xcode Agent"},
77
+ 'AngularJSAgent': {'mode': True, 'id': "AngularJS Agent"},
78
+ }
79
+
80
+ userSelectedModel = {
81
+ "gpt-4o": "gpt-4o",
82
+ "gemini-pro": "gemini-pro",
83
+ 'claude-sonnet-3.5': "claude-sonnet-3.5",
84
+ }
85
+
86
+ model_prefixes = {
87
+ 'gpt-4o': '@GPT-4o',
88
+ 'gemini-pro': '@Gemini-PRO',
89
+ 'claude-sonnet-3.5': '@Claude-Sonnet-3.5',
90
+ 'PythonAgent': '@Python Agent',
91
+ 'JavaAgent': '@Java Agent',
92
+ 'JavaScriptAgent': '@JavaScript Agent',
93
+ 'HTMLAgent': '@HTML Agent',
94
+ 'GoogleCloudAgent': '@Google Cloud Agent',
95
+ 'AndroidDeveloper': '@Android Developer',
96
+ 'SwiftDeveloper': '@Swift Developer',
97
+ 'Next.jsAgent': '@Next.js Agent',
98
+ 'MongoDBAgent': '@MongoDB Agent',
99
+ 'PyTorchAgent': '@PyTorch Agent',
100
+ 'ReactAgent': '@React Agent',
101
+ 'XcodeAgent': '@Xcode Agent',
102
+ 'AngularJSAgent': '@AngularJS Agent',
103
+ 'blackboxai-pro': '@BLACKBOXAI-PRO',
104
+ 'ImageGeneration': '@Image Generation',
105
+ 'Niansuh': '@Niansuh',
106
+ }
107
+
108
+ model_referers = {
109
+ "blackboxai": f"{url}/?model=blackboxai",
110
+ "gpt-4o": f"{url}/?model=gpt-4o",
111
+ "gemini-pro": f"{url}/?model=gemini-pro",
112
+ "claude-sonnet-3.5": f"{url}/?model=claude-sonnet-3.5"
113
+ }
114
+
115
+ model_aliases = {
116
+ "gemini-flash": "gemini-1.5-flash",
117
+ "claude-3.5-sonnet": "claude-sonnet-3.5",
118
+ "flux": "ImageGeneration",
119
+ "niansuh": "Niansuh",
120
+ }
121
+
122
+ @classmethod
123
+ def get_model(cls, model: str) -> Optional[str]:
124
+ if model in cls.models:
125
+ return model
126
+ elif model in cls.userSelectedModel and cls.userSelectedModel[model] in cls.models:
127
+ return cls.userSelectedModel[model]
128
+ elif model in cls.model_aliases and cls.model_aliases[model] in cls.models:
129
+ return cls.model_aliases[model]
130
+ else:
131
+ return cls.default_model if cls.default_model in cls.models else None
132
+
133
+ @classmethod
134
+ async def create_async_generator(
135
+ cls,
136
+ model: str,
137
+ messages: List[Dict[str, str]],
138
+ proxy: Optional[str] = None,
139
+ image: Optional[str] = None,
140
+ image_name: Optional[str] = None,
141
+ webSearchMode: bool = False,
142
+ **kwargs
143
+ ) -> AsyncGenerator[Union[str, ImageResponse], None]:
144
+ model = cls.get_model(model)
145
+ if model is None:
146
+ logger.error(f"Model {model} is not available.")
147
+ raise ModelNotWorkingException(model)
148
+
149
+ logger.info(f"Selected model: {model}")
150
+
151
+ if not cls.working or model not in cls.models:
152
+ logger.error(f"Model {model} is not working or not supported.")
153
+ raise ModelNotWorkingException(model)
154
+
155
+ headers = {
156
+ "accept": "*/*",
157
+ "accept-language": "en-US,en;q=0.9",
158
+ "cache-control": "no-cache",
159
+ "content-type": "application/json",
160
+ "origin": cls.url,
161
+ "pragma": "no-cache",
162
+ "priority": "u=1, i",
163
+ "referer": cls.model_referers.get(model, cls.url),
164
+ "sec-ch-ua": '"Chromium";v="129", "Not=A?Brand";v="8"',
165
+ "sec-ch-ua-mobile": "?0",
166
+ "sec-ch-ua-platform": '"Linux"',
167
+ "sec-fetch-dest": "empty",
168
+ "sec-fetch-mode": "cors",
169
+ "sec-fetch-site": "same-origin",
170
+ "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
171
+ }
172
+
173
+ if model in cls.model_prefixes:
174
+ prefix = cls.model_prefixes[model]
175
+ if not messages[0]['content'].startswith(prefix):
176
+ logger.debug(f"Adding prefix '{prefix}' to the first message.")
177
+ messages[0]['content'] = f"{prefix} {messages[0]['content']}"
178
+
179
+ random_id = ''.join(random.choices(string.ascii_letters + string.digits, k=7))
180
+ messages[-1]['id'] = random_id
181
+ messages[-1]['role'] = 'user'
182
+
183
+ # Don't log the full message content for privacy
184
+ logger.debug(f"Generated message ID: {random_id} for model: {model}")
185
+
186
+ if image is not None:
187
+ messages[-1]['data'] = {
188
+ 'fileText': '',
189
+ 'imageBase64': image,
190
+ 'title': image_name
191
+ }
192
+ messages[-1]['content'] = 'FILE:BB\n$#$\n\n$#$\n' + messages[-1]['content']
193
+ logger.debug("Image data added to the message.")
194
+
195
+ data = {
196
+ "messages": messages,
197
+ "id": random_id,
198
+ "previewToken": None,
199
+ "userId": None,
200
+ "codeModelMode": True,
201
+ "agentMode": {},
202
+ "trendingAgentMode": {},
203
+ "isMicMode": False,
204
+ "userSystemPrompt": None,
205
+ "maxTokens": 99999999,
206
+ "playgroundTopP": 0.9,
207
+ "playgroundTemperature": 0.5,
208
+ "isChromeExt": False,
209
+ "githubToken": None,
210
+ "clickedAnswer2": False,
211
+ "clickedAnswer3": False,
212
+ "clickedForceWebSearch": False,
213
+ "visitFromDelta": False,
214
+ "mobileClient": False,
215
+ "userSelectedModel": None,
216
+ "webSearchMode": webSearchMode,
217
+ }
218
+
219
+ if model in cls.agentMode:
220
+ data["agentMode"] = cls.agentMode[model]
221
+ elif model in cls.trendingAgentMode:
222
+ data["trendingAgentMode"] = cls.trendingAgentMode[model]
223
+ elif model in cls.userSelectedModel:
224
+ data["userSelectedModel"] = cls.userSelectedModel[model]
225
+ logger.info(f"Sending request to {cls.api_endpoint} with data (excluding messages).")
226
+
227
+ timeout = ClientTimeout(total=60) # Set an appropriate timeout
228
+ retry_attempts = 10 # Set the number of retry attempts
229
+
230
+ for attempt in range(retry_attempts):
231
+ try:
232
+ async with ClientSession(headers=headers, timeout=timeout) as session:
233
+ async with session.post(cls.api_endpoint, json=data, proxy=proxy) as response:
234
+ response.raise_for_status()
235
+ logger.info(f"Received response with status {response.status}")
236
+ if model in cls.image_models:
237
+ response_text = await response.text()
238
+ # Extract image URL from the response
239
+ url_match = re.search(r'https://storage\.googleapis\.com/[^\s\)]+', response_text)
240
+ if url_match:
241
+ image_url = url_match.group(0)
242
+ logger.info(f"Image URL found: {image_url}")
243
+ yield ImageResponse(url=image_url, alt=messages[-1]['content'])
244
+ else:
245
+ logger.error("Image URL not found in the response.")
246
+ raise Exception("Image URL not found in the response")
247
+ else:
248
+ full_response = ""
249
+ search_results_json = ""
250
+ try:
251
+ async for chunk, _ in response.content.iter_chunks():
252
+ if chunk:
253
+ decoded_chunk = chunk.decode(errors='ignore')
254
+ decoded_chunk = re.sub(r'\$@\$v=[^$]+\$@\$', '', decoded_chunk)
255
+ if decoded_chunk.strip():
256
+ if '$~~~$' in decoded_chunk:
257
+ search_results_json += decoded_chunk
258
+ else:
259
+ full_response += decoded_chunk
260
+ yield decoded_chunk
261
+ logger.info("Finished streaming response chunks.")
262
+ except Exception as e:
263
+ logger.exception("Error while iterating over response chunks.")
264
+ raise e
265
+ if data["webSearchMode"] and search_results_json:
266
+ match = re.search(r'\$~~~\$(.*?)\$~~~\$', search_results_json, re.DOTALL)
267
+ if match:
268
+ try:
269
+ search_results = json.loads(match.group(1))
270
+ formatted_results = "\n\n**Sources:**\n"
271
+ for i, result in enumerate(search_results[:5], 1):
272
+ formatted_results += f"{i}. [{result['title']}]({result['link']})\n"
273
+ logger.info("Formatted search results.")
274
+ yield formatted_results
275
+ except json.JSONDecodeError as je:
276
+ logger.error("Failed to parse search results JSON.")
277
+ raise je
278
+ break # Exit the retry loop if successful
279
+ except ClientError as ce:
280
+ logger.error(f"Client error occurred: {ce}. Retrying attempt {attempt + 1}/{retry_attempts}")
281
+ if attempt == retry_attempts - 1:
282
+ raise HTTPException(status_code=502, detail="Error communicating with the external API.")
283
+ except asyncio.TimeoutError:
284
+ logger.error(f"Request timed out. Retrying attempt {attempt + 1}/{retry_attempts}")
285
+ if attempt == retry_attempts - 1: