pygpt-net 2.7.7__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 +7 -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/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/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 +9 -6
- pygpt_net/data/config/models.json +5 -4
- pygpt_net/data/config/settings.json +54 -1
- 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 +4 -3
- pygpt_net/data/locale/locale.en.ini +14 -4
- pygpt_net/data/locale/locale.es.ini +4 -3
- pygpt_net/data/locale/locale.fr.ini +4 -3
- pygpt_net/data/locale/locale.it.ini +4 -3
- pygpt_net/data/locale/locale.pl.ini +5 -4
- pygpt_net/data/locale/locale.uk.ini +4 -3
- pygpt_net/data/locale/locale.zh.ini +4 -3
- pygpt_net/icons.qrc +4 -0
- pygpt_net/icons_rc.py +282 -138
- pygpt_net/provider/api/anthropic/__init__.py +2 -0
- pygpt_net/provider/api/anthropic/chat.py +84 -1
- pygpt_net/provider/api/anthropic/store.py +307 -0
- pygpt_net/provider/api/anthropic/stream.py +75 -0
- pygpt_net/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 +59 -2
- pygpt_net/provider/api/google/store.py +124 -3
- pygpt_net/provider/api/google/stream.py +91 -24
- pygpt_net/provider/api/google/worker/importer.py +16 -28
- pygpt_net/provider/api/openai/assistants.py +2 -2
- pygpt_net/provider/api/openai/store.py +4 -1
- 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 +30 -6
- 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/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_tools.py +19 -1
- pygpt_net/provider/api/x_ai/store.py +610 -0
- pygpt_net/provider/api/x_ai/stream.py +30 -9
- 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 +18 -3
- pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +2 -2
- pygpt_net/provider/core/model/patch.py +13 -0
- pygpt_net/tools/image_viewer/tool.py +334 -34
- pygpt_net/tools/image_viewer/ui/dialogs.py +317 -21
- 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/{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-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/METADATA +9 -2
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/RECORD +82 -70
- 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.7.dist-info → pygpt_net-2.7.8.dist-info}/LICENSE +0 -0
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/WHEEL +0 -0
- {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,198 @@
|
|
|
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: 2026.01.06 20:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
from typing import Optional, Dict, Any
|
|
14
|
+
|
|
15
|
+
from pygpt_net.core.bridge import BridgeContext
|
|
16
|
+
from pygpt_net.core.events import RealtimeEvent
|
|
17
|
+
from pygpt_net.core.realtime.options import RealtimeOptions
|
|
18
|
+
from pygpt_net.core.realtime.shared.session import extract_last_session_id
|
|
19
|
+
from pygpt_net.item.model import ModelItem
|
|
20
|
+
from pygpt_net.utils import trans
|
|
21
|
+
|
|
22
|
+
from .client import xAIIRealtimeClient
|
|
23
|
+
|
|
24
|
+
class Realtime:
|
|
25
|
+
|
|
26
|
+
PROVIDER = "x_ai"
|
|
27
|
+
|
|
28
|
+
def __init__(self, window=None):
|
|
29
|
+
"""
|
|
30
|
+
OpenAI API realtime controller
|
|
31
|
+
|
|
32
|
+
:param window: Window instance
|
|
33
|
+
"""
|
|
34
|
+
self.window = window
|
|
35
|
+
self.handler = xAIIRealtimeClient(window)
|
|
36
|
+
self.prev_auto_turn = False
|
|
37
|
+
self.prev_vad_silence = 2000
|
|
38
|
+
self.prev_vad_prefix = 300
|
|
39
|
+
|
|
40
|
+
def begin(
|
|
41
|
+
self,
|
|
42
|
+
context: BridgeContext,
|
|
43
|
+
model: Optional[ModelItem] = None,
|
|
44
|
+
extra: Optional[Dict[str, Any]] = None,
|
|
45
|
+
rt_signals=None
|
|
46
|
+
) -> bool:
|
|
47
|
+
"""
|
|
48
|
+
Begin realtime session if applicable
|
|
49
|
+
|
|
50
|
+
:param context: BridgeContext
|
|
51
|
+
:param model: Optional[ModelItem]
|
|
52
|
+
:param extra: Optional dict with extra parameters
|
|
53
|
+
:param rt_signals: RealtimeSignals
|
|
54
|
+
:return: True if realtime session started, False otherwise
|
|
55
|
+
"""
|
|
56
|
+
mm = context.multimodal_ctx
|
|
57
|
+
audio_bytes = getattr(mm, "audio_data", None) if mm and getattr(mm, "is_audio_input", False) else None
|
|
58
|
+
audio_format = getattr(mm, "audio_format", None) if mm else None
|
|
59
|
+
audio_rate = getattr(mm, "audio_rate", None) if mm else None
|
|
60
|
+
is_debug = self.window.core.config.get("log.realtime", False)
|
|
61
|
+
auto_turn = self.window.core.config.get("audio.input.auto_turn", True)
|
|
62
|
+
opt_vad_silence = self.window.core.config.get("audio.input.vad.silence", 2000)
|
|
63
|
+
opt_vad_prefix = self.window.core.config.get("audio.input.vad.prefix", 300)
|
|
64
|
+
|
|
65
|
+
# setup manager
|
|
66
|
+
self.window.controller.realtime.set_current_active(self.PROVIDER)
|
|
67
|
+
self.window.controller.realtime.set_busy()
|
|
68
|
+
self.handler.set_debug(is_debug)
|
|
69
|
+
|
|
70
|
+
# tools
|
|
71
|
+
tools = []
|
|
72
|
+
'''
|
|
73
|
+
tools = self.window.core.api.xai.tools.prepare(model, context.external_functions)
|
|
74
|
+
'''
|
|
75
|
+
|
|
76
|
+
# remote tools
|
|
77
|
+
remote_tools = []
|
|
78
|
+
'''
|
|
79
|
+
remote_tools = self.window.core.api.openai.remote_tools.append_to_tools(
|
|
80
|
+
mode=context.mode,
|
|
81
|
+
model=model,
|
|
82
|
+
stream=context.stream,
|
|
83
|
+
is_expert_call=context.is_expert_call,
|
|
84
|
+
tools=remote_tools,
|
|
85
|
+
preset=context.preset,
|
|
86
|
+
)
|
|
87
|
+
'''
|
|
88
|
+
|
|
89
|
+
# handle sub-reply (tool results from tool calls)
|
|
90
|
+
if context.ctx.internal:
|
|
91
|
+
if context.ctx.prev_ctx and context.ctx.prev_ctx.extra.get("prev_tool_calls"):
|
|
92
|
+
tool_calls = context.ctx.prev_ctx.extra.get("prev_tool_calls", [])
|
|
93
|
+
tool_call_id = None
|
|
94
|
+
if isinstance(tool_calls, list) and len(tool_calls) > 0:
|
|
95
|
+
tool_call_id = tool_calls[0].get("call_id", "") # get first call_id
|
|
96
|
+
if not tool_call_id:
|
|
97
|
+
tool_call_id = tool_calls[0].get("id", "") # fallback to id
|
|
98
|
+
if tool_call_id:
|
|
99
|
+
tool_results = context.ctx.input
|
|
100
|
+
try:
|
|
101
|
+
tool_results = json.loads(tool_results)
|
|
102
|
+
except Exception:
|
|
103
|
+
pass
|
|
104
|
+
self.handler.send_tool_results_sync({
|
|
105
|
+
tool_call_id: tool_results
|
|
106
|
+
})
|
|
107
|
+
self.handler.update_ctx(context.ctx)
|
|
108
|
+
return True # do not start new session, just send tool results
|
|
109
|
+
|
|
110
|
+
# update auto-turn in active session
|
|
111
|
+
if (self.handler.is_session_active()
|
|
112
|
+
and (auto_turn != self.prev_auto_turn
|
|
113
|
+
or opt_vad_silence != self.prev_vad_silence
|
|
114
|
+
or opt_vad_prefix != self.prev_vad_prefix)):
|
|
115
|
+
self.handler.update_session_autoturn_sync(auto_turn, opt_vad_silence, opt_vad_prefix)
|
|
116
|
+
|
|
117
|
+
# if auto-turn is enabled and prompt is empty, update session and context only
|
|
118
|
+
if auto_turn and self.handler.is_session_active() and (context.prompt.strip() == "" or context.prompt == "..."):
|
|
119
|
+
self.handler.update_session_tools_sync(tools, remote_tools)
|
|
120
|
+
self.handler.update_ctx(context.ctx)
|
|
121
|
+
self.window.update_status(trans("speech.listening"))
|
|
122
|
+
return True # do not send new request if session is active
|
|
123
|
+
|
|
124
|
+
# Last session ID
|
|
125
|
+
last_session_id = extract_last_session_id(context.history)
|
|
126
|
+
if is_debug:
|
|
127
|
+
print("[realtime session] Last ID", last_session_id)
|
|
128
|
+
|
|
129
|
+
# Voice
|
|
130
|
+
voice = "ara"
|
|
131
|
+
try:
|
|
132
|
+
v = self.window.core.plugins.get_option("audio_output", "xai_tts_voice")
|
|
133
|
+
if v:
|
|
134
|
+
voice = str(v)
|
|
135
|
+
except Exception:
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
# Options
|
|
139
|
+
opts = RealtimeOptions(
|
|
140
|
+
provider=self.PROVIDER,
|
|
141
|
+
model=context.model.id,
|
|
142
|
+
system_prompt=context.system_prompt,
|
|
143
|
+
prompt=context.prompt,
|
|
144
|
+
voice=voice,
|
|
145
|
+
audio_data=audio_bytes,
|
|
146
|
+
audio_format=audio_format,
|
|
147
|
+
audio_rate=audio_rate,
|
|
148
|
+
vad="server_vad",
|
|
149
|
+
extra=extra or {},
|
|
150
|
+
tools=tools,
|
|
151
|
+
remote_tools=remote_tools,
|
|
152
|
+
rt_signals=rt_signals,
|
|
153
|
+
rt_session_id=last_session_id,
|
|
154
|
+
auto_turn=auto_turn,
|
|
155
|
+
vad_end_silence_ms=opt_vad_silence,
|
|
156
|
+
vad_prefix_padding_ms=opt_vad_prefix,
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Start or append to realtime session via manager
|
|
160
|
+
try:
|
|
161
|
+
if is_debug:
|
|
162
|
+
print("[realtime] Starting session with options:", opts.to_dict())
|
|
163
|
+
rt = self.window.controller.realtime.manager
|
|
164
|
+
rt.start(context.ctx, opts)
|
|
165
|
+
|
|
166
|
+
self.prev_auto_turn = auto_turn
|
|
167
|
+
self.prev_vad_silence = opt_vad_silence
|
|
168
|
+
self.prev_vad_prefix = opt_vad_prefix
|
|
169
|
+
return True
|
|
170
|
+
except Exception as e:
|
|
171
|
+
self.window.core.debug.log(e)
|
|
172
|
+
return False # fallback to non-live path
|
|
173
|
+
|
|
174
|
+
def handle_audio_input(self, event: RealtimeEvent):
|
|
175
|
+
"""
|
|
176
|
+
Handle Realtime audio input event
|
|
177
|
+
|
|
178
|
+
:param event: RealtimeEvent
|
|
179
|
+
"""
|
|
180
|
+
self.handler.rt_handle_audio_input_sync(event)
|
|
181
|
+
|
|
182
|
+
def manual_commit(self):
|
|
183
|
+
"""Manually commit audio input to realtime session"""
|
|
184
|
+
self.handler.force_response_now_sync()
|
|
185
|
+
|
|
186
|
+
def shutdown(self):
|
|
187
|
+
"""Shutdown realtime loops"""
|
|
188
|
+
if self.handler.is_session_active():
|
|
189
|
+
self.handler.close_session_sync()
|
|
190
|
+
try:
|
|
191
|
+
self.handler.stop_loop_sync()
|
|
192
|
+
except Exception:
|
|
193
|
+
pass
|
|
194
|
+
|
|
195
|
+
def reset(self):
|
|
196
|
+
"""Close realtime session"""
|
|
197
|
+
if self.handler.is_session_active():
|
|
198
|
+
self.handler.close_session_sync()
|
|
@@ -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.
|
|
9
|
+
# Updated Date: 2026.01.06 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
@@ -22,6 +22,7 @@ try:
|
|
|
22
22
|
from xai_sdk.tools import x_search as x_x_search
|
|
23
23
|
from xai_sdk.tools import code_execution as x_code_execution
|
|
24
24
|
from xai_sdk.tools import mcp as x_mcp
|
|
25
|
+
from xai_sdk.tools import collections_search as x_collections_search
|
|
25
26
|
except Exception:
|
|
26
27
|
x_web_search = None
|
|
27
28
|
x_x_search = None
|
|
@@ -169,6 +170,23 @@ class Remote:
|
|
|
169
170
|
except Exception:
|
|
170
171
|
pass
|
|
171
172
|
|
|
173
|
+
# COLLECTIONS SEARCH
|
|
174
|
+
is_collections_enabled = bool(cfg.get("remote_tools.xai.collections", False))
|
|
175
|
+
ids = cfg.get("remote_tools.xai.collections.args", "")
|
|
176
|
+
ids_list = []
|
|
177
|
+
if ids:
|
|
178
|
+
try:
|
|
179
|
+
ids_list = [s.strip() for s in ids.split(",") if s.strip()]
|
|
180
|
+
except Exception:
|
|
181
|
+
pass
|
|
182
|
+
if is_collections_enabled and ids_list:
|
|
183
|
+
try:
|
|
184
|
+
tools.append(x_collections_search(
|
|
185
|
+
collection_ids=ids_list
|
|
186
|
+
))
|
|
187
|
+
except Exception:
|
|
188
|
+
pass
|
|
189
|
+
|
|
172
190
|
return {
|
|
173
191
|
"tools": tools,
|
|
174
192
|
"include": include,
|