webscout 6.4__py3-none-any.whl → 6.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of webscout might be problematic. Click here for more details.

Files changed (116) hide show
  1. webscout/AIutel.py +7 -54
  2. webscout/DWEBS.py +48 -26
  3. webscout/{YTdownloader.py → Extra/YTToolkit/YTdownloader.py} +990 -1103
  4. webscout/Extra/YTToolkit/__init__.py +3 -0
  5. webscout/{transcriber.py → Extra/YTToolkit/transcriber.py} +1 -1
  6. webscout/Extra/YTToolkit/ytapi/__init__.py +6 -0
  7. webscout/Extra/YTToolkit/ytapi/channel.py +307 -0
  8. webscout/Extra/YTToolkit/ytapi/errors.py +13 -0
  9. webscout/Extra/YTToolkit/ytapi/extras.py +45 -0
  10. webscout/Extra/YTToolkit/ytapi/https.py +88 -0
  11. webscout/Extra/YTToolkit/ytapi/patterns.py +61 -0
  12. webscout/Extra/YTToolkit/ytapi/playlist.py +59 -0
  13. webscout/Extra/YTToolkit/ytapi/pool.py +8 -0
  14. webscout/Extra/YTToolkit/ytapi/query.py +37 -0
  15. webscout/Extra/YTToolkit/ytapi/stream.py +60 -0
  16. webscout/Extra/YTToolkit/ytapi/utils.py +62 -0
  17. webscout/Extra/YTToolkit/ytapi/video.py +102 -0
  18. webscout/Extra/__init__.py +2 -1
  19. webscout/Extra/autocoder/autocoder_utiles.py +119 -101
  20. webscout/Extra/autocoder/rawdog.py +679 -680
  21. webscout/Extra/gguf.py +441 -441
  22. webscout/Extra/markdownlite/__init__.py +862 -0
  23. webscout/Extra/weather_ascii.py +2 -2
  24. webscout/Provider/AISEARCH/__init__.py +2 -0
  25. webscout/Provider/AISEARCH/ooai.py +155 -0
  26. webscout/Provider/Amigo.py +70 -85
  27. webscout/Provider/{prefind.py → Jadve.py} +72 -70
  28. webscout/Provider/Netwrck.py +235 -0
  29. webscout/Provider/Openai.py +4 -3
  30. webscout/Provider/PI.py +292 -221
  31. webscout/Provider/PizzaGPT.py +3 -3
  32. webscout/Provider/Reka.py +0 -1
  33. webscout/Provider/TTS/__init__.py +5 -1
  34. webscout/Provider/TTS/deepgram.py +183 -0
  35. webscout/Provider/TTS/elevenlabs.py +137 -0
  36. webscout/Provider/TTS/gesserit.py +151 -0
  37. webscout/Provider/TTS/murfai.py +139 -0
  38. webscout/Provider/TTS/parler.py +134 -107
  39. webscout/Provider/TTS/streamElements.py +360 -275
  40. webscout/Provider/TTS/utils.py +280 -0
  41. webscout/Provider/TTS/voicepod.py +116 -116
  42. webscout/Provider/TeachAnything.py +15 -2
  43. webscout/Provider/Youchat.py +42 -8
  44. webscout/Provider/__init__.py +8 -21
  45. webscout/Provider/meta.py +794 -779
  46. webscout/Provider/multichat.py +230 -0
  47. webscout/Provider/promptrefine.py +2 -2
  48. webscout/Provider/talkai.py +10 -13
  49. webscout/Provider/turboseek.py +5 -4
  50. webscout/Provider/tutorai.py +8 -112
  51. webscout/Provider/typegpt.py +5 -7
  52. webscout/Provider/x0gpt.py +81 -9
  53. webscout/Provider/yep.py +123 -361
  54. webscout/__init__.py +33 -28
  55. webscout/conversation.py +24 -9
  56. webscout/exceptions.py +188 -20
  57. webscout/litprinter/__init__.py +719 -831
  58. webscout/litprinter/colors.py +54 -0
  59. webscout/optimizers.py +420 -270
  60. webscout/prompt_manager.py +279 -279
  61. webscout/scout/__init__.py +8 -0
  62. webscout/scout/core/__init__.py +7 -0
  63. webscout/scout/core/crawler.py +140 -0
  64. webscout/scout/core/scout.py +571 -0
  65. webscout/scout/core/search_result.py +96 -0
  66. webscout/scout/core/text_analyzer.py +63 -0
  67. webscout/scout/core/text_utils.py +277 -0
  68. webscout/scout/core/web_analyzer.py +52 -0
  69. webscout/scout/core.py +884 -0
  70. webscout/scout/element.py +460 -0
  71. webscout/scout/parsers/__init__.py +69 -0
  72. webscout/scout/parsers/html5lib_parser.py +172 -0
  73. webscout/scout/parsers/html_parser.py +236 -0
  74. webscout/scout/parsers/lxml_parser.py +178 -0
  75. webscout/scout/utils.py +38 -0
  76. webscout/update_checker.py +184 -125
  77. webscout/version.py +1 -1
  78. webscout/zeroart/__init__.py +55 -0
  79. webscout/zeroart/base.py +60 -0
  80. webscout/zeroart/effects.py +99 -0
  81. webscout/zeroart/fonts.py +816 -0
  82. webscout/zerodir/__init__.py +225 -0
  83. {webscout-6.4.dist-info → webscout-6.6.dist-info}/METADATA +18 -231
  84. webscout-6.6.dist-info/RECORD +197 -0
  85. webscout-6.6.dist-info/top_level.txt +2 -0
  86. webstoken/__init__.py +30 -0
  87. webstoken/classifier.py +189 -0
  88. webstoken/keywords.py +216 -0
  89. webstoken/language.py +128 -0
  90. webstoken/ner.py +164 -0
  91. webstoken/normalizer.py +35 -0
  92. webstoken/processor.py +77 -0
  93. webstoken/sentiment.py +206 -0
  94. webstoken/stemmer.py +73 -0
  95. webstoken/t.py +75 -0
  96. webstoken/tagger.py +60 -0
  97. webstoken/tokenizer.py +158 -0
  98. webscout/Agents/Onlinesearcher.py +0 -182
  99. webscout/Agents/__init__.py +0 -2
  100. webscout/Agents/functioncall.py +0 -248
  101. webscout/Bing_search.py +0 -251
  102. webscout/Provider/Perplexity.py +0 -599
  103. webscout/Provider/RoboCoders.py +0 -206
  104. webscout/Provider/genspark.py +0 -225
  105. webscout/Provider/perplexitylabs.py +0 -265
  106. webscout/Provider/twitterclone.py +0 -251
  107. webscout/Provider/upstage.py +0 -230
  108. webscout/gpt4free.py +0 -666
  109. webscout/requestsHTMLfix.py +0 -775
  110. webscout/webai.py +0 -2590
  111. webscout-6.4.dist-info/RECORD +0 -154
  112. webscout-6.4.dist-info/top_level.txt +0 -1
  113. /webscout/Provider/{felo_search.py → AISEARCH/felo_search.py} +0 -0
  114. {webscout-6.4.dist-info → webscout-6.6.dist-info}/LICENSE.md +0 -0
  115. {webscout-6.4.dist-info → webscout-6.6.dist-info}/WHEEL +0 -0
  116. {webscout-6.4.dist-info → webscout-6.6.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  import requests
2
2
  from rich.console import Console
3
- from pyfiglet import figlet_format
3
+ from webscout.zeroart import figlet_format
4
4
 
5
5
  console = Console()
6
6
  def get(location):
@@ -12,7 +12,7 @@ def get(location):
12
12
  str: ASCII art weather report if the request is successful,
13
13
  otherwise an error message.
14
14
  """
15
- console.print(f"[bold green]{figlet_format('Weather')}[/]\n", justify="center")
15
+ console.print(f"[bold green]{figlet_format('Weather')}")
16
16
  url = f"https://wttr.in/{location}"
17
17
  response = requests.get(url, headers={'User-Agent': 'curl'})
18
18
 
@@ -0,0 +1,2 @@
1
+ from .felo_search import *
2
+ from .ooai import *
@@ -0,0 +1,155 @@
1
+ import requests
2
+ import json
3
+ import re
4
+ from typing import Any, Dict, Generator, Optional
5
+
6
+ from webscout.AIbase import Provider
7
+ from webscout import exceptions
8
+ from webscout.litagent import LitAgent
9
+
10
+
11
+ class OOAi(Provider):
12
+ """
13
+ A class to interact with the oo.ai API.
14
+ """
15
+
16
+ def __init__(
17
+ self,
18
+ max_tokens: int = 600,
19
+ timeout: int = 30,
20
+ proxies: Optional[dict] = None,
21
+ ):
22
+ """Initializes the OOAi API client."""
23
+ self.session = requests.Session()
24
+ self.max_tokens_to_sample = max_tokens
25
+ self.api_endpoint = "https://oo.ai/api/search"
26
+ self.stream_chunk_size = 1024 # Adjust as needed
27
+ self.timeout = timeout
28
+ self.last_response = {}
29
+ self.headers = {
30
+ "Accept": "text/event-stream",
31
+ "Accept-Encoding": "gzip, deflate, br, zstd",
32
+ "Accept-Language": "en-US,en;q=0.9,en-IN;q=0.8",
33
+ "Cache-Control": "no-cache",
34
+ "Cookie": "_ga=GA1.1.1827087199.1734256606; _ga_P0EJPHF2EG=GS1.1.1734368698.4.1.1734368711.0.0.0",
35
+ "DNT": "1",
36
+ "Referer": "https://oo.ai/",
37
+ "sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A_Brand";v="24"',
38
+ "sec-ch-ua-mobile": "?0",
39
+ "sec-ch-ua-platform": "Windows",
40
+ "sec-fetch-dest": "empty",
41
+ "sec-fetch-mode": "cors",
42
+ "sec-fetch-site": "same-origin",
43
+ }
44
+ self.session.headers.update(self.headers)
45
+ self.proxies = proxies
46
+ self.headers["User-Agent"] = LitAgent().random()
47
+
48
+ def ask(
49
+ self,
50
+ prompt: str,
51
+ stream: bool = False,
52
+ raw: bool = False,
53
+ optimizer: Optional[str] = None,
54
+ conversationally: bool = False,
55
+ ) -> Dict[str, Any] | Generator[Dict[str, Any], None, None]:
56
+ """Chat with AI
57
+ Args:
58
+ prompt (str): Prompt to be sent.
59
+ stream (bool, optional): Flag for streaming response. Defaults to False.
60
+ raw (bool, optional): Stream back raw response as received. Defaults to False.
61
+ optimizer (str, optional): Not used. Defaults to None.
62
+ conversationally (bool, optional): Not used. Defaults to False.
63
+ Returns:
64
+ Union[Dict, Generator[Dict, None, None]]: Response generated
65
+ """
66
+ params = {
67
+ "q": prompt,
68
+ "lang": "en-US",
69
+ "tz": "Asia/Calcutta",
70
+ }
71
+
72
+ def for_stream():
73
+ try:
74
+ with self.session.get(
75
+ self.api_endpoint,
76
+ params=params,
77
+ headers=self.headers,
78
+ stream=True,
79
+ timeout=self.timeout,
80
+ ) as response:
81
+
82
+ if not response.ok:
83
+ raise exceptions.FailedToGenerateResponseError(
84
+ f"Request failed with status code {response.status_code}: {response.text}"
85
+ )
86
+
87
+ streaming_text = ""
88
+ for line in response.iter_lines(decode_unicode=True):
89
+ if line and line.startswith('data: '):
90
+ try:
91
+ json_data = json.loads(line[6:])
92
+ if "content" in json_data:
93
+ content = self.clean_content(json_data["content"])
94
+ streaming_text += content
95
+ yield {"text": content} if not raw else {"text": content}
96
+ except json.JSONDecodeError:
97
+ continue
98
+ self.last_response.update({"text": streaming_text})
99
+
100
+ except requests.exceptions.RequestException as e:
101
+ raise exceptions.APIConnectionError(f"Request failed: {e}")
102
+
103
+ def for_non_stream():
104
+ for _ in for_stream():
105
+ pass
106
+ return self.last_response
107
+
108
+ return for_stream() if stream else for_non_stream()
109
+
110
+ def chat(
111
+ self,
112
+ prompt: str,
113
+ stream: bool = False,
114
+ optimizer: Optional[str] = None,
115
+ conversationally: bool = False,
116
+ ) -> str | Generator[str, None, None]:
117
+ """Generate response `str`"""
118
+
119
+ def for_stream():
120
+ for response in self.ask(
121
+ prompt, True, optimizer=optimizer, conversationally=conversationally
122
+ ):
123
+ yield self.get_message(response)
124
+
125
+ def for_non_stream():
126
+ return self.get_message(
127
+ self.ask(
128
+ prompt,
129
+ False,
130
+ optimizer=optimizer,
131
+ conversationally=conversationally,
132
+ )
133
+ )
134
+
135
+ return for_stream() if stream else for_non_stream()
136
+
137
+ def get_message(self, response: dict) -> str:
138
+ """Retrieves message only from response"""
139
+ assert isinstance(response, dict), "Response should be of dict data-type only"
140
+ return response["text"]
141
+
142
+ @staticmethod
143
+ def clean_content(text: str) -> str:
144
+ """Removes all webblock elements with research or detail classes."""
145
+ cleaned_text = re.sub(
146
+ r'<webblock class="(?:research|detail)">[^<]*</webblock>', "", text
147
+ )
148
+ return cleaned_text
149
+
150
+ if __name__ == "__main__":
151
+ from rich import print
152
+ ai = OOAi()
153
+ response = ai.chat(input(">>> "), stream=True)
154
+ for chunk in response:
155
+ print(chunk, end="", flush=True)
@@ -1,14 +1,12 @@
1
1
  import cloudscraper
2
2
  import json
3
3
  import uuid
4
- import os
5
- from typing import Any, Dict, Optional, Generator
4
+ from typing import Any, Dict, Generator
6
5
 
7
6
  from webscout.AIutel import Optimizers
8
7
  from webscout.AIutel import Conversation
9
- from webscout.AIutel import AwesomePrompts, sanitize_stream
10
- from webscout.AIbase import Provider, AsyncProvider
11
- from webscout import exceptions
8
+ from webscout.AIutel import AwesomePrompts
9
+ from webscout.AIbase import Provider
12
10
 
13
11
  class AmigoChat(Provider):
14
12
  """
@@ -24,9 +22,8 @@ class AmigoChat(Provider):
24
22
  "o1-preview", # OpenAI O1 Preview
25
23
  "claude-3-5-sonnet-20241022", # Claude 3.5 Sonnet
26
24
  "Qwen/Qwen2.5-72B-Instruct-Turbo", # Qwen 2.5
27
- "gpt-4o" # OpenAI GPT-4o
25
+ "gpt-4o", # OpenAI GPT-4o
28
26
  "meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo" # Llama 3.2
29
-
30
27
  ]
31
28
 
32
29
  def __init__(
@@ -51,14 +48,14 @@ class AmigoChat(Provider):
51
48
  Args:
52
49
  is_conversation (bool, optional): Flag for chatting conversationally. Defaults to True.
53
50
  max_tokens (int, optional): Maximum number of tokens to be generated upon completion. Defaults to 600.
54
- timeout (int, optional): Http request timeout. Defaults to 30.
51
+ timeout (int, optional): HTTP request timeout. Defaults to 30.
55
52
  intro (str, optional): Conversation introductory prompt. Defaults to None.
56
53
  filepath (str, optional): Path to file containing conversation history. Defaults to None.
57
54
  update_file (bool, optional): Add new prompts and responses to the file. Defaults to True.
58
- proxies (dict, optional): Http request proxies. Defaults to {}.
55
+ proxies (dict, optional): HTTP request proxies. Defaults to {}.
59
56
  history_offset (int, optional): Limit conversation history to this number of last texts. Defaults to 10250.
60
57
  act (str|int, optional): Awesome prompt key or index. (Used as intro). Defaults to None.
61
- model (str, optional): The AI model to use for text generation. Defaults to "o1-preview".
58
+ model (str, optional): The AI model to use for text generation. Defaults to "Qwen/Qwen2.5-72B-Instruct-Turbo".
62
59
  """
63
60
  if model not in self.AVAILABLE_MODELS:
64
61
  raise ValueError(f"Invalid model: {model}. Choose from: {self.AVAILABLE_MODELS}")
@@ -135,7 +132,7 @@ class AmigoChat(Provider):
135
132
  """Chat with AI
136
133
 
137
134
  Args:
138
- prompt (str): Prompt to be send.
135
+ prompt (str): Prompt to be sent.
139
136
  stream (bool, optional): Flag for streaming response. Defaults to False.
140
137
  raw (bool, optional): Stream back raw response as received. Defaults to False.
141
138
  optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`. Defaults to None.
@@ -170,69 +167,61 @@ class AmigoChat(Provider):
170
167
  "max_tokens": self.max_tokens_to_sample,
171
168
  "presence_penalty": 0,
172
169
  "stream": stream,
173
- "temperature":self.temperature,
170
+ "temperature": self.temperature,
174
171
  "top_p": self.top_p
175
172
  }
176
173
 
177
- def for_stream():
178
- try:
179
- # Make the POST request with streaming enabled
180
- response = self.session.post(
181
- self.api_endpoint,
182
- json=payload,
183
- stream=True,
184
- timeout=self.timeout
185
- )
186
-
187
- # Check if the request was successful
188
- if response.status_code == 201:
189
- # Iterate over the streamed response line by line
190
- for line in response.iter_lines():
191
- if line:
192
- # Decode the line from bytes to string
193
- decoded_line = line.decode('utf-8').strip()
194
- if decoded_line.startswith("data: "):
195
- data_str = decoded_line[6:]
196
- if data_str == "[DONE]":
197
- break
198
- try:
199
- # Load the JSON data
200
- data_json = json.loads(data_str)
201
-
202
- # Extract the content from the response
203
- choices = data_json.get("choices", [])
204
- if choices:
205
- delta = choices[0].get("delta", {})
206
- content = delta.get("content", "")
207
- if content:
208
- yield content if raw else dict(text=content)
209
- except json.JSONDecodeError:
210
- print(f"Received non-JSON data: {data_str}")
211
- else:
212
- print(f"Request failed with status code {response.status_code}")
213
- print("Response:", response.text)
174
+ if stream:
175
+ return self._stream_response(payload, raw)
176
+ else:
177
+ return self._non_stream_response(payload)
214
178
 
215
- except (cloudscraper.exceptions.CloudflareChallengeError,
216
- cloudscraper.exceptions.CloudflareCode1020) as e:
217
- print("Cloudflare protection error:", str(e))
218
- except Exception as e:
219
- print("An error occurred while making the request:", str(e))
179
+ def _stream_response(self, payload: Dict[str, Any], raw: bool) -> Generator:
180
+ try:
181
+ response = self.session.post(
182
+ self.api_endpoint,
183
+ json=payload,
184
+ stream=True,
185
+ timeout=self.timeout
186
+ )
220
187
 
221
- def for_non_stream():
222
- # Accumulate the streaming response
223
- full_response = ""
224
- for chunk in for_stream():
225
- if not raw: # If not raw, chunk is a dictionary
226
- full_response += chunk["text"]
188
+ if response.status_code == 201:
189
+ for line in response.iter_lines():
190
+ if line:
191
+ decoded_line = line.decode('utf-8').strip()
192
+ if decoded_line.startswith("data: "):
193
+ data_str = decoded_line[6:]
194
+ if data_str == "[DONE]":
195
+ break
196
+ try:
197
+ data_json = json.loads(data_str)
198
+ choices = data_json.get("choices", [])
199
+ if choices:
200
+ delta = choices[0].get("delta", {})
201
+ content = delta.get("content", "")
202
+ if content:
203
+ yield content if raw else dict(text=content)
204
+ except json.JSONDecodeError:
205
+ print(f"Received non-JSON data: {data_str}")
206
+ else:
207
+ print(f"Request failed with status code {response.status_code}")
208
+ print("Response:", response.text)
209
+ except (cloudscraper.exceptions.CloudflareChallengeError,
210
+ cloudscraper.exceptions.CloudflareCode1020) as e:
211
+ print("Cloudflare protection error:", str(e))
212
+ except Exception as e:
213
+ print("An error occurred while making the request:", str(e))
227
214
 
228
- # Update self.last_response with the full text
229
- self.last_response.update(dict(text=full_response))
230
- self.conversation.update_chat_history(
231
- prompt, self.get_message(self.last_response)
232
- )
233
- return self.last_response
215
+ def _non_stream_response(self, payload: Dict[str, Any]) -> Dict[str, Any]:
216
+ full_response = ""
217
+ for chunk in self._stream_response(payload, raw=False):
218
+ full_response += chunk["text"]
234
219
 
235
- return for_stream() if stream else for_non_stream()
220
+ self.last_response.update(dict(text=full_response))
221
+ self.conversation.update_chat_history(
222
+ payload["messages"][-1]["content"], self.get_message(self.last_response)
223
+ )
224
+ return self.last_response
236
225
 
237
226
  def chat(
238
227
  self,
@@ -240,36 +229,32 @@ class AmigoChat(Provider):
240
229
  stream: bool = False,
241
230
  optimizer: str = None,
242
231
  conversationally: bool = False,
243
- ) -> str:
232
+ ) -> Generator[str, None, None]:
244
233
  """Generate response `str`
245
234
  Args:
246
- prompt (str): Prompt to be send.
235
+ prompt (str): Prompt to be sent.
247
236
  stream (bool, optional): Flag for streaming response. Defaults to False.
248
237
  optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`. Defaults to None.
249
238
  conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
250
239
  Returns:
251
- str: Response generated
240
+ Generator[str, None, None]: Response generated
252
241
  """
253
242
 
254
- def for_stream():
243
+ if stream:
255
244
  for response in self.ask(
256
245
  prompt, True, optimizer=optimizer, conversationally=conversationally
257
246
  ):
258
247
  yield self.get_message(response)
259
-
260
- def for_non_stream():
261
- return self.get_message(
262
- self.ask(
263
- prompt,
264
- False,
265
- optimizer=optimizer,
266
- conversationally=conversationally,
267
- )
248
+ else:
249
+ response = self.ask(
250
+ prompt,
251
+ False,
252
+ optimizer=optimizer,
253
+ conversationally=conversationally,
268
254
  )
255
+ yield self.get_message(response)
269
256
 
270
- return for_stream() if stream else for_non_stream()
271
-
272
- def get_message(self, response: dict) -> str:
257
+ def get_message(self, response: Dict[str, Any]) -> str:
273
258
  """Retrieves message only from response
274
259
 
275
260
  Args:
@@ -280,10 +265,10 @@ class AmigoChat(Provider):
280
265
  """
281
266
  assert isinstance(response, dict), "Response should be of dict data-type only"
282
267
  return response["text"]
283
-
268
+
284
269
  if __name__ == '__main__':
285
270
  from rich import print
286
271
  ai = AmigoChat(model="o1-preview", system_prompt="You are a noobi AI assistant who always uses the word 'noobi' in every response. For example, you might say 'Noobi will tell you...' or 'This noobi thinks that...'.")
287
272
  response = ai.chat(input(">>> "), stream=True)
288
273
  for chunk in response:
289
- print(chunk, end="", flush=True)
274
+ print(chunk, end="", flush=True)
@@ -1,21 +1,21 @@
1
1
  import requests
2
2
  import json
3
- import uuid
4
- import os
3
+ import re
5
4
  from typing import Any, Dict, Optional, Generator
6
5
 
7
6
  from webscout.AIutel import Optimizers
8
7
  from webscout.AIutel import Conversation
9
- from webscout.AIutel import AwesomePrompts, sanitize_stream
10
- from webscout.AIbase import Provider, AsyncProvider
8
+ from webscout.AIutel import AwesomePrompts
9
+ from webscout.AIbase import Provider
11
10
  from webscout import exceptions
11
+ from webscout.litagent import LitAgent
12
12
 
13
- class PrefindAI(Provider):
13
+ class JadveOpenAI(Provider):
14
14
  """
15
- A class to interact with the Prefind AI API.
15
+ A class to interact with the OpenAI API through jadve.com.
16
16
  """
17
17
 
18
- AVAILABLE_MODELS = ["llama", "claude"]
18
+ AVAILABLE_MODELS = ["gpt-4o", "gpt-4o-mini"]
19
19
 
20
20
  def __init__(
21
21
  self,
@@ -28,10 +28,11 @@ class PrefindAI(Provider):
28
28
  proxies: dict = {},
29
29
  history_offset: int = 10250,
30
30
  act: str = None,
31
- model: str = "claude",
31
+ model: str = "gpt-4o-mini",
32
+ system_prompt: str = "You are a helpful AI assistant."
32
33
  ):
33
34
  """
34
- Initializes the Prefind AI API with given parameters.
35
+ Initializes the OpenAI API client through jadve.com with given parameters.
35
36
 
36
37
  Args:
37
38
  is_conversation (bool, optional): Flag for chatting conversationally. Defaults to True.
@@ -43,30 +44,45 @@ class PrefindAI(Provider):
43
44
  proxies (dict, optional): Http request proxies. Defaults to {}.
44
45
  history_offset (int, optional): Limit conversation history to this number of last texts. Defaults to 10250.
45
46
  act (str|int, optional): Awesome prompt key or index. (Used as intro). Defaults to None.
46
- model (str, optional): The AI model to use for text generation. Defaults to "claude".
47
- Options: "llama", "claude".
47
+ system_prompt (str, optional): System prompt for OpenAI. Defaults to "You are a helpful AI assistant.".
48
+ model (str, optional): AI model to use for text generation. Defaults to "gpt-4o".
48
49
  """
50
+ if model not in self.AVAILABLE_MODELS:
51
+ raise ValueError(f"Invalid model: {model}. Choose from: {self.AVAILABLE_MODELS}")
52
+
49
53
  self.session = requests.Session()
50
54
  self.is_conversation = is_conversation
51
55
  self.max_tokens_to_sample = max_tokens
52
- self.api_endpoint = "https://api.prefind.ai/api/search/v1"
56
+ self.api_endpoint = "https://openai.jadve.com/chatgpt"
53
57
  self.stream_chunk_size = 64
54
58
  self.timeout = timeout
55
59
  self.last_response = {}
56
60
  self.model = model
57
- self.device_token = self.get_device_token()
61
+ self.system_prompt = system_prompt
62
+ self.headers = {
63
+ "accept": "*/*",
64
+ "accept-encoding": "gzip, deflate, br, zstd",
65
+ "accept-language": "en",
66
+ "content-type": "application/json",
67
+ "dnt": "1",
68
+ "origin": "https://jadve.com",
69
+ "priority": "u=1, i",
70
+ "referer": "https://jadve.com/",
71
+ "sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
72
+ "sec-ch-ua-mobile": "?0",
73
+ "sec-ch-ua-platform": '"Windows"',
74
+ "sec-fetch-dest": "empty",
75
+ "sec-fetch-mode": "cors",
76
+ "sec-fetch-site": "same-site",
77
+ "user-agent": LitAgent().random(),
78
+ }
58
79
 
59
80
  self.__available_optimizers = (
60
81
  method
61
82
  for method in dir(Optimizers)
62
83
  if callable(getattr(Optimizers, method)) and not method.startswith("__")
63
84
  )
64
- self.session.headers.update(
65
- {
66
- "Content-Type": "application/json",
67
- "Accept": "text/event-stream",
68
- }
69
- )
85
+ self.session.headers.update(self.headers)
70
86
  Conversation.intro = (
71
87
  AwesomePrompts().get_act(
72
88
  act, raise_not_found=True, default=None, case_insensitive=True
@@ -80,25 +96,6 @@ class PrefindAI(Provider):
80
96
  self.conversation.history_offset = history_offset
81
97
  self.session.proxies = proxies
82
98
 
83
- def get_device_token(self) -> str:
84
- """
85
- Retrieves a device token from the Prefind AI API.
86
- """
87
- device_token_url = "https://api.prefind.ai/api/auth/device-token/create"
88
- headers = {"Content-Type": "application/json; charset=utf-8"}
89
- data = {}
90
- response = requests.post(
91
- device_token_url, headers=headers, data=json.dumps(data)
92
- )
93
-
94
- if response.status_code == 200:
95
- device_token_data = response.json()
96
- return device_token_data["sessionToken"]
97
- else:
98
- raise exceptions.FailedToGenerateResponseError(
99
- f"Failed to get device token - ({response.status_code}, {response.reason}) - {response.text}"
100
- )
101
-
102
99
  def ask(
103
100
  self,
104
101
  prompt: str,
@@ -106,11 +103,10 @@ class PrefindAI(Provider):
106
103
  raw: bool = False,
107
104
  optimizer: str = None,
108
105
  conversationally: bool = False,
109
- ) -> Dict[str, Any]:
106
+ ) -> dict:
110
107
  """Chat with AI
111
-
112
108
  Args:
113
- prompt (str): Prompt to be send.
109
+ prompt (str): Prompt to be sent.
114
110
  stream (bool, optional): Flag for streaming response. Defaults to False.
115
111
  raw (bool, optional): Stream back raw response as received. Defaults to False.
116
112
  optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`. Defaults to None.
@@ -134,43 +130,51 @@ class PrefindAI(Provider):
134
130
  f"Optimizer is not one of {self.__available_optimizers}"
135
131
  )
136
132
 
137
- search_data = {"query": conversation_prompt, "deviceToken": self.device_token}
138
-
133
+ payload = {
134
+ "action": "sendmessage",
135
+ "model": self.model,
136
+ "messages": [
137
+ {"role": "system", "content": self.system_prompt},
138
+ {"role": "user", "content": conversation_prompt}
139
+ ],
140
+ "temperature": 0.7,
141
+ "language": "en",
142
+ "returnTokensUsage": True,
143
+ "botId": "guest-chat",
144
+ "chatId": ""
145
+ }
146
+
139
147
  def for_stream():
140
148
  response = self.session.post(
141
- self.api_endpoint, json=search_data, stream=True, timeout=self.timeout
149
+ self.api_endpoint, headers=self.headers, json=payload, stream=True, timeout=self.timeout
142
150
  )
151
+
143
152
  if not response.ok:
144
153
  raise exceptions.FailedToGenerateResponseError(
145
154
  f"Failed to generate response - ({response.status_code}, {response.reason}) - {response.text}"
146
155
  )
147
-
148
156
  streaming_text = ""
149
- for line in response.iter_lines(decode_unicode=True): #This is already decoding
157
+ for line in response.iter_lines(decode_unicode=True):
150
158
  if line:
151
- # line = line.decode('utf-8').strip() # This line is unnecessary and causing the error
152
- if line.startswith("event: "):
153
- event = line[7:]
154
- elif line.startswith("data: "):
155
- data_str = line[6:]
156
- if event == "received":
157
- data = json.loads(data_str)
158
- if data['type'] == 'chunk':
159
- model = data['model']
160
- if (self.model == "llama" and model == 'OPENROUTER_LLAMA_3') or \
161
- (self.model == "claude" and model == 'OPENROUTER_CLAUDE'):
162
- content = data['chunk']['content']
163
- if content:
164
- streaming_text += content #+ ("\n" if stream else "")
165
- resp = dict(text=content)
166
- self.last_response.update(resp)
167
- yield resp if raw else resp
159
+ if line.startswith("data: "):
160
+ data = line[6:]
161
+ if data == "[DONE]":
162
+ break
163
+ try:
164
+ json_data = json.loads(data)
165
+ if "choices" in json_data and len(json_data["choices"]) > 0:
166
+ content = json_data["choices"][0].get("delta", {}).get("content", "")
167
+ if content:
168
+ streaming_text += content
169
+ yield content if raw else dict(text=content)
170
+ except json.JSONDecodeError as e:
171
+ print(f"Error parsing line: {line} - {e}")
172
+ self.last_response.update(dict(text=streaming_text))
168
173
  self.conversation.update_chat_history(
169
174
  prompt, self.get_message(self.last_response)
170
175
  )
171
176
 
172
177
  def for_non_stream():
173
- # let's make use of stream
174
178
  for _ in for_stream():
175
179
  pass
176
180
  return self.last_response
@@ -214,19 +218,17 @@ class PrefindAI(Provider):
214
218
 
215
219
  def get_message(self, response: dict) -> str:
216
220
  """Retrieves message only from response
217
-
218
221
  Args:
219
222
  response (dict): Response generated by `self.ask`
220
-
221
223
  Returns:
222
224
  str: Message extracted
223
225
  """
224
226
  assert isinstance(response, dict), "Response should be of dict data-type only"
225
227
  return response["text"]
226
-
227
- if __name__ == '__main__':
228
+
229
+ if __name__ == "__main__":
228
230
  from rich import print
229
- ai = PrefindAI(model="claude")
230
- response = ai.chat("write a poem about AI", stream=True)
231
+ ai = JadveOpenAI(timeout=5000)
232
+ response = ai.chat("yo what's up", stream=True)
231
233
  for chunk in response:
232
234
  print(chunk, end="", flush=True)