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.08.12 15:00:00 #
9
+ # Updated Date: 2025.08.25 03:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -19,8 +19,6 @@ from PySide6.QtWidgets import (QWidget, QPushButton, QHBoxLayout, QVBoxLayout,
19
19
  from pygpt_net.ui.widget.element.labels import HelpLabel
20
20
  from pygpt_net.utils import trans
21
21
 
22
- import pygpt_net.icons_rc
23
-
24
22
  class VideoPlayerWidget(QWidget):
25
23
  def __init__(self, window=None):
26
24
  super().__init__(window)
@@ -28,14 +26,18 @@ class VideoPlayerWidget(QWidget):
28
26
  self.player = None
29
27
  self.audio = None
30
28
  self.video = None
31
- self._QMediaPlayer = None
32
- self._QAudioOutput = None
33
- self._QVideoWidget = None
34
29
  self.loaded = False
35
30
  self.path = None
36
31
  self.stopped = False
37
32
  self.seeking = False
38
33
 
34
+ self._QMediaPlayer = None
35
+ self._QAudioOutput = None
36
+ self._QVideoWidget = None
37
+
38
+ self._waiting_position_set = False
39
+ self._last_position = -1
40
+
39
41
  self.update_timer = QTimer(self)
40
42
  self.update_timer.setInterval(200)
41
43
  self.update_timer.timeout.connect(self.update_ui)
@@ -48,11 +50,15 @@ class VideoPlayerWidget(QWidget):
48
50
  self._video_placeholder.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
49
51
  self._video_placeholder.setMinimumSize(640, 480)
50
52
 
53
+ self._icon_play = self.style().standardIcon(QStyle.SP_MediaPlay)
54
+ self._icon_pause = self.style().standardIcon(QStyle.SP_MediaPause)
55
+ self._icon_stop = self.style().standardIcon(QStyle.SP_MediaStop)
56
+
51
57
  self.btn_play_pause = QPushButton()
52
58
  self.btn_play_pause.setEnabled(False)
53
59
 
54
60
  self.btn_stop = QPushButton()
55
- self.btn_stop.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))
61
+ self.btn_stop.setIcon(self._icon_stop)
56
62
  self.btn_stop.setEnabled(False)
57
63
 
58
64
  self.btn_mute = QPushButton()
@@ -149,6 +155,7 @@ class VideoPlayerWidget(QWidget):
149
155
  self.volume_slider.valueChanged.connect(self.adjust_volume)
150
156
  self.slider.sliderPressed.connect(self.on_slider_pressed)
151
157
  self.slider.sliderReleased.connect(self.on_slider_released)
158
+ self.slider.valueChanged.connect(self.on_slider_value_changed)
152
159
  self._video_placeholder.mousePressEvent = self.video_widget_clicked
153
160
  self.seeking = False
154
161
 
@@ -210,7 +217,7 @@ class VideoPlayerWidget(QWidget):
210
217
  self.stopped = True
211
218
  self.slider.setValue(0)
212
219
  self.label_time.setText(self.format_time(0))
213
- self.btn_play_pause.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
220
+ self.btn_play_pause.setIcon(self._icon_play)
214
221
  self.update_timer.stop()
215
222
 
216
223
  def toggle_play_pause(self):
@@ -226,11 +233,13 @@ class VideoPlayerWidget(QWidget):
226
233
  if self.player and self.player.source():
227
234
  self.player.stop()
228
235
  self.player.setSource(QUrl())
229
- self.btn_play_pause.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
236
+ self.btn_play_pause.setIcon(self._icon_play)
230
237
  self.update_timer.stop()
231
238
  self.slider.setValue(0)
232
239
  self.seeking = False
233
240
  self.loaded = False
241
+ self._waiting_position_set = False
242
+ self._last_position = -1
234
243
 
235
244
  def reset_player(self):
236
245
  """Reset player to default state"""
@@ -296,6 +305,7 @@ class VideoPlayerWidget(QWidget):
296
305
  def on_close(self):
297
306
  """Stop video"""
298
307
  self.reset()
308
+ self.autoplay_timer.stop()
299
309
 
300
310
  def toggle_fullscreen(self):
301
311
  """Toggle fullscreen"""
@@ -387,22 +397,28 @@ class VideoPlayerWidget(QWidget):
387
397
  return
388
398
  if self._QMediaPlayer and self.player.playbackState() == self._QMediaPlayer.PlayingState:
389
399
  self.player.pause()
390
- self.player.positionChanged.connect(self.on_position_set)
400
+ self._waiting_position_set = True
391
401
  self.player.setPosition(position)
392
402
 
393
403
  def on_slider_pressed(self):
394
404
  """Slider pressed"""
395
405
  self.seeking = True
406
+ self._waiting_position_set = False
396
407
  if self.player:
397
408
  self.player.pause()
398
409
 
410
+ def on_slider_value_changed(self, value):
411
+ """Slider value changed"""
412
+ if self.seeking:
413
+ self.label_time.setText(self.format_time(value))
414
+
399
415
  def on_slider_released(self):
400
416
  """Slider released"""
401
417
  if self.seeking:
402
418
  if self.player:
403
419
  self.player.setPosition(self.slider.value())
404
420
  self.update_audio()
405
- self.player.play()
421
+ QTimer.singleShot(0, self.player.play)
406
422
  self.seeking = False
407
423
 
408
424
  def position_changed(self, position):
@@ -411,25 +427,15 @@ class VideoPlayerWidget(QWidget):
411
427
 
412
428
  :param position: position
413
429
  """
430
+ if self._waiting_position_set and self.player:
431
+ self._waiting_position_set = False
432
+ if self._QMediaPlayer and self.player.playbackState() == self._QMediaPlayer.PausedState:
433
+ QTimer.singleShot(100, self.player.play)
414
434
  if not self.seeking:
435
+ self._last_position = position
415
436
  self.slider.setValue(position)
416
437
  self.label_time.setText(self.format_time(position))
417
438
 
418
- def on_position_set(self, position):
419
- """
420
- On position set
421
-
422
- :param position: position
423
- """
424
- if self.seeking and self.player:
425
- try:
426
- self.player.positionChanged.disconnect(self.on_position_set)
427
- except Exception:
428
- pass
429
- if self._QMediaPlayer and self.player.playbackState() == self._QMediaPlayer.PausedState:
430
- QTimer.singleShot(100, self.player.play)
431
- self.seeking = False
432
-
433
439
  def update_label_path(self):
434
440
  """Update label path"""
435
441
  if self.path:
@@ -440,32 +446,50 @@ class VideoPlayerWidget(QWidget):
440
446
  def update_play_pause_icon(self):
441
447
  """Update play/pause icon"""
442
448
  if self.player and self._QMediaPlayer and self.player.playbackState() == self._QMediaPlayer.PlayingState:
443
- self.btn_play_pause.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))
444
- self.update_timer.start()
449
+ self.btn_play_pause.setIcon(self._icon_pause)
450
+ if not self.update_timer.isActive():
451
+ self.update_timer.start()
445
452
  else:
446
- self.btn_play_pause.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
447
- self.update_timer.stop()
453
+ self.btn_play_pause.setIcon(self._icon_play)
454
+ if self.update_timer.isActive():
455
+ self.update_timer.stop()
448
456
 
449
457
  def update_audio(self):
450
458
  """Re-assign audio"""
451
459
  if self.player and self.audio:
452
- self.player.setAudioOutput(None)
453
- self.player.setAudioOutput(self.audio)
460
+ try:
461
+ current = self.player.audioOutput()
462
+ except Exception:
463
+ current = None
464
+ if current is not self.audio:
465
+ self.player.setAudioOutput(self.audio)
454
466
 
455
467
  def update_mute_icon(self):
456
468
  """Update mute icon"""
457
469
  if self.audio:
458
- self.btn_mute.setChecked(self.audio.isMuted())
470
+ muted = self.audio.isMuted()
471
+ if self.btn_mute.isChecked() != muted:
472
+ block = self.btn_mute.blockSignals(True)
473
+ self.btn_mute.setChecked(muted)
474
+ self.btn_mute.blockSignals(block)
459
475
 
460
476
  def update_volume_slider(self):
461
477
  """Update volume slider"""
462
478
  if self.audio:
463
- self.volume_slider.setValue(int(self.audio.volume() * 100))
479
+ v = int(self.audio.volume() * 100)
480
+ if self.volume_slider.value() != v:
481
+ block = self.volume_slider.blockSignals(True)
482
+ self.volume_slider.setValue(v)
483
+ self.volume_slider.blockSignals(block)
464
484
 
465
485
  def update_ui(self):
466
486
  """Update UI"""
467
- if self.player:
468
- self.position_changed(self.player.position())
487
+ if self.player and not self.seeking:
488
+ pos = self.player.position()
489
+ if pos != self._last_position:
490
+ self._last_position = pos
491
+ self.slider.setValue(pos)
492
+ self.label_time.setText(self.format_time(pos))
469
493
 
470
494
  def format_time(self, ms):
471
495
  """
@@ -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.26 15:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction, QIcon, QKeySequence
@@ -14,8 +14,6 @@ from PySide6.QtGui import QAction, QIcon, QKeySequence
14
14
  from pygpt_net.ui.widget.textarea.editor import BaseCodeEditor
15
15
  from pygpt_net.utils import trans
16
16
 
17
- import pygpt_net.icons_rc
18
-
19
17
  class TextFileEditor(BaseCodeEditor):
20
18
  def __init__(self, window=None):
21
19
  """
@@ -23,7 +21,7 @@ class TextFileEditor(BaseCodeEditor):
23
21
 
24
22
  :param window: main window
25
23
  """
26
- super(TextFileEditor, self).__init__(window)
24
+ super().__init__(window)
27
25
  self.window = window
28
26
  self.setReadOnly(True)
29
27
  self.value = 12
@@ -33,6 +31,10 @@ class TextFileEditor(BaseCodeEditor):
33
31
  self.default_stylesheet = ""
34
32
  self.setStyleSheet(self.default_stylesheet)
35
33
 
34
+ self._icon_volume = QIcon(":/icons/volume.svg")
35
+ self._icon_save = QIcon(":/icons/save.svg")
36
+ self._icon_search = QIcon(":/icons/search.svg")
37
+
36
38
  def contextMenuEvent(self, event):
37
39
  """
38
40
  Context menu event
@@ -40,38 +42,35 @@ class TextFileEditor(BaseCodeEditor):
40
42
  :param event: Event
41
43
  """
42
44
  menu = self.createStandardContextMenu()
43
- selected_text = self.textCursor().selectedText()
45
+ cursor = self.textCursor()
44
46
 
45
- if selected_text:
46
- # plain text
47
- plain_text = self.textCursor().selection().toPlainText()
47
+ if cursor.hasSelection():
48
+ selected_text = cursor.selectedText()
49
+ plain_text = cursor.selection().toPlainText()
48
50
 
49
- # audio read
50
- action = QAction(QIcon(":/icons/volume.svg"), trans('text.context_menu.audio.read'), self)
51
+ action = QAction(self._icon_volume, trans('text.context_menu.audio.read'), menu)
51
52
  action.triggered.connect(self.audio_read_selection)
52
53
  menu.addAction(action)
53
54
 
54
- # copy to
55
- copy_to_menu = self.window.ui.context_menu.get_copy_to_menu(self, selected_text)
55
+ copy_to_menu = self.window.ui.context_menu.get_copy_to_menu(menu, selected_text)
56
56
  menu.addMenu(copy_to_menu)
57
57
 
58
- # save as (selected)
59
- action = QAction(QIcon(":/icons/save.svg"), trans('action.save_as'), self)
58
+ action = QAction(self._icon_save, trans('action.save_as'), menu)
60
59
  action.triggered.connect(
61
60
  lambda: self.window.controller.chat.common.save_text(plain_text)
62
61
  )
63
62
  menu.addAction(action)
64
63
  else:
65
- # save as (all)
66
- action = QAction(QIcon(":/icons/save.svg"), trans('action.save_as'), self)
64
+ action = QAction(self._icon_save, trans('action.save_as'), menu)
67
65
  action.triggered.connect(
68
66
  lambda: self.window.controller.chat.common.save_text(self.toPlainText())
69
67
  )
70
68
  menu.addAction(action)
71
69
 
72
- action = QAction(QIcon(":/icons/search.svg"), trans('text.context_menu.find'), self)
70
+ action = QAction(self._icon_search, trans('text.context_menu.find'), menu)
73
71
  action.triggered.connect(self.find_open)
74
- action.setShortcut(QKeySequence("Ctrl+F"))
72
+ action.setShortcut(QKeySequence.StandardKey.Find)
75
73
  menu.addAction(action)
76
74
 
77
- menu.exec_(event.globalPos())
75
+ menu.exec_(event.globalPos())
76
+ menu.deleteLater()
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.09 15:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt, Slot, QObject, Signal
@@ -16,7 +16,6 @@ from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QTextEdit, QWidget, QSpl
16
16
  from pygpt_net.core.text.finder import Finder
17
17
  from pygpt_net.ui.widget.option.combo import OptionCombo
18
18
 
19
- import pygpt_net.icons_rc
20
19
  from pygpt_net.ui.widget.textarea.search_input import SearchInput
21
20
  from pygpt_net.utils import trans
22
21
 
@@ -338,11 +337,11 @@ class TextareaField(QTextEdit):
338
337
 
339
338
  :param window: main window
340
339
  """
341
- super(TextareaField, self).__init__(window)
340
+ super().__init__(window)
342
341
  self.window = window
343
342
  self.id = id # assigned in setup
344
343
  self.setReadOnly(False)
345
- self.acceptRichText = False # disable rich text
344
+ self.setAcceptRichText(False)
346
345
  self.value = 12
347
346
  self.max_font_size = 42
348
347
  self.min_font_size = 8
@@ -353,6 +352,12 @@ class TextareaField(QTextEdit):
353
352
  self.finder = Finder(window, self)
354
353
  self.installEventFilter(self)
355
354
 
355
+ self._icon_volume = QIcon(":/icons/volume.svg")
356
+ self._icon_save = QIcon(":/icons/save.svg")
357
+ self._icon_search = QIcon(":/icons/search.svg")
358
+ self._icon_clear = QIcon(":/icons/clear.svg")
359
+ self._seq_find = QKeySequence("Ctrl+F")
360
+
356
361
  # tabulation
357
362
  metrics = QFontMetrics(self.font())
358
363
  space_width = metrics.horizontalAdvance(" ")
@@ -381,7 +386,6 @@ class TextareaField(QTextEdit):
381
386
  """
382
387
  return super().eventFilter(source, event)
383
388
 
384
-
385
389
  def contextMenuEvent(self, event):
386
390
  """
387
391
  Context menu event
@@ -389,13 +393,14 @@ class TextareaField(QTextEdit):
389
393
  :param event: Event
390
394
  """
391
395
  menu = self.createStandardContextMenu()
392
- selected_text = self.textCursor().selectedText()
396
+ cursor = self.textCursor()
397
+ selected_text = cursor.selectedText()
393
398
  if selected_text:
394
399
  # plain text
395
- plain_text = self.textCursor().selection().toPlainText()
400
+ plain_text = cursor.selection().toPlainText()
396
401
 
397
402
  # audio read
398
- action = QAction(QIcon(":/icons/volume.svg"), trans('text.context_menu.audio.read'), self)
403
+ action = QAction(self._icon_volume, trans('text.context_menu.audio.read'), menu)
399
404
  action.triggered.connect(self.audio_read_selection)
400
405
  menu.addAction(action)
401
406
 
@@ -405,31 +410,31 @@ class TextareaField(QTextEdit):
405
410
  excluded = ["translator_left"]
406
411
  elif self.id == "right":
407
412
  excluded = ["translator_right"]
408
- copy_to_menu = self.window.ui.context_menu.get_copy_to_menu(self, selected_text, excluded=excluded)
409
- menu.addMenu(copy_to_menu)
413
+ copy_to_menu = self.window.ui.context_menu.get_copy_to_menu(menu, selected_text, excluded=excluded)
414
+ if copy_to_menu is not None:
415
+ menu.addMenu(copy_to_menu)
410
416
 
411
417
  # save as (selected)
412
- action = QAction(QIcon(":/icons/save.svg"), trans('action.save_selection_as'), self)
413
- action.triggered.connect(
414
- lambda: self.window.controller.chat.common.save_text(plain_text))
418
+ action = QAction(self._icon_save, trans('action.save_selection_as'), menu)
419
+ action.triggered.connect(lambda pt=plain_text: self.window.controller.chat.common.save_text(pt))
415
420
  menu.addAction(action)
416
421
  else:
417
422
  # save as (all)
418
- action = QAction(QIcon(":/icons/save.svg"), trans('action.save_as'), self)
419
- action.triggered.connect(
420
- lambda: self.window.controller.chat.common.save_text(self.toPlainText()))
423
+ action = QAction(self._icon_save, trans('action.save_as'), menu)
424
+ action.triggered.connect(lambda: self.window.controller.chat.common.save_text(self.toPlainText()))
421
425
  menu.addAction(action)
422
426
 
423
- action = QAction(QIcon(":/icons/search.svg"), trans('text.context_menu.find'), self)
427
+ action = QAction(self._icon_search, trans('text.context_menu.find'), menu)
424
428
  action.triggered.connect(self.find_open)
425
- action.setShortcut(QKeySequence("Ctrl+F"))
429
+ action.setShortcut(self._seq_find)
426
430
  menu.addAction(action)
427
431
 
428
- action = QAction(QIcon(":/icons/clear.svg"), trans('translators.menu.file.clear'), self)
432
+ action = QAction(self._icon_clear, trans('translators.menu.file.clear'), menu)
429
433
  action.triggered.connect(self.action_clear)
430
434
  menu.addAction(action)
431
435
 
432
436
  menu.exec_(event.globalPos())
437
+ menu.deleteLater()
433
438
 
434
439
  def action_clear(self):
435
440
  """
@@ -462,9 +467,9 @@ class TextareaField(QTextEdit):
462
467
  """
463
468
  if e.key() == Qt.Key_F and e.modifiers() & Qt.ControlModifier:
464
469
  self.find_open()
465
- else:
466
- self.finder.clear(restore=True, to_end=False)
467
- super(TextareaField, self).keyPressEvent(e)
470
+ return
471
+ self.finder.clear(restore=True, to_end=False)
472
+ super().keyPressEvent(e)
468
473
 
469
474
  def update_stylesheet(self, data: str):
470
475
  """
@@ -472,7 +477,9 @@ class TextareaField(QTextEdit):
472
477
 
473
478
  :param data: stylesheet CSS
474
479
  """
475
- self.setStyleSheet(self.default_stylesheet + data)
480
+ combined = self.default_stylesheet + data
481
+ if combined != self.styleSheet():
482
+ self.setStyleSheet(combined)
476
483
 
477
484
  def wheelEvent(self, event):
478
485
  """
@@ -481,17 +488,14 @@ class TextareaField(QTextEdit):
481
488
  :param event: Event
482
489
  """
483
490
  if event.modifiers() & Qt.ControlModifier:
484
- if event.angleDelta().y() > 0:
485
- if self.value < self.max_font_size:
486
- self.value += 1
487
- else:
488
- if self.value > self.min_font_size:
489
- self.value -= 1
490
-
491
- self.update_stylesheet(f"QTextEdit {{ font-size: {self.value}px }};")
491
+ delta = 1 if event.angleDelta().y() > 0 else -1
492
+ new_value = max(self.min_font_size, min(self.max_font_size, self.value + delta))
493
+ if new_value != self.value:
494
+ self.value = new_value
495
+ self.update_stylesheet(f"QTextEdit {{ font-size: {self.value}px }};")
492
496
  event.accept()
493
- else:
494
- super(TextareaField, self).wheelEvent(event)
497
+ return
498
+ super().wheelEvent(event)
495
499
 
496
500
  def focusInEvent(self, e):
497
501
  """
@@ -500,7 +504,7 @@ class TextareaField(QTextEdit):
500
504
  :param e: focus event
501
505
  """
502
506
  self.window.controller.finder.focus_in(self.finder)
503
- super(TextareaField, self).focusInEvent(e)
507
+ super().focusInEvent(e)
504
508
 
505
509
  def focusOutEvent(self, e):
506
510
  """
@@ -508,7 +512,7 @@ class TextareaField(QTextEdit):
508
512
 
509
513
  :param e: focus event
510
514
  """
511
- super(TextareaField, self).focusOutEvent(e)
515
+ super().focusOutEvent(e)
512
516
  self.window.controller.finder.focus_out(self.finder)
513
517
 
514
518
 
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.15 03:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtWidgets import QMenu
@@ -14,10 +14,10 @@ from PySide6.QtGui import QAction, QIcon
14
14
 
15
15
  from pygpt_net.core.tabs.tab import Tab
16
16
  from pygpt_net.utils import trans
17
- import pygpt_net.icons_rc
18
17
 
19
18
 
20
19
  class ContextMenu:
20
+
21
21
  _ICON_INPUT = QIcon(":/icons/input.svg")
22
22
  _ICON_SCHEDULE = QIcon(":/icons/schedule.svg")
23
23
  _ICON_PASTE = QIcon(":/icons/paste.svg")
@@ -32,11 +32,16 @@ class ContextMenu:
32
32
  """
33
33
  self.window = window
34
34
 
35
- def get_copy_to_menu(self, parent, selected_text: str = None, excluded: list = None) -> QMenu:
35
+ def get_copy_to_menu(
36
+ self,
37
+ parent,
38
+ selected_text: str = None,
39
+ excluded: list = None
40
+ ) -> QMenu:
36
41
  """
37
42
  Get copy to menu
38
43
 
39
- :param parent: Parent widget
44
+ :param parent: Parent menu
40
45
  :param selected_text: Selected text
41
46
  :param excluded: Excluded items
42
47
  :return: Menu
pygpt_net/ui/dialog/db.py CHANGED
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.04.17 01:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt
@@ -17,8 +17,6 @@ from PySide6.QtWidgets import QGridLayout, QScrollArea, QSplitter, QComboBox, QL
17
17
  from pygpt_net.ui.widget.dialog.db import DatabaseDialog
18
18
  from pygpt_net.ui.widget.lists.db import DatabaseList, DatabaseTableModel
19
19
  from pygpt_net.ui.widget.textarea.editor import CodeEditor
20
-
21
- import pygpt_net.icons_rc
22
20
  from pygpt_net.utils import trans
23
21
 
24
22
 
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.02 20:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -30,8 +30,6 @@ from pygpt_net.ui.widget.option.slider import OptionSlider
30
30
  from pygpt_net.ui.widget.option.textarea import OptionTextarea
31
31
  from pygpt_net.utils import trans
32
32
 
33
- import pygpt_net.icons_rc
34
-
35
33
  class Models:
36
34
  def __init__(self, window=None):
37
35
  """
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.02 20:00:00 #
9
+ # Updated Date: 2025.08.24 23:00:00 #
10
10
  # ================================================== #
11
11
  from PySide6 import QtCore
12
12
  from PySide6.QtGui import QIcon
@@ -14,11 +14,9 @@ from PySide6.QtWidgets import QPushButton, QHBoxLayout, QVBoxLayout, QLabel
14
14
 
15
15
  from pygpt_net.ui.widget.lists.model_importer import ModelImporter
16
16
  from pygpt_net.ui.widget.dialog.model_importer import ModelImporterOllamaDialog
17
- from pygpt_net.ui.widget.option.combo import NoScrollCombo, OptionCombo
17
+ from pygpt_net.ui.widget.option.combo import OptionCombo
18
18
  from pygpt_net.utils import trans
19
19
 
20
- import pygpt_net.icons_rc
21
-
22
20
 
23
21
  class ModelsImporter:
24
22
  def __init__(self, window=None):