pygpt-net 2.7.7__py3-none-any.whl → 2.7.8__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 +7 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +5 -1
- pygpt_net/controller/assistant/batch.py +2 -2
- pygpt_net/controller/assistant/files.py +7 -6
- pygpt_net/controller/assistant/threads.py +0 -0
- pygpt_net/controller/chat/command.py +0 -0
- pygpt_net/controller/dialogs/confirm.py +35 -58
- pygpt_net/controller/lang/mapping.py +9 -9
- pygpt_net/controller/remote_store/{google/batch.py → batch.py} +209 -252
- pygpt_net/controller/remote_store/remote_store.py +982 -13
- pygpt_net/core/command/command.py +0 -0
- pygpt_net/core/db/viewer.py +1 -1
- pygpt_net/core/realtime/worker.py +3 -1
- pygpt_net/{controller/remote_store/google → core/remote_store/anthropic}/__init__.py +0 -1
- pygpt_net/core/remote_store/anthropic/files.py +211 -0
- pygpt_net/core/remote_store/anthropic/store.py +208 -0
- pygpt_net/core/remote_store/openai/store.py +5 -4
- pygpt_net/core/remote_store/remote_store.py +5 -1
- pygpt_net/{controller/remote_store/openai → core/remote_store/xai}/__init__.py +0 -1
- pygpt_net/core/remote_store/xai/files.py +225 -0
- pygpt_net/core/remote_store/xai/store.py +219 -0
- pygpt_net/data/config/config.json +9 -6
- pygpt_net/data/config/models.json +5 -4
- pygpt_net/data/config/settings.json +54 -1
- pygpt_net/data/icons/folder_eye.svg +1 -0
- pygpt_net/data/icons/folder_eye_filled.svg +1 -0
- pygpt_net/data/icons/folder_open.svg +1 -0
- pygpt_net/data/icons/folder_open_filled.svg +1 -0
- pygpt_net/data/locale/locale.de.ini +4 -3
- pygpt_net/data/locale/locale.en.ini +14 -4
- pygpt_net/data/locale/locale.es.ini +4 -3
- pygpt_net/data/locale/locale.fr.ini +4 -3
- pygpt_net/data/locale/locale.it.ini +4 -3
- pygpt_net/data/locale/locale.pl.ini +5 -4
- pygpt_net/data/locale/locale.uk.ini +4 -3
- pygpt_net/data/locale/locale.zh.ini +4 -3
- pygpt_net/icons.qrc +4 -0
- pygpt_net/icons_rc.py +282 -138
- pygpt_net/provider/api/anthropic/__init__.py +2 -0
- pygpt_net/provider/api/anthropic/chat.py +84 -1
- pygpt_net/provider/api/anthropic/store.py +307 -0
- pygpt_net/provider/api/anthropic/stream.py +75 -0
- pygpt_net/provider/api/anthropic/worker/__init__.py +0 -0
- pygpt_net/provider/api/anthropic/worker/importer.py +278 -0
- pygpt_net/provider/api/google/chat.py +59 -2
- pygpt_net/provider/api/google/store.py +124 -3
- pygpt_net/provider/api/google/stream.py +91 -24
- pygpt_net/provider/api/google/worker/importer.py +16 -28
- pygpt_net/provider/api/openai/assistants.py +2 -2
- pygpt_net/provider/api/openai/store.py +4 -1
- pygpt_net/provider/api/openai/worker/importer.py +19 -61
- pygpt_net/provider/api/openai/worker/importer_assistants.py +230 -0
- pygpt_net/provider/api/x_ai/__init__.py +30 -6
- pygpt_net/provider/api/x_ai/audio.py +43 -11
- pygpt_net/provider/api/x_ai/chat.py +92 -4
- pygpt_net/provider/api/x_ai/realtime/__init__.py +12 -0
- pygpt_net/provider/api/x_ai/realtime/client.py +1825 -0
- pygpt_net/provider/api/x_ai/realtime/realtime.py +198 -0
- pygpt_net/provider/api/x_ai/remote_tools.py +19 -1
- pygpt_net/provider/api/x_ai/store.py +610 -0
- pygpt_net/provider/api/x_ai/stream.py +30 -9
- pygpt_net/provider/api/x_ai/worker/importer.py +308 -0
- pygpt_net/provider/audio_input/xai_grok_voice.py +390 -0
- pygpt_net/provider/audio_output/xai_tts.py +325 -0
- pygpt_net/provider/core/config/patch.py +18 -3
- pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +2 -2
- pygpt_net/provider/core/model/patch.py +13 -0
- pygpt_net/tools/image_viewer/tool.py +334 -34
- pygpt_net/tools/image_viewer/ui/dialogs.py +317 -21
- pygpt_net/ui/dialog/assistant.py +1 -1
- pygpt_net/ui/dialog/plugins.py +13 -5
- pygpt_net/ui/dialog/remote_store.py +552 -0
- pygpt_net/ui/dialogs.py +3 -5
- pygpt_net/ui/layout/ctx/ctx_list.py +58 -7
- pygpt_net/ui/menu/tools.py +6 -13
- pygpt_net/ui/widget/dialog/{remote_store_google.py → remote_store.py} +10 -10
- pygpt_net/ui/widget/element/button.py +4 -4
- pygpt_net/ui/widget/image/display.py +2 -2
- pygpt_net/ui/widget/lists/context.py +2 -2
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/METADATA +9 -2
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/RECORD +82 -70
- pygpt_net/controller/remote_store/google/store.py +0 -615
- pygpt_net/controller/remote_store/openai/batch.py +0 -524
- pygpt_net/controller/remote_store/openai/store.py +0 -699
- pygpt_net/ui/dialog/remote_store_google.py +0 -539
- pygpt_net/ui/dialog/remote_store_openai.py +0 -539
- pygpt_net/ui/widget/dialog/remote_store_openai.py +0 -56
- pygpt_net/ui/widget/lists/remote_store_google.py +0 -248
- pygpt_net/ui/widget/lists/remote_store_openai.py +0 -317
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/LICENSE +0 -0
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/WHEEL +0 -0
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/entry_points.txt +0 -0
|
@@ -1,615 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
# ================================================== #
|
|
4
|
-
# This file is a part of PYGPT package #
|
|
5
|
-
# Website: https://pygpt.net #
|
|
6
|
-
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
|
-
# MIT License #
|
|
8
|
-
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2026.01.02 20:00:00 #
|
|
10
|
-
# ================================================== #
|
|
11
|
-
|
|
12
|
-
import copy
|
|
13
|
-
import json
|
|
14
|
-
from typing import Optional, Union
|
|
15
|
-
|
|
16
|
-
from PySide6.QtWidgets import QApplication
|
|
17
|
-
from PySide6.QtGui import QStandardItem
|
|
18
|
-
from PySide6.QtCore import Qt, QTimer
|
|
19
|
-
|
|
20
|
-
from pygpt_net.item.store import RemoteStoreItem
|
|
21
|
-
from pygpt_net.utils import trans
|
|
22
|
-
|
|
23
|
-
from .batch import Batch
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class GoogleRemoteStore:
|
|
27
|
-
def __init__(self, window=None):
|
|
28
|
-
"""
|
|
29
|
-
Google File Search store editor controller
|
|
30
|
-
|
|
31
|
-
:param window: Window instance
|
|
32
|
-
"""
|
|
33
|
-
self.window = window
|
|
34
|
-
self.batch = Batch(window)
|
|
35
|
-
self.dialog = False
|
|
36
|
-
self.config_initialized = False
|
|
37
|
-
self.current = None
|
|
38
|
-
self.width = 800
|
|
39
|
-
self.height = 500
|
|
40
|
-
self.id = "remote_store.google"
|
|
41
|
-
self.options = {
|
|
42
|
-
"id": {
|
|
43
|
-
"type": "text",
|
|
44
|
-
"label": "remote_store.id",
|
|
45
|
-
"read_only": True,
|
|
46
|
-
"value": "",
|
|
47
|
-
},
|
|
48
|
-
"name": {
|
|
49
|
-
"type": "text",
|
|
50
|
-
"label": "remote_store.name",
|
|
51
|
-
"value": "",
|
|
52
|
-
},
|
|
53
|
-
"status": {
|
|
54
|
-
"type": "textarea",
|
|
55
|
-
"label": "remote_store.status",
|
|
56
|
-
"read_only": True,
|
|
57
|
-
"value": "",
|
|
58
|
-
},
|
|
59
|
-
}
|
|
60
|
-
self._files_row_to_id = []
|
|
61
|
-
|
|
62
|
-
def get_options(self) -> dict:
|
|
63
|
-
return self.options
|
|
64
|
-
|
|
65
|
-
def get_option(self, key: str) -> Optional[dict]:
|
|
66
|
-
if key in self.options:
|
|
67
|
-
return self.options[key]
|
|
68
|
-
|
|
69
|
-
def setup(self):
|
|
70
|
-
"""Set up store editor"""
|
|
71
|
-
idx = None
|
|
72
|
-
self.window.remote_store_google.setup(idx)
|
|
73
|
-
|
|
74
|
-
def toggle_editor(self):
|
|
75
|
-
"""Toggle editor dialog"""
|
|
76
|
-
if self.dialog:
|
|
77
|
-
self.close()
|
|
78
|
-
else:
|
|
79
|
-
self.open()
|
|
80
|
-
|
|
81
|
-
def reset(self):
|
|
82
|
-
"""Reset store editor"""
|
|
83
|
-
self.current = None
|
|
84
|
-
if self.dialog:
|
|
85
|
-
self.init()
|
|
86
|
-
|
|
87
|
-
def open(self, force: bool = False):
|
|
88
|
-
"""
|
|
89
|
-
Open store editor dialog
|
|
90
|
-
|
|
91
|
-
:param force: force open dialog
|
|
92
|
-
"""
|
|
93
|
-
if not self.config_initialized:
|
|
94
|
-
self.setup()
|
|
95
|
-
self.config_initialized = True
|
|
96
|
-
if not self.dialog or force:
|
|
97
|
-
self.current = self.window.controller.assistant.editor.get_selected_store_id()
|
|
98
|
-
self.init()
|
|
99
|
-
self.window.ui.dialogs.open(
|
|
100
|
-
"remote_store.google",
|
|
101
|
-
width=self.width,
|
|
102
|
-
height=self.height,
|
|
103
|
-
)
|
|
104
|
-
self.dialog = True
|
|
105
|
-
|
|
106
|
-
def close(self):
|
|
107
|
-
"""Close editor dialog"""
|
|
108
|
-
if self.dialog:
|
|
109
|
-
self.window.ui.dialogs.close('remote_store.google')
|
|
110
|
-
self.dialog = False
|
|
111
|
-
|
|
112
|
-
def init(self):
|
|
113
|
-
"""Initialize editor options"""
|
|
114
|
-
self.reload_items()
|
|
115
|
-
|
|
116
|
-
if self.current is None:
|
|
117
|
-
self.current = self.get_first_visible()
|
|
118
|
-
|
|
119
|
-
options = copy.deepcopy(self.get_options())
|
|
120
|
-
if self.current is not None and self.window.core.remote_store.google.has(self.current):
|
|
121
|
-
store = self.window.core.remote_store.google.items[self.current]
|
|
122
|
-
data_dict = store.to_dict()
|
|
123
|
-
for key in options:
|
|
124
|
-
if key in data_dict:
|
|
125
|
-
value = data_dict[key]
|
|
126
|
-
options[key]["value"] = value
|
|
127
|
-
if key == "status":
|
|
128
|
-
options[key]["value"] = json.dumps(value, indent=4)
|
|
129
|
-
|
|
130
|
-
self.set_tab_by_id(self.current)
|
|
131
|
-
self.window.controller.config.load_options(self.id, options)
|
|
132
|
-
else:
|
|
133
|
-
self.current = None
|
|
134
|
-
self.window.controller.config.load_options(self.id, options)
|
|
135
|
-
|
|
136
|
-
self.update_files_list()
|
|
137
|
-
|
|
138
|
-
def refresh_status(self):
|
|
139
|
-
"""Reload store status"""
|
|
140
|
-
if self.current is not None:
|
|
141
|
-
if self.window.core.remote_store.google.has(self.current):
|
|
142
|
-
self.window.update_status(trans('status.sending'))
|
|
143
|
-
QApplication.processEvents()
|
|
144
|
-
store = self.window.core.remote_store.google.items[self.current]
|
|
145
|
-
self.refresh_store(store)
|
|
146
|
-
self.window.update_status(trans('status.finished'))
|
|
147
|
-
self.update()
|
|
148
|
-
self.update_files_list()
|
|
149
|
-
|
|
150
|
-
def refresh_store(self, store: RemoteStoreItem, update: bool = True):
|
|
151
|
-
"""
|
|
152
|
-
Refresh store by item
|
|
153
|
-
|
|
154
|
-
:param store: store object
|
|
155
|
-
:param update: apply updates to current
|
|
156
|
-
"""
|
|
157
|
-
self.window.core.remote_store.google.update_status(store.id)
|
|
158
|
-
self.window.core.remote_store.google.update(store)
|
|
159
|
-
if update and store.id == self.current:
|
|
160
|
-
self.update_current()
|
|
161
|
-
|
|
162
|
-
def refresh_by_idx(self, idx: Union[int, list]):
|
|
163
|
-
"""
|
|
164
|
-
Refresh store by list index or list of indexes
|
|
165
|
-
|
|
166
|
-
:param idx: index or list
|
|
167
|
-
"""
|
|
168
|
-
store_ids = []
|
|
169
|
-
ids = idx if isinstance(idx, list) else [idx]
|
|
170
|
-
for i in ids:
|
|
171
|
-
store_id = self.get_by_tab_idx(i)
|
|
172
|
-
if store_id is not None:
|
|
173
|
-
store_ids.append(store_id)
|
|
174
|
-
self.refresh_by_store_id(store_ids)
|
|
175
|
-
|
|
176
|
-
def refresh_by_store_id(self, store_id: Union[str, list]):
|
|
177
|
-
"""
|
|
178
|
-
Refresh store by ID(s)
|
|
179
|
-
|
|
180
|
-
:param store_id: store name or list
|
|
181
|
-
"""
|
|
182
|
-
ids = store_id if isinstance(store_id, list) else [store_id]
|
|
183
|
-
updated = False
|
|
184
|
-
is_current = False
|
|
185
|
-
for sid in ids:
|
|
186
|
-
if sid is not None and sid in self.window.core.remote_store.google.items:
|
|
187
|
-
store = self.window.core.remote_store.google.items[sid]
|
|
188
|
-
if store is not None:
|
|
189
|
-
self.window.update_status(trans('status.sending'))
|
|
190
|
-
QApplication.processEvents()
|
|
191
|
-
self.refresh_store(store)
|
|
192
|
-
updated = True
|
|
193
|
-
if self.current == sid:
|
|
194
|
-
is_current = True
|
|
195
|
-
if updated:
|
|
196
|
-
self.window.update_status(trans('status.finished'))
|
|
197
|
-
self.update()
|
|
198
|
-
if is_current:
|
|
199
|
-
self.update_files_list()
|
|
200
|
-
|
|
201
|
-
def update_current(self):
|
|
202
|
-
"""Update current store values in the UI"""
|
|
203
|
-
if self.current is not None and self.window.core.remote_store.google.has(self.current):
|
|
204
|
-
store = self.window.core.remote_store.google.items[self.current]
|
|
205
|
-
option = copy.deepcopy(self.get_option("status"))
|
|
206
|
-
option["value"] = json.dumps(store.status, indent=4)
|
|
207
|
-
self.window.controller.config.apply(self.id, "status", option)
|
|
208
|
-
|
|
209
|
-
option = copy.deepcopy(self.get_option("name"))
|
|
210
|
-
option["value"] = store.name
|
|
211
|
-
self.window.controller.config.apply(self.id, "name", option)
|
|
212
|
-
|
|
213
|
-
def save_btn(self):
|
|
214
|
-
"""Save editor and refresh"""
|
|
215
|
-
self.window.update_status("Saving...")
|
|
216
|
-
self.save()
|
|
217
|
-
self.refresh_status()
|
|
218
|
-
self.window.update_status("Saved.")
|
|
219
|
-
|
|
220
|
-
def save(self, persist: bool = True):
|
|
221
|
-
"""
|
|
222
|
-
Save editor data to local store and (if possible) remote
|
|
223
|
-
|
|
224
|
-
:param persist: persist to file and close dialog
|
|
225
|
-
"""
|
|
226
|
-
if self.current is not None:
|
|
227
|
-
current = self.window.core.remote_store.google.items[self.current].to_dict()
|
|
228
|
-
options = copy.deepcopy(self.get_options())
|
|
229
|
-
data_dict = {}
|
|
230
|
-
for key in options:
|
|
231
|
-
if key == "status":
|
|
232
|
-
data_dict[key] = current[key]
|
|
233
|
-
continue
|
|
234
|
-
value = self.window.controller.config.get_value(
|
|
235
|
-
parent_id="remote_store.google",
|
|
236
|
-
key=key,
|
|
237
|
-
option=options[key],
|
|
238
|
-
)
|
|
239
|
-
data_dict[key] = value
|
|
240
|
-
self.window.core.remote_store.google.items[self.current].from_dict(data_dict)
|
|
241
|
-
|
|
242
|
-
if persist:
|
|
243
|
-
self.window.update_status(trans('status.sending'))
|
|
244
|
-
QApplication.processEvents()
|
|
245
|
-
if self.current is not None:
|
|
246
|
-
# No remote patch endpoint; we save locally and fetch remote for status
|
|
247
|
-
store = self.window.core.remote_store.google.update(
|
|
248
|
-
self.window.core.remote_store.google.items[self.current]
|
|
249
|
-
)
|
|
250
|
-
if store is None:
|
|
251
|
-
self.window.update_status(trans('status.error'))
|
|
252
|
-
self.window.ui.dialogs.alert("Failed to save File Search store")
|
|
253
|
-
return
|
|
254
|
-
|
|
255
|
-
self.update()
|
|
256
|
-
self.window.update_status(trans("info.settings.saved"))
|
|
257
|
-
self.restore_selection()
|
|
258
|
-
self.update_files_list()
|
|
259
|
-
|
|
260
|
-
def reload_items(self):
|
|
261
|
-
"""Reload list items"""
|
|
262
|
-
items = self.window.core.remote_store.google.items
|
|
263
|
-
self.window.remote_store_google.update_list("remote_store.google.list", items)
|
|
264
|
-
self.restore_selection()
|
|
265
|
-
|
|
266
|
-
def restore_selection(self):
|
|
267
|
-
"""Restore selection"""
|
|
268
|
-
if self.current is not None:
|
|
269
|
-
idx = self.get_tab_by_id(self.current)
|
|
270
|
-
if idx is not None:
|
|
271
|
-
self.set_by_tab(idx)
|
|
272
|
-
|
|
273
|
-
def select(self, idx: int):
|
|
274
|
-
"""Select store by index"""
|
|
275
|
-
self.save(persist=False)
|
|
276
|
-
self.current = self.get_by_tab_idx(idx)
|
|
277
|
-
self.init()
|
|
278
|
-
self.update_files_list()
|
|
279
|
-
|
|
280
|
-
def new(self, name = "", force: bool = False):
|
|
281
|
-
"""
|
|
282
|
-
Create new File Search store
|
|
283
|
-
|
|
284
|
-
:param name: store name
|
|
285
|
-
:param force: force create without confirmation
|
|
286
|
-
"""
|
|
287
|
-
if not force:
|
|
288
|
-
self.window.ui.dialog['create'].id = 'remote_store.google.new'
|
|
289
|
-
self.window.ui.dialog['create'].input.setText("New file search store")
|
|
290
|
-
self.window.ui.dialog['create'].current = "New file search store"
|
|
291
|
-
self.window.ui.dialog['create'].show()
|
|
292
|
-
return
|
|
293
|
-
|
|
294
|
-
self.window.ui.dialog['create'].close()
|
|
295
|
-
self.window.update_status(trans('status.sending'))
|
|
296
|
-
QApplication.processEvents()
|
|
297
|
-
|
|
298
|
-
store = self.window.core.remote_store.google.create(name)
|
|
299
|
-
if store is None:
|
|
300
|
-
self.window.update_status(trans('status.error'))
|
|
301
|
-
self.window.ui.dialogs.alert("Failed to create new File Search store")
|
|
302
|
-
return
|
|
303
|
-
|
|
304
|
-
self.window.update_status(trans('status.finished'))
|
|
305
|
-
|
|
306
|
-
self.window.core.remote_store.google.update(store)
|
|
307
|
-
self.update()
|
|
308
|
-
|
|
309
|
-
self.current = store.id
|
|
310
|
-
idx = self.get_tab_by_id(self.current)
|
|
311
|
-
self.set_by_tab(idx)
|
|
312
|
-
self.init()
|
|
313
|
-
self.restore_selection()
|
|
314
|
-
self.refresh_by_store_id(store.id)
|
|
315
|
-
self.update_files_list()
|
|
316
|
-
|
|
317
|
-
def delete_by_idx(self, idx: Union[int, list], force: bool = False):
|
|
318
|
-
"""
|
|
319
|
-
Delete store(s) by index
|
|
320
|
-
|
|
321
|
-
:param idx: index or list of indexes
|
|
322
|
-
:param force: force confirm
|
|
323
|
-
"""
|
|
324
|
-
store_ids = []
|
|
325
|
-
ids = idx if isinstance(idx, list) else [idx]
|
|
326
|
-
for i in ids:
|
|
327
|
-
store_id = self.get_by_tab_idx(i)
|
|
328
|
-
if store_id is not None:
|
|
329
|
-
store_ids.append(store_id)
|
|
330
|
-
self.delete(store_ids, force=force)
|
|
331
|
-
|
|
332
|
-
def delete(self, store_id: Optional[Union[str, list]] = None, force: bool = False):
|
|
333
|
-
"""
|
|
334
|
-
Delete store(s) by ID
|
|
335
|
-
|
|
336
|
-
:param store_id: id or list
|
|
337
|
-
:param force: force confirm
|
|
338
|
-
"""
|
|
339
|
-
if not force:
|
|
340
|
-
self.window.ui.dialogs.confirm(
|
|
341
|
-
type="remote_store.google.delete",
|
|
342
|
-
id=store_id,
|
|
343
|
-
msg=trans("dialog.remote_store.delete.confirm"),
|
|
344
|
-
)
|
|
345
|
-
return
|
|
346
|
-
|
|
347
|
-
if store_id is None:
|
|
348
|
-
self.window.ui.dialogs.alert("Please select File Search store first.")
|
|
349
|
-
return
|
|
350
|
-
|
|
351
|
-
self.window.update_status(trans('status.sending'))
|
|
352
|
-
updated = False
|
|
353
|
-
QApplication.processEvents()
|
|
354
|
-
ids = store_id if isinstance(store_id, list) else [store_id]
|
|
355
|
-
for sid in ids:
|
|
356
|
-
if self.current == sid:
|
|
357
|
-
self.current = None
|
|
358
|
-
try:
|
|
359
|
-
print("Deleting store: {}".format(sid))
|
|
360
|
-
if self.window.core.remote_store.google.delete(sid):
|
|
361
|
-
self.window.controller.assistant.batch.remove_store_from_assistants(sid)
|
|
362
|
-
self.window.update_status(trans('status.deleted'))
|
|
363
|
-
self.window.core.remote_store.google.save()
|
|
364
|
-
updated = True
|
|
365
|
-
else:
|
|
366
|
-
self.window.update_status(trans('status.error'))
|
|
367
|
-
except Exception as e:
|
|
368
|
-
self.window.update_status(trans('status.error'))
|
|
369
|
-
self.window.ui.dialogs.alert(e)
|
|
370
|
-
if updated:
|
|
371
|
-
self.window.controller.assistant.files.update()
|
|
372
|
-
self.update()
|
|
373
|
-
self.init()
|
|
374
|
-
self.restore_selection()
|
|
375
|
-
self.update_files_list()
|
|
376
|
-
|
|
377
|
-
def set_by_tab(self, idx: int):
|
|
378
|
-
"""Set current by list index"""
|
|
379
|
-
store_idx = 0
|
|
380
|
-
for id in self.window.core.remote_store.google.get_ids():
|
|
381
|
-
if self.window.core.remote_store.google.is_hidden(id):
|
|
382
|
-
continue
|
|
383
|
-
if store_idx == idx:
|
|
384
|
-
self.current = id
|
|
385
|
-
break
|
|
386
|
-
store_idx += 1
|
|
387
|
-
current = self.window.ui.models['remote_store.google.list'].index(idx, 0)
|
|
388
|
-
self.window.ui.nodes['remote_store.google.list'].setCurrentIndex(current)
|
|
389
|
-
|
|
390
|
-
def set_tab_by_id(self, store_id: str):
|
|
391
|
-
"""Set current list to id"""
|
|
392
|
-
idx = self.get_tab_idx(store_id)
|
|
393
|
-
current = self.window.ui.models['remote_store.google.list'].index(idx, 0)
|
|
394
|
-
self.window.ui.nodes['remote_store.google.list'].setCurrentIndex(current)
|
|
395
|
-
|
|
396
|
-
def get_tab_idx(self, store_id: str) -> int:
|
|
397
|
-
"""Get list index by id"""
|
|
398
|
-
store_idx = None
|
|
399
|
-
i = 0
|
|
400
|
-
for id in self.window.core.remote_store.google.get_ids():
|
|
401
|
-
if self.window.core.remote_store.google.is_hidden(id):
|
|
402
|
-
continue
|
|
403
|
-
if id == store_id:
|
|
404
|
-
store_idx = i
|
|
405
|
-
break
|
|
406
|
-
i += 1
|
|
407
|
-
return store_idx
|
|
408
|
-
|
|
409
|
-
def get_tab_by_id(self, store_id: str) -> int:
|
|
410
|
-
"""Get list index by id"""
|
|
411
|
-
idx = None
|
|
412
|
-
i = 0
|
|
413
|
-
for id in self.window.core.remote_store.google.get_ids():
|
|
414
|
-
if self.window.core.remote_store.google.is_hidden(id):
|
|
415
|
-
continue
|
|
416
|
-
if id == store_id:
|
|
417
|
-
idx = i
|
|
418
|
-
break
|
|
419
|
-
i += 1
|
|
420
|
-
return idx
|
|
421
|
-
|
|
422
|
-
def get_by_tab_idx(self, idx: int) -> Optional[str]:
|
|
423
|
-
"""Get id by list index"""
|
|
424
|
-
store_idx = 0
|
|
425
|
-
for id in self.window.core.remote_store.google.get_ids():
|
|
426
|
-
if self.window.core.remote_store.google.is_hidden(id):
|
|
427
|
-
continue
|
|
428
|
-
if store_idx == idx:
|
|
429
|
-
return id
|
|
430
|
-
store_idx += 1
|
|
431
|
-
return None
|
|
432
|
-
|
|
433
|
-
def get_first_visible(self) -> Optional[str]:
|
|
434
|
-
"""Get first visible store id"""
|
|
435
|
-
for id in self.window.core.remote_store.google.get_ids():
|
|
436
|
-
if not self.window.core.remote_store.google.is_hidden(id):
|
|
437
|
-
return id
|
|
438
|
-
return None
|
|
439
|
-
|
|
440
|
-
def open_by_idx(self, idx: int):
|
|
441
|
-
store = self.window.core.remote_store.google.get_by_idx(idx)
|
|
442
|
-
if store is None:
|
|
443
|
-
return
|
|
444
|
-
self.current = store
|
|
445
|
-
self.open(force=True)
|
|
446
|
-
|
|
447
|
-
def update(self):
|
|
448
|
-
"""Update editor"""
|
|
449
|
-
self.reload_items()
|
|
450
|
-
self.window.controller.assistant.editor.update_store_list()
|
|
451
|
-
self.update_files_list()
|
|
452
|
-
|
|
453
|
-
def set_hide_thread(self, state: bool):
|
|
454
|
-
"""Toggle show thread stores"""
|
|
455
|
-
self.window.core.config.set("remote_store.google.hide_threads", state)
|
|
456
|
-
self.update()
|
|
457
|
-
|
|
458
|
-
# ==================== Files (Documents) ====================
|
|
459
|
-
|
|
460
|
-
def update_files_list(self):
|
|
461
|
-
"""
|
|
462
|
-
Update files list (documents) for the current store from local DB
|
|
463
|
-
"""
|
|
464
|
-
model_id = 'remote_store.google.files.list'
|
|
465
|
-
if model_id not in self.window.ui.models:
|
|
466
|
-
return
|
|
467
|
-
model = self.window.ui.models[model_id]
|
|
468
|
-
try:
|
|
469
|
-
model.removeRows(0, model.rowCount())
|
|
470
|
-
except Exception:
|
|
471
|
-
pass
|
|
472
|
-
|
|
473
|
-
self._files_row_to_id = []
|
|
474
|
-
|
|
475
|
-
if self.current is None:
|
|
476
|
-
return
|
|
477
|
-
|
|
478
|
-
files_db = self.window.core.remote_store.google.files
|
|
479
|
-
if files_db is None:
|
|
480
|
-
return
|
|
481
|
-
|
|
482
|
-
try:
|
|
483
|
-
store_files = files_db.get_by_store_or_thread(self.current, None) or {}
|
|
484
|
-
except Exception as e:
|
|
485
|
-
self.window.core.debug.log(e)
|
|
486
|
-
store_files = {}
|
|
487
|
-
|
|
488
|
-
i = 0
|
|
489
|
-
for file_id, file_obj in store_files.items():
|
|
490
|
-
if isinstance(file_obj, dict):
|
|
491
|
-
data = file_obj
|
|
492
|
-
else:
|
|
493
|
-
data = {}
|
|
494
|
-
for key in ('id', 'file_id', 'name', 'filename', 'bytes', 'size', 'usage_bytes', 'status'):
|
|
495
|
-
try:
|
|
496
|
-
if hasattr(file_obj, key):
|
|
497
|
-
data[key] = getattr(file_obj, key)
|
|
498
|
-
except Exception:
|
|
499
|
-
pass
|
|
500
|
-
if not data and hasattr(file_obj, 'to_dict'):
|
|
501
|
-
try:
|
|
502
|
-
data = file_obj.to_dict()
|
|
503
|
-
except Exception:
|
|
504
|
-
data = {}
|
|
505
|
-
|
|
506
|
-
name = data.get('name') or data.get('filename') or file_id
|
|
507
|
-
size_val = data.get('size')
|
|
508
|
-
|
|
509
|
-
size_txt = ""
|
|
510
|
-
try:
|
|
511
|
-
if size_val:
|
|
512
|
-
size_txt = self.window.core.filesystem.sizeof_fmt(int(size_val))
|
|
513
|
-
except Exception:
|
|
514
|
-
pass
|
|
515
|
-
|
|
516
|
-
extra = []
|
|
517
|
-
if size_txt:
|
|
518
|
-
extra.append(size_txt)
|
|
519
|
-
label = name
|
|
520
|
-
if extra:
|
|
521
|
-
label += " ({})".format(", ".join(extra))
|
|
522
|
-
|
|
523
|
-
item = QStandardItem(label)
|
|
524
|
-
item.setEditable(False)
|
|
525
|
-
item.setData(file_id, Qt.UserRole)
|
|
526
|
-
model.setItem(i, 0, item)
|
|
527
|
-
self._files_row_to_id.append(data['file_id'] if 'file_id' in data else file_id)
|
|
528
|
-
i += 1
|
|
529
|
-
|
|
530
|
-
def delete_file_by_idx(self, idx: int, force: bool = False):
|
|
531
|
-
"""
|
|
532
|
-
Delete a single document from the current store.
|
|
533
|
-
|
|
534
|
-
:param idx: row index
|
|
535
|
-
:param force: skip confirm
|
|
536
|
-
"""
|
|
537
|
-
if self.current is None:
|
|
538
|
-
self.window.ui.dialogs.alert("Please select File Search store first.")
|
|
539
|
-
return
|
|
540
|
-
|
|
541
|
-
if not force:
|
|
542
|
-
self.window.ui.dialogs.confirm(
|
|
543
|
-
type='remote_store.google.file.delete',
|
|
544
|
-
id=idx,
|
|
545
|
-
msg=trans('confirm.remote_store.file.delete'),
|
|
546
|
-
)
|
|
547
|
-
return
|
|
548
|
-
|
|
549
|
-
model_id = 'remote_store.google.files.list'
|
|
550
|
-
if model_id not in self.window.ui.models:
|
|
551
|
-
return
|
|
552
|
-
if idx < 0 or idx >= len(self._files_row_to_id):
|
|
553
|
-
return
|
|
554
|
-
|
|
555
|
-
file_id = self._files_row_to_id[idx]
|
|
556
|
-
if not file_id:
|
|
557
|
-
return
|
|
558
|
-
|
|
559
|
-
self.window.update_status(trans('status.sending'))
|
|
560
|
-
QApplication.processEvents()
|
|
561
|
-
|
|
562
|
-
try:
|
|
563
|
-
api = self.window.core.api.google.store
|
|
564
|
-
removed = False
|
|
565
|
-
|
|
566
|
-
if hasattr(api, 'remove_store_file'):
|
|
567
|
-
try:
|
|
568
|
-
api.remove_store_file(self.current, file_id)
|
|
569
|
-
removed = True
|
|
570
|
-
except Exception as e:
|
|
571
|
-
self.window.core.debug.log(e)
|
|
572
|
-
|
|
573
|
-
if not removed and hasattr(api, 'delete_store_file'):
|
|
574
|
-
try:
|
|
575
|
-
api.delete_store_file(self.current, file_id)
|
|
576
|
-
removed = True
|
|
577
|
-
except Exception as e:
|
|
578
|
-
self.window.core.debug.log(e)
|
|
579
|
-
|
|
580
|
-
if not removed:
|
|
581
|
-
raise RuntimeError("Remove file API not available.")
|
|
582
|
-
|
|
583
|
-
try:
|
|
584
|
-
self.window.core.remote_store.google.files.delete_by_file_id(file_id)
|
|
585
|
-
except Exception as e:
|
|
586
|
-
self.window.core.debug.log(e)
|
|
587
|
-
|
|
588
|
-
try:
|
|
589
|
-
self.window.ui.models[model_id].removeRow(idx)
|
|
590
|
-
try:
|
|
591
|
-
del self._files_row_to_id[idx]
|
|
592
|
-
except Exception:
|
|
593
|
-
pass
|
|
594
|
-
except Exception:
|
|
595
|
-
pass
|
|
596
|
-
|
|
597
|
-
# Ensure the list panel is in sync immediately
|
|
598
|
-
try:
|
|
599
|
-
self.update_files_list()
|
|
600
|
-
except Exception:
|
|
601
|
-
pass
|
|
602
|
-
|
|
603
|
-
try:
|
|
604
|
-
self.window.update_status("Refreshing status...")
|
|
605
|
-
QTimer.singleShot(1000, lambda: self.window.controller.remote_store.google.refresh_status())
|
|
606
|
-
except Exception as e:
|
|
607
|
-
self.window.core.debug.log(e)
|
|
608
|
-
|
|
609
|
-
self.window.update_status(trans('status.deleted'))
|
|
610
|
-
|
|
611
|
-
except Exception as e:
|
|
612
|
-
self.window.update_status(trans('status.error'))
|
|
613
|
-
self.window.ui.dialogs.alert("Failed to delete file: {}".format(e))
|
|
614
|
-
self.window.core.debug.log(e)
|
|
615
|
-
self.update_files_list()
|