pygpt-net 2.4.41__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 +19 -0
- README.md +151 -71
- pygpt_net/CHANGELOG.txt +19 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +3 -1
- pygpt_net/controller/attachment.py +31 -3
- pygpt_net/controller/audio/__init__.py +2 -2
- pygpt_net/controller/camera.py +1 -10
- pygpt_net/controller/chat/attachment.py +37 -36
- pygpt_net/controller/chat/audio.py +2 -2
- pygpt_net/controller/config/placeholder.py +20 -4
- pygpt_net/controller/idx/common.py +7 -3
- pygpt_net/controller/ui/mode.py +16 -21
- pygpt_net/core/attachments/__init__.py +7 -2
- pygpt_net/core/attachments/context.py +52 -34
- pygpt_net/core/audio/__init__.py +4 -1
- pygpt_net/core/audio/whisper.py +37 -0
- pygpt_net/core/bridge/worker.py +2 -2
- pygpt_net/core/db/__init__.py +2 -1
- pygpt_net/core/debug/attachments.py +1 -0
- pygpt_net/core/debug/events.py +22 -10
- pygpt_net/core/debug/tabs.py +6 -3
- pygpt_net/core/history.py +3 -2
- pygpt_net/core/idx/__init__.py +23 -6
- pygpt_net/core/idx/chat.py +15 -5
- pygpt_net/core/idx/indexing.py +47 -14
- pygpt_net/core/idx/ui/__init__.py +22 -0
- pygpt_net/core/idx/ui/loaders.py +217 -0
- pygpt_net/core/installer.py +2 -4
- pygpt_net/core/models.py +62 -17
- pygpt_net/core/modes.py +11 -13
- pygpt_net/core/notepad.py +4 -4
- pygpt_net/core/plugins.py +27 -16
- pygpt_net/core/presets.py +20 -9
- pygpt_net/core/profile.py +11 -3
- pygpt_net/core/render/web/parser.py +3 -1
- pygpt_net/core/settings.py +5 -5
- pygpt_net/core/tabs/tab.py +10 -2
- pygpt_net/core/tokens.py +8 -6
- pygpt_net/core/web/__init__.py +105 -0
- pygpt_net/core/{web.py → web/helpers.py} +93 -67
- 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 +12 -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.cmd_web.en.ini +2 -0
- pygpt_net/data/locale/plugin.mailer.en.ini +21 -0
- pygpt_net/item/attachment.py +5 -1
- pygpt_net/item/ctx.py +111 -3
- pygpt_net/migrations/Version20241215110000.py +25 -0
- pygpt_net/migrations/__init__.py +3 -1
- pygpt_net/plugin/agent/__init__.py +7 -2
- pygpt_net/plugin/audio_output/__init__.py +6 -1
- pygpt_net/plugin/base/plugin.py +58 -26
- pygpt_net/plugin/base/worker.py +20 -17
- pygpt_net/plugin/cmd_files/__init__.py +3 -2
- pygpt_net/plugin/cmd_history/config.py +2 -2
- pygpt_net/plugin/cmd_web/__init__.py +3 -4
- pygpt_net/plugin/cmd_web/config.py +71 -3
- pygpt_net/plugin/cmd_web/websearch.py +20 -12
- pygpt_net/plugin/cmd_web/worker.py +67 -4
- pygpt_net/plugin/idx_llama_index/config.py +3 -3
- pygpt_net/plugin/mailer/__init__.py +123 -0
- pygpt_net/plugin/mailer/config.py +149 -0
- pygpt_net/plugin/mailer/runner.py +285 -0
- pygpt_net/plugin/mailer/worker.py +123 -0
- pygpt_net/provider/agents/base.py +5 -2
- pygpt_net/provider/agents/openai.py +4 -2
- pygpt_net/provider/agents/openai_assistant.py +4 -2
- pygpt_net/provider/agents/planner.py +4 -2
- pygpt_net/provider/agents/react.py +4 -2
- pygpt_net/provider/audio_output/openai_tts.py +5 -11
- pygpt_net/provider/core/assistant/base.py +5 -3
- pygpt_net/provider/core/assistant/json_file.py +8 -5
- pygpt_net/provider/core/assistant_file/base.py +4 -3
- pygpt_net/provider/core/assistant_file/db_sqlite/__init__.py +4 -3
- pygpt_net/provider/core/assistant_file/db_sqlite/storage.py +3 -2
- pygpt_net/provider/core/assistant_store/base.py +6 -4
- pygpt_net/provider/core/assistant_store/db_sqlite/__init__.py +5 -4
- pygpt_net/provider/core/assistant_store/db_sqlite/storage.py +5 -3
- pygpt_net/provider/core/attachment/base.py +5 -3
- pygpt_net/provider/core/attachment/json_file.py +7 -3
- pygpt_net/provider/core/calendar/base.py +5 -3
- pygpt_net/provider/core/calendar/db_sqlite/__init__.py +6 -5
- pygpt_net/provider/core/calendar/db_sqlite/storage.py +5 -4
- pygpt_net/provider/core/config/base.py +8 -6
- pygpt_net/provider/core/config/json_file.py +9 -7
- pygpt_net/provider/core/config/patch.py +6 -0
- pygpt_net/provider/core/ctx/base.py +27 -25
- pygpt_net/provider/core/ctx/db_sqlite/__init__.py +51 -35
- pygpt_net/provider/core/ctx/db_sqlite/storage.py +92 -38
- pygpt_net/provider/core/ctx/db_sqlite/utils.py +37 -11
- pygpt_net/provider/core/index/base.py +129 -23
- pygpt_net/provider/core/index/db_sqlite/__init__.py +130 -23
- pygpt_net/provider/core/index/db_sqlite/storage.py +130 -23
- pygpt_net/provider/core/index/db_sqlite/utils.py +4 -2
- pygpt_net/provider/core/mode/base.py +5 -3
- pygpt_net/provider/core/mode/json_file.py +7 -6
- pygpt_net/provider/core/model/base.py +6 -4
- pygpt_net/provider/core/model/json_file.py +9 -7
- pygpt_net/provider/core/notepad/base.py +5 -3
- pygpt_net/provider/core/notepad/db_sqlite/__init__.py +5 -4
- pygpt_net/provider/core/notepad/db_sqlite/storage.py +4 -3
- pygpt_net/provider/core/plugin_preset/base.py +4 -2
- pygpt_net/provider/core/plugin_preset/json_file.py +5 -3
- pygpt_net/provider/core/preset/base.py +6 -4
- pygpt_net/provider/core/preset/json_file.py +9 -9
- pygpt_net/provider/core/prompt/base.py +6 -3
- pygpt_net/provider/core/prompt/json_file.py +11 -6
- pygpt_net/provider/gpt/assistants.py +15 -6
- pygpt_net/provider/gpt/audio.py +5 -5
- pygpt_net/provider/gpt/chat.py +7 -5
- pygpt_net/provider/gpt/completion.py +8 -4
- pygpt_net/provider/gpt/image.py +3 -3
- pygpt_net/provider/gpt/store.py +46 -12
- pygpt_net/provider/gpt/vision.py +16 -11
- pygpt_net/provider/llms/anthropic.py +7 -2
- pygpt_net/provider/llms/azure_openai.py +26 -5
- pygpt_net/provider/llms/base.py +47 -9
- pygpt_net/provider/llms/google.py +7 -2
- pygpt_net/provider/llms/hugging_face.py +13 -3
- pygpt_net/provider/llms/hugging_face_api.py +18 -4
- pygpt_net/provider/llms/local.py +7 -2
- pygpt_net/provider/llms/ollama.py +30 -6
- pygpt_net/provider/llms/openai.py +32 -6
- 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/__init__.py +45 -14
- pygpt_net/provider/vector_stores/base.py +35 -8
- pygpt_net/provider/vector_stores/chroma.py +13 -3
- pygpt_net/provider/vector_stores/ctx_attachment.py +32 -13
- pygpt_net/provider/vector_stores/elasticsearch.py +12 -3
- pygpt_net/provider/vector_stores/pinecode.py +12 -3
- pygpt_net/provider/vector_stores/redis.py +12 -3
- pygpt_net/provider/vector_stores/simple.py +12 -3
- pygpt_net/provider/vector_stores/temp.py +16 -4
- pygpt_net/provider/web/base.py +10 -3
- pygpt_net/provider/web/google_custom_search.py +9 -3
- pygpt_net/provider/web/microsoft_bing.py +9 -3
- pygpt_net/tools/__init__.py +13 -5
- pygpt_net/tools/audio_transcriber/__init__.py +4 -3
- pygpt_net/tools/base.py +15 -8
- pygpt_net/tools/code_interpreter/__init__.py +4 -3
- pygpt_net/tools/html_canvas/__init__.py +4 -3
- pygpt_net/tools/image_viewer/__init__.py +10 -4
- pygpt_net/tools/indexer/__init__.py +15 -46
- pygpt_net/tools/indexer/ui/web.py +20 -78
- pygpt_net/tools/media_player/__init__.py +4 -3
- pygpt_net/tools/text_editor/__init__.py +36 -10
- pygpt_net/ui/layout/chat/output.py +2 -2
- pygpt_net/ui/layout/ctx/ctx_list.py +86 -18
- pygpt_net/ui/menu/audio.py +12 -1
- 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.41.dist-info → pygpt_net-2.4.44.dist-info}/METADATA +152 -72
- {pygpt_net-2.4.41.dist-info → pygpt_net-2.4.44.dist-info}/RECORD +183 -173
- {pygpt_net-2.4.41.dist-info → pygpt_net-2.4.44.dist-info}/LICENSE +0 -0
- {pygpt_net-2.4.41.dist-info → pygpt_net-2.4.44.dist-info}/WHEEL +0 -0
- {pygpt_net-2.4.41.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
|
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
|
"""
|
pygpt_net/ui/menu/audio.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: 2024.
|
9
|
+
# Updated Date: 2024.12.14 18:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from PySide6.QtGui import QAction, QIcon
|
@@ -52,6 +52,13 @@ class Audio:
|
|
52
52
|
checkable=False,
|
53
53
|
)
|
54
54
|
|
55
|
+
self.window.ui.menu['audio.stop'] = QAction(
|
56
|
+
QIcon(":/icons/mute.svg"),
|
57
|
+
trans("menu.audio.stop"),
|
58
|
+
self.window,
|
59
|
+
checkable=False,
|
60
|
+
)
|
61
|
+
|
55
62
|
self.window.ui.menu['audio.output'].triggered.connect(
|
56
63
|
lambda: self.window.controller.plugins.toggle('audio_output')
|
57
64
|
)
|
@@ -67,6 +74,9 @@ class Audio:
|
|
67
74
|
self.window.ui.menu['audio.cache.clear'].triggered.connect(
|
68
75
|
lambda: self.window.controller.audio.clear_cache()
|
69
76
|
)
|
77
|
+
self.window.ui.menu['audio.stop'].triggered.connect(
|
78
|
+
lambda: self.window.controller.audio.stop_audio()
|
79
|
+
)
|
70
80
|
|
71
81
|
self.window.ui.menu['menu.audio'] = self.window.menuBar().addMenu(trans("menu.audio"))
|
72
82
|
self.window.ui.menu['menu.audio'].addAction(self.window.ui.menu['audio.input'])
|
@@ -76,3 +86,4 @@ class Audio:
|
|
76
86
|
self.window.ui.menu['menu.audio'].addAction(self.window.ui.menu['audio.control.global'])
|
77
87
|
self.window.ui.menu['menu.audio'].addSeparator()
|
78
88
|
self.window.ui.menu['menu.audio'].addAction(self.window.ui.menu['audio.cache.clear'])
|
89
|
+
self.window.ui.menu['menu.audio'].addAction(self.window.ui.menu['audio.stop'])
|
@@ -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)
|
@@ -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
|
@@ -14,6 +14,7 @@ import datetime
|
|
14
14
|
from PySide6 import QtWidgets, QtCore, QtGui
|
15
15
|
from PySide6.QtGui import QAction, QIcon, QColor, QPixmap, QStandardItem
|
16
16
|
from PySide6.QtWidgets import QMenu
|
17
|
+
from overrides import overrides
|
17
18
|
|
18
19
|
from pygpt_net.ui.widget.lists.base import BaseList
|
19
20
|
from pygpt_net.utils import trans
|
@@ -31,13 +32,13 @@ class ContextList(BaseList):
|
|
31
32
|
super(ContextList, self).__init__(window)
|
32
33
|
self.window = window
|
33
34
|
self.id = id
|
34
|
-
self.clicked.connect(self.click)
|
35
35
|
self.expanded_items = set()
|
36
36
|
self.setItemDelegate(ImportantItemDelegate())
|
37
37
|
|
38
|
+
|
38
39
|
def click(self, index):
|
39
40
|
"""
|
40
|
-
Click event
|
41
|
+
Click event (override, connected in BaseList class)
|
41
42
|
|
42
43
|
:param index: index
|
43
44
|
"""
|
@@ -49,8 +50,10 @@ class ContextList(BaseList):
|
|
49
50
|
self.window.controller.ctx.set_group(item.id)
|
50
51
|
if self.window.ui.nodes['ctx.list'].isExpanded(index):
|
51
52
|
self.expanded_items.discard(item.id)
|
53
|
+
self.window.ui.nodes['ctx.list'].collapse(index)
|
52
54
|
else:
|
53
55
|
self.expanded_items.add(item.id)
|
56
|
+
self.window.ui.nodes['ctx.list'].expand(index)
|
54
57
|
else:
|
55
58
|
self.window.controller.ctx.select_by_id(item.id)
|
56
59
|
else:
|
@@ -76,7 +79,7 @@ class ContextList(BaseList):
|
|
76
79
|
|
77
80
|
:param index: index
|
78
81
|
"""
|
79
|
-
|
82
|
+
print("dblclick")
|
80
83
|
|
81
84
|
def mousePressEvent(self, event):
|
82
85
|
"""
|
@@ -407,20 +410,28 @@ class ImportantItemDelegate(QtWidgets.QStyledItemDelegate):
|
|
407
410
|
label = 0
|
408
411
|
is_important = False
|
409
412
|
is_attachment = False
|
413
|
+
is_group = False
|
414
|
+
in_group = False
|
415
|
+
|
410
416
|
if "label" in data:
|
411
417
|
label = data["label"]
|
412
418
|
if "is_important" in data and data["is_important"]:
|
413
419
|
is_important = True
|
414
420
|
if "is_attachment" in data and data["is_attachment"]:
|
415
421
|
is_attachment = True
|
422
|
+
if "is_group" in data and data["is_group"]:
|
423
|
+
is_group = True
|
424
|
+
if "in_group" in data and data["in_group"]:
|
425
|
+
in_group = True
|
416
426
|
|
417
427
|
painter.save()
|
418
428
|
|
419
429
|
if is_attachment:
|
420
430
|
icon = QtGui.QIcon(":/icons/attachment.svg")
|
421
431
|
icon_size = option.decorationSize or QtCore.QSize(16, 16)
|
432
|
+
icon_pos = option.rect.right() - icon_size.width()
|
422
433
|
icon_rect = QtCore.QRect(
|
423
|
-
|
434
|
+
icon_pos,
|
424
435
|
option.rect.top() + (option.rect.height() - icon_size.height()) / 2,
|
425
436
|
icon_size.width(),
|
426
437
|
icon_size.height()
|
@@ -447,8 +458,6 @@ class ImportantItemDelegate(QtWidgets.QStyledItemDelegate):
|
|
447
458
|
)
|
448
459
|
painter.drawRect(square_rect)
|
449
460
|
|
450
|
-
#label = label - 10 # remove pin status
|
451
|
-
|
452
461
|
# label (0-9)
|
453
462
|
if label > 0:
|
454
463
|
color = self.get_color_for_status(label)
|
@@ -495,6 +504,7 @@ class GroupItem(QStandardItem):
|
|
495
504
|
self.name = name
|
496
505
|
self.isFolder = True
|
497
506
|
self.isPinned = False
|
507
|
+
self.hasAttachments = False
|
498
508
|
self.dt = None
|
499
509
|
|
500
510
|
class Item(QStandardItem):
|
@@ -507,12 +517,16 @@ class Item(QStandardItem):
|
|
507
517
|
self.dt = None
|
508
518
|
|
509
519
|
class SectionItem(QStandardItem):
|
510
|
-
def __init__(self, title):
|
520
|
+
def __init__(self, title, group: bool = False):
|
511
521
|
super().__init__(title)
|
512
522
|
self.title = title
|
523
|
+
self.group = group
|
513
524
|
self.setSelectable(False)
|
514
525
|
self.setEnabled(False)
|
515
|
-
self.
|
526
|
+
if self.group:
|
527
|
+
self.setTextAlignment(QtCore.Qt.AlignLeft)
|
528
|
+
else:
|
529
|
+
self.setTextAlignment(QtCore.Qt.AlignRight)
|
516
530
|
font = self.font()
|
517
531
|
font.setBold(True)
|
518
532
|
self.setFont(font)
|
pygpt_net/utils.py
CHANGED