pygpt-net 2.4.42__py3-none-any.whl → 2.4.44__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.
- CHANGELOG.md +11 -0
- README.md +17 -2
- pygpt_net/CHANGELOG.txt +11 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/attachment.py +31 -3
- pygpt_net/controller/chat/attachment.py +37 -36
- pygpt_net/controller/config/placeholder.py +6 -4
- pygpt_net/controller/idx/common.py +7 -3
- pygpt_net/core/attachments/__init__.py +7 -2
- pygpt_net/core/attachments/context.py +52 -34
- pygpt_net/core/db/__init__.py +2 -1
- pygpt_net/core/debug/attachments.py +1 -0
- pygpt_net/core/idx/__init__.py +8 -3
- pygpt_net/core/idx/indexing.py +24 -7
- pygpt_net/core/idx/ui/__init__.py +22 -0
- pygpt_net/core/idx/ui/loaders.py +217 -0
- pygpt_net/data/config/config.json +4 -4
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/modes.json +3 -3
- pygpt_net/data/config/settings.json +5 -5
- pygpt_net/data/locale/locale.de.ini +3 -3
- pygpt_net/data/locale/locale.en.ini +11 -9
- pygpt_net/data/locale/locale.es.ini +3 -3
- pygpt_net/data/locale/locale.fr.ini +3 -3
- pygpt_net/data/locale/locale.it.ini +3 -3
- pygpt_net/data/locale/locale.pl.ini +3 -3
- pygpt_net/data/locale/locale.uk.ini +3 -3
- pygpt_net/data/locale/locale.zh.ini +3 -3
- pygpt_net/data/locale/plugin.mailer.en.ini +5 -5
- pygpt_net/item/attachment.py +5 -1
- pygpt_net/item/ctx.py +99 -2
- pygpt_net/migrations/Version20241215110000.py +25 -0
- pygpt_net/migrations/__init__.py +3 -1
- pygpt_net/plugin/cmd_files/__init__.py +3 -2
- pygpt_net/provider/core/attachment/json_file.py +4 -1
- pygpt_net/provider/core/config/patch.py +6 -0
- pygpt_net/provider/core/ctx/db_sqlite/storage.py +50 -7
- pygpt_net/provider/core/ctx/db_sqlite/utils.py +29 -5
- pygpt_net/provider/loaders/base.py +14 -0
- pygpt_net/provider/loaders/hub/yt/base.py +5 -0
- pygpt_net/provider/loaders/web_database.py +13 -5
- pygpt_net/provider/loaders/web_github_issues.py +5 -1
- pygpt_net/provider/loaders/web_google_calendar.py +9 -1
- pygpt_net/provider/loaders/web_google_docs.py +6 -1
- pygpt_net/provider/loaders/web_google_drive.py +10 -1
- pygpt_net/provider/loaders/web_google_gmail.py +2 -1
- pygpt_net/provider/loaders/web_google_keep.py +5 -1
- pygpt_net/provider/loaders/web_google_sheets.py +5 -1
- pygpt_net/provider/loaders/web_microsoft_onedrive.py +15 -1
- pygpt_net/provider/loaders/web_page.py +4 -2
- pygpt_net/provider/loaders/web_rss.py +2 -1
- pygpt_net/provider/loaders/web_sitemap.py +2 -1
- pygpt_net/provider/loaders/web_twitter.py +4 -2
- pygpt_net/provider/loaders/web_yt.py +17 -2
- pygpt_net/provider/vector_stores/ctx_attachment.py +1 -1
- pygpt_net/tools/indexer/__init__.py +8 -40
- pygpt_net/tools/indexer/ui/web.py +20 -78
- pygpt_net/ui/layout/ctx/ctx_list.py +86 -18
- pygpt_net/ui/widget/dialog/url.py +151 -14
- pygpt_net/ui/widget/element/group.py +15 -2
- pygpt_net/ui/widget/lists/context.py +23 -9
- pygpt_net/utils.py +1 -1
- {pygpt_net-2.4.42.dist-info → pygpt_net-2.4.44.dist-info}/METADATA +18 -3
- {pygpt_net-2.4.42.dist-info → pygpt_net-2.4.44.dist-info}/RECORD +67 -64
- {pygpt_net-2.4.42.dist-info → pygpt_net-2.4.44.dist-info}/LICENSE +0 -0
- {pygpt_net-2.4.42.dist-info → pygpt_net-2.4.44.dist-info}/WHEEL +0 -0
- {pygpt_net-2.4.42.dist-info → pygpt_net-2.4.44.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: 2024.12.
|
9
|
+
# Updated Date: 2024.12.16 01:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import datetime
|
@@ -311,48 +311,16 @@ class IndexerTool(BaseTool):
|
|
311
311
|
|
312
312
|
:param force: force indexing
|
313
313
|
"""
|
314
|
-
input_params =
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
314
|
+
result, loader, input_params, input_config = self.window.core.idx.ui.loaders.handle_options(
|
315
|
+
self.window.ui.nodes["tool.indexer.web.loader"],
|
316
|
+
"tool.indexer.web.loader.option",
|
317
|
+
"tool.indexer.web.loader.config",
|
318
|
+
)
|
319
|
+
if not result:
|
319
320
|
self.window.ui.dialogs.alert(trans("tool.indexer.alert.no_loader"))
|
320
321
|
return
|
321
|
-
loaders = self.window.core.idx.indexing.get_external_instructions()
|
322
|
-
if loader in loaders:
|
323
|
-
params = loaders[loader]
|
324
|
-
for k in params["args"]:
|
325
|
-
key_path = "tool.indexer.web.loader.option." + loader + "." + k
|
326
|
-
if key_path in self.window.ui.nodes:
|
327
|
-
input_params[k] = self.window.ui.nodes[key_path].text()
|
328
322
|
|
329
|
-
|
330
|
-
if loader in loaders:
|
331
|
-
params = loaders[loader]
|
332
|
-
for k in params:
|
333
|
-
key_path = "tool.indexer.web.loader.config." + loader + "." + k
|
334
|
-
type = params[k]["type"]
|
335
|
-
if key_path in self.window.ui.nodes:
|
336
|
-
tmp_value = self.window.ui.nodes[key_path].text()
|
337
|
-
try:
|
338
|
-
if tmp_value:
|
339
|
-
if type == "int":
|
340
|
-
tmp_value = int(tmp_value)
|
341
|
-
elif type == "float":
|
342
|
-
tmp_value = float(tmp_value)
|
343
|
-
elif type == "bool":
|
344
|
-
if tmp_value.lower() in ["true", "1"]:
|
345
|
-
tmp_value = True
|
346
|
-
else:
|
347
|
-
tmp_value = False
|
348
|
-
elif type == "list":
|
349
|
-
tmp_value = tmp_value.split(",")
|
350
|
-
elif type == "dict":
|
351
|
-
tmp_value = json.loads(tmp_value)
|
352
|
-
input_config[k] = tmp_value
|
353
|
-
except Exception as e:
|
354
|
-
self.window.core.debug.log(e)
|
355
|
-
self.window.ui.dialogs.alert(e)
|
323
|
+
is_replace = self.window.ui.nodes["tool.indexer.web.options.replace"].isChecked()
|
356
324
|
if not force:
|
357
325
|
self.window.ui.dialogs.confirm(
|
358
326
|
type="idx.tool.index",
|
@@ -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.
|
9
|
+
# Updated Date: 2024.12.16 01:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import json
|
@@ -15,6 +15,7 @@ from PySide6.QtCore import Qt
|
|
15
15
|
from PySide6.QtWidgets import QLabel, QVBoxLayout, QWidget, QCheckBox, QHBoxLayout, QScrollArea, \
|
16
16
|
QSizePolicy
|
17
17
|
|
18
|
+
from pygpt_net.ui.widget.element.group import QVLine, QHLine
|
18
19
|
from pygpt_net.ui.widget.element.labels import HelpLabel, UrlLabel
|
19
20
|
from pygpt_net.ui.widget.option.combo import OptionCombo
|
20
21
|
from pygpt_net.ui.widget.option.input import OptionInput
|
@@ -33,15 +34,17 @@ class WebTab:
|
|
33
34
|
self.params_widget = None
|
34
35
|
|
35
36
|
def setup(self):
|
36
|
-
"""
|
37
|
-
Setup tab widget
|
38
|
-
"""
|
37
|
+
"""Setup tab widget"""
|
39
38
|
# get loaders list
|
40
39
|
loaders = self.window.controller.config.placeholder.apply_by_id("llama_index_loaders_web")
|
41
40
|
loaders_list = []
|
42
41
|
for loader in loaders:
|
43
|
-
|
44
|
-
|
42
|
+
k = list(loader.keys())[0]
|
43
|
+
key = k.replace("web_", "")
|
44
|
+
value = loader[k]
|
45
|
+
loaders_list.append({
|
46
|
+
key: value,
|
47
|
+
})
|
45
48
|
|
46
49
|
self.window.ui.nodes["tool.indexer.web.loader"] = OptionCombo(
|
47
50
|
self.window,
|
@@ -55,14 +58,14 @@ class WebTab:
|
|
55
58
|
)
|
56
59
|
|
57
60
|
self.window.ui.nodes["tool.indexer.web.loader"].layout.setContentsMargins(0, 0, 0, 0)
|
58
|
-
self.window.ui.nodes["tool.indexer.web.loader.label"] =
|
61
|
+
self.window.ui.nodes["tool.indexer.web.loader.label"] = HelpLabel(trans("tool.indexer.tab.web.loader"))
|
59
62
|
self.window.ui.add_hook("update.tool.indexer.web.loader", self.hook_loader_change)
|
60
63
|
|
61
64
|
self.window.ui.nodes["tool.indexer.web.options.label"] = HelpLabel(trans("tool.indexer.tab.web.source"))
|
62
65
|
self.window.ui.nodes["tool.indexer.web.config.label"] = HelpLabel(trans("tool.indexer.tab.web.cfg"))
|
63
66
|
self.window.ui.nodes["tool.indexer.web.config.help"] = UrlLabel(
|
64
67
|
trans("tool.indexer.tab.web.help"),
|
65
|
-
"https://pygpt.readthedocs.io/en/latest/
|
68
|
+
"https://pygpt.readthedocs.io/en/latest/configuration.html#data-loaders")
|
66
69
|
|
67
70
|
# --------------------------------------------------
|
68
71
|
|
@@ -78,7 +81,7 @@ class WebTab:
|
|
78
81
|
|
79
82
|
# params
|
80
83
|
params_layout.addWidget(self.window.ui.nodes["tool.indexer.web.options.label"])
|
81
|
-
inputs, groups = self.setup_loader_options()
|
84
|
+
inputs, groups = self.window.core.idx.ui.loaders.setup_loader_options()
|
82
85
|
for loader in inputs:
|
83
86
|
for k in inputs[loader]:
|
84
87
|
self.window.ui.nodes["tool.indexer.web.loader.option." + loader + "." + k] = inputs[loader][k]
|
@@ -87,9 +90,13 @@ class WebTab:
|
|
87
90
|
params_layout.addWidget(self.window.ui.nodes["tool.indexer.web.loader.option_group"][loader])
|
88
91
|
self.window.ui.nodes["tool.indexer.web.loader.option_group"][loader].hide() # hide on start
|
89
92
|
|
93
|
+
# separator
|
94
|
+
params_layout.addWidget(QHLine())
|
95
|
+
|
90
96
|
# config
|
91
97
|
params_layout.addWidget(self.window.ui.nodes["tool.indexer.web.config.label"])
|
92
|
-
|
98
|
+
self.window.ui.nodes["tool.indexer.web.config.label"].setAlignment(Qt.AlignCenter)
|
99
|
+
inputs, groups = self.window.core.idx.ui.loaders.setup_loader_config()
|
93
100
|
for loader in inputs:
|
94
101
|
for k in inputs[loader]:
|
95
102
|
self.window.ui.nodes["tool.indexer.web.loader.config." + loader + "." + k] = inputs[loader][k]
|
@@ -99,6 +106,7 @@ class WebTab:
|
|
99
106
|
self.window.ui.nodes["tool.indexer.web.loader.config_group"][loader].hide() # hide on start
|
100
107
|
params_layout.addWidget(self.window.ui.nodes["tool.indexer.web.config.help"], alignment=Qt.AlignCenter)
|
101
108
|
|
109
|
+
# stretch
|
102
110
|
params_layout.addStretch(1)
|
103
111
|
|
104
112
|
self.params_widget = QWidget()
|
@@ -117,9 +125,10 @@ class WebTab:
|
|
117
125
|
|
118
126
|
self.window.ui.nodes["tool.indexer.provider"] = HelpLabel(self.window.core.config.get("llama.idx.storage"))
|
119
127
|
|
120
|
-
loader_layout =
|
128
|
+
loader_layout = QVBoxLayout()
|
121
129
|
loader_layout.addWidget(self.window.ui.nodes["tool.indexer.web.loader.label"])
|
122
130
|
loader_layout.addWidget(self.window.ui.nodes["tool.indexer.web.loader"])
|
131
|
+
loader_layout.setContentsMargins(0, 10, 0, 0)
|
123
132
|
|
124
133
|
options_layout = QVBoxLayout()
|
125
134
|
options_layout.addWidget(self.window.ui.nodes["tool.indexer.web.options.replace"])
|
@@ -177,70 +186,3 @@ class WebTab:
|
|
177
186
|
|
178
187
|
self.params_widget.adjustSize()
|
179
188
|
self.params_scroll.update()
|
180
|
-
|
181
|
-
def setup_loader_options(self):
|
182
|
-
"""
|
183
|
-
Setup loader options
|
184
|
-
"""
|
185
|
-
inputs = {}
|
186
|
-
groups = {}
|
187
|
-
loaders = self.window.core.idx.indexing.get_external_instructions()
|
188
|
-
for loader in loaders:
|
189
|
-
params = loaders[loader]
|
190
|
-
inputs[loader] = {}
|
191
|
-
group = QVBoxLayout()
|
192
|
-
for k in params["args"]:
|
193
|
-
widget = OptionInput(self.window, "tool.indexer", f"web.loader.{loader}.option.{k}", {
|
194
|
-
"label": k,
|
195
|
-
"value": "",
|
196
|
-
})
|
197
|
-
widget.setPlaceholderText(params["args"][k]["type"])
|
198
|
-
inputs[loader][k] = widget
|
199
|
-
row = QHBoxLayout() # cols
|
200
|
-
row.addWidget(QLabel(k))
|
201
|
-
row.addWidget(widget)
|
202
|
-
group.addLayout(row)
|
203
|
-
group_widget = QWidget()
|
204
|
-
group_widget.setLayout(group)
|
205
|
-
groups[loader] = group_widget
|
206
|
-
|
207
|
-
return inputs, groups
|
208
|
-
|
209
|
-
def setup_loader_config(self):
|
210
|
-
"""
|
211
|
-
Setup loader config
|
212
|
-
"""
|
213
|
-
inputs = {}
|
214
|
-
groups = {}
|
215
|
-
loaders = self.window.core.idx.indexing.get_external_config()
|
216
|
-
for loader in loaders:
|
217
|
-
params = loaders[loader]
|
218
|
-
inputs[loader] = {}
|
219
|
-
group = QVBoxLayout()
|
220
|
-
for k in params:
|
221
|
-
widget = OptionInput(self.window, "tool.indexer", f"web.loader.{loader}.config.{k}", {
|
222
|
-
"label": k,
|
223
|
-
"value": params[k]["value"],
|
224
|
-
})
|
225
|
-
try:
|
226
|
-
if params[k]["value"] is not None:
|
227
|
-
if params[k]["type"] == "list" and isinstance(params[k]["value"], list):
|
228
|
-
widget.setText(", ".join(params[k]["value"]))
|
229
|
-
elif params[k]["type"] == "dict" and isinstance(params[k]["value"], dict):
|
230
|
-
widget.setText(json.dumps(params[k]["value"]))
|
231
|
-
else:
|
232
|
-
widget.setText(str(params[k]["value"]))
|
233
|
-
except Exception as e:
|
234
|
-
self.window.core.debug.log(e)
|
235
|
-
|
236
|
-
widget.setPlaceholderText(params[k]["type"])
|
237
|
-
inputs[loader][k] = widget
|
238
|
-
row = QHBoxLayout() # cols
|
239
|
-
row.addWidget(QLabel(k))
|
240
|
-
row.addWidget(widget)
|
241
|
-
group.addLayout(row)
|
242
|
-
group_widget = QWidget()
|
243
|
-
group_widget.setLayout(group)
|
244
|
-
groups[loader] = group_widget
|
245
|
-
|
246
|
-
return inputs, groups
|
@@ -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.12.
|
9
|
+
# Updated Date: 2024.12.16 01:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from PySide6 import QtCore
|
@@ -81,9 +81,11 @@ class CtxList:
|
|
81
81
|
self.window.ui.models[id].removeRows(0, self.window.ui.models[id].rowCount())
|
82
82
|
|
83
83
|
if self.window.core.config.get("ctx.records.folders.top"):
|
84
|
+
self.update_items_pinned(id, data)
|
84
85
|
self.update_groups(id, data)
|
85
86
|
self.update_items(id, data)
|
86
87
|
else:
|
88
|
+
self.update_items_pinned(id, data)
|
87
89
|
self.update_items(id, data)
|
88
90
|
self.update_groups(id, data)
|
89
91
|
|
@@ -96,13 +98,43 @@ class CtxList:
|
|
96
98
|
"""
|
97
99
|
i = 0
|
98
100
|
last_dt_str = None
|
101
|
+
separators = self.window.core.config.get("ctx.records.separators")
|
102
|
+
pinned_separators = self.window.core.config.get("ctx.records.pinned.separators")
|
99
103
|
for meta_id in data:
|
100
104
|
if data[meta_id].group_id is None or data[meta_id].group_id == 0:
|
105
|
+
if data[meta_id].important:
|
106
|
+
continue
|
101
107
|
item = self.build_item(meta_id, data[meta_id], is_group=False)
|
102
|
-
if
|
103
|
-
if not item.isPinned or
|
108
|
+
if separators:
|
109
|
+
if not item.isPinned or pinned_separators:
|
104
110
|
if i == 0 or last_dt_str != item.dt:
|
105
|
-
section = self.build_date_section(item.dt)
|
111
|
+
section = self.build_date_section(item.dt, group=False)
|
112
|
+
if section:
|
113
|
+
self.window.ui.models[id].appendRow(section)
|
114
|
+
last_dt_str = item.dt
|
115
|
+
self.window.ui.models[id].appendRow(item)
|
116
|
+
i += 1
|
117
|
+
|
118
|
+
def update_items_pinned(self, id, data):
|
119
|
+
"""
|
120
|
+
Update items pinned
|
121
|
+
|
122
|
+
:param id: ID of the list
|
123
|
+
:param data: Data to update
|
124
|
+
"""
|
125
|
+
i = 0
|
126
|
+
last_dt_str = None
|
127
|
+
separators = self.window.core.config.get("ctx.records.separators")
|
128
|
+
pinned_separators = self.window.core.config.get("ctx.records.pinned.separators")
|
129
|
+
for meta_id in data:
|
130
|
+
if data[meta_id].group_id is None or data[meta_id].group_id == 0:
|
131
|
+
if not data[meta_id].important:
|
132
|
+
continue
|
133
|
+
item = self.build_item(meta_id, data[meta_id], is_group=False)
|
134
|
+
if separators:
|
135
|
+
if pinned_separators:
|
136
|
+
if i == 0 or last_dt_str != item.dt:
|
137
|
+
section = self.build_date_section(item.dt, group=False)
|
106
138
|
if section:
|
107
139
|
self.window.ui.models[id].appendRow(section)
|
108
140
|
last_dt_str = item.dt
|
@@ -116,21 +148,37 @@ class CtxList:
|
|
116
148
|
:param id: ID of the list
|
117
149
|
:param data: Data to update
|
118
150
|
"""
|
119
|
-
# get groups
|
120
|
-
groups = self.window.core.ctx.get_groups()
|
121
|
-
|
151
|
+
groups = self.window.core.ctx.get_groups() # get groups
|
122
152
|
for group_id in groups:
|
123
153
|
last_dt_str = None
|
124
154
|
group = groups[group_id]
|
125
155
|
c = self.count_in_group(group.id, data)
|
126
|
-
if c == 0 and self.window.core.ctx.get_search_string() is not None
|
156
|
+
if (c == 0 and self.window.core.ctx.get_search_string() is not None
|
157
|
+
and self.window.core.ctx.get_search_string() != ""):
|
127
158
|
continue # skip empty groups when searching
|
128
159
|
|
129
160
|
suffix = ""
|
130
161
|
if c > 0:
|
131
162
|
suffix = " (" + str(c) + ")"
|
163
|
+
is_attachment = group.has_additional_ctx()
|
132
164
|
group_name = group.name + suffix
|
133
165
|
group_item = GroupItem(QIcon(":/icons/folder_filled.svg"), group_name, group.id)
|
166
|
+
group_item.hasAttachments = group.has_additional_ctx()
|
167
|
+
custom_data = {
|
168
|
+
"is_group": True,
|
169
|
+
"is_attachment": is_attachment,
|
170
|
+
}
|
171
|
+
if is_attachment:
|
172
|
+
files = group.get_attachment_names()
|
173
|
+
num = len(files)
|
174
|
+
files_str = ", ".join(files)
|
175
|
+
if len(files_str) > 40:
|
176
|
+
files_str = files_str[:40] + '...'
|
177
|
+
tooltip_str = trans("attachments.ctx.tooltip.list").format(num=num) + ": " + files_str
|
178
|
+
group_item.setToolTip(tooltip_str)
|
179
|
+
|
180
|
+
group_item.setData(custom_data, QtCore.Qt.ItemDataRole.UserRole)
|
181
|
+
|
134
182
|
i = 0
|
135
183
|
for meta_id in data:
|
136
184
|
if data[meta_id].group_id != group.id:
|
@@ -139,7 +187,7 @@ class CtxList:
|
|
139
187
|
if self.window.core.config.get("ctx.records.groups.separators"):
|
140
188
|
if not item.isPinned or self.window.core.config.get("ctx.records.pinned.separators"):
|
141
189
|
if i == 0 or last_dt_str != item.dt:
|
142
|
-
section = self.build_date_section(item.dt)
|
190
|
+
section = self.build_date_section(item.dt, group=True)
|
143
191
|
if section:
|
144
192
|
group_item.appendRow(section)
|
145
193
|
last_dt_str = item.dt
|
@@ -178,6 +226,17 @@ class CtxList:
|
|
178
226
|
:return: Item
|
179
227
|
"""
|
180
228
|
append_dt = True
|
229
|
+
is_important = False
|
230
|
+
is_attachment = False
|
231
|
+
in_group = False
|
232
|
+
label = data.label
|
233
|
+
if data.important:
|
234
|
+
is_important = True
|
235
|
+
if data.has_additional_ctx():
|
236
|
+
is_attachment = True
|
237
|
+
if data.group:
|
238
|
+
in_group = True
|
239
|
+
|
181
240
|
if is_group:
|
182
241
|
if self.window.core.config.get("ctx.records.groups.separators"):
|
183
242
|
append_dt = False
|
@@ -206,35 +265,44 @@ class CtxList:
|
|
206
265
|
mode_str,
|
207
266
|
id,
|
208
267
|
)
|
268
|
+
|
269
|
+
# append attachments to tooltip
|
270
|
+
if is_attachment:
|
271
|
+
files = data.get_attachment_names()
|
272
|
+
num = len(files)
|
273
|
+
files_str = ", ".join(files)
|
274
|
+
if len(files_str) > 40:
|
275
|
+
files_str = files_str[:40] + '...'
|
276
|
+
tooltip_str = trans("attachments.ctx.tooltip.list").format(num=num) + ": " + files_str
|
277
|
+
tooltip_text += "\n" + tooltip_str
|
278
|
+
|
209
279
|
item = Item(name, id)
|
210
280
|
item.id = id
|
211
281
|
item.dt = dt
|
212
282
|
item.isPinned = data.important
|
213
283
|
item.setData(tooltip_text, QtCore.Qt.ToolTipRole)
|
214
|
-
|
215
|
-
is_attachment = False
|
216
|
-
label = data.label
|
217
|
-
if data.important:
|
218
|
-
is_important = True
|
219
|
-
if data.additional_ctx and len(data.additional_ctx) > 0:
|
220
|
-
is_attachment = True
|
284
|
+
|
221
285
|
custom_data = {
|
222
286
|
"label": label,
|
223
287
|
"is_important": is_important,
|
224
288
|
"is_attachment": is_attachment,
|
289
|
+
"in_group": in_group,
|
225
290
|
}
|
226
291
|
item.setData(custom_data, QtCore.Qt.ItemDataRole.UserRole)
|
227
292
|
item.setData(name)
|
228
293
|
return item
|
229
294
|
|
230
|
-
def build_date_section(self, dt: str) -> SectionItem:
|
295
|
+
def build_date_section(self, dt: str, group: bool = False) -> SectionItem:
|
231
296
|
"""
|
232
297
|
Build date section
|
233
298
|
|
234
299
|
:param dt: date section string
|
300
|
+
:param group: is group
|
235
301
|
:return: SectionItem
|
236
302
|
"""
|
237
|
-
|
303
|
+
item = SectionItem(dt, group=group)
|
304
|
+
# item.setToolTip(dt)
|
305
|
+
return item
|
238
306
|
|
239
307
|
def convert_date(self, timestamp: int) -> str:
|
240
308
|
"""
|
@@ -6,12 +6,15 @@
|
|
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.
|
9
|
+
# Updated Date: 2024.12.16 01:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
|
-
from PySide6.
|
12
|
+
from PySide6.QtCore import Qt
|
13
|
+
from PySide6.QtWidgets import QDialog, QLabel, QHBoxLayout, QVBoxLayout, QPushButton, QScrollArea, QWidget, QSizePolicy
|
13
14
|
|
14
|
-
from pygpt_net.ui.widget.element.
|
15
|
+
from pygpt_net.ui.widget.element.group import QHLine
|
16
|
+
from pygpt_net.ui.widget.element.labels import HelpLabel, UrlLabel
|
17
|
+
from pygpt_net.ui.widget.option.combo import OptionCombo
|
15
18
|
from pygpt_net.utils import trans
|
16
19
|
from pygpt_net.ui.widget.textarea.url import UrlInput
|
17
20
|
|
@@ -28,15 +31,19 @@ class UrlDialog(QDialog):
|
|
28
31
|
self.window = window
|
29
32
|
self.id = id
|
30
33
|
self.current = None
|
31
|
-
self.input = UrlInput(window, id)
|
32
|
-
self.input.setMinimumWidth(400)
|
34
|
+
#self.input = UrlInput(window, id)
|
35
|
+
#self.input.setMinimumWidth(400)
|
36
|
+
self.initialized = False
|
37
|
+
self.params_scroll = None
|
38
|
+
|
39
|
+
def init(self):
|
40
|
+
"""Initialize dialog"""
|
41
|
+
if self.initialized:
|
42
|
+
return
|
33
43
|
|
34
44
|
self.window.ui.nodes['dialog.url.btn.update'] = QPushButton(trans('dialog.url.update'))
|
35
45
|
self.window.ui.nodes['dialog.url.btn.update'].clicked.connect(
|
36
|
-
lambda: self.window.controller.
|
37
|
-
self.id,
|
38
|
-
self.window.ui.dialog['url'].current,
|
39
|
-
self.input.text()),
|
46
|
+
lambda: self.window.controller.attachment.attach_url()
|
40
47
|
)
|
41
48
|
|
42
49
|
self.window.ui.nodes['dialog.url.btn.dismiss'] = QPushButton(trans('dialog.url.dismiss'))
|
@@ -47,13 +54,143 @@ class UrlDialog(QDialog):
|
|
47
54
|
bottom.addWidget(self.window.ui.nodes['dialog.url.btn.dismiss'])
|
48
55
|
bottom.addWidget(self.window.ui.nodes['dialog.url.btn.update'])
|
49
56
|
|
50
|
-
self.window.ui.nodes['dialog.url.label'] = QLabel(trans("dialog.url.title"))
|
51
|
-
self.window.ui.nodes['dialog.url.tip'] = HelpLabel(trans("dialog.url.tip"))
|
57
|
+
#self.window.ui.nodes['dialog.url.label'] = QLabel(trans("dialog.url.title"))
|
58
|
+
#self.window.ui.nodes['dialog.url.tip'] = HelpLabel(trans("dialog.url.tip"))
|
59
|
+
|
60
|
+
# -----------------
|
61
|
+
|
62
|
+
loaders = self.window.controller.config.placeholder.apply_by_id("llama_index_loaders_web")
|
63
|
+
loaders_list = []
|
64
|
+
for loader in loaders:
|
65
|
+
k = list(loader.keys())[0]
|
66
|
+
key = k.replace("web_", "")
|
67
|
+
value = loader[k]
|
68
|
+
loaders_list.append({
|
69
|
+
key: value,
|
70
|
+
})
|
71
|
+
|
72
|
+
self.window.ui.nodes["dialog.url.loader"] = OptionCombo(
|
73
|
+
self.window,
|
74
|
+
"dialog.url",
|
75
|
+
"web.loader",
|
76
|
+
{
|
77
|
+
"label": trans("tool.indexer.tab.web.loader"),
|
78
|
+
"keys": loaders_list,
|
79
|
+
"value": "webpage",
|
80
|
+
}
|
81
|
+
)
|
82
|
+
|
83
|
+
self.window.ui.nodes["dialog.url.loader"].layout.setContentsMargins(0, 0, 0, 0)
|
84
|
+
self.window.ui.nodes["dialog.url.loader.label"] = HelpLabel(trans("tool.indexer.tab.web.loader"))
|
85
|
+
self.window.ui.add_hook("update.dialog.url.web.loader", self.hook_loader_change)
|
86
|
+
|
87
|
+
self.window.ui.nodes["dialog.url.options.label"] = HelpLabel(trans("tool.indexer.tab.web.source"))
|
88
|
+
self.window.ui.nodes["dialog.url.config.label"] = HelpLabel(trans("tool.indexer.tab.web.cfg"))
|
89
|
+
self.window.ui.nodes["dialog.url.config.help"] = UrlLabel(
|
90
|
+
trans("tool.indexer.tab.web.help"),
|
91
|
+
"https://pygpt.readthedocs.io/en/latest/configuration.html#data-loaders")
|
92
|
+
|
93
|
+
params_layout = QVBoxLayout()
|
94
|
+
params_layout.setContentsMargins(0, 0, 0, 0)
|
95
|
+
|
96
|
+
self.params_scroll = QScrollArea()
|
97
|
+
self.params_scroll.setWidgetResizable(True)
|
98
|
+
self.window.ui.nodes["dialog.url.loader.option"] = {}
|
99
|
+
self.window.ui.nodes["dialog.url.loader.option_group"] = {}
|
100
|
+
self.window.ui.nodes["dialog.url.loader.config"] = {}
|
101
|
+
self.window.ui.nodes["dialog.url.loader.config_group"] = {}
|
102
|
+
|
103
|
+
# params
|
104
|
+
params_layout.addWidget(self.window.ui.nodes["dialog.url.options.label"])
|
105
|
+
inputs, groups = self.window.core.idx.ui.loaders.setup_loader_options()
|
106
|
+
|
107
|
+
for loader in inputs:
|
108
|
+
for k in inputs[loader]:
|
109
|
+
self.window.ui.nodes["dialog.url.loader.option." + loader + "." + k] = inputs[loader][k]
|
110
|
+
for loader in groups:
|
111
|
+
self.window.ui.nodes["dialog.url.loader.option_group"][loader] = groups[loader]
|
112
|
+
params_layout.addWidget(self.window.ui.nodes["dialog.url.loader.option_group"][loader])
|
113
|
+
self.window.ui.nodes["dialog.url.loader.option_group"][loader].hide() # hide on start
|
114
|
+
|
115
|
+
# separator
|
116
|
+
params_layout.addWidget(QHLine())
|
117
|
+
|
118
|
+
# config
|
119
|
+
params_layout.addWidget(self.window.ui.nodes["dialog.url.config.label"])
|
120
|
+
self.window.ui.nodes["dialog.url.config.label"].setAlignment(Qt.AlignCenter)
|
121
|
+
inputs, groups = self.window.core.idx.ui.loaders.setup_loader_config()
|
122
|
+
|
123
|
+
for loader in inputs:
|
124
|
+
for k in inputs[loader]:
|
125
|
+
self.window.ui.nodes["dialog.url.loader.config." + loader + "." + k] = inputs[loader][k]
|
126
|
+
for loader in groups:
|
127
|
+
self.window.ui.nodes["dialog.url.loader.config_group"][loader] = groups[loader]
|
128
|
+
params_layout.addWidget(self.window.ui.nodes["dialog.url.loader.config_group"][loader])
|
129
|
+
self.window.ui.nodes["dialog.url.loader.config_group"][loader].hide() # hide on start
|
130
|
+
params_layout.addWidget(self.window.ui.nodes["dialog.url.config.help"], alignment=Qt.AlignCenter)
|
131
|
+
|
132
|
+
# stretch
|
133
|
+
params_layout.addStretch(1)
|
134
|
+
|
135
|
+
self.params_widget = QWidget()
|
136
|
+
self.params_widget.setLayout(params_layout)
|
137
|
+
self.params_scroll.setWidget(self.params_widget)
|
138
|
+
|
139
|
+
# resize
|
140
|
+
self.params_scroll.setWidgetResizable(True)
|
141
|
+
self.params_scroll.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
|
142
|
+
|
143
|
+
# -----------------
|
52
144
|
|
53
145
|
layout = QVBoxLayout()
|
54
|
-
layout.addWidget(self.window.ui.nodes['dialog.url.label'])
|
55
|
-
layout.addWidget(self.input)
|
56
|
-
layout.addWidget(self.window.ui.nodes['dialog.url.tip'])
|
146
|
+
#layout.addWidget(self.window.ui.nodes['dialog.url.label'])
|
147
|
+
#layout.addWidget(self.input)
|
148
|
+
#layout.addWidget(self.window.ui.nodes['dialog.url.tip'])
|
149
|
+
layout.addWidget(self.window.ui.nodes['dialog.url.loader.label'])
|
150
|
+
layout.addWidget(self.window.ui.nodes['dialog.url.loader'])
|
151
|
+
layout.addWidget(self.params_scroll)
|
57
152
|
layout.addLayout(bottom)
|
58
153
|
|
154
|
+
# defaults
|
155
|
+
self.window.ui.nodes["dialog.url.loader"].set_value("webpage")
|
156
|
+
|
59
157
|
self.setLayout(layout)
|
158
|
+
|
159
|
+
self.initialized = True
|
160
|
+
|
161
|
+
def hook_loader_change(self, key, value, caller, *args, **kwargs):
|
162
|
+
"""
|
163
|
+
Hook: on loader change
|
164
|
+
|
165
|
+
:param key: Option key
|
166
|
+
:param value: Option value
|
167
|
+
:param caller: Caller
|
168
|
+
:param args: Args
|
169
|
+
:param kwargs: Kwargs
|
170
|
+
"""
|
171
|
+
# hide/show options
|
172
|
+
for loader in self.window.ui.nodes["dialog.url.loader.option_group"]:
|
173
|
+
self.window.ui.nodes["dialog.url.loader.option_group"][loader].hide()
|
174
|
+
if value in self.window.ui.nodes["dialog.url.loader.option_group"]:
|
175
|
+
self.window.ui.nodes["dialog.url.loader.option_group"][value].show()
|
176
|
+
|
177
|
+
# show/hide label if options are available
|
178
|
+
self.window.ui.nodes["dialog.url.options.label"].hide()
|
179
|
+
if value in self.window.ui.nodes["dialog.url.loader.option_group"]:
|
180
|
+
self.window.ui.nodes["dialog.url.options.label"].show()
|
181
|
+
|
182
|
+
# hide/show config
|
183
|
+
for loader in self.window.ui.nodes["dialog.url.loader.config_group"]:
|
184
|
+
self.window.ui.nodes["dialog.url.loader.config_group"][loader].hide()
|
185
|
+
if value in self.window.ui.nodes["dialog.url.loader.config_group"]:
|
186
|
+
self.window.ui.nodes["dialog.url.loader.config_group"][value].show()
|
187
|
+
|
188
|
+
# show/hide label if config are available
|
189
|
+
self.window.ui.nodes["dialog.url.config.label"].hide()
|
190
|
+
self.window.ui.nodes["dialog.url.config.help"].hide()
|
191
|
+
if value in self.window.ui.nodes["dialog.url.loader.config_group"]:
|
192
|
+
self.window.ui.nodes["dialog.url.config.label"].show()
|
193
|
+
self.window.ui.nodes["dialog.url.config.help"].show()
|
194
|
+
|
195
|
+
self.params_widget.adjustSize()
|
196
|
+
self.params_scroll.update()
|
@@ -6,11 +6,12 @@
|
|
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.
|
9
|
+
# Updated Date: 2024.12.16 01:00:00 #
|
10
10
|
# ================================================== #
|
11
|
+
|
11
12
|
from PySide6.QtCore import Qt
|
12
13
|
from PySide6.QtGui import QIcon
|
13
|
-
from PySide6.QtWidgets import QCheckBox, QWidget, QVBoxLayout
|
14
|
+
from PySide6.QtWidgets import QCheckBox, QWidget, QVBoxLayout, QFrame
|
14
15
|
|
15
16
|
import pygpt_net.icons_rc
|
16
17
|
|
@@ -105,3 +106,15 @@ class CollapsedGroup(QWidget):
|
|
105
106
|
:param option: option widget
|
106
107
|
"""
|
107
108
|
self.options.addWidget(option)
|
109
|
+
|
110
|
+
class QHLine(QFrame):
|
111
|
+
def __init__(self):
|
112
|
+
super(QHLine, self).__init__()
|
113
|
+
self.setFrameShape(QFrame.HLine)
|
114
|
+
self.setFrameShadow(QFrame.Sunken)
|
115
|
+
|
116
|
+
class QVLine(QFrame):
|
117
|
+
def __init__(self):
|
118
|
+
super(QVLine, self).__init__()
|
119
|
+
self.setFrameShape(QFrame.VLine)
|
120
|
+
self.setFrameShadow(QFrame.Sunken)
|