pygpt-net 2.6.3__py3-none-any.whl → 2.6.4__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.
- pygpt_net/CHANGELOG.txt +5 -0
- pygpt_net/__init__.py +1 -1
- pygpt_net/config.py +55 -65
- pygpt_net/controller/chat/chat.py +38 -35
- pygpt_net/controller/chat/render.py +144 -217
- pygpt_net/controller/chat/stream.py +51 -25
- pygpt_net/controller/config/config.py +39 -42
- pygpt_net/controller/config/field/checkbox.py +16 -12
- pygpt_net/controller/config/field/checkbox_list.py +36 -31
- pygpt_net/controller/config/field/cmd.py +51 -57
- pygpt_net/controller/config/field/combo.py +33 -16
- pygpt_net/controller/config/field/dictionary.py +48 -55
- pygpt_net/controller/config/field/input.py +50 -32
- pygpt_net/controller/config/field/slider.py +40 -45
- pygpt_net/controller/config/field/textarea.py +20 -6
- pygpt_net/controller/config/placeholder.py +110 -231
- pygpt_net/controller/lang/mapping.py +57 -95
- pygpt_net/controller/lang/plugins.py +64 -55
- pygpt_net/controller/lang/settings.py +39 -38
- pygpt_net/controller/layout/layout.py +11 -2
- pygpt_net/controller/plugins/plugins.py +19 -1
- pygpt_net/controller/ui/mode.py +107 -125
- pygpt_net/core/bridge/bridge.py +5 -5
- pygpt_net/core/command/command.py +149 -219
- pygpt_net/core/ctx/ctx.py +94 -146
- pygpt_net/core/debug/debug.py +48 -58
- pygpt_net/core/models/models.py +74 -112
- pygpt_net/core/modes/modes.py +13 -21
- pygpt_net/core/plugins/plugins.py +154 -177
- pygpt_net/core/presets/presets.py +103 -176
- pygpt_net/core/render/web/body.py +2 -3
- pygpt_net/core/render/web/renderer.py +109 -180
- pygpt_net/core/text/utils.py +28 -44
- pygpt_net/core/tokens/tokens.py +104 -203
- pygpt_net/data/config/config.json +2 -2
- pygpt_net/data/config/models.json +2 -2
- pygpt_net/item/ctx.py +141 -139
- pygpt_net/plugin/agent/plugin.py +2 -1
- pygpt_net/plugin/audio_output/plugin.py +5 -2
- pygpt_net/plugin/base/plugin.py +77 -93
- pygpt_net/plugin/bitbucket/plugin.py +3 -2
- pygpt_net/plugin/cmd_code_interpreter/plugin.py +3 -2
- pygpt_net/plugin/cmd_custom/plugin.py +3 -2
- pygpt_net/plugin/cmd_files/plugin.py +3 -2
- pygpt_net/plugin/cmd_history/plugin.py +3 -2
- pygpt_net/plugin/cmd_mouse_control/plugin.py +5 -2
- pygpt_net/plugin/cmd_serial/plugin.py +3 -2
- pygpt_net/plugin/cmd_system/plugin.py +3 -6
- pygpt_net/plugin/cmd_web/plugin.py +3 -2
- pygpt_net/plugin/experts/plugin.py +2 -2
- pygpt_net/plugin/facebook/plugin.py +3 -4
- pygpt_net/plugin/github/plugin.py +4 -2
- pygpt_net/plugin/google/plugin.py +3 -3
- pygpt_net/plugin/idx_llama_index/plugin.py +3 -2
- pygpt_net/plugin/mailer/plugin.py +3 -5
- pygpt_net/plugin/openai_vision/plugin.py +3 -2
- pygpt_net/plugin/real_time/plugin.py +52 -60
- pygpt_net/plugin/slack/plugin.py +3 -4
- pygpt_net/plugin/telegram/plugin.py +3 -4
- pygpt_net/plugin/twitter/plugin.py +3 -4
- pygpt_net/ui/widget/textarea/web.py +18 -14
- {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/METADATA +7 -2
- {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/RECORD +66 -66
- {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/entry_points.txt +0 -0
|
@@ -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: 2025.08.15
|
|
9
|
+
# Updated Date: 2025.08.15 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import json
|
|
@@ -15,8 +15,6 @@ import re
|
|
|
15
15
|
from datetime import datetime
|
|
16
16
|
from typing import Optional, List
|
|
17
17
|
|
|
18
|
-
from PySide6 import QtCore
|
|
19
|
-
|
|
20
18
|
from pygpt_net.core.render.base import BaseRenderer
|
|
21
19
|
from pygpt_net.core.text.utils import has_unclosed_code_tag
|
|
22
20
|
from pygpt_net.item.ctx import CtxItem, CtxMeta
|
|
@@ -51,6 +49,11 @@ class Renderer(BaseRenderer):
|
|
|
51
49
|
self.prev_chunk_replace = False
|
|
52
50
|
self.prev_chunk_newline = False
|
|
53
51
|
|
|
52
|
+
app_path = self.window.core.config.get_app_path() if self.window else ""
|
|
53
|
+
self._icon_expand = os.path.join(app_path, "data", "icons", "expand.svg")
|
|
54
|
+
self._icon_sync = os.path.join(app_path, "data", "icons", "sync.svg")
|
|
55
|
+
self._file_prefix = 'file:///' if self.window and self.window.core.platforms.is_windows() else 'file://'
|
|
56
|
+
|
|
54
57
|
def prepare(self):
|
|
55
58
|
"""
|
|
56
59
|
Prepare renderer
|
|
@@ -83,7 +86,7 @@ class Renderer(BaseRenderer):
|
|
|
83
86
|
:param meta: context meta
|
|
84
87
|
:param tab: Tab
|
|
85
88
|
"""
|
|
86
|
-
if meta is None:
|
|
89
|
+
if meta is None or tab is None:
|
|
87
90
|
return
|
|
88
91
|
pid = tab.pid
|
|
89
92
|
if pid is None or pid not in self.pids:
|
|
@@ -157,7 +160,6 @@ class Renderer(BaseRenderer):
|
|
|
157
160
|
:param state: state name
|
|
158
161
|
:param meta: context meta
|
|
159
162
|
"""
|
|
160
|
-
# BUSY: current pid only
|
|
161
163
|
if state == RenderEvent.STATE_BUSY:
|
|
162
164
|
if meta:
|
|
163
165
|
pid = self.get_pid(meta)
|
|
@@ -169,7 +171,6 @@ class Renderer(BaseRenderer):
|
|
|
169
171
|
except Exception as e:
|
|
170
172
|
pass
|
|
171
173
|
|
|
172
|
-
# IDLE: all pids
|
|
173
174
|
elif state == RenderEvent.STATE_IDLE:
|
|
174
175
|
for pid in self.pids:
|
|
175
176
|
node = self.get_output_node_by_pid(pid)
|
|
@@ -180,7 +181,6 @@ class Renderer(BaseRenderer):
|
|
|
180
181
|
except Exception as e:
|
|
181
182
|
pass
|
|
182
183
|
|
|
183
|
-
# ERROR: all pids
|
|
184
184
|
elif state == RenderEvent.STATE_ERROR:
|
|
185
185
|
for pid in self.pids:
|
|
186
186
|
node = self.get_output_node_by_pid(pid)
|
|
@@ -207,7 +207,7 @@ class Renderer(BaseRenderer):
|
|
|
207
207
|
pid = self.get_or_create_pid(meta)
|
|
208
208
|
self.init(pid)
|
|
209
209
|
self.reset_names(meta)
|
|
210
|
-
self.tool_output_end()
|
|
210
|
+
self.tool_output_end()
|
|
211
211
|
self.prev_chunk_replace = False
|
|
212
212
|
|
|
213
213
|
def end(
|
|
@@ -229,6 +229,7 @@ class Renderer(BaseRenderer):
|
|
|
229
229
|
if self.pids[pid].item is not None and stream:
|
|
230
230
|
self.append_context_item(meta, self.pids[pid].item)
|
|
231
231
|
self.pids[pid].item = None
|
|
232
|
+
self.pids[pid].clear()
|
|
232
233
|
|
|
233
234
|
def end_extra(
|
|
234
235
|
self,
|
|
@@ -309,34 +310,32 @@ class Renderer(BaseRenderer):
|
|
|
309
310
|
|
|
310
311
|
if clear:
|
|
311
312
|
self.reset(meta)
|
|
312
|
-
i = 0
|
|
313
313
|
|
|
314
314
|
self.pids[pid].use_buffer = True
|
|
315
315
|
self.pids[pid].html = ""
|
|
316
316
|
prev_ctx = None
|
|
317
|
-
|
|
317
|
+
total = len(items)
|
|
318
|
+
for i, item in enumerate(items):
|
|
318
319
|
self.update_names(meta, item)
|
|
319
320
|
item.idx = i
|
|
320
321
|
if i == 0:
|
|
321
322
|
item.first = True
|
|
322
|
-
next_item = items[i + 1] if i + 1 <
|
|
323
|
+
next_item = items[i + 1] if i + 1 < total else None
|
|
323
324
|
self.append_context_item(
|
|
324
325
|
meta,
|
|
325
326
|
item,
|
|
326
327
|
prev_ctx=prev_ctx,
|
|
327
328
|
next_ctx=next_item
|
|
328
|
-
)
|
|
329
|
+
)
|
|
329
330
|
prev_ctx = item
|
|
330
|
-
i += 1
|
|
331
331
|
self.pids[pid].use_buffer = False
|
|
332
332
|
|
|
333
|
-
# flush
|
|
334
333
|
if self.pids[pid].html != "":
|
|
335
334
|
self.append(
|
|
336
335
|
pid,
|
|
337
336
|
self.pids[pid].html,
|
|
338
337
|
flush=True
|
|
339
|
-
)
|
|
338
|
+
)
|
|
340
339
|
|
|
341
340
|
def append_input(
|
|
342
341
|
self, meta: CtxMeta,
|
|
@@ -352,7 +351,7 @@ class Renderer(BaseRenderer):
|
|
|
352
351
|
:param flush: flush HTML
|
|
353
352
|
:param append: True if force append node
|
|
354
353
|
"""
|
|
355
|
-
self.tool_output_end()
|
|
354
|
+
self.tool_output_end()
|
|
356
355
|
pid = self.get_or_create_pid(meta)
|
|
357
356
|
if not flush:
|
|
358
357
|
self.clear_chunks_input(pid)
|
|
@@ -363,7 +362,6 @@ class Renderer(BaseRenderer):
|
|
|
363
362
|
|
|
364
363
|
text = ctx.input
|
|
365
364
|
|
|
366
|
-
# if sub-reply
|
|
367
365
|
if isinstance(ctx.extra, dict) and "sub_reply" in ctx.extra and ctx.extra["sub_reply"]:
|
|
368
366
|
try:
|
|
369
367
|
json_encoded = json.loads(text)
|
|
@@ -374,18 +372,16 @@ class Renderer(BaseRenderer):
|
|
|
374
372
|
except json.JSONDecodeError:
|
|
375
373
|
pass
|
|
376
374
|
|
|
377
|
-
# hidden internal call
|
|
378
375
|
if ctx.internal \
|
|
379
376
|
and not ctx.first \
|
|
380
377
|
and not ctx.input.strip().startswith("user: ") \
|
|
381
|
-
and not ctx.input.strip().startswith("@"):
|
|
378
|
+
and not ctx.input.strip().startswith("@"):
|
|
382
379
|
return
|
|
383
380
|
else:
|
|
384
|
-
# don't show user prefix if provided in internal call goal update
|
|
385
381
|
if ctx.internal and ctx.input.startswith("user: "):
|
|
386
382
|
text = re.sub(r'^user: ', '> ', ctx.input)
|
|
387
383
|
|
|
388
|
-
if flush:
|
|
384
|
+
if flush:
|
|
389
385
|
if self.is_stream() and not append:
|
|
390
386
|
content = self.prepare_node(meta, ctx, text.strip(), self.NODE_INPUT)
|
|
391
387
|
self.append_chunk_input(meta, ctx, content, False)
|
|
@@ -410,17 +406,15 @@ class Renderer(BaseRenderer):
|
|
|
410
406
|
:param prev_ctx: previous context
|
|
411
407
|
:param next_ctx: next context
|
|
412
408
|
"""
|
|
413
|
-
self.tool_output_end()
|
|
409
|
+
self.tool_output_end()
|
|
414
410
|
output = ctx.output
|
|
415
|
-
if
|
|
416
|
-
and "output" in ctx.extra
|
|
417
|
-
and ctx.extra["output"]):
|
|
411
|
+
if isinstance(ctx.extra, dict) and ctx.extra.get("output"):
|
|
418
412
|
if self.window.core.config.get("llama.idx.chat.agent.render.all", False):
|
|
419
|
-
output = "__agent_begin__" + ctx.output + "__agent_end__" + ctx.extra["output"]
|
|
413
|
+
output = "__agent_begin__" + (ctx.output or "") + "__agent_end__" + ctx.extra["output"]
|
|
420
414
|
else:
|
|
421
415
|
output = ctx.extra["output"]
|
|
422
416
|
else:
|
|
423
|
-
if
|
|
417
|
+
if not output:
|
|
424
418
|
return
|
|
425
419
|
self.append_node(
|
|
426
420
|
meta=meta,
|
|
@@ -604,38 +598,24 @@ class Renderer(BaseRenderer):
|
|
|
604
598
|
self.pids[pid].item = ctx
|
|
605
599
|
if text_chunk is None or text_chunk == "":
|
|
606
600
|
if begin:
|
|
607
|
-
self.pids[pid].live_buffer = ""
|
|
601
|
+
self.pids[pid].live_buffer = ""
|
|
608
602
|
return
|
|
609
603
|
self.update_names(meta, ctx)
|
|
610
|
-
raw_chunk = str(text_chunk)
|
|
611
|
-
raw_chunk = raw_chunk.replace("<", "<")
|
|
612
|
-
raw_chunk = raw_chunk.replace(">", ">")
|
|
604
|
+
raw_chunk = str(text_chunk).translate({ord('<'): '<', ord('>'): '>'})
|
|
613
605
|
if begin:
|
|
614
|
-
# debug
|
|
615
606
|
debug = ""
|
|
616
607
|
if self.is_debug():
|
|
617
608
|
debug = self.append_debug(ctx, pid, "stream")
|
|
618
609
|
if debug:
|
|
619
610
|
raw_chunk = debug + raw_chunk
|
|
620
|
-
self.pids[pid].live_buffer = ""
|
|
621
|
-
self.pids[pid].is_cmd = False
|
|
622
|
-
self.clear_live(meta, ctx)
|
|
623
|
-
self.pids[pid].
|
|
611
|
+
self.pids[pid].live_buffer = ""
|
|
612
|
+
self.pids[pid].is_cmd = False
|
|
613
|
+
self.clear_live(meta, ctx)
|
|
614
|
+
self.pids[pid].append_live_buffer(raw_chunk)
|
|
624
615
|
|
|
625
|
-
"""
|
|
626
|
-
# cooldown (throttling) to prevent high CPU usage on huge text chunks
|
|
627
|
-
if len(self.buffer) > self.throttling_min_chars:
|
|
628
|
-
current_time = time.time()
|
|
629
|
-
if current_time - self.last_time_called <= self.cooldown:
|
|
630
|
-
return # wait a moment
|
|
631
|
-
else:
|
|
632
|
-
self.last_time_called = current_time
|
|
633
|
-
"""
|
|
634
|
-
|
|
635
|
-
# parse chunks
|
|
636
616
|
to_append = self.pids[pid].live_buffer
|
|
637
617
|
if has_unclosed_code_tag(self.pids[pid].live_buffer):
|
|
638
|
-
to_append += "\n```"
|
|
618
|
+
to_append += "\n```"
|
|
639
619
|
html = self.parser.parse(to_append)
|
|
640
620
|
escaped_chunk = json.dumps(html)
|
|
641
621
|
try:
|
|
@@ -655,8 +635,7 @@ class Renderer(BaseRenderer):
|
|
|
655
635
|
return
|
|
656
636
|
pid = self.get_or_create_pid(meta)
|
|
657
637
|
if not self.pids[pid].loaded:
|
|
658
|
-
js = "var element = document.getElementById('_append_live_');"
|
|
659
|
-
js += "if (element) { element.innerHTML = ''; }"
|
|
638
|
+
js = "var element = document.getElementById('_append_live_');if (element) { element.innerHTML = ''; }"
|
|
660
639
|
else:
|
|
661
640
|
js = "clearLive();"
|
|
662
641
|
try:
|
|
@@ -714,11 +693,11 @@ class Renderer(BaseRenderer):
|
|
|
714
693
|
"""
|
|
715
694
|
if self.pids[pid].loaded and not self.pids[pid].use_buffer:
|
|
716
695
|
self.clear_chunks(pid)
|
|
717
|
-
self.flush_output(pid, html)
|
|
696
|
+
self.flush_output(pid, html)
|
|
718
697
|
self.pids[pid].html = ""
|
|
719
698
|
else:
|
|
720
699
|
if not flush:
|
|
721
|
-
self.pids[pid].html
|
|
700
|
+
self.pids[pid].append_html(html)
|
|
722
701
|
|
|
723
702
|
def append_context_item(
|
|
724
703
|
self,
|
|
@@ -746,7 +725,7 @@ class Renderer(BaseRenderer):
|
|
|
746
725
|
flush=False,
|
|
747
726
|
prev_ctx=prev_ctx,
|
|
748
727
|
next_ctx=next_ctx
|
|
749
|
-
)
|
|
728
|
+
)
|
|
750
729
|
|
|
751
730
|
def append_extra(
|
|
752
731
|
self,
|
|
@@ -764,32 +743,28 @@ class Renderer(BaseRenderer):
|
|
|
764
743
|
:param render: True if render, False if only return HTML
|
|
765
744
|
:return: HTML code
|
|
766
745
|
"""
|
|
767
|
-
self.tool_output_end()
|
|
746
|
+
self.tool_output_end()
|
|
768
747
|
|
|
769
748
|
pid = self.get_pid(meta)
|
|
770
|
-
appended =
|
|
771
|
-
|
|
772
|
-
|
|
749
|
+
appended = set()
|
|
750
|
+
html_parts = []
|
|
751
|
+
|
|
773
752
|
c = len(ctx.images)
|
|
774
753
|
if c > 0:
|
|
775
754
|
n = 1
|
|
776
755
|
for image in ctx.images:
|
|
777
756
|
if image is None:
|
|
778
757
|
continue
|
|
779
|
-
# don't append if it is an external url
|
|
780
|
-
# if image.startswith("http"):
|
|
781
|
-
# continue
|
|
782
758
|
if image in appended or image in self.pids[pid].images_appended:
|
|
783
759
|
continue
|
|
784
760
|
try:
|
|
785
|
-
appended.
|
|
786
|
-
|
|
761
|
+
appended.add(image)
|
|
762
|
+
html_parts.append(self.body.get_image_html(image, n, c))
|
|
787
763
|
self.pids[pid].images_appended.append(image)
|
|
788
764
|
n += 1
|
|
789
765
|
except Exception as e:
|
|
790
766
|
pass
|
|
791
767
|
|
|
792
|
-
# files and attachments, TODO check attachments
|
|
793
768
|
c = len(ctx.files)
|
|
794
769
|
if c > 0:
|
|
795
770
|
files_html = []
|
|
@@ -798,16 +773,15 @@ class Renderer(BaseRenderer):
|
|
|
798
773
|
if file in appended or file in self.pids[pid].files_appended:
|
|
799
774
|
continue
|
|
800
775
|
try:
|
|
801
|
-
appended.
|
|
776
|
+
appended.add(file)
|
|
802
777
|
files_html.append(self.body.get_file_html(file, n, c))
|
|
803
778
|
self.pids[pid].files_appended.append(file)
|
|
804
779
|
n += 1
|
|
805
780
|
except Exception as e:
|
|
806
781
|
pass
|
|
807
782
|
if files_html:
|
|
808
|
-
|
|
783
|
+
html_parts.append("<br/>" + "<br/>".join(files_html))
|
|
809
784
|
|
|
810
|
-
# urls
|
|
811
785
|
c = len(ctx.urls)
|
|
812
786
|
if c > 0:
|
|
813
787
|
urls_html = []
|
|
@@ -816,32 +790,33 @@ class Renderer(BaseRenderer):
|
|
|
816
790
|
if url in appended or url in self.pids[pid].urls_appended:
|
|
817
791
|
continue
|
|
818
792
|
try:
|
|
819
|
-
appended.
|
|
793
|
+
appended.add(url)
|
|
820
794
|
urls_html.append(self.body.get_url_html(url, n, c))
|
|
821
795
|
self.pids[pid].urls_appended.append(url)
|
|
822
796
|
n += 1
|
|
823
797
|
except Exception as e:
|
|
824
798
|
pass
|
|
825
799
|
if urls_html:
|
|
826
|
-
|
|
800
|
+
html_parts.append("<br/>" + "<br/>".join(urls_html))
|
|
827
801
|
|
|
828
|
-
# docs json
|
|
829
802
|
if self.window.core.config.get('ctx.sources'):
|
|
830
803
|
if ctx.doc_ids is not None and len(ctx.doc_ids) > 0:
|
|
831
804
|
try:
|
|
832
805
|
docs = self.body.get_docs_html(ctx.doc_ids)
|
|
833
|
-
|
|
806
|
+
html_parts.append(docs)
|
|
834
807
|
except Exception as e:
|
|
835
808
|
pass
|
|
836
|
-
|
|
809
|
+
|
|
810
|
+
html = "".join(html_parts)
|
|
837
811
|
if render and html != "":
|
|
838
812
|
if footer:
|
|
839
|
-
# append to output
|
|
840
813
|
self.append(pid, html)
|
|
841
814
|
else:
|
|
842
|
-
# append to existing message box using JS
|
|
843
815
|
escaped_html = json.dumps(html)
|
|
844
|
-
|
|
816
|
+
try:
|
|
817
|
+
self.get_output_node(meta).page().runJavaScript("appendExtra('{}',{});".format(ctx.id, escaped_html))
|
|
818
|
+
except Exception as e:
|
|
819
|
+
pass
|
|
845
820
|
|
|
846
821
|
return html
|
|
847
822
|
|
|
@@ -881,16 +856,13 @@ class Renderer(BaseRenderer):
|
|
|
881
856
|
:param meta: Context meta
|
|
882
857
|
"""
|
|
883
858
|
pid = self.get_pid(meta)
|
|
884
|
-
if pid is not None and pid in self.pids:
|
|
859
|
+
if pid is not None and pid in self.pids:
|
|
885
860
|
self.reset_by_pid(pid)
|
|
886
861
|
else:
|
|
887
|
-
# there is no pid here if empty context so check for meta, and clear current
|
|
888
862
|
if meta is not None:
|
|
889
|
-
# create new PID using only meta
|
|
890
863
|
pid = self.get_or_create_pid(meta)
|
|
891
864
|
self.reset_by_pid(pid)
|
|
892
865
|
|
|
893
|
-
# clear live output
|
|
894
866
|
self.clear_live(meta, CtxItem())
|
|
895
867
|
|
|
896
868
|
def reset_by_pid(self, pid: Optional[int]):
|
|
@@ -907,7 +879,9 @@ class Renderer(BaseRenderer):
|
|
|
907
879
|
self.pids[pid].images_appended = []
|
|
908
880
|
self.pids[pid].urls_appended = []
|
|
909
881
|
self.pids[pid].files_appended = []
|
|
910
|
-
self.get_output_node_by_pid(pid)
|
|
882
|
+
node = self.get_output_node_by_pid(pid)
|
|
883
|
+
if node is not None:
|
|
884
|
+
node.reset_current_content()
|
|
911
885
|
self.reset_names_by_pid(pid)
|
|
912
886
|
self.prev_chunk_replace = False
|
|
913
887
|
|
|
@@ -950,8 +924,7 @@ class Renderer(BaseRenderer):
|
|
|
950
924
|
if pid is None:
|
|
951
925
|
return
|
|
952
926
|
if not self.pids[pid].loaded:
|
|
953
|
-
js = "var element = document.getElementById('_append_input_');"
|
|
954
|
-
js += "if (element) { element.innerHTML = ''; }"
|
|
927
|
+
js = "var element = document.getElementById('_append_input_');if (element) { element.innerHTML = ''; }"
|
|
955
928
|
else:
|
|
956
929
|
js = "clearInput();"
|
|
957
930
|
try:
|
|
@@ -970,8 +943,7 @@ class Renderer(BaseRenderer):
|
|
|
970
943
|
"""
|
|
971
944
|
self.prev_chunk_replace = False
|
|
972
945
|
if not self.pids[pid].loaded:
|
|
973
|
-
js = "var element = document.getElementById('_append_output_');"
|
|
974
|
-
js += "if (element) { element.innerHTML = ''; }"
|
|
946
|
+
js = "var element = document.getElementById('_append_output_');if (element) { element.innerHTML = ''; }"
|
|
975
947
|
else:
|
|
976
948
|
js = "clearOutput();"
|
|
977
949
|
try:
|
|
@@ -989,8 +961,7 @@ class Renderer(BaseRenderer):
|
|
|
989
961
|
:pid: context PID
|
|
990
962
|
"""
|
|
991
963
|
if not self.pids[pid].loaded:
|
|
992
|
-
js = "var element = document.getElementById('_nodes_');"
|
|
993
|
-
js += "if (element) { element.innerHTML = ''; }"
|
|
964
|
+
js = "var element = document.getElementById('_nodes_');if (element) { element.innerHTML = ''; }"
|
|
994
965
|
else:
|
|
995
966
|
js = "clearNodes();"
|
|
996
967
|
try:
|
|
@@ -1069,7 +1040,6 @@ class Renderer(BaseRenderer):
|
|
|
1069
1040
|
if type(ctx.extra) is dict and "agent_evaluate" in ctx.extra:
|
|
1070
1041
|
name = trans("msg.name.evaluation")
|
|
1071
1042
|
|
|
1072
|
-
# debug
|
|
1073
1043
|
debug = ""
|
|
1074
1044
|
if self.is_debug():
|
|
1075
1045
|
debug = self.append_debug(ctx, pid, "input")
|
|
@@ -1080,21 +1050,14 @@ class Renderer(BaseRenderer):
|
|
|
1080
1050
|
extra = ctx.extra["footer"]
|
|
1081
1051
|
extra_style = "display:block;"
|
|
1082
1052
|
html = (
|
|
1083
|
-
'<div class="msg-box msg-user" id="{msg_id}">'
|
|
1084
|
-
'<div class="name-header name-user">{name}</div>'
|
|
1085
|
-
'<div class="msg">'
|
|
1086
|
-
'{html}'
|
|
1087
|
-
'<div class="msg-extra" style="{extra_style}">{extra}</div>'
|
|
1088
|
-
'{debug}'
|
|
1089
|
-
'</div>'
|
|
1090
|
-
'</div>'
|
|
1091
|
-
).format(
|
|
1092
|
-
msg_id=msg_id,
|
|
1093
|
-
name=name,
|
|
1094
|
-
html=html,
|
|
1095
|
-
extra=extra,
|
|
1096
|
-
extra_style=extra_style,
|
|
1097
|
-
debug=debug,
|
|
1053
|
+
f'<div class="msg-box msg-user" id="{msg_id}">'
|
|
1054
|
+
f'<div class="name-header name-user">{name}</div>'
|
|
1055
|
+
f'<div class="msg">'
|
|
1056
|
+
f'{html}'
|
|
1057
|
+
f'<div class="msg-extra" style="{extra_style}">{extra}</div>'
|
|
1058
|
+
f'{debug}'
|
|
1059
|
+
f'</div>'
|
|
1060
|
+
f'</div>'
|
|
1098
1061
|
)
|
|
1099
1062
|
|
|
1100
1063
|
return html
|
|
@@ -1117,17 +1080,13 @@ class Renderer(BaseRenderer):
|
|
|
1117
1080
|
:param next_ctx: next context item
|
|
1118
1081
|
:return: prepared HTML
|
|
1119
1082
|
"""
|
|
1120
|
-
is_cmd =
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
):
|
|
1126
|
-
is_cmd = True
|
|
1083
|
+
is_cmd = (
|
|
1084
|
+
next_ctx is not None and
|
|
1085
|
+
next_ctx.internal and
|
|
1086
|
+
(len(ctx.cmds) > 0 or (ctx.extra_ctx is not None and len(ctx.extra_ctx) > 0))
|
|
1087
|
+
)
|
|
1127
1088
|
pid = self.get_or_create_pid(meta)
|
|
1128
1089
|
msg_id = "msg-bot-" + str(ctx.id) if ctx is not None else ""
|
|
1129
|
-
# if is_cmd:
|
|
1130
|
-
# html = self.helpers.format_cmd_text(html)
|
|
1131
1090
|
html = self.helpers.pre_format_text(html)
|
|
1132
1091
|
html = self.parser.parse(html)
|
|
1133
1092
|
html = self.append_timestamp(ctx, html, type=self.NODE_OUTPUT)
|
|
@@ -1135,42 +1094,28 @@ class Renderer(BaseRenderer):
|
|
|
1135
1094
|
extra = self.append_extra(meta, ctx, footer=True, render=False)
|
|
1136
1095
|
footer = self.body.prepare_action_icons(ctx)
|
|
1137
1096
|
|
|
1138
|
-
# append tool output
|
|
1139
1097
|
tool_output = ""
|
|
1140
1098
|
spinner = ""
|
|
1141
|
-
icon = os.path.join(
|
|
1142
|
-
self.window.core.config.get_app_path(),
|
|
1143
|
-
"data", "icons", "expand.svg"
|
|
1144
|
-
)
|
|
1145
1099
|
output_class = "display:none"
|
|
1146
|
-
cmd_icon =
|
|
1147
|
-
'<img src="file://{}" width="25" height="25" valign="middle">'
|
|
1148
|
-
.format(icon)
|
|
1149
|
-
)
|
|
1100
|
+
cmd_icon = f'<img src="{self._file_prefix}{self._icon_expand}" width="25" height="25" valign="middle">'
|
|
1150
1101
|
expand_btn = (
|
|
1151
|
-
"<span class='toggle-cmd-output' onclick='toggleToolOutput({});' title='{}' "
|
|
1152
|
-
"role='button'>{}</span>"
|
|
1153
|
-
.format(str(ctx.id), trans('action.cmd.expand'), cmd_icon)
|
|
1102
|
+
f"<span class='toggle-cmd-output' onclick='toggleToolOutput({str(ctx.id)});' title='{trans('action.cmd.expand')}' "
|
|
1103
|
+
f"role='button'>{cmd_icon}</span>"
|
|
1154
1104
|
)
|
|
1155
1105
|
|
|
1156
|
-
# check if next ctx is internal and current ctx has commands
|
|
1157
1106
|
if is_cmd:
|
|
1158
|
-
# first, check current input if agent step and results
|
|
1159
1107
|
if ctx.results is not None and len(ctx.results) > 0 \
|
|
1160
1108
|
and isinstance(ctx.extra, dict) and "agent_step" in ctx.extra:
|
|
1161
1109
|
tool_output = self.helpers.format_cmd_text(str(ctx.input))
|
|
1162
|
-
output_class = ""
|
|
1110
|
+
output_class = ""
|
|
1163
1111
|
else:
|
|
1164
|
-
# get output from next input (JSON response)
|
|
1165
1112
|
tool_output = self.helpers.format_cmd_text(str(next_ctx.input))
|
|
1166
|
-
output_class = ""
|
|
1113
|
+
output_class = ""
|
|
1167
1114
|
|
|
1168
|
-
# check if agent step and results in current ctx
|
|
1169
1115
|
elif ctx.results is not None and len(ctx.results) > 0 \
|
|
1170
1116
|
and isinstance(ctx.extra, dict) and "agent_step" in ctx.extra:
|
|
1171
1117
|
tool_output = self.helpers.format_cmd_text(str(ctx.input))
|
|
1172
1118
|
else:
|
|
1173
|
-
# loading spinner
|
|
1174
1119
|
if (
|
|
1175
1120
|
next_ctx is None and
|
|
1176
1121
|
(
|
|
@@ -1181,22 +1126,15 @@ class Renderer(BaseRenderer):
|
|
|
1181
1126
|
len(ctx.cmds) > 0
|
|
1182
1127
|
)
|
|
1183
1128
|
):
|
|
1184
|
-
spinner_class = "display:none"
|
|
1185
|
-
if ctx.live:
|
|
1186
|
-
spinner_class = "" # show spinner only if commands and active run
|
|
1187
|
-
icon = os.path.join(
|
|
1188
|
-
self.window.core.config.get_app_path(),
|
|
1189
|
-
"data", "icons", "sync.svg"
|
|
1190
|
-
)
|
|
1129
|
+
spinner_class = "" if ctx.live else "display:none"
|
|
1191
1130
|
spinner = (
|
|
1192
|
-
'<span class="spinner" style="{}">'
|
|
1193
|
-
'<img src="
|
|
1194
|
-
'class="loading"></span>'
|
|
1195
|
-
.format(spinner_class, icon)
|
|
1131
|
+
f'<span class="spinner" style="{spinner_class}">'
|
|
1132
|
+
f'<img src="{self._file_prefix}{self._icon_sync}" width="30" height="30" '
|
|
1133
|
+
f'class="loading"></span>'
|
|
1196
1134
|
)
|
|
1197
1135
|
|
|
1198
1136
|
html_tools = (
|
|
1199
|
-
'<div class="tool-output" style="{}">'
|
|
1137
|
+
f'<div class="tool-output" style="{output_class}">' +
|
|
1200
1138
|
expand_btn +
|
|
1201
1139
|
'<div class="content" style="display:none">' +
|
|
1202
1140
|
tool_output +
|
|
@@ -1204,33 +1142,24 @@ class Renderer(BaseRenderer):
|
|
|
1204
1142
|
)
|
|
1205
1143
|
tool_extra = self.body.prepare_tool_extra(ctx)
|
|
1206
1144
|
|
|
1207
|
-
# debug
|
|
1208
1145
|
debug = ""
|
|
1209
1146
|
if self.is_debug():
|
|
1210
1147
|
debug = self.append_debug(ctx, pid, "output")
|
|
1211
1148
|
|
|
1212
1149
|
name_header = self.get_name_header(ctx)
|
|
1213
1150
|
html = (
|
|
1214
|
-
'<div class="msg-box msg-bot" id="{msg_id}">'
|
|
1215
|
-
|
|
1216
|
-
'<div class="msg">'
|
|
1217
|
-
'{html}'
|
|
1218
|
-
'
|
|
1219
|
-
'{
|
|
1220
|
-
'
|
|
1221
|
-
'{
|
|
1222
|
-
'{
|
|
1223
|
-
'
|
|
1151
|
+
f'<div class="msg-box msg-bot" id="{msg_id}">' +
|
|
1152
|
+
name_header +
|
|
1153
|
+
'<div class="msg">' +
|
|
1154
|
+
f'{html}' +
|
|
1155
|
+
f'{spinner}' +
|
|
1156
|
+
f'<div class="msg-tool-extra">{tool_extra}</div>' +
|
|
1157
|
+
f'{html_tools}' +
|
|
1158
|
+
f'<div class="msg-extra">{extra}</div>' +
|
|
1159
|
+
f'{footer}' +
|
|
1160
|
+
f'{debug}' +
|
|
1161
|
+
'</div>' +
|
|
1224
1162
|
'</div>'
|
|
1225
|
-
).format(
|
|
1226
|
-
msg_id=msg_id,
|
|
1227
|
-
name_bot=self.pids[pid].name_bot,
|
|
1228
|
-
html=html,
|
|
1229
|
-
html_tools=html_tools,
|
|
1230
|
-
extra=extra,
|
|
1231
|
-
footer=footer,
|
|
1232
|
-
tool_extra=tool_extra,
|
|
1233
|
-
debug=debug,
|
|
1234
1163
|
)
|
|
1235
1164
|
|
|
1236
1165
|
return html
|
|
@@ -1263,11 +1192,7 @@ class Renderer(BaseRenderer):
|
|
|
1263
1192
|
avatars_dir = os.path.join(presets_dir, "avatars")
|
|
1264
1193
|
avatar_path = os.path.join(avatars_dir, preset.ai_avatar)
|
|
1265
1194
|
if os.path.exists(avatar_path):
|
|
1266
|
-
|
|
1267
|
-
prefix = 'file:///'
|
|
1268
|
-
else:
|
|
1269
|
-
prefix = 'file://'
|
|
1270
|
-
avatar_html = "<img src=\"" + prefix + avatar_path + "\" class=\"avatar\"> "
|
|
1195
|
+
avatar_html = f"<img src=\"{self._file_prefix}{avatar_path}\" class=\"avatar\"> "
|
|
1271
1196
|
|
|
1272
1197
|
if not output_name and not avatar_html:
|
|
1273
1198
|
return ""
|
|
@@ -1288,13 +1213,12 @@ class Renderer(BaseRenderer):
|
|
|
1288
1213
|
try:
|
|
1289
1214
|
node = self.get_output_node_by_pid(pid)
|
|
1290
1215
|
node.page().runJavaScript(f"if (typeof window.appendNode !== 'undefined') appendNode({escaped_html});")
|
|
1291
|
-
node.update_current_content()
|
|
1292
1216
|
except Exception as e:
|
|
1293
1217
|
pass
|
|
1294
1218
|
|
|
1295
1219
|
def reload(self):
|
|
1296
1220
|
"""Reload output, called externally only on theme change to redraw content"""
|
|
1297
|
-
self.window.controller.ctx.refresh_output()
|
|
1221
|
+
self.window.controller.ctx.refresh_output()
|
|
1298
1222
|
|
|
1299
1223
|
def flush(
|
|
1300
1224
|
self,
|
|
@@ -1307,11 +1231,13 @@ class Renderer(BaseRenderer):
|
|
|
1307
1231
|
:param pid: context PID
|
|
1308
1232
|
"""
|
|
1309
1233
|
if self.pids[pid].loaded:
|
|
1310
|
-
return
|
|
1234
|
+
return
|
|
1311
1235
|
|
|
1312
1236
|
html = self.body.get_html(pid)
|
|
1313
1237
|
self.pids[pid].document = html
|
|
1314
|
-
self.get_output_node_by_pid(pid)
|
|
1238
|
+
node = self.get_output_node_by_pid(pid)
|
|
1239
|
+
if node is not None:
|
|
1240
|
+
node.setHtml(html, baseUrl="file://")
|
|
1315
1241
|
|
|
1316
1242
|
def fresh(
|
|
1317
1243
|
self,
|
|
@@ -1329,8 +1255,9 @@ class Renderer(BaseRenderer):
|
|
|
1329
1255
|
self.pids[pid].loaded = False
|
|
1330
1256
|
self.pids[pid].document = html
|
|
1331
1257
|
node = self.get_output_node_by_pid(pid)
|
|
1332
|
-
node
|
|
1333
|
-
|
|
1258
|
+
if node is not None:
|
|
1259
|
+
node.resetPage()
|
|
1260
|
+
node.setHtml(html, baseUrl="file://")
|
|
1334
1261
|
|
|
1335
1262
|
def get_output_node(
|
|
1336
1263
|
self,
|
|
@@ -1378,7 +1305,9 @@ class Renderer(BaseRenderer):
|
|
|
1378
1305
|
if pid is None:
|
|
1379
1306
|
return ""
|
|
1380
1307
|
if plain:
|
|
1381
|
-
return self.parser.to_plain_text(
|
|
1308
|
+
return self.parser.to_plain_text(
|
|
1309
|
+
self.pids[pid].document.replace("<br>", "\n").replace("<br/>", "\n")
|
|
1310
|
+
)
|
|
1382
1311
|
return self.pids[pid].document
|
|
1383
1312
|
|
|
1384
1313
|
def remove_item(self, ctx: CtxItem):
|
|
@@ -1388,8 +1317,9 @@ class Renderer(BaseRenderer):
|
|
|
1388
1317
|
:param ctx: context item
|
|
1389
1318
|
"""
|
|
1390
1319
|
try:
|
|
1320
|
+
_id = json.dumps(ctx.id)
|
|
1391
1321
|
self.get_output_node(ctx.meta).page().runJavaScript(
|
|
1392
|
-
"if (typeof window.removeNode !== 'undefined') removeNode({});"
|
|
1322
|
+
f"if (typeof window.removeNode !== 'undefined') removeNode({_id});")
|
|
1393
1323
|
except Exception as e:
|
|
1394
1324
|
pass
|
|
1395
1325
|
|
|
@@ -1400,8 +1330,9 @@ class Renderer(BaseRenderer):
|
|
|
1400
1330
|
:param ctx: context item
|
|
1401
1331
|
"""
|
|
1402
1332
|
try:
|
|
1333
|
+
_id = json.dumps(ctx.id)
|
|
1403
1334
|
self.get_output_node(ctx.meta).page().runJavaScript(
|
|
1404
|
-
"if (typeof window.removeNodesFromId !== 'undefined') removeNodesFromId({});"
|
|
1335
|
+
f"if (typeof window.removeNodesFromId !== 'undefined') removeNodesFromId({_id});")
|
|
1405
1336
|
except Exception as e:
|
|
1406
1337
|
pass
|
|
1407
1338
|
|
|
@@ -1431,7 +1362,6 @@ class Renderer(BaseRenderer):
|
|
|
1431
1362
|
|
|
1432
1363
|
:param ctx: context item
|
|
1433
1364
|
"""
|
|
1434
|
-
# remove all items from ID
|
|
1435
1365
|
self.remove_items_from(ctx)
|
|
1436
1366
|
|
|
1437
1367
|
def on_edit_submit(self, ctx: CtxItem):
|
|
@@ -1440,7 +1370,6 @@ class Renderer(BaseRenderer):
|
|
|
1440
1370
|
|
|
1441
1371
|
:param ctx: context item
|
|
1442
1372
|
"""
|
|
1443
|
-
# remove all items from ID
|
|
1444
1373
|
self.remove_items_from(ctx)
|
|
1445
1374
|
|
|
1446
1375
|
def on_enable_edit(self, live: bool = True):
|
|
@@ -1564,12 +1493,12 @@ class Renderer(BaseRenderer):
|
|
|
1564
1493
|
for node in nodes:
|
|
1565
1494
|
try:
|
|
1566
1495
|
node.page().runJavaScript(
|
|
1567
|
-
"if (typeof window.updateCSS !== 'undefined') updateCSS({});"
|
|
1496
|
+
f"if (typeof window.updateCSS !== 'undefined') updateCSS({to_json});")
|
|
1568
1497
|
if self.window.core.config.get('render.blocks'):
|
|
1569
1498
|
node.page().runJavaScript("if (typeof window.enableBlocks !== 'undefined') enableBlocks();")
|
|
1570
1499
|
else:
|
|
1571
1500
|
node.page().runJavaScript(
|
|
1572
|
-
"if (typeof window.disableBlocks !== 'undefined') disableBlocks();")
|
|
1501
|
+
"if (typeof window.disableBlocks !== 'undefined') disableBlocks();")
|
|
1573
1502
|
except Exception as e:
|
|
1574
1503
|
pass
|
|
1575
1504
|
return
|
|
@@ -1681,4 +1610,4 @@ class Renderer(BaseRenderer):
|
|
|
1681
1610
|
Remove PID from renderer
|
|
1682
1611
|
"""
|
|
1683
1612
|
if pid in self.pids:
|
|
1684
|
-
del self.pids[pid]
|
|
1613
|
+
del self.pids[pid]
|