pygpt-net 2.6.15__py3-none-any.whl → 2.6.17__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/__init__.py +8 -2
- pygpt_net/controller/chat/command.py +18 -6
- pygpt_net/controller/ctx/ctx.py +2 -2
- pygpt_net/controller/mode/mode.py +3 -2
- pygpt_net/controller/plugins/plugins.py +31 -15
- pygpt_net/controller/presets/editor.py +11 -32
- pygpt_net/controller/settings/profile.py +16 -3
- pygpt_net/controller/settings/workdir.py +184 -124
- pygpt_net/controller/theme/theme.py +11 -5
- pygpt_net/core/agents/observer/evaluation.py +3 -14
- pygpt_net/core/agents/runners/llama_workflow.py +7 -6
- pygpt_net/core/command/command.py +5 -3
- pygpt_net/core/experts/experts.py +58 -13
- pygpt_net/core/plugins/plugins.py +12 -1
- pygpt_net/core/render/plain/body.py +10 -19
- pygpt_net/core/render/plain/renderer.py +27 -27
- pygpt_net/data/config/config.json +6 -6
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/locale/locale.en.ini +2 -2
- pygpt_net/data/locale/plugin.openai_dalle.de.ini +1 -1
- pygpt_net/data/locale/plugin.openai_dalle.en.ini +1 -1
- pygpt_net/data/locale/plugin.openai_dalle.es.ini +1 -1
- pygpt_net/data/locale/plugin.openai_dalle.fr.ini +1 -1
- pygpt_net/data/locale/plugin.openai_dalle.it.ini +1 -1
- pygpt_net/data/locale/plugin.openai_dalle.pl.ini +1 -1
- pygpt_net/data/locale/plugin.openai_dalle.uk.ini +1 -1
- pygpt_net/data/locale/plugin.openai_dalle.zh.ini +1 -1
- pygpt_net/data/locale/plugin.openai_vision.de.ini +1 -1
- pygpt_net/data/locale/plugin.openai_vision.en.ini +1 -1
- pygpt_net/data/locale/plugin.openai_vision.es.ini +1 -1
- pygpt_net/data/locale/plugin.openai_vision.fr.ini +1 -1
- pygpt_net/data/locale/plugin.openai_vision.it.ini +1 -1
- pygpt_net/data/locale/plugin.openai_vision.pl.ini +1 -1
- pygpt_net/data/locale/plugin.openai_vision.uk.ini +1 -1
- pygpt_net/data/locale/plugin.openai_vision.zh.ini +1 -1
- pygpt_net/item/ctx.py +5 -4
- pygpt_net/plugin/idx_llama_index/plugin.py +9 -5
- pygpt_net/plugin/idx_llama_index/worker.py +5 -2
- pygpt_net/plugin/openai_dalle/plugin.py +1 -1
- pygpt_net/tools/translator/ui/dialogs.py +1 -0
- pygpt_net/tools/translator/ui/widgets.py +1 -2
- pygpt_net/ui/__init__.py +12 -10
- pygpt_net/ui/base/config_dialog.py +15 -10
- pygpt_net/ui/dialog/about.py +26 -18
- pygpt_net/ui/dialog/plugins.py +6 -4
- pygpt_net/ui/dialog/settings.py +75 -87
- pygpt_net/ui/dialog/workdir.py +7 -2
- pygpt_net/ui/main.py +5 -1
- pygpt_net/ui/widget/textarea/editor.py +1 -2
- pygpt_net/ui/widget/textarea/web.py +22 -16
- {pygpt_net-2.6.15.dist-info → pygpt_net-2.6.17.dist-info}/METADATA +26 -14
- {pygpt_net-2.6.15.dist-info → pygpt_net-2.6.17.dist-info}/RECORD +57 -57
- {pygpt_net-2.6.15.dist-info → pygpt_net-2.6.17.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.15.dist-info → pygpt_net-2.6.17.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.15.dist-info → pygpt_net-2.6.17.dist-info}/entry_points.txt +0 -0
pygpt_net/item/ctx.py
CHANGED
|
@@ -13,6 +13,7 @@ import copy
|
|
|
13
13
|
import datetime
|
|
14
14
|
import json
|
|
15
15
|
import time
|
|
16
|
+
from typing import Optional
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class CtxItem:
|
|
@@ -94,7 +95,7 @@ class CtxItem:
|
|
|
94
95
|
|
|
95
96
|
|
|
96
97
|
@property
|
|
97
|
-
def final_input(self) -> str:
|
|
98
|
+
def final_input(self) -> Optional[str]:
|
|
98
99
|
"""
|
|
99
100
|
Final input
|
|
100
101
|
|
|
@@ -103,11 +104,11 @@ class CtxItem:
|
|
|
103
104
|
if self.input is None:
|
|
104
105
|
return None
|
|
105
106
|
if self.hidden_input:
|
|
106
|
-
return "\n\n".join(self.input, self.hidden_input)
|
|
107
|
+
return "\n\n".join([self.input, self.hidden_input])
|
|
107
108
|
return self.input
|
|
108
109
|
|
|
109
110
|
@property
|
|
110
|
-
def final_output(self) -> str:
|
|
111
|
+
def final_output(self) -> Optional[str]:
|
|
111
112
|
"""
|
|
112
113
|
Final output
|
|
113
114
|
|
|
@@ -116,7 +117,7 @@ class CtxItem:
|
|
|
116
117
|
if self.output is None:
|
|
117
118
|
return None
|
|
118
119
|
if self.hidden_output:
|
|
119
|
-
return "\n\n".join(self.output, self.hidden_output)
|
|
120
|
+
return "\n\n".join([self.output, self.hidden_output])
|
|
120
121
|
return self.output
|
|
121
122
|
|
|
122
123
|
def clear_reply(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: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.20 09:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import json
|
|
@@ -174,14 +174,16 @@ class Plugin(BasePlugin):
|
|
|
174
174
|
prepared_question = response
|
|
175
175
|
return prepared_question
|
|
176
176
|
|
|
177
|
-
def get_from_retrieval(self, query: str) -> str:
|
|
177
|
+
def get_from_retrieval(self, query: str, idx: str = None) -> str:
|
|
178
178
|
"""
|
|
179
179
|
Get response from retrieval
|
|
180
180
|
|
|
181
181
|
:param query: query
|
|
182
|
+
:param idx: index to query, if None then use default index
|
|
182
183
|
:return: response
|
|
183
184
|
"""
|
|
184
|
-
idx
|
|
185
|
+
if idx is None:
|
|
186
|
+
idx = self.get_option_value("idx")
|
|
185
187
|
indexes = idx.split(",")
|
|
186
188
|
response = ""
|
|
187
189
|
for index in indexes:
|
|
@@ -226,16 +228,18 @@ class Plugin(BasePlugin):
|
|
|
226
228
|
prompt += "\nADDITIONAL CONTEXT: " + response
|
|
227
229
|
return prompt
|
|
228
230
|
|
|
229
|
-
def query(self, question: str) -> Tuple[str, list, list]:
|
|
231
|
+
def query(self, question: str, idx: str = None) -> Tuple[str, list, list]:
|
|
230
232
|
"""
|
|
231
233
|
Query Llama-index
|
|
232
234
|
|
|
233
235
|
:param question: question
|
|
236
|
+
:param idx: index to query, if None then use default index
|
|
234
237
|
:return: response, list of document ids, list of metadata
|
|
235
238
|
"""
|
|
236
239
|
doc_ids = []
|
|
237
240
|
metas = []
|
|
238
|
-
idx
|
|
241
|
+
if idx is None:
|
|
242
|
+
idx = self.get_option_value("idx")
|
|
239
243
|
model = self.window.core.models.from_defaults()
|
|
240
244
|
|
|
241
245
|
if self.get_option_value("model_query") is not None:
|
|
@@ -72,9 +72,12 @@ class Worker(BaseWorker):
|
|
|
72
72
|
:return: response item
|
|
73
73
|
"""
|
|
74
74
|
question = self.get_param(item, "query")
|
|
75
|
+
idx = None
|
|
76
|
+
if self.has_param(item, "idx"):
|
|
77
|
+
idx = self.get_param(item, "idx")
|
|
75
78
|
self.status("Please wait... querying: {}...".format(question))
|
|
76
79
|
# at first, try to get from retrieval
|
|
77
|
-
response = self.plugin.get_from_retrieval(question)
|
|
80
|
+
response = self.plugin.get_from_retrieval(question, idx=idx) # get response from retrieval
|
|
78
81
|
if response is not None and response != "":
|
|
79
82
|
self.log("Found using retrieval...")
|
|
80
83
|
context = "ADDITIONAL CONTEXT (response from DB):\n--------------------------------\n" + response
|
|
@@ -83,7 +86,7 @@ class Worker(BaseWorker):
|
|
|
83
86
|
}
|
|
84
87
|
return self.make_response(item, response, extra=extra)
|
|
85
88
|
|
|
86
|
-
content, doc_ids, metas = self.plugin.query(question) # send question to Llama-index
|
|
89
|
+
content, doc_ids, metas = self.plugin.query(question, idx=idx) # send question to Llama-index
|
|
87
90
|
result = content
|
|
88
91
|
context = "ADDITIONAL CONTEXT (response from DB):\n--------------------------------\n" + content
|
|
89
92
|
if doc_ids:
|
|
@@ -34,7 +34,7 @@ class Plugin(BasePlugin):
|
|
|
34
34
|
def __init__(self, *args, **kwargs):
|
|
35
35
|
super(Plugin, self).__init__(*args, **kwargs)
|
|
36
36
|
self.id = "openai_dalle"
|
|
37
|
-
self.name = "
|
|
37
|
+
self.name = "Image generation"
|
|
38
38
|
self.description = "Integrates DALL-E 3 image generation with any chat"
|
|
39
39
|
self.prefix = "DALL-E"
|
|
40
40
|
self.type = [
|
|
@@ -488,8 +488,7 @@ class TextareaField(QTextEdit):
|
|
|
488
488
|
if self.value > self.min_font_size:
|
|
489
489
|
self.value -= 1
|
|
490
490
|
|
|
491
|
-
|
|
492
|
-
self.update_stylesheet(f"font-size: {size_str};")
|
|
491
|
+
self.update_stylesheet(f"QTextEdit {{ font-size: {self.value}px }};")
|
|
493
492
|
event.accept()
|
|
494
493
|
else:
|
|
495
494
|
super(TextareaField, self).wheelEvent(event)
|
pygpt_net/ui/__init__.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.08.20 20:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
@@ -89,12 +89,6 @@ class UI:
|
|
|
89
89
|
self.splitters['main'].addWidget(self.parts['chat']) # chat box
|
|
90
90
|
self.splitters['main'].addWidget(self.parts['toolbox']) # toolbox
|
|
91
91
|
|
|
92
|
-
# FIRST RUN: initial sizes if not set yet
|
|
93
|
-
if not self.window.core.config.has("layout.splitters") \
|
|
94
|
-
or self.window.core.config.get("layout.splitters") == {}\
|
|
95
|
-
or self.window.core.config.get("license.accepted") == False:
|
|
96
|
-
self.set_initial_size()
|
|
97
|
-
|
|
98
92
|
# menus
|
|
99
93
|
self.menus.setup()
|
|
100
94
|
|
|
@@ -107,6 +101,14 @@ class UI:
|
|
|
107
101
|
# set window title
|
|
108
102
|
self.update_title()
|
|
109
103
|
|
|
104
|
+
def on_show(self):
|
|
105
|
+
"""Called after MainWindow onShow() event"""
|
|
106
|
+
# FIRST RUN: initial sizes if not set yet
|
|
107
|
+
if not self.window.core.config.has("layout.splitters") \
|
|
108
|
+
or self.window.core.config.get("layout.splitters") == {} \
|
|
109
|
+
or self.window.core.config.get("license.accepted") == False:
|
|
110
|
+
self.set_initial_size()
|
|
111
|
+
|
|
110
112
|
def set_initial_size(self):
|
|
111
113
|
"""Set default sizes"""
|
|
112
114
|
def set_initial_splitter_height():
|
|
@@ -118,19 +120,19 @@ class UI:
|
|
|
118
120
|
self.window.ui.splitters['main.output'].setSizes([size_output, size_input])
|
|
119
121
|
else:
|
|
120
122
|
QTimer.singleShot(0, set_initial_splitter_height)
|
|
121
|
-
QTimer.singleShot(
|
|
123
|
+
QTimer.singleShot(10, set_initial_splitter_height)
|
|
122
124
|
|
|
123
125
|
def set_initial_splitter_width():
|
|
124
126
|
"""Set initial splitter width"""
|
|
125
127
|
total_width = self.window.ui.splitters['main'].size().width()
|
|
126
128
|
if total_width > 0:
|
|
127
|
-
size_output = int(total_width * 0.
|
|
129
|
+
size_output = int(total_width * 0.75)
|
|
128
130
|
size_ctx = (total_width - size_output) / 2
|
|
129
131
|
size_toolbox = (total_width - size_output) / 2
|
|
130
132
|
self.window.ui.splitters['main'].setSizes([size_ctx, size_output, size_toolbox])
|
|
131
133
|
else:
|
|
132
134
|
QTimer.singleShot(0, set_initial_splitter_width)
|
|
133
|
-
QTimer.singleShot(
|
|
135
|
+
QTimer.singleShot(10, set_initial_splitter_width)
|
|
134
136
|
|
|
135
137
|
def update_title(self):
|
|
136
138
|
"""Update window title"""
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt
|
|
13
13
|
from PySide6.QtWidgets import QHBoxLayout, QLabel, QVBoxLayout, QSizePolicy, QWidget, QFrame
|
|
14
|
+
from PySide6.QtGui import QFont
|
|
14
15
|
|
|
15
16
|
from pygpt_net.ui.widget.element.labels import TitleLabel, UrlLabel
|
|
16
17
|
from pygpt_net.ui.widget.option.checkbox import OptionCheckbox
|
|
@@ -57,7 +58,9 @@ class BaseConfigDialog:
|
|
|
57
58
|
if slider and t in ('int', 'float'):
|
|
58
59
|
widgets[key] = OptionSlider(self.window, id, key, option)
|
|
59
60
|
else:
|
|
60
|
-
widgets[key] = PasswordInput(self.window, id, key, option) if secret else OptionInput(self.window,
|
|
61
|
+
widgets[key] = PasswordInput(self.window, id, key, option) if secret else OptionInput(self.window,
|
|
62
|
+
id, key,
|
|
63
|
+
option)
|
|
61
64
|
|
|
62
65
|
elif t == 'textarea':
|
|
63
66
|
w = OptionTextarea(self.window, id, key, option)
|
|
@@ -99,20 +102,21 @@ class BaseConfigDialog:
|
|
|
99
102
|
label = option['label']
|
|
100
103
|
desc = option.get('description')
|
|
101
104
|
extra = option.get('extra') or {}
|
|
102
|
-
label_key = label
|
|
105
|
+
label_key = f'{label}.label'
|
|
103
106
|
nodes = self.window.ui.nodes
|
|
104
107
|
|
|
108
|
+
txt = trans(label)
|
|
105
109
|
if extra.get('bold'):
|
|
106
|
-
nodes[label_key] = TitleLabel(
|
|
110
|
+
nodes[label_key] = TitleLabel(txt)
|
|
107
111
|
else:
|
|
108
|
-
nodes[label_key] = QLabel(
|
|
112
|
+
nodes[label_key] = QLabel(txt)
|
|
109
113
|
nodes[label_key].setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
|
|
110
114
|
nodes[label_key].setMinimumWidth(120)
|
|
111
115
|
nodes[label_key].setWordWrap(True)
|
|
112
116
|
|
|
113
117
|
desc_key = None
|
|
114
118
|
if desc is not None:
|
|
115
|
-
desc_key = label
|
|
119
|
+
desc_key = f'{label}.desc'
|
|
116
120
|
nodes[desc_key] = self.add_description(desc)
|
|
117
121
|
|
|
118
122
|
if option.get('type') == 'textarea':
|
|
@@ -142,21 +146,22 @@ class BaseConfigDialog:
|
|
|
142
146
|
:return: QHBoxLayout
|
|
143
147
|
"""
|
|
144
148
|
label = option['label']
|
|
145
|
-
label_key = label
|
|
149
|
+
label_key = f'{label}.label'
|
|
146
150
|
desc = option.get('description')
|
|
147
151
|
extra = option.get('extra') or {}
|
|
148
152
|
nodes = self.window.ui.nodes
|
|
149
153
|
|
|
154
|
+
txt = trans(label)
|
|
150
155
|
if extra.get('bold'):
|
|
151
|
-
nodes[label_key] = TitleLabel(
|
|
156
|
+
nodes[label_key] = TitleLabel(txt)
|
|
152
157
|
else:
|
|
153
|
-
nodes[label_key] = QLabel(
|
|
158
|
+
nodes[label_key] = QLabel(txt)
|
|
154
159
|
nodes[label_key].setMinimumHeight(30)
|
|
155
160
|
nodes[label_key].setWordWrap(True)
|
|
156
161
|
|
|
157
162
|
desc_key = None
|
|
158
163
|
if desc is not None:
|
|
159
|
-
desc_key = label
|
|
164
|
+
desc_key = f'{label}.desc'
|
|
160
165
|
nodes[desc_key] = self.add_description(desc)
|
|
161
166
|
|
|
162
167
|
layout = QVBoxLayout()
|
|
@@ -191,7 +196,7 @@ class BaseConfigDialog:
|
|
|
191
196
|
|
|
192
197
|
desc_key = None
|
|
193
198
|
if desc is not None:
|
|
194
|
-
desc_key = label
|
|
199
|
+
desc_key = f'{label}.desc'
|
|
195
200
|
nodes[desc_key] = self.add_description(desc)
|
|
196
201
|
|
|
197
202
|
urls = extra.get('urls')
|
pygpt_net/ui/dialog/about.py
CHANGED
|
@@ -114,18 +114,22 @@ class About:
|
|
|
114
114
|
pixmap = QPixmap(path)
|
|
115
115
|
logo_label.setPixmap(pixmap)
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
btn_web = QPushButton(QIcon(":/icons/home.svg"), trans('about.btn.website'))
|
|
118
|
+
btn_web.clicked.connect(lambda: self.window.controller.dialogs.info.goto_website())
|
|
119
|
+
btn_web.setCursor(Qt.PointingHandCursor)
|
|
120
|
+
btn_web.setStyleSheet("font-size: 11px;")
|
|
121
|
+
self.window.ui.nodes['dialog.about.btn.website'] = btn_web
|
|
121
122
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
btn_git = QPushButton(QIcon(":/icons/code.svg"), trans('about.btn.github'))
|
|
124
|
+
btn_git.clicked.connect(lambda: self.window.controller.dialogs.info.goto_github())
|
|
125
|
+
btn_git.setCursor(Qt.PointingHandCursor)
|
|
126
|
+
self.window.ui.nodes['dialog.about.btn.github'] = btn_git
|
|
125
127
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
self.window.
|
|
128
|
+
|
|
129
|
+
btn_support = QPushButton(QIcon(":/icons/favorite.svg"), trans('about.btn.support'))
|
|
130
|
+
btn_support.clicked.connect(lambda: self.window.controller.dialogs.info.goto_donate())
|
|
131
|
+
btn_support.setCursor(Qt.PointingHandCursor)
|
|
132
|
+
self.window.ui.nodes['dialog.about.btn.support'] = btn_support
|
|
129
133
|
|
|
130
134
|
buttons_layout = QHBoxLayout()
|
|
131
135
|
buttons_layout.addWidget(self.window.ui.nodes['dialog.about.btn.support'])
|
|
@@ -133,10 +137,13 @@ class About:
|
|
|
133
137
|
buttons_layout.addWidget(self.window.ui.nodes['dialog.about.btn.github'])
|
|
134
138
|
|
|
135
139
|
string = self.prepare_content()
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
self.window.ui.nodes['dialog.about.
|
|
139
|
-
|
|
140
|
+
content = QLabel(string)
|
|
141
|
+
content.setTextInteractionFlags(Qt.TextSelectableByMouse)
|
|
142
|
+
self.window.ui.nodes['dialog.about.content'] = content
|
|
143
|
+
|
|
144
|
+
thanks = QLabel(trans('about.thanks'))
|
|
145
|
+
thanks.setAlignment(Qt.AlignCenter)
|
|
146
|
+
self.window.ui.nodes['dialog.about.thanks'] = thanks
|
|
140
147
|
|
|
141
148
|
title = QLabel("PyGPT")
|
|
142
149
|
title.setContentsMargins(0, 0, 0, 0)
|
|
@@ -150,10 +157,11 @@ class About:
|
|
|
150
157
|
)
|
|
151
158
|
title.setAlignment(Qt.AlignCenter)
|
|
152
159
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
160
|
+
thanks_content = QPlainTextEdit()
|
|
161
|
+
thanks_content.setReadOnly(True)
|
|
162
|
+
thanks_content.setPlainText("")
|
|
163
|
+
thanks_content.setStyleSheet("font-size: 11px;")
|
|
164
|
+
self.window.ui.nodes['dialog.about.thanks.content'] = thanks_content
|
|
157
165
|
|
|
158
166
|
layout = QVBoxLayout()
|
|
159
167
|
layout.addWidget(logo_label)
|
pygpt_net/ui/dialog/plugins.py
CHANGED
|
@@ -76,12 +76,14 @@ class Plugins:
|
|
|
76
76
|
self.window.ui.tabs['plugin.settings'] = QTabWidget()
|
|
77
77
|
self.window.ui.tabs['plugin.settings.tabs'] = {}
|
|
78
78
|
|
|
79
|
+
sorted_ids = self.window.core.plugins.get_ids(sort=True)
|
|
80
|
+
|
|
79
81
|
# build plugin settings tabs
|
|
80
|
-
for id in
|
|
82
|
+
for id in sorted_ids:
|
|
81
83
|
content_tabs = {}
|
|
82
84
|
scroll_tabs = {}
|
|
83
85
|
|
|
84
|
-
plugin = self.window.core.plugins.
|
|
86
|
+
plugin = self.window.core.plugins.get(id)
|
|
85
87
|
parent_id = "plugin." + id
|
|
86
88
|
|
|
87
89
|
# create plugin options entry if not exists
|
|
@@ -231,8 +233,8 @@ class Plugins:
|
|
|
231
233
|
)
|
|
232
234
|
|
|
233
235
|
data = {}
|
|
234
|
-
for plugin_id in
|
|
235
|
-
plugin = self.window.core.plugins.
|
|
236
|
+
for plugin_id in sorted_ids:
|
|
237
|
+
plugin = self.window.core.plugins.get(plugin_id)
|
|
236
238
|
data[plugin_id] = plugin
|
|
237
239
|
|
|
238
240
|
# plugins list
|
pygpt_net/ui/dialog/settings.py
CHANGED
|
@@ -65,6 +65,7 @@ class Settings(BaseConfigDialog):
|
|
|
65
65
|
|
|
66
66
|
# settings section tabs
|
|
67
67
|
self.window.ui.tabs['settings.section'] = QTabWidget()
|
|
68
|
+
options_get = self.window.controller.settings.editor.get_options
|
|
68
69
|
|
|
69
70
|
# build settings tabs
|
|
70
71
|
for section_id in sections:
|
|
@@ -74,21 +75,26 @@ class Settings(BaseConfigDialog):
|
|
|
74
75
|
first_tab = "general"
|
|
75
76
|
|
|
76
77
|
# get settings options for section
|
|
77
|
-
fields =
|
|
78
|
+
fields = options_get(section_id)
|
|
78
79
|
is_general = False
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
|
|
81
|
+
tab_by_key = {}
|
|
82
|
+
for key, field in fields.items():
|
|
83
|
+
if 'tab' in field:
|
|
84
|
+
tab = field['tab']
|
|
82
85
|
if tab is not None:
|
|
83
86
|
if first_tab == "general":
|
|
84
87
|
first_tab = tab
|
|
85
|
-
if tab.lower() == "general":
|
|
88
|
+
if isinstance(tab, str) and tab.lower() == "general":
|
|
86
89
|
is_general = True
|
|
87
|
-
break
|
|
88
90
|
else:
|
|
89
91
|
is_general = True
|
|
90
|
-
break
|
|
91
92
|
|
|
93
|
+
tab_id = field['tab'] if field.get('tab') not in (None, "") else "general"
|
|
94
|
+
tab_by_key[key] = tab_id
|
|
95
|
+
|
|
96
|
+
if field.get('advanced'):
|
|
97
|
+
advanced_keys.setdefault(tab_id, []).append(key)
|
|
92
98
|
|
|
93
99
|
# extract tab ids, general is default
|
|
94
100
|
tab_ids = self.extract_option_tabs(fields)
|
|
@@ -97,109 +103,85 @@ class Settings(BaseConfigDialog):
|
|
|
97
103
|
tab_ids += extra_tabs
|
|
98
104
|
for tab_id in tab_ids:
|
|
99
105
|
content_tabs[tab_id] = QVBoxLayout()
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
# prepare advanced options keys
|
|
104
|
-
for key in fields:
|
|
105
|
-
if 'advanced' in fields[key] and fields[key]['advanced']:
|
|
106
|
-
tab_id = "general"
|
|
107
|
-
if 'tab' in fields[key]:
|
|
108
|
-
tab = fields[key]['tab']
|
|
109
|
-
if tab is not None and tab != "":
|
|
110
|
-
tab_id = tab
|
|
111
|
-
if tab_id not in advanced_keys:
|
|
112
|
-
advanced_keys[tab_id] = []
|
|
113
|
-
advanced_keys[tab_id].append(key)
|
|
106
|
+
s = QScrollArea()
|
|
107
|
+
s.setWidgetResizable(True)
|
|
108
|
+
scroll_tabs[tab_id] = s
|
|
114
109
|
|
|
115
110
|
# build settings widgets
|
|
116
111
|
widgets = self.build_widgets(self.id, fields)
|
|
117
112
|
|
|
118
113
|
# apply settings widgets
|
|
119
|
-
|
|
120
|
-
self.window.ui.config[self.id][key] = widgets[key]
|
|
114
|
+
self.window.ui.config[self.id].update(widgets)
|
|
121
115
|
|
|
122
116
|
# apply widgets to layouts
|
|
123
117
|
options = {}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
118
|
+
add_option = self.add_option
|
|
119
|
+
add_row_option = self.add_row_option
|
|
120
|
+
add_raw_option = self.add_raw_option
|
|
121
|
+
register_dictionary = self.window.ui.dialogs.register_dictionary
|
|
122
|
+
|
|
123
|
+
for key, widget in widgets.items():
|
|
124
|
+
f = fields[key]
|
|
125
|
+
t = f['type']
|
|
126
|
+
if t in ('text', 'int', 'float', 'combo', 'bool_list'):
|
|
127
|
+
options[key] = add_option(widget, f)
|
|
128
|
+
elif t in ('textarea', 'dict'):
|
|
129
|
+
options[key] = add_row_option(widget, f)
|
|
130
|
+
if t == 'dict':
|
|
131
|
+
# register dict to editor:
|
|
132
|
+
register_dictionary(
|
|
133
|
+
key,
|
|
134
|
+
parent="config",
|
|
135
|
+
option=f,
|
|
136
|
+
)
|
|
137
|
+
elif t == 'bool':
|
|
138
|
+
options[key] = add_raw_option(widget, f)
|
|
139
|
+
|
|
140
|
+
# self.window.ui.nodes['settings.api_key.label'].setMinimumHeight(60)
|
|
145
141
|
|
|
146
142
|
# append widgets options layouts to scroll area
|
|
147
|
-
for
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if tab is not None and tab != "":
|
|
153
|
-
tab_id = tab
|
|
143
|
+
advanced_membership = {tid: set(keys) for tid, keys in advanced_keys.items()}
|
|
144
|
+
last_option_key = next(reversed(options)) if options else None
|
|
145
|
+
|
|
146
|
+
for key, option in options.items():
|
|
147
|
+
tab_id = tab_by_key.get(key, "general")
|
|
154
148
|
|
|
155
149
|
# hide advanced options
|
|
156
|
-
if tab_id in
|
|
150
|
+
if tab_id in advanced_membership and key in advanced_membership[tab_id]:
|
|
157
151
|
continue
|
|
158
152
|
|
|
159
|
-
content_tabs[tab_id].addLayout(option)
|
|
153
|
+
content_tabs[tab_id].addLayout(option)
|
|
160
154
|
|
|
161
155
|
# append URLs
|
|
162
156
|
if 'urls' in fields[key]:
|
|
163
157
|
content_tabs[tab_id].addWidget(self.add_urls(fields[key]['urls']))
|
|
164
158
|
|
|
165
159
|
# check if not last option
|
|
166
|
-
if key !=
|
|
160
|
+
if key != last_option_key or tab_id in advanced_keys:
|
|
167
161
|
content_tabs[tab_id].addWidget(self.add_line())
|
|
168
162
|
|
|
169
163
|
# append advanced options at the end
|
|
170
164
|
if len(advanced_keys) > 0:
|
|
171
165
|
groups = {}
|
|
172
|
-
for
|
|
173
|
-
|
|
174
|
-
if 'tab' in fields[key]:
|
|
175
|
-
tab = fields[key]['tab']
|
|
176
|
-
if tab is not None and tab != "":
|
|
177
|
-
tab_id = tab
|
|
178
|
-
|
|
179
|
-
if tab_id not in advanced_keys:
|
|
180
|
-
continue
|
|
181
|
-
|
|
182
|
-
# ignore non-advanced options
|
|
183
|
-
if key not in advanced_keys[tab_id]:
|
|
166
|
+
for tab_id, adv_list in advanced_keys.items():
|
|
167
|
+
if not adv_list:
|
|
184
168
|
continue
|
|
185
169
|
|
|
186
170
|
group_id = 'settings.advanced.' + section_id + '.' + tab_id
|
|
171
|
+
groups[tab_id] = CollapsedGroup(self.window, group_id, None, False, None)
|
|
172
|
+
groups[tab_id].box.setText(trans('settings.advanced.collapse'))
|
|
187
173
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
groups[tab_id].
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
# add line if not last option
|
|
195
|
-
if key != advanced_keys[tab_id][-1]:
|
|
196
|
-
groups[tab_id].add_widget(self.add_line())
|
|
174
|
+
last_idx = len(adv_list) - 1
|
|
175
|
+
for idx, key in enumerate(adv_list):
|
|
176
|
+
groups[tab_id].add_layout(options[key])
|
|
177
|
+
if idx != last_idx:
|
|
178
|
+
groups[tab_id].add_widget(self.add_line())
|
|
197
179
|
|
|
198
180
|
# add advanced options group to scrolls
|
|
199
|
-
for tab_id in groups:
|
|
181
|
+
for tab_id, group in groups.items():
|
|
200
182
|
group_id = 'settings.advanced.' + section_id + '.' + tab_id
|
|
201
|
-
content_tabs[tab_id].addWidget(
|
|
202
|
-
self.window.ui.groups[group_id] =
|
|
183
|
+
content_tabs[tab_id].addWidget(group)
|
|
184
|
+
self.window.ui.groups[group_id] = group
|
|
203
185
|
|
|
204
186
|
# add extra features buttons
|
|
205
187
|
self.append_extra(content_tabs, section_id, options, fields)
|
|
@@ -214,10 +196,10 @@ class Settings(BaseConfigDialog):
|
|
|
214
196
|
tab_widget = QTabWidget()
|
|
215
197
|
|
|
216
198
|
# sort to make general tab first if exists
|
|
217
|
-
|
|
218
|
-
|
|
199
|
+
tab_order = (["general"] + [tid for tid in content_tabs if
|
|
200
|
+
tid != "general"]) if "general" in content_tabs else list(content_tabs)
|
|
219
201
|
|
|
220
|
-
for tab_id in
|
|
202
|
+
for tab_id in tab_order:
|
|
221
203
|
if tab_id == "general":
|
|
222
204
|
name_key = trans("settings.section.tab.general")
|
|
223
205
|
else:
|
|
@@ -315,21 +297,27 @@ class Settings(BaseConfigDialog):
|
|
|
315
297
|
:return: list with keys
|
|
316
298
|
"""
|
|
317
299
|
keys = []
|
|
300
|
+
seen = set()
|
|
318
301
|
is_default = False
|
|
319
|
-
|
|
320
|
-
|
|
302
|
+
|
|
303
|
+
for option in options.values():
|
|
321
304
|
if 'tab' in option:
|
|
322
305
|
tab = option['tab']
|
|
323
306
|
if tab == "" or tab is None:
|
|
324
307
|
is_default = True
|
|
325
|
-
|
|
326
|
-
|
|
308
|
+
try:
|
|
309
|
+
if tab not in seen:
|
|
310
|
+
seen.add(tab)
|
|
311
|
+
keys.append(tab)
|
|
312
|
+
except TypeError:
|
|
313
|
+
if tab not in keys:
|
|
314
|
+
keys.append(tab)
|
|
327
315
|
else:
|
|
328
316
|
is_default = True
|
|
329
317
|
|
|
330
|
-
|
|
331
|
-
if len(keys) == 0 or (is_default and "general" not in keys):
|
|
318
|
+
if not keys or (is_default and "general" not in keys):
|
|
332
319
|
keys.append("general")
|
|
320
|
+
|
|
333
321
|
return keys
|
|
334
322
|
|
|
335
323
|
def append_extra(self, content: dict, section_id: str, widgets: dict, options: dict):
|