pygpt-net 2.6.66__py3-none-any.whl → 2.7.0__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 +18 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/assistant/assistant.py +13 -8
- pygpt_net/controller/assistant/batch.py +29 -15
- pygpt_net/controller/assistant/files.py +19 -14
- pygpt_net/controller/assistant/store.py +63 -41
- pygpt_net/controller/attachment/attachment.py +45 -35
- pygpt_net/controller/chat/attachment.py +50 -39
- pygpt_net/controller/config/field/dictionary.py +26 -14
- pygpt_net/controller/config/field/textarea.py +2 -2
- pygpt_net/controller/ctx/common.py +27 -17
- pygpt_net/controller/ctx/ctx.py +182 -101
- pygpt_net/controller/dialogs/info.py +2 -2
- pygpt_net/controller/files/files.py +101 -41
- pygpt_net/controller/idx/indexer.py +87 -31
- pygpt_net/controller/kernel/kernel.py +13 -2
- pygpt_net/controller/media/media.py +29 -1
- pygpt_net/controller/mode/mode.py +3 -3
- pygpt_net/controller/model/editor.py +141 -21
- pygpt_net/controller/model/importer.py +153 -54
- pygpt_net/controller/painter/painter.py +2 -2
- pygpt_net/controller/presets/experts.py +68 -15
- pygpt_net/controller/presets/presets.py +72 -36
- pygpt_net/controller/settings/editor.py +25 -1
- pygpt_net/controller/settings/profile.py +76 -35
- pygpt_net/controller/settings/workdir.py +70 -39
- pygpt_net/core/assistants/files.py +20 -18
- pygpt_net/core/filesystem/actions.py +111 -10
- pygpt_net/core/filesystem/filesystem.py +2 -1
- pygpt_net/core/idx/idx.py +12 -11
- pygpt_net/core/idx/worker.py +13 -1
- pygpt_net/core/models/models.py +4 -4
- pygpt_net/core/profile/profile.py +13 -3
- pygpt_net/core/types/image.py +10 -1
- pygpt_net/core/video/video.py +43 -3
- pygpt_net/data/config/config.json +3 -3
- pygpt_net/data/config/models.json +25 -14
- pygpt_net/data/css/style.dark.css +39 -1
- pygpt_net/data/css/style.light.css +39 -1
- pygpt_net/data/locale/locale.de.ini +4 -1
- pygpt_net/data/locale/locale.en.ini +4 -1
- pygpt_net/data/locale/locale.es.ini +4 -1
- pygpt_net/data/locale/locale.fr.ini +4 -1
- pygpt_net/data/locale/locale.it.ini +4 -1
- pygpt_net/data/locale/locale.pl.ini +5 -2
- pygpt_net/data/locale/locale.uk.ini +4 -1
- pygpt_net/data/locale/locale.zh.ini +4 -1
- pygpt_net/item/model.py +1 -1
- pygpt_net/provider/api/openai/__init__.py +4 -2
- pygpt_net/provider/api/openai/video.py +2 -2
- pygpt_net/provider/core/config/patch.py +9 -1
- pygpt_net/provider/core/model/patch.py +26 -1
- pygpt_net/tools/image_viewer/tool.py +17 -0
- pygpt_net/tools/text_editor/tool.py +9 -0
- pygpt_net/ui/__init__.py +2 -2
- pygpt_net/ui/dialog/models.py +10 -1
- pygpt_net/ui/layout/ctx/ctx_list.py +16 -6
- pygpt_net/ui/layout/toolbox/video.py +14 -6
- pygpt_net/ui/main.py +3 -1
- pygpt_net/ui/widget/calendar/select.py +3 -3
- pygpt_net/ui/widget/filesystem/explorer.py +1082 -142
- pygpt_net/ui/widget/lists/assistant.py +185 -24
- pygpt_net/ui/widget/lists/assistant_store.py +245 -42
- pygpt_net/ui/widget/lists/attachment.py +230 -47
- pygpt_net/ui/widget/lists/attachment_ctx.py +189 -33
- pygpt_net/ui/widget/lists/base_list_combo.py +2 -2
- pygpt_net/ui/widget/lists/context.py +1253 -70
- pygpt_net/ui/widget/lists/experts.py +110 -8
- pygpt_net/ui/widget/lists/model_editor.py +217 -14
- pygpt_net/ui/widget/lists/model_importer.py +125 -6
- pygpt_net/ui/widget/lists/preset.py +460 -71
- pygpt_net/ui/widget/lists/profile.py +149 -27
- pygpt_net/ui/widget/lists/uploaded.py +230 -38
- pygpt_net/ui/widget/option/combo.py +1046 -32
- pygpt_net/ui/widget/option/dictionary.py +35 -7
- pygpt_net/ui/widget/option/input.py +3 -1
- {pygpt_net-2.6.66.dist-info → pygpt_net-2.7.0.dist-info}/METADATA +20 -57
- {pygpt_net-2.6.66.dist-info → pygpt_net-2.7.0.dist-info}/RECORD +81 -81
- {pygpt_net-2.6.66.dist-info → pygpt_net-2.7.0.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.66.dist-info → pygpt_net-2.7.0.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.66.dist-info → pygpt_net-2.7.0.dist-info}/entry_points.txt +0 -0
pygpt_net/CHANGELOG.txt
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
2.7.0 (2025-12-28)
|
|
2
|
+
|
|
3
|
+
- Added multi-select functionality using CTRL or SHIFT and batch actions to the context list, preset list, attachments list, and other list-based widgets.
|
|
4
|
+
- Added a search field to comboboxes, such as the model selector.
|
|
5
|
+
- Added a Duplicate option to the models editor.
|
|
6
|
+
- Added drag-and-drop to context list.
|
|
7
|
+
- Added multi-select, drag-and-drop, Cut, Copy, and Paste features to the File Explorer.
|
|
8
|
+
- Fix: scroll restoration after actions in the context list.
|
|
9
|
+
- Fix: 'Use as image' option in the File Explorer.
|
|
10
|
+
- Fix: current preset system prompt disappearing on profile change.
|
|
11
|
+
- Other UI fixes/improvements.
|
|
12
|
+
|
|
13
|
+
2.6.67 (2025-12-26)
|
|
14
|
+
|
|
15
|
+
- Added a provider filter to the models editor.
|
|
16
|
+
- Added video options (resolution, duration) to the toolbox.
|
|
17
|
+
- Updated the models configuration.
|
|
18
|
+
|
|
1
19
|
2.6.66 (2025-12-25)
|
|
2
20
|
|
|
3
21
|
- Added Sora 2 support - #155.
|
pygpt_net/__init__.py
CHANGED
|
@@ -6,15 +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: 2025.12.
|
|
9
|
+
# Updated Date: 2025.12.28 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
__author__ = "Marcin Szczygliński"
|
|
13
13
|
__copyright__ = "Copyright 2025, Marcin Szczygliński"
|
|
14
14
|
__credits__ = ["Marcin Szczygliński"]
|
|
15
15
|
__license__ = "MIT"
|
|
16
|
-
__version__ = "2.
|
|
17
|
-
__build__ = "2025-12-
|
|
16
|
+
__version__ = "2.7.0"
|
|
17
|
+
__build__ = "2025-12-28"
|
|
18
18
|
__maintainer__ = "Marcin Szczygliński"
|
|
19
19
|
__github__ = "https://github.com/szczyglis-dev/py-gpt"
|
|
20
20
|
__report__ = "https://github.com/szczyglis-dev/py-gpt/issues"
|
|
@@ -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.12.28 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import Optional
|
|
@@ -23,6 +23,7 @@ from pygpt_net.core.text.utils import has_unclosed_code_tag
|
|
|
23
23
|
from pygpt_net.utils import trans
|
|
24
24
|
from pygpt_net.item.ctx import CtxItem
|
|
25
25
|
from pygpt_net.core.events import RenderEvent
|
|
26
|
+
from pygpt_net.core.types import MODE_ASSISTANT
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
class Assistant:
|
|
@@ -193,6 +194,9 @@ class Assistant:
|
|
|
193
194
|
|
|
194
195
|
:param no_scroll: True if do not scroll to selected item
|
|
195
196
|
"""
|
|
197
|
+
mode = self.window.core.config.get('mode')
|
|
198
|
+
if mode != MODE_ASSISTANT:
|
|
199
|
+
return
|
|
196
200
|
assistant_id = self.window.core.config.get('assistant')
|
|
197
201
|
items = self.window.core.assistants.get_all()
|
|
198
202
|
if assistant_id in items:
|
|
@@ -208,15 +212,16 @@ class Assistant:
|
|
|
208
212
|
|
|
209
213
|
def select_default(self):
|
|
210
214
|
"""Set default assistant"""
|
|
215
|
+
mode = self.window.core.config.get('mode')
|
|
216
|
+
if mode != MODE_ASSISTANT:
|
|
217
|
+
return
|
|
211
218
|
assistant = self.window.core.config.get('assistant')
|
|
212
219
|
if assistant is None or assistant == "":
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
self.window.core.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
)
|
|
219
|
-
self.update()
|
|
220
|
+
self.window.core.config.set(
|
|
221
|
+
'assistant',
|
|
222
|
+
self.window.core.assistants.get_default_assistant(),
|
|
223
|
+
)
|
|
224
|
+
self.update()
|
|
220
225
|
|
|
221
226
|
def create(self) -> AssistantItem:
|
|
222
227
|
"""
|
|
@@ -6,10 +6,10 @@
|
|
|
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.12.27 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
|
-
from typing import Optional, Any
|
|
12
|
+
from typing import Optional, Any, Union
|
|
13
13
|
|
|
14
14
|
from PySide6.QtCore import QTimer
|
|
15
15
|
from PySide6.QtWidgets import QFileDialog, QApplication
|
|
@@ -143,17 +143,21 @@ class Batch:
|
|
|
143
143
|
QApplication.processEvents()
|
|
144
144
|
self.window.core.api.openai.assistants.importer.truncate_files() # remove all files from API
|
|
145
145
|
|
|
146
|
-
def truncate_store_files_by_idx(self, idx: int, force: bool = False):
|
|
146
|
+
def truncate_store_files_by_idx(self, idx: Union[int, list], force: bool = False):
|
|
147
147
|
"""
|
|
148
148
|
Truncate all files in API (store)
|
|
149
149
|
|
|
150
|
-
:param idx: store index
|
|
150
|
+
:param idx: store index or list of indexes
|
|
151
151
|
:param force: if True, imports without confirmation
|
|
152
152
|
"""
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
store_ids = []
|
|
154
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
155
|
+
for i in ids:
|
|
156
|
+
store_id = self.window.controller.assistant.store.get_by_tab_idx(i)
|
|
157
|
+
store_ids.append(store_id)
|
|
158
|
+
self.truncate_store_files(store_ids, force)
|
|
155
159
|
|
|
156
|
-
def truncate_store_files(self, store_id: str, force: bool = False):
|
|
160
|
+
def truncate_store_files(self, store_id: Union[str, list], force: bool = False):
|
|
157
161
|
"""
|
|
158
162
|
Truncate all files in API (store)
|
|
159
163
|
|
|
@@ -174,31 +178,37 @@ class Batch:
|
|
|
174
178
|
# run asynchronous
|
|
175
179
|
self.window.update_status("Removing files...please wait...")
|
|
176
180
|
QApplication.processEvents()
|
|
177
|
-
|
|
181
|
+
ids = store_id if isinstance(store_id, list) else [store_id]
|
|
182
|
+
for store_id in ids:
|
|
183
|
+
self.window.core.api.openai.assistants.importer.truncate_files(store_id) # remove all files from API
|
|
178
184
|
|
|
179
185
|
def clear_store_files_by_idx(
|
|
180
186
|
self,
|
|
181
|
-
idx: int,
|
|
187
|
+
idx: Union[int, list],
|
|
182
188
|
force: bool = False
|
|
183
189
|
):
|
|
184
190
|
"""
|
|
185
191
|
Clear files (store, local only)
|
|
186
192
|
|
|
187
|
-
:param idx: store index
|
|
193
|
+
:param idx: store index or list of indexes
|
|
188
194
|
:param force: if True, clears without confirmation
|
|
189
195
|
"""
|
|
190
|
-
|
|
191
|
-
|
|
196
|
+
store_ids = []
|
|
197
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
198
|
+
for i in ids:
|
|
199
|
+
store_id = self.window.controller.assistant.store.get_by_tab_idx(i)
|
|
200
|
+
store_ids.append(store_id)
|
|
201
|
+
self.clear_store_files(store_ids, force)
|
|
192
202
|
|
|
193
203
|
def clear_store_files(
|
|
194
204
|
self,
|
|
195
|
-
store_id: Optional[str] = None,
|
|
205
|
+
store_id: Optional[Union[str, list]] = None,
|
|
196
206
|
force: bool = False
|
|
197
207
|
):
|
|
198
208
|
"""
|
|
199
209
|
Clear files (store, local only)
|
|
200
210
|
|
|
201
|
-
:param store_id: store ID
|
|
211
|
+
:param store_id: store ID or list of store IDs
|
|
202
212
|
:param force: if True, clears without confirmation
|
|
203
213
|
"""
|
|
204
214
|
if store_id is None:
|
|
@@ -214,7 +224,11 @@ class Batch:
|
|
|
214
224
|
return
|
|
215
225
|
self.window.update_status("Clearing store files...please wait...")
|
|
216
226
|
QApplication.processEvents()
|
|
217
|
-
|
|
227
|
+
|
|
228
|
+
ids = store_id if isinstance(store_id, list) else [store_id]
|
|
229
|
+
for store_id in ids:
|
|
230
|
+
self.window.core.assistants.files.truncate_local(store_id) # clear files local
|
|
231
|
+
|
|
218
232
|
self.window.controller.assistant.files.update()
|
|
219
233
|
self.window.update_status("OK. All store files cleared.")
|
|
220
234
|
self.window.ui.dialogs.alert(trans("status.finished"))
|
|
@@ -6,11 +6,11 @@
|
|
|
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.12.27 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
13
|
-
from typing import Optional, Dict, List
|
|
13
|
+
from typing import Optional, Dict, List, Union
|
|
14
14
|
|
|
15
15
|
from PySide6.QtWidgets import QApplication
|
|
16
16
|
|
|
@@ -78,11 +78,11 @@ class Files:
|
|
|
78
78
|
self.window.update_status("Importing files...please wait...")
|
|
79
79
|
self.window.core.api.openai.assistants.importer.import_files(store_id)
|
|
80
80
|
|
|
81
|
-
def download(self, idx: int):
|
|
81
|
+
def download(self, idx: Union[int, list]):
|
|
82
82
|
"""
|
|
83
83
|
Download file
|
|
84
84
|
|
|
85
|
-
:param idx: selected attachment index
|
|
85
|
+
:param idx: selected attachment index or list of indexes
|
|
86
86
|
"""
|
|
87
87
|
id = self.window.core.config.get('assistant')
|
|
88
88
|
if id is None or id == "":
|
|
@@ -93,10 +93,11 @@ class Files:
|
|
|
93
93
|
|
|
94
94
|
# get file by list index
|
|
95
95
|
thread_id = self.window.core.config.get('assistant_thread')
|
|
96
|
-
file_id = self.window.core.assistants.files.get_file_id_by_idx(idx, assistant.vector_store, thread_id)
|
|
97
96
|
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
98
|
+
for idx in ids:
|
|
99
|
+
file_id = self.window.core.assistants.files.get_file_id_by_idx(idx, assistant.vector_store, thread_id)
|
|
100
|
+
self.window.controller.attachment.download(file_id) # download file
|
|
100
101
|
|
|
101
102
|
def rename(self, idx: int):
|
|
102
103
|
"""
|
|
@@ -186,11 +187,11 @@ class Files:
|
|
|
186
187
|
|
|
187
188
|
self.update()
|
|
188
189
|
|
|
189
|
-
def delete(self, idx: int, force: bool = False):
|
|
190
|
+
def delete(self, idx: Union[int, list], force: bool = False):
|
|
190
191
|
"""
|
|
191
192
|
Delete file
|
|
192
193
|
|
|
193
|
-
:param idx: file idx
|
|
194
|
+
:param idx: file idx or list of idxs
|
|
194
195
|
:param force: force delete without confirmation
|
|
195
196
|
"""
|
|
196
197
|
if not force:
|
|
@@ -209,17 +210,21 @@ class Files:
|
|
|
209
210
|
if assistant is None:
|
|
210
211
|
return
|
|
211
212
|
|
|
212
|
-
|
|
213
|
+
files = []
|
|
213
214
|
thread_id = self.window.core.config.get('assistant_thread')
|
|
214
|
-
|
|
215
|
-
if
|
|
216
|
-
|
|
215
|
+
# get files by list index
|
|
216
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
217
|
+
for idx in ids:
|
|
218
|
+
file = self.window.core.assistants.files.get_file_by_idx(idx, assistant.vector_store, thread_id)
|
|
219
|
+
if file is None:
|
|
220
|
+
continue
|
|
221
|
+
files.append(file)
|
|
217
222
|
|
|
218
223
|
# delete file in API
|
|
219
224
|
self.window.update_status(trans('status.sending'))
|
|
220
225
|
QApplication.processEvents()
|
|
221
226
|
try:
|
|
222
|
-
self.window.core.assistants.files.delete(
|
|
227
|
+
self.window.core.assistants.files.delete(files) # delete from DB, API and vector stores
|
|
223
228
|
|
|
224
229
|
# update store status
|
|
225
230
|
if assistant.vector_store:
|
|
@@ -6,12 +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: 2025.
|
|
9
|
+
# Updated Date: 2025.12.27 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
13
13
|
import json
|
|
14
|
-
from typing import Optional
|
|
14
|
+
from typing import Optional, Union
|
|
15
15
|
|
|
16
16
|
from PySide6.QtWidgets import QApplication
|
|
17
17
|
from PySide6.QtGui import QStandardItem
|
|
@@ -183,32 +183,44 @@ class VectorStore:
|
|
|
183
183
|
if update and store.id == self.current:
|
|
184
184
|
self.update_current()
|
|
185
185
|
|
|
186
|
-
def refresh_by_idx(self, idx: int):
|
|
186
|
+
def refresh_by_idx(self, idx: Union[int, list]):
|
|
187
187
|
"""
|
|
188
188
|
Refresh store by idx
|
|
189
189
|
|
|
190
|
-
:param idx: store idx
|
|
190
|
+
:param idx: store idx or list of idxs
|
|
191
191
|
"""
|
|
192
|
-
|
|
193
|
-
if
|
|
194
|
-
|
|
192
|
+
store_ids = []
|
|
193
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
194
|
+
for i in ids:
|
|
195
|
+
store_id = self.get_by_tab_idx(i)
|
|
196
|
+
if store_id is not None:
|
|
197
|
+
store_ids.append(store_id)
|
|
198
|
+
self.refresh_by_store_id(store_ids)
|
|
195
199
|
|
|
196
|
-
def refresh_by_store_id(self, store_id: str):
|
|
200
|
+
def refresh_by_store_id(self, store_id: Union[str, list]):
|
|
197
201
|
"""
|
|
198
202
|
Refresh store by ID
|
|
199
203
|
|
|
200
204
|
:param store_id: store id
|
|
201
205
|
"""
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
self.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
self.
|
|
206
|
+
ids = store_id if isinstance(store_id, list) else [store_id]
|
|
207
|
+
updated = False
|
|
208
|
+
is_current = False
|
|
209
|
+
for store_id in ids:
|
|
210
|
+
if store_id is not None and store_id in self.window.core.assistants.store.items:
|
|
211
|
+
store = self.window.core.assistants.store.items[store_id]
|
|
212
|
+
if store is not None:
|
|
213
|
+
self.window.update_status(trans('status.sending'))
|
|
214
|
+
QApplication.processEvents()
|
|
215
|
+
self.refresh_store(store)
|
|
216
|
+
updated = True
|
|
217
|
+
if self.current == store_id:
|
|
218
|
+
is_current = True
|
|
219
|
+
if updated:
|
|
220
|
+
self.window.update_status(trans('status.assistant.saved'))
|
|
221
|
+
self.update()
|
|
222
|
+
if is_current:
|
|
223
|
+
self.update_files_list()
|
|
212
224
|
|
|
213
225
|
def update_current(self):
|
|
214
226
|
"""Update current store"""
|
|
@@ -327,27 +339,32 @@ class VectorStore:
|
|
|
327
339
|
|
|
328
340
|
def delete_by_idx(
|
|
329
341
|
self,
|
|
330
|
-
idx: int,
|
|
342
|
+
idx: Union[int, list],
|
|
331
343
|
force: bool = False
|
|
332
344
|
):
|
|
333
345
|
"""
|
|
334
346
|
Delete store by idx
|
|
335
347
|
|
|
336
|
-
:param idx: store idx
|
|
348
|
+
:param idx: store idx or list of idxs
|
|
337
349
|
:param force: force delete
|
|
338
350
|
"""
|
|
339
|
-
|
|
340
|
-
|
|
351
|
+
store_ids = []
|
|
352
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
353
|
+
for i in ids:
|
|
354
|
+
store_id = self.get_by_tab_idx(i)
|
|
355
|
+
if store_id is not None:
|
|
356
|
+
store_ids.append(store_id)
|
|
357
|
+
self.delete(store_ids, force=force)
|
|
341
358
|
|
|
342
359
|
def delete(
|
|
343
360
|
self,
|
|
344
|
-
store_id: Optional[str] = None,
|
|
361
|
+
store_id: Optional[Union[str, list]] = None,
|
|
345
362
|
force: bool = False
|
|
346
363
|
):
|
|
347
364
|
"""
|
|
348
365
|
Delete store by idx
|
|
349
366
|
|
|
350
|
-
:param store_id: store id
|
|
367
|
+
:param store_id: store id or list of store ids
|
|
351
368
|
:param force: force delete
|
|
352
369
|
"""
|
|
353
370
|
if not force:
|
|
@@ -363,25 +380,30 @@ class VectorStore:
|
|
|
363
380
|
return
|
|
364
381
|
|
|
365
382
|
self.window.update_status(trans('status.sending'))
|
|
383
|
+
updated = False
|
|
366
384
|
QApplication.processEvents()
|
|
367
|
-
if
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
self.window.
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
385
|
+
ids = store_id if isinstance(store_id, list) else [store_id]
|
|
386
|
+
for store_id in ids:
|
|
387
|
+
if self.current == store_id:
|
|
388
|
+
self.current = None
|
|
389
|
+
try:
|
|
390
|
+
print("Deleting store: {}".format(store_id))
|
|
391
|
+
if self.window.core.assistants.store.delete(store_id):
|
|
392
|
+
self.window.controller.assistant.batch.remove_store_from_assistants(store_id)
|
|
393
|
+
self.window.update_status(trans('status.deleted'))
|
|
394
|
+
self.window.core.assistants.store.save()
|
|
395
|
+
updated = True
|
|
396
|
+
else:
|
|
397
|
+
self.window.update_status(trans('status.error'))
|
|
398
|
+
except Exception as e:
|
|
381
399
|
self.window.update_status(trans('status.error'))
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
self.window.
|
|
400
|
+
self.window.ui.dialogs.alert(e)
|
|
401
|
+
if updated:
|
|
402
|
+
self.window.controller.assistant.files.update()
|
|
403
|
+
self.update() # update stores list in assistant dialog
|
|
404
|
+
self.init()
|
|
405
|
+
self.restore_selection()
|
|
406
|
+
self.update_files_list()
|
|
385
407
|
|
|
386
408
|
def set_by_tab(self, idx: int):
|
|
387
409
|
"""
|
|
@@ -6,12 +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: 2025.
|
|
9
|
+
# Updated Date: 2025.12.27 21:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
13
13
|
from datetime import datetime
|
|
14
|
-
from typing import Optional
|
|
14
|
+
from typing import Optional, Union
|
|
15
15
|
from urllib.parse import urlparse
|
|
16
16
|
|
|
17
17
|
from PySide6.QtGui import QImage
|
|
@@ -128,14 +128,14 @@ class Attachment:
|
|
|
128
128
|
|
|
129
129
|
def delete(
|
|
130
130
|
self,
|
|
131
|
-
idx: int,
|
|
131
|
+
idx: Union[int, list],
|
|
132
132
|
force: bool = False,
|
|
133
133
|
remove_local: bool = False
|
|
134
134
|
):
|
|
135
135
|
"""
|
|
136
136
|
Delete attachment
|
|
137
137
|
|
|
138
|
-
:param idx: index of attachment
|
|
138
|
+
:param idx: index of attachment to delete (or list of indices)
|
|
139
139
|
:param force: force delete
|
|
140
140
|
:param remove_local: remove local file
|
|
141
141
|
"""
|
|
@@ -148,19 +148,25 @@ class Attachment:
|
|
|
148
148
|
)
|
|
149
149
|
return
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
)
|
|
151
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
152
|
+
file_ids = []
|
|
153
|
+
for idx in ids:
|
|
154
|
+
file_id = self.window.core.attachments.get_id_by_idx(
|
|
155
|
+
mode=mode,
|
|
156
|
+
idx=idx,
|
|
157
|
+
)
|
|
158
|
+
file_ids.append(file_id)
|
|
160
159
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
for file_id in file_ids:
|
|
161
|
+
self.window.core.attachments.delete(
|
|
162
|
+
mode=mode,
|
|
163
|
+
id=file_id,
|
|
164
|
+
remove_local=remove_local,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# clear current if current == deleted
|
|
168
|
+
if self.window.core.attachments.current == file_id:
|
|
169
|
+
self.window.core.attachments.current = None
|
|
164
170
|
|
|
165
171
|
if not self.has(mode):
|
|
166
172
|
self.window.controller.chat.vision.unavailable()
|
|
@@ -363,38 +369,42 @@ class Attachment:
|
|
|
363
369
|
self.update()
|
|
364
370
|
self.window.ui.dialog['url'].close()
|
|
365
371
|
|
|
366
|
-
def open_dir(self, mode: str, idx: int):
|
|
372
|
+
def open_dir(self, mode: str, idx: Union[int, list]):
|
|
367
373
|
"""
|
|
368
374
|
Open in directory
|
|
369
375
|
|
|
370
376
|
:param mode: mode
|
|
371
|
-
:param idx: index
|
|
377
|
+
:param idx: index or list of indices
|
|
372
378
|
"""
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
self.window.controller.files.open_dir(
|
|
379
|
-
path=path,
|
|
380
|
-
select=True,
|
|
379
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
380
|
+
for idx in ids:
|
|
381
|
+
path = self.get_path_by_idx(
|
|
382
|
+
mode=mode,
|
|
383
|
+
idx=idx,
|
|
381
384
|
)
|
|
385
|
+
if path is not None and path != '' and os.path.exists(path):
|
|
386
|
+
self.window.controller.files.open_dir(
|
|
387
|
+
path=path,
|
|
388
|
+
select=True,
|
|
389
|
+
)
|
|
382
390
|
|
|
383
|
-
def open(self, mode: str, idx: int):
|
|
391
|
+
def open(self, mode: str, idx: Union[int, list]):
|
|
384
392
|
"""
|
|
385
393
|
Open attachment
|
|
386
394
|
|
|
387
395
|
:param mode: mode
|
|
388
|
-
:param idx: index
|
|
396
|
+
:param idx: index or list of indices
|
|
389
397
|
"""
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
self.window.controller.files.open(
|
|
396
|
-
path=path,
|
|
398
|
+
ids = idx if isinstance(idx, list) else [idx]
|
|
399
|
+
for idx in ids:
|
|
400
|
+
path = self.get_path_by_idx(
|
|
401
|
+
mode=mode,
|
|
402
|
+
idx=idx,
|
|
397
403
|
)
|
|
404
|
+
if path is not None and path != '' and os.path.exists(path):
|
|
405
|
+
self.window.controller.files.open(
|
|
406
|
+
path=path,
|
|
407
|
+
)
|
|
398
408
|
|
|
399
409
|
def get_path_by_idx(self, mode: str, idx: int) -> str:
|
|
400
410
|
"""
|