pygpt-net 2.5.89__py3-none-any.whl → 2.5.90__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 (34) hide show
  1. pygpt_net/CHANGELOG.txt +6 -0
  2. pygpt_net/__init__.py +2 -2
  3. pygpt_net/controller/chat/output.py +2 -2
  4. pygpt_net/controller/layout/layout.py +10 -4
  5. pygpt_net/controller/ui/tabs.py +53 -3
  6. pygpt_net/controller/ui/ui.py +2 -0
  7. pygpt_net/core/tabs/tabs.py +61 -1
  8. pygpt_net/data/config/config.json +2 -2
  9. pygpt_net/data/config/models.json +2 -2
  10. pygpt_net/data/config/settings.json +20 -11
  11. pygpt_net/data/css/style.dark.css +3 -0
  12. pygpt_net/data/css/style.light.css +3 -0
  13. pygpt_net/data/css/web-blocks.css +35 -0
  14. pygpt_net/data/css/web-blocks.dark.css +4 -0
  15. pygpt_net/data/css/web-blocks.light.css +5 -0
  16. pygpt_net/data/locale/locale.de.ini +2 -0
  17. pygpt_net/data/locale/locale.en.ini +2 -0
  18. pygpt_net/data/locale/locale.es.ini +2 -0
  19. pygpt_net/data/locale/locale.fr.ini +2 -0
  20. pygpt_net/data/locale/locale.it.ini +2 -0
  21. pygpt_net/data/locale/locale.pl.ini +2 -0
  22. pygpt_net/data/locale/locale.uk.ini +2 -0
  23. pygpt_net/data/locale/locale.zh.ini +2 -0
  24. pygpt_net/provider/core/config/patch.py +10 -0
  25. pygpt_net/tools/code_interpreter/tool.py +33 -21
  26. pygpt_net/ui/layout/chat/chat.py +14 -0
  27. pygpt_net/ui/layout/chat/input.py +6 -1
  28. pygpt_net/ui/layout/chat/output.py +6 -6
  29. pygpt_net/ui/widget/element/labels.py +63 -4
  30. {pygpt_net-2.5.89.dist-info → pygpt_net-2.5.90.dist-info}/METADATA +8 -2
  31. {pygpt_net-2.5.89.dist-info → pygpt_net-2.5.90.dist-info}/RECORD +34 -34
  32. {pygpt_net-2.5.89.dist-info → pygpt_net-2.5.90.dist-info}/LICENSE +0 -0
  33. {pygpt_net-2.5.89.dist-info → pygpt_net-2.5.90.dist-info}/WHEEL +0 -0
  34. {pygpt_net-2.5.89.dist-info → pygpt_net-2.5.90.dist-info}/entry_points.txt +0 -0
pygpt_net/CHANGELOG.txt CHANGED
@@ -1,3 +1,9 @@
1
+ 2.5.90 (2025-08-07)
2
+
3
+ - Fix: Initialize context summary if a conversation starts with a tool call.
4
+ - Fix: Store splitter positions even if the object is deleted from memory.
5
+ - Update: CSS improvements.
6
+
1
7
  2.5.89 (2025-08-07)
2
8
 
3
9
  - Added audio output device selection in Config -> Audio - issue #117
pygpt_net/__init__.py CHANGED
@@ -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.06 00:00:00 #
9
+ # Updated Date: 2025.08.07 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.5.89"
16
+ __version__ = "2.5.90"
17
17
  __build__ = "2025-08-07"
18
18
  __maintainer__ = "Marcin Szczygliński"
19
19
  __github__ = "https://github.com/szczyglis-dev/py-gpt"
@@ -226,7 +226,7 @@ class Output:
226
226
  self.window.controller.chat.common.unlock_input() # unlock input
227
227
 
228
228
  # handle ctx name (generate title from summary if not initialized)
229
- if not reply and not internal: # don't call if reply or internal mode
229
+ if not ctx.meta or not ctx.meta.initialized: # don't call if reply or internal mode
230
230
  if self.window.core.config.get('ctx.auto_summary'):
231
231
  self.log("Calling for prepare context name...")
232
232
  self.window.controller.ctx.prepare_name(ctx) # async
@@ -295,7 +295,7 @@ class Output:
295
295
  self.window.dispatch(event) # reload chat window
296
296
 
297
297
  # self.window.core.debug.mem("END") # debug memory usage
298
- gc.collect()
298
+ # gc.collect()
299
299
 
300
300
  def log(self, data: Any):
301
301
  """
@@ -112,8 +112,11 @@ class Layout:
112
112
  # do not save main splitter state if notepad was not opened yet
113
113
  if splitter == "calendar" and not self.window.controller.notepad.opened_once:
114
114
  continue
115
- if splitter in self.window.ui.splitters:
116
- data[splitter] = self.window.ui.splitters[splitter].sizes()
115
+ try:
116
+ if splitter in self.window.ui.splitters:
117
+ data[splitter] = self.window.ui.splitters[splitter].sizes()
118
+ except Exception as e:
119
+ pass
117
120
  self.window.core.config.set('layout.splitters', data)
118
121
 
119
122
  def splitters_restore(self):
@@ -151,8 +154,11 @@ class Layout:
151
154
 
152
155
  # notepads
153
156
  for id in self.window.ui.notepad:
154
- scroll_id = "notepad." + str(id)
155
- data[scroll_id] = self.window.ui.notepad[id].textarea.verticalScrollBar().value()
157
+ try:
158
+ scroll_id = "notepad." + str(id)
159
+ data[scroll_id] = self.window.ui.notepad[id].textarea.verticalScrollBar().value()
160
+ except Exception as e:
161
+ pass
156
162
  self.window.core.config.set('layout.scroll', data)
157
163
 
158
164
  def scroll_restore(self):
@@ -6,10 +6,10 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.07.20 23:00:00 #
9
+ # Updated Date: 2025.08.07 18:00:00 #
10
10
  # ================================================== #
11
11
 
12
- from typing import Any, Optional
12
+ from typing import Any, Optional, Tuple
13
13
 
14
14
  from PySide6.QtCore import QTimer
15
15
 
@@ -178,6 +178,7 @@ class Tabs:
178
178
 
179
179
  prev_tab = self.current
180
180
  prev_column = self.column_idx
181
+
181
182
  self.current = idx
182
183
  self.column_idx = column_idx
183
184
  self.window.controller.ui.mode.update()
@@ -287,6 +288,38 @@ class Tabs:
287
288
  """
288
289
  return self.window.core.tabs.get_min_idx_by_type(type, self.column_idx)
289
290
 
291
+ def get_prev_idx_from(self, idx: int) -> Tuple[int, bool]:
292
+ """
293
+ Get previous tab index from given index
294
+
295
+ :param idx: tab index
296
+ :return: tuple of previous index and boolean indicating if it exists
297
+ """
298
+ return self.window.core.tabs.get_prev_idx_from(idx, self.column_idx)
299
+
300
+ def get_next_idx_from(self, idx: int) -> Tuple[int, bool]:
301
+ """
302
+ Get next tab index from given index
303
+
304
+ :param idx: tab index
305
+ :return: tuple of next index and boolean indicating if it exists
306
+ """
307
+ return self.window.core.tabs.get_next_idx_from(idx, self.column_idx)
308
+
309
+ def get_after_close_idx(self, idx: int) -> int:
310
+ """
311
+ Get tab index after closing the given index
312
+
313
+ :param idx: tab index
314
+ :return: previous tab index if exists, otherwise None
315
+ """
316
+ prev_idx, exists = self.get_prev_idx_from(idx)
317
+ if exists:
318
+ return prev_idx
319
+ next_idx, exists = self.get_next_idx_from(idx)
320
+ if exists:
321
+ return next_idx
322
+
290
323
  def on_column_changed(self):
291
324
  """Column changed event"""
292
325
  if self.locked:
@@ -381,7 +414,21 @@ class Tabs:
381
414
  """
382
415
  if self.locked:
383
416
  return
417
+
418
+ previous_current = self.current
419
+ idx_after = None # <--- next tab index after close to switch to
420
+ if previous_current != idx and self.column_idx == column_idx:
421
+ idx_after = previous_current
422
+ if idx_after > idx:
423
+ idx_after -= 1 # if current is after closed tab, idx will be shifted
424
+
425
+ if idx_after is None:
426
+ idx_after = self.get_after_close_idx(idx) # find next tab index after close
427
+
384
428
  self.window.core.tabs.remove_tab_by_idx(idx, column_idx)
429
+ if idx_after is not None:
430
+ self.switch_tab_by_idx(idx_after, column_idx)
431
+
385
432
  self.on_changed()
386
433
  self.update_current()
387
434
  self.debug()
@@ -639,7 +686,10 @@ class Tabs:
639
686
 
640
687
  :param column_idx: column index
641
688
  """
642
- idx = self.get_current_idx(column_idx)
689
+ # append at the end of column
690
+ idx = self.window.core.tabs.get_max_idx_by_column(column_idx)
691
+ if idx == -1:
692
+ idx = 0
643
693
  self.append(
644
694
  type=Tab.TAB_CHAT,
645
695
  tool_id=None,
@@ -42,6 +42,8 @@ class UI:
42
42
  7: {'label': 'label.color.violet', 'color': QColor(238, 130, 238), 'font': QColor(255, 255, 255)},
43
43
  }
44
44
  self.stop_action = None
45
+ self.splitter_output_size_input = None
46
+ self.splitter_output_size_files = None
45
47
 
46
48
  def setup(self):
47
49
  """Setup UI"""
@@ -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.05 21:00:00 #
9
+ # Updated Date: 2025.08.07 18:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import uuid
@@ -447,6 +447,66 @@ class Tabs:
447
447
  column_idx = tab.column_idx
448
448
  return min, column_idx, exists
449
449
 
450
+ def get_prev_idx_from(self, idx: int, column_idx: int = 0) -> Tuple[int, bool]:
451
+ """
452
+ Get previous index from the specified index
453
+
454
+ :param idx: Tab index
455
+ :param column_idx: Column index
456
+ :return: Previous index and exists flag
457
+ """
458
+ tabs = self.window.ui.layout.get_tabs_by_idx(column_idx)
459
+ if idx < 1:
460
+ return -1, False
461
+ prev_idx = idx - 1
462
+ if prev_idx < 0 or prev_idx >= tabs.count():
463
+ return -1, False
464
+ tab = self.get_tab_by_index(prev_idx, column_idx)
465
+ if tab is None:
466
+ return -1, False
467
+ if tab.column_idx != column_idx:
468
+ return -1, False
469
+ return prev_idx, True
470
+
471
+ def get_next_idx_from(self, idx: int, column_idx: int = 0) -> Tuple[int, bool]:
472
+ """
473
+ Get next index from the specified index
474
+
475
+ :param idx: Tab index
476
+ :param column_idx: Column index
477
+ :return: Next index and exists flag
478
+ """
479
+ tabs = self.window.ui.layout.get_tabs_by_idx(column_idx)
480
+ if idx < 0 or idx >= tabs.count():
481
+ return -1, False
482
+ next_idx = idx + 1
483
+ if next_idx < 0 or next_idx >= tabs.count():
484
+ return -1, False
485
+ tab = self.get_tab_by_index(next_idx, column_idx)
486
+ if tab is None:
487
+ return -1, False
488
+ if tab.column_idx != column_idx:
489
+ return -1, False
490
+ return next_idx, True
491
+
492
+ def get_max_idx_by_column(self, column_idx: int = 0) -> int:
493
+ """
494
+ Get max index in column
495
+
496
+ :param column_idx: Column index
497
+ :return: Max index
498
+ """
499
+ tabs = self.window.ui.layout.get_tabs_by_idx(column_idx)
500
+ if tabs.count() == 0:
501
+ return -1
502
+ max_idx = -1
503
+ for idx in range(tabs.count()):
504
+ tab = self.get_tab_by_index(idx, column_idx)
505
+ if tab is not None and tab.column_idx == column_idx:
506
+ if tab.idx > max_idx:
507
+ max_idx = tab.idx
508
+ return max_idx
509
+
450
510
  def update(self):
451
511
  """Update tabs data (pids) from UI (all columns)"""
452
512
  for n in range(0, self.NUM_COLS):
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.5.89",
4
- "app.version": "2.5.89",
3
+ "version": "2.5.90",
4
+ "app.version": "2.5.90",
5
5
  "updated_at": "2025-08-07T00:00:00"
6
6
  },
7
7
  "access.audio.event.speech": false,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.5.89",
4
- "app.version": "2.5.89",
3
+ "version": "2.5.90",
4
+ "app.version": "2.5.90",
5
5
  "updated_at": "2025-08-07T23:07:35"
6
6
  },
7
7
  "items": {
@@ -1305,7 +1305,7 @@
1305
1305
  "multiplier": 1,
1306
1306
  "step": 1,
1307
1307
  "advanced": false
1308
- },
1308
+ },
1309
1309
  "audio.input.backend": {
1310
1310
  "section": "audio",
1311
1311
  "type": "combo",
@@ -1313,7 +1313,8 @@
1313
1313
  "label": "settings.audio.input.backend",
1314
1314
  "description": "settings.audio.input.backend.desc",
1315
1315
  "value": 0,
1316
- "advanced": false
1316
+ "advanced": false,
1317
+ "tab": "device"
1317
1318
  },
1318
1319
  "audio.input.device": {
1319
1320
  "section": "audio",
@@ -1322,7 +1323,8 @@
1322
1323
  "label": "settings.audio.input.device",
1323
1324
  "description": "settings.audio.input.device.desc",
1324
1325
  "value": 0,
1325
- "advanced": false
1326
+ "advanced": false,
1327
+ "tab": "device"
1326
1328
  },
1327
1329
  "audio.output.backend": {
1328
1330
  "section": "audio",
@@ -1331,7 +1333,8 @@
1331
1333
  "label": "settings.audio.output.backend",
1332
1334
  "description": "settings.audio.output.backend.desc",
1333
1335
  "value": 0,
1334
- "advanced": false
1336
+ "advanced": false,
1337
+ "tab": "device"
1335
1338
  },
1336
1339
  "audio.output.device": {
1337
1340
  "section": "audio",
@@ -1340,7 +1343,8 @@
1340
1343
  "label": "settings.audio.output.device",
1341
1344
  "description": "settings.audio.output.device.desc",
1342
1345
  "value": 0,
1343
- "advanced": false
1346
+ "advanced": false,
1347
+ "tab": "device"
1344
1348
  },
1345
1349
  "audio.input.channels": {
1346
1350
  "section": "audio",
@@ -1353,7 +1357,8 @@
1353
1357
  "max": 4,
1354
1358
  "multiplier": 1,
1355
1359
  "step": 1,
1356
- "advanced": false
1360
+ "advanced": false,
1361
+ "tab": "device"
1357
1362
  },
1358
1363
  "audio.input.rate": {
1359
1364
  "section": "audio",
@@ -1366,8 +1371,9 @@
1366
1371
  "max": 256000,
1367
1372
  "multiplier": 1,
1368
1373
  "step": 1,
1369
- "advanced": false
1370
- },
1374
+ "advanced": false,
1375
+ "tab": "device"
1376
+ },
1371
1377
  "audio.input.stop_interval": {
1372
1378
  "section": "audio",
1373
1379
  "type": "int",
@@ -1379,7 +1385,8 @@
1379
1385
  "max": 120,
1380
1386
  "multiplier": 1,
1381
1387
  "step": 1,
1382
- "advanced": false
1388
+ "advanced": false,
1389
+ "tab": "options"
1383
1390
  },
1384
1391
  "audio.input.timeout": {
1385
1392
  "section": "audio",
@@ -1391,7 +1398,8 @@
1391
1398
  "min": 0,
1392
1399
  "multiplier": 1,
1393
1400
  "step": 1,
1394
- "advanced": false
1401
+ "advanced": false,
1402
+ "tab": "options"
1395
1403
  },
1396
1404
  "audio.input.timeout.continuous": {
1397
1405
  "section": "audio",
@@ -1403,7 +1411,8 @@
1403
1411
  "max": null,
1404
1412
  "multiplier": null,
1405
1413
  "step": null,
1406
- "advanced": false
1414
+ "advanced": false,
1415
+ "tab": "options"
1407
1416
  },
1408
1417
  "remote_tools.web_search": {
1409
1418
  "section": "remote_tools",
@@ -115,4 +115,7 @@ QMenu,
115
115
  QTextEdit,
116
116
  QLineEdit {{
117
117
  border: none;
118
+ }}
119
+ QComboBox::item:checked {{
120
+ font-weight: bold;
118
121
  }}
@@ -225,4 +225,7 @@ QTreeView,
225
225
  QTextEdit,
226
226
  QLineEdit {{
227
227
  border: none;
228
+ }}
229
+ QComboBox::item:checked {{
230
+ font-weight: bold;
228
231
  }}
@@ -304,6 +304,7 @@ code {{
304
304
  }}
305
305
  .empty_list {{
306
306
  }}
307
+
307
308
  .spinner {{
308
309
  display: inline-block;
309
310
  animation: spin 2s linear infinite;
@@ -344,4 +345,38 @@ think {{
344
345
  background: #0d1117;
345
346
  padding: 10px;
346
347
  font-size: 0.9rem;
348
+ }}
349
+
350
+ /* loader */
351
+ .loader-global {{
352
+ text-align: center;
353
+ margin-top: 2rem;
354
+ margin-bottom: 2rem;
355
+ }}
356
+ .lds-ring {{
357
+ opacity: 0.75;
358
+ }}
359
+ .loader-global .lds-ring {{
360
+ width: 40px;
361
+ height: 40px;
362
+ }}
363
+ .loader-global .lds-ring div {{
364
+ width: 32px;
365
+ height: 32px;
366
+ border-width: 5px;
367
+ }}
368
+ .append_live {{
369
+ font-size: 0.8rem;
370
+ }}
371
+ .hidden {{
372
+ display: block;
373
+ opacity: 0;
374
+ visibility: hidden;
375
+ transition: opacity 0.5s ease, visibility 0.5s ease;
376
+ }}
377
+
378
+ .visible {{
379
+ opacity: 1;
380
+ visibility: visible;
381
+ transition: opacity 0.5s ease, visibility 0.5s ease;
347
382
  }}
@@ -71,4 +71,8 @@ code {{
71
71
  }}
72
72
  .display-blocks .name-user::before {{
73
73
  background-color: silver;
74
+ }}
75
+ /* loader */
76
+ .lds-ring {{
77
+ color: #fff;
74
78
  }}
@@ -79,4 +79,9 @@ code {{
79
79
  .msg-extra a:hover {{
80
80
  text-decoration: none;
81
81
  color: #000 !important;
82
+ }}
83
+ /* loader */
84
+ .lds-ring {{
85
+ color: #000;
86
+ opacity:0.5;
82
87
  }}
@@ -1239,6 +1239,8 @@ settings.section.api_keys.openai = OpenAI
1239
1239
  settings.section.api_keys.perplexity = Perplexity
1240
1240
  settings.section.api_keys.xai = xAI
1241
1241
  settings.section.audio = Audio
1242
+ settings.section.audio.device = Geräte
1243
+ settings.section.audio.options = Optionen
1242
1244
  settings.section.ctx = Kontext
1243
1245
  settings.section.developer = Entwickler
1244
1246
  settings.section.files = Dateien und Anhänge
@@ -1249,6 +1249,8 @@ settings.section.api_keys.openai = OpenAI
1249
1249
  settings.section.api_keys.perplexity = Perplexity
1250
1250
  settings.section.api_keys.xai = xAI
1251
1251
  settings.section.audio = Audio
1252
+ settings.section.audio.device = Devices
1253
+ settings.section.audio.options = Options
1252
1254
  settings.section.ctx = Context
1253
1255
  settings.section.developer = Developer
1254
1256
  settings.section.files = Files and attachments
@@ -1240,6 +1240,8 @@ settings.section.api_keys.openai = OpenAI
1240
1240
  settings.section.api_keys.perplexity = Perplexity
1241
1241
  settings.section.api_keys.xai = xAI
1242
1242
  settings.section.audio = Audio
1243
+ settings.section.audio.device = Dispositivos
1244
+ settings.section.audio.options = Opciones
1243
1245
  settings.section.ctx = Contexto
1244
1246
  settings.section.developer = Desarrollador
1245
1247
  settings.section.files = Archivos y adjuntos
@@ -1239,6 +1239,8 @@ settings.section.api_keys.openai = OpenAI
1239
1239
  settings.section.api_keys.perplexity = Perplexity
1240
1240
  settings.section.api_keys.xai = xAI
1241
1241
  settings.section.audio = Audio
1242
+ settings.section.audio.device = Appareils
1243
+ settings.section.audio.options = Options
1242
1244
  settings.section.ctx = Contexte
1243
1245
  settings.section.developer = Développeur
1244
1246
  settings.section.files = Fichiers et pièces jointes
@@ -1239,6 +1239,8 @@ settings.section.api_keys.openai = OpenAI
1239
1239
  settings.section.api_keys.perplexity = Perplexity
1240
1240
  settings.section.api_keys.xai = xAI
1241
1241
  settings.section.audio = Audio
1242
+ settings.section.audio.device = Dispositivi
1243
+ settings.section.audio.options = Opzioni
1242
1244
  settings.section.ctx = Contesto
1243
1245
  settings.section.developer = Sviluppatore
1244
1246
  settings.section.files = File e allegati
@@ -1241,6 +1241,8 @@ settings.section.api_keys.openai = OpenAI
1241
1241
  settings.section.api_keys.perplexity = Perplexity
1242
1242
  settings.section.api_keys.xai = xAI
1243
1243
  settings.section.audio = Audio
1244
+ settings.section.audio.device = Urządzenia
1245
+ settings.section.audio.options = Opcje
1244
1246
  settings.section.ctx = Kontekst
1245
1247
  settings.section.developer = Deweloper
1246
1248
  settings.section.files = Pliki i załączniki
@@ -1239,6 +1239,8 @@ settings.section.api_keys.openai = OpenAI
1239
1239
  settings.section.api_keys.perplexity = Perplexity
1240
1240
  settings.section.api_keys.xai = xAI
1241
1241
  settings.section.audio = Аудіо
1242
+ settings.section.audio.device = Пристрої
1243
+ settings.section.audio.options = Параметри
1242
1244
  settings.section.ctx = Контекст
1243
1245
  settings.section.developer = Розробник
1244
1246
  settings.section.files = Файли та вкладення
@@ -1239,6 +1239,8 @@ settings.section.api_keys.openai = OpenAI
1239
1239
  settings.section.api_keys.perplexity = Perplexity
1240
1240
  settings.section.api_keys.xai = xAI
1241
1241
  settings.section.audio = 音频
1242
+ settings.section.audio.device = 设备
1243
+ settings.section.audio.options = 选项
1242
1244
  settings.section.ctx = 上下文
1243
1245
  settings.section.developer = 開發者
1244
1246
  settings.section.files = 文件和附件
@@ -2174,6 +2174,16 @@ class Patch:
2174
2174
  if "audio.output.device" not in data:
2175
2175
  data["audio.output.device"] = "0"
2176
2176
 
2177
+ # < 2.5.90
2178
+ if old < parse_version("2.5.90"):
2179
+ print("Migrating config from < 2.5.90...")
2180
+ self.window.core.updater.patch_css('style.dark.css', True) # force replace file
2181
+ self.window.core.updater.patch_css('style.light.css', True) # force replace file
2182
+ self.window.core.updater.patch_css('web-blocks.css', True) # force replace file
2183
+ self.window.core.updater.patch_css('web-blocks.dark.css', True) # force replace file
2184
+ self.window.core.updater.patch_css('web-blocks.light.css', True) # force replace file
2185
+ updated = True
2186
+
2177
2187
  # update file
2178
2188
  migrated = False
2179
2189
  if updated:
@@ -94,34 +94,46 @@ class CodeInterpreter(BaseTool):
94
94
 
95
95
  def set_initial_size(self):
96
96
  """Set default sizes"""
97
+ # --------------------------------------------------------
98
+ # INFO: object may be deleted before this method is called
99
+ # --------------------------------------------------------
97
100
  def set_initial_splitter_height():
98
- total_height = self.window.ui.splitters['interpreter'].size().height()
99
- if total_height > 0:
100
- size_output = int(total_height * 0.85)
101
- size_input = total_height - size_output
102
- self.window.ui.splitters['interpreter'].setSizes([size_output, size_input])
103
- else:
104
- QTimer.singleShot(0, set_initial_splitter_height)
101
+ try:
102
+ total_height = self.window.ui.splitters['interpreter'].size().height()
103
+ if total_height > 0:
104
+ size_output = int(total_height * 0.85)
105
+ size_input = total_height - size_output
106
+ self.window.ui.splitters['interpreter'].setSizes([size_output, size_input])
107
+ else:
108
+ QTimer.singleShot(0, set_initial_splitter_height)
109
+ except Exception as e:
110
+ pass
105
111
  QTimer.singleShot(0, set_initial_splitter_height)
106
112
 
107
113
  def set_initial_splitter_dialog_height():
108
- total_height = self.window.ui.splitters['interpreter_dialog'].size().height()
109
- if total_height > 0:
110
- size_output = int(total_height * 0.85)
111
- size_input = total_height - size_output
112
- self.window.ui.splitters['interpreter_dialog'].setSizes([size_output, size_input])
113
- else:
114
- QTimer.singleShot(0, set_initial_splitter_dialog_height)
114
+ try:
115
+ total_height = self.window.ui.splitters['interpreter_dialog'].size().height()
116
+ if total_height > 0:
117
+ size_output = int(total_height * 0.85)
118
+ size_input = total_height - size_output
119
+ self.window.ui.splitters['interpreter_dialog'].setSizes([size_output, size_input])
120
+ else:
121
+ QTimer.singleShot(0, set_initial_splitter_dialog_height)
122
+ except Exception as e:
123
+ pass
115
124
  QTimer.singleShot(0, set_initial_splitter_dialog_height)
116
125
 
117
126
  def set_initial_splitter_width():
118
- total_width = self.window.ui.splitters['interpreter.columns'].size().width()
119
- if total_width > 0:
120
- size_output = int(total_width * 0.85)
121
- size_history = total_width - size_output
122
- self.window.ui.splitters['interpreter.columns'].setSizes([size_output, size_history])
123
- else:
124
- QTimer.singleShot(0, set_initial_splitter_width)
127
+ try:
128
+ total_width = self.window.ui.splitters['interpreter.columns'].size().width()
129
+ if total_width > 0:
130
+ size_output = int(total_width * 0.85)
131
+ size_history = total_width - size_output
132
+ self.window.ui.splitters['interpreter.columns'].setSizes([size_output, size_history])
133
+ else:
134
+ QTimer.singleShot(0, set_initial_splitter_width)
135
+ except Exception as e:
136
+ pass
125
137
  QTimer.singleShot(0, set_initial_splitter_width)
126
138
 
127
139
  def handle_ipython_output(self, line: str):
@@ -43,5 +43,19 @@ class ChatMain:
43
43
  self.window.ui.splitters['main.output'].addWidget(input)
44
44
  self.window.ui.splitters['main.output'].setStretchFactor(0, 9) # Output widget stretch factor
45
45
  self.window.ui.splitters['main.output'].setStretchFactor(1, 1) # Input widget stretch factor
46
+ self.window.ui.splitters['main.output'].splitterMoved.connect(self.on_splitter_moved)
47
+ self.window.controller.ui.splitter_output_size_input = self.window.ui.splitters['main.output'].sizes()
46
48
 
47
49
  return self.window.ui.splitters['main.output']
50
+
51
+ def on_splitter_moved(self, pos, index):
52
+ """
53
+ Store the size of the output splitter when it is moved
54
+ """
55
+ if "input" not in self.window.ui.tabs:
56
+ return
57
+ idx = self.window.ui.tabs['input'].currentIndex()
58
+ if idx != 0:
59
+ self.window.controller.ui.splitter_output_size_files = self.window.ui.splitters['main.output'].sizes()
60
+ else:
61
+ self.window.controller.ui.splitter_output_size_input = self.window.ui.splitters['main.output'].sizes()
@@ -45,6 +45,7 @@ class Input:
45
45
  self.min_height_files_tab = 120
46
46
  self.min_height_input_tab = 80
47
47
  self.min_height_input = 50
48
+ self.prev_input_splitter_value = 0
48
49
 
49
50
  def setup(self) -> QWidget:
50
51
  """
@@ -267,6 +268,10 @@ class Input:
267
268
  if idx == 0:
268
269
  self.window.ui.nodes['input'].setMinimumHeight(self.min_height_input)
269
270
  self.window.ui.tabs['input'].setMinimumHeight(self.min_height_input_tab)
271
+ if self.window.controller.ui.splitter_output_size_input:
272
+ self.window.ui.splitters['main.output'].setSizes(self.window.controller.ui.splitter_output_size_input)
270
273
  else:
274
+ if self.window.controller.ui.splitter_output_size_files:
275
+ self.window.ui.splitters['main.output'].setSizes(self.window.controller.ui.splitter_output_size_files)
271
276
  self.window.ui.nodes['input'].setMinimumHeight(self.min_height_files_tab)
272
- self.window.ui.tabs['input'].setMinimumHeight(self.min_height_files_tab + 60)
277
+ self.window.ui.tabs['input'].setMinimumHeight(self.min_height_files_tab + 90)
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.06 19:00:00 #
9
+ # Updated Date: 2025.08.07 19:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt
@@ -70,35 +70,35 @@ class Output:
70
70
  :return: QHBoxLayout
71
71
  """
72
72
  # video capture icon
73
- self.window.ui.nodes['icon.video.capture'] = IconLabel(":/icons/webcam.svg")
73
+ self.window.ui.nodes['icon.video.capture'] = IconLabel(":/icons/webcam.svg", window=self.window)
74
74
  self.window.ui.nodes['icon.video.capture'].setToolTip(trans("icon.video.capture"))
75
75
  self.window.ui.nodes['icon.video.capture'].clicked.connect(
76
76
  lambda:self.window.controller.camera.toggle_capture()
77
77
  )
78
78
 
79
79
  # audio output icon
80
- self.window.ui.nodes['icon.audio.output'] = IconLabel(":/icons/volume.svg")
80
+ self.window.ui.nodes['icon.audio.output'] = IconLabel(":/icons/volume.svg", window=self.window)
81
81
  self.window.ui.nodes['icon.audio.output'].setToolTip(trans("icon.audio.output"))
82
82
  self.window.ui.nodes['icon.audio.output'].clicked.connect(
83
83
  lambda: self.window.controller.plugins.toggle('audio_output')
84
84
  )
85
85
 
86
86
  # audio input icon
87
- self.window.ui.nodes['icon.audio.input'] = IconLabel(":/icons/mic.svg")
87
+ self.window.ui.nodes['icon.audio.input'] = IconLabel(":/icons/mic.svg", window=self.window)
88
88
  self.window.ui.nodes['icon.audio.input'].setToolTip(trans("icon.audio.input"))
89
89
  self.window.ui.nodes['icon.audio.input'].clicked.connect(
90
90
  lambda: self.window.controller.plugins.toggle('audio_input')
91
91
  )
92
92
 
93
93
  # interpreter icon
94
- self.window.ui.nodes['icon.interpreter'] = IconLabel(":/icons/code.svg")
94
+ self.window.ui.nodes['icon.interpreter'] = IconLabel(":/icons/code.svg", window=self.window)
95
95
  self.window.ui.nodes['icon.interpreter'].setToolTip("Python Code Interpreter")
96
96
  self.window.ui.nodes['icon.interpreter'].clicked.connect(
97
97
  lambda: self.window.tools.get("interpreter").toggle()
98
98
  )
99
99
 
100
100
  # indexer icon
101
- self.window.ui.nodes['icon.indexer'] = IconLabel(":/icons/db.svg")
101
+ self.window.ui.nodes['icon.indexer'] = IconLabel(":/icons/db.svg", window=self.window)
102
102
  self.window.ui.nodes['icon.indexer'].setToolTip("Indexer")
103
103
  self.window.ui.nodes['icon.indexer'].clicked.connect(
104
104
  lambda: self.window.tools.get("indexer").toggle()
@@ -6,11 +6,11 @@
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.07 19:00:00 #
10
10
  # ================================================== #
11
11
 
12
- from PySide6.QtCore import Qt, QTimer, QRect, Signal, QUrl
13
- from PySide6.QtGui import QCursor, QAction, QIcon, QDesktopServices
12
+ from PySide6.QtCore import Qt, QTimer, QRect, Signal, QUrl, QEvent
13
+ from PySide6.QtGui import QCursor, QAction, QIcon, QDesktopServices, QPainter, QPixmap, QColor
14
14
  from PySide6.QtWidgets import QLabel, QLineEdit, QToolTip
15
15
 
16
16
  from pygpt_net.utils import trans
@@ -117,10 +117,69 @@ class IconLabel(QLabel):
117
117
  self.setAlignment(Qt.AlignRight)
118
118
  self.setProperty('class', 'label-chat-status')
119
119
  self.setContentsMargins(0, 0, 0, 0)
120
+ self.setMouseTracking(True)
121
+
122
+ self.original_pixmap = None
123
+ self.hover_pixmap = None
120
124
  self.set_icon(icon)
121
125
 
126
+ def sizeHint(self):
127
+ if self.original_pixmap and not self.original_pixmap.isNull():
128
+ return self.original_pixmap.size()
129
+ return super().sizeHint()
130
+
131
+ def minimumSizeHint(self):
132
+ if self.original_pixmap and not self.original_pixmap.isNull():
133
+ return self.original_pixmap.size()
134
+ return super().minimumSizeHint()
135
+
122
136
  def set_icon(self, icon: str):
123
- self.setPixmap(QIcon(icon).pixmap(16, 16))
137
+ icon_obj = QIcon(icon)
138
+ self.original_pixmap = icon_obj.pixmap(16, 16)
139
+ if self.original_pixmap.isNull():
140
+ return
141
+ self.setPixmap(self.original_pixmap)
142
+
143
+ def create_hover_icon(self, pixmap: QPixmap) -> QPixmap:
144
+ if pixmap.isNull():
145
+ return pixmap
146
+
147
+ recolored = QPixmap(pixmap.size())
148
+ recolored.setDevicePixelRatio(pixmap.devicePixelRatio())
149
+ recolored.fill(Qt.transparent)
150
+
151
+ painter = QPainter(recolored)
152
+ painter.drawPixmap(0, 0, pixmap)
153
+ painter.setCompositionMode(QPainter.CompositionMode_SourceIn)
154
+
155
+ is_dark = False
156
+ if self.window and self.window.core and self.window.core.config:
157
+ theme = self.window.core.config.get("theme", "default")
158
+ if theme.startswith("dark"):
159
+ is_dark = True
160
+
161
+ if is_dark:
162
+ painter.fillRect(recolored.rect(), QColor("#c4c4c4"))
163
+ else:
164
+ painter.fillRect(recolored.rect(), QColor("#000000"))
165
+ painter.end()
166
+
167
+ return recolored
168
+
169
+ def enterEvent(self, event: QEvent):
170
+ self.setCursor(Qt.PointingHandCursor)
171
+ self.hover_pixmap = self.create_hover_icon(self.original_pixmap)
172
+ if self.hover_pixmap is not None and not self.hover_pixmap.isNull():
173
+ self.setPixmap(self.hover_pixmap)
174
+ else:
175
+ self.setPixmap(self.original_pixmap)
176
+ super().enterEvent(event)
177
+
178
+ def leaveEvent(self, event: QEvent):
179
+ self.unsetCursor()
180
+ self.setPixmap(self.original_pixmap)
181
+ super().leaveEvent(event)
124
182
 
125
183
  def mousePressEvent(self, event):
126
184
  self.clicked.emit()
185
+ super().mousePressEvent(event)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pygpt-net
3
- Version: 2.5.89
3
+ Version: 2.5.90
4
4
  Summary: Desktop AI Assistant powered by: OpenAI o1, o3, GPT-4o, GPT-4 Vision, DALL-E 3, Llama 3, Mistral, Gemini, Claude, Grok, DeepSeek, Bielik, 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: py_gpt,py-gpt,pygpt,desktop,app,o1,o3,gpt,gpt4,gpt-4o,gpt-4v,gpt3.5,gpt-4,gpt-4-vision,gpt-3.5,llama3,mistral,gemini,grok,deepseek,bielik,claude,tts,whisper,vision,chatgpt,dall-e,chat,chatbot,assistant,text completion,image generation,ai,api,openai,api key,langchain,llama-index,ollama,presets,ui,qt,pyside
@@ -104,7 +104,7 @@ Description-Content-Type: text/markdown
104
104
 
105
105
  [![pygpt](https://snapcraft.io/pygpt/badge.svg)](https://snapcraft.io/pygpt)
106
106
 
107
- Release: **2.5.89** | build: **2025-08-07** | Python: **>=3.10, <3.14**
107
+ Release: **2.5.90** | build: **2025-08-07** | Python: **>=3.10, <3.14**
108
108
 
109
109
  > Official website: https://pygpt.net | Documentation: https://pygpt.readthedocs.io
110
110
  >
@@ -4351,6 +4351,12 @@ may consume additional tokens that are not displayed in the main window.
4351
4351
 
4352
4352
  ## Recent changes:
4353
4353
 
4354
+ **2.5.90 (2025-08-07)**
4355
+
4356
+ - Fix: Initialize context summary if a conversation starts with a tool call.
4357
+ - Fix: Store splitter positions even if the object is deleted from memory.
4358
+ - Update: CSS improvements.
4359
+
4354
4360
  **2.5.89 (2025-08-07)**
4355
4361
 
4356
4362
  - Added audio output device selection in Config -> Audio - issue #117
@@ -1,6 +1,6 @@
1
- pygpt_net/CHANGELOG.txt,sha256=___1QgiskL54LiqcjEXPe7OEMUZQxMwdQNKRSnbLZ94,96442
1
+ pygpt_net/CHANGELOG.txt,sha256=tR-VL3IzWyj381eB1wlv33rbQ6gfYvJA5t761DiY7S0,96644
2
2
  pygpt_net/LICENSE,sha256=dz9sfFgYahvu2NZbx4C1xCsVn9GVer2wXcMkFRBvqzY,1146
3
- pygpt_net/__init__.py,sha256=kdRHYHn7bgL6wqpa5zG-N9u0clD2PlGqSuj-OJAMlvU,1373
3
+ pygpt_net/__init__.py,sha256=6LY7TUV4-1DqyzazVedWML0FNJcIS7IizCOWO2a1SHc,1373
4
4
  pygpt_net/app.py,sha256=86COG6F-sC9dIRURMjBPS4fkD3Zzrp5kwCFQuM4tikc,18971
5
5
  pygpt_net/config.py,sha256=FxN39zmTpOY84lgrfhfIDuxKmNPrePhNHdGxvEOKqK8,16881
6
6
  pygpt_net/container.py,sha256=4puHeSNIyj3q6gTjPLsQKE1U-4fAhoNANYKiDq-mTqA,4054
@@ -40,7 +40,7 @@ pygpt_net/controller/chat/common.py,sha256=0V7RteHjkyvG6fM4d3ZB-JMjelPzHcN_DsuzV
40
40
  pygpt_net/controller/chat/files.py,sha256=VFiiTeWTYR15Nwf1CTLEmeXqlmRHzNQVkNaU6hY2Gz4,2846
41
41
  pygpt_net/controller/chat/image.py,sha256=B7Ya6TN8V0O-YIQph_xsZAof_Nu0ccDSq5RVeRw3Blo,8721
42
42
  pygpt_net/controller/chat/input.py,sha256=YJ_e-oNVcJewrRJznDXLmpAdoTdb9PkXdHy0dGsqHe4,12414
43
- pygpt_net/controller/chat/output.py,sha256=lA6KUN6rqW2nqPziRpServjxt8Au55PKaSHOt7vHrPA,10835
43
+ pygpt_net/controller/chat/output.py,sha256=fy83-qKWUvBXRL1B6DDuPQIvzEqklrfoCLE5Ek6V9LM,10851
44
44
  pygpt_net/controller/chat/render.py,sha256=nCkFse_fQAdU35BDi72NQpIBZOZicwZFxM7YNdig83Y,19867
45
45
  pygpt_net/controller/chat/response.py,sha256=5v1kGiVwSSd0gd15VNDLrDvrM50Uq7LoU3T8Q0AZQVc,11715
46
46
  pygpt_net/controller/chat/stream.py,sha256=YOTFyeWt_Lu_jtqsjzwZSeRoxSMkCu9WkQO_DcjuzvE,22217
@@ -94,7 +94,7 @@ pygpt_net/controller/lang/settings.py,sha256=mtBQrsBq06vNWqVJqT__EBsinJOANKhypG0
94
94
  pygpt_net/controller/launcher/__init__.py,sha256=UazTdz_xgkpPFUGrgxN7nDFHg6V2zQJ6MW6khEfvMZg,512
95
95
  pygpt_net/controller/launcher/launcher.py,sha256=zY2yIrSd7y5dhVtMJExKxHI4JhD1--PTfRelxsBarsk,1416
96
96
  pygpt_net/controller/layout/__init__.py,sha256=0pxxzjAUa1hS27d80Q0SgDV1Uzs7A9mZrUxb1cs-oHs,510
97
- pygpt_net/controller/layout/layout.py,sha256=9R30zrZtvedAf1OxQLzxDWt8o2XirUq0bkcFRnpCztg,11433
97
+ pygpt_net/controller/layout/layout.py,sha256=aSPVMXMBPWj5lz2eCb95_f2zAnkShFK84aKU7L1Vvrk,11595
98
98
  pygpt_net/controller/mode/__init__.py,sha256=1Kcz0xHc2IW_if9S9eQozBUvIu69eLAe7T-Re2lJxhk,508
99
99
  pygpt_net/controller/mode/mode.py,sha256=rg9kmXarD1z4pwJ9GVgnzgScPjkY4Y1vA2-mlB_IZq0,8183
100
100
  pygpt_net/controller/model/__init__.py,sha256=mQXq9u269D8TD3u_44J6DFFyHKkaZplk-tRFCssBGbE,509
@@ -130,8 +130,8 @@ pygpt_net/controller/tools/__init__.py,sha256=ds63rOuwLEIe-SlY_sQkhWSdXS0lfVwseU
130
130
  pygpt_net/controller/tools/tools.py,sha256=GfDcAVyAiF1CcZ8ATnSJgfCwXYOaGQ1xoxXztVvU3qc,2905
131
131
  pygpt_net/controller/ui/__init__.py,sha256=cxfh2SYeEDATGAZpcYDqCxYfp4KReQ1CYehevSf89EU,507
132
132
  pygpt_net/controller/ui/mode.py,sha256=wABB2BdevFx4vIacnlokIiJE30Hc7WiQGdVxLkHq5WI,12949
133
- pygpt_net/controller/ui/tabs.py,sha256=JVpsSWcNFeBy277AKRCVUrnUrc4328fdcv9QyrwFzks,27790
134
- pygpt_net/controller/ui/ui.py,sha256=o90Xjjh-ARwoTPcUUttrP307WP5QN4bgis1FE3dzKUc,6979
133
+ pygpt_net/controller/ui/tabs.py,sha256=Vhf2TLudbUEFxxO_fydK_6wpyiXXWidwEJCoK3ndKpg,29518
134
+ pygpt_net/controller/ui/ui.py,sha256=S_1w94VdbA7ESm-wPObXxy93Qxc6JfvyBseFAqnAWE4,7073
135
135
  pygpt_net/controller/ui/vision.py,sha256=DBi1YKaPGzAcRkHtcZoZH6Kd-eXA1ThhgTiQ_Lx2E-c,2601
136
136
  pygpt_net/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
137
  pygpt_net/core/access/__init__.py,sha256=6HA7ahoksA6B8J56EnHKFIjMwIrQ0AVVWlKkzsSFOD8,510
@@ -311,7 +311,7 @@ pygpt_net/core/settings/__init__.py,sha256=GQ6_gJ2jf_Chm7ZuZLvkcvEh_sfMDVMBieeoJ
311
311
  pygpt_net/core/settings/settings.py,sha256=onqwNiICm2VhHfmXLvp1MiEJ14m2jzeeI2pjUiaUwtY,7787
312
312
  pygpt_net/core/tabs/__init__.py,sha256=reDufOWWDQsZwfvtnXrFQROEdl9nqoKI7S3bFA3D9As,508
313
313
  pygpt_net/core/tabs/tab.py,sha256=uYnIt7_5fyr6nMXQ84NcJF_V99qKTuzUP8_NHKR2OWk,4922
314
- pygpt_net/core/tabs/tabs.py,sha256=3ofBbGieIO-kf3neO1tYza3BBl33y1JqO4jin5smXpA,27585
314
+ pygpt_net/core/tabs/tabs.py,sha256=oikrmgSfphVGafTH_urn2f_XqNbrbkjIvbw-gTB8OIs,29617
315
315
  pygpt_net/core/text/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
316
316
  pygpt_net/core/text/finder.py,sha256=NBzYUE_Av3oZH8RlCrSe6EeLcHpfz79WJV_vSK0P1jI,6656
317
317
  pygpt_net/core/text/utils.py,sha256=f6dNhfDSRo61S0FI8dvyps-VY9R6FxnzNysRBexVI1o,3077
@@ -340,8 +340,8 @@ pygpt_net/css_rc.py,sha256=i13kX7irhbYCWZ5yJbcMmnkFp_UfS4PYnvRFSPF7XXo,11349
340
340
  pygpt_net/data/audio/click_off.mp3,sha256=aNiRDP1pt-Jy7ija4YKCNFBwvGWbzU460F4pZWZDS90,65201
341
341
  pygpt_net/data/audio/click_on.mp3,sha256=qfdsSnthAEHVXzeyN4LlC0OvXuyW8p7stb7VXtlvZ1k,65201
342
342
  pygpt_net/data/audio/ok.mp3,sha256=LTiV32pEBkpUGBkKkcOdOFB7Eyt_QoP2Nv6c5AaXftk,32256
343
- pygpt_net/data/config/config.json,sha256=IEa3_As9nThm4HFR-F3elhg4RkTEgsomqrlyN63R-H4,24686
344
- pygpt_net/data/config/models.json,sha256=MpTwLb34s3Vj6uztmp-YTZ4enTR6DFG6w-fY_Z0v9D4,104302
343
+ pygpt_net/data/config/config.json,sha256=z44tI4VjcgDW0jYrqxN8QrmBkp2stE0qlPuil0JWmrw,24686
344
+ pygpt_net/data/config/models.json,sha256=93-itPLPadsGqjnlf05UVxh4V3Z8jyaVDoiSUpbt02Y,104302
345
345
  pygpt_net/data/config/modes.json,sha256=M882iiqX_R2sNQl9cqZ3k-uneEvO9wpARtHRMLx_LHw,2265
346
346
  pygpt_net/data/config/presets/agent_code_act.json,sha256=GYHqhxtKFLUCvRI3IJAJ7Qe1k8yD9wGGNwManldWzlI,754
347
347
  pygpt_net/data/config/presets/agent_openai.json,sha256=vMTR-soRBiEZrpJJHuFLWyx8a3Ez_BqtqjyXgxCAM_Q,733
@@ -374,7 +374,7 @@ pygpt_net/data/config/presets/current.vision.json,sha256=x1ll5B3ROSKYQA6l27PRGXU
374
374
  pygpt_net/data/config/presets/dalle_white_cat.json,sha256=esqUb43cqY8dAo7B5u99tRC0MBV5lmlrVLnJhTSkL8w,552
375
375
  pygpt_net/data/config/presets/joke_agent.json,sha256=R6n9P7KRb0s-vZWZE7kHdlOfXAx1yYrPmUw8uLyw8OE,474
376
376
  pygpt_net/data/config/presets/joke_expert.json,sha256=jjcoIYEOaEp8kLoIbecxQROiq4J3Zess5w8_HmngPOY,671
377
- pygpt_net/data/config/settings.json,sha256=RejAz99Z5oWrvt4P2wUEqdaTeTbz0ykeOai32ZstPRQ,63863
377
+ pygpt_net/data/config/settings.json,sha256=9imY03YwU5LtOZGinAliy3Cp39h7D7cvE7ozeIas4sQ,64171
378
378
  pygpt_net/data/config/settings_section.json,sha256=Ng6kgmgxVmvt-KYFIqZvIDAEK4DfISNjNVF55DFWNjs,1082
379
379
  pygpt_net/data/css/fix_windows.css,sha256=Mks14Vg25ncbMqZJfAMStrhvZmgHF6kU75ohTWRZeI8,664
380
380
  pygpt_net/data/css/fix_windows.dark.css,sha256=7hGbT_qI5tphYC_WlFpJRDAcmjBb0AQ2Yc-y-_Zzf2M,161
@@ -383,11 +383,11 @@ pygpt_net/data/css/markdown.css,sha256=yaoJPogZZ_ghbqP8vTXTycwVyD61Ik5_033NpzuUz
383
383
  pygpt_net/data/css/markdown.dark.css,sha256=ixAwuT69QLesZttKhO4RAy-QukplZwwfXCZsWLN9TP4,730
384
384
  pygpt_net/data/css/markdown.light.css,sha256=UZdv0jtuFgJ_4bYWsDaDQ4X4AP9tVNLUHBAckC_oD8k,833
385
385
  pygpt_net/data/css/style.css,sha256=dgVlVqEL38zF-4Ok-y1rwfALC8zETJAIuIbkwat_hTk,337
386
- pygpt_net/data/css/style.dark.css,sha256=DS-Q7_WSGl3_p8hRFfDLY6m2dSREHIWb0alJcft_yxc,1889
387
- pygpt_net/data/css/style.light.css,sha256=egIPnKa7q0QJEXa1BpxlwHgQItwpnT5qbQqTG4s-N7I,4131
388
- pygpt_net/data/css/web-blocks.css,sha256=H_crm4OL_qsdSe8Ln8Lzcwu4NOe0myhmiBbmOKPPIGE,6316
389
- pygpt_net/data/css/web-blocks.dark.css,sha256=x0b3DYWv0-XeUgCSKajIpkAXAEEg-YR7GIg94pwXO7A,1319
390
- pygpt_net/data/css/web-blocks.light.css,sha256=TEzRZsdjY3xLkMQNzQemxORzsKvHkW_c53mYFNAGnNc,1379
386
+ pygpt_net/data/css/style.dark.css,sha256=Tvl44HL3bE4EDwFyJpUsdW4bPjPO9SyZzthN3Dypspg,1940
387
+ pygpt_net/data/css/style.light.css,sha256=LByvskAhfZ3hBR_8ERQqF7y0h5oCljGS2WUY86XZwWE,4182
388
+ pygpt_net/data/css/web-blocks.css,sha256=MYPMzXoC9snHmFrkNiXtm5Kg-1-KGQ7yLdaAoPMbvik,6874
389
+ pygpt_net/data/css/web-blocks.dark.css,sha256=XUYzp0Okw-b2XOiFK661yU8-n_o2PoBYRTCDWb5Zad0,1364
390
+ pygpt_net/data/css/web-blocks.light.css,sha256=wCCLZee_1PtIqAyNO9ke0tUqaomX9DFPwQv9BzAyKbY,1440
391
391
  pygpt_net/data/css/web-chatgpt.css,sha256=UwgJIxDTnea_-gSiaH-0xiAhTAEjTwEPHYZCo-yQr1Q,7315
392
392
  pygpt_net/data/css/web-chatgpt.dark.css,sha256=QS3hegsRPMCfk7ekIeHqyuEi2bN31Ka5L202xNPTqfY,1192
393
393
  pygpt_net/data/css/web-chatgpt.light.css,sha256=PauCHULIviEKPVP4XBo91ucuWeCcWcFM_RwrwlNz0qU,1298
@@ -1597,14 +1597,14 @@ pygpt_net/data/js/katex/fonts/KaTeX_Typewriter-Regular.woff,sha256=4U_tArGrp86fW
1597
1597
  pygpt_net/data/js/katex/fonts/KaTeX_Typewriter-Regular.woff2,sha256=cdUX1ngneHz6vfGGkUzDNY7aU543kxlB8rL9SiH2jAs,13568
1598
1598
  pygpt_net/data/js/katex/katex.min.css,sha256=lVaKnUaQNG4pI71WHffQZVALLQF4LMZEk4nOia8U9ow,23532
1599
1599
  pygpt_net/data/js/katex/katex.min.js,sha256=KLASOtKS2x8pUxWVzCDmlWJ4jhuLb0vtrgakbD6gDDo,276757
1600
- pygpt_net/data/locale/locale.de.ini,sha256=jaB47_jQ4hMwp0N4njhpFmJPUiZGiFPesu6pdlB5EoE,94856
1601
- pygpt_net/data/locale/locale.en.ini,sha256=3ZK_mjaXeBQpz7yGn6DVZ3K4AVxaCg1UYnJS6JXOCFo,86067
1602
- pygpt_net/data/locale/locale.es.ini,sha256=8PJvgaPlg7xdpZqAjxPWxrTo1v63qrA6HQiDSQGpabg,95606
1603
- pygpt_net/data/locale/locale.fr.ini,sha256=UtZnx5F7K5DGpUm-zxMPU66ApNPb4y4hk26TO0xrLfU,98057
1604
- pygpt_net/data/locale/locale.it.ini,sha256=f_0SoowNxR54-77fe6YdgnmefVr4YUskxlh8uyVAgvw,93446
1605
- pygpt_net/data/locale/locale.pl.ini,sha256=AIImLGoN_pAXzJOl-K2Udst3L6oV58iyvmGXdrM1x5I,93174
1606
- pygpt_net/data/locale/locale.uk.ini,sha256=vIATSz_HAPsDKHPH6Xr-BWAyEg-5pvgg4Ci7muS6DQI,129528
1607
- pygpt_net/data/locale/locale.zh.ini,sha256=7UPoObVwUQliQ0LU1GaNdkTYRX1EDPgcFIWW__77fAc,83424
1600
+ pygpt_net/data/locale/locale.de.ini,sha256=0_UQYSyEQ0IqTpaHl-OtDU1IhpXlkjbzUdN-D5DA_vg,94938
1601
+ pygpt_net/data/locale/locale.en.ini,sha256=oFFhqeyj1njU39eNYTDFkxbizxUtCOGn38b8n5H7so0,86148
1602
+ pygpt_net/data/locale/locale.es.ini,sha256=IhrRh_grMooCSYj9GLzydWKRqUH_4BGDEvYwRvG1SM4,95693
1603
+ pygpt_net/data/locale/locale.fr.ini,sha256=2xKiEaCJhVmhQttPEQi7nW2KaNIn7JIDO6uTGvBeDWk,98140
1604
+ pygpt_net/data/locale/locale.it.ini,sha256=IsMjpgm4QPxwrXb7ndJEN8ClG548T6Scdj_2Yb6bVaw,93531
1605
+ pygpt_net/data/locale/locale.pl.ini,sha256=uUrH_7JNzwaniZFM84TONSxCZ6vnFU04qB3NQyll-eI,93258
1606
+ pygpt_net/data/locale/locale.uk.ini,sha256=C5Y_2C8jAD8ABZlOxOmXNMcjy0vNULAej5ho064ippA,129629
1607
+ pygpt_net/data/locale/locale.zh.ini,sha256=63zhP-WN-HoapipZ6yjbJgwdaipyWdxNIKt2WgxpskE,83503
1608
1608
  pygpt_net/data/locale/plugin.agent.de.ini,sha256=BY28KpfFvgfVYJzcw2o5ScWnR4uuErIYGyc3NVHlmTw,1714
1609
1609
  pygpt_net/data/locale/plugin.agent.en.ini,sha256=HwOWCI7e8uzlIgyRWRVyr1x6Xzs8Xjv5pfEc7jfLOo4,1728
1610
1610
  pygpt_net/data/locale/plugin.agent.es.ini,sha256=bqaJQne8HPKFVtZ8Ukzo1TSqVW41yhYbGUqW3j2x1p8,1680
@@ -1985,7 +1985,7 @@ pygpt_net/provider/core/calendar/db_sqlite/storage.py,sha256=QDclQCQdr4QyRIqjgGX
1985
1985
  pygpt_net/provider/core/config/__init__.py,sha256=jQQgG9u_ZLsZWXustoc1uvC-abUvj4RBKPAM30-f2Kc,488
1986
1986
  pygpt_net/provider/core/config/base.py,sha256=cbvzbMNqL2XgC-36gGubnU37t94AX7LEw0lecb2Nm80,1365
1987
1987
  pygpt_net/provider/core/config/json_file.py,sha256=fQHjoVIPYdW7kl3fe0uNl7f5fMU76hoJK72qx_yKY9o,6453
1988
- pygpt_net/provider/core/config/patch.py,sha256=FUBCTB7ZKCsm9fhUz42Cf0jbgRI80mcjbjQUcvAjWmM,114516
1988
+ pygpt_net/provider/core/config/patch.py,sha256=QwsceOLEafvDgJlHXq5AhrSheesvrsj3StVXqcpPCwU,115173
1989
1989
  pygpt_net/provider/core/ctx/__init__.py,sha256=jQQgG9u_ZLsZWXustoc1uvC-abUvj4RBKPAM30-f2Kc,488
1990
1990
  pygpt_net/provider/core/ctx/base.py,sha256=Tfb4MDNe9BXXPU3lbzpdYwJF9S1oa2-mzgu5XT4It9g,3003
1991
1991
  pygpt_net/provider/core/ctx/db_sqlite/__init__.py,sha256=0dP8VhI4bnFsQQKxAkaleKFlyaMycDD_cnE7gBCa57Y,512
@@ -2155,7 +2155,7 @@ pygpt_net/tools/audio_transcriber/ui/dialogs.py,sha256=D-roLNGj5Zkl7_2nlahGX4fwD
2155
2155
  pygpt_net/tools/base.py,sha256=KxTSYGIG8eQyL_loyAWP2loPJni0TOg_wwvlq5tLYrg,3833
2156
2156
  pygpt_net/tools/code_interpreter/__init__.py,sha256=7FScUoJWFBsF6Rbmt14zb2YEERcywW_xAeX0GTAHhX4,508
2157
2157
  pygpt_net/tools/code_interpreter/body.py,sha256=mMdkosviBgpMLB9-9kAnWe3YVMC3GLooe6MuQn37zp4,14139
2158
- pygpt_net/tools/code_interpreter/tool.py,sha256=pTI3-5YLUreQrht1SVsxvndLaTYjX216JR6a57O4RUc,23511
2158
+ pygpt_net/tools/code_interpreter/tool.py,sha256=S_JKvExPd2Wc05qfOUdhiaFd8la26ac0XIAi_WSm-G8,24015
2159
2159
  pygpt_net/tools/code_interpreter/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2160
2160
  pygpt_net/tools/code_interpreter/ui/dialogs.py,sha256=iYCtmn_gPMKhvy8Ygga_oYPVg80zP3-10SZgv0O6xYQ,5429
2161
2161
  pygpt_net/tools/code_interpreter/ui/html.py,sha256=6sUvhgiYPW9YWCcnwGcCrpLgHDIPljtdD_LbdDKbyyU,23580
@@ -2228,11 +2228,11 @@ pygpt_net/ui/layout/chat/attachments.py,sha256=A9kWYwKjGjkSrjKmUqQV8tghFSSU2Eoxe
2228
2228
  pygpt_net/ui/layout/chat/attachments_ctx.py,sha256=qyidK2bbTufWX-crtEhat2i3-Juqql-VEwIlfz6iL_s,7239
2229
2229
  pygpt_net/ui/layout/chat/attachments_uploaded.py,sha256=8xKa9xwU56ESSfBN5ybwT_BUZEwgij-tjHbhhzNuV2U,5462
2230
2230
  pygpt_net/ui/layout/chat/calendar.py,sha256=ocO7puuh82iZVi-RB_U68dOoI_68C2Yb2mG0xSeVVL0,5940
2231
- pygpt_net/ui/layout/chat/chat.py,sha256=e89R6PXRXXhWx8dWL5TqUTysxdAmi1TqwM5il4vquMk,1598
2231
+ pygpt_net/ui/layout/chat/chat.py,sha256=8ED6t5cohget-QcYKFAWgRSpEG2wApFo_DYYkMBXZwc,2325
2232
2232
  pygpt_net/ui/layout/chat/explorer.py,sha256=Jg6aK5qTCTNgb4EXr-zeZXSexARQSzn4W8unqV1MGe8,1358
2233
- pygpt_net/ui/layout/chat/input.py,sha256=54Kd3KJNgN41vyydSsRtr9554BS_IDkymPQGiYEkaYY,10907
2233
+ pygpt_net/ui/layout/chat/input.py,sha256=hdnF77f7CqnBNwqXWSUO61rGJ--FjyjVpx3ojVeKUqI,11326
2234
2234
  pygpt_net/ui/layout/chat/markdown.py,sha256=hjYY8Da1z0IZZD086_csMcDY1wwagpuQTDZ-XfgeNgs,18656
2235
- pygpt_net/ui/layout/chat/output.py,sha256=GRV4Gkg4JnadxLlxycq5WfmI8xMRr0Fno3Ew6Tb9F48,9896
2235
+ pygpt_net/ui/layout/chat/output.py,sha256=svZ1cDo-j8r-ZwjoDPp3vB2lSnE_2_FJW-TZ7x6vpDg,9996
2236
2236
  pygpt_net/ui/layout/chat/painter.py,sha256=tveiIs1mNk71c03ZX-K4so4daO3-ED8ZgRNcUrrQtcw,5535
2237
2237
  pygpt_net/ui/layout/ctx/__init__.py,sha256=NJ9L0yJKIx1nKnk2sczp7ILWVbu2hfpvUz4E56EFuPI,509
2238
2238
  pygpt_net/ui/layout/ctx/ctx.py,sha256=GDJyolAnFlAd49bbu9-LGsCxOUTAImSH5In4i8YHFOo,1653
@@ -2313,7 +2313,7 @@ pygpt_net/ui/widget/element/__init__.py,sha256=8HT4tQFqQogEEpGYTv2RplKBthlsFKcl5
2313
2313
  pygpt_net/ui/widget/element/button.py,sha256=l_yz620U5NZTRTlltUOBzyDARGQQAX7fJrfIS1XC9DM,4173
2314
2314
  pygpt_net/ui/widget/element/checkbox.py,sha256=i7774WlRHEg8Js7XdpdMF5LGW1DrBXU4Makub_j2LtM,2532
2315
2315
  pygpt_net/ui/widget/element/group.py,sha256=a76-dsfLnI7EBIMu7Q-So1lsYw8870M-GhzfRwLLf-8,3632
2316
- pygpt_net/ui/widget/element/labels.py,sha256=feaWOMAkjzO6JO86vJdsy7WSTa2j9RURNPFlDiepYgc,3919
2316
+ pygpt_net/ui/widget/element/labels.py,sha256=qg6wfOjOEya7H7fHmv4UmSJxOySwV5da359FnfdsOhs,6003
2317
2317
  pygpt_net/ui/widget/filesystem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2318
2318
  pygpt_net/ui/widget/filesystem/explorer.py,sha256=GLWvASeb4O5Ks817IHCyMmN7b5V2GEZa6PeZBdHmMtw,23902
2319
2319
  pygpt_net/ui/widget/image/__init__.py,sha256=X9-pucLqQF9_ocDV-qNY6EQAJ_4dubGb-7TcWIzCXBo,488
@@ -2379,8 +2379,8 @@ pygpt_net/ui/widget/textarea/web.py,sha256=7VTiA1LwWSUmbJ7r1uhKV-RFndOfNC_r_EAJi
2379
2379
  pygpt_net/ui/widget/vision/__init__.py,sha256=8HT4tQFqQogEEpGYTv2RplKBthlsFKcl5egnv4lzzEw,488
2380
2380
  pygpt_net/ui/widget/vision/camera.py,sha256=T8b5cmK6uhf_WSSxzPt_Qod8JgMnst6q8sQqRvgQiSA,2584
2381
2381
  pygpt_net/utils.py,sha256=mQ_9Esbs2htAw82tPG5rzST8IZwXFwO2eLPsHRTCMJ4,6936
2382
- pygpt_net-2.5.89.dist-info/LICENSE,sha256=rbPqNB_xxANH8hKayJyIcTwD4bj4Y2G-Mcm85r1OImM,1126
2383
- pygpt_net-2.5.89.dist-info/METADATA,sha256=GcVbnnu75ZzJ_TMHSfKEqkEoY25BuXaguJ90AqnY-34,182431
2384
- pygpt_net-2.5.89.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
2385
- pygpt_net-2.5.89.dist-info/entry_points.txt,sha256=qvpII6UHIt8XfokmQWnCYQrTgty8FeJ9hJvOuUFCN-8,43
2386
- pygpt_net-2.5.89.dist-info/RECORD,,
2382
+ pygpt_net-2.5.90.dist-info/LICENSE,sha256=rbPqNB_xxANH8hKayJyIcTwD4bj4Y2G-Mcm85r1OImM,1126
2383
+ pygpt_net-2.5.90.dist-info/METADATA,sha256=3KEd-zfK2BFlVHQb1J8hanO_xzKxnv0142kA2g4ZsnI,182637
2384
+ pygpt_net-2.5.90.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
2385
+ pygpt_net-2.5.90.dist-info/entry_points.txt,sha256=qvpII6UHIt8XfokmQWnCYQrTgty8FeJ9hJvOuUFCN-8,43
2386
+ pygpt_net-2.5.90.dist-info/RECORD,,