pygpt-net 2.6.67__py3-none-any.whl → 2.7.0__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 (69) hide show
  1. pygpt_net/CHANGELOG.txt +12 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/controller/assistant/assistant.py +13 -8
  4. pygpt_net/controller/assistant/batch.py +29 -15
  5. pygpt_net/controller/assistant/files.py +19 -14
  6. pygpt_net/controller/assistant/store.py +63 -41
  7. pygpt_net/controller/attachment/attachment.py +45 -35
  8. pygpt_net/controller/chat/attachment.py +50 -39
  9. pygpt_net/controller/config/field/dictionary.py +26 -14
  10. pygpt_net/controller/ctx/common.py +27 -17
  11. pygpt_net/controller/ctx/ctx.py +182 -101
  12. pygpt_net/controller/files/files.py +101 -41
  13. pygpt_net/controller/idx/indexer.py +87 -31
  14. pygpt_net/controller/kernel/kernel.py +13 -2
  15. pygpt_net/controller/mode/mode.py +3 -3
  16. pygpt_net/controller/model/editor.py +70 -15
  17. pygpt_net/controller/model/importer.py +153 -54
  18. pygpt_net/controller/painter/painter.py +2 -2
  19. pygpt_net/controller/presets/experts.py +68 -15
  20. pygpt_net/controller/presets/presets.py +72 -36
  21. pygpt_net/controller/settings/profile.py +76 -35
  22. pygpt_net/controller/settings/workdir.py +70 -39
  23. pygpt_net/core/assistants/files.py +20 -18
  24. pygpt_net/core/filesystem/actions.py +111 -10
  25. pygpt_net/core/filesystem/filesystem.py +2 -1
  26. pygpt_net/core/idx/idx.py +12 -11
  27. pygpt_net/core/idx/worker.py +13 -1
  28. pygpt_net/core/models/models.py +4 -4
  29. pygpt_net/core/profile/profile.py +13 -3
  30. pygpt_net/data/config/config.json +3 -3
  31. pygpt_net/data/config/models.json +3 -3
  32. pygpt_net/data/css/style.dark.css +39 -1
  33. pygpt_net/data/css/style.light.css +39 -1
  34. pygpt_net/data/locale/locale.de.ini +3 -1
  35. pygpt_net/data/locale/locale.en.ini +3 -1
  36. pygpt_net/data/locale/locale.es.ini +3 -1
  37. pygpt_net/data/locale/locale.fr.ini +3 -1
  38. pygpt_net/data/locale/locale.it.ini +3 -1
  39. pygpt_net/data/locale/locale.pl.ini +4 -2
  40. pygpt_net/data/locale/locale.uk.ini +3 -1
  41. pygpt_net/data/locale/locale.zh.ini +3 -1
  42. pygpt_net/provider/api/openai/__init__.py +4 -2
  43. pygpt_net/provider/core/config/patch.py +9 -1
  44. pygpt_net/tools/image_viewer/tool.py +17 -0
  45. pygpt_net/tools/text_editor/tool.py +9 -0
  46. pygpt_net/ui/__init__.py +2 -2
  47. pygpt_net/ui/layout/ctx/ctx_list.py +16 -6
  48. pygpt_net/ui/main.py +3 -1
  49. pygpt_net/ui/widget/calendar/select.py +3 -3
  50. pygpt_net/ui/widget/filesystem/explorer.py +1082 -142
  51. pygpt_net/ui/widget/lists/assistant.py +185 -24
  52. pygpt_net/ui/widget/lists/assistant_store.py +245 -42
  53. pygpt_net/ui/widget/lists/attachment.py +230 -47
  54. pygpt_net/ui/widget/lists/attachment_ctx.py +189 -33
  55. pygpt_net/ui/widget/lists/base_list_combo.py +2 -2
  56. pygpt_net/ui/widget/lists/context.py +1253 -70
  57. pygpt_net/ui/widget/lists/experts.py +110 -8
  58. pygpt_net/ui/widget/lists/model_editor.py +217 -14
  59. pygpt_net/ui/widget/lists/model_importer.py +125 -6
  60. pygpt_net/ui/widget/lists/preset.py +460 -71
  61. pygpt_net/ui/widget/lists/profile.py +149 -27
  62. pygpt_net/ui/widget/lists/uploaded.py +230 -38
  63. pygpt_net/ui/widget/option/combo.py +1046 -32
  64. pygpt_net/ui/widget/option/dictionary.py +35 -7
  65. {pygpt_net-2.6.67.dist-info → pygpt_net-2.7.0.dist-info}/METADATA +14 -57
  66. {pygpt_net-2.6.67.dist-info → pygpt_net-2.7.0.dist-info}/RECORD +69 -69
  67. {pygpt_net-2.6.67.dist-info → pygpt_net-2.7.0.dist-info}/LICENSE +0 -0
  68. {pygpt_net-2.6.67.dist-info → pygpt_net-2.7.0.dist-info}/WHEEL +0 -0
  69. {pygpt_net-2.6.67.dist-info → pygpt_net-2.7.0.dist-info}/entry_points.txt +0 -0
pygpt_net/core/idx/idx.py CHANGED
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.21 07:00:00 #
9
+ # Updated Date: 2025.12.27 17:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import datetime
@@ -505,16 +505,17 @@ class Idx:
505
505
  self.llm.get_service_context(stream=False) # init environment only (ENV API keys, etc.)
506
506
  store_id = self.get_current_store()
507
507
  if store_id in self.items and idx in self.items[store_id]:
508
- if file in self.items[store_id][idx].items:
509
- # remove from storage
510
- doc_id = self.items[store_id][idx].items[file]["id"]
511
- self.storage.remove_document(
512
- id=idx,
513
- doc_id=doc_id,
514
- )
515
- # remove from index data and db
516
- del self.items[store_id][idx].items[file]
517
- self.files.remove(store_id, idx, doc_id)
508
+ for basename in list(self.items[store_id][idx].items.keys()):
509
+ item = self.items[store_id][idx].items[basename]
510
+ if file == item["path"]:
511
+ doc_id = item ["id"]
512
+ self.storage.remove_document(
513
+ id=idx,
514
+ doc_id=doc_id,
515
+ )
516
+ # remove from index data and db
517
+ del self.items[store_id][idx].items[basename]
518
+ self.files.remove(store_id, idx, doc_id)
518
519
 
519
520
  def load(self):
520
521
  """Load indexes and indexed items"""
@@ -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.21 07:00:00 #
9
+ # Updated Date: 2025.12.27 19:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import QObject, Signal, QRunnable, Slot
@@ -29,6 +29,7 @@ class IndexWorker(QRunnable):
29
29
  self.replace = None
30
30
  self.recursive = None
31
31
  self.from_ts = 0
32
+ self.from_ts_batch = {}
32
33
  self.idx = None
33
34
  self.type = None
34
35
  self.silent = False
@@ -70,6 +71,17 @@ class IndexWorker(QRunnable):
70
71
  self.content,
71
72
  self.from_ts,
72
73
  )
74
+ elif self.type == "db_meta_batch":
75
+ result = 0
76
+ errors = []
77
+ for meta_id in self.content:
78
+ r, e = self.window.core.idx.index_db_by_meta_id(
79
+ self.idx,
80
+ meta_id,
81
+ self.from_ts_batch[meta_id],
82
+ )
83
+ result += r
84
+ errors.extend(e)
73
85
  elif self.type == "db_current":
74
86
  result, errors = self.window.core.idx.index_db_from_updated_ts(
75
87
  self.idx,
@@ -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.09.17 19:00:00 #
9
+ # Updated Date: 2025.12.26 20:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
13
- from typing import Optional, List, Dict
13
+ from typing import Optional, List, Dict, Tuple
14
14
 
15
15
  from httpx_socks import SyncProxyTransport
16
16
  from openai import DefaultHttpxClient
@@ -272,7 +272,7 @@ class Models:
272
272
  """
273
273
  return self.multimodal
274
274
 
275
- def create_empty(self, append: bool = True) -> ModelItem:
275
+ def create_empty(self, append: bool = True) -> Tuple[ModelItem, str]:
276
276
  """
277
277
  Create new empty model
278
278
 
@@ -288,7 +288,7 @@ class Models:
288
288
  model.output = ["text"]
289
289
  if append:
290
290
  self.items[id] = model
291
- return model
291
+ return model, id
292
292
 
293
293
  def get_all(self) -> Dict[str, ModelItem]:
294
294
  """
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.12.14 22:00:00 #
9
+ # Updated Date: 2025.12.28 04:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import json
@@ -116,9 +116,19 @@ class Profile:
116
116
  'profiles': self.profiles
117
117
  }
118
118
  json_data = json.dumps(config, indent=4)
119
+ f_lock = os.path.join(self.base_workdir, self.PROFILE_FILE + '.lock')
119
120
  f = os.path.join(self.base_workdir, self.PROFILE_FILE)
120
- with open(f, 'w', encoding='utf-8') as f:
121
- f.write(json_data)
121
+ # check lock first
122
+ if os.path.exists(f_lock):
123
+ print("WARNING: Profile save aborted, lock exists. Please remove lock file:", f_lock)
124
+ return # abort if lock exists
125
+ with open(f_lock, 'w', encoding='utf-8') as file:
126
+ file.write('lock')
127
+ with open(f, 'w', encoding='utf-8') as file:
128
+ file.write(json_data)
129
+ # remove lock
130
+ if os.path.exists(f_lock):
131
+ os.remove(f_lock)
122
132
 
123
133
  def add(
124
134
  self,
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.6.67",
4
- "app.version": "2.6.67",
5
- "updated_at": "2025-12-26T00:00:00"
3
+ "version": "2.7.0",
4
+ "app.version": "2.7.0",
5
+ "updated_at": "2025-12-28T00:00:00"
6
6
  },
7
7
  "access.audio.event.speech": false,
8
8
  "access.audio.event.speech.disabled": [],
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.6.67",
4
- "app.version": "2.6.67",
5
- "updated_at": "2025-12-26T00:00:00"
3
+ "version": "2.7.0",
4
+ "app.version": "2.7.0",
5
+ "updated_at": "2025-12-28T00:00:00"
6
6
  },
7
7
  "items": {
8
8
  "SpeakLeash/bielik-11b-v2.3-instruct:Q4_K_M": {
@@ -174,4 +174,42 @@ NodeEditor {{
174
174
  /* Status Bar */
175
175
  #StatusBarTimer {{
176
176
  color: #999 !important;
177
- }}
177
+ }}
178
+
179
+ /* ComboBox */
180
+ QComboBox QAbstractItemView {{
181
+ border: 1px solid rgba(0,0,0,0.18);
182
+ border-radius: 0;
183
+ outline: 0;
184
+ }}
185
+
186
+ QListView#ComboPopupList {{
187
+ border-radius: 0;
188
+ outline: 0;
189
+ }}
190
+
191
+ QComboBox QAbstractItemView::item,
192
+ QListView#ComboPopupList::item {{
193
+ min-height: 20px;
194
+ padding: 8px 33px;
195
+ margin: 0;
196
+ color: #fff;
197
+ }}
198
+
199
+ QComboBox QAbstractItemView::item:selected,
200
+ QListView#ComboPopupList::item:selected {{
201
+ background: #fff;
202
+ color: #000;
203
+ selection-color: #000;
204
+ font-weight: bold;
205
+ }}
206
+
207
+ QListView#ComboPopupList::item:disabled {{
208
+ color: #c9c9c9;
209
+ background: #363d42;
210
+ padding: 15px;
211
+ }}
212
+
213
+ QComboBox QAbstractItemView::item:hover,
214
+ QListView#ComboPopupList::item:hover {{ }}
215
+ QListView#ComboPopupList > QWidget#ComboPopupViewport {{ }}
@@ -290,4 +290,42 @@ NodeEditor {{
290
290
  /* Status Bar */
291
291
  #StatusBarTimer {{
292
292
  color: #5d5d5d !important;
293
- }}
293
+ }}
294
+
295
+ /* ComboBox */
296
+ QComboBox QAbstractItemView {{
297
+ border: 1px solid rgba(0,0,0,0.18);
298
+ border-radius: 0;
299
+ outline: 0;
300
+ }}
301
+
302
+ QListView#ComboPopupList {{
303
+ border-radius: 0;
304
+ outline: 0;
305
+ }}
306
+
307
+ QComboBox QAbstractItemView::item,
308
+ QListView#ComboPopupList::item {{
309
+ min-height: 20px;
310
+ padding: 8px 32px;
311
+ margin: 0;
312
+ color: #000;
313
+ }}
314
+
315
+ QComboBox QAbstractItemView::item:selected,
316
+ QListView#ComboPopupList::item:selected {{
317
+ background: #fff;
318
+ color: #000;
319
+ selection-color: #000;
320
+ font-weight: bold;
321
+ }}
322
+
323
+ QListView#ComboPopupList::item:disabled {{
324
+ color: #3f3f3f;
325
+ background: #d9d9d9;
326
+ padding: 15px;
327
+ }}
328
+
329
+ QComboBox QAbstractItemView::item:hover,
330
+ QListView#ComboPopupList::item:hover {{ }}
331
+ QListView#ComboPopupList > QWidget#ComboPopupViewport {{ }}
@@ -16,6 +16,7 @@ action.ctx.indexed = Zuletzt indiziert am
16
16
  action.ctx.new = Neuer Kontext...
17
17
  action.ctx.new.in_group = Neuer Kontext in: {group}...
18
18
  action.ctx_reset = Zurücksetzen (löschen)
19
+ action.cut = Schneiden
19
20
  action.delete = Löschen
20
21
  action.download = Herunterladen
21
22
  action.duplicate = Duplizieren
@@ -26,6 +27,7 @@ action.group.new = Neue Gruppe
26
27
  action.group.remove = Aus Gruppe entfernen
27
28
  action.idx = Index with LlamaIndex...
28
29
  action.idx.remove = Entfernen aus
30
+ action.import = Importieren
29
31
  action.mkdir = Verzeichnis erstellen...
30
32
  action.move_to = Verschieben nach
31
33
  action.new = Neu...
@@ -1570,7 +1572,7 @@ tip.input.attachments.ctx = Poniżej znajdują się załączone i zindeksowane z
1570
1572
  tip.input.attachments.uploaded = Hier ist eine Liste von Dateien, die im Assistant-Modus auf den Server hochgeladen wurden. Diese Dateien befinden sich auf einem entfernten Server und nicht auf Ihrem lokalen Computer, sodass das Modell sie mit extern auf dem entfernten Server verfügbaren Werkzeugen verwenden und analysieren kann.
1571
1573
  tip.output.tab.calendar = Mit dem Kalender können Sie zu ausgewählten Gesprächen von einem bestimmten Tag navigieren. Klicken Sie in den Kalender auf einen Tag, um die Anzeige des Chat-Verlaufs auf diesen Tag zu beschränken. Sie können auch Tagesnotizen erstellen und ihnen farbige Etiketten zuweisen.
1572
1574
  tip.output.tab.draw = Sie können das Zeichenwerkzeug für schnelle Skizzen oder das Erfassen eines Bildes von der Kamera verwenden, und dann solche Bilder im Vision-Modus zur Analyse an die KI senden. Sie können hier ein Bild mit der Kamera erfassen oder ein Bild von der Festplatte öffnen. Wenn Sie ein Bild verwenden, wird es als Anhang in der gesendeten Nachricht enthalten sein.
1573
- tip.output.tab.files = Dieses Verzeichnis mit Arbeitsdateien befindet sich auf Ihrer Festplatte. Die Dateien hier sind für KI zum Lesen zugänglich. KI kann Dateien lesen und schreiben sowie Code aus diesem Verzeichnis ausführen. Sie können dieses Verzeichnis lokal auf Ihrem System öffnen und beliebige Dateien hierhin verschieben. Sie können auch die Dateien mit Llama-Index indizieren, damit sie als zusätzliche Wissens Quelle dienen.
1575
+ tip.output.tab.files = Dieses Verzeichnis mit Arbeitsdateien befindet sich auf Ihrer Festplatte. Die Dateien hier sind für KI zum Lesen zugänglich. KI kann Dateien lesen und schreiben sowie Code aus diesem Verzeichnis ausführen. Sie können dieses Verzeichnis lokal auf Ihrem System öffnen und beliebige Dateien hierhin verschieben. Sie können auch die Dateien mit Llama-Index indizieren, damit sie als zusätzliche Wissens Quelle dienen. Verwenden Sie CTRL/SHIFT für die Mehrfachauswahl.
1574
1576
  tip.output.tab.notepad = Der Notizblock kann als Werkzeug zum Notieren und Speichern von Informationen dienen. Sie können hier beliebigen Text speichern, Text aus dem Chatfenster kopieren und alle Informationen werden automatisch gespeichert. Sie können weitere Notizblöcke erstellen, indem Sie einen neuen Tab erstellen.
1575
1577
  tip.tokens.ctx = Kontext (Erinnerung): in Gebrauch / alle - Token
1576
1578
  tip.tokens.input = Token: Benutzereingabeaufforderung + Systemaufforderung + Kontext + extra + Anhänge = Summe / Maximum
@@ -16,6 +16,7 @@ action.ctx.indexed = Last indexed at
16
16
  action.ctx.new = New context...
17
17
  action.ctx.new.in_group = New context in: {group}...
18
18
  action.ctx_reset = Reset (clear)
19
+ action.cut = Cut
19
20
  action.delete = Delete
20
21
  action.download = Download
21
22
  action.duplicate = Duplicate
@@ -26,6 +27,7 @@ action.group.new = New group
26
27
  action.group.remove = Remove from group
27
28
  action.idx = Index with LlamaIndex...
28
29
  action.idx.remove = Remove from
30
+ action.import = Import
29
31
  action.mkdir = Create directory...
30
32
  action.move_to = Move to
31
33
  action.new = New...
@@ -1649,7 +1651,7 @@ tip.input.attachments.ctx = Below are the uploaded and indexed attachments avail
1649
1651
  tip.input.attachments.uploaded = Here is a list of files uploaded to the server in Assistant mode. These files are located on a remote server, not on your local computer, so the model can use and analyze them using tools available externally on the remote server.
1650
1652
  tip.output.tab.calendar = Using the calendar, you can navigate back to selected conversations from a specific day. Click on a day in the calendar to limit the display of chat history to that day. You can also create day notes and assign them colorful labels.
1651
1653
  tip.output.tab.draw = You can use the drawing tool for quick sketching or capturing an image from the camera, and then send such images to the AI in Vision mode for analysis. You can capture an image with the camera here or open an image from the disk. When using an image, it will be included in the sent message as an attachment.
1652
- tip.output.tab.files = This working files directory is on your disk. The files here are accessible for AI. AI can write and read files, as well as run code from this directory. You can open this directory locally on your system and place any files here. You can also index the files from here with LlamaIndex, so they serve as an additional knowledge source.
1654
+ tip.output.tab.files = This working files directory is on your disk. The files here are accessible for AI. AI can write and read files, as well as run code from this directory. You can open this directory locally on your system and place any files here. You can also index the files from here with LlamaIndex, so they serve as an additional knowledge source. Use CTRL/SHIFT for multiple selection.
1653
1655
  tip.output.tab.notepad = The notepad can serve as a tool for taking notes and storing information. You can keep any text here, copy text from the chat window, and all information will be automatically saved. You can create more notepads by creating a new Tab.
1654
1656
  tip.tokens.ctx = Context (memory): in use / all - tokens
1655
1657
  tip.tokens.input = Tokens: input prompt + system prompt + context + extra + attachments = sum / max
@@ -16,6 +16,7 @@ action.ctx.indexed = Última indexación el
16
16
  action.ctx.new = Nuevo contexto...
17
17
  action.ctx.new.in_group = Nuevo contexto en: {group}...
18
18
  action.ctx_reset = Restablecer (borrar)
19
+ action.cut = Cortar
19
20
  action.delete = Eliminar
20
21
  action.download = Descargar
21
22
  action.duplicate = Duplicar
@@ -26,6 +27,7 @@ action.group.new = Nuevo grupo
26
27
  action.group.remove = Quitar del grupo
27
28
  action.idx = Indexar con LlamaIndex...
28
29
  action.idx.remove = Eliminar de
30
+ action.import = Importar
29
31
  action.mkdir = Crear directorio...
30
32
  action.move_to = Mover a
31
33
  action.new = Nuevo...
@@ -1571,7 +1573,7 @@ tip.input.attachments.ctx = A continuación se detallan los archivos adjuntos su
1571
1573
  tip.input.attachments.uploaded = Aquí tienes una lista de archivos subidos al servidor en el modo Asistente. Estos archivos están ubicados en un servidor remoto, no en tu computadora local, por lo que el modelo puede usarlos y analizarlos utilizando herramientas disponibles externamente en el servidor remoto.
1572
1574
  tip.output.tab.calendar = Usando el calendario, puedes navegar de vuelta a conversaciones seleccionadas de un día específico. Haz clic en un día en el calendario para limitar la visualización del historial de chat a ese día. También puedes crear notas diarias y asignarles etiquetas de colores.
1573
1575
  tip.output.tab.draw = Puedes usar la herramienta de dibujo para hacer bocetos rápidos o capturar una imagen de la cámara, y luego enviar dichas imágenes a la IA en modo Visión para su análisis. Puedes capturar una imagen con la cámara aquí o abrir una imagen desde el disco. Al usar una imagen, se incluirá en el mensaje enviado como un adjunto.
1574
- tip.output.tab.files = Este directorio de archivos de trabajo se encuentra en tu disco. Los archivos aquí son accesibles para que la IA los lea. La IA puede escribir y leer archivos, así como ejecutar código desde este directorio. Puedes abrir este directorio localmente en tu sistema y colocar cualquier archivo aquí. También puedes indexar los archivos con LlamaIndex, para que sirvan como una fuente de conocimiento adicional.
1576
+ tip.output.tab.files = Este directorio de archivos de trabajo se encuentra en tu disco. Los archivos aquí son accesibles para que la IA los lea. La IA puede escribir y leer archivos, así como ejecutar código desde este directorio. Puedes abrir este directorio localmente en tu sistema y colocar cualquier archivo aquí. También puedes indexar los archivos con LlamaIndex, para que sirvan como una fuente de conocimiento adicional. Usa CTRL/SHIFT para la selección múltiple.
1575
1577
  tip.output.tab.notepad = El bloc de notas puede servir como una herramienta para tomar notas y almacenar información. Puedes mantener cualquier texto aquí, copiar texto desde la ventana de chat, y toda la información se guardará automáticamente. Puedes crear más blocs de notas creando una nueva pestaña.
1576
1578
  tip.tokens.ctx = Contexto (memoria): en uso / todos - tokens
1577
1579
  tip.tokens.input = Fichas: indicación del usuario + indicación del sistema + contexto + adicional + adjuntos = suma / máximo
@@ -16,6 +16,7 @@ action.ctx.indexed = Dernière indexation le
16
16
  action.ctx.new = Nouveau contexte...
17
17
  action.ctx.new.in_group = Nouveau contexte dans : {group}...
18
18
  action.ctx_reset = Réinitialiser (effacer)
19
+ action.cut = Couper
19
20
  action.delete = Supprimer
20
21
  action.download = Télécharger
21
22
  action.duplicate = Dupliquer
@@ -26,6 +27,7 @@ action.group.new = Nouveau groupe
26
27
  action.group.remove = Retirer du groupe
27
28
  action.idx = Indexer avec LlamaIndex...
28
29
  action.idx.remove = Retirer de
30
+ action.import = Importer
29
31
  action.mkdir = Créer un répertoire...
30
32
  action.move_to = Déplacer vers
31
33
  action.new = Nouveau...
@@ -1570,7 +1572,7 @@ tip.input.attachments.ctx = Vous trouverez ci-dessous les pièces jointes télé
1570
1572
  tip.input.attachments.uploaded = Voici une liste de fichiers téléchargés sur le serveur en mode Assistant. Ces fichiers sont situés sur un serveur distant, pas sur votre ordinateur local, donc le modèle peut les utiliser et les analyser à l'aide des outils disponibles à l'extérieur sur le serveur distant.
1571
1573
  tip.output.tab.calendar = En utilisant le calendrier, vous pouvez revenir à des conversations sélectionnées d'un jour spécifique. Cliquez sur un jour dans le calendrier pour limiter l'affichage de l'historique de chat à ce jour. Vous pouvez également créer des notes de jour et leur attribuer des étiquettes colorées.
1572
1574
  tip.output.tab.draw = Vous pouvez utiliser l'outil de dessin pour esquisser rapidement ou capturer une image de la caméra, puis envoyer de telles images à l'IA en mode Vision pour analyse. Vous pouvez capturer une image avec la caméra ici ou ouvrir une image du disque. Lors de l'utilisation d'une image, elle sera incluse dans le message envoyé en tant que pièce jointe.
1573
- tip.output.tab.files = Ce répertoire de fichiers de travail se trouve sur votre disque. Les fichiers ici sont accessibles pour l'IA à lire. L'IA peut lire et écrire des fichiers, ainsi qu'exécuter du code à partir de ce répertoire. Vous pouvez ouvrir ce répertoire localement sur votre système et placer n'importe quels fichiers ici. Vous pouvez également indexer les fichiers avec LlamaIndex, afin qu'ils servent de source de connaissances supplémentaire.
1575
+ tip.output.tab.files = Ce répertoire de fichiers de travail se trouve sur votre disque. Les fichiers ici sont accessibles pour l'IA à lire. L'IA peut lire et écrire des fichiers, ainsi qu'exécuter du code à partir de ce répertoire. Vous pouvez ouvrir ce répertoire localement sur votre système et placer n'importe quels fichiers ici. Vous pouvez également indexer les fichiers avec LlamaIndex, afin qu'ils servent de source de connaissances supplémentaire. Utilisez CTRL/SHIFT pour la sélection multiple.
1574
1576
  tip.output.tab.notepad = Le bloc-notes peut servir d'outil pour prendre des notes et stocker des informations. Vous pouvez garder n'importe quel texte ici, copier du texte depuis la fenêtre de chat, et toutes les informations seront automatiquement enregistrées. Vous pouvez créer plus de blocs-notes en créant un nouvel onglet.
1575
1577
  tip.tokens.ctx = Contexte (mémoire) : en utilisation / total - jetons
1576
1578
  tip.tokens.input = Jetons: invite de l'utilisateur + invite système + contexte + extra + pièces jointes = somme / maximum
@@ -16,6 +16,7 @@ action.ctx.indexed = Ultima indicizzazione il
16
16
  action.ctx.new = Nuovo contesto...
17
17
  action.ctx.new.in_group = Nuovo contesto in: {group}...
18
18
  action.ctx_reset = Reimposta (cancella)
19
+ action.cut = Taglia
19
20
  action.delete = Elimina
20
21
  action.download = Scarica
21
22
  action.duplicate = Duplica
@@ -26,6 +27,7 @@ action.group.new = Nuovo gruppo
26
27
  action.group.remove = Rimuovi dal gruppo
27
28
  action.idx = Indicizzare con LlamaIndex...
28
29
  action.idx.remove = Rimuovi da
30
+ action.import = Importa
29
31
  action.mkdir = Crea directory...
30
32
  action.move_to = Sposta in
31
33
  action.new = Nuovo...
@@ -1570,7 +1572,7 @@ tip.input.attachments.ctx = Di seguito sono disponibili gli allegati caricati e
1570
1572
  tip.input.attachments.uploaded = Qui è presente un elenco di файлы caricati sul server in modalità Assistant. Questi файлы si trovano su un сервер remoto, non sul tuo computer locale, quindi il modello può utilizzarli e analizzarli utilizzando strumenti disponibili all'esterno sul сервер remoto.
1571
1573
  tip.output.tab.calendar = Utilizzando il calendario, puoi tornare a conversazioni selezionate di un giorno specifico. Clicca su un giorno nel calendario per limitare la visualizzazione della cronologia della chat a quel giorno. Puoi anche creare note giornaliere e assegnarle etichette colorate.
1572
1574
  tip.output.tab.draw = Puoi utilizzare lo strumento di disegno per fare rapidi schizzi o catturare un'immagine dalla fotocamera, e poi inviare tali immagini all'IA in modalità Vision per l'analisi. Puoi catturare un'immagine con la fotocamera qui o aprire un'immagine dal disco. Quando utilizzi un'immagine, questa sarà inclusa nel messaggio inviato come allegato.
1573
- tip.output.tab.files = Questa directory di file di lavoro si trova sul tuo disco. I file qui sono accessibili per l'IA per la lettura. L'IA può scrivere e leggere file, così come eseguire codice da questa directory. Puoi aprire questa directory localmente sul tuo sistema e posizionare qui qualsiasi file. Puoi anche indicizzare i file con LlamaIndex, in modo che servano come fonte di conoscenza aggiuntiva.
1575
+ tip.output.tab.files = Questa directory di file di lavoro si trova sul tuo disco. I file qui sono accessibili per l'IA per la lettura. L'IA può scrivere e leggere file, così come eseguire codice da questa directory. Puoi aprire questa directory localmente sul tuo sistema e posizionare qui qualsiasi file. Puoi anche indicizzare i file con LlamaIndex, in modo che servano come fonte di conoscenza aggiuntiva. Usa CTRL/SHIFT per la selezione multipla.
1574
1576
  tip.output.tab.notepad = Il blocco note può servire come strumento per prendere appunti e memorizzare informazioni. Puoi mantenere qualsiasi testo qui, copiare testo dalla finestra della chat e tutte le informazioni verranno salvate automaticamente. Puoi creare più blocchi note creando una nuova scheda.
1575
1577
  tip.tokens.ctx = Contesto (memoria): in uso / totale - token
1576
1578
  tip.tokens.input = Gettoni: prompt dell'utente + prompt di sistema + contesto + extra + allegati = somma / massimo
@@ -16,6 +16,7 @@ action.ctx.indexed = Ostatnio zindeksowane
16
16
  action.ctx.new = Nowy kontekst...
17
17
  action.ctx.new.in_group = Nowy kontekst w: {group}...
18
18
  action.ctx_reset = Resetuj (wyczyść)
19
+ action.cut = Wytnij
19
20
  action.delete = Usuń
20
21
  action.download = Pobierz
21
22
  action.duplicate = Zduplikuj
@@ -26,6 +27,7 @@ action.group.new = Nowa grupa
26
27
  action.group.remove = Usuń z grupy
27
28
  action.idx = Indeksuj w LlamaIndex...
28
29
  action.idx.remove = Usuń z
30
+ action.import = Importuj
29
31
  action.mkdir = Utwórz katalog...
30
32
  action.move_to = Przenieś do
31
33
  action.new = Nowy...
@@ -790,7 +792,7 @@ ipython.docker.install = Uruchomienie IPython wymaga zainstalowania Dockera. Doc
790
792
  ipython.docker.install.snap = \n\nWERSJA SNAP: \nNie jesteś połączony z wbudowanym daemonem Docker. Połącz sloty za pomocą:\n\nsudo snap connect pygpt:docker-executables docker:docker-executables\n\nsudo snap connect pygpt:docker docker:docker-daemon\n\n...i uruchom ponownie aplikację.
791
793
  ipython.image.build = Obraz Dockera dla IPython nie został jeszcze zbudowany. Nastąpi to teraz i może to potrwać chwilę (ale to jednorazowa procedura). Wykonywanie polecenia zostało wstrzymane. Po zbudowaniu obrazu możesz ponownie poprosić o wykonanie polecenia.
792
794
  layout.split = Podziel ekran
793
- list.all = --- WSZYSTKIE ---
795
+ list.all = --- WSZYSTKIE ---
794
796
  menu.audio = Audio / Mowa
795
797
  menu.audio.cache.clear = Wyczyść pamięć podręczną audio...
796
798
  menu.audio.control.global = Kontrola głosowa (globalna)
@@ -1571,7 +1573,7 @@ tip.input.attachments.ctx = Poniżej znajdują się załączone i zindeksowane z
1571
1573
  tip.input.attachments.uploaded = Tutaj znajduje się lista plików przesłanych na serwer w trybie Asystenta. Te pliki znajdują się na zdalnym serwerze, a nie na lokalnym komputerze, więc model może używać i analizować je za pomocą narzędzi dostępnych zewnętrznie na zdalnym serwerze.
1572
1574
  tip.output.tab.calendar = Korzystając z kalendarza, możesz wrócić do wybranych rozmów z określonego dnia. Kliknij na dzień w kalendarzu, aby ograniczyć wyświetlanie historii czatu do tego dnia. Możesz również tworzyć notatki dnia i przypisywać im kolorowe etykiety.
1573
1575
  tip.output.tab.draw = Możesz użyć narzędzia do rysowania do szybkiego szkicowania lub przechwytywania obrazu z kamery, a następnie wysyłać takie obrazy do AI w trybie Vision do analizy. Możesz tu przechwycić obraz za pomocą kamery lub otworzyć obraz z dysku. Przy użyciu obrazu zostanie on dołączony do wysłanej wiadomości jako załącznik.
1574
- tip.output.tab.files = Katalog z plikami roboczymi znajduje się na Twoim dysku. Pliki tutaj są dostępne dla AI. AI może czytać i zapisywać pliki, a także uruchamiać kod z tego katalogu. Możesz otworzyć ten katalog lokalnie w swoim systemie i umieścić tutaj dowolne pliki. Możesz także zindeksować pliki tutaj przy użyciu LlamaIndex, aby służyły jako dodatkowe źródło wiedzy.
1576
+ tip.output.tab.files = Katalog z plikami roboczymi znajduje się na Twoim dysku. Pliki tutaj są dostępne dla AI. AI może czytać i zapisywać pliki, a także uruchamiać kod z tego katalogu. Możesz otworzyć ten katalog lokalnie w swoim systemie i umieścić tutaj dowolne pliki. Możesz także zindeksować pliki tutaj przy użyciu LlamaIndex, aby służyły jako dodatkowe źródło wiedzy. Użyj CTRL/SHIFT, aby dokonać wielokrotnego wyboru.
1575
1577
  tip.output.tab.notepad = Notatnik może służyć jako narzędzie do robienia notatek i przechowywania informacji. Możesz tutaj przechowywać dowolny tekst, kopiować tekst z okna czatu, a wszystkie informacje będą automatycznie zapisywane. Możesz tworzyć więcej notatników, tworząc nową kartę.
1576
1578
  tip.tokens.ctx = Kontekst (pamięć): w użyciu / całość - l.tokenów
1577
1579
  tip.tokens.input = Tokeny: prompt użytkownika + systemowy prompt + kontekst + dodatkowe + załączniki = suma / max
@@ -16,6 +16,7 @@ action.ctx.indexed = Останнє індексування в
16
16
  action.ctx.new = Новий контекст...
17
17
  action.ctx.new.in_group = Новий контекст у: {group}...
18
18
  action.ctx_reset = Скинути (очистити)
19
+ action.cut = Вирізати
19
20
  action.delete = Видалити
20
21
  action.download = Завантажити
21
22
  action.duplicate = Дублювати
@@ -26,6 +27,7 @@ action.group.new = Нова група
26
27
  action.group.remove = Видалити з групи
27
28
  action.idx = Індексувати за допомогою LlamaIndex...
28
29
  action.idx.remove = Видалити з
30
+ action.import = Імпорт
29
31
  action.mkdir = Створити каталог...
30
32
  action.move_to = Перемістити до
31
33
  action.new = Новий...
@@ -1570,7 +1572,7 @@ tip.input.attachments.ctx = Нижче наведено завантажені
1570
1572
  tip.input.attachments.uploaded = Тут є список файлів, завантажених на сервер у режимі Асистента. Ці файли розташовані на віддаленому сервері, а не на вашому локальному комп'ютері, тому модель може використовувати їх та аналізувати за допомогою інструментів, доступних ззовні на віддаленому сервері.
1571
1573
  tip.output.tab.calendar = Використовуючи календар, ви можете повертатись до обраних розмов з певного дня. Натисніть на день у календарі, щоб обмежити відображення історії чату до цього дня. Ви також можете створювати денні нотатки та присвоювати їм кольорові мітки.
1572
1574
  tip.output.tab.draw = Ви можете використовувати інструмент малювання для швидкого скетчингу або захоплення зображення з камери, а потім надсилати такі зображення ШІ у режимі Vision для аналізу. Ви можете захопити зображення за допомогою камери тут або відкрити зображення з диску. При використанні зображення, воно буде включене в наді слане повідомлення як вкладення.
1573
- tip.output.tab.files = Ця директорія робочих файлів знаходиться на вашому диску. Файли тут доступні для ШІ для читання. ШІ може читати і записувати файли, а також виконувати код з цієї директорії. Ви можете відкрити цю директорію локально на вашій системі та розмістити будь-які файли тут. Ви також можете індексувати файли за допомогою LlamaIndex, щоб вони служили додатковим джерелом знань.
1575
+ tip.output.tab.files = Ця директорія робочих файлів знаходиться на вашому диску. Файли тут доступні для ШІ для читання. ШІ може читати і записувати файли, а також виконувати код з цієї директорії. Ви можете відкрити цю директорію локально на вашій системі та розмістити будь-які файли тут. Ви також можете індексувати файли за допомогою LlamaIndex, щоб вони служили додатковим джерелом знань. Використовуйте CTRL/SHIFT для множинного вибору.
1574
1576
  tip.output.tab.notepad = Блокнот може слугувати інструментом для ведення нотаток та зберігання інформації. Ви можете зберігати тут будь-який текст, копіювати текст із вікна чату, і вся інформація буде автоматично зберігатися. Ви можете створити більше блокнотів, створивши нову вкладку.
1575
1577
  tip.tokens.ctx = Контекст (пам'ять): використано / всього - токени
1576
1578
  tip.tokens.input = Токени: запит користувача + системний запит + контекст + додаткові + вкладення = сума / макс
@@ -16,6 +16,7 @@ action.ctx.indexed = 最後索引於
16
16
  action.ctx.new = 新建上下文...
17
17
  action.ctx.new.in_group = 新的上下文在:{group}...
18
18
  action.ctx_reset = 重置(清除)
19
+ action.cut = 剪切
19
20
  action.delete = 刪除
20
21
  action.download = 下載
21
22
  action.duplicate = 複製
@@ -26,6 +27,7 @@ action.group.new = 新建组
26
27
  action.group.remove = 从组中移除
27
28
  action.idx = 使用LlamaIndex索引...
28
29
  action.idx.remove = 從中移除
30
+ action.import = 导入
29
31
  action.mkdir = 創建目錄...
30
32
  action.move_to = 移动到
31
33
  action.new = 新建...
@@ -1570,7 +1572,7 @@ tip.input.attachments.ctx = 以下是上传和索引的附件,可用作上述
1570
1572
  tip.input.attachments.uploaded = 這是已上傳到服務器的文件列表,在助手模式下。這些文件位於遠程服務器上,而不是您的本地計算機上,因此模型可以使用並分析外部遠程服務器上可用的工具。
1571
1573
  tip.output.tab.calendar = 使用日曆,您可以導航回特定日期的選定對話。點擊日曆中的一天以限制聊天歷史顯示到該天。您還可以創建日記並為它們分配彩色標籤。
1572
1574
  tip.output.tab.draw = 您可以使用繪圖工具進行快速素描或從相機捕獲圖像,然後將這些圖像發送到AI在視覺模式下進行分析。您可以在這裡使用相機捕獲圖像或從磁盤打開圖像。使用圖像時,它將作為附件包含在發送的消息中。
1573
- tip.output.tab.files = 此工作文件目錄位於您的磁盤上。這裡的文件可供AI訪問。AI可以寫入和讀取文件,也可以從此目錄運行代碼。您可以在本地系統上打開此目錄並放置任何文件。您還可以使用LlamaIndex對這裡的文件進行索引,以便它們作為額外的知識來源。
1575
+ tip.output.tab.files = 此工作文件目錄位於您的磁盤上。這裡的文件可供AI訪問。AI可以寫入和讀取文件,也可以從此目錄運行代碼。您可以在本地系統上打開此目錄並放置任何文件。您還可以使用LlamaIndex對這裡的文件進行索引,以便它們作為額外的知識來源。使用 CTRL/SHIFT 进行多重选择。
1574
1576
  tip.output.tab.notepad = 记事本可以用作记笔记和存储信息的工具。您可以在这里保留任何文本,从聊天窗口复制文本,所有信息将自动保存。您可以通过创建新选项卡来创建更多记事本。
1575
1577
  tip.tokens.ctx = 上下文(記憶):使用中 / 全部 - 令牌
1576
1578
  tip.tokens.input = 代币:用户输入提示 + 系统提示 + 上下文 + 额外 + 附件 = 总和 / 最大值
@@ -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.12.25 20:00:00 #
9
+ # Updated Date: 2025.12.28 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from openai import OpenAI
@@ -83,7 +83,9 @@ class ApiOpenAI:
83
83
  """
84
84
  # prepare client args by mode and model provider
85
85
  args = self.window.core.models.prepare_client_args(mode, model)
86
- return OpenAI(**args)
86
+ self.client = OpenAI(**args)
87
+ self.last_client_args = args # store last args for debug
88
+ return self.client
87
89
 
88
90
  def call(
89
91
  self,
@@ -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.09.26 03:00:00 #
9
+ # Updated Date: 2025.12.27 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -183,6 +183,14 @@ class Patch:
183
183
  data["img_mode"] = "image"
184
184
  updated = True
185
185
 
186
+ # < 2.7.0
187
+ if old < parse_version("2.7.0"):
188
+ print("Migrating config from < 2.7.0...")
189
+ # add: combo boxes css
190
+ patch_css('style.light.css', True)
191
+ patch_css('style.dark.css', True)
192
+ updated = True
193
+
186
194
  # update file
187
195
  migrated = False
188
196
  if updated:
@@ -70,6 +70,23 @@ class ImageViewer(BaseTool):
70
70
  if path:
71
71
  self.open_preview(path, id, auto_close)
72
72
 
73
+ def open_preview_batch(
74
+ self,
75
+ paths: list,
76
+ current_id: str = None,
77
+ auto_close: bool = True):
78
+ """
79
+ Open image preview batch in dialog
80
+
81
+ :param paths:
82
+ :param current_id:
83
+ :param auto_close:
84
+ :return:
85
+ """
86
+ for path in paths:
87
+ self.open_preview(path, current_id, auto_close)
88
+
89
+
73
90
  def open_preview(
74
91
  self,
75
92
  path: str = None,
@@ -112,6 +112,15 @@ class TextEditor(BaseTool):
112
112
  """Open new instance"""
113
113
  self.open()
114
114
 
115
+ def open_batch(self, files: list):
116
+ """
117
+ Open multiple files in editor instances
118
+
119
+ :param files: list of files to open
120
+ """
121
+ for file in files:
122
+ self.open(file, auto_close=False, force=True)
123
+
115
124
  def open(
116
125
  self,
117
126
  file: Optional[str] = None,
pygpt_net/ui/__init__.py CHANGED
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.20 20:00:00 #
9
+ # Updated Date: 2025.12.27 17:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -143,7 +143,7 @@ class UI:
143
143
  suffix = self.window.core.platforms.get_env_suffix()
144
144
  profile_name = self.window.core.config.profile.get_current_name()
145
145
  self.window.setWindowTitle(
146
- f"PyGPT - Desktop AI Assistant {self.window.meta['version']} | "
146
+ f"PyGPT {self.window.meta['version']} | "
147
147
  f"build {self.window.meta['build'].replace('.', '-')}{suffix} ({profile_name})"
148
148
  )
149
149
 
@@ -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.09.15 22:00:00 #
9
+ # Updated Date: 2025.12.28 12:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6 import QtCore
@@ -69,6 +69,14 @@ class CtxList:
69
69
  models[ctx_id] = model
70
70
  ctx_list.setModel(model)
71
71
 
72
+ # Expose force scroll on model as a thin proxy to the view method for external callers
73
+ try:
74
+ def _model_force_scroll_to_current(*args, **kwargs):
75
+ return ctx_list.force_scroll_to_current(*args, **kwargs)
76
+ setattr(model, "force_scroll_to_current", _model_force_scroll_to_current)
77
+ except Exception:
78
+ pass
79
+
72
80
  ctx = self.window.controller.ctx
73
81
  ctx_list.selectionModel().selectionChanged.connect(lambda *_: ctx.selection_change())
74
82
 
@@ -265,14 +273,17 @@ class CtxList:
265
273
  if c == 0 and search_string:
266
274
  continue
267
275
 
268
- suffix = f" ({c})" if c > 0 else ""
276
+ # Display only the group name; the counter is drawn by delegate on the right
269
277
  is_attachment = group.has_additional_ctx()
270
- group_name = group.name + suffix
278
+ group_name = group.name
271
279
  group_item = GroupItem(folder_icon, group_name, group.id)
272
280
  group_item.hasAttachments = is_attachment
281
+
282
+ # Provide all metadata required by the delegate
273
283
  custom_data = {
274
284
  "is_group": True,
275
285
  "is_attachment": is_attachment,
286
+ "count": c,
276
287
  }
277
288
 
278
289
  if is_attachment:
@@ -299,12 +310,11 @@ class CtxList:
299
310
 
300
311
  model.appendRow(group_item)
301
312
 
313
+ # Always reflect persisted expansion state so groups stay open after actions
302
314
  desired = group.id in node.expanded_items
303
315
  idx = group_item.index()
304
- if node.isExpanded(idx) != desired and expand:
316
+ if node.isExpanded(idx) != desired:
305
317
  node.setExpanded(idx, desired)
306
- else:
307
- node.setExpanded(idx, False)
308
318
 
309
319
  def count_in_group(self, group_id: int, data: dict) -> int:
310
320
  """