pygpt-net 2.6.26__py3-none-any.whl → 2.6.28__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 +10 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +5 -1
- pygpt_net/controller/access/voice.py +3 -5
- pygpt_net/controller/audio/audio.py +9 -6
- pygpt_net/controller/audio/ui.py +263 -0
- pygpt_net/controller/chat/common.py +17 -1
- pygpt_net/controller/kernel/kernel.py +2 -0
- pygpt_net/controller/notepad/notepad.py +10 -1
- pygpt_net/controller/theme/markdown.py +2 -0
- pygpt_net/controller/theme/theme.py +4 -1
- pygpt_net/controller/ui/tabs.py +5 -0
- pygpt_net/core/audio/backend/native.py +114 -82
- pygpt_net/core/audio/backend/pyaudio.py +16 -19
- pygpt_net/core/audio/backend/pygame.py +12 -15
- pygpt_net/core/audio/capture.py +10 -9
- pygpt_net/core/audio/context.py +3 -6
- pygpt_net/core/command/command.py +2 -0
- pygpt_net/core/render/web/helpers.py +13 -3
- pygpt_net/core/render/web/renderer.py +3 -3
- pygpt_net/data/config/config.json +7 -5
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/settings.json +24 -10
- pygpt_net/data/css/web-blocks.darkest.css +91 -0
- pygpt_net/data/css/web-chatgpt.css +7 -5
- pygpt_net/data/css/web-chatgpt.dark.css +5 -2
- pygpt_net/data/css/web-chatgpt.darkest.css +91 -0
- pygpt_net/data/css/web-chatgpt.light.css +8 -2
- pygpt_net/data/css/web-chatgpt_wide.css +7 -4
- pygpt_net/data/css/web-chatgpt_wide.dark.css +5 -2
- pygpt_net/data/css/web-chatgpt_wide.darkest.css +91 -0
- pygpt_net/data/css/web-chatgpt_wide.light.css +9 -6
- pygpt_net/data/locale/locale.de.ini +2 -0
- pygpt_net/data/locale/locale.en.ini +2 -0
- pygpt_net/data/locale/locale.es.ini +2 -0
- pygpt_net/data/locale/locale.fr.ini +2 -0
- pygpt_net/data/locale/locale.it.ini +2 -0
- pygpt_net/data/locale/locale.pl.ini +3 -1
- pygpt_net/data/locale/locale.uk.ini +2 -0
- pygpt_net/data/locale/locale.zh.ini +2 -0
- pygpt_net/data/themes/dark_darkest.css +31 -0
- pygpt_net/data/themes/dark_darkest.xml +10 -0
- pygpt_net/plugin/audio_input/simple.py +5 -10
- pygpt_net/plugin/audio_output/plugin.py +4 -17
- pygpt_net/plugin/tuya/__init__.py +12 -0
- pygpt_net/plugin/tuya/config.py +256 -0
- pygpt_net/plugin/tuya/plugin.py +117 -0
- pygpt_net/plugin/tuya/worker.py +588 -0
- pygpt_net/plugin/wikipedia/__init__.py +12 -0
- pygpt_net/plugin/wikipedia/config.py +228 -0
- pygpt_net/plugin/wikipedia/plugin.py +114 -0
- pygpt_net/plugin/wikipedia/worker.py +430 -0
- pygpt_net/provider/core/config/patch.py +11 -0
- pygpt_net/ui/layout/chat/input.py +5 -2
- pygpt_net/ui/main.py +1 -2
- pygpt_net/ui/widget/audio/bar.py +5 -1
- pygpt_net/ui/widget/tabs/output.py +2 -0
- pygpt_net/ui/widget/textarea/input.py +483 -55
- {pygpt_net-2.6.26.dist-info → pygpt_net-2.6.28.dist-info}/METADATA +78 -35
- {pygpt_net-2.6.26.dist-info → pygpt_net-2.6.28.dist-info}/RECORD +63 -49
- {pygpt_net-2.6.26.dist-info → pygpt_net-2.6.28.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.26.dist-info → pygpt_net-2.6.28.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.26.dist-info → pygpt_net-2.6.28.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,430 @@
|
|
|
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.27 20:18:26 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from typing import Any, Dict, List, Optional
|
|
15
|
+
|
|
16
|
+
from PySide6.QtCore import Slot
|
|
17
|
+
from pygpt_net.plugin.base.worker import BaseWorker, BaseSignals
|
|
18
|
+
|
|
19
|
+
# Lazy import
|
|
20
|
+
try:
|
|
21
|
+
import wikipedia as wiki
|
|
22
|
+
from wikipedia.exceptions import (
|
|
23
|
+
DisambiguationError,
|
|
24
|
+
PageError,
|
|
25
|
+
RedirectError,
|
|
26
|
+
HTTPTimeoutError,
|
|
27
|
+
WikipediaException,
|
|
28
|
+
)
|
|
29
|
+
except Exception: # fallback mapping for type hints
|
|
30
|
+
wiki = None
|
|
31
|
+
DisambiguationError = PageError = RedirectError = HTTPTimeoutError = WikipediaException = Exception # type: ignore
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class WorkerSignals(BaseSignals):
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class Worker(BaseWorker):
|
|
39
|
+
"""
|
|
40
|
+
Wikipedia plugin worker: language, search, suggest, summary, page, section, random, geosearch, open.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, *args, **kwargs):
|
|
44
|
+
super(Worker, self).__init__()
|
|
45
|
+
self.signals = WorkerSignals()
|
|
46
|
+
self.args = args
|
|
47
|
+
self.kwargs = kwargs
|
|
48
|
+
self.plugin = None
|
|
49
|
+
self.cmds = None
|
|
50
|
+
self.ctx = None
|
|
51
|
+
self.msg = None
|
|
52
|
+
|
|
53
|
+
# ---------------------- Core runner ----------------------
|
|
54
|
+
|
|
55
|
+
@Slot()
|
|
56
|
+
def run(self):
|
|
57
|
+
try:
|
|
58
|
+
responses = []
|
|
59
|
+
self._apply_settings() # sync module settings with plugin options
|
|
60
|
+
for item in self.cmds:
|
|
61
|
+
if self.is_stopped():
|
|
62
|
+
break
|
|
63
|
+
try:
|
|
64
|
+
response = None
|
|
65
|
+
if item["cmd"] in self.plugin.allowed_cmds and self.plugin.has_cmd(item["cmd"]):
|
|
66
|
+
|
|
67
|
+
# -------- Language --------
|
|
68
|
+
if item["cmd"] == "wp_set_lang":
|
|
69
|
+
response = self.cmd_wp_set_lang(item)
|
|
70
|
+
elif item["cmd"] == "wp_get_lang":
|
|
71
|
+
response = self.cmd_wp_get_lang(item)
|
|
72
|
+
elif item["cmd"] == "wp_languages":
|
|
73
|
+
response = self.cmd_wp_languages(item)
|
|
74
|
+
|
|
75
|
+
# -------- Search / Suggest --------
|
|
76
|
+
elif item["cmd"] == "wp_search":
|
|
77
|
+
response = self.cmd_wp_search(item)
|
|
78
|
+
elif item["cmd"] == "wp_suggest":
|
|
79
|
+
response = self.cmd_wp_suggest(item)
|
|
80
|
+
|
|
81
|
+
# -------- Read --------
|
|
82
|
+
elif item["cmd"] == "wp_summary":
|
|
83
|
+
response = self.cmd_wp_summary(item)
|
|
84
|
+
elif item["cmd"] == "wp_page":
|
|
85
|
+
response = self.cmd_wp_page(item)
|
|
86
|
+
elif item["cmd"] == "wp_section":
|
|
87
|
+
response = self.cmd_wp_section(item)
|
|
88
|
+
|
|
89
|
+
# -------- Discover --------
|
|
90
|
+
elif item["cmd"] == "wp_random":
|
|
91
|
+
response = self.cmd_wp_random(item)
|
|
92
|
+
elif item["cmd"] == "wp_geosearch":
|
|
93
|
+
response = self.cmd_wp_geosearch(item)
|
|
94
|
+
|
|
95
|
+
# -------- Utilities --------
|
|
96
|
+
elif item["cmd"] == "wp_open":
|
|
97
|
+
response = self.cmd_wp_open(item)
|
|
98
|
+
|
|
99
|
+
if response:
|
|
100
|
+
responses.append(response)
|
|
101
|
+
|
|
102
|
+
except DisambiguationError as e:
|
|
103
|
+
responses.append(self.make_response(item, self._wrap_disambig(e)))
|
|
104
|
+
except (PageError, RedirectError, HTTPTimeoutError, WikipediaException) as e:
|
|
105
|
+
responses.append(self.make_response(item, self.throw_error(e)))
|
|
106
|
+
except Exception as e:
|
|
107
|
+
responses.append(self.make_response(item, self.throw_error(e)))
|
|
108
|
+
|
|
109
|
+
if responses:
|
|
110
|
+
self.reply_more(responses)
|
|
111
|
+
if self.msg is not None:
|
|
112
|
+
self.status(self.msg)
|
|
113
|
+
except Exception as e:
|
|
114
|
+
self.error(e)
|
|
115
|
+
finally:
|
|
116
|
+
self.cleanup()
|
|
117
|
+
|
|
118
|
+
# ---------------------- Helpers ----------------------
|
|
119
|
+
|
|
120
|
+
def _require_lib(self):
|
|
121
|
+
if wiki is None:
|
|
122
|
+
raise RuntimeError("Missing 'wikipedia' package. Install with: pip install wikipedia")
|
|
123
|
+
|
|
124
|
+
def _apply_settings(self):
|
|
125
|
+
self._require_lib()
|
|
126
|
+
# Keep module-level settings in sync with plugin options
|
|
127
|
+
lang = (self.plugin.get_option_value("lang") or "en").strip()
|
|
128
|
+
auto_rate = bool(self.plugin.get_option_value("rate_limit") or True)
|
|
129
|
+
ua = (self.plugin.get_option_value("user_agent") or "").strip()
|
|
130
|
+
try:
|
|
131
|
+
wiki.set_lang(lang)
|
|
132
|
+
except Exception:
|
|
133
|
+
pass
|
|
134
|
+
try:
|
|
135
|
+
wiki.set_rate_limit(auto_rate)
|
|
136
|
+
except Exception:
|
|
137
|
+
pass
|
|
138
|
+
if ua:
|
|
139
|
+
try:
|
|
140
|
+
wiki.set_user_agent(ua)
|
|
141
|
+
except Exception:
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
def _opt_bool(self, key: str, default: bool) -> bool:
|
|
145
|
+
v = self.plugin.get_option_value(key)
|
|
146
|
+
return bool(default if v is None else v)
|
|
147
|
+
|
|
148
|
+
def _opt_int(self, key: str, default: int) -> int:
|
|
149
|
+
v = self.plugin.get_option_value(key)
|
|
150
|
+
try:
|
|
151
|
+
return int(default if v is None else v)
|
|
152
|
+
except Exception:
|
|
153
|
+
return default
|
|
154
|
+
|
|
155
|
+
def _params_bool(self, params: dict, key: str, fallback_opt: Optional[str], default: bool) -> bool:
|
|
156
|
+
if key in params and params[key] is not None:
|
|
157
|
+
return bool(params[key])
|
|
158
|
+
if fallback_opt:
|
|
159
|
+
return self._opt_bool(fallback_opt, default)
|
|
160
|
+
return bool(default)
|
|
161
|
+
|
|
162
|
+
def _params_int(self, params: dict, key: str, fallback_opt: Optional[str], default: int) -> int:
|
|
163
|
+
if key in params and params[key] is not None:
|
|
164
|
+
try:
|
|
165
|
+
return int(params[key])
|
|
166
|
+
except Exception:
|
|
167
|
+
return default
|
|
168
|
+
if fallback_opt:
|
|
169
|
+
return self._opt_int(fallback_opt, default)
|
|
170
|
+
return int(default)
|
|
171
|
+
|
|
172
|
+
def _clip_text(self, text: str, max_chars: Optional[int]) -> str:
|
|
173
|
+
if text is None:
|
|
174
|
+
return ""
|
|
175
|
+
if not max_chars or max_chars <= 0:
|
|
176
|
+
return text
|
|
177
|
+
if len(text) <= max_chars:
|
|
178
|
+
return text
|
|
179
|
+
return text[: max_chars - 3] + "..."
|
|
180
|
+
|
|
181
|
+
def _clip_list(self, items: List[Any], max_items: Optional[int]) -> List[Any]:
|
|
182
|
+
if not isinstance(items, list):
|
|
183
|
+
return []
|
|
184
|
+
if not max_items or max_items <= 0 or len(items) <= max_items:
|
|
185
|
+
return items
|
|
186
|
+
return items[:max_items]
|
|
187
|
+
|
|
188
|
+
def _wrap_disambig(self, e: DisambiguationError) -> dict:
|
|
189
|
+
# Provide options to let the assistant choose a target
|
|
190
|
+
return {
|
|
191
|
+
"error": "Disambiguation required",
|
|
192
|
+
"type": "DisambiguationError",
|
|
193
|
+
"title": getattr(e, "title", None),
|
|
194
|
+
"options": getattr(e, "options", []),
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
def _auto_suggest_param(self, p: dict) -> bool:
|
|
198
|
+
return self._params_bool(p, "auto_suggest", "auto_suggest", True)
|
|
199
|
+
|
|
200
|
+
def _redirect_param(self, p: dict) -> bool:
|
|
201
|
+
return self._params_bool(p, "redirect", "redirect", True)
|
|
202
|
+
|
|
203
|
+
# Decide whether to return full content (no clipping)
|
|
204
|
+
def _full_content_param(self, p: dict) -> bool:
|
|
205
|
+
if p.get("full") is not None:
|
|
206
|
+
return bool(p["full"])
|
|
207
|
+
if p.get("no_clip") is not None: # alias
|
|
208
|
+
return bool(p["no_clip"])
|
|
209
|
+
return bool(self.plugin.get_option_value("content_full_default") or False)
|
|
210
|
+
|
|
211
|
+
# ---------------------- Commands: Language ----------------------
|
|
212
|
+
|
|
213
|
+
def cmd_wp_set_lang(self, item: dict) -> dict:
|
|
214
|
+
p = item.get("params", {})
|
|
215
|
+
lang = (p.get("lang") or "").strip()
|
|
216
|
+
if not lang:
|
|
217
|
+
return self.make_response(item, "Param 'lang' required")
|
|
218
|
+
self.plugin.set_option_value("lang", lang)
|
|
219
|
+
self._apply_settings()
|
|
220
|
+
return self.make_response(item, {"ok": True, "lang": lang})
|
|
221
|
+
|
|
222
|
+
def cmd_wp_get_lang(self, item: dict) -> dict:
|
|
223
|
+
lang = (self.plugin.get_option_value("lang") or "en").strip()
|
|
224
|
+
return self.make_response(item, {"lang": lang})
|
|
225
|
+
|
|
226
|
+
def cmd_wp_languages(self, item: dict) -> dict:
|
|
227
|
+
self._require_lib()
|
|
228
|
+
p = item.get("params", {})
|
|
229
|
+
short = bool(p.get("short", False))
|
|
230
|
+
langs = wiki.languages() # dict: code -> localized name
|
|
231
|
+
if short:
|
|
232
|
+
data = sorted(list(langs.keys()))
|
|
233
|
+
else:
|
|
234
|
+
data = langs
|
|
235
|
+
max_items = self._opt_int("max_list_items", 50)
|
|
236
|
+
if isinstance(data, list):
|
|
237
|
+
data = self._clip_list(data, max_items)
|
|
238
|
+
elif isinstance(data, dict):
|
|
239
|
+
data = dict(list(data.items())[:max_items])
|
|
240
|
+
return self.make_response(item, {"data": data})
|
|
241
|
+
|
|
242
|
+
# ---------------------- Commands: Search / Suggest ----------------------
|
|
243
|
+
|
|
244
|
+
def cmd_wp_search(self, item: dict) -> dict:
|
|
245
|
+
self._require_lib()
|
|
246
|
+
p = item.get("params", {})
|
|
247
|
+
q = (p.get("q") or p.get("query") or "").strip()
|
|
248
|
+
if not q:
|
|
249
|
+
return self.make_response(item, "Param 'q' required")
|
|
250
|
+
results_limit = self._params_int(p, "results", "results_default", 10)
|
|
251
|
+
suggestion = bool(p.get("suggestion", False))
|
|
252
|
+
if suggestion:
|
|
253
|
+
res, sugg = wiki.search(q, results=results_limit, suggestion=True)
|
|
254
|
+
return self.make_response(item, {"results": res, "suggestion": sugg})
|
|
255
|
+
else:
|
|
256
|
+
res = wiki.search(q, results=results_limit, suggestion=False)
|
|
257
|
+
return self.make_response(item, {"results": res})
|
|
258
|
+
|
|
259
|
+
def cmd_wp_suggest(self, item: dict) -> dict:
|
|
260
|
+
self._require_lib()
|
|
261
|
+
p = item.get("params", {})
|
|
262
|
+
q = (p.get("q") or p.get("query") or "").strip()
|
|
263
|
+
if not q:
|
|
264
|
+
return self.make_response(item, "Param 'q' required")
|
|
265
|
+
sugg = wiki.suggest(q)
|
|
266
|
+
return self.make_response(item, {"suggestion": sugg})
|
|
267
|
+
|
|
268
|
+
# ---------------------- Commands: Read ----------------------
|
|
269
|
+
|
|
270
|
+
def cmd_wp_summary(self, item: dict) -> dict:
|
|
271
|
+
self._require_lib()
|
|
272
|
+
p = item.get("params", {})
|
|
273
|
+
title = (p.get("title") or p.get("q") or p.get("query") or "").strip()
|
|
274
|
+
if not title:
|
|
275
|
+
return self.make_response(item, "Param 'title' (or 'q') required")
|
|
276
|
+
sentences = self._params_int(p, "sentences", "summary_sentences", 3)
|
|
277
|
+
auto_suggest = self._auto_suggest_param(p)
|
|
278
|
+
redirect = self._redirect_param(p)
|
|
279
|
+
summary = wiki.summary(title, sentences=sentences, auto_suggest=auto_suggest, redirect=redirect)
|
|
280
|
+
url = None
|
|
281
|
+
try:
|
|
282
|
+
pg = wiki.page(title, auto_suggest=auto_suggest, redirect=redirect)
|
|
283
|
+
url = getattr(pg, "url", None)
|
|
284
|
+
title = getattr(pg, "title", title)
|
|
285
|
+
except Exception:
|
|
286
|
+
pass
|
|
287
|
+
return self.make_response(item, {"title": title, "summary": summary, "url": url})
|
|
288
|
+
|
|
289
|
+
def cmd_wp_page(self, item: dict) -> dict:
|
|
290
|
+
self._require_lib()
|
|
291
|
+
p = item.get("params", {})
|
|
292
|
+
title = (p.get("title") or "").strip()
|
|
293
|
+
if not title:
|
|
294
|
+
return self.make_response(item, "Param 'title' required")
|
|
295
|
+
auto_suggest = self._auto_suggest_param(p)
|
|
296
|
+
redirect = self._redirect_param(p)
|
|
297
|
+
content_chars = self._params_int(p, "content_chars", "content_max_chars", 5000)
|
|
298
|
+
max_list = self._params_int(p, "max_list_items", "max_list_items", 50)
|
|
299
|
+
full = self._full_content_param(p)
|
|
300
|
+
|
|
301
|
+
include = p.get("include")
|
|
302
|
+
if not include:
|
|
303
|
+
include = ["title", "url", "summary", "content", "sections", "categories", "links", "images", "references"]
|
|
304
|
+
|
|
305
|
+
pg = wiki.page(title, auto_suggest=auto_suggest, redirect=redirect)
|
|
306
|
+
data: Dict[str, Any] = {}
|
|
307
|
+
|
|
308
|
+
if "title" in include:
|
|
309
|
+
data["title"] = getattr(pg, "title", title)
|
|
310
|
+
if "url" in include:
|
|
311
|
+
data["url"] = getattr(pg, "url", None)
|
|
312
|
+
if "summary" in include:
|
|
313
|
+
try:
|
|
314
|
+
data["summary"] = getattr(pg, "summary", None)
|
|
315
|
+
except Exception:
|
|
316
|
+
data["summary"] = None
|
|
317
|
+
if "content" in include:
|
|
318
|
+
try:
|
|
319
|
+
raw = getattr(pg, "content", None)
|
|
320
|
+
data["content_body"] = raw if full else self._clip_text(raw, content_chars)
|
|
321
|
+
except Exception:
|
|
322
|
+
data["content_body"] = None
|
|
323
|
+
if "sections" in include:
|
|
324
|
+
try:
|
|
325
|
+
data["sections"] = self._clip_list(getattr(pg, "sections", []), max_list)
|
|
326
|
+
except Exception:
|
|
327
|
+
data["sections"] = []
|
|
328
|
+
if "categories" in include:
|
|
329
|
+
try:
|
|
330
|
+
data["categories"] = self._clip_list(getattr(pg, "categories", []), max_list)
|
|
331
|
+
except Exception:
|
|
332
|
+
data["categories"] = []
|
|
333
|
+
if "links" in include:
|
|
334
|
+
try:
|
|
335
|
+
data["links"] = self._clip_list(getattr(pg, "links", []), max_list)
|
|
336
|
+
except Exception:
|
|
337
|
+
data["links"] = []
|
|
338
|
+
if "images" in include:
|
|
339
|
+
try:
|
|
340
|
+
data["images"] = self._clip_list(getattr(pg, "images", []), max_list)
|
|
341
|
+
except Exception:
|
|
342
|
+
data["images"] = []
|
|
343
|
+
if "references" in include:
|
|
344
|
+
try:
|
|
345
|
+
data["references"] = self._clip_list(getattr(pg, "references", []), max_list)
|
|
346
|
+
except Exception:
|
|
347
|
+
data["references"] = []
|
|
348
|
+
|
|
349
|
+
if bool(p.get("open", False)):
|
|
350
|
+
try:
|
|
351
|
+
if data.get("url"):
|
|
352
|
+
self.plugin.open_url(data["url"])
|
|
353
|
+
except Exception:
|
|
354
|
+
pass
|
|
355
|
+
|
|
356
|
+
return self.make_response(item, data)
|
|
357
|
+
|
|
358
|
+
def cmd_wp_section(self, item: dict) -> dict:
|
|
359
|
+
self._require_lib()
|
|
360
|
+
p = item.get("params", {})
|
|
361
|
+
title = (p.get("title") or "").strip()
|
|
362
|
+
section = (p.get("section") or "").strip()
|
|
363
|
+
if not title or not section:
|
|
364
|
+
return self.make_response(item, "Params 'title' and 'section' required")
|
|
365
|
+
auto_suggest = self._auto_suggest_param(p)
|
|
366
|
+
redirect = self._redirect_param(p)
|
|
367
|
+
content_chars = self._params_int(p, "content_chars", "content_max_chars", 5000)
|
|
368
|
+
full = self._full_content_param(p)
|
|
369
|
+
|
|
370
|
+
pg = wiki.page(title, auto_suggest=auto_suggest, redirect=redirect)
|
|
371
|
+
txt = pg.section(section)
|
|
372
|
+
|
|
373
|
+
return self.make_response(item, {
|
|
374
|
+
"title": getattr(pg, "title", title),
|
|
375
|
+
"section": section,
|
|
376
|
+
"content_body": (txt or "") if full else self._clip_text(txt or "", content_chars),
|
|
377
|
+
"url": getattr(pg, "url", None),
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
# ---------------------- Commands: Discover ----------------------
|
|
381
|
+
|
|
382
|
+
def cmd_wp_random(self, item: dict) -> dict:
|
|
383
|
+
self._require_lib()
|
|
384
|
+
p = item.get("params", {})
|
|
385
|
+
count = self._params_int(p, "results", "results_default", 1)
|
|
386
|
+
res = wiki.random(pages=count)
|
|
387
|
+
if isinstance(res, str):
|
|
388
|
+
res = [res]
|
|
389
|
+
return self.make_response(item, {"results": res})
|
|
390
|
+
|
|
391
|
+
def cmd_wp_geosearch(self, item: dict) -> dict:
|
|
392
|
+
self._require_lib()
|
|
393
|
+
p = item.get("params", {})
|
|
394
|
+
lat = p.get("lat") or p.get("latitude")
|
|
395
|
+
lon = p.get("lon") or p.get("lng") or p.get("longitude")
|
|
396
|
+
if lat is None or lon is None:
|
|
397
|
+
return self.make_response(item, "Params 'lat' and 'lon' required")
|
|
398
|
+
try:
|
|
399
|
+
lat = float(lat)
|
|
400
|
+
lon = float(lon)
|
|
401
|
+
except Exception:
|
|
402
|
+
return self.make_response(item, "Params 'lat' and 'lon' must be numbers")
|
|
403
|
+
radius = self._params_int(p, "radius", None, 1000)
|
|
404
|
+
results_limit = self._params_int(p, "results", "results_default", 10)
|
|
405
|
+
title = p.get("title")
|
|
406
|
+
res = wiki.geosearch(latitude=lat, longitude=lon, title=title, results=results_limit, radius=radius)
|
|
407
|
+
return self.make_response(item, {"results": res})
|
|
408
|
+
|
|
409
|
+
# ---------------------- Commands: Utilities ----------------------
|
|
410
|
+
|
|
411
|
+
def cmd_wp_open(self, item: dict) -> dict:
|
|
412
|
+
self._require_lib()
|
|
413
|
+
p = item.get("params", {})
|
|
414
|
+
url = p.get("url")
|
|
415
|
+
title = p.get("title")
|
|
416
|
+
auto_suggest = self._auto_suggest_param(p)
|
|
417
|
+
redirect = self._redirect_param(p)
|
|
418
|
+
|
|
419
|
+
if not url and not title:
|
|
420
|
+
return self.make_response(item, "Provide 'url' or 'title'")
|
|
421
|
+
if not url:
|
|
422
|
+
pg = wiki.page(title, auto_suggest=auto_suggest, redirect=redirect)
|
|
423
|
+
url = getattr(pg, "url", None)
|
|
424
|
+
if not url:
|
|
425
|
+
return self.make_response(item, "Unable to resolve URL")
|
|
426
|
+
try:
|
|
427
|
+
self.plugin.open_url(url)
|
|
428
|
+
except Exception:
|
|
429
|
+
pass
|
|
430
|
+
return self.make_response(item, {"ok": True, "url": url})
|
|
@@ -2344,6 +2344,17 @@ class Patch:
|
|
|
2344
2344
|
data["api_endpoint_open_router"] = "https://openrouter.ai/api/v1"
|
|
2345
2345
|
updated = True
|
|
2346
2346
|
|
|
2347
|
+
# < 2.6.28 -- fix: cmd color
|
|
2348
|
+
if old < parse_version("2.6.28"):
|
|
2349
|
+
print("Migrating config from < 2.6.28...")
|
|
2350
|
+
self.window.core.updater.patch_css('web-chatgpt.css', True)
|
|
2351
|
+
self.window.core.updater.patch_css('web-chatgpt_wide.css', True)
|
|
2352
|
+
self.window.core.updater.patch_css('web-chatgpt.dark.css', True)
|
|
2353
|
+
self.window.core.updater.patch_css('web-chatgpt_wide.dark.css', True)
|
|
2354
|
+
self.window.core.updater.patch_css('web-chatgpt.light.css', True)
|
|
2355
|
+
self.window.core.updater.patch_css('web-chatgpt_wide.light.css', True)
|
|
2356
|
+
updated = True
|
|
2357
|
+
|
|
2347
2358
|
# update file
|
|
2348
2359
|
migrated = False
|
|
2349
2360
|
if updated:
|
|
@@ -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: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.27 07:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from functools import partial
|
|
@@ -149,6 +149,9 @@ class Input:
|
|
|
149
149
|
self.window.ui.plugin_addon['audio.input'] = AudioInput(self.window)
|
|
150
150
|
self.window.ui.plugin_addon['audio.input.btn'] = AudioInputButton(self.window)
|
|
151
151
|
|
|
152
|
+
self.window.ui.plugin_addon['audio.input'].setVisible(False)
|
|
153
|
+
self.window.ui.plugin_addon['audio.input.btn'].setVisible(False)
|
|
154
|
+
|
|
152
155
|
grid = QGridLayout()
|
|
153
156
|
|
|
154
157
|
center_layout = QHBoxLayout()
|
|
@@ -204,7 +207,7 @@ class Input:
|
|
|
204
207
|
|
|
205
208
|
nodes['input.stop_btn'] = QPushButton(trans("input.btn.stop"))
|
|
206
209
|
nodes['input.stop_btn'].setVisible(False)
|
|
207
|
-
nodes['input.stop_btn'].clicked.connect(controller.
|
|
210
|
+
nodes['input.stop_btn'].clicked.connect(controller.chat.common.handle_stop)
|
|
208
211
|
|
|
209
212
|
nodes['input.update_btn'] = QPushButton(trans("input.btn.update"))
|
|
210
213
|
nodes['input.update_btn'].setVisible(False)
|
pygpt_net/ui/main.py
CHANGED
|
@@ -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: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.27 07:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import os
|
|
@@ -254,7 +254,6 @@ class MainWindow(QMainWindow, QtStyleTools):
|
|
|
254
254
|
"""
|
|
255
255
|
message = message if isinstance(message, str) else str(message)
|
|
256
256
|
self.dispatch(KernelEvent(KernelEvent.STATUS, {"status": message}))
|
|
257
|
-
del message # free memory
|
|
258
257
|
|
|
259
258
|
@Slot(str)
|
|
260
259
|
def update_state(self, state: str):
|
pygpt_net/ui/widget/audio/bar.py
CHANGED
|
@@ -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: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.27 07:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt
|
|
@@ -25,6 +25,8 @@ class InputBar(QWidget):
|
|
|
25
25
|
|
|
26
26
|
:param level: level
|
|
27
27
|
"""
|
|
28
|
+
if self._level == level:
|
|
29
|
+
return
|
|
28
30
|
self._level = level
|
|
29
31
|
self.update()
|
|
30
32
|
|
|
@@ -69,6 +71,8 @@ class OutputBar(QWidget):
|
|
|
69
71
|
|
|
70
72
|
:param level: level
|
|
71
73
|
"""
|
|
74
|
+
if self._level == level:
|
|
75
|
+
return
|
|
72
76
|
self._level = level
|
|
73
77
|
self.update()
|
|
74
78
|
|
|
@@ -323,6 +323,8 @@ class AddButton(QPushButton):
|
|
|
323
323
|
idx = 0
|
|
324
324
|
column_idx = self.column.get_idx()
|
|
325
325
|
self.show_menu(idx, column_idx, event.globalPos())
|
|
326
|
+
event.accept()
|
|
327
|
+
return
|
|
326
328
|
super(AddButton, self).mousePressEvent(event)
|
|
327
329
|
|
|
328
330
|
def show_menu(self, index: int, column_idx: int, global_pos):
|