pygpt-net 2.7.3__py3-none-any.whl → 2.7.5__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 (157) hide show
  1. pygpt_net/CHANGELOG.txt +15 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +382 -350
  4. pygpt_net/app_core.py +4 -2
  5. pygpt_net/controller/__init__.py +5 -1
  6. pygpt_net/controller/assistant/assistant.py +1 -4
  7. pygpt_net/controller/assistant/batch.py +5 -504
  8. pygpt_net/controller/assistant/editor.py +5 -5
  9. pygpt_net/controller/assistant/files.py +16 -16
  10. pygpt_net/controller/chat/attachment.py +5 -1
  11. pygpt_net/controller/chat/handler/google_stream.py +307 -1
  12. pygpt_net/controller/chat/handler/worker.py +8 -1
  13. pygpt_net/controller/chat/image.py +15 -3
  14. pygpt_net/controller/dialogs/confirm.py +73 -101
  15. pygpt_net/controller/files/files.py +3 -1
  16. pygpt_net/controller/lang/mapping.py +9 -9
  17. pygpt_net/controller/layout/layout.py +2 -2
  18. pygpt_net/controller/painter/capture.py +50 -1
  19. pygpt_net/controller/presets/presets.py +2 -1
  20. pygpt_net/controller/remote_store/__init__.py +12 -0
  21. pygpt_net/{provider/core/assistant_file/db_sqlite → controller/remote_store/google}/__init__.py +2 -2
  22. pygpt_net/controller/remote_store/google/batch.py +402 -0
  23. pygpt_net/controller/remote_store/google/store.py +615 -0
  24. pygpt_net/controller/remote_store/openai/__init__.py +12 -0
  25. pygpt_net/controller/remote_store/openai/batch.py +524 -0
  26. pygpt_net/controller/{assistant → remote_store/openai}/store.py +63 -60
  27. pygpt_net/controller/remote_store/remote_store.py +35 -0
  28. pygpt_net/controller/theme/nodes.py +2 -1
  29. pygpt_net/controller/ui/mode.py +5 -1
  30. pygpt_net/controller/ui/ui.py +36 -2
  31. pygpt_net/core/assistants/assistants.py +3 -15
  32. pygpt_net/core/db/database.py +5 -3
  33. pygpt_net/core/filesystem/url.py +4 -1
  34. pygpt_net/core/locale/placeholder.py +35 -0
  35. pygpt_net/core/remote_store/__init__.py +12 -0
  36. pygpt_net/core/remote_store/google/__init__.py +11 -0
  37. pygpt_net/core/remote_store/google/files.py +224 -0
  38. pygpt_net/core/remote_store/google/store.py +248 -0
  39. pygpt_net/core/remote_store/openai/__init__.py +11 -0
  40. pygpt_net/core/{assistants → remote_store/openai}/files.py +26 -19
  41. pygpt_net/core/{assistants → remote_store/openai}/store.py +32 -15
  42. pygpt_net/core/remote_store/remote_store.py +24 -0
  43. pygpt_net/core/render/web/helpers.py +5 -0
  44. pygpt_net/data/config/config.json +8 -5
  45. pygpt_net/data/config/models.json +77 -3
  46. pygpt_net/data/config/settings.json +45 -14
  47. pygpt_net/data/css/web-blocks.css +3 -0
  48. pygpt_net/data/css/web-chatgpt.css +3 -0
  49. pygpt_net/data/locale/locale.de.ini +43 -41
  50. pygpt_net/data/locale/locale.en.ini +56 -44
  51. pygpt_net/data/locale/locale.es.ini +43 -41
  52. pygpt_net/data/locale/locale.fr.ini +43 -41
  53. pygpt_net/data/locale/locale.it.ini +43 -41
  54. pygpt_net/data/locale/locale.pl.ini +43 -41
  55. pygpt_net/data/locale/locale.uk.ini +43 -41
  56. pygpt_net/data/locale/locale.zh.ini +43 -41
  57. pygpt_net/data/locale/plugin.cmd_history.de.ini +1 -1
  58. pygpt_net/data/locale/plugin.cmd_history.en.ini +1 -1
  59. pygpt_net/data/locale/plugin.cmd_history.es.ini +1 -1
  60. pygpt_net/data/locale/plugin.cmd_history.fr.ini +1 -1
  61. pygpt_net/data/locale/plugin.cmd_history.it.ini +1 -1
  62. pygpt_net/data/locale/plugin.cmd_history.pl.ini +1 -1
  63. pygpt_net/data/locale/plugin.cmd_history.uk.ini +1 -1
  64. pygpt_net/data/locale/plugin.cmd_history.zh.ini +1 -1
  65. pygpt_net/data/locale/plugin.cmd_mouse_control.en.ini +14 -0
  66. pygpt_net/data/locale/plugin.cmd_web.de.ini +1 -1
  67. pygpt_net/data/locale/plugin.cmd_web.en.ini +1 -1
  68. pygpt_net/data/locale/plugin.cmd_web.es.ini +1 -1
  69. pygpt_net/data/locale/plugin.cmd_web.fr.ini +1 -1
  70. pygpt_net/data/locale/plugin.cmd_web.it.ini +1 -1
  71. pygpt_net/data/locale/plugin.cmd_web.pl.ini +1 -1
  72. pygpt_net/data/locale/plugin.cmd_web.uk.ini +1 -1
  73. pygpt_net/data/locale/plugin.cmd_web.zh.ini +1 -1
  74. pygpt_net/data/locale/plugin.idx_llama_index.de.ini +2 -2
  75. pygpt_net/data/locale/plugin.idx_llama_index.en.ini +2 -2
  76. pygpt_net/data/locale/plugin.idx_llama_index.es.ini +2 -2
  77. pygpt_net/data/locale/plugin.idx_llama_index.fr.ini +2 -2
  78. pygpt_net/data/locale/plugin.idx_llama_index.it.ini +2 -2
  79. pygpt_net/data/locale/plugin.idx_llama_index.pl.ini +2 -2
  80. pygpt_net/data/locale/plugin.idx_llama_index.uk.ini +2 -2
  81. pygpt_net/data/locale/plugin.idx_llama_index.zh.ini +2 -2
  82. pygpt_net/item/assistant.py +1 -211
  83. pygpt_net/item/ctx.py +3 -1
  84. pygpt_net/item/store.py +238 -0
  85. pygpt_net/launcher.py +115 -55
  86. pygpt_net/migrations/Version20260102190000.py +35 -0
  87. pygpt_net/migrations/__init__.py +3 -1
  88. pygpt_net/plugin/cmd_mouse_control/config.py +470 -1
  89. pygpt_net/plugin/cmd_mouse_control/plugin.py +488 -22
  90. pygpt_net/plugin/cmd_mouse_control/worker.py +464 -87
  91. pygpt_net/plugin/cmd_mouse_control/worker_sandbox.py +729 -0
  92. pygpt_net/plugin/idx_llama_index/config.py +2 -2
  93. pygpt_net/preload.py +243 -0
  94. pygpt_net/provider/api/google/__init__.py +16 -54
  95. pygpt_net/provider/api/google/chat.py +546 -129
  96. pygpt_net/provider/api/google/computer.py +190 -0
  97. pygpt_net/provider/api/google/image.py +74 -6
  98. pygpt_net/provider/api/google/realtime/realtime.py +2 -2
  99. pygpt_net/provider/api/google/remote_tools.py +93 -0
  100. pygpt_net/provider/api/google/store.py +546 -0
  101. pygpt_net/provider/api/google/video.py +9 -4
  102. pygpt_net/provider/api/google/worker/__init__.py +0 -0
  103. pygpt_net/provider/api/google/worker/importer.py +392 -0
  104. pygpt_net/provider/api/openai/computer.py +10 -1
  105. pygpt_net/provider/api/openai/image.py +42 -19
  106. pygpt_net/provider/api/openai/store.py +6 -6
  107. pygpt_net/provider/api/openai/video.py +27 -2
  108. pygpt_net/provider/api/openai/worker/importer.py +24 -24
  109. pygpt_net/provider/api/x_ai/image.py +25 -2
  110. pygpt_net/provider/core/config/patch.py +23 -1
  111. pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +3 -3
  112. pygpt_net/provider/core/model/patch.py +17 -3
  113. pygpt_net/provider/core/preset/json_file.py +13 -7
  114. pygpt_net/provider/core/{assistant_file → remote_file}/__init__.py +1 -1
  115. pygpt_net/provider/core/{assistant_file → remote_file}/base.py +9 -9
  116. pygpt_net/provider/core/remote_file/db_sqlite/__init__.py +12 -0
  117. pygpt_net/provider/core/{assistant_file → remote_file}/db_sqlite/patch.py +1 -1
  118. pygpt_net/provider/core/{assistant_file → remote_file}/db_sqlite/provider.py +23 -20
  119. pygpt_net/provider/core/{assistant_file → remote_file}/db_sqlite/storage.py +35 -27
  120. pygpt_net/provider/core/{assistant_file → remote_file}/db_sqlite/utils.py +5 -4
  121. pygpt_net/provider/core/{assistant_store → remote_store}/__init__.py +1 -1
  122. pygpt_net/provider/core/{assistant_store → remote_store}/base.py +10 -10
  123. pygpt_net/provider/core/{assistant_store → remote_store}/db_sqlite/__init__.py +1 -1
  124. pygpt_net/provider/core/{assistant_store → remote_store}/db_sqlite/patch.py +1 -1
  125. pygpt_net/provider/core/{assistant_store → remote_store}/db_sqlite/provider.py +16 -15
  126. pygpt_net/provider/core/{assistant_store → remote_store}/db_sqlite/storage.py +30 -23
  127. pygpt_net/provider/core/{assistant_store → remote_store}/db_sqlite/utils.py +5 -4
  128. pygpt_net/provider/core/{assistant_store → remote_store}/json_file.py +9 -9
  129. pygpt_net/provider/llms/google.py +2 -2
  130. pygpt_net/ui/base/config_dialog.py +3 -2
  131. pygpt_net/ui/dialog/assistant.py +3 -3
  132. pygpt_net/ui/dialog/plugins.py +3 -1
  133. pygpt_net/ui/dialog/remote_store_google.py +539 -0
  134. pygpt_net/ui/dialog/{assistant_store.py → remote_store_openai.py} +95 -95
  135. pygpt_net/ui/dialogs.py +5 -3
  136. pygpt_net/ui/layout/chat/attachments_uploaded.py +3 -3
  137. pygpt_net/ui/layout/chat/input.py +20 -2
  138. pygpt_net/ui/layout/chat/painter.py +6 -4
  139. pygpt_net/ui/layout/toolbox/computer_env.py +26 -8
  140. pygpt_net/ui/layout/toolbox/image.py +5 -5
  141. pygpt_net/ui/layout/toolbox/video.py +5 -4
  142. pygpt_net/ui/main.py +84 -3
  143. pygpt_net/ui/menu/tools.py +13 -5
  144. pygpt_net/ui/widget/dialog/base.py +3 -10
  145. pygpt_net/ui/widget/dialog/remote_store_google.py +56 -0
  146. pygpt_net/ui/widget/dialog/{assistant_store.py → remote_store_openai.py} +9 -9
  147. pygpt_net/ui/widget/element/button.py +4 -4
  148. pygpt_net/ui/widget/lists/remote_store_google.py +248 -0
  149. pygpt_net/ui/widget/lists/{assistant_store.py → remote_store_openai.py} +21 -21
  150. pygpt_net/ui/widget/option/checkbox_list.py +47 -9
  151. pygpt_net/ui/widget/option/combo.py +158 -4
  152. pygpt_net/ui/widget/textarea/input_extra.py +664 -0
  153. {pygpt_net-2.7.3.dist-info → pygpt_net-2.7.5.dist-info}/METADATA +48 -9
  154. {pygpt_net-2.7.3.dist-info → pygpt_net-2.7.5.dist-info}/RECORD +157 -130
  155. {pygpt_net-2.7.3.dist-info → pygpt_net-2.7.5.dist-info}/LICENSE +0 -0
  156. {pygpt_net-2.7.3.dist-info → pygpt_net-2.7.5.dist-info}/WHEEL +0 -0
  157. {pygpt_net-2.7.3.dist-info → pygpt_net-2.7.5.dist-info}/entry_points.txt +0 -0
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2025.08.11 14:00:00 #
9
+ # Updated Date: 2026.01.02 19:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -36,17 +36,17 @@ class Importer(QObject):
36
36
  if mode == "assistants":
37
37
  self.window.controller.assistant.batch.handle_imported_assistants_failed(err)
38
38
  elif mode == "import_files":
39
- self.window.controller.assistant.batch.handle_imported_files_failed(err)
39
+ self.window.controller.remote_store.openai.batch.handle_imported_files_failed(err)
40
40
  elif mode == "truncate_files":
41
- self.window.controller.assistant.batch.handle_truncated_files_failed(err)
41
+ self.window.controller.remote_store.openai.batch.handle_truncated_files_failed(err)
42
42
  elif mode == "upload_files":
43
- self.window.controller.assistant.batch.handle_uploaded_files_failed(err)
43
+ self.window.controller.remote_store.openai.batch.handle_uploaded_files_failed(err)
44
44
  elif mode in "vector_stores":
45
- self.window.controller.assistant.batch.handle_imported_stores_failed(err)
45
+ self.window.controller.remote_store.openai.batch.handle_imported_stores_failed(err)
46
46
  elif mode in "truncate_vector_stores":
47
- self.window.controller.assistant.batch.handle_truncated_stores_failed(err)
47
+ self.window.controller.remote_store.openai.batch.handle_truncated_stores_failed(err)
48
48
  elif mode in "refresh_vector_stores":
49
- self.window.controller.assistant.batch.handle_refreshed_stores_failed(err)
49
+ self.window.controller.remote_store.openai.batch.handle_refreshed_stores_failed(err)
50
50
 
51
51
  @Slot(str, str, int)
52
52
  def handle_finished(self, mode: str, store_id: str = None, num: int = 0):
@@ -60,17 +60,17 @@ class Importer(QObject):
60
60
  if mode == "assistants":
61
61
  self.window.controller.assistant.batch.handle_imported_assistants(num)
62
62
  elif mode == "import_files":
63
- self.window.controller.assistant.batch.handle_imported_files(num)
63
+ self.window.controller.remote_store.openai.batch.handle_imported_files(num)
64
64
  elif mode == "truncate_files":
65
- self.window.controller.assistant.batch.handle_truncated_files(store_id, num)
65
+ self.window.controller.remote_store.openai.batch.handle_truncated_files(store_id, num)
66
66
  elif mode == "upload_files":
67
- self.window.controller.assistant.batch.handle_uploaded_files(num)
67
+ self.window.controller.remote_store.openai.batch.handle_uploaded_files(num)
68
68
  elif mode == "vector_stores":
69
- self.window.controller.assistant.batch.handle_imported_stores(num)
69
+ self.window.controller.remote_store.openai.batch.handle_imported_stores(num)
70
70
  elif mode == "truncate_vector_stores":
71
- self.window.controller.assistant.batch.handle_truncated_stores(num)
71
+ self.window.controller.remote_store.openai.batch.handle_truncated_stores(num)
72
72
  elif mode == "refresh_vector_stores":
73
- self.window.controller.assistant.batch.handle_refreshed_stores(num)
73
+ self.window.controller.remote_store.openai.batch.handle_refreshed_stores(num)
74
74
 
75
75
  @Slot(str, str)
76
76
  def handle_status(self, mode: str, msg: str):
@@ -264,10 +264,10 @@ class ImportWorker(QRunnable):
264
264
  """
265
265
  try:
266
266
  self.log("Importing vector stores...")
267
- self.window.core.assistants.store.clear()
267
+ self.window.core.remote_store.openai.clear()
268
268
  items = {}
269
269
  self.window.core.api.openai.store.import_stores(items, callback=self.callback)
270
- self.window.core.assistants.store.import_items(items)
270
+ self.window.core.remote_store.openai.import_items(items)
271
271
  if not silent:
272
272
  self.signals.finished.emit("vector_stores", self.store_id, len(items))
273
273
  return True
@@ -286,8 +286,8 @@ class ImportWorker(QRunnable):
286
286
  try:
287
287
  self.log("Truncating stores...")
288
288
  num = self.window.core.api.openai.store.remove_all(callback=self.callback)
289
- self.window.core.assistants.store.items = {}
290
- self.window.core.assistants.store.save()
289
+ self.window.core.remote_store.openai.items = {}
290
+ self.window.core.remote_store.openai.save()
291
291
  if not silent:
292
292
  self.signals.finished.emit("truncate_vector_stores", self.store_id, num)
293
293
  return True
@@ -306,11 +306,11 @@ class ImportWorker(QRunnable):
306
306
  try:
307
307
  self.log("Refreshing stores...")
308
308
  num = 0
309
- stores = self.window.core.assistants.store.items
309
+ stores = self.window.core.remote_store.openai.items
310
310
  for id in stores:
311
311
  store = stores[id]
312
312
  try:
313
- self.window.controller.assistant.store.refresh_store(store, update=False)
313
+ self.window.controller.remote_store.openai.refresh_store(store, update=False)
314
314
  num += 1
315
315
  except Exception as e:
316
316
  self.log("Failed to refresh store: {}".format(id))
@@ -334,12 +334,12 @@ class ImportWorker(QRunnable):
334
334
  # if empty store_id, truncate all files, otherwise truncate only store files
335
335
  if self.store_id is None:
336
336
  self.log("Truncating all files...")
337
- self.window.core.assistants.files.truncate() # clear all files
337
+ self.window.core.remote_store.openai.files.truncate() # clear all files
338
338
  # remove all files in API
339
339
  num = self.window.core.api.openai.store.remove_files(callback=self.callback)
340
340
  else:
341
341
  self.log("Truncating files for store: {}".format(self.store_id))
342
- self.window.core.assistants.files.truncate(self.store_id) # clear store files, remove from stores / DB
342
+ self.window.core.remote_store.openai.files.truncate(self.store_id) # clear store files, remove from stores / DB
343
343
  # remove store files in API
344
344
  num = self.window.core.api.openai.store.remove_store_files(
345
345
  self.store_id,
@@ -373,7 +373,7 @@ class ImportWorker(QRunnable):
373
373
  )
374
374
  if stored_file is not None:
375
375
  data = self.window.core.api.openai.store.get_file(file_id)
376
- self.window.core.assistants.files.insert(self.store_id, data) # insert to DB
376
+ self.window.core.remote_store.openai.files.insert(self.store_id, data) # insert to DB
377
377
  msg = "Uploaded file: {}/{}".format((num + 1), len(self.files))
378
378
  self.signals.status.emit("upload_files", msg)
379
379
  self.log(msg)
@@ -402,11 +402,11 @@ class ImportWorker(QRunnable):
402
402
  try:
403
403
  if self.store_id is None:
404
404
  self.log("Importing all files...")
405
- self.window.core.assistants.files.truncate_local() # clear local DB (all)
405
+ self.window.core.remote_store.openai.files.truncate_local() # clear local DB (all)
406
406
  num = self.window.core.api.openai.store.import_stores_files(self.callback) # import all files
407
407
  else:
408
408
  self.log("Importing files for store: {}".format(self.store_id))
409
- self.window.core.assistants.files.truncate_local(self.store_id) # clear local DB (all)
409
+ self.window.core.remote_store.openai.files.truncate_local(self.store_id) # clear local DB (all)
410
410
  items = self.window.core.api.openai.store.import_store_files(
411
411
  self.store_id,
412
412
  [],
@@ -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.05 01:00:00 #
9
+ # Updated Date: 2025.12.31 16:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import base64
@@ -49,6 +49,7 @@ class Image:
49
49
  prompt = context.prompt
50
50
  num = int(extra.get("num", 1))
51
51
  inline = bool(extra.get("inline", False))
52
+ extra_prompt = extra.get("extra_prompt", "")
52
53
 
53
54
  # Optional prompt enhancement model (same as in your Google path)
54
55
  prompt_model = self.window.core.models.from_defaults()
@@ -66,6 +67,7 @@ class Image:
66
67
  worker.raw = self.window.core.config.get('img_raw')
67
68
  worker.num = num
68
69
  worker.inline = inline
70
+ worker.extra_prompt = extra_prompt
69
71
 
70
72
  self.worker = worker
71
73
  self.worker.signals.finished.connect(self.window.core.image.handle_finished)
@@ -102,6 +104,7 @@ class ImageWorker(QRunnable):
102
104
  self.input_prompt = ""
103
105
  self.system_prompt = ""
104
106
  self.inline = False
107
+ self.extra_prompt: Optional[str] = None
105
108
  self.raw = False
106
109
  self.num = 1
107
110
 
@@ -131,6 +134,13 @@ class ImageWorker(QRunnable):
131
134
  self.signals.error.emit(e)
132
135
  self.signals.status.emit(trans('img.status.prompt.error') + ": " + str(e))
133
136
 
137
+ # Negative prompt fallback: append as textual instruction (xAI has no native field for it)
138
+ if self.extra_prompt and str(self.extra_prompt).strip():
139
+ try:
140
+ self.input_prompt = self._merge_negative_prompt(self.input_prompt or "", self.extra_prompt)
141
+ except Exception:
142
+ pass
143
+
134
144
  self.signals.status.emit(trans('img.status.generating') + f": {self.input_prompt}...")
135
145
 
136
146
  cfg = self.window.core.config
@@ -205,4 +215,17 @@ class ImageWorker(QRunnable):
205
215
  try:
206
216
  sig.deleteLater()
207
217
  except RuntimeError:
208
- pass
218
+ pass
219
+
220
+ # ---------- prompt utilities ----------
221
+
222
+ @staticmethod
223
+ def _merge_negative_prompt(prompt: str, negative: Optional[str]) -> str:
224
+ """
225
+ Append a negative prompt to the main text prompt for providers without a native negative_prompt field.
226
+ """
227
+ base = (prompt or "").strip()
228
+ neg = (negative or "").strip()
229
+ if not neg:
230
+ return base
231
+ return (base + ("\n" if base else "") + f"Negative prompt: {neg}").strip()
@@ -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.30 22:00:00 #
9
+ # Updated Date: 2026.01.02 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -216,6 +216,28 @@ class Patch:
216
216
  data["img.remix"] = False
217
217
  updated = True
218
218
 
219
+ # < 2.7.4
220
+ if old < parse_version("2.7.4"):
221
+ print("Migrating config from < 2.7.4...")
222
+ patch_css('web-chatgpt.css', True)
223
+ patch_css('web-blocks.css', True)
224
+ updated = True
225
+
226
+ # < 2.7.5
227
+ if old < parse_version("2.7.5"):
228
+ print("Migrating config from < 2.7.5...")
229
+ if "remote_tools.computer_use.sandbox" not in data:
230
+ data["remote_tools.computer_use.sandbox"] = False
231
+ if "remote_tools.google.file_search" not in data:
232
+ data["remote_tools.google.file_search"] = False
233
+ if "remote_tools.google.file_search.args" not in data:
234
+ data["remote_tools.google.file_search.args"] = ""
235
+ if "remote_tools.google.maps" not in data:
236
+ data["remote_tools.google.maps"] = False
237
+ if "remote_store.openai.hide_threads" not in data:
238
+ data["remote_store.openai.hide_threads"] = True
239
+ updated = True
240
+
219
241
  # update file
220
242
  migrated = False
221
243
  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.09.12 00:00:00 #
9
+ # Updated Date: 2026.01.02 20:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -1404,8 +1404,8 @@ class Patch:
1404
1404
  # < 2.1.79
1405
1405
  if old < parse_version("2.1.79"):
1406
1406
  print("Migrating config from < 2.1.79...")
1407
- if 'assistant.store.hide_threads' not in data:
1408
- data["assistant.store.hide_threads"] = True
1407
+ if 'remote_store.openai.hide_threads' not in data:
1408
+ data["remote_store.openai.hide_threads"] = True
1409
1409
  updated = True
1410
1410
 
1411
1411
  # < 2.2.2
@@ -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.26 11:00:00 #
9
+ # Updated Date: 2026.01.03 02:10:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from packaging.version import parse as parse_version, Version
@@ -75,7 +75,7 @@ class Patch:
75
75
  base_model = from_base(model)
76
76
  if base_model:
77
77
  data[model] = base_model
78
- updated = True
78
+ updated = True
79
79
 
80
80
  # < 2.6.67 <--- add missing image input
81
81
  if old < parse_version("2.6.67"):
@@ -100,7 +100,21 @@ class Patch:
100
100
  m = data[model]
101
101
  if not m.is_image_input():
102
102
  m.input.append("image")
103
- updated = True
103
+ updated = True
104
+
105
+ # < 2.7.5 <--- add: gemini-2.5-computer-use-preview-10-2025
106
+ if old < parse_version("2.7.5"):
107
+ print("Migrating models from < 2.7.5...")
108
+ models_to_add = [
109
+ "gemini-2.5-computer-use-preview-10-2025",
110
+ "deep-research-pro-preview-12-2025"
111
+ ]
112
+ for model in models_to_add:
113
+ if model not in data:
114
+ base_model = from_base(model)
115
+ if base_model:
116
+ data[model] = base_model
117
+ updated = True
104
118
 
105
119
  # update file
106
120
  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.28 09:00:00 #
9
+ # Updated Date: 2026.01.02 19:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import json
@@ -77,9 +77,12 @@ class JsonFileProvider(BaseProvider):
77
77
  if filename.endswith(".json"):
78
78
  path = os.path.join(self.window.core.config.get_user_dir('presets'), filename)
79
79
  with open(path, 'r', encoding="utf-8") as f:
80
- preset = PresetItem()
81
- self.deserialize(json.load(f), preset)
82
- items[filename[:-5]] = preset
80
+ try:
81
+ preset = PresetItem()
82
+ self.deserialize(json.load(f), preset)
83
+ items[filename[:-5]] = preset
84
+ except Exception as e:
85
+ pass
83
86
  except Exception as e:
84
87
  self.window.core.debug.log(e)
85
88
 
@@ -104,9 +107,12 @@ class JsonFileProvider(BaseProvider):
104
107
  filename
105
108
  )
106
109
  with open(path, 'r', encoding="utf-8") as f:
107
- preset = PresetItem()
108
- self.deserialize(json.load(f), preset)
109
- items[filename[:-5]] = preset
110
+ try:
111
+ preset = PresetItem()
112
+ self.deserialize(json.load(f), preset)
113
+ items[filename[:-5]] = preset
114
+ except Exception as e:
115
+ pass
110
116
  except Exception as e:
111
117
  self.window.core.debug.log(e)
112
118
 
@@ -6,5 +6,5 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.04.26 23:00:00 #
9
+ # Updated Date: 2026.01.02 20:00:00 #
10
10
  # ================================================== #
@@ -6,20 +6,20 @@
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: 2026.01.02 20:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Dict
13
13
  from packaging.version import Version
14
14
 
15
- from pygpt_net.item.assistant import AssistantFileItem
15
+ from pygpt_net.item.store import RemoteFileItem
16
16
 
17
17
 
18
18
  class BaseProvider:
19
19
  def __init__(self, window=None):
20
20
  self.window = window
21
21
  self.id = ""
22
- self.type = "assistant_file"
22
+ self.type = "remote_file"
23
23
 
24
24
  def attach(self, window):
25
25
  self.window = window
@@ -30,25 +30,25 @@ class BaseProvider:
30
30
  def patch(self, version: Version) -> bool:
31
31
  pass
32
32
 
33
- def create(self, file: AssistantFileItem):
33
+ def create(self, file: RemoteFileItem):
34
34
  pass
35
35
 
36
- def load(self, id) -> AssistantFileItem:
36
+ def load(self, id) -> RemoteFileItem:
37
37
  pass
38
38
 
39
- def load_all(self) -> Dict[str, AssistantFileItem]:
39
+ def load_all(self, provider: str) -> Dict[str, RemoteFileItem]:
40
40
  pass
41
41
 
42
- def save(self, file: AssistantFileItem):
42
+ def save(self, file: RemoteFileItem):
43
43
  pass
44
44
 
45
- def save_all(self, items: Dict[str, AssistantFileItem]):
45
+ def save_all(self, items: Dict[str, RemoteFileItem]):
46
46
  pass
47
47
 
48
48
  def remove(self, id):
49
49
  pass
50
50
 
51
- def truncate(self):
51
+ def truncate(self, provider: str):
52
52
  pass
53
53
 
54
54
  def get_version(self) -> str:
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # ================================================== #
4
+ # This file is a part of PYGPT package #
5
+ # Website: https://pygpt.net #
6
+ # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
+ # MIT License #
8
+ # Created By : Marcin Szczygliński #
9
+ # Updated Date: 2026.01.02 20:00:00 #
10
+ # ================================================== #
11
+
12
+ from .provider import *
@@ -6,7 +6,7 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.04.26 23:00:00 #
9
+ # Updated Date: 2026.01.02 20:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from packaging.version import parse as parse_version, Version
@@ -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: 2026.01.02 20:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import uuid
@@ -14,8 +14,8 @@ from typing import Dict
14
14
 
15
15
  from packaging.version import Version
16
16
 
17
- from pygpt_net.item.assistant import AssistantFileItem
18
- from pygpt_net.provider.core.assistant_file.base import BaseProvider
17
+ from pygpt_net.item.store import RemoteFileItem
18
+ from pygpt_net.provider.core.remote_file.base import BaseProvider
19
19
 
20
20
  from .patch import Patch
21
21
  from .storage import Storage
@@ -28,7 +28,7 @@ class DbSqliteProvider(BaseProvider):
28
28
  self.patcher = Patch(window, self)
29
29
  self.storage = Storage(window)
30
30
  self.id = "db_sqlite"
31
- self.type = "assistant_file"
31
+ self.type = "remote_file"
32
32
 
33
33
  def attach(self, window):
34
34
  """
@@ -56,11 +56,11 @@ class DbSqliteProvider(BaseProvider):
56
56
  """
57
57
  return str(uuid.uuid4())
58
58
 
59
- def create(self, file: AssistantFileItem) -> int:
59
+ def create(self, file: RemoteFileItem) -> int:
60
60
  """
61
61
  Create new and return its ID
62
62
 
63
- :param file: AssistantFileItem
63
+ :param file: RemoteFileItem
64
64
  :return: file ID
65
65
  """
66
66
  if file.record_id is None or file.record_id == "":
@@ -68,15 +68,16 @@ class DbSqliteProvider(BaseProvider):
68
68
  file.record_id = self.storage.insert(file)
69
69
  return file.record_id
70
70
 
71
- def load_all(self) -> Dict[str, AssistantFileItem]:
71
+ def load_all(self, provider: str) -> Dict[str, RemoteFileItem]:
72
72
  """
73
73
  Load files from DB
74
74
 
75
+ :param provider: provider ID
75
76
  :return: files dict
76
77
  """
77
- return self.storage.get_all()
78
+ return self.storage.get_all(provider)
78
79
 
79
- def load(self, id: int) -> AssistantFileItem:
80
+ def load(self, id: int) -> RemoteFileItem:
80
81
  """
81
82
  Load file from DB
82
83
 
@@ -85,11 +86,11 @@ class DbSqliteProvider(BaseProvider):
85
86
  """
86
87
  return self.storage.get_by_id(id)
87
88
 
88
- def save(self, file: AssistantFileItem):
89
+ def save(self, file: RemoteFileItem):
89
90
  """
90
91
  Save file to DB
91
92
 
92
- :param file: AssistantFileItem
93
+ :param file: RemoteFileItem
93
94
  """
94
95
  try:
95
96
  self.storage.save(file)
@@ -97,11 +98,11 @@ class DbSqliteProvider(BaseProvider):
97
98
  self.window.core.debug.log(e)
98
99
  print("Error while saving filed: {}".format(str(e)))
99
100
 
100
- def save_all(self, items: Dict[str, AssistantFileItem]):
101
+ def save_all(self, items: Dict[str, RemoteFileItem]):
101
102
  """
102
103
  Save all files to DB
103
104
 
104
- :param items: dict of AssistantFileItem objects
105
+ :param items: dict of RemoteFileItem objects
105
106
  """
106
107
  try:
107
108
  for id in items:
@@ -113,15 +114,15 @@ class DbSqliteProvider(BaseProvider):
113
114
 
114
115
  def get_by_store_or_thread(self, store_id: str, thread_id: str) -> dict:
115
116
  """
116
- Return dict with AssistantFileItem objects, indexed by record ID
117
+ Return dict with RemoteFileItem objects, indexed by record ID
117
118
 
118
- :return: dict of AssistantFileItem objects
119
+ :return: dict of RemoteFileItem objects
119
120
  """
120
121
  return self.storage.get_by_store_or_thread(store_id, thread_id)
121
122
 
122
123
  def count_by_store_or_thread(self, store_id: str, thread_id: str) -> int:
123
124
  """
124
- Count AssistantFileItem objects, indexed by ID
125
+ Count RemoteFileItem objects, indexed by ID
125
126
 
126
127
  :return: number of files
127
128
  """
@@ -163,13 +164,14 @@ class DbSqliteProvider(BaseProvider):
163
164
  """
164
165
  return self.storage.clear_store_from_files(store_id)
165
166
 
166
- def clear_all_stores_from_files(self) -> bool:
167
+ def clear_all_stores_from_files(self, provider: str) -> bool:
167
168
  """
168
169
  Clear all stores from files
169
170
 
171
+ :param provider: provider ID
170
172
  :return: True if deleted
171
173
  """
172
- return self.storage.clear_all_stores_from_files()
174
+ return self.storage.clear_all_stores_from_files(provider)
173
175
 
174
176
  def rename_file(self, record_id: int, name: str) -> bool:
175
177
  """
@@ -181,13 +183,14 @@ class DbSqliteProvider(BaseProvider):
181
183
  """
182
184
  return self.storage.rename_file(record_id, name)
183
185
 
184
- def truncate_all(self) -> bool:
186
+ def truncate_all(self, provider: str) -> bool:
185
187
  """
186
188
  Truncate all files
187
189
 
190
+ :param provider: provider ID
188
191
  :return: True if truncated
189
192
  """
190
- return self.storage.truncate_all()
193
+ return self.storage.truncate_all(provider)
191
194
 
192
195
  def truncate_by_store(self, store_id: str) -> bool:
193
196
  """