pygpt-net 2.6.28__py3-none-any.whl → 2.6.30__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 (115) hide show
  1. pygpt_net/CHANGELOG.txt +13 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/{container.py → app_core.py} +5 -6
  4. pygpt_net/controller/access/control.py +1 -9
  5. pygpt_net/controller/assistant/assistant.py +4 -4
  6. pygpt_net/controller/assistant/batch.py +7 -7
  7. pygpt_net/controller/assistant/files.py +4 -4
  8. pygpt_net/controller/assistant/threads.py +3 -3
  9. pygpt_net/controller/attachment/attachment.py +4 -7
  10. pygpt_net/controller/chat/common.py +1 -1
  11. pygpt_net/controller/chat/stream.py +961 -294
  12. pygpt_net/controller/chat/vision.py +11 -19
  13. pygpt_net/controller/config/placeholder.py +1 -1
  14. pygpt_net/controller/ctx/ctx.py +1 -1
  15. pygpt_net/controller/ctx/summarizer.py +1 -1
  16. pygpt_net/controller/mode/mode.py +21 -12
  17. pygpt_net/controller/plugins/settings.py +3 -2
  18. pygpt_net/controller/presets/editor.py +112 -99
  19. pygpt_net/controller/theme/common.py +2 -0
  20. pygpt_net/controller/theme/theme.py +6 -2
  21. pygpt_net/controller/ui/vision.py +4 -4
  22. pygpt_net/core/agents/legacy.py +2 -2
  23. pygpt_net/core/agents/runners/openai_workflow.py +2 -2
  24. pygpt_net/core/assistants/files.py +5 -5
  25. pygpt_net/core/assistants/store.py +4 -4
  26. pygpt_net/core/bridge/bridge.py +3 -3
  27. pygpt_net/core/bridge/worker.py +28 -9
  28. pygpt_net/core/debug/console/console.py +2 -2
  29. pygpt_net/core/debug/presets.py +2 -2
  30. pygpt_net/core/experts/experts.py +2 -2
  31. pygpt_net/core/idx/llm.py +21 -3
  32. pygpt_net/core/modes/modes.py +2 -2
  33. pygpt_net/core/presets/presets.py +3 -3
  34. pygpt_net/core/tokens/tokens.py +4 -4
  35. pygpt_net/core/types/mode.py +5 -2
  36. pygpt_net/core/vision/analyzer.py +1 -1
  37. pygpt_net/data/config/config.json +6 -3
  38. pygpt_net/data/config/models.json +75 -3
  39. pygpt_net/data/config/modes.json +3 -9
  40. pygpt_net/data/config/settings.json +112 -55
  41. pygpt_net/data/config/settings_section.json +2 -2
  42. pygpt_net/data/locale/locale.de.ini +2 -2
  43. pygpt_net/data/locale/locale.en.ini +9 -2
  44. pygpt_net/data/locale/locale.es.ini +2 -2
  45. pygpt_net/data/locale/locale.fr.ini +2 -2
  46. pygpt_net/data/locale/locale.it.ini +2 -2
  47. pygpt_net/data/locale/locale.pl.ini +3 -3
  48. pygpt_net/data/locale/locale.uk.ini +2 -2
  49. pygpt_net/data/locale/locale.zh.ini +2 -2
  50. pygpt_net/item/model.py +23 -3
  51. pygpt_net/plugin/openai_dalle/plugin.py +4 -4
  52. pygpt_net/plugin/openai_vision/plugin.py +12 -13
  53. pygpt_net/provider/agents/openai/agent.py +5 -5
  54. pygpt_net/provider/agents/openai/agent_b2b.py +5 -5
  55. pygpt_net/provider/agents/openai/agent_planner.py +5 -6
  56. pygpt_net/provider/agents/openai/agent_with_experts.py +5 -5
  57. pygpt_net/provider/agents/openai/agent_with_experts_feedback.py +4 -4
  58. pygpt_net/provider/agents/openai/agent_with_feedback.py +4 -4
  59. pygpt_net/provider/agents/openai/bot_researcher.py +2 -2
  60. pygpt_net/provider/agents/openai/bots/research_bot/agents/planner_agent.py +1 -1
  61. pygpt_net/provider/agents/openai/bots/research_bot/agents/search_agent.py +1 -1
  62. pygpt_net/provider/agents/openai/bots/research_bot/agents/writer_agent.py +1 -1
  63. pygpt_net/provider/agents/openai/evolve.py +5 -5
  64. pygpt_net/provider/agents/openai/supervisor.py +4 -4
  65. pygpt_net/provider/api/__init__.py +27 -0
  66. pygpt_net/provider/api/anthropic/__init__.py +68 -0
  67. pygpt_net/provider/api/google/__init__.py +262 -0
  68. pygpt_net/provider/api/google/audio.py +114 -0
  69. pygpt_net/provider/api/google/chat.py +552 -0
  70. pygpt_net/provider/api/google/image.py +287 -0
  71. pygpt_net/provider/api/google/tools.py +222 -0
  72. pygpt_net/provider/api/google/vision.py +129 -0
  73. pygpt_net/provider/{gpt → api/openai}/__init__.py +2 -2
  74. pygpt_net/provider/{gpt → api/openai}/agents/computer.py +1 -1
  75. pygpt_net/provider/{gpt → api/openai}/agents/experts.py +1 -1
  76. pygpt_net/provider/{gpt → api/openai}/agents/response.py +1 -1
  77. pygpt_net/provider/{gpt → api/openai}/assistants.py +1 -1
  78. pygpt_net/provider/{gpt → api/openai}/chat.py +15 -8
  79. pygpt_net/provider/{gpt → api/openai}/completion.py +1 -1
  80. pygpt_net/provider/{gpt → api/openai}/image.py +1 -1
  81. pygpt_net/provider/{gpt → api/openai}/remote_tools.py +1 -1
  82. pygpt_net/provider/{gpt → api/openai}/responses.py +34 -20
  83. pygpt_net/provider/{gpt → api/openai}/store.py +2 -2
  84. pygpt_net/provider/{gpt → api/openai}/vision.py +1 -1
  85. pygpt_net/provider/{gpt → api/openai}/worker/assistants.py +4 -4
  86. pygpt_net/provider/{gpt → api/openai}/worker/importer.py +10 -10
  87. pygpt_net/provider/audio_input/openai_whisper.py +1 -1
  88. pygpt_net/provider/audio_output/google_tts.py +12 -0
  89. pygpt_net/provider/audio_output/openai_tts.py +1 -1
  90. pygpt_net/provider/core/config/patch.py +11 -0
  91. pygpt_net/provider/core/model/patch.py +9 -0
  92. pygpt_net/provider/core/preset/json_file.py +2 -4
  93. pygpt_net/provider/llms/anthropic.py +2 -5
  94. pygpt_net/provider/llms/base.py +4 -3
  95. pygpt_net/provider/llms/openai.py +1 -1
  96. pygpt_net/provider/loaders/hub/image_vision/base.py +1 -1
  97. pygpt_net/ui/dialog/preset.py +71 -55
  98. pygpt_net/ui/main.py +6 -4
  99. pygpt_net/utils.py +9 -0
  100. {pygpt_net-2.6.28.dist-info → pygpt_net-2.6.30.dist-info}/METADATA +42 -48
  101. {pygpt_net-2.6.28.dist-info → pygpt_net-2.6.30.dist-info}/RECORD +115 -107
  102. /pygpt_net/provider/{gpt → api/openai}/agents/__init__.py +0 -0
  103. /pygpt_net/provider/{gpt → api/openai}/agents/client.py +0 -0
  104. /pygpt_net/provider/{gpt → api/openai}/agents/remote_tools.py +0 -0
  105. /pygpt_net/provider/{gpt → api/openai}/agents/utils.py +0 -0
  106. /pygpt_net/provider/{gpt → api/openai}/audio.py +0 -0
  107. /pygpt_net/provider/{gpt → api/openai}/computer.py +0 -0
  108. /pygpt_net/provider/{gpt → api/openai}/container.py +0 -0
  109. /pygpt_net/provider/{gpt → api/openai}/summarizer.py +0 -0
  110. /pygpt_net/provider/{gpt → api/openai}/tools.py +0 -0
  111. /pygpt_net/provider/{gpt → api/openai}/utils.py +0 -0
  112. /pygpt_net/provider/{gpt → api/openai}/worker/__init__.py +0 -0
  113. {pygpt_net-2.6.28.dist-info → pygpt_net-2.6.30.dist-info}/LICENSE +0 -0
  114. {pygpt_net-2.6.28.dist-info → pygpt_net-2.6.30.dist-info}/WHEEL +0 -0
  115. {pygpt_net-2.6.28.dist-info → pygpt_net-2.6.30.dist-info}/entry_points.txt +0 -0
@@ -6,12 +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.14 13:00:00 #
9
+ # Updated Date: 2025.08.28 09:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt
13
13
  from PySide6.QtWidgets import QPushButton, QHBoxLayout, QLabel, QVBoxLayout, QSplitter, QWidget, QSizePolicy, \
14
- QTabWidget, QLineEdit, QFileDialog
14
+ QTabWidget, QFileDialog
15
15
 
16
16
  from pygpt_net.core.types import (
17
17
  MODE_AGENT,
@@ -51,12 +51,8 @@ class Preset(BaseConfigDialog):
51
51
  """Setup preset editor dialog"""
52
52
  self.window.ui.nodes['preset.btn.current'] = QPushButton(trans("dialog.preset.btn.current"))
53
53
  self.window.ui.nodes['preset.btn.save'] = QPushButton(trans("dialog.preset.btn.save"))
54
- self.window.ui.nodes['preset.btn.current'].clicked.connect(
55
- lambda: self.window.controller.presets.editor.from_current()
56
- )
57
- self.window.ui.nodes['preset.btn.save'].clicked.connect(
58
- lambda: self.window.controller.presets.editor.save()
59
- )
54
+ self.window.ui.nodes['preset.btn.current'].clicked.connect(self.window.controller.presets.editor.from_current)
55
+ self.window.ui.nodes['preset.btn.save'].clicked.connect(self.window.controller.presets.editor.save)
60
56
 
61
57
  self.window.ui.nodes['preset.btn.current'].setAutoDefault(False)
62
58
  self.window.ui.nodes['preset.btn.save'].setAutoDefault(True)
@@ -119,14 +115,14 @@ class Preset(BaseConfigDialog):
119
115
  mode_keys_middle = [
120
116
  MODE_COMPLETION,
121
117
  MODE_IMAGE,
122
- MODE_VISION,
118
+ # MODE_VISION,
123
119
  MODE_COMPUTER,
120
+ MODE_EXPERT,
124
121
  ]
125
122
  mode_keys_right = [
126
123
  MODE_AGENT_LLAMA,
127
124
  MODE_AGENT_OPENAI,
128
125
  MODE_AGENT,
129
- MODE_EXPERT,
130
126
  ]
131
127
 
132
128
  rows_mode_left = QVBoxLayout()
@@ -156,17 +152,20 @@ class Preset(BaseConfigDialog):
156
152
  rows_mode.addStretch(1)
157
153
 
158
154
  # modes
159
- self.window.ui.nodes['preset.editor.modes'] = QWidget()
160
- self.window.ui.nodes['preset.editor.modes'].setLayout(rows_mode)
161
- self.window.ui.nodes['preset.editor.modes'].setContentsMargins(0, 0, 0, 0)
155
+ modes = QWidget()
156
+ modes.setLayout(rows_mode)
157
+ modes.setContentsMargins(0, 0, 0, 0)
158
+ self.window.ui.nodes['preset.editor.modes'] = modes
162
159
 
163
160
  # experts
164
161
  self.window.ui.nodes['preset.editor.experts'] = ExpertsEditor(self.window)
165
162
 
166
163
  # desc and prompt
167
- self.window.ui.nodes['preset.editor.description'] = QWidget()
168
- self.window.ui.nodes['preset.editor.description'].setLayout(options['description'])
169
- self.window.ui.nodes['preset.editor.description'].setContentsMargins(0, 5, 0, 5)
164
+ desc = QWidget()
165
+ desc.setLayout(options['description'])
166
+ desc.setContentsMargins(0, 5, 0, 5)
167
+ self.window.ui.nodes['preset.editor.description'] = desc
168
+
170
169
 
171
170
  # prompt + extra options
172
171
  prompt_layout = QVBoxLayout()
@@ -195,6 +194,7 @@ class Preset(BaseConfigDialog):
195
194
  "agent_provider_openai",
196
195
  "idx",
197
196
  ]
197
+ # personalize tab
198
198
  personalize_keys = [
199
199
  "ai_name",
200
200
  "user_name",
@@ -202,15 +202,18 @@ class Preset(BaseConfigDialog):
202
202
  "ai_personalize",
203
203
  ]
204
204
  for key in left_keys:
205
- self.window.ui.nodes['preset.editor.' + key] = QWidget()
206
- self.window.ui.nodes['preset.editor.' + key].setLayout(options[key])
207
- self.window.ui.nodes['preset.editor.' + key].setContentsMargins(0, 0, 0, 0)
208
- rows.addWidget(self.window.ui.nodes['preset.editor.' + key])
205
+ node_key = f"preset.editor.{key}"
206
+ node = QWidget()
207
+ node.setLayout(options[key])
208
+ node.setContentsMargins(0, 0, 0, 0)
209
+ rows.addWidget(node)
210
+ self.window.ui.nodes[node_key] = node
209
211
 
210
212
  # remote tools
211
- self.window.ui.nodes['preset.editor.remote_tools'] = QWidget()
212
- self.window.ui.nodes['preset.editor.remote_tools'].setLayout(options['remote_tools'])
213
- self.window.ui.nodes['preset.editor.remote_tools'].setContentsMargins(0, 0, 0, 0)
213
+ remote_tools = QWidget()
214
+ remote_tools.setLayout(options['remote_tools'])
215
+ remote_tools.setContentsMargins(0, 0, 0, 0)
216
+ self.window.ui.nodes['preset.editor.remote_tools'] = remote_tools
214
217
 
215
218
  rows_remote_tools = QVBoxLayout()
216
219
  rows_remote_tools.addWidget(self.window.ui.nodes['preset.editor.remote_tools'])
@@ -222,10 +225,12 @@ class Preset(BaseConfigDialog):
222
225
  # personalize
223
226
  personalize_rows = QVBoxLayout()
224
227
  for key in personalize_keys:
225
- self.window.ui.nodes['preset.editor.' + key] = QWidget()
226
- self.window.ui.nodes['preset.editor.' + key].setLayout(options[key])
227
- self.window.ui.nodes['preset.editor.' + key].setContentsMargins(0, 0, 0, 0)
228
- personalize_rows.addWidget(self.window.ui.nodes['preset.editor.' + key])
228
+ node_key = f"preset.editor.{key}"
229
+ node = QWidget()
230
+ node.setLayout(options[key])
231
+ node.setContentsMargins(0, 0, 0, 0)
232
+ personalize_rows.addWidget(node)
233
+ self.window.ui.nodes[node_key] = node
229
234
 
230
235
  self.window.ui.nodes['preset.editor.ai_avatar'].setVisible(False)
231
236
 
@@ -255,11 +260,12 @@ class Preset(BaseConfigDialog):
255
260
  widget_main = QWidget()
256
261
  widget_main.setLayout(main)
257
262
 
258
- self.window.ui.splitters['editor.presets'] = QSplitter(Qt.Vertical)
259
- self.window.ui.splitters['editor.presets'].addWidget(widget_main)
260
- self.window.ui.splitters['editor.presets'].addWidget(widget_prompt)
261
- self.window.ui.splitters['editor.presets'].setStretchFactor(0, 1)
262
- self.window.ui.splitters['editor.presets'].setStretchFactor(1, 2)
263
+ splitter = QSplitter(Qt.Vertical)
264
+ splitter.addWidget(widget_main)
265
+ splitter.addWidget(widget_prompt)
266
+ splitter.setStretchFactor(0, 1)
267
+ splitter.setStretchFactor(1, 2)
268
+ self.window.ui.splitters['editor.presets'] = splitter
263
269
 
264
270
  widget_personalize = QWidget()
265
271
  widget_personalize.setLayout(personalize_rows)
@@ -270,24 +276,26 @@ class Preset(BaseConfigDialog):
270
276
  widget_experts = QWidget()
271
277
  widget_experts.setLayout(experts_rows)
272
278
 
273
- self.window.ui.tabs['preset.editor.tabs'] = QTabWidget()
274
- self.window.ui.tabs['preset.editor.tabs'].addTab(self.window.ui.splitters['editor.presets'], trans("preset.tab.general"))
275
- self.window.ui.tabs['preset.editor.tabs'].addTab(widget_personalize, trans("preset.tab.personalize"))
276
- self.window.ui.tabs['preset.editor.tabs'].addTab(widget_experts, trans("preset.tab.experts"))
277
- self.window.ui.tabs['preset.editor.tabs'].addTab(widget_remote_tools, trans("preset.tab.remote_tools"))
279
+ tabs = QTabWidget()
280
+ tabs.addTab(splitter, trans("preset.tab.general"))
281
+ tabs.addTab(widget_personalize, trans("preset.tab.personalize"))
282
+ tabs.addTab(widget_experts, trans("preset.tab.experts"))
283
+ tabs.addTab(widget_remote_tools, trans("preset.tab.remote_tools"))
284
+ self.window.ui.tabs['preset.editor.tabs'] = tabs
278
285
 
279
286
  layout = QVBoxLayout()
280
287
  layout.addWidget(self.window.ui.tabs['preset.editor.tabs'])
281
288
  layout.addLayout(footer)
282
289
 
283
- self.window.ui.dialog['editor.' + self.dialog_id] = EditorDialog(self.window, self.dialog_id)
284
- self.window.ui.dialog['editor.' + self.dialog_id].setSizeGripEnabled(True)
285
- self.window.ui.dialog['editor.' + self.dialog_id].setWindowFlags(
286
- self.window.ui.dialog['editor.' + self.dialog_id].windowFlags() | Qt.WindowMaximizeButtonHint
290
+ dialog = EditorDialog(self.window, self.dialog_id)
291
+ dialog.setSizeGripEnabled(True)
292
+ dialog.setWindowFlags(
293
+ dialog.windowFlags() | Qt.WindowMaximizeButtonHint
287
294
  )
288
- self.window.ui.dialog['editor.' + self.dialog_id].setLayout(layout)
289
- self.window.ui.dialog['editor.' + self.dialog_id].setWindowTitle(trans('dialog.preset'))
290
- self.window.ui.dialog['editor.' + self.dialog_id].on_close_callback = self.on_close
295
+ dialog.setLayout(layout)
296
+ dialog.setWindowTitle(trans('dialog.preset'))
297
+ dialog.on_close_callback = self.on_close
298
+ self.window.ui.dialog['editor.' + self.dialog_id] = dialog
291
299
 
292
300
 
293
301
  def prepare_extra_config(self, prompt_layout):
@@ -301,15 +309,17 @@ class Preset(BaseConfigDialog):
301
309
  prompt_widget.setLayout(prompt_layout)
302
310
 
303
311
  self.window.ui.nodes['preset.editor.extra'] = {}
304
- self.window.ui.tabs['preset.editor.extra'] = QTabWidget()
305
- self.window.ui.tabs['preset.editor.extra'].addTab(
312
+
313
+ tabs = QTabWidget()
314
+ tabs.addTab(
306
315
  prompt_widget,
307
316
  trans("preset.prompt"),
308
317
  )
309
- self.window.ui.tabs['preset.editor.extra'].setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
310
- self.window.ui.tabs['preset.editor.extra'].setMinimumHeight(150)
318
+ tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
319
+ tabs.setMinimumHeight(150)
311
320
  layout = QVBoxLayout()
312
- layout.addWidget(self.window.ui.tabs['preset.editor.extra'])
321
+ layout.addWidget(tabs)
322
+ self.window.ui.tabs['preset.editor.extra'] = tabs
313
323
  return layout
314
324
 
315
325
 
@@ -368,6 +378,7 @@ class AvatarWidget(QWidget):
368
378
  self.init_ui()
369
379
 
370
380
  def init_ui(self):
381
+ """Initialize the avatar widget UI."""
371
382
  main_layout = QVBoxLayout(self)
372
383
  main_layout.setContentsMargins(0, 0, 0, 0)
373
384
 
@@ -397,13 +408,19 @@ class AvatarWidget(QWidget):
397
408
  main_layout.addStretch()
398
409
 
399
410
  def open_file_dialog(self):
411
+ """Open a file dialog to select an avatar image file."""
400
412
  file_name, _ = QFileDialog.getOpenFileName(
401
413
  self, trans("preset.personalize.avatar.choose.title"), "", "Images (*.png *.jpg *.jpeg *.bmp *.gif *.webp)"
402
414
  )
403
415
  if file_name:
404
416
  self.window.controller.presets.editor.upload_avatar(file_name)
405
417
 
406
- def load_avatar(self, file_path):
418
+ def load_avatar(self, file_path: str):
419
+ """
420
+ Load and display the avatar image from the given file path.
421
+
422
+ :param file_path: Path to the avatar image file
423
+ """
407
424
  from PySide6.QtGui import QPixmap
408
425
  pixmap = QPixmap(file_path)
409
426
  if not pixmap.isNull():
@@ -420,9 +437,7 @@ class AvatarWidget(QWidget):
420
437
  self.remove_button.setEnabled(enabled)
421
438
 
422
439
  def disable_remove_button(self):
423
- """
424
- Disable the remove button.
425
- """
440
+ """Disable the remove button."""
426
441
  self.enable_remove_button(False)
427
442
 
428
443
  def get_cover_pixmap(self, pixmap, target_width, target_height):
@@ -432,6 +447,7 @@ class AvatarWidget(QWidget):
432
447
  :param pixmap: Original pixmap
433
448
  :param target_width: Target width for the avatar preview
434
449
  :param target_height: Target height for the avatar preview
450
+ :return: Scaled and cropped pixmap
435
451
  """
436
452
  factor = max(target_width / pixmap.width(), target_height / pixmap.height())
437
453
  new_width = int(pixmap.width() * factor)
@@ -439,9 +455,9 @@ class AvatarWidget(QWidget):
439
455
  scaled_pix = pixmap.scaled(new_width, new_height, Qt.KeepAspectRatio, Qt.SmoothTransformation)
440
456
  x = (scaled_pix.width() - target_width) // 2
441
457
  y = (scaled_pix.height() - target_height) // 2
442
- cropped_pix = scaled_pix.copy(x, y, target_width, target_height)
443
- return cropped_pix
458
+ return scaled_pix.copy(x, y, target_width, target_height)
444
459
 
445
460
  def remove_avatar(self):
461
+ """Remove the current avatar image."""
446
462
  self.avatar_preview.clear()
447
463
  self.remove_button.setEnabled(False)
pygpt_net/ui/main.py CHANGED
@@ -17,12 +17,13 @@ from PySide6.QtWidgets import QMainWindow, QApplication
17
17
  from qt_material import QtStyleTools
18
18
 
19
19
  from pygpt_net.core.events import BaseEvent, KernelEvent, ControlEvent
20
- from pygpt_net.container import Container
20
+ from pygpt_net.app_core import Core
21
21
  from pygpt_net.controller import Controller
22
22
  from pygpt_net.tools import Tools
23
23
  from pygpt_net.ui import UI
24
24
  from pygpt_net.ui.widget.textarea.web import ChatWebOutput
25
- from pygpt_net.utils import get_app_meta
25
+ from pygpt_net.utils import get_app_meta, freeze_updates
26
+
26
27
 
27
28
  class MainWindow(QMainWindow, QtStyleTools):
28
29
 
@@ -63,7 +64,7 @@ class MainWindow(QMainWindow, QtStyleTools):
63
64
  self.meta = get_app_meta()
64
65
 
65
66
  # setup service container
66
- self.core = Container(self)
67
+ self.core = Core(self)
67
68
  self.core.init()
68
69
  self.core.patch() # patch version if needed
69
70
  self.core.post_setup()
@@ -85,7 +86,8 @@ class MainWindow(QMainWindow, QtStyleTools):
85
86
 
86
87
  # setup UI
87
88
  self.ui = UI(self)
88
- self.ui.init()
89
+ with freeze_updates(self):
90
+ self.ui.init()
89
91
 
90
92
  # global shortcuts
91
93
  self.shortcuts = []
pygpt_net/utils.py CHANGED
@@ -13,6 +13,7 @@ import json
13
13
  import os
14
14
  import re
15
15
  from datetime import datetime
16
+ from contextlib import contextmanager
16
17
 
17
18
  from PySide6 import QtCore, QtGui
18
19
  from PySide6.QtWidgets import QApplication
@@ -61,6 +62,14 @@ def trans(key: str, reload: bool = False, domain: str = None) -> str:
61
62
  return locale.get(key, domain)
62
63
 
63
64
 
65
+ @contextmanager
66
+ def freeze_updates(widget):
67
+ widget.setUpdatesEnabled(False)
68
+ try:
69
+ yield
70
+ finally:
71
+ widget.setUpdatesEnabled(True)
72
+
64
73
  def get_init_value(key: str = "__version__") -> str:
65
74
  """
66
75
  Return config value from __init__.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pygpt-net
3
- Version: 2.6.28
3
+ Version: 2.6.30
4
4
  Summary: Desktop AI Assistant powered by: OpenAI GPT-5, GPT-4, o1, o3, Gemini, Claude, Grok, DeepSeek, and other models supported by Llama Index, and Ollama. Chatbot, agents, completion, image generation, vision analysis, speech-to-text, plugins, internet access, file handling, command execution and more.
5
5
  License: MIT
6
6
  Keywords: ai,api,api key,app,assistant,bielik,chat,chatbot,chatgpt,claude,dall-e,deepseek,desktop,gemini,gpt,gpt-3.5,gpt-4,gpt-4-vision,gpt-4o,gpt-5,gpt-oss,gpt3.5,gpt4,grok,langchain,llama-index,llama3,mistral,o1,o3,ollama,openai,presets,py-gpt,py_gpt,pygpt,pyside,qt,text completion,tts,ui,vision,whisper
@@ -117,7 +117,7 @@ Description-Content-Type: text/markdown
117
117
 
118
118
  [![pygpt](https://snapcraft.io/pygpt/badge.svg)](https://snapcraft.io/pygpt)
119
119
 
120
- Release: **2.6.28** | build: **2025-08-27** | Python: **>=3.10, <3.14**
120
+ Release: **2.6.30** | build: **2025-08-29** | Python: **>=3.10, <3.14**
121
121
 
122
122
  > Official website: https://pygpt.net | Documentation: https://pygpt.readthedocs.io
123
123
  >
@@ -157,7 +157,7 @@ You can download compiled 64-bit versions for Windows and Linux here: https://py
157
157
 
158
158
  - Desktop AI Assistant for `Linux`, `Windows` and `Mac`, written in Python.
159
159
  - Works similarly to `ChatGPT`, but locally (on a desktop computer).
160
- - 12 modes of operation: Chat, Chat with Files, Chat with Audio, Research (Perplexity), Completion, Image generation, Vision, Assistants, Experts, Computer use, Agents and Autonomous Mode.
160
+ - 11 modes of operation: Chat, Chat with Files, Chat with Audio, Research (Perplexity), Completion, Image generation, Assistants, Experts, Computer use, Agents and Autonomous Mode.
161
161
  - Supports multiple models like `OpenAI GPT-5`, `GPT-4`, `o1`, `o3`, `o4`, `Google Gemini`, `Anthropic Claude`, `xAI Grok`, `DeepSeek V3/R1`, `Perplexity / Sonar`, and any model accessible through `LlamaIndex` and `Ollama` such as `DeepSeek`, `gpt-oss`, `Llama 3`, `Mistral`, `Bielik`, etc.
162
162
  - Chat with your own Files: integrated `LlamaIndex` support: chat with data such as: `txt`, `pdf`, `csv`, `html`, `md`, `docx`, `json`, `epub`, `xlsx`, `xml`, webpages, `Google`, `GitHub`, video/audio, images and other data types, or use conversation history as additional context provided to the model.
163
163
  - Built-in vector databases support and automated files and data embedding.
@@ -181,7 +181,7 @@ You can download compiled 64-bit versions for Windows and Linux here: https://py
181
181
  - Includes simple painter / drawing tool.
182
182
  - Supports multiple languages.
183
183
  - Requires no previous knowledge of using AI models.
184
- - Simplifies image generation using `DALL-E`.
184
+ - Simplifies image generation using image models like `DALL-E` and `Imagen`.
185
185
  - Fully configurable.
186
186
  - Themes support.
187
187
  - Real-time code syntax highlighting.
@@ -439,9 +439,9 @@ Alternatively, you can try removing snap and reinstalling it:
439
439
  `sudo snap install pygpt`
440
440
 
441
441
 
442
- **Access to microphone and audio in Windows version:**
442
+ **Access to a microphone and audio in Windows version:**
443
443
 
444
- If you have a problems with audio or microphone in the non-binary PIP/Python version on Windows, check to see if FFmpeg is installed. If it's not, install it and add it to the PATH. You can find a tutorial on how to do this here: https://phoenixnap.com/kb/ffmpeg-windows. The binary version already includes FFmpeg.
444
+ If you have a problems with audio or a microphone in the non-binary PIP/Python version on Windows, check to see if FFmpeg is installed. If it's not, install it and add it to the PATH. You can find a tutorial on how to do this here: https://phoenixnap.com/kb/ffmpeg-windows. The binary version already includes FFmpeg.
445
445
 
446
446
  **Windows and VC++ Redistributable**
447
447
 
@@ -519,9 +519,16 @@ Here, you can add or manage API keys for any supported provider.
519
519
 
520
520
  **+ Inline Vision and Image generation**
521
521
 
522
- This mode in **PyGPT** mirrors `ChatGPT`, allowing you to chat with models such as `GPT-5`, `GPT-4`, `o1`, `o3`, and`Claude`, `Gemini`, `Grok`, `Perplexity (sonar)`, `Deepseek`, and others. It works by using the `Responses` and `ChatCompletions` OpenAI API (or compatible). You can select the API endpoint to use in: `Config -> Settings -> API Keys`.
522
+ In **PyGPT**, this mode mirrors `ChatGPT`, allowing you to chat with models like `GPT-5`, `GPT-4`, `o1`, `o3`, `Claude`, `Gemini`, `Grok`, `Perplexity (Sonar)`, `Deepseek`, and more. It works using the OpenAI API `Responses` and `ChatCompletions`, or the `Google GenAI SDK` if the Google native client is enabled. You can choose the API endpoint for `ChatCompletions` in `Config -> Settings -> API Keys`.
523
523
 
524
- **Tip: This mode directly uses the OpenAI SDK. Other models, such as Gemini, Claude, Grok, Sonar, or Llama3, are supported in Chat mode via LlamaIndex or OpenAI API compatible endpoints (if available), which the application switches to in the background when working with models other than OpenAI.**
524
+ **Tip:** This mode uses the provider SDK directly. If there's no native client built into the app, models like Gemini, Claude, Grok, Sonar, or Llama3 are supported in Chat mode via LlamaIndex or compatible OpenAI API endpoints. The app automatically switches to these endpoints when using non-OpenAI models.
525
+
526
+ Currently built-in native clients:
527
+
528
+ - OpenAI SDK
529
+ - Google GenAI SDK
530
+
531
+ Support for Anthropic and xAI native clients is coming soon.
525
532
 
526
533
  The main part of the interface is a chat window where you see your conversations. Below it is a message box for typing. On the right side, you can set up or change the model and system prompt. You can also save these settings as presets to easily switch between models or tasks.
527
534
 
@@ -683,17 +690,16 @@ From version `2.0.107` the `davinci` models are deprecated and has been replaced
683
690
 
684
691
  ## Image generation
685
692
 
686
- ### DALL-E 3
693
+ ### OpenAI DALL-E 3 / Google Imagen 3 and 4
687
694
 
688
- **PyGPT** enables quick and easy image creation with `DALL-E 3` or `gpt-image-1`.
689
- The older model version, `DALL-E 2`, is also accessible. Generating images is akin to a chat conversation - a user's prompt triggers the generation, followed by downloading, saving to the computer,
690
- and displaying the image onscreen. You can send raw prompt to `DALL-E` in `Image generation` mode or ask the model for the best prompt.
695
+ **PyGPT** enables quick and easy image creation with image models like `DALL-E 3`, `gpt-image-1` or `Google Imagen`.
696
+ Generating images is akin to a chat conversation - a user's prompt triggers the generation, followed by downloading, saving to the computer, and displaying the image onscreen. You can send raw prompt to the model in `Image generation` mode or ask the model for the best prompt.
691
697
 
692
698
  ![v3_img](https://github.com/szczyglis-dev/py-gpt/raw/master/docs/source/images/v3_img.png)
693
699
 
694
- Image generation using DALL-E is available in every mode via plugin `Image Generation (inline)`. Just ask any model, in any mode, like e.g. GPT-4 to generate an image and it will do it inline, without need to mode change.
700
+ Image generation using image models is also available in every mode via plugin `Image Generation (inline)`. Just ask any model, in any mode, like e.g. GPT or Gemini to generate an image and it will do it inline, without need to mode change.
695
701
 
696
- If you want to generate images (using DALL-E) directly in chat you must enable plugin **Image generation (inline)** in the Plugins menu.
702
+ If you want to generate images directly in chat you must enable plugin **Image generation (inline)** in the Plugins menu.
697
703
  Plugin allows you to generate images in Chat mode:
698
704
 
699
705
  ![v3_img_chat](https://github.com/szczyglis-dev/py-gpt/raw/master/docs/source/images/v3_img_chat.png)
@@ -708,7 +714,7 @@ the bottom of the screen. This replaces the conversation temperature slider when
708
714
 
709
715
  There is an option for switching prompt generation mode.
710
716
 
711
- If **Raw Mode** is enabled, DALL-E will receive the prompt exactly as you have provided it.
717
+ If **Raw Mode** is enabled, a model will receive the prompt exactly as you have provided it.
712
718
  If **Raw Mode** is disabled, a model will generate the best prompt for you based on your instructions.
713
719
 
714
720
  ### Image storage
@@ -724,31 +730,6 @@ prompts for creating new images.
724
730
 
725
731
  Images are stored in ``img`` directory in **PyGPT** user data folder.
726
732
 
727
-
728
- ## Vision
729
-
730
- This mode enables image analysis using the `GPT-5`, `GPT-4o` and other vision (multimodal) models. Functioning much like the chat mode,
731
- it also allows you to upload images or provide URLs to images. The vision feature can analyze both local
732
- images and those found online.
733
-
734
- Vision is also integrated into any chat mode via plugin `Vision (inline)`. Just enable the plugin and use Vision in other work modes, such as Chat or Chat with Files.
735
-
736
- Vision mode also includes real-time video capture from camera. To capture image from camera and append it to chat just click on video at left side. You can also enable `Auto capture` - image will be captured and appended to chat message every time you send message.
737
-
738
- **1) Video camera real-time image capture**
739
-
740
- ![v3_vision_chat](https://github.com/szczyglis-dev/py-gpt/raw/master/docs/source/images/v3_vision_chat.png)
741
-
742
- **2) you can also provide an image URL**
743
-
744
- ![v2_mode_vision](https://github.com/szczyglis-dev/py-gpt/raw/master/docs/source/images/v2_mode_vision.png)
745
-
746
- **3) or you can just upload your local images or use the inline Vision in the standard chat mode:**
747
-
748
- ![v2_mode_vision_upload](https://github.com/szczyglis-dev/py-gpt/raw/master/docs/source/images/v2_mode_vision_upload.png)
749
-
750
- **Tip:** When using `Vision (inline)` by utilizing a plugin in standard mode, such as `Chat` (not `Vision` mode), the `+ Vision` label will appear at the bottom of the Chat window.
751
-
752
733
  ## Assistants
753
734
 
754
735
  This mode uses the OpenAI's **Assistants API**.
@@ -2363,8 +2344,6 @@ Config -> Settings...
2363
2344
 
2364
2345
  - `Directory for file downloads`: Subdirectory for downloaded files, e.g. in Assistants mode, inside "data". Default: "download"
2365
2346
 
2366
- - `Verbose mode`: Enabled verbose mode when using attachment as additional context.
2367
-
2368
2347
  - `Model for querying index`: Model to use for preparing query and querying the index when the RAG option is selected.
2369
2348
 
2370
2349
  - `Model for attachment content summary`: Model to use when generating a summary for the content of a file when the Summary option is selected.
@@ -2569,8 +2548,6 @@ Enable/disable remote tools, like Web Search or Image generation to use in OpenA
2569
2548
 
2570
2549
  **General**
2571
2550
 
2572
- - `Verbose` - enables verbose mode.
2573
-
2574
2551
  - `Auto retrieve additional context from RAG`: Auto retrieve additional context from RAG at the beginning if the index is provided.
2575
2552
 
2576
2553
  - `Display a tray notification when the goal is achieved.`: If enabled, a notification will be displayed after goal achieved / finished run.
@@ -2641,10 +2618,12 @@ Enable/disable remote tools, like Web Search or Image generation to use in OpenA
2641
2618
 
2642
2619
  - `Check for updates in background`: Enables checking for updates in background (checking every 5 minutes). Default: True.
2643
2620
 
2644
- **Developer**
2621
+ **Debug**
2645
2622
 
2646
2623
  - `Show debug menu`: Enables debug (developer) menu.
2647
2624
 
2625
+ - `Log level`: toggle log level (ERROR|WARNING|INFO|DEBUG)
2626
+
2648
2627
  - `Log and debug context`: Enables logging of context input/output.
2649
2628
 
2650
2629
  - `Log and debug events`: Enables logging of event dispatch.
@@ -2653,12 +2632,14 @@ Enable/disable remote tools, like Web Search or Image generation to use in OpenA
2653
2632
 
2654
2633
  - `Log DALL-E usage to console`: Enables logging of DALL-E usage to console.
2655
2634
 
2635
+ - `Log attachments usage to console`: Enables logging of attachments usage to console.
2636
+
2637
+ - `Log Agents usage to console`: Enables logging of Agents usage to console.
2638
+
2656
2639
  - `Log LlamaIndex usage to console`: Enables logging of LlamaIndex usage to console.
2657
2640
 
2658
2641
  - `Log Assistants usage to console`: Enables logging of Assistants API usage to console.
2659
2642
 
2660
- - `Log level`: toggle log level (ERROR|WARNING|INFO|DEBUG)
2661
-
2662
2643
 
2663
2644
  ## JSON files
2664
2645
 
@@ -3363,7 +3344,7 @@ These wrappers are loaded into the application during startup using `launcher.ad
3363
3344
  ```python
3364
3345
  # app.py
3365
3346
 
3366
- from pygpt_net.provider.llms.openai import OpenAILLM
3347
+ from pygpt_net.provider.api.openai import OpenAILLM
3367
3348
  from pygpt_net.provider.llms.azure_openai import AzureOpenAILLM
3368
3349
  from pygpt_net.provider.llms.anthropic import AnthropicLLM
3369
3350
  from pygpt_net.provider.llms.hugging_face import HuggingFaceLLM
@@ -3575,6 +3556,19 @@ may consume additional tokens that are not displayed in the main window.
3575
3556
 
3576
3557
  ## Recent changes:
3577
3558
 
3559
+ **2.6.30 (2025-08-29)**
3560
+
3561
+ - Added native Google GenAI API support (beta); live audio is not supported yet (#132).
3562
+ - Added new predefined models for image generation: Google Imagen3 and Imagen4.
3563
+ - Optimized token usage in the Responses API.
3564
+ - Removed Vision mode (it is now integrated into Chat).
3565
+
3566
+ **2.6.29 (2025-08-28)**
3567
+
3568
+ - Verbose options have been moved to the Developer section in settings.
3569
+ - Enhanced logging of embeddings usage.
3570
+ - Fixed styles list.
3571
+
3578
3572
  **2.6.28 (2025-08-27)**
3579
3573
 
3580
3574
  - Added new plugins: Tuya (IoT) and Wikipedia.