webscout 8.2.9__py3-none-any.whl → 8.3.1__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 (100) hide show
  1. webscout/AIauto.py +6 -6
  2. webscout/AIbase.py +61 -1
  3. webscout/Extra/YTToolkit/ytapi/patterns.py +45 -45
  4. webscout/Extra/YTToolkit/ytapi/stream.py +1 -1
  5. webscout/Extra/YTToolkit/ytapi/video.py +10 -10
  6. webscout/Extra/autocoder/autocoder_utiles.py +1 -1
  7. webscout/Litlogger/formats.py +9 -0
  8. webscout/Litlogger/handlers.py +18 -0
  9. webscout/Litlogger/logger.py +43 -1
  10. webscout/Provider/AISEARCH/scira_search.py +3 -2
  11. webscout/Provider/Blackboxai.py +2 -0
  12. webscout/Provider/ChatSandbox.py +2 -1
  13. webscout/Provider/Deepinfra.py +1 -1
  14. webscout/Provider/HeckAI.py +1 -1
  15. webscout/Provider/LambdaChat.py +8 -1
  16. webscout/Provider/MCPCore.py +7 -3
  17. webscout/Provider/OPENAI/BLACKBOXAI.py +396 -113
  18. webscout/Provider/OPENAI/Cloudflare.py +31 -14
  19. webscout/Provider/OPENAI/FalconH1.py +457 -0
  20. webscout/Provider/OPENAI/FreeGemini.py +29 -13
  21. webscout/Provider/OPENAI/NEMOTRON.py +26 -14
  22. webscout/Provider/OPENAI/PI.py +427 -0
  23. webscout/Provider/OPENAI/Qwen3.py +161 -140
  24. webscout/Provider/OPENAI/README.md +3 -0
  25. webscout/Provider/OPENAI/TogetherAI.py +355 -0
  26. webscout/Provider/OPENAI/TwoAI.py +29 -12
  27. webscout/Provider/OPENAI/__init__.py +4 -1
  28. webscout/Provider/OPENAI/ai4chat.py +33 -23
  29. webscout/Provider/OPENAI/api.py +375 -24
  30. webscout/Provider/OPENAI/autoproxy.py +39 -0
  31. webscout/Provider/OPENAI/base.py +91 -12
  32. webscout/Provider/OPENAI/c4ai.py +31 -10
  33. webscout/Provider/OPENAI/chatgpt.py +56 -24
  34. webscout/Provider/OPENAI/chatgptclone.py +46 -16
  35. webscout/Provider/OPENAI/chatsandbox.py +7 -3
  36. webscout/Provider/OPENAI/copilot.py +26 -10
  37. webscout/Provider/OPENAI/deepinfra.py +29 -12
  38. webscout/Provider/OPENAI/e2b.py +358 -158
  39. webscout/Provider/OPENAI/exaai.py +13 -10
  40. webscout/Provider/OPENAI/exachat.py +10 -6
  41. webscout/Provider/OPENAI/flowith.py +7 -3
  42. webscout/Provider/OPENAI/freeaichat.py +10 -6
  43. webscout/Provider/OPENAI/glider.py +10 -6
  44. webscout/Provider/OPENAI/heckai.py +11 -8
  45. webscout/Provider/OPENAI/llmchatco.py +9 -7
  46. webscout/Provider/OPENAI/mcpcore.py +10 -7
  47. webscout/Provider/OPENAI/multichat.py +3 -1
  48. webscout/Provider/OPENAI/netwrck.py +10 -6
  49. webscout/Provider/OPENAI/oivscode.py +12 -9
  50. webscout/Provider/OPENAI/opkfc.py +31 -8
  51. webscout/Provider/OPENAI/scirachat.py +17 -10
  52. webscout/Provider/OPENAI/sonus.py +10 -6
  53. webscout/Provider/OPENAI/standardinput.py +18 -9
  54. webscout/Provider/OPENAI/textpollinations.py +14 -7
  55. webscout/Provider/OPENAI/toolbaz.py +16 -11
  56. webscout/Provider/OPENAI/typefully.py +14 -7
  57. webscout/Provider/OPENAI/typegpt.py +10 -6
  58. webscout/Provider/OPENAI/uncovrAI.py +22 -8
  59. webscout/Provider/OPENAI/venice.py +10 -6
  60. webscout/Provider/OPENAI/writecream.py +13 -10
  61. webscout/Provider/OPENAI/x0gpt.py +11 -9
  62. webscout/Provider/OPENAI/yep.py +12 -10
  63. webscout/Provider/PI.py +2 -1
  64. webscout/Provider/STT/__init__.py +3 -0
  65. webscout/Provider/STT/base.py +281 -0
  66. webscout/Provider/STT/elevenlabs.py +265 -0
  67. webscout/Provider/TTI/__init__.py +3 -1
  68. webscout/Provider/TTI/aiarta.py +399 -365
  69. webscout/Provider/TTI/base.py +74 -2
  70. webscout/Provider/TTI/fastflux.py +63 -30
  71. webscout/Provider/TTI/gpt1image.py +149 -0
  72. webscout/Provider/TTI/imagen.py +196 -0
  73. webscout/Provider/TTI/magicstudio.py +60 -29
  74. webscout/Provider/TTI/piclumen.py +43 -32
  75. webscout/Provider/TTI/pixelmuse.py +232 -225
  76. webscout/Provider/TTI/pollinations.py +43 -32
  77. webscout/Provider/TTI/together.py +287 -0
  78. webscout/Provider/TTI/utils.py +2 -1
  79. webscout/Provider/TTS/README.md +1 -0
  80. webscout/Provider/TTS/__init__.py +2 -1
  81. webscout/Provider/TTS/freetts.py +140 -0
  82. webscout/Provider/UNFINISHED/ChutesAI.py +314 -0
  83. webscout/Provider/UNFINISHED/fetch_together_models.py +95 -0
  84. webscout/Provider/__init__.py +3 -2
  85. webscout/Provider/granite.py +41 -6
  86. webscout/Provider/oivscode.py +37 -37
  87. webscout/Provider/scira_chat.py +3 -2
  88. webscout/Provider/scnet.py +1 -0
  89. webscout/Provider/toolbaz.py +0 -1
  90. webscout/litagent/Readme.md +12 -3
  91. webscout/litagent/agent.py +99 -62
  92. webscout/version.py +1 -1
  93. {webscout-8.2.9.dist-info → webscout-8.3.1.dist-info}/METADATA +2 -1
  94. {webscout-8.2.9.dist-info → webscout-8.3.1.dist-info}/RECORD +98 -87
  95. {webscout-8.2.9.dist-info → webscout-8.3.1.dist-info}/WHEEL +1 -1
  96. webscout/Provider/ChatGPTGratis.py +0 -194
  97. webscout/Provider/TTI/artbit.py +0 -0
  98. {webscout-8.2.9.dist-info → webscout-8.3.1.dist-info}/entry_points.txt +0 -0
  99. {webscout-8.2.9.dist-info → webscout-8.3.1.dist-info}/licenses/LICENSE.md +0 -0
  100. {webscout-8.2.9.dist-info → webscout-8.3.1.dist-info}/top_level.txt +0 -0
webscout/AIauto.py CHANGED
@@ -6,7 +6,7 @@ API keys or cookies.
6
6
 
7
7
  from webscout.AIbase import Provider
8
8
  from webscout.exceptions import AllProvidersFailure
9
- from typing import Union, Any, Dict, Generator
9
+ from typing import Union, Any, Dict, Generator, Optional
10
10
  import importlib
11
11
  import pkgutil
12
12
  import random
@@ -45,8 +45,8 @@ def load_providers():
45
45
  api_key_providers.add(attr_name.upper())
46
46
  if 'cookie_file' in sig or 'cookie_path' in sig:
47
47
  cookie_providers.add(attr_name.upper())
48
- except Exception:
49
- pass
48
+ except Exception as e:
49
+ print(f"Error loading provider {module_name}: {e}")
50
50
  return provider_map, api_key_providers.union(cookie_providers)
51
51
 
52
52
  provider_map, api_key_providers = load_providers()
@@ -71,7 +71,7 @@ class AUTO(Provider):
71
71
  proxies: dict = {},
72
72
  history_offset: int = 10250,
73
73
  act: str = None,
74
- exclude: list[str] = [],
74
+ exclude: Optional[list[str]] = None,
75
75
  print_provider_info: bool = False,
76
76
  ):
77
77
  """
@@ -90,7 +90,7 @@ class AUTO(Provider):
90
90
  proxies (dict): Proxies for requests. Defaults to {}.
91
91
  history_offset (int): History character offset limit. Defaults to 10250.
92
92
  act (str, optional): Awesome prompt key. Defaults to None.
93
- exclude (list[str]): List of provider names (uppercase) to exclude. Defaults to [].
93
+ exclude (Optional[list[str]]): List of provider names (uppercase) to exclude. Defaults to None.
94
94
  print_provider_info (bool): Whether to print the name of the successful provider. Defaults to False.
95
95
  """
96
96
  self.provider = None # type: Provider
@@ -104,7 +104,7 @@ class AUTO(Provider):
104
104
  self.proxies: dict = proxies
105
105
  self.history_offset: int = history_offset
106
106
  self.act: str = act
107
- self.exclude: list[str] = [e.upper() for e in exclude]
107
+ self.exclude: list[str] = [e.upper() for e in exclude] if exclude else []
108
108
  self.print_provider_info: bool = print_provider_info
109
109
 
110
110
 
webscout/AIbase.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from abc import ABC, abstractmethod
2
2
  from pathlib import Path
3
- from typing import AsyncGenerator, Dict, List, Union, Generator, Optional
3
+ from typing import AsyncGenerator, Dict, List, Union, Generator, Optional, Any
4
4
  from typing_extensions import TypeAlias
5
5
 
6
6
  # Type aliases for better readability
@@ -178,6 +178,66 @@ class AsyncTTSProvider(ABC):
178
178
  """
179
179
  raise NotImplementedError("Method needs to be implemented in subclass")
180
180
 
181
+
182
+ class STTProvider(ABC):
183
+ """Abstract base class for Speech-to-Text providers."""
184
+
185
+ @abstractmethod
186
+ def transcribe(self, audio_path: Union[str, Path], **kwargs) -> Dict[str, Any]:
187
+ """Transcribe audio file to text.
188
+
189
+ Args:
190
+ audio_path (Union[str, Path]): Path to the audio file
191
+ **kwargs: Additional provider-specific parameters
192
+
193
+ Returns:
194
+ Dict[str, Any]: Transcription result in OpenAI Whisper format
195
+ """
196
+ raise NotImplementedError("Method needs to be implemented in subclass")
197
+
198
+ @abstractmethod
199
+ def transcribe_from_url(self, audio_url: str, **kwargs) -> Dict[str, Any]:
200
+ """Transcribe audio from URL to text.
201
+
202
+ Args:
203
+ audio_url (str): URL of the audio file
204
+ **kwargs: Additional provider-specific parameters
205
+
206
+ Returns:
207
+ Dict[str, Any]: Transcription result in OpenAI Whisper format
208
+ """
209
+ raise NotImplementedError("Method needs to be implemented in subclass")
210
+
211
+
212
+ class AsyncSTTProvider(ABC):
213
+ """Abstract base class for asynchronous Speech-to-Text providers."""
214
+
215
+ @abstractmethod
216
+ async def transcribe(self, audio_path: Union[str, Path], **kwargs) -> Dict[str, Any]:
217
+ """Transcribe audio file to text asynchronously.
218
+
219
+ Args:
220
+ audio_path (Union[str, Path]): Path to the audio file
221
+ **kwargs: Additional provider-specific parameters
222
+
223
+ Returns:
224
+ Dict[str, Any]: Transcription result in OpenAI Whisper format
225
+ """
226
+ raise NotImplementedError("Method needs to be implemented in subclass")
227
+
228
+ @abstractmethod
229
+ async def transcribe_from_url(self, audio_url: str, **kwargs) -> Dict[str, Any]:
230
+ """Transcribe audio from URL to text asynchronously.
231
+
232
+ Args:
233
+ audio_url (str): URL of the audio file
234
+ **kwargs: Additional provider-specific parameters
235
+
236
+ Returns:
237
+ Dict[str, Any]: Transcription result in OpenAI Whisper format
238
+ """
239
+ raise NotImplementedError("Method needs to be implemented in subclass")
240
+
181
241
  async def save_audio(self, audio_file: str, destination: str = None, verbose: bool = False) -> str:
182
242
  """Save audio to a specific destination asynchronously.
183
243
 
@@ -2,60 +2,60 @@ import re
2
2
 
3
3
 
4
4
  class _ChannelPatterns:
5
- name = re.compile('channelMetadataRenderer\":{\"title\":\"(.*?)\"')
6
- id = re.compile('channelId\":\"(.*?)\"')
7
- verified = re.compile('"label":"Verified"')
8
- check_live = re.compile('{"text":"LIVE"}')
9
- live = re.compile("thumbnailOverlays\":\[(.*?)]")
10
- video_id = re.compile('videoId\":\"(.*?)\"')
11
- uploads = re.compile("gridVideoRenderer\":{\"videoId\":\"(.*?)\"")
12
- subscribers = re.compile("\"subscriberCountText\":{\"accessibility\":(.*?),")
13
- views = re.compile("viewCountText\":{\"simpleText\":\"(.*?)\"}")
14
- creation = re.compile("{\"text\":\"Joined \"},{\"text\":\"(.*?)\"}")
15
- country = re.compile("country\":{\"simpleText\":\"(.*?)\"}")
16
- custom_url = re.compile("canonicalChannelUrl\":\"(.*?)\"")
17
- description = re.compile("{\"description\":{\"simpleText\":\"(.*?)\"}")
18
- avatar = re.compile("height\":88},{\"url\":\"(.*?)\"")
19
- banner = re.compile("width\":1280,\"height\":351},{\"url\":\"(.*?)\"")
20
- playlists = re.compile("{\"url\":\"/playlist\\?list=(.*?)\"")
21
- video_count = re.compile("videoCountText\":{\"runs\":\[{\"text\":(.*?)}")
22
- socials = re.compile("q=https%3A%2F%2F(.*?)\"")
23
- upload_ids = re.compile("videoId\":\"(.*?)\"")
24
- stream_ids = re.compile("videoId\":\"(.*?)\"")
25
- upload_chunk = re.compile("gridVideoRenderer\":{(.*?)\"navigationEndpoint")
26
- upload_chunk_fl_1 = re.compile("simpleText\":\"Streamed")
27
- upload_chunk_fl_2 = re.compile("default_live.")
28
- upcoming_check = re.compile("\"title\":\"Upcoming live streams\"")
29
- upcoming = re.compile("gridVideoRenderer\":{\"videoId\":\"(.*?)\"")
5
+ name = re.compile(r'channelMetadataRenderer\":{\"title\":\"(.*?)\"')
6
+ id = re.compile(r'channelId\":\"(.*?)\"')
7
+ verified = re.compile(r'"label":"Verified"')
8
+ check_live = re.compile(r'{"text":"LIVE"}')
9
+ live = re.compile(r"thumbnailOverlays\":\[(.*?)]")
10
+ video_id = re.compile(r'videoId\":\"(.*?)\"')
11
+ uploads = re.compile(r"gridVideoRenderer\":{\"videoId\":\"(.*?)\"")
12
+ subscribers = re.compile(r"\"subscriberCountText\":{\"accessibility\":(.*?),")
13
+ views = re.compile(r"viewCountText\":{\"simpleText\":\"(.*?)\"}")
14
+ creation = re.compile(r"{\"text\":\"Joined \"},{\"text\":\"(.*?)\"}")
15
+ country = re.compile(r"country\":{\"simpleText\":\"(.*?)\"}")
16
+ custom_url = re.compile(r"canonicalChannelUrl\":\"(.*?)\"")
17
+ description = re.compile(r"{\"description\":{\"simpleText\":\"(.*?)\"}")
18
+ avatar = re.compile(r"height\":88},{\"url\":\"(.*?)\"")
19
+ banner = re.compile(r"width\":1280,\"height\":351},{\"url\":\"(.*?)\"")
20
+ playlists = re.compile(r"{\"url\":\"/playlist\?list=(.*?)\"")
21
+ video_count = re.compile(r"videoCountText\":{\"runs\":\[{\"text\":(.*?)}")
22
+ socials = re.compile(r"q=https%3A%2F%2F(.*?)\"")
23
+ upload_ids = re.compile(r"videoId\":\"(.*?)\"")
24
+ stream_ids = re.compile(r"videoId\":\"(.*?)\"")
25
+ upload_chunk = re.compile(r"gridVideoRenderer\":{(.*?)\"navigationEndpoint")
26
+ upload_chunk_fl_1 = re.compile(r"simpleText\":\"Streamed")
27
+ upload_chunk_fl_2 = re.compile(r"default_live.")
28
+ upcoming_check = re.compile(r"\"title\":\"Upcoming live streams\"")
29
+ upcoming = re.compile(r"gridVideoRenderer\":{\"videoId\":\"(.*?)\"")
30
30
 
31
31
 
32
32
  class _VideoPatterns:
33
- video_id = re.compile('videoId\":\"(.*?)\"')
34
- title = re.compile("title\":\"(.*?)\"")
35
- duration = re.compile("approxDurationMs\":\"(.*?)\"")
36
- upload_date = re.compile("uploadDate\":\"(.*?)\"")
37
- author_id = re.compile("channelIds\":\[\"(.*?)\"")
38
- description = re.compile("shortDescription\":\"(.*)\",\"isCrawlable")
39
- tags = re.compile("<meta name=\"keywords\" content=\"(.*?)\">")
40
- is_streamed = re.compile("simpleText\":\"Streamed live")
41
- is_premiered = re.compile("dateText\":{\"simpleText\":\"Premiered")
42
- views = re.compile("videoViewCountRenderer\":{\"viewCount\":{\"simpleText\":\"(.*?)\"")
43
- likes = re.compile("toggledText\":{\"accessibility\":{\"accessibilityData\":{\"label\":\"(.*?) ")
44
- thumbnail = re.compile("playerMicroformatRenderer\":{\"thumbnail\":{\"thumbnails\":\[{\"url\":\"(.*?)\"")
33
+ video_id = re.compile(r'videoId\":\"(.*?)\"')
34
+ title = re.compile(r"title\":\"(.*?)\"")
35
+ duration = re.compile(r"approxDurationMs\":\"(.*?)\"")
36
+ upload_date = re.compile(r"uploadDate\":\"(.*?)\"")
37
+ author_id = re.compile(r"channelIds\":\[\"(.*?)\"")
38
+ description = re.compile(r"shortDescription\":\"(.*)\",\"isCrawlable")
39
+ tags = re.compile(r"<meta name=\"keywords\" content=\"(.*?)\">")
40
+ is_streamed = re.compile(r"simpleText\":\"Streamed live")
41
+ is_premiered = re.compile(r"dateText\":{\"simpleText\":\"Premiered")
42
+ views = re.compile(r"videoViewCountRenderer\":{\"viewCount\":{\"simpleText\":\"(.*?)\"")
43
+ likes = re.compile(r"toggledText\":{\"accessibility\":{\"accessibilityData\":{\"label\":\"(.*?) ")
44
+ thumbnail = re.compile(r"playerMicroformatRenderer\":{\"thumbnail\":{\"thumbnails\":\[{\"url\":\"(.*?)\"")
45
45
 
46
46
 
47
47
  class _PlaylistPatterns:
48
- name = re.compile("{\"title\":\"(.*?)\"")
49
- video_count = re.compile("stats\":\[{\"runs\":\[{\"text\":\"(.*?)\"")
50
- video_id = re.compile("videoId\":\"(.*?)\"")
51
- thumbnail = re.compile("og:image\" content=\"(.*?)\?")
48
+ name = re.compile(r"{\"title\":\"(.*?)\"")
49
+ video_count = re.compile(r"stats\":\[{\"runs\":\[{\"text\":\"(.*?)\"")
50
+ video_id = re.compile(r"videoId\":\"(.*?)\"")
51
+ thumbnail = re.compile(r"og:image\" content=\"(.*?)\?")
52
52
 
53
53
 
54
54
  class _ExtraPatterns:
55
- video_id = re.compile("videoId\":\"(.*?)\"")
55
+ video_id = re.compile(r"videoId\":\"(.*?)\"")
56
56
 
57
57
 
58
58
  class _QueryPatterns:
59
- channel_id = re.compile("channelId\":\"(.*?)\"")
60
- video_id = re.compile("videoId\":\"(.*?)\"")
61
- playlist_id = re.compile("playlistId\":\"(.*?)\"")
59
+ channel_id = re.compile(r"channelId\":\"(.*?)\"")
60
+ video_id = re.compile(r"videoId\":\"(.*?)\"")
61
+ playlist_id = re.compile(r"playlistId\":\"(.*?)\"")
@@ -11,7 +11,7 @@ class Video:
11
11
  _HEAD = 'https://www.youtube.com/watch?v='
12
12
 
13
13
  def __init__(self, video_id: str):
14
- pattern = re.compile('.be/(.*?)$|=(.*?)$|^(\w{11})$') # noqa
14
+ pattern = re.compile(r'.be/(.*?)$|=(.*?)$|^(\w{11})$') # noqa
15
15
  self._matched_id = (
16
16
  pattern.search(video_id).group(1)
17
17
  or pattern.search(video_id).group(2)
@@ -17,7 +17,7 @@ class Video:
17
17
  video_id : str
18
18
  The id or url of the video
19
19
  """
20
- pattern = re.compile('.be/(.*?)$|=(.*?)$|^(\w{11})$') # noqa
20
+ pattern = re.compile(r'.be/(.*?)$|=(.*?)$|^(\w{11})$') # noqa
21
21
  match = pattern.search(video_id)
22
22
 
23
23
  if not match:
@@ -33,7 +33,7 @@ class Video:
33
33
  self._url = self._HEAD + self._matched_id
34
34
  self._video_data = video_data(self._matched_id)
35
35
  # Extract basic info for fallback
36
- title_match = re.search('<title>(.*?) - YouTube</title>', self._video_data)
36
+ title_match = re.search(r'<title>(.*?) - YouTube</title>', self._video_data)
37
37
  self.title = title_match.group(1) if title_match else None
38
38
  self.id = self._matched_id
39
39
  else:
@@ -55,19 +55,19 @@ class Video:
55
55
  """
56
56
  # Multiple patterns to try for video details extraction for robustness
57
57
  details_patterns = [
58
- re.compile('videoDetails\":(.*?)\"isLiveContent\":.*?}'),
59
- re.compile('videoDetails\":(.*?),\"playerConfig'),
60
- re.compile('videoDetails\":(.*?),\"playabilityStatus')
58
+ re.compile(r'videoDetails\":(.*?)\"isLiveContent\":.*?}'),
59
+ re.compile(r'videoDetails\":(.*?),\"playerConfig'),
60
+ re.compile(r'videoDetails\":(.*?),\"playabilityStatus')
61
61
  ]
62
62
 
63
63
  # Other metadata patterns
64
- upload_date_pattern = re.compile("<meta itemprop=\"uploadDate\" content=\"(.*?)\">")
65
- genre_pattern = re.compile("<meta itemprop=\"genre\" content=\"(.*?)\">")
64
+ upload_date_pattern = re.compile(r"<meta itemprop=\"uploadDate\" content=\"(.*?)\">")
65
+ genre_pattern = re.compile(r"<meta itemprop=\"genre\" content=\"(.*?)\">")
66
66
  like_count_patterns = [
67
- re.compile("iconType\":\"LIKE\"},\"defaultText\":(.*?)}"),
68
- re.compile('\"likeCount\":\"(\\d+)\"')
67
+ re.compile(r"iconType\":\"LIKE\"},\"defaultText\":(.*?)}"),
68
+ re.compile(r'\"likeCount\":\"(\d+)\"')
69
69
  ]
70
- channel_name_pattern = re.compile('"ownerChannelName":"(.*?)"')
70
+ channel_name_pattern = re.compile(r'"ownerChannelName":"(.*?)"')
71
71
 
72
72
  # Try each pattern for video details
73
73
  raw_details_match = None
@@ -131,7 +131,7 @@ def get_intro_prompt(name: str = "Vortex") -> str:
131
131
  - Actively clean up any temporary processes or files you use.
132
132
  - When looking through files, use git as available to skip files, and skip hidden files (.env, .git, etc) by default.
133
133
  - You can plot anything with matplotlib using Python code.
134
- - **IMPORTANT**: ALWAYS Return your SCRIPT inside of a single pair of \`\`\` delimiters. This SCRIPT can be a mix of Python code and `!`-prefixed shell commands. Only the console output from this SCRIPT (Python prints or `!` command stdout/stderr) is visible to the user, so ensure it's complete.
134
+ - **IMPORTANT**: ALWAYS Return your SCRIPT inside of a single pair of ``` delimiters. This SCRIPT can be a mix of Python code and `!`-prefixed shell commands. Only the console output from this SCRIPT (Python prints or `!` command stdout/stderr) is visible to the user, so ensure it's complete.
135
135
  </conventions>
136
136
 
137
137
  <examples>
@@ -1,4 +1,13 @@
1
1
  DEFAULT_FORMAT = "{time} | {level} | {name} | {message}"
2
2
 
3
+ SIMPLE_FORMAT = "{level}: {message}"
4
+
5
+ DETAILED_FORMAT = "{time} | {level} | {name} | {message} | Thread: {thread} | Process: {process}"
6
+
7
+ JSON_FORMAT = '{{"time": "{time}", "level": "{level}", "name": "{name}", "message": "{message}"}}'
8
+
3
9
  class LogFormat:
4
10
  DEFAULT = DEFAULT_FORMAT
11
+ SIMPLE = SIMPLE_FORMAT
12
+ DETAILED = DETAILED_FORMAT
13
+ JSON = JSON_FORMAT
@@ -101,3 +101,21 @@ class TCPHandler(Handler):
101
101
  return
102
102
  with socket.create_connection((self.host, self.port), timeout=5) as sock:
103
103
  sock.sendall(message.encode() + b"\n")
104
+
105
+ class JSONFileHandler(FileHandler):
106
+ def __init__(self, path: str, level: LogLevel = LogLevel.DEBUG, max_bytes: int = 0, backups: int = 0):
107
+ super().__init__(path, level, max_bytes, backups)
108
+
109
+ def emit(self, message: str, level: LogLevel):
110
+ # Expect message to be a JSON string or dict
111
+ if level < self.level:
112
+ return
113
+ import json
114
+ if isinstance(message, dict):
115
+ log_entry = json.dumps(message)
116
+ else:
117
+ log_entry = message
118
+ self._file.write(log_entry + "\n")
119
+ self._file.flush()
120
+ if self.max_bytes and self._file.tell() >= self.max_bytes:
121
+ self._rotate()
@@ -16,16 +16,58 @@ class Logger:
16
16
  handlers: Optional[List[Handler]] = None,
17
17
  fmt: str = LogFormat.DEFAULT, # <--- use LogFormat.DEFAULT
18
18
  async_mode: bool = False,
19
+ include_context: bool = False, # New flag to include thread/process info
19
20
  ):
21
+ import threading
22
+ import multiprocessing
23
+
20
24
  self.name = name
21
25
  self.level = level
22
26
  self.format = fmt
23
27
  self.async_mode = async_mode
28
+ self.include_context = include_context
24
29
  self.handlers = handlers or [ConsoleHandler()]
30
+ self._thread = threading
31
+ self._multiprocessing = multiprocessing
25
32
 
26
33
  def _format(self, level: LogLevel, message: str) -> str:
27
34
  now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
28
- return self.format.format(time=now, level=level.name, name=self.name, message=message)
35
+ if self.include_context:
36
+ thread_name = self._thread.current_thread().name
37
+ process_id = self._multiprocessing.current_process().pid
38
+ # Check if format is JSON format
39
+ if self.format.strip().startswith('{') and self.format.strip().endswith('}'):
40
+ # Format as JSON string with extra fields
41
+ return self.format.format(
42
+ time=now,
43
+ level=level.name,
44
+ name=self.name,
45
+ message=message,
46
+ thread=thread_name,
47
+ process=process_id
48
+ )
49
+ else:
50
+ # For non-JSON formats, add thread and process info if placeholders exist
51
+ try:
52
+ return self.format.format(
53
+ time=now,
54
+ level=level.name,
55
+ name=self.name,
56
+ message=message,
57
+ thread=thread_name,
58
+ process=process_id
59
+ )
60
+ except KeyError:
61
+ # If thread/process placeholders not in format, append them manually
62
+ base = self.format.format(time=now, level=level.name, name=self.name, message=message)
63
+ return f"{base} | Thread: {thread_name} | Process: {process_id}"
64
+ else:
65
+ return self.format.format(time=now, level=level.name, name=self.name, message=message)
66
+
67
+ def set_format(self, fmt: str, include_context: bool = False):
68
+ """Dynamically change the log format and context inclusion."""
69
+ self.format = fmt
70
+ self.include_context = include_context
29
71
 
30
72
  def _should_log(self, level: LogLevel) -> bool:
31
73
  return level >= self.level
@@ -45,12 +45,13 @@ class Scira(AISearch):
45
45
  AVAILABLE_MODELS = {
46
46
  "scira-default": "Grok3-mini", # thinking model
47
47
  "scira-grok-3": "Grok3",
48
- "scira-anthropic": "Sonnet 3.7 thinking",
48
+ "scira-anthropic": "Claude 4 Sonnet",
49
+ "scira-anthropic-thinking": "Claude 4 Sonnet Thinking", # thinking model
49
50
  "scira-vision" : "Grok2-Vision", # vision model
50
51
  "scira-4o": "GPT4o",
51
52
  "scira-qwq": "QWQ-32B",
52
53
  "scira-o4-mini": "o4-mini",
53
- "scira-google": "gemini 2.5 flash",
54
+ "scira-google": "gemini 2.5 flash Thinking", # thinking model
54
55
  "scira-google-pro": "gemini 2.5 pro",
55
56
  "scira-llama-4": "llama 4 Maverick",
56
57
  }
@@ -92,6 +92,7 @@ class BLACKBOXAI(Provider):
92
92
  # New base models list
93
93
  models = [
94
94
  default_model,
95
+ "gpt-4.1-mini", # Added new model
95
96
  "o3-mini",
96
97
  "gpt-4.1-nano",
97
98
  "Claude Opus 4", # Added Claude Opus 4
@@ -179,6 +180,7 @@ class BLACKBOXAI(Provider):
179
180
  default_model: {'mode': True, 'id': "openai/gpt-4.1", 'name': default_model}, # Assuming GPT-4.1 is agent-compatible
180
181
  'o3-mini': {'mode': True, 'id': "o3-mini", 'name': "o3-mini"}, # Assuming o3-mini is agent-compatible
181
182
  'gpt-4.1-nano': {'mode': True, 'id': "gpt-4.1-nano", 'name': "gpt-4.1-nano"}, # Assuming gpt-4.1-nano is agent-compatible
183
+ 'gpt-4.1-mini': {'mode': True, 'id': "gpt-4.1-mini", 'name': "gpt-4.1-mini"}, # Added agent mode for gpt-4.1-mini
182
184
  }
183
185
 
184
186
  # Trending agent modes
@@ -32,7 +32,8 @@ class ChatSandbox(Provider):
32
32
  >>> print(response)
33
33
  'I'm doing well, thank you for asking! How can I assist you today?'
34
34
  """
35
- AVAILABLE_MODELS = ["openai", "deepseek", "llama", "gemini", "mistral-large"]
35
+ AVAILABLE_MODELS = ["openai", "deepseek", "llama", "gemini", "mistral-large", "deepseek-r1", "deepseek-r1-full", "gemini-thinking", "openai-o1-mini", "llama", "mistral", "gemma-3"]
36
+
36
37
 
37
38
  def __init__(
38
39
  self,
@@ -18,7 +18,7 @@ class DeepInfra(Provider):
18
18
 
19
19
  AVAILABLE_MODELS = [
20
20
  # "anthropic/claude-3-7-sonnet-latest", # >>>> NOT WORKING
21
-
21
+ "deepseek-ai/DeepSeek-R1-0528",
22
22
  "deepseek-ai/DeepSeek-R1",
23
23
  "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
24
24
  "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
@@ -37,7 +37,7 @@ class HeckAI(Provider):
37
37
  """
38
38
 
39
39
  AVAILABLE_MODELS = [
40
- "google/gemini-2.0-flash-001",
40
+ "google/gemini-2.5-flash-preview",
41
41
  "deepseek/deepseek-chat",
42
42
  "deepseek/deepseek-r1",
43
43
  "openai/gpt-4o-mini",
@@ -21,12 +21,19 @@ class LambdaChat(Provider):
21
21
 
22
22
  AVAILABLE_MODELS = [
23
23
  "deepseek-llama3.3-70b",
24
+ "apriel-5b-instruct",
24
25
  "deepseek-r1",
26
+ "deepseek-v3-0324",
27
+ "deepseek-r1-0528",
25
28
  "hermes-3-llama-3.1-405b-fp8",
26
29
  "llama3.1-nemotron-70b-instruct",
27
30
  "lfm-40b",
28
31
  "llama3.3-70b-instruct-fp8",
29
- "qwen25-coder-32b-instruct"
32
+ "qwen25-coder-32b-instruct",
33
+ "qwen3-32b-fp8",
34
+ "llama-4-maverick-70b-128e-instruct-fp8",
35
+ "llama-4-scout-17b-16e-instruct"
36
+
30
37
  ]
31
38
 
32
39
  def __init__(
@@ -66,9 +66,13 @@ class MCPCore(Provider):
66
66
  ):
67
67
  """Initializes the MCPCore API client."""
68
68
  if model not in self.AVAILABLE_MODELS:
69
- print(f"Warning: Model '{model}' not in known AVAILABLE_MODELS. Attempting to use anyway.")
69
+ print(f"Warning: Model '{model}' is not listed in AVAILABLE_MODELS. Proceeding with the provided model.")
70
70
 
71
71
  self.api_endpoint = "https://chat.mcpcore.xyz/api/chat/completions"
72
+
73
+ # Cache the user-agent at the class level
74
+ if not hasattr(MCPCore, '_cached_user_agent'):
75
+ MCPCore._cached_user_agent = LitAgent().random()
72
76
  self.model = model
73
77
  self.system_prompt = system_prompt
74
78
  self.cookies_path = cookies_path
@@ -82,7 +86,7 @@ class MCPCore(Provider):
82
86
  'authority': 'chat.mcpcore.xyz',
83
87
  'accept': '*/*',
84
88
  'accept-language': 'en-US,en;q=0.9,en-IN;q=0.8',
85
- 'authorization': f'Bearer {self.token}' if self.token else '',
89
+ **({'authorization': f'Bearer {self.token}'} if self.token else {}),
86
90
  'content-type': 'application/json',
87
91
  'dnt': '1',
88
92
  'origin': 'https://chat.mcpcore.xyz',
@@ -95,7 +99,7 @@ class MCPCore(Provider):
95
99
  'sec-fetch-mode': 'cors',
96
100
  'sec-fetch-site': 'same-origin',
97
101
  'sec-gpc': '1',
98
- 'user-agent': LitAgent().random(),
102
+ 'user-agent': self._cached_user_agent,
99
103
  }
100
104
 
101
105
  # Apply headers, proxies, and cookies to the session