webscout 8.2.6__py3-none-any.whl → 8.2.8__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 (150) hide show
  1. webscout/AIauto.py +1 -1
  2. webscout/AIutel.py +298 -239
  3. webscout/Extra/Act.md +309 -0
  4. webscout/Extra/GitToolkit/gitapi/README.md +110 -0
  5. webscout/Extra/YTToolkit/README.md +375 -0
  6. webscout/Extra/YTToolkit/ytapi/README.md +44 -0
  7. webscout/Extra/YTToolkit/ytapi/extras.py +92 -19
  8. webscout/Extra/autocoder/autocoder.py +309 -114
  9. webscout/Extra/autocoder/autocoder_utiles.py +15 -15
  10. webscout/Extra/gguf.md +430 -0
  11. webscout/Extra/tempmail/README.md +488 -0
  12. webscout/Extra/weather.md +281 -0
  13. webscout/Litlogger/Readme.md +175 -0
  14. webscout/Provider/AISEARCH/DeepFind.py +41 -37
  15. webscout/Provider/AISEARCH/README.md +279 -0
  16. webscout/Provider/AISEARCH/__init__.py +0 -1
  17. webscout/Provider/AISEARCH/genspark_search.py +228 -86
  18. webscout/Provider/AISEARCH/hika_search.py +11 -11
  19. webscout/Provider/AISEARCH/scira_search.py +324 -322
  20. webscout/Provider/AllenAI.py +7 -14
  21. webscout/Provider/Blackboxai.py +518 -74
  22. webscout/Provider/Cloudflare.py +0 -1
  23. webscout/Provider/Deepinfra.py +23 -21
  24. webscout/Provider/Flowith.py +217 -0
  25. webscout/Provider/FreeGemini.py +250 -0
  26. webscout/Provider/GizAI.py +15 -5
  27. webscout/Provider/Glider.py +11 -8
  28. webscout/Provider/HeckAI.py +80 -52
  29. webscout/Provider/Koboldai.py +7 -4
  30. webscout/Provider/LambdaChat.py +2 -2
  31. webscout/Provider/Marcus.py +10 -18
  32. webscout/Provider/OPENAI/BLACKBOXAI.py +735 -0
  33. webscout/Provider/OPENAI/Cloudflare.py +378 -0
  34. webscout/Provider/OPENAI/FreeGemini.py +282 -0
  35. webscout/Provider/OPENAI/NEMOTRON.py +244 -0
  36. webscout/Provider/OPENAI/README.md +1253 -0
  37. webscout/Provider/OPENAI/__init__.py +8 -0
  38. webscout/Provider/OPENAI/ai4chat.py +293 -286
  39. webscout/Provider/OPENAI/api.py +810 -0
  40. webscout/Provider/OPENAI/base.py +217 -14
  41. webscout/Provider/OPENAI/c4ai.py +373 -367
  42. webscout/Provider/OPENAI/chatgpt.py +7 -0
  43. webscout/Provider/OPENAI/chatgptclone.py +7 -0
  44. webscout/Provider/OPENAI/chatsandbox.py +172 -0
  45. webscout/Provider/OPENAI/deepinfra.py +30 -20
  46. webscout/Provider/OPENAI/e2b.py +6 -0
  47. webscout/Provider/OPENAI/exaai.py +7 -0
  48. webscout/Provider/OPENAI/exachat.py +6 -0
  49. webscout/Provider/OPENAI/flowith.py +162 -0
  50. webscout/Provider/OPENAI/freeaichat.py +359 -352
  51. webscout/Provider/OPENAI/glider.py +323 -316
  52. webscout/Provider/OPENAI/groq.py +361 -354
  53. webscout/Provider/OPENAI/heckai.py +30 -64
  54. webscout/Provider/OPENAI/llmchatco.py +8 -0
  55. webscout/Provider/OPENAI/mcpcore.py +7 -0
  56. webscout/Provider/OPENAI/multichat.py +8 -0
  57. webscout/Provider/OPENAI/netwrck.py +356 -350
  58. webscout/Provider/OPENAI/opkfc.py +8 -0
  59. webscout/Provider/OPENAI/scirachat.py +471 -462
  60. webscout/Provider/OPENAI/sonus.py +9 -0
  61. webscout/Provider/OPENAI/standardinput.py +9 -1
  62. webscout/Provider/OPENAI/textpollinations.py +339 -329
  63. webscout/Provider/OPENAI/toolbaz.py +7 -0
  64. webscout/Provider/OPENAI/typefully.py +355 -0
  65. webscout/Provider/OPENAI/typegpt.py +358 -346
  66. webscout/Provider/OPENAI/uncovrAI.py +7 -0
  67. webscout/Provider/OPENAI/utils.py +103 -7
  68. webscout/Provider/OPENAI/venice.py +12 -0
  69. webscout/Provider/OPENAI/wisecat.py +19 -19
  70. webscout/Provider/OPENAI/writecream.py +7 -0
  71. webscout/Provider/OPENAI/x0gpt.py +7 -0
  72. webscout/Provider/OPENAI/yep.py +50 -21
  73. webscout/Provider/OpenGPT.py +1 -1
  74. webscout/Provider/TTI/AiForce/README.md +159 -0
  75. webscout/Provider/TTI/FreeAIPlayground/README.md +99 -0
  76. webscout/Provider/TTI/ImgSys/README.md +174 -0
  77. webscout/Provider/TTI/MagicStudio/README.md +101 -0
  78. webscout/Provider/TTI/Nexra/README.md +155 -0
  79. webscout/Provider/TTI/PollinationsAI/README.md +146 -0
  80. webscout/Provider/TTI/README.md +128 -0
  81. webscout/Provider/TTI/aiarta/README.md +134 -0
  82. webscout/Provider/TTI/artbit/README.md +100 -0
  83. webscout/Provider/TTI/fastflux/README.md +129 -0
  84. webscout/Provider/TTI/huggingface/README.md +114 -0
  85. webscout/Provider/TTI/piclumen/README.md +161 -0
  86. webscout/Provider/TTI/pixelmuse/README.md +79 -0
  87. webscout/Provider/TTI/talkai/README.md +139 -0
  88. webscout/Provider/TTS/README.md +192 -0
  89. webscout/Provider/TTS/__init__.py +2 -1
  90. webscout/Provider/TTS/speechma.py +500 -100
  91. webscout/Provider/TTS/sthir.py +94 -0
  92. webscout/Provider/TeachAnything.py +3 -7
  93. webscout/Provider/TextPollinationsAI.py +4 -2
  94. webscout/Provider/{aimathgpt.py → UNFINISHED/ChatHub.py} +88 -68
  95. webscout/Provider/UNFINISHED/liner_api_request.py +263 -0
  96. webscout/Provider/UNFINISHED/oivscode.py +351 -0
  97. webscout/Provider/UNFINISHED/test_lmarena.py +119 -0
  98. webscout/Provider/Writecream.py +11 -2
  99. webscout/Provider/__init__.py +8 -14
  100. webscout/Provider/ai4chat.py +4 -58
  101. webscout/Provider/asksteve.py +17 -9
  102. webscout/Provider/cerebras.py +3 -1
  103. webscout/Provider/koala.py +170 -268
  104. webscout/Provider/llmchat.py +3 -0
  105. webscout/Provider/lmarena.py +198 -0
  106. webscout/Provider/meta.py +7 -4
  107. webscout/Provider/samurai.py +223 -0
  108. webscout/Provider/scira_chat.py +4 -2
  109. webscout/Provider/typefully.py +23 -151
  110. webscout/__init__.py +4 -2
  111. webscout/cli.py +3 -28
  112. webscout/conversation.py +35 -35
  113. webscout/litagent/Readme.md +276 -0
  114. webscout/scout/README.md +402 -0
  115. webscout/swiftcli/Readme.md +323 -0
  116. webscout/version.py +1 -1
  117. webscout/webscout_search.py +2 -182
  118. webscout/webscout_search_async.py +1 -179
  119. webscout/zeroart/README.md +89 -0
  120. webscout/zeroart/__init__.py +134 -54
  121. webscout/zeroart/base.py +19 -13
  122. webscout/zeroart/effects.py +101 -99
  123. webscout/zeroart/fonts.py +1239 -816
  124. {webscout-8.2.6.dist-info → webscout-8.2.8.dist-info}/METADATA +116 -74
  125. {webscout-8.2.6.dist-info → webscout-8.2.8.dist-info}/RECORD +130 -103
  126. {webscout-8.2.6.dist-info → webscout-8.2.8.dist-info}/WHEEL +1 -1
  127. webscout-8.2.8.dist-info/entry_points.txt +3 -0
  128. webscout-8.2.8.dist-info/top_level.txt +1 -0
  129. webscout/Provider/AISEARCH/ISou.py +0 -256
  130. webscout/Provider/ElectronHub.py +0 -773
  131. webscout/Provider/Free2GPT.py +0 -241
  132. webscout/Provider/GPTWeb.py +0 -249
  133. webscout/Provider/bagoodex.py +0 -145
  134. webscout/Provider/geminiprorealtime.py +0 -160
  135. webscout/scout/core.py +0 -881
  136. webscout-8.2.6.dist-info/entry_points.txt +0 -3
  137. webscout-8.2.6.dist-info/top_level.txt +0 -2
  138. webstoken/__init__.py +0 -30
  139. webstoken/classifier.py +0 -189
  140. webstoken/keywords.py +0 -216
  141. webstoken/language.py +0 -128
  142. webstoken/ner.py +0 -164
  143. webstoken/normalizer.py +0 -35
  144. webstoken/processor.py +0 -77
  145. webstoken/sentiment.py +0 -206
  146. webstoken/stemmer.py +0 -73
  147. webstoken/tagger.py +0 -60
  148. webstoken/tokenizer.py +0 -158
  149. /webscout/Provider/{Youchat.py → UNFINISHED/Youchat.py} +0 -0
  150. {webscout-8.2.6.dist-info → webscout-8.2.8.dist-info}/licenses/LICENSE.md +0 -0
@@ -17,7 +17,7 @@ from rich.theme import Theme
17
17
  from rich.live import Live
18
18
  from rich.box import ROUNDED
19
19
  from .autocoder_utiles import get_intro_prompt
20
- # Initialize LitLogger with custom format and colors
20
+ # Initialize LitLogger with custom format and colors
21
21
  default_path = tempfile.mkdtemp(prefix="webscout_autocoder")
22
22
 
23
23
  # Custom theme for consistent styling
@@ -36,7 +36,7 @@ class CommandResult(NamedTuple):
36
36
  success: bool
37
37
  stdout: str
38
38
  stderr: str
39
-
39
+
40
40
  def run_system_command(
41
41
  command: str,
42
42
  exit_on_error: bool = False,
@@ -44,13 +44,13 @@ def run_system_command(
44
44
  help: Optional[str] = None
45
45
  ) -> Tuple[bool, CommandResult]:
46
46
  """Execute a system command and return the result.
47
-
47
+
48
48
  Args:
49
49
  command (str): Command to execute
50
50
  exit_on_error (bool): Whether to exit on error. Defaults to False.
51
51
  stdout_error (bool): Whether to include stdout in error messages. Defaults to False.
52
52
  help (str, optional): Help message for errors. Defaults to None.
53
-
53
+
54
54
  Returns:
55
55
  Tuple[bool, CommandResult]: Success status and command result containing stdout/stderr
56
56
  """
@@ -63,49 +63,49 @@ def run_system_command(
63
63
  shell=True,
64
64
  text=True
65
65
  )
66
-
66
+
67
67
  # Get stdout and stderr
68
68
  stdout, stderr = process.communicate()
69
69
  success = process.returncode == 0
70
-
70
+
71
71
  # Create result object
72
72
  result = CommandResult(
73
73
  success=success,
74
74
  stdout=stdout.strip() if stdout else "",
75
75
  stderr=stderr.strip() if stderr else ""
76
76
  )
77
-
77
+
78
78
  # Handle errors if needed
79
79
  if not success and exit_on_error:
80
80
  error_msg = stderr if stderr else stdout if stdout_error else "Command failed"
81
81
  if help:
82
82
  error_msg += f"\n{help}"
83
83
  sys.exit(error_msg)
84
-
84
+
85
85
  return success, result
86
-
86
+
87
87
  except Exception as e:
88
88
  # Handle execution errors
89
89
  error_msg = str(e)
90
90
  if help:
91
91
  error_msg += f"\n{help}"
92
-
92
+
93
93
  if exit_on_error:
94
94
  sys.exit(error_msg)
95
-
95
+
96
96
  return False, CommandResult(success=False, stdout="", stderr=error_msg)
97
97
 
98
98
 
99
99
  class AutoCoder:
100
100
  """Generate and auto-execute Python scripts in the CLI with advanced error handling and retry logic.
101
-
101
+
102
102
  This class provides:
103
- - Automatic code generation
104
- - Script execution with safety checks
105
- - Advanced error handling and retries
103
+ - Automatic code generation
104
+ - Script execution with safety checks
105
+ - Advanced error handling and retries
106
106
  - Beautiful logging with rich console
107
107
  - Execution result capture and display
108
-
108
+
109
109
  Examples:
110
110
  >>> coder = AutoCoder()
111
111
  >>> coder.execute("Get system info")
@@ -146,7 +146,7 @@ class AutoCoder:
146
146
  self.tried_solutions = set()
147
147
  self.ai_instance = ai_instance
148
148
  self.last_execution_result = ""
149
-
149
+
150
150
  # Get Python version with enhanced logging
151
151
  if self.internal_exec:
152
152
  self.python_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
@@ -163,72 +163,154 @@ class AutoCoder:
163
163
 
164
164
  def _extract_code_blocks(self, response: str) -> List[Tuple[str, str]]:
165
165
  """Extract code blocks from a response string.
166
-
166
+
167
167
  Args:
168
168
  response (str): Response string containing code blocks
169
-
169
+
170
170
  Returns:
171
171
  List[Tuple[str, str]]: List of (code_type, code) tuples
172
172
  """
173
173
  blocks = []
174
-
174
+
175
175
  # First try to find code blocks with explicit language tags
176
176
  pattern = r"```(\w+)\n(.*?)```"
177
177
  matches = re.finditer(pattern, response, re.DOTALL)
178
-
178
+
179
179
  for match in matches:
180
180
  code_type = match.group(1).lower()
181
181
  code = match.group(2).strip()
182
- blocks.append((code_type, code))
183
-
182
+
183
+ # Check if this is a shell command (starts with !)
184
+ if code_type == 'bash' or code_type == 'shell' or code.startswith('!'):
185
+ blocks.append(('shell', code))
186
+ else:
187
+ blocks.append((code_type, code))
188
+
184
189
  # If no explicit code blocks found with language tags, try generic code blocks
185
190
  if not blocks:
186
191
  pattern = r"```(.*?)```"
187
192
  matches = re.finditer(pattern, response, re.DOTALL)
188
193
  for match in matches:
189
194
  code = match.group(1).strip()
190
- blocks.append(('python', code))
191
-
195
+
196
+ # Check if this is a shell command (starts with !)
197
+ if code.startswith('!'):
198
+ blocks.append(('shell', code))
199
+ else:
200
+ blocks.append(('python', code))
201
+
192
202
  # If still no code blocks found, treat as raw Python code
193
203
  if not blocks:
194
204
  lines = [line.strip() for line in response.split('\n') if line.strip()]
195
205
  if lines:
196
- blocks.append(('python', '\n'.join(lines)))
197
-
206
+ # Check if this is a shell command (starts with !)
207
+ if lines[0].startswith('!'):
208
+ blocks.append(('shell', '\n'.join(lines)))
209
+ else:
210
+ blocks.append(('python', '\n'.join(lines)))
211
+
198
212
  return blocks
199
213
 
200
214
  def _execute_code_block(self, code_type: str, code: str, ai_instance=None) -> Tuple[bool, str]:
201
215
  """Execute a code block.
202
-
216
+
203
217
  Args:
204
- code_type (str): Type of code block ('python')
218
+ code_type (str): Type of code block ('python' or 'shell')
205
219
  code (str): Code to execute
206
220
  ai_instance: Optional AI instance for error correction
207
-
221
+
208
222
  Returns:
209
223
  Tuple[bool, str]: (Success status, Error message or execution result)
210
224
  """
211
225
  try:
212
- result = self._execute_with_retry(code, ai_instance)
213
- if result is None:
226
+ # Handle shell commands (starting with !)
227
+ if code_type == 'shell':
228
+ # Remove the leading '!' from each line
229
+ shell_commands = []
230
+ for line in code.split('\n'):
231
+ if line.startswith('!'):
232
+ shell_commands.append(line[1:].strip()) # Remove the '!' and any leading whitespace
233
+ else:
234
+ shell_commands.append(line.strip())
235
+
236
+ # Execute each shell command
237
+ overall_success = True
238
+ overall_result = []
239
+
240
+ # Display the shell command in Jupyter-style UI
241
+ if self.prettify:
242
+ # Format the command for display
243
+ cmd_display = '\n'.join([f"!{cmd}" for cmd in shell_commands if cmd])
244
+ syntax = Syntax(cmd_display, "bash", theme="monokai", line_numbers=True)
245
+ console.print(Panel(
246
+ syntax,
247
+ title="[bold blue]In [1]:[/bold blue]",
248
+ border_style="blue",
249
+ expand=True,
250
+ box=ROUNDED
251
+ ))
252
+
253
+ for cmd in shell_commands:
254
+ if not cmd: # Skip empty commands
255
+ continue
256
+
257
+ success, result = run_system_command(cmd)
258
+
259
+ if success:
260
+ if result.stdout:
261
+ overall_result.append(result.stdout)
262
+
263
+ # Display the output in Jupyter-style UI
264
+ if self.prettify:
265
+ console.print(Panel(
266
+ result.stdout,
267
+ title="[bold red]Out [1]:[/bold red]",
268
+ border_style="red",
269
+ expand=True,
270
+ padding=(0, 1),
271
+ box=ROUNDED
272
+ ))
273
+
274
+ self.last_execution_result = '\n'.join(overall_result)
275
+ else:
276
+ error_msg = result.stderr if result.stderr else f"Command failed: {cmd}"
277
+
278
+ # Display the error in Jupyter-style UI
279
+ if self.prettify:
280
+ console.print(Panel(
281
+ f"Error: {error_msg}",
282
+ title="[bold red]Out [1]:[/bold red]",
283
+ border_style="red",
284
+ expand=True,
285
+ padding=(0, 1),
286
+ box=ROUNDED
287
+ ))
288
+
289
+ return False, error_msg
290
+
214
291
  return True, self.last_execution_result
215
- return False, result
292
+ else:
293
+ # Handle Python code
294
+ result = self._execute_with_retry(code, ai_instance)
295
+ if result is None:
296
+ return True, self.last_execution_result
297
+ return False, result
216
298
  except Exception as e:
217
299
  return False, str(e)
218
300
 
219
301
  def _format_output_panel(self, code: str, output_lines: list) -> Panel:
220
302
  """Format code and output into a single panel.
221
-
303
+
222
304
  Args:
223
305
  code (str): The code that was executed
224
306
  output_lines (list): List of output lines
225
-
307
+
226
308
  Returns:
227
309
  Panel: Formatted panel with code and output
228
310
  """
229
311
  # Format output
230
312
  output_text = "\n".join(output_lines) if output_lines else "Running..."
231
-
313
+
232
314
  # Create panel with Jupyter-like styling
233
315
  panel = Panel(
234
316
  output_text,
@@ -238,15 +320,15 @@ class AutoCoder:
238
320
  padding=(0, 1),
239
321
  box=ROUNDED
240
322
  )
241
-
323
+
242
324
  return panel
243
325
 
244
326
  def _format_result_panel(self, output: str) -> Panel:
245
327
  """Format execution result into a panel.
246
-
328
+
247
329
  Args:
248
330
  output (str): Execution output text
249
-
331
+
250
332
  Returns:
251
333
  Panel: Formatted panel with execution result
252
334
  """
@@ -259,15 +341,15 @@ class AutoCoder:
259
341
  padding=(0, 1),
260
342
  box=ROUNDED
261
343
  )
262
-
344
+
263
345
  return panel
264
346
 
265
347
  def _stream_output(self, process: subprocess.Popen) -> Generator[str, None, None]:
266
348
  """Stream output from a subprocess in realtime.
267
-
349
+
268
350
  Args:
269
351
  process: Subprocess to stream output from
270
-
352
+
271
353
  Yields:
272
354
  str: Lines of output
273
355
  """
@@ -278,7 +360,7 @@ class AutoCoder:
278
360
  if decoded_line:
279
361
  output_lines.append(decoded_line)
280
362
  yield decoded_line
281
-
363
+
282
364
  # Check stderr
283
365
  error = process.stderr.read() if process.stderr else None
284
366
  if error:
@@ -286,13 +368,13 @@ class AutoCoder:
286
368
  if error_str:
287
369
  yield f"Error: {error_str}"
288
370
  output_lines.append(f"Error: {error_str}")
289
-
371
+
290
372
  # Store the full execution result
291
373
  self.last_execution_result = "\n".join(output_lines)
292
374
 
293
375
  def _execute_with_retry(self, code: str, ai_instance=None) -> Optional[str]:
294
376
  """Execute code with retry logic and error correction.
295
-
377
+
296
378
  Args:
297
379
  code (str): Code to execute
298
380
  ai_instance: Optional AI instance for error correction
@@ -302,10 +384,10 @@ class AutoCoder:
302
384
  """
303
385
  last_error = None
304
386
  retries = 0
305
-
387
+
306
388
  # Add the solution to tried solutions
307
389
  self.tried_solutions.add(code)
308
-
390
+
309
391
  # Print the code first
310
392
  if self.prettify:
311
393
  syntax = Syntax(code, "python", theme="monokai", line_numbers=True)
@@ -316,7 +398,7 @@ class AutoCoder:
316
398
  expand=True,
317
399
  box=ROUNDED
318
400
  ))
319
-
401
+
320
402
  while retries < self.max_retries:
321
403
  try:
322
404
  if self.path_to_script:
@@ -325,51 +407,51 @@ class AutoCoder:
325
407
  os.makedirs(script_dir, exist_ok=True)
326
408
  with open(self.path_to_script, "w", encoding="utf-8") as f:
327
409
  f.write(code)
328
-
410
+
329
411
  if self.internal_exec:
330
412
  # Create StringIO for output capture
331
413
  import io
332
414
  import sys
333
415
  stdout = io.StringIO()
334
416
  stderr = io.StringIO()
335
-
417
+
336
418
  # Create a queue for realtime output
337
419
  output_queue = queue.Queue()
338
420
  output_lines = []
339
-
421
+
340
422
  def execute_code():
341
423
  try:
342
424
  # Create a local namespace
343
425
  local_namespace: Dict[str, Any] = {}
344
-
426
+
345
427
  # Redirect stdout/stderr
346
428
  sys.stdout = stdout
347
429
  sys.stderr = stderr
348
-
430
+
349
431
  # Execute the code
350
432
  exec(code, globals(), local_namespace)
351
-
433
+
352
434
  # Get any output
353
435
  output = stdout.getvalue()
354
436
  error = stderr.getvalue()
355
-
437
+
356
438
  if error:
357
439
  output_queue.put(("error", error))
358
440
  if output:
359
441
  output_queue.put(("output", output))
360
-
442
+
361
443
  except Exception as e:
362
444
  output_queue.put(("error", str(e)))
363
445
  finally:
364
446
  # Restore stdout/stderr
365
447
  sys.stdout = sys.__stdout__
366
448
  sys.stderr = sys.__stderr__
367
-
449
+
368
450
  # Create and start execution thread
369
451
  thread = threading.Thread(target=execute_code)
370
452
  thread.daemon = True # Make thread daemon to avoid hanging
371
453
  thread.start()
372
-
454
+
373
455
  # Display output in realtime
374
456
  with Live(auto_refresh=True) as live:
375
457
  timeout_counter = 0
@@ -393,21 +475,21 @@ class AutoCoder:
393
475
  live.update(self._format_output_panel(code, output_lines))
394
476
  live.refresh()
395
477
  continue
396
-
478
+
397
479
  # Wait for thread to complete with timeout
398
480
  thread.join(timeout=30) # 30 second timeout
399
481
  if thread.is_alive():
400
482
  output_lines.append("Error: Execution timed out after 30 seconds")
401
483
  raise TimeoutError("Execution timed out after 30 seconds")
402
-
484
+
403
485
  # Check for any final errors
404
486
  error = stderr.getvalue()
405
487
  if error:
406
488
  raise Exception(error)
407
-
489
+
408
490
  # Store the full execution result
409
491
  self.last_execution_result = stdout.getvalue()
410
-
492
+
411
493
  else:
412
494
  try:
413
495
  process = subprocess.Popen(
@@ -417,7 +499,7 @@ class AutoCoder:
417
499
  text=True, # Use text mode to avoid encoding issues
418
500
  bufsize=1,
419
501
  )
420
-
502
+
421
503
  output_lines = []
422
504
  # Stream output in realtime
423
505
  with Live(auto_refresh=True) as live:
@@ -425,9 +507,9 @@ class AutoCoder:
425
507
  output_lines.append(line)
426
508
  live.update(self._format_output_panel(code, output_lines))
427
509
  live.refresh()
428
-
510
+
429
511
  process.wait(timeout=30) # 30 second timeout
430
-
512
+
431
513
  if process.returncode != 0:
432
514
  # Try to read more detailed error information
433
515
  if process.stderr:
@@ -436,18 +518,18 @@ class AutoCoder:
436
518
  if error_str:
437
519
  raise Exception(error_str)
438
520
  raise Exception(f"Process exited with code {process.returncode}")
439
-
521
+
440
522
  # Store the full execution result
441
523
  self.last_execution_result = "\n".join(output_lines)
442
-
524
+
443
525
  except subprocess.TimeoutExpired:
444
526
  # Handle the case where the process times out
445
527
  if process:
446
528
  process.kill()
447
529
  raise TimeoutError("Execution timed out after 30 seconds")
448
-
530
+
449
531
  return None
450
-
532
+
451
533
  except Exception as e:
452
534
  last_error = e
453
535
  if retries < self.max_retries - 1 and ai_instance:
@@ -459,12 +541,12 @@ class AutoCoder:
459
541
  code = fixed_code
460
542
  retries += 1
461
543
  continue
462
-
544
+
463
545
  # Get error context and try to fix the specific error
464
546
  error_context = self._get_error_context(e, code)
465
547
  fixed_response = ai_instance.chat(error_context)
466
548
  fixed_code = self._extract_code_from_response(fixed_response)
467
-
549
+
468
550
  if not fixed_code:
469
551
  # If no code found, try a more general approach
470
552
  general_context = f"""
@@ -486,10 +568,10 @@ Provide only the corrected code without any explanation.
486
568
  """
487
569
  fixed_response = ai_instance.chat(general_context)
488
570
  fixed_code = self._extract_code_from_response(fixed_response)
489
-
571
+
490
572
  if not fixed_code:
491
573
  break
492
-
574
+
493
575
  if self._is_similar_solution(fixed_code):
494
576
  # If solution is too similar, try a different approach
495
577
  different_context = f"""
@@ -511,34 +593,84 @@ Provide only the corrected code without any explanation.
511
593
  """
512
594
  fixed_response = ai_instance.chat(different_context)
513
595
  fixed_code = self._extract_code_from_response(fixed_response)
514
-
596
+
515
597
  if self._is_similar_solution(fixed_code):
516
598
  break
517
-
599
+
518
600
  # Update code and continue with retry
519
601
  code = fixed_code
520
602
  self.tried_solutions.add(code)
521
603
  retries += 1
522
604
  continue
523
-
605
+
524
606
  except Exception as ai_error:
525
607
  console.print(f"Error during AI correction: {str(ai_error)}", style="error")
526
608
  break
527
609
  break
528
-
610
+
529
611
  return str(last_error) if last_error else "Unknown error occurred"
530
612
 
531
613
  def execute(self, prompt: str, ai_instance=None) -> bool:
532
614
  """Execute the given prompt using the appropriate executor.
533
-
615
+
534
616
  Args:
535
617
  prompt (str): Prompt to execute
536
618
  ai_instance: Optional AI instance for error correction
537
-
619
+
538
620
  Returns:
539
621
  bool: True if execution was successful, False otherwise
540
622
  """
541
623
  try:
624
+ # Check if this is a direct shell command (starts with !)
625
+ if prompt.strip().startswith('!'):
626
+ # Handle shell command
627
+ cmd = prompt.strip()[1:].strip() # Remove the '!' and any leading whitespace
628
+
629
+ # Display the shell command in Jupyter-style UI
630
+ if self.prettify:
631
+ syntax = Syntax(f"!{cmd}", "bash", theme="monokai", line_numbers=True)
632
+ console.print(Panel(
633
+ syntax,
634
+ title="[bold blue]In [1]:[/bold blue]",
635
+ border_style="blue",
636
+ expand=True,
637
+ box=ROUNDED
638
+ ))
639
+
640
+ success, result = run_system_command(cmd)
641
+
642
+ if success:
643
+ if result.stdout:
644
+ # Display the output in Jupyter-style UI
645
+ if self.prettify:
646
+ console.print(Panel(
647
+ result.stdout,
648
+ title="[bold red]Out [1]:[/bold red]",
649
+ border_style="red",
650
+ expand=True,
651
+ padding=(0, 1),
652
+ box=ROUNDED
653
+ ))
654
+ else:
655
+ console.print(result.stdout, style="output")
656
+ self.last_execution_result = result.stdout
657
+ return True
658
+ else:
659
+ error_msg = result.stderr if result.stderr else f"Command failed: {cmd}"
660
+ # Display the error in Jupyter-style UI
661
+ if self.prettify:
662
+ console.print(Panel(
663
+ f"Error: {error_msg}",
664
+ title="[bold red]Out [1]:[/bold red]",
665
+ border_style="red",
666
+ expand=True,
667
+ padding=(0, 1),
668
+ box=ROUNDED
669
+ ))
670
+ else:
671
+ console.print(error_msg, style="error")
672
+ return False
673
+
542
674
  # Extract code blocks
543
675
  code_blocks = self._extract_code_blocks(prompt)
544
676
  if not code_blocks:
@@ -549,61 +681,60 @@ Provide only the corrected code without any explanation.
549
681
  overall_success = True
550
682
  for code_type, code in code_blocks:
551
683
  success, result = self._execute_code_block(code_type, code, ai_instance)
552
-
684
+
553
685
  if not success:
554
686
  console.print(f"Execution failed: {result}", style="error")
555
687
  overall_success = False
556
688
 
557
689
  return overall_success
558
-
690
+
559
691
  except Exception as e:
560
692
  console.print(f"Error in execution: {str(e)}", style="error")
561
693
  return False
562
694
 
563
695
  def _extract_code_from_response(self, response: str) -> str:
564
696
  """Extract code from AI response.
565
-
697
+
566
698
  Args:
567
699
  response (str): AI response containing code blocks
568
-
700
+
569
701
  Returns:
570
702
  str: Extracted code from the first code block
571
703
  """
572
704
  if not response:
573
705
  return ""
574
-
706
+
575
707
  # First try to find code blocks with explicit language tags
576
708
  code_blocks = self._extract_code_blocks(response)
577
709
  if code_blocks:
578
710
  # Return the content of the first code block
579
711
  return code_blocks[0][1]
580
-
581
- # If no code blocks found, try to find raw Python code
712
+
713
+ # If no code blocks found, try to find raw Python code or shell commands
582
714
  lines = []
583
- in_code = False
584
715
  for line in response.split('\n'):
585
716
  line = line.strip()
586
717
  if not line:
587
718
  continue
588
-
719
+
589
720
  # Skip markdown headers and other non-code lines
590
721
  if line.startswith(('#', '```', '---', '===', '>>>')):
591
722
  continue
592
-
723
+
593
724
  # Skip common non-code lines
594
725
  if any(line.startswith(prefix) for prefix in ['Please', 'Here', 'The', 'This', 'You']):
595
726
  continue
596
-
727
+
597
728
  lines.append(line)
598
-
729
+
599
730
  if lines:
600
731
  return '\n'.join(lines)
601
-
732
+
602
733
  return ""
603
734
 
604
735
  def _get_error_context(self, error: Exception, code: str) -> str:
605
736
  """Create context about the error for AI correction.
606
-
737
+
607
738
  Args:
608
739
  error (Exception): The caught exception
609
740
  code (str): The code that caused the error
@@ -613,18 +744,18 @@ Provide only the corrected code without any explanation.
613
744
  """
614
745
  error_type = type(error).__name__
615
746
  error_msg = str(error)
616
-
747
+
617
748
  # Get Python version and environment info
618
749
  python_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
619
750
  platform = sys.platform
620
-
751
+
621
752
  # Get the line number where the error occurred if available
622
753
  import traceback
623
754
  tb = traceback.extract_tb(error.__traceback__)
624
755
  line_info = ""
625
756
  if tb:
626
757
  line_info = f"\nError occurred at line {tb[-1].lineno}"
627
-
758
+
628
759
  return f"""
629
760
  The code failed with error:
630
761
  Error Type: {error_type}
@@ -651,7 +782,7 @@ Provide only the corrected code without any explanation.
651
782
 
652
783
  def _handle_import_error(self, error: ImportError, code: str) -> Optional[str]:
653
784
  """Handle missing package errors by attempting to install them.
654
-
785
+
655
786
  Args:
656
787
  error (ImportError): The import error
657
788
  code (str): The code that caused the error
@@ -662,7 +793,7 @@ Provide only the corrected code without any explanation.
662
793
  try:
663
794
  missing_package = str(error).split("'")[1] if "'" in str(error) else str(error).split("No module named")[1].strip()
664
795
  missing_package = missing_package.replace("'", "").strip()
665
-
796
+
666
797
  console.print(f"Installing missing package: {missing_package}", style="info")
667
798
  result = subprocess.run(
668
799
  [sys.executable, "-m", "pip", "install", missing_package],
@@ -680,7 +811,7 @@ Provide only the corrected code without any explanation.
680
811
 
681
812
  def _is_similar_solution(self, new_code: str, threshold: float = 0.8) -> bool:
682
813
  """Check if the new solution is too similar to previously tried ones.
683
-
814
+
684
815
  Args:
685
816
  new_code (str): New solution to check
686
817
  threshold (float): Similarity threshold (0-1). Defaults to 0.8.
@@ -689,13 +820,13 @@ Provide only the corrected code without any explanation.
689
820
  bool: True if solution is too similar to previous attempts
690
821
  """
691
822
  import difflib
692
-
823
+
693
824
  def normalize_code(code: str) -> str:
694
825
  lines = [line.split('#')[0].strip() for line in code.split('\n')]
695
826
  return '\n'.join(line for line in lines if line)
696
-
827
+
697
828
  new_code_norm = normalize_code(new_code)
698
-
829
+
699
830
  for tried_code in self.tried_solutions:
700
831
  tried_code_norm = normalize_code(tried_code)
701
832
  similarity = difflib.SequenceMatcher(None, new_code_norm, tried_code_norm).ratio()
@@ -715,12 +846,75 @@ Provide only the corrected code without any explanation.
715
846
  if not response:
716
847
  return "No response provided"
717
848
 
849
+ # Check if this is a shell command (starts with !)
850
+ if response.strip().startswith('!'):
851
+ # Handle shell command
852
+ cmd = response.strip()[1:].strip() # Remove the '!' and any leading whitespace
853
+
854
+ # Display the shell command in Jupyter-style UI
855
+ if self.prettify:
856
+ syntax = Syntax(f"!{cmd}", "bash", theme="monokai", line_numbers=True)
857
+ console.print(Panel(
858
+ syntax,
859
+ title="[bold blue]In [1]:[/bold blue]",
860
+ border_style="blue",
861
+ expand=True,
862
+ box=ROUNDED
863
+ ))
864
+
865
+ success, result = run_system_command(cmd)
866
+
867
+ if success:
868
+ if result.stdout:
869
+ # Display the output in Jupyter-style UI
870
+ if self.prettify:
871
+ console.print(Panel(
872
+ result.stdout,
873
+ title="[bold red]Out [1]:[/bold red]",
874
+ border_style="red",
875
+ expand=True,
876
+ padding=(0, 1),
877
+ box=ROUNDED
878
+ ))
879
+ self.last_execution_result = result.stdout
880
+ return None
881
+ else:
882
+ error_msg = result.stderr if result.stderr else f"Command failed: {cmd}"
883
+ # Display the error in Jupyter-style UI
884
+ if self.prettify:
885
+ console.print(Panel(
886
+ f"Error: {error_msg}",
887
+ title="[bold red]Out [1]:[/bold red]",
888
+ border_style="red",
889
+ expand=True,
890
+ padding=(0, 1),
891
+ box=ROUNDED
892
+ ))
893
+ else:
894
+ console.print(error_msg, style="error")
895
+ return error_msg
896
+
897
+ # Extract code blocks
898
+ code_blocks = self._extract_code_blocks(response)
899
+ if code_blocks:
900
+ code_type, code = code_blocks[0]
901
+
902
+ # Handle shell commands
903
+ if code_type == 'shell':
904
+ success, result = self._execute_code_block(code_type, code)
905
+ if success:
906
+ return None
907
+ else:
908
+ # Error is already displayed in _execute_code_block
909
+ return result
910
+
911
+ # Handle regular Python code
718
912
  code = self._extract_code_from_response(response)
719
913
  if not code:
720
914
  return "No executable code found in the response"
721
-
915
+
722
916
  ai_instance = self.ai_instance or globals().get('ai')
723
-
917
+
724
918
  if not ai_instance:
725
919
  console.print("AI instance not found, error correction disabled", style="warning")
726
920
  try:
@@ -730,18 +924,18 @@ Provide only the corrected code without any explanation.
730
924
  os.makedirs(script_dir, exist_ok=True)
731
925
  with open(self.path_to_script, "w", encoding="utf-8") as f:
732
926
  f.write(code)
733
-
927
+
734
928
  if self.internal_exec:
735
929
  console.print("[INFO] Executing code internally", style="info")
736
930
  # Create a local namespace
737
931
  local_namespace: Dict[str, Any] = {}
738
-
932
+
739
933
  # Capture stdout
740
934
  import io
741
935
  old_stdout = sys.stdout
742
936
  captured_output = io.StringIO()
743
937
  sys.stdout = captured_output
744
-
938
+
745
939
  # Execute the code
746
940
  try:
747
941
  exec(code, globals(), local_namespace)
@@ -758,23 +952,23 @@ Provide only the corrected code without any explanation.
758
952
  text=True
759
953
  )
760
954
  self.last_execution_result = result.stdout
761
-
955
+
762
956
  if result.returncode != 0:
763
957
  raise Exception(result.stderr or result.stdout)
764
-
958
+
765
959
  return None
766
960
  except Exception as e:
767
961
  error_msg = f"Execution error: {str(e)}"
768
962
  console.print(error_msg, style="error")
769
963
  return error_msg
770
-
964
+
771
965
  result = self._execute_with_retry(code, ai_instance)
772
966
  return result
773
967
 
774
968
  @property
775
969
  def intro_prompt(self) -> str:
776
970
  """Get the introduction prompt.
777
-
971
+
778
972
  Returns:
779
973
  str: Introduction prompt
780
974
  """
@@ -858,10 +1052,11 @@ Provide only the corrected code without any explanation.
858
1052
  # If not Python code, treat as plain text
859
1053
  formatted_output = output
860
1054
 
1055
+ # Use the style parameter for the panel border
861
1056
  console.print(Panel(
862
1057
  formatted_output,
863
1058
  title="[bold red]Out [1]:[/bold red]",
864
- border_style="red",
1059
+ border_style=style if style != "output" else "red",
865
1060
  expand=True,
866
1061
  padding=(0, 1),
867
1062
  box=ROUNDED
@@ -903,8 +1098,8 @@ Provide only the corrected code without any explanation.
903
1098
  table = Table(show_header=True, header_style="bold cyan")
904
1099
  for header in headers:
905
1100
  table.add_column(header)
906
-
1101
+
907
1102
  for row in rows:
908
1103
  table.add_row(*[str(cell) for cell in row])
909
-
1104
+
910
1105
  console.print(table)