pygpt-net 2.6.16__py3-none-any.whl → 2.6.17__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pygpt_net/CHANGELOG.txt +6 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/__init__.py +8 -2
- pygpt_net/controller/ctx/ctx.py +2 -2
- pygpt_net/controller/mode/mode.py +3 -2
- pygpt_net/controller/settings/profile.py +16 -3
- pygpt_net/controller/settings/workdir.py +184 -124
- pygpt_net/controller/theme/theme.py +11 -5
- pygpt_net/core/agents/runners/llama_workflow.py +0 -2
- pygpt_net/core/render/plain/body.py +10 -19
- pygpt_net/core/render/plain/renderer.py +27 -27
- pygpt_net/data/config/config.json +5 -5
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/ui/__init__.py +12 -10
- pygpt_net/ui/base/config_dialog.py +15 -10
- pygpt_net/ui/dialog/about.py +26 -18
- pygpt_net/ui/dialog/settings.py +75 -87
- pygpt_net/ui/dialog/workdir.py +7 -2
- pygpt_net/ui/main.py +5 -1
- pygpt_net/ui/widget/textarea/web.py +22 -16
- {pygpt_net-2.6.16.dist-info → pygpt_net-2.6.17.dist-info}/METADATA +11 -5
- {pygpt_net-2.6.16.dist-info → pygpt_net-2.6.17.dist-info}/RECORD +25 -25
- {pygpt_net-2.6.16.dist-info → pygpt_net-2.6.17.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.16.dist-info → pygpt_net-2.6.17.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.16.dist-info → pygpt_net-2.6.17.dist-info}/entry_points.txt +0 -0
pygpt_net/CHANGELOG.txt
CHANGED
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.08.
|
|
9
|
+
# Updated Date: 2025.08.21 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.6.
|
|
17
|
-
__build__ = "2025-08-
|
|
16
|
+
__version__ = "2.6.17"
|
|
17
|
+
__build__ = "2025-08-21"
|
|
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"
|
pygpt_net/controller/__init__.py
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date:
|
|
9
|
+
# Updated Date: 2025.08.20 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from pygpt_net.controller.access import Access
|
|
@@ -147,8 +147,12 @@ class Controller:
|
|
|
147
147
|
"""Reload components"""
|
|
148
148
|
self.reloading = True # lock
|
|
149
149
|
|
|
150
|
+
print("Reloading components... please wait...")
|
|
151
|
+
|
|
150
152
|
mem_clean() # try to clean memory
|
|
151
153
|
|
|
154
|
+
prev_theme = self.window.core.config.get("theme")
|
|
155
|
+
|
|
152
156
|
self.window.core.reload() # db, config, patch, etc.
|
|
153
157
|
self.ui.tabs.reload()
|
|
154
158
|
self.ctx.reload()
|
|
@@ -175,6 +179,8 @@ class Controller:
|
|
|
175
179
|
self.ctx.reload_after()
|
|
176
180
|
self.ui.tabs.restore_data() # restore opened tabs data
|
|
177
181
|
self.kernel.restart()
|
|
178
|
-
self.theme.reload_all()
|
|
182
|
+
self.theme.reload_all(prev_theme=prev_theme) # do not reload theme if no change
|
|
179
183
|
|
|
180
184
|
self.reloading = False # unlock
|
|
185
|
+
|
|
186
|
+
print("[OK] Components reloaded successfully.")
|
pygpt_net/controller/ctx/ctx.py
CHANGED
|
@@ -22,7 +22,7 @@ from .summarizer import Summarizer
|
|
|
22
22
|
from .extra import Extra
|
|
23
23
|
|
|
24
24
|
from pygpt_net.utils import trans
|
|
25
|
-
from
|
|
25
|
+
from pygpt_net.core.types import MODE_ASSISTANT
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class Ctx:
|
|
@@ -79,7 +79,7 @@ class Ctx:
|
|
|
79
79
|
self.select_by_current(focus=True) # scroll to current ctx
|
|
80
80
|
|
|
81
81
|
# focus input after loading
|
|
82
|
-
QTimer.singleShot(
|
|
82
|
+
QTimer.singleShot(2000, self.window.controller.chat.common.focus_input)
|
|
83
83
|
|
|
84
84
|
def update_mode_in_current(self):
|
|
85
85
|
"""Update current ctx mode"""
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.20 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from pygpt_net.core.events import Event, AppEvent
|
|
@@ -98,7 +98,8 @@ class Mode:
|
|
|
98
98
|
c.model.select_current()
|
|
99
99
|
|
|
100
100
|
# set status: ready
|
|
101
|
-
|
|
101
|
+
if not c.reloading:
|
|
102
|
+
w.update_status(trans('status.started'))
|
|
102
103
|
|
|
103
104
|
# if assistant mode then update ctx label
|
|
104
105
|
if mode == "assistant":
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.20 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
@@ -16,6 +16,7 @@ from typing import Optional, Dict, Any
|
|
|
16
16
|
from PySide6.QtCore import Slot, QTimer
|
|
17
17
|
from PySide6.QtGui import QAction
|
|
18
18
|
|
|
19
|
+
from pygpt_net.core.types import MODE_CHAT
|
|
19
20
|
from pygpt_net.utils import trans
|
|
20
21
|
|
|
21
22
|
|
|
@@ -52,7 +53,8 @@ class Profile:
|
|
|
52
53
|
self,
|
|
53
54
|
uuid: str,
|
|
54
55
|
force: bool = False,
|
|
55
|
-
save_current: bool = True
|
|
56
|
+
save_current: bool = True,
|
|
57
|
+
on_finish: Optional[callable] = None
|
|
56
58
|
):
|
|
57
59
|
"""
|
|
58
60
|
Switch profile
|
|
@@ -60,6 +62,7 @@ class Profile:
|
|
|
60
62
|
:param uuid: Profile UUID
|
|
61
63
|
:param force: Force switch
|
|
62
64
|
:param save_current: Save current profile
|
|
65
|
+
:param on_finish: Callback function to call after switch
|
|
63
66
|
"""
|
|
64
67
|
current = self.window.core.config.profile.get_current()
|
|
65
68
|
if uuid == current and not force:
|
|
@@ -103,6 +106,7 @@ class Profile:
|
|
|
103
106
|
self.update_list()
|
|
104
107
|
self.window.ui.update_title()
|
|
105
108
|
self.window.update_status(trans("dialog.profile.status.changed") + ": " + name)
|
|
109
|
+
self.window.ui.dialogs.close('profile.item')
|
|
106
110
|
self.select_current_on_list()
|
|
107
111
|
|
|
108
112
|
def select_current_on_list(self):
|
|
@@ -291,10 +295,19 @@ class Profile:
|
|
|
291
295
|
|
|
292
296
|
:param uuid: profile UUID
|
|
293
297
|
"""
|
|
294
|
-
self.switch(uuid, force=True)
|
|
298
|
+
self.switch(uuid, force=True, on_finish=self.after_create_finish)
|
|
299
|
+
|
|
300
|
+
def after_create_finish(self, uuid: str):
|
|
301
|
+
"""
|
|
302
|
+
After profile creation
|
|
303
|
+
|
|
304
|
+
:param uuid: profile UUID
|
|
305
|
+
"""
|
|
295
306
|
self.window.ui.dialogs.close('profile.item')
|
|
296
307
|
self.update_menu()
|
|
297
308
|
self.update_list()
|
|
309
|
+
self.window.ui.update_title()
|
|
310
|
+
self.window.controller.mode.select(MODE_CHAT)
|
|
298
311
|
|
|
299
312
|
def dismiss_update(self):
|
|
300
313
|
"""Dismiss update dialog"""
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.20 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
@@ -16,6 +16,7 @@ from typing import Optional
|
|
|
16
16
|
from uuid import uuid4
|
|
17
17
|
|
|
18
18
|
from PySide6.QtCore import QObject, QRunnable, Signal, Slot
|
|
19
|
+
from PySide6.QtWidgets import QApplication
|
|
19
20
|
|
|
20
21
|
from pygpt_net.utils import trans
|
|
21
22
|
|
|
@@ -32,7 +33,7 @@ class WorkerSignals(QObject):
|
|
|
32
33
|
updateStatus = Signal(str) # update status in dialog
|
|
33
34
|
updateGlobalStatus = Signal(str) # update global status
|
|
34
35
|
alert = Signal(object) # dialog alert
|
|
35
|
-
|
|
36
|
+
after_migrate = Signal(bool, str, str, str) # result, profile_name, current_path, new_path
|
|
36
37
|
confirm = Signal(str, str, str) # confirm dialog (action, path, message)
|
|
37
38
|
restored = Signal(str) # after restoring workdir
|
|
38
39
|
updated = Signal(str) # after updating workdir
|
|
@@ -68,12 +69,8 @@ class WorkdirWorker(QRunnable):
|
|
|
68
69
|
@Slot()
|
|
69
70
|
def run(self):
|
|
70
71
|
try:
|
|
71
|
-
if self.action == "
|
|
72
|
-
self.worker_update()
|
|
73
|
-
elif self.action == "migrate":
|
|
72
|
+
if self.action == "migrate":
|
|
74
73
|
self.worker_migrate()
|
|
75
|
-
elif self.action == "restore":
|
|
76
|
-
self.worker_restore()
|
|
77
74
|
elif self.action == "delete":
|
|
78
75
|
self.worker_delete_files()
|
|
79
76
|
elif self.action == "duplicate":
|
|
@@ -116,7 +113,7 @@ class WorkdirWorker(QRunnable):
|
|
|
116
113
|
if not os.path.exists(path) or not os.path.isdir(path):
|
|
117
114
|
self.signals.alert.emit(trans("dialog.profile.alert.path.not_exists"))
|
|
118
115
|
return
|
|
119
|
-
print("Clearing workdir: "
|
|
116
|
+
print(f"Clearing workdir: {path}")
|
|
120
117
|
self.window.core.filesystem.clear_workdir(
|
|
121
118
|
path,
|
|
122
119
|
remove_db=remove_db,
|
|
@@ -149,7 +146,7 @@ class WorkdirWorker(QRunnable):
|
|
|
149
146
|
# copy files from workdir
|
|
150
147
|
path_from = profile['workdir'].replace("%HOME%", str(Path.home()))
|
|
151
148
|
path_to = new_path
|
|
152
|
-
print("Copying all files from {} to: {}"
|
|
149
|
+
print(f"Copying all files from {path_from} to: {path_to}")
|
|
153
150
|
self.signals.updateGlobalStatus.emit("Copying files...")
|
|
154
151
|
result = self.window.core.filesystem.copy_workdir(
|
|
155
152
|
path_from,
|
|
@@ -175,7 +172,7 @@ class WorkdirWorker(QRunnable):
|
|
|
175
172
|
profile = profiles[uuid]
|
|
176
173
|
path = profile['workdir'].replace("%HOME%", str(Path.home()))
|
|
177
174
|
if not os.path.exists(path) or not os.path.isdir(path):
|
|
178
|
-
self.signals.alert.emit("Directory not exists
|
|
175
|
+
self.signals.alert.emit(f"Directory not exists: {path}")
|
|
179
176
|
return
|
|
180
177
|
print("Clearing workdir: ", path)
|
|
181
178
|
self.window.core.db.close()
|
|
@@ -186,53 +183,7 @@ class WorkdirWorker(QRunnable):
|
|
|
186
183
|
)
|
|
187
184
|
if uuid == current:
|
|
188
185
|
self.signals.switch.emit(uuid) # switch to profile
|
|
189
|
-
self.signals.updateGlobalStatus.emit("Profile cleared:
|
|
190
|
-
|
|
191
|
-
def worker_update(self):
|
|
192
|
-
"""Switch working directory to the existing one"""
|
|
193
|
-
print("\n====================")
|
|
194
|
-
print("Changing workdir to: ", self.path)
|
|
195
|
-
print("====================\n")
|
|
196
|
-
current_path = self.window.core.config.get_user_path()
|
|
197
|
-
default_path = self.window.core.config.get_base_workdir()
|
|
198
|
-
|
|
199
|
-
if self.force:
|
|
200
|
-
self.signals.updateStatus.emit(trans("dialog.workdir.result.wait"))
|
|
201
|
-
|
|
202
|
-
lock_file = os.path.join(default_path, 'path.cfg') # put "path.cfg"
|
|
203
|
-
lock_path = self.path.replace(str(Path.home()), "%HOME%")
|
|
204
|
-
if self.path == default_path:
|
|
205
|
-
lock_path = "" # set empty if default dir
|
|
206
|
-
with open(lock_file, 'w', encoding='utf-8') as f:
|
|
207
|
-
f.write(lock_path)
|
|
208
|
-
|
|
209
|
-
# update path in current profile
|
|
210
|
-
self.window.core.config.profile.update_current_workdir(self.path)
|
|
211
|
-
|
|
212
|
-
# reload config
|
|
213
|
-
self.window.core.config.set_workdir(self.path, reload=True)
|
|
214
|
-
self.window.core.config.set('license.accepted', True) # accept license to prevent show dialog again
|
|
215
|
-
|
|
216
|
-
# reload components
|
|
217
|
-
if self.force:
|
|
218
|
-
try:
|
|
219
|
-
self.signals.reload.emit()
|
|
220
|
-
success_msg = trans("dialog.workdir.result.success").format(path=self.path)
|
|
221
|
-
self.signals.updateStatus.emit(success_msg)
|
|
222
|
-
self.signals.alert.emit(success_msg)
|
|
223
|
-
except Exception as e:
|
|
224
|
-
self.window.core.debug.log(e)
|
|
225
|
-
self.signals.alert.emit(str(e))
|
|
226
|
-
print("Error reloading components: ", e)
|
|
227
|
-
self.worker_restore(custom_current=current_path)
|
|
228
|
-
self.window.controller.reloading = False # unlock
|
|
229
|
-
else:
|
|
230
|
-
# always reload
|
|
231
|
-
self.signals.reload.emit()
|
|
232
|
-
|
|
233
|
-
# update profile after workdir change
|
|
234
|
-
if self.profile_name:
|
|
235
|
-
self.signals.updated.emit(self.profile_name)
|
|
186
|
+
self.signals.updateGlobalStatus.emit(f"Profile cleared: {profile['name']}")
|
|
236
187
|
|
|
237
188
|
def worker_migrate(self):
|
|
238
189
|
"""Migrate working directory"""
|
|
@@ -267,7 +218,7 @@ class WorkdirWorker(QRunnable):
|
|
|
267
218
|
|
|
268
219
|
self.signals.hideStatus.emit()
|
|
269
220
|
self.window.controller.settings.workdir.busy = True
|
|
270
|
-
print("Migrating workdir from:
|
|
221
|
+
print(f"Migrating workdir from: {current} to: {self.path}...")
|
|
271
222
|
|
|
272
223
|
# check if path exists
|
|
273
224
|
if not os.path.exists(self.path) or not os.path.isdir(self.path):
|
|
@@ -289,6 +240,8 @@ class WorkdirWorker(QRunnable):
|
|
|
289
240
|
return
|
|
290
241
|
|
|
291
242
|
# copy workdir
|
|
243
|
+
self.signals.updateGlobalStatus.emit(trans("dialog.workdir.result.wait"))
|
|
244
|
+
QApplication.processEvents() # process events to update UI
|
|
292
245
|
try:
|
|
293
246
|
result = self.window.core.filesystem.copy_workdir(current, self.path)
|
|
294
247
|
except Exception as e:
|
|
@@ -297,46 +250,28 @@ class WorkdirWorker(QRunnable):
|
|
|
297
250
|
print("Error migrating workdir: ", e)
|
|
298
251
|
result = False
|
|
299
252
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
# remove old workdir
|
|
303
|
-
self.window.core.debug.info("Clearing old workdir: {}".format(current))
|
|
304
|
-
try:
|
|
305
|
-
# allow errors here
|
|
306
|
-
self.window.core.filesystem.clear_workdir(current)
|
|
307
|
-
except Exception as e:
|
|
308
|
-
self.window.core.debug.log(e)
|
|
309
|
-
print("Error clearing old workdir: ", e)
|
|
253
|
+
# reload UI, config, etc.
|
|
254
|
+
self.signals.after_migrate.emit(result, self.profile_name, current, self.path)
|
|
310
255
|
|
|
311
|
-
# update workdir to new path
|
|
312
|
-
self.worker_update()
|
|
313
|
-
success_msg = trans("dialog.workdir.result.success").format(path=self.path)
|
|
314
|
-
print(success_msg)
|
|
315
|
-
self.signals.updateStatus.emit(success_msg)
|
|
316
|
-
self.signals.alert.emit(success_msg)
|
|
317
|
-
except Exception as e:
|
|
318
|
-
self.window.core.debug.log(e)
|
|
319
|
-
self.signals.alert.emit(str(e))
|
|
320
|
-
print("Error migrating workdir: ", e)
|
|
321
|
-
self.worker_restore(custom_current=current)
|
|
322
|
-
self.window.controller.reloading = False
|
|
323
|
-
else:
|
|
324
|
-
self.signals.updateStatus.emit(trans("dialog.workdir.result.failed"))
|
|
325
|
-
self.signals.alert.emit(trans("dialog.workdir.result.failed"))
|
|
326
|
-
self.worker_restore(custom_current=current)
|
|
327
|
-
self.window.controller.reloading = False
|
|
328
256
|
|
|
329
|
-
|
|
330
|
-
|
|
257
|
+
class Workdir:
|
|
258
|
+
def __init__(self, window=None):
|
|
259
|
+
"""
|
|
260
|
+
Workdir controller
|
|
331
261
|
|
|
332
|
-
|
|
262
|
+
:param window: window instance
|
|
333
263
|
"""
|
|
334
|
-
|
|
264
|
+
self.window = window
|
|
265
|
+
self.is_dialog = False
|
|
266
|
+
self.busy = False
|
|
267
|
+
|
|
268
|
+
def rollback(self, current: str = None):
|
|
269
|
+
"""
|
|
270
|
+
Rollback to the previous working directory
|
|
335
271
|
|
|
336
|
-
:param
|
|
272
|
+
:param current: current working directory (optional)
|
|
337
273
|
"""
|
|
338
|
-
|
|
339
|
-
print("Reverting workdir to: ", current)
|
|
274
|
+
print(f"Reverting workdir to: {current}...")
|
|
340
275
|
self.window.core.config.set_workdir(current, reload=True)
|
|
341
276
|
default_path = self.window.core.config.get_base_workdir()
|
|
342
277
|
lock_file = os.path.join(default_path, 'path.cfg')
|
|
@@ -345,23 +280,151 @@ class WorkdirWorker(QRunnable):
|
|
|
345
280
|
lock_path = ""
|
|
346
281
|
with open(lock_file, 'w', encoding='utf-8') as f:
|
|
347
282
|
f.write(lock_path)
|
|
348
|
-
self.
|
|
349
|
-
self.
|
|
350
|
-
self.
|
|
283
|
+
self.window.ui.dialogs.workdir.set_path(current)
|
|
284
|
+
self.window.ui.dialogs.workdir.show_status(f"Failed. Reverted to previous workdir: {current}.")
|
|
285
|
+
self.window.controller.reload()
|
|
351
286
|
self.window.core.config.profile.update_current_workdir(current)
|
|
352
287
|
|
|
288
|
+
def update_workdir(
|
|
289
|
+
self,
|
|
290
|
+
force: bool = False,
|
|
291
|
+
path: str = None
|
|
292
|
+
):
|
|
293
|
+
"""
|
|
294
|
+
Update working directory
|
|
353
295
|
|
|
354
|
-
|
|
355
|
-
|
|
296
|
+
:param force: boolean indicating if update should be forced (confirm)
|
|
297
|
+
:param path: new working directory to set
|
|
356
298
|
"""
|
|
357
|
-
|
|
299
|
+
print("\n====================")
|
|
300
|
+
print(f"Changing workdir to: {path}")
|
|
301
|
+
print("====================\n")
|
|
302
|
+
default_path = self.window.core.config.get_base_workdir()
|
|
303
|
+
if force:
|
|
304
|
+
self.window.ui.dialogs.workdir.show_status(trans("dialog.workdir.result.wait"))
|
|
358
305
|
|
|
359
|
-
|
|
306
|
+
lock_file = os.path.join(default_path, 'path.cfg') # put "path.cfg"
|
|
307
|
+
lock_path = path.replace(str(Path.home()), "%HOME%")
|
|
308
|
+
if path == default_path:
|
|
309
|
+
lock_path = "" # set empty if default dir
|
|
310
|
+
with open(lock_file, 'w', encoding='utf-8') as f:
|
|
311
|
+
f.write(lock_path)
|
|
312
|
+
|
|
313
|
+
# update path in current profile
|
|
314
|
+
self.window.core.config.profile.update_current_workdir(path)
|
|
315
|
+
|
|
316
|
+
# reload config
|
|
317
|
+
self.window.core.config.set_workdir(path, reload=True)
|
|
318
|
+
self.window.core.config.set('license.accepted', True) # accept license to prevent show dialog again
|
|
319
|
+
|
|
320
|
+
@Slot(bool, str, str, str)
|
|
321
|
+
def do_update(
|
|
322
|
+
self,
|
|
323
|
+
force: bool,
|
|
324
|
+
profile_name: str,
|
|
325
|
+
current_path: str,
|
|
326
|
+
new_path: str
|
|
327
|
+
) -> bool:
|
|
360
328
|
"""
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
329
|
+
Update working directory
|
|
330
|
+
|
|
331
|
+
:param force: boolean indicating if update should be forced (confirm)
|
|
332
|
+
:param profile_name: profile name to update after workdir change
|
|
333
|
+
:param current_path: current working directory before update
|
|
334
|
+
:param new_path: new working directory to set
|
|
335
|
+
:return: boolean indicating if update was successful
|
|
336
|
+
"""
|
|
337
|
+
self.update_workdir(
|
|
338
|
+
force=force,
|
|
339
|
+
path=new_path,
|
|
340
|
+
)
|
|
341
|
+
rollback = False
|
|
342
|
+
success = False
|
|
343
|
+
if force:
|
|
344
|
+
try:
|
|
345
|
+
self.window.ui.dialogs.workdir.show_status(trans("dialog.workdir.result.wait"))
|
|
346
|
+
self.window.controller.reload()
|
|
347
|
+
self.window.ui.dialogs.workdir.show_status(trans("dialog.workdir.result.wait"))
|
|
348
|
+
msg = trans("dialog.workdir.result.success").format(path=new_path)
|
|
349
|
+
self.window.ui.dialogs.workdir.show_status(msg)
|
|
350
|
+
self.window.ui.dialogs.alert(msg)
|
|
351
|
+
success = True
|
|
352
|
+
except Exception as e:
|
|
353
|
+
rollback = True
|
|
354
|
+
self.window.core.debug.log(e)
|
|
355
|
+
self.window.ui.dialogs.alert(str(e))
|
|
356
|
+
print("Error reloading components: ", e)
|
|
357
|
+
self.window.controller.reloading = False # unlock
|
|
358
|
+
else:
|
|
359
|
+
self.window.controller.reload() # reload only
|
|
360
|
+
|
|
361
|
+
if rollback: # if failed
|
|
362
|
+
self.rollback(current=current_path) # revert to previous workdir
|
|
363
|
+
else:
|
|
364
|
+
# update profile after workdir change
|
|
365
|
+
if profile_name:
|
|
366
|
+
self.window.controller.settings.profile.after_update(profile_name)
|
|
367
|
+
return success
|
|
368
|
+
|
|
369
|
+
@Slot(bool, str, str, str)
|
|
370
|
+
def do_migrate(
|
|
371
|
+
self,
|
|
372
|
+
result: bool,
|
|
373
|
+
profile_name: str,
|
|
374
|
+
current_path: str,
|
|
375
|
+
new_path: str
|
|
376
|
+
) -> bool:
|
|
377
|
+
"""
|
|
378
|
+
Handle migration result
|
|
379
|
+
|
|
380
|
+
:param result: boolean indicating if migration was successful
|
|
381
|
+
:param profile_name: profile name to update after migration
|
|
382
|
+
:param current_path: current working directory before migration
|
|
383
|
+
:param new_path: new working directory after migration
|
|
384
|
+
:return: boolean indicating if migration was successful
|
|
385
|
+
"""
|
|
386
|
+
success = False
|
|
387
|
+
if result:
|
|
388
|
+
try:
|
|
389
|
+
# update workdir to new path
|
|
390
|
+
success = self.do_update(
|
|
391
|
+
force=True,
|
|
392
|
+
profile_name=profile_name,
|
|
393
|
+
current_path=current_path,
|
|
394
|
+
new_path=new_path,
|
|
395
|
+
) # with rollback if failed
|
|
396
|
+
|
|
397
|
+
if not success:
|
|
398
|
+
raise Exception("Migration failed, workdir not updated.")
|
|
399
|
+
|
|
400
|
+
msg = trans("dialog.workdir.result.success").format(path=new_path)
|
|
401
|
+
self.window.ui.dialogs.workdir.show_status(msg)
|
|
402
|
+
self.window.ui.dialogs.alert(msg)
|
|
403
|
+
|
|
404
|
+
# remove old workdir only if success
|
|
405
|
+
self.window.core.debug.info(f"Clearing old workdir: {current_path}...")
|
|
406
|
+
try:
|
|
407
|
+
self.window.core.filesystem.clear_workdir(current_path) # allow errors here
|
|
408
|
+
self.window.core.debug.info(f"Old workdir cleared: {current_path}.")
|
|
409
|
+
except Exception as e:
|
|
410
|
+
self.window.core.debug.log(e)
|
|
411
|
+
print("Error clearing old workdir: ", e)
|
|
412
|
+
|
|
413
|
+
except Exception as e:
|
|
414
|
+
self.window.core.debug.log(e)
|
|
415
|
+
self.window.ui.dialogs.alert(str(e))
|
|
416
|
+
print("Error migrating workdir: ", e)
|
|
417
|
+
self.window.controller.reloading = False
|
|
418
|
+
else:
|
|
419
|
+
# if migration failed
|
|
420
|
+
self.window.ui.dialogs.workdir.show_status(trans("dialog.workdir.result.failed"))
|
|
421
|
+
self.window.ui.dialogs.alert(trans("dialog.workdir.result.failed"))
|
|
422
|
+
self.window.controller.reloading = False
|
|
423
|
+
|
|
424
|
+
self.window.controller.settings.workdir.busy = False
|
|
425
|
+
if success:
|
|
426
|
+
self.window.core.debug.info(f"Finished migrating workdir from: {current_path} to: {new_path}.")
|
|
427
|
+
return success
|
|
365
428
|
|
|
366
429
|
def change(self):
|
|
367
430
|
"""Change working directory (open dialog)"""
|
|
@@ -402,7 +465,7 @@ class Workdir:
|
|
|
402
465
|
:param profile_new_name: new profile name (optional, for duplicate action)
|
|
403
466
|
:param profile_new_path: new profile path (optional, for duplicate action)
|
|
404
467
|
"""
|
|
405
|
-
|
|
468
|
+
worker = WorkdirWorker(
|
|
406
469
|
window=self.window,
|
|
407
470
|
action=action,
|
|
408
471
|
path=path,
|
|
@@ -415,21 +478,21 @@ class Workdir:
|
|
|
415
478
|
)
|
|
416
479
|
|
|
417
480
|
# connect signals
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
481
|
+
worker.signals.updateGlobalStatus.connect(self.window.update_status)
|
|
482
|
+
worker.signals.updateStatus.connect(self.window.ui.dialogs.workdir.show_status)
|
|
483
|
+
worker.signals.hideStatus.connect(self.window.ui.dialogs.workdir.hide_status)
|
|
484
|
+
worker.signals.alert.connect(self.window.ui.dialogs.alert)
|
|
485
|
+
worker.signals.error.connect(lambda err: self.window.core.debug.log(f"Worker error: {err}"))
|
|
486
|
+
worker.signals.confirm.connect(self.window.ui.dialogs.confirm)
|
|
487
|
+
worker.signals.restored.connect(lambda current: self.window.ui.dialogs.workdir.set_path(current))
|
|
488
|
+
worker.signals.updated.connect(self.window.controller.settings.profile.after_update)
|
|
489
|
+
worker.signals.deleted.connect(self.window.controller.settings.profile.after_delete)
|
|
490
|
+
worker.signals.duplicated.connect(self.window.controller.settings.profile.after_duplicate)
|
|
491
|
+
worker.signals.switch.connect(self.window.controller.settings.profile.switch_current)
|
|
492
|
+
worker.signals.after_migrate.connect(self.do_migrate)
|
|
430
493
|
|
|
431
494
|
# start worker in thread pool
|
|
432
|
-
self.window.threadpool.start(
|
|
495
|
+
self.window.threadpool.start(worker)
|
|
433
496
|
|
|
434
497
|
def update(
|
|
435
498
|
self,
|
|
@@ -444,11 +507,11 @@ class Workdir:
|
|
|
444
507
|
:param force: force update (confirm)
|
|
445
508
|
:param profile_name: profile name (optional, for future use)
|
|
446
509
|
"""
|
|
447
|
-
self.
|
|
448
|
-
action="update",
|
|
449
|
-
path=path,
|
|
510
|
+
self.do_update(
|
|
450
511
|
force=force,
|
|
451
512
|
profile_name=profile_name,
|
|
513
|
+
current_path=self.window.core.config.get_user_path(),
|
|
514
|
+
new_path=path,
|
|
452
515
|
)
|
|
453
516
|
|
|
454
517
|
def migrate(
|
|
@@ -477,10 +540,7 @@ class Workdir:
|
|
|
477
540
|
|
|
478
541
|
:param current: current working directory
|
|
479
542
|
"""
|
|
480
|
-
self.
|
|
481
|
-
action="restore",
|
|
482
|
-
current=current,
|
|
483
|
-
)
|
|
543
|
+
self.rollback(current=current)
|
|
484
544
|
|
|
485
545
|
def delete_files(
|
|
486
546
|
self,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.20 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
@@ -248,8 +248,14 @@ class Theme:
|
|
|
248
248
|
"""
|
|
249
249
|
return self.common.get_style(element)
|
|
250
250
|
|
|
251
|
-
def reload_all(self):
|
|
252
|
-
"""
|
|
253
|
-
|
|
254
|
-
|
|
251
|
+
def reload_all(self, prev_theme: Optional[str] = None):
|
|
252
|
+
"""
|
|
253
|
+
Reload all
|
|
254
|
+
|
|
255
|
+
:param prev_theme: previous theme name
|
|
256
|
+
"""
|
|
257
|
+
current_theme = self.window.core.config.get('theme')
|
|
258
|
+
if not prev_theme or prev_theme != current_theme:
|
|
259
|
+
self.setup()
|
|
260
|
+
self.update_style()
|
|
255
261
|
self.update_syntax()
|
|
@@ -240,8 +240,6 @@ class LlamaWorkflow(BaseRunner):
|
|
|
240
240
|
item_ctx.output = "" # empty to prevent render
|
|
241
241
|
item_ctx.stream = "" # for stream
|
|
242
242
|
|
|
243
|
-
print("RUN AGENT!!!!!!!!!!!!!!!!!!!!")
|
|
244
|
-
|
|
245
243
|
async for event in handler.stream_events():
|
|
246
244
|
if self.is_stopped():
|
|
247
245
|
# persist current output on stop
|