pygpt-net 2.4.37__py3-none-any.whl → 2.4.42__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 (340) hide show
  1. CHANGELOG.md +37 -0
  2. README.md +176 -182
  3. pygpt_net/CHANGELOG.txt +37 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/app.py +3 -1
  6. pygpt_net/controller/__init__.py +7 -3
  7. pygpt_net/controller/access/control.py +1 -1
  8. pygpt_net/controller/access/voice.py +11 -5
  9. pygpt_net/controller/agent/experts.py +11 -6
  10. pygpt_net/controller/agent/legacy.py +8 -6
  11. pygpt_net/controller/agent/llama.py +4 -2
  12. pygpt_net/controller/assistant/__init__.py +9 -4
  13. pygpt_net/controller/assistant/batch.py +38 -21
  14. pygpt_net/controller/assistant/editor.py +7 -6
  15. pygpt_net/controller/assistant/files.py +23 -7
  16. pygpt_net/controller/assistant/store.py +20 -7
  17. pygpt_net/controller/assistant/threads.py +34 -8
  18. pygpt_net/controller/attachment.py +29 -10
  19. pygpt_net/controller/audio/__init__.py +26 -5
  20. pygpt_net/controller/calendar/__init__.py +23 -4
  21. pygpt_net/controller/calendar/note.py +57 -11
  22. pygpt_net/controller/camera.py +4 -12
  23. pygpt_net/controller/chat/__init__.py +5 -3
  24. pygpt_net/controller/chat/attachment.py +34 -7
  25. pygpt_net/controller/chat/audio.py +2 -2
  26. pygpt_net/controller/chat/command.py +4 -2
  27. pygpt_net/controller/chat/common.py +11 -4
  28. pygpt_net/controller/chat/files.py +10 -3
  29. pygpt_net/controller/chat/image.py +17 -5
  30. pygpt_net/controller/chat/input.py +10 -7
  31. pygpt_net/controller/chat/output.py +21 -6
  32. pygpt_net/controller/chat/render.py +100 -21
  33. pygpt_net/controller/chat/response.py +34 -7
  34. pygpt_net/controller/chat/stream.py +4 -2
  35. pygpt_net/controller/chat/text.py +6 -4
  36. pygpt_net/controller/command.py +11 -3
  37. pygpt_net/controller/config/__init__.py +34 -6
  38. pygpt_net/controller/config/field/checkbox.py +7 -4
  39. pygpt_net/controller/config/field/cmd.py +7 -5
  40. pygpt_net/controller/config/field/combo.py +14 -6
  41. pygpt_net/controller/config/field/dictionary.py +14 -11
  42. pygpt_net/controller/config/field/input.py +9 -6
  43. pygpt_net/controller/config/field/slider.py +11 -8
  44. pygpt_net/controller/config/field/textarea.py +8 -5
  45. pygpt_net/controller/config/placeholder.py +66 -21
  46. pygpt_net/controller/ctx/__init__.py +138 -49
  47. pygpt_net/controller/ctx/common.py +15 -4
  48. pygpt_net/controller/ctx/extra.py +11 -3
  49. pygpt_net/controller/ctx/summarizer.py +24 -5
  50. pygpt_net/controller/debug/__init__.py +27 -6
  51. pygpt_net/controller/dialogs/confirm.py +34 -7
  52. pygpt_net/controller/dialogs/debug.py +4 -2
  53. pygpt_net/controller/dialogs/info.py +7 -2
  54. pygpt_net/controller/files.py +48 -10
  55. pygpt_net/controller/finder.py +11 -5
  56. pygpt_net/controller/idx/__init__.py +10 -3
  57. pygpt_net/controller/idx/common.py +4 -2
  58. pygpt_net/controller/idx/indexer.py +25 -17
  59. pygpt_net/controller/idx/settings.py +9 -3
  60. pygpt_net/controller/kernel/__init__.py +34 -8
  61. pygpt_net/controller/kernel/reply.py +12 -3
  62. pygpt_net/controller/kernel/stack.py +5 -3
  63. pygpt_net/controller/lang/custom.py +2 -7
  64. pygpt_net/controller/lang/mapping.py +5 -3
  65. pygpt_net/controller/layout.py +2 -2
  66. pygpt_net/controller/mode.py +16 -4
  67. pygpt_net/controller/model/__init__.py +14 -3
  68. pygpt_net/controller/model/editor.py +8 -3
  69. pygpt_net/controller/notepad.py +26 -12
  70. pygpt_net/controller/painter/capture.py +23 -4
  71. pygpt_net/controller/painter/common.py +9 -7
  72. pygpt_net/controller/plugins/__init__.py +19 -5
  73. pygpt_net/controller/plugins/presets.py +15 -6
  74. pygpt_net/controller/plugins/settings.py +9 -3
  75. pygpt_net/controller/presets/__init__.py +55 -16
  76. pygpt_net/controller/presets/editor.py +26 -10
  77. pygpt_net/controller/settings/__init__.py +3 -2
  78. pygpt_net/controller/settings/editor.py +29 -7
  79. pygpt_net/controller/settings/profile.py +22 -5
  80. pygpt_net/controller/theme/__init__.py +54 -12
  81. pygpt_net/controller/theme/common.py +24 -2
  82. pygpt_net/controller/theme/markdown.py +32 -16
  83. pygpt_net/controller/theme/menu.py +26 -5
  84. pygpt_net/controller/theme/nodes.py +2 -5
  85. pygpt_net/controller/tools/__init__.py +40 -2
  86. pygpt_net/controller/ui/__init__.py +4 -6
  87. pygpt_net/controller/ui/mode.py +16 -21
  88. pygpt_net/controller/ui/tabs.py +363 -65
  89. pygpt_net/core/access/actions.py +6 -4
  90. pygpt_net/core/access/shortcuts.py +4 -3
  91. pygpt_net/core/access/voice.py +6 -5
  92. pygpt_net/core/agents/legacy.py +4 -2
  93. pygpt_net/core/agents/memory.py +7 -2
  94. pygpt_net/core/agents/observer/evaluation.py +15 -7
  95. pygpt_net/core/agents/provider.py +9 -4
  96. pygpt_net/core/agents/runner.py +61 -15
  97. pygpt_net/core/agents/tools.py +23 -5
  98. pygpt_net/core/assistants/__init__.py +6 -4
  99. pygpt_net/core/assistants/files.py +35 -12
  100. pygpt_net/core/assistants/store.py +20 -10
  101. pygpt_net/core/attachments/__init__.py +54 -15
  102. pygpt_net/core/attachments/context.py +92 -29
  103. pygpt_net/core/audio/__init__.py +74 -3
  104. pygpt_net/core/audio/context.py +7 -2
  105. pygpt_net/core/audio/whisper.py +37 -0
  106. pygpt_net/core/bridge/__init__.py +22 -6
  107. pygpt_net/core/bridge/context.py +5 -3
  108. pygpt_net/core/bridge/worker.py +2 -2
  109. pygpt_net/core/calendar/__init__.py +57 -11
  110. pygpt_net/core/chain/__init__.py +8 -2
  111. pygpt_net/core/chain/chat.py +10 -8
  112. pygpt_net/core/chain/completion.py +10 -7
  113. pygpt_net/core/command.py +62 -17
  114. pygpt_net/core/ctx/__init__.py +260 -58
  115. pygpt_net/core/ctx/bag.py +25 -4
  116. pygpt_net/core/ctx/container.py +28 -17
  117. pygpt_net/core/ctx/idx.py +45 -8
  118. pygpt_net/core/ctx/output.py +95 -74
  119. pygpt_net/core/ctx/reply.py +5 -2
  120. pygpt_net/core/db/__init__.py +8 -7
  121. pygpt_net/core/db/viewer.py +17 -11
  122. pygpt_net/core/debug/__init__.py +10 -9
  123. pygpt_net/core/debug/events.py +22 -10
  124. pygpt_net/core/debug/tabs.py +9 -3
  125. pygpt_net/core/docker/__init__.py +11 -5
  126. pygpt_net/core/docker/builder.py +11 -3
  127. pygpt_net/core/events/app.py +5 -3
  128. pygpt_net/core/events/base.py +11 -5
  129. pygpt_net/core/events/control.py +5 -3
  130. pygpt_net/core/events/event.py +17 -7
  131. pygpt_net/core/events/kernel.py +5 -3
  132. pygpt_net/core/events/render.py +5 -3
  133. pygpt_net/core/experts/__init__.py +5 -4
  134. pygpt_net/core/filesystem/__init__.py +52 -34
  135. pygpt_net/core/filesystem/actions.py +8 -5
  136. pygpt_net/core/filesystem/editor.py +13 -3
  137. pygpt_net/core/filesystem/types.py +12 -7
  138. pygpt_net/core/filesystem/url.py +7 -3
  139. pygpt_net/core/history.py +3 -2
  140. pygpt_net/core/idx/__init__.py +48 -27
  141. pygpt_net/core/idx/chat.py +51 -17
  142. pygpt_net/core/idx/context.py +6 -2
  143. pygpt_net/core/idx/indexing.py +107 -42
  144. pygpt_net/core/idx/llm.py +11 -3
  145. pygpt_net/core/idx/metadata.py +13 -3
  146. pygpt_net/core/idx/types/ctx.py +32 -6
  147. pygpt_net/core/idx/types/external.py +41 -7
  148. pygpt_net/core/idx/types/files.py +31 -6
  149. pygpt_net/core/image.py +15 -4
  150. pygpt_net/core/installer.py +2 -4
  151. pygpt_net/core/llm/__init__.py +13 -3
  152. pygpt_net/core/locale.py +34 -8
  153. pygpt_net/core/models.py +63 -17
  154. pygpt_net/core/modes.py +11 -13
  155. pygpt_net/core/notepad.py +10 -5
  156. pygpt_net/core/plugins.py +31 -19
  157. pygpt_net/core/presets.py +37 -17
  158. pygpt_net/core/profile.py +21 -7
  159. pygpt_net/core/prompt/__init__.py +10 -3
  160. pygpt_net/core/prompt/custom.py +7 -6
  161. pygpt_net/core/prompt/template.py +9 -3
  162. pygpt_net/core/render/base.py +117 -22
  163. pygpt_net/core/render/markdown/body.py +27 -7
  164. pygpt_net/core/render/markdown/renderer.py +119 -22
  165. pygpt_net/core/render/plain/body.py +22 -5
  166. pygpt_net/core/render/plain/renderer.py +97 -21
  167. pygpt_net/core/render/web/body.py +75 -25
  168. pygpt_net/core/render/web/parser.py +3 -1
  169. pygpt_net/core/render/web/renderer.py +313 -63
  170. pygpt_net/core/settings.py +10 -5
  171. pygpt_net/core/tabs/__init__.py +290 -103
  172. pygpt_net/core/tabs/tab.py +26 -5
  173. pygpt_net/core/tokens.py +47 -12
  174. pygpt_net/core/updater/__init__.py +20 -7
  175. pygpt_net/core/vision/analyzer.py +29 -6
  176. pygpt_net/core/{web.py → web/__init__.py} +29 -7
  177. pygpt_net/core/web/helpers.py +237 -0
  178. pygpt_net/data/config/config.json +15 -4
  179. pygpt_net/data/config/models.json +3 -3
  180. pygpt_net/data/config/modes.json +3 -3
  181. pygpt_net/data/config/settings.json +55 -10
  182. pygpt_net/data/config/settings_section.json +3 -0
  183. pygpt_net/data/css/style.light.css +1 -0
  184. pygpt_net/data/css/{web.css → web-blocks.css} +162 -133
  185. pygpt_net/data/css/{web.light.css → web-blocks.light.css} +7 -0
  186. pygpt_net/data/css/web-chatgpt.css +350 -0
  187. pygpt_net/data/css/web-chatgpt.dark.css +64 -0
  188. pygpt_net/data/css/web-chatgpt.light.css +75 -0
  189. pygpt_net/data/css/web-chatgpt_wide.css +350 -0
  190. pygpt_net/data/css/web-chatgpt_wide.dark.css +64 -0
  191. pygpt_net/data/css/web-chatgpt_wide.light.css +75 -0
  192. pygpt_net/data/icons/split_screen.svg +1 -0
  193. pygpt_net/data/locale/locale.de.ini +12 -0
  194. pygpt_net/data/locale/locale.en.ini +18 -2
  195. pygpt_net/data/locale/locale.es.ini +12 -0
  196. pygpt_net/data/locale/locale.fr.ini +12 -0
  197. pygpt_net/data/locale/locale.it.ini +12 -0
  198. pygpt_net/data/locale/locale.pl.ini +12 -0
  199. pygpt_net/data/locale/locale.uk.ini +12 -0
  200. pygpt_net/data/locale/locale.zh.ini +12 -0
  201. pygpt_net/data/locale/plugin.cmd_web.de.ini +2 -0
  202. pygpt_net/data/locale/plugin.cmd_web.en.ini +22 -10
  203. pygpt_net/data/locale/plugin.cmd_web.es.ini +2 -0
  204. pygpt_net/data/locale/plugin.cmd_web.fr.ini +2 -0
  205. pygpt_net/data/locale/plugin.cmd_web.it.ini +2 -0
  206. pygpt_net/data/locale/plugin.cmd_web.pl.ini +2 -0
  207. pygpt_net/data/locale/plugin.cmd_web.uk.ini +2 -0
  208. pygpt_net/data/locale/plugin.cmd_web.zh.ini +2 -0
  209. pygpt_net/data/locale/plugin.mailer.en.ini +21 -0
  210. pygpt_net/icons.qrc +1 -0
  211. pygpt_net/icons_rc.py +165 -136
  212. pygpt_net/item/ctx.py +58 -25
  213. pygpt_net/plugin/agent/__init__.py +7 -2
  214. pygpt_net/plugin/audio_input/simple.py +21 -5
  215. pygpt_net/plugin/audio_output/__init__.py +9 -1
  216. pygpt_net/plugin/base/config.py +4 -2
  217. pygpt_net/plugin/base/plugin.py +75 -23
  218. pygpt_net/plugin/base/worker.py +42 -11
  219. pygpt_net/plugin/cmd_code_interpreter/__init__.py +39 -37
  220. pygpt_net/plugin/cmd_code_interpreter/runner.py +25 -12
  221. pygpt_net/plugin/cmd_history/config.py +2 -2
  222. pygpt_net/plugin/cmd_web/__init__.py +48 -9
  223. pygpt_net/plugin/cmd_web/config.py +135 -41
  224. pygpt_net/plugin/cmd_web/websearch.py +74 -33
  225. pygpt_net/plugin/cmd_web/worker.py +142 -13
  226. pygpt_net/plugin/idx_llama_index/config.py +3 -3
  227. pygpt_net/plugin/mailer/__init__.py +123 -0
  228. pygpt_net/plugin/mailer/config.py +149 -0
  229. pygpt_net/plugin/mailer/runner.py +285 -0
  230. pygpt_net/plugin/mailer/worker.py +123 -0
  231. pygpt_net/provider/agents/base.py +5 -2
  232. pygpt_net/provider/agents/openai.py +4 -2
  233. pygpt_net/provider/agents/openai_assistant.py +4 -2
  234. pygpt_net/provider/agents/planner.py +4 -2
  235. pygpt_net/provider/agents/react.py +4 -2
  236. pygpt_net/provider/audio_output/openai_tts.py +5 -11
  237. pygpt_net/provider/core/assistant/base.py +5 -3
  238. pygpt_net/provider/core/assistant/json_file.py +8 -5
  239. pygpt_net/provider/core/assistant_file/base.py +4 -3
  240. pygpt_net/provider/core/assistant_file/db_sqlite/__init__.py +4 -3
  241. pygpt_net/provider/core/assistant_file/db_sqlite/storage.py +3 -2
  242. pygpt_net/provider/core/assistant_store/base.py +6 -4
  243. pygpt_net/provider/core/assistant_store/db_sqlite/__init__.py +5 -4
  244. pygpt_net/provider/core/assistant_store/db_sqlite/storage.py +5 -3
  245. pygpt_net/provider/core/attachment/base.py +5 -3
  246. pygpt_net/provider/core/attachment/json_file.py +4 -3
  247. pygpt_net/provider/core/calendar/base.py +5 -3
  248. pygpt_net/provider/core/calendar/db_sqlite/__init__.py +6 -5
  249. pygpt_net/provider/core/calendar/db_sqlite/storage.py +5 -4
  250. pygpt_net/provider/core/config/base.py +8 -6
  251. pygpt_net/provider/core/config/json_file.py +9 -7
  252. pygpt_net/provider/core/config/patch.py +43 -1
  253. pygpt_net/provider/core/ctx/base.py +30 -25
  254. pygpt_net/provider/core/ctx/db_sqlite/__init__.py +59 -34
  255. pygpt_net/provider/core/ctx/db_sqlite/storage.py +62 -30
  256. pygpt_net/provider/core/ctx/db_sqlite/utils.py +11 -9
  257. pygpt_net/provider/core/index/base.py +129 -23
  258. pygpt_net/provider/core/index/db_sqlite/__init__.py +130 -23
  259. pygpt_net/provider/core/index/db_sqlite/storage.py +130 -23
  260. pygpt_net/provider/core/index/db_sqlite/utils.py +4 -2
  261. pygpt_net/provider/core/mode/base.py +5 -3
  262. pygpt_net/provider/core/mode/json_file.py +7 -6
  263. pygpt_net/provider/core/model/base.py +6 -4
  264. pygpt_net/provider/core/model/json_file.py +9 -7
  265. pygpt_net/provider/core/notepad/base.py +5 -3
  266. pygpt_net/provider/core/notepad/db_sqlite/__init__.py +5 -4
  267. pygpt_net/provider/core/notepad/db_sqlite/storage.py +4 -3
  268. pygpt_net/provider/core/plugin_preset/base.py +4 -2
  269. pygpt_net/provider/core/plugin_preset/json_file.py +5 -3
  270. pygpt_net/provider/core/preset/base.py +6 -4
  271. pygpt_net/provider/core/preset/json_file.py +9 -9
  272. pygpt_net/provider/core/prompt/base.py +6 -3
  273. pygpt_net/provider/core/prompt/json_file.py +11 -6
  274. pygpt_net/provider/gpt/assistants.py +21 -11
  275. pygpt_net/provider/gpt/audio.py +6 -5
  276. pygpt_net/provider/gpt/chat.py +10 -7
  277. pygpt_net/provider/gpt/completion.py +11 -5
  278. pygpt_net/provider/gpt/image.py +9 -2
  279. pygpt_net/provider/gpt/store.py +53 -18
  280. pygpt_net/provider/gpt/vision.py +17 -11
  281. pygpt_net/provider/llms/anthropic.py +7 -2
  282. pygpt_net/provider/llms/azure_openai.py +26 -5
  283. pygpt_net/provider/llms/base.py +47 -9
  284. pygpt_net/provider/llms/google.py +7 -2
  285. pygpt_net/provider/llms/hugging_face.py +13 -3
  286. pygpt_net/provider/llms/hugging_face_api.py +18 -4
  287. pygpt_net/provider/llms/local.py +7 -2
  288. pygpt_net/provider/llms/ollama.py +30 -6
  289. pygpt_net/provider/llms/openai.py +32 -6
  290. pygpt_net/provider/vector_stores/__init__.py +45 -14
  291. pygpt_net/provider/vector_stores/base.py +35 -8
  292. pygpt_net/provider/vector_stores/chroma.py +13 -3
  293. pygpt_net/provider/vector_stores/ctx_attachment.py +31 -12
  294. pygpt_net/provider/vector_stores/elasticsearch.py +12 -3
  295. pygpt_net/provider/vector_stores/pinecode.py +12 -3
  296. pygpt_net/provider/vector_stores/redis.py +12 -3
  297. pygpt_net/provider/vector_stores/simple.py +12 -3
  298. pygpt_net/provider/vector_stores/temp.py +16 -4
  299. pygpt_net/provider/web/base.py +10 -3
  300. pygpt_net/provider/web/google_custom_search.py +9 -3
  301. pygpt_net/provider/web/microsoft_bing.py +9 -3
  302. pygpt_net/tools/__init__.py +20 -4
  303. pygpt_net/tools/audio_transcriber/__init__.py +4 -3
  304. pygpt_net/tools/base.py +28 -7
  305. pygpt_net/tools/code_interpreter/__init__.py +177 -77
  306. pygpt_net/tools/code_interpreter/ui/dialogs.py +21 -103
  307. pygpt_net/tools/code_interpreter/ui/widgets.py +284 -9
  308. pygpt_net/tools/html_canvas/__init__.py +81 -25
  309. pygpt_net/tools/html_canvas/ui/dialogs.py +46 -62
  310. pygpt_net/tools/html_canvas/ui/widgets.py +96 -3
  311. pygpt_net/tools/image_viewer/__init__.py +10 -4
  312. pygpt_net/tools/indexer/__init__.py +8 -7
  313. pygpt_net/tools/media_player/__init__.py +4 -3
  314. pygpt_net/tools/text_editor/__init__.py +36 -10
  315. pygpt_net/ui/base/context_menu.py +2 -2
  316. pygpt_net/ui/layout/chat/input.py +10 -18
  317. pygpt_net/ui/layout/chat/output.py +27 -45
  318. pygpt_net/ui/layout/ctx/ctx_list.py +13 -4
  319. pygpt_net/ui/layout/toolbox/footer.py +18 -2
  320. pygpt_net/ui/main.py +2 -2
  321. pygpt_net/ui/menu/audio.py +12 -1
  322. pygpt_net/ui/menu/config.py +7 -11
  323. pygpt_net/ui/menu/debug.py +11 -1
  324. pygpt_net/ui/menu/theme.py +9 -2
  325. pygpt_net/ui/widget/filesystem/explorer.py +2 -2
  326. pygpt_net/ui/widget/lists/context.py +27 -5
  327. pygpt_net/ui/widget/tabs/Input.py +2 -2
  328. pygpt_net/ui/widget/tabs/body.py +2 -1
  329. pygpt_net/ui/widget/tabs/layout.py +195 -0
  330. pygpt_net/ui/widget/tabs/output.py +218 -55
  331. pygpt_net/ui/widget/textarea/html.py +11 -1
  332. pygpt_net/ui/widget/textarea/output.py +10 -1
  333. pygpt_net/ui/widget/textarea/search_input.py +4 -1
  334. pygpt_net/ui/widget/textarea/web.py +49 -9
  335. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/METADATA +177 -183
  336. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/RECORD +340 -325
  337. /pygpt_net/data/css/{web.dark.css → web-blocks.dark.css} +0 -0
  338. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/LICENSE +0 -0
  339. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.dist-info}/WHEEL +0 -0
  340. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.42.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.02.25 01:00:00 #
9
+ # Updated Date: 2024.12.14 22:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import json
13
+ from typing import List, Dict
13
14
  from urllib.parse import quote
14
15
 
15
16
  import requests
@@ -60,7 +61,12 @@ class MicrosoftBingSearch(BaseProvider):
60
61
  tab="microsoft_bing",
61
62
  )
62
63
 
63
- def search(self, query: str, limit: int = 10, offset: int = 0) -> list:
64
+ def search(
65
+ self,
66
+ query: str,
67
+ limit: int = 10,
68
+ offset: int = 0
69
+ ) -> List[str]:
64
70
  """
65
71
  Execute search query and return list of urls
66
72
 
@@ -97,7 +103,7 @@ class MicrosoftBingSearch(BaseProvider):
97
103
  print('Error:', response.status_code, response.text)
98
104
  return urls
99
105
 
100
- def is_configured(self, cmds: list) -> bool:
106
+ def is_configured(self, cmds: List[Dict]) -> bool:
101
107
  """
102
108
  Check if provider is configured (required API keys, etc.)
103
109
 
@@ -6,9 +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.04.19 01:00:00 #
9
+ # Updated Date: 2024.12.14 22:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ from typing import Dict, Optional
13
+
14
+ from PySide6.QtGui import QAction
15
+
12
16
  from pygpt_net.ui.widget.dialog.base import BaseDialog
13
17
  from .base import BaseTool
14
18
 
@@ -42,6 +46,14 @@ class Tools:
42
46
  if id in self.tools:
43
47
  return self.tools[id]
44
48
 
49
+ def get_all(self) -> Dict[str, BaseTool]:
50
+ """
51
+ Get all tools
52
+
53
+ :return: dict with tools
54
+ """
55
+ return self.tools
56
+
45
57
  def setup(self):
46
58
  """Setup tools"""
47
59
  self.setup_dialogs()
@@ -75,7 +87,7 @@ class Tools:
75
87
  for id in self.tools:
76
88
  self.tools[id].on_reload()
77
89
 
78
- def setup_menu_actions(self) -> dict:
90
+ def setup_menu_actions(self) -> Dict[str, QAction]:
79
91
  """
80
92
  Setup Tools menu actions
81
93
 
@@ -102,7 +114,11 @@ class Tools:
102
114
  for id in self.tools:
103
115
  self.tools[id].setup_theme()
104
116
 
105
- def get_instance(self, type_id: str, dialog_id: str = None) -> BaseDialog:
117
+ def get_instance(
118
+ self,
119
+ type_id: str,
120
+ dialog_id: Optional[str] = None
121
+ ) -> Optional[BaseDialog]:
106
122
  """
107
123
  Spawn and return dialog instance
108
124
 
@@ -115,7 +131,7 @@ class Tools:
115
131
  if instance is not None:
116
132
  return instance
117
133
 
118
- def get_lang_mappings(self) -> dict:
134
+ def get_lang_mappings(self) -> Dict[str, dict]:
119
135
  """
120
136
  Get language mappings
121
137
 
@@ -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.20 03:00:00 #
9
+ # Updated Date: 2024.12.14 22:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
+ from typing import Dict
13
14
 
14
15
  from PySide6.QtGui import QAction, QIcon
15
16
  from PySide6.QtWidgets import QFileDialog
@@ -255,7 +256,7 @@ class AudioTranscriber(BaseTool):
255
256
  self.window.ui.nodes['audio.transcribe.status'].setText("")
256
257
  self.store("")
257
258
 
258
- def setup_menu(self) -> dict:
259
+ def setup_menu(self) -> Dict[str, QAction]:
259
260
  """
260
261
  Setup main menu
261
262
 
@@ -278,7 +279,7 @@ class AudioTranscriber(BaseTool):
278
279
  self.dialog = AudioTranscribe(self.window)
279
280
  self.dialog.setup()
280
281
 
281
- def get_lang_mappings(self) -> dict:
282
+ def get_lang_mappings(self) -> Dict[str, Dict]:
282
283
  """
283
284
  Get language mappings
284
285
 
pygpt_net/tools/base.py CHANGED
@@ -6,11 +6,16 @@
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.14 01:00:00 #
9
+ # Updated Date: 2024.12.14 22:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ from typing import Optional, Dict
13
+
12
14
  from PySide6.QtCore import QObject
15
+ from PySide6.QtGui import QAction
16
+ from PySide6.QtWidgets import QWidget
13
17
 
18
+ from pygpt_net.core.tabs.tab import Tab
14
19
  from pygpt_net.ui.widget.dialog.base import BaseDialog
15
20
 
16
21
  class BaseTool(QObject):
@@ -25,6 +30,9 @@ class BaseTool(QObject):
25
30
  super(BaseTool, self).__init__()
26
31
  self.window = None
27
32
  self.id = ""
33
+ self.has_tab = False
34
+ self.tab_title = ""
35
+ self.tab_icon = ":/icons/build.svg"
28
36
 
29
37
  def setup(self):
30
38
  """Setup tool"""
@@ -58,13 +66,13 @@ class BaseTool(QObject):
58
66
  """
59
67
  self.window = window
60
68
 
61
- def setup_menu(self) -> list:
69
+ def setup_menu(self) -> Dict[str, QAction]:
62
70
  """
63
71
  Setup main menu
64
72
 
65
- :return list with menu actions
73
+ :return dict with menu actions
66
74
  """
67
- return []
75
+ return {}
68
76
 
69
77
  def setup_dialogs(self):
70
78
  """Setup dialogs (static)"""
@@ -74,16 +82,29 @@ class BaseTool(QObject):
74
82
  """Setup theme"""
75
83
  pass
76
84
 
77
- def get_instance(self, id: str, dialog_id: str = None) -> BaseDialog or None:
85
+ def get_instance(
86
+ self,
87
+ type_id: str,
88
+ dialog_id: Optional[str] = None
89
+ ) -> Optional[BaseDialog]:
78
90
  """
79
91
  Spawn and return dialog instance
80
92
 
81
- :param id: dialog instance ID
93
+ :param type_id: dialog instance ID
82
94
  :param dialog_id: dialog instance ID
83
95
  """
84
96
  return None
85
97
 
86
- def get_lang_mappings(self) -> dict:
98
+ def as_tab(self, tab: Tab) -> Optional[QWidget]:
99
+ """
100
+ Spawn and return tab instance
101
+
102
+ :param tab: Parent tab instance
103
+ :return: Tab widget instance
104
+ """
105
+ return None
106
+
107
+ def get_lang_mappings(self) -> Dict[str, Dict]:
87
108
  """
88
109
  Get language mappings
89
110
 
@@ -6,20 +6,25 @@
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.20 03:00:00 #
9
+ # Updated Date: 2024.12.14 22:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
+ from typing import Dict
13
14
 
14
15
  from PySide6.QtCore import QTimer
15
16
  from PySide6.QtGui import QTextCursor, QAction, QIcon
17
+ from PySide6.QtWidgets import QWidget
16
18
 
19
+ from pygpt_net.core.tabs.tab import Tab
17
20
  from pygpt_net.tools.base import BaseTool
18
- from pygpt_net.tools.code_interpreter.ui.dialogs import Interpreter
21
+ from pygpt_net.tools.code_interpreter.ui.dialogs import Tool
19
22
  from pygpt_net.core.events import Event
20
23
  from pygpt_net.item.ctx import CtxItem
21
24
  from pygpt_net.utils import trans
22
25
 
26
+ from .ui.widgets import PythonInput, PythonOutput, ToolWidget, ToolSignals
27
+
23
28
 
24
29
  class CodeInterpreter(BaseTool):
25
30
  def __init__(self, *args, **kwargs):
@@ -30,11 +35,15 @@ class CodeInterpreter(BaseTool):
30
35
  """
31
36
  super(CodeInterpreter, self).__init__(*args, **kwargs)
32
37
  self.id = "interpreter"
38
+ self.has_tab = True
39
+ self.tab_title = "menu.tools.interpreter"
40
+ self.tab_icon = ":/icons/code.svg"
33
41
  self.opened = False
34
42
  self.is_edit = False
35
43
  self.auto_clear = False
36
44
  self.dialog = None
37
45
  self.ipython = True
46
+ self.signals = ToolSignals()
38
47
 
39
48
  # interpreter data files in /data directory
40
49
  self.file_current = ".interpreter.current.py"
@@ -49,15 +58,15 @@ class CodeInterpreter(BaseTool):
49
58
 
50
59
  # restore
51
60
  if self.window.core.config.has("interpreter.input"):
52
- self.window.ui.nodes['interpreter.input'].setPlainText(self.window.core.config.get("interpreter.input"))
61
+ self.signals.update_input.emit(self.window.core.config.get("interpreter.input"))
53
62
  if self.window.core.config.has("interpreter.execute_all"):
54
- self.window.ui.nodes['interpreter.all'].setChecked(self.window.core.config.get("interpreter.execute_all"))
63
+ self.signals.set_checkbox_all.emit(self.window.core.config.get("interpreter.execute_all"))
55
64
  if self.window.core.config.has("interpreter.auto_clear"):
56
- self.window.ui.nodes['interpreter.auto_clear'].setChecked(self.window.core.config.get("interpreter.auto_clear"))
65
+ self.signals.set_checkbox_auto_clear.emit(self.window.core.config.get("interpreter.auto_clear"))
57
66
  if self.window.core.config.has("interpreter.ipython"):
58
- self.window.ui.nodes['interpreter.ipython'].setChecked(self.window.core.config.get("interpreter.ipython"))
67
+ self.signals.set_checkbox_ipython.emit(self.window.core.config.get("interpreter.ipython"))
59
68
  if self.ipython:
60
- self.window.ui.nodes['interpreter.all'].setVisible(False)
69
+ self.signals.toggle_all_visible.emit(False)
61
70
 
62
71
  # set initial size
63
72
  if not self.window.core.config.has("interpreter.dialog.initialized"):
@@ -119,28 +128,62 @@ class CodeInterpreter(BaseTool):
119
128
  :param type: Output type
120
129
  :param kwargs: Additional parameters
121
130
  """
122
- area = self.window.interpreter
123
- if type == "stdin":
124
- data = ">> " + str(output)
125
- else:
126
- data = str(output)
127
- cur = area.textCursor()
128
- cur.movePosition(QTextCursor.End)
129
- s = data + "\n"
130
- while s:
131
- head, sep, s = s.partition("\n")
132
- cur.insertText(head)
133
- if sep: # New line if LF
134
- cur.insertText("\n")
135
- area.setTextCursor(cur)
131
+ self.signals.update.emit(output, type)
136
132
  self.save_output()
137
133
  self.load_history()
138
134
 
135
+ def get_path_input(self) -> str:
136
+ """
137
+ Get input path
138
+
139
+ :return: Input path
140
+ """
141
+ return os.path.join(self.window.core.config.get_user_dir("data"), self.file_input)
142
+
143
+ def get_path_output(self) -> str:
144
+ """
145
+ Get output path
146
+
147
+ :return: Output path
148
+ """
149
+ return os.path.join(self.window.core.config.get_user_dir("data"), self.file_output)
150
+
151
+ def get_widget(self) -> ToolWidget:
152
+ """
153
+ Get tool widget
154
+
155
+ :return: ToolWidget instance
156
+ """
157
+ return self.dialog.widget
158
+
159
+ def get_widget_history(self) -> PythonOutput:
160
+ """
161
+ Get history widget
162
+
163
+ :return: PythonOutput widget
164
+ """
165
+ return self.dialog.widget.history
166
+
167
+ def get_widget_output(self) -> PythonOutput:
168
+ """
169
+ Get output widget
170
+
171
+ :return: PythonOutput widget
172
+ """
173
+ return self.dialog.widget.output
174
+
175
+ def get_widget_input(self) -> PythonInput:
176
+ """
177
+ Get input widget
178
+
179
+ :return: PythonInput widget
180
+ """
181
+ return self.dialog.widget.input
182
+
139
183
  def load_history(self):
140
184
  """Load history data from file"""
141
185
  data = self.get_history()
142
- self.window.ui.nodes['interpreter.code'].setPlainText(data)
143
- self.cursor_to_end()
186
+ self.signals.update_history.emit(data)
144
187
 
145
188
  def get_output(self) -> str:
146
189
  """
@@ -149,7 +192,7 @@ class CodeInterpreter(BaseTool):
149
192
  :return: Output data
150
193
  """
151
194
  data = ""
152
- path = os.path.join(self.window.core.config.get_user_dir("data"), self.file_output)
195
+ path = self.get_path_output()
153
196
  if os.path.exists(path):
154
197
  with open(path, "r", encoding="utf-8") as f:
155
198
  try:
@@ -161,13 +204,13 @@ class CodeInterpreter(BaseTool):
161
204
  def load_output(self):
162
205
  """Load output data from file"""
163
206
  data = self.get_output()
164
- self.window.interpreter.setPlainText(data)
165
- self.window.ui.nodes['interpreter.input'].setFocus()
207
+ self.signals.update.emit(data, "stdout")
208
+ self.signals.focus_input.emit()
166
209
 
167
210
  def save_output(self):
168
211
  """Save output data to file"""
169
- path = os.path.join(self.window.core.config.get_user_dir("data"), self.file_output)
170
- data = self.window.interpreter.toPlainText()
212
+ path = self.get_path_output()
213
+ data = self.get_widget_output().toPlainText()
171
214
  with open(path, "w", encoding="utf-8") as f:
172
215
  f.write(data)
173
216
 
@@ -178,7 +221,7 @@ class CodeInterpreter(BaseTool):
178
221
  :return: History data
179
222
  """
180
223
  data = ""
181
- path = os.path.join(self.window.core.config.get_user_dir("data"), self.file_input)
224
+ path = self.get_path_input()
182
225
  if os.path.exists(path):
183
226
  with open(path, "r", encoding="utf-8") as f:
184
227
  try:
@@ -193,23 +236,23 @@ class CodeInterpreter(BaseTool):
193
236
 
194
237
  :param input: Input data
195
238
  """
196
- path = os.path.join(self.window.core.config.get_user_dir("data"), self.file_input)
239
+ path = self.get_path_input()
197
240
  with open(path , "w", encoding="utf-8") as f:
198
241
  f.write(input)
199
242
 
200
243
  def clear_history(self):
201
244
  """Clear input"""
202
- path = os.path.join(self.window.core.config.get_user_dir("data"), self.file_input)
245
+ path = self.get_path_input()
203
246
  if os.path.exists(path):
204
247
  os.remove(path)
205
- self.window.ui.nodes['interpreter.code'].clear()
248
+ self.signals.clear_history.emit()
206
249
 
207
250
  def clear_output(self):
208
251
  """Clear output"""
209
- path = os.path.join(self.window.core.config.get_user_dir("data"), self.file_output)
252
+ path = self.get_path_output()
210
253
  if os.path.exists(path):
211
254
  os.remove(path)
212
- self.window.interpreter.clear()
255
+ self.signals.clear_output.emit()
213
256
 
214
257
  def clear(self, force: bool = False):
215
258
  """
@@ -248,15 +291,32 @@ class CodeInterpreter(BaseTool):
248
291
  })
249
292
  event.ctx = CtxItem() # tmp
250
293
  self.window.controller.command.dispatch_only(event)
251
- self.window.ui.nodes['interpreter.input'].setFocus()
294
+ self.signals.focus_input.emit()
295
+
296
+ def send_input(self, widget: ToolWidget):
297
+ """
298
+ Send input to interpreter
252
299
 
253
- def send_input(self):
254
- """Send input to interpreter"""
255
- self.store_history()
300
+ :param widget: PythonInput widget
301
+ """
302
+ self.store_history(widget)
256
303
  if self.auto_clear:
257
304
  self.clear_output()
258
305
 
259
- input = str(self.window.ui.nodes['interpreter.input'].toPlainText())
306
+ input_textarea = widget.input
307
+ input = str(input_textarea.toPlainText()).strip()
308
+
309
+ if input == "/restart":
310
+ self.restart_kernel()
311
+ input_textarea.clear()
312
+ input_textarea.setFocus()
313
+ return
314
+ elif input == "/clear":
315
+ self.clear(force=True)
316
+ input_textarea.clear()
317
+ input_textarea.setFocus()
318
+ return
319
+
260
320
  if self.is_all():
261
321
  cmd = "code_execute_all"
262
322
  else:
@@ -284,12 +344,12 @@ class CodeInterpreter(BaseTool):
284
344
  })
285
345
  event.ctx = CtxItem() # tmp
286
346
  self.window.controller.command.dispatch_only(event)
287
- self.window.ui.nodes['interpreter.input'].clear()
288
- self.window.ui.nodes['interpreter.input'].setFocus()
347
+ input_textarea.clear()
348
+ input_textarea.setFocus()
289
349
 
290
350
  def update_input(self):
291
351
  """Update input data"""
292
- data = self.window.ui.nodes['interpreter.input'].toPlainText()
352
+ data = self.get_widget_input().toPlainText()
293
353
  self.window.core.config.set("interpreter.input", data)
294
354
 
295
355
  def append_to_input(self, data: str):
@@ -298,11 +358,7 @@ class CodeInterpreter(BaseTool):
298
358
 
299
359
  :param data: Data
300
360
  """
301
- current = self.window.ui.nodes['interpreter.input'].toPlainText()
302
- if current:
303
- current += "\n"
304
- current += data
305
- self.window.ui.nodes['interpreter.input'].setPlainText(current)
361
+ self.signals.append_input.emit(data)
306
362
 
307
363
  def append_to_edit(self, data: str):
308
364
  """
@@ -317,9 +373,15 @@ class CodeInterpreter(BaseTool):
317
373
  self.save_history(prev)
318
374
  self.load_history()
319
375
 
320
- def store_history(self):
321
- """Save history data to file"""
322
- data = self.window.ui.nodes['interpreter.code'].toPlainText()
376
+ def store_history(self, widget: ToolWidget):
377
+ """
378
+ Save history data to file
379
+
380
+ :param widget: ToolWidget
381
+ """
382
+ if not widget.history:
383
+ return
384
+ data = widget.history.toPlainText()
323
385
  self.save_history(data)
324
386
 
325
387
  def open(self):
@@ -328,7 +390,7 @@ class CodeInterpreter(BaseTool):
328
390
  self.load_history()
329
391
  self.load_output()
330
392
  self.window.ui.dialogs.open('interpreter', width=800, height=600)
331
- self.window.ui.nodes['interpreter.input'].setFocus()
393
+ self.get_widget_input().setFocus()
332
394
  self.cursor_to_end()
333
395
  self.scroll_to_bottom()
334
396
  self.update()
@@ -341,11 +403,11 @@ class CodeInterpreter(BaseTool):
341
403
 
342
404
  def scroll_to_bottom(self):
343
405
  """Scroll down"""
344
- self.window.ui.nodes['interpreter.code'].verticalScrollBar().setValue(
345
- self.window.ui.nodes['interpreter.code'].verticalScrollBar().maximum()
406
+ self.get_widget_history().verticalScrollBar().setValue(
407
+ self.get_widget_history().verticalScrollBar().maximum()
346
408
  )
347
- self.window.interpreter.verticalScrollBar().setValue(
348
- self.window.interpreter.verticalScrollBar().maximum()
409
+ self.get_widget_output().verticalScrollBar().setValue(
410
+ self.get_widget_output().verticalScrollBar().maximum()
349
411
  )
350
412
 
351
413
  def toggle(self):
@@ -366,31 +428,55 @@ class CodeInterpreter(BaseTool):
366
428
  else:
367
429
  self.close()
368
430
 
431
+ def get_toolbar_icon(self) -> QWidget:
432
+ """
433
+ Get toolbar icon
434
+
435
+ :return: QWidget
436
+ """
437
+ return self.window.ui.nodes['icon.interpreter']
438
+
369
439
  def toggle_icon(self, state: bool):
370
440
  """
371
441
  Toggle interpreter icon
372
442
 
373
443
  :param state: State
374
444
  """
375
- self.window.ui.nodes['icon.interpreter'].setVisible(state)
445
+ self.get_toolbar_icon().setVisible(state)
376
446
 
377
- def toggle_auto_clear(self):
378
- """Toggle auto clear"""
379
- self.auto_clear = self.window.ui.nodes['interpreter.auto_clear'].isChecked()
447
+ def toggle_auto_clear(self, widget: ToolWidget):
448
+ """
449
+ Toggle auto clear
450
+
451
+ :param widget: ToolWidget instance
452
+ """
453
+ self.auto_clear = widget.checkbox_auto_clear.isChecked()
380
454
  self.window.core.config.set("interpreter.auto_clear", self.auto_clear)
455
+ self.signals.set_checkbox_auto_clear.emit(self.auto_clear)
456
+
457
+ def toggle_ipython(self, widget: ToolWidget):
458
+ """
459
+ Toggle ipython
381
460
 
382
- def toggle_ipython(self):
383
- """Toggle ipython"""
384
- self.ipython = self.window.ui.nodes['interpreter.ipython'].isChecked()
461
+ :param widget: ToolWidget instance
462
+ """
463
+ self.ipython = widget.checkbox_ipython.isChecked()
385
464
  self.window.core.config.set("interpreter.ipython", self.ipython)
465
+ self.signals.set_checkbox_ipython.emit(self.ipython)
386
466
  if self.ipython:
387
- self.window.ui.nodes['interpreter.all'].setVisible(False)
467
+ self.signals.toggle_all_visible.emit(False)
388
468
  else:
389
- self.window.ui.nodes['interpreter.all'].setVisible(True)
469
+ self.signals.toggle_all_visible.emit(True)
470
+
471
+ def toggle_all(self, widget: ToolWidget):
472
+ """
473
+ Toggle execute all
390
474
 
391
- def toggle_all(self):
392
- """Toggle execute all"""
393
- self.window.core.config.set("interpreter.execute_all", self.window.ui.nodes['interpreter.all'].isChecked())
475
+ :param widget: ToolWidget instance
476
+ """
477
+ state = widget.checkbox_all.isChecked()
478
+ self.window.core.config.set("interpreter.execute_all", state)
479
+ self.signals.set_checkbox_all.emit(state)
394
480
 
395
481
  def get_current_output(self) -> str:
396
482
  """
@@ -398,7 +484,7 @@ class CodeInterpreter(BaseTool):
398
484
 
399
485
  :return: Output data
400
486
  """
401
- return self.window.interpreter.toPlainText()
487
+ return self.get_output()
402
488
 
403
489
  def get_current_history(self) -> str:
404
490
  """
@@ -406,7 +492,7 @@ class CodeInterpreter(BaseTool):
406
492
 
407
493
  :return: Edit code
408
494
  """
409
- return self.window.ui.nodes['interpreter.code'].toPlainText()
495
+ return self.get_history()
410
496
 
411
497
  def is_all(self) -> bool:
412
498
  """
@@ -414,15 +500,15 @@ class CodeInterpreter(BaseTool):
414
500
 
415
501
  :return: True if execute all is enabled
416
502
  """
417
- return self.window.ui.nodes['interpreter.all'].isChecked()
503
+ return self.get_widget().checkbox_all.isChecked()
418
504
 
419
505
  def cursor_to_end(self):
420
506
  """Move cursor to end"""
421
- cur = self.window.ui.nodes['interpreter.code'].textCursor()
507
+ cur = self.get_widget_history().textCursor()
422
508
  cur.movePosition(QTextCursor.End)
423
- self.window.ui.nodes['interpreter.code'].setTextCursor(cur)
509
+ self.get_widget_history().setTextCursor(cur)
424
510
 
425
- def setup_menu(self) -> dict:
511
+ def setup_menu(self) -> Dict[str, QAction]:
426
512
  """
427
513
  Setup main menu
428
514
 
@@ -440,17 +526,31 @@ class CodeInterpreter(BaseTool):
440
526
  )
441
527
  return actions
442
528
 
529
+ def as_tab(self, tab: Tab) -> QWidget:
530
+ """
531
+ Spawn and return tab instance
532
+
533
+ :param tab: Parent Tab instance
534
+ :return: Tab widget instance
535
+ """
536
+ tool = Tool(window=self.window, tool=self)
537
+ layout = tool.widget.setup(all=False)
538
+ widget = QWidget()
539
+ widget.setLayout(layout)
540
+ self.load_history()
541
+ self.load_output()
542
+ return widget
543
+
443
544
  def setup_dialogs(self):
444
545
  """Setup dialogs (static)"""
445
- self.dialog = Interpreter(self.window)
546
+ self.dialog = Tool(self.window, self)
446
547
  self.dialog.setup()
447
548
 
448
549
  def setup_theme(self):
449
550
  """Setup theme"""
450
- size = self.window.core.config.get('font_size')
451
- self.window.interpreter.value = size
551
+ self.get_widget_output().value = self.window.core.config.get('font_size')
452
552
 
453
- def get_lang_mappings(self) -> dict:
553
+ def get_lang_mappings(self) -> Dict[str, Dict]:
454
554
  """
455
555
  Get language mappings
456
556