webscout 8.3.4__py3-none-any.whl → 8.3.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of webscout might be problematic. Click here for more details.

Files changed (98) hide show
  1. webscout/AIutel.py +52 -1016
  2. webscout/Bard.py +12 -6
  3. webscout/DWEBS.py +66 -57
  4. webscout/Provider/AISEARCH/PERPLEXED_search.py +214 -0
  5. webscout/Provider/AISEARCH/__init__.py +11 -10
  6. webscout/Provider/AISEARCH/felo_search.py +7 -3
  7. webscout/Provider/AISEARCH/scira_search.py +2 -0
  8. webscout/Provider/AISEARCH/stellar_search.py +53 -8
  9. webscout/Provider/Deepinfra.py +13 -1
  10. webscout/Provider/Flowith.py +6 -1
  11. webscout/Provider/GithubChat.py +1 -0
  12. webscout/Provider/GptOss.py +207 -0
  13. webscout/Provider/Kimi.py +445 -0
  14. webscout/Provider/Netwrck.py +3 -6
  15. webscout/Provider/OPENAI/README.md +2 -1
  16. webscout/Provider/OPENAI/TogetherAI.py +12 -8
  17. webscout/Provider/OPENAI/TwoAI.py +94 -1
  18. webscout/Provider/OPENAI/__init__.py +4 -4
  19. webscout/Provider/OPENAI/copilot.py +20 -4
  20. webscout/Provider/OPENAI/deepinfra.py +12 -0
  21. webscout/Provider/OPENAI/e2b.py +60 -8
  22. webscout/Provider/OPENAI/flowith.py +4 -3
  23. webscout/Provider/OPENAI/generate_api_key.py +48 -0
  24. webscout/Provider/OPENAI/gptoss.py +288 -0
  25. webscout/Provider/OPENAI/kimi.py +469 -0
  26. webscout/Provider/OPENAI/netwrck.py +8 -12
  27. webscout/Provider/OPENAI/refact.py +274 -0
  28. webscout/Provider/OPENAI/scirachat.py +4 -0
  29. webscout/Provider/OPENAI/textpollinations.py +11 -10
  30. webscout/Provider/OPENAI/toolbaz.py +1 -0
  31. webscout/Provider/OPENAI/venice.py +1 -0
  32. webscout/Provider/Perplexitylabs.py +163 -147
  33. webscout/Provider/Qodo.py +30 -6
  34. webscout/Provider/TTI/__init__.py +1 -0
  35. webscout/Provider/TTI/bing.py +14 -2
  36. webscout/Provider/TTI/together.py +11 -9
  37. webscout/Provider/TTI/venice.py +368 -0
  38. webscout/Provider/TTS/README.md +0 -1
  39. webscout/Provider/TTS/__init__.py +0 -1
  40. webscout/Provider/TTS/base.py +479 -159
  41. webscout/Provider/TTS/deepgram.py +409 -156
  42. webscout/Provider/TTS/elevenlabs.py +425 -111
  43. webscout/Provider/TTS/freetts.py +317 -140
  44. webscout/Provider/TTS/gesserit.py +192 -128
  45. webscout/Provider/TTS/murfai.py +248 -113
  46. webscout/Provider/TTS/openai_fm.py +347 -129
  47. webscout/Provider/TTS/speechma.py +620 -586
  48. webscout/Provider/TextPollinationsAI.py +11 -10
  49. webscout/Provider/TogetherAI.py +12 -4
  50. webscout/Provider/TwoAI.py +96 -2
  51. webscout/Provider/TypliAI.py +33 -27
  52. webscout/Provider/UNFINISHED/VercelAIGateway.py +339 -0
  53. webscout/Provider/UNFINISHED/fetch_together_models.py +6 -11
  54. webscout/Provider/Venice.py +1 -0
  55. webscout/Provider/WiseCat.py +18 -20
  56. webscout/Provider/__init__.py +2 -96
  57. webscout/Provider/cerebras.py +83 -33
  58. webscout/Provider/copilot.py +42 -23
  59. webscout/Provider/scira_chat.py +4 -0
  60. webscout/Provider/toolbaz.py +6 -10
  61. webscout/Provider/typefully.py +1 -11
  62. webscout/__init__.py +3 -15
  63. webscout/auth/__init__.py +19 -4
  64. webscout/auth/api_key_manager.py +189 -189
  65. webscout/auth/auth_system.py +25 -40
  66. webscout/auth/config.py +105 -6
  67. webscout/auth/database.py +377 -22
  68. webscout/auth/models.py +185 -130
  69. webscout/auth/request_processing.py +175 -11
  70. webscout/auth/routes.py +99 -2
  71. webscout/auth/server.py +9 -2
  72. webscout/auth/simple_logger.py +236 -0
  73. webscout/conversation.py +22 -20
  74. webscout/sanitize.py +1078 -0
  75. webscout/scout/README.md +20 -23
  76. webscout/scout/core/crawler.py +125 -38
  77. webscout/scout/core/scout.py +26 -5
  78. webscout/version.py +1 -1
  79. webscout/webscout_search.py +13 -6
  80. webscout/webscout_search_async.py +10 -8
  81. webscout/yep_search.py +13 -5
  82. {webscout-8.3.4.dist-info → webscout-8.3.6.dist-info}/METADATA +10 -149
  83. {webscout-8.3.4.dist-info → webscout-8.3.6.dist-info}/RECORD +88 -87
  84. webscout/Provider/Glider.py +0 -225
  85. webscout/Provider/OPENAI/README_AUTOPROXY.md +0 -238
  86. webscout/Provider/OPENAI/c4ai.py +0 -394
  87. webscout/Provider/OPENAI/glider.py +0 -330
  88. webscout/Provider/OPENAI/typegpt.py +0 -368
  89. webscout/Provider/OPENAI/uncovrAI.py +0 -477
  90. webscout/Provider/TTS/sthir.py +0 -94
  91. webscout/Provider/WritingMate.py +0 -273
  92. webscout/Provider/typegpt.py +0 -284
  93. webscout/Provider/uncovr.py +0 -333
  94. /webscout/Provider/{samurai.py → UNFINISHED/samurai.py} +0 -0
  95. {webscout-8.3.4.dist-info → webscout-8.3.6.dist-info}/WHEEL +0 -0
  96. {webscout-8.3.4.dist-info → webscout-8.3.6.dist-info}/entry_points.txt +0 -0
  97. {webscout-8.3.4.dist-info → webscout-8.3.6.dist-info}/licenses/LICENSE.md +0 -0
  98. {webscout-8.3.4.dist-info → webscout-8.3.6.dist-info}/top_level.txt +0 -0
@@ -1,19 +1,17 @@
1
- import ssl
2
1
  import json
3
2
  import time
4
- import socket
5
3
  import random
6
- from threading import Thread, Event
4
+ from threading import Event
7
5
  from curl_cffi import requests
8
- from websocket import WebSocketApp
9
- from typing import Dict, Any, Union, Generator, List, Optional
6
+ from typing import Dict, Any, Union, Generator
10
7
 
11
8
  from webscout.AIutel import Optimizers
12
9
  from webscout.AIutel import Conversation
13
- from webscout.AIutel import AwesomePrompts, sanitize_stream
10
+ from webscout.AIutel import AwesomePrompts
14
11
  from webscout.AIbase import Provider
15
12
  from webscout import exceptions
16
- from webscout.litagent import LitAgent
13
+
14
+ API_URL = "https://www.perplexity.ai/socket.io/"
17
15
 
18
16
  class PerplexityLabs(Provider):
19
17
  """
@@ -70,26 +68,16 @@ class PerplexityLabs(Provider):
70
68
  self.connected = Event()
71
69
  self.last_answer = None
72
70
 
73
- # Initialize session with headers using LitAgent user agent
74
- self.session = requests.Session(headers={
75
- 'User-Agent': LitAgent().random(),
76
- 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
77
- 'accept-language': 'en-US,en;q=0.9',
78
- 'cache-control': 'max-age=0',
79
- 'dnt': '1',
80
- 'priority': 'u=0, i',
81
- 'sec-ch-ua': '"Not;A=Brand";v="24", "Chromium";v="128"',
82
- 'sec-ch-ua-mobile': '?0',
83
- 'sec-ch-ua-platform': '"Windows"',
84
- 'sec-fetch-dest': 'document',
85
- 'sec-fetch-mode': 'navigate',
86
- 'sec-fetch-site': 'same-origin',
87
- 'sec-fetch-user': '?1',
88
- 'upgrade-insecure-requests': '1',
89
- })
71
+ # Initialize session with headers matching the working example
72
+ self.headers = {
73
+ "Origin": "https://labs.perplexity.ai",
74
+ "Referer": "https://labs.perplexity.ai/",
75
+ }
76
+ self.session = requests.Session(impersonate="chrome")
90
77
 
91
78
  # Apply proxies if provided
92
- self.session.proxies.update(proxies)
79
+ if proxies:
80
+ self.session.proxies.update(proxies)
93
81
 
94
82
  # Set up conversation handling
95
83
  self.is_conversation = is_conversation
@@ -117,14 +105,14 @@ class PerplexityLabs(Provider):
117
105
  self._initialize_connection()
118
106
 
119
107
  def _initialize_connection(self) -> None:
120
- """Initialize the connection to Perplexity with retries"""
108
+ """Initialize the connection to Perplexity using polling approach"""
121
109
  for attempt in range(1, self.max_retries + 1):
122
110
  try:
123
111
  # Get a session ID via polling
124
112
  self.timestamp = format(random.getrandbits(32), '08x')
125
- poll_url = f'https://www.perplexity.ai/socket.io/?EIO=4&transport=polling&t={self.timestamp}'
113
+ poll_url = f'{API_URL}?EIO=4&transport=polling&t={self.timestamp}'
126
114
 
127
- response = self.session.get(poll_url)
115
+ response = self.session.get(poll_url, headers=self.headers)
128
116
  if response.status_code != 200:
129
117
  if attempt == self.max_retries:
130
118
  raise ConnectionError(f"Failed to get session ID: HTTP {response.status_code}")
@@ -132,57 +120,35 @@ class PerplexityLabs(Provider):
132
120
 
133
121
  # Extract the session ID
134
122
  try:
135
- self.sid = json.loads(response.text[1:])['sid']
123
+ text = response.text
124
+ if not text.startswith("0"):
125
+ raise ConnectionError("Invalid response format")
126
+ self.sid = json.loads(text[1:])['sid']
136
127
  except (json.JSONDecodeError, KeyError) as e:
137
128
  if attempt == self.max_retries:
138
129
  raise ConnectionError(f"Failed to parse session ID: {e}")
139
130
  continue
140
131
 
141
132
  # Authenticate the session
142
- auth_url = f'https://www.perplexity.ai/socket.io/?EIO=4&transport=polling&t={self.timestamp}&sid={self.sid}'
143
- auth_response = self.session.post(auth_url, data='40{"jwt":"anonymous-ask-user"}')
133
+ self.auth_url = f'{API_URL}?EIO=4&transport=polling&t={self.timestamp}&sid={self.sid}'
134
+ post_data = '40{"jwt":"anonymous-ask-user"}'
135
+ auth_response = self.session.post(self.auth_url, data=post_data, headers=self.headers)
144
136
 
145
137
  if auth_response.status_code != 200 or auth_response.text != 'OK':
146
138
  if attempt == self.max_retries:
147
139
  raise ConnectionError("Authentication failed")
148
140
  continue
149
141
 
150
- # Setup SSL socket
151
- context = ssl.create_default_context()
152
- context.minimum_version = ssl.TLSVersion.TLSv1_3
153
- try:
154
- self.sock = context.wrap_socket(
155
- socket.create_connection(('www.perplexity.ai', 443), timeout=self.connection_timeout),
156
- server_hostname='www.perplexity.ai'
157
- )
158
- except (socket.timeout, socket.error, ssl.SSLError) as e:
142
+ # Get additional response to complete handshake
143
+ get_response = self.session.get(self.auth_url, headers=self.headers)
144
+ if get_response.status_code != 200:
159
145
  if attempt == self.max_retries:
160
- raise ConnectionError(f"Socket connection failed: {e}")
146
+ raise ConnectionError("Failed to complete authentication handshake")
161
147
  continue
162
148
 
163
- # Setup WebSocket
164
- ws_url = f'wss://www.perplexity.ai/socket.io/?EIO=4&transport=websocket&sid={self.sid}'
165
- cookies = '; '.join([f'{key}={value}' for key, value in self.session.cookies.get_dict().items()])
166
-
167
- self.connected.clear()
168
- self.ws = WebSocketApp(
169
- url=ws_url,
170
- header={'User-Agent': self.session.headers['User-Agent']},
171
- cookie=cookies,
172
- on_open=self._on_open,
173
- on_message=self._on_message,
174
- on_error=self._on_error,
175
- on_close=self._on_close,
176
- socket=self.sock
177
- )
178
-
179
- # Start WebSocket in a thread
180
- self.ws_thread = Thread(target=self.ws.run_forever, daemon=True)
181
- self.ws_thread.start()
182
-
183
- # Wait for connection to be established
184
- if self.connected.wait(timeout=self.connection_timeout):
185
- return
149
+ # Connection successful - using polling instead of WebSocket
150
+ self.connected.set()
151
+ return
186
152
 
187
153
  except Exception as e:
188
154
  if attempt == self.max_retries:
@@ -195,37 +161,107 @@ class PerplexityLabs(Provider):
195
161
 
196
162
  raise exceptions.FailedToGenerateResponseError("Failed to connect to Perplexity after multiple attempts")
197
163
 
198
- def _on_open(self, ws):
199
- """Handle websocket open event"""
200
- ws.send('2probe')
201
- ws.send('5')
164
+ def _send_query_polling(self, message_data):
165
+ """Send query using polling approach"""
166
+ payload = '42' + json.dumps(["perplexity_labs", message_data])
167
+ response = self.session.post(self.auth_url, data=payload, headers=self.headers, timeout=10)
168
+ return response.status_code == 200
202
169
 
203
- def _on_close(self, ws, close_status_code, close_msg):
204
- """Handle websocket close event"""
205
- self.connected.clear()
206
-
207
- def _on_message(self, ws, message):
208
- """Handle websocket message events"""
209
- if message == '2':
210
- ws.send('3')
211
-
212
- elif message == '3probe':
213
- self.connected.set()
214
-
215
- elif message.startswith('40'):
216
- self.connected.set()
170
+ def _poll_for_response(self, timeout_seconds):
171
+ """Poll for response using the polling approach"""
172
+ start_time = time.time()
173
+ last_message = 0
174
+ full_output = ""
175
+
176
+ while True:
177
+ if time.time() - start_time > timeout_seconds:
178
+ if last_message == 0:
179
+ raise exceptions.FailedToGenerateResponseError("Response timed out")
180
+ else:
181
+ # Return partial response if we got some content
182
+ yield {"text": "", "final": True, "full_output": full_output}
183
+ return
217
184
 
218
- elif message.startswith('42'):
219
185
  try:
220
- response = json.loads(message[2:])[1]
221
- if 'final' in response or 'partial' in response:
222
- self.last_answer = response
223
- except (json.JSONDecodeError, IndexError):
224
- pass
225
-
226
- def _on_error(self, ws, error):
227
- """Handle websocket error events"""
228
- self.connected.clear()
186
+ poll_response = self.session.get(self.auth_url, headers=self.headers, timeout=3)
187
+
188
+ if poll_response.status_code == 400:
189
+ # Session expired, try to return what we have
190
+ if full_output:
191
+ yield {"text": "", "final": True, "full_output": full_output}
192
+ return
193
+ else:
194
+ raise exceptions.FailedToGenerateResponseError("Session expired")
195
+
196
+ if poll_response.status_code != 200:
197
+ time.sleep(0.5)
198
+ continue
199
+
200
+ response_text = poll_response.text
201
+
202
+ # Handle heartbeat
203
+ if response_text == '2':
204
+ try:
205
+ self.session.post(self.auth_url, data='3', headers=self.headers, timeout=3)
206
+ except:
207
+ pass
208
+ continue
209
+
210
+ # Handle data messages containing output
211
+ if '42[' in response_text and 'output' in response_text:
212
+ try:
213
+ # Find the JSON part more reliably
214
+ start = response_text.find('42[')
215
+ if start != -1:
216
+ # Find the end of this JSON message
217
+ bracket_count = 0
218
+ json_start = start + 2
219
+ json_end = json_start
220
+
221
+ for j, char in enumerate(response_text[json_start:]):
222
+ if char == '[':
223
+ bracket_count += 1
224
+ elif char == ']':
225
+ bracket_count -= 1
226
+ if bracket_count == 0:
227
+ json_end = json_start + j + 1
228
+ break
229
+
230
+ json_str = response_text[json_start:json_end]
231
+ parsed_data = json.loads(json_str)
232
+
233
+ if len(parsed_data) > 1 and isinstance(parsed_data[1], dict):
234
+ data = parsed_data[1]
235
+
236
+ # Handle error responses
237
+ if data.get("status") == "failed":
238
+ error_message = data.get("text", "Unknown API error")
239
+ raise exceptions.FailedToGenerateResponseError(f"API Error: {error_message}")
240
+
241
+ # Handle normal responses
242
+ if "output" in data:
243
+ current_output = data["output"]
244
+ if len(current_output) > last_message:
245
+ delta = current_output[last_message:]
246
+ last_message = len(current_output)
247
+ full_output = current_output
248
+ yield {"text": delta, "final": data.get("final", False), "full_output": full_output}
249
+
250
+ if data.get("final", False):
251
+ return
252
+
253
+ except (json.JSONDecodeError, IndexError, KeyError) as e:
254
+ # Continue on parsing errors
255
+ pass
256
+
257
+ except Exception as e:
258
+ # Handle timeout and other errors more gracefully
259
+ if "timeout" in str(e).lower():
260
+ continue
261
+ time.sleep(0.5)
262
+ continue
263
+
264
+ time.sleep(0.5)
229
265
 
230
266
  def ask(
231
267
  self,
@@ -270,67 +306,47 @@ class PerplexityLabs(Provider):
270
306
  else:
271
307
  raise Exception(f"Optimizer is not one of {self.__available_optimizers}")
272
308
 
273
- self.last_answer = None
309
+ # Send the query using polling approach
310
+ message_data = {
311
+ "version": "2.18",
312
+ "source": "default",
313
+ "model": use_model,
314
+ "messages": [{"role": "user", "content": conversation_prompt}],
315
+ }
274
316
 
275
- # Send the query through websocket
276
- payload = json.dumps([
277
- 'perplexity_labs',
278
- {
279
- 'messages': [{'role': 'user', 'content': conversation_prompt}],
280
- 'model': use_model,
281
- 'source': 'default',
282
- 'version': '2.18',
283
- }
284
- ])
285
- self.ws.send('42' + payload)
317
+ # Send query
318
+ if not self._send_query_polling(message_data):
319
+ raise exceptions.FailedToGenerateResponseError("Failed to send query")
286
320
 
287
321
  def for_stream():
288
- """Handle streaming responses"""
289
- last_seen = None
290
- start_time = time.time()
291
- streaming_text = ""
292
-
293
- while True:
294
- # Check for timeout
295
- if time.time() - start_time > self.timeout:
296
- raise exceptions.FailedToGenerateResponseError("Response stream timed out")
297
-
298
- # If we have a new response different from what we've seen
299
- if self.last_answer != last_seen:
300
- last_seen = self.last_answer
301
- if last_seen is not None:
302
- if 'output' in last_seen:
303
- current_output = last_seen['output']
304
- # For delta output in streaming
305
- delta = current_output[len(streaming_text):]
306
- streaming_text = current_output
307
- resp = dict(text=delta)
308
- yield resp if raw else resp
322
+ """Handle streaming responses using polling"""
323
+ full_text = ""
324
+ for response_chunk in self._poll_for_response(self.timeout):
325
+ if response_chunk["text"]:
326
+ full_text += response_chunk["text"]
327
+ yield dict(text=response_chunk["text"]) if raw else dict(text=response_chunk["text"])
309
328
 
310
- # If we have the final response, add to history and return
311
- if self.last_answer and self.last_answer.get('final', False):
312
- answer = self.last_answer
313
- self.conversation.update_chat_history(prompt, streaming_text)
329
+ if response_chunk["final"]:
330
+ self.conversation.update_chat_history(prompt, full_text)
314
331
  return
315
-
316
- time.sleep(0.01)
317
332
 
318
333
  def for_non_stream():
319
- """Handle non-streaming responses"""
320
- start_time = time.time()
321
-
322
- while True:
323
- # Check for successful response
324
- if self.last_answer and self.last_answer.get('final', False):
325
- answer = self.last_answer
326
- self.conversation.update_chat_history(prompt, answer['output'])
327
- return answer if raw else dict(text=answer['output'])
334
+ """Handle non-streaming responses using polling"""
335
+ full_text = ""
336
+ for response_chunk in self._poll_for_response(self.timeout):
337
+ if response_chunk["text"]:
338
+ full_text += response_chunk["text"]
328
339
 
329
- # Check for timeout
330
- if time.time() - start_time > self.timeout:
331
- raise exceptions.FailedToGenerateResponseError("Response timed out")
332
-
333
- time.sleep(0.01)
340
+ if response_chunk["final"]:
341
+ self.conversation.update_chat_history(prompt, full_text)
342
+ return dict(text=full_text) if raw else dict(text=full_text)
343
+
344
+ # If we get here, no final response was received
345
+ if full_text:
346
+ self.conversation.update_chat_history(prompt, full_text)
347
+ return dict(text=full_text) if raw else dict(text=full_text)
348
+ else:
349
+ raise exceptions.FailedToGenerateResponseError("No response received")
334
350
 
335
351
  return for_stream() if stream else for_non_stream()
336
352
 
@@ -396,7 +412,7 @@ if __name__ == "__main__":
396
412
 
397
413
  for model in PerplexityLabs.AVAILABLE_MODELS:
398
414
  try:
399
- test_ai = PerplexityLabs(model=model, timeout=60)
415
+ test_ai = PerplexityLabs(model=model, timeout=30, connection_timeout=5.0)
400
416
  response = test_ai.chat("Say 'Hello' in one word", stream=True)
401
417
  response_text = ""
402
418
  for chunk in response:
@@ -412,4 +428,4 @@ if __name__ == "__main__":
412
428
  display_text = "Empty or invalid response"
413
429
  print(f"\r{model:<50} {status:<10} {display_text}")
414
430
  except Exception as e:
415
- print(f"\r{model:<50} {'✗':<10} {str(e)}")
431
+ print(f"\r{model:<50} {'✗':<10} {str(e)[:80]}")
webscout/Provider/Qodo.py CHANGED
@@ -23,6 +23,7 @@ class QodoAI(Provider):
23
23
  "o4-mini",
24
24
  "claude-4-sonnet",
25
25
  "gemini-2.5-pro",
26
+ "grok-4"
26
27
 
27
28
  ]
28
29
 
@@ -225,15 +226,27 @@ class QodoAI(Provider):
225
226
  payload = self._build_payload(conversation_prompt)
226
227
  payload["stream"] = stream
227
228
 
229
+
228
230
  def for_stream():
229
231
  try:
230
232
  response = self.session.post(
231
- self.url,
232
- json=payload,
233
- stream=True,
233
+ self.url,
234
+ json=payload,
235
+ stream=True,
234
236
  timeout=self.timeout,
235
237
  impersonate=self.fingerprint.get("browser_type", "chrome110")
236
238
  )
239
+ # Check for internal server error with session ID in the response
240
+ if response.status_code == 500 and response.text and "Internal server error, session ID:" in response.text:
241
+ # Switch to continue-task endpoint and retry
242
+ self.url = "https://api.cli.qodo.ai/v2/agentic/continue-task"
243
+ response = self.session.post(
244
+ self.url,
245
+ json=payload,
246
+ stream=True,
247
+ timeout=self.timeout,
248
+ impersonate=self.fingerprint.get("browser_type", "chrome110")
249
+ )
237
250
  if response.status_code == 401:
238
251
  raise exceptions.FailedToGenerateResponseError(
239
252
  "Invalid API key. You need to provide your own API key.\n"
@@ -270,11 +283,20 @@ class QodoAI(Provider):
270
283
  try:
271
284
  payload["stream"] = False
272
285
  response = self.session.post(
273
- self.url,
274
- json=payload,
286
+ self.url,
287
+ json=payload,
275
288
  timeout=self.timeout,
276
289
  impersonate=self.fingerprint.get("browser_type", "chrome110")
277
290
  )
291
+ # Check for internal server error with session ID in the response
292
+ if response.status_code == 500 and response.text and "Internal server error, session ID:" in response.text:
293
+ self.url = "https://api.cli.qodo.ai/v2/agentic/continue-task"
294
+ response = self.session.post(
295
+ self.url,
296
+ json=payload,
297
+ timeout=self.timeout,
298
+ impersonate=self.fingerprint.get("browser_type", "chrome110")
299
+ )
278
300
  if response.status_code == 401:
279
301
  raise exceptions.FailedToGenerateResponseError(
280
302
  "Invalid API key. You need to provide your own API key.\n"
@@ -386,7 +408,9 @@ class QodoAI(Provider):
386
408
  )
387
409
 
388
410
  # Fallback to generated session ID if API call fails
389
- return f"20250630-{str(uuid.uuid4())}"
411
+ from datetime import datetime
412
+ today = datetime.now().strftime("%Y%m%d")
413
+ return f"{today}-{str(uuid.uuid4())}"
390
414
 
391
415
  except exceptions.FailedToGenerateResponseError:
392
416
  # Re-raise our custom exceptions
@@ -9,3 +9,4 @@ from .together import *
9
9
  from .bing import *
10
10
  from .infip import *
11
11
  from .monochat import *
12
+ from .venice import *
@@ -20,7 +20,7 @@ class Images(BaseImages):
20
20
  def create(
21
21
  self,
22
22
  *,
23
- model: str = "bing",
23
+ model: str = "dalle",
24
24
  prompt: str,
25
25
  n: int = 1,
26
26
  size: str = "1024x1024",
@@ -42,10 +42,21 @@ class Images(BaseImages):
42
42
  headers = self._client.headers
43
43
  images = []
44
44
  urls = []
45
+
46
+ # Map model names to Bing model codes
47
+ model_mapping = {
48
+ "dalle": "0",
49
+ "gpt4o": "1",
50
+ }
51
+
52
+ # Get the appropriate model code
53
+ model_code = model_mapping.get(model.lower(), "4")
54
+
45
55
  for _ in range(n):
46
56
  data = {
47
57
  "q": prompt,
48
58
  "rt": "4",
59
+ "mdl": model_code,
49
60
  "FORM": "GENCRE"
50
61
  }
51
62
  response = session.post(
@@ -221,8 +232,9 @@ class BingImageAI(TTICompatibleProvider):
221
232
 
222
233
  if __name__ == "__main__":
223
234
  from rich import print
224
- client = BingImageAI(cookie="1pkdvumH1SEjFkDjFymRYKouIRoXZlh_p5RTfAttx4DaaNOSDyz8qFP2M7LbZ93fbl4f6Xm8fTGwXHNDB648Gom5jfnTU_Iz-VH47l0HTYJDS1sItbBBS-sqSISFgXR62SoqnW5eX5MFht-j2uB1gZ4uDnpR_60fLRTCdW1SIRegDvnBm1TGhRiZsi6wUPyzwFg7-PsXAs3Fq9iV9m-0FEw")
235
+ client = BingImageAI(cookie="1QyBY4Z1eHBW6fbI25kdM5TrlRGWzn5PFySapCOfvvz04zaounFG660EipVJSOXXvcdeXXLwsWHdDI8bNymucF_QnMHSlY1mc0pPI7e9Ar6o-_7e9Ik5QOe1nkJIe5vz22pibioTqx0IfVKwmVbX22A3bFD7ODaSZalKFr-AuxgAaRVod-giTTry6Ei7RVgisF7BHlkMPPwtCeO234ujgug")
225
236
  response = client.images.create(
237
+ model="gpt4o",
226
238
  prompt="A cat riding a bicycle",
227
239
  response_format="url",
228
240
  n=4,
@@ -202,23 +202,25 @@ class Images(BaseImages):
202
202
  class TogetherImage(TTICompatibleProvider):
203
203
  """
204
204
  Together.xyz Text-to-Image provider
205
- Updated: 2025-06-02 10:42:41 UTC by OEvortex
205
+ Updated: 2025-08-01 10:42:41 UTC by OEvortex
206
206
  Supports FLUX and other image generation models
207
207
  """
208
208
 
209
209
  # Image models from Together.xyz API (filtered for image type only)
210
210
  AVAILABLE_MODELS = [
211
- "black-forest-labs/FLUX.1-schnell-Free",
212
- "black-forest-labs/FLUX.1.1-pro",
213
- "black-forest-labs/FLUX.1-pro",
214
- "black-forest-labs/FLUX.1-redux",
215
- "black-forest-labs/FLUX.1-depth",
216
211
  "black-forest-labs/FLUX.1-canny",
217
- "black-forest-labs/FLUX.1-kontext-max",
218
- "black-forest-labs/FLUX.1-dev-lora",
219
- "black-forest-labs/FLUX.1-schnell",
212
+ "black-forest-labs/FLUX.1-depth",
220
213
  "black-forest-labs/FLUX.1-dev",
214
+ "black-forest-labs/FLUX.1-dev-lora",
215
+ "black-forest-labs/FLUX.1-kontext-dev",
216
+ "black-forest-labs/FLUX.1-kontext-max",
221
217
  "black-forest-labs/FLUX.1-kontext-pro",
218
+ "black-forest-labs/FLUX.1-krea-dev",
219
+ "black-forest-labs/FLUX.1-pro",
220
+ "black-forest-labs/FLUX.1-redux",
221
+ "black-forest-labs/FLUX.1-schnell",
222
+ "black-forest-labs/FLUX.1-schnell-Free",
223
+ "black-forest-labs/FLUX.1.1-pro"
222
224
  ]
223
225
 
224
226
  def __init__(self):