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,17 +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.11.20 21:00:00 #
9
+ # Updated Date: 2024.12.14 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
+ from typing import Any, Optional
14
+
15
+ from pygpt_net.core.events import RenderEvent
13
16
 
14
17
  from .common import Common
15
18
  from .markdown import Markdown
16
19
  from .menu import Menu
17
20
  from .nodes import Nodes
18
- from ...core.events import RenderEvent
19
-
20
21
 
21
22
  class Theme:
22
23
  def __init__(self, window=None):
@@ -47,7 +48,11 @@ class Theme:
47
48
  # apply current theme to nodes
48
49
  self.reload(force=False)
49
50
 
50
- def toggle(self, name: str, force: bool = True):
51
+ def toggle(
52
+ self,
53
+ name: str,
54
+ force: bool = True
55
+ ):
51
56
  """
52
57
  Toggle theme by name
53
58
 
@@ -68,12 +73,27 @@ class Theme:
68
73
  # update themes menu
69
74
  self.menu.update_list()
70
75
  self.menu.update_syntax()
71
- self.window.ui.menu['theme.blocks'].setChecked(self.window.core.config.get("render.blocks"))
72
76
 
73
77
  if force:
74
78
  self.window.controller.ui.restore_state() # restore state after theme change
75
79
 
76
- def toggle_option(self, name: str, value: any = None):
80
+ def toggle_style(self, name: str):
81
+ """
82
+ Toggle theme style (web)
83
+
84
+ :param name: web style name
85
+ """
86
+ self.window.core.config.set('theme.style', name)
87
+ self.window.core.config.save()
88
+ event = RenderEvent(RenderEvent.ON_THEME_CHANGE)
89
+ self.window.dispatch(event)
90
+ self.reload()
91
+
92
+ def toggle_option(
93
+ self,
94
+ name: str,
95
+ value: Any = None
96
+ ):
77
97
  """
78
98
  Toggle theme menu option
79
99
 
@@ -106,7 +126,11 @@ class Theme:
106
126
  self.window.core.config.save()
107
127
  self.nodes.apply_all()
108
128
 
109
- def toggle_syntax(self, name: str, update_menu: bool = False):
129
+ def toggle_syntax(
130
+ self,
131
+ name: str,
132
+ update_menu: bool = False
133
+ ):
110
134
  """
111
135
  Toggle syntax highlight
112
136
 
@@ -120,10 +144,24 @@ class Theme:
120
144
  if update_menu:
121
145
  self.menu.update_syntax()
122
146
 
147
+ def update_style(self):
148
+ """Update style"""
149
+ current = self.window.core.config.get('theme.style')
150
+ self.toggle_style(current)
151
+
152
+ def update_theme(self, force: bool = True):
153
+ """
154
+ Update theme
155
+
156
+ :param force: force theme change (manual trigger)
157
+ """
158
+ current = self.window.core.config.get('theme')
159
+ self.toggle(current, force=force)
160
+
123
161
  def update_syntax(self):
124
162
  """Update syntax menu"""
125
- curr = self.window.core.config.get('render.code_syntax')
126
- self.toggle_syntax(curr, update_menu=True)
163
+ current = self.window.core.config.get('render.code_syntax')
164
+ self.toggle_syntax(current, update_menu=True)
127
165
 
128
166
  def reload(self, force: bool = True):
129
167
  """
@@ -131,10 +169,13 @@ class Theme:
131
169
 
132
170
  :param force: force theme change (manual trigger)
133
171
  """
134
- current = self.window.core.config.get('theme')
135
- self.toggle(current, force=force)
172
+ self.update_theme(force=force)
136
173
 
137
- def apply(self, theme: str = 'dark_teal.xml', custom: str = None):
174
+ def apply(
175
+ self,
176
+ theme: str = 'dark_teal.xml',
177
+ custom: Optional[str] = None
178
+ ):
138
179
  """
139
180
  Update material theme and apply custom CSS
140
181
 
@@ -183,4 +224,5 @@ class Theme:
183
224
  def reload_all(self):
184
225
  """Reload all"""
185
226
  self.setup()
227
+ self.update_style()
186
228
  self.update_syntax()
@@ -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.04.30 15:00:00 #
9
+ # Updated Date: 2024.12.14 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
13
+ from typing import List
13
14
 
14
15
  from pygpt_net.utils import trans
15
16
 
@@ -108,7 +109,7 @@ class Common:
108
109
  elif element == "font.toolbox":
109
110
  return 'font-size: {}px;'.format(self.window.core.config.get('font_size.toolbox'))
110
111
 
111
- def get_themes_list(self) -> list:
112
+ def get_themes_list(self) -> List[str]:
112
113
  """
113
114
  Return a list of available themes
114
115
 
@@ -156,3 +157,24 @@ class Common:
156
157
  with open(path) as file:
157
158
  content += file.read()
158
159
  return content
160
+
161
+ def get_styles_list(self) -> List[str]:
162
+ """
163
+ Return a list of available styles
164
+
165
+ :return: list of styles names
166
+ """
167
+ styles = []
168
+ app_dir = os.path.join(self.window.core.config.get_app_path(), 'data', 'css')
169
+ user_dir = os.path.join(self.window.core.config.path, 'css')
170
+ for path in [app_dir, user_dir]:
171
+ if not os.path.exists(path):
172
+ continue
173
+ for file in os.listdir(path):
174
+ if file.startswith("web-") and file.endswith('.css'):
175
+ to_replace = ['web-', '.css', '.light', '.dark']
176
+ for item in to_replace:
177
+ file = file.replace(item, '')
178
+ if file not in styles:
179
+ styles.append(file)
180
+ return sorted(styles)
@@ -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.20 21:00:00 #
9
+ # Updated Date: 2024.12.14 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -23,6 +23,7 @@ class Markdown:
23
23
  """
24
24
  self.window = window
25
25
  self.css = {} # external styles
26
+ self.web_style = ""
26
27
 
27
28
  def update(self, force: bool = False):
28
29
  """
@@ -60,7 +61,8 @@ class Markdown:
60
61
 
61
62
  :return: stylesheet
62
63
  """
63
- if "web" not in self.css:
64
+ web_style = self.window.core.config.get("theme.style", "blocks")
65
+ if "web" not in self.css or self.web_style != web_style:
64
66
  self.load()
65
67
  if "web" in self.css:
66
68
  return self.css["web"]
@@ -73,31 +75,41 @@ class Markdown:
73
75
  self.window.dispatch(event) # per current engine
74
76
  self.window.controller.ctx.refresh()
75
77
  self.window.controller.ctx.refresh_output()
76
- data = {
78
+ event = RenderEvent(RenderEvent.END, {
77
79
  "meta": meta,
78
- }
79
- event = RenderEvent(RenderEvent.END, data)
80
+ })
80
81
  self.window.dispatch(event)
81
82
 
82
83
  def load(self):
83
84
  """Load markdown styles"""
84
- parents = ["markdown", "web"]
85
+ parents = [
86
+ "markdown",
87
+ "web",
88
+ ]
89
+ web_style = self.window.core.config.get("theme.style", "blocks")
85
90
  for base_name in parents:
91
+ suffix = ""
92
+ if base_name == 'web':
93
+ suffix = "-" + web_style
94
+ self.web_style = web_style
86
95
  theme = self.window.core.config.get('theme')
87
96
  name = str(base_name)
88
- color_name = str(base_name)
89
97
  if theme.startswith('light'):
90
- color_name += '.light'
98
+ color = '.light'
91
99
  else:
92
- color_name += '.dark'
100
+ color = '.dark'
101
+
102
+ # load CSS, app + user
103
+ file_base = name + suffix + '.css'
104
+ file_color = name + suffix + color + '.css'
93
105
  paths = []
94
- paths.append(os.path.join(self.window.core.config.get_app_path(), 'data', 'css', name + '.css'))
95
- paths.append(os.path.join(self.window.core.config.get_app_path(), 'data', 'css', color_name + '.css'))
96
- paths.append(os.path.join(self.window.core.config.get_user_path(), 'css', name + '.css'))
97
- paths.append(os.path.join(self.window.core.config.get_user_path(), 'css', color_name + '.css'))
106
+ paths.append(os.path.join(self.window.core.config.get_app_path(), 'data', 'css', file_base))
107
+ paths.append(os.path.join(self.window.core.config.get_app_path(), 'data', 'css', file_color))
108
+ paths.append(os.path.join(self.window.core.config.get_user_path(), 'css', file_base))
109
+ paths.append(os.path.join(self.window.core.config.get_user_path(), 'css', file_color))
98
110
  content = ''
99
111
  for path in paths:
100
- if os.path.exists(path):
112
+ if os.path.exists(path) and os.path.isfile(path):
101
113
  with open(path, 'r') as file:
102
114
  content += file.read()
103
115
 
@@ -107,8 +119,12 @@ class Markdown:
107
119
  except KeyError as e: # ignore missing env vars
108
120
  pass
109
121
 
110
- def get_default(self):
111
- """Set default markdown CSS"""
122
+ def get_default(self) -> str:
123
+ """
124
+ Set default markdown CSS
125
+
126
+ :return: default CSS
127
+ """
112
128
  colors = {
113
129
  "dark": {
114
130
  "a": "#fff",
@@ -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.05 23:00:00 #
9
+ # Updated Date: 2024.12.07 21:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction
@@ -30,6 +30,18 @@ class Menu:
30
30
  # setup themes list menu
31
31
  if self.loaded:
32
32
  return
33
+
34
+ # styles
35
+ styles = self.window.controller.theme.common.get_styles_list()
36
+ for style in styles:
37
+ style_id = style.lower()
38
+ title = style.replace('_', ' ').title()
39
+ self.window.ui.menu['theme_style'][style_id] = QAction(title, self.window, checkable=True)
40
+ self.window.ui.menu['theme_style'][style_id].triggered.connect(
41
+ lambda checked=None, style=style_id: self.window.controller.theme.toggle_style(style))
42
+ self.window.ui.menu['theme.style'].addAction(self.window.ui.menu['theme_style'][style_id])
43
+
44
+ # color themes
33
45
  themes = self.window.controller.theme.common.get_themes_list()
34
46
  for theme in themes:
35
47
  name = self.window.controller.theme.common.translate(theme)
@@ -42,6 +54,7 @@ class Menu:
42
54
  self.window.ui.menu['theme.dark'].addAction(self.window.ui.menu['theme'][theme])
43
55
  elif theme.startswith('light'):
44
56
  self.window.ui.menu['theme.light'].addAction(self.window.ui.menu['theme'][theme])
57
+
45
58
  self.loaded = True
46
59
 
47
60
  def setup_syntax(self):
@@ -86,14 +99,22 @@ class Menu:
86
99
 
87
100
  def update_list(self):
88
101
  """Update theme list menu"""
89
- current = self.window.core.config.get('theme')
102
+ # styles
103
+ current_style = self.window.core.config.get('theme.style')
104
+ for style in self.window.ui.menu['theme_style']:
105
+ self.window.ui.menu['theme_style'][style].setChecked(False)
106
+ if current_style in self.window.ui.menu['theme_style']:
107
+ self.window.ui.menu['theme_style'][current_style].setChecked(True)
108
+
109
+ # color themes
110
+ current_theme = self.window.core.config.get('theme')
90
111
  for theme in self.window.ui.menu['theme']:
91
112
  self.window.ui.menu['theme'][theme].setChecked(False)
92
- if current in self.window.ui.menu['theme']:
93
- self.window.ui.menu['theme'][current].setChecked(True)
113
+ if current_theme in self.window.ui.menu['theme']:
114
+ self.window.ui.menu['theme'][current_theme].setChecked(True)
94
115
 
95
116
  def update_syntax(self):
96
- """Update syntax menu"""
117
+ """Update code syntax highlight menu"""
97
118
  current = self.window.core.config.get('render.code_syntax')
98
119
  for style in self.window.ui.menu['theme_syntax']:
99
120
  self.window.ui.menu['theme_syntax'][style].setChecked(False)
@@ -6,9 +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.20 21:00:00 #
9
+ # Updated Date: 2024.12.12 01:00:00 #
10
10
  # ================================================== #
11
- #
11
+
12
12
  from pygpt_net.core.events import RenderEvent
13
13
 
14
14
 
@@ -93,9 +93,6 @@ class Nodes:
93
93
  continue
94
94
  self.apply(key, type)
95
95
 
96
- # self.window.interpreter.update_stylesheet(self.window.controller.theme.style('font.chat.output'))
97
- # self.window.ui.nodes['interpreter.input'].update_stylesheet(self.window.controller.theme.style('font.chat.input'))
98
-
99
96
  # apply to notepads
100
97
  num_notepads = self.window.controller.notepad.get_num_notepads()
101
98
  if num_notepads > 0:
@@ -6,10 +6,17 @@
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.07 23:00:00 #
9
+ # Updated Date: 2024.12.14 08:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ from typing import Dict, List
13
+
14
+ from PySide6.QtGui import QAction, QIcon
15
+ from PySide6.QtWidgets import QTabWidget, QMenu
16
+
12
17
  from pygpt_net.core.tabs.tab import Tab
18
+ from pygpt_net.utils import trans
19
+
13
20
 
14
21
  class Tools:
15
22
  def __init__(self, window=None):
@@ -44,7 +51,38 @@ class Tools:
44
51
  if idx is not None:
45
52
  self.window.controller.ui.tabs.switch_tab_by_idx(idx)
46
53
 
47
- def get_tab_tools(self) -> dict:
54
+ def append_tab_menu(
55
+ self,
56
+ parent: QTabWidget,
57
+ menu: QMenu,
58
+ idx: int,
59
+ column_idx: int
60
+ ) -> QMenu:
61
+ """
62
+ Append tab menu
63
+
64
+ :param parent: parent widget
65
+ :param menu: menu
66
+ :param idx: tab index
67
+ :param column_idx: column index
68
+ :return: tab add submenu
69
+ """
70
+ submenu = menu.addMenu(QIcon(":/icons/add.svg"), trans("action.tab.add.tool"))
71
+ tools = self.window.tools.get_all()
72
+ for id in tools:
73
+ tool = tools[id]
74
+ if not tool.has_tab:
75
+ continue
76
+ icon = tool.tab_icon
77
+ title = trans(tool.tab_title)
78
+ action = QAction(QIcon(icon), title, parent)
79
+ action.triggered.connect(
80
+ lambda idx=idx, column_idx=column_idx, id=id: parent.add_tab(idx, column_idx, Tab.TAB_TOOL, id)
81
+ )
82
+ submenu.addAction(action)
83
+ return submenu
84
+
85
+ def get_tab_tools(self) -> Dict[str, List[str]]:
48
86
  """
49
87
  Get tab tools
50
88
 
@@ -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.21 20:00:00 #
9
+ # Updated Date: 2024.12.14 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ from typing import Optional
13
+
12
14
  from PySide6.QtGui import QColor
13
15
 
14
16
  from pygpt_net.utils import trans
@@ -47,10 +49,6 @@ class UI:
47
49
  self.update()
48
50
  self.init_toolbox()
49
51
 
50
- def pre_setup(self):
51
- """Post setup UI"""
52
- self.tabs.setup()
53
-
54
52
  def update(self):
55
53
  """Update all elements"""
56
54
 
@@ -149,7 +147,7 @@ class UI:
149
147
  model_str = str(model)
150
148
  self.window.ui.nodes['chat.model'].setText(model_str)
151
149
 
152
- def update_ctx_label(self, label: str = None):
150
+ def update_ctx_label(self, label: Optional[str] = None):
153
151
  """
154
152
  Update ctx label
155
153
 
@@ -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.23 00:00:00 #
9
+ # Updated Date: 2024.12.14 19:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from pygpt_net.core.types import (
@@ -189,8 +189,12 @@ class Mode:
189
189
  self.window.ui.tabs['input'].setTabVisible(2, False)
190
190
  self.window.ui.tabs['input'].setTabVisible(3, False)
191
191
 
192
- # toggle chat footer
193
- if not self.is_chat_tab():
192
+ # chat footer
193
+ self.toggle_chat_footer()
194
+
195
+ def toggle_chat_footer(self):
196
+ """Toggle chat footer"""
197
+ if self.window.controller.ui.tabs.get_current_type() != Tab.TAB_CHAT:
194
198
  self.hide_chat_footer()
195
199
  else:
196
200
  self.show_chat_footer()
@@ -200,18 +204,12 @@ class Mode:
200
204
  Check if vision is allowed
201
205
 
202
206
  :param mode: current mode
207
+ :return: True if vision is allowed
203
208
  """
204
- if mode == MODE_VISION:
205
- return True
206
-
207
- allowed = self.window.controller.painter.is_active()
208
- if allowed:
209
+ if self.window.controller.ui.vision.has_vision():
209
210
  return True
210
211
 
211
- if mode in [MODE_IMAGE, MODE_ASSISTANT]:
212
- return False
213
-
214
- if self.window.controller.ui.vision.is_vision_model():
212
+ if self.window.controller.painter.is_active():
215
213
  return True
216
214
 
217
215
  # event: UI: vision
@@ -224,7 +222,12 @@ class Mode:
224
222
  return event.data['value']
225
223
 
226
224
  def are_attachments(self, mode: str) -> bool:
227
- """Check if attachments are allowed"""
225
+ """
226
+ Check if attachments are allowed
227
+
228
+ :param mode: current mode
229
+ :return: True if attachments are allowed
230
+ """
228
231
  if mode in [MODE_VISION, MODE_ASSISTANT]:
229
232
  return True
230
233
 
@@ -243,14 +246,6 @@ class Mode:
243
246
  self.window.dispatch(event)
244
247
  return event.data['value']
245
248
 
246
- def is_chat_tab(self) -> bool:
247
- """
248
- Check if current tab is chat
249
-
250
- :return: True if chat tab
251
- """
252
- return self.window.controller.ui.tabs.get_current_type() == Tab.TAB_CHAT
253
-
254
249
  def show_chat_footer(self):
255
250
  """Show chat footer"""
256
251
  self.window.ui.nodes['chat.footer'].setVisible(True)