pygpt-net 2.4.39__py3-none-any.whl → 2.4.40__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.
Files changed (85) hide show
  1. CHANGELOG.md +13 -0
  2. README.md +19 -2
  3. pygpt_net/CHANGELOG.txt +13 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/controller/__init__.py +5 -3
  6. pygpt_net/controller/audio/__init__.py +9 -1
  7. pygpt_net/controller/chat/input.py +2 -1
  8. pygpt_net/controller/chat/render.py +2 -2
  9. pygpt_net/controller/ctx/__init__.py +2 -2
  10. pygpt_net/controller/debug/__init__.py +13 -2
  11. pygpt_net/controller/kernel/__init__.py +2 -1
  12. pygpt_net/controller/notepad.py +7 -6
  13. pygpt_net/controller/theme/nodes.py +2 -5
  14. pygpt_net/controller/tools/__init__.py +37 -1
  15. pygpt_net/controller/ui/__init__.py +1 -5
  16. pygpt_net/controller/ui/tabs.py +104 -12
  17. pygpt_net/core/command.py +3 -1
  18. pygpt_net/core/ctx/__init__.py +6 -2
  19. pygpt_net/core/ctx/container.py +5 -5
  20. pygpt_net/core/debug/tabs.py +3 -1
  21. pygpt_net/core/render/base.py +2 -2
  22. pygpt_net/core/render/web/body.py +1 -1
  23. pygpt_net/core/render/web/renderer.py +208 -38
  24. pygpt_net/core/tabs/__init__.py +104 -43
  25. pygpt_net/core/tabs/tab.py +4 -1
  26. pygpt_net/core/web.py +127 -1
  27. pygpt_net/data/config/config.json +4 -3
  28. pygpt_net/data/config/models.json +3 -3
  29. pygpt_net/data/config/modes.json +3 -3
  30. pygpt_net/data/css/web-blocks.css +18 -0
  31. pygpt_net/data/css/web-blocks.light.css +7 -0
  32. pygpt_net/data/css/web-chatgpt.css +8 -0
  33. pygpt_net/data/css/web-chatgpt_wide.css +8 -0
  34. pygpt_net/data/icons/split_screen.svg +1 -0
  35. pygpt_net/data/locale/locale.de.ini +1 -1
  36. pygpt_net/data/locale/locale.en.ini +4 -2
  37. pygpt_net/data/locale/locale.es.ini +1 -1
  38. pygpt_net/data/locale/locale.fr.ini +1 -1
  39. pygpt_net/data/locale/locale.it.ini +1 -1
  40. pygpt_net/data/locale/locale.pl.ini +2 -2
  41. pygpt_net/data/locale/locale.uk.ini +1 -1
  42. pygpt_net/data/locale/locale.zh.ini +1 -1
  43. pygpt_net/data/locale/plugin.cmd_web.de.ini +2 -0
  44. pygpt_net/data/locale/plugin.cmd_web.en.ini +20 -10
  45. pygpt_net/data/locale/plugin.cmd_web.es.ini +2 -0
  46. pygpt_net/data/locale/plugin.cmd_web.fr.ini +2 -0
  47. pygpt_net/data/locale/plugin.cmd_web.it.ini +2 -0
  48. pygpt_net/data/locale/plugin.cmd_web.pl.ini +2 -0
  49. pygpt_net/data/locale/plugin.cmd_web.uk.ini +2 -0
  50. pygpt_net/data/locale/plugin.cmd_web.zh.ini +2 -0
  51. pygpt_net/icons.qrc +1 -0
  52. pygpt_net/icons_rc.py +165 -136
  53. pygpt_net/item/ctx.py +46 -24
  54. pygpt_net/plugin/audio_output/__init__.py +4 -1
  55. pygpt_net/plugin/base/plugin.py +18 -4
  56. pygpt_net/plugin/cmd_code_interpreter/__init__.py +39 -37
  57. pygpt_net/plugin/cmd_code_interpreter/runner.py +25 -12
  58. pygpt_net/plugin/cmd_web/__init__.py +46 -6
  59. pygpt_net/plugin/cmd_web/config.py +74 -48
  60. pygpt_net/plugin/cmd_web/websearch.py +61 -28
  61. pygpt_net/plugin/cmd_web/worker.py +79 -13
  62. pygpt_net/provider/core/config/patch.py +22 -1
  63. pygpt_net/tools/__init__.py +9 -1
  64. pygpt_net/tools/base.py +15 -1
  65. pygpt_net/tools/code_interpreter/__init__.py +174 -75
  66. pygpt_net/tools/code_interpreter/ui/dialogs.py +21 -103
  67. pygpt_net/tools/code_interpreter/ui/widgets.py +284 -9
  68. pygpt_net/tools/html_canvas/__init__.py +78 -23
  69. pygpt_net/tools/html_canvas/ui/dialogs.py +46 -62
  70. pygpt_net/tools/html_canvas/ui/widgets.py +96 -3
  71. pygpt_net/ui/base/context_menu.py +2 -2
  72. pygpt_net/ui/layout/ctx/ctx_list.py +13 -4
  73. pygpt_net/ui/layout/toolbox/footer.py +1 -1
  74. pygpt_net/ui/main.py +2 -2
  75. pygpt_net/ui/menu/debug.py +11 -1
  76. pygpt_net/ui/widget/filesystem/explorer.py +2 -2
  77. pygpt_net/ui/widget/lists/context.py +26 -5
  78. pygpt_net/ui/widget/tabs/Input.py +2 -2
  79. pygpt_net/ui/widget/tabs/body.py +2 -1
  80. pygpt_net/ui/widget/tabs/output.py +126 -61
  81. {pygpt_net-2.4.39.dist-info → pygpt_net-2.4.40.dist-info}/METADATA +20 -3
  82. {pygpt_net-2.4.39.dist-info → pygpt_net-2.4.40.dist-info}/RECORD +85 -84
  83. {pygpt_net-2.4.39.dist-info → pygpt_net-2.4.40.dist-info}/LICENSE +0 -0
  84. {pygpt_net-2.4.39.dist-info → pygpt_net-2.4.40.dist-info}/WHEEL +0 -0
  85. {pygpt_net-2.4.39.dist-info → pygpt_net-2.4.40.dist-info}/entry_points.txt +0 -0
pygpt_net/core/command.py CHANGED
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.11.21 20:00:00 #
9
+ # Updated Date: 2024.12.13 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -18,6 +18,7 @@ from pygpt_net.core.types import (
18
18
  MODE_COMPLETION,
19
19
  MODE_LANGCHAIN,
20
20
  MODE_LLAMA_INDEX,
21
+ MODE_AUDIO,
21
22
  )
22
23
  from pygpt_net.core.events import Event
23
24
  from pygpt_net.item.ctx import CtxItem
@@ -537,6 +538,7 @@ class Command:
537
538
  MODE_LLAMA_INDEX,
538
539
  MODE_LANGCHAIN,
539
540
  MODE_COMPLETION,
541
+ MODE_AUDIO,
540
542
  ]
541
543
  mode = self.window.core.config.get('mode')
542
544
  if mode in disabled_modes:
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.12.09 00:00:00 #
9
+ # Updated Date: 2024.12.13 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -1371,10 +1371,13 @@ class Ctx:
1371
1371
  """
1372
1372
  prev_ctx = CtxItem()
1373
1373
  prev_ctx.urls = copy.deepcopy(ctx.urls)
1374
+ prev_ctx.urls_before = copy.deepcopy(ctx.urls_before)
1374
1375
  prev_ctx.images = copy.deepcopy(ctx.images)
1375
1376
  prev_ctx.images_before = copy.deepcopy(ctx.images_before)
1376
1377
  prev_ctx.files = copy.deepcopy(ctx.files)
1378
+ prev_ctx.files_before = copy.deepcopy(ctx.files_before)
1377
1379
  prev_ctx.attachments = copy.deepcopy(ctx.attachments)
1380
+ prev_ctx.attachments_before = copy.deepcopy(ctx.attachments_before)
1378
1381
  prev_ctx.results = copy.deepcopy(ctx.results)
1379
1382
  prev_ctx.index_meta = copy.deepcopy(ctx.index_meta)
1380
1383
  prev_ctx.doc_ids = copy.deepcopy(ctx.doc_ids)
@@ -1382,7 +1385,8 @@ class Ctx:
1382
1385
  prev_ctx.output_name = copy.deepcopy(ctx.output_name)
1383
1386
 
1384
1387
  ctx.clear_reply() # clear current reply result
1385
- ctx.from_previous() # get result from previous if exists
1388
+ if len(ctx.cmds) == 0:
1389
+ ctx.from_previous() # get result from previous if exists
1386
1390
  return prev_ctx
1387
1391
 
1388
1392
  def dump(self, ctx: CtxItem) -> str:
@@ -6,15 +6,15 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.12.09 00:00:00 #
9
+ # Updated Date: 2024.12.12 04:00:00 #
10
10
  # ================================================== #
11
11
 
12
- from PySide6.QtWidgets import QVBoxLayout
12
+ from PySide6.QtWidgets import QVBoxLayout, QWidget
13
13
 
14
- from .bag import Bag
14
+ from pygpt_net.core.tabs.tab import Tab
15
15
  from pygpt_net.ui.widget.textarea.output import ChatOutput
16
- from ..tabs import Tab
17
16
 
17
+ from .bag import Bag
18
18
 
19
19
  class Container:
20
20
  def __init__(self, window=None):
@@ -27,7 +27,7 @@ class Container:
27
27
  self.bags = {}
28
28
  self.bags[0] = Bag(window) # always create initial bag
29
29
 
30
- def get(self, tab: Tab):
30
+ def get(self, tab: Tab) -> QWidget:
31
31
  """
32
32
  Register and return output
33
33
 
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.12.09 00:00:00 #
9
+ # Updated Date: 2024.12.12 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  class TabsDebug:
@@ -27,6 +27,8 @@ class TabsDebug:
27
27
  self.window.core.debug.add(self.id, 'current Type', str(self.window.controller.ui.tabs.get_current_type()))
28
28
  self.window.core.debug.add(self.id, 'current Column', str(self.window.controller.ui.tabs.get_current_column_idx()))
29
29
  self.window.core.debug.add(self.id, 'last_pid', str(self.window.core.tabs.last_pid))
30
+ self.window.core.debug.add(self.id, 'locked', str(self.window.controller.ui.tabs.locked))
31
+ self.window.core.debug.add(self.id, 'col', str(self.window.controller.ui.tabs.col))
30
32
  self.window.core.debug.add(self.id, 'count(pids)', str(len(self.window.core.tabs.pids)))
31
33
  self.window.core.debug.add(self.id, 'count(ctx bags)', str(len(self.window.core.ctx.container.bags)))
32
34
  self.window.core.debug.add(self.id, '----', '')
@@ -6,10 +6,10 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.12.09 00:00:00 #
9
+ # Updated Date: 2024.12.12 04:00:00 #
10
10
  # ================================================== #
11
11
 
12
- from pygpt_net.core.tabs import Tab
12
+ from pygpt_net.core.tabs.tab import Tab
13
13
  from pygpt_net.item.ctx import CtxItem, CtxMeta
14
14
 
15
15
 
@@ -207,7 +207,7 @@ class Body:
207
207
  num_str = ""
208
208
  if num is not None and num_all is not None and num_all > 1:
209
209
  num_str = " [{}]".format(num)
210
- return """{icon}<b>{num}</b> <a href="{url}" title="{url}">{url}</a>""". \
210
+ return """{icon}<a href="{url}" title="{url}">{url}</a> <small>{num}</small>""". \
211
211
  format(url=url,
212
212
  num=num_str,
213
213
  icon=icon,
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.12.09 03:00:00 #
9
+ # Updated Date: 2024.12.13 19:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import json
@@ -19,7 +19,7 @@ from pygpt_net.core.text.utils import has_unclosed_code_tag
19
19
  from pygpt_net.item.ctx import CtxItem, CtxMeta
20
20
  from pygpt_net.ui.widget.textarea.input import ChatInput
21
21
  from pygpt_net.utils import trans
22
- from pygpt_net.core.tabs import Tab
22
+ from pygpt_net.core.tabs.tab import Tab
23
23
 
24
24
  from .body import Body
25
25
  from .helpers import Helpers
@@ -167,7 +167,7 @@ class Renderer(BaseRenderer):
167
167
  :param meta: context meta
168
168
  :param ctx: context item
169
169
  """
170
- pass # do nothing
170
+ pass
171
171
 
172
172
  def stream_end(self, meta: CtxMeta, ctx: CtxItem):
173
173
  """
@@ -182,7 +182,12 @@ class Renderer(BaseRenderer):
182
182
  self.append_context_item(meta, self.pids[pid].item)
183
183
  self.pids[pid].item = None
184
184
 
185
- def append_context(self, meta: CtxMeta, items: list, clear: bool = True):
185
+ def append_context(
186
+ self,
187
+ meta: CtxMeta,
188
+ items: list,
189
+ clear: bool = True
190
+ ):
186
191
  """
187
192
  Append all context to output
188
193
 
@@ -203,22 +208,37 @@ class Renderer(BaseRenderer):
203
208
 
204
209
  self.pids[pid].use_buffer = True
205
210
  self.pids[pid].html = ""
211
+ prev_ctx = None
206
212
  for item in items:
207
213
  self.update_names(meta, item)
208
214
  item.idx = i
209
215
  if i == 0:
210
216
  item.first = True
211
217
  next_item = items[i + 1] if i + 1 < len(items) else None # append next item if exists
212
- self.append_context_item(meta, item, next_item) # to html buffer
218
+ self.append_context_item(
219
+ meta,
220
+ item,
221
+ prev_ctx=prev_ctx,
222
+ next_ctx=next_item
223
+ ) # to html buffer
224
+ prev_ctx = item
213
225
  i += 1
214
226
  self.pids[pid].use_buffer = False
215
227
 
216
228
  # flush
217
229
  if self.pids[pid].html != "":
218
- self.append(pid, self.pids[pid].html,
219
- flush=True) # flush buffer if page loaded, otherwise it will be flushed on page load
220
-
221
- def append_input(self, meta: CtxMeta, ctx: CtxItem, flush: bool = True, append: bool = False):
230
+ self.append(
231
+ pid,
232
+ self.pids[pid].html,
233
+ flush=True
234
+ ) # flush buffer if page loaded, otherwise it will be flushed on page load
235
+
236
+ def append_input(
237
+ self, meta: CtxMeta,
238
+ ctx: CtxItem,
239
+ flush: bool = True,
240
+ append: bool = False
241
+ ):
222
242
  """
223
243
  Append text input to output
224
244
 
@@ -250,29 +270,49 @@ class Renderer(BaseRenderer):
250
270
  text = re.sub(r'^user: ', '> ', ctx.input)
251
271
 
252
272
  if flush: # to chunk buffer
253
- content = self.prepare_node(meta, ctx, text.strip(), self.NODE_INPUT)
254
273
  if self.is_stream() and not append:
274
+ content = self.prepare_node(meta, ctx, text.strip(), self.NODE_INPUT)
255
275
  self.append_chunk_input(meta, ctx, content, False)
256
- else:
257
- self.append_node(meta, ctx, text.strip(), self.NODE_INPUT)
258
- else:
259
- self.append_node(meta, ctx, text.strip(), self.NODE_INPUT)
276
+ return
277
+
278
+ self.append_node(meta, ctx, text.strip(), self.NODE_INPUT)
260
279
 
261
- def append_output(self, meta: CtxMeta, ctx: CtxItem, flush: bool = True, next_ctx: CtxItem = None):
280
+ def append_output(
281
+ self,
282
+ meta: CtxMeta,
283
+ ctx: CtxItem,
284
+ flush: bool = True,
285
+ prev_ctx: CtxItem = None,
286
+ next_ctx: CtxItem = None
287
+ ):
262
288
  """
263
289
  Append text output to output
264
290
 
265
291
  :param meta: context meta
266
292
  :param ctx: context item
267
293
  :param flush: flush HTML
294
+ :param prev_ctx: previous context
268
295
  :param next_ctx: next context
269
296
  """
270
297
  self.tool_output_end() # reset tools
271
298
  if ctx.output is None or ctx.output == "":
272
299
  return
273
- self.append_node(meta, ctx, ctx.output.strip(), self.NODE_OUTPUT, next_ctx)
300
+ self.append_node(
301
+ meta=meta,
302
+ ctx=ctx,
303
+ html=ctx.output.strip(),
304
+ type=self.NODE_OUTPUT,
305
+ prev_ctx=prev_ctx,
306
+ next_ctx=next_ctx
307
+ )
274
308
 
275
- def append_chunk(self, meta: CtxMeta, ctx: CtxItem, text_chunk: str, begin: bool = False):
309
+ def append_chunk(
310
+ self,
311
+ meta: CtxMeta,
312
+ ctx: CtxItem,
313
+ text_chunk: str,
314
+ begin: bool = False
315
+ ):
276
316
  """
277
317
  Append output chunk to output
278
318
 
@@ -291,6 +331,12 @@ class Renderer(BaseRenderer):
291
331
  self.update_names(meta, ctx)
292
332
  raw_chunk = str(text_chunk)
293
333
  if begin:
334
+ # debug
335
+ debug = ""
336
+ if self.is_debug():
337
+ debug = self.append_debug(ctx, pid, "stream")
338
+ if debug:
339
+ raw_chunk = debug + raw_chunk
294
340
  self.pids[pid].buffer = "" # reset buffer
295
341
  self.pids[pid].is_cmd = False # reset command flag
296
342
  self.clear_chunks_output(pid)
@@ -318,7 +364,13 @@ class Renderer(BaseRenderer):
318
364
  except Exception as e:
319
365
  pass
320
366
 
321
- def append_chunk_input(self, meta: CtxMeta, ctx: CtxItem, text_chunk: str, begin: bool = False):
367
+ def append_chunk_input(
368
+ self,
369
+ meta: CtxMeta,
370
+ ctx: CtxItem,
371
+ text_chunk: str,
372
+ begin: bool = False
373
+ ):
322
374
  """
323
375
  Append output chunk to output
324
376
 
@@ -341,7 +393,15 @@ class Renderer(BaseRenderer):
341
393
  except Exception as e:
342
394
  pass
343
395
 
344
- def append_node(self, meta: CtxMeta, ctx: CtxItem, html: str, type: int = 1, next_ctx: CtxItem = None):
396
+ def append_node(
397
+ self,
398
+ meta: CtxMeta,
399
+ ctx: CtxItem,
400
+ html: str,
401
+ type: int = 1,
402
+ prev_ctx: CtxItem = None,
403
+ next_ctx: CtxItem = None
404
+ ):
345
405
  """
346
406
  Append and format raw text to output
347
407
 
@@ -349,15 +409,31 @@ class Renderer(BaseRenderer):
349
409
  :param html: text to append
350
410
  :param type: type of message
351
411
  :param ctx: CtxItem instance
412
+ :param prev_ctx: previous context item
352
413
  :param next_ctx: next context item
353
414
  """
354
415
  if ctx.hidden:
355
416
  return
356
417
 
357
418
  pid = self.get_or_create_pid(meta)
358
- self.append(pid, self.prepare_node(meta, ctx, html, type, next_ctx))
419
+ self.append(
420
+ pid,
421
+ self.prepare_node(
422
+ meta=meta,
423
+ ctx=ctx,
424
+ html=html,
425
+ type=type,
426
+ prev_ctx=prev_ctx,
427
+ next_ctx=next_ctx
428
+ )
429
+ )
359
430
 
360
- def append(self, pid, html: str, flush: bool = False):
431
+ def append(
432
+ self,
433
+ pid,
434
+ html: str,
435
+ flush: bool = False
436
+ ):
361
437
  """
362
438
  Append text to output
363
439
 
@@ -373,18 +449,41 @@ class Renderer(BaseRenderer):
373
449
  if not flush:
374
450
  self.pids[pid].html += html # to buffer
375
451
 
376
- def append_context_item(self, meta: CtxMeta, ctx: CtxItem, next_ctx: CtxItem = None):
452
+ def append_context_item(
453
+ self,
454
+ meta: CtxMeta,
455
+ ctx: CtxItem,
456
+ prev_ctx: CtxItem = None,
457
+ next_ctx: CtxItem = None
458
+ ):
377
459
  """
378
460
  Append context item to output
379
461
 
380
462
  :param meta: context meta
381
463
  :param ctx: context item
464
+ :param prev_ctx: previous context item
382
465
  :param next_ctx: next context item
383
466
  """
384
- self.append_input(meta, ctx, flush=False)
385
- self.append_output(meta, ctx, flush=False, next_ctx=next_ctx) # + extra
467
+ self.append_input(
468
+ meta,
469
+ ctx,
470
+ flush=False
471
+ )
472
+ self.append_output(
473
+ meta,
474
+ ctx,
475
+ flush=False,
476
+ prev_ctx=prev_ctx,
477
+ next_ctx=next_ctx
478
+ ) # + extra
386
479
 
387
- def append_extra(self, meta: CtxMeta, ctx: CtxItem, footer: bool = False, render: bool = True) -> str:
480
+ def append_extra(
481
+ self,
482
+ meta: CtxMeta,
483
+ ctx: CtxItem,
484
+ footer: bool = False,
485
+ render: bool = True
486
+ ) -> str:
388
487
  """
389
488
  Append extra data (images, files, etc.) to output
390
489
 
@@ -407,8 +506,8 @@ class Renderer(BaseRenderer):
407
506
  if image is None:
408
507
  continue
409
508
  # don't append if it is an external url
410
- if image.startswith("http"):
411
- continue
509
+ # if image.startswith("http"):
510
+ # continue
412
511
  if image in appended or image in self.pids[pid].images_appended:
413
512
  continue
414
513
  try:
@@ -475,7 +574,12 @@ class Renderer(BaseRenderer):
475
574
 
476
575
  return html
477
576
 
478
- def append_timestamp(self, ctx: CtxItem, text: str, type: int = None) -> str:
577
+ def append_timestamp(
578
+ self,
579
+ ctx: CtxItem,
580
+ text: str,
581
+ type: int = None
582
+ ) -> str:
479
583
  """
480
584
  Append timestamp to text
481
585
 
@@ -496,7 +600,10 @@ class Renderer(BaseRenderer):
496
600
  text = '<span class="ts">{}: </span>{}'.format(hour, text)
497
601
  return text
498
602
 
499
- def reset(self, meta: CtxMeta = None):
603
+ def reset(
604
+ self,
605
+ meta: CtxMeta = None
606
+ ):
500
607
  """
501
608
  Reset
502
609
 
@@ -558,6 +665,8 @@ class Renderer(BaseRenderer):
558
665
 
559
666
  :pid: context PID
560
667
  """
668
+ if pid is None:
669
+ return
561
670
  if not self.pids[pid].loaded:
562
671
  js = "var element = document.getElementById('_append_input_');"
563
672
  js += "if (element) { element.innerHTML = ''; }"
@@ -600,7 +709,15 @@ class Renderer(BaseRenderer):
600
709
  except Exception as e:
601
710
  pass
602
711
 
603
- def prepare_node(self, meta: CtxMeta, ctx: CtxItem, html: str, type: int = 1, next_ctx: CtxItem = None) -> str:
712
+ def prepare_node(
713
+ self,
714
+ meta: CtxMeta,
715
+ ctx: CtxItem,
716
+ html: str,
717
+ type: int = 1,
718
+ prev_ctx: CtxItem = None,
719
+ next_ctx: CtxItem = None
720
+ ) -> str:
604
721
  """
605
722
  Prepare node HTML
606
723
 
@@ -608,20 +725,35 @@ class Renderer(BaseRenderer):
608
725
  :param ctx: CtxItem instance
609
726
  :param html: html text
610
727
  :param type: type of message
728
+ :param prev_ctx: previous context item
611
729
  :param next_ctx: next context item
612
730
  :return: prepared HTML
613
731
  """
614
732
  pid = self.get_or_create_pid(meta)
615
733
  if type == self.NODE_OUTPUT:
616
- return self.prepare_node_output(meta, ctx, html, next_ctx)
734
+ return self.prepare_node_output(
735
+ meta=meta,
736
+ ctx=ctx,
737
+ html=html,
738
+ prev_ctx=prev_ctx,
739
+ next_ctx=next_ctx
740
+ )
617
741
  elif type == self.NODE_INPUT:
618
- return self.prepare_node_input(pid, ctx, html)
742
+ return self.prepare_node_input(
743
+ pid=pid,
744
+ ctx=ctx,
745
+ html=html,
746
+ prev_ctx=prev_ctx,
747
+ next_ctx=next_ctx
748
+ )
619
749
 
620
750
  def prepare_node_input(
621
751
  self,
622
752
  pid,
623
753
  ctx: CtxItem,
624
- html: str
754
+ html: str,
755
+ prev_ctx: CtxItem = None,
756
+ next_ctx: CtxItem = None
625
757
  ) -> str:
626
758
  """
627
759
  Prepare input node
@@ -629,6 +761,8 @@ class Renderer(BaseRenderer):
629
761
  :param pid: context PID
630
762
  :param ctx: CtxItem instance
631
763
  :param html: html text
764
+ :param prev_ctx: previous context item
765
+ :param next_ctx: next context item
632
766
  :return: prepared HTML
633
767
  """
634
768
  msg_id = "msg-user-" + str(ctx.id) if ctx is not None else ""
@@ -646,6 +780,11 @@ class Renderer(BaseRenderer):
646
780
  if type(ctx.extra) is dict and "agent_evaluate" in ctx.extra:
647
781
  name = trans("msg.name.evaluation")
648
782
 
783
+ # debug
784
+ debug = ""
785
+ if self.is_debug():
786
+ debug = self.append_debug(ctx, pid, "input")
787
+
649
788
  extra = ""
650
789
  if ctx.extra is not None and "footer" in ctx.extra:
651
790
  extra = ctx.extra["footer"]
@@ -655,6 +794,7 @@ class Renderer(BaseRenderer):
655
794
  '<div class="msg">'
656
795
  '{html}'
657
796
  '<div class="msg-extra">{extra}</div>'
797
+ '{debug}'
658
798
  '</div>'
659
799
  '</div>'
660
800
  ).format(
@@ -662,6 +802,7 @@ class Renderer(BaseRenderer):
662
802
  name=name,
663
803
  html=html,
664
804
  extra=extra,
805
+ debug=debug,
665
806
  )
666
807
 
667
808
  return html
@@ -671,6 +812,7 @@ class Renderer(BaseRenderer):
671
812
  meta: CtxMeta,
672
813
  ctx: CtxItem,
673
814
  html: str,
815
+ prev_ctx: CtxItem = None,
674
816
  next_ctx: CtxItem = None
675
817
  ) -> str:
676
818
  """
@@ -679,7 +821,8 @@ class Renderer(BaseRenderer):
679
821
  :param meta: context meta
680
822
  :param ctx: CtxItem instance
681
823
  :param html: html text
682
- :param next_ctx: previous context item
824
+ :param prev_ctx: previous context item
825
+ :param next_ctx: next context item
683
826
  :return: prepared HTML
684
827
  """
685
828
  is_cmd = False
@@ -691,8 +834,8 @@ class Renderer(BaseRenderer):
691
834
  is_cmd = True
692
835
  pid = self.get_or_create_pid(meta)
693
836
  msg_id = "msg-bot-" + str(ctx.id) if ctx is not None else ""
694
- #if is_cmd:
695
- #html = self.helpers.format_cmd_text(html)
837
+ # if is_cmd:
838
+ # html = self.helpers.format_cmd_text(html)
696
839
  html = self.helpers.pre_format_text(html)
697
840
  html = self.append_timestamp(ctx, html, type=self.NODE_OUTPUT)
698
841
  html = self.parser.parse(html)
@@ -732,7 +875,7 @@ class Renderer(BaseRenderer):
732
875
 
733
876
  # check if agent step and results in current ctx
734
877
  elif ctx.results is not None and len(ctx.results) > 0 \
735
- and isinstance(ctx.extra, dict) and "agent_step" in ctx.extra:
878
+ and isinstance(ctx.extra, dict) and "agent_step" in ctx.extra:
736
879
  tool_output = self.helpers.format_cmd_text(str(ctx.input))
737
880
  else:
738
881
  # loading spinner
@@ -768,16 +911,21 @@ class Renderer(BaseRenderer):
768
911
  )
769
912
  tool_extra = self.body.prepare_tool_extra(ctx)
770
913
 
914
+ # debug
915
+ debug = ""
916
+ if self.is_debug():
917
+ debug = self.append_debug(ctx, pid, "output")
918
+
771
919
  html = (
772
920
  '<div class="msg-box msg-bot" id="{msg_id}">'
773
921
  '<div class="name-header name-bot">{name_bot}</div>'
774
922
  '<div class="msg">'
775
923
  '{html}'
776
-
777
924
  '<div class="msg-tool-extra">{tool_extra}</div>'
778
925
  '{html_tools}'
779
926
  '<div class="msg-extra">{extra}</div>'
780
927
  '{footer}'
928
+ '{debug}'
781
929
  '</div>'
782
930
  '</div>'
783
931
  ).format(
@@ -788,6 +936,7 @@ class Renderer(BaseRenderer):
788
936
  extra=extra,
789
937
  footer=footer,
790
938
  tool_extra=tool_extra,
939
+ debug=debug,
791
940
  )
792
941
 
793
942
  return html
@@ -1106,3 +1255,24 @@ class Renderer(BaseRenderer):
1106
1255
  self.get_output_node().page().runJavaScript(f"endToolOutput();")
1107
1256
  except Exception as e:
1108
1257
  pass
1258
+
1259
+ def append_debug(self, ctx: CtxItem, pid, title: str = None) -> str:
1260
+ """
1261
+ Append debug info
1262
+
1263
+ :param ctx: context item
1264
+ :param pid: context PID
1265
+ :param title: debug title
1266
+ """
1267
+ if title is None:
1268
+ title = "debug"
1269
+ debug = "<b>" +title+ ":</b> pid: "+str(pid)+", ctx: " + str(ctx.to_dict())
1270
+ return "<div class='debug'>" + debug + "</div>"
1271
+
1272
+ def is_debug(self) -> bool:
1273
+ """
1274
+ Check if debug mode is enabled
1275
+
1276
+ :return: True if debug mode is enabled
1277
+ """
1278
+ return self.window.core.config.get("debug.render", False)