webscout 6.5__py3-none-any.whl → 6.7__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/Extra/autocoder/autocoder_utiles.py +119 -101
- webscout/Extra/weather.py +5 -5
- webscout/Provider/AISEARCH/__init__.py +2 -0
- webscout/Provider/AISEARCH/ooai.py +155 -0
- webscout/Provider/Amigo.py +70 -85
- webscout/Provider/{prefind.py → Jadve.py} +72 -70
- webscout/Provider/Netwrck.py +239 -0
- webscout/Provider/Openai.py +4 -3
- webscout/Provider/PI.py +2 -2
- webscout/Provider/PizzaGPT.py +3 -3
- webscout/Provider/TeachAnything.py +15 -2
- webscout/Provider/Youchat.py +42 -8
- webscout/Provider/__init__.py +134 -147
- webscout/Provider/meta.py +1 -1
- webscout/Provider/multichat.py +230 -0
- webscout/Provider/promptrefine.py +2 -2
- webscout/Provider/talkai.py +10 -13
- webscout/Provider/turboseek.py +5 -4
- webscout/Provider/tutorai.py +8 -112
- webscout/Provider/typegpt.py +4 -5
- webscout/Provider/x0gpt.py +81 -9
- webscout/Provider/yep.py +123 -361
- webscout/__init__.py +10 -1
- webscout/cli.py +31 -39
- webscout/conversation.py +24 -9
- webscout/exceptions.py +188 -20
- webscout/litprinter/__init__.py +19 -123
- webscout/litprinter/colors.py +54 -0
- webscout/optimizers.py +335 -185
- webscout/scout/__init__.py +2 -5
- webscout/scout/core/__init__.py +7 -0
- webscout/scout/core/crawler.py +140 -0
- webscout/scout/core/scout.py +571 -0
- webscout/scout/core/search_result.py +96 -0
- webscout/scout/core/text_analyzer.py +63 -0
- webscout/scout/core/text_utils.py +277 -0
- webscout/scout/core/web_analyzer.py +52 -0
- webscout/scout/element.py +6 -5
- webscout/update_checker.py +117 -58
- webscout/version.py +1 -1
- webscout/webscout_search.py +1 -1
- webscout/zeroart/base.py +15 -16
- webscout/zeroart/effects.py +1 -1
- webscout/zeroart/fonts.py +1 -1
- {webscout-6.5.dist-info → webscout-6.7.dist-info}/METADATA +9 -172
- {webscout-6.5.dist-info → webscout-6.7.dist-info}/RECORD +63 -45
- {webscout-6.5.dist-info → webscout-6.7.dist-info}/entry_points.txt +1 -1
- webscout-6.7.dist-info/top_level.txt +2 -0
- webstoken/__init__.py +30 -0
- webstoken/classifier.py +189 -0
- webstoken/keywords.py +216 -0
- webstoken/language.py +128 -0
- webstoken/ner.py +164 -0
- webstoken/normalizer.py +35 -0
- webstoken/processor.py +77 -0
- webstoken/sentiment.py +206 -0
- webstoken/stemmer.py +73 -0
- webstoken/t.py +75 -0
- webstoken/tagger.py +60 -0
- webstoken/tokenizer.py +158 -0
- webscout/Provider/Perplexity.py +0 -591
- webscout/Provider/RoboCoders.py +0 -206
- webscout/Provider/genspark.py +0 -225
- webscout/Provider/perplexitylabs.py +0 -265
- webscout/Provider/twitterclone.py +0 -251
- webscout/Provider/upstage.py +0 -230
- webscout-6.5.dist-info/top_level.txt +0 -1
- /webscout/Provider/{felo_search.py → AISEARCH/felo_search.py} +0 -0
- {webscout-6.5.dist-info → webscout-6.7.dist-info}/LICENSE.md +0 -0
- {webscout-6.5.dist-info → webscout-6.7.dist-info}/WHEEL +0 -0
webscout/Provider/yep.py
CHANGED
|
@@ -3,7 +3,7 @@ import uuid
|
|
|
3
3
|
import cloudscraper
|
|
4
4
|
import json
|
|
5
5
|
|
|
6
|
-
from typing import Any, Dict, Optional,
|
|
6
|
+
from typing import Any, Dict, Optional, Generator, Union
|
|
7
7
|
from dataclasses import dataclass, asdict
|
|
8
8
|
from datetime import date
|
|
9
9
|
|
|
@@ -12,47 +12,19 @@ from webscout.AIutel import Conversation
|
|
|
12
12
|
from webscout.AIutel import AwesomePrompts
|
|
13
13
|
from webscout.AIbase import Provider
|
|
14
14
|
from webscout import WEBS, exceptions
|
|
15
|
+
from webscout.Litlogger import LitLogger, LogFormat, ColorScheme
|
|
16
|
+
from webscout.litagent import LitAgent
|
|
15
17
|
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
tool_input: Dict[str, Any]
|
|
19
|
+
class YEPCHAT(Provider):
|
|
20
|
+
"""
|
|
21
|
+
YEPCHAT is a provider class for interacting with the Yep API.
|
|
21
22
|
|
|
23
|
+
Attributes:
|
|
24
|
+
AVAILABLE_MODELS (list): List of available models for the provider.
|
|
25
|
+
"""
|
|
22
26
|
|
|
23
|
-
class YEPCHAT(Provider):
|
|
24
27
|
AVAILABLE_MODELS = ["Mixtral-8x7B-Instruct-v0.1"]
|
|
25
|
-
tool_call_start = "```tool_code"
|
|
26
|
-
tool_call_end = "```"
|
|
27
|
-
|
|
28
|
-
class ToolRegistry:
|
|
29
|
-
def __init__(self):
|
|
30
|
-
self.tools: Dict[str, Dict[str, Union[Callable, str, Dict]]] = {}
|
|
31
|
-
|
|
32
|
-
def register_tool(
|
|
33
|
-
self,
|
|
34
|
-
name: str,
|
|
35
|
-
function: Callable,
|
|
36
|
-
description: str = "",
|
|
37
|
-
parameters: Optional[Dict[str, Any]] = None,
|
|
38
|
-
):
|
|
39
|
-
self.tools[name] = {
|
|
40
|
-
"function": function,
|
|
41
|
-
"description": description,
|
|
42
|
-
"parameters": parameters,
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
def get_tool(self, name: str) -> Optional[Callable]:
|
|
46
|
-
tool = self.tools.get(name)
|
|
47
|
-
return tool["function"] if tool else None
|
|
48
|
-
|
|
49
|
-
def get_tool_description(self, name: str) -> str:
|
|
50
|
-
tool = self.tools.get(name)
|
|
51
|
-
return tool["description"] if tool else ""
|
|
52
|
-
|
|
53
|
-
def get_tool_parameters(self, name: str) -> Optional[Dict[str, Any]]:
|
|
54
|
-
tool = self.tools.get(name)
|
|
55
|
-
return tool["parameters"] if tool else None
|
|
56
28
|
|
|
57
29
|
def __init__(
|
|
58
30
|
self,
|
|
@@ -68,10 +40,19 @@ class YEPCHAT(Provider):
|
|
|
68
40
|
model: str = "Mixtral-8x7B-Instruct-v0.1",
|
|
69
41
|
temperature: float = 0.6,
|
|
70
42
|
top_p: float = 0.7,
|
|
71
|
-
|
|
72
|
-
retries: int = 3,
|
|
73
|
-
retry_delay: int = 5,
|
|
43
|
+
logging: bool = False,
|
|
74
44
|
):
|
|
45
|
+
"""
|
|
46
|
+
Initializes the YEPCHAT provider with the specified parameters.
|
|
47
|
+
|
|
48
|
+
Examples:
|
|
49
|
+
>>> ai = YEPCHAT(logging=True)
|
|
50
|
+
>>> ai.ask("What's the weather today?")
|
|
51
|
+
Sends a prompt to the Yep API and returns the response.
|
|
52
|
+
|
|
53
|
+
>>> ai.chat("Tell me a joke", stream=True)
|
|
54
|
+
Initiates a chat with the Yep API using the provided prompt.
|
|
55
|
+
"""
|
|
75
56
|
if model not in self.AVAILABLE_MODELS:
|
|
76
57
|
raise ValueError(
|
|
77
58
|
f"Invalid model: {model}. Choose from: {self.AVAILABLE_MODELS}"
|
|
@@ -87,7 +68,10 @@ class YEPCHAT(Provider):
|
|
|
87
68
|
self.model = model
|
|
88
69
|
self.temperature = temperature
|
|
89
70
|
self.top_p = top_p
|
|
90
|
-
|
|
71
|
+
|
|
72
|
+
# Initialize LitAgent for user agent generation
|
|
73
|
+
self.agent = LitAgent()
|
|
74
|
+
|
|
91
75
|
self.headers = {
|
|
92
76
|
"Accept": "*/*",
|
|
93
77
|
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
@@ -99,7 +83,7 @@ class YEPCHAT(Provider):
|
|
|
99
83
|
"Sec-CH-UA": '"Not)A;Brand";v="99", "Microsoft Edge";v="127", "Chromium";v="127"',
|
|
100
84
|
"Sec-CH-UA-Mobile": "?0",
|
|
101
85
|
"Sec-CH-UA-Platform": '"Windows"',
|
|
102
|
-
"User-Agent":
|
|
86
|
+
"User-Agent": self.agent.random(), # Use LitAgent to generate a random user agent
|
|
103
87
|
}
|
|
104
88
|
self.cookies = {"__Host-session": uuid.uuid4().hex}
|
|
105
89
|
|
|
@@ -120,10 +104,10 @@ class YEPCHAT(Provider):
|
|
|
120
104
|
self.conversation.history_offset = history_offset
|
|
121
105
|
self.session.proxies = proxies
|
|
122
106
|
|
|
123
|
-
self.tool_registry = self.ToolRegistry()
|
|
124
107
|
self.knowledge_cutoff = "December 2023"
|
|
125
|
-
|
|
126
|
-
|
|
108
|
+
|
|
109
|
+
# Initialize logger
|
|
110
|
+
self.logger = LitLogger(name="YEPCHAT", format=LogFormat.MODERN_EMOJI, color_scheme=ColorScheme.CYBERPUNK) if logging else None
|
|
127
111
|
|
|
128
112
|
def ask(
|
|
129
113
|
self,
|
|
@@ -132,8 +116,21 @@ class YEPCHAT(Provider):
|
|
|
132
116
|
raw: bool = False,
|
|
133
117
|
optimizer: str = None,
|
|
134
118
|
conversationally: bool = False,
|
|
135
|
-
) ->
|
|
136
|
-
|
|
119
|
+
) -> Union[Dict[str, Any], Generator]:
|
|
120
|
+
"""
|
|
121
|
+
Sends a prompt to the Yep API and returns the response.
|
|
122
|
+
|
|
123
|
+
Examples:
|
|
124
|
+
>>> ai = YEPCHAT()
|
|
125
|
+
>>> ai.ask("What's the weather today?")
|
|
126
|
+
Returns the response from the Yep API.
|
|
127
|
+
|
|
128
|
+
>>> ai.ask("Tell me a joke", stream=True)
|
|
129
|
+
Streams the response from the Yep API.
|
|
130
|
+
"""
|
|
131
|
+
if self.logger:
|
|
132
|
+
self.logger.debug(f"ask() called with prompt: {prompt}")
|
|
133
|
+
|
|
137
134
|
conversation_prompt = self.conversation.gen_complete_prompt(prompt)
|
|
138
135
|
if optimizer:
|
|
139
136
|
if optimizer in self.__available_optimizers:
|
|
@@ -141,149 +138,66 @@ class YEPCHAT(Provider):
|
|
|
141
138
|
conversation_prompt if conversationally else prompt
|
|
142
139
|
)
|
|
143
140
|
else:
|
|
141
|
+
if self.logger:
|
|
142
|
+
self.logger.error(f"Invalid optimizer: {optimizer}")
|
|
144
143
|
raise Exception(
|
|
145
144
|
f"Optimizer is not one of {self.__available_optimizers}"
|
|
146
145
|
)
|
|
147
146
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
tool_call_data = self._parse_function_call(initial_response)
|
|
157
|
-
if tool_call_data and "error" not in tool_call_data:
|
|
158
|
-
tool_call = ToolCall(**tool_call_data)
|
|
159
|
-
tool_output = self.execute_tool(tool_call)
|
|
160
|
-
# logging.info(f"Tool output: {tool_output}")
|
|
161
|
-
|
|
162
|
-
final_response = self._get_final_response(
|
|
163
|
-
prompt,
|
|
164
|
-
initial_response,
|
|
165
|
-
tool_call_data,
|
|
166
|
-
tool_output,
|
|
167
|
-
self.retries,
|
|
168
|
-
self.retry_delay,
|
|
169
|
-
)
|
|
170
|
-
# logging.info(f"Final AI response: {final_response}")
|
|
171
|
-
|
|
172
|
-
self.last_response.update(dict(text=final_response))
|
|
173
|
-
self.conversation.update_chat_history(
|
|
174
|
-
prompt, self.get_message(self.last_response)
|
|
175
|
-
)
|
|
176
|
-
return self.last_response
|
|
147
|
+
data = {
|
|
148
|
+
"stream": stream,
|
|
149
|
+
"max_tokens": self.max_tokens_to_sample,
|
|
150
|
+
"top_p": self.top_p,
|
|
151
|
+
"temperature": self.temperature,
|
|
152
|
+
"messages": [{"content": conversation_prompt, "role": "user"}],
|
|
153
|
+
"model": self.model,
|
|
154
|
+
}
|
|
177
155
|
|
|
178
|
-
|
|
179
|
-
for attempt in range(retries + 1):
|
|
180
|
-
try:
|
|
181
|
-
prompt = self._generate_system_message(prompt)
|
|
182
|
-
data = {
|
|
183
|
-
"stream": False,
|
|
184
|
-
"max_tokens": self.max_tokens_to_sample,
|
|
185
|
-
"top_p": self.top_p,
|
|
186
|
-
"temperature": self.temperature,
|
|
187
|
-
"messages": [{"content": prompt, "role": "user"}],
|
|
188
|
-
"model": self.model,
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
response = self.session.post(
|
|
192
|
-
self.chat_endpoint,
|
|
193
|
-
headers=self.headers,
|
|
194
|
-
cookies=self.cookies,
|
|
195
|
-
json=data,
|
|
196
|
-
timeout=self.timeout,
|
|
197
|
-
)
|
|
198
|
-
if not response.ok:
|
|
199
|
-
raise exceptions.FailedToGenerateResponseError(
|
|
200
|
-
f"Failed to generate response - ({response.status_code}, {response.reason}) - {response.text}"
|
|
201
|
-
)
|
|
202
|
-
return response.json()["choices"][0]["message"]["content"]
|
|
203
|
-
except exceptions.FailedToGenerateResponseError as e:
|
|
204
|
-
if attempt < retries:
|
|
205
|
-
# logging.warning(f"API request failed: {e}. Retrying in {retry_delay} seconds...")
|
|
206
|
-
time.sleep(retry_delay)
|
|
207
|
-
else:
|
|
208
|
-
raise e
|
|
209
|
-
except Exception as e:
|
|
210
|
-
if attempt < retries:
|
|
211
|
-
# logging.warning(
|
|
212
|
-
# f"An unexpected error occurred: {e}. Retrying in {retry_delay} seconds..."
|
|
213
|
-
# )
|
|
214
|
-
time.sleep(retry_delay)
|
|
215
|
-
else:
|
|
216
|
-
raise e
|
|
217
|
-
|
|
218
|
-
def _get_final_response(
|
|
219
|
-
self,
|
|
220
|
-
prompt: str,
|
|
221
|
-
initial_response: str,
|
|
222
|
-
tool_call_data: Optional[Dict],
|
|
223
|
-
tool_output: Optional[str],
|
|
224
|
-
retries: int,
|
|
225
|
-
retry_delay: int,
|
|
226
|
-
) -> str:
|
|
227
|
-
for attempt in range(retries + 1):
|
|
156
|
+
def for_stream():
|
|
228
157
|
try:
|
|
229
|
-
data =
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
self.
|
|
261
|
-
headers=self.headers,
|
|
262
|
-
cookies=self.cookies,
|
|
263
|
-
json=data,
|
|
264
|
-
timeout=self.timeout,
|
|
265
|
-
)
|
|
266
|
-
if not response.ok:
|
|
267
|
-
raise exceptions.FailedToGenerateResponseError(
|
|
268
|
-
f"Failed to generate response - ({response.status_code}, {response.reason}) - {response.text}"
|
|
269
|
-
)
|
|
270
|
-
return response.json()["choices"][0]["message"]["content"]
|
|
271
|
-
except exceptions.FailedToGenerateResponseError as e:
|
|
272
|
-
if attempt < retries:
|
|
273
|
-
# logging.warning(
|
|
274
|
-
# f"API request failed: {e}. Retrying in {retry_delay} seconds..."
|
|
275
|
-
# )
|
|
276
|
-
time.sleep(retry_delay)
|
|
277
|
-
else:
|
|
278
|
-
raise e
|
|
158
|
+
with self.session.post(self.chat_endpoint, headers=self.headers, cookies=self.cookies, json=data, stream=True, timeout=self.timeout) as response:
|
|
159
|
+
if not response.ok:
|
|
160
|
+
if self.logger:
|
|
161
|
+
self.logger.error(f"Failed to generate response: {response.status_code} {response.reason}")
|
|
162
|
+
raise exceptions.FailedToGenerateResponseError(
|
|
163
|
+
f"Failed to generate response - ({response.status_code}, {response.reason}) - {response.text}"
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
streaming_text = ""
|
|
167
|
+
for line in response.iter_lines(decode_unicode=True):
|
|
168
|
+
if line:
|
|
169
|
+
line = line.strip()
|
|
170
|
+
if line.startswith("data: "):
|
|
171
|
+
json_str = line[6:]
|
|
172
|
+
if json_str == "[DONE]":
|
|
173
|
+
break
|
|
174
|
+
try:
|
|
175
|
+
json_data = json.loads(json_str)
|
|
176
|
+
if 'choices' in json_data:
|
|
177
|
+
choice = json_data['choices'][0]
|
|
178
|
+
if 'delta' in choice and 'content' in choice['delta']:
|
|
179
|
+
content = choice['delta']['content']
|
|
180
|
+
streaming_text += content
|
|
181
|
+
|
|
182
|
+
# Yield ONLY the new content:
|
|
183
|
+
resp = dict(text=content)
|
|
184
|
+
yield resp if raw else resp
|
|
185
|
+
except json.JSONDecodeError:
|
|
186
|
+
if self.logger:
|
|
187
|
+
self.logger.warning("JSONDecodeError encountered.")
|
|
188
|
+
pass
|
|
189
|
+
self.conversation.update_chat_history(prompt, streaming_text)
|
|
279
190
|
except Exception as e:
|
|
280
|
-
if
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
191
|
+
if self.logger:
|
|
192
|
+
self.logger.error(f"Request failed: {e}")
|
|
193
|
+
raise exceptions.FailedToGenerateResponseError(f"Request failed: {e}")
|
|
194
|
+
|
|
195
|
+
def for_non_stream():
|
|
196
|
+
for _ in for_stream():
|
|
197
|
+
pass
|
|
198
|
+
return self.last_response
|
|
199
|
+
|
|
200
|
+
return for_stream() if stream else for_non_stream()
|
|
287
201
|
|
|
288
202
|
def chat(
|
|
289
203
|
self,
|
|
@@ -292,6 +206,20 @@ class YEPCHAT(Provider):
|
|
|
292
206
|
optimizer: str = None,
|
|
293
207
|
conversationally: bool = False,
|
|
294
208
|
) -> str:
|
|
209
|
+
"""
|
|
210
|
+
Initiates a chat with the Yep API using the provided prompt.
|
|
211
|
+
|
|
212
|
+
Examples:
|
|
213
|
+
>>> ai = YEPCHAT()
|
|
214
|
+
>>> ai.chat("Tell me a joke")
|
|
215
|
+
Returns the chat response from the Yep API.
|
|
216
|
+
|
|
217
|
+
>>> ai.chat("What's the weather today?", stream=True)
|
|
218
|
+
Streams the chat response from the Yep API.
|
|
219
|
+
"""
|
|
220
|
+
if self.logger:
|
|
221
|
+
self.logger.debug(f"chat() called with prompt: {prompt}")
|
|
222
|
+
|
|
295
223
|
def for_stream():
|
|
296
224
|
for response in self.ask(
|
|
297
225
|
prompt, True, optimizer=optimizer, conversationally=conversationally
|
|
@@ -311,190 +239,24 @@ class YEPCHAT(Provider):
|
|
|
311
239
|
return for_stream() if stream else for_non_stream()
|
|
312
240
|
|
|
313
241
|
def get_message(self, response: dict) -> str:
|
|
242
|
+
"""
|
|
243
|
+
Extracts the message content from the API response.
|
|
244
|
+
|
|
245
|
+
Examples:
|
|
246
|
+
>>> ai = YEPCHAT()
|
|
247
|
+
>>> response = ai.ask("Tell me a joke")
|
|
248
|
+
>>> ai.get_message(response)
|
|
249
|
+
Extracts and returns the message content from the response.
|
|
250
|
+
"""
|
|
314
251
|
assert isinstance(response, dict)
|
|
315
252
|
return response["text"]
|
|
316
253
|
|
|
317
|
-
def _generate_system_message(self, user_message: str) -> str:
|
|
318
|
-
tools_description = ""
|
|
319
|
-
for name, tool_data in self.tool_registry.tools.items():
|
|
320
|
-
description = tool_data["description"]
|
|
321
|
-
parameters = tool_data.get("parameters")
|
|
322
|
-
if parameters:
|
|
323
|
-
params_str = ", ".join(
|
|
324
|
-
f"{param_name}: {param_desc['description']}"
|
|
325
|
-
for param_name, param_desc in parameters["properties"].items()
|
|
326
|
-
)
|
|
327
|
-
tools_description += f"- **{name}({params_str}):** {description}\n"
|
|
328
|
-
else:
|
|
329
|
-
tools_description += f"- **{name}()**: {description}\n"
|
|
330
|
-
|
|
331
|
-
current_date = date.today().strftime("%B %d, %Y")
|
|
332
|
-
return (
|
|
333
|
-
f"Today's date is {current_date}. Your knowledge cutoff is {self.knowledge_cutoff}.\n"
|
|
334
|
-
"You are a helpful AI assistant designed to assist users with their questions. "
|
|
335
|
-
"You have access to a set of tools that can help you provide more accurate and informative answers. "
|
|
336
|
-
f"Here is a list of the available tools and their functions:\n{tools_description}\n\n"
|
|
337
|
-
"**Instructions:**\n"
|
|
338
|
-
"1. Carefully analyze the user's request to understand their intent.\n"
|
|
339
|
-
"2. Determine if any of the provided tools can be used to fulfill the request.\n"
|
|
340
|
-
"3. If a tool can be used, choose the MOST APPROPRIATE tool. Don't choose a tool if it's not relevant to the request.\n"
|
|
341
|
-
"4. If you decide to use a tool, provide your response ONLY in the following JSON format:\n"
|
|
342
|
-
" ```json\n"
|
|
343
|
-
" {{\n"
|
|
344
|
-
' "tool_name": "name_of_the_tool",\n'
|
|
345
|
-
' "tool_input": {{\n'
|
|
346
|
-
' "parameter1": "value1",\n'
|
|
347
|
-
' "parameter2": "value2"\n'
|
|
348
|
-
' }}\n'
|
|
349
|
-
" }}\n"
|
|
350
|
-
" ```\n"
|
|
351
|
-
" - Replace 'name_of_the_tool' with the actual name of the tool.\n"
|
|
352
|
-
" - Replace 'parameter1', 'parameter2', etc., with the actual parameters of the tool, along with their corresponding values.\n"
|
|
353
|
-
" - Do NOT include any explanations or additional text within the JSON response.\n"
|
|
354
|
-
"5. If you determine that no tool is needed to answer the user's question, respond with the following JSON:\n"
|
|
355
|
-
" ```json\n"
|
|
356
|
-
" {{\n"
|
|
357
|
-
' "tool_name": "general_ai",\n'
|
|
358
|
-
' "tool_input": "None"\n'
|
|
359
|
-
" }}\n"
|
|
360
|
-
" ```\n"
|
|
361
|
-
f"User Request: {user_message}\n"
|
|
362
|
-
"Your Response (JSON only):"
|
|
363
|
-
)
|
|
364
|
-
|
|
365
|
-
def _parse_function_call(self, response: str) -> dict:
|
|
366
|
-
try:
|
|
367
|
-
parsed_response = json.loads(response)
|
|
368
|
-
if isinstance(parsed_response, dict) and "tool_name" in parsed_response:
|
|
369
|
-
# Ensure tool_input is a dictionary
|
|
370
|
-
if "tool_input" not in parsed_response or not isinstance(parsed_response["tool_input"], dict):
|
|
371
|
-
parsed_response["tool_input"] = {"query": parsed_response.get("tool_input", "")}
|
|
372
|
-
return parsed_response
|
|
373
|
-
except json.JSONDecodeError:
|
|
374
|
-
pass
|
|
375
|
-
|
|
376
|
-
# If JSON parsing fails or doesn't contain expected structure, try to extract JSON from the response
|
|
377
|
-
start_idx = response.find("{")
|
|
378
|
-
end_idx = response.rfind("}") + 1
|
|
379
|
-
if start_idx != -1 and end_idx != -1:
|
|
380
|
-
try:
|
|
381
|
-
parsed_response = json.loads(response[start_idx:end_idx])
|
|
382
|
-
if "tool_name" in parsed_response:
|
|
383
|
-
# Ensure tool_input is a dictionary
|
|
384
|
-
if "tool_input" not in parsed_response or not isinstance(parsed_response["tool_input"], dict):
|
|
385
|
-
parsed_response["tool_input"] = {"query": parsed_response.get("tool_input", "")}
|
|
386
|
-
return parsed_response
|
|
387
|
-
except json.JSONDecodeError:
|
|
388
|
-
pass
|
|
389
|
-
# logging.error("Error parsing tool call: Invalid JSON structure.")
|
|
390
|
-
|
|
391
|
-
# logging.error("Error parsing tool call: No valid JSON structure found.")
|
|
392
|
-
return {"error": "No valid JSON structure found."}
|
|
393
|
-
|
|
394
|
-
def _should_call_tool(self, response_text: str) -> bool:
|
|
395
|
-
return any(
|
|
396
|
-
tool_name.lower() in response_text.lower()
|
|
397
|
-
for tool_name in self.tool_registry.tools
|
|
398
|
-
)
|
|
399
|
-
|
|
400
|
-
def execute_tool(self, tool_call: ToolCall) -> str:
|
|
401
|
-
tool_name = tool_call.tool_name
|
|
402
|
-
tool_input = tool_call.tool_input
|
|
403
|
-
|
|
404
|
-
if tool_name == "general_ai":
|
|
405
|
-
return tool_input
|
|
406
|
-
|
|
407
|
-
tool_function = self.tool_registry.get_tool(tool_name)
|
|
408
|
-
if tool_function:
|
|
409
|
-
try:
|
|
410
|
-
parameters = self.tool_registry.get_tool_parameters(tool_name)
|
|
411
|
-
if parameters:
|
|
412
|
-
# If the tool expects parameters, pass them as keyword arguments
|
|
413
|
-
tool_output = tool_function(**tool_input)
|
|
414
|
-
else:
|
|
415
|
-
# If the tool doesn't expect parameters, call it without arguments
|
|
416
|
-
tool_output = tool_function()
|
|
417
|
-
return tool_output
|
|
418
|
-
except Exception as e:
|
|
419
|
-
# logging.error(f"Error executing tool {tool_name}: {e}")
|
|
420
|
-
return f"Error executing tool {tool_name}: {e}"
|
|
421
|
-
else:
|
|
422
|
-
return f"Tool '{tool_name}' not found."
|
|
423
|
-
|
|
424
254
|
|
|
425
255
|
if __name__ == "__main__":
|
|
426
256
|
from rich import print
|
|
427
257
|
|
|
428
|
-
|
|
429
|
-
"""Returns the current time in HH:MM:SS format."""
|
|
430
|
-
return time.strftime("%H:%M:%S")
|
|
431
|
-
|
|
432
|
-
def get_weather(location: str) -> str:
|
|
433
|
-
"""
|
|
434
|
-
Gets the current weather for a given location.
|
|
435
|
-
|
|
436
|
-
Args:
|
|
437
|
-
location (str): The location for which to retrieve the weather,
|
|
438
|
-
such as a city and state, or a zip code.
|
|
439
|
-
Examples: "London, UK", "90210".
|
|
258
|
+
ai = YEPCHAT(logging=False)
|
|
440
259
|
|
|
441
|
-
|
|
442
|
-
str: A string describing the current weather in the specified location.
|
|
443
|
-
Note: This is a placeholder and should be replaced with an actual weather API call.
|
|
444
|
-
"""
|
|
445
|
-
return f"The weather in {location} is sunny."
|
|
446
|
-
|
|
447
|
-
def web_search(query: str) -> str:
|
|
448
|
-
"""
|
|
449
|
-
Performs a web search and returns the top 3 results.
|
|
450
|
-
|
|
451
|
-
Args:
|
|
452
|
-
query (str): The search query to use.
|
|
453
|
-
|
|
454
|
-
Returns:
|
|
455
|
-
str: A formatted string containing the title, body, and URL of
|
|
456
|
-
the top 3 search results.
|
|
457
|
-
If no results are found, returns "No results found for your query."
|
|
458
|
-
"""
|
|
459
|
-
webs = WEBS()
|
|
460
|
-
results = webs.text(query, max_results=3)
|
|
461
|
-
if results:
|
|
462
|
-
formatted_results = "\n\n".join(
|
|
463
|
-
f"**{i+1}. {result['title']}**\n{result['body']}\n[URL: {result['href']}]"
|
|
464
|
-
for i, result in enumerate(results)
|
|
465
|
-
)
|
|
466
|
-
return formatted_results
|
|
467
|
-
else:
|
|
468
|
-
return "No results found for your query."
|
|
469
|
-
|
|
470
|
-
ai = YEPCHAT(Tools=False)
|
|
471
|
-
|
|
472
|
-
ai.tool_registry.register_tool("get_current_time", get_current_time, "Gets the current time.")
|
|
473
|
-
ai.tool_registry.register_tool(
|
|
474
|
-
"get_weather",
|
|
475
|
-
get_weather,
|
|
476
|
-
"Gets the weather for a given location.",
|
|
477
|
-
parameters={
|
|
478
|
-
"type": "object",
|
|
479
|
-
"properties": {
|
|
480
|
-
"location": {"type": "string", "description": "The city and state, or zip code"}
|
|
481
|
-
},
|
|
482
|
-
"required": ["location"],
|
|
483
|
-
},
|
|
484
|
-
)
|
|
485
|
-
ai.tool_registry.register_tool(
|
|
486
|
-
"web_search",
|
|
487
|
-
web_search,
|
|
488
|
-
"Searches the web for information.",
|
|
489
|
-
parameters={
|
|
490
|
-
"type": "object",
|
|
491
|
-
"properties": {
|
|
492
|
-
"query": {"type": "string", "description": "The search query."}
|
|
493
|
-
},
|
|
494
|
-
"required": ["query"],
|
|
495
|
-
},
|
|
496
|
-
)
|
|
497
|
-
|
|
498
|
-
response = ai.chat("hi")
|
|
260
|
+
response = ai.chat("hi", stream=True)
|
|
499
261
|
for chunk in response:
|
|
500
|
-
print(chunk, end="", flush=True)
|
|
262
|
+
print(chunk, end="", flush=True)
|
webscout/__init__.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# webscout/__init__.py
|
|
2
|
+
|
|
1
3
|
from .webscout_search import WEBS
|
|
2
4
|
from .webscout_search_async import AsyncWEBS
|
|
3
5
|
from .version import __version__
|
|
@@ -7,10 +9,10 @@ from .LLM import VLM, LLM
|
|
|
7
9
|
from .Provider import *
|
|
8
10
|
from .Provider.TTI import *
|
|
9
11
|
from .Provider.TTS import *
|
|
12
|
+
from .Provider.AISEARCH import *
|
|
10
13
|
from .Extra import *
|
|
11
14
|
from .Litlogger import *
|
|
12
15
|
from .optimizers import *
|
|
13
|
-
from .litprinter import *
|
|
14
16
|
from .swiftcli import *
|
|
15
17
|
from .litagent import LitAgent
|
|
16
18
|
from .scout import *
|
|
@@ -20,5 +22,12 @@ agent = LitAgent()
|
|
|
20
22
|
|
|
21
23
|
__repo__ = "https://github.com/OE-LUCIFER/Webscout"
|
|
22
24
|
|
|
25
|
+
# Add update checker
|
|
26
|
+
from .update_checker import check_for_updates
|
|
27
|
+
try:
|
|
28
|
+
check_for_updates()
|
|
29
|
+
except Exception:
|
|
30
|
+
pass # Silently handle any update check errors
|
|
31
|
+
|
|
23
32
|
import logging
|
|
24
33
|
logging.getLogger("webscout").addHandler(logging.NullHandler())
|