pygpt-net 2.7.7__py3-none-any.whl → 2.7.9__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 (98) hide show
  1. pygpt_net/CHANGELOG.txt +12 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +5 -1
  4. pygpt_net/controller/assistant/batch.py +2 -2
  5. pygpt_net/controller/assistant/files.py +7 -6
  6. pygpt_net/controller/assistant/threads.py +0 -0
  7. pygpt_net/controller/chat/command.py +0 -0
  8. pygpt_net/controller/dialogs/confirm.py +35 -58
  9. pygpt_net/controller/lang/mapping.py +9 -9
  10. pygpt_net/controller/realtime/realtime.py +13 -1
  11. pygpt_net/controller/remote_store/{google/batch.py → batch.py} +209 -252
  12. pygpt_net/controller/remote_store/remote_store.py +982 -13
  13. pygpt_net/core/command/command.py +0 -0
  14. pygpt_net/core/db/viewer.py +1 -1
  15. pygpt_net/core/realtime/worker.py +3 -1
  16. pygpt_net/{controller/remote_store/google → core/remote_store/anthropic}/__init__.py +0 -1
  17. pygpt_net/core/remote_store/anthropic/files.py +211 -0
  18. pygpt_net/core/remote_store/anthropic/store.py +208 -0
  19. pygpt_net/core/remote_store/openai/store.py +5 -4
  20. pygpt_net/core/remote_store/remote_store.py +5 -1
  21. pygpt_net/{controller/remote_store/openai → core/remote_store/xai}/__init__.py +0 -1
  22. pygpt_net/core/remote_store/xai/files.py +225 -0
  23. pygpt_net/core/remote_store/xai/store.py +219 -0
  24. pygpt_net/data/config/config.json +10 -6
  25. pygpt_net/data/config/models.json +38 -22
  26. pygpt_net/data/config/settings.json +54 -1
  27. pygpt_net/data/icons/folder_eye.svg +1 -0
  28. pygpt_net/data/icons/folder_eye_filled.svg +1 -0
  29. pygpt_net/data/icons/folder_open.svg +1 -0
  30. pygpt_net/data/icons/folder_open_filled.svg +1 -0
  31. pygpt_net/data/locale/locale.de.ini +4 -3
  32. pygpt_net/data/locale/locale.en.ini +14 -4
  33. pygpt_net/data/locale/locale.es.ini +4 -3
  34. pygpt_net/data/locale/locale.fr.ini +4 -3
  35. pygpt_net/data/locale/locale.it.ini +4 -3
  36. pygpt_net/data/locale/locale.pl.ini +5 -4
  37. pygpt_net/data/locale/locale.uk.ini +4 -3
  38. pygpt_net/data/locale/locale.zh.ini +4 -3
  39. pygpt_net/icons.qrc +4 -0
  40. pygpt_net/icons_rc.py +282 -138
  41. pygpt_net/provider/api/anthropic/__init__.py +2 -0
  42. pygpt_net/provider/api/anthropic/chat.py +84 -1
  43. pygpt_net/provider/api/anthropic/store.py +307 -0
  44. pygpt_net/provider/api/anthropic/stream.py +75 -0
  45. pygpt_net/provider/api/anthropic/worker/__init__.py +0 -0
  46. pygpt_net/provider/api/anthropic/worker/importer.py +278 -0
  47. pygpt_net/provider/api/google/chat.py +59 -2
  48. pygpt_net/provider/api/google/realtime/client.py +70 -24
  49. pygpt_net/provider/api/google/realtime/realtime.py +48 -12
  50. pygpt_net/provider/api/google/store.py +124 -3
  51. pygpt_net/provider/api/google/stream.py +91 -24
  52. pygpt_net/provider/api/google/worker/importer.py +16 -28
  53. pygpt_net/provider/api/openai/assistants.py +2 -2
  54. pygpt_net/provider/api/openai/realtime/realtime.py +26 -6
  55. pygpt_net/provider/api/openai/store.py +4 -1
  56. pygpt_net/provider/api/openai/worker/importer.py +19 -61
  57. pygpt_net/provider/api/openai/worker/importer_assistants.py +230 -0
  58. pygpt_net/provider/api/x_ai/__init__.py +27 -6
  59. pygpt_net/provider/api/x_ai/audio.py +43 -11
  60. pygpt_net/provider/api/x_ai/chat.py +92 -4
  61. pygpt_net/provider/api/x_ai/realtime/__init__.py +12 -0
  62. pygpt_net/provider/api/x_ai/realtime/client.py +1864 -0
  63. pygpt_net/provider/api/x_ai/realtime/realtime.py +213 -0
  64. pygpt_net/provider/api/x_ai/remote_tools.py +102 -1
  65. pygpt_net/provider/api/x_ai/store.py +610 -0
  66. pygpt_net/provider/api/x_ai/stream.py +30 -9
  67. pygpt_net/provider/api/x_ai/tools.py +51 -0
  68. pygpt_net/provider/api/x_ai/worker/importer.py +308 -0
  69. pygpt_net/provider/audio_input/xai_grok_voice.py +390 -0
  70. pygpt_net/provider/audio_output/xai_tts.py +325 -0
  71. pygpt_net/provider/core/config/patch.py +29 -3
  72. pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +2 -2
  73. pygpt_net/provider/core/model/patch.py +49 -1
  74. pygpt_net/tools/image_viewer/tool.py +334 -34
  75. pygpt_net/tools/image_viewer/ui/dialogs.py +317 -21
  76. pygpt_net/ui/dialog/assistant.py +1 -1
  77. pygpt_net/ui/dialog/plugins.py +13 -5
  78. pygpt_net/ui/dialog/remote_store.py +552 -0
  79. pygpt_net/ui/dialogs.py +3 -5
  80. pygpt_net/ui/layout/ctx/ctx_list.py +58 -7
  81. pygpt_net/ui/menu/tools.py +6 -13
  82. pygpt_net/ui/widget/dialog/{remote_store_google.py → remote_store.py} +10 -10
  83. pygpt_net/ui/widget/element/button.py +4 -4
  84. pygpt_net/ui/widget/image/display.py +2 -2
  85. pygpt_net/ui/widget/lists/context.py +2 -2
  86. {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.9.dist-info}/METADATA +14 -2
  87. {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.9.dist-info}/RECORD +87 -75
  88. pygpt_net/controller/remote_store/google/store.py +0 -615
  89. pygpt_net/controller/remote_store/openai/batch.py +0 -524
  90. pygpt_net/controller/remote_store/openai/store.py +0 -699
  91. pygpt_net/ui/dialog/remote_store_google.py +0 -539
  92. pygpt_net/ui/dialog/remote_store_openai.py +0 -539
  93. pygpt_net/ui/widget/dialog/remote_store_openai.py +0 -56
  94. pygpt_net/ui/widget/lists/remote_store_google.py +0 -248
  95. pygpt_net/ui/widget/lists/remote_store_openai.py +0 -317
  96. {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.9.dist-info}/LICENSE +0 -0
  97. {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.9.dist-info}/WHEEL +0 -0
  98. {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.9.dist-info}/entry_points.txt +0 -0
@@ -6,27 +6,59 @@
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: 2026.01.06 20:00:00 #
10
10
  # ================================================== #
11
11
 
12
- from typing import Tuple
12
+ import base64
13
+ from typing import Optional, Union, List, Dict, Any
14
+
15
+ from pygpt_net.core.bridge.context import MultimodalContext
13
16
 
14
17
 
15
18
  class Audio:
16
19
  def __init__(self, window=None):
17
20
  """
18
- Audio helpers for xAI.
19
-
20
- Note: As of now, the public xAI Python SDK does not expose TTS/STT or realtime audio APIs.
21
- This class exists to keep provider surface compatible.
21
+ Audio input wrapper
22
22
 
23
23
  :param window: Window instance
24
24
  """
25
25
  self.window = window
26
26
 
27
- # Placeholders to keep interface parity
28
- def build_part(self, multimodal_ctx) -> None:
29
- return None
27
+ def build_content(
28
+ self,
29
+ content: Optional[Union[str, list]] = None,
30
+ multimodal_ctx: Optional[MultimodalContext] = None,
31
+ ) -> List[Dict[str, Any]]:
32
+ """
33
+ Build audio content from multimodal context
34
+
35
+ :param content: previous content or input prompt
36
+ :param multimodal_ctx: multimodal context
37
+ :return: List of contents
38
+ """
39
+ if not isinstance(content, list):
40
+ if content:
41
+ content = [
42
+ {
43
+ "type": "text",
44
+ "text": str(content),
45
+ }
46
+ ]
47
+ else:
48
+ content = [] # if empty input return empty list
49
+
50
+ # abort if no audio input provided
51
+ if not multimodal_ctx.is_audio_input:
52
+ return content
30
53
 
31
- def extract_first_audio_part(self, response) -> Tuple[None, None]:
32
- return None, None
54
+ encoded = base64.b64encode(multimodal_ctx.audio_data).decode('utf-8')
55
+ audio_format = multimodal_ctx.audio_format # wav by default
56
+ audio_data = {
57
+ "type": "input_audio",
58
+ "input_audio": {
59
+ "data": encoded,
60
+ "format": audio_format,
61
+ }
62
+ }
63
+ content.append(audio_data)
64
+ return content
@@ -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: 2026.01.03 17:00:00 #
9
+ # Updated Date: 2026.01.05 20:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from __future__ import annotations
@@ -34,7 +34,6 @@ class Chat:
34
34
  """
35
35
  self.window = window
36
36
  self.input_tokens = 0
37
- # Image constraints (can be overridden by config keys below)
38
37
  self.allowed_mimes = {"image/jpeg", "image/png"}
39
38
  self.default_image_max_bytes = 10 * 1024 * 1024 # 10 MiB default
40
39
 
@@ -319,6 +318,12 @@ class Chat:
319
318
  except Exception:
320
319
  pass
321
320
 
321
+ try:
322
+ # Attempt to auto-download file parts or references (file id)
323
+ self._maybe_download_files_from_response(response, ctx)
324
+ except Exception:
325
+ pass
326
+
322
327
  # Usage
323
328
  try:
324
329
  if isinstance(response, dict) and response.get("usage"):
@@ -1089,7 +1094,7 @@ class Chat:
1089
1094
 
1090
1095
  def _collect_images_from_message_parts(self, parts: List[dict], ctx: CtxItem):
1091
1096
  """
1092
- Inspect assistant message parts for image_url outputs and store them.
1097
+ Inspect assistant message parts for image_url outputs and URLs.
1093
1098
  For http(s) URLs -> add to ctx.urls; for data URLs -> save to file and add to ctx.images.
1094
1099
  """
1095
1100
  try:
@@ -1098,6 +1103,25 @@ class Chat:
1098
1103
  for p in parts:
1099
1104
  if not isinstance(p, dict):
1100
1105
  continue
1106
+ if p.get("type") == "file":
1107
+ file_id = p.get("id") or p.get("file_id")
1108
+ if isinstance(file_id, str):
1109
+ try:
1110
+ save = self.window.core.api.xai.store.download_to_dir(file_id)
1111
+ if save:
1112
+ if not isinstance(ctx.files, list):
1113
+ ctx.files = []
1114
+ if save not in ctx.files:
1115
+ ctx.files.append(save)
1116
+ ext = os.path.splitext(save)[1].lower().lstrip(".")
1117
+ if ext in ["png", "jpg", "jpeg", "gif", "bmp", "tiff", "webp"]:
1118
+ if not isinstance(ctx.images, list):
1119
+ ctx.images = []
1120
+ if save not in ctx.images:
1121
+ ctx.images.append(save)
1122
+ except Exception:
1123
+ pass
1124
+ continue
1101
1125
  if p.get("type") != "image_url":
1102
1126
  continue
1103
1127
  img = p.get("image_url") or {}
@@ -1135,4 +1159,68 @@ class Chat:
1135
1159
  """
1136
1160
  Return the locally estimated input tokens count.
1137
1161
  """
1138
- return self.input_tokens
1162
+ return self.input_tokens
1163
+
1164
+ def _maybe_download_files_from_response(self, response, ctx: CtxItem) -> None:
1165
+ """
1166
+ Attempt to download any files referenced by id in response payloads (dict/SDK/proto).
1167
+ """
1168
+ def _walk(o, acc: set):
1169
+ if o is None:
1170
+ return
1171
+ if isinstance(o, dict):
1172
+ fid = o.get("file_id") or o.get("id") if o.get("type") == "file" else None
1173
+ if isinstance(fid, str) and fid.startswith("file-"):
1174
+ acc.add(fid)
1175
+ for v in o.values():
1176
+ _walk(v, acc)
1177
+ elif isinstance(o, (list, tuple)):
1178
+ for it in o:
1179
+ _walk(it, acc)
1180
+
1181
+ ids = set()
1182
+ try:
1183
+ if isinstance(response, dict):
1184
+ _walk(response, ids)
1185
+ else:
1186
+ msg = getattr(response, "message", None) or getattr(response, "output_message", None)
1187
+ if msg:
1188
+ _walk(getattr(msg, "content", None), ids)
1189
+ proto = getattr(response, "proto", None)
1190
+ if proto:
1191
+ ch = getattr(proto, "choices", None) or []
1192
+ if ch:
1193
+ m = getattr(ch[0], "message", None)
1194
+ if m:
1195
+ _walk(getattr(m, "content", None), ids)
1196
+ except Exception:
1197
+ pass
1198
+
1199
+ if not ids:
1200
+ return
1201
+ saved = []
1202
+ for fid in ids:
1203
+ try:
1204
+ p = self.window.core.api.xai.store.download_to_dir(fid)
1205
+ if p:
1206
+ saved.append(p)
1207
+ except Exception:
1208
+ continue
1209
+ if saved:
1210
+ saved = self.window.core.filesystem.make_local_list(saved)
1211
+ if not isinstance(ctx.files, list):
1212
+ ctx.files = []
1213
+ for p in saved:
1214
+ if p not in ctx.files:
1215
+ ctx.files.append(p)
1216
+ imgs = []
1217
+ for p in saved:
1218
+ ext = os.path.splitext(p)[1].lower().lstrip(".")
1219
+ if ext in ["png", "jpg", "jpeg", "gif", "bmp", "tiff", "webp"]:
1220
+ imgs.append(p)
1221
+ if imgs:
1222
+ if not isinstance(ctx.images, list):
1223
+ ctx.images = []
1224
+ for p in imgs:
1225
+ if p not in ctx.images:
1226
+ ctx.images.append(p)
@@ -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