webscout 1.4.3__py3-none-any.whl → 1.4.5__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/AI.py CHANGED
@@ -25,9 +25,259 @@ from webscout.AIutel import AwesomePrompts, sanitize_stream
25
25
  from webscout.AIbase import Provider, AsyncProvider
26
26
  from Helpingai_T2 import Perplexity
27
27
  from webscout import exceptions
28
- from typing import Any, AsyncGenerator
28
+ from typing import Any, AsyncGenerator, Dict
29
29
  import logging
30
30
  import httpx
31
+ #------------------------------------ThinkAnyAI------------
32
+ class ThinkAnyAI(Provider):
33
+ def __init__(
34
+ self,
35
+ model: str = "claude-3-haiku",
36
+ locale: str = "en",
37
+ web_search: bool = False,
38
+ chunk_size: int = 1,
39
+ streaming: bool = True,
40
+ is_conversation: bool = True,
41
+ max_tokens: int = 600,
42
+ timeout: int = 30,
43
+ intro: str = None,
44
+ filepath: str = None,
45
+ update_file: bool = True,
46
+ proxies: dict = {},
47
+ history_offset: int = 10250,
48
+ act: str = None,
49
+ ):
50
+ """Initializes ThinkAnyAI
51
+
52
+ Args:
53
+ model (str): The AI model to be used for generating responses. Defaults to "claude-3-haiku".
54
+ locale (str): The language locale. Defaults to "en" (English).
55
+ web_search (bool): Whether to include web search results in the response. Defaults to False.
56
+ chunk_size (int): The size of data chunks when streaming responses. Defaults to 1.
57
+ streaming (bool): Whether to stream response data. Defaults to True.
58
+ is_conversation (bool, optional): Flag for chatting conversationally. Defaults to True.
59
+ max_tokens (int, optional): Maximum number of tokens to be generated upon completion. Defaults to 600.
60
+ timeout (int, optional): Http request timeout. Defaults to 30.
61
+ intro (str, optional): Conversation introductory prompt. Defaults to None.
62
+ filepath (str, optional): Path to file containing conversation history. Defaults to None.
63
+ update_file (bool, optional): Add new prompts and responses to the file. Defaults to True.
64
+ proxies (dict, optional): Http request proxies. Defaults to {}.
65
+ history_offset (int, optional): Limit conversation history to this number of last texts. Defaults to 10250.
66
+ act (str|int, optional): Awesome prompt key or index. (Used as intro). Defaults to None.
67
+ """
68
+ self.base_url = "https://thinkany.ai/api"
69
+ self.model = model
70
+ self.locale = locale
71
+ self.web_search = web_search
72
+ self.chunk_size = chunk_size
73
+ self.streaming = streaming
74
+ self.last_response = {}
75
+ self.session = requests.Session()
76
+ self.session.proxies = proxies
77
+
78
+ self.__available_optimizers = (
79
+ method
80
+ for method in dir(Optimizers)
81
+ if callable(getattr(Optimizers, method)) and not method.startswith("__")
82
+ )
83
+
84
+ Conversation.intro = (
85
+ AwesomePrompts().get_act(
86
+ act, raise_not_found=True, default=None, case_insensitive=True
87
+ )
88
+ if act
89
+ else intro or Conversation.intro
90
+ )
91
+ self.conversation = Conversation(
92
+ is_conversation, max_tokens, filepath, update_file
93
+ )
94
+ self.conversation.history_offset = history_offset
95
+
96
+ def ask(
97
+ self,
98
+ prompt: str,
99
+ stream: bool = False,
100
+ raw: bool = False,
101
+ optimizer: str = None,
102
+ conversationally: bool = False,
103
+ ) -> dict | AsyncGenerator:
104
+ """Chat with AI asynchronously.
105
+
106
+ Args:
107
+ prompt (str): Prompt to be send.
108
+ stream (bool, optional): Flag for streaming response. Defaults to False.
109
+ raw (bool, optional): Stream back raw response as received. Defaults to False.
110
+ optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`. Defeaults to None
111
+ conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
112
+ Returns:
113
+ dict : {}
114
+ ```json
115
+ {
116
+ "content": "General Kenobi! \n\n(I couldn't help but respond with the iconic Star Wars greeting since you used it first. )\n\nIs there anything I can help you with today?\n[Image of Hello there General Kenobi]",
117
+ "conversation_id": "c_f13f6217f9a997aa",
118
+ "response_id": "r_d3665f95975c368f",
119
+ "factualityQueries": null,
120
+ "textQuery": [
121
+ "hello there",
122
+ 1
123
+ ],
124
+ "choices": [
125
+ {
126
+ "id": "rc_ea075c9671bfd8cb",
127
+ "content": [
128
+ "General Kenobi! \n\n(I couldn't help but respond with the iconic Star Wars greeting since you used it first. )\n\nIs there anything I can help you with today?\n[Image of Hello there General Kenobi]"
129
+ ]
130
+ },
131
+ {
132
+ "id": "rc_de6dd3fb793a5402",
133
+ "content": [
134
+ "General Kenobi! (or just a friendly hello, whichever you prefer!). \n\nI see you're a person of culture as well. *Star Wars* references are always appreciated. \n\nHow can I help you today?\n"
135
+ ]
136
+ },
137
+ {
138
+ "id": "rc_a672ac089caf32db",
139
+ "content": [
140
+ "General Kenobi! (or just a friendly hello if you're not a Star Wars fan!). \n\nHow can I help you today? Feel free to ask me anything, or tell me what you'd like to chat about. I'm here to assist in any way I can.\n[Image of Obi-Wan Kenobi saying hello there]"
141
+ ]
142
+ }
143
+ ],
144
+
145
+ "images": [
146
+ "https://i.pinimg.com/originals/40/74/60/407460925c9e419d82b93313f0b42f71.jpg"
147
+ ]
148
+ }
149
+
150
+ ```
151
+ """
152
+ conversation_prompt = self.conversation.gen_complete_prompt(prompt)
153
+ if optimizer:
154
+ if optimizer in self.__available_optimizers:
155
+ conversation_prompt = getattr(Optimizers, optimizer)(
156
+ conversation_prompt if conversationally else prompt
157
+ )
158
+ else:
159
+ raise Exception(
160
+ f"Optimizer is not one of {self.__available_optimizers}"
161
+ )
162
+
163
+ def initiate_conversation(query: str) -> str:
164
+ """
165
+ Initiates a new conversation with the ThinkAny AI API.
166
+
167
+ Args:
168
+ query (str): The initial query to start the conversation.
169
+
170
+ Returns:
171
+ str: The UUID (Unique Identifier) of the conversation.
172
+ """
173
+ url = f"{self.base_url}/new-conversation"
174
+ payload = {
175
+ "content": query,
176
+ "locale": self.locale,
177
+ "mode": "search" if self.web_search else "chat",
178
+ "model": self.model,
179
+ "source": "all",
180
+ }
181
+ response = self.session.post(url, json=payload)
182
+ return response.json().get("data", {}).get("uuid", "DevsDoCode")
183
+
184
+ def RAG_search(uuid: str) -> tuple[bool, list]:
185
+ """
186
+ Performs a web search using the Retrieve And Generate (RAG) model.
187
+
188
+ Args:
189
+ uuid (str): The UUID of the conversation.
190
+
191
+ Returns:
192
+ tuple: A tuple containing a boolean indicating the success of the search
193
+ and a list of search result links.
194
+ """
195
+ if not self.web_search:
196
+ return True, []
197
+ url = f"{self.base_url}/rag-search"
198
+ payload = {"conv_uuid": uuid}
199
+ response = self.session.post(url, json=payload)
200
+ links = [source["link"] for source in response.json().get("data", [])]
201
+ return response.json().get("message", "").strip(), links
202
+
203
+ def for_stream():
204
+ conversation_uuid = initiate_conversation(conversation_prompt)
205
+ web_search_result, links = RAG_search(conversation_uuid)
206
+ if not web_search_result:
207
+ print("Failed to generate WEB response. Making normal Query...")
208
+
209
+ url = f"{self.base_url}/chat"
210
+ payload = {
211
+ "role": "user",
212
+ "content": prompt,
213
+ "conv_uuid": conversation_uuid,
214
+ "model": self.model,
215
+ }
216
+ response = self.session.post(url, json=payload, stream=True)
217
+ complete_content = ""
218
+ for content in response.iter_content(
219
+ decode_unicode=True, chunk_size=self.chunk_size
220
+ ):
221
+ complete_content += content
222
+ yield content if raw else dict(text=complete_content)
223
+ self.last_response.update(dict(text=complete_content, links=links))
224
+ self.conversation.update_chat_history(
225
+ prompt, self.get_message(self.last_response)
226
+ )
227
+
228
+ def for_non_stream():
229
+ for _ in for_stream():
230
+ pass
231
+ return self.last_response
232
+
233
+ return for_stream() if stream else for_non_stream()
234
+
235
+ def chat(
236
+ self,
237
+ prompt: str,
238
+ stream: bool = False,
239
+ optimizer: str = None,
240
+ conversationally: bool = False,
241
+ ) -> str:
242
+ """Generate response `str`
243
+ Args:
244
+ prompt (str): Prompt to be send.
245
+ stream (bool, optional): Flag for streaming response. Defaults to False.
246
+ optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`. Defaults to None.
247
+ conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
248
+ Returns:
249
+ str: Response generated
250
+ """
251
+
252
+ def for_stream():
253
+ for response in self.ask(
254
+ prompt, True, optimizer=optimizer, conversationally=conversationally
255
+ ):
256
+ yield self.get_message(response)
257
+
258
+ def for_non_stream():
259
+ return self.get_message(
260
+ self.ask(
261
+ prompt,
262
+ False,
263
+ optimizer=optimizer,
264
+ conversationally=conversationally,
265
+ )
266
+ )
267
+
268
+ return for_stream() if stream else for_non_stream()
269
+
270
+ def get_message(self, response: Dict[str, Any]) -> str:
271
+ """Retrieves message only from response
272
+
273
+ Args:
274
+ response (dict): Response generated by `self.ask`
275
+
276
+ Returns:
277
+ str: Message extracted
278
+ """
279
+ assert isinstance(response, dict), "Response should be of dict data-type only"
280
+ return response["text"]
31
281
  #-----------------------------------------------xjai-------------------------------------------
32
282
  class Xjai(Provider):
33
283
  def __init__(
@@ -2802,6 +3052,7 @@ class AsyncKOBOLDAI(AsyncProvider):
2802
3052
  class OPENGPT:
2803
3053
  def __init__(
2804
3054
  self,
3055
+ assistant_id,
2805
3056
  is_conversation: bool = True,
2806
3057
  max_tokens: int = 600,
2807
3058
  timeout: int = 30,
@@ -2834,7 +3085,7 @@ class OPENGPT:
2834
3085
  self.stream_chunk_size = 64
2835
3086
  self.timeout = timeout
2836
3087
  self.last_response = {}
2837
- self.assistant_id = "bca37014-6f97-4f2b-8928-81ea8d478d88"
3088
+ self.assistant_id = assistant_id
2838
3089
  self.authority = "opengpts-example-vz4y4ooboq-uc.a.run.app"
2839
3090
 
2840
3091
  self.headers = {
@@ -3026,7 +3277,6 @@ class OPENGPT:
3026
3277
  str: Message extracted
3027
3278
  """
3028
3279
  assert isinstance(response, dict), "Response should be of dict data-type only"
3029
- return response["content"]
3030
3280
  class AsyncOPENGPT(AsyncProvider):
3031
3281
  def __init__(
3032
3282
  self,
webscout/AIutel.py CHANGED
@@ -18,6 +18,7 @@ from pathlib import Path
18
18
  from playsound import playsound
19
19
  from time import sleep as wait
20
20
  import pathlib
21
+ import urllib.parse
21
22
  appdir = appdirs.AppDirs("AIWEBS", "vortex")
22
23
 
23
24
  default_path = appdir.user_cache_dir
@@ -39,7 +40,8 @@ webai = [
39
40
  "cohere",
40
41
  "yepchat",
41
42
  "you",
42
- "xjai"
43
+ "xjai",
44
+ "thinkany"
43
45
  ]
44
46
 
45
47
  gpt4free_providers = [
@@ -938,7 +940,7 @@ class Audio:
938
940
  ), f"Voice '{voice}' not one of [{', '.join(cls.all_voices)}]"
939
941
  # Base URL for provider API
940
942
  url: str = (
941
- f"https://api.streamelements.com/kappa/v2/speech?voice={voice}&text={{{message}}}"
943
+ f"https://api.streamelements.com/kappa/v2/speech?voice={voice}&text={{{urllib.parse.quote(message)}}}"
942
944
  )
943
945
  resp = requests.get(url=url, headers=cls.headers, stream=True)
944
946
  if not resp.ok:
webscout/__init__.py CHANGED
@@ -29,7 +29,8 @@ webai = [
29
29
  "cohere",
30
30
  "yepchat",
31
31
  "you",
32
- "xjai"
32
+ "xjai",
33
+ "thinkany"
33
34
  ]
34
35
 
35
36
  gpt4free_providers = [
webscout/utils.py CHANGED
@@ -4,7 +4,6 @@ from html import unescape
4
4
  from math import atan2, cos, radians, sin, sqrt
5
5
  from typing import Any, Dict, List, Union
6
6
  from urllib.parse import unquote
7
-
8
7
  import orjson
9
8
 
10
9
  from .exceptions import WebscoutE
webscout/version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "1.4.3"
1
+ __version__ = "1.4.5"
2
2
 
webscout/webai.py CHANGED
@@ -471,6 +471,20 @@ class Main(cmd.Cmd):
471
471
  history_offset=history_offset,
472
472
  act=awesome_prompt,
473
473
  )
474
+ elif provider == "thinkany":
475
+ from webscout.AI import ThinkAnyAI
476
+
477
+ self.bot = ThinkAnyAI(
478
+ is_conversation=disable_conversation,
479
+ max_tokens=max_tokens,
480
+ timeout=timeout,
481
+ intro=intro,
482
+ filepath=filepath,
483
+ update_file=update_file,
484
+ proxies=proxies,
485
+ history_offset=history_offset,
486
+ act=awesome_prompt,
487
+ )
474
488
  elif provider == "yepchat":
475
489
  from webscout.AI import YEPCHAT
476
490
 
@@ -981,7 +995,7 @@ class Main(cmd.Cmd):
981
995
  self.output_bond("Chat History", formatted_history, self.color)
982
996
  if click.confirm("Do you wish to save this chat"):
983
997
  save_to = click.prompt(
984
- "Enter path/file-name", default="llama-conversation.txt"
998
+ "Enter path/file-name", default=f"{self.provider}-chat.txt"
985
999
  )
986
1000
  with open(save_to, "a") as fh:
987
1001
  fh.write(history)
@@ -20,11 +20,19 @@ class WEBS(AsyncWEBS):
20
20
  def __init__(
21
21
  self,
22
22
  headers: Optional[Dict[str, str]] = None,
23
- proxies: Union[Dict[str, str], str, None] = None,
23
+ proxy: Optional[str] = None,
24
+ proxies: Union[Dict[str, str], str, None] = None, # deprecated
24
25
  timeout: Optional[int] = 10,
25
26
  ) -> None:
26
- super().__init__(headers=headers, proxies=proxies, timeout=timeout)
27
- self._exit_done = False
27
+ """Initialize the DDGS object.
28
+
29
+ Args:
30
+ headers (dict, optional): Dictionary of headers for the HTTP client. Defaults to None.
31
+ proxy (str, optional): proxy for the HTTP client, supports http/https/socks5 protocols.
32
+ example: "http://user:pass@example.com:3128". Defaults to None.
33
+ timeout (int, optional): Timeout value for the HTTP client. Defaults to 10.
34
+ """
35
+ super().__init__(headers=headers, proxy=proxy, proxies=proxies, timeout=timeout)
28
36
 
29
37
  def __enter__(self) -> "WEBS":
30
38
  return self
@@ -42,13 +50,8 @@ class WEBS(AsyncWEBS):
42
50
 
43
51
  def _close_session(self) -> None:
44
52
  """Close the curl-cffi async session."""
45
- if self._exit_done is False:
46
- # Ensure self._asession.close() is a coroutine
47
- coro = self._asession.close()
48
- # Check if coro is a coroutine object
49
- if asyncio.iscoroutine(coro):
50
- self._run_async_in_thread(coro)
51
- self._exit_done = True
53
+ if hasattr(self, "_asession") and self._asession._closed is False:
54
+ self._run_async_in_thread(self._asession.close()) # type: ignore
52
55
 
53
56
  def _run_async_in_thread(self, coro: Awaitable[Any]) -> Any:
54
57
  """Runs an async coroutine in a separate thread."""
@@ -5,10 +5,10 @@ from concurrent.futures import ThreadPoolExecutor
5
5
  from contextlib import suppress
6
6
  from datetime import datetime, timezone
7
7
  from decimal import Decimal
8
- from functools import partial
8
+ from functools import cached_property, partial
9
9
  from itertools import cycle, islice
10
10
  from types import TracebackType
11
- from typing import Dict, List, Optional, Tuple, Union
11
+ from typing import Dict, List, Optional, Tuple, Type, Union, cast
12
12
 
13
13
  from curl_cffi import requests
14
14
 
@@ -34,68 +34,71 @@ logger = logging.getLogger("webscout_search.AsyncWEBS")
34
34
 
35
35
 
36
36
  class AsyncWEBS:
37
- """Webscout async class to get search results from duckduckgo.com."""
37
+ """webscout_search async class to get search results from duckduckgo.com."""
38
38
 
39
39
  _executor: Optional[ThreadPoolExecutor] = None
40
40
 
41
41
  def __init__(
42
42
  self,
43
43
  headers: Optional[Dict[str, str]] = None,
44
- proxies: Union[Dict[str, str], str, None] = None,
44
+ proxy: Optional[str] = None,
45
+ proxies: Union[Dict[str, str], str, None] = None, # deprecated
45
46
  timeout: Optional[int] = 10,
46
47
  ) -> None:
47
48
  """Initialize the AsyncWEBS object.
48
49
 
49
50
  Args:
50
51
  headers (dict, optional): Dictionary of headers for the HTTP client. Defaults to None.
51
- proxies (Union[dict, str], optional): Proxies for the HTTP client (can be dict or str). Defaults to None.
52
+ proxy (str, optional): proxy for the HTTP client, supports http/https/socks5 protocols.
53
+ example: "http://user:pass@example.com:3128". Defaults to None.
52
54
  timeout (int, optional): Timeout value for the HTTP client. Defaults to 10.
53
55
  """
54
- self.proxies = {"all": proxies} if isinstance(proxies, str) else proxies
56
+ self.proxy: Optional[str] = proxy
57
+ assert self.proxy is None or isinstance(self.proxy, str), "proxy must be a str"
58
+ if not proxy and proxies:
59
+ warnings.warn("'proxies' is deprecated, use 'proxy' instead.", stacklevel=1)
60
+ self.proxy = proxies.get("http") or proxies.get("https") if isinstance(proxies, dict) else proxies
55
61
  self._asession = requests.AsyncSession(
56
62
  headers=headers,
57
- proxies=self.proxies,
63
+ proxy=self.proxy,
58
64
  timeout=timeout,
59
65
  impersonate="chrome",
60
66
  allow_redirects=False,
61
67
  )
62
68
  self._asession.headers["Referer"] = "https://duckduckgo.com/"
63
- self._parser: Optional[LHTMLParser] = None
64
69
  self._exception_event = asyncio.Event()
65
- self._exit_done = False
66
70
 
67
71
  async def __aenter__(self) -> "AsyncWEBS":
68
72
  return self
69
73
 
70
74
  async def __aexit__(
71
75
  self,
72
- exc_type: Optional[BaseException] = None,
76
+ exc_type: Optional[Type[BaseException]] = None,
73
77
  exc_val: Optional[BaseException] = None,
74
78
  exc_tb: Optional[TracebackType] = None,
75
79
  ) -> None:
76
- await self._session_close()
80
+ await self._asession.__aexit__(exc_type, exc_val, exc_tb) # type: ignore
77
81
 
78
82
  def __del__(self) -> None:
79
- if self._exit_done is False:
80
- asyncio.create_task(self._session_close())
83
+ if hasattr(self, "_asession") and self._asession._closed is False:
84
+ with suppress(RuntimeError, RuntimeWarning):
85
+ asyncio.create_task(self._asession.close()) # type: ignore
81
86
 
82
- async def _session_close(self) -> None:
83
- """Close the curl-cffi async session."""
84
- if self._exit_done is False:
85
- await self._asession.close()
86
- self._exit_done = True
87
-
88
- def _get_parser(self) -> "LHTMLParser":
87
+ @cached_property
88
+ def parser(self) -> Optional["LHTMLParser"]:
89
89
  """Get HTML parser."""
90
- if self._parser is None:
91
- self._parser = LHTMLParser(remove_blank_text=True, remove_comments=True, remove_pis=True, collect_ids=False)
92
- return self._parser
90
+ return LHTMLParser(remove_blank_text=True, remove_comments=True, remove_pis=True, collect_ids=False)
93
91
 
94
- def _get_executor(self, max_workers: int = 1) -> ThreadPoolExecutor:
92
+ @classmethod
93
+ def _get_executor(cls, max_workers: int = 1) -> ThreadPoolExecutor:
95
94
  """Get ThreadPoolExecutor. Default max_workers=1, because >=2 leads to a big overhead"""
96
- if AsyncWEBS._executor is None:
97
- AsyncWEBS._executor = ThreadPoolExecutor(max_workers=max_workers)
98
- return AsyncWEBS._executor
95
+ if cls._executor is None:
96
+ cls._executor = ThreadPoolExecutor(max_workers=max_workers)
97
+ return cls._executor
98
+
99
+ @property
100
+ def executor(cls) -> Optional[ThreadPoolExecutor]:
101
+ return cls._get_executor()
99
102
 
100
103
  async def _aget_url(
101
104
  self,
@@ -107,19 +110,18 @@ class AsyncWEBS:
107
110
  if self._exception_event.is_set():
108
111
  raise WebscoutE("Exception occurred in previous call.")
109
112
  try:
110
- resp = await self._asession.request(method, url, data=data, params=params, stream=True)
111
- resp_content: bytes = await resp.acontent()
113
+ resp = await self._asession.request(method, url, data=data, params=params)
112
114
  except Exception as ex:
113
115
  self._exception_event.set()
114
116
  if "time" in str(ex).lower():
115
117
  raise TimeoutE(f"{url} {type(ex).__name__}: {ex}") from ex
116
118
  raise WebscoutE(f"{url} {type(ex).__name__}: {ex}") from ex
117
- logger.debug(f"_aget_url() {resp.url} {resp.status_code} {resp.elapsed:.2f} {len(resp_content)}")
119
+ logger.debug(f"_aget_url() {resp.url} {resp.status_code} {resp.elapsed:.2f} {len(resp.content)}")
118
120
  if resp.status_code == 200:
119
- return resp_content
121
+ return cast(bytes, resp.content)
120
122
  self._exception_event.set()
121
123
  if resp.status_code in (202, 301, 403):
122
- raise RatelimitE(f"{resp.url} {resp.status_code}")
124
+ raise RatelimitE(f"{resp.url} {resp.status_code} Ratelimit")
123
125
  raise WebscoutE(f"{resp.url} return None. {params=} {data=}")
124
126
 
125
127
  async def _aget_vqd(self, keywords: str) -> str:
@@ -136,7 +138,7 @@ class AsyncWEBS:
136
138
  backend: str = "api",
137
139
  max_results: Optional[int] = None,
138
140
  ) -> List[Dict[str, str]]:
139
- """Webscout text search generator. Query params: https://duckduckgo.com/params.
141
+ """webscout text search generator. Query params: https://duckduckgo.com/params.
140
142
 
141
143
  Args:
142
144
  keywords: keywords for query.
@@ -153,7 +155,7 @@ class AsyncWEBS:
153
155
  List of dictionaries with search results, or None if there was an error.
154
156
 
155
157
  Raises:
156
- WebscoutE: Base exception for Webscout errors.
158
+ WebscoutE: Base exception for webscout_search errors.
157
159
  RatelimitE: Inherits from WebscoutE, raised for exceeding API request rate limits.
158
160
  TimeoutE: Inherits from WebscoutE, raised for API request timeouts.
159
161
  """
@@ -177,7 +179,7 @@ class AsyncWEBS:
177
179
  timelimit: Optional[str] = None,
178
180
  max_results: Optional[int] = None,
179
181
  ) -> List[Dict[str, str]]:
180
- """Webscout text search generator. Query params: https://duckduckgo.com/params.
182
+ """webscout text search generator. Query params: https://duckduckgo.com/params.
181
183
 
182
184
  Args:
183
185
  keywords: keywords for query.
@@ -190,7 +192,7 @@ class AsyncWEBS:
190
192
  List of dictionaries with search results.
191
193
 
192
194
  Raises:
193
- WebscoutE: Base exception for Webscout errors.
195
+ WebscoutE: Base exception for webscout_search errors.
194
196
  RatelimitE: Inherits from WebscoutE, raised for exceeding API request rate limits.
195
197
  TimeoutE: Inherits from WebscoutE, raised for API request timeouts.
196
198
  """
@@ -241,11 +243,19 @@ class AsyncWEBS:
241
243
  }
242
244
  results[priority] = result
243
245
 
244
- tasks = [_text_api_page(0, 0)]
246
+ tasks = [asyncio.create_task(_text_api_page(0, 0))]
245
247
  if max_results:
246
248
  max_results = min(max_results, 500)
247
- tasks.extend(_text_api_page(s, i) for i, s in enumerate(range(23, max_results, 50), start=1))
248
- await asyncio.gather(*tasks)
249
+ tasks.extend(
250
+ asyncio.create_task(_text_api_page(s, i)) for i, s in enumerate(range(23, max_results, 50), start=1)
251
+ )
252
+ try:
253
+ await asyncio.gather(*tasks)
254
+ except Exception as e:
255
+ for task in tasks:
256
+ task.cancel()
257
+ await asyncio.gather(*tasks, return_exceptions=True)
258
+ raise e
249
259
 
250
260
  return list(islice(filter(None, results), max_results))
251
261
 
@@ -257,7 +267,7 @@ class AsyncWEBS:
257
267
  timelimit: Optional[str] = None,
258
268
  max_results: Optional[int] = None,
259
269
  ) -> List[Dict[str, str]]:
260
- """Webscout text search generator. Query params: https://duckduckgo.com/params.
270
+ """webscout text search generator. Query params: https://duckduckgo.com/params.
261
271
 
262
272
  Args:
263
273
  keywords: keywords for query.
@@ -270,7 +280,7 @@ class AsyncWEBS:
270
280
  List of dictionaries with search results.
271
281
 
272
282
  Raises:
273
- WebscoutE: Base exception for Webscout errors.
283
+ WebscoutE: Base exception for webscout_search errors.
274
284
  RatelimitE: Inherits from WebscoutE, raised for exceeding API request rate limits.
275
285
  TimeoutE: Inherits from WebscoutE, raised for API request timeouts.
276
286
  """
@@ -302,7 +312,7 @@ class AsyncWEBS:
302
312
  return
303
313
 
304
314
  tree = await self._asession.loop.run_in_executor(
305
- self._get_executor(), partial(document_fromstring, resp_content, self._get_parser())
315
+ self.executor, partial(document_fromstring, resp_content, self.parser)
306
316
  )
307
317
 
308
318
  for e in tree.xpath("//div[h2]"):
@@ -327,11 +337,19 @@ class AsyncWEBS:
327
337
  }
328
338
  results[priority] = result
329
339
 
330
- tasks = [_text_html_page(0, 0)]
340
+ tasks = [asyncio.create_task(_text_html_page(0, 0))]
331
341
  if max_results:
332
342
  max_results = min(max_results, 500)
333
- tasks.extend(_text_html_page(s, i) for i, s in enumerate(range(23, max_results, 50), start=1))
334
- await asyncio.gather(*tasks)
343
+ tasks.extend(
344
+ asyncio.create_task(_text_html_page(s, i)) for i, s in enumerate(range(23, max_results, 50), start=1)
345
+ )
346
+ try:
347
+ await asyncio.gather(*tasks)
348
+ except Exception as e:
349
+ for task in tasks:
350
+ task.cancel()
351
+ await asyncio.gather(*tasks, return_exceptions=True)
352
+ raise e
335
353
 
336
354
  return list(islice(filter(None, results), max_results))
337
355
 
@@ -342,7 +360,7 @@ class AsyncWEBS:
342
360
  timelimit: Optional[str] = None,
343
361
  max_results: Optional[int] = None,
344
362
  ) -> List[Dict[str, str]]:
345
- """Webscout text search generator. Query params: https://duckduckgo.com/params.
363
+ """webscout text search generator. Query params: https://duckduckgo.com/params.
346
364
 
347
365
  Args:
348
366
  keywords: keywords for query.
@@ -354,7 +372,7 @@ class AsyncWEBS:
354
372
  List of dictionaries with search results.
355
373
 
356
374
  Raises:
357
- WebscoutE: Base exception for Webscout errors.
375
+ WebscoutE: Base exception for webscout_search errors.
358
376
  RatelimitE: Inherits from WebscoutE, raised for exceeding API request rate limits.
359
377
  TimeoutE: Inherits from WebscoutE, raised for API request timeouts.
360
378
  """
@@ -381,7 +399,7 @@ class AsyncWEBS:
381
399
  return
382
400
 
383
401
  tree = await self._asession.loop.run_in_executor(
384
- self._get_executor(), partial(document_fromstring, resp_content, self._get_parser())
402
+ self.executor, partial(document_fromstring, resp_content, self.parser)
385
403
  )
386
404
 
387
405
  data = zip(cycle(range(1, 5)), tree.xpath("//table[last()]//tr"))
@@ -410,11 +428,19 @@ class AsyncWEBS:
410
428
  }
411
429
  results[priority] = result
412
430
 
413
- tasks = [_text_lite_page(0, 0)]
431
+ tasks = [asyncio.create_task(_text_lite_page(0, 0))]
414
432
  if max_results:
415
433
  max_results = min(max_results, 500)
416
- tasks.extend(_text_lite_page(s, i) for i, s in enumerate(range(23, max_results, 50), start=1))
417
- await asyncio.gather(*tasks)
434
+ tasks.extend(
435
+ asyncio.create_task(_text_lite_page(s, i)) for i, s in enumerate(range(23, max_results, 50), start=1)
436
+ )
437
+ try:
438
+ await asyncio.gather(*tasks)
439
+ except Exception as e:
440
+ for task in tasks:
441
+ task.cancel()
442
+ await asyncio.gather(*tasks, return_exceptions=True)
443
+ raise e
418
444
 
419
445
  return list(islice(filter(None, results), max_results))
420
446
 
@@ -431,7 +457,7 @@ class AsyncWEBS:
431
457
  license_image: Optional[str] = None,
432
458
  max_results: Optional[int] = None,
433
459
  ) -> List[Dict[str, str]]:
434
- """Webscout images search. Query params: https://duckduckgo.com/params.
460
+ """webscout images search. Query params: https://duckduckgo.com/params.
435
461
 
436
462
  Args:
437
463
  keywords: keywords for query.
@@ -454,7 +480,7 @@ class AsyncWEBS:
454
480
  List of dictionaries with images search results.
455
481
 
456
482
  Raises:
457
- WebscoutE: Base exception for Webscout errors.
483
+ WebscoutE: Base exception for webscout_search errors.
458
484
  RatelimitE: Inherits from WebscoutE, raised for exceeding API request rate limits.
459
485
  TimeoutE: Inherits from WebscoutE, raised for API request timeouts.
460
486
  """
@@ -505,11 +531,19 @@ class AsyncWEBS:
505
531
  }
506
532
  results[priority] = result
507
533
 
508
- tasks = [_images_page(0, page=0)]
534
+ tasks = [asyncio.create_task(_images_page(0, page=0))]
509
535
  if max_results:
510
536
  max_results = min(max_results, 500)
511
- tasks.extend(_images_page(s, i) for i, s in enumerate(range(100, max_results, 100), start=1))
512
- await asyncio.gather(*tasks)
537
+ tasks.extend(
538
+ asyncio.create_task(_images_page(s, i)) for i, s in enumerate(range(100, max_results, 100), start=1)
539
+ )
540
+ try:
541
+ await asyncio.gather(*tasks)
542
+ except Exception as e:
543
+ for task in tasks:
544
+ task.cancel()
545
+ await asyncio.gather(*tasks, return_exceptions=True)
546
+ raise e
513
547
 
514
548
  return list(islice(filter(None, results), max_results))
515
549
 
@@ -524,7 +558,7 @@ class AsyncWEBS:
524
558
  license_videos: Optional[str] = None,
525
559
  max_results: Optional[int] = None,
526
560
  ) -> List[Dict[str, str]]:
527
- """Webscout videos search. Query params: https://duckduckgo.com/params.
561
+ """webscout videos search. Query params: https://duckduckgo.com/params.
528
562
 
529
563
  Args:
530
564
  keywords: keywords for query.
@@ -540,7 +574,7 @@ class AsyncWEBS:
540
574
  List of dictionaries with videos search results.
541
575
 
542
576
  Raises:
543
- WebscoutE: Base exception for Webscout errors.
577
+ WebscoutE: Base exception for webscout_search errors.
544
578
  RatelimitE: Inherits from WebscoutE, raised for exceeding API request rate limits.
545
579
  TimeoutE: Inherits from WebscoutE, raised for API request timeouts.
546
580
  """
@@ -579,11 +613,19 @@ class AsyncWEBS:
579
613
  priority += 1
580
614
  results[priority] = row
581
615
 
582
- tasks = [_videos_page(0, 0)]
616
+ tasks = [asyncio.create_task(_videos_page(0, 0))]
583
617
  if max_results:
584
618
  max_results = min(max_results, 400)
585
- tasks.extend(_videos_page(s, i) for i, s in enumerate(range(59, max_results, 59), start=1))
586
- await asyncio.gather(*tasks)
619
+ tasks.extend(
620
+ asyncio.create_task(_videos_page(s, i)) for i, s in enumerate(range(59, max_results, 59), start=1)
621
+ )
622
+ try:
623
+ await asyncio.gather(*tasks)
624
+ except Exception as e:
625
+ for task in tasks:
626
+ task.cancel()
627
+ await asyncio.gather(*tasks, return_exceptions=True)
628
+ raise e
587
629
 
588
630
  return list(islice(filter(None, results), max_results))
589
631
 
@@ -595,7 +637,7 @@ class AsyncWEBS:
595
637
  timelimit: Optional[str] = None,
596
638
  max_results: Optional[int] = None,
597
639
  ) -> List[Dict[str, str]]:
598
- """Webscout news search. Query params: https://duckduckgo.com/params.
640
+ """webscout news search. Query params: https://duckduckgo.com/params.
599
641
 
600
642
  Args:
601
643
  keywords: keywords for query.
@@ -608,7 +650,7 @@ class AsyncWEBS:
608
650
  List of dictionaries with news search results.
609
651
 
610
652
  Raises:
611
- WebscoutE: Base exception for Webscout errors.
653
+ WebscoutE: Base exception for webscout_search errors.
612
654
  RatelimitE: Inherits from WebscoutE, raised for exceeding API request rate limits.
613
655
  TimeoutE: Inherits from WebscoutE, raised for API request timeouts.
614
656
  """
@@ -653,16 +695,24 @@ class AsyncWEBS:
653
695
  }
654
696
  results[priority] = result
655
697
 
656
- tasks = [_news_page(0, 0)]
698
+ tasks = [asyncio.create_task(_news_page(0, 0))]
657
699
  if max_results:
658
700
  max_results = min(max_results, 200)
659
- tasks.extend(_news_page(s, i) for i, s in enumerate(range(29, max_results, 29), start=1))
660
- await asyncio.gather(*tasks)
701
+ tasks.extend(
702
+ asyncio.create_task(_news_page(s, i)) for i, s in enumerate(range(29, max_results, 29), start=1)
703
+ )
704
+ try:
705
+ await asyncio.gather(*tasks)
706
+ except Exception as e:
707
+ for task in tasks:
708
+ task.cancel()
709
+ await asyncio.gather(*tasks, return_exceptions=True)
710
+ raise e
661
711
 
662
712
  return list(islice(filter(None, results), max_results))
663
713
 
664
714
  async def answers(self, keywords: str) -> List[Dict[str, str]]:
665
- """Webscout instant answers. Query params: https://duckduckgo.com/params.
715
+ """webscout instant answers. Query params: https://duckduckgo.com/params.
666
716
 
667
717
  Args:
668
718
  keywords: keywords for query,
@@ -671,7 +721,7 @@ class AsyncWEBS:
671
721
  List of dictionaries with instant answers results.
672
722
 
673
723
  Raises:
674
- WebscoutE: Base exception for Webscout errors.
724
+ WebscoutE: Base exception for webscout_search errors.
675
725
  RatelimitE: Inherits from WebscoutE, raised for exceeding API request rate limits.
676
726
  TimeoutE: Inherits from WebscoutE, raised for API request timeouts.
677
727
  """
@@ -733,7 +783,7 @@ class AsyncWEBS:
733
783
  return results
734
784
 
735
785
  async def suggestions(self, keywords: str, region: str = "wt-wt") -> List[Dict[str, str]]:
736
- """Webscout suggestions. Query params: https://duckduckgo.com/params.
786
+ """webscout suggestions. Query params: https://duckduckgo.com/params.
737
787
 
738
788
  Args:
739
789
  keywords: keywords for query.
@@ -743,7 +793,7 @@ class AsyncWEBS:
743
793
  List of dictionaries with suggestions results.
744
794
 
745
795
  Raises:
746
- WebscoutE: Base exception for Webscout errors.
796
+ WebscoutE: Base exception for webscout_search errors.
747
797
  RatelimitE: Inherits from WebscoutE, raised for exceeding API request rate limits.
748
798
  TimeoutE: Inherits from WebscoutE, raised for API request timeouts.
749
799
  """
@@ -772,7 +822,7 @@ class AsyncWEBS:
772
822
  radius: int = 0,
773
823
  max_results: Optional[int] = None,
774
824
  ) -> List[Dict[str, str]]:
775
- """Webscout maps search. Query params: https://duckduckgo.com/params.
825
+ """webscout maps search. Query params: https://duckduckgo.com/params.
776
826
 
777
827
  Args:
778
828
  keywords: keywords for query
@@ -793,7 +843,7 @@ class AsyncWEBS:
793
843
  List of dictionaries with maps search results, or None if there was an error.
794
844
 
795
845
  Raises:
796
- WebscoutE: Base exception for Webscout errors.
846
+ WebscoutE: Base exception for webscout_search errors.
797
847
  RatelimitE: Inherits from WebscoutE, raised for exceeding API request rate limits.
798
848
  TimeoutE: Inherits from WebscoutE, raised for API request timeouts.
799
849
  """
@@ -945,7 +995,7 @@ class AsyncWEBS:
945
995
  async def translate(
946
996
  self, keywords: Union[List[str], str], from_: Optional[str] = None, to: str = "en"
947
997
  ) -> List[Dict[str, str]]:
948
- """Webscout translate.
998
+ """webscout translate.
949
999
 
950
1000
  Args:
951
1001
  keywords: string or list of strings to translate.
@@ -956,7 +1006,7 @@ class AsyncWEBS:
956
1006
  List od dictionaries with translated keywords.
957
1007
 
958
1008
  Raises:
959
- WebscoutE: Base exception for Webscout errors.
1009
+ WebscoutE: Base exception for webscout_search errors.
960
1010
  RatelimitE: Inherits from WebscoutE, raised for exceeding API request rate limits.
961
1011
  TimeoutE: Inherits from WebscoutE, raised for API request timeouts.
962
1012
  """
@@ -987,7 +1037,13 @@ class AsyncWEBS:
987
1037
 
988
1038
  if isinstance(keywords, str):
989
1039
  keywords = [keywords]
990
- tasks = [_translate_keyword(keyword) for keyword in keywords]
991
- await asyncio.gather(*tasks)
1040
+ tasks = [asyncio.create_task(_translate_keyword(keyword)) for keyword in keywords]
1041
+ try:
1042
+ await asyncio.gather(*tasks)
1043
+ except Exception as e:
1044
+ for task in tasks:
1045
+ task.cancel()
1046
+ await asyncio.gather(*tasks, return_exceptions=True)
1047
+ raise e
992
1048
 
993
1049
  return results
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: webscout
3
- Version: 1.4.3
3
+ Version: 1.4.5
4
4
  Summary: Search for anything using the Google, DuckDuckGo, phind.com. Also containes AI models, can transcribe yt videos, temporary email and phone number generation, have TTS support and webai(terminal gpt and open interpeter)
5
5
  Author: OEvortex
6
6
  Author-email: helpingai5@gmail.com
@@ -54,9 +54,31 @@ Provides-Extra: dev
54
54
  Requires-Dist: ruff >=0.1.6 ; extra == 'dev'
55
55
  Requires-Dist: pytest >=7.4.2 ; extra == 'dev'
56
56
 
57
- # webscout
58
- <p align="center">
57
+ <div align="center">
58
+ <!-- Replace `#` with your actual links -->
59
+ <a href="https://t.me/devsdocode"><img alt="Telegram" src="https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white"></a>
60
+ <a href="https://www.instagram.com/sree.shades_/"><img alt="Instagram" src="https://img.shields.io/badge/Instagram-E4405F?style=for-the-badge&logo=instagram&logoColor=white"></a>
61
+ <a href="https://www.linkedin.com/in/developer-sreejan/"><img alt="LinkedIn" src="https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white"></a>
62
+ <a href="https://buymeacoffee.com/devsdocode"><img alt="Buy Me A Coffee" src="https://img.shields.io/badge/Buy%20Me%20A%20Coffee-FFDD00?style=for-the-badge&logo=buymeacoffee&logoColor=black"></a>
63
+ </div>
64
+
65
+ <div align="center">
66
+ <!-- Replace `#` with your actual links -->
67
+ <a href="https://youtube.com/@@OEvortex">&#10148; Vortex's YouTube Channel</a>
68
+ </div>
69
+ <div align="center">
70
+ <a href="https://youtube.com/@devsdocode">&#10148; Devs Do Code's YouTube Channel</a>
71
+ </div>
72
+
73
+
59
74
 
75
+
76
+ # WEBSCOUT
77
+ </div>
78
+ <p align="center">
79
+ <div align="center">
80
+ <img src="https://img.shields.io/badge/WebScout-API-blue?style=for-the-badge&logo=WebScout" alt="WebScout API Badge">
81
+ </div>
60
82
  <a href="#"><img alt="Python version" src="https://img.shields.io/pypi/pyversions/webscout"/></a>
61
83
  <a href="https://pepy.tech/project/webscout"><img alt="Downloads" src="https://static.pepy.tech/badge/webscout"></a>
62
84
 
@@ -64,7 +86,7 @@ Search for anything using the Google, DuckDuckGo, phind.com. Also containes AI m
64
86
 
65
87
 
66
88
  ## Table of Contents
67
- - [webscout](#webscout)
89
+ - [WEBSCOUT](#webscout)
68
90
  - [Table of Contents](#table-of-contents)
69
91
  - [Install](#install)
70
92
  - [CLI version](#cli-version)
@@ -105,6 +127,7 @@ Search for anything using the Google, DuckDuckGo, phind.com. Also containes AI m
105
127
  - [10. `Reka` - chat with reka](#10-reka---chat-with-reka)
106
128
  - [11. `Cohere` - chat with cohere](#11-cohere---chat-with-cohere)
107
129
  - [12. `Xjai` - chat with free gpt 3.5](#12-xjai---chat-with-free-gpt-35)
130
+ - [`ThinkAny` - AI search engine](#thinkany---ai-search-engine)
108
131
  - [`LLM`](#llm)
109
132
  - [`LLM` with internet](#llm-with-internet)
110
133
  - [LLM with deepwebs](#llm-with-deepwebs)
@@ -790,7 +813,7 @@ print(response)
790
813
  ```python
791
814
  from webscout.AI import OPENGPT
792
815
 
793
- opengpt = OPENGPT(is_conversation=True, max_tokens=8000, timeout=30)
816
+ opengpt = OPENGPT(is_conversation=True, max_tokens=8000, timeout=30, assistant_id="bca37014-6f97-4f2b-8928-81ea8d478d88")
794
817
  while True:
795
818
  # Prompt the user for input
796
819
  prompt = input("Enter your prompt: ")
@@ -862,7 +885,31 @@ prompt = "Tell me about india"
862
885
  response = ai.chat(prompt)
863
886
  print(response)
864
887
  ```
888
+ ### `ThinkAny` - AI search engine
889
+ ```python
890
+ from webscout.AI import ThinkAnyAI
865
891
 
892
+ ai = ThinkAnyAI(
893
+ is_conversation=True,
894
+ max_tokens=800,
895
+ timeout=30,
896
+ intro=None,
897
+ filepath=None,
898
+ update_file=True,
899
+ proxies={},
900
+ history_offset=10250,
901
+ act=None,
902
+ web_search=False,
903
+ )
904
+
905
+ prompt = "what is meaning of life"
906
+
907
+ response = ai.ask(prompt)
908
+
909
+ # Extract and print the message from the response
910
+ message = ai.get_message(response)
911
+ print(message)
912
+ ```
866
913
  ### `LLM`
867
914
  ```python
868
915
  from webscout.LLM import LLM
@@ -1093,3 +1140,21 @@ if __name__ == "__main__":
1093
1140
  ```shell
1094
1141
  python -m webscout.webai webai --provider "phind" --rawdog
1095
1142
  ```
1143
+
1144
+ <div align="center">
1145
+ <!-- Replace `#` with your actual links -->
1146
+ <a href="https://t.me/devsdocode"><img alt="Telegram" src="https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white"></a>
1147
+ <a href="https://www.instagram.com/sree.shades_/"><img alt="Instagram" src="https://img.shields.io/badge/Instagram-E4405F?style=for-the-badge&logo=instagram&logoColor=white"></a>
1148
+ <a href="https://www.linkedin.com/in/developer-sreejan/"><img alt="LinkedIn" src="https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white"></a>
1149
+ <a href="https://buymeacoffee.com/devsdocode"><img alt="Buy Me A Coffee" src="https://img.shields.io/badge/Buy%20Me%20A%20Coffee-FFDD00?style=for-the-badge&logo=buymeacoffee&logoColor=black"></a>
1150
+ </div>
1151
+
1152
+ <div align="center">
1153
+ <!-- Replace `#` with your actual links -->
1154
+ <a href="https://youtube.com/@@OEvortex">&#10148; Vortex's YouTube Channel</a>
1155
+ </div>
1156
+ <div align="center">
1157
+ <a href="https://youtube.com/@devsdocode">&#10148; Devs Do Code's YouTube Channel</a>
1158
+ </div>
1159
+
1160
+
@@ -10,12 +10,12 @@ DeepWEBS/networks/webpage_fetcher.py,sha256=vRB9T3o-nMgrMkG2NPHTDctNeXaPSKCmBXqu
10
10
  DeepWEBS/utilsdw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  DeepWEBS/utilsdw/enver.py,sha256=vpI7s4_o_VL9govSryOv-z1zYK3pTEW3-H9QNN8JYtc,2472
12
12
  DeepWEBS/utilsdw/logger.py,sha256=Z0nFUcEGyU8r28yKiIyvEtO26xxpmJgbvNToTfwZecc,8174
13
- webscout/AI.py,sha256=cC3v-b4uH9h8DKtXrnHNQotiuhzrJk10HNa7_KWtN9E,215473
13
+ webscout/AI.py,sha256=sQGpHRwikBBXcxWsB-nRCSBG3oYhSVBHUFr3C2dHrv8,226145
14
14
  webscout/AIbase.py,sha256=GoHbN8r0gq2saYRZv6LA-Fr9Jlcjv80STKFXUq2ZeGU,4710
15
- webscout/AIutel.py,sha256=Mfmw_MYg1f1VJT02wfgqh0zzX-WpVikBG4IT2HlAbVY,33159
15
+ webscout/AIutel.py,sha256=WJXAUaNK4IQ-txweZhm3scE11b-pK_tlIjS5VWJN8_E,33217
16
16
  webscout/DWEBS.py,sha256=QT-7-dUgWhQ_H7EVZD53AVyXxyskoPMKCkFIpzkN56Q,7332
17
17
  webscout/LLM.py,sha256=CiDz0okZNEoXuxMwadZnwRGSLpqk2zg0vzvXSxQZjcE,1910
18
- webscout/__init__.py,sha256=7IVxt29I9ZFX4BMdb7oJk5ZmnH1dtJwpS-B6650jFms,1073
18
+ webscout/__init__.py,sha256=WcRrw6-MIpt_lHtA498MaO5oWuMRkEk5qYH0mVt4_Nc,1090
19
19
  webscout/__main__.py,sha256=ZtTRgsRjUi2JOvYFLF1ZCh55Sdoz94I-BS-TlJC7WDU,126
20
20
  webscout/async_providers.py,sha256=pPoSdfB_4SlOYcpAtkKIyDtl7sZ9DGgWy5aIBOjBO9Q,971
21
21
  webscout/cli.py,sha256=F888fdrFUQgczMBN4yMOSf6Nh-IbvkqpPhDsbnA2FtQ,17059
@@ -24,15 +24,15 @@ webscout/g4f.py,sha256=F7POjR03ek7eZvcTX-p7gMe1b0nLNoIqF-L_vZwos0c,24489
24
24
  webscout/models.py,sha256=5iQIdtedT18YuTZ3npoG7kLMwcrKwhQ7928dl_7qZW0,692
25
25
  webscout/tempid.py,sha256=5oc3UbXhPGKxrMRTfRABT-V-dNzH_hOKWtLYM6iCWd4,5896
26
26
  webscout/transcriber.py,sha256=EddvTSq7dPJ42V3pQVnGuEiYQ7WjJ9uyeR9kMSxN7uY,20622
27
- webscout/utils.py,sha256=c_98M4oqpb54pUun3fpGGlCerFD6ZHUbghyp5b7Mwgo,2605
28
- webscout/version.py,sha256=gOqqpnGHPIpFBhG81HqrJ8d0hLm31uWy0NtgxrQYAlY,25
27
+ webscout/utils.py,sha256=CxeXvp0rWIulUrEaPZMaNfg_tSuQLRSV8uuHA2chyKE,2603
28
+ webscout/version.py,sha256=2IusSRAul_UY0-wnbdAHj0XD7AIfWOrO2BBUSV-Sep0,25
29
29
  webscout/voice.py,sha256=0QjXTHAQmCK07IDZXRc7JXem47cnPJH7u3X0sVP1-UQ,967
30
- webscout/webai.py,sha256=et6gQFFiU5XQkTNNjrTucSOTEM9PmJFMWPIcWZ9dW_g,82281
31
- webscout/webscout_search.py,sha256=3_lli-hDb8_kCGwscK29xuUcOS833ROgpNhDzrxh0dk,3085
32
- webscout/webscout_search_async.py,sha256=Y5frH0k3hLqBCR-8dn7a_b7EvxdYxn6wHiKl3jWosE0,40670
33
- webscout-1.4.3.dist-info/LICENSE.md,sha256=mRVwJuT4SXC5O93BFdsfWBjlXjGn2Np90Zm5SocUzM0,3150
34
- webscout-1.4.3.dist-info/METADATA,sha256=r00ZVw3ZELW_A0WNLxjpyIuU4myUz3KYsvbUd2CZu3I,40471
35
- webscout-1.4.3.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
36
- webscout-1.4.3.dist-info/entry_points.txt,sha256=8-93eRslYrzTHs5E-6yFRJrve00C9q-SkXJD113jzRY,197
37
- webscout-1.4.3.dist-info/top_level.txt,sha256=OD5YKy6Y3hldL7SmuxsiEDxAG4LgdSSWwzYk22MF9fk,18
38
- webscout-1.4.3.dist-info/RECORD,,
30
+ webscout/webai.py,sha256=Ijnkr8b0mO2I8-mdCZggoIZ5cqMfxaVFpKpeJf7xtTw,82831
31
+ webscout/webscout_search.py,sha256=bBod97PffHDhS1AiyzMJJN74PXWK3A5OFCcEoHYWtcw,3393
32
+ webscout/webscout_search_async.py,sha256=4_L_t_I9WlvpPEI3FI0K3v6Aayr0pNvD3chYOp7JR8o,42902
33
+ webscout-1.4.5.dist-info/LICENSE.md,sha256=mRVwJuT4SXC5O93BFdsfWBjlXjGn2Np90Zm5SocUzM0,3150
34
+ webscout-1.4.5.dist-info/METADATA,sha256=rLuICqX1CjT-NAz4IxoEvn2k78rmNyCLL-ecsHWr3wU,43430
35
+ webscout-1.4.5.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
36
+ webscout-1.4.5.dist-info/entry_points.txt,sha256=8-93eRslYrzTHs5E-6yFRJrve00C9q-SkXJD113jzRY,197
37
+ webscout-1.4.5.dist-info/top_level.txt,sha256=OD5YKy6Y3hldL7SmuxsiEDxAG4LgdSSWwzYk22MF9fk,18
38
+ webscout-1.4.5.dist-info/RECORD,,