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/core/debug/debug.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.08.
|
|
9
|
+
# Updated Date: 2025.08.15 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import gc
|
|
@@ -38,6 +38,7 @@ class Debug:
|
|
|
38
38
|
self.window = window
|
|
39
39
|
self.console = Console(window)
|
|
40
40
|
self.pause_idx = 1
|
|
41
|
+
self._process = psutil.Process(os.getpid())
|
|
41
42
|
|
|
42
43
|
@staticmethod
|
|
43
44
|
def init(level: int = logging.ERROR):
|
|
@@ -46,13 +47,13 @@ class Debug:
|
|
|
46
47
|
|
|
47
48
|
:param level: log level (default: ERROR)
|
|
48
49
|
"""
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
workdir = Config.prepare_workdir()
|
|
51
|
+
Path(workdir).mkdir(parents=True, exist_ok=True)
|
|
51
52
|
|
|
52
53
|
logging.basicConfig(
|
|
53
54
|
level=level,
|
|
54
55
|
format='%(asctime)s - %(levelname)s - %(message)s',
|
|
55
|
-
filename=str(Path(
|
|
56
|
+
filename=str(Path(workdir) / 'app.log'),
|
|
56
57
|
filemode='a',
|
|
57
58
|
encoding='utf-8',
|
|
58
59
|
)
|
|
@@ -66,11 +67,13 @@ class Debug:
|
|
|
66
67
|
:param tb: traceback
|
|
67
68
|
"""
|
|
68
69
|
logger = logging.getLogger()
|
|
69
|
-
if not
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
if not getattr(handle_exception, "_handling", False):
|
|
71
|
+
handle_exception._handling = True
|
|
72
|
+
try:
|
|
73
|
+
logger.error("Uncaught exception:", exc_info=(exc_type, value, tb))
|
|
74
|
+
traceback.print_exception(exc_type, value, tb)
|
|
75
|
+
finally:
|
|
76
|
+
handle_exception._handling = False
|
|
74
77
|
else:
|
|
75
78
|
traceback.print_exception(exc_type, value, tb)
|
|
76
79
|
|
|
@@ -84,7 +87,7 @@ class Debug:
|
|
|
84
87
|
for handler in logger.handlers[:]:
|
|
85
88
|
logger.removeHandler(handler)
|
|
86
89
|
handler.close()
|
|
87
|
-
file_handler = logging.FileHandler(filename=Path(path), mode='a', encoding='utf-8')
|
|
90
|
+
file_handler = logging.FileHandler(filename=str(Path(path)), mode='a', encoding='utf-8')
|
|
88
91
|
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
|
|
89
92
|
file_handler.setFormatter(formatter)
|
|
90
93
|
file_handler.setLevel(level)
|
|
@@ -124,16 +127,13 @@ class Debug:
|
|
|
124
127
|
:param id: log level id
|
|
125
128
|
:return: log level name
|
|
126
129
|
"""
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return "debug"
|
|
135
|
-
else:
|
|
136
|
-
return "unknown"
|
|
130
|
+
mapping = {
|
|
131
|
+
logging.ERROR: "error",
|
|
132
|
+
logging.WARNING: "warning",
|
|
133
|
+
logging.INFO: "info",
|
|
134
|
+
logging.DEBUG: "debug",
|
|
135
|
+
}
|
|
136
|
+
return mapping.get(id, "unknown")
|
|
137
137
|
|
|
138
138
|
def info(self, message: Any = None, console: bool = True):
|
|
139
139
|
"""
|
|
@@ -200,43 +200,36 @@ class Debug:
|
|
|
200
200
|
return
|
|
201
201
|
|
|
202
202
|
logger = logging.getLogger()
|
|
203
|
+
enabled = self.has_level(level)
|
|
203
204
|
|
|
204
205
|
try:
|
|
205
|
-
# string message
|
|
206
206
|
if isinstance(message, str):
|
|
207
|
-
if
|
|
207
|
+
if enabled:
|
|
208
208
|
logger.log(level, message)
|
|
209
209
|
if console:
|
|
210
210
|
print(message)
|
|
211
|
-
|
|
212
|
-
# exception
|
|
213
211
|
elif isinstance(message, Exception):
|
|
214
212
|
is_sys, data = self.parse_exception(message)
|
|
215
|
-
msg = "Exception: {}"
|
|
213
|
+
msg = f"Exception: {message}"
|
|
216
214
|
if not is_sys:
|
|
217
|
-
msg += "\n{}"
|
|
215
|
+
msg += f"\n{data}"
|
|
218
216
|
logger.log(level, msg, exc_info=is_sys)
|
|
219
|
-
if
|
|
217
|
+
if enabled and console and data:
|
|
220
218
|
print(data)
|
|
221
|
-
|
|
222
|
-
# other messages
|
|
223
219
|
else:
|
|
224
|
-
if
|
|
220
|
+
if enabled:
|
|
225
221
|
logger.log(level, message)
|
|
226
222
|
if console:
|
|
227
223
|
print(message)
|
|
228
|
-
except Exception
|
|
224
|
+
except Exception:
|
|
229
225
|
pass
|
|
230
226
|
|
|
231
227
|
try:
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
thread_suffix = ""
|
|
236
|
-
if not threading.current_thread() is threading.main_thread():
|
|
237
|
-
thread_suffix = " [THREAD: {}]".format(threading.current_thread().ident)
|
|
228
|
+
if enabled and self.window is not None:
|
|
229
|
+
t = threading.current_thread()
|
|
230
|
+
thread_suffix = "" if t is threading.main_thread() else f" [THREAD: {t.ident}]"
|
|
238
231
|
self.window.logger_message.emit(str(message) + thread_suffix)
|
|
239
|
-
except Exception
|
|
232
|
+
except Exception:
|
|
240
233
|
pass
|
|
241
234
|
|
|
242
235
|
def parse_exception(self, e: Any = None, limit: int = 4) -> Tuple[bool, str]:
|
|
@@ -249,9 +242,9 @@ class Debug:
|
|
|
249
242
|
"""
|
|
250
243
|
is_sys = False
|
|
251
244
|
type_name = ""
|
|
252
|
-
etype, value, tb = sys.exc_info()
|
|
245
|
+
etype, value, tb = sys.exc_info()
|
|
253
246
|
if etype is None and e is not None:
|
|
254
|
-
tb = e.__traceback__
|
|
247
|
+
tb = e.__traceback__
|
|
255
248
|
type_name = type(e).__name__
|
|
256
249
|
value = str(e)
|
|
257
250
|
else:
|
|
@@ -259,7 +252,6 @@ class Debug:
|
|
|
259
252
|
is_sys = True
|
|
260
253
|
type_name = etype.__name__
|
|
261
254
|
|
|
262
|
-
# traceback
|
|
263
255
|
traceback_details = traceback.extract_tb(tb)
|
|
264
256
|
if len(traceback_details) >= limit:
|
|
265
257
|
last_calls = traceback_details[-limit:]
|
|
@@ -269,7 +261,6 @@ class Debug:
|
|
|
269
261
|
if last_calls:
|
|
270
262
|
formatted_traceback = "".join(traceback.format_list(last_calls))
|
|
271
263
|
|
|
272
|
-
# parse data
|
|
273
264
|
data = ""
|
|
274
265
|
if type_name:
|
|
275
266
|
data += "Type: {}".format(type_name)
|
|
@@ -299,7 +290,7 @@ class Debug:
|
|
|
299
290
|
:param level: logging level
|
|
300
291
|
:return: True if enabled
|
|
301
292
|
"""
|
|
302
|
-
return
|
|
293
|
+
return logging.getLogger().isEnabledFor(level)
|
|
303
294
|
|
|
304
295
|
def enabled(self) -> bool:
|
|
305
296
|
"""
|
|
@@ -346,8 +337,7 @@ class Debug:
|
|
|
346
337
|
:param label: label for memory usage
|
|
347
338
|
:return: formatted memory usage string
|
|
348
339
|
"""
|
|
349
|
-
|
|
350
|
-
mem_mb = process.memory_info().rss / (1024 * 1024)
|
|
340
|
+
mem_mb = self._process.memory_info().rss / (1024 * 1024)
|
|
351
341
|
data = f"Memory Usage: {mem_mb:.2f} MB"
|
|
352
342
|
print(f"[{label}] {data}")
|
|
353
343
|
return data
|
|
@@ -376,24 +366,25 @@ class Debug:
|
|
|
376
366
|
res += self.print_memory_usage(label)
|
|
377
367
|
|
|
378
368
|
try:
|
|
379
|
-
from pympler import asizeof, summary, muppy
|
|
369
|
+
from pympler import asizeof, summary, muppy
|
|
380
370
|
objs = muppy.get_objects()
|
|
381
|
-
# objs_by_type = muppy.filter(objs, Type=dict)
|
|
382
371
|
sum_by_type = summary.summarize(objs)
|
|
383
|
-
# sum_by_type = summary.summarize(objs_by_type)
|
|
384
372
|
summary.print_(sum_by_type)
|
|
385
373
|
|
|
386
|
-
|
|
374
|
+
pids = self.window.controller.chat.render.web_renderer.pids
|
|
375
|
+
total_bytes = asizeof.asizeof(pids)
|
|
387
376
|
pids_total_mb = total_bytes / (1024 * 1024)
|
|
388
|
-
count_pids = len(
|
|
377
|
+
count_pids = len(pids)
|
|
389
378
|
|
|
390
|
-
|
|
379
|
+
meta = self.window.core.ctx.meta
|
|
380
|
+
total_bytes = asizeof.asizeof(meta)
|
|
391
381
|
meta_total_mb = total_bytes / (1024 * 1024)
|
|
392
|
-
count_meta = len(
|
|
382
|
+
count_meta = len(meta)
|
|
393
383
|
|
|
394
|
-
|
|
384
|
+
ctx_items = self.window.core.ctx.get_items()
|
|
385
|
+
total_bytes = asizeof.asizeof(ctx_items)
|
|
395
386
|
ctx_total_mb = total_bytes / (1024 * 1024)
|
|
396
|
-
count_ctx = len(
|
|
387
|
+
count_ctx = len(ctx_items)
|
|
397
388
|
|
|
398
389
|
stats.append(f"Pids: {pids_total_mb:.4f} MB ({count_pids})")
|
|
399
390
|
stats.append(f"CtxMeta: {meta_total_mb:.4f} MB ({count_meta})")
|
|
@@ -420,14 +411,13 @@ class Debug:
|
|
|
420
411
|
:param args: objects to dump
|
|
421
412
|
"""
|
|
422
413
|
dt = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
|
423
|
-
|
|
424
|
-
|
|
414
|
+
t = threading.current_thread()
|
|
415
|
+
thread_info = "[MAIN THREAD]" if t is threading.main_thread() else f"[THREAD: {t.ident}]"
|
|
425
416
|
print(f"\n{Color.FAIL}{Color.BOLD}<DEBUG: PAUSED> #{self.pause_idx} {dt}{Color.ENDC}")
|
|
426
417
|
print(f"\n{Color.BOLD}{thread_info}{Color.ENDC}")
|
|
427
418
|
print("------------------------------>")
|
|
428
419
|
self.pause_idx += 1
|
|
429
420
|
|
|
430
|
-
# dump args
|
|
431
421
|
for index, arg in enumerate(args):
|
|
432
422
|
print(f"\n{Color.BOLD}Dump {index + 1}:{Color.ENDC}")
|
|
433
423
|
print(f"{Color.BOLD}Type: {type(arg)}{Color.ENDC}")
|
|
@@ -439,4 +429,4 @@ class Debug:
|
|
|
439
429
|
traceback.print_stack()
|
|
440
430
|
|
|
441
431
|
input(f"<------------------------------\n\n{Color.OKGREEN}Paused. Press Enter to continue...{Color.ENDC}")
|
|
442
|
-
print(f"------------------------------\n{Color.OKGREEN}{Color.BOLD}<RESUMED>{Color.ENDC}\n")
|
|
432
|
+
print(f"------------------------------\n{Color.OKGREEN}{Color.BOLD}<RESUMED>{Color.ENDC}\n")
|
pygpt_net/core/models/models.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.08.
|
|
9
|
+
# Updated Date: 2025.08.15 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
@@ -72,47 +72,37 @@ class Models:
|
|
|
72
72
|
"""
|
|
73
73
|
base_items = self.get_base()
|
|
74
74
|
updated = False
|
|
75
|
-
added_keys = []
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
for key in base_items:
|
|
76
|
+
for key, base in base_items.items():
|
|
79
77
|
if key not in self.items:
|
|
80
|
-
self.items[key] = copy.deepcopy(
|
|
78
|
+
self.items[key] = copy.deepcopy(base)
|
|
81
79
|
updated = True
|
|
82
80
|
|
|
83
|
-
|
|
84
|
-
for key in base_items:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if self.items[old_key].id == model_id:
|
|
89
|
-
old_exists = True
|
|
90
|
-
break
|
|
91
|
-
if not old_exists and key not in added_keys:
|
|
92
|
-
self.items[key] = copy.deepcopy(base_items[key])
|
|
93
|
-
added_keys.append(key)
|
|
81
|
+
existing_ids = {it.id for it in self.items.values()}
|
|
82
|
+
for key, base in base_items.items():
|
|
83
|
+
if base.id not in existing_ids:
|
|
84
|
+
self.items[key] = copy.deepcopy(base)
|
|
85
|
+
existing_ids.add(base.id)
|
|
94
86
|
updated = True
|
|
95
87
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
for
|
|
108
|
-
if isinstance(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
self.items[key].output = ["text"]
|
|
115
|
-
updated = True
|
|
88
|
+
for key, base in base_items.items():
|
|
89
|
+
item = self.items.get(key)
|
|
90
|
+
if not item:
|
|
91
|
+
continue
|
|
92
|
+
if base.input != item.input:
|
|
93
|
+
item.input = base.input
|
|
94
|
+
updated = True
|
|
95
|
+
if base.output != item.output:
|
|
96
|
+
item.output = base.output
|
|
97
|
+
updated = True
|
|
98
|
+
|
|
99
|
+
for item in self.items.values():
|
|
100
|
+
if isinstance(item.input, list) and not item.input:
|
|
101
|
+
item.input = ["text"]
|
|
102
|
+
updated = True
|
|
103
|
+
if isinstance(item.output, list) and not item.output:
|
|
104
|
+
item.output = ["text"]
|
|
105
|
+
updated = True
|
|
116
106
|
|
|
117
107
|
if updated:
|
|
118
108
|
self.save()
|
|
@@ -126,8 +116,7 @@ class Models:
|
|
|
126
116
|
:param key: model name
|
|
127
117
|
:return: model config object
|
|
128
118
|
"""
|
|
129
|
-
|
|
130
|
-
return self.items[key]
|
|
119
|
+
return self.items.get(key)
|
|
131
120
|
|
|
132
121
|
def get_ids(self) -> List[str]:
|
|
133
122
|
"""
|
|
@@ -167,9 +156,7 @@ class Models:
|
|
|
167
156
|
:param mode: mode name
|
|
168
157
|
:return: True if model is allowed for mode
|
|
169
158
|
"""
|
|
170
|
-
|
|
171
|
-
return mode in self.items[model].mode
|
|
172
|
-
return False
|
|
159
|
+
return model in self.items and mode in self.items[model].mode
|
|
173
160
|
|
|
174
161
|
def get_id(
|
|
175
162
|
self,
|
|
@@ -181,8 +168,8 @@ class Models:
|
|
|
181
168
|
:param key: model key
|
|
182
169
|
:return: model id
|
|
183
170
|
"""
|
|
184
|
-
|
|
185
|
-
|
|
171
|
+
item = self.items.get(key)
|
|
172
|
+
return item.id if item else None
|
|
186
173
|
|
|
187
174
|
def get_by_idx(
|
|
188
175
|
self,
|
|
@@ -209,11 +196,7 @@ class Models:
|
|
|
209
196
|
:param mode: mode name
|
|
210
197
|
:return: models dict for mode
|
|
211
198
|
"""
|
|
212
|
-
items
|
|
213
|
-
for key in self.items:
|
|
214
|
-
if mode in self.items[key].mode:
|
|
215
|
-
items[key] = self.items[key]
|
|
216
|
-
return items
|
|
199
|
+
return {k: v for k, v in self.items.items() if mode in v.mode}
|
|
217
200
|
|
|
218
201
|
def get_next(
|
|
219
202
|
self,
|
|
@@ -259,10 +242,17 @@ class Models:
|
|
|
259
242
|
|
|
260
243
|
:return: new model id
|
|
261
244
|
"""
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
245
|
+
prefix = "model-"
|
|
246
|
+
used = set()
|
|
247
|
+
for k in self.items.keys():
|
|
248
|
+
if isinstance(k, str) and k.startswith(prefix):
|
|
249
|
+
suffix = k[len(prefix):]
|
|
250
|
+
if suffix.isdigit():
|
|
251
|
+
used.add(int(suffix))
|
|
252
|
+
n = 0
|
|
253
|
+
while n in used:
|
|
254
|
+
n += 1
|
|
255
|
+
return f"{prefix}{n:03d}"
|
|
266
256
|
|
|
267
257
|
def get_multimodal_list(self) -> List[str]:
|
|
268
258
|
"""
|
|
@@ -336,8 +326,8 @@ class Models:
|
|
|
336
326
|
:param model: model name
|
|
337
327
|
:return: True if model exists for mode
|
|
338
328
|
"""
|
|
339
|
-
|
|
340
|
-
return
|
|
329
|
+
item = self.items.get(model)
|
|
330
|
+
return bool(item and mode in item.mode)
|
|
341
331
|
|
|
342
332
|
def get_default(self, mode: str) -> Optional[str]:
|
|
343
333
|
"""
|
|
@@ -346,13 +336,10 @@ class Models:
|
|
|
346
336
|
:param mode: mode name
|
|
347
337
|
:return: default model name
|
|
348
338
|
"""
|
|
349
|
-
models = {}
|
|
350
339
|
items = self.get_by_mode(mode)
|
|
351
|
-
|
|
352
|
-
models[k] = items[k]
|
|
353
|
-
if len(models) == 0:
|
|
340
|
+
if not items:
|
|
354
341
|
return None
|
|
355
|
-
return
|
|
342
|
+
return next(iter(items))
|
|
356
343
|
|
|
357
344
|
def get_tokens(self, model: str) -> int:
|
|
358
345
|
"""
|
|
@@ -385,12 +372,10 @@ class Models:
|
|
|
385
372
|
|
|
386
373
|
:param model: model name
|
|
387
374
|
"""
|
|
388
|
-
# restore all models
|
|
389
375
|
if model is None:
|
|
390
376
|
self.load_base()
|
|
391
377
|
return
|
|
392
378
|
|
|
393
|
-
# restore single model
|
|
394
379
|
items = self.provider.load_base()
|
|
395
380
|
if model in items:
|
|
396
381
|
self.items[model] = items[model]
|
|
@@ -435,34 +420,24 @@ class Models:
|
|
|
435
420
|
:return: mode (supported)
|
|
436
421
|
"""
|
|
437
422
|
prev_mode = mode
|
|
438
|
-
|
|
439
|
-
if model.is_supported(MODE_CHAT) and mode != MODE_LLAMA_INDEX: # do not switch if llama_index mode!
|
|
423
|
+
if model.is_supported(MODE_CHAT) and mode != MODE_LLAMA_INDEX:
|
|
440
424
|
if prev_mode != MODE_CHAT:
|
|
441
425
|
self.window.core.debug.info(
|
|
442
426
|
"WARNING: Switching to chat mode (model not supported in: {})".format(prev_mode))
|
|
443
427
|
return MODE_CHAT
|
|
444
428
|
|
|
445
|
-
# Research / Perplexity
|
|
446
429
|
if model.is_supported(MODE_RESEARCH):
|
|
447
430
|
if prev_mode != MODE_RESEARCH:
|
|
448
431
|
self.window.core.debug.info(
|
|
449
432
|
"WARNING: Switching to research mode (model not supported in: {})".format(mode))
|
|
450
433
|
mode = MODE_RESEARCH
|
|
451
434
|
|
|
452
|
-
# Llama Index / Chat with Files
|
|
453
435
|
elif model.is_supported(MODE_LLAMA_INDEX):
|
|
454
436
|
if prev_mode != MODE_LLAMA_INDEX:
|
|
455
437
|
self.window.core.debug.info(
|
|
456
438
|
"WARNING: Switching to llama_index mode (model not supported in: {})".format(mode))
|
|
457
439
|
mode = MODE_LLAMA_INDEX
|
|
458
440
|
|
|
459
|
-
# LangChain
|
|
460
|
-
"""
|
|
461
|
-
elif model.is_supported(MODE_LANGCHAIN):
|
|
462
|
-
self.window.core.debug.info(
|
|
463
|
-
"WARNING: Switching to langchain mode (model not supported in: {})".format(mode))
|
|
464
|
-
mode = MODE_LANGCHAIN
|
|
465
|
-
"""
|
|
466
441
|
return mode
|
|
467
442
|
|
|
468
443
|
def prepare_client_args(
|
|
@@ -477,65 +452,55 @@ class Models:
|
|
|
477
452
|
:param model: ModelItem
|
|
478
453
|
:return: client arguments dict
|
|
479
454
|
"""
|
|
455
|
+
cfg = self.window.core.config
|
|
480
456
|
args = {
|
|
481
|
-
"api_key":
|
|
482
|
-
"organization":
|
|
457
|
+
"api_key": cfg.get('api_key'),
|
|
458
|
+
"organization": cfg.get('organization_key'),
|
|
483
459
|
}
|
|
484
|
-
|
|
485
|
-
if
|
|
486
|
-
endpoint =
|
|
460
|
+
|
|
461
|
+
if cfg.has('api_endpoint'):
|
|
462
|
+
endpoint = cfg.get('api_endpoint')
|
|
487
463
|
if endpoint:
|
|
488
464
|
args["base_url"] = endpoint
|
|
489
|
-
|
|
490
|
-
if
|
|
491
|
-
proxy =
|
|
465
|
+
|
|
466
|
+
if cfg.has('api_proxy'):
|
|
467
|
+
proxy = cfg.get('api_proxy')
|
|
492
468
|
if proxy:
|
|
493
469
|
transport = SyncProxyTransport.from_url(proxy)
|
|
494
|
-
args["http_client"] = DefaultHttpxClient(
|
|
495
|
-
transport=transport,
|
|
496
|
-
)
|
|
470
|
+
args["http_client"] = DefaultHttpxClient(transport=transport)
|
|
497
471
|
|
|
498
|
-
# research mode endpoint - Perplexity
|
|
499
472
|
if model is not None:
|
|
500
|
-
# xAI / grok
|
|
501
473
|
if model.provider == "x_ai":
|
|
502
|
-
args["api_key"] =
|
|
503
|
-
args["base_url"] =
|
|
474
|
+
args["api_key"] = cfg.get('api_key_xai', "")
|
|
475
|
+
args["base_url"] = cfg.get('api_endpoint_xai', "")
|
|
504
476
|
self.window.core.debug.info("[api] Using client: xAI")
|
|
505
|
-
# Perplexity
|
|
506
477
|
elif model.provider == "perplexity":
|
|
507
|
-
args["api_key"] =
|
|
508
|
-
args["base_url"] =
|
|
478
|
+
args["api_key"] = cfg.get('api_key_perplexity', "")
|
|
479
|
+
args["base_url"] = cfg.get('api_endpoint_perplexity', "")
|
|
509
480
|
self.window.core.debug.info("[api] Using client: Perplexity")
|
|
510
|
-
# Google
|
|
511
481
|
elif model.provider == "google":
|
|
512
|
-
args["api_key"] =
|
|
513
|
-
args["base_url"] =
|
|
482
|
+
args["api_key"] = cfg.get('api_key_google', "")
|
|
483
|
+
args["base_url"] = cfg.get('api_endpoint_google', "")
|
|
514
484
|
self.window.core.debug.info("[api] Using client: Google")
|
|
515
|
-
# Anthropic
|
|
516
485
|
elif model.provider == "anthropic":
|
|
517
|
-
args["api_key"] =
|
|
518
|
-
args["base_url"] =
|
|
486
|
+
args["api_key"] = cfg.get('api_key_anthropic', "")
|
|
487
|
+
args["base_url"] = cfg.get('api_endpoint_anthropic', "")
|
|
519
488
|
self.window.core.debug.info("[api] Using client: Anthropic")
|
|
520
|
-
# Deepseek
|
|
521
489
|
elif model.provider == "deepseek_api":
|
|
522
|
-
args["api_key"] =
|
|
523
|
-
args["base_url"] =
|
|
490
|
+
args["api_key"] = cfg.get('api_key_deepseek', "")
|
|
491
|
+
args["base_url"] = cfg.get('api_endpoint_deepseek', "")
|
|
524
492
|
self.window.core.debug.info("[api] Using client: Deepseek API")
|
|
525
|
-
# Mistral AI
|
|
526
493
|
elif model.provider == "mistral_ai":
|
|
527
|
-
args["api_key"] =
|
|
528
|
-
args["base_url"] =
|
|
494
|
+
args["api_key"] = cfg.get('api_key_mistral', "")
|
|
495
|
+
args["base_url"] = cfg.get('api_endpoint_mistral', "")
|
|
529
496
|
self.window.core.debug.info("[api] Using client: Mistral AI API")
|
|
530
|
-
# HuggingFace Router
|
|
531
497
|
elif model.provider == "huggingface_router":
|
|
532
|
-
args["api_key"] =
|
|
533
|
-
args["base_url"] =
|
|
498
|
+
args["api_key"] = cfg.get('api_key_hugging_face', "")
|
|
499
|
+
args["base_url"] = cfg.get('api_endpoint_hugging_face', "")
|
|
534
500
|
self.window.core.debug.info("[api] Using client: HuggingFace Router API")
|
|
535
501
|
else:
|
|
536
502
|
self.window.core.debug.info("[api] Using client: OpenAI (default)")
|
|
537
503
|
|
|
538
|
-
# do not include organization for non-OpenAI providers
|
|
539
504
|
if model.provider != "openai":
|
|
540
505
|
if "organization" in args:
|
|
541
506
|
del args["organization"]
|
|
@@ -554,12 +519,9 @@ class Models:
|
|
|
554
519
|
if mode == MODE_LLAMA_INDEX:
|
|
555
520
|
if model.provider == "google":
|
|
556
521
|
stream = self.window.core.config.get('stream', False)
|
|
557
|
-
use_react = self.window.core.config.get("llama.idx.react", False)
|
|
522
|
+
use_react = self.window.core.config.get("llama.idx.react", False)
|
|
558
523
|
if stream:
|
|
559
|
-
|
|
560
|
-
return True
|
|
561
|
-
else:
|
|
562
|
-
return False
|
|
524
|
+
return bool(use_react)
|
|
563
525
|
if model.tool_calls:
|
|
564
526
|
return True
|
|
565
527
|
return False
|
|
@@ -570,4 +532,4 @@ class Models:
|
|
|
570
532
|
|
|
571
533
|
:return: config version
|
|
572
534
|
"""
|
|
573
|
-
return self.provider.get_version()
|
|
535
|
+
return self.provider.get_version()
|
pygpt_net/core/modes/modes.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
|
from typing import Dict, List
|
|
@@ -41,7 +41,7 @@ class Modes:
|
|
|
41
41
|
self.window = window
|
|
42
42
|
self.provider = JsonFileProvider(window)
|
|
43
43
|
self.initialized = False
|
|
44
|
-
self.all =
|
|
44
|
+
self.all = (
|
|
45
45
|
MODE_AGENT,
|
|
46
46
|
MODE_AGENT_LLAMA,
|
|
47
47
|
MODE_AGENT_OPENAI,
|
|
@@ -56,7 +56,7 @@ class Modes:
|
|
|
56
56
|
MODE_VISION,
|
|
57
57
|
MODE_RESEARCH,
|
|
58
58
|
MODE_COMPUTER,
|
|
59
|
-
|
|
59
|
+
)
|
|
60
60
|
self.items = {}
|
|
61
61
|
|
|
62
62
|
def get_by_idx(self, idx) -> str:
|
|
@@ -66,8 +66,8 @@ class Modes:
|
|
|
66
66
|
:param idx: index of mode
|
|
67
67
|
:return: mode name
|
|
68
68
|
"""
|
|
69
|
-
|
|
70
|
-
return
|
|
69
|
+
keys = tuple(self.items)
|
|
70
|
+
return keys[idx]
|
|
71
71
|
|
|
72
72
|
def get_idx_by_name(self, name) -> int:
|
|
73
73
|
"""
|
|
@@ -76,8 +76,8 @@ class Modes:
|
|
|
76
76
|
:param name: mode name
|
|
77
77
|
:return: mode index
|
|
78
78
|
"""
|
|
79
|
-
|
|
80
|
-
return
|
|
79
|
+
keys = tuple(self.items)
|
|
80
|
+
return keys.index(name)
|
|
81
81
|
|
|
82
82
|
def get_all(self) -> Dict[str, List[str]]:
|
|
83
83
|
"""
|
|
@@ -93,9 +93,7 @@ class Modes:
|
|
|
93
93
|
|
|
94
94
|
:return: default mode name
|
|
95
95
|
"""
|
|
96
|
-
for
|
|
97
|
-
if self.items[id].default:
|
|
98
|
-
return id
|
|
96
|
+
return next((k for k, v in self.items.items() if v.default), None)
|
|
99
97
|
|
|
100
98
|
def get_next(self, mode: str) -> str:
|
|
101
99
|
"""
|
|
@@ -104,12 +102,9 @@ class Modes:
|
|
|
104
102
|
:param mode: current mode
|
|
105
103
|
:return: next mode
|
|
106
104
|
"""
|
|
107
|
-
|
|
108
|
-
keys = list(modes.keys())
|
|
105
|
+
keys = tuple(self.items)
|
|
109
106
|
idx = keys.index(mode)
|
|
110
|
-
|
|
111
|
-
return keys[idx + 1]
|
|
112
|
-
return keys[0]
|
|
107
|
+
return keys[(idx + 1) % len(keys)]
|
|
113
108
|
|
|
114
109
|
def get_prev(self, mode: str) -> str:
|
|
115
110
|
"""
|
|
@@ -118,12 +113,9 @@ class Modes:
|
|
|
118
113
|
:param mode: current mode
|
|
119
114
|
:return: previous mode
|
|
120
115
|
"""
|
|
121
|
-
|
|
122
|
-
keys = list(modes.keys())
|
|
116
|
+
keys = tuple(self.items)
|
|
123
117
|
idx = keys.index(mode)
|
|
124
|
-
|
|
125
|
-
return keys[idx - 1]
|
|
126
|
-
return keys[-1]
|
|
118
|
+
return keys[(idx - 1) % len(keys)]
|
|
127
119
|
|
|
128
120
|
def load(self):
|
|
129
121
|
"""Load modes"""
|
|
@@ -131,4 +123,4 @@ class Modes:
|
|
|
131
123
|
|
|
132
124
|
def save(self):
|
|
133
125
|
"""Save modes"""
|
|
134
|
-
self.provider.save(self.items)
|
|
126
|
+
self.provider.save(self.items)
|