pygpt-net 2.7.9__py3-none-any.whl → 2.7.10__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 +9 -0
- pygpt_net/LICENSE +1 -1
- pygpt_net/__init__.py +3 -3
- pygpt_net/config.py +15 -1
- pygpt_net/controller/chat/common.py +5 -4
- pygpt_net/controller/chat/image.py +3 -3
- pygpt_net/controller/chat/stream.py +76 -41
- pygpt_net/controller/chat/stream_worker.py +3 -3
- pygpt_net/controller/ctx/extra.py +3 -1
- pygpt_net/controller/dialogs/debug.py +37 -8
- pygpt_net/controller/kernel/kernel.py +3 -7
- pygpt_net/controller/lang/custom.py +25 -12
- pygpt_net/controller/lang/lang.py +45 -3
- pygpt_net/controller/lang/mapping.py +15 -2
- pygpt_net/controller/notepad/notepad.py +68 -25
- pygpt_net/controller/presets/editor.py +5 -1
- pygpt_net/controller/presets/presets.py +17 -5
- pygpt_net/controller/theme/theme.py +11 -2
- pygpt_net/controller/ui/tabs.py +1 -1
- pygpt_net/core/ctx/output.py +38 -12
- pygpt_net/core/db/database.py +4 -2
- pygpt_net/core/debug/console/console.py +30 -2
- pygpt_net/core/debug/context.py +2 -1
- pygpt_net/core/debug/ui.py +26 -4
- pygpt_net/core/filesystem/filesystem.py +6 -2
- pygpt_net/core/notepad/notepad.py +2 -2
- pygpt_net/core/tabs/tabs.py +79 -19
- pygpt_net/data/config/config.json +3 -3
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/settings.json +12 -0
- pygpt_net/data/locale/locale.ar.ini +1833 -0
- pygpt_net/data/locale/locale.bg.ini +1833 -0
- pygpt_net/data/locale/locale.cs.ini +1833 -0
- pygpt_net/data/locale/locale.da.ini +1833 -0
- pygpt_net/data/locale/locale.de.ini +4 -1
- pygpt_net/data/locale/locale.en.ini +70 -67
- pygpt_net/data/locale/locale.es.ini +4 -1
- pygpt_net/data/locale/locale.fi.ini +1833 -0
- pygpt_net/data/locale/locale.fr.ini +4 -1
- pygpt_net/data/locale/locale.he.ini +1833 -0
- pygpt_net/data/locale/locale.hi.ini +1833 -0
- pygpt_net/data/locale/locale.hu.ini +1833 -0
- pygpt_net/data/locale/locale.it.ini +4 -1
- pygpt_net/data/locale/locale.ja.ini +1833 -0
- pygpt_net/data/locale/locale.ko.ini +1833 -0
- pygpt_net/data/locale/locale.nl.ini +1833 -0
- pygpt_net/data/locale/locale.no.ini +1833 -0
- pygpt_net/data/locale/locale.pl.ini +5 -2
- pygpt_net/data/locale/locale.pt.ini +1833 -0
- pygpt_net/data/locale/locale.ro.ini +1833 -0
- pygpt_net/data/locale/locale.ru.ini +1833 -0
- pygpt_net/data/locale/locale.sk.ini +1833 -0
- pygpt_net/data/locale/locale.sv.ini +1833 -0
- pygpt_net/data/locale/locale.tr.ini +1833 -0
- pygpt_net/data/locale/locale.uk.ini +4 -1
- pygpt_net/data/locale/locale.zh.ini +4 -1
- pygpt_net/item/notepad.py +8 -2
- pygpt_net/migrations/Version20260121190000.py +25 -0
- pygpt_net/migrations/Version20260122140000.py +25 -0
- pygpt_net/migrations/__init__.py +5 -1
- pygpt_net/preload.py +246 -3
- pygpt_net/provider/api/__init__.py +16 -2
- pygpt_net/provider/api/anthropic/__init__.py +21 -7
- pygpt_net/provider/api/google/__init__.py +21 -7
- pygpt_net/provider/api/google/image.py +89 -2
- pygpt_net/provider/api/google/video.py +2 -2
- pygpt_net/provider/api/openai/__init__.py +26 -11
- pygpt_net/provider/api/openai/image.py +79 -3
- pygpt_net/provider/api/openai/responses.py +11 -31
- pygpt_net/provider/api/openai/video.py +2 -2
- pygpt_net/provider/api/x_ai/__init__.py +21 -7
- pygpt_net/provider/core/notepad/db_sqlite/storage.py +53 -10
- pygpt_net/tools/agent_builder/ui/dialogs.py +2 -1
- pygpt_net/tools/audio_transcriber/ui/dialogs.py +2 -1
- pygpt_net/tools/code_interpreter/ui/dialogs.py +2 -1
- pygpt_net/tools/html_canvas/ui/dialogs.py +2 -1
- pygpt_net/tools/image_viewer/ui/dialogs.py +3 -5
- pygpt_net/tools/indexer/ui/dialogs.py +2 -1
- pygpt_net/tools/media_player/ui/dialogs.py +2 -1
- pygpt_net/tools/translator/ui/dialogs.py +2 -1
- pygpt_net/tools/translator/ui/widgets.py +6 -2
- pygpt_net/ui/dialog/about.py +2 -2
- pygpt_net/ui/dialog/db.py +2 -1
- pygpt_net/ui/dialog/debug.py +169 -6
- pygpt_net/ui/dialog/logger.py +6 -2
- pygpt_net/ui/dialog/models.py +36 -3
- pygpt_net/ui/dialog/preset.py +5 -1
- pygpt_net/ui/dialog/remote_store.py +2 -1
- pygpt_net/ui/main.py +3 -2
- pygpt_net/ui/widget/dialog/editor_file.py +2 -1
- pygpt_net/ui/widget/lists/debug.py +12 -7
- pygpt_net/ui/widget/option/checkbox.py +2 -8
- pygpt_net/ui/widget/option/combo.py +10 -2
- pygpt_net/ui/widget/textarea/console.py +156 -7
- pygpt_net/ui/widget/textarea/highlight.py +66 -0
- pygpt_net/ui/widget/textarea/input.py +624 -57
- pygpt_net/ui/widget/textarea/notepad.py +294 -27
- {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.dist-info}/LICENSE +1 -1
- {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.dist-info}/METADATA +11 -64
- {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.dist-info}/RECORD +102 -81
- {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.dist-info}/WHEEL +0 -0
- {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.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:
|
|
9
|
+
# Updated Date: 2026.01.22 17:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt
|
|
@@ -35,6 +35,7 @@ class AudioTranscribe:
|
|
|
35
35
|
def setup_menu(self, parent=None) -> QMenuBar:
|
|
36
36
|
"""Setup audio transcriber dialog menu"""
|
|
37
37
|
self.menu_bar = QMenuBar(parent)
|
|
38
|
+
self.menu_bar.setNativeMenuBar(False)
|
|
38
39
|
self.file_menu = self.menu_bar.addMenu(trans("menu.file"))
|
|
39
40
|
t = self.window.tools.get("transcriber")
|
|
40
41
|
|
|
@@ -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:
|
|
9
|
+
# Updated Date: 2026.01.22 17:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt
|
|
@@ -75,6 +75,7 @@ class Tool:
|
|
|
75
75
|
"""
|
|
76
76
|
# create menu bar
|
|
77
77
|
self.menu_bar = QMenuBar()
|
|
78
|
+
self.menu_bar.setNativeMenuBar(False)
|
|
78
79
|
self.menu["file"] = self.menu_bar.addMenu(trans("interpreter.menu.file"))
|
|
79
80
|
self.menu["kernel"] = self.menu_bar.addMenu(trans("interpreter.menu.kernel"))
|
|
80
81
|
|
|
@@ -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:
|
|
9
|
+
# Updated Date: 2026.01.22 17:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import re
|
|
@@ -53,6 +53,7 @@ class Tool:
|
|
|
53
53
|
"""
|
|
54
54
|
# create menu bar
|
|
55
55
|
self.menu_bar = QMenuBar()
|
|
56
|
+
self.menu_bar.setNativeMenuBar(False)
|
|
56
57
|
self.menu["file"] = self.menu_bar.addMenu(trans("menu.file"))
|
|
57
58
|
|
|
58
59
|
self.actions["file.open"] = QAction(QIcon(":/icons/folder.svg"), trans("tool.html_canvas.menu.file.open"))
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
# dialog.py
|
|
2
|
-
|
|
3
|
-
# dialog.py
|
|
4
|
-
|
|
5
1
|
#!/usr/bin/env python3
|
|
6
2
|
# -*- coding: utf-8 -*-
|
|
7
3
|
# ================================================== #
|
|
@@ -10,7 +6,7 @@
|
|
|
10
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
11
7
|
# MIT License #
|
|
12
8
|
# Created By : Marcin Szczygliński #
|
|
13
|
-
# Updated Date: 2026.01.
|
|
9
|
+
# Updated Date: 2026.01.22 17:00:00 #
|
|
14
10
|
# ================================================== #
|
|
15
11
|
|
|
16
12
|
from PySide6.QtCore import Qt, QPoint, QSize, QEvent
|
|
@@ -61,6 +57,7 @@ class DialogSpawner:
|
|
|
61
57
|
source.setVisible(False)
|
|
62
58
|
pixmap = ImageLabel(dialog, self.path)
|
|
63
59
|
pixmap.setSizePolicy(QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored))
|
|
60
|
+
pixmap.setAlignment(Qt.AlignCenter)
|
|
64
61
|
|
|
65
62
|
# scrollable container for pixmap
|
|
66
63
|
scroll = QScrollArea(dialog)
|
|
@@ -212,6 +209,7 @@ class ImageViewerDialog(BaseDialog):
|
|
|
212
209
|
:return: QMenuBar
|
|
213
210
|
"""
|
|
214
211
|
self.menu_bar = QMenuBar(self)
|
|
212
|
+
self.menu_bar.setNativeMenuBar(False)
|
|
215
213
|
self.file_menu = self.menu_bar.addMenu(trans("menu.file"))
|
|
216
214
|
|
|
217
215
|
self.actions["new"] = QAction(self._icon_add, trans("action.new"), self)
|
|
@@ -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:
|
|
9
|
+
# Updated Date: 2026.01.22 17:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt
|
|
@@ -49,6 +49,7 @@ class DialogBuilder:
|
|
|
49
49
|
"""
|
|
50
50
|
# create menu bar
|
|
51
51
|
self.menu_bar = QMenuBar()
|
|
52
|
+
self.menu_bar.setNativeMenuBar(False)
|
|
52
53
|
self.menu["file"] = self.menu_bar.addMenu(trans("menu.file"))
|
|
53
54
|
self.menu["config"] = self.menu_bar.addMenu(trans("menu.config"))
|
|
54
55
|
|
|
@@ -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:
|
|
9
|
+
# Updated Date: 2026.01.22 17:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt
|
|
@@ -34,6 +34,7 @@ class VideoPlayer:
|
|
|
34
34
|
def setup_menu(self) -> QMenuBar:
|
|
35
35
|
"""Setup video dialog menu"""
|
|
36
36
|
self.menu_bar = QMenuBar()
|
|
37
|
+
self.menu_bar.setNativeMenuBar(False)
|
|
37
38
|
self.file_menu = self.menu_bar.addMenu(trans("menu.file"))
|
|
38
39
|
|
|
39
40
|
# open
|
|
@@ -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:
|
|
9
|
+
# Updated Date: 2026.01.22 17:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt
|
|
@@ -51,6 +51,7 @@ class Tool:
|
|
|
51
51
|
"""
|
|
52
52
|
# create menu bar
|
|
53
53
|
self.menu_bar = QMenuBar()
|
|
54
|
+
self.menu_bar.setNativeMenuBar(False)
|
|
54
55
|
self.menu["file"] = self.menu_bar.addMenu(trans("menu.file"))
|
|
55
56
|
self.actions["file.open"] = QAction(QIcon(":/icons/folder.svg"), trans("tool.html_canvas.menu.file.open"))
|
|
56
57
|
self.actions["file.open"].triggered.connect(
|
|
@@ -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:
|
|
9
|
+
# Updated Date: 2026.01.20 20:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt, Slot, QObject, Signal
|
|
@@ -14,6 +14,7 @@ from PySide6.QtGui import QAction, QIcon, QKeySequence, QFontMetrics
|
|
|
14
14
|
from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QTextEdit, QWidget, QSplitter, QPushButton, QLabel
|
|
15
15
|
|
|
16
16
|
from pygpt_net.core.text.finder import Finder
|
|
17
|
+
from pygpt_net.core.types import MODE_CHAT
|
|
17
18
|
from pygpt_net.ui.widget.option.combo import OptionCombo
|
|
18
19
|
|
|
19
20
|
from pygpt_net.ui.widget.textarea.search_input import SearchInput
|
|
@@ -67,6 +68,9 @@ class ToolWidget:
|
|
|
67
68
|
"type": "combo",
|
|
68
69
|
"label": "menu.tools.translator.model",
|
|
69
70
|
"use": "models",
|
|
71
|
+
"use_params": {
|
|
72
|
+
"mode": [MODE_CHAT]
|
|
73
|
+
},
|
|
70
74
|
"value": "gpt-4o-mini",
|
|
71
75
|
}
|
|
72
76
|
self.model_select = OptionCombo(
|
|
@@ -319,7 +323,7 @@ class TextColumn(QWidget):
|
|
|
319
323
|
:param search_text: Text to search in languages
|
|
320
324
|
"""
|
|
321
325
|
key = self.window.core.text.find_lang_id_by_search_string(search_text)
|
|
322
|
-
if key:
|
|
326
|
+
if key and key != "-":
|
|
323
327
|
self.lang_select.set_value(key)
|
|
324
328
|
|
|
325
329
|
def on_clear(self):
|
pygpt_net/ui/dialog/about.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:
|
|
9
|
+
# Updated Date: 2026.01.21 02:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
@@ -20,7 +20,7 @@ from pygpt_net.utils import trans
|
|
|
20
20
|
|
|
21
21
|
class About:
|
|
22
22
|
|
|
23
|
-
RELEASE_YEAR =
|
|
23
|
+
RELEASE_YEAR = 2026
|
|
24
24
|
|
|
25
25
|
def __init__(self, window=None):
|
|
26
26
|
"""
|
pygpt_net/ui/dialog/db.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:
|
|
9
|
+
# Updated Date: 2026.01.22 17:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt, QTimer, QSignalBlocker, QObject, QEvent
|
|
@@ -178,6 +178,7 @@ class Database:
|
|
|
178
178
|
splitter.splitterMoved.connect(self._on_splitter_moved)
|
|
179
179
|
|
|
180
180
|
self.menu_bar = QMenuBar()
|
|
181
|
+
self.menu_bar.setNativeMenuBar(False)
|
|
181
182
|
self.batch_actions_menu = self.menu_bar.addMenu("Actions")
|
|
182
183
|
self.delete_all_action = QAction(QIcon(":/icons/delete.svg"), "Delete all records")
|
|
183
184
|
self.delete_all_action.triggered.connect(self.viewer.delete_all)
|
pygpt_net/ui/dialog/debug.py
CHANGED
|
@@ -6,17 +6,137 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date:
|
|
9
|
+
# Updated Date: 2026.01.21 01:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
|
-
from PySide6.QtCore import Qt
|
|
13
|
-
from PySide6.QtWidgets import
|
|
12
|
+
from PySide6.QtCore import Qt, QEvent, QTimer, QObject
|
|
13
|
+
from PySide6.QtWidgets import QScrollArea, QSplitter, QSplitterHandle, QPushButton, \
|
|
14
|
+
QCheckBox, QHBoxLayout, QAbstractItemView, QLabel, QVBoxLayout
|
|
14
15
|
|
|
15
16
|
from pygpt_net.ui.widget.dialog.debug import DebugDialog
|
|
16
17
|
from pygpt_net.ui.widget.lists.debug import DebugList
|
|
17
18
|
from pygpt_net.ui.widget.textarea.editor import CodeEditor
|
|
18
19
|
|
|
19
20
|
|
|
21
|
+
class SmoothSplitterHandle(QSplitterHandle):
|
|
22
|
+
"""
|
|
23
|
+
Splitter handle that notifies the parent splitter about drag begin/end.
|
|
24
|
+
This allows the splitter to temporarily freeze heavy widgets during drag.
|
|
25
|
+
"""
|
|
26
|
+
def __init__(self, orientation, parent):
|
|
27
|
+
super().__init__(orientation, parent)
|
|
28
|
+
self._drag_active = False
|
|
29
|
+
|
|
30
|
+
def mousePressEvent(self, event):
|
|
31
|
+
if event.button() == Qt.LeftButton:
|
|
32
|
+
self._drag_active = True
|
|
33
|
+
sp = self.splitter()
|
|
34
|
+
if hasattr(sp, "_on_drag_begin"):
|
|
35
|
+
sp._on_drag_begin()
|
|
36
|
+
super().mousePressEvent(event)
|
|
37
|
+
|
|
38
|
+
def mouseReleaseEvent(self, event):
|
|
39
|
+
super().mouseReleaseEvent(event)
|
|
40
|
+
if self._drag_active:
|
|
41
|
+
sp = self.splitter()
|
|
42
|
+
if hasattr(sp, "_on_drag_end"):
|
|
43
|
+
sp._on_drag_end()
|
|
44
|
+
self._drag_active = False
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class SmoothSplitter(QSplitter):
|
|
48
|
+
"""
|
|
49
|
+
Splitter optimized for heavy child widgets:
|
|
50
|
+
- Uses non-opaque resize to avoid continuous relayout during drag.
|
|
51
|
+
- Freezes updates on registered heavy widgets while dragging.
|
|
52
|
+
"""
|
|
53
|
+
def __init__(self, orientation, parent=None):
|
|
54
|
+
super().__init__(orientation, parent)
|
|
55
|
+
self._heavy_widgets = []
|
|
56
|
+
self.setOpaqueResize(False) # rubber-band; resize applied on release
|
|
57
|
+
self.setChildrenCollapsible(False) # keep both panes visible
|
|
58
|
+
|
|
59
|
+
def createHandle(self):
|
|
60
|
+
return SmoothSplitterHandle(self.orientation(), self)
|
|
61
|
+
|
|
62
|
+
def add_heavy_widget(self, w):
|
|
63
|
+
if w and w not in self._heavy_widgets:
|
|
64
|
+
self._heavy_widgets.append(w)
|
|
65
|
+
|
|
66
|
+
def _on_drag_begin(self):
|
|
67
|
+
for w in self._heavy_widgets:
|
|
68
|
+
try:
|
|
69
|
+
w.setUpdatesEnabled(False)
|
|
70
|
+
except Exception:
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
def _on_drag_end(self):
|
|
74
|
+
for w in self._heavy_widgets:
|
|
75
|
+
try:
|
|
76
|
+
w.setUpdatesEnabled(True)
|
|
77
|
+
w.update()
|
|
78
|
+
except Exception:
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ResizeFreezeFilter(QObject):
|
|
83
|
+
"""
|
|
84
|
+
Event filter that throttles expensive repaints during parent widget resize.
|
|
85
|
+
Freezes updates for registered heavy widgets while the resize is in progress,
|
|
86
|
+
and restores them shortly after the last resize event.
|
|
87
|
+
"""
|
|
88
|
+
def __init__(self, heavy_widgets, parent=None, defer_ms=120):
|
|
89
|
+
super().__init__(parent)
|
|
90
|
+
self._heavy_widgets = [w for w in heavy_widgets if w is not None]
|
|
91
|
+
self._defer_ms = defer_ms
|
|
92
|
+
self._timer = QTimer(self)
|
|
93
|
+
self._timer.setSingleShot(True)
|
|
94
|
+
self._timer.timeout.connect(self._unfreeze)
|
|
95
|
+
self._frozen = False
|
|
96
|
+
self._saved_view_update_modes = {}
|
|
97
|
+
|
|
98
|
+
def eventFilter(self, obj, event):
|
|
99
|
+
if event.type() == QEvent.Resize:
|
|
100
|
+
self._freeze()
|
|
101
|
+
self._timer.start(self._defer_ms)
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
def _freeze(self):
|
|
105
|
+
if self._frozen:
|
|
106
|
+
return
|
|
107
|
+
self._frozen = True
|
|
108
|
+
for w in self._heavy_widgets:
|
|
109
|
+
try:
|
|
110
|
+
if isinstance(w, QAbstractItemView):
|
|
111
|
+
self._saved_view_update_modes[w] = w.viewportUpdateMode()
|
|
112
|
+
w.setViewportUpdateMode(QAbstractItemView.NoViewportUpdate)
|
|
113
|
+
except Exception:
|
|
114
|
+
pass
|
|
115
|
+
try:
|
|
116
|
+
w.setUpdatesEnabled(False)
|
|
117
|
+
except Exception:
|
|
118
|
+
pass
|
|
119
|
+
|
|
120
|
+
def _unfreeze(self):
|
|
121
|
+
if not self._frozen:
|
|
122
|
+
return
|
|
123
|
+
self._frozen = False
|
|
124
|
+
for w in self._heavy_widgets:
|
|
125
|
+
try:
|
|
126
|
+
w.setUpdatesEnabled(True)
|
|
127
|
+
except Exception:
|
|
128
|
+
pass
|
|
129
|
+
try:
|
|
130
|
+
if isinstance(w, QAbstractItemView) and w in self._saved_view_update_modes:
|
|
131
|
+
w.setViewportUpdateMode(self._saved_view_update_modes.pop(w))
|
|
132
|
+
except Exception:
|
|
133
|
+
pass
|
|
134
|
+
try:
|
|
135
|
+
w.update()
|
|
136
|
+
except Exception:
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
|
|
20
140
|
class Debug:
|
|
21
141
|
def __init__(self, window=None):
|
|
22
142
|
"""
|
|
@@ -43,15 +163,58 @@ class Debug:
|
|
|
43
163
|
viewer.setReadOnly(True)
|
|
44
164
|
self.window.ui.debug[id].viewer = viewer
|
|
45
165
|
|
|
46
|
-
splitter
|
|
166
|
+
# optimized splitter for heavy widgets
|
|
167
|
+
splitter = SmoothSplitter(Qt.Horizontal)
|
|
47
168
|
splitter.addWidget(scroll)
|
|
48
169
|
splitter.addWidget(viewer)
|
|
49
170
|
splitter.setStretchFactor(0, 3)
|
|
50
171
|
splitter.setStretchFactor(1, 1)
|
|
51
172
|
|
|
52
|
-
|
|
53
|
-
|
|
173
|
+
# register heavy widgets to freeze during drag
|
|
174
|
+
splitter.add_heavy_widget(self.window.ui.debug[id])
|
|
175
|
+
splitter.add_heavy_widget(self.window.ui.debug[id].viewport())
|
|
176
|
+
splitter.add_heavy_widget(viewer)
|
|
177
|
+
|
|
178
|
+
realtime_btn = QCheckBox("Realtime")
|
|
179
|
+
realtime_btn.setChecked(False)
|
|
180
|
+
realtime_btn.toggled.connect(
|
|
181
|
+
lambda checked: self.window.controller.dialogs.debug.set_realtime(id, checked)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
refresh_btn = QPushButton("Refresh")
|
|
185
|
+
refresh_btn.clicked.connect(
|
|
186
|
+
lambda: self.window.controller.dialogs.debug.refresh(id)
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
last_update_label = QLabel("Last update: N/A")
|
|
190
|
+
self.window.ui.debug[id].last_update_label = last_update_label
|
|
191
|
+
|
|
192
|
+
opts_layout = QHBoxLayout()
|
|
193
|
+
opts_layout.addWidget(realtime_btn)
|
|
194
|
+
opts_layout.addStretch(1)
|
|
195
|
+
opts_layout.addWidget(refresh_btn)
|
|
196
|
+
opts_layout.addStretch(1)
|
|
197
|
+
opts_layout.addWidget(last_update_label)
|
|
198
|
+
|
|
199
|
+
layout = QVBoxLayout()
|
|
200
|
+
layout.addWidget(splitter, 1)
|
|
201
|
+
layout.addLayout(opts_layout, 0)
|
|
202
|
+
layout.setContentsMargins(5, 5, 5, 5)
|
|
54
203
|
|
|
55
204
|
self.window.ui.dialog['debug.' + id] = DebugDialog(self.window, id)
|
|
56
205
|
self.window.ui.dialog['debug.' + id].setLayout(layout)
|
|
57
206
|
self.window.ui.dialog['debug.' + id].setWindowTitle("Debug" + ": " + id)
|
|
207
|
+
|
|
208
|
+
# throttle heavy repaints during dialog resize
|
|
209
|
+
heavy_widgets = [
|
|
210
|
+
self.window.ui.debug[id],
|
|
211
|
+
getattr(self.window.ui.debug[id], "viewport", lambda: None)(),
|
|
212
|
+
viewer,
|
|
213
|
+
scroll,
|
|
214
|
+
getattr(scroll, "viewport", lambda: None)(),
|
|
215
|
+
]
|
|
216
|
+
resize_filter = ResizeFreezeFilter(heavy_widgets, parent=self.window.ui.dialog['debug.' + id], defer_ms=120)
|
|
217
|
+
self.window.ui.dialog['debug.' + id].installEventFilter(resize_filter)
|
|
218
|
+
splitter.installEventFilter(resize_filter)
|
|
219
|
+
# keep a strong reference to avoid garbage collection
|
|
220
|
+
self.window.ui.dialog['debug.' + id]._resize_freeze_filter = resize_filter
|
pygpt_net/ui/dialog/logger.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:
|
|
9
|
+
# Updated Date: 2026.01.20 21:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtWidgets import QPushButton, QHBoxLayout, QVBoxLayout
|
|
@@ -34,6 +34,10 @@ class Logger:
|
|
|
34
34
|
|
|
35
35
|
self.window.console = ConsoleInput(self.window)
|
|
36
36
|
|
|
37
|
+
# TAB completion commands
|
|
38
|
+
if hasattr(self.window.core.debug, "console") and hasattr(self.window.core.debug.console, "get_supported_commands"):
|
|
39
|
+
self.window.console.set_commands(self.window.core.debug.console.get_supported_commands())
|
|
40
|
+
|
|
37
41
|
send_btn = QPushButton("Send")
|
|
38
42
|
send_btn.clicked.connect(self.window.core.debug.console.on_send)
|
|
39
43
|
|
|
@@ -58,4 +62,4 @@ class Logger:
|
|
|
58
62
|
self.window.ui.dialog['logger'] = LoggerDialog(self.window)
|
|
59
63
|
self.window.ui.dialog['logger'].setLayout(layout)
|
|
60
64
|
self.window.ui.dialog['logger'].setWindowTitle(trans('dialog.logger.title'))
|
|
61
|
-
self.window.ui.dialog['logger'].resize(800, 500)
|
|
65
|
+
self.window.ui.dialog['logger'].resize(800, 500)
|
pygpt_net/ui/dialog/models.py
CHANGED
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date:
|
|
9
|
+
# Updated Date: 2026.01.22 17:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
13
13
|
from typing import Dict, List, Optional
|
|
14
14
|
|
|
15
15
|
from PySide6.QtCore import Qt
|
|
16
|
-
from PySide6.QtGui import QStandardItemModel, QIcon
|
|
16
|
+
from PySide6.QtGui import QStandardItemModel, QIcon, QAction
|
|
17
17
|
from PySide6.QtWidgets import QPushButton, QHBoxLayout, QLabel, QVBoxLayout, QScrollArea, QWidget, QTabWidget, QFrame, \
|
|
18
|
-
QSplitter, QSizePolicy
|
|
18
|
+
QSplitter, QSizePolicy, QMenuBar
|
|
19
19
|
|
|
20
20
|
from pygpt_net.ui.widget.dialog.model import ModelDialog
|
|
21
21
|
from pygpt_net.ui.widget.element.group import CollapsedGroup
|
|
@@ -41,6 +41,11 @@ class Models:
|
|
|
41
41
|
"""
|
|
42
42
|
self.window = window
|
|
43
43
|
self.dialog_id = "models.editor"
|
|
44
|
+
self.menu_bar = None
|
|
45
|
+
|
|
46
|
+
# Keep menu objects alive and correctly parented
|
|
47
|
+
self._file_menu = None
|
|
48
|
+
self._menu_actions: Dict[str, QAction] = {}
|
|
44
49
|
|
|
45
50
|
# Internal state for filtering/mapping
|
|
46
51
|
self._filter_text: str = ""
|
|
@@ -204,6 +209,34 @@ class Models:
|
|
|
204
209
|
|
|
205
210
|
self.window.ui.dialog[self.dialog_id] = ModelDialog(self.window, self.dialog_id)
|
|
206
211
|
self.window.ui.dialog[self.dialog_id].setLayout(layout)
|
|
212
|
+
|
|
213
|
+
self.menu_bar = QMenuBar(self.window.ui.dialog[self.dialog_id])
|
|
214
|
+
self.menu_bar.setNativeMenuBar(False)
|
|
215
|
+
self._file_menu = self.menu_bar.addMenu(trans("menu.file"))
|
|
216
|
+
|
|
217
|
+
# open importer
|
|
218
|
+
self._menu_actions["import"] = QAction(
|
|
219
|
+
QIcon(":/icons/download.svg"),
|
|
220
|
+
trans("action.import"),
|
|
221
|
+
self.window.ui.dialog[self.dialog_id],
|
|
222
|
+
)
|
|
223
|
+
self._menu_actions["import"].triggered.connect(
|
|
224
|
+
lambda checked=False: self.window.controller.model.importer.open()
|
|
225
|
+
)
|
|
226
|
+
self._menu_actions["close"] = QAction(
|
|
227
|
+
QIcon(":/icons/logout.svg"),
|
|
228
|
+
trans("menu.file.exit"),
|
|
229
|
+
self.window.ui.dialog[self.dialog_id],
|
|
230
|
+
)
|
|
231
|
+
self._menu_actions["close"].triggered.connect(
|
|
232
|
+
lambda checked=False: self.window.ui.dialog[self.dialog_id].close()
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# add actions
|
|
236
|
+
self._file_menu.addAction(self._menu_actions["import"])
|
|
237
|
+
self._file_menu.addAction(self._menu_actions["close"])
|
|
238
|
+
layout.setMenuBar(self.menu_bar)
|
|
239
|
+
|
|
207
240
|
self.window.ui.dialog[self.dialog_id].setWindowTitle(trans('dialog.models.editor'))
|
|
208
241
|
|
|
209
242
|
# restore current opened tab if idx is set
|
pygpt_net/ui/dialog/preset.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:
|
|
9
|
+
# Updated Date: 2026.01.21 01:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt
|
|
@@ -252,6 +252,7 @@ class Preset(BaseConfigDialog):
|
|
|
252
252
|
|
|
253
253
|
# warning label
|
|
254
254
|
warn_label = HelpLabel(trans("preset.personalize.warning"))
|
|
255
|
+
self.window.ui.nodes['preset.editor.warn_label'] = warn_label
|
|
255
256
|
|
|
256
257
|
# avatar
|
|
257
258
|
self.window.ui.nodes['preset.editor.avatar'] = AvatarWidget(self.window)
|
|
@@ -442,6 +443,9 @@ class AvatarWidget(QWidget):
|
|
|
442
443
|
main_layout.setContentsMargins(0, 10, 0, 0)
|
|
443
444
|
main_layout.addStretch()
|
|
444
445
|
|
|
446
|
+
self.window.ui.nodes['preset.editor.personalize.avatar.choose'] = self.choose_button
|
|
447
|
+
self.window.ui.nodes['preset.editor.personalize.avatar.remove'] = self.remove_button
|
|
448
|
+
|
|
445
449
|
def open_file_dialog(self):
|
|
446
450
|
"""Open a file dialog to select an avatar image file."""
|
|
447
451
|
file_name, _ = QFileDialog.getOpenFileName(
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
8
8
|
# MIT License #
|
|
9
9
|
# Created By : Marcin Szczygliński #
|
|
10
|
-
# Updated Date: 2026.01.
|
|
10
|
+
# Updated Date: 2026.01.22 17:00:00 #
|
|
11
11
|
# ================================================== #
|
|
12
12
|
|
|
13
13
|
import copy
|
|
@@ -238,6 +238,7 @@ class RemoteStore:
|
|
|
238
238
|
controller = self.window.controller
|
|
239
239
|
self.actions = {}
|
|
240
240
|
self.menu_bar = QMenuBar()
|
|
241
|
+
self.menu_bar.setNativeMenuBar(False)
|
|
241
242
|
|
|
242
243
|
self.menu = {}
|
|
243
244
|
self.menu["current"] = self.menu_bar.addMenu(trans("dialog.remote_store.menu.current"))
|
pygpt_net/ui/main.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:
|
|
9
|
+
# Updated Date: 2026.01.20 20:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
@@ -376,7 +376,8 @@ class MainWindow(QMainWindow, QtStyleTools):
|
|
|
376
376
|
self.core.presets.save_all()
|
|
377
377
|
print("Exiting...")
|
|
378
378
|
print("")
|
|
379
|
-
print(f"{trans('exit.msg')} https://pygpt.net/#donate")
|
|
379
|
+
print(f"⭐☕ {trans('exit.msg')} https://pygpt.net/#donate ☕⭐")
|
|
380
|
+
print("")
|
|
380
381
|
|
|
381
382
|
def changeEvent(self, event):
|
|
382
383
|
"""
|
|
@@ -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:
|
|
9
|
+
# Updated Date: 2026.01.22 17:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import datetime
|
|
@@ -72,6 +72,7 @@ class EditorFileDialog(BaseDialog):
|
|
|
72
72
|
:return: menu bar
|
|
73
73
|
"""
|
|
74
74
|
self.menu_bar = QMenuBar(self)
|
|
75
|
+
self.menu_bar.setNativeMenuBar(False)
|
|
75
76
|
self.file_menu = self.menu_bar.addMenu(trans("menu.file"))
|
|
76
77
|
self.actions = {}
|
|
77
78
|
|
|
@@ -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:
|
|
9
|
+
# Updated Date: 2026.01.21 01:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import json
|
|
@@ -48,17 +48,22 @@ class DebugList(QTableView):
|
|
|
48
48
|
On data update begin
|
|
49
49
|
"""
|
|
50
50
|
self.adjustColumns()
|
|
51
|
+
self.setUpdatesEnabled(False)
|
|
51
52
|
|
|
52
53
|
def on_data_end(self):
|
|
53
54
|
"""
|
|
54
55
|
On data update end
|
|
55
56
|
"""
|
|
56
57
|
# update data viewer
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
self.
|
|
61
|
-
|
|
58
|
+
try:
|
|
59
|
+
if self.viewer_index:
|
|
60
|
+
new = self.model().data(self.viewer_index)
|
|
61
|
+
if self.viewer_current != new:
|
|
62
|
+
self.viewer.setPlainText(self.parse_view(new))
|
|
63
|
+
self.viewer_current = new
|
|
64
|
+
self.setUpdatesEnabled(True)
|
|
65
|
+
except Exception:
|
|
66
|
+
pass
|
|
62
67
|
|
|
63
68
|
def parse_view(self, data):
|
|
64
69
|
"""
|
|
@@ -116,4 +121,4 @@ class DebugList(QTableView):
|
|
|
116
121
|
data = self.model().data(index)
|
|
117
122
|
self.viewer.setPlainText(str(self.parse_view(data)))
|
|
118
123
|
self.viewer_index = index
|
|
119
|
-
self.viewer_current = data
|
|
124
|
+
self.viewer_current = data
|