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.11.26 02:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -19,8 +19,6 @@ from pygpt_net.ui.widget.element.labels import HelpLabel
19
19
  from pygpt_net.ui.widget.lists.attachment_ctx import AttachmentCtxList
20
20
  from pygpt_net.utils import trans
21
21
 
22
- import pygpt_net.icons_rc
23
-
24
22
  class AttachmentsCtx:
25
23
  def __init__(self, window=None):
26
24
  """
@@ -65,11 +63,9 @@ class AttachmentsCtx:
65
63
  self.window.controller.chat.attachment.MODE_DISABLED
66
64
  ))
67
65
 
68
- # buttons layout
69
66
  buttons_layout = QHBoxLayout()
70
67
  buttons_layout.addWidget(self.window.ui.nodes['attachments_ctx.btn.clear'])
71
68
  buttons_layout.addWidget(empty_widget)
72
- # buttons_layout.addStretch()
73
69
  buttons_layout.addWidget(self.window.ui.nodes['input.attachments.ctx.mode.label'])
74
70
  buttons_layout.addWidget(self.window.ui.nodes['input.attachments.ctx.mode.full'])
75
71
  buttons_layout.addWidget(self.window.ui.nodes['input.attachments.ctx.mode.query'])
@@ -77,7 +73,6 @@ class AttachmentsCtx:
77
73
  buttons_layout.addWidget(self.window.ui.nodes['input.attachments.ctx.mode.off'])
78
74
  buttons_layout.addStretch()
79
75
 
80
- # layout
81
76
  layout = QVBoxLayout()
82
77
  layout.addWidget(self.window.ui.nodes['tip.input.attachments.ctx'])
83
78
  layout.addWidget(self.window.ui.nodes['attachments_ctx'])
@@ -87,16 +82,14 @@ class AttachmentsCtx:
87
82
 
88
83
  def setup_attachments(self):
89
84
  """Setup attachments uploaded list"""
90
- # attachments
91
85
  self.window.ui.nodes[self.id] = AttachmentCtxList(self.window)
92
86
 
93
- # buttons
94
87
  self.window.ui.nodes['attachments_ctx.btn.clear'] = QPushButton(QIcon(":/icons/close.svg"), trans('attachments_uploaded.btn.clear'))
95
88
  self.window.ui.nodes['attachments_ctx.btn.clear'].clicked.connect(
96
89
  lambda: self.window.controller.chat.attachment.clear()
97
90
  )
98
91
 
99
- self.window.ui.models[self.id] = self.create_model(self.window)
92
+ self.window.ui.models[self.id] = self.create_model(self.window.ui.nodes[self.id])
100
93
  self.window.ui.nodes[self.id].setModel(self.window.ui.models[self.id])
101
94
 
102
95
  def create_model(self, parent) -> QStandardItemModel:
@@ -120,43 +113,46 @@ class AttachmentsCtx:
120
113
 
121
114
  :param data: Data to update
122
115
  """
123
- self.window.ui.models[self.id].removeRows(0, self.window.ui.models[self.id].rowCount())
124
- i = 0
125
- for item in data:
126
- indexed = False
127
- name = "No name"
128
- if 'name' in item:
129
- name = item['name']
130
- size = "-"
131
- path = "No path"
132
- if 'path' in item:
133
- path = item['path']
134
- uuid = ""
135
- if 'uuid' in item:
136
- uuid = item['uuid']
116
+ model = self.window.ui.models[self.id]
117
+ row_count = len(data)
118
+ model.beginResetModel()
119
+ model.setRowCount(row_count)
120
+
121
+ m_index = model.index
122
+ m_setData = model.setData
123
+ tooltip_role = QtCore.Qt.ToolTipRole
124
+ trans_indexed = trans("attachments.ctx.indexed")
125
+ sizeof_fmt = self.window.core.filesystem.sizeof_fmt
126
+ stat = os.stat
127
+
128
+ for i, item in enumerate(data):
129
+ name = item.get('name', "No name")
130
+ path = item.get('path', "No path")
131
+ uuid = item.get('uuid', "")
137
132
  length = "-"
138
133
  if 'length' in item:
139
134
  length = str(item['length'])
140
135
  if 'tokens' in item:
141
136
  length += ' / ~' + str(item['tokens'])
142
- if 'indexed' in item and item['indexed']:
143
- indexed = True
144
-
145
- idx_str = ""
146
- if indexed:
147
- idx_str = trans("attachments.ctx.indexed")
148
-
149
- if os.path.exists(path):
150
- size = self.window.core.filesystem.sizeof_fmt(os.path.getsize(path))
151
- elif 'size' in item:
152
- size = self.window.core.filesystem.sizeof_fmt(item['size'])
153
-
154
- self.window.ui.models[self.id].insertRow(i)
155
- index = self.window.ui.models[self.id].index(i, 0)
156
- self.window.ui.models[self.id].setData(index, "uuid: " + str(uuid), QtCore.Qt.ToolTipRole)
157
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 0), name)
158
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 1), path)
159
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 2), size)
160
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 3), length)
161
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 4), idx_str)
162
- i += 1
137
+ idx_str = trans_indexed if item.get('indexed') else ""
138
+
139
+ size = "-"
140
+ if isinstance(path, str):
141
+ try:
142
+ st = stat(path)
143
+ except (OSError, ValueError, TypeError):
144
+ pass
145
+ else:
146
+ size = sizeof_fmt(st.st_size)
147
+ if size == "-" and 'size' in item:
148
+ size = sizeof_fmt(item['size'])
149
+
150
+ idx0 = m_index(i, 0)
151
+ m_setData(idx0, "uuid: " + str(uuid), tooltip_role)
152
+ m_setData(idx0, name)
153
+ m_setData(m_index(i, 1), path)
154
+ m_setData(m_index(i, 2), size)
155
+ m_setData(m_index(i, 3), length)
156
+ m_setData(m_index(i, 4), idx_str)
157
+
158
+ model.endResetModel()
@@ -6,22 +6,20 @@
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.29 16:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
13
 
14
14
  from PySide6 import QtCore
15
15
  from PySide6.QtGui import QStandardItemModel, Qt, QIcon
16
- from PySide6.QtWidgets import QVBoxLayout, QPushButton, QHBoxLayout, QCheckBox, QLabel, QWidget
16
+ from PySide6.QtWidgets import QVBoxLayout, QPushButton, QHBoxLayout, QWidget
17
17
 
18
18
  from pygpt_net.ui.widget.element.button import SyncButton
19
19
  from pygpt_net.ui.widget.element.labels import HelpLabel
20
20
  from pygpt_net.ui.widget.lists.uploaded import UploadedFileList
21
21
  from pygpt_net.utils import trans
22
22
 
23
- import pygpt_net.icons_rc
24
-
25
23
  class AttachmentsUploaded:
26
24
  def __init__(self, window=None):
27
25
  """
@@ -39,16 +37,15 @@ class AttachmentsUploaded:
39
37
  :return: QVBoxLayout
40
38
  """
41
39
  self.setup_attachments()
42
- empty_widget = QWidget()
40
+ empty_widget = QWidget(self.window)
43
41
 
44
- self.window.ui.nodes['attachments_uploaded.sync.tip'] = HelpLabel(trans('attachments_uploaded.sync.tip'))
42
+ self.window.ui.nodes['attachments_uploaded.sync.tip'] = HelpLabel(trans('attachments_uploaded.sync.tip'), self.window)
45
43
  self.window.ui.nodes['attachments_uploaded.sync.tip'].setWordWrap(False)
46
44
  self.window.ui.nodes['attachments_uploaded.sync.tip'].setAlignment(Qt.AlignCenter)
47
45
 
48
46
  self.window.ui.nodes['tip.input.attachments.uploaded'] = HelpLabel(trans('tip.input.attachments.uploaded'),
49
47
  self.window)
50
48
 
51
- # buttons layout
52
49
  buttons_layout = QHBoxLayout()
53
50
  buttons_layout.addWidget(self.window.ui.nodes['attachments_uploaded.btn.sync'])
54
51
  buttons_layout.addWidget(self.window.ui.nodes['attachments_uploaded.btn.clear'])
@@ -56,8 +53,6 @@ class AttachmentsUploaded:
56
53
  buttons_layout.addWidget(self.window.ui.nodes['attachments_uploaded.sync.tip'])
57
54
  buttons_layout.addStretch()
58
55
 
59
-
60
- # layout
61
56
  layout = QVBoxLayout()
62
57
  layout.addWidget(self.window.ui.nodes['tip.input.attachments.uploaded'])
63
58
  layout.addWidget(self.window.ui.nodes['attachments_uploaded'])
@@ -69,10 +64,8 @@ class AttachmentsUploaded:
69
64
  """
70
65
  Setup attachments uploaded list
71
66
  """
72
- # attachments
73
67
  self.window.ui.nodes[self.id] = UploadedFileList(self.window)
74
68
 
75
- # buttons
76
69
  self.window.ui.nodes['attachments_uploaded.btn.sync'] = SyncButton(trans('attachments_uploaded.btn.sync'), self.window)
77
70
  self.window.ui.nodes['attachments_uploaded.btn.clear'] = QPushButton(QIcon(":/icons/close.svg"), trans('attachments_uploaded.btn.clear'))
78
71
  self.window.ui.nodes['attachments_uploaded.btn.clear'].clicked.connect(
@@ -102,32 +95,36 @@ class AttachmentsUploaded:
102
95
 
103
96
  :param data: Data to update
104
97
  """
98
+ model = self.window.ui.models[self.id]
105
99
  store_names = self.window.core.assistants.store.get_names()
106
- self.window.ui.models[self.id].removeRows(0, self.window.ui.models[self.id].rowCount())
107
- i = 0
108
- for id in data:
109
- item = data[id]
110
- size = "-"
111
- path = item.path
112
-
113
- # size
114
- if item.size is not None:
115
- size = self.window.core.filesystem.sizeof_fmt(item.size)
116
- else:
117
- if path and os.path.exists(path):
118
- size = self.window.core.filesystem.sizeof_fmt(os.path.getsize(path))
119
-
120
- # vector stores
121
- if item.store_id is not None and item.store_id in store_names:
122
- vector_store = store_names[item.store_id]
123
- else:
124
- vector_store = trans("assistant.store.thread_only")
125
-
126
- self.window.ui.models[self.id].insertRow(i)
127
- index = self.window.ui.models[self.id].index(i, 0)
128
- self.window.ui.models[self.id].setData(index, "file_id: " + str(item.file_id), QtCore.Qt.ToolTipRole)
129
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 0), item.name)
130
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 1), path)
131
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 2), size)
132
- self.window.ui.models[self.id].setData(self.window.ui.models[self.id].index(i, 3), vector_store)
133
- i += 1
100
+ thread_only_label = trans("assistant.store.thread_only")
101
+ fs = self.window.core.filesystem
102
+
103
+ model.beginResetModel()
104
+ model.setRowCount(0)
105
+ count = len(data)
106
+ if count:
107
+ model.setRowCount(count)
108
+ for i, item in enumerate(data.values()):
109
+ path = item.path
110
+ if item.size is not None:
111
+ size_str = fs.sizeof_fmt(item.size)
112
+ else:
113
+ size_str = "-"
114
+ if path:
115
+ try:
116
+ st = os.stat(path)
117
+ except OSError:
118
+ pass
119
+ else:
120
+ size_str = fs.sizeof_fmt(st.st_size)
121
+
122
+ store_name = store_names.get(item.store_id, thread_only_label)
123
+
124
+ idx0 = model.index(i, 0)
125
+ model.setData(idx0, item.name)
126
+ model.setData(idx0, f"file_id: {item.file_id}", QtCore.Qt.ToolTipRole)
127
+ model.setData(model.index(i, 1), path)
128
+ model.setData(model.index(i, 2), size_str)
129
+ model.setData(model.index(i, 3), store_name)
130
+ model.endResetModel()
@@ -6,11 +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: 2025.01.19 02:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt
13
- from PySide6.QtWidgets import QVBoxLayout, QLabel, QHBoxLayout, QWidget, QSplitter, QSizePolicy, QRadioButton, QCheckBox
13
+ from PySide6.QtWidgets import QVBoxLayout, QLabel, QHBoxLayout, QWidget, QSplitter, QSizePolicy, QRadioButton, QCheckBox, QButtonGroup
14
14
 
15
15
  from pygpt_net.ui.widget.calendar.select import CalendarSelect
16
16
  from pygpt_net.ui.widget.element.checkbox import ColorCheckbox
@@ -20,6 +20,8 @@ from pygpt_net.utils import trans
20
20
 
21
21
 
22
22
  class Calendar:
23
+ __slots__ = ('window',)
24
+
23
25
  def __init__(self, window=None):
24
26
  """
25
27
  Calendar UI
@@ -34,8 +36,11 @@ class Calendar:
34
36
 
35
37
  :return: QWidget
36
38
  """
37
- self.window.ui.calendar['select'] = CalendarSelect(self.window)
38
- self.window.ui.calendar['note'] = CalendarNote(self.window)
39
+ ui = self.window.ui
40
+ ui.calendar['select'] = CalendarSelect(self.window)
41
+ ui.calendar['select'].setMinimumSize(200, 200)
42
+ ui.calendar['select'].setGridVisible(True)
43
+ ui.calendar['note'] = CalendarNote(self.window)
39
44
 
40
45
  def setup(self) -> QWidget:
41
46
  """
@@ -49,58 +54,76 @@ class Calendar:
49
54
  body.append(self.window.ui.calendar['select'])
50
55
  return body
51
56
 
57
+ def _on_filter_id_clicked(self, id_: int) -> None:
58
+ key = "all" if id_ == 0 else ("pinned" if id_ == 1 else "indexed")
59
+ self.window.controller.ctx.common.toggle_display_filter(key)
60
+
61
+ def _on_counters_all_toggled(self, checked: bool) -> None:
62
+ self.window.controller.calendar.note.toggle_counters_all(checked)
63
+
52
64
  def setup_filters(self) -> QWidget:
53
65
  """
54
66
  Setup calendar filters
55
67
 
56
68
  :return: QWidget
57
69
  """
58
- self.window.ui.nodes['filter.ctx.label'] = QLabel(trans("filter.ctx.label"))
59
-
60
- # display: all
61
- self.window.ui.nodes['filter.ctx.radio.all'] = QRadioButton(trans("filter.ctx.radio.all"))
62
- self.window.ui.nodes['filter.ctx.radio.all'].clicked.connect(
63
- lambda: self.window.controller.ctx.common.toggle_display_filter("all"))
64
-
65
- # display: only pinned
66
- self.window.ui.nodes['filter.ctx.radio.pinned'] = QRadioButton(trans("filter.ctx.radio.pinned"))
67
- self.window.ui.nodes['filter.ctx.radio.pinned'].clicked.connect(
68
- lambda: self.window.controller.ctx.common.toggle_display_filter("pinned"))
69
-
70
- # display: only indexed
71
- self.window.ui.nodes['filter.ctx.radio.indexed'] = QRadioButton(trans("filter.ctx.radio.indexed"))
72
- self.window.ui.nodes['filter.ctx.radio.indexed'].clicked.connect(
73
- lambda: self.window.controller.ctx.common.toggle_display_filter("indexed"))
74
-
75
- # all counters
76
- self.window.ui.nodes['filter.ctx.counters.all'] = QCheckBox(trans("filter.ctx.counters.all"))
77
- self.window.ui.nodes['filter.ctx.counters.all'].stateChanged.connect(
78
- lambda: self.window.controller.calendar.note.toggle_counters_all(
79
- self.window.ui.nodes['filter.ctx.counters.all'].isChecked())
80
- )
81
- if self.window.core.config.get("ctx.counters.all"):
82
- self.window.ui.nodes['filter.ctx.counters.all'].setChecked(True)
70
+ ui = self.window.ui
71
+ nodes = ui.nodes
72
+
73
+ label_existing = nodes.get('filter.ctx.label')
74
+ if label_existing is None:
75
+ layout = QHBoxLayout()
76
+ widget = QWidget()
77
+ rows = QVBoxLayout()
78
+ widget.setLayout(rows)
79
+
80
+ label = QLabel(trans("filter.ctx.label"), widget)
81
+
82
+ radio_all = QRadioButton(trans("filter.ctx.radio.all"), widget)
83
+ radio_pinned = QRadioButton(trans("filter.ctx.radio.pinned"), widget)
84
+ radio_indexed = QRadioButton(trans("filter.ctx.radio.indexed"), widget)
85
+
86
+ counters_all = QCheckBox(trans("filter.ctx.counters.all"), widget)
87
+
88
+ layout.addWidget(label)
89
+ layout.addWidget(radio_all)
90
+ layout.addWidget(radio_pinned)
91
+ layout.addWidget(radio_indexed)
92
+ layout.addWidget(counters_all)
93
+ layout.addStretch()
94
+
95
+ nodes['filter.ctx.labels'] = ColorCheckbox(self.window)
96
+
97
+ rows.addLayout(layout)
98
+ rows.addWidget(nodes['filter.ctx.labels'])
99
+
100
+ group = QButtonGroup(widget)
101
+ group.setExclusive(True)
102
+ group.addButton(radio_all, 0)
103
+ group.addButton(radio_pinned, 1)
104
+ group.addButton(radio_indexed, 2)
105
+ group.idClicked.connect(self._on_filter_id_clicked)
106
+
107
+ counters_all.toggled.connect(self._on_counters_all_toggled)
108
+
109
+ nodes['filter.ctx.label'] = label
110
+ nodes['filter.ctx.radio.all'] = radio_all
111
+ nodes['filter.ctx.radio.pinned'] = radio_pinned
112
+ nodes['filter.ctx.radio.indexed'] = radio_indexed
113
+ nodes['filter.ctx.counters.all'] = counters_all
83
114
  else:
84
- self.window.ui.nodes['filter.ctx.counters.all'].setChecked(False)
85
-
86
- # layout
87
- layout = QHBoxLayout()
88
- layout.addWidget(self.window.ui.nodes['filter.ctx.label'])
89
- layout.addWidget(self.window.ui.nodes['filter.ctx.radio.all'])
90
- layout.addWidget(self.window.ui.nodes['filter.ctx.radio.pinned'])
91
- layout.addWidget(self.window.ui.nodes['filter.ctx.radio.indexed'])
92
- layout.addWidget(self.window.ui.nodes['filter.ctx.counters.all'])
93
- layout.addStretch()
94
-
95
- self.window.ui.nodes['filter.ctx.labels'] = ColorCheckbox(self.window)
96
-
97
- rows = QVBoxLayout()
98
- rows.addLayout(layout)
99
- rows.addWidget(self.window.ui.nodes['filter.ctx.labels'])
100
-
101
- widget = QWidget()
102
- widget.setLayout(rows)
103
-
115
+ widget = nodes['filter.ctx.label'].parentWidget()
116
+ nodes['filter.ctx.label'].setText(trans("filter.ctx.label"))
117
+ nodes['filter.ctx.radio.all'].setText(trans("filter.ctx.radio.all"))
118
+ nodes['filter.ctx.radio.pinned'].setText(trans("filter.ctx.radio.pinned"))
119
+ nodes['filter.ctx.radio.indexed'].setText(trans("filter.ctx.radio.indexed"))
120
+ nodes['filter.ctx.counters.all'].setText(trans("filter.ctx.counters.all"))
121
+
122
+ desired = bool(self.window.core.config.get("ctx.counters.all"))
123
+ if nodes['filter.ctx.counters.all'].isChecked() != desired:
124
+ nodes['filter.ctx.counters.all'].setChecked(desired)
125
+
126
+ widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
104
127
  return widget
105
128
 
106
129
  def setup_calendar(self) -> QWidget:
@@ -109,22 +132,32 @@ class Calendar:
109
132
 
110
133
  :return: QSplitter
111
134
  """
112
- # calendar
135
+ ui = self.window.ui
136
+ nodes = ui.nodes
137
+ calendar = ui.calendar
138
+
113
139
  select_layout = QVBoxLayout()
114
- self.window.ui.calendar['select'].setMinimumHeight(200)
115
- self.window.ui.calendar['select'].setMinimumWidth(200)
116
- self.window.ui.calendar['select'].setGridVisible(True)
117
- select_layout.addWidget(self.window.ui.calendar['select'])
140
+ select_layout.addWidget(calendar['select'])
118
141
  select_layout.setContentsMargins(5, 0, 5, 0)
119
142
 
120
- self.window.ui.nodes['tip.output.tab.calendar'] = HelpLabel(trans('tip.output.tab.calendar'), self.window)
143
+ tip = nodes.get('tip.output.tab.calendar')
144
+ if tip is None:
145
+ tip = HelpLabel(trans('tip.output.tab.calendar'), self.window)
146
+ nodes['tip.output.tab.calendar'] = tip
147
+ else:
148
+ tip.setText(trans('tip.output.tab.calendar'))
149
+
150
+ note_label = calendar.get('note.label')
151
+ if note_label is None:
152
+ note_label = QLabel(trans('calendar.note.label'))
153
+ calendar['note.label'] = note_label
154
+ else:
155
+ note_label.setText(trans('calendar.note.label'))
121
156
 
122
- # note
123
- self.window.ui.calendar['note.label'] = QLabel(trans('calendar.note.label'))
124
157
  layout = QVBoxLayout()
125
- layout.addWidget(self.window.ui.calendar['note.label'])
126
- layout.addWidget(self.window.ui.calendar['note'])
127
- layout.addWidget(self.window.ui.nodes['tip.output.tab.calendar'])
158
+ layout.addWidget(note_label)
159
+ layout.addWidget(calendar['note'])
160
+ layout.addWidget(tip)
128
161
  layout.setContentsMargins(0, 0, 0, 0)
129
162
 
130
163
  widget = QWidget()
@@ -136,16 +169,13 @@ class Calendar:
136
169
  select_widget = QWidget()
137
170
  select_widget.setLayout(select_layout)
138
171
 
139
- # layout / splitter
140
- self.window.ui.splitters['calendar'] = QSplitter(Qt.Horizontal)
141
- self.window.ui.splitters['calendar'].addWidget(select_widget)
142
- self.window.ui.splitters['calendar'].addWidget(widget)
143
- self.window.ui.splitters['calendar'].setStretchFactor(0, 6) # 60%
144
- self.window.ui.splitters['calendar'].setStretchFactor(1, 4) # 40%
172
+ ui.splitters['calendar'] = QSplitter(Qt.Horizontal)
173
+ ui.splitters['calendar'].addWidget(select_widget)
174
+ ui.splitters['calendar'].addWidget(widget)
175
+ ui.splitters['calendar'].setStretchFactor(0, 6)
176
+ ui.splitters['calendar'].setStretchFactor(1, 4)
145
177
 
146
- self.window.ui.splitters['calendar'].setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
178
+ ui.splitters['calendar'].setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
147
179
  filters.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
148
180
 
149
- # build tab body
150
- return self.window.core.tabs.from_widget(self.window.ui.splitters['calendar'])
151
-
181
+ return self.window.core.tabs.from_widget(ui.splitters['calendar'])
@@ -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: 2024.11.17 03:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
- from PySide6.QtCore import Qt
12
+ from PySide6.QtCore import Qt, Slot
13
13
  from PySide6.QtWidgets import QSplitter
14
14
 
15
15
  from pygpt_net.ui.layout.chat.input import Input
@@ -34,28 +34,34 @@ class ChatMain:
34
34
  :return: QSplitter
35
35
  :rtype: QSplitter
36
36
  """
37
- input = self.input.setup()
38
- output = self.output.setup()
37
+ input_widget = self.input.setup()
38
+ output_widget = self.output.setup()
39
39
 
40
- # main vertical splitter
41
- self.window.ui.splitters['main.output'] = QSplitter(Qt.Vertical)
42
- self.window.ui.splitters['main.output'].addWidget(output)
43
- self.window.ui.splitters['main.output'].addWidget(input)
44
- self.window.ui.splitters['main.output'].setStretchFactor(0, 9) # Output widget stretch factor
45
- self.window.ui.splitters['main.output'].setStretchFactor(1, 1) # Input widget stretch factor
46
- self.window.ui.splitters['main.output'].splitterMoved.connect(self.on_splitter_moved)
47
- self.window.controller.ui.splitter_output_size_input = self.window.ui.splitters['main.output'].sizes()
40
+ splitter = QSplitter(Qt.Vertical)
41
+ self.window.ui.splitters['main.output'] = splitter
42
+ splitter.addWidget(output_widget)
43
+ splitter.addWidget(input_widget)
44
+ splitter.setStretchFactor(0, 9) # Output widget stretch factor
45
+ splitter.setStretchFactor(1, 1) # Input widget stretch factor
46
+ splitter.splitterMoved.connect(self.on_splitter_moved)
47
+ self.window.controller.ui.splitter_output_size_input = splitter.sizes()
48
48
 
49
- return self.window.ui.splitters['main.output']
49
+ return splitter
50
50
 
51
+ @Slot(int, int)
51
52
  def on_splitter_moved(self, pos, index):
52
53
  """
53
54
  Store the size of the output splitter when it is moved
54
55
  """
55
- if "input" not in self.window.ui.tabs:
56
+ tabs = self.window.ui.tabs
57
+ if "input" not in tabs:
56
58
  return
57
- idx = self.window.ui.tabs['input'].currentIndex()
59
+ splitter = self.window.ui.splitters.get('main.output')
60
+ if splitter is None:
61
+ return
62
+ idx = tabs['input'].currentIndex()
63
+ sizes = splitter.sizes()
58
64
  if idx != 0:
59
- self.window.controller.ui.splitter_output_size_files = self.window.ui.splitters['main.output'].sizes()
65
+ self.window.controller.ui.splitter_output_size_files = sizes
60
66
  else:
61
- self.window.controller.ui.splitter_output_size_input = self.window.ui.splitters['main.output'].sizes()
67
+ self.window.controller.ui.splitter_output_size_input = sizes