pygpt-net 2.6.21__py3-none-any.whl → 2.6.22__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 (144) hide show
  1. pygpt_net/CHANGELOG.txt +4 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +3 -1
  4. pygpt_net/controller/__init__.py +4 -8
  5. pygpt_net/controller/access/voice.py +2 -2
  6. pygpt_net/controller/assistant/batch.py +2 -3
  7. pygpt_net/controller/assistant/editor.py +2 -2
  8. pygpt_net/controller/assistant/files.py +2 -3
  9. pygpt_net/controller/assistant/store.py +2 -2
  10. pygpt_net/controller/audio/audio.py +2 -2
  11. pygpt_net/controller/ctx/ctx.py +2 -1
  12. pygpt_net/controller/idx/indexer.py +85 -76
  13. pygpt_net/controller/lang/lang.py +52 -34
  14. pygpt_net/controller/model/importer.py +2 -2
  15. pygpt_net/controller/notepad/notepad.py +86 -84
  16. pygpt_net/controller/plugins/settings.py +3 -4
  17. pygpt_net/controller/settings/profile.py +105 -124
  18. pygpt_net/controller/theme/menu.py +154 -57
  19. pygpt_net/controller/theme/nodes.py +51 -44
  20. pygpt_net/controller/theme/theme.py +33 -9
  21. pygpt_net/controller/tools/tools.py +2 -2
  22. pygpt_net/controller/ui/tabs.py +2 -3
  23. pygpt_net/core/ctx/container.py +13 -12
  24. pygpt_net/core/ctx/output.py +7 -4
  25. pygpt_net/core/debug/console/console.py +2 -2
  26. pygpt_net/core/filesystem/actions.py +1 -2
  27. pygpt_net/core/render/plain/helpers.py +2 -5
  28. pygpt_net/core/render/plain/renderer.py +26 -30
  29. pygpt_net/core/render/web/body.py +1 -1
  30. pygpt_net/core/settings/settings.py +43 -13
  31. pygpt_net/core/tabs/tabs.py +20 -13
  32. pygpt_net/data/config/config.json +4 -4
  33. pygpt_net/data/config/models.json +3 -3
  34. pygpt_net/data/locale/locale.de.ini +4 -1
  35. pygpt_net/data/locale/locale.en.ini +4 -1
  36. pygpt_net/data/locale/locale.es.ini +4 -1
  37. pygpt_net/data/locale/locale.fr.ini +4 -1
  38. pygpt_net/data/locale/locale.it.ini +4 -1
  39. pygpt_net/data/locale/locale.pl.ini +5 -4
  40. pygpt_net/data/locale/locale.uk.ini +4 -1
  41. pygpt_net/data/locale/locale.zh.ini +4 -1
  42. pygpt_net/plugin/twitter/plugin.py +2 -2
  43. pygpt_net/tools/audio_transcriber/ui/dialogs.py +44 -54
  44. pygpt_net/tools/code_interpreter/body.py +1 -2
  45. pygpt_net/tools/code_interpreter/tool.py +7 -4
  46. pygpt_net/tools/code_interpreter/ui/html.py +1 -3
  47. pygpt_net/tools/code_interpreter/ui/widgets.py +2 -3
  48. pygpt_net/tools/html_canvas/ui/widgets.py +1 -3
  49. pygpt_net/tools/image_viewer/ui/dialogs.py +40 -37
  50. pygpt_net/tools/indexer/ui/widgets.py +2 -4
  51. pygpt_net/tools/media_player/tool.py +2 -5
  52. pygpt_net/tools/media_player/ui/widgets.py +60 -36
  53. pygpt_net/tools/text_editor/ui/widgets.py +18 -19
  54. pygpt_net/tools/translator/ui/widgets.py +39 -35
  55. pygpt_net/ui/base/context_menu.py +9 -4
  56. pygpt_net/ui/dialog/db.py +1 -3
  57. pygpt_net/ui/dialog/models.py +1 -3
  58. pygpt_net/ui/dialog/models_importer.py +2 -4
  59. pygpt_net/ui/dialogs.py +34 -30
  60. pygpt_net/ui/layout/chat/attachments.py +72 -84
  61. pygpt_net/ui/layout/chat/attachments_ctx.py +40 -44
  62. pygpt_net/ui/layout/chat/attachments_uploaded.py +36 -39
  63. pygpt_net/ui/layout/chat/calendar.py +100 -70
  64. pygpt_net/ui/layout/chat/chat.py +23 -17
  65. pygpt_net/ui/layout/chat/input.py +95 -118
  66. pygpt_net/ui/layout/chat/output.py +100 -162
  67. pygpt_net/ui/layout/chat/painter.py +89 -61
  68. pygpt_net/ui/layout/ctx/ctx_list.py +43 -52
  69. pygpt_net/ui/layout/status.py +23 -14
  70. pygpt_net/ui/layout/toolbox/agent.py +27 -38
  71. pygpt_net/ui/layout/toolbox/agent_llama.py +42 -45
  72. pygpt_net/ui/layout/toolbox/assistants.py +42 -38
  73. pygpt_net/ui/layout/toolbox/computer_env.py +32 -23
  74. pygpt_net/ui/layout/toolbox/footer.py +13 -16
  75. pygpt_net/ui/layout/toolbox/image.py +18 -21
  76. pygpt_net/ui/layout/toolbox/indexes.py +46 -89
  77. pygpt_net/ui/layout/toolbox/mode.py +20 -7
  78. pygpt_net/ui/layout/toolbox/model.py +12 -10
  79. pygpt_net/ui/layout/toolbox/presets.py +68 -52
  80. pygpt_net/ui/layout/toolbox/prompt.py +31 -58
  81. pygpt_net/ui/layout/toolbox/toolbox.py +25 -21
  82. pygpt_net/ui/layout/toolbox/vision.py +20 -22
  83. pygpt_net/ui/main.py +2 -4
  84. pygpt_net/ui/menu/about.py +64 -84
  85. pygpt_net/ui/menu/audio.py +87 -63
  86. pygpt_net/ui/menu/config.py +121 -127
  87. pygpt_net/ui/menu/debug.py +69 -76
  88. pygpt_net/ui/menu/file.py +32 -35
  89. pygpt_net/ui/menu/menu.py +2 -3
  90. pygpt_net/ui/menu/plugins.py +69 -33
  91. pygpt_net/ui/menu/theme.py +45 -46
  92. pygpt_net/ui/menu/tools.py +56 -60
  93. pygpt_net/ui/menu/video.py +20 -25
  94. pygpt_net/ui/tray.py +1 -2
  95. pygpt_net/ui/widget/audio/bar.py +1 -3
  96. pygpt_net/ui/widget/audio/input_button.py +3 -4
  97. pygpt_net/ui/widget/calendar/select.py +1 -2
  98. pygpt_net/ui/widget/dialog/base.py +12 -9
  99. pygpt_net/ui/widget/dialog/editor_file.py +20 -23
  100. pygpt_net/ui/widget/dialog/find.py +25 -24
  101. pygpt_net/ui/widget/dialog/profile.py +57 -53
  102. pygpt_net/ui/widget/draw/painter.py +62 -93
  103. pygpt_net/ui/widget/element/button.py +42 -30
  104. pygpt_net/ui/widget/element/checkbox.py +23 -15
  105. pygpt_net/ui/widget/element/group.py +6 -5
  106. pygpt_net/ui/widget/element/labels.py +1 -2
  107. pygpt_net/ui/widget/filesystem/explorer.py +93 -102
  108. pygpt_net/ui/widget/image/display.py +1 -2
  109. pygpt_net/ui/widget/lists/assistant.py +1 -2
  110. pygpt_net/ui/widget/lists/attachment.py +1 -2
  111. pygpt_net/ui/widget/lists/attachment_ctx.py +1 -2
  112. pygpt_net/ui/widget/lists/context.py +2 -4
  113. pygpt_net/ui/widget/lists/index.py +1 -2
  114. pygpt_net/ui/widget/lists/model.py +1 -2
  115. pygpt_net/ui/widget/lists/model_editor.py +1 -2
  116. pygpt_net/ui/widget/lists/model_importer.py +1 -2
  117. pygpt_net/ui/widget/lists/preset.py +1 -2
  118. pygpt_net/ui/widget/lists/preset_plugins.py +1 -2
  119. pygpt_net/ui/widget/lists/profile.py +1 -2
  120. pygpt_net/ui/widget/lists/uploaded.py +1 -2
  121. pygpt_net/ui/widget/option/checkbox.py +2 -4
  122. pygpt_net/ui/widget/option/checkbox_list.py +1 -4
  123. pygpt_net/ui/widget/option/cmd.py +1 -4
  124. pygpt_net/ui/widget/option/dictionary.py +25 -28
  125. pygpt_net/ui/widget/option/input.py +1 -3
  126. pygpt_net/ui/widget/tabs/Input.py +16 -12
  127. pygpt_net/ui/widget/tabs/body.py +5 -3
  128. pygpt_net/ui/widget/tabs/layout.py +36 -25
  129. pygpt_net/ui/widget/tabs/output.py +96 -74
  130. pygpt_net/ui/widget/textarea/calendar_note.py +1 -2
  131. pygpt_net/ui/widget/textarea/editor.py +41 -73
  132. pygpt_net/ui/widget/textarea/find.py +11 -10
  133. pygpt_net/ui/widget/textarea/html.py +3 -6
  134. pygpt_net/ui/widget/textarea/input.py +63 -64
  135. pygpt_net/ui/widget/textarea/notepad.py +54 -38
  136. pygpt_net/ui/widget/textarea/output.py +65 -54
  137. pygpt_net/ui/widget/textarea/search_input.py +5 -4
  138. pygpt_net/ui/widget/textarea/web.py +2 -4
  139. pygpt_net/ui/widget/vision/camera.py +2 -31
  140. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.22.dist-info}/METADATA +15 -151
  141. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.22.dist-info}/RECORD +144 -144
  142. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.22.dist-info}/LICENSE +0 -0
  143. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.22.dist-info}/WHEEL +0 -0
  144. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.22.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: 2024.12.12 01:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from pygpt_net.core.events import RenderEvent
@@ -28,24 +28,33 @@ class Nodes:
28
28
  :param key: UI node key
29
29
  :param type: stylesheet type
30
30
  """
31
- if key not in self.window.ui.nodes:
31
+ nodes = self.window.ui.nodes
32
+ theme = self.window.controller.theme
33
+
34
+ if key not in nodes:
32
35
  return
33
36
 
34
37
  if type == 'font.toolbox':
35
- self.window.ui.nodes[key].setStyleSheet(self.window.controller.theme.style('font.toolbox'))
38
+ nodes[key].setStyleSheet(theme.style('font.toolbox'))
36
39
  elif type == 'font.chat.output':
37
- for pid in self.window.ui.nodes[key]:
40
+ style_output = theme.style('font.chat.output')
41
+ for pid in nodes[key]:
38
42
  try:
39
- self.window.ui.nodes[key][pid].setStyleSheet(self.window.controller.theme.style('font.chat.output'))
43
+ nodes[key][pid].setStyleSheet(style_output)
40
44
  except Exception as e:
41
45
  pass
42
46
  elif type == 'font.chat.input':
43
- self.window.ui.nodes[key].setStyleSheet(self.window.controller.theme.style('font.chat.input'))
47
+ nodes[key].setStyleSheet(theme.style('font.chat.input'))
44
48
  elif type == 'font.ctx.list':
45
- self.window.ui.nodes[key].setStyleSheet(self.window.controller.theme.style('font.ctx.list'))
49
+ nodes[key].setStyleSheet(theme.style('font.ctx.list'))
46
50
 
47
51
  def apply_all(self):
48
52
  """Apply stylesheets to nodes"""
53
+ w = self.window
54
+ ui = w.ui
55
+ ctrl = w.controller
56
+ engine = ctrl.chat.render.get_engine()
57
+
49
58
  nodes = {
50
59
  'font.chat.input': [
51
60
  'input',
@@ -90,58 +99,56 @@ class Nodes:
90
99
  }
91
100
 
92
101
  # apply to nodes
93
- for type in nodes:
94
- for key in nodes[type]:
95
- if key == "output" and self.window.controller.chat.render.get_engine() != 'legacy':
102
+ apply_ref = self.apply
103
+ skip_output = engine != 'legacy'
104
+ for t, keys in nodes.items():
105
+ for k in keys:
106
+ if skip_output and k == "output":
96
107
  continue
97
- self.apply(key, type)
108
+ apply_ref(k, t)
98
109
 
99
110
  # apply to notepads
100
- num_notepads = self.window.controller.notepad.get_num_notepads()
101
- if num_notepads > 0:
102
- for id in self.window.ui.notepad:
103
- self.window.ui.notepad[id].textarea.setStyleSheet(self.window.controller.theme.style('font.chat.output'))
111
+ size = w.core.config.get('font_size')
112
+ style_output = ctrl.theme.style('font.chat.output')
113
+ if ui.notepad:
114
+ for np in ui.notepad.values():
115
+ ta = np.textarea
116
+ ta.setStyleSheet(style_output)
117
+ ta.value = size
104
118
 
105
119
  # apply to calendar
106
- if 'note' in self.window.ui.calendar:
107
- self.window.ui.calendar['note'].setStyleSheet(self.window.controller.theme.style('font.chat.output'))
108
-
109
- # update value
110
- size = self.window.core.config.get('font_size')
111
- if 'note' in self.window.ui.calendar:
112
- self.window.ui.calendar['note'].value = size
113
- if num_notepads > 0:
114
- for id in range(1, num_notepads + 1):
115
- if id in self.window.ui.notepad:
116
- self.window.ui.notepad[id].textarea.value = size
120
+ note = ui.calendar.get('note')
121
+ if note is not None:
122
+ note.setStyleSheet(style_output)
123
+ note.value = size
117
124
 
118
125
  # plain text/markdown
119
- for pid in self.window.ui.nodes['output_plain']:
126
+ output_plain = ui.nodes.get('output_plain', {})
127
+ for obj in output_plain.values():
120
128
  try:
121
- self.window.ui.nodes['output_plain'][pid].value = size
122
- self.window.ui.nodes['output_plain'][pid].update()
123
- except Exception as e:
129
+ obj.value = size
130
+ obj.update()
131
+ except Exception:
124
132
  pass
125
133
 
126
134
  # ------------------------
127
135
 
128
136
  # zoom, (Chromium, web engine)
129
- if self.window.controller.chat.render.get_engine() == 'web':
130
- zoom = self.window.core.config.get('zoom')
131
- for pid in self.window.ui.nodes['output']:
137
+ output_nodes = ui.nodes.get('output', {})
138
+ if engine == 'web':
139
+ zoom = w.core.config.get('zoom')
140
+ for obj in output_nodes.values():
132
141
  try:
133
- self.window.ui.nodes['output'][pid].value = zoom
134
- self.window.ui.nodes['output'][pid].update_zoom()
135
- except Exception as e:
142
+ obj.value = zoom
143
+ obj.update_zoom()
144
+ except Exception:
136
145
  pass
137
- event = RenderEvent(RenderEvent.ON_THEME_CHANGE)
138
- self.window.dispatch(event)
146
+ w.dispatch(RenderEvent(RenderEvent.ON_THEME_CHANGE))
139
147
 
140
148
  # font size, legacy (markdown)
141
- elif self.window.controller.chat.render.get_engine() == 'legacy':
142
- for pid in self.window.ui.nodes['output']:
143
- self.window.ui.nodes['output'][pid].value = size
144
- self.window.ui.nodes['output'][pid].update()
149
+ elif engine == 'legacy':
150
+ for obj in output_nodes.values():
151
+ obj.value = size
152
+ obj.update()
145
153
 
146
- # update tools
147
- self.window.tools.setup_theme()
154
+ w.tools.setup_theme() # update tools
@@ -6,13 +6,16 @@
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.20 23:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
13
  from typing import Any, Optional
14
14
 
15
+ from PySide6.QtWidgets import QApplication
16
+
15
17
  from pygpt_net.core.events import RenderEvent
18
+ from pygpt_net.utils import trans
16
19
 
17
20
  from .common import Common
18
21
  from .markdown import Markdown
@@ -41,6 +44,29 @@ class Theme:
41
44
  self.common.toggle_tooltips()
42
45
  self.reload(force=False)
43
46
 
47
+ def toggle_theme_by_menu(self, name):
48
+ """
49
+ Toggle theme by menu action
50
+
51
+ :param name: theme name
52
+ """
53
+ self.window.update_status(trans("status.loading"))
54
+ QApplication.processEvents()
55
+ self.toggle(name, force=True)
56
+ self.window.update_status("")
57
+
58
+ def toggle_option_by_menu(self, name: str, value: Any = None):
59
+ """
60
+ Toggle theme option by menu action
61
+
62
+ :param name: option name
63
+ :param value: option value
64
+ """
65
+ self.window.update_status(trans("status.loading"))
66
+ QApplication.processEvents()
67
+ self.toggle_option(name, value)
68
+ self.window.update_status("")
69
+
44
70
  def toggle(
45
71
  self,
46
72
  name: str,
@@ -85,6 +111,7 @@ class Theme:
85
111
 
86
112
  :param name: web style name
87
113
  """
114
+ QApplication.processEvents()
88
115
  core = self.window.core
89
116
  core.config.set('theme.style', name)
90
117
  core.config.save()
@@ -103,6 +130,7 @@ class Theme:
103
130
  :param name: option name
104
131
  :param value: option value
105
132
  """
133
+ QApplication.processEvents()
106
134
  window = self.window
107
135
  core = window.core
108
136
  cfg = core.config
@@ -149,8 +177,7 @@ class Theme:
149
177
 
150
178
  def update_style(self):
151
179
  """Update style"""
152
- current = self.window.core.config.get('theme.style')
153
- self.toggle_style(current)
180
+ self.toggle_style(self.window.core.config.get('theme.style'))
154
181
 
155
182
  def update_theme(self, force: bool = True):
156
183
  """
@@ -158,13 +185,11 @@ class Theme:
158
185
 
159
186
  :param force: force theme change (manual trigger)
160
187
  """
161
- current = self.window.core.config.get('theme')
162
- self.toggle(current, force=force)
188
+ self.toggle(self.window.core.config.get('theme'), force=force)
163
189
 
164
190
  def update_syntax(self):
165
191
  """Update syntax menu"""
166
- current = self.window.core.config.get('render.code_syntax')
167
- self.toggle_syntax(current, update_menu=True)
192
+ self.toggle_syntax(self.window.core.config.get('render.code_syntax'), update_menu=True)
168
193
 
169
194
  def reload(self, force: bool = True):
170
195
  """
@@ -254,8 +279,7 @@ class Theme:
254
279
 
255
280
  :param prev_theme: previous theme name
256
281
  """
257
- current_theme = self.window.core.config.get('theme')
258
- if not prev_theme or prev_theme != current_theme:
282
+ if not prev_theme or prev_theme != self.window.core.config.get('theme'):
259
283
  self.setup()
260
284
  self.update_style()
261
285
  self.update_syntax()
@@ -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: 2024.12.14 08:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Dict, List
@@ -81,7 +81,7 @@ class Tools:
81
81
  caller = parent
82
82
  action = QAction(QIcon(icon), title, parent)
83
83
  action.triggered.connect(
84
- lambda idx=idx, column_idx=column_idx, id=id, caller=caller: caller.add_tab(idx, column_idx, Tab.TAB_TOOL, id)
84
+ lambda checked=False, idx=idx, column_idx=column_idx, id=id, caller=caller: caller.add_tab(idx, column_idx, Tab.TAB_TOOL, id)
85
85
  )
86
86
  submenu.addAction(action)
87
87
  return submenu
@@ -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.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Any, Optional, Tuple
@@ -134,8 +134,7 @@ class Tabs:
134
134
  def reload(self):
135
135
  """Reload tabs"""
136
136
  self.window.core.tabs.reload()
137
- event = RenderEvent(RenderEvent.PREPARE)
138
- self.window.dispatch(event)
137
+ self.window.dispatch(RenderEvent(RenderEvent.PREPARE))
139
138
  self.debug()
140
139
 
141
140
  def reload_after(self):
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.05 21:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import List
@@ -15,9 +15,9 @@ from PySide6.QtWidgets import QVBoxLayout, QWidget
15
15
 
16
16
  from pygpt_net.core.tabs.tab import Tab
17
17
  from pygpt_net.ui.widget.textarea.output import ChatOutput
18
+ from pygpt_net.item.ctx import CtxItem
18
19
 
19
20
  from .bag import Bag
20
- from ...item.ctx import CtxItem
21
21
 
22
22
 
23
23
  class Container:
@@ -28,8 +28,7 @@ class Container:
28
28
  :param window: Window
29
29
  """
30
30
  self.window = window
31
- self.bags = {}
32
- self.bags[0] = Bag(window) # always create initial bag
31
+ self.bags = {0: Bag(window)}
33
32
 
34
33
  def get(self, tab: Tab) -> QWidget:
35
34
  """
@@ -92,14 +91,16 @@ class Container:
92
91
 
93
92
  :param tab: Tab
94
93
  """
95
- if tab.pid in self.window.ui.nodes['output_plain']:
96
- self.window.ui.nodes['output_plain'][tab.pid].on_delete() # clean up
97
- self.window.ui.nodes['output_plain'][tab.pid] = None
98
- del self.window.ui.nodes['output_plain'][tab.pid]
99
- if tab.pid in self.window.ui.nodes['output']:
100
- self.window.ui.nodes['output'][tab.pid].on_delete() # clean up
101
- self.window.ui.nodes['output'][tab.pid] = None
102
- del self.window.ui.nodes['output'][tab.pid]
94
+ nodes = self.window.ui.nodes
95
+
96
+ if tab.pid in nodes['output_plain']:
97
+ nodes['output_plain'][tab.pid].on_delete() # clean up
98
+ nodes['output_plain'][tab.pid] = None
99
+ del nodes['output_plain'][tab.pid]
100
+ if tab.pid in nodes['output']:
101
+ nodes['output'][tab.pid].on_delete() # clean up
102
+ nodes['output'][tab.pid] = None
103
+ del nodes['output'][tab.pid]
103
104
 
104
105
  self.window.controller.chat.render.remove_pid(tab.pid) # remove pid data from renderer registry
105
106
  self.window.core.ctx.output.remove_pid(tab.pid) # remove pid from ctx output mapping
@@ -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: 2024.12.14 08:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional, List, Dict
@@ -87,6 +87,9 @@ class Output:
87
87
  def is_mapped(self, meta: CtxMeta) -> bool:
88
88
  """
89
89
  Check if meta is mapped anywhere
90
+
91
+ :param meta: Meta
92
+ :return: True if mapped, False otherwise
90
93
  """
91
94
  self.init()
92
95
 
@@ -182,6 +185,8 @@ class Output:
182
185
  def is_empty(self) -> bool:
183
186
  """
184
187
  Check if mapping is empty for the active PID across columns
188
+
189
+ :return: True if empty, False otherwise
185
190
  """
186
191
  self.init()
187
192
 
@@ -211,9 +216,7 @@ class Output:
211
216
  return self.store(meta)
212
217
 
213
218
  def clear(self):
214
- """
215
- Clear mapping
216
- """
219
+ """Clear mapping"""
217
220
  self.mapping.clear()
218
221
  self.last_pids.clear()
219
222
  self.last_pid = 0
@@ -6,10 +6,10 @@
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.11 18:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
- from qasync import QApplication
12
+ from PySide6.QtWidgets import QApplication
13
13
 
14
14
  from pygpt_net.utils import mem_clean
15
15
 
@@ -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: 2024.12.14 08:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -16,7 +16,6 @@ from PySide6.QtGui import QAction, QIcon
16
16
  from PySide6.QtWidgets import QWidget
17
17
 
18
18
  from pygpt_net.utils import trans
19
- import pygpt_net.icons_rc
20
19
 
21
20
 
22
21
  class Actions:
@@ -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.07.14 00:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
 
@@ -27,10 +27,7 @@ class Helpers:
27
27
  :param text: text to format
28
28
  :return: formatted text
29
29
  """
30
- text = text.strip()
31
- #text = text.replace("#~###~", "~###~") # fix for #~###~ in text (previous versions)
32
- #text = text.replace("# ~###~", "~###~") # fix for # ~###~ in text (previous versions)
33
- return text
30
+ return text.strip()
34
31
 
35
32
  def post_format_text(self, text: str) -> str:
36
33
  """
@@ -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.21 00:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from datetime import datetime
@@ -178,11 +178,9 @@ class Renderer(BaseRenderer):
178
178
  if clear:
179
179
  self.clear_output(meta)
180
180
 
181
- i = 0
182
- for item in items:
181
+ for i, item in enumerate(items):
183
182
  item.idx = i
184
183
  self.append_context_item(meta, item)
185
- i += 1
186
184
 
187
185
  def append_input(
188
186
  self,
@@ -251,20 +249,23 @@ class Renderer(BaseRenderer):
251
249
  :param item: context item
252
250
  :param footer: True if it is a footer
253
251
  """
254
- appended = []
252
+ appended = set()
255
253
  pid = self.get_or_create_pid(meta)
256
254
 
257
255
  # images
258
256
  c = len(item.images)
259
257
  if c > 0:
260
258
  n = 1
259
+ pd = self.pids[pid]
260
+ already = set(pd.images_appended)
261
261
  for image in item.images:
262
- if image in appended or image in self.pids[pid].images_appended:
262
+ if image in appended or image in already:
263
263
  continue
264
264
  try:
265
- appended.append(image)
265
+ appended.add(image)
266
266
  self.append_raw(meta, item, self.body.get_image_html(image, n, c))
267
- self.pids[pid].images_appended.append(image)
267
+ pd.images_appended.append(image)
268
+ already.add(image)
268
269
  n += 1
269
270
  except Exception as e:
270
271
  pass
@@ -277,7 +278,7 @@ class Renderer(BaseRenderer):
277
278
  if file in appended:
278
279
  continue
279
280
  try:
280
- appended.append(file)
281
+ appended.add(file)
281
282
  self.append_raw(meta, item, self.body.get_file_html(file, n, c))
282
283
  n += 1
283
284
  except Exception as e:
@@ -288,13 +289,16 @@ class Renderer(BaseRenderer):
288
289
  if c > 0:
289
290
  urls_str = []
290
291
  n = 1
292
+ pd = self.pids[pid]
293
+ already = set(pd.urls_appended)
291
294
  for url in item.urls:
292
- if url in appended or url in self.pids[pid].urls_appended:
295
+ if url in appended or url in already:
293
296
  continue
294
297
  try:
295
- appended.append(url)
298
+ appended.add(url)
296
299
  urls_str.append(self.body.get_url_html(url, n, c))
297
- self.pids[pid].urls_appended.append(url)
300
+ pd.urls_appended.append(url)
301
+ already.add(url)
298
302
  n += 1
299
303
  except Exception as e:
300
304
  pass
@@ -337,8 +341,9 @@ class Renderer(BaseRenderer):
337
341
  raw_chunk = str(text_chunk)
338
342
 
339
343
  if begin:
340
- self.pids[pid].buffer = "" # reset buffer
341
- self.pids[pid].is_cmd = False # reset command flag
344
+ pd = self.pids[pid]
345
+ pd.buffer = ""
346
+ pd.is_cmd = False
342
347
 
343
348
  if self.is_timestamp_enabled() and item.output_timestamp is not None:
344
349
  name = ""
@@ -386,13 +391,12 @@ class Renderer(BaseRenderer):
386
391
  :param text: text to append
387
392
  """
388
393
  node = self.get_output_node(meta)
389
- prev_text = node.toPlainText()
390
- if prev_text != "":
391
- prev_text += "\n\n"
392
- new_text = f"{prev_text}{text.strip()}"
393
- node.setPlainText(new_text)
394
- cur = node.textCursor() # Move cursor to end of text
394
+ cur = node.textCursor()
395
395
  cur.movePosition(QTextCursor.End)
396
+ if not node.document().isEmpty():
397
+ cur.insertText("\n\n")
398
+ cur.insertText(text.strip())
399
+ node.setTextCursor(cur)
396
400
 
397
401
  def append_chunk_start(self, meta: CtxMeta, ctx: CtxItem):
398
402
  """
@@ -437,14 +441,9 @@ class Renderer(BaseRenderer):
437
441
  :param end: end of the line character
438
442
  """
439
443
  node = self.get_output_node(meta)
440
- cur = node.textCursor() # Move cursor to end of text
444
+ cur = node.textCursor()
441
445
  cur.movePosition(QTextCursor.End)
442
- s = f"{str(text)}{end}"
443
- while s:
444
- head, sep, s = s.partition("\n") # Split line at LF
445
- cur.insertText(head)
446
- if sep:
447
- cur.insertText("\n")
446
+ cur.insertText(f"{str(text)}{end}")
448
447
  node.setTextCursor(cur)
449
448
 
450
449
  def append_timestamp(
@@ -549,9 +548,6 @@ class Renderer(BaseRenderer):
549
548
  for node in self.get_all_nodes():
550
549
  try:
551
550
  node.clear()
552
- node.document().setMarkdown("")
553
- node.document().setHtml("")
554
- node.setPlainText("")
555
551
  except Exception as e:
556
552
  pass
557
553
 
@@ -881,7 +881,7 @@ class Body:
881
881
  }
882
882
  });
883
883
  });
884
- setTimeout(cycleTips, 60000); // after 60 seconds
884
+ setTimeout(cycleTips, 10000); // after 10 seconds
885
885
  </script>
886
886
  </head>
887
887
  <body """