pygpt-net 2.6.3__py3-none-any.whl → 2.6.4__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 +5 -0
- pygpt_net/__init__.py +1 -1
- pygpt_net/config.py +55 -65
- pygpt_net/controller/chat/chat.py +38 -35
- pygpt_net/controller/chat/render.py +144 -217
- pygpt_net/controller/chat/stream.py +51 -25
- pygpt_net/controller/config/config.py +39 -42
- pygpt_net/controller/config/field/checkbox.py +16 -12
- pygpt_net/controller/config/field/checkbox_list.py +36 -31
- pygpt_net/controller/config/field/cmd.py +51 -57
- pygpt_net/controller/config/field/combo.py +33 -16
- pygpt_net/controller/config/field/dictionary.py +48 -55
- pygpt_net/controller/config/field/input.py +50 -32
- pygpt_net/controller/config/field/slider.py +40 -45
- pygpt_net/controller/config/field/textarea.py +20 -6
- pygpt_net/controller/config/placeholder.py +110 -231
- pygpt_net/controller/lang/mapping.py +57 -95
- pygpt_net/controller/lang/plugins.py +64 -55
- pygpt_net/controller/lang/settings.py +39 -38
- pygpt_net/controller/layout/layout.py +11 -2
- pygpt_net/controller/plugins/plugins.py +19 -1
- pygpt_net/controller/ui/mode.py +107 -125
- pygpt_net/core/bridge/bridge.py +5 -5
- pygpt_net/core/command/command.py +149 -219
- pygpt_net/core/ctx/ctx.py +94 -146
- pygpt_net/core/debug/debug.py +48 -58
- pygpt_net/core/models/models.py +74 -112
- pygpt_net/core/modes/modes.py +13 -21
- pygpt_net/core/plugins/plugins.py +154 -177
- pygpt_net/core/presets/presets.py +103 -176
- pygpt_net/core/render/web/body.py +2 -3
- pygpt_net/core/render/web/renderer.py +109 -180
- pygpt_net/core/text/utils.py +28 -44
- pygpt_net/core/tokens/tokens.py +104 -203
- pygpt_net/data/config/config.json +2 -2
- pygpt_net/data/config/models.json +2 -2
- pygpt_net/item/ctx.py +141 -139
- pygpt_net/plugin/agent/plugin.py +2 -1
- pygpt_net/plugin/audio_output/plugin.py +5 -2
- pygpt_net/plugin/base/plugin.py +77 -93
- pygpt_net/plugin/bitbucket/plugin.py +3 -2
- pygpt_net/plugin/cmd_code_interpreter/plugin.py +3 -2
- pygpt_net/plugin/cmd_custom/plugin.py +3 -2
- pygpt_net/plugin/cmd_files/plugin.py +3 -2
- pygpt_net/plugin/cmd_history/plugin.py +3 -2
- pygpt_net/plugin/cmd_mouse_control/plugin.py +5 -2
- pygpt_net/plugin/cmd_serial/plugin.py +3 -2
- pygpt_net/plugin/cmd_system/plugin.py +3 -6
- pygpt_net/plugin/cmd_web/plugin.py +3 -2
- pygpt_net/plugin/experts/plugin.py +2 -2
- pygpt_net/plugin/facebook/plugin.py +3 -4
- pygpt_net/plugin/github/plugin.py +4 -2
- pygpt_net/plugin/google/plugin.py +3 -3
- pygpt_net/plugin/idx_llama_index/plugin.py +3 -2
- pygpt_net/plugin/mailer/plugin.py +3 -5
- pygpt_net/plugin/openai_vision/plugin.py +3 -2
- pygpt_net/plugin/real_time/plugin.py +52 -60
- pygpt_net/plugin/slack/plugin.py +3 -4
- pygpt_net/plugin/telegram/plugin.py +3 -4
- pygpt_net/plugin/twitter/plugin.py +3 -4
- pygpt_net/ui/widget/textarea/web.py +18 -14
- {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/METADATA +7 -2
- {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/RECORD +66 -66
- {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.4.dist-info}/entry_points.txt +0 -0
pygpt_net/CHANGELOG.txt
CHANGED
pygpt_net/__init__.py
CHANGED
|
@@ -13,7 +13,7 @@ __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.
|
|
16
|
+
__version__ = "2.6.4"
|
|
17
17
|
__build__ = "2025-08-15"
|
|
18
18
|
__maintainer__ = "Marcin Szczygliński"
|
|
19
19
|
__github__ = "https://github.com/szczyglis-dev/py-gpt"
|
pygpt_net/config.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: 2025.
|
|
9
|
+
# Updated Date: 2025.08.15 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
@@ -16,11 +16,15 @@ import re
|
|
|
16
16
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
from packaging.version import Version
|
|
19
|
+
from operator import itemgetter
|
|
19
20
|
|
|
20
21
|
from pygpt_net.core.profile import Profile
|
|
21
22
|
from pygpt_net.provider.core.config.json_file import JsonFileProvider
|
|
22
23
|
from pygpt_net.core.types.console import Color
|
|
23
24
|
|
|
25
|
+
_RE_VERSION = re.compile(r'__version__\s*=\s*[\'"]([^\'"]*)[\'"]')
|
|
26
|
+
_RE_BUILD = re.compile(r'__build__\s*=\s*[\'"]([^\'"]*)[\'"]')
|
|
27
|
+
|
|
24
28
|
|
|
25
29
|
class Config:
|
|
26
30
|
CONFIG_DIR = 'pygpt-net'
|
|
@@ -46,9 +50,9 @@ class Config:
|
|
|
46
50
|
self.initialized_base = False
|
|
47
51
|
self.initialized_workdir = False
|
|
48
52
|
self.db_echo = False
|
|
49
|
-
self.data = {}
|
|
50
|
-
self.data_base = {}
|
|
51
|
-
self.data_session = {}
|
|
53
|
+
self.data = {}
|
|
54
|
+
self.data_base = {}
|
|
55
|
+
self.data_session = {}
|
|
52
56
|
self.version = version
|
|
53
57
|
self.dirs = {
|
|
54
58
|
"capture": "capture",
|
|
@@ -63,6 +67,9 @@ class Config:
|
|
|
63
67
|
"upload": "upload",
|
|
64
68
|
"tmp": "tmp",
|
|
65
69
|
}
|
|
70
|
+
self._app_path = None
|
|
71
|
+
self._version_cache = version if version else None
|
|
72
|
+
self._build_cache = None
|
|
66
73
|
self.provider = JsonFileProvider(window)
|
|
67
74
|
self.provider.path_app = self.get_app_path()
|
|
68
75
|
self.provider.meta = self.append_meta()
|
|
@@ -81,10 +88,8 @@ class Config:
|
|
|
81
88
|
|
|
82
89
|
def install(self):
|
|
83
90
|
"""Install database and provider data"""
|
|
84
|
-
self.window.core.db.echo = self.db_echo
|
|
91
|
+
self.window.core.db.echo = self.db_echo
|
|
85
92
|
self.window.core.db.init()
|
|
86
|
-
|
|
87
|
-
# install provider configs
|
|
88
93
|
self.provider.install()
|
|
89
94
|
|
|
90
95
|
def get_path(self) -> str:
|
|
@@ -108,7 +113,6 @@ class Config:
|
|
|
108
113
|
path = os.path.join(Path.home(), '.config', Config.CONFIG_DIR)
|
|
109
114
|
if "PYGPT_WORKDIR" in os.environ and os.environ["PYGPT_WORKDIR"] != "":
|
|
110
115
|
print("FORCE using workdir: {}".format(os.environ["PYGPT_WORKDIR"]))
|
|
111
|
-
# convert relative path to absolute path if needed
|
|
112
116
|
if not os.path.isabs(os.environ["PYGPT_WORKDIR"]):
|
|
113
117
|
path = os.path.join(os.getcwd(), os.environ["PYGPT_WORKDIR"])
|
|
114
118
|
else:
|
|
@@ -128,11 +132,11 @@ class Config:
|
|
|
128
132
|
"""
|
|
129
133
|
is_test = os.environ.get('ENV_TEST') == '1'
|
|
130
134
|
path = Path(Config.get_base_workdir())
|
|
131
|
-
if not path.exists() and not is_test:
|
|
135
|
+
if not path.exists() and not is_test:
|
|
132
136
|
path.mkdir(parents=True, exist_ok=True)
|
|
133
137
|
path_file = "path.cfg"
|
|
134
138
|
p = os.path.join(str(path), path_file)
|
|
135
|
-
if not os.path.exists(p) and not is_test:
|
|
139
|
+
if not os.path.exists(p) and not is_test:
|
|
136
140
|
with open(p, 'w', encoding='utf-8') as f:
|
|
137
141
|
f.write("")
|
|
138
142
|
else:
|
|
@@ -155,6 +159,7 @@ class Config:
|
|
|
155
159
|
"""
|
|
156
160
|
self.path = path
|
|
157
161
|
self.provider.path = path
|
|
162
|
+
self.initialized_workdir = True
|
|
158
163
|
if reload:
|
|
159
164
|
self.initialized = False
|
|
160
165
|
self.init(True)
|
|
@@ -178,7 +183,7 @@ class Config:
|
|
|
178
183
|
if dir not in self.dirs:
|
|
179
184
|
raise Exception('Unknown dir: {}'.format(dir))
|
|
180
185
|
|
|
181
|
-
dir_data_allowed =
|
|
186
|
+
dir_data_allowed = ("img", "capture", "upload")
|
|
182
187
|
|
|
183
188
|
if self.has("upload.data_dir") \
|
|
184
189
|
and self.get("upload.data_dir") \
|
|
@@ -186,8 +191,7 @@ class Config:
|
|
|
186
191
|
path = os.path.join(self.get_user_path(), self.dirs["data"], self.dirs[dir])
|
|
187
192
|
else:
|
|
188
193
|
path = os.path.join(self.get_user_path(), self.dirs[dir])
|
|
189
|
-
|
|
190
|
-
os.makedirs(path, exist_ok=True)
|
|
194
|
+
os.makedirs(path, exist_ok=True)
|
|
191
195
|
|
|
192
196
|
return path
|
|
193
197
|
|
|
@@ -208,10 +212,13 @@ class Config:
|
|
|
208
212
|
|
|
209
213
|
:return: app root path
|
|
210
214
|
"""
|
|
211
|
-
if self
|
|
212
|
-
return
|
|
215
|
+
if hasattr(self, '_app_path') and self._app_path is not None:
|
|
216
|
+
return self._app_path
|
|
217
|
+
if self.is_compiled():
|
|
218
|
+
self._app_path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
|
213
219
|
else:
|
|
214
|
-
|
|
220
|
+
self._app_path = os.path.abspath(os.path.dirname(__file__))
|
|
221
|
+
return self._app_path
|
|
215
222
|
|
|
216
223
|
def get_user_path(self) -> str:
|
|
217
224
|
"""
|
|
@@ -229,15 +236,14 @@ class Config:
|
|
|
229
236
|
"""
|
|
230
237
|
if not self.initialized:
|
|
231
238
|
|
|
232
|
-
# if app initialization
|
|
233
239
|
if all:
|
|
234
240
|
v = self.get_version()
|
|
235
241
|
build = self.get_build().replace('.', '-')
|
|
236
|
-
|
|
242
|
+
os_name = self.window.core.platforms.get_os()
|
|
237
243
|
architecture = self.window.core.platforms.get_architecture()
|
|
238
244
|
|
|
239
245
|
print("===================================================")
|
|
240
|
-
print(f" {Color.BOLD}PyGPT {v}{Color.ENDC} build {build} ({
|
|
246
|
+
print(f" {Color.BOLD}PyGPT {v}{Color.ENDC} build {build} ({os_name}, {architecture})")
|
|
241
247
|
print(" Author: Marcin Szczyglinski")
|
|
242
248
|
print(" GitHub: https://github.com/szczyglis-dev/py-gpt")
|
|
243
249
|
print(" Website: https://pygpt.net")
|
|
@@ -246,7 +252,6 @@ class Config:
|
|
|
246
252
|
print("")
|
|
247
253
|
print(f"{Color.BOLD}Initializing...{Color.ENDC}")
|
|
248
254
|
|
|
249
|
-
# prepare and install
|
|
250
255
|
self.window.core.installer.install()
|
|
251
256
|
|
|
252
257
|
self.load(all)
|
|
@@ -258,12 +263,15 @@ class Config:
|
|
|
258
263
|
|
|
259
264
|
:return: version string
|
|
260
265
|
"""
|
|
266
|
+
if hasattr(self, '_version_cache') and self._version_cache is not None:
|
|
267
|
+
return self._version_cache
|
|
261
268
|
path = os.path.abspath(os.path.join(self.get_app_path(), '__init__.py'))
|
|
262
269
|
try:
|
|
263
270
|
with open(path, 'r', encoding="utf-8") as f:
|
|
264
271
|
data = f.read()
|
|
265
|
-
result =
|
|
266
|
-
|
|
272
|
+
result = _RE_VERSION.search(data)
|
|
273
|
+
self._version_cache = result.group(1)
|
|
274
|
+
return self._version_cache
|
|
267
275
|
except Exception as e:
|
|
268
276
|
if self.window is not None:
|
|
269
277
|
self.window.core.debug.log(e)
|
|
@@ -276,12 +284,15 @@ class Config:
|
|
|
276
284
|
|
|
277
285
|
:return: build string
|
|
278
286
|
"""
|
|
287
|
+
if self._build_cache is not None:
|
|
288
|
+
return self._build_cache
|
|
279
289
|
path = os.path.abspath(os.path.join(self.get_app_path(), '__init__.py'))
|
|
280
290
|
try:
|
|
281
291
|
with open(path, 'r', encoding="utf-8") as f:
|
|
282
292
|
data = f.read()
|
|
283
|
-
result =
|
|
284
|
-
|
|
293
|
+
result = _RE_BUILD.search(data)
|
|
294
|
+
self._build_cache = result.group(1)
|
|
295
|
+
return self._build_cache
|
|
285
296
|
except Exception as e:
|
|
286
297
|
if self.window is not None:
|
|
287
298
|
self.window.core.debug.log(e)
|
|
@@ -312,9 +323,7 @@ class Config:
|
|
|
312
323
|
:param default: default value
|
|
313
324
|
:return: value
|
|
314
325
|
"""
|
|
315
|
-
|
|
316
|
-
return self.data[key]
|
|
317
|
-
return default
|
|
326
|
+
return self.data.get(key, default)
|
|
318
327
|
|
|
319
328
|
def get_session(self, key: str, default: any = None) -> any:
|
|
320
329
|
"""
|
|
@@ -324,9 +333,7 @@ class Config:
|
|
|
324
333
|
:param default: default value
|
|
325
334
|
:return: value
|
|
326
335
|
"""
|
|
327
|
-
|
|
328
|
-
return self.data_session[key]
|
|
329
|
-
return default
|
|
336
|
+
return self.data_session.get(key, default)
|
|
330
337
|
|
|
331
338
|
def get_lang(self) -> str:
|
|
332
339
|
"""
|
|
@@ -334,7 +341,7 @@ class Config:
|
|
|
334
341
|
|
|
335
342
|
:return: language code
|
|
336
343
|
"""
|
|
337
|
-
test_lang = os.environ.get('TEST_LANGUAGE')
|
|
344
|
+
test_lang = os.environ.get('TEST_LANGUAGE')
|
|
338
345
|
if test_lang:
|
|
339
346
|
return test_lang
|
|
340
347
|
return self.get('lang', 'en')
|
|
@@ -364,12 +371,7 @@ class Config:
|
|
|
364
371
|
:param key: key
|
|
365
372
|
:return: True if exists
|
|
366
373
|
"""
|
|
367
|
-
|
|
368
|
-
return False
|
|
369
|
-
|
|
370
|
-
if key in self.data:
|
|
371
|
-
return True
|
|
372
|
-
return False
|
|
374
|
+
return key in self.data
|
|
373
375
|
|
|
374
376
|
def has_session(self, key: str) -> bool:
|
|
375
377
|
"""
|
|
@@ -378,9 +380,7 @@ class Config:
|
|
|
378
380
|
:param key: key
|
|
379
381
|
:return: True if exists
|
|
380
382
|
"""
|
|
381
|
-
|
|
382
|
-
return True
|
|
383
|
-
return False
|
|
383
|
+
return key in self.data_session
|
|
384
384
|
|
|
385
385
|
def all(self) -> dict:
|
|
386
386
|
"""
|
|
@@ -404,32 +404,21 @@ class Config:
|
|
|
404
404
|
|
|
405
405
|
:return: list with available languages (user + app)
|
|
406
406
|
"""
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
if os.path.exists(
|
|
410
|
-
for file in os.listdir(
|
|
407
|
+
langs_set = set()
|
|
408
|
+
path_app = os.path.join(self.get_app_path(), 'data', 'locale')
|
|
409
|
+
if os.path.exists(path_app):
|
|
410
|
+
for file in os.listdir(path_app):
|
|
411
411
|
if file.startswith('locale.') and file.endswith(".ini"):
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
path = os.path.join(self.get_user_path(), 'locale')
|
|
417
|
-
if os.path.exists(path):
|
|
418
|
-
for file in os.listdir(path):
|
|
412
|
+
langs_set.add(file.replace('locale.', '').replace('.ini', ''))
|
|
413
|
+
path_user = os.path.join(self.get_user_path(), 'locale')
|
|
414
|
+
if os.path.exists(path_user):
|
|
415
|
+
for file in os.listdir(path_user):
|
|
419
416
|
if file.startswith('locale.') and file.endswith(".ini"):
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
langs.append(lang_id)
|
|
423
|
-
|
|
424
|
-
# sort by name
|
|
425
|
-
langs.sort()
|
|
426
|
-
|
|
427
|
-
# make English first
|
|
417
|
+
langs_set.add(file.replace('locale.', '').replace('.ini', ''))
|
|
418
|
+
langs = sorted(langs_set)
|
|
428
419
|
if 'en' in langs:
|
|
429
420
|
langs.remove('en')
|
|
430
421
|
langs.insert(0, 'en')
|
|
431
|
-
|
|
432
|
-
# make Polish second
|
|
433
422
|
if 'pl' in langs:
|
|
434
423
|
langs.remove('pl')
|
|
435
424
|
langs.insert(1, 'pl')
|
|
@@ -469,7 +458,7 @@ class Config:
|
|
|
469
458
|
"""
|
|
470
459
|
self.data = self.provider.load(all)
|
|
471
460
|
if self.data is not None:
|
|
472
|
-
self.data = dict(sorted(self.data.items(), key=
|
|
461
|
+
self.data = dict(sorted(self.data.items(), key=itemgetter(0)))
|
|
473
462
|
|
|
474
463
|
def load_base_config(self):
|
|
475
464
|
"""
|
|
@@ -477,7 +466,7 @@ class Config:
|
|
|
477
466
|
"""
|
|
478
467
|
self.data_base = self.provider.load_base()
|
|
479
468
|
if self.data_base is not None:
|
|
480
|
-
self.data_base = dict(sorted(self.data_base.items(), key=
|
|
469
|
+
self.data_base = dict(sorted(self.data_base.items(), key=itemgetter(0)))
|
|
481
470
|
self.initialized_base = True
|
|
482
471
|
|
|
483
472
|
def from_base_config(self):
|
|
@@ -543,11 +532,12 @@ class Config:
|
|
|
543
532
|
if "app.env" not in self.data or not isinstance(self.data["app.env"], list):
|
|
544
533
|
return
|
|
545
534
|
list_loaded = []
|
|
535
|
+
conf = self.all()
|
|
546
536
|
for item in self.data["app.env"]:
|
|
547
537
|
if item['name'] is None or item['name'] == "":
|
|
548
538
|
continue
|
|
549
539
|
try:
|
|
550
|
-
value = str(item['value'].format(**
|
|
540
|
+
value = str(item['value'].format(**conf))
|
|
551
541
|
os.environ[item['name']] = value
|
|
552
542
|
list_loaded.append(item['name'])
|
|
553
543
|
except Exception as e:
|
|
@@ -561,4 +551,4 @@ class Config:
|
|
|
561
551
|
|
|
562
552
|
:param filename: filename
|
|
563
553
|
"""
|
|
564
|
-
self.provider.save(self.data, filename)
|
|
554
|
+
self.provider.save(self.data, filename)
|
|
@@ -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.15 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import Any
|
|
@@ -37,68 +37,71 @@ class Chat:
|
|
|
37
37
|
:param window: Window instance
|
|
38
38
|
"""
|
|
39
39
|
self.window = window
|
|
40
|
-
|
|
41
|
-
self.
|
|
42
|
-
self.
|
|
43
|
-
self.
|
|
44
|
-
self.
|
|
45
|
-
self.
|
|
46
|
-
self.
|
|
47
|
-
self.
|
|
48
|
-
self.
|
|
49
|
-
self.
|
|
50
|
-
self.
|
|
51
|
-
self.
|
|
52
|
-
self.
|
|
53
|
-
|
|
54
|
-
|
|
40
|
+
w = window
|
|
41
|
+
self.attachment = Attachment(w)
|
|
42
|
+
self.audio = Audio(w)
|
|
43
|
+
self.command = Command(w)
|
|
44
|
+
self.common = Common(w)
|
|
45
|
+
self.files = Files(w)
|
|
46
|
+
self.image = Image(w)
|
|
47
|
+
self.input = Input(w)
|
|
48
|
+
self.output = Output(w)
|
|
49
|
+
self.render = Render(w)
|
|
50
|
+
self.response = Response(w)
|
|
51
|
+
self.stream = Stream(w)
|
|
52
|
+
self.text = Text(w)
|
|
53
|
+
self.vision = Vision(w)
|
|
54
|
+
|
|
55
|
+
def init(self) -> None:
|
|
55
56
|
"""Init"""
|
|
56
57
|
self.render.setup() # setup render engine
|
|
57
58
|
|
|
58
|
-
def setup(self):
|
|
59
|
+
def setup(self) -> None:
|
|
59
60
|
"""Setup"""
|
|
60
61
|
self.common.setup()
|
|
61
62
|
self.attachment.setup()
|
|
62
63
|
|
|
63
|
-
def reload(self):
|
|
64
|
+
def reload(self) -> None:
|
|
64
65
|
"""Reload"""
|
|
65
66
|
self.common.setup()
|
|
66
67
|
self.render.reload()
|
|
67
68
|
self.attachment.reload()
|
|
68
69
|
|
|
69
|
-
def handle_error(self, err: Any):
|
|
70
|
+
def handle_error(self, err: Any) -> None:
|
|
70
71
|
"""
|
|
71
72
|
Handle error
|
|
72
73
|
|
|
73
74
|
:param err: Exception
|
|
74
75
|
"""
|
|
75
|
-
self.window
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
self.
|
|
81
|
-
|
|
82
|
-
#
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
76
|
+
w = self.window
|
|
77
|
+
err_str = str(err)
|
|
78
|
+
w.core.debug.log(err)
|
|
79
|
+
w.ui.dialogs.alert(err_str)
|
|
80
|
+
w.update_status(err_str)
|
|
81
|
+
self.common.unlock_input() # always unlock input on error
|
|
82
|
+
w.stateChanged.emit(w.STATE_ERROR)
|
|
83
|
+
w.dispatch(AppEvent(AppEvent.INPUT_ERROR)) # app event
|
|
84
|
+
|
|
85
|
+
if w.controller.agent.legacy.enabled():
|
|
86
|
+
w.controller.agent.legacy.on_stop()
|
|
87
|
+
|
|
88
|
+
def log_ctx(self, ctx: CtxItem, mode: str) -> None:
|
|
87
89
|
"""
|
|
88
90
|
Log context item
|
|
89
91
|
|
|
90
92
|
:param ctx: CtxItem
|
|
91
93
|
:param mode: mode (input/output)
|
|
92
94
|
"""
|
|
95
|
+
upper_mode = mode.upper()
|
|
93
96
|
if self.window.core.config.get("log.ctx"):
|
|
94
|
-
self.log("[ctx] {}: {
|
|
97
|
+
self.log(f"[ctx] {upper_mode}: {ctx.dump()}") # log
|
|
95
98
|
else:
|
|
96
|
-
self.log("[ctx] {}."
|
|
99
|
+
self.log(f"[ctx] {upper_mode}.")
|
|
97
100
|
|
|
98
|
-
def log(self, data: Any):
|
|
101
|
+
def log(self, data: Any) -> None:
|
|
99
102
|
"""
|
|
100
103
|
Log data to debug
|
|
101
104
|
|
|
102
105
|
:param data: Data to log
|
|
103
106
|
"""
|
|
104
|
-
self.window.core.debug.info("[chat] "
|
|
107
|
+
self.window.core.debug.info(f"[chat] {data}")
|