pygpt-net 2.6.49__py3-none-any.whl → 2.6.50__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 +6 -0
- pygpt_net/__init__.py +1 -1
- pygpt_net/controller/plugins/plugins.py +1 -1
- pygpt_net/core/render/plain/pid.py +2 -0
- pygpt_net/core/tabs/tabs.py +3 -2
- pygpt_net/data/config/config.json +2 -2
- pygpt_net/data/config/models.json +2 -2
- pygpt_net/data/fixtures/fake_stream.txt +21 -0
- pygpt_net/data/js/app.js +69 -15
- pygpt_net/js_rc.py +12200 -12058
- {pygpt_net-2.6.49.dist-info → pygpt_net-2.6.50.dist-info}/METADATA +8 -2
- {pygpt_net-2.6.49.dist-info → pygpt_net-2.6.50.dist-info}/RECORD +15 -15
- {pygpt_net-2.6.49.dist-info → pygpt_net-2.6.50.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.49.dist-info → pygpt_net-2.6.50.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.49.dist-info → pygpt_net-2.6.50.dist-info}/entry_points.txt +0 -0
pygpt_net/CHANGELOG.txt
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
2.6.50 (2025-09-16)
|
|
2
|
+
|
|
3
|
+
- Optimized: Improved memory cleanup when switching profiles and unloading tabs.
|
|
4
|
+
- Fix: Resolved missing PID data in text output.
|
|
5
|
+
- Fix: Enhanced real-time parsing of execute tags.
|
|
6
|
+
|
|
1
7
|
2.6.49 (2025-09-16)
|
|
2
8
|
|
|
3
9
|
- Fixed: Occasional crashes when focusing on an output container unloaded from memory in the second column.
|
pygpt_net/__init__.py
CHANGED
|
@@ -13,7 +13,7 @@ __author__ = "Marcin Szczygliński"
|
|
|
13
13
|
__copyright__ = "Copyright 2025, Marcin Szczygliński"
|
|
14
14
|
__credits__ = ["Marcin Szczygliński"]
|
|
15
15
|
__license__ = "MIT"
|
|
16
|
-
__version__ = "2.6.
|
|
16
|
+
__version__ = "2.6.50"
|
|
17
17
|
__build__ = "2025-09-16"
|
|
18
18
|
__maintainer__ = "Marcin Szczygliński"
|
|
19
19
|
__github__ = "https://github.com/szczyglis-dev/py-gpt"
|
|
@@ -23,6 +23,7 @@ class PidData:
|
|
|
23
23
|
files_appended: list = field(default_factory=list)
|
|
24
24
|
_buffer: io.StringIO = field(default_factory=io.StringIO)
|
|
25
25
|
is_cmd: bool = False
|
|
26
|
+
loaded: bool = False
|
|
26
27
|
|
|
27
28
|
def __init__(self, pid, meta=None):
|
|
28
29
|
"""Pid Data"""
|
|
@@ -33,6 +34,7 @@ class PidData:
|
|
|
33
34
|
self.files_appended = []
|
|
34
35
|
self._buffer = io.StringIO()
|
|
35
36
|
self.is_cmd = False
|
|
37
|
+
self.loaded = False
|
|
36
38
|
|
|
37
39
|
@property
|
|
38
40
|
def buffer(self) -> str:
|
pygpt_net/core/tabs/tabs.py
CHANGED
|
@@ -17,7 +17,7 @@ from PySide6.QtGui import QIcon
|
|
|
17
17
|
from PySide6.QtWidgets import QVBoxLayout, QWidget, QLayout
|
|
18
18
|
|
|
19
19
|
from pygpt_net.ui.widget.tabs.body import TabBody
|
|
20
|
-
from pygpt_net.utils import trans
|
|
20
|
+
from pygpt_net.utils import trans, mem_clean
|
|
21
21
|
|
|
22
22
|
from .tab import Tab
|
|
23
23
|
|
|
@@ -318,6 +318,7 @@ class Tabs:
|
|
|
318
318
|
print(f"Error unloading tab {pid}: {e}")
|
|
319
319
|
self.window.core.debug.log(e)
|
|
320
320
|
|
|
321
|
+
mem_clean(force=True)
|
|
321
322
|
column_idx = tab.column_idx
|
|
322
323
|
self.window.ui.layout.get_tabs_by_idx(column_idx).removeTab(tab.idx)
|
|
323
324
|
del self.pids[pid]
|
|
@@ -325,7 +326,7 @@ class Tabs:
|
|
|
325
326
|
|
|
326
327
|
def remove_all(self):
|
|
327
328
|
"""Remove all tabs"""
|
|
328
|
-
for pid in list(self.pids):
|
|
329
|
+
for pid in list(self.pids.keys()):
|
|
329
330
|
self.remove(pid) # delete from PIDs and UI
|
|
330
331
|
self.pids = {}
|
|
331
332
|
self.window.core.ctx.output.clear() # clear mapping
|
|
@@ -6,6 +6,27 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent lobortis lorem
|
|
|
6
6
|
b = 2
|
|
7
7
|
c = a + b
|
|
8
8
|
print(c)
|
|
9
|
+
class ChatWebOutput(QWebEngineView):
|
|
10
|
+
def __init__(self, window=None):
|
|
11
|
+
"""
|
|
12
|
+
HTML output (WebEngine)
|
|
13
|
+
|
|
14
|
+
:param window: Window instance
|
|
15
|
+
"""
|
|
16
|
+
super(ChatWebOutput, self).__init__(window)
|
|
17
|
+
self.window = window
|
|
18
|
+
self.finder = WebFinder(window, self)
|
|
19
|
+
self.loadFinished.connect(self.on_page_loaded)
|
|
20
|
+
self.customContextMenuRequested.connect(self.on_context_menu)
|
|
21
|
+
self.signals = WebEngineSignals(self)
|
|
22
|
+
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
|
23
|
+
self.filter = FocusEventFilter(self, self.on_focus)
|
|
24
|
+
self.installEventFilter(self)
|
|
25
|
+
self.plain = None
|
|
26
|
+
self.html_content = None
|
|
27
|
+
self.meta = None
|
|
28
|
+
self.tab = None
|
|
29
|
+
self.setProperty('class', 'layout-output-web')
|
|
9
30
|
</execute>
|
|
10
31
|
|
|
11
32
|
<tool>{"cmd": "fake_cmd", "params": {"foo": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."}}</tool>
|
pygpt_net/data/js/app.js
CHANGED
|
@@ -1383,6 +1383,7 @@
|
|
|
1383
1383
|
const rules = this.__compiled;
|
|
1384
1384
|
if (!rules || !rules.length) return s;
|
|
1385
1385
|
|
|
1386
|
+
// Candidates: rules that want source-phase replacements (``` fences)
|
|
1386
1387
|
const candidates = [];
|
|
1387
1388
|
for (let i = 0; i < rules.length; i++) {
|
|
1388
1389
|
const r = rules[i];
|
|
@@ -1391,27 +1392,42 @@
|
|
|
1391
1392
|
}
|
|
1392
1393
|
if (!candidates.length) return s;
|
|
1393
1394
|
|
|
1395
|
+
// Avoid touching content already inside Markdown code fences
|
|
1394
1396
|
const fences = this._findFenceRanges(s);
|
|
1397
|
+
|
|
1398
|
+
let result = '';
|
|
1395
1399
|
if (!fences.length) {
|
|
1396
|
-
|
|
1400
|
+
result = this._applySourceReplacementsInChunk(s, s, 0, candidates);
|
|
1401
|
+
} else {
|
|
1402
|
+
let out = '';
|
|
1403
|
+
let last = 0;
|
|
1404
|
+
for (let k = 0; k < fences.length; k++) {
|
|
1405
|
+
const [a, b] = fences[k];
|
|
1406
|
+
if (a > last) {
|
|
1407
|
+
const chunk = s.slice(last, a);
|
|
1408
|
+
out += this._applySourceReplacementsInChunk(s, chunk, last, candidates);
|
|
1409
|
+
}
|
|
1410
|
+
out += s.slice(a, b);
|
|
1411
|
+
last = b;
|
|
1412
|
+
}
|
|
1413
|
+
if (last < s.length) {
|
|
1414
|
+
const tail = s.slice(last);
|
|
1415
|
+
out += this._applySourceReplacementsInChunk(s, tail, last, candidates);
|
|
1416
|
+
}
|
|
1417
|
+
result = out;
|
|
1397
1418
|
}
|
|
1398
1419
|
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1420
|
+
// NEW: streaming-aware partial injection for unmatched source-fence openers.
|
|
1421
|
+
// If we are streaming and see a last opener without a closer, convert it to its openReplace
|
|
1422
|
+
// (e.g., <execute> -> ```python\n) so the snapshot immediately materializes a code block.
|
|
1423
|
+
if (opts && opts.streaming === true) {
|
|
1424
|
+
const fenceRules = candidates.filter(r => !!r.isSourceFence);
|
|
1425
|
+
if (fenceRules.length) {
|
|
1426
|
+
result = this._injectUnmatchedSourceOpeners(result, fenceRules);
|
|
1406
1427
|
}
|
|
1407
|
-
out += s.slice(a, b);
|
|
1408
|
-
last = b;
|
|
1409
1428
|
}
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
out += this._applySourceReplacementsInChunk(s, tail, last, candidates);
|
|
1413
|
-
}
|
|
1414
|
-
return out;
|
|
1429
|
+
|
|
1430
|
+
return result;
|
|
1415
1431
|
}
|
|
1416
1432
|
|
|
1417
1433
|
getSourceFenceSpecs() {
|
|
@@ -1996,6 +2012,44 @@
|
|
|
1996
2012
|
}
|
|
1997
2013
|
return t;
|
|
1998
2014
|
}
|
|
2015
|
+
|
|
2016
|
+
// === NEW: streaming helper for unmatched source-fence openers ===
|
|
2017
|
+
_injectUnmatchedSourceOpeners(text, fenceRules) {
|
|
2018
|
+
// Production-grade guardrails
|
|
2019
|
+
let s = String(text || '');
|
|
2020
|
+
if (!s || !fenceRules || !fenceRules.length) return s;
|
|
2021
|
+
|
|
2022
|
+
// Find the last opener (closest to the end) that has no matching closer after it
|
|
2023
|
+
let best = null; // { r, idx }
|
|
2024
|
+
for (let i = 0; i < fenceRules.length; i++) {
|
|
2025
|
+
const r = fenceRules[i];
|
|
2026
|
+
if (!r || !r.open || !r.close || !r.openReplace) continue;
|
|
2027
|
+
|
|
2028
|
+
const idx = s.lastIndexOf(r.open);
|
|
2029
|
+
if (idx === -1) continue;
|
|
2030
|
+
|
|
2031
|
+
// Must be top-level line (so that ``` can start a fenced block)
|
|
2032
|
+
if (!this._isTopLevelLineInSource(s, idx)) continue;
|
|
2033
|
+
|
|
2034
|
+
// Ensure there is no closer after this opener in the current snapshot
|
|
2035
|
+
const after = s.indexOf(r.close, idx + r.open.length);
|
|
2036
|
+
if (after !== -1) continue;
|
|
2037
|
+
|
|
2038
|
+
if (!best || idx > best.idx) best = { r, idx };
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
if (!best) return s;
|
|
2042
|
+
|
|
2043
|
+
const r = best.r;
|
|
2044
|
+
const i = best.idx;
|
|
2045
|
+
|
|
2046
|
+
// Replace the raw opener token with its source-fence open replacement (e.g. ```python\n)
|
|
2047
|
+
// This is ephemeral per-snapshot; underlying buffer remains unchanged.
|
|
2048
|
+
const before = s.slice(0, i);
|
|
2049
|
+
const after = s.slice(i + r.open.length);
|
|
2050
|
+
const injected = String(r.openReplace || '');
|
|
2051
|
+
return before + injected + after;
|
|
2052
|
+
}
|
|
1999
2053
|
}
|
|
2000
2054
|
|
|
2001
2055
|
// ==========================================================================
|