webscout 8.2.3__py3-none-any.whl → 8.2.4__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.
- inferno/lol.py +589 -0
- webscout/AIutel.py +226 -14
- webscout/Bard.py +579 -206
- webscout/DWEBS.py +78 -35
- webscout/Extra/tempmail/base.py +1 -1
- webscout/Provider/AISEARCH/hika_search.py +4 -0
- webscout/Provider/AllenAI.py +163 -126
- webscout/Provider/ChatGPTClone.py +96 -84
- webscout/Provider/Deepinfra.py +95 -67
- webscout/Provider/ElectronHub.py +55 -0
- webscout/Provider/GPTWeb.py +96 -46
- webscout/Provider/Groq.py +194 -91
- webscout/Provider/HeckAI.py +89 -47
- webscout/Provider/HuggingFaceChat.py +113 -106
- webscout/Provider/Hunyuan.py +94 -83
- webscout/Provider/Jadve.py +107 -75
- webscout/Provider/LambdaChat.py +106 -64
- webscout/Provider/Llama3.py +94 -39
- webscout/Provider/MCPCore.py +318 -0
- webscout/Provider/Marcus.py +85 -36
- webscout/Provider/Netwrck.py +76 -43
- webscout/Provider/OPENAI/__init__.py +4 -1
- webscout/Provider/OPENAI/ai4chat.py +286 -0
- webscout/Provider/OPENAI/chatgptclone.py +35 -14
- webscout/Provider/OPENAI/deepinfra.py +37 -0
- webscout/Provider/OPENAI/groq.py +354 -0
- webscout/Provider/OPENAI/heckai.py +6 -2
- webscout/Provider/OPENAI/mcpcore.py +376 -0
- webscout/Provider/OPENAI/multichat.py +368 -0
- webscout/Provider/OPENAI/netwrck.py +3 -1
- webscout/Provider/OpenGPT.py +48 -38
- webscout/Provider/PI.py +168 -92
- webscout/Provider/PizzaGPT.py +66 -36
- webscout/Provider/TeachAnything.py +85 -51
- webscout/Provider/TextPollinationsAI.py +109 -51
- webscout/Provider/TwoAI.py +109 -60
- webscout/Provider/Venice.py +93 -56
- webscout/Provider/VercelAI.py +2 -2
- webscout/Provider/WiseCat.py +65 -28
- webscout/Provider/Writecream.py +37 -11
- webscout/Provider/WritingMate.py +135 -63
- webscout/Provider/__init__.py +3 -21
- webscout/Provider/ai4chat.py +6 -7
- webscout/Provider/copilot.py +0 -3
- webscout/Provider/elmo.py +101 -58
- webscout/Provider/granite.py +91 -46
- webscout/Provider/hermes.py +87 -47
- webscout/Provider/koala.py +1 -1
- webscout/Provider/learnfastai.py +104 -50
- webscout/Provider/llama3mitril.py +86 -51
- webscout/Provider/llmchat.py +88 -46
- webscout/Provider/llmchatco.py +74 -49
- webscout/Provider/meta.py +41 -37
- webscout/Provider/multichat.py +54 -25
- webscout/Provider/scnet.py +93 -43
- webscout/Provider/searchchat.py +82 -75
- webscout/Provider/sonus.py +103 -51
- webscout/Provider/toolbaz.py +132 -77
- webscout/Provider/turboseek.py +92 -41
- webscout/Provider/tutorai.py +82 -64
- webscout/Provider/typefully.py +75 -33
- webscout/Provider/typegpt.py +96 -35
- webscout/Provider/uncovr.py +112 -62
- webscout/Provider/x0gpt.py +69 -26
- webscout/Provider/yep.py +79 -66
- webscout/conversation.py +35 -21
- webscout/exceptions.py +20 -0
- webscout/prompt_manager.py +56 -42
- webscout/version.py +1 -1
- webscout/webscout_search.py +65 -47
- webscout/webscout_search_async.py +81 -126
- webscout/yep_search.py +93 -43
- {webscout-8.2.3.dist-info → webscout-8.2.4.dist-info}/METADATA +22 -10
- {webscout-8.2.3.dist-info → webscout-8.2.4.dist-info}/RECORD +78 -81
- {webscout-8.2.3.dist-info → webscout-8.2.4.dist-info}/WHEEL +1 -1
- webscout/Provider/C4ai.py +0 -432
- webscout/Provider/ChatGPTES.py +0 -237
- webscout/Provider/DeepSeek.py +0 -196
- webscout/Provider/Llama.py +0 -200
- webscout/Provider/Phind.py +0 -535
- webscout/Provider/WebSim.py +0 -228
- webscout/Provider/labyrinth.py +0 -340
- webscout/Provider/lepton.py +0 -194
- webscout/Provider/llamatutor.py +0 -192
- {webscout-8.2.3.dist-info → webscout-8.2.4.dist-info}/entry_points.txt +0 -0
- {webscout-8.2.3.dist-info → webscout-8.2.4.dist-info/licenses}/LICENSE.md +0 -0
- {webscout-8.2.3.dist-info → webscout-8.2.4.dist-info}/top_level.txt +0 -0
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
import
|
|
2
|
-
from
|
|
1
|
+
from curl_cffi.requests import Session # Import Session
|
|
2
|
+
from curl_cffi import CurlError # Import CurlError
|
|
3
3
|
from typing import Union, Any, Dict
|
|
4
|
-
from webscout.
|
|
5
|
-
from webscout
|
|
4
|
+
from webscout.AIbase import Provider # Import Provider base class
|
|
5
|
+
from webscout import exceptions # Import custom exceptions
|
|
6
|
+
from webscout.conversation import Conversation
|
|
7
|
+
from webscout.optimizers import Optimizers
|
|
6
8
|
from webscout.prompt_manager import AwesomePrompts
|
|
9
|
+
from webscout.litagent import LitAgent
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
# Inherit from Provider
|
|
12
|
+
class TeachAnything(Provider):
|
|
9
13
|
"""
|
|
10
14
|
A class to interact with the Teach-Anything API.
|
|
11
15
|
"""
|
|
12
|
-
|
|
16
|
+
# Add AVAILABLE_MODELS if applicable, otherwise remove model param
|
|
17
|
+
# AVAILABLE_MODELS = ["default"] # Example
|
|
13
18
|
|
|
14
19
|
def __init__(
|
|
15
20
|
self,
|
|
16
21
|
is_conversation: bool = True,
|
|
17
|
-
max_tokens: int = 600,
|
|
22
|
+
max_tokens: int = 600, # Note: max_tokens is not used by this API
|
|
18
23
|
timeout: int = 30,
|
|
19
24
|
intro: str = None,
|
|
20
25
|
filepath: str = None,
|
|
@@ -22,6 +27,7 @@ class TeachAnything:
|
|
|
22
27
|
proxies: dict = {},
|
|
23
28
|
history_offset: int = 10250,
|
|
24
29
|
act: str = None,
|
|
30
|
+
# model: str = "default" # Remove if not used
|
|
25
31
|
) -> None:
|
|
26
32
|
"""
|
|
27
33
|
Initializes the Teach-Anything API with given parameters.
|
|
@@ -40,7 +46,8 @@ class TeachAnything:
|
|
|
40
46
|
"""
|
|
41
47
|
|
|
42
48
|
|
|
43
|
-
|
|
49
|
+
# Initialize curl_cffi Session
|
|
50
|
+
self.session = Session()
|
|
44
51
|
self.is_conversation = is_conversation
|
|
45
52
|
self.max_tokens_to_sample = max_tokens
|
|
46
53
|
self.api_endpoint = "https://www.teach-anything.com/api/generate"
|
|
@@ -48,8 +55,6 @@ class TeachAnything:
|
|
|
48
55
|
self.last_response = {}
|
|
49
56
|
self.headers = {
|
|
50
57
|
"authority": "www.teach-anything.com",
|
|
51
|
-
"path": "/api/generate",
|
|
52
|
-
"scheme": "https",
|
|
53
58
|
"accept": "*/*",
|
|
54
59
|
"accept-encoding": "gzip, deflate, br, zstd",
|
|
55
60
|
"accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
|
|
@@ -57,13 +62,16 @@ class TeachAnything:
|
|
|
57
62
|
"origin": "https://www.teach-anything.com",
|
|
58
63
|
"referer": "https://www.teach-anything.com/",
|
|
59
64
|
"user-agent": LitAgent().random(),
|
|
65
|
+
# Add sec-ch-ua headers if needed for impersonation consistency
|
|
60
66
|
}
|
|
61
67
|
self.__available_optimizers = (
|
|
62
68
|
method
|
|
63
69
|
for method in dir(Optimizers)
|
|
64
70
|
if callable(getattr(Optimizers, method)) and not method.startswith("__")
|
|
65
71
|
)
|
|
72
|
+
# Update curl_cffi session headers and proxies
|
|
66
73
|
self.session.headers.update(self.headers)
|
|
74
|
+
self.session.proxies = proxies # Assign proxies directly
|
|
67
75
|
Conversation.intro = (
|
|
68
76
|
AwesomePrompts().get_act(
|
|
69
77
|
act, raise_not_found=True, default=None, case_insensitive=True
|
|
@@ -75,12 +83,12 @@ class TeachAnything:
|
|
|
75
83
|
is_conversation, self.max_tokens_to_sample, filepath, update_file
|
|
76
84
|
)
|
|
77
85
|
self.conversation.history_offset = history_offset
|
|
78
|
-
|
|
86
|
+
|
|
79
87
|
def ask(
|
|
80
88
|
self,
|
|
81
89
|
prompt: str,
|
|
82
|
-
stream: bool = False,
|
|
83
|
-
raw: bool = False,
|
|
90
|
+
stream: bool = False, # Keep stream param for interface, but API doesn't stream
|
|
91
|
+
raw: bool = False, # Keep raw param for interface
|
|
84
92
|
optimizer: str = None,
|
|
85
93
|
conversationally: bool = False,
|
|
86
94
|
) -> dict:
|
|
@@ -110,31 +118,40 @@ class TeachAnything:
|
|
|
110
118
|
payload = {
|
|
111
119
|
"prompt": conversation_prompt
|
|
112
120
|
}
|
|
113
|
-
def for_stream():
|
|
114
|
-
response = self.session.post(self.api_endpoint, headers=self.headers, json=payload, timeout=self.timeout)
|
|
115
|
-
if not response.ok:
|
|
116
|
-
raise RequestException(
|
|
117
|
-
f"Failed to generate response - ({response.status_code}, {response.reason}) - {response.text}"
|
|
118
|
-
)
|
|
119
121
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
+
# API does not stream, so implement non-stream logic directly
|
|
123
|
+
try:
|
|
124
|
+
# Use curl_cffi session post with impersonate
|
|
125
|
+
response = self.session.post(
|
|
126
|
+
self.api_endpoint,
|
|
127
|
+
# headers are set on the session
|
|
128
|
+
json=payload,
|
|
129
|
+
timeout=self.timeout,
|
|
130
|
+
impersonate="chrome110" # Use a common impersonation profile
|
|
131
|
+
)
|
|
132
|
+
response.raise_for_status() # Check for HTTP errors
|
|
133
|
+
|
|
134
|
+
# Use response.text which is already decoded
|
|
135
|
+
resp_text = response.text
|
|
136
|
+
# The response is plain text, wrap it in the expected dict format
|
|
137
|
+
self.last_response = {"text": resp_text}
|
|
122
138
|
self.conversation.update_chat_history(
|
|
123
|
-
prompt,
|
|
139
|
+
prompt, resp_text
|
|
124
140
|
)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
# Return dict or raw string based on raw flag
|
|
142
|
+
return resp_text if raw else self.last_response
|
|
143
|
+
|
|
144
|
+
except CurlError as e: # Catch CurlError
|
|
145
|
+
raise exceptions.FailedToGenerateResponseError(f"Request failed (CurlError): {e}") from e
|
|
146
|
+
except Exception as e: # Catch other potential exceptions (like HTTPError)
|
|
147
|
+
err_text = getattr(e, 'response', None) and getattr(e.response, 'text', '')
|
|
148
|
+
raise exceptions.FailedToGenerateResponseError(f"An unexpected error occurred ({type(e).__name__}): {e} - {err_text}") from e
|
|
131
149
|
|
|
132
|
-
return for_stream() if stream else for_non_stream()
|
|
133
150
|
|
|
134
151
|
def chat(
|
|
135
152
|
self,
|
|
136
153
|
prompt: str,
|
|
137
|
-
stream: bool = False,
|
|
154
|
+
stream: bool = False, # Keep stream param for interface consistency
|
|
138
155
|
optimizer: str = None,
|
|
139
156
|
conversationally: bool = False,
|
|
140
157
|
) -> str:
|
|
@@ -148,23 +165,22 @@ class TeachAnything:
|
|
|
148
165
|
str: Response generated
|
|
149
166
|
"""
|
|
150
167
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return for_stream() if stream else for_non_stream()
|
|
168
|
+
# Since ask() now handles both stream=True/False by returning the full response dict/str:
|
|
169
|
+
response_data = self.ask(
|
|
170
|
+
prompt,
|
|
171
|
+
stream=False, # Call ask in non-stream mode internally
|
|
172
|
+
raw=False, # Ensure ask returns dict
|
|
173
|
+
optimizer=optimizer,
|
|
174
|
+
conversationally=conversationally
|
|
175
|
+
)
|
|
176
|
+
# If stream=True was requested, simulate streaming by yielding the full message at once
|
|
177
|
+
if stream:
|
|
178
|
+
def stream_wrapper():
|
|
179
|
+
yield self.get_message(response_data)
|
|
180
|
+
return stream_wrapper()
|
|
181
|
+
else:
|
|
182
|
+
# If stream=False, return the full message directly
|
|
183
|
+
return self.get_message(response_data)
|
|
168
184
|
|
|
169
185
|
def get_message(self, response: dict) -> str:
|
|
170
186
|
"""Retrieves message only from response
|
|
@@ -180,8 +196,26 @@ class TeachAnything:
|
|
|
180
196
|
|
|
181
197
|
|
|
182
198
|
if __name__ == '__main__':
|
|
199
|
+
# Ensure curl_cffi is installed
|
|
183
200
|
from rich import print
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
201
|
+
try: # Add try-except block for testing
|
|
202
|
+
ai = TeachAnything(timeout=60)
|
|
203
|
+
print("[bold blue]Testing Chat (Non-Stream Simulation):[/bold blue]")
|
|
204
|
+
# Test non-stream first as API doesn't truly stream
|
|
205
|
+
response_non_stream = ai.chat("hi", stream=False)
|
|
206
|
+
print(response_non_stream)
|
|
207
|
+
print("[bold green]Non-Stream Test Complete.[/bold green]\n")
|
|
208
|
+
|
|
209
|
+
# Test stream interface (will yield the full response at once)
|
|
210
|
+
print("[bold blue]Testing Chat (Stream Simulation):[/bold blue]")
|
|
211
|
+
response_stream = ai.chat("hello again", stream=True)
|
|
212
|
+
full_stream_response = ""
|
|
213
|
+
for chunk in response_stream:
|
|
214
|
+
print(chunk, end="", flush=True)
|
|
215
|
+
full_stream_response += chunk
|
|
216
|
+
print("\n[bold green]Stream Test Complete.[/bold green]")
|
|
217
|
+
|
|
218
|
+
except exceptions.FailedToGenerateResponseError as e:
|
|
219
|
+
print(f"\n[bold red]API Error:[/bold red] {e}")
|
|
220
|
+
except Exception as e:
|
|
221
|
+
print(f"\n[bold red]An unexpected error occurred:[/bold red] {e}")
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
from curl_cffi.requests import Session
|
|
2
|
+
from curl_cffi import CurlError
|
|
2
3
|
import json
|
|
3
4
|
from typing import Union, Any, Dict, Generator, Optional, List
|
|
4
5
|
from webscout.AIutel import Optimizers, Conversation, AwesomePrompts
|
|
@@ -39,7 +40,7 @@ class TextPollinationsAI(Provider):
|
|
|
39
40
|
def __init__(
|
|
40
41
|
self,
|
|
41
42
|
is_conversation: bool = True,
|
|
42
|
-
max_tokens: int = 8096,
|
|
43
|
+
max_tokens: int = 8096, # Note: max_tokens is not directly used by this API endpoint
|
|
43
44
|
timeout: int = 30,
|
|
44
45
|
intro: str = None,
|
|
45
46
|
filepath: str = None,
|
|
@@ -54,7 +55,8 @@ class TextPollinationsAI(Provider):
|
|
|
54
55
|
if model not in self.AVAILABLE_MODELS:
|
|
55
56
|
raise ValueError(f"Invalid model: {model}. Choose from: {self.AVAILABLE_MODELS}")
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
# Initialize curl_cffi Session
|
|
59
|
+
self.session = Session()
|
|
58
60
|
self.is_conversation = is_conversation
|
|
59
61
|
self.max_tokens_to_sample = max_tokens
|
|
60
62
|
self.api_endpoint = "https://text.pollinations.ai/openai"
|
|
@@ -69,10 +71,12 @@ class TextPollinationsAI(Provider):
|
|
|
69
71
|
'Accept-Language': 'en-US,en;q=0.9',
|
|
70
72
|
'User-Agent': Lit().random(),
|
|
71
73
|
'Content-Type': 'application/json',
|
|
74
|
+
# Add sec-ch-ua headers if needed for impersonation consistency
|
|
72
75
|
}
|
|
73
76
|
|
|
77
|
+
# Update curl_cffi session headers and proxies
|
|
74
78
|
self.session.headers.update(self.headers)
|
|
75
|
-
self.session.proxies = proxies
|
|
79
|
+
self.session.proxies = proxies # Assign proxies directly
|
|
76
80
|
|
|
77
81
|
self.__available_optimizers = (
|
|
78
82
|
method for method in dir(Optimizers)
|
|
@@ -128,52 +132,96 @@ class TextPollinationsAI(Provider):
|
|
|
128
132
|
payload["tool_choice"] = tool_choice
|
|
129
133
|
|
|
130
134
|
def for_stream():
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
raise exceptions.FailedToGenerateResponseError(
|
|
141
|
-
f"Failed to generate response - ({response.status_code}, {response.reason}) - {response.text}"
|
|
135
|
+
try: # Add try block for CurlError
|
|
136
|
+
# Use curl_cffi session post with impersonate
|
|
137
|
+
response = self.session.post(
|
|
138
|
+
self.api_endpoint,
|
|
139
|
+
# headers are set on the session
|
|
140
|
+
json=payload,
|
|
141
|
+
stream=True,
|
|
142
|
+
timeout=self.timeout,
|
|
143
|
+
impersonate="chrome120" # Add impersonate
|
|
142
144
|
)
|
|
143
145
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
146
|
+
if not response.ok:
|
|
147
|
+
raise exceptions.FailedToGenerateResponseError(
|
|
148
|
+
f"Failed to generate response - ({response.status_code}, {response.reason}) - {response.text}"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
full_response = ""
|
|
152
|
+
# Iterate over bytes and decode manually
|
|
153
|
+
for line_bytes in response.iter_lines():
|
|
154
|
+
if line_bytes:
|
|
155
|
+
line = line_bytes.decode('utf-8').strip()
|
|
156
|
+
if line == "data: [DONE]":
|
|
157
|
+
break
|
|
158
|
+
if line.startswith('data: '):
|
|
159
|
+
try:
|
|
160
|
+
json_data = json.loads(line[6:])
|
|
161
|
+
if 'choices' in json_data and len(json_data['choices']) > 0:
|
|
162
|
+
choice = json_data['choices'][0]
|
|
163
|
+
if 'delta' in choice:
|
|
164
|
+
if 'content' in choice['delta'] and choice['delta']['content'] is not None:
|
|
165
|
+
content = choice['delta']['content']
|
|
166
|
+
full_response += content
|
|
167
|
+
# Yield dict or raw string
|
|
168
|
+
yield content if raw else dict(text=content)
|
|
169
|
+
elif 'tool_calls' in choice['delta']:
|
|
170
|
+
# Handle tool calls in streaming response
|
|
171
|
+
tool_calls = choice['delta']['tool_calls']
|
|
172
|
+
# Yield dict or raw list
|
|
173
|
+
yield tool_calls if raw else dict(tool_calls=tool_calls)
|
|
174
|
+
except json.JSONDecodeError:
|
|
175
|
+
continue
|
|
176
|
+
except UnicodeDecodeError:
|
|
177
|
+
continue
|
|
178
|
+
|
|
179
|
+
# Update history and last response after stream finishes
|
|
180
|
+
# Note: last_response might only contain text, not tool calls if they occurred
|
|
181
|
+
self.last_response.update(dict(text=full_response))
|
|
182
|
+
if full_response: # Only update history if text was received
|
|
183
|
+
self.conversation.update_chat_history(
|
|
184
|
+
prompt, full_response # Use the fully aggregated text
|
|
185
|
+
)
|
|
186
|
+
except CurlError as e: # Catch CurlError
|
|
187
|
+
raise exceptions.FailedToGenerateResponseError(f"Request failed (CurlError): {e}") from e
|
|
188
|
+
except Exception as e: # Catch other potential exceptions
|
|
189
|
+
raise exceptions.FailedToGenerateResponseError(f"An unexpected error occurred ({type(e).__name__}): {e}") from e
|
|
190
|
+
|
|
171
191
|
|
|
172
192
|
def for_non_stream():
|
|
173
|
-
|
|
174
|
-
|
|
193
|
+
# Aggregate the stream using the updated for_stream logic
|
|
194
|
+
final_content = ""
|
|
195
|
+
tool_calls_aggregated = None # To store potential tool calls
|
|
196
|
+
for chunk_data in for_stream():
|
|
197
|
+
if isinstance(chunk_data, dict):
|
|
198
|
+
if "text" in chunk_data:
|
|
199
|
+
final_content += chunk_data["text"]
|
|
200
|
+
elif "tool_calls" in chunk_data:
|
|
201
|
+
# Aggregate tool calls (simple aggregation, might need refinement)
|
|
202
|
+
if tool_calls_aggregated is None:
|
|
203
|
+
tool_calls_aggregated = []
|
|
204
|
+
tool_calls_aggregated.extend(chunk_data["tool_calls"])
|
|
205
|
+
elif isinstance(chunk_data, str): # Handle raw stream case
|
|
206
|
+
final_content += chunk_data
|
|
207
|
+
# Handle raw tool calls list if raw=True
|
|
208
|
+
elif isinstance(chunk_data, list) and raw:
|
|
209
|
+
if tool_calls_aggregated is None:
|
|
210
|
+
tool_calls_aggregated = []
|
|
211
|
+
tool_calls_aggregated.extend(chunk_data)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
# last_response and history are updated within for_stream (for text)
|
|
215
|
+
# Return a dict containing text and/or tool_calls
|
|
216
|
+
result = {}
|
|
217
|
+
if final_content:
|
|
218
|
+
result["text"] = final_content
|
|
219
|
+
if tool_calls_aggregated:
|
|
220
|
+
result["tool_calls"] = tool_calls_aggregated
|
|
221
|
+
self.last_response = result # Update last_response with aggregated result
|
|
175
222
|
return self.last_response
|
|
176
223
|
|
|
224
|
+
|
|
177
225
|
return for_stream() if stream else for_non_stream()
|
|
178
226
|
|
|
179
227
|
def chat(
|
|
@@ -217,6 +265,7 @@ class TextPollinationsAI(Provider):
|
|
|
217
265
|
return json.dumps(response["tool_calls"])
|
|
218
266
|
|
|
219
267
|
if __name__ == "__main__":
|
|
268
|
+
# Ensure curl_cffi is installed
|
|
220
269
|
print("-" * 80)
|
|
221
270
|
print(f"{'Model':<50} {'Status':<10} {'Response'}")
|
|
222
271
|
print("-" * 80)
|
|
@@ -228,19 +277,28 @@ if __name__ == "__main__":
|
|
|
228
277
|
for model in TextPollinationsAI.AVAILABLE_MODELS:
|
|
229
278
|
try:
|
|
230
279
|
test_ai = TextPollinationsAI(model=model, timeout=60)
|
|
231
|
-
|
|
280
|
+
# Test stream first
|
|
281
|
+
response_stream = test_ai.chat("Say 'Hello' in one word", stream=True)
|
|
232
282
|
response_text = ""
|
|
233
|
-
|
|
283
|
+
print(f"\r{model:<50} {'Streaming...':<10}", end="", flush=True)
|
|
284
|
+
for chunk in response_stream:
|
|
234
285
|
response_text += chunk
|
|
235
|
-
print(f"\r{model:<50} {'Testing...':<10}", end="", flush=True)
|
|
236
286
|
|
|
237
287
|
if response_text and len(response_text.strip()) > 0:
|
|
238
288
|
status = "✓"
|
|
239
|
-
#
|
|
240
|
-
|
|
289
|
+
# Clean and truncate response
|
|
290
|
+
clean_text = response_text.strip()
|
|
291
|
+
display_text = clean_text[:50] + "..." if len(clean_text) > 50 else clean_text
|
|
241
292
|
else:
|
|
242
|
-
status = "✗"
|
|
243
|
-
display_text = "Empty or invalid response"
|
|
293
|
+
status = "✗ (Stream)"
|
|
294
|
+
display_text = "Empty or invalid stream response"
|
|
244
295
|
print(f"\r{model:<50} {status:<10} {display_text}")
|
|
296
|
+
|
|
297
|
+
# Optional: Add non-stream test if needed
|
|
298
|
+
# print(f"\r{model:<50} {'Non-Stream...':<10}", end="", flush=True)
|
|
299
|
+
# response_non_stream = test_ai.chat("Say 'Hi' again", stream=False)
|
|
300
|
+
# if not response_non_stream or len(response_non_stream.strip()) == 0:
|
|
301
|
+
# print(f"\r{model:<50} {'✗ (Non-Stream)':<10} Empty non-stream response")
|
|
302
|
+
|
|
245
303
|
except Exception as e:
|
|
246
304
|
print(f"\r{model:<50} {'✗':<10} {str(e)}")
|