pygpt-net 2.6.57__py3-none-any.whl → 2.6.58__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 +4 -0
- pygpt_net/__init__.py +1 -1
- pygpt_net/app.py +30 -25
- pygpt_net/controller/debug/debug.py +3 -3
- pygpt_net/controller/dialogs/info.py +6 -2
- pygpt_net/controller/ui/tabs.py +17 -0
- pygpt_net/core/filesystem/url.py +5 -2
- pygpt_net/data/config/config.json +3 -2
- pygpt_net/data/config/models.json +2 -2
- pygpt_net/data/config/settings.json +41 -2
- pygpt_net/data/js/app/ui.js +1 -1
- pygpt_net/data/js/app.min.js +2 -2
- pygpt_net/data/locale/locale.de.ini +5 -1
- pygpt_net/data/locale/locale.en.ini +5 -1
- pygpt_net/data/locale/locale.es.ini +5 -1
- pygpt_net/data/locale/locale.fr.ini +5 -1
- pygpt_net/data/locale/locale.it.ini +5 -1
- pygpt_net/data/locale/locale.pl.ini +5 -1
- pygpt_net/data/locale/locale.uk.ini +5 -1
- pygpt_net/data/locale/locale.zh.ini +5 -1
- pygpt_net/js_rc.py +5 -5
- pygpt_net/plugin/base/plugin.py +3 -5
- pygpt_net/provider/core/config/patch.py +8 -1
- pygpt_net/tools/html_canvas/ui/widgets.py +19 -18
- pygpt_net/tools/web_browser/__init__.py +12 -0
- pygpt_net/tools/web_browser/tool.py +232 -0
- pygpt_net/tools/web_browser/ui/__init__.py +0 -0
- pygpt_net/tools/web_browser/ui/dialogs.py +123 -0
- pygpt_net/tools/web_browser/ui/widgets.py +351 -0
- pygpt_net/ui/widget/textarea/html.py +172 -24
- {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.58.dist-info}/METADATA +18 -2
- {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.58.dist-info}/RECORD +35 -30
- {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.58.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.58.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.58.dist-info}/entry_points.txt +0 -0
|
@@ -833,6 +833,7 @@ menu.tools.interpreter = Інтерпретатор коду Python
|
|
|
833
833
|
menu.tools.media.player = Медіаплеєр
|
|
834
834
|
menu.tools.text.editor = Редактор текстів
|
|
835
835
|
menu.tools.translator = Перекладач
|
|
836
|
+
menu.tools.web_browser = Веб-браузер (Chromium)
|
|
836
837
|
menu.tray.notepad = Відкрити Блокнот...
|
|
837
838
|
menu.tray.scheduled = Заплановані завдання
|
|
838
839
|
menu.tray.screenshot = Запитати зі скріншотом...
|
|
@@ -1107,8 +1108,8 @@ settings.api_key.perplexity.desc = Обов'язковий для Perplexity API
|
|
|
1107
1108
|
settings.api_key.xai = КЛЮЧ API xAI
|
|
1108
1109
|
settings.api_key.xai.desc = Обов'язковий для xAI API та моделей Grok.
|
|
1109
1110
|
settings.api_proxy = Використовувати проксі
|
|
1110
|
-
settings.api_proxy.enabled = Проксі-адреса
|
|
1111
1111
|
settings.api_proxy.desc = Опціонально, проксі для API SDK, наприклад, http://proxy.example.com або socks5://user:pass@host:port
|
|
1112
|
+
settings.api_proxy.enabled = Проксі-адреса
|
|
1112
1113
|
settings.api_proxy.enabled.desc = Увімкніть цю опцію, щоб використовувати проксі для підключень до API
|
|
1113
1114
|
settings.api_use_responses = Використовувати API відповідей у режимі чату
|
|
1114
1115
|
settings.api_use_responses.desc = Використовувати API відповідей замість API ChatCompletions у режимі чату
|
|
@@ -1182,6 +1183,8 @@ settings.ctx.search_content = Шукати також у вмісті розмо
|
|
|
1182
1183
|
settings.ctx.search.desc = Увімкнути пошук також у вмісті елементів контексту
|
|
1183
1184
|
settings.ctx.sources = Показати джерела індексу Llama
|
|
1184
1185
|
settings.ctx.sources.desc = Якщо включено, використані джерела будуть відображатися в відповіді (якщо доступно, не працюватиме в потоковому чаті)
|
|
1186
|
+
settings.ctx.urls.internal = Відкривайте URL-адреси у вбудованому браузері
|
|
1187
|
+
settings.ctx.urls.internal.desc = Увімкніть цю опцію, щоб відкривати всі URL-адреси у вбудованому браузері (Chromium) замість зовнішнього браузера.
|
|
1185
1188
|
settings.ctx.use_extra = Використовувати додатковий контекст виводу
|
|
1186
1189
|
settings.ctx.use_extra.desc = Якщо увімкнено, звичайний текстовий вивід (якщо доступний) з результатів команд буде відображений поруч з JSON виводом.
|
|
1187
1190
|
settings.debug.show_menu = Показати меню налагодження
|
|
@@ -1546,6 +1549,7 @@ tool.indexer.tab.web.loader = Завантажувач даних
|
|
|
1546
1549
|
tool.indexer.tab.web.source = Джерело даних
|
|
1547
1550
|
tool.indexer.tab.web.tip = Виберіть завантажувач даних та визначте параметри завантажувача для вбудовування зовнішніх даних з вебу.
|
|
1548
1551
|
tool.indexer.title = Індексатор
|
|
1552
|
+
tool.web_browser.security.footer = ПОВІДОМЛЕННЯ ПРО БЕЗПЕКУ: Для вашого захисту уникайте використання вбудованого браузера для чутливих або критичних завдань. Він призначений лише для базового використання.
|
|
1549
1553
|
translator.btn.left = Перекласти >>
|
|
1550
1554
|
translator.btn.right = << Перекласти
|
|
1551
1555
|
translator.clear.confirm = Очистити вихідні дані перекладача (обидві колонки)?
|
|
@@ -833,6 +833,7 @@ menu.tools.interpreter = Python 代码解释器
|
|
|
833
833
|
menu.tools.media.player = 媒体播放器
|
|
834
834
|
menu.tools.text.editor = 文本编辑器
|
|
835
835
|
menu.tools.translator = 翻译
|
|
836
|
+
menu.tools.web_browser = 网络浏览器 (Chromium)
|
|
836
837
|
menu.tray.notepad = 打開記事本...
|
|
837
838
|
menu.tray.scheduled = 已排程任務
|
|
838
839
|
menu.tray.screenshot = 使用截圖提問...
|
|
@@ -1107,8 +1108,8 @@ settings.api_key.perplexity.desc = Perplexity API 所需。
|
|
|
1107
1108
|
settings.api_key.xai = xAI API 密钥
|
|
1108
1109
|
settings.api_key.xai.desc = xAI API 和 Grok 模型所需。
|
|
1109
1110
|
settings.api_proxy = 代理地址
|
|
1110
|
-
settings.api_proxy.enabled = 使用代理
|
|
1111
1111
|
settings.api_proxy.desc = 可选,用于 API SDK 的代理,例如 http://proxy.example.com 或 socks5://user:pass@host:port
|
|
1112
|
+
settings.api_proxy.enabled = 使用代理
|
|
1112
1113
|
settings.api_proxy.enabled.desc = 启用此选项以使用代理进行 API 连接
|
|
1113
1114
|
settings.api_use_responses = 在聊天模式中使用 Responses API
|
|
1114
1115
|
settings.api_use_responses.desc = 在聊天模式中使用 Responses API 而不是 ChatCompletions API
|
|
@@ -1182,6 +1183,8 @@ settings.ctx.search_content = 也在對話內容中搜索,而不僅僅是標
|
|
|
1182
1183
|
settings.ctx.search.desc = 啟用在上下文項目內容中進行搜索的功能
|
|
1183
1184
|
settings.ctx.sources = 显示Llama索引源
|
|
1184
1185
|
settings.ctx.sources.desc = 如果启用,使用的源将在回应中显示(如果可用,不适用于流式聊天)
|
|
1186
|
+
settings.ctx.urls.internal = 在内置浏览器中打开网址
|
|
1187
|
+
settings.ctx.urls.internal.desc = 启用此选项以在内置浏览器 (Chromium) 中打开所有网址,而不是外部浏览器。
|
|
1185
1188
|
settings.ctx.use_extra = 使用额外的上下文输出
|
|
1186
1189
|
settings.ctx.use_extra.desc = 如果启用,将在命令结果的 JSON 输出旁边显示纯文本输出(如果有)。
|
|
1187
1190
|
settings.debug.show_menu = 显示调试菜单
|
|
@@ -1546,6 +1549,7 @@ tool.indexer.tab.web.loader = 数据加载器
|
|
|
1546
1549
|
tool.indexer.tab.web.source = 数据来源
|
|
1547
1550
|
tool.indexer.tab.web.tip = 选择数据加载器并定义加载器参数,以便嵌入来自网络的外部数据。
|
|
1548
1551
|
tool.indexer.title = 索引器
|
|
1552
|
+
tool.web_browser.security.footer = 安全提示:为保护您的安全,请避免使用内置浏览器进行敏感或关键的任务。 它仅用于基本用途。
|
|
1549
1553
|
translator.btn.left = 翻译 >>
|
|
1550
1554
|
translator.btn.right = << 翻译
|
|
1551
1555
|
translator.clear.confirm = 清除翻译输出(两列)?
|
pygpt_net/js_rc.py
CHANGED
|
@@ -70566,8 +70566,8 @@ eight: 0; border\
|
|
|
70566
70566
|
sparent; backgro\
|
|
70567
70567
|
und: transparent\
|
|
70568
70568
|
; }',\x0a\x09\x09\x09'.msg-b\
|
|
70569
|
-
ox.msg-user
|
|
70570
|
-
|
|
70569
|
+
ox.msg-user .msg\
|
|
70570
|
+
:hover .msg-copy\
|
|
70571
70571
|
-btn, .msg-box.m\
|
|
70572
70572
|
sg-user .msg:foc\
|
|
70573
70573
|
us-within .msg-c\
|
|
@@ -113507,8 +113507,8 @@ ros||{},d(e,r)}}\
|
|
|
113507
113507
|
/\
|
|
113508
113508
|
* app.min.js \xe2\x80\x94\
|
|
113509
113509
|
generated on 20\
|
|
113510
|
-
25-09-22
|
|
113511
|
-
|
|
113510
|
+
25-09-22 09:05:0\
|
|
113511
|
+
8 by bin/minify_\
|
|
113512
113512
|
js.py using rjsm\
|
|
113513
113513
|
in */\x0a\x0a/* data/j\
|
|
113514
113514
|
s/app/async.js *\
|
|
@@ -114086,7 +114086,7 @@ VE_CODES_MAX',12\
|
|
|
114086
114086
|
E_AFTER_LINES:Ut\
|
|
114087
114087
|
ils.g('STREAM_PL\
|
|
114088
114088
|
AIN_ACTIVATE_AFT\
|
|
114089
|
-
ER_LINES',
|
|
114089
|
+
ER_LINES',80),};\
|
|
114090
114090
|
this.MATH={IDLE_\
|
|
114091
114091
|
TIMEOUT_MS:Utils\
|
|
114092
114092
|
.g('MATH_IDLE_TI\
|
pygpt_net/plugin/base/plugin.py
CHANGED
|
@@ -6,14 +6,13 @@
|
|
|
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.
|
|
9
|
+
# Updated Date: 2025.09.22 19:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
13
13
|
from typing import Optional, Any, Dict, List
|
|
14
14
|
|
|
15
|
-
from PySide6.QtCore import QObject, Slot
|
|
16
|
-
from PySide6.QtGui import QDesktopServices
|
|
15
|
+
from PySide6.QtCore import QObject, Slot
|
|
17
16
|
|
|
18
17
|
from pygpt_net.core.bridge.context import BridgeContext
|
|
19
18
|
from pygpt_net.core.events import Event, KernelEvent
|
|
@@ -554,5 +553,4 @@ class BasePlugin(QObject):
|
|
|
554
553
|
|
|
555
554
|
:param url: URL to open
|
|
556
555
|
"""
|
|
557
|
-
|
|
558
|
-
QDesktopServices.openUrl(QUrl(url))
|
|
556
|
+
self.window.controller.dialogs.info.open_url(url)
|
|
@@ -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.09.
|
|
9
|
+
# Updated Date: 2025.09.22 19:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
@@ -144,6 +144,13 @@ class Patch:
|
|
|
144
144
|
data["api_proxy.enabled"] = True
|
|
145
145
|
updated = True
|
|
146
146
|
|
|
147
|
+
# < 2.6.58
|
|
148
|
+
if old < parse_version("2.6.58"):
|
|
149
|
+
print("Migrating config from < 2.6.58...")
|
|
150
|
+
if "ctx.urls.internal" not in data:
|
|
151
|
+
data["ctx.urls.internal"] = False
|
|
152
|
+
updated = True
|
|
153
|
+
|
|
147
154
|
# update file
|
|
148
155
|
migrated = False
|
|
149
156
|
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.09.
|
|
9
|
+
# Updated Date: 2025.09.22 18:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt, Slot, QUrl, QObject, Signal, QSize
|
|
@@ -41,7 +41,7 @@ class ToolWidget:
|
|
|
41
41
|
self.edit = None # canvas edit
|
|
42
42
|
self.btn_edit = None # edit checkbox
|
|
43
43
|
|
|
44
|
-
# --- Navigation bar state
|
|
44
|
+
# --- Navigation bar state ---
|
|
45
45
|
# This toolbar is shown only when opening via URL (open_url),
|
|
46
46
|
# and hidden when using set_output/load_output.
|
|
47
47
|
self.nav_bar = None
|
|
@@ -50,7 +50,7 @@ class ToolWidget:
|
|
|
50
50
|
self.btn_back = None
|
|
51
51
|
self.btn_next = None
|
|
52
52
|
self.btn_reload = None
|
|
53
|
-
self.btn_go = None
|
|
53
|
+
self.btn_go = None
|
|
54
54
|
|
|
55
55
|
def on_open(self):
|
|
56
56
|
"""On open"""
|
|
@@ -88,7 +88,7 @@ class ToolWidget:
|
|
|
88
88
|
lambda: self.tool.save_output()
|
|
89
89
|
)
|
|
90
90
|
|
|
91
|
-
# ---- Navigation bar
|
|
91
|
+
# ---- Navigation bar ----
|
|
92
92
|
# Visible only when navigating URLs via open_url or address bar.
|
|
93
93
|
self.nav_bar = QWidget()
|
|
94
94
|
self.nav_layout = QHBoxLayout(self.nav_bar)
|
|
@@ -101,14 +101,14 @@ class ToolWidget:
|
|
|
101
101
|
nav_height = max(32, min(44, icon_size_px + 16)) # compact, never half-screen
|
|
102
102
|
self.nav_bar.setFixedHeight(nav_height)
|
|
103
103
|
|
|
104
|
-
# Buttons
|
|
104
|
+
# Buttons
|
|
105
105
|
self.btn_back = QPushButton()
|
|
106
106
|
self.btn_back.setToolTip("Back")
|
|
107
107
|
self.btn_back.setIcon(QIcon(":/icons/back.svg"))
|
|
108
108
|
self.btn_back.setIconSize(QSize(icon_size_px, icon_size_px))
|
|
109
109
|
self.btn_back.setFixedHeight(nav_height - 8)
|
|
110
110
|
self.btn_back.setEnabled(False)
|
|
111
|
-
self.btn_back.setAutoDefault(False) # prevent Enter from triggering this
|
|
111
|
+
self.btn_back.setAutoDefault(False) # prevent Enter from triggering this
|
|
112
112
|
try:
|
|
113
113
|
self.btn_back.setDefault(False)
|
|
114
114
|
except Exception:
|
|
@@ -116,11 +116,11 @@ class ToolWidget:
|
|
|
116
116
|
|
|
117
117
|
self.btn_next = QPushButton()
|
|
118
118
|
self.btn_next.setToolTip("Next")
|
|
119
|
-
self.btn_next.setIcon(QIcon(":/icons/
|
|
119
|
+
self.btn_next.setIcon(QIcon(":/icons/forward.svg"))
|
|
120
120
|
self.btn_next.setIconSize(QSize(icon_size_px, icon_size_px))
|
|
121
121
|
self.btn_next.setFixedHeight(nav_height - 8)
|
|
122
122
|
self.btn_next.setEnabled(False)
|
|
123
|
-
self.btn_next.setAutoDefault(False)
|
|
123
|
+
self.btn_next.setAutoDefault(False)
|
|
124
124
|
try:
|
|
125
125
|
self.btn_next.setDefault(False)
|
|
126
126
|
except Exception:
|
|
@@ -131,17 +131,19 @@ class ToolWidget:
|
|
|
131
131
|
self.btn_reload.setIcon(QIcon(":/icons/reload.svg"))
|
|
132
132
|
self.btn_reload.setIconSize(QSize(icon_size_px, icon_size_px))
|
|
133
133
|
self.btn_reload.setFixedHeight(nav_height - 8)
|
|
134
|
-
self.btn_reload.setAutoDefault(False)
|
|
134
|
+
self.btn_reload.setAutoDefault(False)
|
|
135
135
|
try:
|
|
136
136
|
self.btn_reload.setDefault(False)
|
|
137
137
|
except Exception:
|
|
138
138
|
pass
|
|
139
139
|
|
|
140
|
-
# "Go" button
|
|
141
|
-
self.btn_go = QPushButton(
|
|
140
|
+
# "Go" button
|
|
141
|
+
self.btn_go = QPushButton()
|
|
142
142
|
self.btn_go.setToolTip("Open URL")
|
|
143
|
+
self.btn_go.setIcon(QIcon(":/icons/redo.svg"))
|
|
144
|
+
self.btn_go.setIconSize(QSize(icon_size_px, icon_size_px))
|
|
143
145
|
self.btn_go.setFixedHeight(nav_height - 8)
|
|
144
|
-
self.btn_go.setAutoDefault(False) # avoid stealing Enter
|
|
146
|
+
self.btn_go.setAutoDefault(False) # avoid stealing Enter
|
|
145
147
|
try:
|
|
146
148
|
self.btn_go.setDefault(False)
|
|
147
149
|
except Exception:
|
|
@@ -185,7 +187,7 @@ class ToolWidget:
|
|
|
185
187
|
|
|
186
188
|
output_layout = QVBoxLayout()
|
|
187
189
|
# put navigation bar above the web output
|
|
188
|
-
output_layout.addWidget(self.nav_bar)
|
|
190
|
+
output_layout.addWidget(self.nav_bar)
|
|
189
191
|
output_layout.addWidget(self.output)
|
|
190
192
|
output_layout.addWidget(self.edit)
|
|
191
193
|
output_layout.setContentsMargins(0, 0, 0, 0)
|
|
@@ -256,9 +258,9 @@ class ToolWidget:
|
|
|
256
258
|
# Hide navigation bar when loading from local file/path
|
|
257
259
|
self._show_navbar(False)
|
|
258
260
|
|
|
259
|
-
#
|
|
260
|
-
# Navigation helpers
|
|
261
|
-
#
|
|
261
|
+
# ------------------
|
|
262
|
+
# Navigation helpers
|
|
263
|
+
# ------------------
|
|
262
264
|
def _show_navbar(self, show: bool):
|
|
263
265
|
"""Show/hide the navigation bar."""
|
|
264
266
|
if self.nav_bar:
|
|
@@ -287,7 +289,6 @@ class ToolWidget:
|
|
|
287
289
|
text = self.address_bar.text().strip()
|
|
288
290
|
if not text:
|
|
289
291
|
return
|
|
290
|
-
# Use fromUserInput to accept entries like 'example.com'
|
|
291
292
|
url = QUrl.fromUserInput(text)
|
|
292
293
|
if url.isValid():
|
|
293
294
|
self._show_navbar(True)
|
|
@@ -371,7 +372,7 @@ class CanvasEdit(BaseCodeEditor):
|
|
|
371
372
|
return super().eventFilter(source, event)
|
|
372
373
|
|
|
373
374
|
|
|
374
|
-
# --- Address bar input widget
|
|
375
|
+
# --- Address bar input widget ---
|
|
375
376
|
class AddressLineEdit(QLineEdit):
|
|
376
377
|
"""
|
|
377
378
|
Custom QLineEdit that ensures Enter triggers opening the typed URL
|
|
@@ -0,0 +1,12 @@
|
|
|
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.22 19:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
from .tool import *
|
|
@@ -0,0 +1,232 @@
|
|
|
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.22 19:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
from typing import Dict
|
|
13
|
+
|
|
14
|
+
from PySide6.QtCore import QTimer, Slot
|
|
15
|
+
from PySide6.QtGui import QAction, QIcon
|
|
16
|
+
from PySide6.QtWidgets import QWidget
|
|
17
|
+
|
|
18
|
+
from pygpt_net.core.tabs.tab import Tab
|
|
19
|
+
from pygpt_net.core.text.utils import output_clean_html, output_html2text
|
|
20
|
+
from pygpt_net.tools.base import BaseTool, TabWidget
|
|
21
|
+
from pygpt_net.utils import trans
|
|
22
|
+
|
|
23
|
+
from .ui.dialogs import Tool
|
|
24
|
+
from .ui.widgets import ToolSignals
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class WebBrowser(BaseTool):
|
|
28
|
+
def __init__(self, *args, **kwargs):
|
|
29
|
+
"""
|
|
30
|
+
Web Browser tool
|
|
31
|
+
|
|
32
|
+
:param window: Window instance
|
|
33
|
+
"""
|
|
34
|
+
super(WebBrowser, self).__init__(*args, **kwargs)
|
|
35
|
+
self.id = "web_browser"
|
|
36
|
+
self.dialog_id = "web_browser"
|
|
37
|
+
self.has_tab = True
|
|
38
|
+
self.tab_title = "menu.tools.web_browser"
|
|
39
|
+
self.tab_icon = ":/icons/web_on.svg"
|
|
40
|
+
self.opened = False
|
|
41
|
+
self.is_edit = False
|
|
42
|
+
self.auto_clear = True
|
|
43
|
+
self.dialog = None
|
|
44
|
+
self.is_edit = False
|
|
45
|
+
self.auto_opened = False
|
|
46
|
+
self.signals = ToolSignals()
|
|
47
|
+
|
|
48
|
+
def setup(self):
|
|
49
|
+
"""Setup"""
|
|
50
|
+
self.update()
|
|
51
|
+
|
|
52
|
+
def on_reload(self):
|
|
53
|
+
"""On app profile reload"""
|
|
54
|
+
self.setup()
|
|
55
|
+
|
|
56
|
+
def update(self):
|
|
57
|
+
"""Update menu"""
|
|
58
|
+
self.update_menu()
|
|
59
|
+
|
|
60
|
+
def update_menu(self):
|
|
61
|
+
"""Update menu"""
|
|
62
|
+
"""
|
|
63
|
+
if self.opened:
|
|
64
|
+
self.window.ui.menu['tools.web_browser'].setChecked(True)
|
|
65
|
+
else:
|
|
66
|
+
self.window.ui.menu['tools.web_browser'].setChecked(False)
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def get_dialog_id(self) -> str:
|
|
70
|
+
"""
|
|
71
|
+
Get dialog ID
|
|
72
|
+
|
|
73
|
+
:return: Dialog ID
|
|
74
|
+
"""
|
|
75
|
+
return self.dialog_id
|
|
76
|
+
|
|
77
|
+
def set_url(self, url: str):
|
|
78
|
+
"""
|
|
79
|
+
Set output URL
|
|
80
|
+
|
|
81
|
+
:param url: URL to load
|
|
82
|
+
"""
|
|
83
|
+
self.signals.url.emit(url)
|
|
84
|
+
|
|
85
|
+
def open(self, load: bool = True):
|
|
86
|
+
"""
|
|
87
|
+
Open HTML canvas dialog
|
|
88
|
+
|
|
89
|
+
:param load: Load output data
|
|
90
|
+
"""
|
|
91
|
+
if not self.opened:
|
|
92
|
+
self.opened = True
|
|
93
|
+
self.auto_opened = False
|
|
94
|
+
self.window.ui.dialogs.open(self.dialog_id, width=800, height=600)
|
|
95
|
+
self.dialog.widget.on_open()
|
|
96
|
+
self.update()
|
|
97
|
+
|
|
98
|
+
def auto_open(self, load: bool = True):
|
|
99
|
+
"""
|
|
100
|
+
Auto open canvas dialog or tab
|
|
101
|
+
|
|
102
|
+
:param load: Load output data
|
|
103
|
+
"""
|
|
104
|
+
if self.window.controller.ui.tabs.is_current_tool(self.id):
|
|
105
|
+
tool_col = self.window.controller.ui.tabs.get_tool_column(self.id)
|
|
106
|
+
current_col = self.window.controller.ui.tabs.column_idx
|
|
107
|
+
if tool_col == 1 and tool_col != current_col:
|
|
108
|
+
self.window.controller.ui.tabs.enable_split_screen(True) # enable split screen
|
|
109
|
+
return # do not open if already opened in tab
|
|
110
|
+
elif self.window.controller.ui.tabs.is_tool(self.id):
|
|
111
|
+
tab = self.window.controller.ui.tabs.get_first_tab_by_tool(self.id)
|
|
112
|
+
if tab:
|
|
113
|
+
tool_col = tab.column_idx
|
|
114
|
+
current_col = self.window.controller.ui.tabs.column_idx
|
|
115
|
+
self.window.controller.ui.tabs.switch_tab_by_idx(tab.idx, tab.column_idx)
|
|
116
|
+
if tool_col == 1 and tool_col != current_col:
|
|
117
|
+
self.window.controller.ui.tabs.enable_split_screen(True) # enable split screen
|
|
118
|
+
return
|
|
119
|
+
if not self.auto_opened:
|
|
120
|
+
self.auto_opened = True
|
|
121
|
+
self.open(load=load)
|
|
122
|
+
|
|
123
|
+
def close(self):
|
|
124
|
+
"""Close HTML canvas dialog"""
|
|
125
|
+
self.opened = False
|
|
126
|
+
self.signals.closed.emit()
|
|
127
|
+
self.window.ui.dialogs.close(self.dialog_id)
|
|
128
|
+
self.update()
|
|
129
|
+
|
|
130
|
+
def toggle(self):
|
|
131
|
+
"""Toggle HTML canvas dialog open/close"""
|
|
132
|
+
if self.opened:
|
|
133
|
+
self.close()
|
|
134
|
+
else:
|
|
135
|
+
self.open()
|
|
136
|
+
|
|
137
|
+
@Slot(str, str)
|
|
138
|
+
def handle_save_as(self, text: str, type: str = 'txt'):
|
|
139
|
+
"""
|
|
140
|
+
Handle save as signal
|
|
141
|
+
|
|
142
|
+
:param text: Data to save
|
|
143
|
+
:param type: File type
|
|
144
|
+
"""
|
|
145
|
+
if type == 'html':
|
|
146
|
+
text = output_clean_html(text)
|
|
147
|
+
else:
|
|
148
|
+
text = output_html2text(text)
|
|
149
|
+
# fix: QTimer required here to prevent crash if signal emitted from WebEngine window
|
|
150
|
+
QTimer.singleShot(0, lambda: self.window.controller.chat.common.save_text(text, type))
|
|
151
|
+
|
|
152
|
+
def show_hide(self, show: bool = True):
|
|
153
|
+
"""
|
|
154
|
+
Show/hide HTML canvas window
|
|
155
|
+
|
|
156
|
+
:param show: show/hide
|
|
157
|
+
"""
|
|
158
|
+
if show:
|
|
159
|
+
self.open()
|
|
160
|
+
else:
|
|
161
|
+
self.close()
|
|
162
|
+
|
|
163
|
+
def get_toolbar_icon(self) -> QWidget:
|
|
164
|
+
"""
|
|
165
|
+
Get toolbar icon
|
|
166
|
+
|
|
167
|
+
:return: QWidget
|
|
168
|
+
"""
|
|
169
|
+
return self.window.ui.nodes['icon.web_browser']
|
|
170
|
+
|
|
171
|
+
def toggle_icon(self, state: bool):
|
|
172
|
+
"""
|
|
173
|
+
Toggle canvas icon
|
|
174
|
+
|
|
175
|
+
:param state: State
|
|
176
|
+
"""
|
|
177
|
+
self.get_toolbar_icon().setVisible(state)
|
|
178
|
+
|
|
179
|
+
def setup_menu(self) -> Dict[str, QAction]:
|
|
180
|
+
"""
|
|
181
|
+
Setup main menu
|
|
182
|
+
|
|
183
|
+
:return dict with menu actions
|
|
184
|
+
"""
|
|
185
|
+
actions = {}
|
|
186
|
+
actions["web_browser"] = QAction(
|
|
187
|
+
QIcon(":/icons/web_on.svg"),
|
|
188
|
+
trans("menu.tools.web_browser"),
|
|
189
|
+
self.window,
|
|
190
|
+
checkable=False,
|
|
191
|
+
)
|
|
192
|
+
actions["web_browser"].triggered.connect(
|
|
193
|
+
lambda: self.toggle()
|
|
194
|
+
)
|
|
195
|
+
return actions
|
|
196
|
+
|
|
197
|
+
def as_tab(self, tab: Tab) -> QWidget:
|
|
198
|
+
"""
|
|
199
|
+
Spawn and return tab instance
|
|
200
|
+
|
|
201
|
+
:param tab: Parent Tab instance
|
|
202
|
+
:return: Tab widget instance
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
tool = Tool(window=self.window, tool=self) # dialog
|
|
206
|
+
tool_widget = tool.as_tab() # ToolWidget
|
|
207
|
+
widget = TabWidget()
|
|
208
|
+
widget.from_tool(tool_widget)
|
|
209
|
+
widget.setup()
|
|
210
|
+
tool.set_tab(tab)
|
|
211
|
+
return widget
|
|
212
|
+
|
|
213
|
+
def setup_dialogs(self):
|
|
214
|
+
"""Setup dialogs (static)"""
|
|
215
|
+
self.dialog = Tool(window=self.window, tool=self)
|
|
216
|
+
self.dialog.setup()
|
|
217
|
+
|
|
218
|
+
def setup_theme(self):
|
|
219
|
+
"""Setup theme"""
|
|
220
|
+
pass
|
|
221
|
+
|
|
222
|
+
def get_lang_mappings(self) -> Dict[str, Dict]:
|
|
223
|
+
"""
|
|
224
|
+
Get language mappings
|
|
225
|
+
|
|
226
|
+
:return: dict with language mappings
|
|
227
|
+
"""
|
|
228
|
+
return {
|
|
229
|
+
'menu.text': {
|
|
230
|
+
'tools.web_browser': 'menu.tools.web_browser',
|
|
231
|
+
}
|
|
232
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,123 @@
|
|
|
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.22 19:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
|
|
14
|
+
from PySide6.QtCore import Qt
|
|
15
|
+
from PySide6.QtGui import QAction, QIcon
|
|
16
|
+
from PySide6.QtWidgets import QMenuBar, QVBoxLayout
|
|
17
|
+
|
|
18
|
+
from pygpt_net.core.tabs.tab import Tab
|
|
19
|
+
from pygpt_net.ui.widget.dialog.base import BaseDialog
|
|
20
|
+
from pygpt_net.utils import trans
|
|
21
|
+
|
|
22
|
+
from .widgets import ToolWidget
|
|
23
|
+
|
|
24
|
+
class Tool:
|
|
25
|
+
def __init__(self, window=None, tool=None):
|
|
26
|
+
"""
|
|
27
|
+
HTML/JS canvas dialog
|
|
28
|
+
|
|
29
|
+
:param window: Window instance
|
|
30
|
+
:param tool: Tool instance
|
|
31
|
+
"""
|
|
32
|
+
self.window = window
|
|
33
|
+
self.tool = tool # tool instance
|
|
34
|
+
self.widget = ToolWidget(window, tool)
|
|
35
|
+
self.layout = None
|
|
36
|
+
self.menu_bar = None
|
|
37
|
+
self.menu = {}
|
|
38
|
+
self.actions = {} # menu actions
|
|
39
|
+
|
|
40
|
+
def as_tab(self) -> ToolWidget:
|
|
41
|
+
"""
|
|
42
|
+
Return tool as tab
|
|
43
|
+
|
|
44
|
+
:return: ToolWidget
|
|
45
|
+
"""
|
|
46
|
+
return self.widget
|
|
47
|
+
|
|
48
|
+
def set_tab(self, tab: Tab):
|
|
49
|
+
"""
|
|
50
|
+
Set tab
|
|
51
|
+
|
|
52
|
+
:param tab: Tab
|
|
53
|
+
"""
|
|
54
|
+
self.widget.set_tab(tab)
|
|
55
|
+
|
|
56
|
+
def setup(self):
|
|
57
|
+
"""Setup canvas dialog"""
|
|
58
|
+
self.layout = self.widget.setup()
|
|
59
|
+
|
|
60
|
+
id = self.tool.get_dialog_id()
|
|
61
|
+
dialog = ToolDialog(window=self.window, tool=self.tool)
|
|
62
|
+
dialog.setLayout(self.layout)
|
|
63
|
+
dialog.setWindowTitle(trans("menu.tools.web_browser"))
|
|
64
|
+
dialog.resize(800, 500)
|
|
65
|
+
self.window.ui.dialog[id] = dialog
|
|
66
|
+
|
|
67
|
+
def get_widget(self) -> ToolWidget:
|
|
68
|
+
"""
|
|
69
|
+
Get widget
|
|
70
|
+
|
|
71
|
+
:return: ToolWidget
|
|
72
|
+
"""
|
|
73
|
+
return self.widget
|
|
74
|
+
|
|
75
|
+
def get_tab(self) -> QVBoxLayout:
|
|
76
|
+
"""
|
|
77
|
+
Get layout
|
|
78
|
+
|
|
79
|
+
:return: QVBoxLayout
|
|
80
|
+
"""
|
|
81
|
+
return self.layout
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class ToolDialog(BaseDialog):
|
|
85
|
+
def __init__(self, window=None, id="html_canvas", tool=None):
|
|
86
|
+
"""
|
|
87
|
+
HTML canvas dialog
|
|
88
|
+
|
|
89
|
+
:param window: main window
|
|
90
|
+
:param id: logger id
|
|
91
|
+
"""
|
|
92
|
+
super(ToolDialog, self).__init__(window, id)
|
|
93
|
+
self.window = window
|
|
94
|
+
self.tool = tool
|
|
95
|
+
|
|
96
|
+
def closeEvent(self, event):
|
|
97
|
+
"""
|
|
98
|
+
Close event
|
|
99
|
+
|
|
100
|
+
:param event: close event
|
|
101
|
+
"""
|
|
102
|
+
self.cleanup()
|
|
103
|
+
super(ToolDialog, self).closeEvent(event)
|
|
104
|
+
|
|
105
|
+
def keyPressEvent(self, event):
|
|
106
|
+
"""
|
|
107
|
+
Key press event
|
|
108
|
+
|
|
109
|
+
:param event: key press event
|
|
110
|
+
"""
|
|
111
|
+
if event.key() == Qt.Key_Escape:
|
|
112
|
+
self.cleanup()
|
|
113
|
+
self.close() # close dialog when the Esc key is pressed.
|
|
114
|
+
else:
|
|
115
|
+
super(ToolDialog, self).keyPressEvent(event)
|
|
116
|
+
|
|
117
|
+
def cleanup(self):
|
|
118
|
+
"""Cleanup on close"""
|
|
119
|
+
if self.window is None or self.tool is None:
|
|
120
|
+
return
|
|
121
|
+
self.tool.opened = False
|
|
122
|
+
self.tool.close()
|
|
123
|
+
self.tool.update()
|