pygpt-net 2.6.1__py3-none-any.whl → 2.6.6__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 +23 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +20 -1
- pygpt_net/config.py +55 -65
- pygpt_net/controller/__init__.py +5 -2
- pygpt_net/controller/calendar/note.py +101 -126
- pygpt_net/controller/chat/chat.py +38 -35
- pygpt_net/controller/chat/render.py +154 -214
- pygpt_net/controller/chat/response.py +5 -3
- pygpt_net/controller/chat/stream.py +92 -27
- 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/ctx/common.py +48 -48
- pygpt_net/controller/ctx/ctx.py +91 -132
- 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 +176 -109
- pygpt_net/controller/mode/mode.py +88 -85
- pygpt_net/controller/model/model.py +73 -73
- pygpt_net/controller/plugins/plugins.py +209 -223
- pygpt_net/controller/plugins/presets.py +54 -55
- pygpt_net/controller/plugins/settings.py +54 -69
- pygpt_net/controller/presets/editor.py +33 -88
- pygpt_net/controller/presets/experts.py +20 -1
- pygpt_net/controller/presets/presets.py +293 -298
- pygpt_net/controller/settings/profile.py +16 -4
- pygpt_net/controller/theme/theme.py +72 -81
- pygpt_net/controller/ui/mode.py +118 -186
- pygpt_net/controller/ui/tabs.py +69 -90
- pygpt_net/controller/ui/ui.py +47 -56
- pygpt_net/controller/ui/vision.py +24 -23
- pygpt_net/core/agents/runner.py +15 -7
- 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/experts/experts.py +3 -3
- 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 +217 -215
- pygpt_net/core/render/web/renderer.py +330 -474
- pygpt_net/core/text/utils.py +28 -44
- pygpt_net/core/tokens/tokens.py +104 -203
- pygpt_net/data/config/config.json +3 -3
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/locale/locale.de.ini +2 -0
- pygpt_net/data/locale/locale.en.ini +2 -0
- pygpt_net/data/locale/locale.es.ini +2 -0
- pygpt_net/data/locale/locale.fr.ini +2 -0
- pygpt_net/data/locale/locale.it.ini +2 -0
- pygpt_net/data/locale/locale.pl.ini +3 -1
- pygpt_net/data/locale/locale.uk.ini +2 -0
- pygpt_net/data/locale/locale.zh.ini +2 -0
- 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 +101 -85
- pygpt_net/plugin/bitbucket/__init__.py +12 -0
- pygpt_net/plugin/bitbucket/config.py +267 -0
- pygpt_net/plugin/bitbucket/plugin.py +126 -0
- pygpt_net/plugin/bitbucket/worker.py +569 -0
- 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/__init__.py +12 -0
- pygpt_net/plugin/facebook/config.py +359 -0
- pygpt_net/plugin/facebook/plugin.py +113 -0
- pygpt_net/plugin/facebook/worker.py +698 -0
- pygpt_net/plugin/github/__init__.py +12 -0
- pygpt_net/plugin/github/config.py +441 -0
- pygpt_net/plugin/github/plugin.py +126 -0
- pygpt_net/plugin/github/worker.py +674 -0
- pygpt_net/plugin/google/__init__.py +12 -0
- pygpt_net/plugin/google/config.py +367 -0
- pygpt_net/plugin/google/plugin.py +126 -0
- pygpt_net/plugin/google/worker.py +826 -0
- 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/__init__.py +12 -0
- pygpt_net/plugin/slack/config.py +349 -0
- pygpt_net/plugin/slack/plugin.py +115 -0
- pygpt_net/plugin/slack/worker.py +639 -0
- pygpt_net/plugin/telegram/__init__.py +12 -0
- pygpt_net/plugin/telegram/config.py +308 -0
- pygpt_net/plugin/telegram/plugin.py +117 -0
- pygpt_net/plugin/telegram/worker.py +563 -0
- pygpt_net/plugin/twitter/__init__.py +12 -0
- pygpt_net/plugin/twitter/config.py +491 -0
- pygpt_net/plugin/twitter/plugin.py +125 -0
- pygpt_net/plugin/twitter/worker.py +837 -0
- pygpt_net/provider/agents/llama_index/legacy/openai_assistant.py +35 -3
- pygpt_net/tools/code_interpreter/tool.py +0 -1
- pygpt_net/tools/translator/tool.py +1 -1
- pygpt_net/ui/base/config_dialog.py +86 -100
- pygpt_net/ui/base/context_menu.py +48 -46
- pygpt_net/ui/dialog/preset.py +34 -77
- pygpt_net/ui/layout/ctx/ctx_list.py +10 -6
- pygpt_net/ui/layout/toolbox/presets.py +41 -41
- pygpt_net/ui/main.py +49 -31
- pygpt_net/ui/tray.py +61 -60
- pygpt_net/ui/widget/calendar/select.py +86 -70
- pygpt_net/ui/widget/lists/attachment.py +86 -44
- pygpt_net/ui/widget/lists/base_list_combo.py +85 -33
- pygpt_net/ui/widget/lists/context.py +135 -188
- pygpt_net/ui/widget/lists/preset.py +59 -61
- pygpt_net/ui/widget/textarea/web.py +161 -48
- pygpt_net/utils.py +8 -1
- {pygpt_net-2.6.1.dist-info → pygpt_net-2.6.6.dist-info}/METADATA +164 -2
- {pygpt_net-2.6.1.dist-info → pygpt_net-2.6.6.dist-info}/RECORD +131 -103
- {pygpt_net-2.6.1.dist-info → pygpt_net-2.6.6.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.1.dist-info → pygpt_net-2.6.6.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.1.dist-info → pygpt_net-2.6.6.dist-info}/entry_points.txt +0 -0
|
@@ -171,8 +171,9 @@ class Response:
|
|
|
171
171
|
if output and has_unclosed_code_tag(output):
|
|
172
172
|
ctx.output += "\n```"
|
|
173
173
|
ctx.msg_id = None
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
if ctx.id is None:
|
|
175
|
+
self.window.core.ctx.add(ctx) # store context to prevent current output from being lost
|
|
176
|
+
self.window.controller.ctx.prepare_name(ctx) # summarize if not yet
|
|
176
177
|
|
|
177
178
|
# finish render
|
|
178
179
|
self.window.dispatch(AppEvent(AppEvent.CTX_END)) # app event
|
|
@@ -228,7 +229,8 @@ class Response:
|
|
|
228
229
|
}
|
|
229
230
|
event = RenderEvent(RenderEvent.INPUT_APPEND, data)
|
|
230
231
|
self.window.dispatch(event)
|
|
231
|
-
|
|
232
|
+
if ctx.id is None:
|
|
233
|
+
self.window.core.ctx.add(ctx)
|
|
232
234
|
self.window.controller.ctx.update(
|
|
233
235
|
reload=True,
|
|
234
236
|
all=False,
|
|
@@ -6,11 +6,13 @@
|
|
|
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.16 00:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import base64
|
|
13
|
-
|
|
13
|
+
import gc
|
|
14
|
+
import io
|
|
15
|
+
from typing import Optional, Literal
|
|
14
16
|
|
|
15
17
|
from PySide6.QtCore import QObject, Signal, Slot, QRunnable
|
|
16
18
|
|
|
@@ -20,6 +22,32 @@ from pygpt_net.core.types import MODE_ASSISTANT
|
|
|
20
22
|
from pygpt_net.core.text.utils import has_unclosed_code_tag
|
|
21
23
|
from pygpt_net.item.ctx import CtxItem
|
|
22
24
|
|
|
25
|
+
EventType = Literal[
|
|
26
|
+
"response.completed",
|
|
27
|
+
"response.output_text.delta",
|
|
28
|
+
"response.output_item.added",
|
|
29
|
+
"response.function_call_arguments.delta",
|
|
30
|
+
"response.function_call_arguments.done",
|
|
31
|
+
"response.output_text.annotation.added",
|
|
32
|
+
"response.reasoning_summary_text.delta",
|
|
33
|
+
"response.output_item.done",
|
|
34
|
+
"response.code_interpreter_call_code.delta",
|
|
35
|
+
"response.code_interpreter_call_code.done",
|
|
36
|
+
"response.image_generation_call.partial_image",
|
|
37
|
+
"response.created",
|
|
38
|
+
"response.done",
|
|
39
|
+
"response.failed",
|
|
40
|
+
"error",
|
|
41
|
+
]
|
|
42
|
+
ChunkType = Literal[
|
|
43
|
+
"api_chat",
|
|
44
|
+
"api_chat_responses",
|
|
45
|
+
"api_completion",
|
|
46
|
+
"langchain_chat",
|
|
47
|
+
"llama_chat",
|
|
48
|
+
"raw",
|
|
49
|
+
]
|
|
50
|
+
|
|
23
51
|
class WorkerSignals(QObject):
|
|
24
52
|
"""
|
|
25
53
|
Defines the signals available from a running worker thread.
|
|
@@ -54,15 +82,15 @@ class StreamWorker(QRunnable):
|
|
|
54
82
|
output_tokens = 0
|
|
55
83
|
begin = True
|
|
56
84
|
error = None
|
|
57
|
-
fn_args_buffers = {}
|
|
58
|
-
citations = []
|
|
85
|
+
fn_args_buffers: dict[str, io.StringIO] = {}
|
|
86
|
+
citations: Optional[list] = []
|
|
59
87
|
files = []
|
|
60
88
|
img_path = core.image.gen_unique_path(ctx)
|
|
61
89
|
is_image = False
|
|
62
90
|
is_code = False
|
|
63
91
|
force_func_call = False
|
|
64
92
|
stopped = False
|
|
65
|
-
chunk_type = "raw"
|
|
93
|
+
chunk_type: ChunkType = "raw"
|
|
66
94
|
generator = ctx.stream
|
|
67
95
|
ctx.stream = None
|
|
68
96
|
|
|
@@ -77,6 +105,21 @@ class StreamWorker(QRunnable):
|
|
|
77
105
|
if generator is not None:
|
|
78
106
|
for chunk in generator:
|
|
79
107
|
if ctrl.kernel.stopped():
|
|
108
|
+
if hasattr(generator, 'close'):
|
|
109
|
+
try:
|
|
110
|
+
generator.close()
|
|
111
|
+
except Exception:
|
|
112
|
+
pass
|
|
113
|
+
elif hasattr(generator, 'cancel'):
|
|
114
|
+
try:
|
|
115
|
+
generator.cancel()
|
|
116
|
+
except Exception:
|
|
117
|
+
pass
|
|
118
|
+
elif hasattr(generator, 'stop'):
|
|
119
|
+
try:
|
|
120
|
+
generator.stop()
|
|
121
|
+
except Exception:
|
|
122
|
+
pass
|
|
80
123
|
ctx.msg_id = None
|
|
81
124
|
stopped = True
|
|
82
125
|
break
|
|
@@ -86,12 +129,12 @@ class StreamWorker(QRunnable):
|
|
|
86
129
|
stopped = True
|
|
87
130
|
break
|
|
88
131
|
|
|
89
|
-
etype = None
|
|
132
|
+
etype: Optional[EventType] = None
|
|
90
133
|
response = None
|
|
91
134
|
|
|
92
135
|
if ctx.use_responses_api:
|
|
93
136
|
if hasattr(chunk, 'type'):
|
|
94
|
-
etype = chunk.type
|
|
137
|
+
etype = chunk.type # type: ignore[assignment]
|
|
95
138
|
chunk_type = "api_chat_responses"
|
|
96
139
|
else:
|
|
97
140
|
continue
|
|
@@ -113,7 +156,6 @@ class StreamWorker(QRunnable):
|
|
|
113
156
|
else:
|
|
114
157
|
chunk_type = "raw"
|
|
115
158
|
|
|
116
|
-
# OpenAI chat completion
|
|
117
159
|
if chunk_type == "api_chat":
|
|
118
160
|
citations = None
|
|
119
161
|
delta = chunk.choices[0].delta
|
|
@@ -143,7 +185,6 @@ class StreamWorker(QRunnable):
|
|
|
143
185
|
if getattr(tool_chunk.function, "arguments", None):
|
|
144
186
|
tool_call["function"]["arguments"] += tool_chunk.function.arguments
|
|
145
187
|
|
|
146
|
-
# OpenAI Responses API
|
|
147
188
|
elif chunk_type == "api_chat_responses":
|
|
148
189
|
if etype == "response.completed":
|
|
149
190
|
for item in chunk.response.output:
|
|
@@ -182,7 +223,6 @@ class StreamWorker(QRunnable):
|
|
|
182
223
|
elif etype == "response.output_text.delta":
|
|
183
224
|
response = chunk.delta
|
|
184
225
|
|
|
185
|
-
# function_call
|
|
186
226
|
elif etype == "response.output_item.added" and chunk.item.type == "function_call":
|
|
187
227
|
tool_calls.append({
|
|
188
228
|
"id": chunk.item.id,
|
|
@@ -190,18 +230,23 @@ class StreamWorker(QRunnable):
|
|
|
190
230
|
"type": "function",
|
|
191
231
|
"function": {"name": chunk.item.name, "arguments": ""}
|
|
192
232
|
})
|
|
193
|
-
fn_args_buffers[chunk.item.id] =
|
|
233
|
+
fn_args_buffers[chunk.item.id] = io.StringIO()
|
|
194
234
|
elif etype == "response.function_call_arguments.delta":
|
|
195
|
-
fn_args_buffers
|
|
235
|
+
buf = fn_args_buffers.get(chunk.item_id)
|
|
236
|
+
if buf is not None:
|
|
237
|
+
buf.write(chunk.delta)
|
|
196
238
|
elif etype == "response.function_call_arguments.done":
|
|
197
239
|
buf = fn_args_buffers.pop(chunk.item_id, None)
|
|
198
240
|
if buf is not None:
|
|
241
|
+
try:
|
|
242
|
+
args_val = buf.getvalue()
|
|
243
|
+
finally:
|
|
244
|
+
buf.close()
|
|
199
245
|
for tc in tool_calls:
|
|
200
246
|
if tc["id"] == chunk.item_id:
|
|
201
|
-
tc["function"]["arguments"] =
|
|
247
|
+
tc["function"]["arguments"] = args_val
|
|
202
248
|
break
|
|
203
249
|
|
|
204
|
-
# annotations
|
|
205
250
|
elif etype == "response.output_text.annotation.added":
|
|
206
251
|
ann = chunk.annotation
|
|
207
252
|
if ann['type'] == "url_citation":
|
|
@@ -216,7 +261,6 @@ class StreamWorker(QRunnable):
|
|
|
216
261
|
"file_id": ann['file_id'],
|
|
217
262
|
})
|
|
218
263
|
|
|
219
|
-
# computer use
|
|
220
264
|
elif etype == "response.reasoning_summary_text.delta":
|
|
221
265
|
response = chunk.delta
|
|
222
266
|
|
|
@@ -225,7 +269,6 @@ class StreamWorker(QRunnable):
|
|
|
225
269
|
if has_calls:
|
|
226
270
|
force_func_call = True
|
|
227
271
|
|
|
228
|
-
# code interpreter
|
|
229
272
|
elif etype == "response.code_interpreter_call_code.delta":
|
|
230
273
|
if not is_code:
|
|
231
274
|
response = "\n\n**Code interpreter**\n```python\n" + chunk.delta
|
|
@@ -235,36 +278,30 @@ class StreamWorker(QRunnable):
|
|
|
235
278
|
elif etype == "response.code_interpreter_call_code.done":
|
|
236
279
|
response = "\n\n```\n-----------\n"
|
|
237
280
|
|
|
238
|
-
# image gen
|
|
239
281
|
elif etype == "response.image_generation_call.partial_image":
|
|
240
282
|
image_base64 = chunk.partial_image_b64
|
|
241
283
|
image_bytes = base64.b64decode(image_base64)
|
|
242
|
-
# prosty i bezpieczny overwrite (jak w oryginale)
|
|
243
284
|
with open(img_path, "wb") as f:
|
|
244
285
|
f.write(image_bytes)
|
|
286
|
+
del image_bytes
|
|
245
287
|
is_image = True
|
|
246
288
|
|
|
247
|
-
# response ID
|
|
248
289
|
elif etype == "response.created":
|
|
249
290
|
ctx.msg_id = str(chunk.response.id)
|
|
250
291
|
core.ctx.update_item(ctx)
|
|
251
292
|
|
|
252
|
-
# end/error etype – nic nie robimy
|
|
253
293
|
elif etype in {"response.done", "response.failed", "error"}:
|
|
254
294
|
pass
|
|
255
295
|
|
|
256
|
-
# OpenAI completion
|
|
257
296
|
elif chunk_type == "api_completion":
|
|
258
297
|
choice0 = chunk.choices[0]
|
|
259
298
|
if choice0.text is not None:
|
|
260
299
|
response = choice0.text
|
|
261
300
|
|
|
262
|
-
# langchain chat
|
|
263
301
|
elif chunk_type == "langchain_chat":
|
|
264
302
|
if chunk.content is not None:
|
|
265
303
|
response = str(chunk.content)
|
|
266
304
|
|
|
267
|
-
# llama chat
|
|
268
305
|
elif chunk_type == "llama_chat":
|
|
269
306
|
if chunk.delta is not None:
|
|
270
307
|
response = str(chunk.delta)
|
|
@@ -288,7 +325,6 @@ class StreamWorker(QRunnable):
|
|
|
288
325
|
tool_calls.clear()
|
|
289
326
|
tool_calls.append(tool_call)
|
|
290
327
|
|
|
291
|
-
# raw text (llama-index / langchain completion)
|
|
292
328
|
else:
|
|
293
329
|
if chunk is not None:
|
|
294
330
|
response = str(chunk)
|
|
@@ -313,13 +349,11 @@ class StreamWorker(QRunnable):
|
|
|
313
349
|
|
|
314
350
|
chunk = None
|
|
315
351
|
|
|
316
|
-
# tool calls
|
|
317
352
|
if tool_calls:
|
|
318
353
|
ctx.force_call = force_func_call
|
|
319
354
|
core.debug.info("[chat] Tool calls found, unpacking...")
|
|
320
355
|
core.command.unpack_tool_calls_chunks(ctx, tool_calls)
|
|
321
356
|
|
|
322
|
-
# image
|
|
323
357
|
if is_image:
|
|
324
358
|
core.debug.info("[chat] Image generation call found")
|
|
325
359
|
ctx.images = [img_path]
|
|
@@ -358,11 +392,17 @@ class StreamWorker(QRunnable):
|
|
|
358
392
|
|
|
359
393
|
emit_end(ctx)
|
|
360
394
|
|
|
395
|
+
for _buf in fn_args_buffers.values():
|
|
396
|
+
try:
|
|
397
|
+
_buf.close()
|
|
398
|
+
except Exception:
|
|
399
|
+
pass
|
|
361
400
|
fn_args_buffers.clear()
|
|
362
401
|
files.clear()
|
|
363
402
|
tool_calls.clear()
|
|
364
|
-
if citations is not None:
|
|
403
|
+
if citations is not None and citations is not ctx.urls:
|
|
365
404
|
citations.clear()
|
|
405
|
+
citations = None
|
|
366
406
|
|
|
367
407
|
self.cleanup()
|
|
368
408
|
|
|
@@ -407,6 +447,14 @@ class Stream:
|
|
|
407
447
|
):
|
|
408
448
|
"""
|
|
409
449
|
Asynchronous append of stream worker to the thread.
|
|
450
|
+
|
|
451
|
+
:param ctx: Context item
|
|
452
|
+
:param mode: Mode of operation (e.g., MODE_ASSISTANT)
|
|
453
|
+
:param is_response: Whether this is a response stream
|
|
454
|
+
:param reply: Reply identifier
|
|
455
|
+
:param internal: Whether this is an internal stream
|
|
456
|
+
:param context: Optional BridgeContext for additional context
|
|
457
|
+
:param extra: Additional data to pass to the stream
|
|
410
458
|
"""
|
|
411
459
|
self.ctx = ctx
|
|
412
460
|
self.mode = mode
|
|
@@ -430,6 +478,8 @@ class Stream:
|
|
|
430
478
|
def handleEnd(self, ctx: CtxItem):
|
|
431
479
|
"""
|
|
432
480
|
Slot for handling end of stream
|
|
481
|
+
|
|
482
|
+
:param ctx: Context item
|
|
433
483
|
"""
|
|
434
484
|
self.window.controller.ui.update_tokens()
|
|
435
485
|
|
|
@@ -457,9 +507,19 @@ class Stream:
|
|
|
457
507
|
self.worker = None
|
|
458
508
|
|
|
459
509
|
def handleEvent(self, event):
|
|
510
|
+
"""
|
|
511
|
+
Slot for handling stream events
|
|
512
|
+
|
|
513
|
+
:param event: RenderEvent
|
|
514
|
+
"""
|
|
460
515
|
self.window.dispatch(event)
|
|
461
516
|
|
|
462
517
|
def handleError(self, error):
|
|
518
|
+
"""
|
|
519
|
+
Slot for handling stream errors
|
|
520
|
+
|
|
521
|
+
:param error: Exception or error message
|
|
522
|
+
"""
|
|
463
523
|
self.window.core.debug.log(error)
|
|
464
524
|
if self.is_response:
|
|
465
525
|
if not isinstance(self.extra, dict):
|
|
@@ -475,4 +535,9 @@ class Stream:
|
|
|
475
535
|
)
|
|
476
536
|
|
|
477
537
|
def log(self, data: object):
|
|
538
|
+
"""
|
|
539
|
+
Log data to the debug console
|
|
540
|
+
|
|
541
|
+
:param data: object to log
|
|
542
|
+
"""
|
|
478
543
|
self.window.core.debug.info(data)
|
|
@@ -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 Any, Dict, List
|
|
@@ -40,6 +40,24 @@ class Config:
|
|
|
40
40
|
self.slider = Slider(window)
|
|
41
41
|
self.textarea = Textarea(window)
|
|
42
42
|
|
|
43
|
+
self._apply_map = {
|
|
44
|
+
'text': self.input.apply,
|
|
45
|
+
'textarea': self.textarea.apply,
|
|
46
|
+
'bool': self.checkbox.apply,
|
|
47
|
+
'bool_list': self.checkbox_list.apply,
|
|
48
|
+
'dict': self.dictionary.apply,
|
|
49
|
+
'combo': self.combo.apply,
|
|
50
|
+
'cmd': self.cmd.apply,
|
|
51
|
+
}
|
|
52
|
+
self._get_map = {
|
|
53
|
+
'text': self.input.get_value,
|
|
54
|
+
'textarea': self.textarea.get_value,
|
|
55
|
+
'bool': self.checkbox.get_value,
|
|
56
|
+
'bool_list': self.checkbox_list.get_value,
|
|
57
|
+
'dict': self.dictionary.get_value,
|
|
58
|
+
'cmd': self.cmd.get_value,
|
|
59
|
+
}
|
|
60
|
+
|
|
43
61
|
def load_options(
|
|
44
62
|
self,
|
|
45
63
|
parent_id: str,
|
|
@@ -51,8 +69,7 @@ class Config:
|
|
|
51
69
|
:param parent_id: Parent ID
|
|
52
70
|
:param options: Options dict
|
|
53
71
|
"""
|
|
54
|
-
for key in options:
|
|
55
|
-
option = options[key]
|
|
72
|
+
for key, option in options.items():
|
|
56
73
|
self.apply(parent_id, key, option)
|
|
57
74
|
|
|
58
75
|
def apply(
|
|
@@ -68,25 +85,16 @@ class Config:
|
|
|
68
85
|
:param key: Option key
|
|
69
86
|
:param option: Option dict
|
|
70
87
|
"""
|
|
71
|
-
|
|
72
|
-
|
|
88
|
+
t = option['type']
|
|
89
|
+
if t in ('int', 'float'):
|
|
90
|
+
if option.get('slider'):
|
|
73
91
|
self.slider.apply(parent_id, key, option)
|
|
74
92
|
else:
|
|
75
93
|
self.input.apply(parent_id, key, option)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
elif option['type'] == 'bool':
|
|
81
|
-
self.checkbox.apply(parent_id, key, option)
|
|
82
|
-
elif option['type'] == 'bool_list':
|
|
83
|
-
self.checkbox_list.apply(parent_id, key, option)
|
|
84
|
-
elif option['type'] == 'dict':
|
|
85
|
-
self.dictionary.apply(parent_id, key, option)
|
|
86
|
-
elif option['type'] == 'combo':
|
|
87
|
-
self.combo.apply(parent_id, key, option)
|
|
88
|
-
elif option['type'] == 'cmd':
|
|
89
|
-
self.cmd.apply(parent_id, key, option)
|
|
94
|
+
return
|
|
95
|
+
func = self._apply_map.get(t)
|
|
96
|
+
if func:
|
|
97
|
+
func(parent_id, key, option)
|
|
90
98
|
|
|
91
99
|
def apply_value(
|
|
92
100
|
self,
|
|
@@ -122,25 +130,16 @@ class Config:
|
|
|
122
130
|
:param idx: return selected idx, not the value
|
|
123
131
|
:return: Option value
|
|
124
132
|
"""
|
|
125
|
-
|
|
126
|
-
|
|
133
|
+
t = option['type']
|
|
134
|
+
if t in ('int', 'float'):
|
|
135
|
+
if option.get('slider'):
|
|
127
136
|
return self.slider.get_value(parent_id, key, option)
|
|
128
|
-
else:
|
|
129
|
-
return self.input.get_value(parent_id, key, option)
|
|
130
|
-
elif option['type'] == 'text':
|
|
131
137
|
return self.input.get_value(parent_id, key, option)
|
|
132
|
-
|
|
133
|
-
return self.textarea.get_value(parent_id, key, option)
|
|
134
|
-
elif option['type'] == 'bool':
|
|
135
|
-
return self.checkbox.get_value(parent_id, key, option)
|
|
136
|
-
elif option['type'] == 'bool_list':
|
|
137
|
-
return self.checkbox_list.get_value(parent_id, key, option)
|
|
138
|
-
elif option['type'] == 'dict':
|
|
139
|
-
return self.dictionary.get_value(parent_id, key, option)
|
|
140
|
-
elif option['type'] == 'combo':
|
|
138
|
+
if t == 'combo':
|
|
141
139
|
return self.combo.get_value(parent_id, key, option, idx)
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
func = self._get_map.get(t)
|
|
141
|
+
if func:
|
|
142
|
+
return func(parent_id, key, option)
|
|
144
143
|
|
|
145
144
|
def update_list(
|
|
146
145
|
self,
|
|
@@ -159,13 +158,11 @@ class Config:
|
|
|
159
158
|
"""
|
|
160
159
|
if "type" not in option:
|
|
161
160
|
return
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
for
|
|
165
|
-
for k, v in item.items():
|
|
166
|
-
as_dict[k] = v
|
|
161
|
+
t = option['type']
|
|
162
|
+
if t == 'combo':
|
|
163
|
+
as_dict = {k: v for d in items for k, v in d.items()}
|
|
167
164
|
self.update_combo(parent_id, key, as_dict)
|
|
168
|
-
elif
|
|
165
|
+
elif t == 'bool_list':
|
|
169
166
|
self.update_bool_list(parent_id, key, items)
|
|
170
167
|
|
|
171
168
|
def update_combo(
|
|
@@ -196,4 +193,4 @@ class Config:
|
|
|
196
193
|
:param key: Option key
|
|
197
194
|
:param items: Items dict
|
|
198
195
|
"""
|
|
199
|
-
self.checkbox_list.update_list(parent_id, key, items)
|
|
196
|
+
self.checkbox_list.update_list(parent_id, key, items)
|
|
@@ -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 Any, Dict
|
|
@@ -26,7 +26,7 @@ class Checkbox:
|
|
|
26
26
|
parent_id: str,
|
|
27
27
|
key: str,
|
|
28
28
|
option: Dict[str, Any]
|
|
29
|
-
):
|
|
29
|
+
) -> None:
|
|
30
30
|
"""
|
|
31
31
|
Apply value to checkbox
|
|
32
32
|
|
|
@@ -39,17 +39,19 @@ class Checkbox:
|
|
|
39
39
|
value = option["value"]
|
|
40
40
|
if value is None:
|
|
41
41
|
value = False
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
cfg_parent = self.window.ui.config[parent_id]
|
|
43
|
+
row = cfg_parent.get(key)
|
|
44
|
+
if row is not None:
|
|
45
|
+
row.box.setChecked(bool(value))
|
|
44
46
|
|
|
45
47
|
def on_update(
|
|
46
48
|
self,
|
|
47
49
|
parent_id: str,
|
|
48
50
|
key: str,
|
|
49
|
-
option:
|
|
51
|
+
option: Dict[str, Any],
|
|
50
52
|
value: Any,
|
|
51
53
|
hooks: bool = True
|
|
52
|
-
):
|
|
54
|
+
) -> None:
|
|
53
55
|
"""
|
|
54
56
|
Event: on update checkbox value
|
|
55
57
|
|
|
@@ -59,11 +61,11 @@ class Checkbox:
|
|
|
59
61
|
:param value: Option value
|
|
60
62
|
:param hooks: Run hooks
|
|
61
63
|
"""
|
|
62
|
-
# on update hooks
|
|
63
64
|
if hooks:
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
ui = self.window.ui
|
|
66
|
+
hook_name = f"update.{parent_id}.{key}"
|
|
67
|
+
if ui.has_hook(hook_name):
|
|
68
|
+
hook = ui.get_hook(hook_name)
|
|
67
69
|
try:
|
|
68
70
|
hook(key, value, 'checkbox')
|
|
69
71
|
except Exception as e:
|
|
@@ -83,6 +85,8 @@ class Checkbox:
|
|
|
83
85
|
:param option: Option data dict
|
|
84
86
|
:return: Option value
|
|
85
87
|
"""
|
|
86
|
-
|
|
88
|
+
cfg_parent = self.window.ui.config[parent_id]
|
|
89
|
+
row = cfg_parent.get(key)
|
|
90
|
+
if row is None:
|
|
87
91
|
return False
|
|
88
|
-
return
|
|
92
|
+
return row.box.isChecked()
|
|
@@ -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 Any, Dict, List
|
|
@@ -37,19 +37,24 @@ class CheckboxList:
|
|
|
37
37
|
if "value" not in option:
|
|
38
38
|
return
|
|
39
39
|
value = option["value"]
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
selection = {s.strip() for s in value.split(",")} if isinstance(value, str) else set()
|
|
41
|
+
selection.discard("")
|
|
42
|
+
|
|
43
|
+
ui = self.window.ui
|
|
44
|
+
cfg_parent = ui.config.get(parent_id)
|
|
45
|
+
if not cfg_parent:
|
|
46
|
+
return
|
|
47
|
+
entry = cfg_parent.get(key)
|
|
48
|
+
if entry is None or not hasattr(entry, "boxes"):
|
|
49
|
+
return
|
|
50
|
+
boxes = entry.boxes
|
|
51
|
+
|
|
52
|
+
for name, cb in boxes.items():
|
|
53
|
+
if cb is None:
|
|
51
54
|
continue
|
|
52
|
-
|
|
55
|
+
desired = name in selection
|
|
56
|
+
if cb.isChecked() != desired:
|
|
57
|
+
cb.setChecked(desired)
|
|
53
58
|
|
|
54
59
|
def on_update(
|
|
55
60
|
self,
|
|
@@ -70,15 +75,16 @@ class CheckboxList:
|
|
|
70
75
|
:param subkey: Subkey for specific checkbox
|
|
71
76
|
:param hooks: Run hooks
|
|
72
77
|
"""
|
|
73
|
-
# on update hooks
|
|
74
78
|
if hooks:
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
ui = self.window.ui
|
|
80
|
+
hook_name = f"update.{parent_id}.{key}"
|
|
81
|
+
if ui.has_hook(hook_name):
|
|
82
|
+
hook = ui.get_hook(hook_name)
|
|
83
|
+
if hook:
|
|
84
|
+
try:
|
|
85
|
+
hook(key, value, 'bool_list')
|
|
86
|
+
except Exception as e:
|
|
87
|
+
self.window.core.debug.log(e)
|
|
82
88
|
|
|
83
89
|
def get_value(
|
|
84
90
|
self,
|
|
@@ -94,16 +100,15 @@ class CheckboxList:
|
|
|
94
100
|
:param option: Option data dict
|
|
95
101
|
:return: Option value
|
|
96
102
|
"""
|
|
97
|
-
|
|
103
|
+
ui = self.window.ui
|
|
104
|
+
cfg_parent = ui.config.get(parent_id)
|
|
105
|
+
if not cfg_parent:
|
|
98
106
|
return ""
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
imploded_list.append(item)
|
|
105
|
-
return ",".join(imploded_list)
|
|
106
|
-
|
|
107
|
+
entry = cfg_parent.get(key)
|
|
108
|
+
if entry is None or not hasattr(entry, "boxes"):
|
|
109
|
+
return ""
|
|
110
|
+
boxes = entry.boxes
|
|
111
|
+
return ",".join(name for name, cb in boxes.items() if cb is not None and cb.isChecked())
|
|
107
112
|
|
|
108
113
|
def update_list(
|
|
109
114
|
self,
|
|
@@ -118,4 +123,4 @@ class CheckboxList:
|
|
|
118
123
|
:param key: Option key
|
|
119
124
|
:param items: Items dict
|
|
120
125
|
"""
|
|
121
|
-
self.window.ui.config[parent_id][key].update_boxes_list(items)
|
|
126
|
+
self.window.ui.config[parent_id][key].update_boxes_list(items)
|