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
@@ -53,7 +53,12 @@ class Stellar(AISearch):
53
53
 
54
54
  @staticmethod
55
55
  def _stellar_extractor(chunk: Union[str, bytes, Dict[str, Any]]) -> Optional[str]:
56
- """Extracts content from the Stellar stream format with hex keys and diff arrays. Handles both str and bytes input."""
56
+ """
57
+ Extracts content from the Stellar stream format with focused pattern matching.
58
+
59
+ Prioritizes the primary diff pattern to avoid duplication and focuses on
60
+ incremental content building from stellar.chatastra.ai streaming response.
61
+ """
57
62
  if isinstance(chunk, bytes):
58
63
  try:
59
64
  chunk = chunk.decode('utf-8', errors='replace')
@@ -61,14 +66,54 @@ class Stellar(AISearch):
61
66
  return None
62
67
  if not isinstance(chunk, str):
63
68
  return None
64
- # Match patterns like 6e:{"diff":[0," empathy"],"next":"$@6f"}
65
- pattern = r'[0-9a-f]+:\{"diff":\[0,"([^"\\]*)"\]'
66
- matches = re.findall(pattern, chunk)
67
- if matches:
68
- extracted_text = ''.join(matches)
69
- # Fix escaped newlines
70
- extracted_text = extracted_text.replace('\\n', '\n').replace('\\n\\n', '\n\n')
69
+
70
+ # Primary pattern: Hex key diff format (most reliable for streaming)
71
+ # Matches: 16:{"diff":[0,"AI"],"next":"$@18"}
72
+ primary_pattern = r'[0-9a-f]+:\{"diff":\[0,"([^"]*?)"\]'
73
+ primary_matches = re.findall(primary_pattern, chunk)
74
+
75
+ if primary_matches:
76
+ # Join the matches and clean up
77
+ extracted_text = ''.join(primary_matches)
78
+
79
+ # Handle escape sequences properly
80
+ extracted_text = extracted_text.replace('\\n', '\n')
81
+ extracted_text = extracted_text.replace('\\r', '\r')
82
+ extracted_text = extracted_text.replace('\\"', '"')
83
+ extracted_text = extracted_text.replace('\\t', '\t')
84
+ extracted_text = extracted_text.replace('\\/', '/')
85
+ extracted_text = extracted_text.replace('\\\\', '\\')
86
+
87
+ # Clean up markdown formatting
88
+ extracted_text = extracted_text.replace('\\*', '*')
89
+ extracted_text = extracted_text.replace('\\#', '#')
90
+ extracted_text = extracted_text.replace('\\[', '[')
91
+ extracted_text = extracted_text.replace('\\]', ']')
92
+ extracted_text = extracted_text.replace('\\(', '(')
93
+ extracted_text = extracted_text.replace('\\)', ')')
94
+
71
95
  return extracted_text if extracted_text.strip() else None
96
+
97
+ # # Fallback: Look for Ta24 content blocks (complete responses)
98
+ # if ':Ta24,' in chunk:
99
+ # ta24_pattern = r':Ta24,([^}]*?)(?:\d+:|$)'
100
+ # ta24_matches = re.findall(ta24_pattern, chunk)
101
+ # if ta24_matches:
102
+ # extracted_text = ''.join(ta24_matches)
103
+ # # Basic cleanup
104
+ # extracted_text = extracted_text.replace('\\n', '\n')
105
+ # extracted_text = extracted_text.replace('\\"', '"')
106
+ # return extracted_text.strip() if extracted_text.strip() else None
107
+
108
+ # # Secondary fallback: Direct diff patterns without hex prefix
109
+ # fallback_pattern = r'\{"diff":\[0,"([^"]*?)"\]'
110
+ # fallback_matches = re.findall(fallback_pattern, chunk)
111
+ # if fallback_matches:
112
+ # extracted_text = ''.join(fallback_matches)
113
+ # extracted_text = extracted_text.replace('\\n', '\n')
114
+ # extracted_text = extracted_text.replace('\\"', '"')
115
+ # return extracted_text if extracted_text.strip() else None
116
+
72
117
  return None
73
118
 
74
119
  def search(self, prompt: str, stream: bool = False, raw: bool = False) -> Union[SearchResponse, Generator[Union[Dict[str, str], SearchResponse, str], None, None]]:
@@ -18,8 +18,13 @@ class DeepInfra(Provider):
18
18
 
19
19
  AVAILABLE_MODELS = [
20
20
  "anthropic/claude-4-opus",
21
+ "moonshotai/Kimi-K2-Instruct",
21
22
  "anthropic/claude-4-sonnet",
22
23
  "deepseek-ai/DeepSeek-R1-0528-Turbo",
24
+ "Qwen/Qwen3-235B-A22B-Thinking-2507",
25
+ "Qwen/Qwen3-Coder-480B-A35B-Instruct",
26
+ "Qwen/Qwen3-Coder-480B-A35B-Instruct-Turbo",
27
+ "Qwen/Qwen3-235B-A22B-Instruct-2507",
23
28
  "Qwen/Qwen3-235B-A22B",
24
29
  "Qwen/Qwen3-30B-A3B",
25
30
  "Qwen/Qwen3-32B",
@@ -71,12 +76,19 @@ class DeepInfra(Provider):
71
76
  "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
72
77
  "microsoft/WizardLM-2-8x22B",
73
78
  "mistralai/Devstral-Small-2505",
79
+ "mistralai/Devstral-Small-2507",
74
80
  "mistralai/Mistral-7B-Instruct-v0.3",
75
81
  "mistralai/Mistral-Nemo-Instruct-2407",
76
82
  "mistralai/Mistral-Small-24B-Instruct-2501",
77
83
  "mistralai/Mistral-Small-3.2-24B-Instruct-2506",
78
84
  "mistralai/Mixtral-8x7B-Instruct-v0.1",
79
85
  "nvidia/Llama-3.1-Nemotron-70B-Instruct",
86
+ "zai-org/GLM-4.5-Air",
87
+ "zai-org/GLM-4.5",
88
+ "zai-org/GLM-4.5V",
89
+ "openai/gpt-oss-120b",
90
+ "openai/gpt-oss-20b",
91
+ "allenai/olmOCR-7B-0725-FP8",
80
92
  ]
81
93
 
82
94
  @staticmethod
@@ -339,7 +351,7 @@ if __name__ == "__main__":
339
351
 
340
352
  for model in DeepInfra.AVAILABLE_MODELS:
341
353
  try:
342
- test_ai = DeepInfra(model=model, timeout=60, api_key="jwt:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJnaDoxNTg5ODg0NzgiLCJleHAiOjE3NTI3NDI5NDV9.qM93p6bPZYi_ejaOo1Dbe4UjYXrFiM7XvBLN4-9BWag")
354
+ test_ai = DeepInfra(model=model, timeout=60,)
343
355
  response = test_ai.chat("Say 'Hello' in one word", stream=True)
344
356
  response_text = ""
345
357
  for chunk in response:
@@ -15,7 +15,12 @@ class Flowith(Provider):
15
15
  """
16
16
  A provider class for interacting with the Flowith API.
17
17
  """
18
- AVAILABLE_MODELS = ["gpt-4.1-nano", "gpt-4.1-mini", "deepseek-chat", "deepseek-reasoner", "claude-3.5-haiku", "gemini-2.0-flash", "gemini-2.5-flash", "grok-3-mini"]
18
+ # Updated list of supported models
19
+ AVAILABLE_MODELS = [
20
+ "gpt-5-nano", "gpt-5-mini", "glm-4.5", "gpt-oss-120b", "gpt-oss-20b", "kimi-k2",
21
+ "gpt-4.1", "gpt-4.1-mini", "deepseek-chat", "deepseek-reasoner",
22
+ "gemini-2.5-flash", "grok-3-mini"
23
+ ]
19
24
 
20
25
  def __init__(
21
26
  self,
@@ -20,6 +20,7 @@ class GithubChat(Provider):
20
20
  # Available models
21
21
  AVAILABLE_MODELS = [
22
22
  "gpt-4o",
23
+ "gpt-5",
23
24
  "o3-mini",
24
25
  "o1",
25
26
  "claude-3.5-sonnet",
@@ -0,0 +1,207 @@
1
+
2
+ import requests
3
+ from typing import Any, Dict, Generator, Optional, Union, List
4
+ from webscout.litagent import LitAgent
5
+ from webscout.AIutel import sanitize_stream, Optimizers, Conversation, AwesomePrompts
6
+ from webscout.AIbase import Provider
7
+ from webscout import exceptions
8
+
9
+ class GptOss(Provider):
10
+ """
11
+ Provider for GPT-OSS API.
12
+ """
13
+ AVAILABLE_MODELS = ["gpt-oss-20b", "gpt-oss-120b"]
14
+
15
+ def __init__(
16
+ self,
17
+ model: str = "gpt-oss-120b",
18
+ is_conversation: bool = True,
19
+ max_tokens: int = 600,
20
+ timeout: int = 30,
21
+ intro: str = None,
22
+ filepath: str = None,
23
+ update_file: bool = True,
24
+ proxies: dict = {},
25
+ history_offset: int = 10250,
26
+ act: str = None,
27
+ system_prompt: str = "You are a helpful assistant.",
28
+ reasoning_effort: str = "high"
29
+ ):
30
+ self.api_endpoint = "https://api.gpt-oss.com/chatkit"
31
+ self.model = model if model in self.AVAILABLE_MODELS else self.AVAILABLE_MODELS[0]
32
+ self.is_conversation = is_conversation
33
+ self.max_tokens_to_sample = max_tokens
34
+ self.timeout = timeout
35
+ self.last_response = {}
36
+ self.system_prompt = system_prompt
37
+ self.reasoning_effort = reasoning_effort
38
+ self.agent = LitAgent()
39
+ self.proxies = proxies
40
+ self.__available_optimizers = (
41
+ method
42
+ for method in dir(Optimizers)
43
+ if callable(getattr(Optimizers, method)) and not method.startswith("__")
44
+ )
45
+ Conversation.intro = (
46
+ AwesomePrompts().get_act(
47
+ act, raise_not_found=True, default=None, case_insensitive=True
48
+ )
49
+ if act
50
+ else intro or Conversation.intro
51
+ )
52
+ self.conversation = Conversation(
53
+ is_conversation, self.max_tokens_to_sample, filepath, update_file
54
+ )
55
+ self.conversation.history_offset = history_offset
56
+
57
+ def ask(
58
+ self,
59
+ prompt: str,
60
+ stream: bool = False,
61
+ raw: bool = False,
62
+ optimizer: str = None,
63
+ conversationally: bool = False,
64
+ ) -> Union[Dict[str, Any], Generator]:
65
+ conversation_prompt = self.conversation.gen_complete_prompt(prompt)
66
+ if optimizer:
67
+ if optimizer in self.__available_optimizers:
68
+ conversation_prompt = getattr(Optimizers, optimizer)(
69
+ conversation_prompt if conversationally else prompt
70
+ )
71
+ else:
72
+ raise Exception(
73
+ f"Optimizer is not one of {self.__available_optimizers}"
74
+ )
75
+
76
+ data = {
77
+ "op": "threads.create",
78
+ "params": {
79
+ "input": {
80
+ "text": conversation_prompt,
81
+ "content": [{"type": "input_text", "text": conversation_prompt}],
82
+ "quoted_text": "",
83
+ "attachments": []
84
+ }
85
+ }
86
+ }
87
+ headers = self.agent.generate_fingerprint()
88
+ headers.update({
89
+ "accept": "text/event-stream",
90
+ "x-reasoning-effort": self.reasoning_effort,
91
+ "x-selected-model": self.model,
92
+ "x-show-reasoning": "true"
93
+ })
94
+ cookies = {}
95
+
96
+ def for_stream():
97
+ full_response_content = ""
98
+ try:
99
+ with requests.post(
100
+ self.api_endpoint,
101
+ headers=headers,
102
+ cookies=cookies,
103
+ json=data,
104
+ stream=True,
105
+ proxies=self.proxies if self.proxies else None,
106
+ timeout=self.timeout
107
+ ) as response:
108
+ response.raise_for_status()
109
+ for chunk in sanitize_stream(
110
+ response.iter_lines(),
111
+ intro_value="data: ",
112
+ to_json=True,
113
+ skip_markers=["[DONE]"],
114
+ strip_chars=None,
115
+ content_extractor=lambda d: d.get('update', {}).get('delta') if d.get('type') == 'thread.item_updated' and d.get('update', {}).get('type') == 'assistant_message.content_part.text_delta' else None,
116
+ yield_raw_on_error=False,
117
+ encoding="utf-8",
118
+ raw=raw
119
+ ):
120
+ if chunk:
121
+ yield chunk
122
+ full_response_content += chunk
123
+ self.last_response.update(dict(text=full_response_content))
124
+ self.conversation.update_chat_history(
125
+ prompt, self.get_message(self.last_response)
126
+ )
127
+ except Exception as e:
128
+ raise exceptions.FailedToGenerateResponseError(f"Request failed: {e}")
129
+
130
+ def for_non_stream():
131
+ result = ""
132
+ try:
133
+ with requests.post(
134
+ self.api_endpoint,
135
+ headers=headers,
136
+ cookies=cookies,
137
+ json=data,
138
+ stream=False,
139
+ proxies=self.proxies if self.proxies else None,
140
+ timeout=self.timeout
141
+ ) as response:
142
+ response.raise_for_status()
143
+ # The API is event-stream only, so we simulate non-stream by joining all chunks
144
+ for chunk in sanitize_stream(
145
+ response.iter_lines(),
146
+ intro_value="data: ",
147
+ to_json=True,
148
+ skip_markers=["[DONE]"],
149
+ strip_chars=None,
150
+ content_extractor=lambda d: d.get('update', {}).get('delta') if d.get('type') == 'thread.item_updated' and d.get('update', {}).get('type') == 'assistant_message.content_part.text_delta' else None,
151
+ yield_raw_on_error=False,
152
+ encoding="utf-8",
153
+ raw=raw
154
+ ):
155
+ if chunk:
156
+ result += chunk
157
+ self.last_response.update(dict(text=result))
158
+ self.conversation.update_chat_history(
159
+ prompt, self.get_message(self.last_response)
160
+ )
161
+ return self.last_response
162
+ except Exception as e:
163
+ raise exceptions.FailedToGenerateResponseError(f"Request failed: {e}")
164
+
165
+ return for_stream() if stream else for_non_stream()
166
+
167
+ def chat(
168
+ self,
169
+ prompt: str,
170
+ stream: bool = False,
171
+ optimizer: str = None,
172
+ conversationally: bool = False,
173
+ raw: bool = False,
174
+ ) -> Union[str, Generator[str, None, None]]:
175
+ def for_stream():
176
+ for response in self.ask(
177
+ prompt, True, raw=raw, optimizer=optimizer, conversationally=conversationally
178
+ ):
179
+ yield response
180
+
181
+ def for_non_stream():
182
+ result = self.ask(
183
+ prompt,
184
+ False,
185
+ raw=raw,
186
+ optimizer=optimizer,
187
+ conversationally=conversationally,
188
+ )
189
+ return self.get_message(result)
190
+
191
+ return for_stream() if stream else for_non_stream()
192
+
193
+ def get_message(self, response: dict) -> str:
194
+ assert isinstance(response, dict), "Response should be of dict data-type only"
195
+ text = response.get("text", "")
196
+ return text
197
+
198
+ if __name__ == "__main__":
199
+ from webscout.AIutel import timeIt
200
+ from rich import print
201
+ ai = GptOss(timeout=30)
202
+ @timeIt
203
+ def get_response():
204
+ response = ai.chat("write a poem about AI", stream=True, raw=False)
205
+ for chunk in response:
206
+ print(chunk, end="", flush=True)
207
+ get_response()