pygpt-net 2.6.56__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.
Files changed (221) hide show
  1. pygpt_net/CHANGELOG.txt +10 -0
  2. pygpt_net/__init__.py +1 -1
  3. pygpt_net/app.py +30 -25
  4. pygpt_net/config.py +44 -0
  5. pygpt_net/controller/chat/remote_tools.py +5 -3
  6. pygpt_net/controller/debug/debug.py +3 -3
  7. pygpt_net/controller/dialogs/info.py +6 -2
  8. pygpt_net/controller/ui/mode.py +5 -3
  9. pygpt_net/controller/ui/tabs.py +17 -0
  10. pygpt_net/core/filesystem/url.py +5 -2
  11. pygpt_net/core/models/models.py +2 -1
  12. pygpt_net/core/plugins/plugins.py +60 -0
  13. pygpt_net/data/config/config.json +4 -2
  14. pygpt_net/data/config/models.json +2 -2
  15. pygpt_net/data/config/settings.json +55 -2
  16. pygpt_net/data/js/app/ui.js +1 -1
  17. pygpt_net/data/js/app.min.js +2 -2
  18. pygpt_net/data/locale/locale.de.ini +7 -1
  19. pygpt_net/data/locale/locale.en.ini +12 -7
  20. pygpt_net/data/locale/locale.es.ini +6 -0
  21. pygpt_net/data/locale/locale.fr.ini +6 -0
  22. pygpt_net/data/locale/locale.it.ini +6 -0
  23. pygpt_net/data/locale/locale.pl.ini +7 -1
  24. pygpt_net/data/locale/locale.uk.ini +7 -1
  25. pygpt_net/data/locale/locale.zh.ini +6 -0
  26. pygpt_net/data/locale/plugin.agent.de.ini +0 -0
  27. pygpt_net/data/locale/plugin.agent.en.ini +0 -0
  28. pygpt_net/data/locale/plugin.agent.es.ini +0 -0
  29. pygpt_net/data/locale/plugin.agent.fr.ini +0 -0
  30. pygpt_net/data/locale/plugin.agent.it.ini +0 -0
  31. pygpt_net/data/locale/plugin.agent.pl.ini +0 -0
  32. pygpt_net/data/locale/plugin.agent.uk.ini +0 -0
  33. pygpt_net/data/locale/plugin.agent.zh.ini +0 -0
  34. pygpt_net/data/locale/plugin.audio_input.de.ini +0 -0
  35. pygpt_net/data/locale/plugin.audio_input.en.ini +0 -0
  36. pygpt_net/data/locale/plugin.audio_input.es.ini +0 -0
  37. pygpt_net/data/locale/plugin.audio_input.fr.ini +0 -0
  38. pygpt_net/data/locale/plugin.audio_input.it.ini +0 -0
  39. pygpt_net/data/locale/plugin.audio_input.pl.ini +0 -0
  40. pygpt_net/data/locale/plugin.audio_input.uk.ini +0 -0
  41. pygpt_net/data/locale/plugin.audio_input.zh.ini +0 -0
  42. pygpt_net/data/locale/plugin.audio_output.de.ini +0 -0
  43. pygpt_net/data/locale/plugin.audio_output.en.ini +0 -0
  44. pygpt_net/data/locale/plugin.audio_output.es.ini +0 -0
  45. pygpt_net/data/locale/plugin.audio_output.fr.ini +0 -0
  46. pygpt_net/data/locale/plugin.audio_output.it.ini +0 -0
  47. pygpt_net/data/locale/plugin.audio_output.pl.ini +0 -0
  48. pygpt_net/data/locale/plugin.audio_output.uk.ini +0 -0
  49. pygpt_net/data/locale/plugin.audio_output.zh.ini +0 -0
  50. pygpt_net/data/locale/plugin.cmd_api.de.ini +0 -0
  51. pygpt_net/data/locale/plugin.cmd_api.en.ini +0 -0
  52. pygpt_net/data/locale/plugin.cmd_api.es.ini +0 -0
  53. pygpt_net/data/locale/plugin.cmd_api.fr.ini +0 -0
  54. pygpt_net/data/locale/plugin.cmd_api.it.ini +0 -0
  55. pygpt_net/data/locale/plugin.cmd_api.pl.ini +0 -0
  56. pygpt_net/data/locale/plugin.cmd_api.uk.ini +0 -0
  57. pygpt_net/data/locale/plugin.cmd_api.zh.ini +0 -0
  58. pygpt_net/data/locale/plugin.cmd_code_interpreter.de.ini +0 -0
  59. pygpt_net/data/locale/plugin.cmd_code_interpreter.en.ini +0 -0
  60. pygpt_net/data/locale/plugin.cmd_code_interpreter.es.ini +0 -0
  61. pygpt_net/data/locale/plugin.cmd_code_interpreter.fr.ini +0 -0
  62. pygpt_net/data/locale/plugin.cmd_code_interpreter.it.ini +0 -0
  63. pygpt_net/data/locale/plugin.cmd_code_interpreter.pl.ini +0 -0
  64. pygpt_net/data/locale/plugin.cmd_code_interpreter.uk.ini +0 -0
  65. pygpt_net/data/locale/plugin.cmd_code_interpreter.zh.ini +0 -0
  66. pygpt_net/data/locale/plugin.cmd_custom.de.ini +0 -0
  67. pygpt_net/data/locale/plugin.cmd_custom.en.ini +0 -0
  68. pygpt_net/data/locale/plugin.cmd_custom.es.ini +0 -0
  69. pygpt_net/data/locale/plugin.cmd_custom.fr.ini +0 -0
  70. pygpt_net/data/locale/plugin.cmd_custom.it.ini +0 -0
  71. pygpt_net/data/locale/plugin.cmd_custom.pl.ini +0 -0
  72. pygpt_net/data/locale/plugin.cmd_custom.uk.ini +0 -0
  73. pygpt_net/data/locale/plugin.cmd_custom.zh.ini +0 -0
  74. pygpt_net/data/locale/plugin.cmd_files.de.ini +0 -0
  75. pygpt_net/data/locale/plugin.cmd_files.en.ini +0 -0
  76. pygpt_net/data/locale/plugin.cmd_files.es.ini +0 -0
  77. pygpt_net/data/locale/plugin.cmd_files.fr.ini +0 -0
  78. pygpt_net/data/locale/plugin.cmd_files.it.ini +0 -0
  79. pygpt_net/data/locale/plugin.cmd_files.pl.ini +0 -0
  80. pygpt_net/data/locale/plugin.cmd_files.uk.ini +0 -0
  81. pygpt_net/data/locale/plugin.cmd_files.zh.ini +0 -0
  82. pygpt_net/data/locale/plugin.cmd_history.de.ini +0 -0
  83. pygpt_net/data/locale/plugin.cmd_history.en.ini +0 -0
  84. pygpt_net/data/locale/plugin.cmd_history.es.ini +0 -0
  85. pygpt_net/data/locale/plugin.cmd_history.fr.ini +0 -0
  86. pygpt_net/data/locale/plugin.cmd_history.it.ini +0 -0
  87. pygpt_net/data/locale/plugin.cmd_history.pl.ini +0 -0
  88. pygpt_net/data/locale/plugin.cmd_history.uk.ini +0 -0
  89. pygpt_net/data/locale/plugin.cmd_history.zh.ini +0 -0
  90. pygpt_net/data/locale/plugin.cmd_mouse_control.de.ini +0 -0
  91. pygpt_net/data/locale/plugin.cmd_mouse_control.en.ini +0 -0
  92. pygpt_net/data/locale/plugin.cmd_mouse_control.es.ini +0 -0
  93. pygpt_net/data/locale/plugin.cmd_mouse_control.fr.ini +0 -0
  94. pygpt_net/data/locale/plugin.cmd_mouse_control.it.ini +0 -0
  95. pygpt_net/data/locale/plugin.cmd_mouse_control.pl.ini +0 -0
  96. pygpt_net/data/locale/plugin.cmd_mouse_control.uk.ini +0 -0
  97. pygpt_net/data/locale/plugin.cmd_mouse_control.zh.ini +0 -0
  98. pygpt_net/data/locale/plugin.cmd_serial.de.ini +0 -0
  99. pygpt_net/data/locale/plugin.cmd_serial.en.ini +0 -0
  100. pygpt_net/data/locale/plugin.cmd_serial.es.ini +0 -0
  101. pygpt_net/data/locale/plugin.cmd_serial.fr.ini +0 -0
  102. pygpt_net/data/locale/plugin.cmd_serial.it.ini +0 -0
  103. pygpt_net/data/locale/plugin.cmd_serial.pl.ini +0 -0
  104. pygpt_net/data/locale/plugin.cmd_serial.uk.ini +0 -0
  105. pygpt_net/data/locale/plugin.cmd_serial.zh.ini +0 -0
  106. pygpt_net/data/locale/plugin.cmd_system.de.ini +0 -0
  107. pygpt_net/data/locale/plugin.cmd_system.en.ini +0 -0
  108. pygpt_net/data/locale/plugin.cmd_system.es.ini +0 -0
  109. pygpt_net/data/locale/plugin.cmd_system.fr.ini +0 -0
  110. pygpt_net/data/locale/plugin.cmd_system.it.ini +0 -0
  111. pygpt_net/data/locale/plugin.cmd_system.pl.ini +0 -0
  112. pygpt_net/data/locale/plugin.cmd_system.uk.ini +0 -0
  113. pygpt_net/data/locale/plugin.cmd_system.zh.ini +0 -0
  114. pygpt_net/data/locale/plugin.cmd_web.de.ini +0 -0
  115. pygpt_net/data/locale/plugin.cmd_web.en.ini +0 -0
  116. pygpt_net/data/locale/plugin.cmd_web.es.ini +0 -0
  117. pygpt_net/data/locale/plugin.cmd_web.fr.ini +0 -0
  118. pygpt_net/data/locale/plugin.cmd_web.it.ini +0 -0
  119. pygpt_net/data/locale/plugin.cmd_web.pl.ini +0 -0
  120. pygpt_net/data/locale/plugin.cmd_web.uk.ini +0 -0
  121. pygpt_net/data/locale/plugin.cmd_web.zh.ini +0 -0
  122. pygpt_net/data/locale/plugin.crontab.de.ini +0 -0
  123. pygpt_net/data/locale/plugin.crontab.en.ini +0 -0
  124. pygpt_net/data/locale/plugin.crontab.es.ini +0 -0
  125. pygpt_net/data/locale/plugin.crontab.fr.ini +0 -0
  126. pygpt_net/data/locale/plugin.crontab.it.ini +0 -0
  127. pygpt_net/data/locale/plugin.crontab.pl.ini +0 -0
  128. pygpt_net/data/locale/plugin.crontab.uk.ini +0 -0
  129. pygpt_net/data/locale/plugin.crontab.zh.ini +0 -0
  130. pygpt_net/data/locale/plugin.experts.de.ini +0 -0
  131. pygpt_net/data/locale/plugin.experts.en.ini +0 -0
  132. pygpt_net/data/locale/plugin.experts.es.ini +0 -0
  133. pygpt_net/data/locale/plugin.experts.fr.ini +0 -0
  134. pygpt_net/data/locale/plugin.experts.it.ini +0 -0
  135. pygpt_net/data/locale/plugin.experts.pl.ini +0 -0
  136. pygpt_net/data/locale/plugin.experts.uk.ini +0 -0
  137. pygpt_net/data/locale/plugin.experts.zh.ini +0 -0
  138. pygpt_net/data/locale/plugin.extra_prompt.de.ini +0 -0
  139. pygpt_net/data/locale/plugin.extra_prompt.en.ini +0 -0
  140. pygpt_net/data/locale/plugin.extra_prompt.es.ini +0 -0
  141. pygpt_net/data/locale/plugin.extra_prompt.fr.ini +0 -0
  142. pygpt_net/data/locale/plugin.extra_prompt.it.ini +0 -0
  143. pygpt_net/data/locale/plugin.extra_prompt.pl.ini +0 -0
  144. pygpt_net/data/locale/plugin.extra_prompt.uk.ini +0 -0
  145. pygpt_net/data/locale/plugin.extra_prompt.zh.ini +0 -0
  146. pygpt_net/data/locale/plugin.idx_llama_index.de.ini +0 -0
  147. pygpt_net/data/locale/plugin.idx_llama_index.en.ini +0 -0
  148. pygpt_net/data/locale/plugin.idx_llama_index.es.ini +0 -0
  149. pygpt_net/data/locale/plugin.idx_llama_index.fr.ini +0 -0
  150. pygpt_net/data/locale/plugin.idx_llama_index.it.ini +0 -0
  151. pygpt_net/data/locale/plugin.idx_llama_index.pl.ini +0 -0
  152. pygpt_net/data/locale/plugin.idx_llama_index.uk.ini +0 -0
  153. pygpt_net/data/locale/plugin.idx_llama_index.zh.ini +0 -0
  154. pygpt_net/data/locale/plugin.mailer.en.ini +0 -0
  155. pygpt_net/data/locale/plugin.mcp.en.ini +0 -0
  156. pygpt_net/data/locale/plugin.openai_dalle.de.ini +0 -0
  157. pygpt_net/data/locale/plugin.openai_dalle.en.ini +0 -0
  158. pygpt_net/data/locale/plugin.openai_dalle.es.ini +0 -0
  159. pygpt_net/data/locale/plugin.openai_dalle.fr.ini +0 -0
  160. pygpt_net/data/locale/plugin.openai_dalle.it.ini +0 -0
  161. pygpt_net/data/locale/plugin.openai_dalle.pl.ini +0 -0
  162. pygpt_net/data/locale/plugin.openai_dalle.uk.ini +0 -0
  163. pygpt_net/data/locale/plugin.openai_dalle.zh.ini +0 -0
  164. pygpt_net/data/locale/plugin.openai_vision.de.ini +0 -0
  165. pygpt_net/data/locale/plugin.openai_vision.en.ini +0 -0
  166. pygpt_net/data/locale/plugin.openai_vision.es.ini +0 -0
  167. pygpt_net/data/locale/plugin.openai_vision.fr.ini +0 -0
  168. pygpt_net/data/locale/plugin.openai_vision.it.ini +0 -0
  169. pygpt_net/data/locale/plugin.openai_vision.pl.ini +0 -0
  170. pygpt_net/data/locale/plugin.openai_vision.uk.ini +0 -0
  171. pygpt_net/data/locale/plugin.openai_vision.zh.ini +0 -0
  172. pygpt_net/data/locale/plugin.osm.en.ini +24 -24
  173. pygpt_net/data/locale/plugin.real_time.de.ini +0 -0
  174. pygpt_net/data/locale/plugin.real_time.en.ini +0 -0
  175. pygpt_net/data/locale/plugin.real_time.es.ini +0 -0
  176. pygpt_net/data/locale/plugin.real_time.fr.ini +0 -0
  177. pygpt_net/data/locale/plugin.real_time.it.ini +0 -0
  178. pygpt_net/data/locale/plugin.real_time.pl.ini +0 -0
  179. pygpt_net/data/locale/plugin.real_time.uk.ini +0 -0
  180. pygpt_net/data/locale/plugin.real_time.zh.ini +0 -0
  181. pygpt_net/data/locale/plugin.voice_control.de.ini +0 -0
  182. pygpt_net/data/locale/plugin.voice_control.en.ini +0 -0
  183. pygpt_net/data/locale/plugin.voice_control.es.ini +0 -0
  184. pygpt_net/data/locale/plugin.voice_control.fr.ini +0 -0
  185. pygpt_net/data/locale/plugin.voice_control.it.ini +0 -0
  186. pygpt_net/data/locale/plugin.voice_control.pl.ini +0 -0
  187. pygpt_net/data/locale/plugin.voice_control.uk.ini +0 -0
  188. pygpt_net/data/locale/plugin.voice_control.zh.ini +0 -0
  189. pygpt_net/data/locale/plugin.wolfram.en.ini +9 -9
  190. pygpt_net/js_rc.py +5 -5
  191. pygpt_net/plugin/base/plugin.py +3 -5
  192. pygpt_net/plugin/cmd_web/config.py +17 -17
  193. pygpt_net/plugin/cmd_web/worker.py +325 -171
  194. pygpt_net/provider/api/x_ai/__init__.py +2 -0
  195. pygpt_net/provider/core/config/patch.py +23 -1
  196. pygpt_net/provider/core/config/patches/patch_before_2_6_42.py +1 -0
  197. pygpt_net/provider/llms/anthropic.py +4 -0
  198. pygpt_net/provider/llms/base.py +2 -0
  199. pygpt_net/provider/llms/deepseek_api.py +2 -0
  200. pygpt_net/provider/llms/google.py +2 -0
  201. pygpt_net/provider/llms/hugging_face_api.py +4 -0
  202. pygpt_net/provider/llms/hugging_face_router.py +2 -0
  203. pygpt_net/provider/llms/mistral.py +4 -0
  204. pygpt_net/provider/llms/perplexity.py +2 -0
  205. pygpt_net/provider/llms/x_ai.py +2 -0
  206. pygpt_net/tools/html_canvas/ui/widgets.py +19 -18
  207. pygpt_net/tools/web_browser/__init__.py +12 -0
  208. pygpt_net/tools/web_browser/tool.py +232 -0
  209. pygpt_net/tools/web_browser/ui/__init__.py +0 -0
  210. pygpt_net/tools/web_browser/ui/dialogs.py +123 -0
  211. pygpt_net/tools/web_browser/ui/widgets.py +351 -0
  212. pygpt_net/ui/layout/chat/output.py +5 -5
  213. pygpt_net/ui/widget/dialog/base.py +4 -1
  214. pygpt_net/ui/widget/textarea/html.py +173 -24
  215. pygpt_net/ui/widget/textarea/input.py +19 -3
  216. pygpt_net/ui/widget/textarea/web.py +2 -1
  217. {pygpt_net-2.6.56.dist-info → pygpt_net-2.6.58.dist-info}/METADATA +26 -2
  218. {pygpt_net-2.6.56.dist-info → pygpt_net-2.6.58.dist-info}/RECORD +59 -54
  219. {pygpt_net-2.6.56.dist-info → pygpt_net-2.6.58.dist-info}/LICENSE +0 -0
  220. {pygpt_net-2.6.56.dist-info → pygpt_net-2.6.58.dist-info}/WHEEL +0 -0
  221. {pygpt_net-2.6.56.dist-info → pygpt_net-2.6.58.dist-info}/entry_points.txt +0 -0
@@ -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.17 05:00:00 #
9
+ # Updated Date: 2025.09.22 19:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -31,6 +31,7 @@ class Patch:
31
31
  """
32
32
  data = self.window.core.config.all()
33
33
  cfg_get_base = self.window.core.config.get_base
34
+ remove_plugin_config = self.window.core.config.remove_plugin_config
34
35
  patch_css = self.window.core.updater.patch_css
35
36
  current = "0.0.0"
36
37
  updated = False
@@ -129,6 +130,27 @@ class Patch:
129
130
  patch_css('web-chatgpt_wide.darkest.css', True)
130
131
  updated = True
131
132
 
133
+ # < 2.6.57
134
+ if old < parse_version("2.6.57"):
135
+ print("Migrating config from < 2.6.57...")
136
+ remove_plugin_config("cmd_web", "max_open_urls")
137
+ remove_plugin_config("cmd_web", "cmd.web_url_open")
138
+ remove_plugin_config("cmd_web", "cmd.web_url_raw")
139
+ remove_plugin_config("cmd_web", "cmd.web_extract_links")
140
+ remove_plugin_config("cmd_web", "cmd.web_extract_images")
141
+ if "api_proxy.enabled" not in data:
142
+ data["api_proxy.enabled"] = False
143
+ if "api_proxy" in data and data["api_proxy"]:
144
+ data["api_proxy.enabled"] = True
145
+ updated = True
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
+
132
154
  # update file
133
155
  migrated = False
134
156
  if updated:
@@ -29,6 +29,7 @@ class Patch:
29
29
  """
30
30
  data = self.window.core.config.all()
31
31
  cfg_get_base = self.window.core.config.get_base
32
+ remove_plugin_config = self.window.core.config.remove_plugin_config
32
33
  patch_css = self.window.core.updater.patch_css
33
34
  current = "0.0.0"
34
35
  updated = False
@@ -73,6 +73,8 @@ class AnthropicLLM(BaseLLM):
73
73
 
74
74
  args = self.parse_args(model.llama_index, window)
75
75
  proxy = window.core.config.get("api_proxy", None)
76
+ if not window.core.config.get("api_proxy.enabled", False):
77
+ proxy = None
76
78
  if "model" not in args:
77
79
  args["model"] = model.id
78
80
  if "api_key" not in args or args["api_key"] == "":
@@ -136,6 +138,8 @@ class AnthropicLLM(BaseLLM):
136
138
  timeout = window.core.config.get("api_native_voyage.timeout")
137
139
  max_retries = window.core.config.get("api_native_voyage.max_retries")
138
140
  proxy = window.core.config.get("api_proxy")
141
+ if not window.core.config.get("api_proxy.enabled", False):
142
+ proxy = ""
139
143
  return VoyageEmbeddingWithProxy(
140
144
  **args,
141
145
  proxy=proxy,
@@ -231,6 +231,8 @@ class BaseLLM:
231
231
  def inject_llamaindex_http_clients(self, args: dict, cfg) -> dict:
232
232
  import httpx
233
233
  proxy = (cfg.get("api_proxy") or "").strip() # e.g. "http://user:pass@host:3128"
234
+ if not cfg.get("api_proxy.enabled", False):
235
+ proxy = ""
234
236
  common_kwargs = dict(timeout=60.0, follow_redirects=True)
235
237
  if proxy:
236
238
  common_kwargs["proxy"] = proxy # httpx>=0.28
@@ -80,6 +80,8 @@ class DeepseekApiLLM(BaseLLM):
80
80
  timeout = window.core.config.get("api_native_voyage.timeout")
81
81
  max_retries = window.core.config.get("api_native_voyage.max_retries")
82
82
  proxy = window.core.config.get("api_proxy")
83
+ if not window.core.config.get("api_proxy.enabled", False):
84
+ proxy = ""
83
85
  return VoyageEmbeddingWithProxy(
84
86
  **args,
85
87
  proxy=proxy,
@@ -140,6 +140,8 @@ class GoogleLLM(BaseLLM):
140
140
 
141
141
  def inject_llamaindex_http_clients(self, args: dict, cfg) -> dict:
142
142
  proxy = cfg.get("api_proxy")
143
+ if not cfg.get("api_proxy.enabled", False):
144
+ proxy = ""
143
145
  if proxy:
144
146
  http_options = gtypes.HttpOptions(
145
147
  client_args={"proxy": proxy},
@@ -117,6 +117,8 @@ class HuggingFaceApiLLM(BaseLLM):
117
117
 
118
118
  # proxy + trust_env (async)
119
119
  proxy = cfg.get("api_proxy") or cfg.get("api_native_hf.proxy")
120
+ if not cfg.get("api_proxy.enabled", False):
121
+ proxy = ""
120
122
  trust_env = cfg.get("api_native_hf.trust_env", False)
121
123
 
122
124
  return HuggingFaceInferenceAPIWithProxy(proxy=proxy, trust_env=trust_env, **args)
@@ -152,6 +154,8 @@ class HuggingFaceApiLLM(BaseLLM):
152
154
 
153
155
  # proxy + trust_env (async)
154
156
  proxy = window.core.config.get("api_proxy") or window.core.config.get("api_native_hf.proxy")
157
+ if not window.core.config.get("api_proxy.enabled", False):
158
+ proxy = ""
155
159
  trust_env = window.core.config.get("api_native_hf.trust_env", False)
156
160
 
157
161
  return HFEmbed(proxy=proxy, trust_env=trust_env, **args)
@@ -132,6 +132,8 @@ class HuggingFaceRouterLLM(BaseLLM):
132
132
 
133
133
  # proxy + trust_env (async)
134
134
  proxy = window.core.config.get("api_proxy") or window.core.config.get("api_native_hf.proxy")
135
+ if not window.core.config.get("api_proxy.enabled", False):
136
+ proxy = ""
135
137
  trust_env = window.core.config.get("api_native_hf.trust_env", False)
136
138
 
137
139
  return HFEmbed(proxy=proxy, trust_env=trust_env, **args)
@@ -74,6 +74,8 @@ class MistralAILLM(BaseLLM):
74
74
 
75
75
  args = self.parse_args(model.llama_index, window)
76
76
  proxy = window.core.config.get("api_proxy") or None
77
+ if not window.core.config.get("api_proxy.enabled", False):
78
+ proxy = None
77
79
  if "model" not in args:
78
80
  args["model"] = model.id
79
81
  if "api_key" not in args or args["api_key"] == "":
@@ -130,6 +132,8 @@ class MistralAILLM(BaseLLM):
130
132
  args["model_name"] = args.pop("model")
131
133
 
132
134
  proxy = window.core.config.get("api_proxy") or None
135
+ if not window.core.config.get("api_proxy.enabled", False):
136
+ proxy = None
133
137
  return MistralAIEmbeddingWithProxy(**args, proxy=proxy)
134
138
 
135
139
  def init_embeddings(
@@ -101,6 +101,8 @@ class PerplexityLLM(BaseLLM):
101
101
  # -----------------------------------
102
102
  # TODO: fallback
103
103
  proxy = cfg.get("api_proxy") or cfg.get("api_native_perplexity.proxy")
104
+ if not cfg.get("api_proxy.enabled", False):
105
+ proxy = ""
104
106
 
105
107
  class PerplexityWithProxy(LlamaPerplexity):
106
108
  def __init__(self, *a, **kw):
@@ -158,6 +158,8 @@ class xAILLM(BaseLLM):
158
158
  args["api_base"] = cfg.get("api_endpoint_xai", "https://api.x.ai/v1")
159
159
 
160
160
  proxy = cfg.get("api_proxy") or cfg.get("api_native_xai.proxy")
161
+ if not cfg.get("api_proxy.enabled", False):
162
+ proxy = ""
161
163
  timeout = cfg.get("api_native_xai.timeout")
162
164
 
163
165
  # 1) REST (OpenAI-compatible)
@@ -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()