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: 2025.08.05 21:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional, Tuple
@@ -20,8 +20,6 @@ from pygpt_net.ui.widget.tabs.body import TabBody
20
20
  from pygpt_net.ui.widget.textarea.notepad import NotepadWidget
21
21
  from pygpt_net.utils import trans
22
22
 
23
- import pygpt_net.icons_rc
24
-
25
23
 
26
24
  class Notepad:
27
25
  def __init__(self, window=None):
@@ -32,8 +30,7 @@ class Notepad:
32
30
  """
33
31
  self.window = window
34
32
  self.opened_once = False
35
- self.opened_idx = []
36
-
33
+ self.opened_idx = set()
37
34
 
38
35
  def get_next_suffix(self) -> int:
39
36
  """
@@ -41,13 +38,16 @@ class Notepad:
41
38
 
42
39
  :return: next notepad suffix
43
40
  """
44
- idx = self.window.core.tabs.count_by_type(Tab.TAB_NOTEPAD)
45
- for tab in self.window.core.tabs.get_tabs_by_type(Tab.TAB_NOTEPAD):
41
+ tabs_core = self.window.core.tabs
42
+ tabs = tabs_core.get_tabs_by_type(Tab.TAB_NOTEPAD)
43
+ idx = tabs_core.count_by_type(Tab.TAB_NOTEPAD)
44
+ for tab in tabs:
45
+ title = tab.title or ""
46
46
  try:
47
- num = int(tab.title.split(" ")[-1])
48
- if num >= idx:
47
+ num = int(title.rsplit(" ", 1)[-1])
48
+ if num > idx:
49
49
  idx = num
50
- except ValueError:
50
+ except (ValueError, IndexError):
51
51
  continue
52
52
  return idx + 1
53
53
 
@@ -58,12 +58,7 @@ class Notepad:
58
58
  :return: next available notepad index
59
59
  """
60
60
  tabs = self.window.core.tabs.get_tabs_by_type(Tab.TAB_NOTEPAD)
61
- opened = False
62
- for tab in tabs:
63
- if tab.data_id == idx:
64
- opened = True
65
- break
66
- return opened
61
+ return any(tab.data_id == idx for tab in tabs)
67
62
 
68
63
  def create(
69
64
  self,
@@ -77,27 +72,30 @@ class Notepad:
77
72
  :param tab: existing tab to use (optional)
78
73
  :return: notepad widget (TabBody)
79
74
  """
80
- if idx is None:
81
- idx = self.window.core.tabs.count_by_type(Tab.TAB_NOTEPAD) + 1
82
- suffix = self.get_next_suffix()
83
- else:
84
- suffix = self.get_next_suffix()
75
+ tabs_core = self.window.core.tabs
76
+ existing_tabs = tabs_core.get_tabs_by_type(Tab.TAB_NOTEPAD)
77
+ used_ids = {t.data_id for t in existing_tabs}
85
78
 
86
- while self.is_opened(idx):
79
+ if idx is None:
80
+ idx = 1
81
+ while idx in used_ids:
87
82
  idx += 1
88
- suffix = self.get_next_suffix()
83
+
84
+ suffix = self.get_next_suffix()
89
85
 
90
86
  data_id = idx
91
- self.window.ui.notepad[data_id] = NotepadWidget(self.window)
92
- self.window.ui.notepad[data_id].id = idx
93
- self.window.ui.notepad[data_id].textarea.id = idx
94
- title = trans('output.tab.notepad')
95
- title += " " + str(suffix)
87
+ widget = NotepadWidget(self.window)
88
+ widget.id = idx
89
+ widget.textarea.id = idx
90
+ self.window.ui.notepad[data_id] = widget
91
+
92
+ title = trans('output.tab.notepad') + " " + str(suffix)
96
93
  if tab:
97
94
  if not tab.title:
98
95
  tab.title = title
99
- child = self.window.core.tabs.from_widget(self.window.ui.notepad[data_id])
100
- child.on_delete = self.on_delete # cleanup callback
96
+
97
+ child = tabs_core.from_widget(widget)
98
+ child.on_delete = self.on_delete
101
99
  return child, idx, data_id
102
100
 
103
101
  def on_delete(self, body: TabBody):
@@ -115,6 +113,8 @@ class Notepad:
115
113
  if idx in self.window.ui.notepad:
116
114
  self.window.ui.notepad[idx].on_delete()
117
115
  del self.window.ui.notepad[idx]
116
+ if idx in self.opened_idx:
117
+ self.opened_idx.discard(idx)
118
118
  self.update()
119
119
 
120
120
  def load(self):
@@ -130,9 +130,10 @@ class Notepad:
130
130
  items[idx] = item
131
131
 
132
132
  if num_notepads > 0:
133
- for idx in items:
134
- if idx in self.window.ui.notepad:
135
- self.window.ui.notepad[idx].setText(items[idx].content)
133
+ for idx, item in items.items():
134
+ widget = self.window.ui.notepad.get(idx)
135
+ if widget is not None:
136
+ widget.setText(item.content)
136
137
 
137
138
  def get_notepad_name(self, idx: int):
138
139
  """
@@ -159,17 +160,19 @@ class Notepad:
159
160
 
160
161
  :param idx: notepad idx
161
162
  """
162
- item = self.window.core.notepad.get_by_id(idx)
163
+ core_notepad = self.window.core.notepad
164
+ item = core_notepad.get_by_id(idx)
163
165
  if item is None:
164
166
  item = NotepadItem()
165
167
  item.idx = idx
166
- self.window.core.notepad.items[idx] = item
167
-
168
- if idx in self.window.ui.notepad:
169
- prev_content = item.content
170
- item.content = self.window.ui.notepad[idx].toPlainText()
171
- if prev_content != item.content: # update only if content changed
172
- self.window.core.notepad.update(item)
168
+ core_notepad.items[idx] = item
169
+
170
+ widget = self.window.ui.notepad.get(idx)
171
+ if widget is not None:
172
+ text = widget.toPlainText()
173
+ if item.content != text:
174
+ item.content = text
175
+ core_notepad.update(item)
173
176
  self.update()
174
177
 
175
178
  def save_all(self):
@@ -177,16 +180,18 @@ class Notepad:
177
180
  items = self.window.core.notepad.get_all()
178
181
  num_notepads = self.get_num_notepads()
179
182
  if num_notepads > 0:
180
- tabs = self.window.core.tabs.get_tabs_by_type(Tab.TAB_NOTEPAD)
181
- for tab in tabs:
183
+ ui_notepad = self.window.ui.notepad
184
+ for tab in self.window.core.tabs.get_tabs_by_type(Tab.TAB_NOTEPAD):
182
185
  idx = tab.data_id
183
- if idx in self.window.ui.notepad:
184
- if idx in items:
185
- prev_content = str(items[idx].content)
186
- items[idx].content = self.window.ui.notepad[idx].toPlainText()
187
- # update only if content changed
188
- if prev_content != items[idx].content:
189
- self.window.core.notepad.update(items[idx])
186
+ widget = ui_notepad.get(idx)
187
+ if widget is None:
188
+ continue
189
+ if idx in items:
190
+ prev_content = str(items[idx].content)
191
+ text = widget.toPlainText()
192
+ if prev_content != text:
193
+ items[idx].content = text
194
+ self.window.core.notepad.update(items[idx])
190
195
  self.update()
191
196
 
192
197
  def setup(self):
@@ -200,21 +205,19 @@ class Notepad:
200
205
  :param text: text to append
201
206
  :param idx: notepad idx
202
207
  """
203
- if idx not in self.window.ui.notepad:
208
+ widget = self.window.ui.notepad.get(idx)
209
+ if widget is None:
204
210
  return
205
- dt = "" # TODO: add to config append date/time
206
- # dt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + ":\n--------------------------\n"
207
- prev_text = self.window.ui.notepad[idx].toPlainText()
208
- if prev_text.strip() != "":
209
- prev_text += "\n"
210
- new_text = prev_text + dt + text.strip()
211
- self.window.ui.notepad[idx].setText(new_text)
212
- self.save(idx)
213
-
214
- # move cursor to end
215
- cursor = self.window.ui.notepad[idx].textarea.textCursor()
211
+ dt = ""
212
+ prev_text = widget.toPlainText()
213
+ need_nl = prev_text.strip() != ""
214
+ textarea = widget.textarea
215
+ cursor = textarea.textCursor()
216
216
  cursor.movePosition(QTextCursor.End)
217
- self.window.ui.notepad[idx].textarea.setTextCursor(cursor)
217
+ to_insert = (("\n" if need_nl else "") + dt + text.strip())
218
+ cursor.insertText(to_insert)
219
+ textarea.setTextCursor(cursor)
220
+ self.save(idx)
218
221
 
219
222
  def get_num_notepads(self) -> int:
220
223
  """
@@ -230,8 +233,9 @@ class Notepad:
230
233
 
231
234
  :return: current notepad index
232
235
  """
236
+ tabs_ctrl = self.window.controller.ui.tabs
233
237
  if self.is_active():
234
- tab = self.window.controller.ui.tabs.get_current_tab()
238
+ tab = tabs_ctrl.get_current_tab()
235
239
  if tab is not None:
236
240
  return tab.data_id
237
241
  return 1
@@ -246,17 +250,14 @@ class Notepad:
246
250
 
247
251
  def open(self):
248
252
  """Open notepad"""
249
- # if notepad disabled, do nothing
250
253
  if self.get_num_notepads() == 0:
251
254
  return
252
-
253
- # switch to first notepad tab if current tab is not notepad
254
- tabs = self.window.ui.layout.get_active_tabs()
255
255
  if self.window.controller.ui.tabs.get_current_type() != Tab.TAB_NOTEPAD:
256
256
  idx = self.window.core.tabs.get_min_idx_by_type(Tab.TAB_NOTEPAD)
257
257
  if idx is not None:
258
+ tabs = self.window.ui.layout.get_active_tabs()
258
259
  tabs.setCurrentIndex(idx)
259
- self.window.activateWindow() # focus
260
+ self.window.activateWindow()
260
261
 
261
262
  def update(self):
262
263
  """Update notepads UI"""
@@ -299,9 +300,8 @@ class Notepad:
299
300
  :return: current notepad text
300
301
  """
301
302
  idx = self.get_current_active()
302
- if idx in self.window.ui.notepad:
303
- return self.window.ui.notepad[idx].toPlainText()
304
- return ""
303
+ widget = self.window.ui.notepad.get(idx)
304
+ return widget.toPlainText() if widget is not None else ""
305
305
 
306
306
  def get_notepad_text(self, idx: int) -> str:
307
307
  """
@@ -310,9 +310,8 @@ class Notepad:
310
310
  :param idx: notepad index
311
311
  :return: notepad text
312
312
  """
313
- if idx in self.window.ui.notepad:
314
- return self.window.ui.notepad[idx].toPlainText()
315
- return ""
313
+ widget = self.window.ui.notepad.get(idx)
314
+ return widget.toPlainText() if widget is not None else ""
316
315
 
317
316
  def clear(self, idx: int) -> bool:
318
317
  """
@@ -320,8 +319,9 @@ class Notepad:
320
319
 
321
320
  :param idx: notepad idx
322
321
  """
323
- if idx in self.window.ui.notepad:
324
- self.window.ui.notepad[idx].textarea.clear()
322
+ widget = self.window.ui.notepad.get(idx)
323
+ if widget is not None:
324
+ widget.textarea.clear()
325
325
  self.save(idx)
326
326
  return True
327
327
  return False
@@ -342,10 +342,12 @@ class Notepad:
342
342
  return
343
343
  if tab.type == Tab.TAB_NOTEPAD:
344
344
  idx = tab.data_id
345
- if idx in self.window.ui.notepad:
346
- if idx not in self.opened_idx:
347
- QTimer.singleShot(0, self.window.ui.notepad[idx].scroll_to_bottom)
348
- if not self.window.ui.notepad[idx].opened:
349
- self.window.ui.notepad[idx].opened = True
350
- if idx not in self.opened_idx:
351
- self.opened_idx.append(idx)
345
+ widget = self.window.ui.notepad.get(idx)
346
+ if widget is None:
347
+ return
348
+ if idx not in self.opened_idx:
349
+ QTimer.singleShot(0, widget.scroll_to_bottom)
350
+ if not widget.opened:
351
+ widget.opened = True
352
+ if idx not in self.opened_idx:
353
+ self.opened_idx.add(idx)
@@ -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
@@ -138,10 +138,9 @@ class Settings:
138
138
  window.controller.plugins.presets.save_current()
139
139
  window.core.config.save()
140
140
  self.close()
141
- window.update_status(trans('info.settings.saved'))
142
141
 
143
- event = Event(Event.PLUGIN_SETTINGS_CHANGED)
144
- window.dispatch(event)
142
+ window.update_status(trans('info.settings.saved'))
143
+ window.dispatch(Event(Event.PLUGIN_SETTINGS_CHANGED))
145
144
  window.controller.ui.update_tokens()
146
145
 
147
146
  def close(self):