webscout 8.2.8__py3-none-any.whl → 8.3__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 (197) hide show
  1. webscout/AIauto.py +34 -16
  2. webscout/AIbase.py +96 -37
  3. webscout/AIutel.py +491 -87
  4. webscout/Bard.py +441 -323
  5. webscout/Extra/GitToolkit/__init__.py +10 -10
  6. webscout/Extra/YTToolkit/ytapi/video.py +232 -232
  7. webscout/Litlogger/README.md +10 -0
  8. webscout/Litlogger/__init__.py +7 -59
  9. webscout/Litlogger/formats.py +4 -0
  10. webscout/Litlogger/handlers.py +103 -0
  11. webscout/Litlogger/levels.py +13 -0
  12. webscout/Litlogger/logger.py +92 -0
  13. webscout/Provider/AISEARCH/Perplexity.py +332 -358
  14. webscout/Provider/AISEARCH/felo_search.py +9 -35
  15. webscout/Provider/AISEARCH/genspark_search.py +30 -56
  16. webscout/Provider/AISEARCH/hika_search.py +4 -16
  17. webscout/Provider/AISEARCH/iask_search.py +410 -436
  18. webscout/Provider/AISEARCH/monica_search.py +4 -30
  19. webscout/Provider/AISEARCH/scira_search.py +6 -32
  20. webscout/Provider/AISEARCH/webpilotai_search.py +38 -64
  21. webscout/Provider/Blackboxai.py +155 -35
  22. webscout/Provider/ChatSandbox.py +2 -1
  23. webscout/Provider/Deepinfra.py +339 -339
  24. webscout/Provider/ExaChat.py +358 -358
  25. webscout/Provider/Gemini.py +169 -169
  26. webscout/Provider/GithubChat.py +1 -2
  27. webscout/Provider/Glider.py +3 -3
  28. webscout/Provider/HeckAI.py +172 -82
  29. webscout/Provider/LambdaChat.py +1 -0
  30. webscout/Provider/MCPCore.py +7 -3
  31. webscout/Provider/OPENAI/BLACKBOXAI.py +421 -139
  32. webscout/Provider/OPENAI/Cloudflare.py +38 -21
  33. webscout/Provider/OPENAI/FalconH1.py +457 -0
  34. webscout/Provider/OPENAI/FreeGemini.py +35 -18
  35. webscout/Provider/OPENAI/NEMOTRON.py +34 -34
  36. webscout/Provider/OPENAI/PI.py +427 -0
  37. webscout/Provider/OPENAI/Qwen3.py +304 -0
  38. webscout/Provider/OPENAI/README.md +952 -1253
  39. webscout/Provider/OPENAI/TwoAI.py +374 -0
  40. webscout/Provider/OPENAI/__init__.py +7 -1
  41. webscout/Provider/OPENAI/ai4chat.py +73 -63
  42. webscout/Provider/OPENAI/api.py +869 -644
  43. webscout/Provider/OPENAI/base.py +2 -0
  44. webscout/Provider/OPENAI/c4ai.py +34 -13
  45. webscout/Provider/OPENAI/chatgpt.py +575 -556
  46. webscout/Provider/OPENAI/chatgptclone.py +512 -487
  47. webscout/Provider/OPENAI/chatsandbox.py +11 -6
  48. webscout/Provider/OPENAI/copilot.py +258 -0
  49. webscout/Provider/OPENAI/deepinfra.py +327 -318
  50. webscout/Provider/OPENAI/e2b.py +140 -104
  51. webscout/Provider/OPENAI/exaai.py +420 -411
  52. webscout/Provider/OPENAI/exachat.py +448 -443
  53. webscout/Provider/OPENAI/flowith.py +7 -3
  54. webscout/Provider/OPENAI/freeaichat.py +12 -8
  55. webscout/Provider/OPENAI/glider.py +15 -8
  56. webscout/Provider/OPENAI/groq.py +5 -2
  57. webscout/Provider/OPENAI/heckai.py +311 -307
  58. webscout/Provider/OPENAI/llmchatco.py +9 -7
  59. webscout/Provider/OPENAI/mcpcore.py +18 -9
  60. webscout/Provider/OPENAI/multichat.py +7 -5
  61. webscout/Provider/OPENAI/netwrck.py +16 -11
  62. webscout/Provider/OPENAI/oivscode.py +290 -0
  63. webscout/Provider/OPENAI/opkfc.py +507 -496
  64. webscout/Provider/OPENAI/pydantic_imports.py +172 -0
  65. webscout/Provider/OPENAI/scirachat.py +29 -17
  66. webscout/Provider/OPENAI/sonus.py +308 -303
  67. webscout/Provider/OPENAI/standardinput.py +442 -433
  68. webscout/Provider/OPENAI/textpollinations.py +18 -11
  69. webscout/Provider/OPENAI/toolbaz.py +419 -413
  70. webscout/Provider/OPENAI/typefully.py +17 -10
  71. webscout/Provider/OPENAI/typegpt.py +21 -11
  72. webscout/Provider/OPENAI/uncovrAI.py +477 -462
  73. webscout/Provider/OPENAI/utils.py +90 -79
  74. webscout/Provider/OPENAI/venice.py +435 -425
  75. webscout/Provider/OPENAI/wisecat.py +387 -381
  76. webscout/Provider/OPENAI/writecream.py +166 -163
  77. webscout/Provider/OPENAI/x0gpt.py +26 -37
  78. webscout/Provider/OPENAI/yep.py +384 -356
  79. webscout/Provider/PI.py +2 -1
  80. webscout/Provider/TTI/README.md +55 -101
  81. webscout/Provider/TTI/__init__.py +4 -9
  82. webscout/Provider/TTI/aiarta.py +365 -0
  83. webscout/Provider/TTI/artbit.py +0 -0
  84. webscout/Provider/TTI/base.py +64 -0
  85. webscout/Provider/TTI/fastflux.py +200 -0
  86. webscout/Provider/TTI/magicstudio.py +201 -0
  87. webscout/Provider/TTI/piclumen.py +203 -0
  88. webscout/Provider/TTI/pixelmuse.py +225 -0
  89. webscout/Provider/TTI/pollinations.py +221 -0
  90. webscout/Provider/TTI/utils.py +11 -0
  91. webscout/Provider/TTS/__init__.py +2 -1
  92. webscout/Provider/TTS/base.py +159 -159
  93. webscout/Provider/TTS/openai_fm.py +129 -0
  94. webscout/Provider/TextPollinationsAI.py +308 -308
  95. webscout/Provider/TwoAI.py +239 -44
  96. webscout/Provider/UNFINISHED/Youchat.py +330 -330
  97. webscout/Provider/UNFINISHED/puterjs.py +635 -0
  98. webscout/Provider/UNFINISHED/test_lmarena.py +119 -119
  99. webscout/Provider/Writecream.py +246 -246
  100. webscout/Provider/__init__.py +2 -2
  101. webscout/Provider/ai4chat.py +33 -8
  102. webscout/Provider/granite.py +41 -6
  103. webscout/Provider/koala.py +169 -169
  104. webscout/Provider/oivscode.py +309 -0
  105. webscout/Provider/samurai.py +3 -2
  106. webscout/Provider/scnet.py +1 -0
  107. webscout/Provider/typegpt.py +3 -3
  108. webscout/Provider/uncovr.py +368 -368
  109. webscout/client.py +70 -0
  110. webscout/litprinter/__init__.py +58 -58
  111. webscout/optimizers.py +419 -419
  112. webscout/scout/README.md +3 -1
  113. webscout/scout/core/crawler.py +134 -64
  114. webscout/scout/core/scout.py +148 -109
  115. webscout/scout/element.py +106 -88
  116. webscout/swiftcli/Readme.md +323 -323
  117. webscout/swiftcli/plugins/manager.py +9 -2
  118. webscout/version.py +1 -1
  119. webscout/zeroart/__init__.py +134 -134
  120. webscout/zeroart/effects.py +100 -100
  121. webscout/zeroart/fonts.py +1238 -1238
  122. {webscout-8.2.8.dist-info → webscout-8.3.dist-info}/METADATA +160 -35
  123. webscout-8.3.dist-info/RECORD +290 -0
  124. {webscout-8.2.8.dist-info → webscout-8.3.dist-info}/WHEEL +1 -1
  125. {webscout-8.2.8.dist-info → webscout-8.3.dist-info}/entry_points.txt +1 -0
  126. webscout/Litlogger/Readme.md +0 -175
  127. webscout/Litlogger/core/__init__.py +0 -6
  128. webscout/Litlogger/core/level.py +0 -23
  129. webscout/Litlogger/core/logger.py +0 -165
  130. webscout/Litlogger/handlers/__init__.py +0 -12
  131. webscout/Litlogger/handlers/console.py +0 -33
  132. webscout/Litlogger/handlers/file.py +0 -143
  133. webscout/Litlogger/handlers/network.py +0 -173
  134. webscout/Litlogger/styles/__init__.py +0 -7
  135. webscout/Litlogger/styles/colors.py +0 -249
  136. webscout/Litlogger/styles/formats.py +0 -458
  137. webscout/Litlogger/styles/text.py +0 -87
  138. webscout/Litlogger/utils/__init__.py +0 -6
  139. webscout/Litlogger/utils/detectors.py +0 -153
  140. webscout/Litlogger/utils/formatters.py +0 -200
  141. webscout/Provider/ChatGPTGratis.py +0 -194
  142. webscout/Provider/TTI/AiForce/README.md +0 -159
  143. webscout/Provider/TTI/AiForce/__init__.py +0 -22
  144. webscout/Provider/TTI/AiForce/async_aiforce.py +0 -224
  145. webscout/Provider/TTI/AiForce/sync_aiforce.py +0 -245
  146. webscout/Provider/TTI/FreeAIPlayground/README.md +0 -99
  147. webscout/Provider/TTI/FreeAIPlayground/__init__.py +0 -9
  148. webscout/Provider/TTI/FreeAIPlayground/async_freeaiplayground.py +0 -181
  149. webscout/Provider/TTI/FreeAIPlayground/sync_freeaiplayground.py +0 -180
  150. webscout/Provider/TTI/ImgSys/README.md +0 -174
  151. webscout/Provider/TTI/ImgSys/__init__.py +0 -23
  152. webscout/Provider/TTI/ImgSys/async_imgsys.py +0 -202
  153. webscout/Provider/TTI/ImgSys/sync_imgsys.py +0 -195
  154. webscout/Provider/TTI/MagicStudio/README.md +0 -101
  155. webscout/Provider/TTI/MagicStudio/__init__.py +0 -2
  156. webscout/Provider/TTI/MagicStudio/async_magicstudio.py +0 -111
  157. webscout/Provider/TTI/MagicStudio/sync_magicstudio.py +0 -109
  158. webscout/Provider/TTI/Nexra/README.md +0 -155
  159. webscout/Provider/TTI/Nexra/__init__.py +0 -22
  160. webscout/Provider/TTI/Nexra/async_nexra.py +0 -286
  161. webscout/Provider/TTI/Nexra/sync_nexra.py +0 -258
  162. webscout/Provider/TTI/PollinationsAI/README.md +0 -146
  163. webscout/Provider/TTI/PollinationsAI/__init__.py +0 -23
  164. webscout/Provider/TTI/PollinationsAI/async_pollinations.py +0 -311
  165. webscout/Provider/TTI/PollinationsAI/sync_pollinations.py +0 -265
  166. webscout/Provider/TTI/aiarta/README.md +0 -134
  167. webscout/Provider/TTI/aiarta/__init__.py +0 -2
  168. webscout/Provider/TTI/aiarta/async_aiarta.py +0 -482
  169. webscout/Provider/TTI/aiarta/sync_aiarta.py +0 -440
  170. webscout/Provider/TTI/artbit/README.md +0 -100
  171. webscout/Provider/TTI/artbit/__init__.py +0 -22
  172. webscout/Provider/TTI/artbit/async_artbit.py +0 -155
  173. webscout/Provider/TTI/artbit/sync_artbit.py +0 -148
  174. webscout/Provider/TTI/fastflux/README.md +0 -129
  175. webscout/Provider/TTI/fastflux/__init__.py +0 -22
  176. webscout/Provider/TTI/fastflux/async_fastflux.py +0 -261
  177. webscout/Provider/TTI/fastflux/sync_fastflux.py +0 -252
  178. webscout/Provider/TTI/huggingface/README.md +0 -114
  179. webscout/Provider/TTI/huggingface/__init__.py +0 -22
  180. webscout/Provider/TTI/huggingface/async_huggingface.py +0 -199
  181. webscout/Provider/TTI/huggingface/sync_huggingface.py +0 -195
  182. webscout/Provider/TTI/piclumen/README.md +0 -161
  183. webscout/Provider/TTI/piclumen/__init__.py +0 -23
  184. webscout/Provider/TTI/piclumen/async_piclumen.py +0 -268
  185. webscout/Provider/TTI/piclumen/sync_piclumen.py +0 -233
  186. webscout/Provider/TTI/pixelmuse/README.md +0 -79
  187. webscout/Provider/TTI/pixelmuse/__init__.py +0 -4
  188. webscout/Provider/TTI/pixelmuse/async_pixelmuse.py +0 -249
  189. webscout/Provider/TTI/pixelmuse/sync_pixelmuse.py +0 -182
  190. webscout/Provider/TTI/talkai/README.md +0 -139
  191. webscout/Provider/TTI/talkai/__init__.py +0 -4
  192. webscout/Provider/TTI/talkai/async_talkai.py +0 -229
  193. webscout/Provider/TTI/talkai/sync_talkai.py +0 -207
  194. webscout/Provider/UNFINISHED/oivscode.py +0 -351
  195. webscout-8.2.8.dist-info/RECORD +0 -334
  196. {webscout-8.2.8.dist-info → webscout-8.3.dist-info}/licenses/LICENSE.md +0 -0
  197. {webscout-8.2.8.dist-info → webscout-8.3.dist-info}/top_level.txt +0 -0
@@ -4,37 +4,11 @@ import re
4
4
  import uuid
5
5
  from typing import Dict, Optional, Generator, Union, Any
6
6
 
7
- from webscout.AIbase import AISearch
7
+ from webscout.AIbase import AISearch, SearchResponse
8
8
  from webscout import exceptions
9
9
  from webscout.litagent import LitAgent
10
10
 
11
11
 
12
- class Response:
13
- """A wrapper class for Monica API responses.
14
-
15
- This class automatically converts response objects to their text representation
16
- when printed or converted to string.
17
-
18
- Attributes:
19
- text (str): The text content of the response
20
-
21
- Example:
22
- >>> response = Response("Hello, world!")
23
- >>> print(response)
24
- Hello, world!
25
- >>> str(response)
26
- 'Hello, world!'
27
- """
28
- def __init__(self, text: str):
29
- self.text = text
30
-
31
- def __str__(self):
32
- return self.text
33
-
34
- def __repr__(self):
35
- return self.text
36
-
37
-
38
12
  class Monica(AISearch):
39
13
  """A class to interact with the Monica AI search API.
40
14
 
@@ -121,7 +95,7 @@ class Monica(AISearch):
121
95
  prompt: str,
122
96
  stream: bool = False,
123
97
  raw: bool = False,
124
- ) -> Union[Response, Generator[Union[Dict[str, str], Response], None, None]]:
98
+ ) -> Union[SearchResponse, Generator[Union[Dict[str, str], SearchResponse], None, None]]:
125
99
  """Search using the Monica API and get AI-generated responses.
126
100
 
127
101
  This method sends a search query to Monica and returns the AI-generated response.
@@ -185,7 +159,7 @@ class Monica(AISearch):
185
159
  if raw:
186
160
  yield {"text": text_chunk}
187
161
  else:
188
- yield Response(text_chunk)
162
+ yield SearchResponse(text_chunk)
189
163
 
190
164
  # Check if stream is finished
191
165
  if "finished" in data and data["finished"]:
@@ -210,7 +184,7 @@ class Monica(AISearch):
210
184
  if not raw:
211
185
  # Process the full response to clean up formatting
212
186
  formatted_response = self.format_response(full_response)
213
- self.last_response = Response(formatted_response)
187
+ self.last_response = SearchResponse(formatted_response)
214
188
  return self.last_response
215
189
 
216
190
  return for_stream() if stream else for_non_stream()
@@ -5,37 +5,11 @@ import uuid
5
5
  import time
6
6
  from typing import Dict, Optional, Generator, Union, Any
7
7
 
8
- from webscout.AIbase import AISearch
8
+ from webscout.AIbase import AISearch, SearchResponse
9
9
  from webscout import exceptions
10
10
  from webscout.litagent import LitAgent
11
11
 
12
12
 
13
- class Response:
14
- """A wrapper class for SCIRA API responses.
15
-
16
- This class automatically converts response objects to their text representation
17
- when printed or converted to string.
18
-
19
- Attributes:
20
- text (str): The text content of the response
21
-
22
- Example:
23
- >>> response = Response("Hello, world!")
24
- >>> print(response)
25
- Hello, world!
26
- >>> str(response)
27
- 'Hello, world!'
28
- """
29
- def __init__(self, text: str):
30
- self.text = text
31
-
32
- def __str__(self):
33
- return self.text
34
-
35
- def __repr__(self):
36
- return self.text
37
-
38
-
39
13
  class Scira(AISearch):
40
14
  """A class to interact with the SCIRA AI search API.
41
15
 
@@ -131,7 +105,7 @@ class Scira(AISearch):
131
105
  prompt: str,
132
106
  stream: bool = False,
133
107
  raw: bool = False,
134
- ) -> Union[Response, Generator[Union[Dict[str, str], Response], None, None]]:
108
+ ) -> Union[SearchResponse, Generator[Union[Dict[str, str], SearchResponse], None, None]]:
135
109
  """Search using the SCIRA API and get AI-generated responses.
136
110
 
137
111
  This method sends a search query to SCIRA and returns the AI-generated response.
@@ -224,7 +198,7 @@ class Scira(AISearch):
224
198
  self,
225
199
  response: requests.Response,
226
200
  raw: bool
227
- ) -> Generator[Union[Dict[str, str], Response], None, None]:
201
+ ) -> Generator[Union[Dict[str, str], SearchResponse], None, None]:
228
202
  """Handle streaming response from the API.
229
203
 
230
204
  Args:
@@ -252,7 +226,7 @@ class Scira(AISearch):
252
226
  if raw:
253
227
  yield {"text": content}
254
228
  else:
255
- yield Response(content)
229
+ yield SearchResponse(content)
256
230
  except Exception:
257
231
  # Skip lines that can't be processed
258
232
  pass
@@ -261,7 +235,7 @@ class Scira(AISearch):
261
235
  self,
262
236
  response: requests.Response,
263
237
  raw: bool
264
- ) -> Union[Dict[str, str], Response]:
238
+ ) -> Union[Dict[str, str], SearchResponse]:
265
239
  """Handle non-streaming response from the API.
266
240
 
267
241
  Args:
@@ -295,7 +269,7 @@ class Scira(AISearch):
295
269
  if raw:
296
270
  return {"text": full_text}
297
271
  else:
298
- return Response(full_text)
272
+ return SearchResponse(full_text)
299
273
 
300
274
  @staticmethod
301
275
  def clean_content(text: str) -> str:
@@ -3,43 +3,17 @@ import json
3
3
  import re
4
4
  from typing import Dict, Optional, Generator, Union, Any
5
5
 
6
- from webscout.AIbase import AISearch
6
+ from webscout.AIbase import AISearch, SearchResponse
7
7
  from webscout import exceptions
8
8
  from webscout.litagent import LitAgent
9
9
 
10
10
 
11
- class Response:
12
- """A wrapper class for webpilotai API responses.
13
-
14
- This class automatically converts response objects to their text representation
15
- when printed or converted to string.
16
-
17
- Attributes:
18
- text (str): The text content of the response
19
-
20
- Example:
21
- >>> response = Response("Hello, world!")
22
- >>> print(response)
23
- Hello, world!
24
- >>> str(response)
25
- 'Hello, world!'
26
- """
27
- def __init__(self, text: str):
28
- self.text = text
29
-
30
- def __str__(self):
31
- return self.text
32
-
33
- def __repr__(self):
34
- return self.text
35
-
36
-
37
11
  class webpilotai(AISearch):
38
12
  """A class to interact with the webpilotai (WebPilot) AI search API.
39
13
 
40
- webpilotai provides a web-based comprehensive search response interface that returns AI-generated
41
- responses with source references and related questions. It supports both streaming and
42
- non-streaming responses.
14
+ webpilotai provides a web-based comprehensive search SearchResponse interface that returns AI-generated
15
+ SearchResponses with source references and related questions. It supports both streaming and
16
+ non-streaming SearchResponses.
43
17
 
44
18
  Basic Usage:
45
19
  >>> from webscout import webpilotai
@@ -54,7 +28,7 @@ class webpilotai(AISearch):
54
28
  ... print(chunk, end="", flush=True)
55
29
  Artificial Intelligence is...
56
30
 
57
- >>> # Raw response format
31
+ >>> # Raw SearchResponse format
58
32
  >>> for chunk in ai.search("Hello", stream=True, raw=True):
59
33
  ... print(chunk)
60
34
  {'text': 'Hello'}
@@ -83,7 +57,7 @@ class webpilotai(AISearch):
83
57
  self.session = requests.Session()
84
58
  self.api_endpoint = "https://api.webpilotai.com/rupee/v1/search"
85
59
  self.timeout = timeout
86
- self.last_response = {}
60
+ self.last_SearchResponse = {}
87
61
 
88
62
  # The 'Bearer null' is part of the API's expected headers
89
63
  self.headers = {
@@ -103,24 +77,24 @@ class webpilotai(AISearch):
103
77
  prompt: str,
104
78
  stream: bool = False,
105
79
  raw: bool = False,
106
- ) -> Union[Response, Generator[Union[Dict[str, str], Response], None, None]]:
107
- """Search using the webpilotai API and get AI-generated responses.
80
+ ) -> Union[SearchResponse, Generator[Union[Dict[str, str], SearchResponse], None, None]]:
81
+ """Search using the webpilotai API and get AI-generated SearchResponses.
108
82
 
109
- This method sends a search query to webpilotai and returns the AI-generated response.
110
- It supports both streaming and non-streaming modes, as well as raw response format.
83
+ This method sends a search query to webpilotai and returns the AI-generated SearchResponse.
84
+ It supports both streaming and non-streaming modes, as well as raw SearchResponse format.
111
85
 
112
86
  Args:
113
87
  prompt (str): The search query or prompt to send to the API.
114
- stream (bool, optional): If True, yields response chunks as they arrive.
115
- If False, returns complete response. Defaults to False.
116
- raw (bool, optional): If True, returns raw response dictionaries with 'text' key.
117
- If False, returns Response objects that convert to text automatically.
88
+ stream (bool, optional): If True, yields SearchResponse chunks as they arrive.
89
+ If False, returns complete SearchResponse. Defaults to False.
90
+ raw (bool, optional): If True, returns raw SearchResponse dictionaries with 'text' key.
91
+ If False, returns SearchResponse objects that convert to text automatically.
118
92
  Defaults to False.
119
93
 
120
94
  Returns:
121
- Union[Response, Generator[Union[Dict[str, str], Response], None, None]]:
122
- - If stream=False: Returns complete response as Response object
123
- - If stream=True: Yields response chunks as either Dict or Response objects
95
+ Union[SearchResponse, Generator[Union[Dict[str, str], SearchResponse], None, None]]:
96
+ - If stream=False: Returns complete SearchResponse as SearchResponse object
97
+ - If stream=True: Yields SearchResponse chunks as either Dict or SearchResponse objects
124
98
 
125
99
  Raises:
126
100
  APIConnectionError: If the API request fails
@@ -132,12 +106,12 @@ class webpilotai(AISearch):
132
106
  >>> print(response)
133
107
  Python is a programming language...
134
108
 
135
- Streaming response:
109
+ Streaming SearchResponse:
136
110
  >>> for chunk in ai.search("Tell me about AI", stream=True):
137
111
  ... print(chunk, end="")
138
112
  Artificial Intelligence...
139
113
 
140
- Raw response format:
114
+ Raw SearchResponse format:
141
115
  >>> for chunk in ai.search("Hello", stream=True, raw=True):
142
116
  ... print(chunk)
143
117
  {'text': 'Hello'}
@@ -149,7 +123,7 @@ class webpilotai(AISearch):
149
123
  }
150
124
 
151
125
  def for_stream():
152
- full_response_content = ""
126
+ full_SearchResponse_content = ""
153
127
  current_event_name = None
154
128
  current_data_buffer = []
155
129
 
@@ -175,17 +149,17 @@ class webpilotai(AISearch):
175
149
  if current_event_name == "message":
176
150
  try:
177
151
  data_payload = json.loads(full_data)
178
- # Check structure based on the API response
152
+ # Check structure based on the API SearchResponse
179
153
  if data_payload.get('type') == 'data':
180
154
  content_chunk = data_payload.get('data', {}).get('content', "")
181
155
  if content_chunk:
182
- full_response_content += content_chunk
156
+ full_SearchResponse_content += content_chunk
183
157
 
184
158
  # Yield the new content chunk
185
159
  if raw:
186
160
  yield {"text": content_chunk}
187
161
  else:
188
- yield Response(content_chunk)
162
+ yield SearchResponse(content_chunk)
189
163
  except json.JSONDecodeError:
190
164
  pass
191
165
  except Exception as e:
@@ -214,14 +188,14 @@ class webpilotai(AISearch):
214
188
  data_payload = json.loads(full_data)
215
189
  if data_payload.get('type') == 'data':
216
190
  content_chunk = data_payload.get('data', {}).get('content', "")
217
- if content_chunk and len(content_chunk) > len(full_response_content):
218
- delta = content_chunk[len(full_response_content):]
219
- full_response_content += delta
191
+ if content_chunk and len(content_chunk) > len(full_SearchResponse_content):
192
+ delta = content_chunk[len(full_SearchResponse_content):]
193
+ full_SearchResponse_content += delta
220
194
 
221
195
  if raw:
222
196
  yield {"text": delta}
223
197
  else:
224
- yield Response(delta)
198
+ yield SearchResponse(delta)
225
199
  except (json.JSONDecodeError, Exception):
226
200
  pass
227
201
 
@@ -231,27 +205,27 @@ class webpilotai(AISearch):
231
205
  raise exceptions.APIConnectionError(f"Request failed: {e}")
232
206
 
233
207
  def for_non_stream():
234
- full_response = ""
208
+ full_SearchResponse = ""
235
209
  for chunk in for_stream():
236
210
  if raw:
237
211
  yield chunk
238
212
  else:
239
- full_response += str(chunk)
213
+ full_SearchResponse += str(chunk)
240
214
 
241
215
  if not raw:
242
- # Format the response for better readability
243
- formatted_response = self.format_response(full_response)
244
- self.last_response = Response(formatted_response)
245
- return self.last_response
216
+ # Format the SearchResponse for better readability
217
+ formatted_SearchResponse = self.format_SearchResponse(full_SearchResponse)
218
+ self.last_response = SearchResponse(formatted_SearchResponse)
219
+ return self.last_SearchResponse
246
220
 
247
221
  return for_stream() if stream else for_non_stream()
248
222
 
249
223
  @staticmethod
250
- def format_response(text: str) -> str:
251
- """Format the response text for better readability.
224
+ def format_SearchResponse(text: str) -> str:
225
+ """Format the SearchResponse text for better readability.
252
226
 
253
227
  Args:
254
- text (str): The raw response text
228
+ text (str): The raw SearchResponse text
255
229
 
256
230
  Returns:
257
231
  str: Formatted text with improved structure
@@ -276,6 +250,6 @@ if __name__ == "__main__":
276
250
  from rich import print
277
251
 
278
252
  ai = webpilotai()
279
- response = ai.search(input(">>> "), stream=True, raw=False)
280
- for chunk in response:
253
+ r = ai.search(input(">>> "), stream=True, raw=False)
254
+ for chunk in r:
281
255
  print(chunk, end="", flush=True)
@@ -92,10 +92,16 @@ 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",
98
+ "Claude Opus 4", # Added Claude Opus 4
99
+ "Claude Sonnet 4", # Added Claude Sonnet 4
97
100
  "Claude-sonnet-3.7",
98
101
  "Claude-sonnet-3.5",
102
+ "Grok 3", # Added Grok 3
103
+ "Gemini 2.5 Pro", # Added Gemini 2.5 Pro
104
+ "UI-TARS 72B", # Added UI-TARS 72B
99
105
  "DeepSeek-R1",
100
106
  "Mistral-Small-24B-Instruct-2501",
101
107
  *openrouter_models,
@@ -109,10 +115,10 @@ class BLACKBOXAI(Provider):
109
115
  ]
110
116
 
111
117
  # Models that support vision capabilities
112
- vision_models = [default_vision_model, 'o3-mini', "Llama 3.2 11B Vision Instruct"] # Added Llama vision
118
+ vision_models = [default_vision_model, 'o3-mini', "Llama 3.2 11B Vision Instruct", "Gemini 2.5 Pro", "Claude Sonnet 4", "Claude Opus 4", "UI-TARS 72B"] # Added Llama vision, Gemini 2.5 Pro, Claude Sonnet 4, Claude Opus 4, and UI-TARS 72B
113
119
 
114
120
  # Models that can be directly selected by users
115
- userSelectedModel = ['o3-mini','Claude-sonnet-3.7', 'Claude-sonnet-3.5', 'DeepSeek-R1', 'Mistral-Small-24B-Instruct-2501'] + openrouter_models
121
+ userSelectedModel = ['o3-mini', 'Claude Opus 4', 'Claude Sonnet 4', 'Claude-sonnet-3.7', 'Claude-sonnet-3.5', 'Grok 3', 'Gemini 2.5 Pro', 'UI-TARS 72B', 'DeepSeek-R1', 'Mistral-Small-24B-Instruct-2501'] + openrouter_models
116
122
 
117
123
  # Agent mode configurations
118
124
  agentMode = {
@@ -161,14 +167,20 @@ class BLACKBOXAI(Provider):
161
167
  'R1 Distill Qwen 14B': {'mode': True, 'id': "deepseek/deepseek-r1-distill-qwen-14b:free", 'name': "R1 Distill Qwen 14B"},
162
168
  'R1 Distill Qwen 32B': {'mode': True, 'id': "deepseek/deepseek-r1-distill-qwen-32b:free", 'name': "R1 Distill Qwen 32B"},
163
169
  # Default models from the new list
170
+ 'Claude Opus 4': {'mode': True, 'id': "anthropic/claude-opus-4", 'name': "Claude Opus 4"},
171
+ 'Claude Sonnet 4': {'mode': True, 'id': "anthropic/claude-sonnet-4", 'name': "Claude Sonnet 4"},
164
172
  'Claude-sonnet-3.7': {'mode': True, 'id': "Claude-sonnet-3.7", 'name': "Claude-sonnet-3.7"},
165
173
  'Claude-sonnet-3.5': {'mode': True, 'id': "Claude-sonnet-3.5", 'name': "Claude-sonnet-3.5"},
174
+ 'Grok 3': {'mode': True, 'id': "x-ai/grok-3-beta", 'name': "Grok 3"},
175
+ 'Gemini 2.5 Pro': {'mode': True, 'id': "google/gemini-2.5-pro-preview-03-25", 'name': "Gemini 2.5 Pro"},
176
+ 'UI-TARS 72B': {'mode': True, 'id': "bytedance-research/ui-tars-72b:free", 'name': "UI-TARS 72B"},
166
177
  'DeepSeek-R1': {'mode': True, 'id': "deepseek-reasoner", 'name': "DeepSeek-R1"}, # This is 'R1' in openrouter, but 'DeepSeek-R1' in base models
167
178
  'Mistral-Small-24B-Instruct-2501': {'mode': True, 'id': "mistralai/Mistral-Small-24B-Instruct-2501", 'name': "Mistral-Small-24B-Instruct-2501"},
168
179
  # Add default_model if it's not covered and has an agent mode
169
180
  default_model: {'mode': True, 'id': "openai/gpt-4.1", 'name': default_model}, # Assuming GPT-4.1 is agent-compatible
170
181
  'o3-mini': {'mode': True, 'id': "o3-mini", 'name': "o3-mini"}, # Assuming o3-mini is agent-compatible
171
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
172
184
  }
173
185
 
174
186
  # Trending agent modes
@@ -224,8 +236,18 @@ class BLACKBOXAI(Provider):
224
236
  "gpt-4.1": default_model,
225
237
  "gpt-4o": default_model, # Defaulting to GPT-4.1 as per previous logic if specific GPT-4o handling isn't defined elsewhere
226
238
  "gpt-4o-mini": default_model, # Defaulting
239
+ "claude-opus-4": "Claude Opus 4",
240
+ "claude-4-opus": "Claude Opus 4",
241
+ "claude-sonnet-4": "Claude Sonnet 4",
242
+ "claude-4-sonnet": "Claude Sonnet 4",
227
243
  "claude-3.7-sonnet": "Claude-sonnet-3.7",
228
244
  "claude-3.5-sonnet": "Claude-sonnet-3.5",
245
+ "grok-3": "Grok 3",
246
+ "grok3": "Grok 3",
247
+ "gemini-2.5-pro": "Gemini 2.5 Pro",
248
+ "gemini-2.5": "Gemini 2.5 Pro",
249
+ "ui-tars-72b": "UI-TARS 72B",
250
+ "ui-tars": "UI-TARS 72B",
229
251
  # "deepseek-r1": "DeepSeek-R1", # This is in base models, maps to R1 or DeepSeek R1 Zero in agentMode
230
252
  #
231
253
  "deepcoder-14b": "Deepcoder 14B Preview",
@@ -307,10 +329,10 @@ class BLACKBOXAI(Provider):
307
329
  '__cf_bm': self.generate_id(32),
308
330
  }
309
331
 
310
- self.__available_optimizers = (
332
+ self.__available_optimizers = [
311
333
  method for method in dir(Optimizers)
312
334
  if callable(getattr(Optimizers, method)) and not method.startswith("__")
313
- )
335
+ ]
314
336
 
315
337
  Conversation.intro = (
316
338
  AwesomePrompts().get_act(
@@ -347,22 +369,79 @@ class BLACKBOXAI(Provider):
347
369
  raise ValueError(f"Unknown model: {model}. Available models: {', '.join(cls.AVAILABLE_MODELS)}")
348
370
 
349
371
  @classmethod
350
- def generate_session(cls, email: str, id_length: int = 21, days_ahead: int = 30) -> dict:
372
+ def generate_session(cls, email: str = None, id_length: int = 21, days_ahead: int = 30) -> dict:
351
373
  """
352
374
  Generate a dynamic session with proper ID and expiry format using a specific email.
375
+ Uses a large hardcoded list of names and domains for diversity.
353
376
 
354
377
  Args:
355
- email: The email to use for this session
378
+ email: The email to use for this session (optional, will be generated if not provided)
356
379
  id_length: Length of the numeric ID (default: 21)
357
380
  days_ahead: Number of days ahead for expiry (default: 30)
358
381
 
359
382
  Returns:
360
383
  dict: A session dictionary with user information and expiry
361
384
  """
362
- # Generate a random name
363
- first_names = ["Alex", "Jordan", "Taylor", "Morgan", "Casey", "Riley", "Avery", "Quinn", "Skyler", "Dakota"]
364
- last_names = ["Smith", "Johnson", "Williams", "Brown", "Jones", "Miller", "Davis", "Garcia", "Rodriguez", "Wilson"]
385
+ # Large list of first and last names
386
+ first_names = [
387
+ "Alex", "Jordan", "Taylor", "Morgan", "Casey", "Riley", "Avery", "Quinn", "Skyler", "Dakota",
388
+ "Jamie", "Cameron", "Drew", "Harper", "Peyton", "Reese", "Rowan", "Sawyer", "Shawn", "Terry",
389
+ "Robin", "Kendall", "Finley", "Blake", "Charlie", "Emerson", "Hayden", "Jesse", "Kai", "Lane",
390
+ "Logan", "Marley", "Micah", "Parker", "Phoenix", "Remy", "Rory", "Sage", "Shiloh", "Spencer",
391
+ "Sydney", "Tatum", "Teagan", "Tristan", "Val", "Winter", "Zion", "Bailey", "Brett", "Case",
392
+ "Corey", "Devon", "Eden", "Ellis", "Frankie", "Gray", "Indigo", "Jaden", "Jules", "Justice",
393
+ "Kieran", "Lake", "Lennon", "Linden", "Luca", "Milan", "Monroe", "Oakley", "Perry", "Quincy",
394
+ "Reagan", "Reed", "Rene", "River", "Robin", "Sasha", "Shane", "Shawn", "Sky", "Sterling",
395
+ "Storm", "Toby", "Vesper", "Wren", "Zane", "Zuri", "Ainsley", "Arden", "Aspen", "Blaine", "Briar",
396
+ "Campbell", "Cleo", "Cruz", "Dallas", "Darby", "Denver", "Echo", "Emery", "Everest", "Hollis",
397
+ "Indy", "Joss", "Karsen", "Kit", "Laken", "Linden", "Lyle", "Marlow", "Merritt", "Nico", "Onyx",
398
+ "Pax", "Peyton", "Quill", "Raleigh", "Reeve", "Ridley", "Rio", "Rylan", "Sailor", "Scout", "Shia",
399
+ "Sonny", "Story", "Tanner", "Tate", "Tegan", "Tiernan", "True", "Vaughn", "Wynn", "Zephyr",
400
+ # Add more names as needed for diversity
401
+ ]
402
+ last_names = [
403
+ "Smith", "Johnson", "Williams", "Brown", "Jones", "Miller", "Davis", "Garcia", "Rodriguez", "Wilson",
404
+ "Martinez", "Anderson", "Taylor", "Thomas", "Hernandez", "Moore", "Martin", "Jackson", "Thompson", "White",
405
+ "Lopez", "Lee", "Gonzalez", "Harris", "Clark", "Lewis", "Robinson", "Walker", "Perez", "Hall",
406
+ "Young", "Allen", "Sanchez", "Wright", "King", "Scott", "Green", "Baker", "AdAMS", "Nelson",
407
+ "Carter", "Mitchell", "Perez", "Roberts", "Turner", "Phillips", "Campbell", "Parker", "Evans", "Edwards",
408
+ "Collins", "Stewart", "Sanchez", "Morris", "Rogers", "Reed", "Cook", "Morgan", "Bell", "Murphy",
409
+ "Bailey", "Rivera", "Cooper", "Richardson", "Cox", "Howard", "Ward", "Torres", "Peterson", "Gray",
410
+ "Ramirez", "James", "Watson", "Brooks", "Kelly", "Sanders", "Price", "Bennett", "Wood", "Barnes",
411
+ "Ross", "Henderson", "Coleman", "Jenkins", "Perry", "Powell", "Long", "Patterson", "Hughes", "Flores",
412
+ "Washington", "Butler", "Simmons", "Foster", "Gonzales", "Bryant", "Alexander", "Russell", "Griffin", "Diaz",
413
+ # Add more last names as needed
414
+ ]
415
+ # Large list of fake domains
416
+ fake_domains = [
417
+ "example.com", "mailinator.com", "fakemail.com", "tempmail.net", "yopmail.com", "testmail.org", "maildrop.cc",
418
+ "inboxkitten.com", "guerrillamail.com", "sharklasers.com", "mailnesia.com", "dispostable.com", "getnada.com",
419
+ "10minutemail.com", "throwawaymail.com", "mailcatch.com", "spambog.com", "mintemail.com", "mail-temp.com",
420
+ "fakeinbox.com", "mytrashmail.com", "trashmail.com", "mailnull.com", "spamgourmet.com", "mailhazard.com",
421
+ "mailbox52.ga", "mailpoof.com", "mailtothis.com", "nowmymail.com", "mailimate.com", "mailboxy.fun",
422
+ "mailbolt.net", "mailblip.com", "mailbucket.org", "mailchimp.biz", "mailclark.ai", "maildog.info",
423
+ "maildrop.cc", "maildu.de", "maileater.com", "mailexpire.com", "mailforspam.com", "mailfreeonline.com",
424
+ "mailhub24.com", "mailimate.com", "mailin8r.com", "mailinator.net", "mailismagic.com", "mailjunk.cf",
425
+ "mailmate.com", "mailme24.com", "mailmoat.com", "mailnator.com", "mailnesia.com", "mailnull.com",
426
+ "mailpick.biz", "mailrock.biz", "mailsac.com", "mailseal.de", "mailtemp.net", "mailtothis.com",
427
+ "mailtrash.net", "mailtv.net", "mailup.net", "mailwire.net", "mailzilla.com", "meltmail.com",
428
+ "moakt.com", "my10minutemail.com", "mytemp.email", "neomailbox.com", "nospamfor.us", "objectmail.com",
429
+ "oneoffemail.com", "owlpic.com", "pookmail.com", "proxymail.eu", "rcpt.at", "sharklasers.com",
430
+ "smellfear.com", "sogetthis.com", "spam4.me", "spamavert.com", "spambob.com", "spambog.com",
431
+ "spambox.us", "spamcannon.com", "spamday.com", "spamex.com", "spamfree24.com", "spamgourmet.com",
432
+ "spamhole.com", "spaminator.de", "spamkill.info", "spaml.com", "spammotel.com", "spamobox.com",
433
+ "spamspot.com", "superrito.com", "teleworm.us", "temp-mail.org", "temp-mail.ru", "tempail.com",
434
+ "tempe-mail.com", "tempemail.co.za", "tempinbox.com", "tempmail.eu", "tempmail.net", "tempmail.us",
435
+ "tempomail.fr", "temporaryemail.net", "thankyou2010.com", "thisisnotmyrealemail.com", "throwam.com",
436
+ "throwawayemailaddress.com", "trash-mail.com", "trash2009.com", "trashdevil.com", "trashemail.de",
437
+ "trashmail.at", "trashmail.com", "trashmail.me", "trashmail.net", "trashymail.com", "trbvm.com",
438
+ "yepmail.net", "yopmail.com", "zoemail.net"
439
+ # Add more as needed
440
+ ]
365
441
  name = f"{random.choice(first_names)} {random.choice(last_names)}"
442
+ if not email:
443
+ domain = random.choice(fake_domains)
444
+ email = f"{name.lower().replace(' ','.')}{random.randint(1,9999)}@{domain}"
366
445
 
367
446
  # Generate numeric ID - using Google-like ID format
368
447
  numeric_id = ''.join(random.choice('0123456789') for _ in range(id_length))
@@ -433,7 +512,34 @@ class BLACKBOXAI(Provider):
433
512
  # Generate a random email for the session
434
513
  chars = string.ascii_lowercase + string.digits
435
514
  random_team = ''.join(random.choice(chars) for _ in range(8))
436
- request_email = f"{random_team}@blackbox.ai"
515
+ # Use a random domain from the fake_domains set for the request email
516
+ fake_domains = [
517
+ "example.com", "mailinator.com", "fakemail.com", "tempmail.net", "yopmail.com", "testmail.org", "maildrop.cc",
518
+ "inboxkitten.com", "guerrillamail.com", "sharklasers.com", "mailnesia.com", "dispostable.com", "getnada.com",
519
+ "10minutemail.com", "throwawaymail.com", "mailcatch.com", "spambog.com", "mintemail.com", "mail-temp.com",
520
+ "fakeinbox.com", "mytrashmail.com", "trashmail.com", "mailnull.com", "spamgourmet.com", "mailhazard.com",
521
+ "mailbox52.ga", "mailpoof.com", "mailtothis.com", "nowmymail.com", "mailimate.com", "mailboxy.fun",
522
+ "mailbolt.net", "mailblip.com", "mailbucket.org", "mailchimp.biz", "mailclark.ai", "maildog.info",
523
+ "maildrop.cc", "maildu.de", "maileater.com", "mailexpire.com", "mailforspam.com", "mailfreeonline.com",
524
+ "mailhub24.com", "mailimate.com", "mailin8r.com", "mailinator.net", "mailismagic.com", "mailjunk.cf",
525
+ "mailmate.com", "mailme24.com", "mailmoat.com", "mailnator.com", "mailnesia.com", "mailnull.com",
526
+ "mailpick.biz", "mailrock.biz", "mailsac.com", "mailseal.de", "mailtemp.net", "mailtothis.com",
527
+ "mailtrash.net", "mailtv.net", "mailup.net", "mailwire.net", "mailzilla.com", "meltmail.com",
528
+ "moakt.com", "my10minutemail.com", "mytemp.email", "neomailbox.com", "nospamfor.us", "objectmail.com",
529
+ "oneoffemail.com", "owlpic.com", "pookmail.com", "proxymail.eu", "rcpt.at", "sharklasers.com",
530
+ "smellfear.com", "sogetthis.com", "spam4.me", "spamavert.com", "spambob.com", "spambog.com",
531
+ "spambox.us", "spamcannon.com", "spamday.com", "spamex.com", "spamfree24.com", "spamgourmet.com",
532
+ "spamhole.com", "spaminator.de", "spamkill.info", "spaml.com", "spammotel.com", "spamobox.com",
533
+ "spamspot.com", "superrito.com", "teleworm.us", "temp-mail.org", "temp-mail.ru", "tempail.com",
534
+ "tempe-mail.com", "tempemail.co.za", "tempinbox.com", "tempmail.eu", "tempmail.net", "tempmail.us",
535
+ "tempomail.fr", "temporaryemail.net", "thankyou2010.com", "thisisnotmyrealemail.com", "throwam.com",
536
+ "throwawayemailaddress.com", "trash-mail.com", "trash2009.com", "trashdevil.com", "trashemail.de",
537
+ "trashmail.at", "trashmail.com", "trashmail.me", "trashmail.net", "trashymail.com", "trbvm.com",
538
+ "yepmail.net", "yopmail.com", "zoemail.net"
539
+ # Add more as needed
540
+ ]
541
+ domain = random.choice(fake_domains)
542
+ request_email = f"{random_team}@{domain}"
437
543
 
438
544
  # Generate a session with the email
439
545
  session_data = self.generate_session(request_email)
@@ -538,15 +644,24 @@ class BLACKBOXAI(Provider):
538
644
  raise exceptions.FailedToGenerateResponseError(error_msg)
539
645
 
540
646
  if stream:
541
- for line in response.iter_lines(decode_unicode=True):
542
- if line:
543
- if "You have reached your request limit for the hour" in line:
544
- raise exceptions.RateLimitError("Rate limit exceeded")
545
- yield line
647
+ buffer = ""
648
+ chunk_size = 32
649
+ for chunk in response.iter_content(chunk_size=chunk_size):
650
+ if not chunk:
651
+ continue
652
+ text = chunk.decode(errors="ignore")
653
+ buffer += text
654
+ while len(buffer) >= chunk_size:
655
+ out = buffer[:chunk_size]
656
+ buffer = buffer[chunk_size:]
657
+ if out.strip():
658
+ yield out
659
+ if buffer.strip():
660
+ yield buffer
546
661
  else:
547
662
  response_text = response.text
548
663
  if "You have reached your request limit for the hour" in response_text:
549
- raise exceptions.RateLimitError("Rate limit exceeded")
664
+ raise exceptions.RatelimitE("Rate limit exceeded")
550
665
  yield response_text
551
666
 
552
667
  except requests.exceptions.RequestException as e:
@@ -651,23 +766,28 @@ class BLACKBOXAI(Provider):
651
766
  return response["text"].replace('\\n', '\n').replace('\\n\\n', '\n\n')
652
767
 
653
768
  if __name__ == "__main__":
654
- print("-" * 80)
655
- print(f"{'Model':<50} {'Status':<10} {'Response'}")
656
- print("-" * 80)
657
-
658
- for model in BLACKBOXAI.AVAILABLE_MODELS:
659
- try:
660
- test_ai = BLACKBOXAI(model=model, timeout=60)
661
- response = test_ai.chat("Say 'Hello' in one word")
662
- response_text = response
769
+ # print("-" * 80)
770
+ # print(f"{'Model':<50} {'Status':<10} {'Response'}")
771
+ # print("-" * 80)
772
+
773
+ # for model in BLACKBOXAI.AVAILABLE_MODELS:
774
+ # try:
775
+ # test_ai = BLACKBOXAI(model=model, timeout=60)
776
+ # response = test_ai.chat("Say 'Hello' in one word")
777
+ # response_text = response
663
778
 
664
- if response_text and len(response_text.strip()) > 0:
665
- status = "✓"
666
- # Truncate response if too long
667
- display_text = response_text.strip()[:50] + "..." if len(response_text.strip()) > 50 else response_text.strip()
668
- else:
669
- status = "✗"
670
- display_text = "Empty or invalid response"
671
- print(f"{model:<50} {status:<10} {display_text}")
672
- except Exception as e:
673
- print(f"{model:<50} {'✗':<10} {str(e)}")
779
+ # if response_text and len(response_text.strip()) > 0:
780
+ # status = "✓"
781
+ # # Truncate response if too long
782
+ # display_text = response_text.strip()[:50] + "..." if len(response_text.strip()) > 50 else response_text.strip()
783
+ # else:
784
+ # status = "✗"
785
+ # display_text = "Empty or invalid response"
786
+ # print(f"{model:<50} {status:<10} {display_text}")
787
+ # except Exception as e:
788
+ # print(f"{model:<50} {'✗':<10} {str(e)}")
789
+
790
+ ai = BLACKBOXAI(model="gpt-4.1", timeout=60)
791
+ response = ai.chat("tell me about humans", stream=True)
792
+ for line in response:
793
+ print(line, end="", flush=True)