pygpt-net 2.6.3__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.
Files changed (78) hide show
  1. pygpt_net/CHANGELOG.txt +14 -0
  2. pygpt_net/__init__.py +2 -2
  3. pygpt_net/app.py +6 -1
  4. pygpt_net/config.py +55 -65
  5. pygpt_net/controller/__init__.py +5 -2
  6. pygpt_net/controller/chat/chat.py +38 -35
  7. pygpt_net/controller/chat/render.py +144 -217
  8. pygpt_net/controller/chat/stream.py +52 -25
  9. pygpt_net/controller/config/config.py +39 -42
  10. pygpt_net/controller/config/field/checkbox.py +16 -12
  11. pygpt_net/controller/config/field/checkbox_list.py +36 -31
  12. pygpt_net/controller/config/field/cmd.py +51 -57
  13. pygpt_net/controller/config/field/combo.py +33 -16
  14. pygpt_net/controller/config/field/dictionary.py +48 -55
  15. pygpt_net/controller/config/field/input.py +50 -32
  16. pygpt_net/controller/config/field/slider.py +40 -45
  17. pygpt_net/controller/config/field/textarea.py +20 -6
  18. pygpt_net/controller/config/placeholder.py +110 -231
  19. pygpt_net/controller/ctx/common.py +48 -49
  20. pygpt_net/controller/ctx/ctx.py +24 -4
  21. pygpt_net/controller/lang/mapping.py +57 -95
  22. pygpt_net/controller/lang/plugins.py +64 -55
  23. pygpt_net/controller/lang/settings.py +39 -38
  24. pygpt_net/controller/layout/layout.py +11 -2
  25. pygpt_net/controller/plugins/plugins.py +19 -1
  26. pygpt_net/controller/settings/profile.py +16 -4
  27. pygpt_net/controller/ui/mode.py +107 -125
  28. pygpt_net/core/bridge/bridge.py +5 -5
  29. pygpt_net/core/command/command.py +149 -219
  30. pygpt_net/core/ctx/ctx.py +94 -146
  31. pygpt_net/core/debug/debug.py +48 -58
  32. pygpt_net/core/models/models.py +74 -112
  33. pygpt_net/core/modes/modes.py +13 -21
  34. pygpt_net/core/plugins/plugins.py +154 -177
  35. pygpt_net/core/presets/presets.py +103 -176
  36. pygpt_net/core/render/web/body.py +50 -39
  37. pygpt_net/core/render/web/renderer.py +154 -251
  38. pygpt_net/core/text/utils.py +28 -44
  39. pygpt_net/core/tokens/tokens.py +104 -203
  40. pygpt_net/data/config/config.json +3 -3
  41. pygpt_net/data/config/models.json +3 -3
  42. pygpt_net/item/ctx.py +141 -139
  43. pygpt_net/plugin/agent/plugin.py +2 -1
  44. pygpt_net/plugin/audio_output/plugin.py +5 -2
  45. pygpt_net/plugin/base/plugin.py +77 -93
  46. pygpt_net/plugin/bitbucket/plugin.py +3 -2
  47. pygpt_net/plugin/cmd_code_interpreter/plugin.py +3 -2
  48. pygpt_net/plugin/cmd_custom/plugin.py +3 -2
  49. pygpt_net/plugin/cmd_files/plugin.py +3 -2
  50. pygpt_net/plugin/cmd_history/plugin.py +3 -2
  51. pygpt_net/plugin/cmd_mouse_control/plugin.py +5 -2
  52. pygpt_net/plugin/cmd_serial/plugin.py +3 -2
  53. pygpt_net/plugin/cmd_system/plugin.py +3 -6
  54. pygpt_net/plugin/cmd_web/plugin.py +3 -2
  55. pygpt_net/plugin/experts/plugin.py +2 -2
  56. pygpt_net/plugin/facebook/plugin.py +3 -4
  57. pygpt_net/plugin/github/plugin.py +4 -2
  58. pygpt_net/plugin/google/plugin.py +3 -3
  59. pygpt_net/plugin/idx_llama_index/plugin.py +3 -2
  60. pygpt_net/plugin/mailer/plugin.py +3 -5
  61. pygpt_net/plugin/openai_vision/plugin.py +3 -2
  62. pygpt_net/plugin/real_time/plugin.py +52 -60
  63. pygpt_net/plugin/slack/plugin.py +3 -4
  64. pygpt_net/plugin/telegram/plugin.py +3 -4
  65. pygpt_net/plugin/twitter/plugin.py +3 -4
  66. pygpt_net/tools/code_interpreter/tool.py +0 -1
  67. pygpt_net/tools/translator/tool.py +1 -1
  68. pygpt_net/ui/layout/ctx/ctx_list.py +10 -6
  69. pygpt_net/ui/main.py +46 -30
  70. pygpt_net/ui/tray.py +61 -60
  71. pygpt_net/ui/widget/lists/context.py +2 -2
  72. pygpt_net/ui/widget/textarea/web.py +161 -48
  73. pygpt_net/utils.py +8 -1
  74. {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.6.dist-info}/METADATA +16 -2
  75. {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.6.dist-info}/RECORD +78 -78
  76. {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.6.dist-info}/LICENSE +0 -0
  77. {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.6.dist-info}/WHEEL +0 -0
  78. {pygpt_net-2.6.3.dist-info → pygpt_net-2.6.6.dist-info}/entry_points.txt +0 -0
@@ -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.15 03:00:00 #
9
+ # Updated Date: 2025.08.15 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional, List
@@ -24,6 +24,13 @@ from pygpt_net.item.ctx import CtxItem, CtxMeta
24
24
 
25
25
 
26
26
  class Render:
27
+
28
+ _STATE_EVENTS = (
29
+ RenderEvent.STATE_IDLE,
30
+ RenderEvent.STATE_BUSY,
31
+ RenderEvent.STATE_ERROR,
32
+ )
33
+
27
34
  def __init__(self, window=None):
28
35
  """
29
36
  Render controller
@@ -38,130 +45,128 @@ class Render:
38
45
  self.scroll = 0
39
46
  self.renderer = None
40
47
 
41
- def setup(self):
48
+ def setup(self) -> None:
42
49
  """Setup render"""
43
50
  self.engine = self.window.core.config.get("render.engine")
51
+ if self.window.core.config.get('render.plain'):
52
+ self.renderer = self.plaintext_renderer
53
+ else:
54
+ self.renderer = self.web_renderer if self.engine == "web" else self.markdown_renderer
44
55
 
45
- def prepare(self):
56
+ def prepare(self) -> None:
46
57
  """Prepare render"""
47
58
  self.markdown_renderer.prepare()
48
59
  self.plaintext_renderer.prepare()
49
60
  self.web_renderer.prepare()
50
61
 
51
- def handle(self, event: RenderEvent):
62
+ def handle(self, event: RenderEvent) -> None:
52
63
  """
53
64
  Handle render event
54
65
 
55
66
  :param event: RenderEvent
56
67
  """
57
68
  name = event.name
58
- data = event.data
59
- if data is None:
60
- data = {}
61
-
62
- chunk = data.get("chunk", "")
63
- begin = data.get("begin", False)
64
- stream = data.get("stream", False)
65
- ctx = data.get("ctx")
66
- meta = data.get("meta")
67
- tool_data = data.get("tool_data")
68
- items = data.get("items")
69
- clear = data.get("clear", False)
70
- flush = data.get("flush", False)
71
- append = data.get("append", False)
72
- footer = data.get("footer", False)
73
- initialized = data.get("initialized", False)
74
- tab = data.get("tab")
69
+ data = event.data or {}
75
70
 
76
71
  if name == RenderEvent.BEGIN:
77
- self.begin(meta, ctx, stream)
72
+ self.begin(data.get("meta"), data.get("ctx"), data.get("stream", False))
78
73
  elif name == RenderEvent.END:
79
- self.end(meta, ctx, stream)
74
+ self.end(data.get("meta"), data.get("ctx"), data.get("stream", False))
80
75
  elif name == RenderEvent.RELOAD:
81
76
  self.reload()
82
77
  elif name == RenderEvent.RESET:
83
- self.reset(meta)
78
+ self.reset(data.get("meta"))
84
79
  elif name == RenderEvent.PREPARE:
85
80
  self.prepare()
86
81
 
87
82
  elif name == RenderEvent.STREAM_BEGIN:
88
- self.stream_begin(meta, ctx)
83
+ self.stream_begin(data.get("meta"), data.get("ctx"))
89
84
  elif name == RenderEvent.STREAM_APPEND:
90
- self.instance().append_chunk(meta, ctx, chunk, begin)
85
+ self.instance().append_chunk(
86
+ data.get("meta"),
87
+ data.get("ctx"),
88
+ data.get("chunk", ""),
89
+ data.get("begin", False),
90
+ )
91
91
  elif name == RenderEvent.STREAM_NEXT:
92
- self.next_chunk(meta, ctx)
92
+ self.next_chunk(data.get("meta"), data.get("ctx"))
93
93
  elif name == RenderEvent.STREAM_END:
94
- self.stream_end(meta, ctx)
94
+ self.stream_end(data.get("meta"), data.get("ctx"))
95
95
 
96
96
  elif name == RenderEvent.ON_PAGE_LOAD:
97
- self.on_page_loaded(meta, tab)
97
+ self.on_page_loaded(data.get("meta"), data.get("tab"))
98
98
  elif name == RenderEvent.ON_THEME_CHANGE:
99
99
  self.on_theme_change()
100
100
  elif name == RenderEvent.ON_LOAD:
101
- self.on_load(meta)
101
+ self.on_load(data.get("meta"))
102
102
  elif name == RenderEvent.FRESH:
103
- self.fresh(meta)
103
+ self.fresh(data.get("meta"))
104
104
  elif name == RenderEvent.ON_TS_ENABLE:
105
- self.on_enable_timestamp(live=initialized)
105
+ self.on_enable_timestamp(live=data.get("initialized", False))
106
106
  elif name == RenderEvent.ON_TS_DISABLE:
107
- self.on_disable_timestamp(live=initialized)
107
+ self.on_disable_timestamp(live=data.get("initialized", False))
108
108
  elif name == RenderEvent.ON_EDIT_ENABLE:
109
- self.on_enable_edit(live=initialized)
109
+ self.on_enable_edit(live=data.get("initialized", False))
110
110
  elif name == RenderEvent.ON_EDIT_DISABLE:
111
- self.on_disable_edit(live=initialized)
111
+ self.on_disable_edit(live=data.get("initialized", False))
112
112
  elif name == RenderEvent.ON_SWITCH:
113
113
  self.switch()
114
114
 
115
115
  elif name == RenderEvent.CLEAR_INPUT:
116
116
  self.clear_input()
117
117
  elif name == RenderEvent.CLEAR_OUTPUT:
118
- self.clear_output(meta)
118
+ self.clear_output(data.get("meta"))
119
119
  elif name == RenderEvent.CLEAR_ALL:
120
120
  self.clear_all()
121
121
  elif name == RenderEvent.CLEAR:
122
- self.clear(meta)
122
+ self.clear(data.get("meta"))
123
123
 
124
124
  elif name == RenderEvent.TOOL_UPDATE:
125
- self.tool_output_update(meta, tool_data)
125
+ self.tool_output_update(data.get("meta"), data.get("tool_data"))
126
126
  elif name == RenderEvent.TOOL_CLEAR:
127
- self.tool_output_clear(meta)
127
+ self.tool_output_clear(data.get("meta"))
128
128
  elif name == RenderEvent.TOOL_BEGIN:
129
- self.tool_output_begin(meta)
129
+ self.tool_output_begin(data.get("meta"))
130
130
  elif name == RenderEvent.TOOL_END:
131
131
  self.tool_output_end()
132
132
 
133
133
  elif name == RenderEvent.CTX_APPEND:
134
- self.append_context(meta, items, clear)
134
+ self.append_context(data.get("meta"), data.get("items"), data.get("clear", True))
135
135
  elif name == RenderEvent.INPUT_APPEND:
136
- self.append_input(meta, ctx, flush, append)
136
+ self.append_input(
137
+ data.get("meta"),
138
+ data.get("ctx"),
139
+ data.get("flush", True),
140
+ data.get("append", False),
141
+ )
137
142
  elif name == RenderEvent.OUTPUT_APPEND:
138
- self.append_output(meta, ctx)
143
+ self.append_output(data.get("meta"), data.get("ctx"))
139
144
 
140
145
  elif name == RenderEvent.EXTRA_APPEND:
141
- self.append_extra(meta, ctx, footer)
146
+ self.append_extra(data.get("meta"), data.get("ctx"), data.get("footer", False))
142
147
  elif name == RenderEvent.EXTRA_END:
143
- self.end_extra(meta, ctx)
148
+ self.end_extra(data.get("meta"), data.get("ctx"))
144
149
 
145
150
  elif name == RenderEvent.LIVE_APPEND:
146
- self.append_live(meta, ctx, chunk, begin)
151
+ self.append_live(
152
+ data.get("meta"),
153
+ data.get("ctx"),
154
+ data.get("chunk", ""),
155
+ data.get("begin", False),
156
+ )
147
157
  elif name == RenderEvent.LIVE_CLEAR:
148
- self.clear_live(meta, ctx)
158
+ self.clear_live(data.get("meta"), data.get("ctx"))
149
159
 
150
160
  elif name == RenderEvent.ACTION_REGEN_SUBMIT:
151
- self.on_reply_submit(ctx)
161
+ self.on_reply_submit(data.get("ctx"))
152
162
  elif name == RenderEvent.ACTION_EDIT_SUBMIT:
153
- self.on_edit_submit(ctx)
154
-
155
- # kernel state changed
156
- elif name in [
157
- RenderEvent.STATE_IDLE,
158
- RenderEvent.STATE_BUSY,
159
- RenderEvent.STATE_ERROR,
160
- ]:
161
- meta = meta or self.window.core.ctx.get_current_meta()
163
+ self.on_edit_submit(data.get("ctx"))
164
+
165
+ elif name in self._STATE_EVENTS:
166
+ meta = data.get("meta") or self.window.core.ctx.get_current_meta()
162
167
  self.on_state_changed(name, meta)
163
168
 
164
- def on_state_changed(self, state: str, meta: Optional[CtxMeta] = None):
169
+ def on_state_changed(self, state: str, meta: Optional[CtxMeta] = None) -> None:
165
170
  """
166
171
  Handle state change event
167
172
 
@@ -170,7 +175,7 @@ class Render:
170
175
  """
171
176
  self.instance().state_changed(state, meta)
172
177
 
173
- def append_live(self, meta: CtxMeta, ctx: CtxItem, text_chunk: str, begin: bool = False):
178
+ def append_live(self, meta: CtxMeta, ctx: CtxItem, text_chunk: str, begin: bool = False) -> None:
174
179
  """
175
180
  Append live text chunk to output
176
181
 
@@ -181,7 +186,7 @@ class Render:
181
186
  """
182
187
  self.instance().append_live(meta, ctx, text_chunk, begin)
183
188
 
184
- def clear_live(self, meta: CtxMeta, ctx: CtxItem):
189
+ def clear_live(self, meta: CtxMeta, ctx: CtxItem) -> None:
185
190
  """
186
191
  Clear live output
187
192
 
@@ -200,12 +205,7 @@ class Render:
200
205
  """
201
206
  return self.instance().get_pid(meta)
202
207
 
203
- def begin(
204
- self,
205
- meta: CtxMeta,
206
- ctx: CtxItem,
207
- stream: bool = False
208
- ):
208
+ def begin(self, meta: CtxMeta, ctx: CtxItem, stream: bool = False) -> None:
209
209
  """
210
210
  Render begin
211
211
 
@@ -216,12 +216,7 @@ class Render:
216
216
  self.instance().begin(meta, ctx, stream)
217
217
  self.update()
218
218
 
219
- def end(
220
- self,
221
- meta: CtxMeta,
222
- ctx: CtxItem,
223
- stream: bool = False
224
- ):
219
+ def end(self, meta: CtxMeta, ctx: CtxItem, stream: bool = False) -> None:
225
220
  """
226
221
  Render end
227
222
 
@@ -232,15 +227,10 @@ class Render:
232
227
  self.instance().end(meta, ctx, stream)
233
228
  self.update()
234
229
 
235
- def end_extra(
236
- self,
237
- meta: CtxMeta,
238
- ctx: CtxItem,
239
- stream: bool = False
240
- ):
230
+ def end_extra(self, meta: CtxMeta, ctx: CtxItem, stream: bool = False) -> None:
241
231
  """
242
232
  Render end extra
243
-
233
+
244
234
  :param meta: context meta
245
235
  :param ctx: context item
246
236
  :param stream: True if it is a stream
@@ -248,38 +238,27 @@ class Render:
248
238
  self.instance().end_extra(meta, ctx, stream)
249
239
  self.update()
250
240
 
251
- def stream_begin(
252
- self,
253
- meta: CtxMeta,
254
- ctx: CtxItem
255
- ):
241
+ def stream_begin(self, meta: CtxMeta, ctx: CtxItem) -> None:
256
242
  """
257
243
  Render stream begin
258
-
244
+
259
245
  :param meta: context meta
260
246
  :param ctx: context item
261
247
  """
262
248
  self.instance().stream_begin(meta, ctx)
263
249
  self.update()
264
250
 
265
- def stream_end(
266
- self,
267
- meta: CtxMeta,
268
- ctx: CtxItem
269
- ):
251
+ def stream_end(self, meta: CtxMeta, ctx: CtxItem) -> None:
270
252
  """
271
253
  Render stream end
272
-
254
+
273
255
  :param meta: context meta
274
256
  :param ctx: context item
275
257
  """
276
258
  self.instance().stream_end(meta, ctx)
277
259
  self.update()
278
260
 
279
- def clear_output(
280
- self,
281
- meta: Optional[CtxMeta] = None
282
- ):
261
+ def clear_output(self, meta: Optional[CtxMeta] = None) -> None:
283
262
  """
284
263
  Clear current active output
285
264
 
@@ -288,14 +267,11 @@ class Render:
288
267
  self.instance().clear_output(meta) # TODO: get meta id on load
289
268
  self.update()
290
269
 
291
- def clear_input(self):
270
+ def clear_input(self) -> None:
292
271
  """Clear input"""
293
272
  self.instance().clear_input()
294
273
 
295
- def on_load(
296
- self,
297
- meta: Optional[CtxMeta] = None
298
- ):
274
+ def on_load(self, meta: Optional[CtxMeta] = None) -> None:
299
275
  """
300
276
  On load (meta)
301
277
 
@@ -305,10 +281,7 @@ class Render:
305
281
  self.update()
306
282
  self.window.controller.ui.tabs.update_tooltip(meta.name) # update tab tooltip
307
283
 
308
- def fresh(
309
- self,
310
- meta: Optional[CtxMeta] = None
311
- ):
284
+ def fresh(self, meta: Optional[CtxMeta] = None) -> None:
312
285
  """
313
286
  On load (meta)
314
287
 
@@ -316,10 +289,7 @@ class Render:
316
289
  """
317
290
  self.instance().fresh(meta)
318
291
 
319
- def reset(
320
- self,
321
- meta: Optional[CtxMeta] = None
322
- ):
292
+ def reset(self, meta: Optional[CtxMeta] = None) -> None:
323
293
  """
324
294
  Reset current meta
325
295
 
@@ -328,17 +298,12 @@ class Render:
328
298
  self.instance().reset(meta) # TODO: get meta id on load
329
299
  self.update()
330
300
 
331
- def reload(self):
301
+ def reload(self) -> None:
332
302
  """Reload current output"""
333
303
  self.instance().reload() # TODO: or all outputs?
334
304
  self.update()
335
305
 
336
- def append_context(
337
- self,
338
- meta: CtxMeta,
339
- items: List[CtxItem],
340
- clear: bool = True
341
- ):
306
+ def append_context(self, meta: CtxMeta, items: List[CtxItem], clear: bool = True) -> None:
342
307
  """
343
308
  Append all context to output
344
309
 
@@ -349,16 +314,10 @@ class Render:
349
314
  self.instance().append_context(meta, items, clear)
350
315
  self.update()
351
316
 
352
- def append_input(
353
- self,
354
- meta: CtxMeta,
355
- ctx: CtxItem,
356
- flush: bool = True,
357
- append: bool = False
358
- ):
317
+ def append_input(self, meta: CtxMeta, ctx: CtxItem, flush: bool = True, append: bool = False) -> None:
359
318
  """
360
319
  Append text input to output
361
-
320
+
362
321
  :param meta: context meta
363
322
  :param ctx: context item
364
323
  :param flush: True if flush output
@@ -367,29 +326,20 @@ class Render:
367
326
  self.instance().append_input(meta, ctx, flush=flush, append=append)
368
327
  self.update()
369
328
 
370
- def append_output(
371
- self,
372
- meta: CtxMeta,
373
- ctx: CtxItem
374
- ):
329
+ def append_output(self, meta: CtxMeta, ctx: CtxItem) -> None:
375
330
  """
376
331
  Append text output to output
377
-
332
+
378
333
  :param meta: context meta
379
334
  :param ctx: context item
380
335
  """
381
336
  self.instance().append_output(meta, ctx)
382
337
  self.update()
383
338
 
384
- def append_extra(
385
- self,
386
- meta: CtxMeta,
387
- ctx: CtxItem,
388
- footer: bool = False
389
- ):
339
+ def append_extra(self, meta: CtxMeta, ctx: CtxItem, footer: bool = False) -> None:
390
340
  """
391
341
  Append extra data (images, files, etc.) to output
392
-
342
+
393
343
  :param meta: context meta
394
344
  :param ctx: context item
395
345
  :param footer: True if it is a footer
@@ -397,16 +347,10 @@ class Render:
397
347
  self.instance().append_extra(meta, ctx, footer)
398
348
  self.update()
399
349
 
400
- def append_chunk(
401
- self,
402
- meta: CtxMeta,
403
- ctx: CtxItem,
404
- text_chunk: str,
405
- begin: bool = False
406
- ):
350
+ def append_chunk(self, meta: CtxMeta, ctx: CtxItem, text_chunk: str, begin: bool = False) -> None:
407
351
  """
408
352
  Append output stream chunk to output
409
-
353
+
410
354
  :param meta: context meta
411
355
  :param ctx: context item
412
356
  :param text_chunk: text chunk
@@ -414,21 +358,17 @@ class Render:
414
358
  """
415
359
  self.instance().append_chunk(meta, ctx, text_chunk, begin)
416
360
 
417
- def next_chunk(
418
- self,
419
- meta: CtxMeta,
420
- ctx: CtxItem,
421
- ):
361
+ def next_chunk(self, meta: CtxMeta, ctx: CtxItem) -> None:
422
362
  """
423
363
  Flush current stream and start with new chunks
424
-
364
+
425
365
  :param meta: context meta
426
366
  :param ctx: context item
427
367
  """
428
368
  self.instance().next_chunk(meta, ctx)
429
369
  self.update()
430
370
 
431
- def on_enable_edit(self, live: bool = True):
371
+ def on_enable_edit(self, live: bool = True) -> None:
432
372
  """
433
373
  On enable edit icons - global
434
374
 
@@ -437,7 +377,7 @@ class Render:
437
377
  self.instance().on_enable_edit(live)
438
378
  self.update()
439
379
 
440
- def on_disable_edit(self, live: bool = True):
380
+ def on_disable_edit(self, live: bool = True) -> None:
441
381
  """
442
382
  On disable edit icons - global
443
383
 
@@ -446,7 +386,7 @@ class Render:
446
386
  self.instance().on_disable_edit(live)
447
387
  self.update()
448
388
 
449
- def on_enable_timestamp(self, live: bool = True):
389
+ def on_enable_timestamp(self, live: bool = True) -> None:
450
390
  """
451
391
  On enable timestamp - global
452
392
 
@@ -455,7 +395,7 @@ class Render:
455
395
  self.instance().on_enable_timestamp(live)
456
396
  self.update()
457
397
 
458
- def on_disable_timestamp(self, live: bool = True):
398
+ def on_disable_timestamp(self, live: bool = True) -> None:
459
399
  """
460
400
  On disable timestamp - global
461
401
 
@@ -464,7 +404,7 @@ class Render:
464
404
  self.instance().on_disable_timestamp(live)
465
405
  self.update()
466
406
 
467
- def remove_item(self, id: int):
407
+ def remove_item(self, id: int) -> None:
468
408
  """
469
409
  Remove item from output
470
410
 
@@ -473,7 +413,7 @@ class Render:
473
413
  self.instance().remove_item(id)
474
414
  self.update()
475
415
 
476
- def remove_items_from(self, id: int):
416
+ def remove_items_from(self, id: int) -> None:
477
417
  """
478
418
  Remove item from output
479
419
 
@@ -482,7 +422,7 @@ class Render:
482
422
  self.instance().remove_items_from(id)
483
423
  self.update()
484
424
 
485
- def on_edit_submit(self, ctx: CtxItem):
425
+ def on_edit_submit(self, ctx: CtxItem) -> None:
486
426
  """
487
427
  On edit submit
488
428
 
@@ -491,7 +431,7 @@ class Render:
491
431
  self.instance().on_edit_submit(ctx)
492
432
  self.update()
493
433
 
494
- def on_remove_submit(self, ctx: CtxItem):
434
+ def on_remove_submit(self, ctx: CtxItem) -> None:
495
435
  """
496
436
  On remove submit
497
437
 
@@ -500,7 +440,7 @@ class Render:
500
440
  self.instance().on_remove_submit(ctx)
501
441
  self.update()
502
442
 
503
- def on_reply_submit(self, ctx: CtxItem):
443
+ def on_reply_submit(self, ctx: CtxItem) -> None:
504
444
  """
505
445
  On regenerate submit
506
446
 
@@ -509,11 +449,7 @@ class Render:
509
449
  self.instance().on_reply_submit(ctx)
510
450
  self.update()
511
451
 
512
- def on_page_loaded(
513
- self,
514
- meta: CtxMeta,
515
- tab: Optional[Tab] = None
516
- ):
452
+ def on_page_loaded(self, meta: CtxMeta, tab: Optional[Tab] = None) -> None:
517
453
  """
518
454
  On page loaded callback
519
455
 
@@ -523,7 +459,7 @@ class Render:
523
459
  self.instance().on_page_loaded(meta, tab)
524
460
  self.update()
525
461
 
526
- def on_theme_change(self):
462
+ def on_theme_change(self) -> None:
527
463
  """On theme change - global"""
528
464
  if self.get_engine() == "web":
529
465
  self.web_renderer.on_theme_change()
@@ -539,7 +475,7 @@ class Render:
539
475
  """
540
476
  return self.instance().get_scroll_position()
541
477
 
542
- def set_scroll_position(self, position: int):
478
+ def set_scroll_position(self, position: int) -> None:
543
479
  """
544
480
  Set scroll position - active
545
481
 
@@ -548,26 +484,32 @@ class Render:
548
484
  self.instance().set_scroll_position(position)
549
485
  self.update()
550
486
 
551
- def update(self):
487
+ def update(self) -> None:
552
488
  """On update - active"""
553
- for pid in self.window.ui.nodes['output']:
554
- self.window.ui.nodes['output'][pid].on_update()
489
+ nodes = self.window.ui.nodes
490
+ outputs = nodes.get('output')
491
+ if not outputs:
492
+ return
493
+ for node in outputs.values():
494
+ node.on_update()
555
495
 
556
- def clear(self, meta: CtxMeta):
496
+ def clear(self, meta: CtxMeta) -> None:
557
497
  """
558
498
  Clear renderer
559
499
 
560
500
  :param meta: ctx meta instance
561
501
  """
562
- self.reset(meta)
563
- self.clear_output(meta)
502
+ inst = self.instance()
503
+ inst.reset(meta)
504
+ inst.clear_output(meta)
505
+ self.update()
564
506
 
565
- def clear_all(self):
507
+ def clear_all(self) -> None:
566
508
  """Clear all"""
567
509
  self.instance().clear_all()
568
510
  self.update()
569
511
 
570
- def remove_pid(self, pid: int):
512
+ def remove_pid(self, pid: int) -> None:
571
513
  """
572
514
  Remove PID from renderer
573
515
 
@@ -577,11 +519,7 @@ class Render:
577
519
  self.markdown_renderer.remove_pid(pid)
578
520
  self.web_renderer.remove_pid(pid)
579
521
 
580
- def tool_output_append(
581
- self,
582
- meta: CtxMeta,
583
- content: str
584
- ):
522
+ def tool_output_append(self, meta: CtxMeta, content: str) -> None:
585
523
  """
586
524
  Add tool output (append)
587
525
 
@@ -591,11 +529,7 @@ class Render:
591
529
  self.instance().tool_output_append(meta, content)
592
530
  self.update()
593
531
 
594
- def tool_output_update(
595
- self,
596
- meta: CtxMeta,
597
- content: str
598
- ):
532
+ def tool_output_update(self, meta: CtxMeta, content: str) -> None:
599
533
  """
600
534
  Replace tool output
601
535
 
@@ -605,7 +539,7 @@ class Render:
605
539
  self.instance().tool_output_update(meta, content)
606
540
  self.update()
607
541
 
608
- def tool_output_clear(self, meta: CtxMeta):
542
+ def tool_output_clear(self, meta: CtxMeta) -> None:
609
543
  """
610
544
  Clear tool output
611
545
 
@@ -614,7 +548,7 @@ class Render:
614
548
  self.instance().tool_output_clear(meta)
615
549
  self.update()
616
550
 
617
- def tool_output_begin(self, meta: CtxMeta):
551
+ def tool_output_begin(self, meta: CtxMeta) -> None:
618
552
  """
619
553
  Begin tool output
620
554
 
@@ -623,7 +557,7 @@ class Render:
623
557
  self.instance().tool_output_begin(meta)
624
558
  self.update()
625
559
 
626
- def tool_output_end(self):
560
+ def tool_output_end(self) -> None:
627
561
  """
628
562
  End tool output
629
563
 
@@ -640,35 +574,34 @@ class Render:
640
574
  """
641
575
  return self.engine
642
576
 
643
- def switch(self):
577
+ def switch(self) -> None:
644
578
  """
645
579
  Switch renderer (markdown/web <==> plain text) - active, TODO: remove from settings, leave only checkbox
646
580
  """
647
581
  plain = self.window.core.config.get('render.plain')
582
+ nodes = self.window.ui.nodes
648
583
  if plain:
649
584
  self.window.controller.theme.markdown.clear()
650
- self.window.ui.nodes['output.timestamp'].setVisible(True)
651
- for pid in self.window.ui.nodes['output_plain']:
652
- try:
653
- if self.window.ui.nodes['output_plain'][pid] is not None:
654
- self.window.ui.nodes['output'][pid].setVisible(False)
655
- self.window.ui.nodes['output_plain'][pid].setVisible(True)
656
- except Exception as e:
657
- pass
585
+ nodes['output.timestamp'].setVisible(True)
586
+ outputs = nodes.get('output', {})
587
+ outputs_plain = nodes.get('output_plain', {})
588
+ for pid, w_plain in outputs_plain.items():
589
+ w = outputs.get(pid)
590
+ if w and w_plain:
591
+ w.setVisible(False)
592
+ w_plain.setVisible(True)
658
593
  else:
659
- self.window.ui.nodes['output.timestamp'].setVisible(False)
660
-
594
+ nodes['output.timestamp'].setVisible(False)
661
595
  self.window.controller.theme.markdown.update(force=True)
662
- for pid in self.window.ui.nodes['output']:
663
- try:
664
- if self.window.ui.nodes['output'][pid] is not None:
665
- self.window.ui.nodes['output'][pid].setVisible(True)
666
- self.window.ui.nodes['output_plain'][pid].setVisible(False)
667
- except Exception as e:
668
- pass
669
-
670
- # cache renderer instance
671
- if self.window.core.config.get('render.plain'):
596
+ outputs = nodes.get('output', {})
597
+ outputs_plain = nodes.get('output_plain', {})
598
+ for pid, w in outputs.items():
599
+ w_plain = outputs_plain.get(pid)
600
+ if w and w_plain:
601
+ w.setVisible(True)
602
+ w_plain.setVisible(False)
603
+
604
+ if plain:
672
605
  self.renderer = self.plaintext_renderer
673
606
  else:
674
607
  if self.engine == "web":
@@ -685,9 +618,7 @@ class Render:
685
618
  :return: Renderer instance
686
619
  """
687
620
  if self.renderer:
688
- return self.renderer # return cached renderer instance
689
-
690
- # get selected renderer
621
+ return self.renderer
691
622
  if self.window.core.config.get('render.plain'):
692
623
  return self.plaintext_renderer
693
624
  else:
@@ -697,11 +628,7 @@ class Render:
697
628
  return self.markdown_renderer
698
629
 
699
630
  @Slot(str, str)
700
- def handle_save_as(
701
- self,
702
- text: str,
703
- type: str = 'txt'
704
- ):
631
+ def handle_save_as(self, text: str, type: str = 'txt') -> None:
705
632
  """
706
633
  Handle save as signal # TODO: move to another class
707
634
 
@@ -722,4 +649,4 @@ class Render:
722
649
 
723
650
  :param text: Text to read # TODO: move to another class
724
651
  """
725
- self.window.controller.audio.read_text(text)
652
+ self.window.controller.audio.read_text(text)