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,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.21 02:00:00 #
9
+ # Updated Date: 2024.12.08 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import pyaudio
@@ -84,11 +84,25 @@ class Simple:
84
84
  self.timer.timeout.connect(self.stop_timeout)
85
85
  self.timer.start(self.TIMEOUT_SECONDS * 1000)
86
86
 
87
+ # select audio input device
88
+ device_id = int(self.plugin.window.core.config.get('audio.input.device', 0))
89
+ rate = int(self.plugin.window.core.config.get('audio.input.rate', 44100))
90
+ channels = int(self.plugin.window.core.config.get('audio.input.channels', 1))
91
+ if not self.plugin.window.core.audio.is_device_compatible(device_id):
92
+ err = self.plugin.window.core.audio.get_last_error()
93
+ message = "Selected audio input device is not compatible. Please select another one. ERROR: " + str(err)
94
+ self.is_recording = False
95
+ self.plugin.window.core.debug.log(message)
96
+ self.plugin.window.ui.dialogs.alert(message)
97
+ self.switch_btn_start() # switch button to start
98
+ return
99
+
87
100
  self.p = pyaudio.PyAudio()
88
101
  self.stream = self.p.open(format=pyaudio.paInt16,
89
- channels=1,
90
- rate=44100,
102
+ channels=channels,
103
+ rate=rate,
91
104
  input=True,
105
+ input_device_index=device_id,
92
106
  frames_per_buffer=1024,
93
107
  stream_callback=callback)
94
108
 
@@ -137,9 +151,11 @@ class Simple:
137
151
  self.plugin.window.dispatch(AppEvent(AppEvent.VOICE_CONTROL_STOPPED)) # app event
138
152
  return
139
153
  wf = wave.open(path, 'wb')
140
- wf.setnchannels(1)
154
+ channels = int(self.plugin.window.core.config.get('audio.input.channels', 1))
155
+ rate = int(self.plugin.window.core.config.get('audio.input.rate', 44100))
156
+ wf.setnchannels(channels)
141
157
  wf.setsampwidth(self.p.get_sample_size(pyaudio.paInt16))
142
- wf.setframerate(44100)
158
+ wf.setframerate(rate)
143
159
  wf.writeframes(b''.join(self.frames))
144
160
  wf.close()
145
161
  self.plugin.handle_thread(True) # handle transcription in simple mode
@@ -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.26 19:00:00 #
9
+ # Updated Date: 2024.12.14 18:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Slot
@@ -127,12 +127,15 @@ class Plugin(BasePlugin):
127
127
  elif name == Event.CTX_AFTER:
128
128
  if mode == MODE_AUDIO:
129
129
  return # skip if audio mode
130
+ self.stop_audio()
130
131
  self.on_generate(ctx, event)
131
132
 
132
133
  elif name == Event.AUDIO_READ_TEXT:
134
+ self.stop_audio()
133
135
  self.on_generate(ctx, event)
134
136
 
135
137
  elif name == Event.AUDIO_PLAYBACK:
138
+ self.stop_audio()
136
139
  self.on_playback(ctx, event)
137
140
 
138
141
  elif name == Event.AUDIO_OUTPUT_STOP:
@@ -164,6 +167,11 @@ class Plugin(BasePlugin):
164
167
  cache_file = None
165
168
  if event.data is not None and isinstance(event.data, dict) and "cache_file" in event.data:
166
169
  cache_file = event.data["cache_file"]
170
+
171
+ # check for audio read allowed. Prevents reading audio in commands, results, etc.
172
+ if name == Event.CTX_AFTER:
173
+ if not ctx.audio_read_allowed():
174
+ return # abort if audio read is not allowed (commands, results, etc.)
167
175
 
168
176
  try:
169
177
  if text is not None and len(text) > 0:
@@ -6,16 +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.16 05:00:00 #
9
+ # Updated Date: 2024.12.14 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ from typing import Optional
13
+
12
14
  from .plugin import BasePlugin
13
15
 
14
16
  class BaseConfig:
15
17
  def __init__(self, plugin: BasePlugin = None, *args, **kwargs):
16
18
  self.plugin = plugin
17
19
 
18
- def from_defaults(self, plugin: BasePlugin = None):
20
+ def from_defaults(self, plugin: Optional[BasePlugin] = None):
19
21
  """
20
22
  Set default options for plugin
21
23
 
@@ -6,16 +6,14 @@
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 22:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
13
+ from typing import Optional, Any, Dict, List
13
14
 
14
15
  from PySide6.QtCore import QObject, Slot
15
16
 
16
- from pygpt_net.core.types import (
17
- MODE_AGENT_LLAMA,
18
- )
19
17
  from pygpt_net.core.bridge.context import BridgeContext
20
18
  from pygpt_net.core.events import Event, KernelEvent
21
19
  from pygpt_net.item.ctx import CtxItem
@@ -42,7 +40,7 @@ class BasePlugin(QObject):
42
40
  self.use_locale = False
43
41
  self.order = 0
44
42
 
45
- def setup(self) -> dict:
43
+ def setup(self) -> Dict[str, Any]:
46
44
  """
47
45
  Return available config options
48
46
 
@@ -50,7 +48,12 @@ class BasePlugin(QObject):
50
48
  """
51
49
  return self.options
52
50
 
53
- def add_option(self, name: str, type: str, **kwargs) -> dict:
51
+ def add_option(
52
+ self,
53
+ name: str,
54
+ type: str,
55
+ **kwargs
56
+ ) -> Dict[str, Any]:
54
57
  """
55
58
  Add plugin configuration option
56
59
 
@@ -83,7 +86,11 @@ class BasePlugin(QObject):
83
86
  self.options[name] = option
84
87
  return option
85
88
 
86
- def add_cmd(self, cmd: str, **kwargs) -> dict:
89
+ def add_cmd(
90
+ self,
91
+ cmd: str,
92
+ **kwargs
93
+ ) -> Dict[str, Any]:
87
94
  """
88
95
  Add plugin command
89
96
 
@@ -124,7 +131,10 @@ class BasePlugin(QObject):
124
131
 
125
132
  return self.add_option(name, "cmd", **kwargs)
126
133
 
127
- def has_cmd(self, cmd: str) -> bool:
134
+ def has_cmd(
135
+ self,
136
+ cmd: str
137
+ ) -> bool:
128
138
  """
129
139
  Check if command exists
130
140
 
@@ -137,7 +147,10 @@ class BasePlugin(QObject):
137
147
  return self.options[key]["value"]["enabled"]
138
148
  return False
139
149
 
140
- def cmd_allowed(self, cmd: str) -> bool:
150
+ def cmd_allowed(
151
+ self,
152
+ cmd: str
153
+ ) -> bool:
141
154
  """
142
155
  Check if command allowed
143
156
 
@@ -156,7 +169,10 @@ class BasePlugin(QObject):
156
169
  """
157
170
  return self.window.core.config.get("cmd")
158
171
 
159
- def get_cmd(self, cmd: str) -> dict:
172
+ def get_cmd(
173
+ self,
174
+ cmd: str
175
+ ) -> Dict[str, Any]:
160
176
  """
161
177
  Return command
162
178
 
@@ -169,7 +185,10 @@ class BasePlugin(QObject):
169
185
  data = {"cmd": cmd, **data}
170
186
  return data
171
187
 
172
- def has_option(self, name: str) -> bool:
188
+ def has_option(
189
+ self,
190
+ name: str
191
+ ) -> bool:
173
192
  """
174
193
  Check if option exists
175
194
 
@@ -178,7 +197,10 @@ class BasePlugin(QObject):
178
197
  """
179
198
  return name in self.options
180
199
 
181
- def get_option(self, name: str) -> dict:
200
+ def get_option(
201
+ self,
202
+ name: str
203
+ ) -> Dict[str, Any]:
182
204
  """
183
205
  Return option
184
206
 
@@ -188,7 +210,10 @@ class BasePlugin(QObject):
188
210
  if self.has_option(name):
189
211
  return self.options[name]
190
212
 
191
- def get_option_value(self, name: str) -> any:
213
+ def get_option_value(
214
+ self,
215
+ name: str
216
+ ) -> Any:
192
217
  """
193
218
  Return option value
194
219
 
@@ -206,7 +231,12 @@ class BasePlugin(QObject):
206
231
  """
207
232
  self.window = window
208
233
 
209
- def handle(self, event: Event, *args, **kwargs):
234
+ def handle(
235
+ self,
236
+ event: Event,
237
+ *args,
238
+ **kwargs
239
+ ):
210
240
  """
211
241
  Handle event
212
242
 
@@ -234,7 +264,10 @@ class BasePlugin(QObject):
234
264
  """
235
265
  return
236
266
 
237
- def trans(self, text: str = None) -> str:
267
+ def trans(
268
+ self,
269
+ text: Optional[str] = None
270
+ ) -> str:
238
271
  """
239
272
  Translate text using plugin domain
240
273
 
@@ -246,7 +279,7 @@ class BasePlugin(QObject):
246
279
  domain = 'plugin.{}'.format(self.id)
247
280
  return trans(text, False, domain)
248
281
 
249
- def error(self, err: any):
282
+ def error(self, err: Any):
250
283
  """
251
284
  Send error message to logger and alert dialog
252
285
 
@@ -256,7 +289,7 @@ class BasePlugin(QObject):
256
289
  msg = self.window.core.debug.parse_alert(err)
257
290
  self.window.ui.dialogs.alert("{}: {}".format(self.name, msg))
258
291
 
259
- def debug(self, data: any):
292
+ def debug(self, data: Any):
260
293
  """
261
294
  Send debug message to logger window
262
295
 
@@ -264,7 +297,12 @@ class BasePlugin(QObject):
264
297
  """
265
298
  self.window.core.debug.info(data)
266
299
 
267
- def reply(self, response: dict, ctx: CtxItem = None, extra_data: dict = None):
300
+ def reply(
301
+ self,
302
+ response: dict,
303
+ ctx: Optional[CtxItem] = None,
304
+ extra_data: Optional[dict] = None
305
+ ):
268
306
  """
269
307
  Send reply from plugin (command response)
270
308
 
@@ -329,7 +367,12 @@ class BasePlugin(QObject):
329
367
  }))
330
368
 
331
369
  @Slot(object, object, dict)
332
- def handle_finished(self, response: dict, ctx: CtxItem = None, extra_data: dict = None):
370
+ def handle_finished(
371
+ self,
372
+ response: Dict[str, Any],
373
+ ctx: Optional[CtxItem] = None,
374
+ extra_data: Optional[Dict[str, Any]] = None
375
+ ):
333
376
  """
334
377
  Handle finished response signal
335
378
 
@@ -354,7 +397,12 @@ class BasePlugin(QObject):
354
397
  self.window.dispatch(event)
355
398
 
356
399
  @Slot(object, object, dict)
357
- def handle_finished_more(self, responses: list, ctx: CtxItem = None, extra_data: dict = None):
400
+ def handle_finished_more(
401
+ self,
402
+ responses: List[Dict[str, Any]],
403
+ ctx: Optional[CtxItem] = None,
404
+ extra_data: Optional[Dict[str, Any]] = None
405
+ ):
358
406
  """
359
407
  Handle finished response signal
360
408
 
@@ -379,7 +427,11 @@ class BasePlugin(QObject):
379
427
  })
380
428
  self.window.dispatch(event)
381
429
 
382
- def prepare_reply_ctx(self, response: dict, ctx: CtxItem = None) -> dict:
430
+ def prepare_reply_ctx(
431
+ self,
432
+ response: Dict[str, Any],
433
+ ctx: Optional[CtxItem] = None
434
+ ) -> Dict[str, Any]:
383
435
  """
384
436
  Prepare reply context
385
437
 
@@ -434,7 +486,7 @@ class BasePlugin(QObject):
434
486
  self.window.update_status(str(data))
435
487
 
436
488
  @Slot(object)
437
- def handle_error(self, err: any):
489
+ def handle_error(self, err: Any):
438
490
  """
439
491
  Handle thread error signal
440
492
 
@@ -443,7 +495,7 @@ class BasePlugin(QObject):
443
495
  self.error(err)
444
496
 
445
497
  @Slot(object)
446
- def handle_debug(self, msg: any):
498
+ def handle_debug(self, msg: Any):
447
499
  """
448
500
  Handle debug message signal
449
501
 
@@ -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.24 04:00:00 #
9
+ # Updated Date: 2024.12.14 22:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ from typing import Optional, Any, Dict, List
13
+
12
14
  from PySide6.QtCore import QObject, QRunnable
13
15
  from typing_extensions import deprecated
14
16
 
@@ -17,7 +19,7 @@ from .signals import BaseSignals
17
19
 
18
20
 
19
21
  class BaseWorker(QObject, QRunnable):
20
- def __init__(self, plugin: BasePlugin = None, *args, **kwargs):
22
+ def __init__(self, plugin: Optional[BasePlugin] = None, *args, **kwargs):
21
23
  QObject.__init__(self)
22
24
  QRunnable.__init__(self)
23
25
  self.plugin = plugin
@@ -42,7 +44,7 @@ class BaseWorker(QObject, QRunnable):
42
44
  if self.signals is not None and hasattr(self.signals, "destroyed"):
43
45
  self.signals.destroyed.emit()
44
46
 
45
- def error(self, err: any):
47
+ def error(self, err: Any):
46
48
  """
47
49
  Emit error signal
48
50
 
@@ -63,7 +65,11 @@ class BaseWorker(QObject, QRunnable):
63
65
  self.signals.log.emit(msg)
64
66
 
65
67
  @deprecated("From 2.1.29: BaseWorker.response() is deprecated, use BaseWorker.reply() instead")
66
- def response(self, response: dict, extra_data: dict = None):
68
+ def response(
69
+ self,
70
+ response: Dict[str, Any],
71
+ extra_data: Optional[Dict[str, Any]] = None
72
+ ):
67
73
  """
68
74
  Emit finished signal (deprecated)
69
75
 
@@ -74,7 +80,11 @@ class BaseWorker(QObject, QRunnable):
74
80
  self.debug("BaseWorker.response is deprecated from 2.1.29, use BaseWorker.reply instead")
75
81
  self.reply(response, extra_data)
76
82
 
77
- def reply(self, response: dict, extra_data: dict = None):
83
+ def reply(
84
+ self,
85
+ response: Dict[str, Any],
86
+ extra_data: Optional[Dict[str, Any]] = None
87
+ ):
78
88
  """
79
89
  Emit finished signal (on reply from command output)
80
90
 
@@ -89,7 +99,11 @@ class BaseWorker(QObject, QRunnable):
89
99
  if self.signals is not None and hasattr(self.signals, "finished"):
90
100
  self.signals.finished.emit(response, self.ctx, extra_data)
91
101
 
92
- def reply_more(self, responses: list, extra_data: dict = None):
102
+ def reply_more(
103
+ self,
104
+ responses: List[Dict[str, Any]],
105
+ extra_data: Optional[Dict[str, Any]] = None
106
+ ):
93
107
  """
94
108
  Emit finished_more signal (on reply from command output, multiple responses)
95
109
 
@@ -152,7 +166,10 @@ class BaseWorker(QObject, QRunnable):
152
166
  self.signals.status.connect(parent.handle_status)
153
167
  self.signals.error.connect(parent.handle_error)
154
168
 
155
- def from_request(self, item: dict) -> dict:
169
+ def from_request(
170
+ self,
171
+ item: Dict[str, Any]
172
+ ) -> Dict[str, Any]:
156
173
  """
157
174
  Prepare request item for result
158
175
 
@@ -161,7 +178,12 @@ class BaseWorker(QObject, QRunnable):
161
178
  """
162
179
  return {"cmd": item["cmd"]}
163
180
 
164
- def make_response(self, item: dict, result: any, extra: dict = None) -> dict:
181
+ def make_response(
182
+ self,
183
+ item: Dict[str, Any],
184
+ result: Any,
185
+ extra: Optional[Dict[str, Any]] = None
186
+ ) -> Dict[str, Any]:
165
187
  """
166
188
  Prepare response item
167
189
 
@@ -190,7 +212,11 @@ class BaseWorker(QObject, QRunnable):
190
212
  self.log(msg)
191
213
  return msg
192
214
 
193
- def has_param(self, item: dict, param: str) -> bool:
215
+ def has_param(
216
+ self,
217
+ item: Dict[str, Any],
218
+ param: str
219
+ ) -> bool:
194
220
  """
195
221
  Check if item has parameter
196
222
 
@@ -202,7 +228,12 @@ class BaseWorker(QObject, QRunnable):
202
228
  return False
203
229
  return "params" in item and param in item["params"]
204
230
 
205
- def get_param(self, item: dict, param: str, default: any = None) -> any:
231
+ def get_param(
232
+ self,
233
+ item: Dict[str, Any],
234
+ param: str,
235
+ default: Any = None
236
+ ) -> Any:
206
237
  """
207
238
  Get parameter value from item
208
239
 
@@ -215,7 +246,7 @@ class BaseWorker(QObject, QRunnable):
215
246
  return item["params"][param]
216
247
  return default
217
248
 
218
- def is_stopped(self):
249
+ def is_stopped(self) -> bool:
219
250
  """
220
251
  Check if worker is stopped
221
252
 
@@ -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.25 02:00:00 #
9
+ # Updated Date: 2024.12.12 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -118,42 +118,6 @@ class Plugin(BasePlugin):
118
118
  "directory is mapped as volume in host machine to: {}").format(legacy_data)
119
119
  data['cmd'].append(cmd) # append command
120
120
 
121
- @Slot(object, str)
122
- def handle_interpreter_output(self, data, type):
123
- """
124
- Handle interpreter output
125
-
126
- :param data: output data
127
- :param type: output type
128
- """
129
- if not self.get_option_value("attach_output"):
130
- return
131
- self.window.tools.get("interpreter").append_output(data, type)
132
-
133
- @Slot()
134
- def handle_interpreter_clear(self):
135
- """Handle interpreter clear"""
136
- self.window.tools.get("interpreter").clear_all()
137
-
138
- @Slot(object)
139
- def handle_html_output(self, data):
140
- """
141
- Handle HTML/JS canvas output
142
-
143
- :param data: HTML/JS code
144
- """
145
- self.window.tools.get("html_canvas").set_output(data)
146
- self.window.tools.get("html_canvas").open()
147
- def get_interpreter(self):
148
- """
149
- Get interpreter
150
-
151
- :return: interpreter
152
- """
153
- if self.get_option_value("sandbox_ipython"):
154
- return self.ipython_docker
155
- else:
156
- return self.ipython_local
157
121
 
158
122
  def cmd(self, ctx: CtxItem, cmds: list, silent: bool = False):
159
123
  """
@@ -270,3 +234,41 @@ class Plugin(BasePlugin):
270
234
  self.window.tools.get("interpreter").append_output(cleaned_data)
271
235
  if self.window.tools.get("interpreter").opened:
272
236
  self.window.update_status("")
237
+
238
+ @Slot(object, str)
239
+ def handle_interpreter_output(self, data, type):
240
+ """
241
+ Handle interpreter output
242
+
243
+ :param data: output data
244
+ :param type: output type
245
+ """
246
+ if not self.get_option_value("attach_output"):
247
+ return
248
+ self.window.tools.get("interpreter").append_output(data, type)
249
+
250
+ @Slot()
251
+ def handle_interpreter_clear(self):
252
+ """Handle interpreter clear"""
253
+ self.window.tools.get("interpreter").clear_all()
254
+
255
+ @Slot(object)
256
+ def handle_html_output(self, data):
257
+ """
258
+ Handle HTML/JS canvas output
259
+
260
+ :param data: HTML/JS code
261
+ """
262
+ self.window.tools.get("html_canvas").set_output(data)
263
+ self.window.tools.get("html_canvas").auto_open()
264
+
265
+ def get_interpreter(self):
266
+ """
267
+ Get interpreter
268
+
269
+ :return: interpreter
270
+ """
271
+ if self.get_option_value("sandbox_ipython"):
272
+ return self.ipython_docker
273
+ else:
274
+ return self.ipython_local
@@ -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.26 04:00:00 #
9
+ # Updated Date: 2024.12.12 01:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os.path
@@ -164,6 +164,14 @@ class Runner:
164
164
  """
165
165
  return self.plugin.get_option_value('sandbox_docker')
166
166
 
167
+ def is_sandbox_ipython(self) -> bool:
168
+ """
169
+ Check if sandbox is enabled for IPython
170
+
171
+ :return: True if sandbox is enabled
172
+ """
173
+ return self.plugin.get_option_value('sandbox_ipython')
174
+
167
175
  def get_docker(self) -> docker.client.DockerClient:
168
176
  """
169
177
  Get docker client
@@ -392,13 +400,14 @@ class Runner:
392
400
  :param all: execute all
393
401
  :return: response dict
394
402
  """
403
+ sandbox = self.is_sandbox_ipython()
395
404
  data = item["params"]['code']
396
405
  if not all:
397
406
  path = self.plugin.window.tools.get("interpreter").file_current
398
407
  if "path" in item["params"]:
399
408
  path = item["params"]['path']
400
409
  msg = "Saving Python file: {}".format(path)
401
- self.log(msg, sandbox=True)
410
+ self.log(msg, sandbox=sandbox)
402
411
  with open(self.prepare_path(path, on_host=True), 'w', encoding="utf-8") as file:
403
412
  file.write(data)
404
413
  else:
@@ -412,12 +421,13 @@ class Runner:
412
421
 
413
422
  # run code in IPython interpreter
414
423
  msg = "Executing Python code: {}".format(item["params"]['code'])
415
- self.log(msg, sandbox=True)
416
- self.log("Connecting to IPython interpreter...", sandbox=True)
424
+ self.log(msg, sandbox=sandbox)
425
+ self.log("Connecting to IPython interpreter...", sandbox=sandbox)
417
426
  try:
418
- self.log("Please wait...", sandbox=True)
427
+ self.log("Please wait...", sandbox=sandbox)
419
428
  result = self.plugin.get_interpreter().execute(data, current=False)
420
429
  result = self.handle_result_ipython(ctx, result)
430
+ self.log("Python Code Executed.", sandbox=sandbox)
421
431
  except Exception as e:
422
432
  self.error(e)
423
433
  result = str(e)
@@ -437,13 +447,14 @@ class Runner:
437
447
  :param all: execute all
438
448
  :return: response dict
439
449
  """
450
+ sandbox = self.is_sandbox_ipython()
440
451
  data = item["params"]['code']
441
452
  if not all:
442
453
  path = self.plugin.window.tools.get("interpreter").file_current
443
454
  if "path" in item["params"]:
444
455
  path = item["params"]['path']
445
456
  msg = "Saving Python file: {}".format(path)
446
- self.log(msg, sandbox=True)
457
+ self.log(msg, sandbox=sandbox)
447
458
  with open(self.prepare_path(path, on_host=True), 'w', encoding="utf-8") as file:
448
459
  file.write(data)
449
460
  else:
@@ -457,12 +468,13 @@ class Runner:
457
468
 
458
469
  # run code in IPython interpreter
459
470
  msg = "Executing Python code: {}".format(item["params"]['code'])
460
- self.log(msg, sandbox=True)
461
- self.log("Connecting to IPython interpreter...", sandbox=True)
471
+ self.log(msg, sandbox=sandbox)
472
+ self.log("Connecting to IPython interpreter...", sandbox=sandbox)
462
473
  try:
463
- self.log("Please wait...", sandbox=True)
474
+ self.log("Please wait...", sandbox=sandbox)
464
475
  result = self.plugin.get_interpreter().execute(data, current=True)
465
476
  result = self.handle_result_ipython(ctx, result)
477
+ self.log("Python Code Executed.", sandbox=sandbox)
466
478
  except Exception as e:
467
479
  self.error(e)
468
480
  result = str(e)
@@ -482,13 +494,14 @@ class Runner:
482
494
  :param all: execute all
483
495
  :return: response dict
484
496
  """
497
+ sandbox = self.is_sandbox_ipython()
485
498
  self.append_input("")
486
499
  self.send_interpreter_input("") # send input to interpreter tool
487
500
 
488
501
  # restart IPython interpreter
489
- self.log("Connecting to IPython interpreter...", sandbox=True)
502
+ self.log("Connecting to IPython interpreter...", sandbox=sandbox)
490
503
  try:
491
- self.log("Restarting IPython kernel...", sandbox=True)
504
+ self.log("Restarting IPython kernel...", sandbox=sandbox)
492
505
  response = self.plugin.get_interpreter().restart_kernel()
493
506
  except Exception as e:
494
507
  self.error(e)
@@ -497,7 +510,7 @@ class Runner:
497
510
  result = "Kernel restarted"
498
511
  else:
499
512
  result = "Kernel not restarted"
500
- self.log(result)
513
+ self.log(result, sandbox=sandbox)
501
514
  return {
502
515
  "request": request,
503
516
  "result": str(result),