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.
- webscout/AIutel.py +52 -1016
- webscout/Bard.py +12 -6
- webscout/DWEBS.py +66 -57
- webscout/Provider/AISEARCH/PERPLEXED_search.py +214 -0
- webscout/Provider/AISEARCH/__init__.py +11 -10
- webscout/Provider/AISEARCH/felo_search.py +7 -3
- webscout/Provider/AISEARCH/scira_search.py +2 -0
- webscout/Provider/AISEARCH/stellar_search.py +53 -8
- webscout/Provider/Deepinfra.py +13 -1
- webscout/Provider/Flowith.py +6 -1
- webscout/Provider/GithubChat.py +1 -0
- webscout/Provider/GptOss.py +207 -0
- webscout/Provider/Kimi.py +445 -0
- webscout/Provider/Netwrck.py +3 -6
- webscout/Provider/OPENAI/README.md +2 -1
- webscout/Provider/OPENAI/TogetherAI.py +12 -8
- webscout/Provider/OPENAI/TwoAI.py +94 -1
- webscout/Provider/OPENAI/__init__.py +4 -4
- webscout/Provider/OPENAI/copilot.py +20 -4
- webscout/Provider/OPENAI/deepinfra.py +12 -0
- webscout/Provider/OPENAI/e2b.py +60 -8
- webscout/Provider/OPENAI/flowith.py +4 -3
- webscout/Provider/OPENAI/generate_api_key.py +48 -0
- webscout/Provider/OPENAI/gptoss.py +288 -0
- webscout/Provider/OPENAI/kimi.py +469 -0
- webscout/Provider/OPENAI/netwrck.py +8 -12
- webscout/Provider/OPENAI/refact.py +274 -0
- webscout/Provider/OPENAI/scirachat.py +4 -0
- webscout/Provider/OPENAI/textpollinations.py +11 -10
- webscout/Provider/OPENAI/toolbaz.py +1 -0
- webscout/Provider/OPENAI/venice.py +1 -0
- webscout/Provider/Perplexitylabs.py +163 -147
- webscout/Provider/Qodo.py +30 -6
- webscout/Provider/TTI/__init__.py +1 -0
- webscout/Provider/TTI/bing.py +14 -2
- webscout/Provider/TTI/together.py +11 -9
- webscout/Provider/TTI/venice.py +368 -0
- webscout/Provider/TTS/README.md +0 -1
- webscout/Provider/TTS/__init__.py +0 -1
- webscout/Provider/TTS/base.py +479 -159
- webscout/Provider/TTS/deepgram.py +409 -156
- webscout/Provider/TTS/elevenlabs.py +425 -111
- webscout/Provider/TTS/freetts.py +317 -140
- webscout/Provider/TTS/gesserit.py +192 -128
- webscout/Provider/TTS/murfai.py +248 -113
- webscout/Provider/TTS/openai_fm.py +347 -129
- webscout/Provider/TTS/speechma.py +620 -586
- webscout/Provider/TextPollinationsAI.py +11 -10
- webscout/Provider/TogetherAI.py +12 -4
- webscout/Provider/TwoAI.py +96 -2
- webscout/Provider/TypliAI.py +33 -27
- webscout/Provider/UNFINISHED/VercelAIGateway.py +339 -0
- webscout/Provider/UNFINISHED/fetch_together_models.py +6 -11
- webscout/Provider/Venice.py +1 -0
- webscout/Provider/WiseCat.py +18 -20
- webscout/Provider/__init__.py +2 -96
- webscout/Provider/cerebras.py +83 -33
- webscout/Provider/copilot.py +42 -23
- webscout/Provider/scira_chat.py +4 -0
- webscout/Provider/toolbaz.py +6 -10
- webscout/Provider/typefully.py +1 -11
- webscout/__init__.py +3 -15
- webscout/auth/__init__.py +19 -4
- webscout/auth/api_key_manager.py +189 -189
- webscout/auth/auth_system.py +25 -40
- webscout/auth/config.py +105 -6
- webscout/auth/database.py +377 -22
- webscout/auth/models.py +185 -130
- webscout/auth/request_processing.py +175 -11
- webscout/auth/routes.py +99 -2
- webscout/auth/server.py +9 -2
- webscout/auth/simple_logger.py +236 -0
- webscout/conversation.py +22 -20
- webscout/sanitize.py +1078 -0
- webscout/scout/README.md +20 -23
- webscout/scout/core/crawler.py +125 -38
- webscout/scout/core/scout.py +26 -5
- webscout/version.py +1 -1
- webscout/webscout_search.py +13 -6
- webscout/webscout_search_async.py +10 -8
- webscout/yep_search.py +13 -5
- {webscout-8.3.4.dist-info → webscout-8.3.6.dist-info}/METADATA +10 -149
- {webscout-8.3.4.dist-info → webscout-8.3.6.dist-info}/RECORD +88 -87
- webscout/Provider/Glider.py +0 -225
- webscout/Provider/OPENAI/README_AUTOPROXY.md +0 -238
- webscout/Provider/OPENAI/c4ai.py +0 -394
- webscout/Provider/OPENAI/glider.py +0 -330
- webscout/Provider/OPENAI/typegpt.py +0 -368
- webscout/Provider/OPENAI/uncovrAI.py +0 -477
- webscout/Provider/TTS/sthir.py +0 -94
- webscout/Provider/WritingMate.py +0 -273
- webscout/Provider/typegpt.py +0 -284
- webscout/Provider/uncovr.py +0 -333
- /webscout/Provider/{samurai.py → UNFINISHED/samurai.py} +0 -0
- {webscout-8.3.4.dist-info → webscout-8.3.6.dist-info}/WHEEL +0 -0
- {webscout-8.3.4.dist-info → webscout-8.3.6.dist-info}/entry_points.txt +0 -0
- {webscout-8.3.4.dist-info → webscout-8.3.6.dist-info}/licenses/LICENSE.md +0 -0
- {webscout-8.3.4.dist-info → webscout-8.3.6.dist-info}/top_level.txt +0 -0
|
@@ -49,11 +49,11 @@ def fetch_together_models():
|
|
|
49
49
|
print(f"Model: {model_id}")
|
|
50
50
|
print(f" Type: {model_type}")
|
|
51
51
|
print(f" Context Length: {context_length}")
|
|
52
|
-
if model.get("config"):
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
print("-" * 40)
|
|
52
|
+
# if model.get("config"):
|
|
53
|
+
# config = model["config"]
|
|
54
|
+
# if config.get("stop"):
|
|
55
|
+
# print(f" Stop Tokens: {config['stop']}")
|
|
56
|
+
# print("-" * 40)
|
|
57
57
|
|
|
58
58
|
print(f"\nSUMMARY:")
|
|
59
59
|
print(f"Chat Models: {len(chat_models)}")
|
|
@@ -87,9 +87,4 @@ if __name__ == "__main__":
|
|
|
87
87
|
result = fetch_together_models()
|
|
88
88
|
|
|
89
89
|
if result:
|
|
90
|
-
print(f"\n📊 Successfully fetched {len(result['all_models'])} models from Together.xyz")
|
|
91
|
-
|
|
92
|
-
# Save to file
|
|
93
|
-
with open("together_models.json", "w") as f:
|
|
94
|
-
json.dump(result, f, indent=2)
|
|
95
|
-
print("✅ Results saved to together_models.json")
|
|
90
|
+
print(f"\n📊 Successfully fetched {len(result['all_models'])} models from Together.xyz")
|
webscout/Provider/Venice.py
CHANGED
webscout/Provider/WiseCat.py
CHANGED
|
@@ -76,16 +76,6 @@ class WiseCat(Provider):
|
|
|
76
76
|
)
|
|
77
77
|
self.conversation.history_offset = history_offset
|
|
78
78
|
|
|
79
|
-
@staticmethod
|
|
80
|
-
def _wisecat_extractor(chunk: Union[str, Dict[str, Any]]) -> Optional[str]:
|
|
81
|
-
"""Extracts content from the WiseCat stream format '0:"..."'."""
|
|
82
|
-
if isinstance(chunk, str):
|
|
83
|
-
match = re.search(r'0:"(.*?)"', chunk)
|
|
84
|
-
if match:
|
|
85
|
-
# Decode potential unicode escapes like \u00e9
|
|
86
|
-
content = match.group(1).encode().decode('unicode_escape')
|
|
87
|
-
return content.replace('\\\\', '\\').replace('\\"', '"') # Handle escaped backslashes and quotes
|
|
88
|
-
return None
|
|
89
79
|
|
|
90
80
|
def ask(
|
|
91
81
|
self,
|
|
@@ -138,19 +128,27 @@ class WiseCat(Provider):
|
|
|
138
128
|
data=response.iter_content(chunk_size=None),
|
|
139
129
|
intro_value=None,
|
|
140
130
|
to_json=False,
|
|
141
|
-
|
|
131
|
+
extract_regexes=[
|
|
132
|
+
r'0:"(.*?)"' # Extract content from 0:"..." format
|
|
133
|
+
],
|
|
134
|
+
skip_regexes=[
|
|
135
|
+
r'\(\d+\.?\d*s\)', # Skip timing information like (0.3s), (1s), (0.5s)
|
|
136
|
+
r'\(\d+\.?\d*ms\)', # Skip millisecond timing like (300ms)
|
|
137
|
+
],
|
|
142
138
|
raw=raw
|
|
143
139
|
)
|
|
144
140
|
for content_chunk in processed_stream:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if
|
|
152
|
-
|
|
153
|
-
|
|
141
|
+
if content_chunk and isinstance(content_chunk, str):
|
|
142
|
+
# Content is already extracted by sanitize_stream
|
|
143
|
+
# Handle unicode escaping and quote unescaping
|
|
144
|
+
extracted_content = content_chunk.encode().decode('unicode_escape')
|
|
145
|
+
extracted_content = extracted_content.replace('\\\\', '\\').replace('\\"', '"')
|
|
146
|
+
|
|
147
|
+
if raw:
|
|
148
|
+
yield extracted_content
|
|
149
|
+
else:
|
|
150
|
+
streaming_text += extracted_content
|
|
151
|
+
yield dict(text=extracted_content)
|
|
154
152
|
self.last_response.update(dict(text=streaming_text))
|
|
155
153
|
self.conversation.update_chat_history(
|
|
156
154
|
prompt, self.get_message(self.last_response)
|
webscout/Provider/__init__.py
CHANGED
|
@@ -34,13 +34,11 @@ from .llmchatco import LLMChatCo # Add new LLMChat.co provider
|
|
|
34
34
|
from .talkai import *
|
|
35
35
|
from .llama3mitril import *
|
|
36
36
|
from .Marcus import *
|
|
37
|
-
from .typegpt import *
|
|
38
37
|
from .multichat import *
|
|
39
38
|
from .Jadve import *
|
|
40
39
|
from .chatglm import *
|
|
41
40
|
from .hermes import *
|
|
42
41
|
from .TextPollinationsAI import *
|
|
43
|
-
from .Glider import *
|
|
44
42
|
from .QwenLM import *
|
|
45
43
|
from .granite import *
|
|
46
44
|
from .WiseCat import *
|
|
@@ -54,7 +52,6 @@ from .Venice import *
|
|
|
54
52
|
from .GithubChat import *
|
|
55
53
|
from .copilot import *
|
|
56
54
|
from .sonus import *
|
|
57
|
-
from .uncovr import *
|
|
58
55
|
from .LambdaChat import *
|
|
59
56
|
from .ChatGPTClone import *
|
|
60
57
|
from .VercelAI import *
|
|
@@ -68,7 +65,6 @@ from .scira_chat import *
|
|
|
68
65
|
from .StandardInput import *
|
|
69
66
|
from .toolbaz import Toolbaz
|
|
70
67
|
from .scnet import SCNet
|
|
71
|
-
from .WritingMate import WritingMate
|
|
72
68
|
from .MCPCore import MCPCore
|
|
73
69
|
from .TypliAI import TypliAI
|
|
74
70
|
from .ChatSandbox import ChatSandbox
|
|
@@ -77,7 +73,6 @@ from .WrDoChat import WrDoChat
|
|
|
77
73
|
from .Nemotron import NEMOTRON
|
|
78
74
|
from .FreeGemini import FreeGemini
|
|
79
75
|
from .Flowith import Flowith
|
|
80
|
-
from .samurai import samurai
|
|
81
76
|
from .lmarena import lmarena
|
|
82
77
|
from .oivscode import oivscode
|
|
83
78
|
from .XenAI import XenAI
|
|
@@ -87,94 +82,5 @@ from .TogetherAI import TogetherAI
|
|
|
87
82
|
from .MiniMax import MiniMax
|
|
88
83
|
from .Qodo import *
|
|
89
84
|
from .monochat import MonoChat
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
'MonoChat',
|
|
93
|
-
'MiniMax',
|
|
94
|
-
'QodoAI',
|
|
95
|
-
'GeminiProxy',
|
|
96
|
-
'TogetherAI',
|
|
97
|
-
'oivscode',
|
|
98
|
-
'DeepSeekAssistant',
|
|
99
|
-
'lmarena',
|
|
100
|
-
'XenAI',
|
|
101
|
-
'NEMOTRON',
|
|
102
|
-
'Flowith',
|
|
103
|
-
'samurai',
|
|
104
|
-
'FreeGemini',
|
|
105
|
-
'WrDoChat',
|
|
106
|
-
'GizAI',
|
|
107
|
-
'ChatSandbox',
|
|
108
|
-
'SciraAI',
|
|
109
|
-
'StandardInputAI',
|
|
110
|
-
'OpenGPT',
|
|
111
|
-
'Venice',
|
|
112
|
-
'ExaAI',
|
|
113
|
-
'Copilot',
|
|
114
|
-
'TwoAI',
|
|
115
|
-
'HeckAI',
|
|
116
|
-
'AllenAI',
|
|
117
|
-
'PerplexityLabs',
|
|
118
|
-
'AkashGPT',
|
|
119
|
-
'WritingMate',
|
|
120
|
-
'WiseCat',
|
|
121
|
-
'IBMGranite',
|
|
122
|
-
'QwenLM',
|
|
123
|
-
'LambdaChat',
|
|
124
|
-
'TextPollinationsAI',
|
|
125
|
-
'GliderAI',
|
|
126
|
-
'Cohere',
|
|
127
|
-
'REKA',
|
|
128
|
-
'GROQ',
|
|
129
|
-
'AsyncGROQ',
|
|
130
|
-
'OPENAI',
|
|
131
|
-
'AsyncOPENAI',
|
|
132
|
-
'KOBOLDAI',
|
|
133
|
-
'AsyncKOBOLDAI',
|
|
134
|
-
'BLACKBOXAI',
|
|
135
|
-
'GEMINI',
|
|
136
|
-
'DeepInfra',
|
|
137
|
-
'AI4Chat',
|
|
138
|
-
'OLLAMA',
|
|
139
|
-
'AndiSearch',
|
|
140
|
-
'Sambanova',
|
|
141
|
-
'KOALA',
|
|
142
|
-
'Meta',
|
|
143
|
-
'PiAI',
|
|
144
|
-
'Julius',
|
|
145
|
-
'YEPCHAT',
|
|
146
|
-
'Cloudflare',
|
|
147
|
-
'TurboSeek',
|
|
148
|
-
'TeachAnything',
|
|
149
|
-
'X0GPT',
|
|
150
|
-
'Cerebras',
|
|
151
|
-
'GEMINIAPI',
|
|
152
|
-
'SonusAI',
|
|
153
|
-
'Cleeai',
|
|
154
|
-
'Elmo',
|
|
155
|
-
'ChatGPTClone',
|
|
156
|
-
'TypefullyAI',
|
|
157
|
-
'Netwrck',
|
|
158
|
-
'LLMChat',
|
|
159
|
-
'LLMChatCo',
|
|
160
|
-
'Talkai',
|
|
161
|
-
'Llama3Mitril',
|
|
162
|
-
'Marcus',
|
|
163
|
-
'TypeGPT',
|
|
164
|
-
'Netwrck',
|
|
165
|
-
'MultiChatAI',
|
|
166
|
-
'JadveOpenAI',
|
|
167
|
-
'ChatGLM',
|
|
168
|
-
'NousHermes',
|
|
169
|
-
'FreeAIChat',
|
|
170
|
-
'GithubChat',
|
|
171
|
-
'UncovrAI',
|
|
172
|
-
'VercelAI',
|
|
173
|
-
'ExaChat',
|
|
174
|
-
'AskSteve',
|
|
175
|
-
'Aitopia',
|
|
176
|
-
'SearchChatAI',
|
|
177
|
-
'Toolbaz',
|
|
178
|
-
'MCPCore',
|
|
179
|
-
'TypliAI',
|
|
180
|
-
]
|
|
85
|
+
from .Kimi import Kimi
|
|
86
|
+
from .GptOss import GptOss
|
webscout/Provider/cerebras.py
CHANGED
|
@@ -1,34 +1,48 @@
|
|
|
1
1
|
|
|
2
2
|
import re
|
|
3
|
+
|
|
4
|
+
# Import trio before curl_cffi to prevent eventlet socket monkey-patching conflicts
|
|
5
|
+
# See: https://github.com/python-trio/trio/issues/3015
|
|
6
|
+
try:
|
|
7
|
+
import trio # noqa: F401
|
|
8
|
+
except ImportError:
|
|
9
|
+
pass # trio is optional, ignore if not available
|
|
10
|
+
import json
|
|
11
|
+
from typing import Any, Dict, Generator, List, Optional, Union
|
|
12
|
+
|
|
3
13
|
import curl_cffi
|
|
4
14
|
from curl_cffi.requests import Session
|
|
5
|
-
|
|
6
|
-
import os
|
|
7
|
-
from typing import Any, Dict, Optional, Generator, List, Union
|
|
8
|
-
from webscout.AIutel import Optimizers, Conversation, AwesomePrompts, sanitize_stream # Import sanitize_stream
|
|
9
|
-
from webscout.AIbase import Provider
|
|
15
|
+
|
|
10
16
|
from webscout import exceptions
|
|
17
|
+
from webscout.AIbase import Provider
|
|
18
|
+
from webscout.AIutel import ( # Import sanitize_stream
|
|
19
|
+
AwesomePrompts,
|
|
20
|
+
Conversation,
|
|
21
|
+
Optimizers,
|
|
22
|
+
sanitize_stream,
|
|
23
|
+
)
|
|
11
24
|
from webscout.litagent import LitAgent as UserAgent
|
|
12
25
|
|
|
26
|
+
|
|
13
27
|
class Cerebras(Provider):
|
|
14
28
|
"""
|
|
15
29
|
A class to interact with the Cerebras API using a cookie for authentication.
|
|
16
30
|
"""
|
|
17
|
-
|
|
31
|
+
|
|
18
32
|
AVAILABLE_MODELS = [
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"llama-4-scout-17b-16e-instruct",
|
|
33
|
+
"qwen-3-coder-480b",
|
|
34
|
+
"qwen-3-235b-a22b-instruct-2507",
|
|
35
|
+
"qwen-3-235b-a22b-thinking-2507",
|
|
23
36
|
"qwen-3-32b",
|
|
24
|
-
|
|
25
|
-
|
|
37
|
+
"llama-3.3-70b",
|
|
38
|
+
"llama-4-maverick-17b-128e-instruct"
|
|
26
39
|
]
|
|
27
40
|
|
|
28
41
|
def __init__(
|
|
29
42
|
self,
|
|
43
|
+
cookie_path: str = None,
|
|
30
44
|
is_conversation: bool = True,
|
|
31
|
-
max_tokens: int =
|
|
45
|
+
max_tokens: int = 40000,
|
|
32
46
|
timeout: int = 30,
|
|
33
47
|
intro: str = None,
|
|
34
48
|
filepath: str = None,
|
|
@@ -36,9 +50,11 @@ class Cerebras(Provider):
|
|
|
36
50
|
proxies: dict = {},
|
|
37
51
|
history_offset: int = 10250,
|
|
38
52
|
act: str = None,
|
|
39
|
-
|
|
40
|
-
model: str = "
|
|
53
|
+
api_key: str = None,
|
|
54
|
+
model: str = "qwen-3-coder-480b",
|
|
41
55
|
system_prompt: str = "You are a helpful assistant.",
|
|
56
|
+
temperature: float = 0.7,
|
|
57
|
+
top_p: float = 0.8,
|
|
42
58
|
):
|
|
43
59
|
# Validate model choice
|
|
44
60
|
if model not in self.AVAILABLE_MODELS:
|
|
@@ -52,15 +68,26 @@ class Cerebras(Provider):
|
|
|
52
68
|
self.system_prompt = system_prompt
|
|
53
69
|
self.is_conversation = is_conversation
|
|
54
70
|
self.max_tokens_to_sample = max_tokens
|
|
71
|
+
self.temperature = temperature
|
|
72
|
+
self.top_p = top_p
|
|
55
73
|
self.last_response = {}
|
|
56
74
|
|
|
57
75
|
self.session = Session() # Initialize curl_cffi session
|
|
58
76
|
|
|
59
|
-
#
|
|
60
|
-
|
|
61
|
-
self.api_key =
|
|
62
|
-
|
|
63
|
-
|
|
77
|
+
# Handle API key - either provided directly or retrieved from cookies
|
|
78
|
+
if api_key:
|
|
79
|
+
self.api_key = api_key.strip()
|
|
80
|
+
# Basic validation for API key format
|
|
81
|
+
if not self.api_key or len(self.api_key) < 10:
|
|
82
|
+
raise ValueError("Invalid API key format. API key must be at least 10 characters long.")
|
|
83
|
+
elif cookie_path:
|
|
84
|
+
# Get API key from cookies
|
|
85
|
+
try:
|
|
86
|
+
self.api_key = self.get_demo_api_key(cookie_path)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
raise exceptions.APIConnectionError(f"Failed to initialize Cerebras client: {e}")
|
|
89
|
+
else:
|
|
90
|
+
raise ValueError("Either api_key must be provided or cookie_path must be specified")
|
|
64
91
|
|
|
65
92
|
# Initialize optimizers
|
|
66
93
|
self.__available_optimizers = (
|
|
@@ -72,16 +99,16 @@ class Cerebras(Provider):
|
|
|
72
99
|
# Initialize conversation settings
|
|
73
100
|
Conversation.intro = (
|
|
74
101
|
AwesomePrompts().get_act(
|
|
75
|
-
act, raise_not_found=True, default=
|
|
102
|
+
act, raise_not_found=True, default="You are a helpful assistant.", case_insensitive=True
|
|
76
103
|
)
|
|
77
104
|
if act
|
|
78
|
-
else
|
|
105
|
+
else "You are a helpful assistant."
|
|
79
106
|
)
|
|
80
107
|
self.conversation = Conversation(
|
|
81
108
|
is_conversation, self.max_tokens_to_sample, filepath, update_file
|
|
82
109
|
)
|
|
83
110
|
self.conversation.history_offset = history_offset
|
|
84
|
-
|
|
111
|
+
|
|
85
112
|
# Apply proxies to the session
|
|
86
113
|
self.session.proxies = proxies
|
|
87
114
|
|
|
@@ -105,8 +132,10 @@ class Cerebras(Provider):
|
|
|
105
132
|
return chunk.get("choices", [{}])[0].get("delta", {}).get("content")
|
|
106
133
|
return None
|
|
107
134
|
|
|
108
|
-
def get_demo_api_key(self, cookie_path: str) -> str: # Keep this using requests or switch to curl_cffi
|
|
135
|
+
def get_demo_api_key(self, cookie_path: str = None) -> str: # Keep this using requests or switch to curl_cffi
|
|
109
136
|
"""Retrieves the demo API key using the provided cookie."""
|
|
137
|
+
if not cookie_path:
|
|
138
|
+
raise ValueError("cookie_path must be provided when using cookie-based authentication")
|
|
110
139
|
try:
|
|
111
140
|
with open(cookie_path, "r") as file:
|
|
112
141
|
cookies = {item["name"]: item["value"] for item in json.load(file)}
|
|
@@ -159,7 +188,10 @@ class Cerebras(Provider):
|
|
|
159
188
|
payload = {
|
|
160
189
|
"model": self.model,
|
|
161
190
|
"messages": messages,
|
|
162
|
-
"stream": stream
|
|
191
|
+
"stream": stream,
|
|
192
|
+
"max_tokens": self.max_tokens_to_sample,
|
|
193
|
+
"temperature": self.temperature,
|
|
194
|
+
"top_p": self.top_p
|
|
163
195
|
}
|
|
164
196
|
|
|
165
197
|
try:
|
|
@@ -197,8 +229,26 @@ class Cerebras(Provider):
|
|
|
197
229
|
|
|
198
230
|
except curl_cffi.CurlError as e:
|
|
199
231
|
raise exceptions.APIConnectionError(f"Request failed (CurlError): {e}") from e
|
|
200
|
-
except Exception as e:
|
|
201
|
-
|
|
232
|
+
except Exception as e:
|
|
233
|
+
# Check if it's an HTTP error with status code
|
|
234
|
+
if hasattr(e, 'response') and hasattr(e.response, 'status_code'):
|
|
235
|
+
status_code = e.response.status_code
|
|
236
|
+
if status_code == 401:
|
|
237
|
+
raise exceptions.APIConnectionError(
|
|
238
|
+
"Authentication failed (401): Invalid API key. Please check your API key and try again."
|
|
239
|
+
) from e
|
|
240
|
+
elif status_code == 403:
|
|
241
|
+
raise exceptions.APIConnectionError(
|
|
242
|
+
"Access forbidden (403): Your API key may not have permission to access this resource."
|
|
243
|
+
) from e
|
|
244
|
+
elif status_code == 429:
|
|
245
|
+
raise exceptions.APIConnectionError(
|
|
246
|
+
"Rate limit exceeded (429): Too many requests. Please wait and try again."
|
|
247
|
+
) from e
|
|
248
|
+
else:
|
|
249
|
+
raise exceptions.APIConnectionError(f"HTTP {status_code} error: {e}") from e
|
|
250
|
+
else:
|
|
251
|
+
raise exceptions.APIConnectionError(f"Request failed: {e}") from e
|
|
202
252
|
|
|
203
253
|
def ask(
|
|
204
254
|
self,
|
|
@@ -225,7 +275,7 @@ class Cerebras(Provider):
|
|
|
225
275
|
|
|
226
276
|
try:
|
|
227
277
|
response = self._make_request(messages, stream)
|
|
228
|
-
|
|
278
|
+
|
|
229
279
|
if stream:
|
|
230
280
|
# Wrap the generator to yield dicts or raw strings
|
|
231
281
|
def stream_wrapper():
|
|
@@ -256,7 +306,7 @@ class Cerebras(Provider):
|
|
|
256
306
|
"""Chat with the model."""
|
|
257
307
|
# Ask returns a generator for stream=True, dict/str for stream=False
|
|
258
308
|
response_gen_or_dict = self.ask(prompt, stream, raw=False, optimizer=optimizer, conversationally=conversationally)
|
|
259
|
-
|
|
309
|
+
|
|
260
310
|
if stream:
|
|
261
311
|
# Wrap the generator from ask() to get message text
|
|
262
312
|
def stream_wrapper():
|
|
@@ -276,14 +326,14 @@ class Cerebras(Provider):
|
|
|
276
326
|
|
|
277
327
|
if __name__ == "__main__":
|
|
278
328
|
from rich import print
|
|
279
|
-
|
|
329
|
+
|
|
280
330
|
# Example usage
|
|
281
331
|
cerebras = Cerebras(
|
|
282
|
-
|
|
283
|
-
model='
|
|
332
|
+
api_key='csk-**********************', # Replace with your actual API key
|
|
333
|
+
model='qwen-3-235b-a22b-instruct-2507',
|
|
284
334
|
system_prompt="You are a helpful AI assistant."
|
|
285
335
|
)
|
|
286
|
-
|
|
336
|
+
|
|
287
337
|
# Test with streaming
|
|
288
338
|
response = cerebras.chat("Hello!", stream=True)
|
|
289
339
|
for chunk in response:
|
webscout/Provider/copilot.py
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import json
|
|
3
|
-
import base64
|
|
4
1
|
import asyncio
|
|
2
|
+
import base64
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from typing import Any, Dict, Generator, Union
|
|
5
6
|
from urllib.parse import quote
|
|
6
|
-
from typing import Optional, Dict, Any, List, Union, Generator
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
# Import trio before curl_cffi to prevent eventlet socket monkey-patching conflicts
|
|
9
|
+
# See: https://github.com/python-trio/trio/issues/3015
|
|
10
|
+
try:
|
|
11
|
+
import trio # noqa: F401
|
|
12
|
+
except ImportError:
|
|
13
|
+
pass # trio is optional, ignore if not available
|
|
14
|
+
from curl_cffi.requests import CurlWsFlag, Session
|
|
9
15
|
|
|
10
|
-
from webscout.AIutel import Optimizers
|
|
11
|
-
from webscout.AIutel import Conversation
|
|
12
|
-
from webscout.AIutel import AwesomePrompts, sanitize_stream
|
|
13
|
-
from webscout.AIbase import Provider, AsyncProvider
|
|
14
16
|
from webscout import exceptions
|
|
17
|
+
from webscout.AIbase import Provider
|
|
18
|
+
from webscout.AIutel import AwesomePrompts, Conversation, Optimizers
|
|
15
19
|
from webscout.litagent import LitAgent
|
|
16
20
|
|
|
17
21
|
try:
|
|
@@ -41,12 +45,17 @@ class Copilot(Provider):
|
|
|
41
45
|
"""
|
|
42
46
|
A class to interact with the Microsoft Copilot API.
|
|
43
47
|
"""
|
|
44
|
-
|
|
48
|
+
|
|
45
49
|
label = "Microsoft Copilot"
|
|
46
50
|
url = "https://copilot.microsoft.com"
|
|
47
51
|
websocket_url = "wss://copilot.microsoft.com/c/api/chat?api-version=2"
|
|
48
52
|
conversation_url = f"{url}/c/api/conversations"
|
|
49
|
-
AVAILABLE_MODELS = ["Copilot", "Think Deeper"]
|
|
53
|
+
AVAILABLE_MODELS = ["Copilot", "Think Deeper", "Smart"]
|
|
54
|
+
MODEL_ALIASES = {
|
|
55
|
+
"gpt-4o": "Copilot",
|
|
56
|
+
"o4-mini": "Think Deeper",
|
|
57
|
+
"gpt-5": "Smart",
|
|
58
|
+
}
|
|
50
59
|
_access_token: str = None
|
|
51
60
|
_cookies: dict = None
|
|
52
61
|
|
|
@@ -64,9 +73,12 @@ class Copilot(Provider):
|
|
|
64
73
|
model: str = "Copilot"
|
|
65
74
|
):
|
|
66
75
|
"""Initializes the Copilot API client."""
|
|
67
|
-
|
|
76
|
+
# Map alias to real model name if needed
|
|
77
|
+
real_model = self.MODEL_ALIASES.get(model, model)
|
|
78
|
+
if real_model not in self.AVAILABLE_MODELS:
|
|
68
79
|
raise ValueError(f"Invalid model: {model}. Choose from: {self.AVAILABLE_MODELS}")
|
|
69
|
-
|
|
80
|
+
self.model = real_model
|
|
81
|
+
|
|
70
82
|
# Use LitAgent for user-agent
|
|
71
83
|
self.headers = {
|
|
72
84
|
'User-Agent': LitAgent().random(),
|
|
@@ -79,7 +91,7 @@ class Copilot(Provider):
|
|
|
79
91
|
'Sec-Fetch-Mode': 'cors',
|
|
80
92
|
'Sec-Fetch-Site': 'same-origin',
|
|
81
93
|
}
|
|
82
|
-
|
|
94
|
+
|
|
83
95
|
self.is_conversation = is_conversation
|
|
84
96
|
self.max_tokens_to_sample = max_tokens
|
|
85
97
|
self.timeout = timeout
|
|
@@ -253,6 +265,12 @@ class Copilot(Provider):
|
|
|
253
265
|
# WebSocket connection
|
|
254
266
|
wss = session.ws_connect(websocket_url)
|
|
255
267
|
wss.send(json.dumps({"event": "setOptions", "supportedCards": ["weather", "local", "image", "sports", "video", "ads", "finance"], "ads": {"supportedTypes": ["multimedia", "product", "tourActivity", "propertyPromotion", "text"]}}))
|
|
268
|
+
if self.model == "Smart":
|
|
269
|
+
mode_value = "smart"
|
|
270
|
+
elif "Think" in self.model:
|
|
271
|
+
mode_value = "reasoning"
|
|
272
|
+
else:
|
|
273
|
+
mode_value = "chat"
|
|
256
274
|
wss.send(json.dumps({
|
|
257
275
|
"event": "send",
|
|
258
276
|
"conversationId": conversation_id,
|
|
@@ -260,7 +278,8 @@ class Copilot(Provider):
|
|
|
260
278
|
"type": "text",
|
|
261
279
|
"text": conversation_prompt,
|
|
262
280
|
}],
|
|
263
|
-
"mode":
|
|
281
|
+
"mode": mode_value,
|
|
282
|
+
"model": self.model
|
|
264
283
|
}).encode(), CurlWsFlag.TEXT)
|
|
265
284
|
|
|
266
285
|
# Event-driven response loop
|
|
@@ -307,8 +326,8 @@ class Copilot(Provider):
|
|
|
307
326
|
**kwargs
|
|
308
327
|
) -> Union[str, Generator]:
|
|
309
328
|
def for_stream():
|
|
310
|
-
for response in self.ask(prompt, True, optimizer=optimizer,
|
|
311
|
-
conversationally=conversationally,
|
|
329
|
+
for response in self.ask(prompt, True, optimizer=optimizer,
|
|
330
|
+
conversationally=conversationally,
|
|
312
331
|
images=images, api_key=api_key, **kwargs):
|
|
313
332
|
if isinstance(response, dict):
|
|
314
333
|
if "text" in response:
|
|
@@ -320,13 +339,13 @@ class Copilot(Provider):
|
|
|
320
339
|
yield "\nSuggested follow-up questions:\n"
|
|
321
340
|
for suggestion in response["suggestions"]:
|
|
322
341
|
yield f"- {suggestion}\n"
|
|
323
|
-
|
|
342
|
+
|
|
324
343
|
def for_non_stream():
|
|
325
|
-
response = self.ask(prompt, False, optimizer=optimizer,
|
|
344
|
+
response = self.ask(prompt, False, optimizer=optimizer,
|
|
326
345
|
conversationally=conversationally,
|
|
327
346
|
images=images, api_key=api_key, **kwargs)
|
|
328
347
|
return self.get_message(response)
|
|
329
|
-
|
|
348
|
+
|
|
330
349
|
return for_stream() if stream else for_non_stream()
|
|
331
350
|
|
|
332
351
|
def get_message(self, response: dict) -> str:
|
|
@@ -379,7 +398,7 @@ def readHAR(url: str):
|
|
|
379
398
|
for file in os.listdir(path):
|
|
380
399
|
if file.endswith(".har"):
|
|
381
400
|
har_files.append(os.path.join(path, file))
|
|
382
|
-
|
|
401
|
+
|
|
383
402
|
for path in har_files:
|
|
384
403
|
with open(path, 'rb') as file:
|
|
385
404
|
try:
|
|
@@ -416,7 +435,7 @@ async def get_nodriver(proxy=None, user_data_dir=None):
|
|
|
416
435
|
|
|
417
436
|
if __name__ == "__main__":
|
|
418
437
|
from rich import print
|
|
419
|
-
ai = Copilot(timeout=900, model="
|
|
438
|
+
ai = Copilot(timeout=900, model="gpt-5")
|
|
420
439
|
response = ai.chat(input("> "), stream=True)
|
|
421
440
|
for chunk in response:
|
|
422
|
-
print(chunk, end="", flush=True)
|
|
441
|
+
print(chunk, end="", flush=True)
|
webscout/Provider/scira_chat.py
CHANGED
|
@@ -43,6 +43,8 @@ class SciraAI(Provider):
|
|
|
43
43
|
"claude-4-opus-20250514": "scira-opus",
|
|
44
44
|
"claude-4-opus-20250514-pro": "scira-opus-pro",
|
|
45
45
|
"meta-llama/llama-4-maverick-17b-128e-instruct": "scira-llama-4",
|
|
46
|
+
"kimi-k2-instruct": "scira-kimi-k2",
|
|
47
|
+
"scira-kimi-k2": "kimi-k2-instruct",
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
# Reverse mapping: Scira format to actual model names
|
|
@@ -57,6 +59,8 @@ class SciraAI(Provider):
|
|
|
57
59
|
SCIRA_TO_MODEL["scira-qwen-30b"] = "qwen3-30b-a3b"
|
|
58
60
|
SCIRA_TO_MODEL["scira-deepseek-v3"] = "deepseek-v3-0324"
|
|
59
61
|
SCIRA_TO_MODEL["scira-grok-4"] = "grok-4"
|
|
62
|
+
SCIRA_TO_MODEL["scira-kimi-k2"] = "kimi-k2-instruct"
|
|
63
|
+
SCIRA_TO_MODEL["kimi-k2-instruct"] = "scira-kimi-k2"
|
|
60
64
|
MODEL_MAPPING["claude-4-opus-20250514-pro"] = "scira-opus-pro"
|
|
61
65
|
# Available models list (actual model names + scira aliases)
|
|
62
66
|
AVAILABLE_MODELS = list(MODEL_MAPPING.keys()) + list(SCIRA_TO_MODEL.keys())
|
webscout/Provider/toolbaz.py
CHANGED
|
@@ -34,11 +34,13 @@ class Toolbaz(Provider):
|
|
|
34
34
|
"Llama-4-Maverick",
|
|
35
35
|
"Llama-4-Scout",
|
|
36
36
|
"Llama-3.3-70B",
|
|
37
|
+
"gpt-oss-120b",
|
|
37
38
|
"Qwen2.5-72B",
|
|
38
39
|
"grok-2-1212",
|
|
39
40
|
"grok-3-beta",
|
|
40
|
-
"toolbaz_v3.5_pro",
|
|
41
41
|
"toolbaz_v3",
|
|
42
|
+
"toolbaz_v3.5_pro",
|
|
43
|
+
"toolbaz_v4",
|
|
42
44
|
"mixtral_8x22b",
|
|
43
45
|
"L3-70B-Euryale-v2.1",
|
|
44
46
|
"midnight-rose",
|
|
@@ -112,12 +114,6 @@ class Toolbaz(Provider):
|
|
|
112
114
|
)
|
|
113
115
|
self.conversation.history_offset = history_offset
|
|
114
116
|
|
|
115
|
-
@staticmethod
|
|
116
|
-
def _toolbaz_extractor(chunk: Union[str, Dict[str, Any]]) -> Optional[str]:
|
|
117
|
-
"""Removes [model:...] tags from a string chunk."""
|
|
118
|
-
if isinstance(chunk, str):
|
|
119
|
-
return re.sub(r"\[model:.*?\]", "", chunk)
|
|
120
|
-
return None
|
|
121
117
|
|
|
122
118
|
def random_string(self, length):
|
|
123
119
|
return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
|
|
@@ -217,14 +213,14 @@ class Toolbaz(Provider):
|
|
|
217
213
|
|
|
218
214
|
streaming_text = ""
|
|
219
215
|
|
|
220
|
-
# Use sanitize_stream with
|
|
216
|
+
# Use sanitize_stream with skip_regexes to remove [model:...] tags
|
|
221
217
|
# It will decode bytes and yield processed string chunks
|
|
222
218
|
processed_stream = sanitize_stream(
|
|
223
219
|
data=resp.iter_content(chunk_size=None), # Pass byte iterator
|
|
224
220
|
intro_value=None, # No simple prefix
|
|
225
221
|
to_json=False, # Content is text
|
|
226
|
-
|
|
227
|
-
yield_raw_on_error=True, # Yield even if
|
|
222
|
+
skip_regexes=[r"\[model:.*?\]"], # Skip [model:...] tags
|
|
223
|
+
yield_raw_on_error=True, # Yield even if regex processing fails
|
|
228
224
|
raw=raw
|
|
229
225
|
)
|
|
230
226
|
|
webscout/Provider/typefully.py
CHANGED
|
@@ -71,16 +71,6 @@ class TypefullyAI(Provider):
|
|
|
71
71
|
)
|
|
72
72
|
self.conversation.history_offset = history_offset
|
|
73
73
|
|
|
74
|
-
@staticmethod
|
|
75
|
-
def _typefully_extractor(chunk: Union[str, Dict[str, Any]]) -> Optional[str]:
|
|
76
|
-
if isinstance(chunk, str):
|
|
77
|
-
if isinstance(chunk, bytes):
|
|
78
|
-
chunk = chunk.decode('utf-8', errors='replace')
|
|
79
|
-
match = re.search(r'0:"(.*?)"', chunk)
|
|
80
|
-
if match:
|
|
81
|
-
content = match.group(1).encode().decode('unicode_escape')
|
|
82
|
-
return content.replace('\\', '\\').replace('\\"', '"')
|
|
83
|
-
return None
|
|
84
74
|
|
|
85
75
|
def ask(
|
|
86
76
|
self,
|
|
@@ -125,7 +115,7 @@ class TypefullyAI(Provider):
|
|
|
125
115
|
data=response.iter_content(chunk_size=None),
|
|
126
116
|
intro_value=None,
|
|
127
117
|
to_json=False,
|
|
128
|
-
|
|
118
|
+
extract_regexes=[r'0:"(.*?)"'],
|
|
129
119
|
raw=raw
|
|
130
120
|
)
|
|
131
121
|
for content_chunk in processed_stream:
|