pygpt-net 2.6.33__py3-none-any.whl → 2.6.36__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 +18 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/assistant/batch.py +14 -4
- pygpt_net/controller/assistant/files.py +1 -0
- pygpt_net/controller/assistant/store.py +195 -1
- pygpt_net/controller/camera/camera.py +1 -1
- pygpt_net/controller/chat/common.py +58 -48
- pygpt_net/controller/chat/handler/stream_worker.py +55 -43
- pygpt_net/controller/config/placeholder.py +95 -75
- pygpt_net/controller/dialogs/confirm.py +3 -1
- pygpt_net/controller/media/media.py +11 -3
- pygpt_net/controller/painter/common.py +243 -13
- pygpt_net/controller/painter/painter.py +11 -2
- pygpt_net/core/assistants/files.py +18 -0
- pygpt_net/core/bridge/bridge.py +1 -5
- pygpt_net/core/bridge/context.py +81 -36
- pygpt_net/core/bridge/worker.py +3 -1
- pygpt_net/core/camera/camera.py +31 -402
- pygpt_net/core/camera/worker.py +430 -0
- pygpt_net/core/ctx/bag.py +4 -0
- pygpt_net/core/events/app.py +10 -17
- pygpt_net/core/events/base.py +17 -25
- pygpt_net/core/events/control.py +9 -17
- pygpt_net/core/events/event.py +9 -62
- pygpt_net/core/events/kernel.py +8 -17
- pygpt_net/core/events/realtime.py +8 -17
- pygpt_net/core/events/render.py +9 -17
- pygpt_net/core/filesystem/url.py +3 -0
- pygpt_net/core/render/web/body.py +483 -40
- pygpt_net/core/render/web/pid.py +39 -24
- pygpt_net/core/render/web/renderer.py +142 -36
- pygpt_net/core/text/utils.py +3 -0
- pygpt_net/data/config/config.json +4 -3
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/settings.json +10 -5
- pygpt_net/data/css/web-blocks.css +4 -3
- pygpt_net/data/css/web-chatgpt.css +4 -2
- pygpt_net/data/css/web-chatgpt_wide.css +4 -2
- pygpt_net/data/locale/locale.de.ini +9 -7
- pygpt_net/data/locale/locale.en.ini +10 -6
- pygpt_net/data/locale/locale.es.ini +9 -7
- pygpt_net/data/locale/locale.fr.ini +9 -7
- pygpt_net/data/locale/locale.it.ini +9 -7
- pygpt_net/data/locale/locale.pl.ini +9 -7
- pygpt_net/data/locale/locale.uk.ini +9 -7
- pygpt_net/data/locale/locale.zh.ini +9 -7
- pygpt_net/item/assistant.py +13 -1
- pygpt_net/provider/api/google/__init__.py +46 -28
- pygpt_net/provider/api/openai/__init__.py +13 -10
- pygpt_net/provider/api/openai/store.py +45 -1
- pygpt_net/provider/core/config/patch.py +18 -0
- pygpt_net/provider/llms/google.py +4 -0
- pygpt_net/ui/dialog/assistant_store.py +213 -203
- pygpt_net/ui/layout/chat/input.py +3 -3
- pygpt_net/ui/layout/chat/painter.py +63 -4
- pygpt_net/ui/widget/draw/painter.py +715 -104
- pygpt_net/ui/widget/option/combo.py +5 -1
- pygpt_net/ui/widget/textarea/input.py +273 -3
- pygpt_net/ui/widget/textarea/web.py +2 -0
- {pygpt_net-2.6.33.dist-info → pygpt_net-2.6.36.dist-info}/METADATA +20 -2
- {pygpt_net-2.6.33.dist-info → pygpt_net-2.6.36.dist-info}/RECORD +64 -63
- {pygpt_net-2.6.33.dist-info → pygpt_net-2.6.36.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.33.dist-info → pygpt_net-2.6.36.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.33.dist-info → pygpt_net-2.6.36.dist-info}/entry_points.txt +0 -0
pygpt_net/core/render/web/pid.py
CHANGED
|
@@ -6,37 +6,52 @@
|
|
|
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.
|
|
9
|
+
# Updated Date: 2025.09.04 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import io
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from typing import Any, Optional
|
|
15
|
+
|
|
13
16
|
from pygpt_net.utils import trans
|
|
14
17
|
|
|
15
18
|
|
|
19
|
+
@dataclass(slots=True)
|
|
16
20
|
class PidData:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
21
|
+
"""Pid Data"""
|
|
22
|
+
# Required/primary data
|
|
23
|
+
pid: Any
|
|
24
|
+
meta: Optional[Any] = None
|
|
25
|
+
|
|
26
|
+
# Collections
|
|
27
|
+
images_appended: list = field(default_factory=list)
|
|
28
|
+
urls_appended: list = field(default_factory=list)
|
|
29
|
+
files_appended: list = field(default_factory=list)
|
|
30
|
+
|
|
31
|
+
# Internal buffers (excluded from repr to avoid large dumps)
|
|
32
|
+
_buffer: io.StringIO = field(default_factory=io.StringIO, repr=False)
|
|
33
|
+
_live_buffer: io.StringIO = field(default_factory=io.StringIO, repr=False)
|
|
34
|
+
_html: io.StringIO = field(default_factory=io.StringIO, repr=False)
|
|
35
|
+
_document: io.StringIO = field(default_factory=io.StringIO, repr=False)
|
|
36
|
+
|
|
37
|
+
# Flags/state
|
|
38
|
+
is_cmd: bool = False
|
|
39
|
+
initialized: bool = False
|
|
40
|
+
loaded: bool = False
|
|
41
|
+
item: Optional[Any] = None
|
|
42
|
+
use_buffer: bool = False
|
|
43
|
+
|
|
44
|
+
# Names
|
|
45
|
+
name_user: str = field(default_factory=lambda: trans("chat.name.user"))
|
|
46
|
+
name_bot: str = field(default_factory=lambda: trans("chat.name.bot"))
|
|
47
|
+
|
|
48
|
+
# Throttling / timing
|
|
49
|
+
last_time_called: float = 0.0
|
|
50
|
+
cooldown: float = 1 / 6
|
|
51
|
+
throttling_min_chars: int = 5000
|
|
52
|
+
|
|
53
|
+
# Misc
|
|
54
|
+
header: Optional[Any] = None
|
|
40
55
|
|
|
41
56
|
@property
|
|
42
57
|
def buffer(self) -> str:
|
|
@@ -6,16 +6,19 @@
|
|
|
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.
|
|
9
|
+
# Updated Date: 2025.09.04 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import json
|
|
13
13
|
import os
|
|
14
14
|
import re
|
|
15
|
+
import gc
|
|
16
|
+
from dataclasses import dataclass, field
|
|
15
17
|
|
|
16
18
|
from datetime import datetime
|
|
17
19
|
from typing import Optional, List, Any
|
|
18
20
|
from time import monotonic
|
|
21
|
+
from io import StringIO
|
|
19
22
|
|
|
20
23
|
from pygpt_net.core.render.base import BaseRenderer
|
|
21
24
|
from pygpt_net.core.text.utils import has_unclosed_code_tag
|
|
@@ -48,6 +51,46 @@ class Renderer(BaseRenderer):
|
|
|
48
51
|
)
|
|
49
52
|
RE_AMP_LT_GT = re.compile(r'&(lt|gt);')
|
|
50
53
|
|
|
54
|
+
@dataclass(slots=True)
|
|
55
|
+
class _AppendBuffer:
|
|
56
|
+
"""Small, allocation-friendly buffer for throttled appends."""
|
|
57
|
+
_buf: StringIO = field(default_factory=StringIO, repr=False)
|
|
58
|
+
_size: int = 0
|
|
59
|
+
|
|
60
|
+
def append(self, s: str) -> None:
|
|
61
|
+
if not s:
|
|
62
|
+
return
|
|
63
|
+
self._buf.write(s)
|
|
64
|
+
self._size += len(s)
|
|
65
|
+
|
|
66
|
+
def is_empty(self) -> bool:
|
|
67
|
+
return self._size == 0
|
|
68
|
+
|
|
69
|
+
def get_and_clear(self) -> str:
|
|
70
|
+
"""Return content and replace underlying buffer to release memory eagerly."""
|
|
71
|
+
if self._size == 0:
|
|
72
|
+
return ""
|
|
73
|
+
data = self._buf.getvalue()
|
|
74
|
+
old = self._buf
|
|
75
|
+
# Replace the internal buffer instance to drop capacity immediately
|
|
76
|
+
self._buf = StringIO()
|
|
77
|
+
self._size = 0
|
|
78
|
+
try:
|
|
79
|
+
old.close()
|
|
80
|
+
except Exception:
|
|
81
|
+
pass
|
|
82
|
+
return data
|
|
83
|
+
|
|
84
|
+
def clear(self) -> None:
|
|
85
|
+
"""Clear content and drop buffer capacity."""
|
|
86
|
+
old = self._buf
|
|
87
|
+
self._buf = StringIO()
|
|
88
|
+
self._size = 0
|
|
89
|
+
try:
|
|
90
|
+
old.close()
|
|
91
|
+
except Exception:
|
|
92
|
+
pass
|
|
93
|
+
|
|
51
94
|
def __init__(self, window=None):
|
|
52
95
|
super(Renderer, self).__init__(window)
|
|
53
96
|
"""
|
|
@@ -69,7 +112,7 @@ class Renderer(BaseRenderer):
|
|
|
69
112
|
self._file_prefix = 'file:///' if self.window and self.window.core.platforms.is_windows() else 'file://'
|
|
70
113
|
|
|
71
114
|
self._thr = {}
|
|
72
|
-
self._throttle_interval = 0.
|
|
115
|
+
self._throttle_interval = 0.03 # 30 ms delay
|
|
73
116
|
|
|
74
117
|
def prepare(self):
|
|
75
118
|
"""
|
|
@@ -328,6 +371,9 @@ class Renderer(BaseRenderer):
|
|
|
328
371
|
except Exception:
|
|
329
372
|
pass
|
|
330
373
|
|
|
374
|
+
# release strings
|
|
375
|
+
gc.collect()
|
|
376
|
+
|
|
331
377
|
def append_context(
|
|
332
378
|
self,
|
|
333
379
|
meta: CtxMeta,
|
|
@@ -597,7 +643,7 @@ class Renderer(BaseRenderer):
|
|
|
597
643
|
if self.window.core.config.get("agent.output.render.all", False):
|
|
598
644
|
output = ctx.output # full agent output
|
|
599
645
|
else:
|
|
600
|
-
output = ctx.extra["output"]
|
|
646
|
+
output = ctx.extra["output"] # final output only
|
|
601
647
|
else:
|
|
602
648
|
if not output:
|
|
603
649
|
return
|
|
@@ -656,6 +702,7 @@ class Renderer(BaseRenderer):
|
|
|
656
702
|
pid = self.get_or_create_pid(meta)
|
|
657
703
|
pctx = self.pids[pid]
|
|
658
704
|
pctx.item = ctx
|
|
705
|
+
|
|
659
706
|
if not text_chunk:
|
|
660
707
|
if begin:
|
|
661
708
|
pctx.clear()
|
|
@@ -663,13 +710,16 @@ class Renderer(BaseRenderer):
|
|
|
663
710
|
self._throttle_reset(pid)
|
|
664
711
|
return
|
|
665
712
|
|
|
666
|
-
if begin:
|
|
713
|
+
if begin:
|
|
714
|
+
# Prepare name header once per streaming session
|
|
667
715
|
pctx.header = self.get_name_header(ctx, stream=True)
|
|
668
716
|
self.update_names(meta, ctx)
|
|
669
717
|
|
|
670
718
|
name_header_str = pctx.header
|
|
671
719
|
text_chunk = text_chunk if isinstance(text_chunk, str) else str(text_chunk)
|
|
672
|
-
|
|
720
|
+
# Escape angle brackets only if present to avoid unnecessary allocations
|
|
721
|
+
if ('<' in text_chunk) or ('>' in text_chunk):
|
|
722
|
+
text_chunk = text_chunk.translate({ord('<'): '<', ord('>'): '>'})
|
|
673
723
|
|
|
674
724
|
if begin:
|
|
675
725
|
if self.is_debug():
|
|
@@ -683,42 +733,69 @@ class Renderer(BaseRenderer):
|
|
|
683
733
|
self.clear_chunks_output(pid)
|
|
684
734
|
self.prev_chunk_replace = False
|
|
685
735
|
|
|
736
|
+
# Append to the logical buffer (owned by pid)
|
|
686
737
|
pctx.append_buffer(text_chunk)
|
|
687
|
-
|
|
688
738
|
buffer = pctx.buffer
|
|
689
|
-
if has_unclosed_code_tag(buffer):
|
|
690
|
-
buffer_to_parse = "".join((buffer, "\n```"))
|
|
691
|
-
else:
|
|
692
|
-
buffer_to_parse = buffer
|
|
693
739
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
740
|
+
# Cheap detection of open code fence without full parse
|
|
741
|
+
open_code = has_unclosed_code_tag(buffer)
|
|
742
|
+
|
|
743
|
+
# Newline/flow state
|
|
698
744
|
is_n = "\n" in text_chunk
|
|
699
|
-
is_newline = is_n or buffer.endswith("\n") or
|
|
700
|
-
force_replace =
|
|
701
|
-
|
|
702
|
-
force_replace = True
|
|
703
|
-
if is_n:
|
|
704
|
-
self.prev_chunk_newline = True
|
|
705
|
-
else:
|
|
706
|
-
self.prev_chunk_newline = False
|
|
745
|
+
is_newline = is_n or buffer.endswith("\n") or open_code
|
|
746
|
+
force_replace = self.prev_chunk_newline
|
|
747
|
+
self.prev_chunk_newline = bool(is_n)
|
|
707
748
|
|
|
708
749
|
replace = False
|
|
709
|
-
if is_newline or force_replace
|
|
750
|
+
if is_newline or force_replace:
|
|
710
751
|
replace = True
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
752
|
+
# Do not replace for an open code block unless a newline arrived
|
|
753
|
+
if open_code and not is_n:
|
|
754
|
+
replace = False
|
|
755
|
+
|
|
756
|
+
thr = self._throttle_get(pid)
|
|
757
|
+
html = None
|
|
714
758
|
|
|
759
|
+
# Only parse when required:
|
|
760
|
+
# - a replace is needed now, or
|
|
761
|
+
# - a replace is pending in the throttle and must be refreshed, or
|
|
762
|
+
# - rarely: we must detect list termination without a newline
|
|
763
|
+
need_parse_for_pending_replace = (thr["op"] == 1)
|
|
764
|
+
need_parse_for_list = False
|
|
765
|
+
|
|
766
|
+
if not replace:
|
|
767
|
+
# Very rare case: list closing without newline. Check on a short tail only.
|
|
768
|
+
# This keeps behavior intact while avoiding full-buffer parse on every chunk.
|
|
769
|
+
tail = buffer[-4096:]
|
|
770
|
+
if tail:
|
|
771
|
+
tail_to_parse = f"{tail}\n```" if open_code else tail
|
|
772
|
+
tail_html = self.parser.parse(tail_to_parse)
|
|
773
|
+
need_parse_for_list = tail_html.endswith(self.ENDINGS_LIST)
|
|
774
|
+
# Tail string is short and will be collected promptly
|
|
775
|
+
del tail_html
|
|
776
|
+
if need_parse_for_list:
|
|
777
|
+
replace = True
|
|
778
|
+
|
|
779
|
+
if replace or need_parse_for_pending_replace:
|
|
780
|
+
buffer_to_parse = f"{buffer}\n```" if open_code else buffer
|
|
781
|
+
html = self.parser.parse(buffer_to_parse)
|
|
782
|
+
# Help the GC by breaking the reference as soon as possible
|
|
783
|
+
del buffer_to_parse
|
|
784
|
+
|
|
785
|
+
is_code_block = open_code
|
|
786
|
+
|
|
787
|
+
# Adjust output chunk formatting based on block type
|
|
715
788
|
if not is_code_block:
|
|
716
789
|
if is_n:
|
|
790
|
+
# Convert text newlines to <br/> in non-code context
|
|
717
791
|
text_chunk = text_chunk.replace("\n", "<br/>")
|
|
718
792
|
else:
|
|
793
|
+
# When previous operation replaced content and this chunk closes the fence,
|
|
794
|
+
# prepend a newline so the final code block renders correctly.
|
|
719
795
|
if self.prev_chunk_replace and (is_code_block and not has_unclosed_code_tag(text_chunk)):
|
|
720
796
|
text_chunk = "\n" + text_chunk
|
|
721
797
|
|
|
798
|
+
# Update replace flag for next iteration AFTER formatting decisions
|
|
722
799
|
self.prev_chunk_replace = replace
|
|
723
800
|
|
|
724
801
|
if begin:
|
|
@@ -727,7 +804,19 @@ class Renderer(BaseRenderer):
|
|
|
727
804
|
except Exception:
|
|
728
805
|
pass
|
|
729
806
|
|
|
730
|
-
|
|
807
|
+
# Queue throttled emission; HTML is only provided when it is really needed
|
|
808
|
+
self._throttle_queue(
|
|
809
|
+
pid=pid,
|
|
810
|
+
name=name_header_str or "",
|
|
811
|
+
html=html if html is not None else "",
|
|
812
|
+
text_chunk=text_chunk,
|
|
813
|
+
replace=replace,
|
|
814
|
+
is_code_block=is_code_block,
|
|
815
|
+
)
|
|
816
|
+
# Explicitly drop local ref to large html string as early as possible
|
|
817
|
+
html = None
|
|
818
|
+
|
|
819
|
+
# Emit if throttle interval allows
|
|
731
820
|
self._throttle_emit(pid, force=False)
|
|
732
821
|
|
|
733
822
|
def next_chunk(
|
|
@@ -1276,7 +1365,7 @@ class Renderer(BaseRenderer):
|
|
|
1276
1365
|
extra = ctx.extra["footer"]
|
|
1277
1366
|
extra_style = "display:block;"
|
|
1278
1367
|
|
|
1279
|
-
return
|
|
1368
|
+
return f'<div class="msg-box msg-user" id="{msg_id}"><div class="name-header name-user">{name}</div><div class="msg">{html}<div class="msg-extra" style="{extra_style}">{extra}</div>{debug}</div></div>'
|
|
1280
1369
|
|
|
1281
1370
|
def prepare_node_output(
|
|
1282
1371
|
self,
|
|
@@ -1289,7 +1378,7 @@ class Renderer(BaseRenderer):
|
|
|
1289
1378
|
"""
|
|
1290
1379
|
Prepare output node
|
|
1291
1380
|
|
|
1292
|
-
:param meta:
|
|
1381
|
+
:param meta: CtxMeta
|
|
1293
1382
|
:param ctx: CtxItem instance
|
|
1294
1383
|
:param html: html text
|
|
1295
1384
|
:param prev_ctx: previous context item
|
|
@@ -1772,6 +1861,9 @@ class Renderer(BaseRenderer):
|
|
|
1772
1861
|
"""
|
|
1773
1862
|
if not html:
|
|
1774
1863
|
return ""
|
|
1864
|
+
# Fast path: avoid regex work and extra allocations when not needed
|
|
1865
|
+
if '&' not in html:
|
|
1866
|
+
return html
|
|
1775
1867
|
return self.RE_AMP_LT_GT.sub(r'&\1;', html)
|
|
1776
1868
|
|
|
1777
1869
|
def append_debug(
|
|
@@ -1819,7 +1911,14 @@ class Renderer(BaseRenderer):
|
|
|
1819
1911
|
"""
|
|
1820
1912
|
thr = self._thr.get(pid)
|
|
1821
1913
|
if thr is None:
|
|
1822
|
-
thr = {
|
|
1914
|
+
thr = {
|
|
1915
|
+
"last": 0.0,
|
|
1916
|
+
"op": 0,
|
|
1917
|
+
"name": "",
|
|
1918
|
+
"replace_html": "",
|
|
1919
|
+
"append": Renderer._AppendBuffer(),
|
|
1920
|
+
"code": False,
|
|
1921
|
+
}
|
|
1823
1922
|
self._thr[pid] = thr
|
|
1824
1923
|
return thr
|
|
1825
1924
|
|
|
@@ -1837,7 +1936,8 @@ class Renderer(BaseRenderer):
|
|
|
1837
1936
|
thr["op"] = 0
|
|
1838
1937
|
thr["name"] = ""
|
|
1839
1938
|
thr["replace_html"] = ""
|
|
1840
|
-
|
|
1939
|
+
# Replace append buffer instance to drop any capacity eagerly
|
|
1940
|
+
thr["append"] = Renderer._AppendBuffer()
|
|
1841
1941
|
thr["code"] = False
|
|
1842
1942
|
|
|
1843
1943
|
def _throttle_queue(
|
|
@@ -1866,10 +1966,12 @@ class Renderer(BaseRenderer):
|
|
|
1866
1966
|
if replace:
|
|
1867
1967
|
thr["op"] = 1
|
|
1868
1968
|
thr["replace_html"] = html
|
|
1969
|
+
# Drop previous append items aggressively when a replace snapshot is available
|
|
1869
1970
|
thr["append"].clear()
|
|
1870
1971
|
thr["code"] = bool(is_code_block)
|
|
1871
1972
|
else:
|
|
1872
1973
|
if thr["op"] == 1:
|
|
1974
|
+
# Refresh the pending replace with the latest HTML snapshot
|
|
1873
1975
|
thr["replace_html"] = html
|
|
1874
1976
|
thr["code"] = bool(is_code_block)
|
|
1875
1977
|
return
|
|
@@ -1895,17 +1997,21 @@ class Renderer(BaseRenderer):
|
|
|
1895
1997
|
|
|
1896
1998
|
try:
|
|
1897
1999
|
if thr["op"] == 1:
|
|
2000
|
+
# Replace snapshot
|
|
2001
|
+
replace_payload = self.sanitize_html(thr["replace_html"])
|
|
1898
2002
|
node.page().bridge.chunk.emit(
|
|
1899
2003
|
thr["name"],
|
|
1900
|
-
|
|
2004
|
+
replace_payload,
|
|
1901
2005
|
"",
|
|
1902
2006
|
True,
|
|
1903
2007
|
bool(thr["code"]),
|
|
1904
2008
|
)
|
|
2009
|
+
thr["replace_html"] = "" # Cut reference ASAP
|
|
1905
2010
|
thr["last"] = now
|
|
1906
2011
|
|
|
1907
|
-
if
|
|
1908
|
-
|
|
2012
|
+
# Append tail (if any)
|
|
2013
|
+
if not thr["append"].is_empty():
|
|
2014
|
+
append_str = thr["append"].get_and_clear()
|
|
1909
2015
|
node.page().bridge.chunk.emit(
|
|
1910
2016
|
thr["name"],
|
|
1911
2017
|
"",
|
|
@@ -1917,8 +2023,8 @@ class Renderer(BaseRenderer):
|
|
|
1917
2023
|
|
|
1918
2024
|
self._throttle_reset(pid)
|
|
1919
2025
|
|
|
1920
|
-
elif thr["op"] == 2 and thr["append"]:
|
|
1921
|
-
append_str =
|
|
2026
|
+
elif thr["op"] == 2 and not thr["append"].is_empty():
|
|
2027
|
+
append_str = thr["append"].get_and_clear()
|
|
1922
2028
|
node.page().bridge.chunk.emit(
|
|
1923
2029
|
thr["name"],
|
|
1924
2030
|
"",
|
pygpt_net/core/text/utils.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"__meta__": {
|
|
3
|
-
"version": "2.6.
|
|
4
|
-
"app.version": "2.6.
|
|
5
|
-
"updated_at": "2025-09-
|
|
3
|
+
"version": "2.6.36",
|
|
4
|
+
"app.version": "2.6.36",
|
|
5
|
+
"updated_at": "2025-09-04T00:00:00"
|
|
6
6
|
},
|
|
7
7
|
"access.audio.event.speech": false,
|
|
8
8
|
"access.audio.event.speech.disabled": [],
|
|
@@ -354,6 +354,7 @@
|
|
|
354
354
|
"painter.brush.mode": "brush",
|
|
355
355
|
"painter.brush.size": 3,
|
|
356
356
|
"painter.canvas.size": "1280x720",
|
|
357
|
+
"painter.zoom": 100,
|
|
357
358
|
"personalize.about": "",
|
|
358
359
|
"personalize.modes": "chat",
|
|
359
360
|
"plugins": {},
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"__meta__": {
|
|
3
|
-
"version": "2.6.
|
|
4
|
-
"app.version": "2.6.
|
|
5
|
-
"updated_at": "2025-09-
|
|
3
|
+
"version": "2.6.36",
|
|
4
|
+
"app.version": "2.6.36",
|
|
5
|
+
"updated_at": "2025-09-04T08:03:34"
|
|
6
6
|
},
|
|
7
7
|
"items": {
|
|
8
8
|
"SpeakLeash/bielik-11b-v2.3-instruct:Q4_K_M": {
|
|
@@ -1520,7 +1520,8 @@
|
|
|
1520
1520
|
},
|
|
1521
1521
|
"vision.capture.idx": {
|
|
1522
1522
|
"section": "vision",
|
|
1523
|
-
"type": "
|
|
1523
|
+
"type": "combo",
|
|
1524
|
+
"use": "camera_devices",
|
|
1524
1525
|
"slider": true,
|
|
1525
1526
|
"label": "settings.vision.capture.idx",
|
|
1526
1527
|
"description": "settings.vision.capture.idx.desc",
|
|
@@ -1529,7 +1530,8 @@
|
|
|
1529
1530
|
"max": 3,
|
|
1530
1531
|
"multiplier": 1,
|
|
1531
1532
|
"step": 1,
|
|
1532
|
-
"advanced": false
|
|
1533
|
+
"advanced": false,
|
|
1534
|
+
"tab": "camera"
|
|
1533
1535
|
},
|
|
1534
1536
|
"vision.capture.width": {
|
|
1535
1537
|
"section": "vision",
|
|
@@ -1541,7 +1543,8 @@
|
|
|
1541
1543
|
"max": 4096,
|
|
1542
1544
|
"multiplier": 1,
|
|
1543
1545
|
"step": 1,
|
|
1544
|
-
"advanced": false
|
|
1546
|
+
"advanced": false,
|
|
1547
|
+
"tab": "camera"
|
|
1545
1548
|
},
|
|
1546
1549
|
"vision.capture.height": {
|
|
1547
1550
|
"section": "vision",
|
|
@@ -1553,7 +1556,8 @@
|
|
|
1553
1556
|
"max": 4096,
|
|
1554
1557
|
"multiplier": 1,
|
|
1555
1558
|
"step": 1,
|
|
1556
|
-
"advanced": false
|
|
1559
|
+
"advanced": false,
|
|
1560
|
+
"tab": "camera"
|
|
1557
1561
|
},
|
|
1558
1562
|
"vision.capture.quality": {
|
|
1559
1563
|
"section": "vision",
|
|
@@ -1565,7 +1569,8 @@
|
|
|
1565
1569
|
"max": 100,
|
|
1566
1570
|
"multiplier": 1,
|
|
1567
1571
|
"step": 1,
|
|
1568
|
-
"advanced": false
|
|
1572
|
+
"advanced": false,
|
|
1573
|
+
"tab": "camera"
|
|
1569
1574
|
},
|
|
1570
1575
|
"audio.input.backend": {
|
|
1571
1576
|
"section": "audio",
|
|
@@ -13,7 +13,6 @@ body {{
|
|
|
13
13
|
word-wrap: break-word;
|
|
14
14
|
padding: 6px;
|
|
15
15
|
line-height: 1.25;
|
|
16
|
-
will-change: transform, opacity;
|
|
17
16
|
margin: 4px;
|
|
18
17
|
padding: 0;
|
|
19
18
|
max-width: 100%;
|
|
@@ -24,12 +23,14 @@ body {{
|
|
|
24
23
|
}}
|
|
25
24
|
::-webkit-scrollbar-thumb {{
|
|
26
25
|
-webkit-border-radius: 1ex;
|
|
27
|
-
-webkit-box-shadow:
|
|
26
|
+
-webkit-box-shadow: none;
|
|
27
|
+
}}
|
|
28
|
+
#container {{
|
|
29
|
+
will-change: transform, opacity;
|
|
28
30
|
}}
|
|
29
31
|
.ts {{
|
|
30
32
|
display: none;
|
|
31
33
|
}}
|
|
32
|
-
|
|
33
34
|
/* base */
|
|
34
35
|
a {{
|
|
35
36
|
text-decoration: none;
|
|
@@ -13,7 +13,6 @@ body {{
|
|
|
13
13
|
word-wrap: break-word;
|
|
14
14
|
padding: 6px;
|
|
15
15
|
line-height: 1.25;
|
|
16
|
-
will-change: transform, opacity;
|
|
17
16
|
padding: 0;
|
|
18
17
|
margin: auto;
|
|
19
18
|
max-width: 720px;
|
|
@@ -25,7 +24,10 @@ body {{
|
|
|
25
24
|
}}
|
|
26
25
|
::-webkit-scrollbar-thumb {{
|
|
27
26
|
-webkit-border-radius: 1ex;
|
|
28
|
-
-webkit-box-shadow:
|
|
27
|
+
-webkit-box-shadow: none;
|
|
28
|
+
}}
|
|
29
|
+
#container {{
|
|
30
|
+
will-change: transform, opacity;
|
|
29
31
|
}}
|
|
30
32
|
.ts {{
|
|
31
33
|
display: none;
|
|
@@ -13,7 +13,6 @@ body {{
|
|
|
13
13
|
word-wrap: break-word;
|
|
14
14
|
padding: 6px;
|
|
15
15
|
line-height: 1.25;
|
|
16
|
-
will-change: transform, opacity;
|
|
17
16
|
padding: 0;
|
|
18
17
|
margin: auto;
|
|
19
18
|
max-width: 100%;
|
|
@@ -25,7 +24,10 @@ body {{
|
|
|
25
24
|
}}
|
|
26
25
|
::-webkit-scrollbar-thumb {{
|
|
27
26
|
-webkit-border-radius: 1ex;
|
|
28
|
-
-webkit-box-shadow:
|
|
27
|
+
-webkit-box-shadow: none;
|
|
28
|
+
}}
|
|
29
|
+
#container {{
|
|
30
|
+
will-change: transform, opacity;
|
|
29
31
|
}}
|
|
30
32
|
.ts {{
|
|
31
33
|
display: none;
|
|
@@ -957,10 +957,11 @@ output.tips.7 = Für eine bessere Leistung deaktivieren Sie die Werkzeuge, wenn
|
|
|
957
957
|
output.tips.8 = Wenn Sie lokale Modelle verwenden, denken Sie daran, das lokale Modell auch für die Kontextzusammenfassung und Einbettungen einzustellen.
|
|
958
958
|
output.tips.9 = Um Audio-Ein- und Ausgangsanbieter zu konfigurieren, gehen Sie zu Plugins -> Einstellungen. Um Audiogeräte zu konfigurieren, gehen Sie zu Konfiguration -> Einstellungen -> Audio.
|
|
959
959
|
output.tips.prefix = Tipp
|
|
960
|
-
painter.btn.crop = Zuschneiden
|
|
961
960
|
painter.btn.camera.capture = Von der Kamera
|
|
962
961
|
painter.btn.capture = Bild erfassen
|
|
963
962
|
painter.btn.clear = Löschen
|
|
963
|
+
painter.btn.crop = Zuschneiden
|
|
964
|
+
painter.btn.fit = Anpassen
|
|
964
965
|
painter.capture.manual.captured.success = Bild erfasst:
|
|
965
966
|
painter.capture.name.prefix = Zeichnung von
|
|
966
967
|
painter.mode.erase = Radieren
|
|
@@ -1364,7 +1365,8 @@ settings.section.remote_tools = Fernwerkzeuge
|
|
|
1364
1365
|
settings.section.remote_tools.openai = OpenAI
|
|
1365
1366
|
settings.section.tab.general = Allgemein
|
|
1366
1367
|
settings.section.updates = Aktualisierungen
|
|
1367
|
-
settings.section.vision = Vision
|
|
1368
|
+
settings.section.vision = Vision und Kamera
|
|
1369
|
+
settings.section.vision.camera = Kamera
|
|
1368
1370
|
settings.store_history = Verlauf speichern
|
|
1369
1371
|
settings.store_history_time = Uhrzeit im Verlauf speichern
|
|
1370
1372
|
settings.temperature = Temperatur
|
|
@@ -1394,11 +1396,11 @@ settings.video.seed = Startwert
|
|
|
1394
1396
|
settings.video.seed.desc = Optionaler Zufallsstartwert für reproduzierbare Ergebnisse; leer lassen für zufällig
|
|
1395
1397
|
settings.vision.capture.auto = Automatisches Erfassen
|
|
1396
1398
|
settings.vision.capture.enabled = Kamera
|
|
1397
|
-
settings.vision.capture.height =
|
|
1398
|
-
settings.vision.capture.idx =
|
|
1399
|
-
settings.vision.capture.idx.desc =
|
|
1400
|
-
settings.vision.capture.quality =
|
|
1401
|
-
settings.vision.capture.width =
|
|
1399
|
+
settings.vision.capture.height = Aufnahmehöhe (in Pixeln)
|
|
1400
|
+
settings.vision.capture.idx = Kameragerät
|
|
1401
|
+
settings.vision.capture.idx.desc = Wählen Sie ein Kameragerät für die Echtzeit-Videoaufnahme
|
|
1402
|
+
settings.vision.capture.quality = Aufnahmequalität (%)
|
|
1403
|
+
settings.vision.capture.width = Aufnahmewidth (in Pixeln)
|
|
1402
1404
|
settings.zoom = Zoomen des Chat-Ausgabefensters
|
|
1403
1405
|
speech.enable = Sprachausgabe aktivieren
|
|
1404
1406
|
speech.listening = Sprechen Sie jetzt...
|
|
@@ -147,6 +147,7 @@ assistant.store.expire_days.desc = 0 = Never
|
|
|
147
147
|
assistant.store.files.suffix = files
|
|
148
148
|
assistant.store.hide_threads = Hide threads vector stores
|
|
149
149
|
assistant.store.id = ID
|
|
150
|
+
assistant.store.menu.file.delete = Delete file
|
|
150
151
|
assistant.store.name = Name
|
|
151
152
|
assistant.store.status = Status
|
|
152
153
|
assistant.store.thread_only = (current thread only)
|
|
@@ -250,6 +251,7 @@ confirm.assistant.import = Import all assistants from API?
|
|
|
250
251
|
confirm.assistant.import_files = Import all files from API?
|
|
251
252
|
confirm.assistant.import_files.store = Import current store files from API?
|
|
252
253
|
confirm.assistant.store.clear = Clear vector stores (local only)?
|
|
254
|
+
confirm.assistant.store.file.delete = Delete selected file in API?
|
|
253
255
|
confirm.assistant.store.import = Import all vector stores from API?
|
|
254
256
|
confirm.assistant.store.refresh = Refresh all stores?
|
|
255
257
|
confirm.assistant.store.truncate = Delete all vector stores in API?
|
|
@@ -958,10 +960,11 @@ output.tips.7 = For better performance, disable tools when using local models if
|
|
|
958
960
|
output.tips.8 = When using local models, remember to set the local model for context summary and embeddings as well.
|
|
959
961
|
output.tips.9 = To configure audio input and output providers, go to Plugins -> Settings. To configure audio devices, go to Config -> Settings -> Audio.
|
|
960
962
|
output.tips.prefix = Tip
|
|
961
|
-
painter.btn.crop = Crop
|
|
962
963
|
painter.btn.camera.capture = From camera
|
|
963
964
|
painter.btn.capture = Use image
|
|
964
965
|
painter.btn.clear = Clear
|
|
966
|
+
painter.btn.crop = Crop
|
|
967
|
+
painter.btn.fit = Fit
|
|
965
968
|
painter.capture.manual.captured.success = Image captured:
|
|
966
969
|
painter.capture.name.prefix = Drawing from
|
|
967
970
|
painter.mode.erase = Erase
|
|
@@ -1406,7 +1409,8 @@ settings.section.remote_tools.google = Google
|
|
|
1406
1409
|
settings.section.remote_tools.openai = OpenAI
|
|
1407
1410
|
settings.section.tab.general = General
|
|
1408
1411
|
settings.section.updates = Updates
|
|
1409
|
-
settings.section.vision = Vision
|
|
1412
|
+
settings.section.vision = Vision and camera
|
|
1413
|
+
settings.section.vision.camera = Camera
|
|
1410
1414
|
settings.store_history = Store history
|
|
1411
1415
|
settings.store_history_time = Store time in history
|
|
1412
1416
|
settings.temperature = Temperature
|
|
@@ -1436,11 +1440,11 @@ settings.video.seed = Seed
|
|
|
1436
1440
|
settings.video.seed.desc = Optional random seed for reproducible results; leave empty for random
|
|
1437
1441
|
settings.vision.capture.auto = Auto capture
|
|
1438
1442
|
settings.vision.capture.enabled = Camera
|
|
1439
|
-
settings.vision.capture.height =
|
|
1440
|
-
settings.vision.capture.idx = Camera
|
|
1441
|
-
settings.vision.capture.idx.desc =
|
|
1443
|
+
settings.vision.capture.height = Capture height (in pixels)
|
|
1444
|
+
settings.vision.capture.idx = Camera Device
|
|
1445
|
+
settings.vision.capture.idx.desc = Select a camera device for real-time video capture
|
|
1442
1446
|
settings.vision.capture.quality = Capture quality (%)
|
|
1443
|
-
settings.vision.capture.width =
|
|
1447
|
+
settings.vision.capture.width = Capture width (in pixels)
|
|
1444
1448
|
settings.zoom = Chat output window zoom
|
|
1445
1449
|
speech.enable = Speak
|
|
1446
1450
|
speech.listening = Speak now...
|