pygpt-net 2.6.20__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 (221) hide show
  1. pygpt_net/CHANGELOG.txt +13 -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/agent.py +130 -2
  7. pygpt_net/controller/agent/experts.py +93 -96
  8. pygpt_net/controller/agent/llama.py +2 -1
  9. pygpt_net/controller/assistant/assistant.py +18 -1
  10. pygpt_net/controller/assistant/batch.py +2 -3
  11. pygpt_net/controller/assistant/editor.py +2 -2
  12. pygpt_net/controller/assistant/files.py +2 -3
  13. pygpt_net/controller/assistant/store.py +2 -2
  14. pygpt_net/controller/attachment/attachment.py +17 -1
  15. pygpt_net/controller/audio/audio.py +2 -2
  16. pygpt_net/controller/camera/camera.py +15 -7
  17. pygpt_net/controller/chat/chat.py +2 -2
  18. pygpt_net/controller/chat/common.py +50 -33
  19. pygpt_net/controller/chat/image.py +67 -77
  20. pygpt_net/controller/chat/input.py +94 -166
  21. pygpt_net/controller/chat/output.py +83 -140
  22. pygpt_net/controller/chat/response.py +83 -102
  23. pygpt_net/controller/chat/text.py +116 -149
  24. pygpt_net/controller/ctx/common.py +2 -1
  25. pygpt_net/controller/ctx/ctx.py +87 -6
  26. pygpt_net/controller/files/files.py +13 -1
  27. pygpt_net/controller/idx/idx.py +26 -2
  28. pygpt_net/controller/idx/indexer.py +85 -76
  29. pygpt_net/controller/kernel/reply.py +53 -66
  30. pygpt_net/controller/kernel/stack.py +16 -16
  31. pygpt_net/controller/lang/lang.py +52 -34
  32. pygpt_net/controller/model/importer.py +3 -2
  33. pygpt_net/controller/model/model.py +62 -3
  34. pygpt_net/controller/notepad/notepad.py +86 -84
  35. pygpt_net/controller/plugins/settings.py +3 -4
  36. pygpt_net/controller/settings/editor.py +4 -4
  37. pygpt_net/controller/settings/profile.py +105 -124
  38. pygpt_net/controller/theme/menu.py +154 -57
  39. pygpt_net/controller/theme/nodes.py +51 -44
  40. pygpt_net/controller/theme/theme.py +33 -9
  41. pygpt_net/controller/tools/tools.py +2 -2
  42. pygpt_net/controller/ui/tabs.py +2 -3
  43. pygpt_net/controller/ui/ui.py +16 -2
  44. pygpt_net/core/agents/observer/evaluation.py +3 -3
  45. pygpt_net/core/agents/provider.py +25 -3
  46. pygpt_net/core/agents/runner.py +4 -1
  47. pygpt_net/core/agents/runners/llama_workflow.py +19 -7
  48. pygpt_net/core/agents/runners/loop.py +3 -1
  49. pygpt_net/core/agents/runners/openai_workflow.py +17 -3
  50. pygpt_net/core/agents/tools.py +4 -1
  51. pygpt_net/core/bridge/context.py +34 -37
  52. pygpt_net/core/ctx/container.py +13 -12
  53. pygpt_net/core/ctx/ctx.py +1 -1
  54. pygpt_net/core/ctx/output.py +7 -4
  55. pygpt_net/core/db/database.py +2 -2
  56. pygpt_net/core/debug/console/console.py +2 -2
  57. pygpt_net/core/debug/debug.py +12 -1
  58. pygpt_net/core/dispatcher/dispatcher.py +24 -1
  59. pygpt_net/core/events/app.py +7 -7
  60. pygpt_net/core/events/control.py +26 -26
  61. pygpt_net/core/events/event.py +6 -3
  62. pygpt_net/core/events/kernel.py +2 -2
  63. pygpt_net/core/events/render.py +13 -13
  64. pygpt_net/core/experts/experts.py +76 -82
  65. pygpt_net/core/experts/worker.py +12 -12
  66. pygpt_net/core/filesystem/actions.py +1 -2
  67. pygpt_net/core/models/models.py +5 -1
  68. pygpt_net/core/models/ollama.py +14 -5
  69. pygpt_net/core/render/plain/helpers.py +2 -5
  70. pygpt_net/core/render/plain/renderer.py +26 -30
  71. pygpt_net/core/render/web/body.py +1 -1
  72. pygpt_net/core/render/web/helpers.py +2 -2
  73. pygpt_net/core/render/web/renderer.py +4 -4
  74. pygpt_net/core/settings/settings.py +43 -13
  75. pygpt_net/core/tabs/tabs.py +20 -13
  76. pygpt_net/core/types/__init__.py +2 -1
  77. pygpt_net/core/types/agent.py +4 -4
  78. pygpt_net/core/types/base.py +19 -0
  79. pygpt_net/core/types/console.py +6 -6
  80. pygpt_net/core/types/mode.py +8 -8
  81. pygpt_net/core/types/multimodal.py +3 -3
  82. pygpt_net/core/types/openai.py +2 -1
  83. pygpt_net/data/config/config.json +5 -5
  84. pygpt_net/data/config/models.json +19 -3
  85. pygpt_net/data/config/settings.json +14 -14
  86. pygpt_net/data/locale/locale.de.ini +4 -1
  87. pygpt_net/data/locale/locale.en.ini +6 -3
  88. pygpt_net/data/locale/locale.es.ini +4 -1
  89. pygpt_net/data/locale/locale.fr.ini +4 -1
  90. pygpt_net/data/locale/locale.it.ini +4 -1
  91. pygpt_net/data/locale/locale.pl.ini +5 -4
  92. pygpt_net/data/locale/locale.uk.ini +4 -1
  93. pygpt_net/data/locale/locale.zh.ini +4 -1
  94. pygpt_net/item/ctx.py +256 -240
  95. pygpt_net/item/model.py +59 -116
  96. pygpt_net/item/preset.py +122 -105
  97. pygpt_net/plugin/twitter/plugin.py +2 -2
  98. pygpt_net/provider/agents/llama_index/workflow/planner.py +3 -3
  99. pygpt_net/provider/agents/openai/agent.py +4 -12
  100. pygpt_net/provider/agents/openai/agent_b2b.py +10 -15
  101. pygpt_net/provider/agents/openai/agent_planner.py +4 -4
  102. pygpt_net/provider/agents/openai/agent_with_experts.py +3 -7
  103. pygpt_net/provider/agents/openai/agent_with_experts_feedback.py +4 -8
  104. pygpt_net/provider/agents/openai/agent_with_feedback.py +4 -8
  105. pygpt_net/provider/agents/openai/bot_researcher.py +2 -18
  106. pygpt_net/provider/agents/openai/bots/__init__.py +0 -0
  107. pygpt_net/provider/agents/openai/bots/research_bot/__init__.py +0 -0
  108. pygpt_net/provider/agents/openai/bots/research_bot/agents/__init__.py +0 -0
  109. pygpt_net/provider/agents/openai/bots/research_bot/agents/planner_agent.py +1 -1
  110. pygpt_net/provider/agents/openai/bots/research_bot/agents/search_agent.py +1 -0
  111. pygpt_net/provider/agents/openai/bots/research_bot/agents/writer_agent.py +1 -1
  112. pygpt_net/provider/agents/openai/bots/research_bot/manager.py +1 -10
  113. pygpt_net/provider/agents/openai/evolve.py +5 -9
  114. pygpt_net/provider/agents/openai/supervisor.py +4 -8
  115. pygpt_net/provider/core/config/patch.py +10 -3
  116. pygpt_net/provider/core/ctx/db_sqlite/utils.py +43 -43
  117. pygpt_net/provider/core/model/patch.py +11 -1
  118. pygpt_net/provider/core/preset/json_file.py +47 -49
  119. pygpt_net/provider/gpt/agents/experts.py +2 -2
  120. pygpt_net/tools/audio_transcriber/ui/dialogs.py +44 -54
  121. pygpt_net/tools/code_interpreter/body.py +1 -2
  122. pygpt_net/tools/code_interpreter/tool.py +7 -4
  123. pygpt_net/tools/code_interpreter/ui/html.py +1 -3
  124. pygpt_net/tools/code_interpreter/ui/widgets.py +2 -3
  125. pygpt_net/tools/html_canvas/ui/widgets.py +1 -3
  126. pygpt_net/tools/image_viewer/ui/dialogs.py +40 -37
  127. pygpt_net/tools/indexer/ui/widgets.py +2 -4
  128. pygpt_net/tools/media_player/tool.py +2 -5
  129. pygpt_net/tools/media_player/ui/widgets.py +60 -36
  130. pygpt_net/tools/text_editor/ui/widgets.py +18 -19
  131. pygpt_net/tools/translator/ui/widgets.py +39 -35
  132. pygpt_net/ui/base/context_menu.py +9 -4
  133. pygpt_net/ui/dialog/db.py +1 -3
  134. pygpt_net/ui/dialog/models.py +1 -3
  135. pygpt_net/ui/dialog/models_importer.py +2 -4
  136. pygpt_net/ui/dialogs.py +34 -30
  137. pygpt_net/ui/layout/chat/attachments.py +72 -84
  138. pygpt_net/ui/layout/chat/attachments_ctx.py +40 -44
  139. pygpt_net/ui/layout/chat/attachments_uploaded.py +36 -39
  140. pygpt_net/ui/layout/chat/calendar.py +100 -70
  141. pygpt_net/ui/layout/chat/chat.py +23 -17
  142. pygpt_net/ui/layout/chat/input.py +95 -118
  143. pygpt_net/ui/layout/chat/output.py +100 -162
  144. pygpt_net/ui/layout/chat/painter.py +89 -61
  145. pygpt_net/ui/layout/ctx/ctx_list.py +43 -52
  146. pygpt_net/ui/layout/status.py +23 -14
  147. pygpt_net/ui/layout/toolbox/agent.py +27 -38
  148. pygpt_net/ui/layout/toolbox/agent_llama.py +42 -45
  149. pygpt_net/ui/layout/toolbox/assistants.py +42 -38
  150. pygpt_net/ui/layout/toolbox/computer_env.py +32 -23
  151. pygpt_net/ui/layout/toolbox/footer.py +13 -16
  152. pygpt_net/ui/layout/toolbox/image.py +18 -21
  153. pygpt_net/ui/layout/toolbox/indexes.py +46 -89
  154. pygpt_net/ui/layout/toolbox/mode.py +20 -7
  155. pygpt_net/ui/layout/toolbox/model.py +12 -10
  156. pygpt_net/ui/layout/toolbox/presets.py +68 -52
  157. pygpt_net/ui/layout/toolbox/prompt.py +31 -58
  158. pygpt_net/ui/layout/toolbox/toolbox.py +25 -21
  159. pygpt_net/ui/layout/toolbox/vision.py +20 -22
  160. pygpt_net/ui/main.py +2 -4
  161. pygpt_net/ui/menu/about.py +64 -84
  162. pygpt_net/ui/menu/audio.py +87 -63
  163. pygpt_net/ui/menu/config.py +121 -127
  164. pygpt_net/ui/menu/debug.py +69 -76
  165. pygpt_net/ui/menu/file.py +32 -35
  166. pygpt_net/ui/menu/menu.py +2 -3
  167. pygpt_net/ui/menu/plugins.py +69 -33
  168. pygpt_net/ui/menu/theme.py +45 -46
  169. pygpt_net/ui/menu/tools.py +56 -60
  170. pygpt_net/ui/menu/video.py +20 -25
  171. pygpt_net/ui/tray.py +1 -2
  172. pygpt_net/ui/widget/audio/bar.py +1 -3
  173. pygpt_net/ui/widget/audio/input_button.py +3 -4
  174. pygpt_net/ui/widget/calendar/select.py +1 -2
  175. pygpt_net/ui/widget/dialog/base.py +12 -9
  176. pygpt_net/ui/widget/dialog/editor_file.py +20 -23
  177. pygpt_net/ui/widget/dialog/find.py +25 -24
  178. pygpt_net/ui/widget/dialog/profile.py +57 -53
  179. pygpt_net/ui/widget/draw/painter.py +62 -93
  180. pygpt_net/ui/widget/element/button.py +42 -30
  181. pygpt_net/ui/widget/element/checkbox.py +23 -15
  182. pygpt_net/ui/widget/element/group.py +6 -5
  183. pygpt_net/ui/widget/element/labels.py +1 -2
  184. pygpt_net/ui/widget/filesystem/explorer.py +93 -102
  185. pygpt_net/ui/widget/image/display.py +1 -2
  186. pygpt_net/ui/widget/lists/assistant.py +1 -2
  187. pygpt_net/ui/widget/lists/attachment.py +1 -2
  188. pygpt_net/ui/widget/lists/attachment_ctx.py +1 -2
  189. pygpt_net/ui/widget/lists/context.py +2 -4
  190. pygpt_net/ui/widget/lists/index.py +1 -2
  191. pygpt_net/ui/widget/lists/model.py +1 -2
  192. pygpt_net/ui/widget/lists/model_editor.py +1 -2
  193. pygpt_net/ui/widget/lists/model_importer.py +1 -2
  194. pygpt_net/ui/widget/lists/preset.py +1 -2
  195. pygpt_net/ui/widget/lists/preset_plugins.py +1 -2
  196. pygpt_net/ui/widget/lists/profile.py +1 -2
  197. pygpt_net/ui/widget/lists/uploaded.py +1 -2
  198. pygpt_net/ui/widget/option/checkbox.py +2 -4
  199. pygpt_net/ui/widget/option/checkbox_list.py +1 -4
  200. pygpt_net/ui/widget/option/cmd.py +1 -4
  201. pygpt_net/ui/widget/option/dictionary.py +25 -28
  202. pygpt_net/ui/widget/option/input.py +1 -3
  203. pygpt_net/ui/widget/tabs/Input.py +16 -12
  204. pygpt_net/ui/widget/tabs/body.py +5 -3
  205. pygpt_net/ui/widget/tabs/layout.py +36 -25
  206. pygpt_net/ui/widget/tabs/output.py +96 -74
  207. pygpt_net/ui/widget/textarea/calendar_note.py +1 -2
  208. pygpt_net/ui/widget/textarea/editor.py +41 -73
  209. pygpt_net/ui/widget/textarea/find.py +11 -10
  210. pygpt_net/ui/widget/textarea/html.py +3 -6
  211. pygpt_net/ui/widget/textarea/input.py +63 -64
  212. pygpt_net/ui/widget/textarea/notepad.py +54 -38
  213. pygpt_net/ui/widget/textarea/output.py +65 -54
  214. pygpt_net/ui/widget/textarea/search_input.py +5 -4
  215. pygpt_net/ui/widget/textarea/web.py +2 -4
  216. pygpt_net/ui/widget/vision/camera.py +2 -31
  217. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/METADATA +25 -154
  218. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/RECORD +218 -217
  219. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/LICENSE +0 -0
  220. {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/WHEEL +0 -0
  221. {pygpt_net-2.6.20.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.01.19 02:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import datetime
@@ -21,7 +21,6 @@ from pygpt_net.core.tabs.tab import Tab
21
21
  from pygpt_net.ui.widget.element.button import ContextMenuButton
22
22
  from pygpt_net.ui.widget.element.labels import HelpLabel
23
23
  from pygpt_net.utils import trans
24
- import pygpt_net.icons_rc
25
24
 
26
25
 
27
26
  class FileExplorer(QWidget):
@@ -45,6 +44,7 @@ class FileExplorer(QWidget):
45
44
  self.treeView = QTreeView()
46
45
  self.treeView.setModel(self.model)
47
46
  self.treeView.setRootIndex(self.model.index(self.directory))
47
+ self.treeView.setUniformRowHeights(True)
48
48
  self.setProperty('class', 'file-explorer')
49
49
 
50
50
  header = QHBoxLayout()
@@ -71,7 +71,6 @@ class FileExplorer(QWidget):
71
71
  self.btn_clear.setMaximumHeight(40)
72
72
  self.btn_clear.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
73
73
 
74
- # btn with icon
75
74
  self.btn_tool = QPushButton(QIcon(":/icons/db.svg"), "")
76
75
  self.btn_tool.setMaximumHeight(40)
77
76
  self.btn_tool.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
@@ -104,7 +103,7 @@ class FileExplorer(QWidget):
104
103
 
105
104
  self.treeView.setContextMenuPolicy(Qt.CustomContextMenu)
106
105
  self.treeView.customContextMenuRequested.connect(self.openContextMenu)
107
- self.treeView.setColumnWidth(0, self.width() / 2)
106
+ self.treeView.setColumnWidth(0, int(self.width() / 2))
108
107
 
109
108
  self.header = self.treeView.header()
110
109
  self.header.setStretchLastSection(True)
@@ -122,6 +121,23 @@ class FileExplorer(QWidget):
122
121
  self.tab = None
123
122
  self.installEventFilter(self)
124
123
 
124
+ self._icons = {
125
+ 'open': QIcon(":/icons/view.svg"),
126
+ 'open_dir': QIcon(":/icons/folder_filled.svg"),
127
+ 'download': QIcon(":/icons/download.svg"),
128
+ 'rename': QIcon(":/icons/edit.svg"),
129
+ 'duplicate': QIcon(":/icons/stack.svg"),
130
+ 'touch': QIcon(":/icons/add.svg"),
131
+ 'mkdir': QIcon(":/icons/add_folder.svg"),
132
+ 'refresh': QIcon(":/icons/reload.svg"),
133
+ 'upload': QIcon(":/icons/upload.svg"),
134
+ 'delete': QIcon(":/icons/delete.svg"),
135
+ 'attachment': QIcon(":/icons/attachment.svg"),
136
+ 'copy': QIcon(":/icons/copy.svg"),
137
+ 'read': QIcon(":/icons/view.svg"),
138
+ 'db': QIcon(":/icons/db.svg"),
139
+ }
140
+
125
141
  def eventFilter(self, source, event):
126
142
  """
127
143
  Focus event filter
@@ -184,7 +200,7 @@ class FileExplorer(QWidget):
184
200
  lambda checked=False,
185
201
  id=id: self.window.controller.idx.indexer.index_all_files(id)
186
202
  )
187
- menu.exec_(parent.mapToGlobal(pos))
203
+ menu.exec(parent.mapToGlobal(pos))
188
204
 
189
205
  def clear_context_menu(self, parent, pos):
190
206
  """
@@ -204,15 +220,19 @@ class FileExplorer(QWidget):
204
220
  lambda checked=False,
205
221
  id=id: self.window.controller.idx.indexer.clear(id)
206
222
  )
207
- menu.exec_(parent.mapToGlobal(pos))
223
+ menu.exec(parent.mapToGlobal(pos))
208
224
 
209
225
  def adjustColumnWidths(self):
210
226
  """Adjust column widths"""
211
227
  total_width = self.treeView.width()
228
+ col_count = self.model.columnCount()
212
229
  first_column_width = int(total_width * self.column_proportion)
213
230
  self.treeView.setColumnWidth(0, first_column_width)
214
- for column in range(1, self.model.columnCount()):
215
- self.treeView.setColumnWidth(column, (total_width - first_column_width) // (self.model.columnCount() - 1))
231
+ if col_count > 1:
232
+ remaining = max(total_width - first_column_width, 0)
233
+ per_col = remaining // (col_count - 1) if col_count > 1 else 0
234
+ for column in range(1, col_count):
235
+ self.treeView.setColumnWidth(column, per_col)
216
236
 
217
237
  def resizeEvent(self, event: QResizeEvent):
218
238
  """
@@ -221,7 +241,8 @@ class FileExplorer(QWidget):
221
241
  :param event: Event object
222
242
  """
223
243
  super().resizeEvent(event)
224
- self.adjustColumnWidths()
244
+ if event.oldSize().width() != event.size().width():
245
+ self.adjustColumnWidths()
225
246
 
226
247
  def openContextMenu(self, position):
227
248
  """
@@ -240,32 +261,27 @@ class FileExplorer(QWidget):
240
261
  if self.window.core.filesystem.actions.has_preview(path):
241
262
  preview_actions = self.window.core.filesystem.actions.get_preview(self, path)
242
263
 
243
- # open file
244
- actions['open'] = QAction(QIcon(":/icons/view.svg"), trans('action.open'), self)
264
+ actions['open'] = QAction(self._icons['open'], trans('action.open'), self)
245
265
  actions['open'].triggered.connect(
246
266
  lambda: self.action_open(path),
247
267
  )
248
268
 
249
- # open in file manager
250
- actions['open_dir'] = QAction(QIcon(":/icons/folder_filled.svg"), trans('action.open_dir'), self)
269
+ actions['open_dir'] = QAction(self._icons['open_dir'], trans('action.open_dir'), self)
251
270
  actions['open_dir'].triggered.connect(
252
271
  lambda: self.action_open_dir(path),
253
272
  )
254
273
 
255
- # download
256
- actions['download'] = QAction(QIcon(":/icons/download.svg"), trans('action.download'), self)
274
+ actions['download'] = QAction(self._icons['download'], trans('action.download'), self)
257
275
  actions['download'].triggered.connect(
258
276
  lambda: self.window.controller.files.download_local(path),
259
277
  )
260
278
 
261
- # rename
262
- actions['rename'] = QAction(QIcon(":/icons/edit.svg"), trans('action.rename'), self)
279
+ actions['rename'] = QAction(self._icons['rename'], trans('action.rename'), self)
263
280
  actions['rename'].triggered.connect(
264
281
  lambda: self.action_rename(path),
265
282
  )
266
283
 
267
- # duplicate
268
- actions['duplicate'] = QAction(QIcon(":/icons/stack.svg"), trans('action.duplicate'), self)
284
+ actions['duplicate'] = QAction(self._icons['duplicate'], trans('action.duplicate'), self)
269
285
  actions['duplicate'].triggered.connect(
270
286
  lambda: self.window.controller.files.duplicate_local(path, ""),
271
287
  )
@@ -275,37 +291,31 @@ class FileExplorer(QWidget):
275
291
  else:
276
292
  parent = os.path.dirname(path)
277
293
 
278
- # touch file
279
- actions['touch'] = QAction(QIcon(":/icons/add.svg"), trans('action.touch'), self)
294
+ actions['touch'] = QAction(self._icons['touch'], trans('action.touch'), self)
280
295
  actions['touch'].triggered.connect(
281
296
  lambda: self.window.controller.files.touch_file(parent),
282
297
  )
283
298
 
284
- # make dir
285
- actions['mkdir'] = QAction(QIcon(":/icons/add_folder.svg"), trans('action.mkdir'), self)
299
+ actions['mkdir'] = QAction(self._icons['mkdir'], trans('action.mkdir'), self)
286
300
  actions['mkdir'].triggered.connect(
287
301
  lambda: self.action_make_dir(parent),
288
302
  )
289
303
 
290
- # refresh
291
- actions['refresh'] = QAction(QIcon(":/icons/reload.svg"), trans('action.refresh'), self)
304
+ actions['refresh'] = QAction(self._icons['refresh'], trans('action.refresh'), self)
292
305
  actions['refresh'].triggered.connect(
293
306
  lambda: self.window.controller.files.update_explorer(),
294
307
  )
295
308
 
296
- # upload to dir
297
- actions['upload'] = QAction(QIcon(":/icons/upload.svg"), trans('action.upload'), self)
309
+ actions['upload'] = QAction(self._icons['upload'], trans('action.upload'), self)
298
310
  actions['upload'].triggered.connect(
299
311
  lambda: self.window.controller.files.upload_local(parent),
300
312
  )
301
313
 
302
- # delete
303
- actions['delete'] = QAction(QIcon(":/icons/delete.svg"), trans('action.delete'), self)
314
+ actions['delete'] = QAction(self._icons['delete'], trans('action.delete'), self)
304
315
  actions['delete'].triggered.connect(
305
316
  lambda: self.action_delete(path),
306
317
  )
307
318
 
308
- # menu
309
319
  menu = QMenu(self)
310
320
  if preview_actions:
311
321
  for action in preview_actions:
@@ -313,27 +323,22 @@ class FileExplorer(QWidget):
313
323
  menu.addAction(actions['open'])
314
324
  menu.addAction(actions['open_dir'])
315
325
 
316
- # use menu
317
326
  use_menu = QMenu(trans('action.use'), self)
318
327
 
319
- # use
320
328
  if not os.path.isdir(path):
321
- # use as attachment
322
329
  actions['use_attachment'] = QAction(
323
- QIcon(":/icons/attachment.svg"),
330
+ self._icons['attachment'],
324
331
  trans('action.use.attachment'),
325
332
  self,
326
333
  )
327
334
  actions['use_attachment'].triggered.connect(
328
335
  lambda: self.window.controller.files.use_attachment(path),
329
336
  )
330
- # use by filetype
331
337
  if self.window.core.filesystem.actions.has_use(path):
332
338
  use_actions = self.window.core.filesystem.actions.get_use(self, path)
333
339
 
334
- # copy work path
335
340
  actions['use_copy_work_path'] = QAction(
336
- QIcon(":/icons/copy.svg"),
341
+ self._icons['copy'],
337
342
  trans('action.use.copy_work_path'),
338
343
  self,
339
344
  )
@@ -341,9 +346,8 @@ class FileExplorer(QWidget):
341
346
  lambda: self.window.controller.files.copy_work_path(path),
342
347
  )
343
348
 
344
- # copy sys path
345
349
  actions['use_copy_sys_path'] = QAction(
346
- QIcon(":/icons/copy.svg"),
350
+ self._icons['copy'],
347
351
  trans('action.use.copy_sys_path'),
348
352
  self,
349
353
  )
@@ -351,52 +355,45 @@ class FileExplorer(QWidget):
351
355
  lambda: self.window.controller.files.copy_sys_path(path),
352
356
  )
353
357
 
354
- # use read cmd
355
- actions['use_read_cmd'] = QAction(QIcon(":/icons/view.svg"), trans('action.use.read_cmd'), self)
358
+ actions['use_read_cmd'] = QAction(self._icons['read'], trans('action.use.read_cmd'), self)
356
359
  actions['use_read_cmd'].triggered.connect(
357
360
  lambda: self.window.controller.files.make_read_cmd(path),
358
361
  )
359
362
 
360
- # add actions to menu
361
363
  if not os.path.isdir(path):
362
364
  use_menu.addAction(actions['use_attachment'])
363
365
 
364
- # use by type
365
366
  if use_actions:
366
367
  for action in use_actions:
367
368
  use_menu.addAction(action)
368
369
 
369
- # use common actions
370
370
  use_menu.addAction(actions['use_copy_work_path'])
371
371
  use_menu.addAction(actions['use_copy_sys_path'])
372
372
  use_menu.addAction(actions['use_read_cmd'])
373
373
  menu.addMenu(use_menu)
374
374
 
375
- # remove from index
376
375
  file_id = self.window.core.idx.files.get_id(path)
377
376
  remove_actions = []
378
377
  for idx in self.index_data:
379
378
  items = self.index_data[idx]
380
379
  if file_id in items:
381
- action = QAction(QIcon(":/icons/delete.svg"), trans("action.idx.remove") + ": " + idx, self)
380
+ action = QAction(self._icons['delete'], trans("action.idx.remove") + ": " + idx, self)
382
381
  action.triggered.connect(
383
382
  lambda checked=False,
384
383
  idx=idx,
385
- file_id=file_id: self.action_idx_remove(file_id, idx) # by file_id, not path
384
+ file_id=file_id: self.action_idx_remove(file_id, idx)
386
385
  )
387
386
  remove_actions.append(action)
388
387
 
389
- # add to index if allowed
390
388
  if self.window.core.idx.indexing.is_allowed(path):
391
389
  idx_menu = QMenu(trans('action.idx'), self)
392
390
  idx_list = self.window.core.config.get('llama.idx.list')
393
391
  if len(idx_list) > 0 or len(remove_actions) > 0:
394
- # add
395
392
  if len(idx_list) > 0:
396
393
  for idx in idx_list:
397
394
  id = idx['id']
398
395
  name = f"{idx['name']} ({idx['id']})"
399
- action = QAction(QIcon(":/icons/db.svg"), f"IDX: {name}", self)
396
+ action = QAction(self._icons['db'], f"IDX: {name}", self)
400
397
  action.triggered.connect(
401
398
  lambda checked=False,
402
399
  id=id,
@@ -404,7 +401,6 @@ class FileExplorer(QWidget):
404
401
  )
405
402
  idx_menu.addAction(action)
406
403
 
407
- # remove
408
404
  if len(remove_actions) > 0:
409
405
  idx_menu.addSeparator()
410
406
  for action in remove_actions:
@@ -424,29 +420,24 @@ class FileExplorer(QWidget):
424
420
 
425
421
  menu.exec(QCursor.pos())
426
422
  else:
427
- # no item selected
428
423
  actions = {}
429
424
 
430
- # touch file
431
- actions['touch'] = QAction(QIcon(":/icons/add.svg"), trans('action.touch'), self)
425
+ actions['touch'] = QAction(self._icons['touch'], trans('action.touch'), self)
432
426
  actions['touch'].triggered.connect(
433
427
  lambda: self.window.controller.files.touch_file(self.directory),
434
428
  )
435
429
 
436
- # open in file manager
437
- actions['open_dir'] = QAction(QIcon(":/icons/folder_filled.svg"), trans('action.open_dir'), self)
430
+ actions['open_dir'] = QAction(self._icons['open_dir'], trans('action.open_dir'), self)
438
431
  actions['open_dir'].triggered.connect(
439
432
  lambda: self.action_open_dir(self.directory),
440
433
  )
441
434
 
442
- # make dir in dir
443
- actions['mkdir'] = QAction(QIcon(":/icons/add_folder.svg"), trans('action.mkdir'), self)
435
+ actions['mkdir'] = QAction(self._icons['mkdir'], trans('action.mkdir'), self)
444
436
  actions['mkdir'].triggered.connect(
445
437
  lambda: self.action_make_dir(self.directory),
446
438
  )
447
439
 
448
- # upload in dir
449
- actions['upload'] = QAction(QIcon(":/icons/upload.svg"), trans('action.upload'), self)
440
+ actions['upload'] = QAction(self._icons['upload'], trans('action.upload'), self)
450
441
  actions['upload'].triggered.connect(
451
442
  lambda: self.window.controller.files.upload_local(),
452
443
  )
@@ -522,11 +513,13 @@ class IndexedFileSystemModel(QFileSystemModel):
522
513
  super().__init__(*args, **kwargs)
523
514
  self.window = window
524
515
  self.index_dict = index_dict
516
+ self._status_cache = {}
525
517
  self.directoryLoaded.connect(self.refresh_path)
526
518
 
527
519
  def refresh_path(self, path):
528
520
  index = self.index(path)
529
521
  if index.isValid():
522
+ self._status_cache.clear()
530
523
  self.dataChanged.emit(index, index)
531
524
 
532
525
  def columnCount(self, parent=QModelIndex()) -> int:
@@ -546,38 +539,35 @@ class IndexedFileSystemModel(QFileSystemModel):
546
539
  :param role: role
547
540
  :return: data
548
541
  """
549
- # index status
550
- if index.column() == self.columnCount() - 1:
542
+ last_col = self.columnCount() - 1
543
+ if index.column() == last_col:
551
544
  if role == Qt.DisplayRole:
552
545
  file_path = self.filePath(index.siblingAtColumn(0))
553
- status = self.get_index_status(file_path) # get index status
546
+ status = self.get_index_status(file_path)
554
547
  if status['indexed']:
555
- ts = datetime.datetime.fromtimestamp(status['last_index_at'])
556
- # check if today
557
- if ts.date() == datetime.date.today():
558
- dt = ts.strftime("%H:%M")
548
+ ts = status['last_index_at']
549
+ dt = datetime.datetime.fromtimestamp(ts)
550
+ if dt.date() == datetime.date.today():
551
+ ds = dt.strftime("%H:%M")
559
552
  else:
560
- dt = ts.strftime("%Y-%m-%d %H:%M")
561
- content = f"{dt} ({','.join(status['indexed_in'])})"
553
+ ds = dt.strftime("%Y-%m-%d %H:%M")
554
+ content = f"{ds} ({','.join(status['indexed_in'])})"
562
555
  else:
563
- content = '-' # if file not indexed
556
+ content = '-'
564
557
  return content
565
- # modified date
566
- elif index.column() == self.columnCount() - 2:
558
+ elif index.column() == last_col - 1:
567
559
  if role == Qt.DisplayRole:
568
- dt = self.lastModified(index)
569
- data = dt.toString("yyyy-MM-dd HH:mm:ss")
570
- ts = dt.toSecsSinceEpoch()
571
- dt_from_ts = datetime.datetime.fromtimestamp(ts)
572
- if dt_from_ts.date() == datetime.date.today():
573
- data = dt_from_ts.strftime("%H:%M")
560
+ dt_qt = self.lastModified(index)
561
+ ts = dt_qt.toSecsSinceEpoch()
562
+ dt_py = datetime.datetime.fromtimestamp(ts)
563
+ if dt_py.date() == datetime.date.today():
564
+ data = dt_py.strftime("%H:%M")
574
565
  else:
575
- data = dt_from_ts.strftime("%Y-%m-%d %H:%M")
566
+ data = dt_py.strftime("%Y-%m-%d %H:%M")
576
567
  file_path = self.filePath(index.siblingAtColumn(0))
577
- status = self.get_index_status(file_path) # get index status
568
+ status = self.get_index_status(file_path)
578
569
  if status['indexed']:
579
- # if modified date is newer, mark file with *
580
- if 'last_index_at' in status and status['last_index_at'] < dt.toSecsSinceEpoch():
570
+ if 'last_index_at' in status and status['last_index_at'] < ts:
581
571
  data += '*'
582
572
  return data
583
573
 
@@ -591,33 +581,31 @@ class IndexedFileSystemModel(QFileSystemModel):
591
581
  :return: file index status
592
582
  """
593
583
  file_id = self.window.core.idx.files.get_id(file_path)
584
+ cached = self._status_cache.get(file_id)
585
+ if cached is not None:
586
+ return cached
594
587
  indexed_in = []
595
588
  indexed_timestamps = {}
596
589
  last_index_at = 0
597
590
  for idx in self.index_dict:
598
591
  items = self.index_dict[idx]
599
592
  if file_id in items:
600
- indexed_in.append(idx) # append idx where file is indexed
601
- indexed_timestamps[idx] = items[file_id]['indexed_ts']
602
- if items[file_id]['indexed_ts'] > last_index_at:
603
- last_index_at = items[file_id]['indexed_ts']
604
-
605
- # sort indexed_in by timestamp DESC
606
- indexed_in = sorted(
607
- indexed_in,
608
- key=lambda x: indexed_timestamps[x],
609
- reverse=True,
610
- )
611
- if len(indexed_in) > 0:
612
- return {
593
+ indexed_in.append(idx)
594
+ ts = items[file_id]['indexed_ts']
595
+ indexed_timestamps[idx] = ts
596
+ if ts > last_index_at:
597
+ last_index_at = ts
598
+ if indexed_in:
599
+ indexed_in.sort(key=lambda x: indexed_timestamps[x], reverse=True)
600
+ result = {
613
601
  'indexed': True,
614
602
  'indexed_in': indexed_in,
615
603
  'last_index_at': last_index_at,
616
604
  }
617
605
  else:
618
- return {
619
- 'indexed': False,
620
- }
606
+ result = {'indexed': False}
607
+ self._status_cache[file_id] = result
608
+ return result
621
609
 
622
610
  def headerData(self, section, orientation, role=Qt.DisplayRole) -> str:
623
611
  """
@@ -648,10 +636,13 @@ class IndexedFileSystemModel(QFileSystemModel):
648
636
  :param idx_data: new index data dict
649
637
  """
650
638
  self.index_dict = idx_data
651
- top_left_index = self.index(0, 0)
652
- bottom_right_index = self.index(self.rowCount() - 1, self.columnCount() - 1)
639
+ self._status_cache.clear()
640
+ row_count = self.rowCount()
641
+ if row_count > 0:
642
+ top_left_index = self.index(0, 0)
643
+ bottom_right_index = self.index(row_count - 1, self.columnCount() - 1)
644
+ self.dataChanged.emit(top_left_index, bottom_right_index, [Qt.DisplayRole])
653
645
  path = self.rootPath()
654
- self.dataChanged.emit(top_left_index, bottom_right_index, [Qt.DisplayRole])
655
646
  self.setRootPath("")
656
647
  self.setRootPath(path)
657
- self.layoutChanged.emit()
648
+ self.layoutChanged.emit()
@@ -6,14 +6,13 @@
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.25 10:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction, QIcon
13
13
  from PySide6.QtWidgets import QMenu, QLabel
14
14
 
15
15
  from pygpt_net.utils import trans
16
- import pygpt_net.icons_rc
17
16
 
18
17
 
19
18
  class ImageLabel(QLabel):
@@ -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.19 17:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import QItemSelectionModel, QPoint
@@ -15,7 +15,6 @@ from PySide6.QtWidgets import QMenu
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
 
21
20
  class AssistantList(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.15 03:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from functools import partial
@@ -18,7 +18,6 @@ from PySide6.QtWidgets import QMenu, QApplication
18
18
  from pygpt_net.item.attachment import AttachmentItem
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 AttachmentList(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.06 19:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from functools import partial
@@ -16,7 +16,6 @@ from PySide6.QtWidgets import QMenu
16
16
 
17
17
  from pygpt_net.ui.widget.lists.base import BaseList
18
18
  from pygpt_net.utils import trans
19
- import pygpt_net.icons_rc
20
19
 
21
20
 
22
21
  class AttachmentCtxList(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.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):