pygpt-net 2.6.21__py3-none-any.whl → 2.6.23__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 (160) hide show
  1. pygpt_net/CHANGELOG.txt +12 -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/agent/llama.py +3 -0
  7. pygpt_net/controller/assistant/batch.py +2 -3
  8. pygpt_net/controller/assistant/editor.py +2 -2
  9. pygpt_net/controller/assistant/files.py +2 -3
  10. pygpt_net/controller/assistant/store.py +2 -2
  11. pygpt_net/controller/audio/audio.py +2 -2
  12. pygpt_net/controller/chat/response.py +4 -0
  13. pygpt_net/controller/ctx/ctx.py +2 -1
  14. pygpt_net/controller/files/files.py +24 -55
  15. pygpt_net/controller/idx/indexer.py +85 -76
  16. pygpt_net/controller/lang/lang.py +52 -34
  17. pygpt_net/controller/model/importer.py +2 -2
  18. pygpt_net/controller/notepad/notepad.py +86 -84
  19. pygpt_net/controller/plugins/settings.py +3 -4
  20. pygpt_net/controller/settings/profile.py +105 -124
  21. pygpt_net/controller/theme/menu.py +154 -57
  22. pygpt_net/controller/theme/nodes.py +51 -44
  23. pygpt_net/controller/theme/theme.py +33 -9
  24. pygpt_net/controller/tools/tools.py +2 -2
  25. pygpt_net/controller/ui/tabs.py +2 -3
  26. pygpt_net/core/agents/observer/evaluation.py +2 -2
  27. pygpt_net/core/agents/runners/loop.py +1 -0
  28. pygpt_net/core/bridge/bridge.py +2 -0
  29. pygpt_net/core/ctx/container.py +13 -12
  30. pygpt_net/core/ctx/output.py +7 -4
  31. pygpt_net/core/debug/console/console.py +2 -2
  32. pygpt_net/core/filesystem/actions.py +1 -2
  33. pygpt_net/core/filesystem/opener.py +261 -0
  34. pygpt_net/core/filesystem/url.py +13 -10
  35. pygpt_net/core/platforms/platforms.py +5 -4
  36. pygpt_net/core/render/plain/helpers.py +2 -5
  37. pygpt_net/core/render/plain/renderer.py +26 -30
  38. pygpt_net/core/render/web/body.py +1 -1
  39. pygpt_net/core/settings/settings.py +43 -13
  40. pygpt_net/core/tabs/tabs.py +20 -13
  41. pygpt_net/data/config/config.json +4 -4
  42. pygpt_net/data/config/models.json +3 -3
  43. pygpt_net/data/css/web-blocks.dark.css +7 -1
  44. pygpt_net/data/css/web-blocks.light.css +5 -2
  45. pygpt_net/data/css/web-chatgpt.dark.css +7 -1
  46. pygpt_net/data/css/web-chatgpt.light.css +3 -0
  47. pygpt_net/data/css/web-chatgpt_wide.dark.css +7 -1
  48. pygpt_net/data/css/web-chatgpt_wide.light.css +3 -0
  49. pygpt_net/data/locale/locale.de.ini +5 -1
  50. pygpt_net/data/locale/locale.en.ini +5 -1
  51. pygpt_net/data/locale/locale.es.ini +5 -1
  52. pygpt_net/data/locale/locale.fr.ini +5 -1
  53. pygpt_net/data/locale/locale.it.ini +5 -1
  54. pygpt_net/data/locale/locale.pl.ini +6 -4
  55. pygpt_net/data/locale/locale.uk.ini +5 -1
  56. pygpt_net/data/locale/locale.zh.ini +5 -1
  57. pygpt_net/plugin/twitter/plugin.py +2 -2
  58. pygpt_net/provider/core/config/patch.py +12 -1
  59. pygpt_net/tools/audio_transcriber/ui/dialogs.py +44 -54
  60. pygpt_net/tools/code_interpreter/body.py +1 -2
  61. pygpt_net/tools/code_interpreter/tool.py +7 -4
  62. pygpt_net/tools/code_interpreter/ui/html.py +1 -3
  63. pygpt_net/tools/code_interpreter/ui/widgets.py +2 -3
  64. pygpt_net/tools/html_canvas/ui/widgets.py +1 -3
  65. pygpt_net/tools/image_viewer/ui/dialogs.py +40 -37
  66. pygpt_net/tools/indexer/ui/widgets.py +2 -4
  67. pygpt_net/tools/media_player/tool.py +2 -5
  68. pygpt_net/tools/media_player/ui/widgets.py +60 -36
  69. pygpt_net/tools/text_editor/ui/widgets.py +18 -19
  70. pygpt_net/tools/translator/ui/widgets.py +39 -35
  71. pygpt_net/ui/base/context_menu.py +9 -4
  72. pygpt_net/ui/dialog/db.py +1 -3
  73. pygpt_net/ui/dialog/models.py +1 -3
  74. pygpt_net/ui/dialog/models_importer.py +2 -4
  75. pygpt_net/ui/dialogs.py +34 -30
  76. pygpt_net/ui/layout/chat/attachments.py +72 -84
  77. pygpt_net/ui/layout/chat/attachments_ctx.py +40 -44
  78. pygpt_net/ui/layout/chat/attachments_uploaded.py +36 -39
  79. pygpt_net/ui/layout/chat/calendar.py +100 -70
  80. pygpt_net/ui/layout/chat/chat.py +23 -17
  81. pygpt_net/ui/layout/chat/input.py +95 -118
  82. pygpt_net/ui/layout/chat/output.py +100 -162
  83. pygpt_net/ui/layout/chat/painter.py +89 -61
  84. pygpt_net/ui/layout/ctx/ctx_list.py +43 -52
  85. pygpt_net/ui/layout/status.py +23 -14
  86. pygpt_net/ui/layout/toolbox/agent.py +27 -38
  87. pygpt_net/ui/layout/toolbox/agent_llama.py +41 -45
  88. pygpt_net/ui/layout/toolbox/assistants.py +42 -38
  89. pygpt_net/ui/layout/toolbox/computer_env.py +32 -23
  90. pygpt_net/ui/layout/toolbox/footer.py +13 -16
  91. pygpt_net/ui/layout/toolbox/image.py +18 -21
  92. pygpt_net/ui/layout/toolbox/indexes.py +46 -89
  93. pygpt_net/ui/layout/toolbox/mode.py +20 -7
  94. pygpt_net/ui/layout/toolbox/model.py +12 -10
  95. pygpt_net/ui/layout/toolbox/presets.py +68 -52
  96. pygpt_net/ui/layout/toolbox/prompt.py +31 -58
  97. pygpt_net/ui/layout/toolbox/toolbox.py +25 -21
  98. pygpt_net/ui/layout/toolbox/vision.py +20 -22
  99. pygpt_net/ui/main.py +2 -4
  100. pygpt_net/ui/menu/about.py +64 -84
  101. pygpt_net/ui/menu/audio.py +87 -63
  102. pygpt_net/ui/menu/config.py +121 -127
  103. pygpt_net/ui/menu/debug.py +69 -76
  104. pygpt_net/ui/menu/file.py +32 -35
  105. pygpt_net/ui/menu/menu.py +2 -3
  106. pygpt_net/ui/menu/plugins.py +69 -33
  107. pygpt_net/ui/menu/theme.py +45 -46
  108. pygpt_net/ui/menu/tools.py +56 -60
  109. pygpt_net/ui/menu/video.py +20 -25
  110. pygpt_net/ui/tray.py +1 -2
  111. pygpt_net/ui/widget/audio/bar.py +1 -3
  112. pygpt_net/ui/widget/audio/input_button.py +3 -4
  113. pygpt_net/ui/widget/calendar/select.py +1 -2
  114. pygpt_net/ui/widget/dialog/base.py +12 -9
  115. pygpt_net/ui/widget/dialog/editor_file.py +20 -23
  116. pygpt_net/ui/widget/dialog/find.py +25 -24
  117. pygpt_net/ui/widget/dialog/profile.py +57 -53
  118. pygpt_net/ui/widget/draw/painter.py +62 -93
  119. pygpt_net/ui/widget/element/button.py +42 -30
  120. pygpt_net/ui/widget/element/checkbox.py +23 -15
  121. pygpt_net/ui/widget/element/group.py +6 -5
  122. pygpt_net/ui/widget/element/labels.py +1 -2
  123. pygpt_net/ui/widget/filesystem/explorer.py +93 -102
  124. pygpt_net/ui/widget/image/display.py +1 -2
  125. pygpt_net/ui/widget/lists/assistant.py +1 -2
  126. pygpt_net/ui/widget/lists/attachment.py +1 -2
  127. pygpt_net/ui/widget/lists/attachment_ctx.py +1 -2
  128. pygpt_net/ui/widget/lists/context.py +2 -4
  129. pygpt_net/ui/widget/lists/index.py +1 -2
  130. pygpt_net/ui/widget/lists/model.py +1 -2
  131. pygpt_net/ui/widget/lists/model_editor.py +1 -2
  132. pygpt_net/ui/widget/lists/model_importer.py +1 -2
  133. pygpt_net/ui/widget/lists/preset.py +1 -2
  134. pygpt_net/ui/widget/lists/preset_plugins.py +1 -2
  135. pygpt_net/ui/widget/lists/profile.py +1 -2
  136. pygpt_net/ui/widget/lists/uploaded.py +1 -2
  137. pygpt_net/ui/widget/option/checkbox.py +2 -4
  138. pygpt_net/ui/widget/option/checkbox_list.py +1 -4
  139. pygpt_net/ui/widget/option/cmd.py +1 -4
  140. pygpt_net/ui/widget/option/dictionary.py +25 -28
  141. pygpt_net/ui/widget/option/input.py +1 -3
  142. pygpt_net/ui/widget/tabs/Input.py +16 -12
  143. pygpt_net/ui/widget/tabs/body.py +5 -3
  144. pygpt_net/ui/widget/tabs/layout.py +41 -28
  145. pygpt_net/ui/widget/tabs/output.py +442 -85
  146. pygpt_net/ui/widget/textarea/calendar_note.py +1 -2
  147. pygpt_net/ui/widget/textarea/editor.py +41 -73
  148. pygpt_net/ui/widget/textarea/find.py +11 -10
  149. pygpt_net/ui/widget/textarea/html.py +3 -6
  150. pygpt_net/ui/widget/textarea/input.py +134 -69
  151. pygpt_net/ui/widget/textarea/notepad.py +54 -38
  152. pygpt_net/ui/widget/textarea/output.py +65 -54
  153. pygpt_net/ui/widget/textarea/search_input.py +5 -4
  154. pygpt_net/ui/widget/textarea/web.py +2 -4
  155. pygpt_net/ui/widget/vision/camera.py +2 -31
  156. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.23.dist-info}/METADATA +38 -174
  157. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.23.dist-info}/RECORD +160 -159
  158. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.23.dist-info}/LICENSE +0 -0
  159. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.23.dist-info}/WHEEL +0 -0
  160. {pygpt_net-2.6.21.dist-info → pygpt_net-2.6.23.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.16 00:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import datetime
@@ -14,13 +14,11 @@ import functools
14
14
 
15
15
  from PySide6 import QtWidgets, QtCore, QtGui
16
16
  from PySide6.QtCore import Qt, QPoint, QItemSelectionModel
17
- from PySide6.QtGui import QAction, QIcon, QColor, QPixmap, QStandardItem
17
+ from PySide6.QtGui import QIcon, QColor, QPixmap, QStandardItem
18
18
  from PySide6.QtWidgets import QMenu
19
- from overrides import overrides
20
19
 
21
20
  from pygpt_net.ui.widget.lists.base import BaseList
22
21
  from pygpt_net.utils import trans
23
- import pygpt_net.icons_rc
24
22
 
25
23
 
26
24
  class ContextList(BaseList):
@@ -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.01.31 18:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction, QIcon
@@ -14,7 +14,6 @@ from PySide6.QtWidgets import QMenu
14
14
 
15
15
  from pygpt_net.ui.widget.lists.base import BaseList
16
16
  from pygpt_net.utils import trans
17
- import pygpt_net.icons_rc
18
17
 
19
18
 
20
19
  class IndexList(BaseList):
@@ -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.01.29 14:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction, QIcon
@@ -14,7 +14,6 @@ from PySide6.QtWidgets import QMenu
14
14
 
15
15
  from pygpt_net.ui.widget.lists.base import BaseList
16
16
  from pygpt_net.utils import trans
17
- import pygpt_net.icons_rc
18
17
 
19
18
 
20
19
  class ModelList(BaseList):
@@ -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.12 19:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction, QIcon
@@ -14,7 +14,6 @@ from PySide6.QtWidgets import QMenu
14
14
 
15
15
  from pygpt_net.ui.widget.lists.base import BaseList
16
16
  from pygpt_net.utils import trans
17
- import pygpt_net.icons_rc
18
17
 
19
18
 
20
19
  class ModelEditorList(BaseList):
@@ -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
  from PySide6 import QtCore
@@ -15,7 +15,6 @@ from PySide6.QtWidgets import QWidget, QHBoxLayout, QPushButton, QVBoxLayout, QL
15
15
 
16
16
  from pygpt_net.ui.widget.lists.base import BaseList
17
17
  from pygpt_net.utils import trans
18
- import pygpt_net.icons_rc
19
18
 
20
19
  class ModelImporter(QWidget):
21
20
  def __init__(self, window=None):
@@ -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.QtCore import QPoint, QItemSelectionModel
@@ -18,7 +18,6 @@ from pygpt_net.core.types import (
18
18
  )
19
19
  from pygpt_net.ui.widget.lists.base import BaseList
20
20
  from pygpt_net.utils import trans
21
- import pygpt_net.icons_rc
22
21
 
23
22
 
24
23
  class PresetList(BaseList):
@@ -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.03.06 22:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction, QIcon
@@ -14,7 +14,6 @@ from PySide6.QtWidgets import QMenu
14
14
 
15
15
  from pygpt_net.ui.widget.lists.base import BaseList
16
16
  from pygpt_net.utils import trans
17
- import pygpt_net.icons_rc
18
17
 
19
18
 
20
19
  class PresetPluginsList(BaseList):
@@ -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.09 23:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction, QIcon
@@ -14,7 +14,6 @@ from PySide6.QtWidgets import QMenu
14
14
 
15
15
  from pygpt_net.ui.widget.lists.base import BaseList
16
16
  from pygpt_net.utils import trans
17
- import pygpt_net.icons_rc
18
17
 
19
18
 
20
19
  class ProfileList(BaseList):
@@ -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.26 23:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction, QIcon, QResizeEvent, Qt
@@ -14,7 +14,6 @@ from PySide6.QtWidgets import QMenu
14
14
 
15
15
  from pygpt_net.ui.widget.lists.base import BaseList
16
16
  from pygpt_net.utils import trans
17
- import pygpt_net.icons_rc
18
17
 
19
18
 
20
19
  class UploadedFileList(BaseList):
@@ -6,17 +6,15 @@
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.22 10:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QIcon
13
- from PySide6.QtWidgets import QCheckBox, QHBoxLayout, QWidget, QLabel
13
+ from PySide6.QtWidgets import QHBoxLayout, QWidget, QLabel
14
14
 
15
15
  from pygpt_net.ui.widget.anims.toggles import AnimToggle
16
16
  from pygpt_net.utils import trans
17
17
 
18
- import pygpt_net.icons_rc
19
-
20
18
  class OptionCheckbox(QWidget):
21
19
  def __init__(
22
20
  self,
@@ -6,17 +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: 2025.06.30 02:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
- from typing import Dict
12
11
 
13
12
  from PySide6.QtWidgets import QCheckBox, QWidget
14
13
 
15
14
  from pygpt_net.ui.base.flow_layout import FlowLayout
16
15
  from pygpt_net.utils import trans
17
16
 
18
- import pygpt_net.icons_rc
19
-
20
17
  class OptionCheckboxList(QWidget):
21
18
  def __init__(
22
19
  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: 2024.11.24 22:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QIcon
@@ -19,9 +19,6 @@ from pygpt_net.ui.widget.option.dictionary import OptionDict
19
19
  from pygpt_net.ui.widget.option.textarea import OptionTextarea
20
20
  from pygpt_net.utils import trans
21
21
 
22
- import pygpt_net.icons_rc
23
-
24
-
25
22
  class OptionCmd(QWidget):
26
23
  def __init__(
27
24
  self,
@@ -6,17 +6,15 @@
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.18 19:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt, QAbstractItemModel, QModelIndex, QSize
13
- from PySide6.QtGui import QAction, QIcon
13
+ from PySide6.QtGui import QIcon
14
14
  from PySide6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QTreeView, QMenu, QStyledItemDelegate, QComboBox, \
15
15
  QCheckBox, QHeaderView, QHBoxLayout
16
16
 
17
17
  from pygpt_net.utils import trans
18
- import pygpt_net.icons_rc
19
-
20
18
 
21
19
  class OptionDict(QWidget):
22
20
  def __init__(self, window=None, parent_id: str = None, id: str = None, option: dict = None):
@@ -112,8 +110,7 @@ class OptionDict(QWidget):
112
110
  if index.isValid():
113
111
  idx = index.row()
114
112
  data = self.model.items[idx]
115
- id = self.parent_id + "." + self.id # dictionary id
116
- self.window.ui.dialogs.open_dictionary_editor(id, self.option, data, idx)
113
+ self.window.ui.dialogs.open_dictionary_editor(f"{self.parent_id}.{self.id}", self.option, data, idx)
117
114
 
118
115
  def update_item(self, idx, data):
119
116
  """
@@ -194,20 +191,26 @@ class OptionDictItems(QTreeView):
194
191
  header.setStretchLastSection(True)
195
192
  header.setSectionResizeMode(QHeaderView.Stretch)
196
193
 
197
- # setup fields
194
+ self._icon_edit = QIcon(":/icons/edit.svg")
195
+ self._icon_delete = QIcon(":/icons/delete.svg")
196
+ self._act_edit_text = trans('action.edit')
197
+ self._act_delete_text = trans('action.delete')
198
+ self._bool_delegate = None
199
+
198
200
  keys = self.parent.keys
201
+ set_delegate_col = self.setItemDelegateForColumn
199
202
  idx = 0
200
203
  for key in keys:
201
204
  item = keys[key]
202
205
  if type(item) is dict:
203
- if "type" in item:
204
- if item["type"] == "combo":
205
- handler = ComboBoxDelegate(self, item["keys"])
206
- self.setItemDelegateForColumn(idx, handler)
206
+ t = item.get("type")
207
+ if t == "combo":
208
+ set_delegate_col(idx, ComboBoxDelegate(self, item["keys"]))
207
209
  elif type(item) is str:
208
210
  if item == "bool":
209
- handler = CheckBoxDelegate(self)
210
- self.setItemDelegateForColumn(idx, handler)
211
+ if self._bool_delegate is None:
212
+ self._bool_delegate = CheckBoxDelegate(self)
213
+ set_delegate_col(idx, self._bool_delegate)
211
214
  elif item == "hidden":
212
215
  continue
213
216
  idx += 1
@@ -218,22 +221,16 @@ class OptionDictItems(QTreeView):
218
221
 
219
222
  :param event: context menu event
220
223
  """
221
- actions = {}
222
- actions['edit'] = QAction(QIcon(":/icons/edit.svg"), trans('action.edit'), self)
223
- actions['edit'].triggered.connect(
224
- lambda: self.parent.edit_item(event))
225
- actions['delete'] = QAction(QIcon(":/icons/delete.svg"), trans('action.delete'), self)
226
- actions['delete'].triggered.connect(
227
- lambda: self.parent.delete_item(event))
228
- menu = QMenu(self)
229
- menu.addAction(actions['edit'])
230
- menu.addAction(actions['delete'])
231
-
232
- # get index of item
233
224
  item = self.indexAt(event.pos())
234
- idx = item.row()
235
- if idx >= 0:
236
- menu.exec_(event.globalPos())
225
+ if not item.isValid():
226
+ return
227
+
228
+ menu = QMenu(self)
229
+ edit_action = menu.addAction(self._icon_edit, self._act_edit_text)
230
+ delete_action = menu.addAction(self._icon_delete, self._act_delete_text)
231
+ edit_action.triggered.connect(lambda: self.parent.edit_item(event))
232
+ delete_action.triggered.connect(lambda: self.parent.delete_item(event))
233
+ menu.exec_(event.globalPos())
237
234
 
238
235
 
239
236
  class OptionDictModel(QAbstractItemModel):
@@ -6,13 +6,11 @@
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.26 23:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
- from PySide6.QtCore import Qt
13
12
  from PySide6.QtGui import QAction, QIcon
14
13
  from PySide6.QtWidgets import QLineEdit, QFileDialog
15
- import pygpt_net.icons_rc
16
14
 
17
15
 
18
16
  class OptionInputInline(QLineEdit):
@@ -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.09 23:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtWidgets import QTabWidget, QMenu
@@ -14,13 +14,17 @@ from PySide6.QtCore import Qt
14
14
  from PySide6.QtGui import QAction, QIcon
15
15
 
16
16
  from pygpt_net.utils import trans
17
- import pygpt_net.icons_rc
18
17
 
19
18
 
20
19
  class InputTabs(QTabWidget):
21
20
  def __init__(self, window=None):
22
- super(InputTabs, self).__init__(window)
21
+ super().__init__(window)
23
22
  self.window = window
23
+ self._attachments_tab_index = 1
24
+ self._context_menu = QMenu(self)
25
+ self._action_clear = QAction(QIcon(":/icons/delete.svg"), trans('attachments.btn.clear'), self)
26
+ self._action_clear.triggered.connect(self._on_clear_triggered)
27
+ self._context_menu.addAction(self._action_clear)
24
28
 
25
29
  def mousePressEvent(self, event):
26
30
  """
@@ -29,10 +33,12 @@ class InputTabs(QTabWidget):
29
33
  :param event: QMouseEvent
30
34
  """
31
35
  if event.button() == Qt.RightButton:
32
- if self.tabBar().tabAt(event.pos()) == 1: # attachments tab
36
+ tb = self.tabBar()
37
+ pos_in_tabbar = tb.mapFrom(self, event.pos())
38
+ if tb.tabAt(pos_in_tabbar) == self._attachments_tab_index:
33
39
  self.show_context_menu(event.globalPos())
34
40
 
35
- super(InputTabs, self).mousePressEvent(event)
41
+ super().mousePressEvent(event)
36
42
 
37
43
  def show_context_menu(self, global_pos):
38
44
  """
@@ -40,10 +46,8 @@ class InputTabs(QTabWidget):
40
46
 
41
47
  :param global_pos: QPoint
42
48
  """
43
- context_menu = QMenu(self)
44
- actions = {}
45
- actions['clear'] = QAction(QIcon(":/icons/delete.svg"), trans('attachments.btn.clear'), self)
46
- actions['clear'].triggered.connect(
47
- lambda: self.window.controller.attachment.clear())
48
- context_menu.addAction(actions['clear'])
49
- context_menu.exec(global_pos)
49
+ self._action_clear.setText(trans('attachments.btn.clear'))
50
+ self._context_menu.exec(global_pos)
51
+
52
+ def _on_clear_triggered(self, checked=False):
53
+ self.window.controller.attachment.clear()
@@ -6,8 +6,9 @@
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
  from typing import Any
12
13
 
13
14
  from PySide6.QtCore import QEvent
@@ -104,12 +105,13 @@ class TabBody(QTabWidget):
104
105
  :param source: source
105
106
  :param event: event
106
107
  """
107
- if (event.type() == QEvent.ChildAdded and
108
+ t = event.type()
109
+ if (t == QEvent.ChildAdded and
108
110
  source is self and
109
111
  event.child().isWidgetType()):
110
112
  self._glwidget = event.child()
111
113
  self._glwidget.installEventFilter(self)
112
- elif (event.type() == event.Type.MouseButtonPress):
114
+ elif t == event.Type.MouseButtonPress:
113
115
  # handle column focus
114
116
  if self.owner is not None:
115
117
  col_idx = self.owner.column_idx
@@ -6,9 +6,12 @@
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.13 15:00:00 #
9
+ # Updated Date: 2025.08.25 18:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ from typing import Optional
13
+ import weakref
14
+
12
15
  from PySide6.QtCore import Qt, QObject, QEvent
13
16
  from PySide6.QtWidgets import QTabWidget, QWidget, QVBoxLayout, QSplitter, QSizePolicy
14
17
 
@@ -16,7 +19,7 @@ from pygpt_net.ui.widget.tabs.output import OutputTabs
16
19
 
17
20
 
18
21
  class OutputColumn(QWidget):
19
- def __init__(self, window=None):
22
+ def __init__(self, window=None, idx: Optional[int] = None):
20
23
  """
21
24
  Output column
22
25
 
@@ -25,6 +28,8 @@ class OutputColumn(QWidget):
25
28
  super(OutputColumn, self).__init__(window)
26
29
  self.window = window
27
30
  self.idx = -1
31
+ if idx is not None:
32
+ self.idx = idx
28
33
  self.tabs = OutputTabs(self.window, column=self)
29
34
  self.layout = QVBoxLayout()
30
35
  self.layout.addWidget(self.tabs)
@@ -41,7 +46,8 @@ class OutputColumn(QWidget):
41
46
  :param widget: widget
42
47
  """
43
48
  self.window.controller.ui.tabs.on_column_focus(self.idx)
44
- widget.setFocus()
49
+ if widget is not None and not widget.hasFocus():
50
+ widget.setFocus()
45
51
 
46
52
  def set_idx(self, idx: int):
47
53
  """
@@ -88,8 +94,8 @@ class OutputLayout(QWidget):
88
94
  self.columns = []
89
95
  self._was_width_zero = None
90
96
 
91
- column1 = OutputColumn(self.window)
92
- column2 = OutputColumn(self.window)
97
+ column1 = OutputColumn(self.window, idx=0)
98
+ column2 = OutputColumn(self.window, idx=1)
93
99
  self.add_column(column1)
94
100
  self.add_column(column2)
95
101
 
@@ -112,9 +118,9 @@ class OutputLayout(QWidget):
112
118
  :param pos: Position of the splitter
113
119
  :param index: Index of the widget that was moved
114
120
  """
115
- widget = self.splitter.widget(1)
116
- if widget:
117
- current_width = widget.width()
121
+ if self.splitter.count() > 1:
122
+ sizes = self.splitter.sizes()
123
+ current_width = sizes[1] if len(sizes) > 1 else 0
118
124
  if current_width == 0:
119
125
  if self._was_width_zero is not True:
120
126
  self._was_width_zero = True
@@ -142,17 +148,15 @@ class OutputLayout(QWidget):
142
148
  column.set_idx(idx)
143
149
  self.columns.append(column)
144
150
 
145
- def get_tabs_by_idx(self, idx: int) -> OutputTabs:
151
+ def get_tabs_by_idx(self, idx: int) -> Optional[OutputTabs]:
146
152
  """
147
153
  Get tabs by column index
148
154
 
149
155
  :param idx: int
150
156
  :return: OutputTabs
151
157
  """
152
- for column in self.columns:
153
- if column.idx == idx:
154
- return column.tabs
155
- return None
158
+ column = self.get_column_by_idx(idx)
159
+ return column.tabs if column is not None else None
156
160
 
157
161
  def get_active_tabs(self) -> OutputTabs:
158
162
  """
@@ -161,17 +165,21 @@ class OutputLayout(QWidget):
161
165
  :return: OutputTabs
162
166
  """
163
167
  current = self.window.controller.ui.tabs.get_current_column_idx()
164
- for column in self.columns:
165
- if column.idx == current:
166
- return column.tabs
168
+ column = self.get_column_by_idx(current)
169
+ if column is not None:
170
+ return column.tabs
167
171
 
168
- def get_column_by_idx(self, idx: int) -> OutputColumn:
172
+ def get_column_by_idx(self, idx: int) -> Optional[OutputColumn]:
169
173
  """
170
174
  Get column by index
171
175
 
172
176
  :param idx: int
173
177
  :return: OutputColumn
174
178
  """
179
+ if 0 <= idx < len(self.columns):
180
+ column = self.columns[idx]
181
+ if column.idx == idx:
182
+ return column
175
183
  for column in self.columns:
176
184
  if column.idx == idx:
177
185
  return column
@@ -184,9 +192,8 @@ class OutputLayout(QWidget):
184
192
  :return: OutputColumn
185
193
  """
186
194
  current = self.window.controller.ui.tabs.get_current_column_idx()
187
- for column in self.columns:
188
- if column.idx == current:
189
- return column
195
+ return self.get_column_by_idx(current)
196
+
190
197
 
191
198
  class FocusEventFilter(QObject):
192
199
  def __init__(self, column, callback):
@@ -196,9 +203,9 @@ class FocusEventFilter(QObject):
196
203
  :param column: parent column
197
204
  :param callback: callback
198
205
  """
199
- super().__init__()
200
- self.column = column
201
- self.callback = callback
206
+ super().__init__(column)
207
+ self._column_ref = weakref.ref(column)
208
+ self._callback = weakref.WeakMethod(callback) if hasattr(callback, "__self__") and callback.__self__ is not None else callback
202
209
 
203
210
  def eventFilter(self, obj, event):
204
211
  """
@@ -207,9 +214,15 @@ class FocusEventFilter(QObject):
207
214
  :param obj: object
208
215
  :param event: event
209
216
  """
210
- if event.type() == QEvent.MouseButtonPress or event.type() == QEvent.FocusIn:
211
- widget = obj
212
- if widget is not None:
213
- self.callback(widget)
217
+ t = event.type()
218
+ if t in (QEvent.MouseButtonPress, QEvent.FocusIn):
219
+ col = self._column_ref()
220
+ if col is not None:
221
+ if isinstance(self._callback, weakref.WeakMethod):
222
+ cb = self._callback()
223
+ else:
224
+ cb = self._callback
225
+ if cb is not None:
226
+ cb(obj)
214
227
  return False
215
- return False
228
+ return False