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
pygpt_net/CHANGELOG.txt CHANGED
@@ -1,3 +1,7 @@
1
+ 2.6.22 (2025-08-25)
2
+
3
+ - UI refactor and optimizations.
4
+
1
5
  2.6.21 (2025-08-24)
2
6
 
3
7
  - Ollama models are now available in OpenAI Agents mode.
pygpt_net/__init__.py CHANGED
@@ -6,15 +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.24 00:00:00 #
9
+ # Updated Date: 2025.08.25 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  __author__ = "Marcin Szczygliński"
13
13
  __copyright__ = "Copyright 2025, Marcin Szczygliński"
14
14
  __credits__ = ["Marcin Szczygliński"]
15
15
  __license__ = "MIT"
16
- __version__ = "2.6.21"
17
- __build__ = "2025-08-24"
16
+ __version__ = "2.6.22"
17
+ __build__ = "2025-08-25"
18
18
  __maintainer__ = "Marcin Szczygliński"
19
19
  __github__ = "https://github.com/szczyglis-dev/py-gpt"
20
20
  __report__ = "https://github.com/szczyglis-dev/py-gpt/issues"
pygpt_net/app.py CHANGED
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.22 10:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -14,6 +14,8 @@ import builtins
14
14
  import io
15
15
  import platform
16
16
 
17
+ import pygpt_net.icons_rc
18
+
17
19
  # disable warnings
18
20
  os.environ["TRANSFORMERS_NO_ADVISORY_WARNINGS"] = "1"
19
21
  os.environ["QT_LOGGING_RULES"] = "qt.multimedia.ffmpeg=false;qt.qpa.fonts=false"
@@ -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.20 23:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from pygpt_net.controller.access import Access
@@ -39,7 +39,7 @@ from pygpt_net.controller.settings import Settings
39
39
  from pygpt_net.controller.theme import Theme
40
40
  from pygpt_net.controller.tools import Tools
41
41
  from pygpt_net.controller.ui import UI
42
- from pygpt_net.utils import mem_clean
42
+ from pygpt_net.utils import trans
43
43
 
44
44
 
45
45
  class Controller:
@@ -109,8 +109,6 @@ class Controller:
109
109
  self.camera.setup_ui()
110
110
  self.access.setup()
111
111
 
112
-
113
-
114
112
  def post_setup(self):
115
113
  """Post-setup, after plugins are loaded"""
116
114
  self.settings.setup()
@@ -147,9 +145,7 @@ class Controller:
147
145
  """Reload components"""
148
146
  self.reloading = True # lock
149
147
 
150
- print("Reloading components... please wait...")
151
-
152
- mem_clean() # try to clean memory
148
+ print(trans("status.reloading.profile.begin"))
153
149
 
154
150
  prev_theme = self.window.core.config.get("theme")
155
151
 
@@ -183,4 +179,4 @@ class Controller:
183
179
 
184
180
  self.reloading = False # unlock
185
181
 
186
- print("[OK] Components reloaded successfully.")
182
+ print(trans("status.reloading.profile.end"))
@@ -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.07 22:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional, List, Dict, Any
@@ -14,7 +14,7 @@ from typing import Optional, List, Dict, Any
14
14
  import os
15
15
 
16
16
  from PySide6.QtCore import QTimer, Slot, QObject
17
- from qasync import QApplication
17
+ from PySide6.QtWidgets import QApplication
18
18
 
19
19
  from pygpt_net.item.ctx import CtxItem
20
20
  from pygpt_net.plugin.audio_input.worker import ControlWorker
@@ -6,13 +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.08.03 14:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional, Any
13
13
 
14
- from qasync import QApplication
15
- from PySide6.QtWidgets import QFileDialog
14
+ from PySide6.QtWidgets import QFileDialog, QApplication
16
15
 
17
16
  from pygpt_net.utils import trans
18
17
 
@@ -6,13 +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: 2025.08.03 14:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
13
13
  from typing import Optional
14
14
 
15
- from qasync import QApplication
15
+ from PySide6.QtWidgets import QApplication
16
16
 
17
17
  from pygpt_net.core.types import MODEL_DEFAULT
18
18
  from pygpt_net.item.assistant import AssistantItem
@@ -6,17 +6,16 @@
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.03 14:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
13
  from typing import Optional, Dict, List
14
14
 
15
- from qasync import QApplication
15
+ from PySide6.QtWidgets import QApplication
16
16
 
17
17
  from pygpt_net.item.assistant import AssistantItem
18
18
  from pygpt_net.item.attachment import AttachmentItem
19
- from pygpt_net.item.ctx import CtxItem
20
19
  from pygpt_net.utils import trans
21
20
 
22
21
 
@@ -6,14 +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.08.03 14:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
13
13
  import json
14
14
  from typing import Optional
15
15
 
16
- from qasync import QApplication
16
+ from PySide6.QtWidgets import QApplication
17
17
 
18
18
  from pygpt_net.item.assistant import AssistantStoreItem
19
19
  from pygpt_net.utils import trans
@@ -6,13 +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: 2025.08.07 22:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
13
  from typing import Optional
14
14
 
15
- from qasync import QApplication
15
+ from PySide6.QtWidgets import QApplication
16
16
 
17
17
  from pygpt_net.core.tabs.tab import Tab
18
18
  from pygpt_net.core.events import Event, BaseEvent
@@ -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.23 15:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional, List
@@ -358,6 +358,7 @@ class Ctx:
358
358
 
359
359
  self.window.dispatch(AppEvent(AppEvent.CTX_CREATED))
360
360
  self.select(meta.id)
361
+ QTimer.singleShot(1000, self.window.controller.chat.common.focus_input)
361
362
  return meta
362
363
 
363
364
  def add(self, ctx: CtxItem):
@@ -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.03 14:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import datetime
@@ -14,7 +14,7 @@ import os
14
14
  from typing import Any, List, Dict
15
15
 
16
16
  from PySide6.QtCore import Slot, QObject
17
- from qasync import QApplication
17
+ from PySide6.QtWidgets import QApplication
18
18
 
19
19
  from pygpt_net.core.idx.worker import IndexWorker
20
20
  from pygpt_net.item.ctx import CtxMeta
@@ -83,7 +83,7 @@ class Indexer(QObject):
83
83
  """
84
84
  if not force:
85
85
  self.tmp_idx = idx # store tmp index name (for confirmation)
86
- content = trans('idx.confirm.db.content') + "\n" + trans('idx.token.warn')
86
+ content = f"{trans('idx.confirm.db.content')}\n{trans('idx.token.warn')}"
87
87
  self.window.ui.dialogs.confirm(
88
88
  type='idx.index.db',
89
89
  id=meta_id,
@@ -92,18 +92,19 @@ class Indexer(QObject):
92
92
  return
93
93
 
94
94
  meta = self.window.core.ctx.get_meta_by_id(meta_id)
95
- from_ts = meta.indexed
96
95
  self.window.update_status(trans('idx.status.indexing'))
97
96
 
98
- self.worker = IndexWorker()
99
- self.worker.window = self.window
100
- self.worker.content = meta_id
101
- self.worker.idx = idx
102
- self.worker.type = "db_meta"
103
- self.worker.from_ts = from_ts
104
- self.worker.signals.finished.connect(self.handle_finished_db_meta)
105
- self.worker.signals.error.connect(self.handle_error)
106
- self.window.threadpool.start(self.worker)
97
+ worker = IndexWorker()
98
+ worker.window = self.window
99
+ worker.content = meta_id
100
+ worker.idx = idx
101
+ worker.type = "db_meta"
102
+ worker.from_ts = meta.indexed
103
+ worker.signals.finished.connect(self.handle_finished_db_meta)
104
+ worker.signals.error.connect(self.handle_error)
105
+ self.window.threadpool.start(worker)
106
+ self.worker = worker
107
+
107
108
  self.window.controller.idx.on_idx_start() # on start
108
109
 
109
110
  def index_ctx_current(
@@ -146,15 +147,16 @@ class Indexer(QObject):
146
147
  :param idx: index name
147
148
  :param sync: sync mode
148
149
  """
149
- self.worker = IndexWorker()
150
- self.worker.window = self.window
151
- self.worker.content = meta.id
152
- self.worker.idx = idx
153
- self.worker.type = "db_meta"
154
- self.worker.from_ts = meta.indexed
155
- self.worker.silent = True
156
- self.worker.signals.finished.connect(self.handle_finished_db_meta)
157
- self.worker.signals.error.connect(self.handle_error)
150
+ worker = IndexWorker()
151
+ worker.window = self.window
152
+ worker.content = meta.id
153
+ worker.idx = idx
154
+ worker.type = "db_meta"
155
+ worker.from_ts = meta.indexed
156
+ worker.silent = True
157
+ worker.signals.finished.connect(self.handle_finished_db_meta)
158
+ worker.signals.error.connect(self.handle_error)
159
+ self.worker = worker
158
160
 
159
161
  if sync:
160
162
  self.worker.run()
@@ -204,15 +206,17 @@ class Indexer(QObject):
204
206
  )
205
207
  return
206
208
 
207
- self.worker = IndexWorker()
208
- self.worker.window = self.window
209
- self.worker.content = ts
210
- self.worker.idx = idx
211
- self.worker.type = "db_current"
212
- self.worker.silent = silent
213
- self.worker.signals.finished.connect(self.handle_finished_db_current)
214
- self.worker.signals.error.connect(self.handle_error)
215
- self.window.threadpool.start(self.worker)
209
+ worker = IndexWorker()
210
+ worker.window = self.window
211
+ worker.content = ts
212
+ worker.idx = idx
213
+ worker.type = "db_current"
214
+ worker.silent = silent
215
+ worker.signals.finished.connect(self.handle_finished_db_current)
216
+ worker.signals.error.connect(self.handle_error)
217
+ self.window.threadpool.start(worker)
218
+ self.worker = worker
219
+
216
220
  self.window.controller.idx.on_idx_start() # on start
217
221
 
218
222
  def index_path(
@@ -231,16 +235,19 @@ class Indexer(QObject):
231
235
  :param recursive: recursive indexing
232
236
  """
233
237
  self.window.update_status(trans('idx.status.indexing'))
234
- self.worker = IndexWorker()
235
- self.worker.window = self.window
236
- self.worker.content = path
237
- self.worker.idx = idx
238
- self.worker.type = "file"
239
- self.worker.replace = replace
240
- self.worker.recursive = recursive
241
- self.worker.signals.finished.connect(self.handle_finished_file)
242
- self.worker.signals.error.connect(self.handle_error)
243
- self.window.threadpool.start(self.worker)
238
+
239
+ worker = IndexWorker()
240
+ worker.window = self.window
241
+ worker.content = path
242
+ worker.idx = idx
243
+ worker.type = "file"
244
+ worker.replace = replace
245
+ worker.recursive = recursive
246
+ worker.signals.finished.connect(self.handle_finished_file)
247
+ worker.signals.error.connect(self.handle_error)
248
+ self.window.threadpool.start(worker)
249
+ self.worker = worker
250
+
244
251
  self.window.controller.idx.on_idx_start() # on start
245
252
 
246
253
  def index_paths(
@@ -259,17 +266,20 @@ class Indexer(QObject):
259
266
  :param recursive: recursive indexing
260
267
  """
261
268
  self.window.update_status(trans('idx.status.indexing'))
262
- self.worker = IndexWorker()
263
- self.worker.window = self.window
264
- self.worker.content = paths
265
- self.worker.idx = idx
266
- self.worker.type = "files"
267
- self.worker.replace = replace
268
- self.worker.recursive = recursive
269
- self.worker.silent = False
270
- self.worker.signals.finished.connect(self.handle_finished_file)
271
- self.worker.signals.error.connect(self.handle_error)
272
- self.window.threadpool.start(self.worker)
269
+
270
+ worker = IndexWorker()
271
+ worker.window = self.window
272
+ worker.content = paths
273
+ worker.idx = idx
274
+ worker.type = "files"
275
+ worker.replace = replace
276
+ worker.recursive = recursive
277
+ worker.silent = False
278
+ worker.signals.finished.connect(self.handle_finished_file)
279
+ worker.signals.error.connect(self.handle_error)
280
+ self.window.threadpool.start(worker)
281
+ self.worker = worker
282
+
273
283
  self.window.controller.idx.on_idx_start() # on start
274
284
 
275
285
  def index_all_files(
@@ -393,19 +403,21 @@ class Indexer(QObject):
393
403
  :param config: loader config
394
404
  :param replace: replace index
395
405
  """
396
- self.worker = IndexWorker()
397
- self.worker.window = self.window
398
- self.worker.content = None
399
- self.worker.loader = loader
400
- self.worker.params = params
401
- self.worker.config = config
402
- self.worker.replace = replace
403
- self.worker.silent = False
404
- self.worker.idx = idx
405
- self.worker.type = "web"
406
- self.worker.signals.finished.connect(self.handle_finished_web)
407
- self.worker.signals.error.connect(self.handle_error)
408
- self.window.threadpool.start(self.worker)
406
+ worker = IndexWorker()
407
+ worker.window = self.window
408
+ worker.content = None
409
+ worker.loader = loader
410
+ worker.params = params
411
+ worker.config = config
412
+ worker.replace = replace
413
+ worker.silent = False
414
+ worker.idx = idx
415
+ worker.type = "web"
416
+ worker.signals.finished.connect(self.handle_finished_web)
417
+ worker.signals.error.connect(self.handle_error)
418
+ self.window.threadpool.start(worker)
419
+ self.worker = worker
420
+
409
421
  self.window.controller.idx.on_idx_start() # on start
410
422
 
411
423
  def index_ctx_meta_remove(
@@ -444,8 +456,7 @@ class Indexer(QObject):
444
456
 
445
457
  :param idx: on list idx
446
458
  """
447
- idx_name = self.window.core.idx.get_by_idx(idx)
448
- self.clear(idx_name)
459
+ self.clear(self.window.core.idx.get_by_idx(idx))
449
460
 
450
461
  def truncate_by_idx(self, idx: int):
451
462
  """
@@ -453,8 +464,7 @@ class Indexer(QObject):
453
464
 
454
465
  :param idx: on list idx
455
466
  """
456
- idx_name = self.window.core.idx.get_by_idx(idx)
457
- self.clear(idx_name)
467
+ self.clear(self.window.core.idx.get_by_idx(idx))
458
468
 
459
469
  def clear(
460
470
  self,
@@ -496,7 +506,7 @@ class Indexer(QObject):
496
506
  else:
497
507
  self.window.update_status(trans('idx.status.truncate.error'))
498
508
  except Exception as e:
499
- print(e)
509
+ self.window.core.debug.log(e)
500
510
  self.window.update_status(e)
501
511
 
502
512
  self.window.tools.get("indexer").refresh()
@@ -544,7 +554,7 @@ class Indexer(QObject):
544
554
  else:
545
555
  self.window.update_status(trans('idx.status.truncate.error'))
546
556
  except Exception as e:
547
- print(e)
557
+ self.window.core.debug.log(e)
548
558
  self.window.update_status(e)
549
559
 
550
560
  self.window.tools.get("indexer").refresh()
@@ -559,7 +569,6 @@ class Indexer(QObject):
559
569
  self.window.ui.dialogs.alert(err)
560
570
  self.window.update_status(str(err))
561
571
  self.window.core.debug.log(err)
562
- print(err)
563
572
  self.window.tools.get("indexer").refresh()
564
573
  self.window.controller.idx.on_idx_error() # on error
565
574
 
@@ -580,7 +589,7 @@ class Indexer(QObject):
580
589
  :param silent: silent mode (no msg and status update)
581
590
  """
582
591
  if num > 0:
583
- msg = trans('idx.status.success') + f" {num}"
592
+ msg = f"{trans('idx.status.success')} {num}"
584
593
 
585
594
  # store last DB update timestamp
586
595
  self.window.core.config.set('llama.idx.db.index', idx)
@@ -620,7 +629,7 @@ class Indexer(QObject):
620
629
  :param silent: silent mode (no msg and status update)
621
630
  """
622
631
  if num > 0:
623
- msg = trans('idx.status.success') + f" {num}"
632
+ msg = f"{trans('idx.status.success')} {num}"
624
633
  self.update_idx_status(idx)
625
634
  self.window.controller.idx.after_index(idx) # post-actions (update UI, etc.)
626
635
  if not silent:
@@ -654,7 +663,7 @@ class Indexer(QObject):
654
663
  """
655
664
  num = len(files)
656
665
  if num > 0:
657
- msg = trans('idx.status.success') + f" {num}"
666
+ msg = f"{trans('idx.status.success')} {num}"
658
667
  self.window.core.idx.append(idx, files) # append files list to index
659
668
  self.update_idx_status(idx)
660
669
  self.window.controller.idx.after_index(idx) # post-actions (update UI, etc.)
@@ -688,7 +697,7 @@ class Indexer(QObject):
688
697
  :param silent: silent mode (no msg and status update)
689
698
  """
690
699
  if num > 0:
691
- msg = trans('idx.status.success') + f" {num}"
700
+ msg = f"{trans('idx.status.success')} {num}"
692
701
  if not silent:
693
702
  self.window.update_status(msg)
694
703
  self.window.ui.dialogs.alert(msg)
@@ -6,12 +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.11.20 21:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
- from PySide6.QtGui import QAction
12
+ from PySide6.QtGui import QAction, QActionGroup
13
13
 
14
14
  from pygpt_net.utils import trans, trans_reload
15
+
15
16
  from .custom import Custom
16
17
  from .mapping import Mapping
17
18
  from .plugins import Plugins
@@ -31,28 +32,48 @@ class Lang:
31
32
  self.plugins = Plugins(window)
32
33
  self.settings = Settings(window)
33
34
  self.loaded = False
35
+ self._lang_group = None
36
+
37
+ def _on_lang_triggered(self, action):
38
+ """
39
+ Handle language change triggered by menu action
40
+
41
+ :param action: QAction instance
42
+ """
43
+ self.window.controller.lang.toggle(action.data())
34
44
 
35
45
  def setup(self):
36
46
  """Setup language menu"""
37
- # get files from locale directory
38
47
  if not self.loaded:
39
- langs = self.window.core.config.get_available_langs()
48
+ w = self.window
49
+ menu = w.ui.menu
50
+ if self._lang_group is None:
51
+ self._lang_group = QActionGroup(w)
52
+ self._lang_group.setExclusive(True)
53
+ self._lang_group.triggered.connect(self._on_lang_triggered)
54
+
55
+ langs = w.core.config.get_available_langs()
56
+ menu_lang = menu['lang']
57
+ menu_root = menu['menu.lang']
40
58
  for lang in langs:
41
- self.window.ui.menu['lang'][lang] = QAction(lang.upper(), self.window, checkable=True)
42
- self.window.ui.menu['lang'][lang].triggered.connect(
43
- lambda checked=None,
44
- lang=lang: self.window.controller.lang.toggle(lang))
45
- self.window.ui.menu['menu.lang'].addAction(self.window.ui.menu['lang'][lang])
59
+ act = QAction(lang.upper(), w, checkable=True)
60
+ act.setData(lang)
61
+ menu_lang[lang] = act
62
+ self._lang_group.addAction(act)
63
+ menu_root.addAction(act)
46
64
  self.loaded = True
47
65
  self.update()
48
66
 
49
67
  def update(self):
50
68
  """Update language menu"""
51
- for lang in self.window.ui.menu['lang']:
52
- self.window.ui.menu['lang'][lang].setChecked(False)
53
- lang = self.window.core.config.get('lang')
54
- if lang in self.window.ui.menu['lang']:
55
- self.window.ui.menu['lang'][lang].setChecked(True)
69
+ menu_lang = self.window.ui.menu['lang']
70
+ current = self.window.core.config.get('lang')
71
+ act = menu_lang.get(current)
72
+ if act is not None:
73
+ act.setChecked(True)
74
+ else:
75
+ for a in menu_lang.values():
76
+ a.setChecked(False)
56
77
 
57
78
  def reload_config(self):
58
79
  """Reload language config"""
@@ -64,37 +85,34 @@ class Lang:
64
85
 
65
86
  :param id: language code to toggle
66
87
  """
67
- self.window.core.config.set('lang', id)
68
- self.window.core.config.save()
69
- trans('', True) # force reload locale
70
-
71
- self.update() # update menu
72
- self.mapping.apply() # nodes mapping
73
- self.custom.apply() # custom nodes
88
+ w = self.window
89
+ c = w.controller
90
+ conf = w.core.config
74
91
 
75
- # tabs
76
- self.window.controller.ui.tabs.reload_titles()
92
+ conf.set('lang', id)
93
+ conf.save()
94
+ trans('', True)
77
95
 
78
- # calendar
79
- self.window.controller.calendar.note.update_current()
96
+ self.update()
97
+ self.mapping.apply()
98
+ self.custom.apply()
80
99
 
81
- # settings
100
+ c.ui.tabs.reload_titles()
101
+ c.calendar.note.update_current()
82
102
  self.settings.apply()
83
103
 
84
- # plugins
85
104
  try:
86
105
  self.plugins.apply()
87
106
  except Exception as e:
88
107
  print("Error updating plugin locale", e)
89
- self.window.core.debug.log(e)
108
+ w.core.debug.log(e)
90
109
 
91
- # reload UI
92
- self.window.controller.ctx.common.update_label_by_current()
93
- self.window.controller.ctx.update(True, False)
94
- self.window.controller.ui.update() # update all (toolbox, etc.)
95
- self.window.update_status('') # clear status
110
+ w.controller.ctx.common.update_label_by_current()
111
+ w.controller.ctx.update(True, False)
112
+ w.controller.ui.update()
113
+ w.update_status('')
96
114
 
97
115
  def reload(self):
98
116
  """Reload language"""
99
117
  self.reload_config()
100
- self.setup()
118
+ self.setup()
@@ -6,14 +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.08.24 20:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
13
13
  import os
14
14
  from typing import List, Dict, Optional, Any
15
15
 
16
- from qasync import QApplication
16
+ from PySide6.QtWidgets import QApplication
17
17
 
18
18
  from pygpt_net.core.events import Event
19
19
  from pygpt_net.core.types import (