webscout 5.2__py3-none-any.whl → 5.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.
- webscout/AIauto.py +8 -12
- webscout/AIutel.py +10 -10
- webscout/Agents/Onlinesearcher.py +5 -5
- webscout/Agents/functioncall.py +123 -97
- webscout/DWEBS.py +99 -77
- webscout/Local/_version.py +2 -2
- webscout/Provider/Andi.py +1 -21
- webscout/Provider/BasedGPT.py +1 -21
- webscout/Provider/Blackboxai.py +1 -21
- webscout/Provider/Chatify.py +175 -0
- webscout/Provider/Cloudflare.py +1 -22
- webscout/Provider/Cohere.py +2 -23
- webscout/Provider/DARKAI.py +0 -1
- webscout/Provider/Deepinfra.py +2 -16
- webscout/Provider/EDITEE.py +3 -26
- webscout/Provider/Gemini.py +1 -24
- webscout/Provider/Groq.py +0 -2
- webscout/Provider/Koboldai.py +0 -21
- webscout/Provider/Llama.py +4 -21
- webscout/Provider/NetFly.py +21 -61
- webscout/Provider/OLLAMA.py +0 -17
- webscout/Provider/Openai.py +2 -22
- webscout/Provider/Perplexity.py +1 -2
- webscout/Provider/Phind.py +3 -508
- webscout/Provider/RUBIKSAI.py +11 -5
- webscout/Provider/Reka.py +4 -21
- webscout/Provider/TTS/streamElements.py +1 -22
- webscout/Provider/TTS/voicepod.py +11 -8
- webscout/Provider/ThinkAnyAI.py +17 -78
- webscout/Provider/Youchat.py +3 -20
- webscout/Provider/__init__.py +17 -8
- webscout/Provider/ai4chat.py +14 -8
- webscout/Provider/cerebras.py +199 -0
- webscout/Provider/{Berlin4h.py → cleeai.py} +68 -73
- webscout/Provider/{liaobots.py → elmo.py} +75 -106
- webscout/Provider/felo_search.py +29 -87
- webscout/Provider/geminiapi.py +198 -0
- webscout/Provider/genspark.py +222 -0
- webscout/Provider/julius.py +3 -20
- webscout/Provider/koala.py +1 -1
- webscout/Provider/lepton.py +194 -0
- webscout/Provider/turboseek.py +4 -21
- webscout/Provider/x0gpt.py +182 -0
- webscout/Provider/xdash.py +2 -22
- webscout/Provider/yep.py +391 -149
- webscout/YTdownloader.py +2 -3
- webscout/__init__.py +2 -2
- webscout/exceptions.py +2 -1
- webscout/transcriber.py +195 -140
- webscout/version.py +1 -1
- {webscout-5.2.dist-info → webscout-5.4.dist-info}/METADATA +47 -134
- webscout-5.4.dist-info/RECORD +98 -0
- webscout/voice.py +0 -34
- webscout-5.2.dist-info/RECORD +0 -93
- {webscout-5.2.dist-info → webscout-5.4.dist-info}/LICENSE.md +0 -0
- {webscout-5.2.dist-info → webscout-5.4.dist-info}/WHEEL +0 -0
- {webscout-5.2.dist-info → webscout-5.4.dist-info}/entry_points.txt +0 -0
- {webscout-5.2.dist-info → webscout-5.4.dist-info}/top_level.txt +0 -0
webscout/Provider/yep.py
CHANGED
|
@@ -1,42 +1,58 @@
|
|
|
1
1
|
import time
|
|
2
2
|
import uuid
|
|
3
|
-
|
|
4
|
-
from selenium.webdriver.chrome.options import Options
|
|
5
|
-
from selenium.webdriver.common.by import By
|
|
6
|
-
from selenium.webdriver.support import expected_conditions as EC
|
|
7
|
-
from selenium.webdriver.support.ui import WebDriverWait
|
|
8
|
-
import click
|
|
9
|
-
import requests
|
|
10
|
-
from requests import get
|
|
11
|
-
from uuid import uuid4
|
|
12
|
-
from re import findall
|
|
13
|
-
from requests.exceptions import RequestException
|
|
14
|
-
from curl_cffi.requests import get, RequestsError
|
|
15
|
-
import g4f
|
|
16
|
-
from random import randint
|
|
17
|
-
from PIL import Image
|
|
18
|
-
import io
|
|
19
|
-
import re
|
|
3
|
+
import cloudscraper
|
|
20
4
|
import json
|
|
21
|
-
|
|
5
|
+
|
|
6
|
+
from typing import Any, Dict, Optional, Callable, Union
|
|
7
|
+
from dataclasses import dataclass, asdict
|
|
8
|
+
from datetime import date
|
|
9
|
+
|
|
22
10
|
from webscout.AIutel import Optimizers
|
|
23
11
|
from webscout.AIutel import Conversation
|
|
24
|
-
from webscout.AIutel import AwesomePrompts
|
|
25
|
-
from webscout.AIbase import
|
|
26
|
-
from webscout import exceptions
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
12
|
+
from webscout.AIutel import AwesomePrompts
|
|
13
|
+
from webscout.AIbase import Provider
|
|
14
|
+
from webscout import WEBS, exceptions
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class ToolCall:
|
|
19
|
+
tool_name: str
|
|
20
|
+
tool_input: Dict[str, Any]
|
|
21
|
+
|
|
31
22
|
|
|
32
23
|
class YEPCHAT(Provider):
|
|
33
|
-
""
|
|
34
|
-
|
|
35
|
-
""
|
|
24
|
+
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 ""
|
|
36
52
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
40
56
|
|
|
41
57
|
def __init__(
|
|
42
58
|
self,
|
|
@@ -52,28 +68,16 @@ class YEPCHAT(Provider):
|
|
|
52
68
|
model: str = "Mixtral-8x7B-Instruct-v0.1",
|
|
53
69
|
temperature: float = 0.6,
|
|
54
70
|
top_p: float = 0.7,
|
|
71
|
+
Tools: bool = False,
|
|
72
|
+
retries: int = 3,
|
|
73
|
+
retry_delay: int = 5,
|
|
55
74
|
):
|
|
56
|
-
"""Instantiates YEPCHAT
|
|
57
|
-
|
|
58
|
-
Args:
|
|
59
|
-
is_conversation (bool, optional): Flag for chatting conversationally. Defaults to True.
|
|
60
|
-
max_tokens (int, optional): Maximum number of tokens to be generated upon completion. Defaults to 1280.
|
|
61
|
-
timeout (int, optional): Http request timeout. Defaults to 30.
|
|
62
|
-
intro (str, optional): Conversation introductory prompt. Defaults to None.
|
|
63
|
-
filepath (str, optional): Path to file containing conversation history. Defaults to None.
|
|
64
|
-
update_file (bool, optional): Add new prompts and responses to the file. Defaults to True.
|
|
65
|
-
proxies (dict, optional): Http request proxies. Defaults to {}.
|
|
66
|
-
history_offset (int, optional): Limit conversation history to this number of last texts. Defaults to 10250.
|
|
67
|
-
act (str|int, optional): Awesome prompt key or index. (Used as intro). Defaults to None.
|
|
68
|
-
model (str, optional): Model to use for generating text. Defaults to "Mixtral-8x7B-Instruct-v0.1".
|
|
69
|
-
temperature (float, optional): Temperature parameter for the model. Defaults to 0.6.
|
|
70
|
-
top_p (float, optional): Top_p parameter for the model. Defaults to 0.7.
|
|
71
|
-
"""
|
|
72
|
-
|
|
73
75
|
if model not in self.AVAILABLE_MODELS:
|
|
74
|
-
raise ValueError(
|
|
76
|
+
raise ValueError(
|
|
77
|
+
f"Invalid model: {model}. Choose from: {self.AVAILABLE_MODELS}"
|
|
78
|
+
)
|
|
75
79
|
|
|
76
|
-
self.session = cloudscraper.create_scraper()
|
|
80
|
+
self.session = cloudscraper.create_scraper()
|
|
77
81
|
self.is_conversation = is_conversation
|
|
78
82
|
self.max_tokens_to_sample = max_tokens
|
|
79
83
|
self.chat_endpoint = "https://api.yep.com/v1/chat/completions"
|
|
@@ -83,32 +87,30 @@ class YEPCHAT(Provider):
|
|
|
83
87
|
self.model = model
|
|
84
88
|
self.temperature = temperature
|
|
85
89
|
self.top_p = top_p
|
|
90
|
+
self.use_tools = Tools
|
|
86
91
|
self.headers = {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
self.cookies = {
|
|
100
|
-
'__Host-session': uuid4().hex,
|
|
92
|
+
"Accept": "*/*",
|
|
93
|
+
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
94
|
+
"Accept-Language": "en-US,en;q=0.9,en-IN;q=0.8",
|
|
95
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
96
|
+
"DNT": "1",
|
|
97
|
+
"Origin": "https://yep.com",
|
|
98
|
+
"Referer": "https://yep.com/",
|
|
99
|
+
"Sec-CH-UA": '"Not)A;Brand";v="99", "Microsoft Edge";v="127", "Chromium";v="127"',
|
|
100
|
+
"Sec-CH-UA-Mobile": "?0",
|
|
101
|
+
"Sec-CH-UA-Platform": '"Windows"',
|
|
102
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36 Edg/127.0.0.0",
|
|
101
103
|
}
|
|
104
|
+
self.cookies = {"__Host-session": uuid.uuid4().hex}
|
|
102
105
|
|
|
103
106
|
self.__available_optimizers = (
|
|
104
107
|
method
|
|
105
108
|
for method in dir(Optimizers)
|
|
106
|
-
if callable(getattr(Optimizers, method))
|
|
109
|
+
if callable(getattr(Optimizers, method))
|
|
110
|
+
and not method.startswith("__")
|
|
107
111
|
)
|
|
108
112
|
Conversation.intro = (
|
|
109
|
-
AwesomePrompts().get_act(
|
|
110
|
-
act, raise_not_found=True, default=None, case_insensitive=True
|
|
111
|
-
)
|
|
113
|
+
AwesomePrompts().get_act(act, raise_not_found=True, default=None, case_insensitive=True)
|
|
112
114
|
if act
|
|
113
115
|
else intro or Conversation.intro
|
|
114
116
|
)
|
|
@@ -118,6 +120,11 @@ class YEPCHAT(Provider):
|
|
|
118
120
|
self.conversation.history_offset = history_offset
|
|
119
121
|
self.session.proxies = proxies
|
|
120
122
|
|
|
123
|
+
self.tool_registry = self.ToolRegistry()
|
|
124
|
+
self.knowledge_cutoff = "December 2023"
|
|
125
|
+
self.retries = retries
|
|
126
|
+
self.retry_delay = retry_delay
|
|
127
|
+
|
|
121
128
|
def ask(
|
|
122
129
|
self,
|
|
123
130
|
prompt: str,
|
|
@@ -126,18 +133,7 @@ class YEPCHAT(Provider):
|
|
|
126
133
|
optimizer: str = None,
|
|
127
134
|
conversationally: bool = False,
|
|
128
135
|
) -> dict:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
Args:
|
|
132
|
-
prompt (str): Prompt to be send.
|
|
133
|
-
stream (bool, optional): Whether to stream the response. Defaults to False.
|
|
134
|
-
raw (bool, optional): Whether to return the raw response. Defaults to False.
|
|
135
|
-
optimizer (str, optional): The name of the optimizer to use. Defaults to None.
|
|
136
|
-
conversationally (bool, optional): Whether to chat conversationally. Defaults to False.
|
|
137
|
-
|
|
138
|
-
Returns:
|
|
139
|
-
The response from the API.
|
|
140
|
-
"""
|
|
136
|
+
initial_response = None
|
|
141
137
|
conversation_prompt = self.conversation.gen_complete_prompt(prompt)
|
|
142
138
|
if optimizer:
|
|
143
139
|
if optimizer in self.__available_optimizers:
|
|
@@ -149,60 +145,145 @@ class YEPCHAT(Provider):
|
|
|
149
145
|
f"Optimizer is not one of {self.__available_optimizers}"
|
|
150
146
|
)
|
|
151
147
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
"messages": [
|
|
158
|
-
{"content": conversation_prompt, "role": "user"}
|
|
159
|
-
],
|
|
160
|
-
"model": self.model
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
def for_stream():
|
|
164
|
-
response = self.session.post(
|
|
165
|
-
self.chat_endpoint, headers=self.headers, cookies=self.cookies, json=data, stream=True, timeout=self.timeout
|
|
166
|
-
)
|
|
167
|
-
if not response.ok:
|
|
168
|
-
raise exceptions.FailedToGenerateResponseError(
|
|
169
|
-
f"Failed to generate response - ({response.status_code}, {response.reason})"
|
|
170
|
-
)
|
|
171
|
-
streaming_response = ""
|
|
172
|
-
for line in response.iter_lines(decode_unicode=True):
|
|
173
|
-
if line:
|
|
174
|
-
if line.startswith("data: "):
|
|
175
|
-
json_data = line[6:]
|
|
176
|
-
if json_data == "[DONE]":
|
|
177
|
-
break
|
|
178
|
-
try:
|
|
179
|
-
data = json.loads(json_data)
|
|
180
|
-
content = data["choices"][0]["delta"].get("content", "")
|
|
181
|
-
streaming_response += content
|
|
182
|
-
yield content if raw else dict(text=streaming_response)
|
|
183
|
-
except json.decoder.JSONDecodeError:
|
|
184
|
-
continue
|
|
185
|
-
self.last_response.update(dict(text=streaming_response))
|
|
186
|
-
self.conversation.update_chat_history(
|
|
187
|
-
prompt, self.get_message(self.last_response)
|
|
148
|
+
tool_call_data = None
|
|
149
|
+
tool_output = None
|
|
150
|
+
if self.use_tools:
|
|
151
|
+
initial_response = self._get_initial_response(
|
|
152
|
+
conversation_prompt, self.retries, self.retry_delay
|
|
188
153
|
)
|
|
154
|
+
# logging.info(f"Initial AI response: {initial_response}")
|
|
189
155
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
|
177
|
+
|
|
178
|
+
def _get_initial_response(self, prompt: str, retries: int, retry_delay: int) -> str:
|
|
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
197
|
)
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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
|
|
204
217
|
|
|
205
|
-
|
|
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):
|
|
228
|
+
try:
|
|
229
|
+
data = {
|
|
230
|
+
"stream": False,
|
|
231
|
+
"max_tokens": self.max_tokens_to_sample,
|
|
232
|
+
"top_p": self.top_p,
|
|
233
|
+
"temperature": self.temperature,
|
|
234
|
+
"messages": [{"content": prompt, "role": "user"}],
|
|
235
|
+
"model": self.model,
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if tool_output:
|
|
239
|
+
tool_call = ToolCall(**tool_call_data)
|
|
240
|
+
tool_description = self.tool_registry.get_tool_description(tool_call.tool_name)
|
|
241
|
+
final_prompt = (
|
|
242
|
+
f"I asked you to answer this question: '{prompt}'\n\n"
|
|
243
|
+
f"To assist in answering, you used the '{tool_call.tool_name}' tool, which {tool_description}\n"
|
|
244
|
+
f"The tool was called with these parameters: {json.dumps(tool_call.tool_input)}\n"
|
|
245
|
+
f"The tool provided this output:\n\n{tool_output}\n\n"
|
|
246
|
+
"Based on the original question and the tool's output, please provide a comprehensive and accurate answer. "
|
|
247
|
+
"Make sure to:\n"
|
|
248
|
+
"1. Directly address the user's question\n"
|
|
249
|
+
"2. Incorporate relevant information from the tool's output\n"
|
|
250
|
+
"3. Provide context or explanations where necessary\n"
|
|
251
|
+
"4. If the tool output doesn't fully answer the question, supplement with your general knowledge\n"
|
|
252
|
+
"5. If the tool output is an error message, acknowledge it and try to provide a helpful response based on your general knowledge\n\n"
|
|
253
|
+
"Your response:"
|
|
254
|
+
)
|
|
255
|
+
data["messages"][0]["content"] = final_prompt
|
|
256
|
+
else:
|
|
257
|
+
data["messages"][0]["content"] = prompt
|
|
258
|
+
|
|
259
|
+
response = self.session.post(
|
|
260
|
+
self.chat_endpoint,
|
|
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
|
|
279
|
+
except Exception as e:
|
|
280
|
+
if attempt < retries:
|
|
281
|
+
# logging.warning(
|
|
282
|
+
# f"An unexpected error occurred: {e}. Retrying in {retry_delay} seconds..."
|
|
283
|
+
# )
|
|
284
|
+
time.sleep(retry_delay)
|
|
285
|
+
else:
|
|
286
|
+
raise e
|
|
206
287
|
|
|
207
288
|
def chat(
|
|
208
289
|
self,
|
|
@@ -211,16 +292,6 @@ class YEPCHAT(Provider):
|
|
|
211
292
|
optimizer: str = None,
|
|
212
293
|
conversationally: bool = False,
|
|
213
294
|
) -> str:
|
|
214
|
-
"""Generate response `str`
|
|
215
|
-
Args:
|
|
216
|
-
prompt (str): Prompt to be send.
|
|
217
|
-
stream (bool, optional): Flag for streaming response. Defaults to False.
|
|
218
|
-
optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`. Defaults to None.
|
|
219
|
-
conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
|
|
220
|
-
Returns:
|
|
221
|
-
str: Response generated
|
|
222
|
-
"""
|
|
223
|
-
|
|
224
295
|
def for_stream():
|
|
225
296
|
for response in self.ask(
|
|
226
297
|
prompt, True, optimizer=optimizer, conversationally=conversationally
|
|
@@ -240,19 +311,190 @@ class YEPCHAT(Provider):
|
|
|
240
311
|
return for_stream() if stream else for_non_stream()
|
|
241
312
|
|
|
242
313
|
def get_message(self, response: dict) -> str:
|
|
243
|
-
|
|
314
|
+
assert isinstance(response, dict)
|
|
315
|
+
return response["text"]
|
|
316
|
+
|
|
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
|
+
|
|
425
|
+
if __name__ == "__main__":
|
|
426
|
+
from rich import print
|
|
427
|
+
|
|
428
|
+
def get_current_time():
|
|
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.
|
|
244
435
|
|
|
245
436
|
Args:
|
|
246
|
-
|
|
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".
|
|
247
440
|
|
|
248
441
|
Returns:
|
|
249
|
-
str:
|
|
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.
|
|
250
444
|
"""
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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=True)
|
|
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(input(">>> "))
|
|
257
499
|
for chunk in response:
|
|
258
500
|
print(chunk, end="", flush=True)
|
webscout/YTdownloader.py
CHANGED
|
@@ -11,7 +11,7 @@ from threading import Thread
|
|
|
11
11
|
from sys import stdout
|
|
12
12
|
from click import launch as launch_media, confirm as confirm_from_user
|
|
13
13
|
import warnings
|
|
14
|
-
|
|
14
|
+
from webscout.version import __prog__, __version__
|
|
15
15
|
from os import getcwd, remove
|
|
16
16
|
import appdirs
|
|
17
17
|
"""
|
|
@@ -26,8 +26,7 @@ import appdirs
|
|
|
26
26
|
- max-video quality
|
|
27
27
|
- path to file containing links
|
|
28
28
|
"""
|
|
29
|
-
|
|
30
|
-
__prog__ = "webscout"
|
|
29
|
+
|
|
31
30
|
session = requests.session()
|
|
32
31
|
|
|
33
32
|
headers = {
|
webscout/__init__.py
CHANGED
|
@@ -2,8 +2,8 @@ from .webscout_search import WEBS
|
|
|
2
2
|
from .webscout_search_async import AsyncWEBS
|
|
3
3
|
from .version import __version__
|
|
4
4
|
from .DWEBS import *
|
|
5
|
-
from .transcriber import
|
|
6
|
-
from .
|
|
5
|
+
from .transcriber import *
|
|
6
|
+
from .tempid import *
|
|
7
7
|
from .websx_search import WEBSX
|
|
8
8
|
from .LLM import VLM, LLM
|
|
9
9
|
from .YTdownloader import *
|
webscout/exceptions.py
CHANGED