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,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.08 17:00:00 #
9
+ # Updated Date: 2024.12.14 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from datetime import datetime
13
+ from typing import Dict, Any
13
14
 
14
15
 
15
16
  class Tab:
@@ -21,6 +22,7 @@ class Tab:
21
22
  TAB_FILES = 2
22
23
  TAB_TOOL_PAINTER = 3
23
24
  TAB_TOOL_CALENDAR = 4
25
+ TAB_TOOL = 100
24
26
 
25
27
  def __init__(self):
26
28
  """
@@ -34,15 +36,23 @@ class Tab:
34
36
  self.icon = None
35
37
  self.tooltip = None
36
38
  self.data_id = None
37
- self.reference = None
38
39
  self.new_idx = None
39
40
  self.custom_name = False
41
+ self.child = None
42
+ self.parent = None
43
+ self.column_idx = 0
44
+ self.tool_id = None
40
45
 
41
46
  dt = datetime.now()
42
47
  self.created_at = dt
43
48
  self.updated_at = dt
44
49
 
45
- def to_dict(self):
50
+ def to_dict(self) -> Dict[str, Any]:
51
+ """
52
+ Convert to dict
53
+
54
+ :return: dict
55
+ """
46
56
  return {
47
57
  "uuid": str(self.uuid),
48
58
  "pid": self.pid,
@@ -52,9 +62,12 @@ class Tab:
52
62
  "icon": self.icon,
53
63
  "tooltip": self.tooltip,
54
64
  "data_id": self.data_id,
55
- "reference": str(self.reference),
65
+ "child": str(self.child), # child widget
66
+ "parent": str(self.parent), # parent column
56
67
  "custom_name": self.custom_name,
57
68
  "custom_idx": self.new_idx,
58
69
  "created_at": str(self.created_at),
59
70
  "updated_at": str(self.updated_at),
71
+ "column_idx": self.column_idx,
72
+ "tool_id": self.tool_id,
60
73
  }
pygpt_net/core/tokens.py CHANGED
@@ -6,9 +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.26 19:00:00 #
9
+ # Updated Date: 2024.12.14 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ from typing import Tuple
13
+
12
14
  import tiktoken
13
15
 
14
16
  from pygpt_net.core.types import (
@@ -48,7 +50,10 @@ class Tokens:
48
50
  self.window = window
49
51
 
50
52
  @staticmethod
51
- def from_str(string: str, model: str = "gpt-4") -> int:
53
+ def from_str(
54
+ string: str,
55
+ model: str = "gpt-4"
56
+ ) -> int:
52
57
  """
53
58
  Return number of tokens from string
54
59
 
@@ -91,7 +96,11 @@ class Tokens:
91
96
  return 3
92
97
 
93
98
  @staticmethod
94
- def from_prompt(text: str, name: str, model: str = "gpt-4") -> int:
99
+ def from_prompt(
100
+ text: str,
101
+ name: str,
102
+ model: str = "gpt-4"
103
+ ) -> int:
95
104
  """
96
105
  Return number of tokens from prompt
97
106
 
@@ -116,7 +125,10 @@ class Tokens:
116
125
  return num
117
126
 
118
127
  @staticmethod
119
- def from_text(text: str, model: str = "gpt-4") -> int:
128
+ def from_text(
129
+ text: str,
130
+ model: str = "gpt-4"
131
+ ) -> int:
120
132
  """
121
133
  Return number of tokens from text, without any extra tokens
122
134
 
@@ -138,7 +150,10 @@ class Tokens:
138
150
  return num
139
151
 
140
152
  @staticmethod
141
- def from_messages(messages: list, model: str = "gpt-4") -> int:
153
+ def from_messages(
154
+ messages: list,
155
+ model: str = "gpt-4"
156
+ ) -> int:
142
157
  """
143
158
  Return number of tokens from messages list
144
159
 
@@ -166,7 +181,10 @@ class Tokens:
166
181
  return num
167
182
 
168
183
  @staticmethod
169
- def from_langchain_messages(messages: list, model: str = "gpt-4") -> int:
184
+ def from_langchain_messages(
185
+ messages: list,
186
+ model: str = "gpt-4"
187
+ ) -> int:
170
188
  """
171
189
  Return number of tokens from prompt
172
190
 
@@ -183,7 +201,11 @@ class Tokens:
183
201
  return num
184
202
 
185
203
  @staticmethod
186
- def from_llama_messages(query: str, messages: list, model: str = "gpt-4") -> int:
204
+ def from_llama_messages(
205
+ query: str,
206
+ messages: list,
207
+ model: str = "gpt-4"
208
+ ) -> int:
187
209
  """
188
210
  Return number of tokens from prompt
189
211
 
@@ -202,7 +224,11 @@ class Tokens:
202
224
  return num
203
225
 
204
226
  @staticmethod
205
- def from_ctx(ctx: CtxItem, mode: str = MODE_CHAT, model: str = "gpt-4") -> int:
227
+ def from_ctx(
228
+ ctx: CtxItem,
229
+ mode: str = MODE_CHAT,
230
+ model: str = "gpt-4"
231
+ ) -> int:
206
232
  """
207
233
  Return number of tokens from context ctx
208
234
 
@@ -280,7 +306,10 @@ class Tokens:
280
306
 
281
307
  return num
282
308
 
283
- def get_current(self, input_prompt: str) -> (int, int, int, int, int, int, int, int, int):
309
+ def get_current(
310
+ self,
311
+ input_prompt: str
312
+ ) -> Tuple[int, int, int, int, int, int, int, int, int]:
284
313
  """
285
314
  Return current number of used tokens
286
315
 
@@ -364,7 +393,11 @@ class Tokens:
364
393
  return input_tokens, system_tokens, extra_tokens, ctx_tokens, ctx_len, ctx_len_all, \
365
394
  sum_tokens, max_current, threshold
366
395
 
367
- def from_user(self, system_prompt: str, input_prompt: str) -> int:
396
+ def from_user(
397
+ self,
398
+ system_prompt: str,
399
+ input_prompt: str
400
+ ) -> int:
368
401
  """
369
402
  Count per-user used tokens
370
403
 
@@ -390,7 +423,7 @@ class Tokens:
390
423
  return tokens
391
424
 
392
425
  @staticmethod
393
- def get_config(model: str) -> (str, int, int):
426
+ def get_config(model: str) -> Tuple[str, int, int]:
394
427
  """
395
428
  Return tokens config values
396
429
 
@@ -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.15 02:00:00 #
9
+ # Updated Date: 2024.12.14 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -15,6 +15,7 @@ import shutil
15
15
  import json
16
16
  import ssl
17
17
  import time
18
+ from typing import Tuple
18
19
 
19
20
  from urllib.request import urlopen, Request
20
21
 
@@ -134,7 +135,11 @@ class Updater:
134
135
  if self.window.core.notepad.patch(version):
135
136
  print("Migrated notepad. [OK]")
136
137
 
137
- def patch_dir(self, dir_name: str = "", force: bool = False):
138
+ def patch_dir(
139
+ self,
140
+ dir_name: str = "",
141
+ force: bool = False
142
+ ):
138
143
  """
139
144
  Patch directory (replace all files)
140
145
 
@@ -154,7 +159,11 @@ class Updater:
154
159
  except Exception as e:
155
160
  self.window.core.debug.log(e)
156
161
 
157
- def patch_file(self, filename: str = "", force: bool = False):
162
+ def patch_file(
163
+ self,
164
+ filename: str = "",
165
+ force: bool = False
166
+ ):
158
167
  """
159
168
  Patch file
160
169
 
@@ -175,7 +184,11 @@ class Updater:
175
184
  except Exception as e:
176
185
  self.window.core.debug.log(e)
177
186
 
178
- def patch_css(self, filename: str = "", force: bool = False):
187
+ def patch_css(
188
+ self,
189
+ filename: str = "",
190
+ force: bool = False
191
+ ):
179
192
  """
180
193
  Patch css file
181
194
 
@@ -212,7 +225,7 @@ class Updater:
212
225
  """
213
226
  return self.window.meta['website'] + "/api/version?v=" + str(self.window.meta['version'])
214
227
 
215
- def get_thanks(self) -> (str, str, str):
228
+ def get_thanks(self) -> Tuple[str, str, str]:
216
229
  """
217
230
  Get contributors, donates and sponsors
218
231
 
@@ -237,7 +250,7 @@ class Updater:
237
250
 
238
251
  return self.thanks
239
252
 
240
- def get_fetch_thanks(self) -> (str, str, str):
253
+ def get_fetch_thanks(self) -> Tuple[str, str, str]:
241
254
  """
242
255
  Get contributors, donates and sponsors
243
256
 
@@ -247,7 +260,7 @@ class Updater:
247
260
  return self.get_thanks()
248
261
  return self.thanks
249
262
 
250
- def check_silent(self) -> (bool, str, str, str, str, str):
263
+ def check_silent(self) -> Tuple[bool, str, str, str, str, str]:
251
264
  """
252
265
  Check version in background
253
266
 
@@ -6,8 +6,9 @@
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.23 00:00:00 #
9
+ # Updated Date: 2024.12.14 00:00:00 #
10
10
  # ================================================== #
11
+
11
12
  import os
12
13
 
13
14
  from pygpt_net.core.bridge.context import BridgeContext
@@ -24,7 +25,12 @@ class Analyzer:
24
25
  """
25
26
  self.window = window
26
27
 
27
- def send(self, ctx: CtxItem, prompt: str, files: dict) -> str:
28
+ def send(
29
+ self,
30
+ ctx: CtxItem,
31
+ prompt: str,
32
+ files: dict
33
+ ) -> str:
28
34
  """
29
35
  Send text from user input (called from UI)
30
36
 
@@ -56,7 +62,11 @@ class Analyzer:
56
62
  self.window.controller.attachment.unlock()
57
63
  return output
58
64
 
59
- def from_screenshot(self, ctx: CtxItem, prompt: str) -> str:
65
+ def from_screenshot(
66
+ self,
67
+ ctx: CtxItem,
68
+ prompt: str
69
+ ) -> str:
60
70
  """
61
71
  Image analysis from screenshot
62
72
 
@@ -75,7 +85,11 @@ class Analyzer:
75
85
  }
76
86
  return self.send(ctx, prompt, files)
77
87
 
78
- def from_camera(self, ctx: CtxItem, prompt: str) -> str:
88
+ def from_camera(
89
+ self,
90
+ ctx: CtxItem,
91
+ prompt: str
92
+ ) -> str:
79
93
  """
80
94
  Image analysis from camera
81
95
 
@@ -94,7 +108,12 @@ class Analyzer:
94
108
  else:
95
109
  return "FAILED: There was a problem with capturing the image."
96
110
 
97
- def from_path(self, ctx: CtxItem, prompt: str, path: str) -> str:
111
+ def from_path(
112
+ self,
113
+ ctx: CtxItem,
114
+ prompt: str,
115
+ path: str
116
+ ) -> str:
98
117
  """
99
118
  Image analysis from path
100
119
 
@@ -116,7 +135,11 @@ class Analyzer:
116
135
  }
117
136
  return self.send(ctx, prompt, files)
118
137
 
119
- def from_current_attachments(self, ctx: CtxItem, prompt: str) -> str:
138
+ def from_current_attachments(
139
+ self,
140
+ ctx: CtxItem,
141
+ prompt: str
142
+ ) -> str:
120
143
  """
121
144
  Image analysis from current attachments
122
145
 
pygpt_net/core/web.py CHANGED
@@ -6,9 +6,18 @@
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.02.24 00:00:00 #
9
+ # Updated Date: 2024.12.14 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ import os
13
+ import uuid
14
+ from typing import Optional, List, Dict
15
+
16
+ import requests
17
+
18
+ from bs4 import BeautifulSoup
19
+ from urllib.parse import urljoin
20
+
12
21
  from pygpt_net.provider.web.base import BaseProvider
13
22
 
14
23
 
@@ -58,7 +67,7 @@ class Web:
58
67
  return list(self.providers[type].keys())
59
68
  return []
60
69
 
61
- def get(self, id: str, type: str = "search_engine") -> BaseProvider or None:
70
+ def get(self, id: str, type: str = "search_engine") -> Optional[BaseProvider]:
62
71
  """
63
72
  Get provider instance
64
73
 
@@ -81,3 +90,122 @@ class Web:
81
90
  for t in type:
82
91
  if t in self.providers:
83
92
  self.providers[t][id] = provider
93
+
94
+ def get_main_image(self, url: str) -> Optional[str]:
95
+ """
96
+ Get main image from URL
97
+
98
+ :param url: URL to get image from
99
+ :return: image URL
100
+ """
101
+ response = requests.get(url)
102
+ soup = BeautifulSoup(response.content, 'html.parser')
103
+
104
+ og_image = soup.find('meta', property='og:image')
105
+ if og_image and og_image.get('content'):
106
+ return og_image['content']
107
+
108
+ twitter_image = soup.find('meta', attrs={'name': 'twitter:image'})
109
+ if twitter_image and twitter_image.get('content'):
110
+ return twitter_image['content']
111
+
112
+ link_image = soup.find('link', rel='image_src')
113
+ if link_image and link_image.get('href'):
114
+ return link_image['href']
115
+
116
+ images = soup.find_all('img')
117
+ if images:
118
+ images = [img for img in images if 'logo' not in (img.get('src') or '').lower()]
119
+ largest_image = None
120
+ max_area = 0
121
+ for img in images:
122
+ src = img.get('src')
123
+ if not src:
124
+ continue
125
+ src = requests.compat.urljoin(url, src)
126
+ try:
127
+ img_response = requests.get(src, stream=True, timeout=5)
128
+ img_response.raw.decode_content = True
129
+
130
+ from PIL import Image
131
+ image = Image.open(img_response.raw)
132
+ width, height = image.size
133
+ area = width * height
134
+ if area > max_area:
135
+ max_area = area
136
+ largest_image = src
137
+ except:
138
+ continue
139
+ if largest_image:
140
+ return largest_image
141
+ return None
142
+
143
+ def get_links(self, url: str) -> List[Dict[str, str]]:
144
+ """
145
+ Get links from URL
146
+
147
+ :param url: URL to get links from
148
+ :return: links list
149
+ """
150
+ response = requests.get(url)
151
+ soup = BeautifulSoup(response.content, 'html.parser')
152
+ links = []
153
+ urls = []
154
+ for link in soup.find_all('a'):
155
+ try:
156
+ name = link.get_text(strip=True)
157
+ address = link.get('href')
158
+ if address:
159
+ address = urljoin(url, address)
160
+ if not name:
161
+ title = link.get('title')
162
+ if title:
163
+ name = title
164
+ else:
165
+ name = address
166
+ if address not in urls:
167
+ urls.append(address)
168
+ links.append({name: address})
169
+ except:
170
+ continue
171
+ return links
172
+
173
+
174
+ def get_images(self, url: str) -> List[str]:
175
+ """
176
+ Get images from URL
177
+
178
+ :param url: URL to get images from
179
+ :return: images list
180
+ """
181
+ response = requests.get(url)
182
+ soup = BeautifulSoup(response.content, 'html.parser')
183
+ images = []
184
+ for img in soup.find_all('img'):
185
+ try:
186
+ address = img.get('src')
187
+ if address:
188
+ address = urljoin(url, address)
189
+ if address not in images:
190
+ images.append(address)
191
+ except:
192
+ continue
193
+ return images
194
+
195
+ def download_image(self, img: str) -> str:
196
+ """
197
+ Download image from URL
198
+
199
+ :param img: URL to download image from
200
+ :return: local path to image
201
+ """
202
+ dir = self.window.core.config.get_user_dir("img")
203
+ response = requests.get(img, stream=True)
204
+ name = img.replace("http://", "").replace("https://", "").replace("/", "_")
205
+ path = os.path.join(dir, name)
206
+ if os.path.exists(path):
207
+ name = name + uuid.uuid4().hex[:6].upper()
208
+ download_path = os.path.join(dir, name)
209
+ with open(download_path, 'wb', ) as f:
210
+ f.write(response.content)
211
+ return self.window.core.filesystem.make_local(download_path)
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.4.37",
4
- "app.version": "2.4.37",
5
- "updated_at": "2024-11-30T00:00:00"
3
+ "version": "2.4.41",
4
+ "app.version": "2.4.41",
5
+ "updated_at": "2024-12-14T00:00:00"
6
6
  },
7
7
  "access.audio.event.speech": false,
8
8
  "access.audio.event.speech.disabled": [],
@@ -68,6 +68,9 @@
68
68
  "attachments_auto_index": true,
69
69
  "attachments_send_clear": true,
70
70
  "attachments_capture_clear": true,
71
+ "audio.input.channels": 1,
72
+ "audio.input.device": "0",
73
+ "audio.input.rate": 44100,
71
74
  "audio.transcribe.convert_video": true,
72
75
  "context_threshold": 200,
73
76
  "cmd": false,
@@ -131,6 +134,7 @@
131
134
  "expert": ""
132
135
  },
133
136
  "debug": false,
137
+ "debug.render": false,
134
138
  "download.dir": "download",
135
139
  "experts.mode": "chat",
136
140
  "font_size": 12,
@@ -158,7 +162,13 @@
158
162
  "layout.dpi.scaling": true,
159
163
  "layout.dpi.factor": 1.0,
160
164
  "layout.groups": {},
161
- "layout.splitters": {},
165
+ "layout.splitters": {
166
+ "columns": [
167
+ 1,
168
+ 0
169
+ ]
170
+ },
171
+ "layout.split": false,
162
172
  "layout.tabs": {},
163
173
  "layout.tooltips": true,
164
174
  "layout.tray": true,
@@ -335,6 +345,7 @@
335
345
  "temperature": 1.0,
336
346
  "theme": "dark_cyan",
337
347
  "theme.markdown": true,
348
+ "theme.style": "blocks",
338
349
  "top_p": 1.0,
339
350
  "upload.store": true,
340
351
  "upload.data_dir": false,
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.4.37",
4
- "app.version": "2.4.37",
5
- "updated_at": "2024-11-30T00:00:00"
3
+ "version": "2.4.41",
4
+ "app.version": "2.4.41",
5
+ "updated_at": "2024-12-14T00:00:00"
6
6
  },
7
7
  "items": {
8
8
  "claude-3-5-sonnet-20240620": {
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "__meta__": {
3
- "version": "2.4.37",
4
- "app.version": "2.4.37",
5
- "updated_at": "2024-11-30T00:00:00"
3
+ "version": "2.4.41",
4
+ "app.version": "2.4.41",
5
+ "updated_at": "2024-12-13T00:00:00"
6
6
  },
7
7
  "items": {
8
8
  "chat": {
@@ -146,6 +146,15 @@
146
146
  "step": 1,
147
147
  "advanced": false
148
148
  },
149
+ "theme.style": {
150
+ "section": "layout",
151
+ "type": "combo",
152
+ "use": "styles",
153
+ "label": "settings.theme.style",
154
+ "description": "settings.render.web.only.desc",
155
+ "value": "chatgpt",
156
+ "advanced": false
157
+ },
149
158
  "render.code_syntax": {
150
159
  "section": "layout",
151
160
  "type": "combo",
@@ -937,6 +946,19 @@
937
946
  "step": null,
938
947
  "advanced": true
939
948
  },
949
+ "vision.capture.idx": {
950
+ "section": "vision",
951
+ "type": "int",
952
+ "slider": true,
953
+ "label": "settings.vision.capture.idx",
954
+ "description": "settings.vision.capture.idx.desc",
955
+ "value": 0,
956
+ "min": 0,
957
+ "max": 3,
958
+ "multiplier": 1,
959
+ "step": 1,
960
+ "advanced": false
961
+ },
940
962
  "vision.capture.width": {
941
963
  "section": "vision",
942
964
  "type": "int",
@@ -961,26 +983,49 @@
961
983
  "step": 1,
962
984
  "advanced": false
963
985
  },
964
- "vision.capture.idx": {
986
+ "vision.capture.quality": {
965
987
  "section": "vision",
966
988
  "type": "int",
967
989
  "slider": true,
968
- "label": "settings.vision.capture.idx",
969
- "value": 0,
970
- "min": 0,
971
- "max": 3,
990
+ "label": "settings.vision.capture.quality",
991
+ "value": 85,
992
+ "min": 1,
993
+ "max": 100,
972
994
  "multiplier": 1,
973
995
  "step": 1,
974
996
  "advanced": false
975
997
  },
976
- "vision.capture.quality": {
977
- "section": "vision",
998
+ "audio.input.device": {
999
+ "section": "audio",
1000
+ "type": "combo",
1001
+ "use": "audio_input_devices",
1002
+ "label": "settings.audio.input.device",
1003
+ "description": "settings.audio.input.device.desc",
1004
+ "value": 0,
1005
+ "advanced": false
1006
+ },
1007
+ "audio.input.channels": {
1008
+ "section": "audio",
978
1009
  "type": "int",
979
1010
  "slider": true,
980
- "label": "settings.vision.capture.quality",
981
- "value": 85,
1011
+ "label": "settings.audio.input.channels",
1012
+ "description": "settings.audio.input.channels.desc",
1013
+ "value": 1,
982
1014
  "min": 1,
983
- "max": 100,
1015
+ "max": 4,
1016
+ "multiplier": 1,
1017
+ "step": 1,
1018
+ "advanced": false
1019
+ },
1020
+ "audio.input.rate": {
1021
+ "section": "audio",
1022
+ "type": "int",
1023
+ "slider": true,
1024
+ "label": "settings.audio.input.rate",
1025
+ "description": "settings.audio.input.rate.desc",
1026
+ "value": 44100,
1027
+ "min": 8,
1028
+ "max": 256000,
984
1029
  "multiplier": 1,
985
1030
  "step": 1,
986
1031
  "advanced": false
@@ -23,6 +23,9 @@
23
23
  "vision": {
24
24
  "label": "settings.section.vision"
25
25
  },
26
+ "audio": {
27
+ "label": "settings.section.audio"
28
+ },
26
29
  "llama-index": {
27
30
  "label": "settings.section.llama_index"
28
31
  },
@@ -4,6 +4,7 @@
4
4
  QWidget {{
5
5
  background-color: #e7e7e7;
6
6
  color: #000;
7
+ margin: 1px;
7
8
  }}
8
9
 
9
10
  QListView,