webscout 7.1__py3-none-any.whl → 7.2__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 (144) hide show
  1. webscout/AIauto.py +191 -191
  2. webscout/AIbase.py +122 -122
  3. webscout/AIutel.py +440 -440
  4. webscout/Bard.py +343 -161
  5. webscout/DWEBS.py +489 -492
  6. webscout/Extra/YTToolkit/YTdownloader.py +995 -995
  7. webscout/Extra/YTToolkit/__init__.py +2 -2
  8. webscout/Extra/YTToolkit/transcriber.py +476 -479
  9. webscout/Extra/YTToolkit/ytapi/channel.py +307 -307
  10. webscout/Extra/YTToolkit/ytapi/playlist.py +58 -58
  11. webscout/Extra/YTToolkit/ytapi/pool.py +7 -7
  12. webscout/Extra/YTToolkit/ytapi/utils.py +62 -62
  13. webscout/Extra/YTToolkit/ytapi/video.py +103 -103
  14. webscout/Extra/autocoder/__init__.py +9 -9
  15. webscout/Extra/autocoder/autocoder_utiles.py +199 -199
  16. webscout/Extra/autocoder/rawdog.py +5 -7
  17. webscout/Extra/autollama.py +230 -230
  18. webscout/Extra/gguf.py +3 -3
  19. webscout/Extra/weather.py +171 -171
  20. webscout/LLM.py +442 -442
  21. webscout/Litlogger/__init__.py +67 -681
  22. webscout/Litlogger/core/__init__.py +6 -0
  23. webscout/Litlogger/core/level.py +20 -0
  24. webscout/Litlogger/core/logger.py +123 -0
  25. webscout/Litlogger/handlers/__init__.py +12 -0
  26. webscout/Litlogger/handlers/console.py +50 -0
  27. webscout/Litlogger/handlers/file.py +143 -0
  28. webscout/Litlogger/handlers/network.py +174 -0
  29. webscout/Litlogger/styles/__init__.py +7 -0
  30. webscout/Litlogger/styles/colors.py +231 -0
  31. webscout/Litlogger/styles/formats.py +377 -0
  32. webscout/Litlogger/styles/text.py +87 -0
  33. webscout/Litlogger/utils/__init__.py +6 -0
  34. webscout/Litlogger/utils/detectors.py +154 -0
  35. webscout/Litlogger/utils/formatters.py +200 -0
  36. webscout/Provider/AISEARCH/DeepFind.py +250 -250
  37. webscout/Provider/Blackboxai.py +3 -3
  38. webscout/Provider/ChatGPTGratis.py +226 -0
  39. webscout/Provider/Cloudflare.py +3 -4
  40. webscout/Provider/DeepSeek.py +218 -0
  41. webscout/Provider/Deepinfra.py +3 -3
  42. webscout/Provider/Free2GPT.py +131 -124
  43. webscout/Provider/Gemini.py +100 -115
  44. webscout/Provider/Glider.py +3 -3
  45. webscout/Provider/Groq.py +5 -1
  46. webscout/Provider/Jadve.py +3 -3
  47. webscout/Provider/Marcus.py +191 -192
  48. webscout/Provider/Netwrck.py +3 -3
  49. webscout/Provider/PI.py +2 -2
  50. webscout/Provider/PizzaGPT.py +2 -3
  51. webscout/Provider/QwenLM.py +311 -0
  52. webscout/Provider/TTI/AiForce/__init__.py +22 -22
  53. webscout/Provider/TTI/AiForce/async_aiforce.py +257 -257
  54. webscout/Provider/TTI/AiForce/sync_aiforce.py +242 -242
  55. webscout/Provider/TTI/Nexra/__init__.py +22 -22
  56. webscout/Provider/TTI/Nexra/async_nexra.py +286 -286
  57. webscout/Provider/TTI/Nexra/sync_nexra.py +258 -258
  58. webscout/Provider/TTI/PollinationsAI/__init__.py +23 -23
  59. webscout/Provider/TTI/PollinationsAI/async_pollinations.py +330 -330
  60. webscout/Provider/TTI/PollinationsAI/sync_pollinations.py +285 -285
  61. webscout/Provider/TTI/artbit/__init__.py +22 -22
  62. webscout/Provider/TTI/artbit/async_artbit.py +184 -184
  63. webscout/Provider/TTI/artbit/sync_artbit.py +176 -176
  64. webscout/Provider/TTI/blackbox/__init__.py +4 -4
  65. webscout/Provider/TTI/blackbox/async_blackbox.py +212 -212
  66. webscout/Provider/TTI/blackbox/sync_blackbox.py +199 -199
  67. webscout/Provider/TTI/deepinfra/__init__.py +4 -4
  68. webscout/Provider/TTI/deepinfra/async_deepinfra.py +227 -227
  69. webscout/Provider/TTI/deepinfra/sync_deepinfra.py +199 -199
  70. webscout/Provider/TTI/huggingface/__init__.py +22 -22
  71. webscout/Provider/TTI/huggingface/async_huggingface.py +199 -199
  72. webscout/Provider/TTI/huggingface/sync_huggingface.py +195 -195
  73. webscout/Provider/TTI/imgninza/__init__.py +4 -4
  74. webscout/Provider/TTI/imgninza/async_ninza.py +214 -214
  75. webscout/Provider/TTI/imgninza/sync_ninza.py +209 -209
  76. webscout/Provider/TTI/talkai/__init__.py +4 -4
  77. webscout/Provider/TTI/talkai/async_talkai.py +229 -229
  78. webscout/Provider/TTI/talkai/sync_talkai.py +207 -207
  79. webscout/Provider/TTS/deepgram.py +182 -182
  80. webscout/Provider/TTS/elevenlabs.py +136 -136
  81. webscout/Provider/TTS/gesserit.py +150 -150
  82. webscout/Provider/TTS/murfai.py +138 -138
  83. webscout/Provider/TTS/parler.py +133 -134
  84. webscout/Provider/TTS/streamElements.py +360 -360
  85. webscout/Provider/TTS/utils.py +280 -280
  86. webscout/Provider/TTS/voicepod.py +116 -116
  87. webscout/Provider/TextPollinationsAI.py +2 -3
  88. webscout/Provider/WiseCat.py +193 -0
  89. webscout/Provider/__init__.py +144 -134
  90. webscout/Provider/cerebras.py +242 -227
  91. webscout/Provider/chatglm.py +204 -204
  92. webscout/Provider/dgaf.py +2 -3
  93. webscout/Provider/gaurish.py +2 -3
  94. webscout/Provider/geminiapi.py +208 -208
  95. webscout/Provider/granite.py +223 -0
  96. webscout/Provider/hermes.py +218 -218
  97. webscout/Provider/llama3mitril.py +179 -179
  98. webscout/Provider/llamatutor.py +3 -3
  99. webscout/Provider/llmchat.py +2 -3
  100. webscout/Provider/meta.py +794 -794
  101. webscout/Provider/multichat.py +331 -331
  102. webscout/Provider/typegpt.py +359 -359
  103. webscout/Provider/yep.py +2 -2
  104. webscout/__main__.py +5 -5
  105. webscout/cli.py +319 -319
  106. webscout/conversation.py +241 -242
  107. webscout/exceptions.py +328 -328
  108. webscout/litagent/__init__.py +28 -28
  109. webscout/litagent/agent.py +2 -3
  110. webscout/litprinter/__init__.py +0 -58
  111. webscout/scout/__init__.py +8 -8
  112. webscout/scout/core.py +884 -884
  113. webscout/scout/element.py +459 -459
  114. webscout/scout/parsers/__init__.py +69 -69
  115. webscout/scout/parsers/html5lib_parser.py +172 -172
  116. webscout/scout/parsers/html_parser.py +236 -236
  117. webscout/scout/parsers/lxml_parser.py +178 -178
  118. webscout/scout/utils.py +38 -38
  119. webscout/swiftcli/__init__.py +811 -811
  120. webscout/update_checker.py +2 -12
  121. webscout/version.py +1 -1
  122. webscout/webscout_search.py +5 -4
  123. webscout/zeroart/__init__.py +54 -54
  124. webscout/zeroart/base.py +60 -60
  125. webscout/zeroart/effects.py +99 -99
  126. webscout/zeroart/fonts.py +816 -816
  127. {webscout-7.1.dist-info → webscout-7.2.dist-info}/METADATA +4 -3
  128. webscout-7.2.dist-info/RECORD +217 -0
  129. webstoken/__init__.py +30 -30
  130. webstoken/classifier.py +189 -189
  131. webstoken/keywords.py +216 -216
  132. webstoken/language.py +128 -128
  133. webstoken/ner.py +164 -164
  134. webstoken/normalizer.py +35 -35
  135. webstoken/processor.py +77 -77
  136. webstoken/sentiment.py +206 -206
  137. webstoken/stemmer.py +73 -73
  138. webstoken/tagger.py +60 -60
  139. webstoken/tokenizer.py +158 -158
  140. webscout-7.1.dist-info/RECORD +0 -198
  141. {webscout-7.1.dist-info → webscout-7.2.dist-info}/LICENSE.md +0 -0
  142. {webscout-7.1.dist-info → webscout-7.2.dist-info}/WHEEL +0 -0
  143. {webscout-7.1.dist-info → webscout-7.2.dist-info}/entry_points.txt +0 -0
  144. {webscout-7.1.dist-info → webscout-7.2.dist-info}/top_level.txt +0 -0
@@ -1,19 +1,35 @@
1
- import requests
2
- import uuid
3
- import json
1
+
2
+ #!/usr/bin/env python3
3
+ """
4
+ A merged API client for Free2GPT that supports both GPT and Claude variants
5
+ in a non-streaming manner. The client sends requests to the appropriate endpoint
6
+ based on the chosen variant and returns the complete response as text.
7
+
8
+ Usage:
9
+ python Free2GPT.py
10
+
11
+ Select the variant by passing the 'variant' parameter in the constructor:
12
+ variant="claude" --> Uses https://claude3.free2gpt.xyz/api/generate
13
+ variant="gpt" --> Uses https://chat1.free2gpt.com/api/generate
14
+ """
15
+
16
+ from typing import Optional, Dict
4
17
  import time
18
+ import json
19
+ import requests
5
20
  from hashlib import sha256
6
21
 
7
- from webscout.AIutel import Optimizers
8
- from webscout.AIutel import Conversation
9
- from webscout.AIutel import AwesomePrompts
22
+ from webscout.AIutel import Optimizers, Conversation, AwesomePrompts
10
23
  from webscout.AIbase import Provider
11
24
  from webscout import exceptions
25
+ from webscout.Litlogger import Logger, LogFormat
12
26
  from webscout import LitAgent
13
27
 
28
+
14
29
  class Free2GPT(Provider):
15
30
  """
16
- A class to interact with the Free2GPT API.
31
+ A class to interact with the Free2GPT API in a non-streaming way.
32
+ Supports both GPT and Claude variants via the 'variant' parameter.
17
33
  """
18
34
 
19
35
  def __init__(
@@ -21,35 +37,43 @@ class Free2GPT(Provider):
21
37
  is_conversation: bool = True,
22
38
  max_tokens: int = 600,
23
39
  timeout: int = 30,
24
- intro: str = None,
25
- filepath: str = None,
40
+ intro: Optional[str] = None,
41
+ filepath: Optional[str] = None,
26
42
  update_file: bool = True,
27
43
  proxies: dict = {},
28
44
  history_offset: int = 10250,
29
- act: str = None,
45
+ act: Optional[str] = None,
30
46
  system_prompt: str = "You are a helpful AI assistant.",
47
+ variant: str = "claude" # "claude" or "gpt"
31
48
  ):
32
49
  """
33
- Initializes the Free2GPT API with given parameters.
50
+ Initializes the Free2GPT API client.
34
51
 
35
52
  Args:
36
- is_conversation (bool, optional): Flag for chatting conversationally. Defaults to True.
37
- max_tokens (int, optional): Maximum number of tokens to be generated upon completion. Defaults to 600.
38
- timeout (int, optional): Http request timeout. Defaults to 30.
39
- intro (str, optional): Conversation introductory prompt. Defaults to None.
40
- filepath (str, optional): Path to file containing conversation history. Defaults to None.
41
- update_file (bool, optional): Add new prompts and responses to the file. Defaults to True.
42
- proxies (dict, optional): Http request proxies. Defaults to {}.
43
- history_offset (int, optional): Limit conversation history to this number of last texts. Defaults to 10250.
44
- act (str|int, optional): Awesome prompt key or index. (Used as intro). Defaults to None.
45
- system_prompt (str, optional): System prompt for Free2GPT.
46
- Defaults to "You are a helpful AI assistant.".
53
+ is_conversation (bool): Enable conversational mode. Defaults to True.
54
+ max_tokens (int): Maximum tokens to generate. Defaults to 600.
55
+ timeout (int): HTTP request timeout. Defaults to 30.
56
+ intro (str, optional): Introductory prompt for the conversation. Defaults to None.
57
+ filepath (str, optional): Path to conversation history file. Defaults to None.
58
+ update_file (bool): Whether to update the conversation file. Defaults to True.
59
+ proxies (dict): HTTP proxy settings. Defaults to empty dict.
60
+ history_offset (int): Limit for conversation history. Defaults to 10250.
61
+ act (str, optional): Awesome prompt key/index. Defaults to None.
62
+ system_prompt (str): System prompt. Defaults to "You are a helpful AI assistant.".
63
+ variant (str): Select API variant: "claude" or "gpt". Defaults to "claude".
47
64
  """
48
65
  self.session = requests.Session()
49
66
  self.is_conversation = is_conversation
50
67
  self.max_tokens_to_sample = max_tokens
51
- self.api_endpoint = "https://chat1.free2gpt.com/api/generate"
52
- self.stream_chunk_size = 64
68
+
69
+ # Select API endpoint and header origins based on variant.
70
+ if variant.lower() == "gpt":
71
+ self.api_endpoint = "https://chat1.free2gpt.com/api/generate"
72
+ origin = "https://chat1.free2gpt.co"
73
+ else:
74
+ self.api_endpoint = "https://claude3.free2gpt.xyz/api/generate"
75
+ origin = "https://claude3.free2gpt.xyz"
76
+
53
77
  self.timeout = timeout
54
78
  self.last_response = {}
55
79
  self.system_prompt = system_prompt
@@ -59,8 +83,8 @@ class Free2GPT(Provider):
59
83
  "accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
60
84
  "content-type": "text/plain;charset=UTF-8",
61
85
  "dnt": "1",
62
- "origin": "https://chat1.free2gpt.co",
63
- "referer": "https://chat1.free2gpt.co",
86
+ "origin": origin,
87
+ "referer": origin,
64
88
  "sec-ch-ua": '"Chromium";v="128", "Not;A=Brand";v="24", "Microsoft Edge";v="128"',
65
89
  "sec-ch-ua-mobile": "?0",
66
90
  "sec-ch-ua-platform": '"Windows"',
@@ -69,13 +93,16 @@ class Free2GPT(Provider):
69
93
  "sec-fetch-site": "same-origin",
70
94
  "user-agent": LitAgent().random(),
71
95
  }
96
+ self.session.headers.update(self.headers)
97
+ self.session.proxies = proxies
72
98
 
99
+ # Prepare available optimizers from Optimizers module.
73
100
  self.__available_optimizers = (
74
101
  method
75
102
  for method in dir(Optimizers)
76
103
  if callable(getattr(Optimizers, method)) and not method.startswith("__")
77
104
  )
78
- self.session.headers.update(self.headers)
105
+
79
106
  Conversation.intro = (
80
107
  AwesomePrompts().get_act(
81
108
  act, raise_not_found=True, default=None, case_insensitive=True
@@ -83,39 +110,48 @@ class Free2GPT(Provider):
83
110
  if act
84
111
  else intro or Conversation.intro
85
112
  )
86
- self.conversation = Conversation(
87
- is_conversation, self.max_tokens_to_sample, filepath, update_file
88
- )
113
+ self.conversation = Conversation(is_conversation, self.max_tokens_to_sample, filepath, update_file)
89
114
  self.conversation.history_offset = history_offset
90
- self.session.proxies = proxies
91
115
 
92
- def generate_signature(self, time: int, text: str, secret: str = ""):
93
- message = f"{time}:{text}:{secret}"
116
+ def generate_signature(self, time_val: int, text: str, secret: str = "") -> str:
117
+ """
118
+ Generates a signature for the request.
119
+
120
+ Args:
121
+ time_val (int): Timestamp value.
122
+ text (str): Text to sign.
123
+ secret (str, optional): Optional secret. Defaults to "".
124
+
125
+ Returns:
126
+ str: Hexadecimal signature.
127
+ """
128
+ message = f"{time_val}:{text}:{secret}"
94
129
  return sha256(message.encode()).hexdigest()
95
130
 
96
131
  def ask(
97
132
  self,
98
133
  prompt: str,
99
- stream: bool = False,
134
+ stream: bool = False, # Ignored; always non-streaming.
100
135
  raw: bool = False,
101
- optimizer: str = None,
136
+ optimizer: Optional[str] = None,
102
137
  conversationally: bool = False,
103
- ) -> dict:
104
- """Chat with AI
138
+ ) -> Dict[str, any]:
139
+ """
140
+ Sends a prompt to the API in a non-streaming manner.
105
141
 
106
142
  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]`. Defaults to None.
111
- conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
143
+ prompt (str): The prompt text.
144
+ stream (bool): Ignored; response is always non-streamed.
145
+ raw (bool): Whether to return the raw response. Defaults to False.
146
+ optimizer (str, optional): Optimizer name. Defaults to None.
147
+ conversationally (bool): Whether to use conversational optimization. Defaults to False.
148
+
112
149
  Returns:
113
- dict : {}
114
- ```json
115
- {
116
- "text" : "How may I assist you today?"
117
- }
118
- ```
150
+ dict: A dictionary containing the generated text.
151
+ Example:
152
+ {
153
+ "text": "How may I assist you today?"
154
+ }
119
155
  """
120
156
  conversation_prompt = self.conversation.gen_complete_prompt(prompt)
121
157
  if optimizer:
@@ -124,111 +160,82 @@ class Free2GPT(Provider):
124
160
  conversation_prompt if conversationally else prompt
125
161
  )
126
162
  else:
127
- raise Exception(
128
- f"Optimizer is not one of {self.__available_optimizers}"
129
- )
163
+ raise Exception(f"Optimizer is not one of {list(self.__available_optimizers)}")
130
164
 
131
- # Generate timestamp
165
+ # Generate timestamp and signature.
132
166
  timestamp = int(time.time() * 1e3)
133
-
134
- # Generate signature
135
167
  signature = self.generate_signature(timestamp, conversation_prompt)
136
168
 
137
169
  payload = {
138
170
  "messages": [
139
- {
140
- "role": "system",
141
- "content": self.system_prompt
142
- },
143
- {
144
- "role": "user",
145
- "content": conversation_prompt
146
- }
171
+ {"role": "system", "content": self.system_prompt},
172
+ {"role": "user", "content": conversation_prompt},
147
173
  ],
148
174
  "time": timestamp,
149
175
  "pass": None,
150
- "sign": signature
176
+ "sign": signature,
151
177
  }
152
178
 
153
- def for_stream():
154
- try:
155
- # Send the POST request with streaming enabled
156
- with requests.post(self.api_endpoint, headers=self.headers, data=json.dumps(payload), stream=True) as response:
157
- response.raise_for_status()
158
-
159
- full_response = ""
160
- for chunk in response.iter_content(chunk_size=self.stream_chunk_size):
161
- if chunk:
162
- full_response += chunk.decode('utf-8')
163
- yield chunk.decode('utf-8') if raw else dict(text=chunk.decode('utf-8'))
164
-
165
- self.last_response.update(dict(text=full_response))
166
- self.conversation.update_chat_history(
167
- prompt, self.get_message(self.last_response)
168
- )
169
-
170
- except requests.exceptions.RequestException as e:
171
- raise exceptions.FailedToGenerateResponseError(f"An error occurred: {e}")
172
-
173
- def for_non_stream():
174
- for _ in for_stream():
175
- pass
179
+ try:
180
+ response = requests.post(
181
+ self.api_endpoint,
182
+ headers=self.headers,
183
+ data=json.dumps(payload),
184
+ timeout=self.timeout
185
+ )
186
+ response.raise_for_status()
187
+ full_response = response.text
188
+ self.last_response.update(dict(text=full_response))
189
+ self.conversation.update_chat_history(prompt, self.get_message(self.last_response))
176
190
  return self.last_response
177
-
178
- return for_stream() if stream else for_non_stream()
191
+ except requests.exceptions.RequestException as e:
192
+ raise exceptions.FailedToGenerateResponseError(f"An error occurred: {e}")
179
193
 
180
194
  def chat(
181
195
  self,
182
196
  prompt: str,
183
- stream: bool = False,
184
- optimizer: str = None,
197
+ stream: bool = False, # Ignored; always non-streaming.
198
+ optimizer: Optional[str] = None,
185
199
  conversationally: bool = False,
186
200
  ) -> str:
187
- """Generate response `str`
188
- Args:
189
- prompt (str): Prompt to be send.
190
- stream (bool, optional): Flag for streaming response. Defaults to False.
191
- optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`. Defaults to None.
192
- conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
193
- Returns:
194
- str: Response generated
195
201
  """
202
+ Sends a prompt and returns the generated response as a string.
196
203
 
197
- def for_stream():
198
- for response in self.ask(
199
- prompt, True, optimizer=optimizer, conversationally=conversationally
200
- ):
201
- yield self.get_message(response)
202
-
203
- def for_non_stream():
204
- return self.get_message(
205
- self.ask(
206
- prompt,
207
- False,
208
- optimizer=optimizer,
209
- conversationally=conversationally,
210
- )
211
- )
204
+ Args:
205
+ prompt (str): The prompt to send.
206
+ stream (bool): Ignored; response is always non-streamed.
207
+ optimizer (str, optional): Optimizer name. Defaults to None.
208
+ conversationally (bool): Whether to use conversational optimization. Defaults to False.
212
209
 
213
- return for_stream() if stream else for_non_stream()
210
+ Returns:
211
+ str: Generated response.
212
+ """
213
+ response = self.ask(
214
+ prompt,
215
+ stream=False,
216
+ optimizer=optimizer,
217
+ conversationally=conversationally,
218
+ )
219
+ return self.get_message(response)
214
220
 
215
- def get_message(self, response: dict) -> str:
216
- """Retrieves message only from response
221
+ def get_message(self, response: Dict[str, any]) -> str:
222
+ """
223
+ Extracts the message text from the API response.
217
224
 
218
225
  Args:
219
- response (dict): Response generated by `self.ask`
226
+ response (dict): The API response.
220
227
 
221
228
  Returns:
222
- str: Message extracted
229
+ str: Extracted message text.
223
230
  """
224
- assert isinstance(response, dict), "Response should be of dict data-type only"
231
+ assert isinstance(response, dict), "Response should be a dictionary"
225
232
  return response["text"].replace('\\n', '\n').replace('\\n\\n', '\n\n')
226
233
 
227
234
 
228
235
  if __name__ == "__main__":
229
236
  from rich import print
230
-
231
- ai = Free2GPT(timeout=5000)
232
- response = ai.chat("write a poem about AI", stream=True)
233
- for chunk in response:
234
- print(chunk, end="", flush=True)
237
+ prompt_input = input(">>> ")
238
+ # Choose variant: "claude" or "gpt"
239
+ client = Free2GPT(variant="gpt")
240
+ result = client.chat(prompt_input)
241
+ print(result)
@@ -1,61 +1,90 @@
1
- from ..AIutel import Optimizers
2
- from ..AIutel import Conversation
3
- from ..AIutel import AwesomePrompts, sanitize_stream
4
- from ..AIbase import Provider, AsyncProvider
5
- from webscout import exceptions
6
- from typing import Any, AsyncGenerator, Dict
7
- import logging
8
- from ..Bard import Chatbot
9
- import logging
1
+
10
2
  from os import path
11
- from json import load
12
- from json import dumps
3
+ from json import load, dumps
13
4
  import warnings
14
- logging.getLogger("httpx").setLevel(logging.ERROR)
5
+ from typing import Any, Dict
6
+
7
+ # Import internal modules and dependencies
8
+ from ..AIutel import Optimizers, Conversation, AwesomePrompts, sanitize_stream
9
+ from ..AIbase import Provider, AsyncProvider
10
+ from ..Bard import Chatbot, Model
11
+
12
+ # Import Logger and related classes (assumed similar to what is in yep.py)
13
+ from webscout import Logger, LogFormat
14
+
15
15
  warnings.simplefilter("ignore", category=UserWarning)
16
+
17
+ # Define model aliases for easy usage
18
+ MODEL_ALIASES: Dict[str, Model] = {
19
+ "unspecified": Model.UNSPECIFIED,
20
+ "flash": Model.G_2_0_FLASH,
21
+ "flash-exp": Model.G_2_0_FLASH_EXP,
22
+ "thinking": Model.G_2_0_FLASH_THINKING,
23
+ "thinking-with-apps": Model.G_2_0_FLASH_THINKING_WITH_APPS,
24
+ "exp-advanced": Model.G_2_0_EXP_ADVANCED,
25
+ "1.5-flash": Model.G_1_5_FLASH,
26
+ "1.5-pro": Model.G_1_5_PRO,
27
+ "1.5-pro-research": Model.G_1_5_PRO_RESEARCH,
28
+ }
29
+
30
+ # List of available models (friendly names)
31
+ AVAILABLE_MODELS = list(MODEL_ALIASES.keys())
32
+
16
33
  class GEMINI(Provider):
17
34
  def __init__(
18
35
  self,
19
36
  cookie_file: str,
37
+ model, # Accepts either a Model enum or a str alias.
20
38
  proxy: dict = {},
21
39
  timeout: int = 30,
40
+ logging: bool = False # Flag to enable Logger debugging.
22
41
  ):
23
- """Initializes GEMINI
42
+ """
43
+ Initializes GEMINI with model support and optional debugging.
24
44
 
25
45
  Args:
26
- cookie_file (str): Path to `bard.google.com.cookies.json` file
27
- proxy (dict, optional): Http request proxy. Defaults to {}.
28
- timeout (int, optional): Http request timeout. Defaults to 30.
46
+ cookie_file (str): Path to the cookies JSON file.
47
+ model (Model or str): Selected model for the session. Can be a Model enum
48
+ or a string alias. Available aliases: flash, flash-exp, thinking, thinking-with-apps,
49
+ exp-advanced, 1.5-flash, 1.5-pro, 1.5-pro-research.
50
+ proxy (dict, optional): HTTP request proxy. Defaults to {}.
51
+ timeout (int, optional): HTTP request timeout in seconds. Defaults to 30.
52
+ logging (bool, optional): Flag to enable Logger debugging. Defaults to False.
29
53
  """
30
54
  self.conversation = Conversation(False)
31
- self.session_auth1 = None
32
- self.session_auth2 = None
33
- assert isinstance(
34
- cookie_file, str
35
- ), f"cookie_file should be of {str} only not '{type(cookie_file)}'"
36
- if path.isfile(cookie_file):
37
- # let's assume auth is a path to exported .json cookie-file
38
- with open(cookie_file) as fh:
39
- entries = load(fh)
40
- for entry in entries:
41
- if entry["name"] == "__Secure-1PSID":
42
- self.session_auth1 = entry["value"]
43
- elif entry["name"] == "__Secure-1PSIDTS":
44
- self.session_auth2 = entry["value"]
45
-
46
- assert all(
47
- [self.session_auth1, self.session_auth2]
48
- ), f"Failed to extract the required cookie value from file '{cookie_file}'"
49
- else:
55
+
56
+ # Initialize Logger only if logging is enabled; otherwise, set to None.
57
+ self.logger = Logger(name="GEMINI", format=LogFormat.MODERN_EMOJI) if logging else None
58
+
59
+ # Ensure cookie_file existence.
60
+ if not isinstance(cookie_file, str):
61
+ raise TypeError(f"cookie_file should be of type str, not '{type(cookie_file)}'")
62
+ if not path.isfile(cookie_file):
50
63
  raise Exception(f"{cookie_file} is not a valid file path")
51
64
 
52
- self.session = Chatbot(self.session_auth1, self.session_auth2, proxy, timeout)
65
+ # If model is provided as alias (str), convert to Model enum.
66
+ if isinstance(model, str):
67
+ alias = model.lower()
68
+ if alias in MODEL_ALIASES:
69
+ selected_model = MODEL_ALIASES[alias]
70
+ else:
71
+ raise Exception(f"Unknown model alias: '{model}'. Available aliases: {', '.join(AVAILABLE_MODELS)}")
72
+ elif isinstance(model, Model):
73
+ selected_model = model
74
+ else:
75
+ raise TypeError("model must be a string alias or an instance of Model")
76
+
77
+ # Initialize the Chatbot session using the cookie file.
78
+ self.session = Chatbot(cookie_file, proxy, timeout, selected_model)
53
79
  self.last_response = {}
54
80
  self.__available_optimizers = (
55
- method
56
- for method in dir(Optimizers)
57
- if callable(getattr(Optimizers, method)) and not method.startswith("__")
81
+ method for method in dir(Optimizers) if callable(getattr(Optimizers, method)) and not method.startswith("__")
58
82
  )
83
+ if self.logger:
84
+ self.logger.debug("GEMINI initialized with model: {}".format(selected_model.model_name))
85
+ # Store cookies from Chatbot for later use (e.g. image generation)
86
+ self.session_auth1 = self.session.secure_1psid
87
+ self.session_auth2 = self.session.secure_1psidts
59
88
 
60
89
  def ask(
61
90
  self,
@@ -65,53 +94,17 @@ class GEMINI(Provider):
65
94
  optimizer: str = None,
66
95
  conversationally: bool = False,
67
96
  ) -> dict:
68
- """Chat with AI
69
-
70
- Args:
71
- prompt (str): Prompt to be send.
72
- stream (bool, optional): Flag for streaming response. Defaults to False.
73
- raw (bool, optional): Stream back raw response as received. Defaults to False.
74
- optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`. Defeaults to None
75
- conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
76
- Returns:
77
- dict : {}
78
- ```json
79
- {
80
- "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]",
81
- "conversation_id": "c_f13f6217f9a997aa",
82
- "response_id": "r_d3665f95975c368f",
83
- "factualityQueries": null,
84
- "textQuery": [
85
- "hello there",
86
- 1
87
- ],
88
- "choices": [
89
- {
90
- "id": "rc_ea075c9671bfd8cb",
91
- "content": [
92
- "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]"
93
- ]
94
- },
95
- {
96
- "id": "rc_de6dd3fb793a5402",
97
- "content": [
98
- "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"
99
- ]
100
- },
101
- {
102
- "id": "rc_a672ac089caf32db",
103
- "content": [
104
- "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]"
105
- ]
106
- }
107
- ],
108
-
109
- "images": [
110
- "https://i.pinimg.com/originals/40/74/60/407460925c9e419d82b93313f0b42f71.jpg"
111
- ]
112
- }
113
-
114
- ```
97
+ """Chat with AI.
98
+
99
+ Args:
100
+ prompt (str): Prompt to be sent.
101
+ stream (bool, optional): Flag for streaming response. Defaults to False.
102
+ raw (bool, optional): Stream back raw response as received. Defaults to False.
103
+ optimizer (str, optional): Prompt optimizer name (e.g., 'code', 'shell_command'). Defaults to None.
104
+ conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
105
+
106
+ Returns:
107
+ dict: Response generated by the underlying Chatbot.
115
108
  """
116
109
  conversation_prompt = self.conversation.gen_complete_prompt(prompt)
117
110
  if optimizer:
@@ -120,24 +113,21 @@ class GEMINI(Provider):
120
113
  conversation_prompt if conversationally else prompt
121
114
  )
122
115
  else:
123
- raise Exception(
124
- f"Optimizer is not one of {self.__available_optimizers}"
125
- )
116
+ raise Exception(f"Optimizer is not one of {', '.join(self.__available_optimizers)}")
126
117
 
127
118
  def for_stream():
128
119
  response = self.session.ask(prompt)
129
120
  self.last_response.update(response)
130
- self.conversation.update_chat_history(
131
- prompt, self.get_message(self.last_response)
132
- )
121
+ self.conversation.update_chat_history(prompt, self.get_message(self.last_response))
133
122
  yield dumps(response) if raw else response
134
123
 
135
124
  def for_non_stream():
136
- # let's make use of stream
137
125
  for _ in for_stream():
138
126
  pass
139
127
  return self.last_response
140
128
 
129
+ if self.logger:
130
+ self.logger.debug(f"Request sent: {prompt}")
141
131
  return for_stream() if stream else for_non_stream()
142
132
 
143
133
  def chat(
@@ -147,48 +137,43 @@ class GEMINI(Provider):
147
137
  optimizer: str = None,
148
138
  conversationally: bool = False,
149
139
  ) -> str:
150
- """Generate response `str`
140
+ """Generate response text.
141
+
151
142
  Args:
152
- prompt (str): Prompt to be send.
143
+ prompt (str): Prompt to be sent.
153
144
  stream (bool, optional): Flag for streaming response. Defaults to False.
154
- optimizer (str, optional): Prompt optimizer name - `[code, shell_command]`. Defaults to None.
145
+ optimizer (str, optional): Prompt optimizer name. Defaults to None.
155
146
  conversationally (bool, optional): Chat conversationally when using optimizer. Defaults to False.
147
+
156
148
  Returns:
157
- str: Response generated
149
+ str: Response generated.
158
150
  """
159
-
160
151
  def for_stream():
161
- for response in self.ask(
162
- prompt, True, optimizer=optimizer, conversationally=conversationally
163
- ):
152
+ for response in self.ask(prompt, True, optimizer=optimizer, conversationally=conversationally):
164
153
  yield self.get_message(response)
165
154
 
166
155
  def for_non_stream():
167
- return self.get_message(
168
- self.ask(
169
- prompt,
170
- False,
171
- optimizer=optimizer,
172
- conversationally=conversationally,
173
- )
174
- )
156
+ return self.get_message(self.ask(prompt, False, optimizer=optimizer, conversationally=conversationally))
175
157
 
176
158
  return for_stream() if stream else for_non_stream()
177
159
 
178
160
  def get_message(self, response: dict) -> str:
179
- """Retrieves message only from response
161
+ """Retrieves message content from the response.
180
162
 
181
163
  Args:
182
- response (dict): Response generated by `self.ask`
164
+ response (dict): Response generated by `self.ask`.
183
165
 
184
166
  Returns:
185
- str: Message extracted
167
+ str: Extracted message content.
186
168
  """
187
- assert isinstance(response, dict), "Response should be of dict data-type only"
169
+ if not isinstance(response, dict):
170
+ raise TypeError("Response should be of type dict")
188
171
  return response["content"]
189
172
 
190
173
  def reset(self):
191
- """Reset the current conversation"""
174
+ """Reset the current conversation."""
192
175
  self.session.async_chatbot.conversation_id = ""
193
176
  self.session.async_chatbot.response_id = ""
194
- self.session.async_chatbot.choice_id = ""
177
+ self.session.async_chatbot.choice_id = ""
178
+ if self.logger:
179
+ self.logger.debug("Conversation reset")