pygpt-net 2.4.37__py3-none-any.whl → 2.4.41__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 (255) hide show
  1. CHANGELOG.md +29 -0
  2. README.md +44 -115
  3. pygpt_net/CHANGELOG.txt +29 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/controller/__init__.py +7 -3
  6. pygpt_net/controller/access/control.py +1 -1
  7. pygpt_net/controller/access/voice.py +11 -5
  8. pygpt_net/controller/agent/experts.py +11 -6
  9. pygpt_net/controller/agent/legacy.py +8 -6
  10. pygpt_net/controller/agent/llama.py +4 -2
  11. pygpt_net/controller/assistant/__init__.py +9 -4
  12. pygpt_net/controller/assistant/batch.py +38 -21
  13. pygpt_net/controller/assistant/editor.py +7 -6
  14. pygpt_net/controller/assistant/files.py +23 -7
  15. pygpt_net/controller/assistant/store.py +20 -7
  16. pygpt_net/controller/assistant/threads.py +34 -8
  17. pygpt_net/controller/attachment.py +29 -10
  18. pygpt_net/controller/audio/__init__.py +25 -4
  19. pygpt_net/controller/calendar/__init__.py +23 -4
  20. pygpt_net/controller/calendar/note.py +57 -11
  21. pygpt_net/controller/camera.py +3 -2
  22. pygpt_net/controller/chat/__init__.py +5 -3
  23. pygpt_net/controller/chat/attachment.py +34 -7
  24. pygpt_net/controller/chat/command.py +4 -2
  25. pygpt_net/controller/chat/common.py +11 -4
  26. pygpt_net/controller/chat/files.py +10 -3
  27. pygpt_net/controller/chat/image.py +17 -5
  28. pygpt_net/controller/chat/input.py +10 -7
  29. pygpt_net/controller/chat/output.py +21 -6
  30. pygpt_net/controller/chat/render.py +100 -21
  31. pygpt_net/controller/chat/response.py +34 -7
  32. pygpt_net/controller/chat/stream.py +4 -2
  33. pygpt_net/controller/chat/text.py +6 -4
  34. pygpt_net/controller/command.py +11 -3
  35. pygpt_net/controller/config/__init__.py +34 -6
  36. pygpt_net/controller/config/field/checkbox.py +7 -4
  37. pygpt_net/controller/config/field/cmd.py +7 -5
  38. pygpt_net/controller/config/field/combo.py +14 -6
  39. pygpt_net/controller/config/field/dictionary.py +14 -11
  40. pygpt_net/controller/config/field/input.py +9 -6
  41. pygpt_net/controller/config/field/slider.py +11 -8
  42. pygpt_net/controller/config/field/textarea.py +8 -5
  43. pygpt_net/controller/config/placeholder.py +52 -21
  44. pygpt_net/controller/ctx/__init__.py +138 -49
  45. pygpt_net/controller/ctx/common.py +15 -4
  46. pygpt_net/controller/ctx/extra.py +11 -3
  47. pygpt_net/controller/ctx/summarizer.py +24 -5
  48. pygpt_net/controller/debug/__init__.py +27 -6
  49. pygpt_net/controller/dialogs/confirm.py +34 -7
  50. pygpt_net/controller/dialogs/debug.py +4 -2
  51. pygpt_net/controller/dialogs/info.py +7 -2
  52. pygpt_net/controller/files.py +48 -10
  53. pygpt_net/controller/finder.py +11 -5
  54. pygpt_net/controller/idx/__init__.py +10 -3
  55. pygpt_net/controller/idx/common.py +4 -2
  56. pygpt_net/controller/idx/indexer.py +25 -17
  57. pygpt_net/controller/idx/settings.py +9 -3
  58. pygpt_net/controller/kernel/__init__.py +34 -8
  59. pygpt_net/controller/kernel/reply.py +12 -3
  60. pygpt_net/controller/kernel/stack.py +5 -3
  61. pygpt_net/controller/lang/custom.py +2 -7
  62. pygpt_net/controller/lang/mapping.py +5 -3
  63. pygpt_net/controller/layout.py +2 -2
  64. pygpt_net/controller/mode.py +16 -4
  65. pygpt_net/controller/model/__init__.py +14 -3
  66. pygpt_net/controller/model/editor.py +8 -3
  67. pygpt_net/controller/notepad.py +26 -12
  68. pygpt_net/controller/painter/capture.py +23 -4
  69. pygpt_net/controller/painter/common.py +9 -7
  70. pygpt_net/controller/plugins/__init__.py +19 -5
  71. pygpt_net/controller/plugins/presets.py +15 -6
  72. pygpt_net/controller/plugins/settings.py +9 -3
  73. pygpt_net/controller/presets/__init__.py +55 -16
  74. pygpt_net/controller/presets/editor.py +26 -10
  75. pygpt_net/controller/settings/__init__.py +3 -2
  76. pygpt_net/controller/settings/editor.py +29 -7
  77. pygpt_net/controller/settings/profile.py +22 -5
  78. pygpt_net/controller/theme/__init__.py +54 -12
  79. pygpt_net/controller/theme/common.py +24 -2
  80. pygpt_net/controller/theme/markdown.py +32 -16
  81. pygpt_net/controller/theme/menu.py +26 -5
  82. pygpt_net/controller/theme/nodes.py +2 -5
  83. pygpt_net/controller/tools/__init__.py +40 -2
  84. pygpt_net/controller/ui/__init__.py +4 -6
  85. pygpt_net/controller/ui/tabs.py +363 -65
  86. pygpt_net/core/access/actions.py +6 -4
  87. pygpt_net/core/access/shortcuts.py +4 -3
  88. pygpt_net/core/access/voice.py +6 -5
  89. pygpt_net/core/agents/legacy.py +4 -2
  90. pygpt_net/core/agents/memory.py +7 -2
  91. pygpt_net/core/agents/observer/evaluation.py +15 -7
  92. pygpt_net/core/agents/provider.py +9 -4
  93. pygpt_net/core/agents/runner.py +61 -15
  94. pygpt_net/core/agents/tools.py +23 -5
  95. pygpt_net/core/assistants/__init__.py +6 -4
  96. pygpt_net/core/assistants/files.py +35 -12
  97. pygpt_net/core/assistants/store.py +20 -10
  98. pygpt_net/core/attachments/__init__.py +54 -15
  99. pygpt_net/core/attachments/context.py +92 -29
  100. pygpt_net/core/audio/__init__.py +71 -3
  101. pygpt_net/core/audio/context.py +7 -2
  102. pygpt_net/core/bridge/__init__.py +22 -6
  103. pygpt_net/core/bridge/context.py +5 -3
  104. pygpt_net/core/calendar/__init__.py +57 -11
  105. pygpt_net/core/chain/__init__.py +8 -2
  106. pygpt_net/core/chain/chat.py +10 -8
  107. pygpt_net/core/chain/completion.py +10 -7
  108. pygpt_net/core/command.py +62 -17
  109. pygpt_net/core/ctx/__init__.py +260 -58
  110. pygpt_net/core/ctx/bag.py +25 -4
  111. pygpt_net/core/ctx/container.py +28 -17
  112. pygpt_net/core/ctx/idx.py +45 -8
  113. pygpt_net/core/ctx/output.py +95 -74
  114. pygpt_net/core/ctx/reply.py +5 -2
  115. pygpt_net/core/db/__init__.py +8 -7
  116. pygpt_net/core/db/viewer.py +17 -11
  117. pygpt_net/core/debug/__init__.py +10 -9
  118. pygpt_net/core/debug/tabs.py +5 -2
  119. pygpt_net/core/docker/__init__.py +11 -5
  120. pygpt_net/core/docker/builder.py +11 -3
  121. pygpt_net/core/events/app.py +5 -3
  122. pygpt_net/core/events/base.py +11 -5
  123. pygpt_net/core/events/control.py +5 -3
  124. pygpt_net/core/events/event.py +17 -7
  125. pygpt_net/core/events/kernel.py +5 -3
  126. pygpt_net/core/events/render.py +5 -3
  127. pygpt_net/core/experts/__init__.py +5 -4
  128. pygpt_net/core/filesystem/__init__.py +52 -34
  129. pygpt_net/core/filesystem/actions.py +8 -5
  130. pygpt_net/core/filesystem/editor.py +13 -3
  131. pygpt_net/core/filesystem/types.py +12 -7
  132. pygpt_net/core/filesystem/url.py +7 -3
  133. pygpt_net/core/idx/__init__.py +34 -25
  134. pygpt_net/core/idx/chat.py +40 -16
  135. pygpt_net/core/idx/context.py +6 -2
  136. pygpt_net/core/idx/indexing.py +84 -35
  137. pygpt_net/core/idx/llm.py +11 -3
  138. pygpt_net/core/idx/metadata.py +13 -3
  139. pygpt_net/core/idx/types/ctx.py +32 -6
  140. pygpt_net/core/idx/types/external.py +41 -7
  141. pygpt_net/core/idx/types/files.py +31 -6
  142. pygpt_net/core/image.py +15 -4
  143. pygpt_net/core/llm/__init__.py +13 -3
  144. pygpt_net/core/locale.py +34 -8
  145. pygpt_net/core/models.py +4 -3
  146. pygpt_net/core/notepad.py +9 -4
  147. pygpt_net/core/plugins.py +7 -6
  148. pygpt_net/core/presets.py +19 -10
  149. pygpt_net/core/profile.py +12 -6
  150. pygpt_net/core/prompt/__init__.py +10 -3
  151. pygpt_net/core/prompt/custom.py +7 -6
  152. pygpt_net/core/prompt/template.py +9 -3
  153. pygpt_net/core/render/base.py +117 -22
  154. pygpt_net/core/render/markdown/body.py +27 -7
  155. pygpt_net/core/render/markdown/renderer.py +119 -22
  156. pygpt_net/core/render/plain/body.py +22 -5
  157. pygpt_net/core/render/plain/renderer.py +97 -21
  158. pygpt_net/core/render/web/body.py +75 -25
  159. pygpt_net/core/render/web/renderer.py +313 -63
  160. pygpt_net/core/settings.py +9 -4
  161. pygpt_net/core/tabs/__init__.py +290 -103
  162. pygpt_net/core/tabs/tab.py +17 -4
  163. pygpt_net/core/tokens.py +44 -11
  164. pygpt_net/core/updater/__init__.py +20 -7
  165. pygpt_net/core/vision/analyzer.py +29 -6
  166. pygpt_net/core/web.py +130 -2
  167. pygpt_net/data/config/config.json +15 -4
  168. pygpt_net/data/config/models.json +3 -3
  169. pygpt_net/data/config/modes.json +3 -3
  170. pygpt_net/data/config/settings.json +55 -10
  171. pygpt_net/data/config/settings_section.json +3 -0
  172. pygpt_net/data/css/style.light.css +1 -0
  173. pygpt_net/data/css/{web.css → web-blocks.css} +162 -133
  174. pygpt_net/data/css/{web.light.css → web-blocks.light.css} +7 -0
  175. pygpt_net/data/css/web-chatgpt.css +350 -0
  176. pygpt_net/data/css/web-chatgpt.dark.css +64 -0
  177. pygpt_net/data/css/web-chatgpt.light.css +75 -0
  178. pygpt_net/data/css/web-chatgpt_wide.css +350 -0
  179. pygpt_net/data/css/web-chatgpt_wide.dark.css +64 -0
  180. pygpt_net/data/css/web-chatgpt_wide.light.css +75 -0
  181. pygpt_net/data/icons/split_screen.svg +1 -0
  182. pygpt_net/data/locale/locale.de.ini +12 -0
  183. pygpt_net/data/locale/locale.en.ini +17 -2
  184. pygpt_net/data/locale/locale.es.ini +12 -0
  185. pygpt_net/data/locale/locale.fr.ini +12 -0
  186. pygpt_net/data/locale/locale.it.ini +12 -0
  187. pygpt_net/data/locale/locale.pl.ini +12 -0
  188. pygpt_net/data/locale/locale.uk.ini +12 -0
  189. pygpt_net/data/locale/locale.zh.ini +12 -0
  190. pygpt_net/data/locale/plugin.cmd_web.de.ini +2 -0
  191. pygpt_net/data/locale/plugin.cmd_web.en.ini +20 -10
  192. pygpt_net/data/locale/plugin.cmd_web.es.ini +2 -0
  193. pygpt_net/data/locale/plugin.cmd_web.fr.ini +2 -0
  194. pygpt_net/data/locale/plugin.cmd_web.it.ini +2 -0
  195. pygpt_net/data/locale/plugin.cmd_web.pl.ini +2 -0
  196. pygpt_net/data/locale/plugin.cmd_web.uk.ini +2 -0
  197. pygpt_net/data/locale/plugin.cmd_web.zh.ini +2 -0
  198. pygpt_net/icons.qrc +1 -0
  199. pygpt_net/icons_rc.py +165 -136
  200. pygpt_net/item/ctx.py +46 -24
  201. pygpt_net/plugin/audio_input/simple.py +21 -5
  202. pygpt_net/plugin/audio_output/__init__.py +4 -1
  203. pygpt_net/plugin/base/config.py +4 -2
  204. pygpt_net/plugin/base/plugin.py +26 -6
  205. pygpt_net/plugin/base/worker.py +37 -9
  206. pygpt_net/plugin/cmd_code_interpreter/__init__.py +39 -37
  207. pygpt_net/plugin/cmd_code_interpreter/runner.py +25 -12
  208. pygpt_net/plugin/cmd_web/__init__.py +46 -6
  209. pygpt_net/plugin/cmd_web/config.py +74 -48
  210. pygpt_net/plugin/cmd_web/websearch.py +61 -28
  211. pygpt_net/plugin/cmd_web/worker.py +79 -13
  212. pygpt_net/provider/core/config/patch.py +43 -1
  213. pygpt_net/provider/core/ctx/base.py +4 -1
  214. pygpt_net/provider/core/ctx/db_sqlite/__init__.py +10 -1
  215. pygpt_net/provider/core/ctx/db_sqlite/storage.py +22 -1
  216. pygpt_net/provider/gpt/assistants.py +10 -9
  217. pygpt_net/provider/gpt/audio.py +3 -2
  218. pygpt_net/provider/gpt/chat.py +8 -7
  219. pygpt_net/provider/gpt/completion.py +6 -4
  220. pygpt_net/provider/gpt/image.py +9 -2
  221. pygpt_net/provider/gpt/store.py +14 -13
  222. pygpt_net/provider/gpt/vision.py +6 -5
  223. pygpt_net/tools/__init__.py +9 -1
  224. pygpt_net/tools/base.py +15 -1
  225. pygpt_net/tools/code_interpreter/__init__.py +174 -75
  226. pygpt_net/tools/code_interpreter/ui/dialogs.py +21 -103
  227. pygpt_net/tools/code_interpreter/ui/widgets.py +284 -9
  228. pygpt_net/tools/html_canvas/__init__.py +78 -23
  229. pygpt_net/tools/html_canvas/ui/dialogs.py +46 -62
  230. pygpt_net/tools/html_canvas/ui/widgets.py +96 -3
  231. pygpt_net/ui/base/context_menu.py +2 -2
  232. pygpt_net/ui/layout/chat/input.py +10 -18
  233. pygpt_net/ui/layout/chat/output.py +26 -44
  234. pygpt_net/ui/layout/ctx/ctx_list.py +13 -4
  235. pygpt_net/ui/layout/toolbox/footer.py +18 -2
  236. pygpt_net/ui/main.py +2 -2
  237. pygpt_net/ui/menu/config.py +7 -11
  238. pygpt_net/ui/menu/debug.py +11 -1
  239. pygpt_net/ui/menu/theme.py +9 -2
  240. pygpt_net/ui/widget/filesystem/explorer.py +2 -2
  241. pygpt_net/ui/widget/lists/context.py +27 -5
  242. pygpt_net/ui/widget/tabs/Input.py +2 -2
  243. pygpt_net/ui/widget/tabs/body.py +2 -1
  244. pygpt_net/ui/widget/tabs/layout.py +195 -0
  245. pygpt_net/ui/widget/tabs/output.py +218 -55
  246. pygpt_net/ui/widget/textarea/html.py +11 -1
  247. pygpt_net/ui/widget/textarea/output.py +10 -1
  248. pygpt_net/ui/widget/textarea/search_input.py +4 -1
  249. pygpt_net/ui/widget/textarea/web.py +49 -9
  250. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.41.dist-info}/METADATA +45 -116
  251. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.41.dist-info}/RECORD +255 -247
  252. /pygpt_net/data/css/{web.dark.css → web-blocks.dark.css} +0 -0
  253. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.41.dist-info}/LICENSE +0 -0
  254. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.41.dist-info}/WHEEL +0 -0
  255. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.41.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: 2024.11.18 19:00:00 #
9
+ # Updated Date: 2024.12.13 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from pygpt_net.plugin.base.config import BaseConfig, BasePlugin
@@ -41,6 +41,15 @@ class Config(BaseConfig):
41
41
  min=1,
42
42
  max=None,
43
43
  )
44
+ plugin.add_option(
45
+ "max_open_urls",
46
+ type="int",
47
+ value=1,
48
+ label="Number of max URLs to open at once",
49
+ description="Number of max URLs to open at once",
50
+ min=1,
51
+ max=None,
52
+ )
44
53
  plugin.add_option(
45
54
  "max_page_content_length",
46
55
  type="int",
@@ -59,6 +68,14 @@ class Config(BaseConfig):
59
68
  min=1,
60
69
  max=None,
61
70
  )
71
+ plugin.add_option(
72
+ "raw",
73
+ type="bool",
74
+ value=True,
75
+ label="Use raw content (without summarization)",
76
+ description="Return raw content from web search instead of summarized content",
77
+ tooltip="Use raw content for search",
78
+ )
62
79
  plugin.add_option(
63
80
  "disable_ssl",
64
81
  type="bool",
@@ -67,6 +84,14 @@ class Config(BaseConfig):
67
84
  description="Disables SSL verification when crawling web pages",
68
85
  tooltip="Disable SSL verify",
69
86
  )
87
+ plugin.add_option(
88
+ "img_thumbnail",
89
+ type="bool",
90
+ value=True,
91
+ label="Show thumbnail images",
92
+ description="Enable fetching thumbnails from opened websites",
93
+ tooltip="Enable fetching thumbnails from opened websites",
94
+ )
70
95
  plugin.add_option(
71
96
  "timeout",
72
97
  type="int",
@@ -86,7 +111,7 @@ class Config(BaseConfig):
86
111
  plugin.add_option(
87
112
  "max_result_length",
88
113
  type="int",
89
- value=1500,
114
+ value=50000,
90
115
  label="Max result length",
91
116
  description="Max length of summarized result (characters)",
92
117
  min=0,
@@ -104,10 +129,10 @@ class Config(BaseConfig):
104
129
  plugin.add_option(
105
130
  "model_tmp_query",
106
131
  type="combo",
107
- value="gpt-3.5-turbo",
132
+ value="gpt-4o-mini",
108
133
  label="Model for query in-memory index",
109
134
  description="Model used for query in-memory index for `web_index_query` command, "
110
- "default: gpt-3.5-turbo",
135
+ "default: gpt-4o-mini",
111
136
  tooltip="Query model",
112
137
  use="models",
113
138
  tab="indexing",
@@ -134,10 +159,11 @@ class Config(BaseConfig):
134
159
  )
135
160
  plugin.add_option(
136
161
  "summary_model",
137
- type="text",
138
- value="gpt-3.5-turbo-1106",
162
+ type="combo",
163
+ value="gpt-4o-mini",
139
164
  label="Model used for web page summarize",
140
165
  description="Model used for web page summarize, default: gpt-3.5-turbo-1106",
166
+ use="models",
141
167
  advanced=True,
142
168
  )
143
169
  plugin.add_option(
@@ -163,39 +189,9 @@ class Config(BaseConfig):
163
189
  )
164
190
 
165
191
  # commands
166
- plugin.add_cmd(
167
- "web_search",
168
- instruction="search the Web for more info, prepare a query for the search engine itself, start from page 1. "
169
- "If no results, then try the next page. "
170
- "Use a custom summary prompt if necessary, otherwise, a default summary will be used. "
171
- "Max pages: {max_pages}",
172
- params=[
173
- {
174
- "name": "query",
175
- "type": "str",
176
- "description": "search query",
177
- "required": True,
178
- },
179
- {
180
- "name": "page",
181
- "type": "int",
182
- "description": "page number",
183
- "required": False,
184
- },
185
- {
186
- "name": "summarize_prompt",
187
- "type": "str",
188
- "description": "summary prompt",
189
- "required": False,
190
- },
191
- ],
192
- enabled=True,
193
- description="If enabled, model will be able to search the Web",
194
- )
195
192
  plugin.add_cmd(
196
193
  "web_url_open",
197
- instruction="read and get summarized content from ANY website URL. Use a custom summary prompt if necessary, "
198
- "otherwise default summary will be used",
194
+ instruction="read and get text content from ANY website URL. Always open a max of {max_urls} URLs at a time.",
199
195
  params=[
200
196
  {
201
197
  "name": "url",
@@ -203,19 +199,13 @@ class Config(BaseConfig):
203
199
  "description": "URL to website",
204
200
  "required": True,
205
201
  },
206
- {
207
- "name": "summarize_prompt",
208
- "type": "str",
209
- "description": "summary prompt",
210
- "required": False,
211
- },
212
202
  ],
213
203
  enabled=True,
214
- description="If enabled, model will be able to open URL and summarize content",
204
+ description="If enabled, model will be able to open URL and read text content from it",
215
205
  )
216
206
  plugin.add_cmd(
217
207
  "web_url_raw",
218
- instruction="read and get raw HTML/txt content (not summarized) from ANY website URL",
208
+ instruction="read and get raw HTML body from ANY website URL. Always open a max of {max_urls} URLs at a time.",
219
209
  params=[
220
210
  {
221
211
  "name": "url",
@@ -225,12 +215,14 @@ class Config(BaseConfig):
225
215
  },
226
216
  ],
227
217
  enabled=True,
228
- description="If enabled, model will be able to open specified URL and get raw content",
218
+ description="If enabled, model will be able to open specified URL and get raw HTML body from it",
229
219
  )
230
220
  plugin.add_cmd(
231
- "web_urls",
221
+ "web_search",
232
222
  instruction="search the Web for list of URLs, prepare search query itself, list of "
233
- "URLs will be returned, 10 links per page max.",
223
+ "URLs will be returned, 10 links per page max. After receiving the list of URLs, "
224
+ "choose the best matched URLs and use the `web_url_open` command to read the content. "
225
+ "Always open a max of {max_urls} URLs at a time.",
234
226
  params=[
235
227
  {
236
228
  "name": "query",
@@ -254,6 +246,40 @@ class Config(BaseConfig):
254
246
  enabled=True,
255
247
  description="If enabled, model will be able to search the Web and get founded URLs list",
256
248
  )
249
+ plugin.add_cmd(
250
+ "web_extract_links",
251
+ instruction="open webpage and get list of all links from it",
252
+ params=[
253
+ {
254
+ "name": "url",
255
+ "type": "str",
256
+ "description": "URL to website",
257
+ "required": True,
258
+ },
259
+ ],
260
+ enabled=True,
261
+ description="If enabled, model will be able to open URL and get list of all links from it",
262
+ )
263
+ plugin.add_cmd(
264
+ "web_extract_images",
265
+ instruction="open webpage and get list of all images from it",
266
+ params=[
267
+ {
268
+ "name": "url",
269
+ "type": "str",
270
+ "description": "URL to website",
271
+ "required": True,
272
+ },
273
+ {
274
+ "name": "download",
275
+ "type": "bool",
276
+ "description": "Download images to disk if user wants to, default: False",
277
+ "required": False,
278
+ },
279
+ ],
280
+ enabled=True,
281
+ description="If enabled, model will be able to open URL and get list of all images from it",
282
+ )
257
283
  plugin.add_cmd(
258
284
  "web_index",
259
285
  instruction="",
@@ -6,10 +6,11 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.11.21 02:00:00 #
9
+ # Updated Date: 2024.12.13 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import re
13
+
13
14
  from bs4 import BeautifulSoup
14
15
 
15
16
  from pygpt_net.core.events import KernelEvent
@@ -194,19 +195,22 @@ class WebSearch:
194
195
  query: str,
195
196
  page_no: int = 1,
196
197
  summarize_prompt: str = ""
197
- ) -> (str, int, int, str):
198
+ ) -> (str, int, int, str, str):
198
199
  """
199
200
  Get result from search query
200
201
 
201
202
  :param query: query to search
202
203
  :param page_no: page number
203
204
  :param summarize_prompt: custom prompt
204
- :return: result, total_found, current, url
205
+ :return: result, total_found, current, url, thumb image
205
206
  """
206
207
  self.log("Using web query: " + query)
207
208
  urls = self.get_urls(query)
208
209
 
209
210
  # get options
211
+ is_summary = True
212
+ if self.plugin.get_option_value("raw"):
213
+ is_summary = False
210
214
  max_per_page = int(self.plugin.get_option_value("max_page_content_length"))
211
215
  chunk_size = int(self.plugin.get_option_value("chunk_size"))
212
216
  max_result_size = int(self.plugin.get_option_value("max_result_length"))
@@ -216,6 +220,7 @@ class WebSearch:
216
220
  i = 1
217
221
  current = 1
218
222
  url = ""
223
+ img = None
219
224
  for url in urls:
220
225
  if url is None or url == "":
221
226
  continue
@@ -236,19 +241,27 @@ class WebSearch:
236
241
  if 0 < max_per_page < len(content):
237
242
  content = content[:max_per_page]
238
243
 
239
- chunks = self.to_chunks(content, chunk_size) # it returns list of chunks
240
- self.debug(
241
- "Plugin: cmd_web: URL: {}".format(url)
242
- )
243
- result = self.get_summary(
244
- chunks,
245
- str(query),
246
- summarize_prompt,
247
- )
244
+ # get summary
245
+ if is_summary:
246
+ chunks = self.to_chunks(content, chunk_size) # it returns list of chunks
247
+ self.debug(
248
+ "Plugin: cmd_web: URL: {}".format(url)
249
+ )
250
+ result = self.get_summary(
251
+ chunks,
252
+ str(query),
253
+ summarize_prompt,
254
+ )
255
+ else:
256
+ # no summary
257
+ result = str(content)
258
+
248
259
  # if result then stop
249
260
  if result is not None and result != "":
261
+ # get thumbnail image
262
+ if self.plugin.get_option_value("img_thumbnail"):
263
+ img = self.plugin.window.core.web.get_main_image(url)
250
264
  self.log("Summary generated (chars: {})".format(len(result)))
251
-
252
265
  # index webpage if auto-index is enabled
253
266
  self.index_url(url)
254
267
  break
@@ -262,7 +275,7 @@ class WebSearch:
262
275
  "Plugin: cmd_web: summary length: {}".format(len(result))
263
276
  )
264
277
 
265
- if len(result) > max_result_size:
278
+ if 0 < max_result_size < len(result):
266
279
  result = result[:max_result_size]
267
280
 
268
281
  self.debug(
@@ -273,25 +286,33 @@ class WebSearch:
273
286
  result, \
274
287
  total_found, \
275
288
  current, \
276
- url
289
+ url, \
290
+ img
277
291
 
278
- def open_url(self, url: str, summarize_prompt: str = "") -> (str, str):
292
+ def open_url(self, url: str, summarize_prompt: str = "") -> (str, str, str):
279
293
  """
280
294
  Get result from specified URL
281
295
 
282
296
  :param url: URL to visit
283
297
  :param summarize_prompt: custom prompt
284
- :return: result, url
298
+ :return: result, url, thumb image
285
299
  """
286
300
  self.log("Using URL: " + url)
287
-
288
301
  # get options
302
+ is_summary = True
303
+ if self.plugin.get_option_value("raw"):
304
+ is_summary = False
289
305
  max_per_page = int(self.plugin.get_option_value("max_page_content_length"))
290
306
  chunk_size = int(self.plugin.get_option_value("chunk_size"))
291
307
  max_result_size = int(self.plugin.get_option_value("max_result_length"))
292
308
 
309
+ img = None
293
310
  self.log("URL: " + url)
294
311
  content = self.query_url(url)
312
+
313
+ if content is None:
314
+ return None, url, img
315
+
295
316
  self.log("Content found (chars: {}). Please wait...".format(len(content)))
296
317
 
297
318
  # index webpage if auto-index is enabled
@@ -300,14 +321,23 @@ class WebSearch:
300
321
 
301
322
  if 0 < max_per_page < len(content):
302
323
  content = content[:max_per_page]
303
- chunks = self.to_chunks(
304
- content,
305
- chunk_size,
306
- ) # it returns list of chunks
307
324
 
308
325
  self.debug("Plugin: cmd_web: URL: {}".format(url)) # log
309
326
 
310
- result = self.get_summary(chunks, "", summarize_prompt)
327
+ # get summary
328
+ if is_summary:
329
+ chunks = self.to_chunks(
330
+ content,
331
+ chunk_size,
332
+ ) # it returns list of chunks
333
+ result = self.get_summary(chunks, "", summarize_prompt)
334
+ else:
335
+ # no summary
336
+ result = str(content)
337
+
338
+ # get thumbnail image
339
+ if self.plugin.get_option_value("img_thumbnail"):
340
+ img = self.plugin.window.core.web.get_main_image(url)
311
341
 
312
342
  if result is not None and result != "":
313
343
  self.log("Summary generated (chars: {})".format(len(result)))
@@ -318,21 +348,21 @@ class WebSearch:
318
348
  "Plugin: cmd_web: summary length: {}".format(len(result))
319
349
  )
320
350
 
321
- if len(result) > max_result_size:
351
+ if 0 < max_result_size < len(result):
322
352
  result = result[:max_result_size]
323
353
 
324
354
  self.debug(
325
355
  "Plugin: cmd_web: result length: {}".format(len(result))
326
356
  )
327
357
 
328
- return result, url
358
+ return result, url, img
329
359
 
330
- def open_url_raw(self, url: str) -> (str, str):
360
+ def open_url_raw(self, url: str) -> (str, str, str):
331
361
  """
332
362
  Get raw content from specified URL
333
363
 
334
364
  :param url: URL to visit
335
- :return: result, url
365
+ :return: result, url, thumb image
336
366
  """
337
367
  self.log("Using URL: " + url)
338
368
 
@@ -343,8 +373,11 @@ class WebSearch:
343
373
  result = self.query_url(url)
344
374
  self.log("Content found (chars: {}). Please wait...".format(len(result)))
345
375
 
376
+ img = None
346
377
  # index webpage if auto-index is enabled
347
378
  if result:
379
+ if self.plugin.get_option_value("img_thumbnail"):
380
+ img = self.plugin.window.core.web.get_main_image(url)
348
381
  self.index_url(url)
349
382
 
350
383
  # strip if too long
@@ -355,7 +388,7 @@ class WebSearch:
355
388
  "Plugin: cmd_web: result length: {}".format(len(result))
356
389
  )
357
390
 
358
- return result, url
391
+ return result, url, img
359
392
 
360
393
  def index_url(self, url: str):
361
394
  """
@@ -6,12 +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: 2024.11.18 21:00:00 #
9
+ # Updated Date: 2024.12.13 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import json
13
13
 
14
14
  from PySide6.QtCore import Slot
15
+
15
16
  from pygpt_net.plugin.base.worker import BaseWorker, BaseSignals
16
17
 
17
18
 
@@ -40,7 +41,7 @@ class Worker(BaseWorker):
40
41
  response = None
41
42
  try:
42
43
  if item["cmd"] == "web_search":
43
- response = self.cmd_web_search(item)
44
+ response = self.cmd_web_urls(item) # return URLs
44
45
 
45
46
  elif item["cmd"] == "web_url_open":
46
47
  response = self.cmd_web_url_open(item)
@@ -57,6 +58,12 @@ class Worker(BaseWorker):
57
58
  elif item["cmd"] == "web_index_query":
58
59
  response = self.cmd_web_index_query(item)
59
60
 
61
+ elif item["cmd"] == "web_extract_links":
62
+ response = self.cmd_web_extract_links(item)
63
+
64
+ elif item["cmd"] == "web_extract_images":
65
+ response = self.cmd_web_extract_images(item)
66
+
60
67
  if response:
61
68
  responses.append(response)
62
69
 
@@ -91,7 +98,7 @@ class Worker(BaseWorker):
91
98
  prompt = self.get_param(item, "summarize_prompt")
92
99
 
93
100
  query = self.get_param(item, "query", "")
94
- content, total_found, current, url = self.websearch.make_query(
101
+ content, total_found, current, url, img = self.websearch.make_query(
95
102
  query,
96
103
  page,
97
104
  prompt,
@@ -105,8 +112,12 @@ class Worker(BaseWorker):
105
112
  'total_found': total_found,
106
113
  }
107
114
  if url:
108
- self.ctx.urls.append(url)
115
+ self.ctx.urls_before.append(url)
116
+ if img:
117
+ result["thumb_img"] = img
118
+ self.ctx.images_before.append(img)
109
119
 
120
+ self.ctx.save_reply = True # leave links in context
110
121
  return self.make_response(item, result)
111
122
 
112
123
  def cmd_web_url_open(self, item: dict) -> dict:
@@ -122,7 +133,7 @@ class Worker(BaseWorker):
122
133
  url = self.get_param(item, "url", "")
123
134
 
124
135
  self.msg = "Opening Web URL: '{}'".format(url)
125
- content, url = self.websearch.open_url(
136
+ content, url, img = self.websearch.open_url(
126
137
  url,
127
138
  prompt,
128
139
  )
@@ -130,9 +141,12 @@ class Worker(BaseWorker):
130
141
  'url': url,
131
142
  'content': content,
132
143
  }
133
- context = "From: " + url + ":\n--------------------------------\n" + content
144
+ context = "From: " + url + ":\n--------------------------------\n" + str(content)
134
145
  if url:
135
- self.ctx.urls.append(url)
146
+ self.ctx.urls_before.append(url)
147
+ if img:
148
+ result["thumb_img"] = img
149
+ self.ctx.images_before.append(img)
136
150
 
137
151
  extra = {
138
152
  "context": context,
@@ -148,16 +162,19 @@ class Worker(BaseWorker):
148
162
  """
149
163
  url = self.get_param(item, "url", "")
150
164
  self.msg = "Opening Web URL: '{}'".format(url)
151
- content, url = self.websearch.open_url_raw(
165
+ content, url, img = self.websearch.open_url_raw(
152
166
  url,
153
167
  )
154
168
  result = {
155
169
  'url': url,
156
170
  'content': content,
157
171
  }
158
- context = "From: " + url + ":\n--------------------------------\n" + content
172
+ context = "From: " + url + ":\n--------------------------------\n" + str(content)
159
173
  if url:
160
- self.ctx.urls.append(url)
174
+ self.ctx.urls_before.append(url)
175
+ if img:
176
+ result["thumb_img"] = img
177
+ self.ctx.images_before.append(img)
161
178
 
162
179
  extra = {
163
180
  "context": context,
@@ -201,7 +218,7 @@ class Worker(BaseWorker):
201
218
  }
202
219
  if urls:
203
220
  for url in urls:
204
- self.ctx.urls.append(url)
221
+ self.ctx.urls_before.append(url)
205
222
 
206
223
  return self.make_response(item, result)
207
224
 
@@ -247,7 +264,7 @@ class Worker(BaseWorker):
247
264
  'errors': errors,
248
265
  }
249
266
  if url and (url.startswith("http://") or url.startswith("https://")):
250
- self.ctx.urls.append(url)
267
+ self.ctx.urls_before.append(url)
251
268
 
252
269
  extra = {
253
270
  "url": url,
@@ -327,9 +344,58 @@ class Worker(BaseWorker):
327
344
 
328
345
  # add URL to context
329
346
  if url and (url.startswith("http://") or url.startswith("https://")):
330
- self.ctx.urls.append(url)
347
+ self.ctx.urls_before.append(url)
331
348
 
332
349
  extra = {
333
350
  "context": context,
334
351
  }
335
352
  return self.make_response(item, result, extra=extra)
353
+
354
+ def cmd_web_extract_links(self, item: dict) -> dict:
355
+ """
356
+ Web extract links command
357
+
358
+ :param item: command item
359
+ :return: response item
360
+ """
361
+ url = ""
362
+ if self.has_param(item, "url"):
363
+ url = self.get_param(item, "url")
364
+ if not url:
365
+ return self.make_response(item, "No URL provided")
366
+ links = self.plugin.window.core.web.get_links(url)
367
+ result = {
368
+ 'links': links,
369
+ }
370
+ self.ctx.urls_before.append(url)
371
+ return self.make_response(item, result)
372
+
373
+ def cmd_web_extract_images(self, item: dict) -> dict:
374
+ """
375
+ Web extract images command
376
+
377
+ :param item: command item
378
+ :return: response item
379
+ """
380
+ download = False
381
+ url = ""
382
+ if self.has_param(item, "url"):
383
+ url = self.get_param(item, "url")
384
+ if self.has_param(item, "download"):
385
+ download = bool(self.get_param(item, "download"))
386
+ if not url:
387
+ return self.make_response(item, "No URL provided")
388
+ images = self.plugin.window.core.web.get_images(url)
389
+ result = {
390
+ 'images': images,
391
+ }
392
+ if images and download:
393
+ for img in images:
394
+ try:
395
+ path = self.plugin.window.core.web.download_image(img)
396
+ if path:
397
+ self.ctx.images_before.append(path)
398
+ except Exception as e:
399
+ print(e)
400
+ self.ctx.urls_before.append(url)
401
+ return self.make_response(item, result)
@@ -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: 2024.11.29 23:00:00 #
9
+ # Updated Date: 2024.12.13 19:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -1734,6 +1734,48 @@ class Patch:
1734
1734
  'ctx.attachment.rag.history.max_items')
1735
1735
  updated = True
1736
1736
 
1737
+ # < 2.4.38
1738
+ if old < parse_version("2.4.38"):
1739
+ print("Migrating config from < 2.4.38...")
1740
+ if 'theme.style' not in data:
1741
+ data["theme.style"] = "blocks"
1742
+ if 'audio.input.device' not in data:
1743
+ data["audio.input.device"] = "0"
1744
+ if 'audio.input.channels' not in data:
1745
+ data["audio.input.channels"] = 1
1746
+ if 'audio.input.rate' not in data:
1747
+ data["audio.input.rate"] = 44100
1748
+ self.window.core.updater.patch_css('style.light.css', True) # force update
1749
+ updated = True
1750
+
1751
+ # < 2.4.39
1752
+ if old < parse_version("2.4.39"):
1753
+ print("Migrating config from < 2.4.39...")
1754
+ if 'layout.split' not in data:
1755
+ data["layout.split"] = False
1756
+ updated = True
1757
+
1758
+ # < 2.4.40
1759
+ if old < parse_version("2.4.40"):
1760
+ print("Migrating config from < 2.4.40...")
1761
+ if 'cmd_web' in data['plugins'] \
1762
+ and 'max_result_length' in data['plugins']['cmd_web']:
1763
+ del data['plugins']['cmd_web']['max_result_length']
1764
+ if 'cmd_web' in data['plugins'] \
1765
+ and 'cmd.web_search' in data['plugins']['cmd_web']:
1766
+ del data['plugins']['cmd_web']['cmd.web_search']
1767
+ if 'cmd_web' in data['plugins'] \
1768
+ and 'cmd.web_url_open' in data['plugins']['cmd_web']:
1769
+ del data['plugins']['cmd_web']['cmd.web_url_open']
1770
+ if 'cmd_web' in data['plugins'] \
1771
+ and 'cmd.web_url_raw' in data['plugins']['cmd_web']:
1772
+ del data['plugins']['cmd_web']['cmd.web_url_raw']
1773
+ self.window.core.updater.patch_css('web-blocks.css', True) # force update
1774
+ self.window.core.updater.patch_css('web-blocks.light.css', True) # force update
1775
+ self.window.core.updater.patch_css('web-chatgpt.css', True) # force update
1776
+ self.window.core.updater.patch_css('web-chatgpt_wide.css', True) # force update
1777
+ updated = True
1778
+
1737
1779
  # update file
1738
1780
  migrated = False
1739
1781
  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: 2024.04.08 21:00:00 #
9
+ # Updated Date: 2024.12.09 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from packaging.version import Version
@@ -71,6 +71,9 @@ class BaseProvider:
71
71
  def get_meta_indexed(self):
72
72
  pass
73
73
 
74
+ def get_item_by_id(self, id: int) -> CtxItem:
75
+ pass
76
+
74
77
  def dump(self, ctx: CtxItem):
75
78
  pass
76
79