pygpt-net 2.7.6__py3-none-any.whl → 2.7.8__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.
- pygpt_net/CHANGELOG.txt +13 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +5 -1
- pygpt_net/controller/assistant/batch.py +2 -2
- pygpt_net/controller/assistant/files.py +7 -6
- pygpt_net/controller/assistant/threads.py +0 -0
- pygpt_net/controller/chat/command.py +0 -0
- pygpt_net/controller/chat/remote_tools.py +3 -9
- pygpt_net/controller/chat/stream.py +2 -2
- pygpt_net/controller/chat/{handler/worker.py → stream_worker.py} +13 -35
- pygpt_net/controller/dialogs/confirm.py +35 -58
- pygpt_net/controller/lang/mapping.py +9 -9
- pygpt_net/controller/remote_store/{google/batch.py → batch.py} +209 -252
- pygpt_net/controller/remote_store/remote_store.py +982 -13
- pygpt_net/core/command/command.py +0 -0
- pygpt_net/core/db/viewer.py +1 -1
- pygpt_net/core/debug/models.py +2 -2
- pygpt_net/core/realtime/worker.py +3 -1
- pygpt_net/{controller/remote_store/google → core/remote_store/anthropic}/__init__.py +0 -1
- pygpt_net/core/remote_store/anthropic/files.py +211 -0
- pygpt_net/core/remote_store/anthropic/store.py +208 -0
- pygpt_net/core/remote_store/openai/store.py +5 -4
- pygpt_net/core/remote_store/remote_store.py +5 -1
- pygpt_net/{controller/remote_store/openai → core/remote_store/xai}/__init__.py +0 -1
- pygpt_net/core/remote_store/xai/files.py +225 -0
- pygpt_net/core/remote_store/xai/store.py +219 -0
- pygpt_net/data/config/config.json +18 -5
- pygpt_net/data/config/models.json +193 -4
- pygpt_net/data/config/settings.json +179 -36
- pygpt_net/data/icons/folder_eye.svg +1 -0
- pygpt_net/data/icons/folder_eye_filled.svg +1 -0
- pygpt_net/data/icons/folder_open.svg +1 -0
- pygpt_net/data/icons/folder_open_filled.svg +1 -0
- pygpt_net/data/locale/locale.de.ini +6 -3
- pygpt_net/data/locale/locale.en.ini +46 -12
- pygpt_net/data/locale/locale.es.ini +6 -3
- pygpt_net/data/locale/locale.fr.ini +6 -3
- pygpt_net/data/locale/locale.it.ini +6 -3
- pygpt_net/data/locale/locale.pl.ini +7 -4
- pygpt_net/data/locale/locale.uk.ini +6 -3
- pygpt_net/data/locale/locale.zh.ini +6 -3
- pygpt_net/icons.qrc +4 -0
- pygpt_net/icons_rc.py +282 -138
- pygpt_net/plugin/cmd_mouse_control/worker.py +2 -1
- pygpt_net/plugin/cmd_mouse_control/worker_sandbox.py +2 -1
- pygpt_net/provider/api/anthropic/__init__.py +10 -3
- pygpt_net/provider/api/anthropic/chat.py +342 -11
- pygpt_net/provider/api/anthropic/computer.py +844 -0
- pygpt_net/provider/api/anthropic/remote_tools.py +172 -0
- pygpt_net/provider/api/anthropic/store.py +307 -0
- pygpt_net/{controller/chat/handler/anthropic_stream.py → provider/api/anthropic/stream.py} +99 -10
- pygpt_net/provider/api/anthropic/tools.py +32 -77
- pygpt_net/provider/api/anthropic/utils.py +30 -0
- pygpt_net/{controller/chat/handler → provider/api/anthropic/worker}/__init__.py +0 -0
- pygpt_net/provider/api/anthropic/worker/importer.py +278 -0
- pygpt_net/provider/api/google/chat.py +62 -9
- pygpt_net/provider/api/google/store.py +124 -3
- pygpt_net/{controller/chat/handler/google_stream.py → provider/api/google/stream.py} +92 -25
- pygpt_net/provider/api/google/utils.py +185 -0
- pygpt_net/provider/api/google/worker/importer.py +16 -28
- pygpt_net/provider/api/langchain/__init__.py +0 -0
- pygpt_net/{controller/chat/handler/langchain_stream.py → provider/api/langchain/stream.py} +1 -1
- pygpt_net/provider/api/llama_index/__init__.py +0 -0
- pygpt_net/{controller/chat/handler/llamaindex_stream.py → provider/api/llama_index/stream.py} +1 -1
- pygpt_net/provider/api/openai/assistants.py +2 -2
- pygpt_net/provider/api/openai/image.py +2 -2
- pygpt_net/provider/api/openai/store.py +4 -1
- pygpt_net/{controller/chat/handler/openai_stream.py → provider/api/openai/stream.py} +1 -1
- pygpt_net/provider/api/openai/utils.py +69 -3
- pygpt_net/provider/api/openai/worker/importer.py +19 -61
- pygpt_net/provider/api/openai/worker/importer_assistants.py +230 -0
- pygpt_net/provider/api/x_ai/__init__.py +138 -15
- pygpt_net/provider/api/x_ai/audio.py +43 -11
- pygpt_net/provider/api/x_ai/chat.py +92 -4
- pygpt_net/provider/api/x_ai/image.py +149 -47
- pygpt_net/provider/api/x_ai/realtime/__init__.py +12 -0
- pygpt_net/provider/api/x_ai/realtime/client.py +1825 -0
- pygpt_net/provider/api/x_ai/realtime/realtime.py +198 -0
- pygpt_net/provider/api/x_ai/{remote.py → remote_tools.py} +183 -70
- pygpt_net/provider/api/x_ai/responses.py +507 -0
- pygpt_net/provider/api/x_ai/store.py +610 -0
- pygpt_net/{controller/chat/handler/xai_stream.py → provider/api/x_ai/stream.py} +42 -10
- pygpt_net/provider/api/x_ai/tools.py +59 -8
- pygpt_net/{controller/chat/handler → provider/api/x_ai}/utils.py +1 -2
- pygpt_net/provider/api/x_ai/vision.py +1 -4
- pygpt_net/provider/api/x_ai/worker/importer.py +308 -0
- pygpt_net/provider/audio_input/xai_grok_voice.py +390 -0
- pygpt_net/provider/audio_output/xai_tts.py +325 -0
- pygpt_net/provider/core/config/patch.py +39 -3
- pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +2 -2
- pygpt_net/provider/core/model/patch.py +39 -1
- pygpt_net/tools/image_viewer/tool.py +334 -34
- pygpt_net/tools/image_viewer/ui/dialogs.py +319 -22
- pygpt_net/tools/text_editor/ui/dialogs.py +3 -2
- pygpt_net/tools/text_editor/ui/widgets.py +0 -0
- pygpt_net/ui/dialog/assistant.py +1 -1
- pygpt_net/ui/dialog/plugins.py +13 -5
- pygpt_net/ui/dialog/remote_store.py +552 -0
- pygpt_net/ui/dialogs.py +3 -5
- pygpt_net/ui/layout/ctx/ctx_list.py +58 -7
- pygpt_net/ui/menu/tools.py +6 -13
- pygpt_net/ui/widget/dialog/base.py +16 -5
- pygpt_net/ui/widget/dialog/{remote_store_google.py → remote_store.py} +10 -10
- pygpt_net/ui/widget/element/button.py +4 -4
- pygpt_net/ui/widget/image/display.py +2 -2
- pygpt_net/ui/widget/lists/context.py +2 -2
- pygpt_net/ui/widget/textarea/editor.py +0 -0
- {pygpt_net-2.7.6.dist-info → pygpt_net-2.7.8.dist-info}/METADATA +15 -2
- {pygpt_net-2.7.6.dist-info → pygpt_net-2.7.8.dist-info}/RECORD +107 -89
- pygpt_net/controller/remote_store/google/store.py +0 -615
- pygpt_net/controller/remote_store/openai/batch.py +0 -524
- pygpt_net/controller/remote_store/openai/store.py +0 -699
- pygpt_net/ui/dialog/remote_store_google.py +0 -539
- pygpt_net/ui/dialog/remote_store_openai.py +0 -539
- pygpt_net/ui/widget/dialog/remote_store_openai.py +0 -56
- pygpt_net/ui/widget/lists/remote_store_google.py +0 -248
- pygpt_net/ui/widget/lists/remote_store_openai.py +0 -317
- {pygpt_net-2.7.6.dist-info → pygpt_net-2.7.8.dist-info}/LICENSE +0 -0
- {pygpt_net-2.7.6.dist-info → pygpt_net-2.7.8.dist-info}/WHEEL +0 -0
- {pygpt_net-2.7.6.dist-info → pygpt_net-2.7.8.dist-info}/entry_points.txt +0 -0
|
@@ -6,13 +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:
|
|
9
|
+
# Updated Date: 2026.01.04 19:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import base64
|
|
13
13
|
import datetime
|
|
14
14
|
import os
|
|
15
|
-
from typing import Optional, Dict, Any, List
|
|
15
|
+
from typing import Optional, Dict, Any, List, Iterable
|
|
16
16
|
|
|
17
17
|
import requests
|
|
18
18
|
from PySide6.QtCore import QObject, Signal, QRunnable, Slot
|
|
@@ -35,7 +35,7 @@ class Image:
|
|
|
35
35
|
sync: bool = True
|
|
36
36
|
) -> bool:
|
|
37
37
|
"""
|
|
38
|
-
Generate image(s) via xAI
|
|
38
|
+
Generate image(s) via xAI SDK image API.
|
|
39
39
|
Model: grok-2-image (or -1212 variants).
|
|
40
40
|
|
|
41
41
|
:param context: BridgeContext with prompt, model, ctx
|
|
@@ -60,7 +60,7 @@ class Image:
|
|
|
60
60
|
worker = ImageWorker()
|
|
61
61
|
worker.window = self.window
|
|
62
62
|
worker.ctx = ctx
|
|
63
|
-
worker.model = model.id or "grok-2-image"
|
|
63
|
+
worker.model = (model.id or "grok-2-image")
|
|
64
64
|
worker.input_prompt = prompt
|
|
65
65
|
worker.model_prompt = prompt_model
|
|
66
66
|
worker.system_prompt = self.window.core.prompt.get('img')
|
|
@@ -108,8 +108,10 @@ class ImageWorker(QRunnable):
|
|
|
108
108
|
self.raw = False
|
|
109
109
|
self.num = 1
|
|
110
110
|
|
|
111
|
-
#
|
|
112
|
-
|
|
111
|
+
# SDK image_format:
|
|
112
|
+
# - "base64": returns raw image bytes in SDK response (preferred for local saving)
|
|
113
|
+
# - "url": returns URL on xAI managed storage (fallback: we download)
|
|
114
|
+
self.image_format = "base64"
|
|
113
115
|
|
|
114
116
|
@Slot()
|
|
115
117
|
def run(self):
|
|
@@ -143,48 +145,35 @@ class ImageWorker(QRunnable):
|
|
|
143
145
|
|
|
144
146
|
self.signals.status.emit(trans('img.status.generating') + f": {self.input_prompt}...")
|
|
145
147
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
headers = {
|
|
153
|
-
"Authorization": f"Bearer {api_key}",
|
|
154
|
-
"Content-Type": "application/json",
|
|
155
|
-
}
|
|
156
|
-
payload = {
|
|
157
|
-
"model": self.model or "grok-2-image",
|
|
158
|
-
"prompt": self.input_prompt or "",
|
|
159
|
-
"n": max(1, min(int(self.num), 10)),
|
|
160
|
-
"response_format": "b64_json", # get base64 so we can save locally
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
r = requests.post(self.api_url, headers=headers, json=payload, timeout=180)
|
|
164
|
-
r.raise_for_status()
|
|
165
|
-
data = r.json()
|
|
166
|
-
|
|
167
|
-
images = []
|
|
168
|
-
for idx, img in enumerate((data.get("data") or [])[: self.num]):
|
|
169
|
-
b64 = img.get("b64_json")
|
|
170
|
-
if not b64:
|
|
171
|
-
# fallback: url download
|
|
172
|
-
url = img.get("url")
|
|
173
|
-
if url:
|
|
174
|
-
try:
|
|
175
|
-
rr = requests.get(url, timeout=60)
|
|
176
|
-
if rr.status_code == 200:
|
|
177
|
-
images.append(rr.content)
|
|
178
|
-
except Exception:
|
|
179
|
-
pass
|
|
180
|
-
continue
|
|
181
|
-
try:
|
|
182
|
-
images.append(base64.b64decode(b64))
|
|
183
|
-
except Exception:
|
|
184
|
-
continue
|
|
148
|
+
# use xAI SDK client
|
|
149
|
+
client = self.window.core.api.xai.get_client()
|
|
150
|
+
|
|
151
|
+
# enforce n range [1..10] as per docs
|
|
152
|
+
n = max(1, min(int(self.num or 1), 10))
|
|
185
153
|
|
|
154
|
+
images_bytes: List[bytes] = []
|
|
155
|
+
if n == 1:
|
|
156
|
+
# single image
|
|
157
|
+
resp = client.image.sample(
|
|
158
|
+
model=self.model or "grok-2-image",
|
|
159
|
+
prompt=self.input_prompt or "",
|
|
160
|
+
image_format=("base64" if self.image_format == "base64" else "url"),
|
|
161
|
+
)
|
|
162
|
+
images_bytes = self._extract_bytes_from_single(resp)
|
|
163
|
+
else:
|
|
164
|
+
# batch images
|
|
165
|
+
resp_iter = client.image.sample_batch(
|
|
166
|
+
model=self.model or "grok-2-image",
|
|
167
|
+
prompt=self.input_prompt or "",
|
|
168
|
+
n=n,
|
|
169
|
+
image_format=("base64" if self.image_format == "base64" else "url"),
|
|
170
|
+
)
|
|
171
|
+
images_bytes = self._extract_bytes_from_batch(resp_iter)
|
|
172
|
+
|
|
173
|
+
# save images to files
|
|
186
174
|
paths: List[str] = []
|
|
187
|
-
for i, content in enumerate(
|
|
175
|
+
for i, content in enumerate(images_bytes):
|
|
176
|
+
# generate filename
|
|
188
177
|
name = (
|
|
189
178
|
datetime.date.today().strftime("%Y-%m-%d") + "_" +
|
|
190
179
|
datetime.datetime.now().strftime("%H-%M-%S") + "-" +
|
|
@@ -192,7 +181,7 @@ class ImageWorker(QRunnable):
|
|
|
192
181
|
str(i + 1) + ".jpg"
|
|
193
182
|
)
|
|
194
183
|
path = os.path.join(self.window.core.config.get_user_dir("img"), name)
|
|
195
|
-
self.signals.status.emit(trans('img.status.downloading') + f" ({i + 1} / {
|
|
184
|
+
self.signals.status.emit(trans('img.status.downloading') + f" ({i + 1} / {len(images_bytes)}) -> {path}")
|
|
196
185
|
|
|
197
186
|
if self.window.core.image.save_image(path, content):
|
|
198
187
|
paths.append(path)
|
|
@@ -207,6 +196,119 @@ class ImageWorker(QRunnable):
|
|
|
207
196
|
finally:
|
|
208
197
|
self._cleanup()
|
|
209
198
|
|
|
199
|
+
# ---------- SDK response helpers ----------
|
|
200
|
+
|
|
201
|
+
def _extract_bytes_from_single(self, resp) -> List[bytes]:
|
|
202
|
+
"""
|
|
203
|
+
Normalize single-image SDK response to a list of bytes.
|
|
204
|
+
Accepts:
|
|
205
|
+
- resp.image -> bytes or base64 str (docs say raw bytes)
|
|
206
|
+
- resp.url -> download
|
|
207
|
+
- dict-like/legacy: {'b64_json': ..., 'url': ...}
|
|
208
|
+
"""
|
|
209
|
+
out: List[bytes] = []
|
|
210
|
+
try:
|
|
211
|
+
# preferred path: raw bytes when image_format="base64"
|
|
212
|
+
img_bytes = getattr(resp, "image", None)
|
|
213
|
+
if isinstance(img_bytes, (bytes, bytearray)):
|
|
214
|
+
out.append(bytes(img_bytes))
|
|
215
|
+
return out
|
|
216
|
+
if isinstance(img_bytes, str):
|
|
217
|
+
try:
|
|
218
|
+
out.append(base64.b64decode(img_bytes))
|
|
219
|
+
return out
|
|
220
|
+
except Exception:
|
|
221
|
+
pass
|
|
222
|
+
|
|
223
|
+
# url fallback
|
|
224
|
+
url = getattr(resp, "url", None)
|
|
225
|
+
if isinstance(url, str) and url:
|
|
226
|
+
try:
|
|
227
|
+
r = requests.get(url, timeout=60)
|
|
228
|
+
if r.status_code == 200:
|
|
229
|
+
out.append(r.content)
|
|
230
|
+
return out
|
|
231
|
+
except Exception:
|
|
232
|
+
pass
|
|
233
|
+
|
|
234
|
+
# dict-like fallbacks
|
|
235
|
+
if isinstance(resp, dict):
|
|
236
|
+
if "b64_json" in resp and resp["b64_json"]:
|
|
237
|
+
try:
|
|
238
|
+
out.append(base64.b64decode(resp["b64_json"]))
|
|
239
|
+
return out
|
|
240
|
+
except Exception:
|
|
241
|
+
pass
|
|
242
|
+
if "url" in resp and resp["url"]:
|
|
243
|
+
try:
|
|
244
|
+
r = requests.get(resp["url"], timeout=60)
|
|
245
|
+
if r.status_code == 200:
|
|
246
|
+
out.append(r.content)
|
|
247
|
+
return out
|
|
248
|
+
except Exception:
|
|
249
|
+
pass
|
|
250
|
+
except Exception:
|
|
251
|
+
pass
|
|
252
|
+
return out
|
|
253
|
+
|
|
254
|
+
def _extract_bytes_from_batch(self, resp_iter: Iterable) -> List[bytes]:
|
|
255
|
+
"""
|
|
256
|
+
Normalize batch SDK response (iterable of images) to a list of bytes.
|
|
257
|
+
Handles item.image (bytes/str), item.url, dict-like or bytes directly.
|
|
258
|
+
"""
|
|
259
|
+
out: List[bytes] = []
|
|
260
|
+
if resp_iter is None:
|
|
261
|
+
return out
|
|
262
|
+
try:
|
|
263
|
+
for item in resp_iter:
|
|
264
|
+
# bytes directly
|
|
265
|
+
if isinstance(item, (bytes, bytearray)):
|
|
266
|
+
out.append(bytes(item))
|
|
267
|
+
continue
|
|
268
|
+
|
|
269
|
+
# preferred: raw bytes in item.image
|
|
270
|
+
img_bytes = getattr(item, "image", None)
|
|
271
|
+
if isinstance(img_bytes, (bytes, bytearray)):
|
|
272
|
+
out.append(bytes(img_bytes))
|
|
273
|
+
continue
|
|
274
|
+
if isinstance(img_bytes, str):
|
|
275
|
+
try:
|
|
276
|
+
out.append(base64.b64decode(img_bytes))
|
|
277
|
+
continue
|
|
278
|
+
except Exception:
|
|
279
|
+
pass
|
|
280
|
+
|
|
281
|
+
# url fallback
|
|
282
|
+
url = getattr(item, "url", None)
|
|
283
|
+
if isinstance(url, str) and url:
|
|
284
|
+
try:
|
|
285
|
+
r = requests.get(url, timeout=60)
|
|
286
|
+
if r.status_code == 200:
|
|
287
|
+
out.append(r.content)
|
|
288
|
+
continue
|
|
289
|
+
except Exception:
|
|
290
|
+
pass
|
|
291
|
+
|
|
292
|
+
# dict-like fallbacks
|
|
293
|
+
if isinstance(item, dict):
|
|
294
|
+
if "b64_json" in item and item["b64_json"]:
|
|
295
|
+
try:
|
|
296
|
+
out.append(base64.b64decode(item["b64_json"]))
|
|
297
|
+
continue
|
|
298
|
+
except Exception:
|
|
299
|
+
pass
|
|
300
|
+
if "url" in item and item["url"]:
|
|
301
|
+
try:
|
|
302
|
+
r = requests.get(item["url"], timeout=60)
|
|
303
|
+
if r.status_code == 200:
|
|
304
|
+
out.append(r.content)
|
|
305
|
+
continue
|
|
306
|
+
except Exception:
|
|
307
|
+
pass
|
|
308
|
+
except Exception:
|
|
309
|
+
pass
|
|
310
|
+
return out
|
|
311
|
+
|
|
210
312
|
def _cleanup(self):
|
|
211
313
|
"""Cleanup signals to avoid multiple calls."""
|
|
212
314
|
sig = self.signals
|
|
@@ -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: 2025.08.31 23:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
from .realtime import Realtime
|