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.09 15:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt, Slot, QObject, Signal
@@ -16,7 +16,6 @@ from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QTextEdit, QWidget, QSpl
16
16
  from pygpt_net.core.text.finder import Finder
17
17
  from pygpt_net.ui.widget.option.combo import OptionCombo
18
18
 
19
- import pygpt_net.icons_rc
20
19
  from pygpt_net.ui.widget.textarea.search_input import SearchInput
21
20
  from pygpt_net.utils import trans
22
21
 
@@ -338,11 +337,11 @@ class TextareaField(QTextEdit):
338
337
 
339
338
  :param window: main window
340
339
  """
341
- super(TextareaField, self).__init__(window)
340
+ super().__init__(window)
342
341
  self.window = window
343
342
  self.id = id # assigned in setup
344
343
  self.setReadOnly(False)
345
- self.acceptRichText = False # disable rich text
344
+ self.setAcceptRichText(False)
346
345
  self.value = 12
347
346
  self.max_font_size = 42
348
347
  self.min_font_size = 8
@@ -353,6 +352,12 @@ class TextareaField(QTextEdit):
353
352
  self.finder = Finder(window, self)
354
353
  self.installEventFilter(self)
355
354
 
355
+ self._icon_volume = QIcon(":/icons/volume.svg")
356
+ self._icon_save = QIcon(":/icons/save.svg")
357
+ self._icon_search = QIcon(":/icons/search.svg")
358
+ self._icon_clear = QIcon(":/icons/clear.svg")
359
+ self._seq_find = QKeySequence("Ctrl+F")
360
+
356
361
  # tabulation
357
362
  metrics = QFontMetrics(self.font())
358
363
  space_width = metrics.horizontalAdvance(" ")
@@ -381,7 +386,6 @@ class TextareaField(QTextEdit):
381
386
  """
382
387
  return super().eventFilter(source, event)
383
388
 
384
-
385
389
  def contextMenuEvent(self, event):
386
390
  """
387
391
  Context menu event
@@ -389,13 +393,14 @@ class TextareaField(QTextEdit):
389
393
  :param event: Event
390
394
  """
391
395
  menu = self.createStandardContextMenu()
392
- selected_text = self.textCursor().selectedText()
396
+ cursor = self.textCursor()
397
+ selected_text = cursor.selectedText()
393
398
  if selected_text:
394
399
  # plain text
395
- plain_text = self.textCursor().selection().toPlainText()
400
+ plain_text = cursor.selection().toPlainText()
396
401
 
397
402
  # audio read
398
- action = QAction(QIcon(":/icons/volume.svg"), trans('text.context_menu.audio.read'), self)
403
+ action = QAction(self._icon_volume, trans('text.context_menu.audio.read'), menu)
399
404
  action.triggered.connect(self.audio_read_selection)
400
405
  menu.addAction(action)
401
406
 
@@ -405,31 +410,31 @@ class TextareaField(QTextEdit):
405
410
  excluded = ["translator_left"]
406
411
  elif self.id == "right":
407
412
  excluded = ["translator_right"]
408
- copy_to_menu = self.window.ui.context_menu.get_copy_to_menu(self, selected_text, excluded=excluded)
409
- menu.addMenu(copy_to_menu)
413
+ copy_to_menu = self.window.ui.context_menu.get_copy_to_menu(menu, selected_text, excluded=excluded)
414
+ if copy_to_menu is not None:
415
+ menu.addMenu(copy_to_menu)
410
416
 
411
417
  # save as (selected)
412
- action = QAction(QIcon(":/icons/save.svg"), trans('action.save_selection_as'), self)
413
- action.triggered.connect(
414
- lambda: self.window.controller.chat.common.save_text(plain_text))
418
+ action = QAction(self._icon_save, trans('action.save_selection_as'), menu)
419
+ action.triggered.connect(lambda pt=plain_text: self.window.controller.chat.common.save_text(pt))
415
420
  menu.addAction(action)
416
421
  else:
417
422
  # save as (all)
418
- action = QAction(QIcon(":/icons/save.svg"), trans('action.save_as'), self)
419
- action.triggered.connect(
420
- lambda: self.window.controller.chat.common.save_text(self.toPlainText()))
423
+ action = QAction(self._icon_save, trans('action.save_as'), menu)
424
+ action.triggered.connect(lambda: self.window.controller.chat.common.save_text(self.toPlainText()))
421
425
  menu.addAction(action)
422
426
 
423
- action = QAction(QIcon(":/icons/search.svg"), trans('text.context_menu.find'), self)
427
+ action = QAction(self._icon_search, trans('text.context_menu.find'), menu)
424
428
  action.triggered.connect(self.find_open)
425
- action.setShortcut(QKeySequence("Ctrl+F"))
429
+ action.setShortcut(self._seq_find)
426
430
  menu.addAction(action)
427
431
 
428
- action = QAction(QIcon(":/icons/clear.svg"), trans('translators.menu.file.clear'), self)
432
+ action = QAction(self._icon_clear, trans('translators.menu.file.clear'), menu)
429
433
  action.triggered.connect(self.action_clear)
430
434
  menu.addAction(action)
431
435
 
432
436
  menu.exec_(event.globalPos())
437
+ menu.deleteLater()
433
438
 
434
439
  def action_clear(self):
435
440
  """
@@ -462,9 +467,9 @@ class TextareaField(QTextEdit):
462
467
  """
463
468
  if e.key() == Qt.Key_F and e.modifiers() & Qt.ControlModifier:
464
469
  self.find_open()
465
- else:
466
- self.finder.clear(restore=True, to_end=False)
467
- super(TextareaField, self).keyPressEvent(e)
470
+ return
471
+ self.finder.clear(restore=True, to_end=False)
472
+ super().keyPressEvent(e)
468
473
 
469
474
  def update_stylesheet(self, data: str):
470
475
  """
@@ -472,7 +477,9 @@ class TextareaField(QTextEdit):
472
477
 
473
478
  :param data: stylesheet CSS
474
479
  """
475
- self.setStyleSheet(self.default_stylesheet + data)
480
+ combined = self.default_stylesheet + data
481
+ if combined != self.styleSheet():
482
+ self.setStyleSheet(combined)
476
483
 
477
484
  def wheelEvent(self, event):
478
485
  """
@@ -481,17 +488,14 @@ class TextareaField(QTextEdit):
481
488
  :param event: Event
482
489
  """
483
490
  if event.modifiers() & Qt.ControlModifier:
484
- if event.angleDelta().y() > 0:
485
- if self.value < self.max_font_size:
486
- self.value += 1
487
- else:
488
- if self.value > self.min_font_size:
489
- self.value -= 1
490
-
491
- self.update_stylesheet(f"QTextEdit {{ font-size: {self.value}px }};")
491
+ delta = 1 if event.angleDelta().y() > 0 else -1
492
+ new_value = max(self.min_font_size, min(self.max_font_size, self.value + delta))
493
+ if new_value != self.value:
494
+ self.value = new_value
495
+ self.update_stylesheet(f"QTextEdit {{ font-size: {self.value}px }};")
492
496
  event.accept()
493
- else:
494
- super(TextareaField, self).wheelEvent(event)
497
+ return
498
+ super().wheelEvent(event)
495
499
 
496
500
  def focusInEvent(self, e):
497
501
  """
@@ -500,7 +504,7 @@ class TextareaField(QTextEdit):
500
504
  :param e: focus event
501
505
  """
502
506
  self.window.controller.finder.focus_in(self.finder)
503
- super(TextareaField, self).focusInEvent(e)
507
+ super().focusInEvent(e)
504
508
 
505
509
  def focusOutEvent(self, e):
506
510
  """
@@ -508,7 +512,7 @@ class TextareaField(QTextEdit):
508
512
 
509
513
  :param e: focus event
510
514
  """
511
- super(TextareaField, self).focusOutEvent(e)
515
+ super().focusOutEvent(e)
512
516
  self.window.controller.finder.focus_out(self.finder)
513
517
 
514
518
 
@@ -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 PySide6.QtWidgets import QMenu
@@ -14,10 +14,10 @@ from PySide6.QtGui import QAction, QIcon
14
14
 
15
15
  from pygpt_net.core.tabs.tab import Tab
16
16
  from pygpt_net.utils import trans
17
- import pygpt_net.icons_rc
18
17
 
19
18
 
20
19
  class ContextMenu:
20
+
21
21
  _ICON_INPUT = QIcon(":/icons/input.svg")
22
22
  _ICON_SCHEDULE = QIcon(":/icons/schedule.svg")
23
23
  _ICON_PASTE = QIcon(":/icons/paste.svg")
@@ -32,11 +32,16 @@ class ContextMenu:
32
32
  """
33
33
  self.window = window
34
34
 
35
- def get_copy_to_menu(self, parent, selected_text: str = None, excluded: list = None) -> QMenu:
35
+ def get_copy_to_menu(
36
+ self,
37
+ parent,
38
+ selected_text: str = None,
39
+ excluded: list = None
40
+ ) -> QMenu:
36
41
  """
37
42
  Get copy to menu
38
43
 
39
- :param parent: Parent widget
44
+ :param parent: Parent menu
40
45
  :param selected_text: Selected text
41
46
  :param excluded: Excluded items
42
47
  :return: Menu
pygpt_net/ui/dialog/db.py CHANGED
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.04.17 01:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt
@@ -17,8 +17,6 @@ from PySide6.QtWidgets import QGridLayout, QScrollArea, QSplitter, QComboBox, QL
17
17
  from pygpt_net.ui.widget.dialog.db import DatabaseDialog
18
18
  from pygpt_net.ui.widget.lists.db import DatabaseList, DatabaseTableModel
19
19
  from pygpt_net.ui.widget.textarea.editor import CodeEditor
20
-
21
- import pygpt_net.icons_rc
22
20
  from pygpt_net.utils import trans
23
21
 
24
22
 
@@ -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.02 20:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -30,8 +30,6 @@ from pygpt_net.ui.widget.option.slider import OptionSlider
30
30
  from pygpt_net.ui.widget.option.textarea import OptionTextarea
31
31
  from pygpt_net.utils import trans
32
32
 
33
- import pygpt_net.icons_rc
34
-
35
33
  class Models:
36
34
  def __init__(self, window=None):
37
35
  """
@@ -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.02 20:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
  from PySide6 import QtCore
12
12
  from PySide6.QtGui import QIcon
@@ -14,11 +14,9 @@ from PySide6.QtWidgets import QPushButton, QHBoxLayout, QVBoxLayout, QLabel
14
14
 
15
15
  from pygpt_net.ui.widget.lists.model_importer import ModelImporter
16
16
  from pygpt_net.ui.widget.dialog.model_importer import ModelImporterOllamaDialog
17
- from pygpt_net.ui.widget.option.combo import NoScrollCombo, OptionCombo
17
+ from pygpt_net.ui.widget.option.combo import OptionCombo
18
18
  from pygpt_net.utils import trans
19
19
 
20
- import pygpt_net.icons_rc
21
-
22
20
 
23
21
  class ModelsImporter:
24
22
  def __init__(self, window=None):
pygpt_net/ui/dialogs.py CHANGED
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.01 03:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import threading
@@ -129,11 +129,12 @@ class Dialogs:
129
129
  :param msg: message to show
130
130
  :param parent_object: parent object
131
131
  """
132
- self.window.ui.dialog['confirm'].type = type
133
- self.window.ui.dialog['confirm'].id = id
134
- self.window.ui.dialog['confirm'].message.setText(msg)
135
- self.window.ui.dialog['confirm'].parent_object = parent_object
136
- self.window.ui.dialog['confirm'].show()
132
+ confirm = self.window.ui.dialog.get('confirm')
133
+ confirm.type = type
134
+ confirm.id = id
135
+ confirm.message.setText(msg)
136
+ confirm.parent_object = parent_object
137
+ confirm.show()
137
138
 
138
139
  def alert(self, msg: any):
139
140
  """
@@ -159,9 +160,10 @@ class Dialogs:
159
160
  """
160
161
  if id not in self.window.ui.dialog:
161
162
  return
162
- self.window.ui.dialog[id].resize(width, height)
163
- self.window.ui.dialog[id].data_id = data_id
164
- self.window.ui.dialog[id].show()
163
+ dialog = self.window.ui.dialog[id]
164
+ dialog.resize(width, height)
165
+ dialog.data_id = data_id
166
+ dialog.show()
165
167
 
166
168
  def open_dictionary_editor(
167
169
  self,
@@ -187,10 +189,11 @@ class Dialogs:
187
189
  print("Dialog not found: " + dialog_id)
188
190
  return
189
191
  self.window.controller.config.dictionary.append_editor(id, option, data)
190
- self.window.ui.dialog[dialog_id].resize(width, height)
191
- self.window.ui.dialog[dialog_id].data = data # store editing data
192
- self.window.ui.dialog[dialog_id].idx = idx # store editing record idx
193
- self.window.ui.dialog[dialog_id].show()
192
+ dialog = self.window.ui.dialog[dialog_id]
193
+ dialog.resize(width, height)
194
+ dialog.data = data # store editing data
195
+ dialog.idx = idx # store editing record idx
196
+ dialog.show()
194
197
 
195
198
  def register_dictionary(
196
199
  self,
@@ -205,8 +208,7 @@ class Dialogs:
205
208
  :param parent: parent id
206
209
  :param option: dictionary option keys
207
210
  """
208
- dict_id = parent + "." + key
209
- self.dictionary.register(dict_id, key, parent, option)
211
+ self.dictionary.register(f"{parent}.{key}", key, parent, option)
210
212
 
211
213
  def open(
212
214
  self,
@@ -223,18 +225,19 @@ class Dialogs:
223
225
  """
224
226
  if id not in self.window.ui.dialog:
225
227
  return
226
- self.window.ui.dialog[id].resize(width, height)
227
- self.window.ui.dialog[id].setSizeGripEnabled(True)
228
- self.window.ui.dialog[id].setWindowFlags(
229
- self.window.ui.dialog[id].windowFlags() | Qt.WindowMaximizeButtonHint
228
+ dialog = self.window.ui.dialog[id]
229
+ dialog.resize(width, height)
230
+ dialog.setSizeGripEnabled(True)
231
+ dialog.setWindowFlags(
232
+ dialog.windowFlags() | Qt.WindowMaximizeButtonHint
230
233
  )
231
- qr = self.window.ui.dialog[id].frameGeometry()
234
+ qr = dialog.frameGeometry()
232
235
  cp = self.window.screen().availableGeometry().center()
233
236
  qr.moveCenter(cp)
234
- self.window.ui.dialog[id].move(qr.topLeft())
235
- self.window.ui.dialog[id].show()
236
- self.window.ui.dialog[id].activateWindow()
237
- self.window.ui.dialog[id].setFocus()
237
+ dialog.move(qr.topLeft())
238
+ dialog.show()
239
+ dialog.activateWindow()
240
+ dialog.setFocus()
238
241
 
239
242
  def open_instance(self,
240
243
  id: str,
@@ -256,14 +259,15 @@ class Dialogs:
256
259
  else:
257
260
  print("Dialog not found: " + id)
258
261
  return
259
- self.window.ui.dialog[id].resize(width, height)
260
- qr = self.window.ui.dialog[id].frameGeometry()
262
+ dialog = self.window.ui.dialog[id]
263
+ dialog.resize(width, height)
264
+ qr = dialog.frameGeometry()
261
265
  cp = self.window.screen().availableGeometry().center()
262
266
  qr.moveCenter(cp)
263
- self.window.ui.dialog[id].move(qr.topLeft())
264
- self.window.ui.dialog[id].show()
265
- self.window.ui.dialog[id].activateWindow()
266
- self.window.ui.dialog[id].setFocus()
267
+ dialog.move(qr.topLeft())
268
+ dialog.show()
269
+ dialog.activateWindow()
270
+ dialog.setFocus()
267
271
 
268
272
  def close(self, id: str):
269
273
  """
@@ -6,12 +6,14 @@
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.11.26 02:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
+ from functools import partial
13
14
 
14
- from PySide6.QtGui import QStandardItemModel, Qt, QIcon
15
+ from PySide6.QtGui import QStandardItemModel, QIcon
16
+ from PySide6.QtCore import Qt
15
17
  from PySide6.QtWidgets import QVBoxLayout, QPushButton, QHBoxLayout, QCheckBox, QWidget
16
18
 
17
19
  from pygpt_net.item.attachment import AttachmentItem
@@ -19,8 +21,6 @@ from pygpt_net.ui.widget.element.labels import HelpLabel
19
21
  from pygpt_net.ui.widget.lists.attachment import AttachmentList
20
22
  from pygpt_net.utils import trans
21
23
 
22
- import pygpt_net.icons_rc
23
-
24
24
  class Attachments:
25
25
  def __init__(self, window=None):
26
26
  """
@@ -40,17 +40,16 @@ class Attachments:
40
40
  self.setup_attachments()
41
41
  self.setup_buttons()
42
42
 
43
- empty_widget = QWidget()
44
- self.window.ui.nodes['input.attachments.options.label'] = HelpLabel(trans("attachments.options.label"))
43
+ empty_widget = QWidget(self.window)
44
+ self.window.ui.nodes['input.attachments.options.label'] = HelpLabel(trans("attachments.options.label"), self.window)
45
45
 
46
- # buttons layout
47
46
  buttons = QHBoxLayout()
48
- buttons.addWidget(self.window.ui.nodes['attachments.btn.add'])
49
- buttons.addWidget(self.window.ui.nodes['attachments.btn.add_url'])
50
- buttons.addWidget(self.window.ui.nodes['attachments.btn.clear'])
47
+ nodes = self.window.ui.nodes
48
+ buttons.addWidget(nodes['attachments.btn.add'])
49
+ buttons.addWidget(nodes['attachments.btn.add_url'])
50
+ buttons.addWidget(nodes['attachments.btn.clear'])
51
51
  buttons.addWidget(empty_widget)
52
- buttons.addWidget(self.window.ui.nodes['input.attachments.options.label'])
53
-
52
+ buttons.addWidget(nodes['input.attachments.options.label'])
54
53
  buttons.addWidget(self.setup_auto_index())
55
54
  buttons.addWidget(self.setup_send_clear())
56
55
  buttons.addWidget(self.setup_capture_clear())
@@ -58,30 +57,29 @@ class Attachments:
58
57
 
59
58
  self.window.ui.nodes['tip.input.attachments'] = HelpLabel(trans('tip.input.attachments'), self.window)
60
59
 
61
- # layout
62
60
  layout = QVBoxLayout()
63
61
  layout.addWidget(self.window.ui.nodes['tip.input.attachments'])
64
62
  layout.addWidget(self.window.ui.nodes['attachments'])
65
-
66
63
  layout.addLayout(buttons)
67
64
 
68
65
  return layout
69
66
 
67
+ def _centered_container(self, child: QWidget) -> QWidget:
68
+ layout = QHBoxLayout()
69
+ layout.setContentsMargins(0, 0, 0, 0)
70
+ layout.setAlignment(Qt.AlignCenter)
71
+ layout.addWidget(child)
72
+ widget = QWidget(self.window)
73
+ widget.setLayout(layout)
74
+ return widget
75
+
70
76
  def setup_send_clear(self) -> QWidget:
71
77
  """
72
78
  Setup send clear checkbox
73
79
 
74
80
  :return: QWidget
75
81
  """
76
- layout = QHBoxLayout()
77
- layout.setContentsMargins(0, 0, 0, 0)
78
- layout.setAlignment(Qt.AlignCenter)
79
- layout.addWidget(self.window.ui.nodes['attachments.send_clear'])
80
-
81
- widget = QWidget()
82
- widget.setLayout(layout)
83
-
84
- return widget
82
+ return self._centered_container(self.window.ui.nodes['attachments.send_clear'])
85
83
 
86
84
  def setup_capture_clear(self) -> QWidget:
87
85
  """
@@ -89,15 +87,7 @@ class Attachments:
89
87
 
90
88
  :return: QWidget
91
89
  """
92
- layout = QHBoxLayout()
93
- layout.setContentsMargins(0, 0, 0, 0)
94
- layout.setAlignment(Qt.AlignCenter)
95
- layout.addWidget(self.window.ui.nodes['attachments.capture_clear'])
96
-
97
- widget = QWidget()
98
- widget.setLayout(layout)
99
-
100
- return widget
90
+ return self._centered_container(self.window.ui.nodes['attachments.capture_clear'])
101
91
 
102
92
  def setup_auto_index(self) -> QWidget:
103
93
  """
@@ -105,45 +95,34 @@ class Attachments:
105
95
 
106
96
  :return: QWidget
107
97
  """
108
- layout = QHBoxLayout()
109
- layout.setContentsMargins(0, 0, 0, 0)
110
- layout.setAlignment(Qt.AlignCenter)
111
- layout.addWidget(self.window.ui.nodes['attachments.auto_index'])
112
-
113
- widget = QWidget()
114
- widget.setLayout(layout)
115
-
116
- return widget
98
+ return self._centered_container(self.window.ui.nodes['attachments.auto_index'])
117
99
 
118
100
  def setup_buttons(self):
119
101
  """
120
102
  Setup buttons
121
103
  """
122
- self.window.ui.nodes['attachments.btn.add'] = QPushButton(QIcon(":/icons/add.svg"), trans('attachments.btn.add'))
123
- self.window.ui.nodes['attachments.btn.add_url'] = QPushButton(QIcon(":/icons/add.svg"), trans('attachments.btn.add_url'))
124
- self.window.ui.nodes['attachments.btn.clear'] = QPushButton(QIcon(":/icons/close.svg"), trans('attachments.btn.clear'))
104
+ nodes = self.window.ui.nodes
105
+ ctrl = self.window.controller.attachment
106
+
107
+ icon_add = QIcon(":/icons/add.svg")
108
+ icon_close = QIcon(":/icons/close.svg")
125
109
 
126
- self.window.ui.nodes['attachments.btn.add'].clicked.connect(
127
- lambda: self.window.controller.attachment.open_add())
128
- self.window.ui.nodes['attachments.btn.add_url'].clicked.connect(
129
- lambda: self.window.controller.attachment.open_add_url())
130
- self.window.ui.nodes['attachments.btn.clear'].clicked.connect(
131
- lambda: self.window.controller.attachment.clear(remove_local=True))
110
+ nodes['attachments.btn.add'] = QPushButton(icon_add, trans('attachments.btn.add'), self.window)
111
+ nodes['attachments.btn.add_url'] = QPushButton(icon_add, trans('attachments.btn.add_url'), self.window)
112
+ nodes['attachments.btn.clear'] = QPushButton(icon_close, trans('attachments.btn.clear'), self.window)
132
113
 
133
- self.window.ui.nodes['attachments.send_clear'] = QCheckBox(trans('attachments.send_clear'))
134
- self.window.ui.nodes['attachments.send_clear'].stateChanged.connect(
135
- lambda: self.window.controller.attachment.toggle_send_clear(
136
- self.window.ui.nodes['attachments.send_clear'].isChecked()))
114
+ nodes['attachments.btn.add'].clicked.connect(ctrl.open_add)
115
+ nodes['attachments.btn.add_url'].clicked.connect(ctrl.open_add_url)
116
+ nodes['attachments.btn.clear'].clicked.connect(partial(ctrl.clear, remove_local=True))
137
117
 
138
- self.window.ui.nodes['attachments.capture_clear'] = QCheckBox(trans('attachments.capture_clear'))
139
- self.window.ui.nodes['attachments.capture_clear'].stateChanged.connect(
140
- lambda: self.window.controller.attachment.toggle_capture_clear(
141
- self.window.ui.nodes['attachments.capture_clear'].isChecked()))
118
+ nodes['attachments.send_clear'] = QCheckBox(trans('attachments.send_clear'), self.window)
119
+ nodes['attachments.send_clear'].toggled.connect(ctrl.toggle_send_clear)
142
120
 
143
- self.window.ui.nodes['attachments.auto_index'] = QCheckBox(trans('attachments.auto_index'))
144
- self.window.ui.nodes['attachments.auto_index'].stateChanged.connect(
145
- lambda: self.window.controller.attachment.toggle_auto_index(
146
- self.window.ui.nodes['attachments.auto_index'].isChecked()))
121
+ nodes['attachments.capture_clear'] = QCheckBox(trans('attachments.capture_clear'), self.window)
122
+ nodes['attachments.capture_clear'].toggled.connect(ctrl.toggle_capture_clear)
123
+
124
+ nodes['attachments.auto_index'] = QCheckBox(trans('attachments.auto_index'), self.window)
125
+ nodes['attachments.auto_index'].toggled.connect(ctrl.toggle_auto_index)
147
126
 
148
127
  def setup_attachments(self):
149
128
  """
@@ -161,11 +140,12 @@ class Attachments:
161
140
  :return: QStandardItemModel
162
141
  """
163
142
  model = QStandardItemModel(0, 4, parent)
164
- model.setHeaderData(0, Qt.Horizontal, trans('attachments.header.name'))
165
- model.setHeaderData(1, Qt.Horizontal, trans('attachments.header.path'))
166
- model.setHeaderData(2, Qt.Horizontal, trans('attachments.header.size'))
167
- model.setHeaderData(3, Qt.Horizontal, trans('attachments.header.ctx'))
168
-
143
+ model.setHorizontalHeaderLabels([
144
+ trans('attachments.header.name'),
145
+ trans('attachments.header.path'),
146
+ trans('attachments.header.size'),
147
+ trans('attachments.header.ctx'),
148
+ ])
169
149
  return model
170
150
 
171
151
  def update(self, data):
@@ -174,20 +154,28 @@ class Attachments:
174
154
 
175
155
  :param data: Data to update
176
156
  """
177
- self.window.ui.models[self.id].removeRows(0, self.window.ui.models[self.id].rowCount())
178
- i = 0
179
- for id in data:
180
- path = data[id].path
181
- size = ""
182
- if data[id].type == AttachmentItem.TYPE_FILE:
183
- if path and os.path.exists(path):
184
- size = self.window.core.filesystem.sizeof_fmt(os.path.getsize(path))
185
- ctx_str = ""
186
- if data[id].ctx:
187
- ctx_str = "YES"
188
- self.window.ui.models[self.id].insertRow(i)
189
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 0), data[id].name)
190
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 1),path)
191
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 2), size)
192
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 3), ctx_str)
193
- i += 1
157
+ model = self.window.ui.models[self.id]
158
+ rows = len(data)
159
+ model.setRowCount(rows)
160
+
161
+ exists = os.path.exists
162
+ getsize = os.path.getsize
163
+ sizeof_fmt = self.window.core.filesystem.sizeof_fmt
164
+
165
+ model.beginResetModel()
166
+ for i, (_, item) in enumerate(data.items()):
167
+ path = item.path
168
+ if item.type == AttachmentItem.TYPE_FILE and path and exists(path):
169
+ size = sizeof_fmt(getsize(path))
170
+ else:
171
+ size = ""
172
+ ctx_str = "YES" if item.ctx else ""
173
+
174
+ model.setData(model.index(i, 0), item.name)
175
+ model.setData(model.index(i, 1), path)
176
+ model.setData(model.index(i, 2), size)
177
+ model.setData(model.index(i, 3), ctx_str)
178
+ model.endResetModel()
179
+
180
+ if rows:
181
+ model.dataChanged.emit(model.index(0, 0), model.index(rows - 1, 3), [])