pygpt-net 2.7.8__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.
Files changed (112) hide show
  1. pygpt_net/CHANGELOG.txt +14 -0
  2. pygpt_net/LICENSE +1 -1
  3. pygpt_net/__init__.py +3 -3
  4. pygpt_net/config.py +15 -1
  5. pygpt_net/controller/chat/common.py +5 -4
  6. pygpt_net/controller/chat/image.py +3 -3
  7. pygpt_net/controller/chat/stream.py +76 -41
  8. pygpt_net/controller/chat/stream_worker.py +3 -3
  9. pygpt_net/controller/ctx/extra.py +3 -1
  10. pygpt_net/controller/dialogs/debug.py +37 -8
  11. pygpt_net/controller/kernel/kernel.py +3 -7
  12. pygpt_net/controller/lang/custom.py +25 -12
  13. pygpt_net/controller/lang/lang.py +45 -3
  14. pygpt_net/controller/lang/mapping.py +15 -2
  15. pygpt_net/controller/notepad/notepad.py +68 -25
  16. pygpt_net/controller/presets/editor.py +5 -1
  17. pygpt_net/controller/presets/presets.py +17 -5
  18. pygpt_net/controller/realtime/realtime.py +13 -1
  19. pygpt_net/controller/theme/theme.py +11 -2
  20. pygpt_net/controller/ui/tabs.py +1 -1
  21. pygpt_net/core/ctx/output.py +38 -12
  22. pygpt_net/core/db/database.py +4 -2
  23. pygpt_net/core/debug/console/console.py +30 -2
  24. pygpt_net/core/debug/context.py +2 -1
  25. pygpt_net/core/debug/ui.py +26 -4
  26. pygpt_net/core/filesystem/filesystem.py +6 -2
  27. pygpt_net/core/notepad/notepad.py +2 -2
  28. pygpt_net/core/tabs/tabs.py +79 -19
  29. pygpt_net/data/config/config.json +4 -3
  30. pygpt_net/data/config/models.json +37 -22
  31. pygpt_net/data/config/settings.json +12 -0
  32. pygpt_net/data/locale/locale.ar.ini +1833 -0
  33. pygpt_net/data/locale/locale.bg.ini +1833 -0
  34. pygpt_net/data/locale/locale.cs.ini +1833 -0
  35. pygpt_net/data/locale/locale.da.ini +1833 -0
  36. pygpt_net/data/locale/locale.de.ini +4 -1
  37. pygpt_net/data/locale/locale.en.ini +70 -67
  38. pygpt_net/data/locale/locale.es.ini +4 -1
  39. pygpt_net/data/locale/locale.fi.ini +1833 -0
  40. pygpt_net/data/locale/locale.fr.ini +4 -1
  41. pygpt_net/data/locale/locale.he.ini +1833 -0
  42. pygpt_net/data/locale/locale.hi.ini +1833 -0
  43. pygpt_net/data/locale/locale.hu.ini +1833 -0
  44. pygpt_net/data/locale/locale.it.ini +4 -1
  45. pygpt_net/data/locale/locale.ja.ini +1833 -0
  46. pygpt_net/data/locale/locale.ko.ini +1833 -0
  47. pygpt_net/data/locale/locale.nl.ini +1833 -0
  48. pygpt_net/data/locale/locale.no.ini +1833 -0
  49. pygpt_net/data/locale/locale.pl.ini +5 -2
  50. pygpt_net/data/locale/locale.pt.ini +1833 -0
  51. pygpt_net/data/locale/locale.ro.ini +1833 -0
  52. pygpt_net/data/locale/locale.ru.ini +1833 -0
  53. pygpt_net/data/locale/locale.sk.ini +1833 -0
  54. pygpt_net/data/locale/locale.sv.ini +1833 -0
  55. pygpt_net/data/locale/locale.tr.ini +1833 -0
  56. pygpt_net/data/locale/locale.uk.ini +4 -1
  57. pygpt_net/data/locale/locale.zh.ini +4 -1
  58. pygpt_net/item/notepad.py +8 -2
  59. pygpt_net/migrations/Version20260121190000.py +25 -0
  60. pygpt_net/migrations/Version20260122140000.py +25 -0
  61. pygpt_net/migrations/__init__.py +5 -1
  62. pygpt_net/preload.py +246 -3
  63. pygpt_net/provider/api/__init__.py +16 -2
  64. pygpt_net/provider/api/anthropic/__init__.py +21 -7
  65. pygpt_net/provider/api/google/__init__.py +21 -7
  66. pygpt_net/provider/api/google/image.py +89 -2
  67. pygpt_net/provider/api/google/realtime/client.py +70 -24
  68. pygpt_net/provider/api/google/realtime/realtime.py +48 -12
  69. pygpt_net/provider/api/google/video.py +2 -2
  70. pygpt_net/provider/api/openai/__init__.py +26 -11
  71. pygpt_net/provider/api/openai/image.py +79 -3
  72. pygpt_net/provider/api/openai/realtime/realtime.py +26 -6
  73. pygpt_net/provider/api/openai/responses.py +11 -31
  74. pygpt_net/provider/api/openai/video.py +2 -2
  75. pygpt_net/provider/api/x_ai/__init__.py +21 -10
  76. pygpt_net/provider/api/x_ai/realtime/client.py +185 -146
  77. pygpt_net/provider/api/x_ai/realtime/realtime.py +30 -15
  78. pygpt_net/provider/api/x_ai/remote_tools.py +83 -0
  79. pygpt_net/provider/api/x_ai/tools.py +51 -0
  80. pygpt_net/provider/core/config/patch.py +12 -1
  81. pygpt_net/provider/core/model/patch.py +36 -1
  82. pygpt_net/provider/core/notepad/db_sqlite/storage.py +53 -10
  83. pygpt_net/tools/agent_builder/ui/dialogs.py +2 -1
  84. pygpt_net/tools/audio_transcriber/ui/dialogs.py +2 -1
  85. pygpt_net/tools/code_interpreter/ui/dialogs.py +2 -1
  86. pygpt_net/tools/html_canvas/ui/dialogs.py +2 -1
  87. pygpt_net/tools/image_viewer/ui/dialogs.py +3 -5
  88. pygpt_net/tools/indexer/ui/dialogs.py +2 -1
  89. pygpt_net/tools/media_player/ui/dialogs.py +2 -1
  90. pygpt_net/tools/translator/ui/dialogs.py +2 -1
  91. pygpt_net/tools/translator/ui/widgets.py +6 -2
  92. pygpt_net/ui/dialog/about.py +2 -2
  93. pygpt_net/ui/dialog/db.py +2 -1
  94. pygpt_net/ui/dialog/debug.py +169 -6
  95. pygpt_net/ui/dialog/logger.py +6 -2
  96. pygpt_net/ui/dialog/models.py +36 -3
  97. pygpt_net/ui/dialog/preset.py +5 -1
  98. pygpt_net/ui/dialog/remote_store.py +2 -1
  99. pygpt_net/ui/main.py +3 -2
  100. pygpt_net/ui/widget/dialog/editor_file.py +2 -1
  101. pygpt_net/ui/widget/lists/debug.py +12 -7
  102. pygpt_net/ui/widget/option/checkbox.py +2 -8
  103. pygpt_net/ui/widget/option/combo.py +10 -2
  104. pygpt_net/ui/widget/textarea/console.py +156 -7
  105. pygpt_net/ui/widget/textarea/highlight.py +66 -0
  106. pygpt_net/ui/widget/textarea/input.py +624 -57
  107. pygpt_net/ui/widget/textarea/notepad.py +294 -27
  108. {pygpt_net-2.7.8.dist-info → pygpt_net-2.7.10.dist-info}/LICENSE +1 -1
  109. {pygpt_net-2.7.8.dist-info → pygpt_net-2.7.10.dist-info}/METADATA +16 -64
  110. {pygpt_net-2.7.8.dist-info → pygpt_net-2.7.10.dist-info}/RECORD +112 -91
  111. {pygpt_net-2.7.8.dist-info → pygpt_net-2.7.10.dist-info}/WHEEL +0 -0
  112. {pygpt_net-2.7.8.dist-info → pygpt_net-2.7.10.dist-info}/entry_points.txt +0 -0
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: 2025.09.26 03:00:00 #
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)
@@ -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: 2024.03.18 03:00:00 #
9
+ # Updated Date: 2026.01.21 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
- from PySide6.QtCore import Qt
13
- from PySide6.QtWidgets import QGridLayout, QScrollArea, QSplitter, QPlainTextEdit
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 = QSplitter(Qt.Horizontal)
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
- layout = QGridLayout()
53
- layout.addWidget(splitter, 1, 0)
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
@@ -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.09.05 18:00:00 #
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)
@@ -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: 2025.12.26 13:00:00 #
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
@@ -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.09.28 08:00:00 #
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.06 18:00:00 #
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: 2025.12.31 14:00:00 #
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: 2025.08.24 23:00:00 #
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: 2024.03.06 02:00:00 #
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
- if self.viewer_index:
58
- new = self.model().data(self.viewer_index)
59
- if self.viewer_current != new:
60
- self.viewer.setPlainText(self.parse_view(new))
61
- self.viewer_current = new
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
@@ -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.24 23:00:00 #
9
+ # Updated Date: 2026.01.21 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QIcon
@@ -54,7 +54,6 @@ class OptionCheckbox(QWidget):
54
54
  if "real_time" in self.option:
55
55
  self.real_time = self.option["real_time"]
56
56
 
57
- # self.box = QCheckBox(self.title, self.window)
58
57
  self.box = AnimToggle('', self.window)
59
58
  if self.value is not None:
60
59
  self.box.setChecked(self.value)
@@ -77,17 +76,11 @@ class OptionCheckbox(QWidget):
77
76
  ico.setPixmap(pixmap)
78
77
  self.layout.addWidget(ico)
79
78
 
80
-
81
79
  self.layout.addWidget(self.label)
82
80
  self.layout.addStretch()
83
81
  self.layout.setContentsMargins(0, 0, 0, 0)
84
82
  self.setLayout(self.layout)
85
83
 
86
- # self.layout = QHBoxLayout()
87
- #self.layout.addWidget(self.box)
88
-
89
- #self.setLayout(self.layout)
90
-
91
84
  def trans_or_not(self, label: str):
92
85
  """
93
86
  Translate label or return it as is if translation is not available
@@ -116,6 +109,7 @@ class OptionCheckbox(QWidget):
116
109
 
117
110
  :param text: text
118
111
  """
112
+ self.title = text
119
113
  self.label.setText(text)
120
114
 
121
115
  def setChecked(self, state: bool):
@@ -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: 2026.01.01 15:00:00 #
9
+ # Updated Date: 2026.01.21 01:00:00 #
10
10
  # ================================================== #
11
11
  import sys
12
12
 
@@ -1649,4 +1649,12 @@ class OptionCombo(QWidget):
1649
1649
 
1650
1650
  def fit_to_content(self):
1651
1651
  """Fit to content"""
1652
- self.combo.setSizeAdjustPolicy(QComboBox.AdjustToContents)
1652
+ self.combo.setSizeAdjustPolicy(QComboBox.AdjustToContents)
1653
+
1654
+ def setText(self, title: str):
1655
+ """
1656
+ Set label text
1657
+
1658
+ :param text: text
1659
+ """
1660
+ self.title = title