pygpt-net 2.5.17__py3-none-any.whl → 2.5.18__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 (45) hide show
  1. pygpt_net/CHANGELOG.txt +7 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/controller/chat/common.py +4 -2
  4. pygpt_net/controller/chat/input.py +36 -27
  5. pygpt_net/controller/chat/stream.py +22 -2
  6. pygpt_net/controller/config/placeholder.py +1 -1
  7. pygpt_net/controller/model/__init__.py +1 -1
  8. pygpt_net/controller/model/editor.py +6 -1
  9. pygpt_net/controller/model/importer.py +4 -3
  10. pygpt_net/core/bridge/__init__.py +8 -4
  11. pygpt_net/core/command/__init__.py +10 -1
  12. pygpt_net/core/idx/chat.py +6 -1
  13. pygpt_net/core/image/__init__.py +15 -0
  14. pygpt_net/core/models/__init__.py +14 -6
  15. pygpt_net/core/models/ollama.py +4 -3
  16. pygpt_net/data/config/config.json +4 -3
  17. pygpt_net/data/config/models.json +205 -34
  18. pygpt_net/data/config/modes.json +10 -10
  19. pygpt_net/data/config/settings.json +22 -0
  20. pygpt_net/data/locale/locale.de.ini +1 -1
  21. pygpt_net/data/locale/locale.en.ini +6 -2
  22. pygpt_net/data/locale/locale.es.ini +1 -1
  23. pygpt_net/data/locale/locale.fr.ini +1 -1
  24. pygpt_net/data/locale/locale.pl.ini +1 -1
  25. pygpt_net/data/locale/locale.uk.ini +1 -1
  26. pygpt_net/data/locale/locale.zh.ini +1 -1
  27. pygpt_net/item/model.py +35 -1
  28. pygpt_net/provider/core/config/patch.py +7 -0
  29. pygpt_net/provider/core/model/json_file.py +4 -1
  30. pygpt_net/provider/core/model/patch.py +17 -1
  31. pygpt_net/provider/gpt/__init__.py +14 -0
  32. pygpt_net/provider/gpt/image.py +42 -8
  33. pygpt_net/provider/gpt/responses.py +22 -16
  34. pygpt_net/provider/llms/anthropic.py +3 -1
  35. pygpt_net/provider/llms/google.py +3 -1
  36. pygpt_net/provider/llms/hugging_face.py +3 -1
  37. pygpt_net/provider/llms/hugging_face_api.py +3 -1
  38. pygpt_net/provider/llms/ollama.py +9 -3
  39. pygpt_net/provider/llms/openai.py +7 -1
  40. pygpt_net/ui/dialog/preset.py +1 -1
  41. {pygpt_net-2.5.17.dist-info → pygpt_net-2.5.18.dist-info}/METADATA +13 -6
  42. {pygpt_net-2.5.17.dist-info → pygpt_net-2.5.18.dist-info}/RECORD +45 -45
  43. {pygpt_net-2.5.17.dist-info → pygpt_net-2.5.18.dist-info}/LICENSE +0 -0
  44. {pygpt_net-2.5.17.dist-info → pygpt_net-2.5.18.dist-info}/WHEEL +0 -0
  45. {pygpt_net-2.5.17.dist-info → pygpt_net-2.5.18.dist-info}/entry_points.txt +0 -0
@@ -1027,6 +1027,11 @@
1027
1027
  "step": null,
1028
1028
  "advanced": false,
1029
1029
  "keys": [
1030
+ {"auto": "[gpt-image-1] auto"},
1031
+ {"1024x1024": "[gpt-image-1] 1024x1024"},
1032
+ {"1536x1024": "[gpt-image-1] 1536x1024"},
1033
+ {"1024x1536": "[gpt-image-1] 1024x1536"},
1034
+ {"1536x1024": "[gpt-image-1] 1536x1024"},
1030
1035
  {"1792x1024": "[DALL-E 3] 1792x1024"},
1031
1036
  {"1024x1792": "[DALL-E 3] 1024x1792"},
1032
1037
  {"1024x1024": "[DALL-E 3] 1024x1024"},
@@ -1047,6 +1052,10 @@
1047
1052
  "step": null,
1048
1053
  "advanced": false,
1049
1054
  "keys": [
1055
+ {"auto": "[gpt-image-1] auto"},
1056
+ {"high": "[gpt-image-1] high"},
1057
+ {"medium": "[gpt-image-1] medium"},
1058
+ {"medium": "[gpt-image-1] low"},
1050
1059
  {"standard": "[DALL-E 3] standard"},
1051
1060
  {"hd": "[DALL-E 3] hd"},
1052
1061
  {"standard": "[DALL-E 2] standard"}
@@ -1211,6 +1220,19 @@
1211
1220
  "step": null,
1212
1221
  "advanced": false
1213
1222
  },
1223
+ "remote_tools.image": {
1224
+ "section": "remote_tools",
1225
+ "type": "bool",
1226
+ "slider": false,
1227
+ "label": "settings.remote_tools.image",
1228
+ "description": "settings.remote_tools.image.desc",
1229
+ "value": true,
1230
+ "min": null,
1231
+ "max": null,
1232
+ "multiplier": null,
1233
+ "step": null,
1234
+ "advanced": false
1235
+ },
1214
1236
  "llama.idx.list": {
1215
1237
  "section": "llama-index",
1216
1238
  "type": "dict",
@@ -989,7 +989,7 @@ tip.tokens.input = Token: Benutzereingabeaufforderung + Systemaufforderung + Kon
989
989
  tip.toolbox.assistants = Die Liste der Assistenten zeigt die erstellten Assistenten, die auf dem entfernten Server arbeiten. Alle Änderungen werden mit dem entfernten Assistenten synchronisiert.
990
990
  tip.toolbox.ctx = Erstellen Sie so viele Gesprächskontexte, wie Sie benötigen; Sie können jederzeit zu ihnen zurückkehren.
991
991
  tip.toolbox.indexes = Durch das Indizieren von Gesprächen und Dateien können Sie das verfügbare Wissen mit Ihren eigenen Daten und Gesprächsverläufen erweitern.
992
- tip.toolbox.mode = Sie können den Arbeitsmodus und das Modell in Echtzeit ändern. Um andere Modelle als GPT zu verwenden, nutzen Sie den Modus Chat mit Dateien.
992
+ tip.toolbox.mode = Sie können den Arbeitsmodus und das Modell in Echtzeit ändern.
993
993
  tip.toolbox.presets = Erstellen Sie Voreinstellungen mit verschiedenen Konfigurationen, um schnell zwischen verschiedenen Einstellungen wie dem Systemprompt und anderen zu wechseln.
994
994
  tip.toolbox.prompt = Die aktuelle Systemeingabeaufforderung kann in Echtzeit geändert werden. Um Werkzeuge aus Plugins zu aktivieren, aktivieren Sie die Option "+ Werkzeuge."
995
995
  toolbox.agent.auto_stop.label = Automatischer Stopp
@@ -816,7 +816,7 @@ model.llama_index.mode.desc = Available sub-modes: chat
816
816
  model.llama_index.provider = [LlamaIndex] Provider
817
817
  model.llama_index.provider.desc = LLM provider to use in "Chat with Files" mode
818
818
  model.mode = Mode(s)
819
- model.mode.desc = Available modes: chat, completion, img, audio, vision, assistant, langchain, llama_index, agent, agent_llama, research
819
+ model.mode.desc = Available modes: chat (Chat), llama_index (Chat with Files), audio (Chat with Audio), research (Research), completion (Completion), img (Image), vision (Vision), assistant (Assistants), langchain (Langchain), agent_llama (Agent LlamaIndex), agent (Agent Autonomous), expert (Experts)
820
820
  model.name = Name
821
821
  models.importer.all = Show all
822
822
  models.importer.available.label = Ollama models
@@ -829,6 +829,8 @@ models.importer.error.remove.no_model = No model selected to remove
829
829
  models.importer.error.remove.not_exists = Model already exists in current list
830
830
  models.importer.loaded = Ollama models loaded successfully.
831
831
  models.importer.status.imported = Models imported successfully.
832
+ model.openai = OpenAI API
833
+ model.openai.desc = Supports native OpenAI API
832
834
  model.tokens = Output tokens
833
835
  model.tokens.desc = Max model output tokens
834
836
  mode.research = Research (Perplexity)
@@ -1129,6 +1131,8 @@ settings.prompt.img = DALL-E: image generation
1129
1131
  settings.prompt.img.desc = Prompt for generating prompts for DALL-E (if raw-mode is disabled). Image mode only.
1130
1132
  settings.remote_tools.web_search = Web Search
1131
1133
  settings.remote_tools.web_search.desc = Enable `web_search` remote tool in Chat mode / via OpenAI Responses API.
1134
+ settings.remote_tools.image = Image generation
1135
+ settings.remote_tools.image.desc = Enable `image_generation` remote tool in Chat mode / via OpenAI Responses API.
1132
1136
  settings.render.code_syntax = Code syntax highlight
1133
1137
  settings.render.engine = Rendering engine
1134
1138
  settings.render.open_gl = OpenGL hardware acceleration
@@ -1238,7 +1242,7 @@ tip.tokens.input = Tokens: input prompt + system prompt + context + extra + atta
1238
1242
  tip.toolbox.assistants = The list of assistants shows the assistants created and operating on the remote server. Any changes will be synchronized with the remote assistant.
1239
1243
  tip.toolbox.ctx = Create as many conversation contexts as you need; you can return to them at any time.
1240
1244
  tip.toolbox.indexes = By indexing conversations and files, you can expand the available knowledge with your own data and conversation history.
1241
- tip.toolbox.mode = You can change the working mode and model in real-time. To use models other than GPT, use the Chat with Files mode.
1245
+ tip.toolbox.mode = You can change the working mode and model in real-time.
1242
1246
  tip.toolbox.presets = Create presets with different configurations to quickly switch between various settings, such as the system prompt and others.
1243
1247
  tip.toolbox.prompt = The current system prompt can be modified in real-time. To enable tools from plugins, enable the option "+ Tools."
1244
1248
  toolbox.agent.auto_stop.label = Auto-stop
@@ -989,7 +989,7 @@ tip.tokens.input = Fichas: indicación del usuario + indicación del sistema + c
989
989
  tip.toolbox.assistants = La lista de asistentes muestra los asistentes creados y operando en el servidor remoto. Cualquier cambio se sincronizará con el asistente remoto.
990
990
  tip.toolbox.ctx = Crea tantos contextos de conversación como necesites; puedes volver a ellos en cualquier momento.
991
991
  tip.toolbox.indexes = Al indexar conversaciones y archivos, puedes ampliar el conocimiento disponible con tus propios datos e historial de conversaciones.
992
- tip.toolbox.mode = Puedes cambiar el modo de trabajo y el modelo en tiempo real. Para usar modelos distintos a GPT, utiliza el modo Chat con archivos.
992
+ tip.toolbox.mode = Puedes cambiar el modo de trabajo y el modelo en tiempo real.
993
993
  tip.toolbox.presets = Crea preajustes con diferentes configuraciones para cambiar rápidamente entre varios ajustes, como el prompt del sistema y otros.
994
994
  tip.toolbox.prompt = La solicitud del sistema actual se puede modificar en tiempo real. Para habilitar herramientas desde complementos, habilite la opción "+ Herramientas."
995
995
  toolbox.agent.auto_stop.label = Auto-parada
@@ -989,7 +989,7 @@ tip.tokens.input = Jetons: invite de l'utilisateur + invite système + contexte
989
989
  tip.toolbox.assistants = La liste des assistants montre les assistants créés et opérant sur le serveur distant. Tout changement sera synchronisé avec l'assistant distant.
990
990
  tip.toolbox.ctx = Créez autant de contextes de conversation que vous en avez besoin ; vous pouvez y revenir à tout moment.
991
991
  tip.toolbox.indexes = En indexant des conversations et des fichiers, vous pouvez étendre les connaissances disponibles avec vos propres données et historique de conversation.
992
- tip.toolbox.mode = Vous pouvez changer le mode de travail et le modèle en temps réel. Pour utiliser des modèles autres que GPT, utilisez le mode Chat avec fichiers.
992
+ tip.toolbox.mode = Vous pouvez changer le mode de travail et le modèle en temps réel.
993
993
  tip.toolbox.presets = Créez des préréglages avec différentes configurations pour basculer rapidement entre divers réglages, tels que l'invite système et d'autres.
994
994
  tip.toolbox.prompt = L'invite système actuelle peut être modifiée en temps réel. Pour activer les outils à partir des plugins, activez l'option "+ Outils."
995
995
  toolbox.agent.auto_stop.label = Arrêt automatique
@@ -990,7 +990,7 @@ tip.tokens.input = Tokeny: prompt użytkownika + systemowy prompt + kontekst + d
990
990
  tip.toolbox.assistants = Lista asystentów pokazuje asystentów stworzonych i działających na zdalnym serwerze. Wszelkie zmiany zostaną zsynchronizowane ze zdalnym asystentem.
991
991
  tip.toolbox.ctx = Twórz tyle kontekstów rozmów, ile potrzebujesz; możesz do nich wrócić w dowolnym momencie.
992
992
  tip.toolbox.indexes = Indeksując rozmowy i pliki, możesz rozszerzyć dostępną wiedzę o własne dane i historię rozmów.
993
- tip.toolbox.mode = Możesz zmienić tryb pracy i model w czasie rzeczywistym. Aby użyć modeli innych niż GPT, użyj trybu Czat z plikami.
993
+ tip.toolbox.mode = Możesz zmienić tryb pracy i model w czasie rzeczywistym.
994
994
  tip.toolbox.presets = Twórz presety z różnymi konfiguracjami, aby szybko przełączać się między różnymi ustawieniami, takimi jak prompt systemowy i inne.
995
995
  tip.toolbox.prompt = Aktualna podpowiedź systemu może być modyfikowana w czasie rzeczywistym. Aby włączyć narzędzia z wtyczek, włącz opcję "+ Narzędzia."
996
996
  toolbox.agent.auto_stop.label = Auto-stop
@@ -989,7 +989,7 @@ tip.tokens.input = Токени: запит користувача + систе
989
989
  tip.toolbox.assistants = Список асистентів показує асистентів, створених і що працюють на віддаленому сервері. Будь-які зміни будуть синхронізовані з віддаленим асистентом.
990
990
  tip.toolbox.ctx = Створіть стільки контекстів розмов, як вам потрібно; ви можете повернутися до них у будь-який час.
991
991
  tip.toolbox.indexes = Індексуючи розмови та файли, ви можете розширити доступні знання зі своїми власними даними та історією розмов.
992
- tip.toolbox.mode = Ви можете змінити робочий режим та модель в реальному часі. Щоб використовувати моделі, відмінні від GPT, використовуйте режим Чат з файлами.
992
+ tip.toolbox.mode = Ви можете змінити робочий режим та модель в реальному часі.
993
993
  tip.toolbox.presets = Створіть пресети з різними конфігураціями для швидкого перемикання між різними налаштуваннями, такими як системний сповіщення та інші.
994
994
  tip.toolbox.prompt = Поточну системну підказку можна змінювати в режимі реального часу. Щоб увімкнути інструменти з плагінів, увімкніть опцію "+ Інструменти."
995
995
  toolbox.agent.auto_stop.label = Авто-стоп
@@ -1104,7 +1104,7 @@ tip.tokens.input = 代币:用户输入提示 + 系统提示 + 上下文 + 额
1104
1104
  tip.toolbox.assistants = 助手列表顯示在遠程服務器上創建和運行的助手。任何更改都將與遠程助手同步。
1105
1105
  tip.toolbox.ctx = 創建所需數量的對話上下文;您隨時可以返回它們。
1106
1106
  tip.toolbox.indexes = 通過索引對話和文件,您可以用自己的數據和對話歷史擴展可用知識。
1107
- tip.toolbox.mode = 您可以實時更換工作模式和模型。要使用非GPT模型,请使用“文件聊天模式”模式。
1107
+ tip.toolbox.mode = 您可以實時更換工作模式和模型。
1108
1108
  tip.toolbox.presets = 創建具有不同配置的預設,以便快速切換不同設置,例如系統提示等。
1109
1109
  tip.toolbox.prompt = 当前系统提示可以实时修改。要启用来自插件的工具,请启用“+ 工具”选项。
1110
1110
  toolbox.agent.auto_stop.label = 自動停止
pygpt_net/item/model.py CHANGED
@@ -6,11 +6,13 @@
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.06.24 16:00:00 #
9
+ # Updated Date: 2025.06.26 16:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import json
13
13
 
14
+ from pygpt_net.core.types import MODE_CHAT
15
+
14
16
 
15
17
  class ModelItem:
16
18
  def __init__(self, id=None):
@@ -29,6 +31,7 @@ class ModelItem:
29
31
  self.tokens = 0
30
32
  self.default = False
31
33
  self.imported = False
34
+ self.openai = False # OpenAI API supported model
32
35
  self.extra = {}
33
36
 
34
37
  def from_dict(self, data: dict):
@@ -54,6 +57,8 @@ class ModelItem:
54
57
  self.extra = data['extra']
55
58
  if 'imported' in data:
56
59
  self.imported = data['imported']
60
+ if 'openai' in data:
61
+ self.openai = data['openai']
57
62
 
58
63
  # multimodal
59
64
  if 'multimodal' in data:
@@ -105,6 +110,7 @@ class ModelItem:
105
110
  data['multimodal'] = ','.join(self.multimodal)
106
111
  data['extra'] = self.extra
107
112
  data['imported'] = self.imported
113
+ data['openai'] = self.openai
108
114
 
109
115
  data['langchain.provider'] = None
110
116
  data['langchain.mode'] = ""
@@ -178,6 +184,9 @@ class ModelItem:
178
184
  :param mode: Mode
179
185
  :return: True if supported
180
186
  """
187
+ if mode == MODE_CHAT and not self.is_openai():
188
+ # only OpenAI models are supported for chat mode
189
+ return False
181
190
  return mode in self.mode
182
191
 
183
192
  def is_multimodal(self) -> bool:
@@ -188,6 +197,21 @@ class ModelItem:
188
197
  """
189
198
  return len(self.multimodal) > 0
190
199
 
200
+ def is_openai(self) -> bool:
201
+ """
202
+ Check if model is supported by OpenAI API
203
+
204
+ :return: True if OpenAI
205
+ """
206
+ if (self.id.startswith("gpt-")
207
+ or self.id.startswith("chatgpt")
208
+ or self.id.startswith("o1")
209
+ or self.id.startswith("o3")
210
+ or self.id.startswith("o4")
211
+ or self.id.startswith("o5")):
212
+ return True
213
+ return False
214
+
191
215
  def is_ollama(self) -> bool:
192
216
  """
193
217
  Check if model is Ollama
@@ -196,6 +220,8 @@ class ModelItem:
196
220
  """
197
221
  if self.llama_index is None:
198
222
  return False
223
+ if self.llama_index.get("provider") is None:
224
+ return False
199
225
  return "ollama" in self.llama_index.get("provider", "")
200
226
 
201
227
  def get_ollama_model(self) -> str:
@@ -210,6 +236,14 @@ class ModelItem:
210
236
  return arg["value"]
211
237
  return ""
212
238
 
239
+ def get_llama_provider(self) -> str:
240
+ """
241
+ Get Llama Index provider
242
+
243
+ :return: provider name
244
+ """
245
+ return self.llama_index.get("provider", "")
246
+
213
247
  def has_mode(self, mode: str) -> bool:
214
248
  """
215
249
  Check if model has mode
@@ -1862,6 +1862,13 @@ class Patch:
1862
1862
  data["remote_tools.web_search"] = True
1863
1863
  updated = True
1864
1864
 
1865
+ # < 2.5.18
1866
+ if old < parse_version("2.5.18"):
1867
+ print("Migrating config from < 2.5.18...")
1868
+ if 'remote_tools.image' not in data:
1869
+ data["remote_tools.image"] = False
1870
+ updated = True
1871
+
1865
1872
  # update file
1866
1873
  migrated = False
1867
1874
  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.02.02 02:00:00 #
9
+ # Updated Date: 2025.06.26 16:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import json
@@ -166,6 +166,7 @@ class JsonFileProvider(BaseProvider):
166
166
  'multimodal': item.multimodal,
167
167
  'extra': item.extra,
168
168
  'imported': item.imported,
169
+ 'openai': item.openai,
169
170
  }
170
171
 
171
172
  @staticmethod
@@ -198,6 +199,8 @@ class JsonFileProvider(BaseProvider):
198
199
  item.extra = data['extra']
199
200
  if 'imported' in data:
200
201
  item.imported = data['imported']
202
+ if 'openai' in data:
203
+ item.openai = data['openai']
201
204
 
202
205
  def dump(self, item: ModelItem) -> str:
203
206
  """
@@ -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.06.24 16:00:00 #
9
+ # Updated Date: 2025.06.26 16:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from packaging.version import parse as parse_version, Version
@@ -550,6 +550,22 @@ class Patch:
550
550
  del data[name_to_replace]
551
551
  updated = True
552
552
 
553
+ # < 2.5.18 <--- update openai flag
554
+ if old < parse_version("2.5.18"):
555
+ print("Migrating models from < 2.5.18...")
556
+ for id in data:
557
+ model = data[id]
558
+ if (model.id.startswith("o1")
559
+ or model.id.startswith("o3")
560
+ or model.id.startswith("gpt-")
561
+ or model.id.startswith("chatgpt")
562
+ or model.id.startswith("dall-e")):
563
+ model.openai = True
564
+ if model.is_supported("llama_index"):
565
+ if "chat" not in model.mode:
566
+ model.mode.append("chat")
567
+ updated = True
568
+
553
569
  # update file
554
570
  if updated:
555
571
  data = dict(sorted(data.items()))
@@ -8,6 +8,7 @@
8
8
  # Created By : Marcin Szczygliński #
9
9
  # Updated Date: 2025.06.25 02:00:00 #
10
10
  # ================================================== #
11
+ import base64
11
12
 
12
13
  from httpx_socks import SyncProxyTransport
13
14
 
@@ -271,6 +272,19 @@ class Gpt:
271
272
  response.usage.input_tokens,
272
273
  response.usage.output_tokens,
273
274
  )
275
+ if mode == MODE_CHAT:
276
+ # if image generation call in responses API
277
+ image_data = [
278
+ output.result
279
+ for output in response.output
280
+ if output.type == "image_generation_call"
281
+ ]
282
+ if image_data:
283
+ img_path = self.window.core.image.gen_unique_path(ctx)
284
+ image_base64 = image_data[0]
285
+ with open(img_path, "wb") as f:
286
+ f.write(base64.b64decode(image_base64))
287
+ ctx.images = [img_path]
274
288
  return True
275
289
 
276
290
  def quick_call(self, context: BridgeContext, extra: dict = None) -> str:
@@ -6,9 +6,9 @@
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.06.26 18:00:00 #
10
10
  # ================================================== #
11
-
11
+ import base64
12
12
  import datetime
13
13
  import os
14
14
  from typing import Optional, Dict, Any
@@ -132,6 +132,7 @@ class ImageWorker(QObject, QRunnable):
132
132
  self.allowed_max_num = {
133
133
  "dall-e-2": 4,
134
134
  "dall-e-3": 1,
135
+ "gpt-image-1": 1,
135
136
  }
136
137
  self.allowed_resolutions = {
137
138
  "dall-e-2": [
@@ -144,6 +145,27 @@ class ImageWorker(QObject, QRunnable):
144
145
  "1024x1792",
145
146
  "1024x1024",
146
147
  ],
148
+ "gpt-image-1": [
149
+ "1536x1024",
150
+ "1024x1536",
151
+ "1024x1024",
152
+ "auto",
153
+ ],
154
+ }
155
+ self.allowed_quality = {
156
+ "dall-e-2": [
157
+ "standard",
158
+ ],
159
+ "dall-e-3": [
160
+ "standard",
161
+ "hd",
162
+ ],
163
+ "gpt-image-1": [
164
+ "auto",
165
+ "high",
166
+ "medium",
167
+ "low",
168
+ ],
147
169
  }
148
170
 
149
171
  @Slot()
@@ -188,6 +210,11 @@ class ImageWorker(QObject, QRunnable):
188
210
  if resolution not in self.allowed_resolutions[self.model]:
189
211
  resolution = self.allowed_resolutions[self.model][0]
190
212
 
213
+ quality = self.quality
214
+ if self.model in self.allowed_quality:
215
+ if quality not in self.allowed_quality[self.model]:
216
+ quality = self.allowed_quality[self.model][0]
217
+
191
218
  # send to API
192
219
  response = None
193
220
  if self.model == "dall-e-2":
@@ -197,12 +224,12 @@ class ImageWorker(QObject, QRunnable):
197
224
  n=self.num,
198
225
  size=resolution,
199
226
  )
200
- elif self.model == "dall-e-3":
227
+ elif self.model == "dall-e-3" or self.model == "gpt-image-1":
201
228
  response = self.client.images.generate(
202
229
  model=self.model,
203
230
  prompt=self.input_prompt,
204
231
  n=self.num,
205
- quality=self.quality,
232
+ quality=quality,
206
233
  size=resolution,
207
234
  )
208
235
 
@@ -215,20 +242,27 @@ class ImageWorker(QObject, QRunnable):
215
242
  for i in range(self.num):
216
243
  if i >= len(response.data):
217
244
  break
218
- url = response.data[i].url
219
- res = requests.get(url)
220
245
 
221
246
  # generate filename
222
247
  name = datetime.date.today().strftime(
223
248
  "%Y-%m-%d") + "_" + datetime.datetime.now().strftime("%H-%M-%S") + "-" \
224
- + self.window.core.image.make_safe_filename(self.input_prompt) + "-" + str(i + 1) + ".png"
249
+ + self.window.core.image.make_safe_filename(self.input_prompt) + "-" + str(i + 1) + ".png"
225
250
  path = os.path.join(self.window.core.config.get_user_dir("img"), name)
226
251
 
227
252
  msg = trans('img.status.downloading') + " (" + str(i + 1) + " / " + str(self.num) + ") -> " + str(path)
228
253
  self.signals.status.emit(msg)
229
254
 
255
+ if response.data[i] is None:
256
+ self.signals.error.emit("API Error: empty image data")
257
+ return
258
+ if response.data[i].url: # dall-e 2 and 3 returns URL
259
+ res = requests.get(response.data[i].url)
260
+ data = res.content
261
+ else: # gpt-image-1 returns base64 encoded image
262
+ data = base64.b64decode(response.data[i].b64_json)
263
+
230
264
  # save image
231
- if self.window.core.image.save_image(path, res.content):
265
+ if data and self.window.core.image.save_image(path, data):
232
266
  paths.append(path)
233
267
  else:
234
268
  self.signals.error.emit("Error saving image")
@@ -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.06.25 02:00:00 #
9
+ # Updated Date: 2025.06.26 18:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import json
@@ -17,13 +17,11 @@ from pygpt_net.core.types import (
17
17
  MODE_CHAT,
18
18
  MODE_VISION,
19
19
  MODE_AUDIO,
20
- MODE_RESEARCH,
21
20
  )
22
21
  from pygpt_net.core.bridge.context import BridgeContext, MultimodalContext
23
22
  from pygpt_net.item.ctx import CtxItem
24
23
  from pygpt_net.item.model import ModelItem
25
24
 
26
- from .utils import sanitize_name
27
25
  from pygpt_net.item.attachment import AttachmentItem
28
26
 
29
27
 
@@ -38,6 +36,7 @@ class Responses:
38
36
  self.input_tokens = 0
39
37
  self.audio_prev_id = None
40
38
  self.audio_prev_expires_ts = None
39
+ self.prev_response_id = None
41
40
 
42
41
  def send(
43
42
  self,
@@ -80,6 +79,7 @@ class Responses:
80
79
  user_name=user_name,
81
80
  multimodal_ctx=multimodal_ctx,
82
81
  )
82
+
83
83
  msg_tokens = self.window.core.tokens.from_messages(
84
84
  messages,
85
85
  model.id,
@@ -116,9 +116,15 @@ class Responses:
116
116
  response_kwargs['reasoning']['effort'] = model.extra["reasoning_effort"]
117
117
 
118
118
  # extend tools with external tools
119
- if not model.id.startswith("o1") and not model.id.startswith("o3"):
119
+ if (not model.id.startswith("o1")
120
+ and not model.id.startswith("o3")):
120
121
  if self.window.core.config.get("remote_tools.web_search", False):
121
122
  tools.append({"type": "web_search_preview"})
123
+ if self.window.core.config.get("remote_tools.image", False):
124
+ tool = {"type": "image_generation"}
125
+ if stream:
126
+ tool["partial_images"] = 1 # required for streaming
127
+ tools.append(tool)
122
128
 
123
129
  # tool calls are not supported for o1-mini and o1-preview
124
130
  if (model.id is not None
@@ -126,18 +132,9 @@ class Responses:
126
132
  if len(tools) > 0:
127
133
  response_kwargs['tools'] = tools
128
134
 
129
- # audio mode
130
- if mode in [MODE_AUDIO]:
131
- stream = False
132
- voice_id = "alloy"
133
- tmp_voice = self.window.core.plugins.get_option("audio_output", "openai_voice")
134
- if tmp_voice:
135
- voice_id = tmp_voice
136
- response_kwargs["modalities"] = ["text", "audio"]
137
- response_kwargs["audio"] = {
138
- "voice": voice_id,
139
- "format": "wav"
140
- }
135
+ # attach previous response ID if available
136
+ if self.prev_response_id:
137
+ response_kwargs['previous_response_id'] = self.prev_response_id
141
138
 
142
139
  response = client.responses.create(
143
140
  input=messages,
@@ -145,6 +142,11 @@ class Responses:
145
142
  stream=stream,
146
143
  **response_kwargs,
147
144
  )
145
+
146
+ # store previous response ID
147
+ if not stream and response:
148
+ ctx.msg_id = response.id
149
+
148
150
  return response
149
151
 
150
152
  def build(
@@ -172,6 +174,7 @@ class Responses:
172
174
  :return: messages list
173
175
  """
174
176
  messages = []
177
+ self.prev_response_id = None # reset
175
178
 
176
179
  # tokens config
177
180
  mode = MODE_CHAT
@@ -240,6 +243,9 @@ class Responses:
240
243
  }
241
244
  messages.append(msg)
242
245
 
246
+ if item.msg_id and (item.cmds is None or len(item.cmds) == 0): # if no cmds before
247
+ self.prev_response_id = item.msg_id # previous response ID to use in current input
248
+
243
249
  # use vision and audio if available in current model
244
250
  content = str(prompt)
245
251
  if MODE_VISION in model.mode:
@@ -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.06.26 16:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from llama_index.llms.anthropic import Anthropic
@@ -47,4 +47,6 @@ class AnthropicLLM(BaseLLM):
47
47
  :return: LLM provider instance
48
48
  """
49
49
  args = self.parse_args(model.llama_index)
50
+ if "model" not in args:
51
+ args["model"] = model.id
50
52
  return Anthropic(**args)
@@ -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.01.16 01:00:00 #
9
+ # Updated Date: 2025.06.26 16:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from typing import Optional, List, Dict
@@ -51,6 +51,8 @@ class GoogleLLM(BaseLLM):
51
51
  :return: LLM provider instance
52
52
  """
53
53
  args = self.parse_args(model.llama_index)
54
+ if "model" not in args:
55
+ args["model"] = model.id
54
56
  return Gemini(**args)
55
57
 
56
58
  def get_embeddings_model(
@@ -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.06.26 16:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from langchain_community.llms import HuggingFaceHub
@@ -39,6 +39,8 @@ class HuggingFaceLLM(BaseLLM):
39
39
  :return: LLM provider instance
40
40
  """
41
41
  args = self.parse_args(model.langchain)
42
+ if "model" not in args:
43
+ args["model"] = model.id
42
44
  return HuggingFaceHub(**args)
43
45
 
44
46
  def chat(
@@ -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.06.26 16:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -44,6 +44,8 @@ class HuggingFaceApiLLM(BaseLLM):
44
44
  :return: LLM provider instance
45
45
  """
46
46
  args = self.parse_args(model.llama_index)
47
+ if "model" not in args:
48
+ args["model"] = model.id
47
49
  return HuggingFaceInferenceAPI(**args)
48
50
 
49
51
  def get_embeddings_model(