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.
- pygpt_net/CHANGELOG.txt +12 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/chat/handler/anthropic_stream.py +164 -0
- pygpt_net/controller/chat/handler/google_stream.py +181 -0
- pygpt_net/controller/chat/handler/langchain_stream.py +24 -0
- pygpt_net/controller/chat/handler/llamaindex_stream.py +47 -0
- pygpt_net/controller/chat/handler/openai_stream.py +260 -0
- pygpt_net/controller/chat/handler/utils.py +210 -0
- pygpt_net/controller/chat/handler/worker.py +570 -0
- pygpt_net/controller/chat/handler/xai_stream.py +135 -0
- pygpt_net/controller/chat/stream.py +1 -1
- pygpt_net/controller/ctx/ctx.py +1 -1
- pygpt_net/controller/debug/debug.py +6 -6
- pygpt_net/controller/model/editor.py +3 -0
- pygpt_net/controller/model/importer.py +9 -2
- pygpt_net/controller/plugins/plugins.py +11 -3
- pygpt_net/controller/presets/presets.py +2 -2
- pygpt_net/core/bridge/context.py +35 -35
- pygpt_net/core/bridge/worker.py +40 -16
- pygpt_net/core/ctx/bag.py +7 -2
- pygpt_net/core/ctx/reply.py +17 -2
- pygpt_net/core/db/viewer.py +19 -34
- pygpt_net/core/render/plain/pid.py +12 -1
- pygpt_net/core/render/web/body.py +30 -39
- pygpt_net/core/tabs/tab.py +24 -1
- pygpt_net/data/config/config.json +10 -3
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/settings.json +105 -0
- pygpt_net/data/css/style.dark.css +2 -3
- pygpt_net/data/css/style.light.css +2 -3
- pygpt_net/data/locale/locale.de.ini +3 -1
- pygpt_net/data/locale/locale.en.ini +19 -1
- pygpt_net/data/locale/locale.es.ini +3 -1
- pygpt_net/data/locale/locale.fr.ini +3 -1
- pygpt_net/data/locale/locale.it.ini +3 -1
- pygpt_net/data/locale/locale.pl.ini +4 -2
- pygpt_net/data/locale/locale.uk.ini +3 -1
- pygpt_net/data/locale/locale.zh.ini +3 -1
- pygpt_net/item/assistant.py +51 -2
- pygpt_net/item/attachment.py +21 -20
- pygpt_net/item/calendar_note.py +19 -2
- pygpt_net/item/ctx.py +115 -2
- pygpt_net/item/index.py +9 -2
- pygpt_net/item/mode.py +9 -6
- pygpt_net/item/model.py +20 -3
- pygpt_net/item/notepad.py +14 -2
- pygpt_net/item/preset.py +42 -2
- pygpt_net/item/prompt.py +8 -2
- pygpt_net/plugin/cmd_files/plugin.py +2 -2
- pygpt_net/provider/api/__init__.py +5 -3
- pygpt_net/provider/api/anthropic/__init__.py +190 -29
- pygpt_net/provider/api/anthropic/audio.py +30 -0
- pygpt_net/provider/api/anthropic/chat.py +341 -0
- pygpt_net/provider/api/anthropic/image.py +25 -0
- pygpt_net/provider/api/anthropic/tools.py +266 -0
- pygpt_net/provider/api/anthropic/vision.py +142 -0
- pygpt_net/provider/api/google/chat.py +2 -2
- pygpt_net/provider/api/google/realtime/client.py +2 -2
- pygpt_net/provider/api/google/tools.py +58 -48
- pygpt_net/provider/api/google/vision.py +7 -1
- pygpt_net/provider/api/openai/chat.py +1 -0
- pygpt_net/provider/api/openai/vision.py +6 -0
- pygpt_net/provider/api/x_ai/__init__.py +247 -0
- pygpt_net/provider/api/x_ai/audio.py +32 -0
- pygpt_net/provider/api/x_ai/chat.py +968 -0
- pygpt_net/provider/api/x_ai/image.py +208 -0
- pygpt_net/provider/api/x_ai/remote.py +262 -0
- pygpt_net/provider/api/x_ai/tools.py +120 -0
- pygpt_net/provider/api/x_ai/vision.py +119 -0
- pygpt_net/provider/core/attachment/json_file.py +2 -2
- pygpt_net/provider/core/config/patch.py +28 -0
- pygpt_net/provider/llms/anthropic.py +4 -2
- pygpt_net/tools/text_editor/tool.py +4 -1
- pygpt_net/tools/text_editor/ui/dialogs.py +1 -1
- pygpt_net/ui/base/config_dialog.py +5 -11
- pygpt_net/ui/dialog/db.py +177 -59
- pygpt_net/ui/dialog/dictionary.py +57 -59
- pygpt_net/ui/dialog/editor.py +3 -2
- pygpt_net/ui/dialog/image.py +1 -1
- pygpt_net/ui/dialog/logger.py +3 -2
- pygpt_net/ui/dialog/models.py +16 -16
- pygpt_net/ui/dialog/plugins.py +63 -60
- pygpt_net/ui/layout/ctx/ctx_list.py +3 -4
- pygpt_net/ui/layout/toolbox/__init__.py +2 -2
- pygpt_net/ui/layout/toolbox/assistants.py +8 -9
- pygpt_net/ui/layout/toolbox/presets.py +2 -2
- pygpt_net/ui/main.py +9 -4
- pygpt_net/ui/widget/element/labels.py +20 -4
- pygpt_net/ui/widget/textarea/editor.py +0 -4
- pygpt_net/ui/widget/textarea/web.py +1 -1
- {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/METADATA +18 -6
- {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/RECORD +95 -76
- pygpt_net/controller/chat/handler/stream_worker.py +0 -1136
- {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.36.dist-info → pygpt_net-2.6.38.dist-info}/WHEEL +0 -0
- {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
|