pygpt-net 2.6.57__py3-none-any.whl → 2.6.59__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 (47) hide show
  1. pygpt_net/CHANGELOG.txt +10 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +30 -25
  4. pygpt_net/controller/debug/debug.py +3 -3
  5. pygpt_net/controller/dialogs/info.py +6 -2
  6. pygpt_net/controller/ui/tabs.py +17 -0
  7. pygpt_net/core/agents/runners/llama_workflow.py +0 -0
  8. pygpt_net/core/filesystem/parser.py +37 -24
  9. pygpt_net/core/filesystem/url.py +5 -2
  10. pygpt_net/data/config/config.json +4 -3
  11. pygpt_net/data/config/models.json +3 -3
  12. pygpt_net/data/config/settings.json +41 -2
  13. pygpt_net/data/js/app/ui.js +1 -1
  14. pygpt_net/data/js/app.min.js +2 -2
  15. pygpt_net/data/locale/locale.de.ini +5 -1
  16. pygpt_net/data/locale/locale.en.ini +5 -1
  17. pygpt_net/data/locale/locale.es.ini +5 -1
  18. pygpt_net/data/locale/locale.fr.ini +5 -1
  19. pygpt_net/data/locale/locale.it.ini +5 -1
  20. pygpt_net/data/locale/locale.pl.ini +5 -1
  21. pygpt_net/data/locale/locale.uk.ini +5 -1
  22. pygpt_net/data/locale/locale.zh.ini +5 -1
  23. pygpt_net/data/locale/plugin.cmd_system.en.ini +68 -0
  24. pygpt_net/js_rc.py +5 -5
  25. pygpt_net/plugin/base/plugin.py +3 -5
  26. pygpt_net/plugin/cmd_system/config.py +377 -1
  27. pygpt_net/plugin/cmd_system/plugin.py +52 -8
  28. pygpt_net/plugin/cmd_system/runner.py +508 -32
  29. pygpt_net/plugin/cmd_system/winapi.py +481 -0
  30. pygpt_net/plugin/cmd_system/worker.py +88 -15
  31. pygpt_net/provider/agents/llama_index/workflow/supervisor.py +0 -0
  32. pygpt_net/provider/core/config/patch.py +8 -1
  33. pygpt_net/provider/llms/openai.py +6 -4
  34. pygpt_net/tools/code_interpreter/ui/html.py +2 -1
  35. pygpt_net/tools/html_canvas/ui/widgets.py +19 -18
  36. pygpt_net/tools/web_browser/__init__.py +12 -0
  37. pygpt_net/tools/web_browser/tool.py +232 -0
  38. pygpt_net/tools/web_browser/ui/__init__.py +0 -0
  39. pygpt_net/tools/web_browser/ui/dialogs.py +123 -0
  40. pygpt_net/tools/web_browser/ui/widgets.py +351 -0
  41. pygpt_net/ui/widget/textarea/html.py +172 -24
  42. pygpt_net/ui/widget/textarea/web.py +1 -1
  43. {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.59.dist-info}/METADATA +81 -61
  44. {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.59.dist-info}/RECORD +45 -39
  45. {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.59.dist-info}/LICENSE +0 -0
  46. {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.59.dist-info}/WHEEL +0 -0
  47. {pygpt_net-2.6.57.dist-info → pygpt_net-2.6.59.dist-info}/entry_points.txt +0 -0
@@ -810,7 +810,8 @@ class CustomWebEnginePage(QWebEnginePage):
810
810
  :param line_number: line number
811
811
  :param source_id: source ID
812
812
  """
813
- self.signals.js_message.emit(line_number, message, source_id) # handled in debug controller
813
+ pass
814
+ # self.signals.js_message.emit(line_number, message, source_id) # handled in debug controller
814
815
 
815
816
  def cleanup(self):
816
817
  """Cleanup method to release resources"""
@@ -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.16 02:00:00 #
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 (added) ---
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 # "Go" button (text)
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 (added) ----
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 (use QPushButton with icons from resources)
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 (added)
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/redo.svg")) # use redo.svg as "next"
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) # (added)
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) # (added)
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 is text-only as requested
141
- self.btn_go = QPushButton("GO")
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 (added)
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) # added
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 (added)
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 (added) ---
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()