pygpt-net 2.6.37__py3-none-any.whl → 2.6.38__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 +7 -0
- pygpt_net/__init__.py +1 -1
- pygpt_net/controller/chat/handler/anthropic_stream.py +0 -2
- pygpt_net/controller/chat/handler/worker.py +6 -2
- pygpt_net/controller/debug/debug.py +6 -6
- pygpt_net/controller/model/importer.py +9 -2
- pygpt_net/controller/plugins/plugins.py +11 -3
- pygpt_net/controller/presets/presets.py +2 -2
- pygpt_net/core/ctx/bag.py +7 -2
- pygpt_net/core/ctx/reply.py +17 -2
- pygpt_net/core/db/viewer.py +19 -34
- pygpt_net/core/render/plain/pid.py +12 -1
- pygpt_net/core/render/web/body.py +1 -5
- pygpt_net/core/tabs/tab.py +24 -1
- pygpt_net/data/config/config.json +2 -2
- pygpt_net/data/config/models.json +2 -2
- pygpt_net/item/assistant.py +51 -2
- pygpt_net/item/attachment.py +21 -20
- pygpt_net/item/calendar_note.py +19 -2
- pygpt_net/item/ctx.py +115 -2
- pygpt_net/item/index.py +9 -2
- pygpt_net/item/mode.py +9 -6
- pygpt_net/item/model.py +20 -3
- pygpt_net/item/notepad.py +14 -2
- pygpt_net/item/preset.py +42 -2
- pygpt_net/item/prompt.py +8 -2
- pygpt_net/plugin/cmd_files/plugin.py +2 -2
- pygpt_net/provider/api/anthropic/tools.py +1 -1
- pygpt_net/provider/api/google/realtime/client.py +2 -2
- pygpt_net/provider/core/attachment/json_file.py +2 -2
- pygpt_net/tools/text_editor/tool.py +4 -1
- pygpt_net/tools/text_editor/ui/dialogs.py +1 -1
- pygpt_net/ui/dialog/db.py +177 -59
- pygpt_net/ui/dialog/dictionary.py +57 -59
- pygpt_net/ui/dialog/editor.py +3 -2
- pygpt_net/ui/dialog/image.py +1 -1
- pygpt_net/ui/dialog/logger.py +3 -2
- pygpt_net/ui/dialog/models.py +14 -12
- pygpt_net/ui/dialog/plugins.py +26 -20
- pygpt_net/ui/layout/ctx/ctx_list.py +3 -4
- pygpt_net/ui/layout/toolbox/__init__.py +2 -2
- pygpt_net/ui/layout/toolbox/assistants.py +8 -9
- pygpt_net/ui/layout/toolbox/presets.py +2 -2
- pygpt_net/ui/main.py +9 -4
- pygpt_net/ui/widget/element/labels.py +2 -2
- pygpt_net/ui/widget/textarea/editor.py +0 -4
- {pygpt_net-2.6.37.dist-info → pygpt_net-2.6.38.dist-info}/METADATA +9 -2
- {pygpt_net-2.6.37.dist-info → pygpt_net-2.6.38.dist-info}/RECORD +51 -51
- {pygpt_net-2.6.37.dist-info → pygpt_net-2.6.38.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.37.dist-info → pygpt_net-2.6.38.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.37.dist-info → pygpt_net-2.6.38.dist-info}/entry_points.txt +0 -0
pygpt_net/ui/dialog/db.py
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
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.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
|
-
from PySide6.QtCore import Qt
|
|
13
|
-
from PySide6.QtGui import QAction, QIcon
|
|
12
|
+
from PySide6.QtCore import Qt, QTimer, QSignalBlocker
|
|
13
|
+
from PySide6.QtGui import QAction, QIcon, QIntValidator
|
|
14
14
|
from PySide6.QtWidgets import QGridLayout, QScrollArea, QSplitter, QComboBox, QLineEdit, QPushButton, \
|
|
15
|
-
QHBoxLayout, QVBoxLayout, QLabel, QWidget, QSizePolicy, QCheckBox, QMenuBar
|
|
15
|
+
QHBoxLayout, QVBoxLayout, QLabel, QWidget, QSizePolicy, QCheckBox, QMenuBar, QAbstractItemView, QHeaderView, QStyledItemDelegate
|
|
16
16
|
|
|
17
17
|
from pygpt_net.ui.widget.dialog.db import DatabaseDialog
|
|
18
18
|
from pygpt_net.ui.widget.lists.db import DatabaseList, DatabaseTableModel
|
|
@@ -20,6 +20,18 @@ from pygpt_net.ui.widget.textarea.editor import CodeEditor
|
|
|
20
20
|
from pygpt_net.utils import trans
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
class _FastTextDelegate(QStyledItemDelegate):
|
|
24
|
+
def __init__(self, max_chars=1200, parent=None):
|
|
25
|
+
super().__init__(parent)
|
|
26
|
+
self.max_chars = max_chars
|
|
27
|
+
|
|
28
|
+
def displayText(self, value, locale):
|
|
29
|
+
s = "" if value is None else str(value)
|
|
30
|
+
if len(s) > self.max_chars:
|
|
31
|
+
return s[:self.max_chars] + "…"
|
|
32
|
+
return s
|
|
33
|
+
|
|
34
|
+
|
|
23
35
|
class Database:
|
|
24
36
|
def __init__(self, window=None):
|
|
25
37
|
"""
|
|
@@ -29,6 +41,8 @@ class Database:
|
|
|
29
41
|
"""
|
|
30
42
|
self.window = window
|
|
31
43
|
self.viewer = None
|
|
44
|
+
self._splitter_timer = None
|
|
45
|
+
self._text_viewer = None
|
|
32
46
|
|
|
33
47
|
def setup(self, id: str = "db"):
|
|
34
48
|
"""
|
|
@@ -45,6 +59,7 @@ class Database:
|
|
|
45
59
|
# data viewer
|
|
46
60
|
text_viewer = CodeEditor(self.window)
|
|
47
61
|
text_viewer.setReadOnly(False)
|
|
62
|
+
self._text_viewer = text_viewer
|
|
48
63
|
|
|
49
64
|
self.window.ui.debug[id].browser = self.viewer
|
|
50
65
|
self.window.ui.debug[id].viewer = text_viewer
|
|
@@ -63,6 +78,12 @@ class Database:
|
|
|
63
78
|
splitter.addWidget(editor_widget) # Value viewer
|
|
64
79
|
splitter.setStretchFactor(0, 3)
|
|
65
80
|
splitter.setStretchFactor(1, 1)
|
|
81
|
+
splitter.setOpaqueResize(False)
|
|
82
|
+
|
|
83
|
+
self._splitter_timer = QTimer(self.window)
|
|
84
|
+
self._splitter_timer.setSingleShot(True)
|
|
85
|
+
self._splitter_timer.timeout.connect(self._finish_splitter_move)
|
|
86
|
+
splitter.splitterMoved.connect(self._on_splitter_moved)
|
|
66
87
|
|
|
67
88
|
self.menu_bar = QMenuBar()
|
|
68
89
|
self.batch_actions_menu = self.menu_bar.addMenu("Actions")
|
|
@@ -81,6 +102,18 @@ class Database:
|
|
|
81
102
|
self.window.ui.dialog['debug.db'].setLayout(layout)
|
|
82
103
|
self.window.ui.dialog['debug.db'].setWindowTitle("Debug: Database (SQLite)")
|
|
83
104
|
|
|
105
|
+
def _on_splitter_moved(self, pos, index):
|
|
106
|
+
if self._text_viewer is not None:
|
|
107
|
+
self._text_viewer.setUpdatesEnabled(False)
|
|
108
|
+
self._splitter_timer.start(120)
|
|
109
|
+
|
|
110
|
+
def _finish_splitter_move(self):
|
|
111
|
+
if self._text_viewer is not None:
|
|
112
|
+
self._text_viewer.setUpdatesEnabled(True)
|
|
113
|
+
if hasattr(self._text_viewer, 'viewport'):
|
|
114
|
+
self._text_viewer.viewport().update()
|
|
115
|
+
|
|
116
|
+
|
|
84
117
|
class DataBrowser(QWidget):
|
|
85
118
|
def __init__(self, window=None):
|
|
86
119
|
super().__init__()
|
|
@@ -111,7 +144,7 @@ class DataBrowser(QWidget):
|
|
|
111
144
|
|
|
112
145
|
# buttons
|
|
113
146
|
self.refresh_button = QPushButton(trans("db.refresh"))
|
|
114
|
-
self.refresh_button.clicked.connect(self.
|
|
147
|
+
self.refresh_button.clicked.connect(self.force_refresh)
|
|
115
148
|
self.prev_button = QPushButton(trans("db.prev"))
|
|
116
149
|
self.next_button = QPushButton(trans("db.next"))
|
|
117
150
|
self.limit_input = QLineEdit("100")
|
|
@@ -126,7 +159,7 @@ class DataBrowser(QWidget):
|
|
|
126
159
|
self.page_input_label = QLabel(trans("db.page") + ":")
|
|
127
160
|
self.page_input_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
|
128
161
|
self.page_input.editingFinished.connect(self.on_page_input_change)
|
|
129
|
-
self.page_info_label = QLabel(" / 1")
|
|
162
|
+
self.page_info_label = QLabel(" / 1")
|
|
130
163
|
self.page_info_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
|
131
164
|
|
|
132
165
|
# checkboxes
|
|
@@ -155,18 +188,30 @@ class DataBrowser(QWidget):
|
|
|
155
188
|
self.table_select.addItems(self.get_table_names())
|
|
156
189
|
self.sort_order_select.addItems(['ASC', 'DESC'])
|
|
157
190
|
|
|
191
|
+
self._search_timer = QTimer(self)
|
|
192
|
+
self._search_timer.setSingleShot(True)
|
|
193
|
+
self._search_timer.timeout.connect(self.update_table_view)
|
|
194
|
+
self._last_fetch_sig = None
|
|
195
|
+
self._last_count_sig = None
|
|
196
|
+
self._cached_total_rows = 0
|
|
197
|
+
self._last_columns_sig = None
|
|
198
|
+
|
|
199
|
+
v = QIntValidator(1, 1000000000, self)
|
|
200
|
+
self.limit_input.setValidator(v)
|
|
201
|
+
self.page_input.setValidator(v)
|
|
202
|
+
|
|
158
203
|
# signals
|
|
159
204
|
self.table_select.currentIndexChanged.connect(self.on_table_select_changed)
|
|
160
205
|
self.sort_by_select.currentIndexChanged.connect(self.update_table_view)
|
|
161
206
|
self.sort_order_select.currentIndexChanged.connect(self.update_table_view)
|
|
162
|
-
self.search_input.textChanged.connect(self.
|
|
207
|
+
self.search_input.textChanged.connect(self.on_search_text_changed)
|
|
163
208
|
self.search_column_select.currentIndexChanged.connect(self.update_table_view)
|
|
164
209
|
|
|
165
210
|
self.prev_button.clicked.connect(self.prev_page)
|
|
166
211
|
self.next_button.clicked.connect(self.next_page)
|
|
167
212
|
|
|
168
213
|
self.table_select.setCurrentText(self.get_default_table())
|
|
169
|
-
self.on_table_select_changed()
|
|
214
|
+
self.on_table_select_changed()
|
|
170
215
|
|
|
171
216
|
# setup layouts
|
|
172
217
|
if not self.is_inline():
|
|
@@ -221,6 +266,27 @@ class DataBrowser(QWidget):
|
|
|
221
266
|
|
|
222
267
|
self.setLayout(main_layout)
|
|
223
268
|
|
|
269
|
+
view = self.get_list_widget()
|
|
270
|
+
if hasattr(view, "setUniformRowHeights"):
|
|
271
|
+
view.setUniformRowHeights(True)
|
|
272
|
+
if hasattr(view, "setWordWrap"):
|
|
273
|
+
view.setWordWrap(False)
|
|
274
|
+
if hasattr(view, "setTextElideMode"):
|
|
275
|
+
view.setTextElideMode(Qt.ElideRight)
|
|
276
|
+
if hasattr(view, "setVerticalScrollMode"):
|
|
277
|
+
view.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
|
|
278
|
+
if hasattr(view, "setHorizontalScrollMode"):
|
|
279
|
+
view.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
|
|
280
|
+
if hasattr(view, "setViewportUpdateMode"):
|
|
281
|
+
view.setViewportUpdateMode(QAbstractItemView.MinimalViewportUpdate)
|
|
282
|
+
if hasattr(view, "horizontalHeader"):
|
|
283
|
+
hh = view.horizontalHeader()
|
|
284
|
+
if hh is not None:
|
|
285
|
+
hh.setSectionResizeMode(QHeaderView.Interactive)
|
|
286
|
+
self._fast_delegate = _FastTextDelegate(parent=view)
|
|
287
|
+
if hasattr(view, "setItemDelegate"):
|
|
288
|
+
view.setItemDelegate(self._fast_delegate)
|
|
289
|
+
|
|
224
290
|
def is_inline(self) -> bool:
|
|
225
291
|
return False
|
|
226
292
|
|
|
@@ -339,6 +405,8 @@ class DataBrowser(QWidget):
|
|
|
339
405
|
self.limit_input.setText(str(current_limit))
|
|
340
406
|
return
|
|
341
407
|
self.current_offset = 0
|
|
408
|
+
self._last_fetch_sig = None
|
|
409
|
+
self._last_count_sig = None
|
|
342
410
|
self.update_table_view()
|
|
343
411
|
|
|
344
412
|
def get_page_size(self) -> int:
|
|
@@ -358,27 +426,18 @@ class DataBrowser(QWidget):
|
|
|
358
426
|
|
|
359
427
|
:param update: Update table view
|
|
360
428
|
"""
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
current_table = self.get_table_name(self.table_select.currentText())
|
|
368
|
-
total_rows = self.get_viewer().count_rows(
|
|
369
|
-
current_table,
|
|
370
|
-
search_query=search_query,
|
|
371
|
-
search_column=search_column,
|
|
372
|
-
filters=self.get_filters(),
|
|
373
|
-
)
|
|
429
|
+
try:
|
|
430
|
+
page = int(self.page_input.text()) - 1
|
|
431
|
+
except ValueError:
|
|
432
|
+
page = 0
|
|
433
|
+
limit = self.get_page_size()
|
|
434
|
+
total_rows = self._get_total_rows()
|
|
374
435
|
|
|
375
|
-
# check if page is in range
|
|
376
436
|
if page * limit < total_rows and page >= 0:
|
|
377
437
|
if update:
|
|
378
438
|
self.current_offset = page * limit
|
|
379
439
|
self.update_table_view()
|
|
380
440
|
else:
|
|
381
|
-
# reset page
|
|
382
441
|
current_page = self.current_offset // limit + 1
|
|
383
442
|
self.page_input.setText(str(current_page))
|
|
384
443
|
|
|
@@ -395,38 +454,33 @@ class DataBrowser(QWidget):
|
|
|
395
454
|
"""Table select change event"""
|
|
396
455
|
tables = self.get_tables()
|
|
397
456
|
current_table = self.get_table_name(self.table_select.currentText())
|
|
398
|
-
self.sort_by_select.
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
457
|
+
with QSignalBlocker(self.sort_by_select), QSignalBlocker(self.sort_order_select):
|
|
458
|
+
self.sort_by_select.clear()
|
|
459
|
+
if current_table in tables:
|
|
460
|
+
self.sort_by_select.addItems(tables[current_table]['sort_by'])
|
|
461
|
+
self.sort_by_select.setCurrentText(tables[current_table]['default_sort'])
|
|
462
|
+
self.sort_order_select.setCurrentText(tables[current_table]['default_order'])
|
|
463
|
+
self.page_input.setText("1")
|
|
464
|
+
self.current_offset = 0
|
|
465
|
+
self.update_search_columns()
|
|
466
|
+
self._last_fetch_sig = None
|
|
467
|
+
self._last_count_sig = None
|
|
468
|
+
self._last_columns_sig = None
|
|
469
|
+
self.update_table_view()
|
|
407
470
|
|
|
408
471
|
def update_search_columns(self):
|
|
409
472
|
"""Update search columns"""
|
|
410
473
|
tables = self.get_tables()
|
|
411
474
|
current_table = self.get_table_name(self.table_select.currentText())
|
|
412
|
-
self.search_column_select
|
|
413
|
-
|
|
414
|
-
|
|
475
|
+
with QSignalBlocker(self.search_column_select):
|
|
476
|
+
self.search_column_select.clear()
|
|
477
|
+
self.search_column_select.addItem("*", None)
|
|
478
|
+
self.search_column_select.addItems(tables[current_table]['columns'])
|
|
415
479
|
|
|
416
480
|
def update_pagination_info(self):
|
|
417
481
|
"""Update pagination info"""
|
|
418
|
-
limit =
|
|
419
|
-
|
|
420
|
-
search_column = self.search_column_select.currentText()
|
|
421
|
-
if search_column == "*":
|
|
422
|
-
search_column = None
|
|
423
|
-
current_table = self.get_table_name(self.table_select.currentText())
|
|
424
|
-
total_rows = self.get_viewer().count_rows(
|
|
425
|
-
current_table,
|
|
426
|
-
search_query=search_query,
|
|
427
|
-
search_column=search_column,
|
|
428
|
-
filters=self.get_filters(),
|
|
429
|
-
)
|
|
482
|
+
limit = self.get_page_size()
|
|
483
|
+
total_rows = self._get_total_rows()
|
|
430
484
|
total_pages = (total_rows - 1) // limit + 1
|
|
431
485
|
self.page_info_label.setText(f" / {total_pages} ({total_rows} rows)")
|
|
432
486
|
|
|
@@ -435,21 +489,24 @@ class DataBrowser(QWidget):
|
|
|
435
489
|
self.prev_button.setEnabled(self.current_offset > 0)
|
|
436
490
|
self.next_button.setEnabled(self.current_offset + limit < total_rows)
|
|
437
491
|
|
|
438
|
-
def update_table_view(self):
|
|
492
|
+
def update_table_view(self, *args, force: bool = False):
|
|
439
493
|
"""Update table view"""
|
|
440
494
|
tables = self.get_tables()
|
|
441
495
|
current_table = self.get_table_name(self.table_select.currentText())
|
|
442
496
|
sort_by = self.sort_by_select.currentText()
|
|
443
497
|
sort_order = self.sort_order_select.currentText()
|
|
444
498
|
search_query = self.search_input.text()
|
|
445
|
-
search_column = self.search_column_select.
|
|
446
|
-
|
|
447
|
-
search_column = None
|
|
448
|
-
limit = int(self.limit_input.text())
|
|
499
|
+
search_column = self.search_column_select.currentData()
|
|
500
|
+
limit = self.get_page_size()
|
|
449
501
|
|
|
450
502
|
if current_table not in tables or sort_by == '' or sort_order == '' or limit <= 0:
|
|
451
503
|
return
|
|
452
504
|
|
|
505
|
+
sig = self._params_signature_fetch()
|
|
506
|
+
if not force and self._last_fetch_sig == sig:
|
|
507
|
+
self.update_pagination_info()
|
|
508
|
+
return
|
|
509
|
+
|
|
453
510
|
data = self.get_viewer().fetch_data(
|
|
454
511
|
table=current_table,
|
|
455
512
|
columns=tables[current_table]['columns'],
|
|
@@ -462,11 +519,12 @@ class DataBrowser(QWidget):
|
|
|
462
519
|
filters=self.get_filters(),
|
|
463
520
|
)
|
|
464
521
|
self.load_data(data, tables[current_table])
|
|
522
|
+
self._last_fetch_sig = sig
|
|
465
523
|
self.update_pagination_info()
|
|
466
524
|
|
|
467
525
|
def prev_page(self):
|
|
468
526
|
"""Previous page event"""
|
|
469
|
-
limit =
|
|
527
|
+
limit = self.get_page_size()
|
|
470
528
|
if self.current_offset - limit >= 0:
|
|
471
529
|
self.current_offset -= limit
|
|
472
530
|
else:
|
|
@@ -475,10 +533,8 @@ class DataBrowser(QWidget):
|
|
|
475
533
|
|
|
476
534
|
def next_page(self):
|
|
477
535
|
"""Next page event"""
|
|
478
|
-
limit =
|
|
479
|
-
|
|
480
|
-
total_rows = self.get_viewer().count_rows(current_table)
|
|
481
|
-
|
|
536
|
+
limit = self.get_page_size()
|
|
537
|
+
total_rows = self._get_total_rows()
|
|
482
538
|
if self.current_offset + limit < total_rows:
|
|
483
539
|
self.current_offset += limit
|
|
484
540
|
self.update_table_view()
|
|
@@ -498,11 +554,73 @@ class DataBrowser(QWidget):
|
|
|
498
554
|
self.db_path_label.setText(self.window.core.db.db_path)
|
|
499
555
|
if not self.is_inline():
|
|
500
556
|
convert_timestamps = self.convert_timestamps_checkbox.isChecked()
|
|
557
|
+
view = self.get_list_widget()
|
|
558
|
+
if hasattr(view, 'setSortingEnabled'):
|
|
559
|
+
view.setSortingEnabled(False)
|
|
560
|
+
view.setUpdatesEnabled(False)
|
|
501
561
|
model = DatabaseTableModel(
|
|
502
562
|
data,
|
|
503
563
|
table['columns'],
|
|
504
564
|
timestamp_columns=table.get('timestamp_columns', []),
|
|
505
565
|
convert_timestamps=convert_timestamps,
|
|
506
566
|
)
|
|
507
|
-
|
|
508
|
-
|
|
567
|
+
if hasattr(model, 'setParent'):
|
|
568
|
+
model.setParent(view)
|
|
569
|
+
view.setModel(model)
|
|
570
|
+
if self._last_columns_sig != tuple(table['columns']):
|
|
571
|
+
if hasattr(view, 'adjustColumns'):
|
|
572
|
+
view.adjustColumns()
|
|
573
|
+
if hasattr(view, "horizontalHeader"):
|
|
574
|
+
hh = view.horizontalHeader()
|
|
575
|
+
if hh is not None:
|
|
576
|
+
hh.setSectionResizeMode(QHeaderView.Interactive)
|
|
577
|
+
self._last_columns_sig = tuple(table['columns'])
|
|
578
|
+
view.setUpdatesEnabled(True)
|
|
579
|
+
|
|
580
|
+
def on_search_text_changed(self, text):
|
|
581
|
+
self._search_timer.start(200)
|
|
582
|
+
|
|
583
|
+
def _params_signature_base(self):
|
|
584
|
+
table = self.get_table_name(self.table_select.currentText())
|
|
585
|
+
search_query = self.search_input.text()
|
|
586
|
+
search_column = self.search_column_select.currentData()
|
|
587
|
+
filters = self.get_filters()
|
|
588
|
+
if isinstance(filters, dict):
|
|
589
|
+
filters_key = tuple(sorted(filters.items()))
|
|
590
|
+
else:
|
|
591
|
+
filters_key = str(filters)
|
|
592
|
+
return table, search_query, search_column, filters_key
|
|
593
|
+
|
|
594
|
+
def _params_signature_fetch(self):
|
|
595
|
+
table, search_query, search_column, filters_key = self._params_signature_base()
|
|
596
|
+
tables = self.get_tables()
|
|
597
|
+
columns = tuple(tables[table]['columns']) if table in tables else tuple()
|
|
598
|
+
sort_by = self.sort_by_select.currentText()
|
|
599
|
+
sort_order = self.sort_order_select.currentText()
|
|
600
|
+
limit = self.get_page_size()
|
|
601
|
+
offset = self.current_offset
|
|
602
|
+
return table, columns, sort_by, sort_order, search_query, search_column, filters_key, limit, offset
|
|
603
|
+
|
|
604
|
+
def _params_signature_count(self):
|
|
605
|
+
return self._params_signature_base()
|
|
606
|
+
|
|
607
|
+
def _get_total_rows(self):
|
|
608
|
+
sig = self._params_signature_count()
|
|
609
|
+
if self._last_count_sig == sig:
|
|
610
|
+
return self._cached_total_rows
|
|
611
|
+
table, search_query, search_column, _ = sig
|
|
612
|
+
total_rows = self.get_viewer().count_rows(
|
|
613
|
+
table,
|
|
614
|
+
search_query=search_query,
|
|
615
|
+
search_column=search_column,
|
|
616
|
+
filters=self.get_filters(),
|
|
617
|
+
)
|
|
618
|
+
self._last_count_sig = sig
|
|
619
|
+
self._cached_total_rows = total_rows
|
|
620
|
+
return total_rows
|
|
621
|
+
|
|
622
|
+
def force_refresh(self):
|
|
623
|
+
self._last_fetch_sig = None
|
|
624
|
+
self._last_count_sig = None
|
|
625
|
+
self._last_columns_sig = None
|
|
626
|
+
self.update_table_view()
|
|
@@ -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: 2025.09.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtWidgets import QPushButton, QHBoxLayout, QVBoxLayout, QScrollArea, QWidget, QSizePolicy
|
|
@@ -47,87 +47,85 @@ class Dictionary(BaseConfigDialog):
|
|
|
47
47
|
|
|
48
48
|
def setup(self):
|
|
49
49
|
"""Setup dictionary editor dialogs"""
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
ui = self.window.ui
|
|
51
|
+
controller = self.window.controller
|
|
52
|
+
save_text = trans("dialog.preset.btn.save")
|
|
53
|
+
dismiss_text = trans("dialog.rename.dismiss")
|
|
54
|
+
edit_title = trans('action.edit')
|
|
55
|
+
|
|
56
|
+
for dict_id, data in self.dicts.items():
|
|
57
|
+
parent_id = f"{self.id}.{dict_id}"
|
|
52
58
|
option_key = self.keys[dict_id]
|
|
53
59
|
parent = self.parents[dict_id]
|
|
54
|
-
|
|
55
|
-
self.window.ui.config[parent_id] = {}
|
|
60
|
+
ui.config[parent_id] = {}
|
|
56
61
|
|
|
57
|
-
# widgets
|
|
58
62
|
fields = {}
|
|
59
|
-
|
|
60
|
-
# option type: dict
|
|
61
63
|
if data["type"] == 'dict':
|
|
62
|
-
fields =
|
|
64
|
+
fields = controller.config.dictionary.to_options(
|
|
63
65
|
parent_id,
|
|
64
66
|
data,
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
# option type: cmd
|
|
67
|
+
)
|
|
68
68
|
elif data["type"] == 'cmd':
|
|
69
|
-
fields =
|
|
69
|
+
fields = controller.config.cmd.to_options(
|
|
70
70
|
parent_id,
|
|
71
71
|
data,
|
|
72
|
-
)
|
|
72
|
+
)
|
|
73
73
|
|
|
74
74
|
widgets = self.build_widgets(
|
|
75
75
|
parent_id,
|
|
76
76
|
fields,
|
|
77
77
|
stretch=True,
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
for key in widgets:
|
|
81
|
-
self.window.ui.config[parent_id][key] = widgets[key]
|
|
82
|
-
|
|
83
|
-
# apply widgets to layouts
|
|
84
|
-
options = {}
|
|
85
|
-
is_stretch = False
|
|
86
|
-
for key in widgets:
|
|
87
|
-
if fields[key]["type"] == 'int' or fields[key]["type"] == 'float':
|
|
88
|
-
options[key] = self.add_option(widgets[key], fields[key])
|
|
89
|
-
elif fields[key]["type"] == 'text' or fields[key]["type"] == 'textarea':
|
|
90
|
-
options[key] = self.add_row_option(widgets[key], fields[key])
|
|
91
|
-
elif fields[key]["type"] == 'bool':
|
|
92
|
-
options[key] = self.add_raw_option(widgets[key], fields[key])
|
|
93
|
-
elif fields[key]["type"] == 'dict':
|
|
94
|
-
options[key] = self.add_row_option(widgets[key], fields[key])
|
|
95
|
-
elif fields[key]["type"] == 'combo':
|
|
96
|
-
options[key] = self.add_row_option(widgets[key], fields[key])
|
|
97
|
-
|
|
98
|
-
# stretch all only if textarea is present
|
|
99
|
-
if fields[key]["type"] == 'textarea':
|
|
100
|
-
is_stretch = True
|
|
78
|
+
)
|
|
79
|
+
ui.config[parent_id] = widgets
|
|
101
80
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
81
|
+
add_option = self.add_option
|
|
82
|
+
add_row_option = self.add_row_option
|
|
83
|
+
add_raw_option = self.add_raw_option
|
|
105
84
|
|
|
106
|
-
|
|
85
|
+
rows = QVBoxLayout()
|
|
86
|
+
has_textarea = False
|
|
87
|
+
|
|
88
|
+
for k, f in fields.items():
|
|
89
|
+
t = f.get("type")
|
|
90
|
+
w = widgets.get(k)
|
|
91
|
+
if t in ('int', 'float'):
|
|
92
|
+
row = add_option(w, f)
|
|
93
|
+
elif t in ('text', 'textarea', 'dict', 'combo'):
|
|
94
|
+
row = add_row_option(w, f)
|
|
95
|
+
elif t == 'bool':
|
|
96
|
+
row = add_raw_option(w, f)
|
|
97
|
+
else:
|
|
98
|
+
continue
|
|
99
|
+
rows.addLayout(row)
|
|
100
|
+
if t == 'textarea':
|
|
101
|
+
has_textarea = True
|
|
102
|
+
|
|
103
|
+
if not has_textarea:
|
|
107
104
|
rows.addStretch()
|
|
108
105
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
106
|
+
save_key = f"{parent_id}.btn.save"
|
|
107
|
+
dismiss_key = f"{parent_id}.btn.dismiss"
|
|
108
|
+
|
|
109
|
+
ui.nodes[save_key] = QPushButton(save_text)
|
|
110
|
+
ui.nodes[save_key].clicked.connect(
|
|
112
111
|
lambda checked=True, option_key=option_key, parent=parent, fields=fields:
|
|
113
|
-
|
|
112
|
+
controller.config.dictionary.save_editor(
|
|
114
113
|
option_key,
|
|
115
114
|
parent,
|
|
116
115
|
fields,
|
|
117
116
|
))
|
|
118
|
-
|
|
117
|
+
ui.nodes[save_key].setAutoDefault(True)
|
|
119
118
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
lambda checked=True,
|
|
119
|
+
ui.nodes[dismiss_key] = QPushButton(dismiss_text)
|
|
120
|
+
ui.nodes[dismiss_key].clicked.connect(
|
|
121
|
+
lambda checked=True, pid=parent_id: ui.dialogs.close(f'editor.{pid}')
|
|
123
122
|
)
|
|
124
|
-
|
|
123
|
+
ui.nodes[dismiss_key].setAutoDefault(False)
|
|
125
124
|
|
|
126
125
|
footer = QHBoxLayout()
|
|
127
|
-
footer.addWidget(
|
|
128
|
-
footer.addWidget(
|
|
126
|
+
footer.addWidget(ui.nodes[dismiss_key])
|
|
127
|
+
footer.addWidget(ui.nodes[save_key])
|
|
129
128
|
|
|
130
|
-
# scroll area
|
|
131
129
|
scroll = QScrollArea()
|
|
132
130
|
scroll.setWidgetResizable(True)
|
|
133
131
|
scroll.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
|
@@ -138,10 +136,10 @@ class Dictionary(BaseConfigDialog):
|
|
|
138
136
|
widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
|
139
137
|
|
|
140
138
|
layout = QVBoxLayout()
|
|
141
|
-
layout.addWidget(scroll)
|
|
142
|
-
layout.addLayout(footer)
|
|
139
|
+
layout.addWidget(scroll)
|
|
140
|
+
layout.addLayout(footer)
|
|
143
141
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
142
|
+
dialog_key = f'editor.{parent_id}'
|
|
143
|
+
ui.dialog[dialog_key] = EditorDialog(self.window, parent_id)
|
|
144
|
+
ui.dialog[dialog_key].setLayout(layout)
|
|
145
|
+
ui.dialog[dialog_key].setWindowTitle(edit_title)
|
pygpt_net/ui/dialog/editor.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: 2025.09.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtWidgets import QPushButton, QHBoxLayout, QLabel, QVBoxLayout
|
|
@@ -45,7 +45,8 @@ class Editor:
|
|
|
45
45
|
lambda: self.window.controller.settings.editor.load_editor_defaults_app()
|
|
46
46
|
)
|
|
47
47
|
self.window.ui.nodes['editor.btn.save'].clicked.connect(
|
|
48
|
-
lambda: self.window.core.settings.save_editor()
|
|
48
|
+
lambda: self.window.core.settings.save_editor()
|
|
49
|
+
)
|
|
49
50
|
|
|
50
51
|
bottom_layout = QHBoxLayout()
|
|
51
52
|
bottom_layout.addWidget(self.window.ui.nodes['editor.btn.default'])
|
pygpt_net/ui/dialog/image.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: 2025.09.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QCheckBox
|
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: 2025.
|
|
9
|
+
# Updated Date: 2025.09.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtWidgets import QPushButton, QHBoxLayout, QVBoxLayout
|
|
@@ -44,7 +44,8 @@ class Logger:
|
|
|
44
44
|
|
|
45
45
|
self.window.ui.nodes['logger.btn.clear'] = QPushButton(trans("dialog.logger.btn.clear"))
|
|
46
46
|
self.window.ui.nodes['logger.btn.clear'].clicked.connect(
|
|
47
|
-
lambda: self.window.controller.debug.clear_logger()
|
|
47
|
+
lambda: self.window.controller.debug.clear_logger()
|
|
48
|
+
)
|
|
48
49
|
|
|
49
50
|
bottom_layout = QHBoxLayout()
|
|
50
51
|
bottom_layout.addWidget(self.window.ui.nodes['logger.btn.clear'])
|
pygpt_net/ui/dialog/models.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.
|
|
9
|
+
# Updated Date: 2025.09.05 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
@@ -16,7 +16,6 @@ from PySide6.QtGui import QStandardItemModel, QIcon
|
|
|
16
16
|
from PySide6.QtWidgets import QPushButton, QHBoxLayout, QLabel, QVBoxLayout, QScrollArea, QWidget, QTabWidget, QFrame, \
|
|
17
17
|
QSplitter, QSizePolicy
|
|
18
18
|
|
|
19
|
-
from pygpt_net.item.model import ModelItem
|
|
20
19
|
from pygpt_net.ui.widget.dialog.model import ModelDialog
|
|
21
20
|
from pygpt_net.ui.widget.element.group import CollapsedGroup
|
|
22
21
|
from pygpt_net.ui.widget.element.labels import UrlLabel, DescLabel
|
|
@@ -56,13 +55,17 @@ class Models:
|
|
|
56
55
|
QPushButton(trans("dialog.models.editor.btn.save"))
|
|
57
56
|
|
|
58
57
|
self.window.ui.nodes['models.editor.btn.new'].clicked.connect(
|
|
59
|
-
lambda: self.window.controller.model.editor.new()
|
|
58
|
+
lambda: self.window.controller.model.editor.new()
|
|
59
|
+
)
|
|
60
60
|
self.window.ui.nodes['models.editor.btn.defaults.user'].clicked.connect(
|
|
61
|
-
lambda: self.window.controller.model.editor.load_defaults_user()
|
|
61
|
+
lambda: self.window.controller.model.editor.load_defaults_user()
|
|
62
|
+
)
|
|
62
63
|
self.window.ui.nodes['models.editor.btn.defaults.app'].clicked.connect(
|
|
63
|
-
lambda: self.window.controller.model.editor.load_defaults_app()
|
|
64
|
+
lambda: self.window.controller.model.editor.load_defaults_app()
|
|
65
|
+
)
|
|
64
66
|
self.window.ui.nodes['models.editor.btn.save'].clicked.connect(
|
|
65
|
-
lambda: self.window.controller.model.editor.save()
|
|
67
|
+
lambda: self.window.controller.model.editor.save()
|
|
68
|
+
)
|
|
66
69
|
|
|
67
70
|
# set enter key to save button
|
|
68
71
|
self.window.ui.nodes['models.editor.btn.new'].setAutoDefault(False)
|
|
@@ -111,17 +114,16 @@ class Models:
|
|
|
111
114
|
# append advanced options at the end
|
|
112
115
|
if len(advanced_keys) > 0:
|
|
113
116
|
group_id = 'models.editor.advanced'
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
group = CollapsedGroup(self.window, group_id, None, False, None)
|
|
118
|
+
group.box.setText(trans('settings.advanced.collapse'))
|
|
116
119
|
for key in widgets:
|
|
117
120
|
if key not in advanced_keys: # ignore non-advanced options
|
|
118
121
|
continue
|
|
119
|
-
|
|
120
|
-
option = self.add_option(widgets[key], options[key]) # build option
|
|
121
|
-
self.window.ui.groups[group_id].add_layout(option) # add option to group
|
|
122
|
+
group.add_layout(self.add_option(widgets[key], options[key])) # add option to group
|
|
122
123
|
|
|
123
124
|
# add advanced options group to scroll
|
|
124
|
-
content.addWidget(
|
|
125
|
+
content.addWidget(group)
|
|
126
|
+
self.window.ui.groups[group_id] = group
|
|
125
127
|
|
|
126
128
|
content.addStretch()
|
|
127
129
|
|