webscout 8.3.5__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 (63) hide show
  1. webscout/Bard.py +12 -6
  2. webscout/DWEBS.py +66 -57
  3. webscout/Provider/{UNFINISHED → AISEARCH}/PERPLEXED_search.py +34 -74
  4. webscout/Provider/AISEARCH/__init__.py +1 -1
  5. webscout/Provider/Deepinfra.py +6 -0
  6. webscout/Provider/Flowith.py +6 -1
  7. webscout/Provider/GithubChat.py +1 -0
  8. webscout/Provider/GptOss.py +207 -0
  9. webscout/Provider/Kimi.py +445 -0
  10. webscout/Provider/Netwrck.py +3 -6
  11. webscout/Provider/OPENAI/README.md +2 -1
  12. webscout/Provider/OPENAI/TogetherAI.py +50 -55
  13. webscout/Provider/OPENAI/__init__.py +4 -2
  14. webscout/Provider/OPENAI/copilot.py +20 -4
  15. webscout/Provider/OPENAI/deepinfra.py +6 -0
  16. webscout/Provider/OPENAI/e2b.py +60 -8
  17. webscout/Provider/OPENAI/flowith.py +4 -3
  18. webscout/Provider/OPENAI/generate_api_key.py +48 -0
  19. webscout/Provider/OPENAI/gptoss.py +288 -0
  20. webscout/Provider/OPENAI/kimi.py +469 -0
  21. webscout/Provider/OPENAI/netwrck.py +8 -12
  22. webscout/Provider/OPENAI/refact.py +274 -0
  23. webscout/Provider/OPENAI/textpollinations.py +3 -6
  24. webscout/Provider/OPENAI/toolbaz.py +1 -0
  25. webscout/Provider/TTI/bing.py +14 -2
  26. webscout/Provider/TTI/together.py +10 -9
  27. webscout/Provider/TTS/README.md +0 -1
  28. webscout/Provider/TTS/__init__.py +0 -1
  29. webscout/Provider/TTS/base.py +479 -159
  30. webscout/Provider/TTS/deepgram.py +409 -156
  31. webscout/Provider/TTS/elevenlabs.py +425 -111
  32. webscout/Provider/TTS/freetts.py +317 -140
  33. webscout/Provider/TTS/gesserit.py +192 -128
  34. webscout/Provider/TTS/murfai.py +248 -113
  35. webscout/Provider/TTS/openai_fm.py +347 -129
  36. webscout/Provider/TTS/speechma.py +620 -586
  37. webscout/Provider/TextPollinationsAI.py +3 -6
  38. webscout/Provider/TogetherAI.py +50 -55
  39. webscout/Provider/UNFINISHED/VercelAIGateway.py +339 -0
  40. webscout/Provider/__init__.py +2 -90
  41. webscout/Provider/cerebras.py +83 -33
  42. webscout/Provider/copilot.py +42 -23
  43. webscout/Provider/toolbaz.py +1 -0
  44. webscout/conversation.py +22 -20
  45. webscout/sanitize.py +14 -10
  46. webscout/scout/README.md +20 -23
  47. webscout/scout/core/crawler.py +125 -38
  48. webscout/scout/core/scout.py +26 -5
  49. webscout/version.py +1 -1
  50. webscout/webscout_search.py +13 -6
  51. webscout/webscout_search_async.py +10 -8
  52. webscout/yep_search.py +13 -5
  53. {webscout-8.3.5.dist-info → webscout-8.3.6.dist-info}/METADATA +2 -1
  54. {webscout-8.3.5.dist-info → webscout-8.3.6.dist-info}/RECORD +59 -56
  55. webscout/Provider/Glider.py +0 -225
  56. webscout/Provider/OPENAI/c4ai.py +0 -394
  57. webscout/Provider/OPENAI/glider.py +0 -330
  58. webscout/Provider/TTS/sthir.py +0 -94
  59. /webscout/Provider/{samurai.py → UNFINISHED/samurai.py} +0 -0
  60. {webscout-8.3.5.dist-info → webscout-8.3.6.dist-info}/WHEEL +0 -0
  61. {webscout-8.3.5.dist-info → webscout-8.3.6.dist-info}/entry_points.txt +0 -0
  62. {webscout-8.3.5.dist-info → webscout-8.3.6.dist-info}/licenses/LICENSE.md +0 -0
  63. {webscout-8.3.5.dist-info → webscout-8.3.6.dist-info}/top_level.txt +0 -0
@@ -1,394 +0,0 @@
1
- import time
2
- import uuid
3
- import requests
4
- import json
5
- import re
6
- from typing import List, Dict, Optional, Union, Generator, Any
7
-
8
- # Import base classes and utility structures
9
- from .base import OpenAICompatibleProvider, BaseChat, BaseCompletions
10
- from .utils import (
11
- ChatCompletionChunk, ChatCompletion, Choice, ChoiceDelta,
12
- ChatCompletionMessage, CompletionUsage,
13
- get_system_prompt, get_last_user_message, format_prompt, count_tokens # Import format_prompt
14
- )
15
-
16
- # Attempt to import LitAgent, fallback if not available
17
- try:
18
- from webscout.litagent import LitAgent
19
- except ImportError:
20
- # Define a dummy LitAgent if webscout is not installed or accessible
21
- class LitAgent:
22
- def generate_fingerprint(self, browser: str = "chrome") -> Dict[str, Any]:
23
- # Return minimal default headers if LitAgent is unavailable
24
- print("Warning: LitAgent not found. Using default minimal headers.")
25
- return {
26
- "accept": "*/*",
27
- "accept_language": "en-US,en;q=0.9",
28
- "platform": "Windows",
29
- "sec_ch_ua": '"Not/A)Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"',
30
- "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
31
- "browser_type": browser,
32
- }
33
- def random(self) -> str:
34
- # Return a default user agent if LitAgent is unavailable
35
- print("Warning: LitAgent not found. Using default user agent.")
36
- return "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"
37
-
38
-
39
- class Completions(BaseCompletions):
40
- def __init__(self, client: 'C4AI'):
41
- self._client = client
42
-
43
- def create(
44
- self,
45
- *,
46
- model: str,
47
- messages: List[Dict[str, str]],
48
- max_tokens: Optional[int] = 2000,
49
- stream: bool = False,
50
- temperature: Optional[float] = None,
51
- top_p: Optional[float] = None,
52
- timeout: Optional[int] = None,
53
- proxies: Optional[dict] = None,
54
- **kwargs: Any
55
- ) -> Union[ChatCompletion, Generator[ChatCompletionChunk, None, None]]:
56
- """
57
- Creates a model response for the given chat conversation.
58
- Mimics openai.chat.completions.create
59
- """
60
- # Extract system prompt using utility function
61
- system_prompt = get_system_prompt(messages)
62
- if not system_prompt:
63
- system_prompt = "You are a helpful assistant."
64
-
65
- # Format the conversation history using format_prompt
66
- # Note: C4AI API might expect only the *last* user message here.
67
- # Sending the full history might cause issues.
68
- # We exclude the system prompt from format_prompt as it's sent separately.
69
- # We also set do_continue=True as C4AI adds its own assistant prompt implicitly.
70
- conversation_prompt = format_prompt(messages, include_system=False, do_continue=True)
71
-
72
- if not conversation_prompt:
73
- # Fallback to last user message if formatted prompt is empty
74
- last_user_message = get_last_user_message(messages)
75
- if not last_user_message:
76
- raise ValueError("No user message found or formatted prompt is empty.")
77
- conversation_prompt = last_user_message
78
-
79
- # Create or get conversation ID
80
- if model not in self._client._conversation_data:
81
- conversation_id = self._client.create_conversation(model, system_prompt)
82
- if not conversation_id:
83
- raise IOError(f"Failed to create conversation with model {model}")
84
- else:
85
- conversation_id = self._client._conversation_data[model]["conversationId"]
86
- self._client._conversation_data[model]["messageId"] = self._client.fetch_message_id(conversation_id)
87
-
88
- request_id = f"chatcmpl-{uuid.uuid4()}"
89
- created_time = int(time.time())
90
-
91
- # Pass the formatted conversation prompt
92
- if stream:
93
- return self._create_stream(request_id, created_time, model, conversation_id, conversation_prompt, system_prompt, timeout=timeout, proxies=proxies)
94
- else:
95
- return self._create_non_stream(request_id, created_time, model, conversation_id, conversation_prompt, system_prompt, timeout=timeout, proxies=proxies)
96
-
97
- def _create_stream(
98
- self, request_id: str, created_time: int, model: str, conversation_id: str, prompt: str, system_prompt: str,
99
- timeout: Optional[int] = None, proxies: Optional[dict] = None
100
- ) -> Generator[ChatCompletionChunk, None, None]:
101
- original_proxies = self._client.session.proxies
102
- if proxies is not None:
103
- self._client.session.proxies = proxies
104
- else:
105
- self._client.session.proxies = {}
106
- try:
107
- timeout_val = timeout if timeout is not None else self._client.timeout
108
- message_id = self._client._conversation_data[model]["messageId"]
109
- url = f"{self._client.url}/api/chat/message"
110
- payload = {
111
- "conversationId": conversation_id,
112
- "messageId": message_id,
113
- "model": model,
114
- "prompt": prompt, # Use the formatted conversation history as prompt
115
- "preprompt": system_prompt,
116
- "temperature": 0.7,
117
- "top_p": 1,
118
- "top_k": 50,
119
- "max_tokens": self._client.max_tokens_to_sample,
120
- "stop": [],
121
- "stream": True
122
- }
123
-
124
- response = self._client.session.post(
125
- url,
126
- headers=self._client.headers,
127
- json=payload,
128
- stream=True,
129
- timeout=timeout_val,
130
- proxies=proxies or getattr(self._client, "proxies", None)
131
- )
132
- response.raise_for_status()
133
-
134
- full_text = ""
135
- for line in response.iter_lines():
136
- if line:
137
- line = line.decode('utf-8')
138
- if line.startswith('data: '):
139
- data = line[6:]
140
- if data == "[DONE]":
141
- break
142
-
143
- try:
144
- json_data = json.loads(data)
145
- delta_text = json_data.get('text', '')
146
- new_content = delta_text[len(full_text):]
147
- full_text = delta_text
148
- delta = ChoiceDelta(content=new_content)
149
- choice = Choice(index=0, delta=delta, finish_reason=None)
150
- chunk = ChatCompletionChunk(
151
- id=request_id,
152
- choices=[choice],
153
- created=created_time,
154
- model=model
155
- )
156
- yield chunk
157
- except json.JSONDecodeError:
158
- continue
159
-
160
- delta = ChoiceDelta(content=None)
161
- choice = Choice(index=0, delta=delta, finish_reason="stop")
162
- chunk = ChatCompletionChunk(
163
- id=request_id,
164
- choices=[choice],
165
- created=created_time,
166
- model=model
167
- )
168
- yield chunk
169
-
170
- except Exception as e:
171
- print(f"Error during C4AI stream request: {e}")
172
- raise IOError(f"C4AI request failed: {e}") from e
173
- finally:
174
- self._client.session.proxies = original_proxies
175
-
176
- def _create_non_stream(
177
- self, request_id: str, created_time: int, model: str, conversation_id: str, prompt: str, system_prompt: str,
178
- timeout: Optional[int] = None, proxies: Optional[dict] = None
179
- ) -> ChatCompletion:
180
- original_proxies = self._client.session.proxies
181
- if proxies is not None:
182
- self._client.session.proxies = proxies
183
- else:
184
- self._client.session.proxies = {}
185
- try:
186
- timeout_val = timeout if timeout is not None else self._client.timeout
187
- message_id = self._client._conversation_data[model]["messageId"]
188
- url = f"{self._client.url}/api/chat/message"
189
- payload = {
190
- "conversationId": conversation_id,
191
- "messageId": message_id,
192
- "model": model,
193
- "prompt": prompt, # Use the formatted conversation history as prompt
194
- "preprompt": system_prompt,
195
- "temperature": 0.7,
196
- "top_p": 1,
197
- "top_k": 50,
198
- "max_tokens": self._client.max_tokens_to_sample,
199
- "stop": [],
200
- "stream": False
201
- }
202
-
203
- response = self._client.session.post(
204
- url,
205
- headers=self._client.headers,
206
- json=payload,
207
- timeout=timeout_val,
208
- proxies=proxies or getattr(self._client, "proxies", None)
209
- )
210
- response.raise_for_status()
211
-
212
- data = response.json()
213
- response_text = data.get('text', '')
214
- message = ChatCompletionMessage(role="assistant", content=response_text)
215
- choice = Choice(index=0, message=message, finish_reason="stop")
216
- # Estimate tokens based on the formatted prompt
217
- prompt_tokens = count_tokens(prompt)
218
- completion_tokens = count_tokens(response_text)
219
- usage = CompletionUsage(
220
- prompt_tokens=prompt_tokens,
221
- completion_tokens=completion_tokens,
222
- total_tokens=prompt_tokens + completion_tokens
223
- )
224
- completion = ChatCompletion(
225
- id=request_id,
226
- choices=[choice],
227
- created=created_time,
228
- model=model,
229
- usage=usage
230
- )
231
- return completion
232
-
233
- except Exception as e:
234
- print(f"Error during C4AI non-stream request: {e}")
235
- raise IOError(f"C4AI request failed: {e}") from e
236
- finally:
237
- self._client.session.proxies = original_proxies
238
-
239
- class Chat(BaseChat):
240
- def __init__(self, client: 'C4AI'):
241
- self.completions = Completions(client)
242
-
243
- class C4AI(OpenAICompatibleProvider):
244
- """
245
- OpenAI-compatible client for C4AI API.
246
-
247
- Usage:
248
- client = C4AI()
249
- response = client.chat.completions.create(
250
- model="command-a-03-2025",
251
- messages=[{"role": "user", "content": "Hello!"}]
252
- )
253
- """
254
-
255
- AVAILABLE_MODELS = [
256
- 'command-a-03-2025',
257
- 'command-r-plus-08-2024',
258
- 'command-r-08-2024',
259
- 'command-r-plus',
260
- 'command-r',
261
- 'command-r7b-12-2024',
262
- 'command-r7b-arabic-02-2025'
263
- ]
264
-
265
- def __init__(
266
- self,
267
- browser: str = "chrome"
268
- ):
269
- """
270
- Initialize the C4AI client.
271
-
272
- Args:
273
- browser: Browser name for LitAgent to generate User-Agent.
274
- """
275
- self.timeout = 30
276
- self.url = "https://cohereforai-c4ai-command.hf.space"
277
- self.session = requests.Session()
278
- self.session.proxies = {}
279
- self.max_tokens_to_sample = 2000
280
-
281
- agent = LitAgent()
282
- fingerprint = agent.generate_fingerprint(browser)
283
-
284
- self.headers = {
285
- "Content-Type": "application/json",
286
- "User-Agent": fingerprint["user_agent"],
287
- "Accept": "*/*",
288
- "Accept-Encoding": "gzip, deflate, br, zstd",
289
- "Accept-Language": fingerprint["accept_language"],
290
- "Origin": "https://cohereforai-c4ai-command.hf.space",
291
- "Referer": "https://cohereforai-c4ai-command.hf.space/",
292
- "Sec-Ch-Ua": fingerprint["sec_ch_ua"] or "\"Chromium\";v=\"120\"",
293
- "Sec-Ch-Ua-Mobile": "?0",
294
- "Sec-Ch-Ua-Platform": f"\"{fingerprint['platform']}\"",
295
- "Sec-Fetch-Dest": "empty",
296
- "Sec-Fetch-Mode": "cors",
297
- "Sec-Fetch-Site": "same-origin",
298
- "DNT": "1",
299
- "Priority": "u=1, i"
300
- }
301
-
302
- self._conversation_data = {}
303
- self.chat = Chat(self)
304
- self.update_available_models()
305
-
306
- def update_available_models(self):
307
- """Update the list of available models from the server."""
308
- try:
309
- response = requests.get("https://cohereforai-c4ai-command.hf.space/")
310
- text = response.text
311
- models_match = re.search(r'models:(\[.+?\]),oldModels:', text)
312
-
313
- if not models_match:
314
- return
315
-
316
- models_text = models_match.group(1)
317
- models_text = re.sub(r',parameters:{[^}]+?}', '', models_text)
318
- models_text = models_text.replace('void 0', 'null')
319
-
320
- def add_quotation_mark(match):
321
- return f'{match.group(1)}"{match.group(2)}":'
322
-
323
- models_text = re.sub(r'([{,])([A-Za-z0-9_]+?):', add_quotation_mark, models_text)
324
-
325
- models_data = json.loads(models_text)
326
- self.AVAILABLE_MODELS = [model["id"] for model in models_data]
327
- except Exception:
328
- pass
329
-
330
- def create_conversation(self, model: str, system_prompt: str):
331
- """Create a new conversation with the specified model."""
332
- url = f"{self.url}/api/conversation"
333
- payload = {
334
- "model": model,
335
- "preprompt": system_prompt,
336
- }
337
-
338
- try:
339
- response = self.session.post(
340
- url,
341
- headers=self.headers,
342
- json=payload,
343
- timeout=self.timeout
344
- )
345
- response.raise_for_status()
346
-
347
- data = response.json()
348
- conversation_id = data.get("conversationId")
349
-
350
- if conversation_id:
351
- self._conversation_data[model] = {
352
- "conversationId": conversation_id,
353
- "messageId": self.fetch_message_id(conversation_id)
354
- }
355
- return conversation_id
356
-
357
- return None
358
-
359
- except Exception as e:
360
- print(f"Error creating conversation: {e}")
361
- return None
362
-
363
- def fetch_message_id(self, conversation_id: str):
364
- """Fetch the latest message ID for a conversation."""
365
- url = f"{self.url}/api/conversation/{conversation_id}"
366
-
367
- try:
368
- response = self.session.get(
369
- url,
370
- headers=self.headers,
371
- timeout=self.timeout
372
- )
373
- response.raise_for_status()
374
-
375
- json_data = response.json()
376
-
377
- if json_data.get("nodes", []) and json_data["nodes"][-1].get("type") == "error":
378
- return str(uuid.uuid4())
379
-
380
- data = json_data["nodes"][1]["data"]
381
- keys = data[data[0]["messages"]]
382
- message_keys = data[keys[-1]]
383
- message_id = data[message_keys["id"]]
384
-
385
- return message_id
386
-
387
- except Exception:
388
- return str(uuid.uuid4())
389
- @property
390
- def models(self):
391
- class _ModelList:
392
- def list(inner_self):
393
- return type(self).AVAILABLE_MODELS
394
- return _ModelList()