pygpt-net 2.6.34__py3-none-any.whl → 2.6.35__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 (44) hide show
  1. pygpt_net/CHANGELOG.txt +7 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/controller/chat/common.py +8 -2
  4. pygpt_net/controller/chat/handler/stream_worker.py +55 -43
  5. pygpt_net/controller/painter/common.py +13 -1
  6. pygpt_net/controller/painter/painter.py +11 -2
  7. pygpt_net/core/bridge/bridge.py +1 -5
  8. pygpt_net/core/bridge/context.py +81 -36
  9. pygpt_net/core/bridge/worker.py +3 -1
  10. pygpt_net/core/ctx/bag.py +4 -0
  11. pygpt_net/core/events/app.py +10 -17
  12. pygpt_net/core/events/base.py +17 -25
  13. pygpt_net/core/events/control.py +9 -17
  14. pygpt_net/core/events/event.py +9 -62
  15. pygpt_net/core/events/kernel.py +8 -17
  16. pygpt_net/core/events/realtime.py +8 -17
  17. pygpt_net/core/events/render.py +9 -17
  18. pygpt_net/core/render/web/body.py +394 -36
  19. pygpt_net/core/render/web/pid.py +39 -24
  20. pygpt_net/core/render/web/renderer.py +146 -40
  21. pygpt_net/data/config/config.json +4 -3
  22. pygpt_net/data/config/models.json +3 -3
  23. pygpt_net/data/css/web-blocks.css +3 -2
  24. pygpt_net/data/css/web-chatgpt.css +3 -1
  25. pygpt_net/data/css/web-chatgpt_wide.css +3 -1
  26. pygpt_net/data/locale/locale.de.ini +1 -0
  27. pygpt_net/data/locale/locale.en.ini +3 -2
  28. pygpt_net/data/locale/locale.es.ini +1 -0
  29. pygpt_net/data/locale/locale.fr.ini +1 -0
  30. pygpt_net/data/locale/locale.it.ini +1 -0
  31. pygpt_net/data/locale/locale.pl.ini +2 -1
  32. pygpt_net/data/locale/locale.uk.ini +1 -0
  33. pygpt_net/data/locale/locale.zh.ini +1 -0
  34. pygpt_net/provider/api/google/__init__.py +14 -5
  35. pygpt_net/provider/api/openai/__init__.py +13 -10
  36. pygpt_net/provider/core/config/patch.py +9 -0
  37. pygpt_net/ui/layout/chat/painter.py +63 -4
  38. pygpt_net/ui/widget/draw/painter.py +702 -106
  39. pygpt_net/ui/widget/textarea/web.py +2 -0
  40. {pygpt_net-2.6.34.dist-info → pygpt_net-2.6.35.dist-info}/METADATA +9 -2
  41. {pygpt_net-2.6.34.dist-info → pygpt_net-2.6.35.dist-info}/RECORD +44 -44
  42. {pygpt_net-2.6.34.dist-info → pygpt_net-2.6.35.dist-info}/LICENSE +0 -0
  43. {pygpt_net-2.6.34.dist-info → pygpt_net-2.6.35.dist-info}/WHEEL +0 -0
  44. {pygpt_net-2.6.34.dist-info → pygpt_net-2.6.35.dist-info}/entry_points.txt +0 -0
@@ -81,16 +81,7 @@ class ApiOpenAI:
81
81
  """
82
82
  # update client args by mode and model
83
83
  args = self.window.core.models.prepare_client_args(mode, model)
84
- if self.client is None or self.last_client_args != args:
85
- if self.client is not None:
86
- try:
87
- self.client.close() # close previous client if exists
88
- except Exception as e:
89
- self.window.core.debug.log(e)
90
- print("Error closing previous GPT client:", e)
91
- self.client = OpenAI(**args)
92
- self.last_client_args = args
93
- return self.client
84
+ return OpenAI(**args)
94
85
 
95
86
  def call(
96
87
  self,
@@ -342,3 +333,15 @@ class ApiOpenAI:
342
333
  except Exception as e:
343
334
  self.window.core.debug.log(e)
344
335
  print("Error closing GPT client:", e)
336
+
337
+ def safe_close(self):
338
+ """Close client"""
339
+ if self.locked:
340
+ return
341
+ if self.client is not None:
342
+ try:
343
+ self.client.close()
344
+ self.client = None
345
+ except Exception as e:
346
+ self.window.core.debug.log(e)
347
+ print("Error closing client:", e)
@@ -2429,6 +2429,15 @@ class Patch:
2429
2429
  patch_css('web-blocks.css', True)
2430
2430
  updated = True
2431
2431
 
2432
+ # < 2.6.35
2433
+ if old < parse_version("2.6.35"):
2434
+ print("Migrating config from < 2.6.35...")
2435
+ # remove will-change
2436
+ patch_css('web-chatgpt.css', True)
2437
+ patch_css('web-chatgpt_wide.css', True)
2438
+ patch_css('web-blocks.css', True)
2439
+ updated = True
2440
+
2432
2441
  # update file
2433
2442
  migrated = False
2434
2443
  if updated:
@@ -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.24 23:00:00 #
9
+ # Updated Date: 2025.09.02 15:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QPixmap, QIcon
@@ -15,7 +15,6 @@ from PySide6.QtCore import QSize
15
15
 
16
16
  from pygpt_net.ui.widget.draw.painter import PainterWidget
17
17
  from pygpt_net.ui.widget.element.labels import HelpLabel
18
- from pygpt_net.ui.widget.tabs.body import TabBody
19
18
  from pygpt_net.utils import trans
20
19
 
21
20
 
@@ -90,6 +89,63 @@ class Painter:
90
89
  cb.setSizeAdjustPolicy(QComboBox.AdjustToContents)
91
90
  nodes[key] = cb
92
91
 
92
+ # Zoom combo (view-only scale) placed to the right of canvas size
93
+ key = 'painter.select.zoom'
94
+ if nodes.get(key) is None:
95
+ cb = QComboBox()
96
+ cb.setMinimumContentsLength(8)
97
+ cb.setSizeAdjustPolicy(QComboBox.AdjustToContents)
98
+
99
+ # Preferred preset steps from widget; fallback to defaults
100
+ steps = []
101
+ if hasattr(ui.painter, 'get_zoom_steps_percent'):
102
+ try:
103
+ steps = ui.painter.get_zoom_steps_percent()
104
+ except Exception:
105
+ steps = []
106
+ if not steps:
107
+ steps = [10, 25, 50, 75, 100, 150, 200, 500, 1000]
108
+
109
+ cb.addItems([f"{p}%" for p in steps])
110
+
111
+ # User -> widget
112
+ cb.currentTextChanged.connect(ui.painter.on_zoom_combo_changed)
113
+
114
+ # Widget -> combo (also covers CTRL+wheel and programmatic changes)
115
+ def _sync_zoom_combo_from_widget(z):
116
+ """Keep zoom combobox in sync with the widget's zoom."""
117
+ percent = int(round(float(z) * 100))
118
+ label = f"{percent}%"
119
+ cb.blockSignals(True)
120
+ idx = cb.findText(label)
121
+ if idx >= 0:
122
+ cb.setCurrentIndex(idx)
123
+ else:
124
+ # Insert missing value keeping ascending order
125
+ items = [cb.itemText(i) for i in range(cb.count())]
126
+ if label not in items:
127
+ items.append(label)
128
+ try:
129
+ items_sorted = sorted(
130
+ set(items),
131
+ key=lambda s: float(s.replace('%', '').strip())
132
+ )
133
+ except Exception:
134
+ items_sorted = items
135
+ cb.clear()
136
+ cb.addItems(items_sorted)
137
+ cb.setCurrentText(label)
138
+ cb.blockSignals(False)
139
+
140
+ # Keep reference to prevent GC of the inner function
141
+ cb._sync_zoom_combo_from_widget = _sync_zoom_combo_from_widget
142
+ if hasattr(ui.painter, 'zoomChanged'):
143
+ ui.painter.zoomChanged.connect(cb._sync_zoom_combo_from_widget)
144
+
145
+ # Initial label; actual value will be set by load_zoom below
146
+ cb.setCurrentText("100%")
147
+ nodes[key] = cb
148
+
93
149
  self._initialized = True
94
150
 
95
151
  def setup(self) -> QWidget:
@@ -118,6 +174,8 @@ class Painter:
118
174
  top.addWidget(nodes['painter.select.brush.size'])
119
175
  top.addWidget(nodes['painter.select.brush.color'])
120
176
  top.addWidget(nodes['painter.select.canvas.size'])
177
+ # Zoom combo placed right after canvas size
178
+ top.addWidget(nodes['painter.select.zoom'])
121
179
  top.addStretch(1)
122
180
 
123
181
  if nodes.get('painter.btn.capture') is None:
@@ -141,11 +199,12 @@ class Painter:
141
199
  if getattr(ui, 'painter_scroll', None) is None:
142
200
  ui.painter_scroll = QScrollArea()
143
201
  ui.painter_scroll.setWidget(ui.painter)
144
- ui.painter_scroll.setWidgetResizable(True)
202
+ # Must be False to allow content widget to grow/shrink with zoom and show scrollbars
203
+ ui.painter_scroll.setWidgetResizable(False)
145
204
  else:
146
205
  if ui.painter_scroll.widget() is not ui.painter:
147
206
  ui.painter_scroll.setWidget(ui.painter)
148
- ui.painter_scroll.setWidgetResizable(True)
207
+ ui.painter_scroll.setWidgetResizable(False)
149
208
 
150
209
  if nodes.get('tip.output.tab.draw') is None:
151
210
  nodes['tip.output.tab.draw'] = HelpLabel(trans('tip.output.tab.draw'), self.window)