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.
Files changed (93) hide show
  1. pygpt_net/CHANGELOG.txt +7 -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/remote_store/{google/batch.py → batch.py} +209 -252
  11. pygpt_net/controller/remote_store/remote_store.py +982 -13
  12. pygpt_net/core/command/command.py +0 -0
  13. pygpt_net/core/db/viewer.py +1 -1
  14. pygpt_net/core/realtime/worker.py +3 -1
  15. pygpt_net/{controller/remote_store/google → core/remote_store/anthropic}/__init__.py +0 -1
  16. pygpt_net/core/remote_store/anthropic/files.py +211 -0
  17. pygpt_net/core/remote_store/anthropic/store.py +208 -0
  18. pygpt_net/core/remote_store/openai/store.py +5 -4
  19. pygpt_net/core/remote_store/remote_store.py +5 -1
  20. pygpt_net/{controller/remote_store/openai → core/remote_store/xai}/__init__.py +0 -1
  21. pygpt_net/core/remote_store/xai/files.py +225 -0
  22. pygpt_net/core/remote_store/xai/store.py +219 -0
  23. pygpt_net/data/config/config.json +9 -6
  24. pygpt_net/data/config/models.json +5 -4
  25. pygpt_net/data/config/settings.json +54 -1
  26. pygpt_net/data/icons/folder_eye.svg +1 -0
  27. pygpt_net/data/icons/folder_eye_filled.svg +1 -0
  28. pygpt_net/data/icons/folder_open.svg +1 -0
  29. pygpt_net/data/icons/folder_open_filled.svg +1 -0
  30. pygpt_net/data/locale/locale.de.ini +4 -3
  31. pygpt_net/data/locale/locale.en.ini +14 -4
  32. pygpt_net/data/locale/locale.es.ini +4 -3
  33. pygpt_net/data/locale/locale.fr.ini +4 -3
  34. pygpt_net/data/locale/locale.it.ini +4 -3
  35. pygpt_net/data/locale/locale.pl.ini +5 -4
  36. pygpt_net/data/locale/locale.uk.ini +4 -3
  37. pygpt_net/data/locale/locale.zh.ini +4 -3
  38. pygpt_net/icons.qrc +4 -0
  39. pygpt_net/icons_rc.py +282 -138
  40. pygpt_net/provider/api/anthropic/__init__.py +2 -0
  41. pygpt_net/provider/api/anthropic/chat.py +84 -1
  42. pygpt_net/provider/api/anthropic/store.py +307 -0
  43. pygpt_net/provider/api/anthropic/stream.py +75 -0
  44. pygpt_net/provider/api/anthropic/worker/__init__.py +0 -0
  45. pygpt_net/provider/api/anthropic/worker/importer.py +278 -0
  46. pygpt_net/provider/api/google/chat.py +59 -2
  47. pygpt_net/provider/api/google/store.py +124 -3
  48. pygpt_net/provider/api/google/stream.py +91 -24
  49. pygpt_net/provider/api/google/worker/importer.py +16 -28
  50. pygpt_net/provider/api/openai/assistants.py +2 -2
  51. pygpt_net/provider/api/openai/store.py +4 -1
  52. pygpt_net/provider/api/openai/worker/importer.py +19 -61
  53. pygpt_net/provider/api/openai/worker/importer_assistants.py +230 -0
  54. pygpt_net/provider/api/x_ai/__init__.py +30 -6
  55. pygpt_net/provider/api/x_ai/audio.py +43 -11
  56. pygpt_net/provider/api/x_ai/chat.py +92 -4
  57. pygpt_net/provider/api/x_ai/realtime/__init__.py +12 -0
  58. pygpt_net/provider/api/x_ai/realtime/client.py +1825 -0
  59. pygpt_net/provider/api/x_ai/realtime/realtime.py +198 -0
  60. pygpt_net/provider/api/x_ai/remote_tools.py +19 -1
  61. pygpt_net/provider/api/x_ai/store.py +610 -0
  62. pygpt_net/provider/api/x_ai/stream.py +30 -9
  63. pygpt_net/provider/api/x_ai/worker/importer.py +308 -0
  64. pygpt_net/provider/audio_input/xai_grok_voice.py +390 -0
  65. pygpt_net/provider/audio_output/xai_tts.py +325 -0
  66. pygpt_net/provider/core/config/patch.py +18 -3
  67. pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +2 -2
  68. pygpt_net/provider/core/model/patch.py +13 -0
  69. pygpt_net/tools/image_viewer/tool.py +334 -34
  70. pygpt_net/tools/image_viewer/ui/dialogs.py +317 -21
  71. pygpt_net/ui/dialog/assistant.py +1 -1
  72. pygpt_net/ui/dialog/plugins.py +13 -5
  73. pygpt_net/ui/dialog/remote_store.py +552 -0
  74. pygpt_net/ui/dialogs.py +3 -5
  75. pygpt_net/ui/layout/ctx/ctx_list.py +58 -7
  76. pygpt_net/ui/menu/tools.py +6 -13
  77. pygpt_net/ui/widget/dialog/{remote_store_google.py → remote_store.py} +10 -10
  78. pygpt_net/ui/widget/element/button.py +4 -4
  79. pygpt_net/ui/widget/image/display.py +2 -2
  80. pygpt_net/ui/widget/lists/context.py +2 -2
  81. {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/METADATA +9 -2
  82. {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/RECORD +82 -70
  83. pygpt_net/controller/remote_store/google/store.py +0 -615
  84. pygpt_net/controller/remote_store/openai/batch.py +0 -524
  85. pygpt_net/controller/remote_store/openai/store.py +0 -699
  86. pygpt_net/ui/dialog/remote_store_google.py +0 -539
  87. pygpt_net/ui/dialog/remote_store_openai.py +0 -539
  88. pygpt_net/ui/widget/dialog/remote_store_openai.py +0 -56
  89. pygpt_net/ui/widget/lists/remote_store_google.py +0 -248
  90. pygpt_net/ui/widget/lists/remote_store_openai.py +0 -317
  91. {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/LICENSE +0 -0
  92. {pygpt_net-2.7.7.dist-info → pygpt_net-2.7.8.dist-info}/WHEEL +0 -0
  93. {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.04 19:00:00 #
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,