Update main.py
Browse files
main.py
CHANGED
@@ -49,13 +49,126 @@ def decode_base64_image(data_uri: str) -> bytes:
|
|
49 |
raise e
|
50 |
|
51 |
class Blackbox:
|
52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
|
54 |
@classmethod
|
55 |
async def create_async_generator(
|
56 |
cls,
|
57 |
model: str,
|
58 |
-
messages: List[Dict[str,
|
59 |
proxy: Optional[str] = None,
|
60 |
image: Optional[str] = None, # Expecting a base64 string
|
61 |
image_name: Optional[str] = None,
|
@@ -70,7 +183,21 @@ class Blackbox:
|
|
70 |
raise ModelNotWorkingException(model)
|
71 |
|
72 |
headers = {
|
73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
}
|
75 |
|
76 |
if model in cls.model_prefixes:
|
@@ -80,24 +207,32 @@ class Blackbox:
|
|
80 |
messages[0]['content'] = f"{prefix} {messages[0]['content']}"
|
81 |
|
82 |
random_id = ''.join(random.choices(string.ascii_letters + string.digits, k=7))
|
83 |
-
|
84 |
-
|
85 |
-
|
|
|
|
|
86 |
if image is not None:
|
87 |
try:
|
88 |
image_bytes = decode_base64_image(image)
|
89 |
data_uri = to_data_uri(image_bytes)
|
90 |
-
|
91 |
'fileText': '',
|
92 |
'imageBase64': data_uri,
|
93 |
-
'title': image_name
|
94 |
}
|
95 |
-
|
96 |
logger.debug("Image data added to the message.")
|
97 |
except Exception as e:
|
98 |
logger.error(f"Failed to decode base64 image: {e}")
|
99 |
raise HTTPException(status_code=400, detail="Invalid image data provided.")
|
100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
data = {
|
102 |
"messages": messages,
|
103 |
"id": random_id,
|
@@ -234,8 +369,9 @@ def create_response(content: str, model: str, finish_reason: Optional[str] = Non
|
|
234 |
|
235 |
@app.post("/niansuhai/v1/chat/completions")
|
236 |
async def chat_completions(request: ChatRequest, req: Request):
|
237 |
-
logger.info(f"Received chat completions request: {request}")
|
238 |
try:
|
|
|
239 |
messages = [{"role": msg.role, "content": msg.content} for msg in request.messages]
|
240 |
|
241 |
async_generator = Blackbox.create_async_generator(
|
@@ -252,6 +388,7 @@ async def chat_completions(request: ChatRequest, req: Request):
|
|
252 |
try:
|
253 |
async for chunk in async_generator:
|
254 |
if isinstance(chunk, ImageResponse):
|
|
|
255 |
image_markdown = f""
|
256 |
response_chunk = create_response(image_markdown, request.model)
|
257 |
else:
|
|
|
49 |
raise e
|
50 |
|
51 |
class Blackbox:
|
52 |
+
url = "https://www.blackbox.ai"
|
53 |
+
api_endpoint = "https://www.blackbox.ai/api/chat"
|
54 |
+
working = True
|
55 |
+
supports_stream = True
|
56 |
+
supports_system_message = True
|
57 |
+
supports_message_history = True
|
58 |
+
|
59 |
+
default_model = 'blackboxai'
|
60 |
+
image_models = ['ImageGeneration']
|
61 |
+
models = [
|
62 |
+
default_model,
|
63 |
+
'blackboxai-pro',
|
64 |
+
"llama-3.1-8b",
|
65 |
+
'llama-3.1-70b',
|
66 |
+
'llama-3.1-405b',
|
67 |
+
'gpt-4o',
|
68 |
+
'gemini-pro',
|
69 |
+
'gemini-1.5-flash',
|
70 |
+
'claude-sonnet-3.5',
|
71 |
+
'PythonAgent',
|
72 |
+
'JavaAgent',
|
73 |
+
'JavaScriptAgent',
|
74 |
+
'HTMLAgent',
|
75 |
+
'GoogleCloudAgent',
|
76 |
+
'AndroidDeveloper',
|
77 |
+
'SwiftDeveloper',
|
78 |
+
'Next.jsAgent',
|
79 |
+
'MongoDBAgent',
|
80 |
+
'PyTorchAgent',
|
81 |
+
'ReactAgent',
|
82 |
+
'XcodeAgent',
|
83 |
+
'AngularJSAgent',
|
84 |
+
*image_models,
|
85 |
+
'Niansuh',
|
86 |
+
]
|
87 |
+
|
88 |
+
agentMode = {
|
89 |
+
'ImageGeneration': {'mode': True, 'id': "ImageGenerationLV45LJp", 'name': "Image Generation"},
|
90 |
+
'Niansuh': {'mode': True, 'id': "NiansuhAIk1HgESy", 'name': "Niansuh"},
|
91 |
+
}
|
92 |
+
trendingAgentMode = {
|
93 |
+
"blackboxai": {},
|
94 |
+
"gemini-1.5-flash": {'mode': True, 'id': 'Gemini'},
|
95 |
+
"llama-3.1-8b": {'mode': True, 'id': "llama-3.1-8b"},
|
96 |
+
'llama-3.1-70b': {'mode': True, 'id': "llama-3.1-70b"},
|
97 |
+
'llama-3.1-405b': {'mode': True, 'id': "llama-3.1-405b"},
|
98 |
+
'blackboxai-pro': {'mode': True, 'id': "BLACKBOXAI-PRO"},
|
99 |
+
'PythonAgent': {'mode': True, 'id': "Python Agent"},
|
100 |
+
'JavaAgent': {'mode': True, 'id': "Java Agent"},
|
101 |
+
'JavaScriptAgent': {'mode': True, 'id': "JavaScript Agent"},
|
102 |
+
'HTMLAgent': {'mode': True, 'id': "HTML Agent"},
|
103 |
+
'GoogleCloudAgent': {'mode': True, 'id': "Google Cloud Agent"},
|
104 |
+
'AndroidDeveloper': {'mode': True, 'id': "Android Developer"},
|
105 |
+
'SwiftDeveloper': {'mode': True, 'id': "Swift Developer"},
|
106 |
+
'Next.jsAgent': {'mode': True, 'id': "Next.js Agent"},
|
107 |
+
'MongoDBAgent': {'mode': True, 'id': "MongoDB Agent"},
|
108 |
+
'PyTorchAgent': {'mode': True, 'id': "PyTorch Agent"},
|
109 |
+
'ReactAgent': {'mode': True, 'id': "React Agent"},
|
110 |
+
'XcodeAgent': {'mode': True, 'id': "Xcode Agent"},
|
111 |
+
'AngularJSAgent': {'mode': True, 'id': "AngularJS Agent"},
|
112 |
+
}
|
113 |
+
|
114 |
+
userSelectedModel = {
|
115 |
+
"gpt-4o": "gpt-4o",
|
116 |
+
"gemini-pro": "gemini-pro",
|
117 |
+
'claude-sonnet-3.5': "claude-sonnet-3.5",
|
118 |
+
}
|
119 |
+
|
120 |
+
model_prefixes = {
|
121 |
+
'gpt-4o': '@GPT-4o',
|
122 |
+
'gemini-pro': '@Gemini-PRO',
|
123 |
+
'claude-sonnet-3.5': '@Claude-Sonnet-3.5',
|
124 |
+
'PythonAgent': '@Python Agent',
|
125 |
+
'JavaAgent': '@Java Agent',
|
126 |
+
'JavaScriptAgent': '@JavaScript Agent',
|
127 |
+
'HTMLAgent': '@HTML Agent',
|
128 |
+
'GoogleCloudAgent': '@Google Cloud Agent',
|
129 |
+
'AndroidDeveloper': '@Android Developer',
|
130 |
+
'SwiftDeveloper': '@Swift Developer',
|
131 |
+
'Next.jsAgent': '@Next.js Agent',
|
132 |
+
'MongoDBAgent': '@MongoDB Agent',
|
133 |
+
'PyTorchAgent': '@PyTorch Agent',
|
134 |
+
'ReactAgent': '@React Agent',
|
135 |
+
'XcodeAgent': '@Xcode Agent',
|
136 |
+
'AngularJSAgent': '@AngularJS Agent',
|
137 |
+
'blackboxai-pro': '@BLACKBOXAI-PRO',
|
138 |
+
'ImageGeneration': '@Image Generation',
|
139 |
+
'Niansuh': '@Niansuh',
|
140 |
+
}
|
141 |
+
|
142 |
+
model_referers = {
|
143 |
+
"blackboxai": f"{url}/?model=blackboxai",
|
144 |
+
"gpt-4o": f"{url}/?model=gpt-4o",
|
145 |
+
"gemini-pro": f"{url}/?model=gemini-pro",
|
146 |
+
"claude-sonnet-3.5": f"{url}/?model=claude-sonnet-3.5"
|
147 |
+
}
|
148 |
+
|
149 |
+
model_aliases = {
|
150 |
+
"gemini-flash": "gemini-1.5-flash",
|
151 |
+
"claude-3.5-sonnet": "claude-sonnet-3.5",
|
152 |
+
"flux": "ImageGeneration",
|
153 |
+
"niansuh": "Niansuh",
|
154 |
+
}
|
155 |
+
|
156 |
+
@classmethod
|
157 |
+
def get_model(cls, model: str) -> str:
|
158 |
+
if model in cls.models:
|
159 |
+
return model
|
160 |
+
elif model in cls.userSelectedModel:
|
161 |
+
return cls.userSelectedModel[model]
|
162 |
+
elif model in cls.model_aliases:
|
163 |
+
return cls.model_aliases[model]
|
164 |
+
else:
|
165 |
+
return cls.default_model
|
166 |
|
167 |
@classmethod
|
168 |
async def create_async_generator(
|
169 |
cls,
|
170 |
model: str,
|
171 |
+
messages: List[Dict[str, Any]],
|
172 |
proxy: Optional[str] = None,
|
173 |
image: Optional[str] = None, # Expecting a base64 string
|
174 |
image_name: Optional[str] = None,
|
|
|
183 |
raise ModelNotWorkingException(model)
|
184 |
|
185 |
headers = {
|
186 |
+
"accept": "*/*",
|
187 |
+
"accept-language": "en-US,en;q=0.9",
|
188 |
+
"cache-control": "no-cache",
|
189 |
+
"content-type": "application/json",
|
190 |
+
"origin": cls.url,
|
191 |
+
"pragma": "no-cache",
|
192 |
+
"priority": "u=1, i",
|
193 |
+
"referer": cls.model_referers.get(model, cls.url),
|
194 |
+
"sec-ch-ua": '"Chromium";v="129", "Not=A?Brand";v="8"',
|
195 |
+
"sec-ch-ua-mobile": "?0",
|
196 |
+
"sec-ch-ua-platform": '"Linux"',
|
197 |
+
"sec-fetch-dest": "empty",
|
198 |
+
"sec-fetch-mode": "cors",
|
199 |
+
"sec-fetch-site": "same-origin",
|
200 |
+
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
|
201 |
}
|
202 |
|
203 |
if model in cls.model_prefixes:
|
|
|
207 |
messages[0]['content'] = f"{prefix} {messages[0]['content']}"
|
208 |
|
209 |
random_id = ''.join(random.choices(string.ascii_letters + string.digits, k=7))
|
210 |
+
user_message = {
|
211 |
+
"id": random_id,
|
212 |
+
"role": 'user',
|
213 |
+
"content": 'Hi' # This should be dynamically set based on input
|
214 |
+
}
|
215 |
if image is not None:
|
216 |
try:
|
217 |
image_bytes = decode_base64_image(image)
|
218 |
data_uri = to_data_uri(image_bytes)
|
219 |
+
user_message['data'] = {
|
220 |
'fileText': '',
|
221 |
'imageBase64': data_uri,
|
222 |
+
'title': image_name or "Uploaded Image"
|
223 |
}
|
224 |
+
user_message['content'] = 'FILE:BB\n$#$\n\n$#$\n' + user_message['content']
|
225 |
logger.debug("Image data added to the message.")
|
226 |
except Exception as e:
|
227 |
logger.error(f"Failed to decode base64 image: {e}")
|
228 |
raise HTTPException(status_code=400, detail="Invalid image data provided.")
|
229 |
|
230 |
+
# Update the last message with user_message
|
231 |
+
if messages:
|
232 |
+
messages[-1] = user_message
|
233 |
+
else:
|
234 |
+
messages.append(user_message)
|
235 |
+
|
236 |
data = {
|
237 |
"messages": messages,
|
238 |
"id": random_id,
|
|
|
369 |
|
370 |
@app.post("/niansuhai/v1/chat/completions")
|
371 |
async def chat_completions(request: ChatRequest, req: Request):
|
372 |
+
logger.info(f"Received chat completions request: model='{request.model}' messages={request.messages} stream={request.stream} webSearchMode={request.webSearchMode} image={request.image}")
|
373 |
try:
|
374 |
+
# Convert Pydantic messages to dicts
|
375 |
messages = [{"role": msg.role, "content": msg.content} for msg in request.messages]
|
376 |
|
377 |
async_generator = Blackbox.create_async_generator(
|
|
|
388 |
try:
|
389 |
async for chunk in async_generator:
|
390 |
if isinstance(chunk, ImageResponse):
|
391 |
+
# Use the base64 data URI directly
|
392 |
image_markdown = f""
|
393 |
response_chunk = create_response(image_markdown, request.model)
|
394 |
else:
|