pygpt-net 2.6.36__py3-none-any.whl → 2.6.38__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 (96) hide show
  1. pygpt_net/CHANGELOG.txt +12 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/controller/chat/handler/anthropic_stream.py +164 -0
  4. pygpt_net/controller/chat/handler/google_stream.py +181 -0
  5. pygpt_net/controller/chat/handler/langchain_stream.py +24 -0
  6. pygpt_net/controller/chat/handler/llamaindex_stream.py +47 -0
  7. pygpt_net/controller/chat/handler/openai_stream.py +260 -0
  8. pygpt_net/controller/chat/handler/utils.py +210 -0
  9. pygpt_net/controller/chat/handler/worker.py +570 -0
  10. pygpt_net/controller/chat/handler/xai_stream.py +135 -0
  11. pygpt_net/controller/chat/stream.py +1 -1
  12. pygpt_net/controller/ctx/ctx.py +1 -1
  13. pygpt_net/controller/debug/debug.py +6 -6
  14. pygpt_net/controller/model/editor.py +3 -0
  15. pygpt_net/controller/model/importer.py +9 -2
  16. pygpt_net/controller/plugins/plugins.py +11 -3
  17. pygpt_net/controller/presets/presets.py +2 -2
  18. pygpt_net/core/bridge/context.py +35 -35
  19. pygpt_net/core/bridge/worker.py +40 -16
  20. pygpt_net/core/ctx/bag.py +7 -2
  21. pygpt_net/core/ctx/reply.py +17 -2
  22. pygpt_net/core/db/viewer.py +19 -34
  23. pygpt_net/core/render/plain/pid.py +12 -1
  24. pygpt_net/core/render/web/body.py +30 -39
  25. pygpt_net/core/tabs/tab.py +24 -1
  26. pygpt_net/data/config/config.json +10 -3
  27. pygpt_net/data/config/models.json +3 -3
  28. pygpt_net/data/config/settings.json +105 -0
  29. pygpt_net/data/css/style.dark.css +2 -3
  30. pygpt_net/data/css/style.light.css +2 -3
  31. pygpt_net/data/locale/locale.de.ini +3 -1
  32. pygpt_net/data/locale/locale.en.ini +19 -1
  33. pygpt_net/data/locale/locale.es.ini +3 -1
  34. pygpt_net/data/locale/locale.fr.ini +3 -1
  35. pygpt_net/data/locale/locale.it.ini +3 -1
  36. pygpt_net/data/locale/locale.pl.ini +4 -2
  37. pygpt_net/data/locale/locale.uk.ini +3 -1
  38. pygpt_net/data/locale/locale.zh.ini +3 -1
  39. pygpt_net/item/assistant.py +51 -2
  40. pygpt_net/item/attachment.py +21 -20
  41. pygpt_net/item/calendar_note.py +19 -2
  42. pygpt_net/item/ctx.py +115 -2
  43. pygpt_net/item/index.py +9 -2
  44. pygpt_net/item/mode.py +9 -6
  45. pygpt_net/item/model.py +20 -3
  46. pygpt_net/item/notepad.py +14 -2
  47. pygpt_net/item/preset.py +42 -2
  48. pygpt_net/item/prompt.py +8 -2
  49. pygpt_net/plugin/cmd_files/plugin.py +2 -2
  50. pygpt_net/provider/api/__init__.py +5 -3
  51. pygpt_net/provider/api/anthropic/__init__.py +190 -29
  52. pygpt_net/provider/api/anthropic/audio.py +30 -0
  53. pygpt_net/provider/api/anthropic/chat.py +341 -0
  54. pygpt_net/provider/api/anthropic/image.py +25 -0
  55. pygpt_net/provider/api/anthropic/tools.py +266 -0
  56. pygpt_net/provider/api/anthropic/vision.py +142 -0
  57. pygpt_net/provider/api/google/chat.py +2 -2
  58. pygpt_net/provider/api/google/realtime/client.py +2 -2
  59. pygpt_net/provider/api/google/tools.py +58 -48
  60. pygpt_net/provider/api/google/vision.py +7 -1
  61. pygpt_net/provider/api/openai/chat.py +1 -0
  62. pygpt_net/provider/api/openai/vision.py +6 -0
  63. pygpt_net/provider/api/x_ai/__init__.py +247 -0
  64. pygpt_net/provider/api/x_ai/audio.py +32 -0
  65. pygpt_net/provider/api/x_ai/chat.py +968 -0
  66. pygpt_net/provider/api/x_ai/image.py +208 -0
  67. pygpt_net/provider/api/x_ai/remote.py +262 -0
  68. pygpt_net/provider/api/x_ai/tools.py +120 -0
  69. pygpt_net/provider/api/x_ai/vision.py +119 -0
  70. pygpt_net/provider/core/attachment/json_file.py +2 -2
  71. pygpt_net/provider/core/config/patch.py +28 -0
  72. pygpt_net/provider/llms/anthropic.py +4 -2
  73. pygpt_net/tools/text_editor/tool.py +4 -1
  74. pygpt_net/tools/text_editor/ui/dialogs.py +1 -1
  75. pygpt_net/ui/base/config_dialog.py +5 -11
  76. pygpt_net/ui/dialog/db.py +177 -59
  77. pygpt_net/ui/dialog/dictionary.py +57 -59
  78. pygpt_net/ui/dialog/editor.py +3 -2
  79. pygpt_net/ui/dialog/image.py +1 -1
  80. pygpt_net/ui/dialog/logger.py +3 -2
  81. pygpt_net/ui/dialog/models.py +16 -16
  82. pygpt_net/ui/dialog/plugins.py +63 -60
  83. pygpt_net/ui/layout/ctx/ctx_list.py +3 -4
  84. pygpt_net/ui/layout/toolbox/__init__.py +2 -2
  85. pygpt_net/ui/layout/toolbox/assistants.py +8 -9
  86. pygpt_net/ui/layout/toolbox/presets.py +2 -2
  87. pygpt_net/ui/main.py +9 -4
  88. pygpt_net/ui/widget/element/labels.py +20 -4
  89. pygpt_net/ui/widget/textarea/editor.py +0 -4
  90. pygpt_net/ui/widget/textarea/web.py +1 -1
  91. {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/METADATA +18 -6
  92. {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/RECORD +95 -76
  93. pygpt_net/controller/chat/handler/stream_worker.py +0 -1136
  94. {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/LICENSE +0 -0
  95. {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/WHEEL +0 -0
  96. {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,247 @@
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.09.05 01:00:00 #
10
+ # ================================================== #
11
+
12
+ from typing import Optional, Dict, Any
13
+
14
+ import os
15
+ import json
16
+
17
+ from pygpt_net.core.types import (
18
+ MODE_ASSISTANT,
19
+ MODE_AUDIO,
20
+ MODE_CHAT,
21
+ MODE_COMPLETION,
22
+ MODE_IMAGE,
23
+ MODE_RESEARCH,
24
+ )
25
+ from pygpt_net.core.bridge.context import BridgeContext
26
+ from pygpt_net.item.model import ModelItem
27
+
28
+ import xai_sdk
29
+
30
+ from .chat import Chat
31
+ from .vision import Vision
32
+ from .tools import Tools
33
+ from .audio import Audio
34
+ from .image import Image
35
+ from .remote import Remote
36
+
37
+
38
+ class ApiXAI:
39
+ def __init__(self, window=None):
40
+ """
41
+ xAI (Grok) Python SDK wrapper.
42
+
43
+ :param window: Window instance
44
+ """
45
+ self.window = window
46
+ self.chat = Chat(window)
47
+ self.vision = Vision(window)
48
+ self.tools = Tools(window)
49
+ self.audio = Audio(window)
50
+ self.image = Image(window)
51
+ self.remote = Remote(window) # Live Search builder
52
+ self.client: Optional[xai_sdk.Client] = None
53
+ self.locked = False
54
+ self.last_client_args: Optional[Dict[str, Any]] = None
55
+
56
+ def get_client(
57
+ self,
58
+ mode: str = MODE_CHAT,
59
+ model: ModelItem = None
60
+ ) -> xai_sdk.Client:
61
+ """
62
+ Get or create xAI client.
63
+
64
+ - Reads api_key from config or XAI_API_KEY env.
65
+ - Caches the client instance.
66
+
67
+ :param mode: One of MODE_*
68
+ :param model: ModelItem (optional, not used currently)
69
+ :return: xai_sdk.Client
70
+ """
71
+ if self.client is not None:
72
+ return self.client
73
+
74
+ cfg = self.window.core.config
75
+ api_key = cfg.get("api_key_xai") or os.environ.get("XAI_API_KEY") or ""
76
+ timeout = cfg.get("api_native_xai.timeout") # optional
77
+
78
+ kwargs: Dict[str, Any] = {}
79
+ if api_key:
80
+ kwargs["api_key"] = api_key
81
+ if timeout is not None:
82
+ # Official SDK supports setting a global timeout on client init.
83
+ kwargs["timeout"] = timeout
84
+
85
+ self.client = xai_sdk.Client(**kwargs)
86
+ return self.client
87
+
88
+ def call(
89
+ self,
90
+ context: BridgeContext,
91
+ extra: dict = None,
92
+ rt_signals=None
93
+ ) -> bool:
94
+ """
95
+ Make an API call to xAI.
96
+
97
+ Supports chat (stream/non-stream), images (via REST),
98
+ and function-calling. Audio is not available in public xAI SDK at this time.
99
+
100
+ :param context: BridgeContext
101
+ :param extra: Extra params (not used)
102
+ :param rt_signals: Realtime signals (not used)
103
+ :return: True on success, False on error
104
+ """
105
+ mode = context.mode
106
+ model = context.model
107
+ stream = context.stream
108
+ ctx = context.ctx
109
+ ai_name = (ctx.output_name if ctx else "assistant")
110
+
111
+ # No Responses API in xAI SDK
112
+ if ctx:
113
+ ctx.use_responses_api = False
114
+
115
+ used_tokens = 0
116
+ response = None
117
+
118
+ if mode in (MODE_COMPLETION, MODE_CHAT, MODE_AUDIO, MODE_RESEARCH):
119
+ # There is no public realtime audio in SDK; treat MODE_AUDIO as chat (TTS not supported).
120
+ response = self.chat.send(context=context, extra=extra)
121
+ used_tokens = self.chat.get_used_tokens()
122
+ if ctx:
123
+ self.vision.append_images(ctx)
124
+
125
+ elif mode == MODE_IMAGE:
126
+ # Image generation via REST /v1/images/generations (OpenAI-compatible)
127
+ return self.image.generate(context=context, extra=extra)
128
+
129
+ elif mode == MODE_ASSISTANT:
130
+ return False # not implemented for xAI
131
+
132
+ if stream:
133
+ if ctx:
134
+ ctx.stream = response
135
+ ctx.set_output("", ai_name)
136
+ ctx.input_tokens = used_tokens
137
+ return True
138
+
139
+ if response is None:
140
+ return False
141
+
142
+ if isinstance(response, dict) and "error" in response:
143
+ return False
144
+
145
+ if ctx:
146
+ ctx.ai_name = ai_name
147
+ self.chat.unpack_response(context.mode, response, ctx)
148
+ try:
149
+ for tc in getattr(ctx, "tool_calls", []) or []:
150
+ fn = tc.get("function") or {}
151
+ args = fn.get("arguments")
152
+ if isinstance(args, str):
153
+ try:
154
+ fn["arguments"] = json.loads(args)
155
+ except Exception:
156
+ fn["arguments"] = {}
157
+ except Exception:
158
+ pass
159
+ return True
160
+
161
+ def quick_call(
162
+ self,
163
+ context: BridgeContext,
164
+ extra: dict = None
165
+ ) -> str:
166
+ """
167
+ Quick non-streaming xAI chat call and return output text.
168
+
169
+ If context.request is set, makes a full call() instead (for consistency).
170
+
171
+ :param context: BridgeContext
172
+ :param extra: Extra params (not used)
173
+ :return: Output text or "" on error
174
+ """
175
+ if context.request:
176
+ context.stream = False
177
+ context.mode = MODE_CHAT
178
+ self.locked = True
179
+ self.call(context, extra)
180
+ self.locked = False
181
+ return context.ctx.output
182
+
183
+ self.locked = True
184
+ try:
185
+ ctx = context.ctx
186
+ prompt = context.prompt
187
+ system_prompt = context.system_prompt
188
+ temperature = context.temperature
189
+ history = context.history
190
+ functions = context.external_functions
191
+ model = context.model or self.window.core.models.from_defaults()
192
+
193
+ tools = self.tools.prepare(functions)
194
+
195
+ # If tools are present, prefer non-streaming HTTP Chat Completions path to extract tool calls reliably.
196
+ # Otherwise use native SDK chat.sample().
197
+ if tools:
198
+ out, calls, citations, usage = self.chat.call_http_nonstream(
199
+ model=model.id,
200
+ prompt=prompt,
201
+ system_prompt=system_prompt,
202
+ history=history,
203
+ attachments=context.attachments,
204
+ multimodal_ctx=context.multimodal_ctx,
205
+ tools=tools,
206
+ temperature=temperature,
207
+ max_tokens=context.max_tokens,
208
+ )
209
+ if ctx:
210
+ if calls:
211
+ ctx.tool_calls = calls
212
+ return out or ""
213
+
214
+ # Native SDK path (no tools)
215
+ client = self.get_client(MODE_CHAT, model)
216
+ messages = self.chat.build_messages(
217
+ prompt=prompt,
218
+ system_prompt=system_prompt,
219
+ model=model,
220
+ history=history,
221
+ attachments=context.attachments,
222
+ multimodal_ctx=context.multimodal_ctx,
223
+ )
224
+ chat = client.chat.create(model=model.id, messages=messages)
225
+ resp = chat.sample()
226
+ return getattr(resp, "content", "") or ""
227
+ except Exception as e:
228
+ self.window.core.debug.log(e)
229
+ return ""
230
+ finally:
231
+ self.locked = False
232
+
233
+ def stop(self):
234
+ """On global event stop."""
235
+ pass
236
+
237
+ def close(self):
238
+ """Close xAI client."""
239
+ if self.locked:
240
+ return
241
+ self.client = None # xai-sdk gRPC channels close on GC; explicit close not exposed.
242
+
243
+ def safe_close(self):
244
+ """Close client."""
245
+ if self.locked:
246
+ return
247
+ self.client = None
@@ -0,0 +1,32 @@
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.09.05 01:00:00 #
10
+ # ================================================== #
11
+
12
+ from typing import Tuple
13
+
14
+
15
+ class Audio:
16
+ def __init__(self, window=None):
17
+ """
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.
22
+
23
+ :param window: Window instance
24
+ """
25
+ self.window = window
26
+
27
+ # Placeholders to keep interface parity
28
+ def build_part(self, multimodal_ctx) -> None:
29
+ return None
30
+
31
+ def extract_first_audio_part(self, response) -> Tuple[None, None]:
32
+ return None, None