pygpt-net 2.6.36__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 +12 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/chat/handler/anthropic_stream.py +164 -0
- pygpt_net/controller/chat/handler/google_stream.py +181 -0
- pygpt_net/controller/chat/handler/langchain_stream.py +24 -0
- pygpt_net/controller/chat/handler/llamaindex_stream.py +47 -0
- pygpt_net/controller/chat/handler/openai_stream.py +260 -0
- pygpt_net/controller/chat/handler/utils.py +210 -0
- pygpt_net/controller/chat/handler/worker.py +570 -0
- pygpt_net/controller/chat/handler/xai_stream.py +135 -0
- pygpt_net/controller/chat/stream.py +1 -1
- pygpt_net/controller/ctx/ctx.py +1 -1
- pygpt_net/controller/debug/debug.py +6 -6
- pygpt_net/controller/model/editor.py +3 -0
- 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/bridge/context.py +35 -35
- pygpt_net/core/bridge/worker.py +40 -16
- 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 +30 -39
- pygpt_net/core/tabs/tab.py +24 -1
- pygpt_net/data/config/config.json +10 -3
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/settings.json +105 -0
- pygpt_net/data/css/style.dark.css +2 -3
- pygpt_net/data/css/style.light.css +2 -3
- pygpt_net/data/locale/locale.de.ini +3 -1
- pygpt_net/data/locale/locale.en.ini +19 -1
- pygpt_net/data/locale/locale.es.ini +3 -1
- pygpt_net/data/locale/locale.fr.ini +3 -1
- pygpt_net/data/locale/locale.it.ini +3 -1
- pygpt_net/data/locale/locale.pl.ini +4 -2
- pygpt_net/data/locale/locale.uk.ini +3 -1
- pygpt_net/data/locale/locale.zh.ini +3 -1
- 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/__init__.py +5 -3
- pygpt_net/provider/api/anthropic/__init__.py +190 -29
- pygpt_net/provider/api/anthropic/audio.py +30 -0
- pygpt_net/provider/api/anthropic/chat.py +341 -0
- pygpt_net/provider/api/anthropic/image.py +25 -0
- pygpt_net/provider/api/anthropic/tools.py +266 -0
- pygpt_net/provider/api/anthropic/vision.py +142 -0
- pygpt_net/provider/api/google/chat.py +2 -2
- pygpt_net/provider/api/google/realtime/client.py +2 -2
- pygpt_net/provider/api/google/tools.py +58 -48
- pygpt_net/provider/api/google/vision.py +7 -1
- pygpt_net/provider/api/openai/chat.py +1 -0
- pygpt_net/provider/api/openai/vision.py +6 -0
- pygpt_net/provider/api/x_ai/__init__.py +247 -0
- pygpt_net/provider/api/x_ai/audio.py +32 -0
- pygpt_net/provider/api/x_ai/chat.py +968 -0
- pygpt_net/provider/api/x_ai/image.py +208 -0
- pygpt_net/provider/api/x_ai/remote.py +262 -0
- pygpt_net/provider/api/x_ai/tools.py +120 -0
- pygpt_net/provider/api/x_ai/vision.py +119 -0
- pygpt_net/provider/core/attachment/json_file.py +2 -2
- pygpt_net/provider/core/config/patch.py +28 -0
- pygpt_net/provider/llms/anthropic.py +4 -2
- pygpt_net/tools/text_editor/tool.py +4 -1
- pygpt_net/tools/text_editor/ui/dialogs.py +1 -1
- pygpt_net/ui/base/config_dialog.py +5 -11
- 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 +16 -16
- pygpt_net/ui/dialog/plugins.py +63 -60
- 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 +20 -4
- pygpt_net/ui/widget/textarea/editor.py +0 -4
- pygpt_net/ui/widget/textarea/web.py +1 -1
- {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/METADATA +18 -6
- {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/RECORD +95 -76
- pygpt_net/controller/chat/handler/stream_worker.py +0 -1136
- {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.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: 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,10 +16,9 @@ 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
|
-
from pygpt_net.ui.widget.element.labels import UrlLabel
|
|
21
|
+
from pygpt_net.ui.widget.element.labels import UrlLabel, DescLabel
|
|
23
22
|
from pygpt_net.ui.widget.lists.model_editor import ModelEditorList
|
|
24
23
|
from pygpt_net.ui.widget.option.checkbox import OptionCheckbox
|
|
25
24
|
from pygpt_net.ui.widget.option.checkbox_list import OptionCheckboxList
|
|
@@ -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
|
|
|
@@ -303,10 +305,8 @@ class Models:
|
|
|
303
305
|
layout.addWidget(widget)
|
|
304
306
|
|
|
305
307
|
if desc:
|
|
306
|
-
self.window.ui.nodes[desc_key] =
|
|
307
|
-
self.window.ui.nodes[desc_key].setWordWrap(True)
|
|
308
|
+
self.window.ui.nodes[desc_key] = DescLabel(desc)
|
|
308
309
|
self.window.ui.nodes[desc_key].setMaximumHeight(40)
|
|
309
|
-
self.window.ui.nodes[desc_key].setStyleSheet("font-size: 10px;")
|
|
310
310
|
layout.addWidget(self.window.ui.nodes[desc_key])
|
|
311
311
|
|
|
312
312
|
line = self.add_line() # TODO: change name to separator
|
pygpt_net/ui/dialog/plugins.py
CHANGED
|
@@ -6,18 +6,18 @@
|
|
|
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.QtCore import Qt
|
|
13
13
|
from PySide6.QtGui import QStandardItemModel
|
|
14
|
-
from PySide6.QtWidgets import QPushButton, QHBoxLayout,
|
|
14
|
+
from PySide6.QtWidgets import QPushButton, QHBoxLayout, QVBoxLayout, QScrollArea, QWidget, QTabWidget, QFrame, \
|
|
15
15
|
QSplitter, QSizePolicy
|
|
16
16
|
|
|
17
17
|
from pygpt_net.plugin.base.plugin import BasePlugin
|
|
18
18
|
from pygpt_net.ui.widget.dialog.settings_plugin import PluginSettingsDialog
|
|
19
19
|
from pygpt_net.ui.widget.element.group import CollapsedGroup
|
|
20
|
-
from pygpt_net.ui.widget.element.labels import UrlLabel, HelpLabel
|
|
20
|
+
from pygpt_net.ui.widget.element.labels import UrlLabel, HelpLabel, DescLabel, BaseLabel
|
|
21
21
|
from pygpt_net.ui.widget.lists.plugin import PluginList
|
|
22
22
|
from pygpt_net.ui.widget.option.checkbox import OptionCheckbox
|
|
23
23
|
from pygpt_net.ui.widget.option.checkbox_list import OptionCheckboxList
|
|
@@ -55,11 +55,14 @@ class Plugins:
|
|
|
55
55
|
QPushButton(trans("dialog.plugin.settings.btn.save"))
|
|
56
56
|
|
|
57
57
|
self.window.ui.nodes['plugin.settings.btn.defaults.user'].clicked.connect(
|
|
58
|
-
lambda: self.window.controller.plugins.settings.load_defaults_user()
|
|
58
|
+
lambda: self.window.controller.plugins.settings.load_defaults_user()
|
|
59
|
+
)
|
|
59
60
|
self.window.ui.nodes['plugin.settings.btn.defaults.app'].clicked.connect(
|
|
60
|
-
lambda: self.window.controller.plugins.settings.load_defaults_app()
|
|
61
|
+
lambda: self.window.controller.plugins.settings.load_defaults_app()
|
|
62
|
+
)
|
|
61
63
|
self.window.ui.nodes['plugin.settings.btn.save'].clicked.connect(
|
|
62
|
-
lambda: self.window.controller.plugins.settings.save()
|
|
64
|
+
lambda: self.window.controller.plugins.settings.save()
|
|
65
|
+
)
|
|
63
66
|
|
|
64
67
|
# set enter key to save button
|
|
65
68
|
self.window.ui.nodes['plugin.settings.btn.defaults.user'].setAutoDefault(False)
|
|
@@ -77,14 +80,15 @@ class Plugins:
|
|
|
77
80
|
self.window.ui.tabs['plugin.settings.tabs'] = {}
|
|
78
81
|
|
|
79
82
|
sorted_ids = self.window.core.plugins.get_ids(sort=True)
|
|
83
|
+
get_plugin = self.window.core.plugins.get
|
|
80
84
|
|
|
81
85
|
# build plugin settings tabs
|
|
82
86
|
for id in sorted_ids:
|
|
83
87
|
content_tabs = {}
|
|
84
88
|
scroll_tabs = {}
|
|
85
89
|
|
|
86
|
-
plugin =
|
|
87
|
-
parent_id = "plugin."
|
|
90
|
+
plugin = get_plugin(id)
|
|
91
|
+
parent_id = f"plugin.{id}"
|
|
88
92
|
|
|
89
93
|
# create plugin options entry if not exists
|
|
90
94
|
if parent_id not in self.window.ui.config:
|
|
@@ -137,7 +141,7 @@ class Plugins:
|
|
|
137
141
|
# append advanced options at the end
|
|
138
142
|
if len(advanced_keys) > 0:
|
|
139
143
|
groups = {}
|
|
140
|
-
group_id =
|
|
144
|
+
group_id = f"plugin.settings.advanced.{id}"
|
|
141
145
|
for key in widgets:
|
|
142
146
|
if key not in advanced_keys: # ignore non-advanced options
|
|
143
147
|
continue
|
|
@@ -157,7 +161,7 @@ class Plugins:
|
|
|
157
161
|
|
|
158
162
|
# add advanced options group to scrolls
|
|
159
163
|
for tab_id in groups:
|
|
160
|
-
full_id = group_id
|
|
164
|
+
full_id = f"{group_id}.{tab_id}"
|
|
161
165
|
content_tabs[tab_id].addWidget(groups[tab_id])
|
|
162
166
|
self.window.ui.groups[full_id] = groups[tab_id]
|
|
163
167
|
|
|
@@ -167,17 +171,16 @@ class Plugins:
|
|
|
167
171
|
|
|
168
172
|
# set description, translate if localization is enabled
|
|
169
173
|
name_txt = plugin.name
|
|
170
|
-
desc_key =
|
|
174
|
+
desc_key = f"plugin.settings.{id}.desc"
|
|
171
175
|
desc_txt = plugin.description
|
|
172
176
|
if plugin.use_locale:
|
|
173
|
-
domain =
|
|
177
|
+
domain = f"plugin.{plugin.id}"
|
|
174
178
|
name_txt = trans('plugin.name', False, domain)
|
|
175
179
|
desc_txt = trans('plugin.description', False, domain)
|
|
176
180
|
|
|
177
|
-
self.window.ui.nodes[desc_key] =
|
|
178
|
-
self.window.ui.nodes[desc_key].setWordWrap(True)
|
|
181
|
+
self.window.ui.nodes[desc_key] = DescLabel(desc_txt)
|
|
179
182
|
self.window.ui.nodes[desc_key].setAlignment(Qt.AlignCenter)
|
|
180
|
-
self.window.ui.nodes[desc_key].setStyleSheet("font-weight: bold;")
|
|
183
|
+
#self.window.ui.nodes[desc_key].setStyleSheet("font-weight: bold;")
|
|
181
184
|
|
|
182
185
|
line = self.add_line()
|
|
183
186
|
|
|
@@ -234,8 +237,7 @@ class Plugins:
|
|
|
234
237
|
|
|
235
238
|
data = {}
|
|
236
239
|
for plugin_id in sorted_ids:
|
|
237
|
-
|
|
238
|
-
data[plugin_id] = plugin
|
|
240
|
+
data[plugin_id] = get_plugin(plugin_id)
|
|
239
241
|
|
|
240
242
|
# plugins list
|
|
241
243
|
id = 'plugin.list'
|
|
@@ -250,12 +252,13 @@ class Plugins:
|
|
|
250
252
|
self.window.ui.nodes[id].setMinimumWidth(self.max_list_width)
|
|
251
253
|
|
|
252
254
|
# splitter
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
255
|
+
splitter = QSplitter(Qt.Horizontal)
|
|
256
|
+
splitter.addWidget(self.window.ui.nodes[id]) # list
|
|
257
|
+
splitter.addWidget(self.window.ui.tabs['plugin.settings']) # tabs
|
|
258
|
+
splitter.setStretchFactor(0, 2)
|
|
259
|
+
splitter.setStretchFactor(1, 5)
|
|
260
|
+
splitter.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
|
261
|
+
self.window.ui.splitters['dialog.plugins'] = splitter
|
|
259
262
|
|
|
260
263
|
main_layout = QHBoxLayout()
|
|
261
264
|
main_layout.addWidget(self.window.ui.splitters['dialog.plugins'])
|
|
@@ -279,7 +282,7 @@ class Plugins:
|
|
|
279
282
|
self.window.ui.tabs['plugin.settings'].setCurrentIndex(idx)
|
|
280
283
|
self.window.controller.plugins.set_by_tab(idx)
|
|
281
284
|
except Exception as e:
|
|
282
|
-
print(
|
|
285
|
+
print(f"Failed restore plugin settings tab: {idx}", e)
|
|
283
286
|
else:
|
|
284
287
|
self.window.controller.plugins.set_by_tab(0)
|
|
285
288
|
|
|
@@ -317,36 +320,39 @@ class Plugins:
|
|
|
317
320
|
:return: dict of widgets
|
|
318
321
|
"""
|
|
319
322
|
id = plugin.id
|
|
320
|
-
parent = "plugin."
|
|
323
|
+
parent = f"plugin.{id}" # parent id for plugins is in format: plugin.<plugin_id>
|
|
321
324
|
widgets = {}
|
|
325
|
+
base_types = ('text', 'int', 'float')
|
|
326
|
+
number_types = ('int', 'float')
|
|
327
|
+
apply = self.window.controller.config.placeholder.apply
|
|
322
328
|
|
|
323
329
|
for key in options:
|
|
324
330
|
option = options[key]
|
|
331
|
+
t = option['type']
|
|
325
332
|
# create widget by option type
|
|
326
|
-
if
|
|
327
|
-
if 'slider' in option and option['slider']
|
|
328
|
-
and (option['type'] == 'int' or option['type'] == 'float'):
|
|
333
|
+
if t in base_types:
|
|
334
|
+
if 'slider' in option and option['slider'] and t in number_types:
|
|
329
335
|
widgets[key] = OptionSlider(self.window, parent, key, option) # slider + text input
|
|
330
336
|
else:
|
|
331
337
|
if 'secret' in option and option['secret']:
|
|
332
338
|
widgets[key] = PasswordInput(self.window, parent, key, option) # password input
|
|
333
339
|
else:
|
|
334
340
|
widgets[key] = OptionInput(self.window, parent, key, option) # text input
|
|
335
|
-
elif
|
|
341
|
+
elif t == 'textarea':
|
|
336
342
|
widgets[key] = OptionTextarea(self.window, parent, key, option) # textarea
|
|
337
|
-
elif
|
|
343
|
+
elif t == 'bool':
|
|
338
344
|
widgets[key] = OptionCheckbox(self.window, parent, key, option) # checkbox
|
|
339
|
-
elif
|
|
340
|
-
|
|
345
|
+
elif t == 'bool_list':
|
|
346
|
+
apply(option)
|
|
341
347
|
widgets[key] = OptionCheckboxList(self.window, parent, key, option) # checkbox list
|
|
342
|
-
elif
|
|
343
|
-
|
|
348
|
+
elif t == 'dict':
|
|
349
|
+
apply(option)
|
|
344
350
|
widgets[key] = OptionDict(self.window, parent, key, option) # dictionary
|
|
345
|
-
elif
|
|
346
|
-
|
|
351
|
+
elif t == 'combo':
|
|
352
|
+
apply(option)
|
|
347
353
|
widgets[key] = OptionCombo(self.window, parent, key, option) # combobox
|
|
348
|
-
elif
|
|
349
|
-
|
|
354
|
+
elif t == 'cmd':
|
|
355
|
+
apply(option)
|
|
350
356
|
widgets[key] = OptionCmd(self.window, plugin, parent, key, option) # command
|
|
351
357
|
|
|
352
358
|
return widgets
|
|
@@ -396,14 +402,14 @@ class Plugins:
|
|
|
396
402
|
:param option: option dict
|
|
397
403
|
:return: QVBoxLayout
|
|
398
404
|
"""
|
|
399
|
-
one_column_types =
|
|
400
|
-
no_label_types =
|
|
401
|
-
no_desc_types =
|
|
405
|
+
one_column_types = ('textarea', 'dict', 'bool', 'cmd')
|
|
406
|
+
no_label_types = ('bool', 'cmd')
|
|
407
|
+
no_desc_types = 'cmd'
|
|
402
408
|
allow_locale = True
|
|
403
409
|
|
|
404
410
|
key = option['id']
|
|
405
|
-
label_key =
|
|
406
|
-
desc_key =
|
|
411
|
+
label_key = f"plugin.{plugin.id}.{key}.label"
|
|
412
|
+
desc_key = f"plugin.{plugin.id}.{key}.desc"
|
|
407
413
|
|
|
408
414
|
# get option label and description
|
|
409
415
|
txt_title = option['label']
|
|
@@ -415,14 +421,14 @@ class Plugins:
|
|
|
415
421
|
|
|
416
422
|
# translate if localization is enabled
|
|
417
423
|
if plugin.use_locale and allow_locale:
|
|
418
|
-
domain =
|
|
419
|
-
txt_title = trans(key
|
|
420
|
-
txt_desc = trans(key
|
|
421
|
-
txt_tooltip = trans(key
|
|
424
|
+
domain = f"plugin.{plugin.id}"
|
|
425
|
+
txt_title = trans(f"{key}.label", False, domain)
|
|
426
|
+
txt_desc = trans(f"{key}.description", False, domain)
|
|
427
|
+
# txt_tooltip = trans(f"{key}.tooltip", False, domain)
|
|
422
428
|
|
|
423
429
|
# if empty tooltip then use description
|
|
424
|
-
if txt_tooltip == key
|
|
425
|
-
txt_tooltip = txt_desc
|
|
430
|
+
# if txt_tooltip == f"{key}.tooltip":
|
|
431
|
+
# txt_tooltip = txt_desc
|
|
426
432
|
|
|
427
433
|
|
|
428
434
|
"""
|
|
@@ -431,7 +437,7 @@ class Plugins:
|
|
|
431
437
|
"""
|
|
432
438
|
|
|
433
439
|
if option['type'] not in no_label_types:
|
|
434
|
-
self.window.ui.nodes[label_key] =
|
|
440
|
+
self.window.ui.nodes[label_key] = BaseLabel(txt_title)
|
|
435
441
|
self.window.ui.nodes[label_key].setStyleSheet("font-weight: bold;")
|
|
436
442
|
|
|
437
443
|
# 2-columns layout
|
|
@@ -447,10 +453,8 @@ class Plugins:
|
|
|
447
453
|
cols_widget.setLayout(cols)
|
|
448
454
|
# cols_widget.setMaximumHeight(90)
|
|
449
455
|
|
|
450
|
-
self.window.ui.nodes[desc_key] =
|
|
451
|
-
self.window.ui.nodes[desc_key].setWordWrap(True)
|
|
456
|
+
self.window.ui.nodes[desc_key] = DescLabel(txt_desc)
|
|
452
457
|
self.window.ui.nodes[desc_key].setMaximumHeight(40)
|
|
453
|
-
self.window.ui.nodes[desc_key].setStyleSheet("font-size: 10px;")
|
|
454
458
|
# self.window.ui.nodes[desc_key].setToolTip(txt_tooltip)
|
|
455
459
|
|
|
456
460
|
layout = QVBoxLayout()
|
|
@@ -468,10 +472,8 @@ class Plugins:
|
|
|
468
472
|
layout.addWidget(widget)
|
|
469
473
|
|
|
470
474
|
if option['type'] not in no_desc_types:
|
|
471
|
-
self.window.ui.nodes[desc_key] =
|
|
472
|
-
self.window.ui.nodes[desc_key].setWordWrap(True)
|
|
475
|
+
self.window.ui.nodes[desc_key] = DescLabel(txt_desc)
|
|
473
476
|
self.window.ui.nodes[desc_key].setMaximumHeight(40)
|
|
474
|
-
self.window.ui.nodes[desc_key].setStyleSheet("font-size: 10px;")
|
|
475
477
|
# self.window.ui.nodes[desc_key].setToolTip(txt_tooltip)
|
|
476
478
|
layout.addWidget(self.window.ui.nodes[desc_key])
|
|
477
479
|
|
|
@@ -511,12 +513,13 @@ class Plugins:
|
|
|
511
513
|
:param id: ID of the list
|
|
512
514
|
:param data: Data to update
|
|
513
515
|
"""
|
|
514
|
-
|
|
516
|
+
model = self.window.ui.models[id]
|
|
517
|
+
model.removeRows(0, model.rowCount())
|
|
515
518
|
i = 0
|
|
516
519
|
for n in data:
|
|
517
|
-
|
|
520
|
+
model.insertRow(i)
|
|
518
521
|
name = self.window.core.plugins.get_name(data[n].id)
|
|
519
522
|
tooltip = self.window.core.plugins.get_desc(data[n].id)
|
|
520
|
-
|
|
521
|
-
|
|
523
|
+
model.setData(model.index(i, 0), name)
|
|
524
|
+
model.setData(model.index(i, 0), tooltip, Qt.ToolTipRole)
|
|
522
525
|
i += 1
|
|
@@ -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 import QtCore
|
|
@@ -210,7 +210,7 @@ class CtxList:
|
|
|
210
210
|
files_str = ", ".join(files)
|
|
211
211
|
if len(files_str) > 40:
|
|
212
212
|
files_str = files_str[:40] + '...'
|
|
213
|
-
tooltip_str = trans(
|
|
213
|
+
tooltip_str = f"{trans('attachments.ctx.tooltip.list').format(num=len(files))}: {files_str}"
|
|
214
214
|
group_item.setToolTip(tooltip_str)
|
|
215
215
|
|
|
216
216
|
group_item.setData(custom_data, QtCore.Qt.ItemDataRole.UserRole)
|
|
@@ -282,8 +282,7 @@ class CtxList:
|
|
|
282
282
|
files_str = ", ".join(files)
|
|
283
283
|
if len(files_str) > 40:
|
|
284
284
|
files_str = files_str[:40] + '...'
|
|
285
|
-
|
|
286
|
-
tooltip_text += "\n" + tooltip_str
|
|
285
|
+
tooltip_text += f"\n{trans('attachments.ctx.tooltip.list').format(num=len(files))}: {files_str}"
|
|
287
286
|
|
|
288
287
|
item = Item(name, id)
|
|
289
288
|
item.id = id
|
|
@@ -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
|
-
from .toolbox import
|
|
12
|
+
from .toolbox import ToolboxMain
|
|
@@ -115,15 +115,14 @@ class Assistants:
|
|
|
115
115
|
view.backup_selection()
|
|
116
116
|
view.setUpdatesEnabled(False)
|
|
117
117
|
try:
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
model.setData(index, item.name)
|
|
118
|
+
model.setRowCount(0)
|
|
119
|
+
count = len(data)
|
|
120
|
+
if count:
|
|
121
|
+
model.setRowCount(count)
|
|
122
|
+
for i, item in enumerate(data.values()):
|
|
123
|
+
index = model.index(i, 0)
|
|
124
|
+
model.setData(index, "ID: " + item.id, QtCore.Qt.ToolTipRole)
|
|
125
|
+
model.setData(index, item.name)
|
|
127
126
|
finally:
|
|
128
127
|
view.setUpdatesEnabled(True)
|
|
129
128
|
|
|
@@ -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 import QtCore
|
|
@@ -144,7 +144,7 @@ class Presets:
|
|
|
144
144
|
for i, (key, item) in enumerate(data.items()):
|
|
145
145
|
name = item.name
|
|
146
146
|
if is_expert_mode and item.enabled and not key.startswith(startswith_current):
|
|
147
|
-
name = "[x] "
|
|
147
|
+
name = f"[x] {name}"
|
|
148
148
|
elif is_agent_mode:
|
|
149
149
|
num_experts = count_experts(key)
|
|
150
150
|
if num_experts > 0:
|