pygpt-net 2.4.28__py3-none-any.whl → 2.4.34__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.
- CHANGELOG.md +40 -0
- README.md +62 -5
- pygpt_net/CHANGELOG.txt +40 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/access/__init__.py +5 -5
- pygpt_net/controller/access/control.py +3 -2
- pygpt_net/controller/attachment.py +67 -1
- pygpt_net/controller/audio/__init__.py +34 -6
- pygpt_net/controller/chat/__init__.py +3 -1
- pygpt_net/controller/chat/attachment.py +239 -37
- pygpt_net/controller/chat/audio.py +99 -0
- pygpt_net/controller/chat/input.py +10 -3
- pygpt_net/controller/chat/output.py +4 -1
- pygpt_net/controller/chat/text.py +10 -5
- pygpt_net/controller/dialogs/confirm.py +17 -1
- pygpt_net/controller/kernel/reply.py +5 -8
- pygpt_net/controller/lang/custom.py +3 -1
- pygpt_net/controller/mode.py +2 -1
- pygpt_net/controller/presets/editor.py +11 -2
- pygpt_net/core/access/voice.py +2 -2
- pygpt_net/core/agents/legacy.py +3 -1
- pygpt_net/core/attachments/__init__.py +11 -7
- pygpt_net/core/attachments/context.py +226 -44
- pygpt_net/core/{audio.py → audio/__init__.py} +1 -1
- pygpt_net/core/audio/context.py +34 -0
- pygpt_net/core/bridge/context.py +29 -1
- pygpt_net/core/bridge/worker.py +16 -1
- pygpt_net/core/ctx/__init__.py +4 -1
- pygpt_net/core/db/__init__.py +4 -2
- pygpt_net/core/debug/attachments.py +3 -1
- pygpt_net/core/debug/context.py +5 -1
- pygpt_net/core/debug/presets.py +3 -1
- pygpt_net/core/docker/__init__.py +170 -16
- pygpt_net/core/docker/builder.py +6 -2
- pygpt_net/core/events/event.py +3 -1
- pygpt_net/core/experts/__init__.py +24 -6
- pygpt_net/core/idx/chat.py +55 -4
- pygpt_net/core/idx/indexing.py +123 -15
- pygpt_net/core/modes.py +3 -1
- pygpt_net/core/presets.py +13 -2
- pygpt_net/core/render/markdown/pid.py +2 -1
- pygpt_net/core/render/plain/pid.py +2 -1
- pygpt_net/core/render/web/body.py +34 -12
- pygpt_net/core/render/web/pid.py +2 -1
- pygpt_net/core/render/web/renderer.py +12 -3
- pygpt_net/core/tokens.py +4 -2
- pygpt_net/core/types/mode.py +2 -1
- pygpt_net/data/config/config.json +7 -4
- pygpt_net/data/config/models.json +191 -6
- pygpt_net/data/config/modes.json +11 -5
- pygpt_net/data/config/presets/current.audio.json +34 -0
- pygpt_net/data/config/settings.json +15 -1
- pygpt_net/data/css/web.css +70 -0
- pygpt_net/data/css/web.dark.css +4 -1
- pygpt_net/data/css/web.light.css +1 -1
- pygpt_net/data/locale/locale.de.ini +33 -20
- pygpt_net/data/locale/locale.en.ini +73 -58
- pygpt_net/data/locale/locale.es.ini +33 -20
- pygpt_net/data/locale/locale.fr.ini +35 -22
- pygpt_net/data/locale/locale.it.ini +33 -20
- pygpt_net/data/locale/locale.pl.ini +36 -23
- pygpt_net/data/locale/locale.uk.ini +33 -20
- pygpt_net/data/locale/locale.zh.ini +40 -27
- pygpt_net/data/locale/plugin.cmd_code_interpreter.de.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.en.ini +15 -7
- pygpt_net/data/locale/plugin.cmd_code_interpreter.es.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.fr.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.it.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.pl.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.uk.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_code_interpreter.zh.ini +6 -0
- pygpt_net/data/locale/plugin.cmd_files.de.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.en.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.es.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.fr.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.it.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.pl.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.uk.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_files.zh.ini +4 -4
- pygpt_net/data/locale/plugin.cmd_system.de.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_system.en.ini +12 -6
- pygpt_net/data/locale/plugin.cmd_system.es.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_system.fr.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_system.it.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_system.pl.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_system.uk.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_system.zh.ini +6 -6
- pygpt_net/data/locale/plugin.cmd_web.de.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.en.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.es.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.fr.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.it.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.pl.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.uk.ini +5 -5
- pygpt_net/data/locale/plugin.cmd_web.zh.ini +5 -5
- pygpt_net/data/locale/plugin.idx_llama_index.de.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.en.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.es.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.fr.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.it.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.pl.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.uk.ini +12 -12
- pygpt_net/data/locale/plugin.idx_llama_index.zh.ini +12 -12
- pygpt_net/item/attachment.py +9 -1
- pygpt_net/item/ctx.py +9 -1
- pygpt_net/item/preset.py +5 -1
- pygpt_net/launcher.py +3 -1
- pygpt_net/migrations/Version20241126170000.py +28 -0
- pygpt_net/migrations/__init__.py +3 -1
- pygpt_net/plugin/audio_input/__init__.py +11 -1
- pygpt_net/plugin/audio_input/worker.py +9 -1
- pygpt_net/plugin/audio_output/__init__.py +37 -7
- pygpt_net/plugin/audio_output/worker.py +38 -41
- pygpt_net/plugin/cmd_code_interpreter/__init__.py +51 -35
- pygpt_net/plugin/cmd_code_interpreter/builder.py +16 -4
- pygpt_net/plugin/cmd_code_interpreter/config.py +98 -39
- pygpt_net/plugin/cmd_code_interpreter/docker.py +4 -0
- pygpt_net/plugin/cmd_code_interpreter/ipython/__init__.py +13 -0
- pygpt_net/plugin/cmd_code_interpreter/{ipython.py → ipython/docker_kernel.py} +10 -3
- pygpt_net/plugin/cmd_code_interpreter/ipython/local_kernel.py +220 -0
- pygpt_net/plugin/cmd_code_interpreter/runner.py +5 -5
- pygpt_net/plugin/cmd_mouse_control/__init__.py +4 -2
- pygpt_net/plugin/cmd_system/config.py +50 -0
- pygpt_net/plugin/cmd_system/docker.py +4 -0
- pygpt_net/plugin/idx_llama_index/__init__.py +23 -1
- pygpt_net/plugin/idx_llama_index/worker.py +10 -0
- pygpt_net/plugin/openai_dalle/__init__.py +3 -1
- pygpt_net/plugin/openai_vision/__init__.py +3 -1
- pygpt_net/provider/core/attachment/json_file.py +4 -1
- pygpt_net/provider/core/config/patch.py +25 -0
- pygpt_net/provider/core/ctx/db_sqlite/storage.py +14 -4
- pygpt_net/provider/core/ctx/db_sqlite/utils.py +19 -2
- pygpt_net/provider/core/model/patch.py +7 -1
- pygpt_net/provider/core/preset/json_file.py +5 -1
- pygpt_net/provider/gpt/__init__.py +14 -2
- pygpt_net/provider/gpt/audio.py +63 -0
- pygpt_net/provider/gpt/chat.py +76 -44
- pygpt_net/provider/gpt/utils.py +27 -0
- pygpt_net/provider/gpt/vision.py +37 -15
- pygpt_net/provider/loaders/base.py +10 -1
- pygpt_net/provider/loaders/web_yt.py +19 -1
- pygpt_net/tools/code_interpreter/__init__.py +1 -0
- pygpt_net/tools/image_viewer/ui/dialogs.py +3 -1
- pygpt_net/ui/dialog/preset.py +3 -1
- pygpt_net/ui/dialog/url.py +29 -0
- pygpt_net/ui/dialogs.py +5 -1
- pygpt_net/ui/layout/chat/attachments.py +42 -6
- pygpt_net/ui/layout/chat/attachments_ctx.py +14 -4
- pygpt_net/ui/layout/chat/attachments_uploaded.py +8 -4
- pygpt_net/ui/layout/toolbox/agent.py +8 -7
- pygpt_net/ui/layout/toolbox/agent_llama.py +5 -4
- pygpt_net/ui/layout/toolbox/prompt.py +8 -6
- pygpt_net/ui/menu/tools.py +17 -11
- pygpt_net/ui/widget/anims/toggles.py +167 -0
- pygpt_net/ui/widget/dialog/url.py +59 -0
- pygpt_net/ui/widget/element/group.py +2 -1
- pygpt_net/ui/widget/lists/attachment.py +22 -17
- pygpt_net/ui/widget/lists/attachment_ctx.py +65 -3
- pygpt_net/ui/widget/option/checkbox.py +69 -5
- pygpt_net/ui/widget/option/cmd.py +4 -5
- pygpt_net/ui/widget/option/toggle.py +62 -0
- pygpt_net/ui/widget/option/toggle_label.py +79 -0
- pygpt_net/ui/widget/textarea/url.py +43 -0
- {pygpt_net-2.4.28.dist-info → pygpt_net-2.4.34.dist-info}/METADATA +65 -7
- {pygpt_net-2.4.28.dist-info → pygpt_net-2.4.34.dist-info}/RECORD +168 -154
- {pygpt_net-2.4.28.dist-info → pygpt_net-2.4.34.dist-info}/LICENSE +0 -0
- {pygpt_net-2.4.28.dist-info → pygpt_net-2.4.34.dist-info}/WHEEL +0 -0
- {pygpt_net-2.4.28.dist-info → pygpt_net-2.4.34.dist-info}/entry_points.txt +0 -0
@@ -6,11 +6,12 @@
|
|
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.
|
9
|
+
# Updated Date: 2024.11.26 19:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from PySide6.QtCore import Slot
|
13
13
|
|
14
|
+
from pygpt_net.core.types import MODE_AUDIO
|
14
15
|
from pygpt_net.plugin.base.plugin import BasePlugin
|
15
16
|
from pygpt_net.provider.audio_output.base import BaseProvider
|
16
17
|
from pygpt_net.core.events import Event
|
@@ -118,15 +119,21 @@ class Plugin(BasePlugin):
|
|
118
119
|
name = event.name
|
119
120
|
data = event.data
|
120
121
|
ctx = event.ctx
|
122
|
+
mode = self.window.core.config.get("mode")
|
121
123
|
|
122
124
|
if name == Event.INPUT_BEFORE:
|
123
125
|
self.on_input_before(data['value'])
|
124
126
|
|
125
|
-
elif name
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
127
|
+
elif name == Event.CTX_AFTER:
|
128
|
+
if mode == MODE_AUDIO:
|
129
|
+
return # skip if audio mode
|
130
|
+
self.on_generate(ctx, event)
|
131
|
+
|
132
|
+
elif name == Event.AUDIO_READ_TEXT:
|
133
|
+
self.on_generate(ctx, event)
|
134
|
+
|
135
|
+
elif name == Event.AUDIO_PLAYBACK:
|
136
|
+
self.on_playback(ctx, event)
|
130
137
|
|
131
138
|
elif name == Event.AUDIO_OUTPUT_STOP:
|
132
139
|
self.stop_audio()
|
@@ -139,7 +146,7 @@ class Plugin(BasePlugin):
|
|
139
146
|
"""
|
140
147
|
self.input_text = text
|
141
148
|
|
142
|
-
def
|
149
|
+
def on_generate(self, ctx: CtxItem, event: Event):
|
143
150
|
"""
|
144
151
|
Events: CTX_AFTER, AUDIO_READ_TEXT
|
145
152
|
|
@@ -166,6 +173,7 @@ class Plugin(BasePlugin):
|
|
166
173
|
worker.event = name
|
167
174
|
worker.cache_file = cache_file
|
168
175
|
worker.text = self.window.core.audio.clean_text(text)
|
176
|
+
worker.mode = "generate"
|
169
177
|
|
170
178
|
# signals
|
171
179
|
worker.signals.playback.connect(self.handle_playback)
|
@@ -180,6 +188,28 @@ class Plugin(BasePlugin):
|
|
180
188
|
except Exception as e:
|
181
189
|
self.error(e)
|
182
190
|
|
191
|
+
def on_playback(self, ctx: CtxItem, event: Event):
|
192
|
+
"""
|
193
|
+
Events: AUDIO_PLAYBACK
|
194
|
+
|
195
|
+
:param ctx: CtxItem
|
196
|
+
:param event: Event
|
197
|
+
"""
|
198
|
+
try:
|
199
|
+
worker = Worker()
|
200
|
+
worker.from_defaults(self)
|
201
|
+
worker.audio_file = event.data["audio_file"]
|
202
|
+
worker.mode = "playback"
|
203
|
+
|
204
|
+
# signals
|
205
|
+
worker.signals.playback.connect(self.handle_playback)
|
206
|
+
worker.signals.stop.connect(self.handle_stop)
|
207
|
+
|
208
|
+
worker.run_async()
|
209
|
+
|
210
|
+
except Exception as e:
|
211
|
+
self.error(e)
|
212
|
+
|
183
213
|
def destroy(self):
|
184
214
|
"""Destroy thread"""
|
185
215
|
pass
|
@@ -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.
|
9
|
+
# Updated Date: 2024.11.26 19:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import time
|
@@ -30,28 +30,50 @@ class Worker(BaseWorker):
|
|
30
30
|
self.text = None
|
31
31
|
self.event = None
|
32
32
|
self.cache_file = None # path to cache file
|
33
|
+
self.mode = "generate" # generate|playback
|
34
|
+
self.audio_file = None
|
33
35
|
|
34
36
|
@Slot()
|
35
37
|
def run(self):
|
36
|
-
from pygame import mixer
|
37
38
|
try:
|
38
|
-
if self.
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
if path:
|
43
|
-
mixer.init()
|
44
|
-
playback = mixer.Sound(path)
|
45
|
-
self.stop_playback() # stop previous playback
|
46
|
-
playback.play()
|
47
|
-
self.send(playback) # send playback object to main thread
|
48
|
-
|
49
|
-
# store in cache if enabled
|
50
|
-
if self.cache_file:
|
51
|
-
self.cache_audio_file(path, self.cache_file)
|
39
|
+
if self.mode == "generate":
|
40
|
+
self.generate()
|
41
|
+
elif self.mode == "playback":
|
42
|
+
self.play()
|
52
43
|
except Exception as e:
|
53
44
|
self.error(e)
|
54
45
|
|
46
|
+
def generate(self):
|
47
|
+
"""
|
48
|
+
Generate and play audio file
|
49
|
+
"""
|
50
|
+
if self.text is None or self.text == "":
|
51
|
+
time.sleep(0.2) # wait
|
52
|
+
return
|
53
|
+
path = self.plugin.get_provider().speech(self.text)
|
54
|
+
if path:
|
55
|
+
from pygame import mixer
|
56
|
+
mixer.init()
|
57
|
+
playback = mixer.Sound(path)
|
58
|
+
self.stop_playback() # stop previous playback
|
59
|
+
playback.play()
|
60
|
+
self.send(playback) # send playback object to main thread to allow force stop
|
61
|
+
|
62
|
+
# store in cache if enabled
|
63
|
+
if self.cache_file:
|
64
|
+
self.cache_audio_file(path, self.cache_file)
|
65
|
+
|
66
|
+
def play(self):
|
67
|
+
"""
|
68
|
+
Play audio file only
|
69
|
+
"""
|
70
|
+
if self.audio_file:
|
71
|
+
from pygame import mixer
|
72
|
+
mixer.init()
|
73
|
+
playback = mixer.Sound(self.audio_file)
|
74
|
+
playback.play()
|
75
|
+
self.send(playback) # send playback object to main thread to allow force stop
|
76
|
+
|
55
77
|
def cache_audio_file(self, src: str, dst: str):
|
56
78
|
"""
|
57
79
|
Store audio file in cache
|
@@ -81,28 +103,3 @@ class Worker(BaseWorker):
|
|
81
103
|
def stop(self):
|
82
104
|
"""Send stop signal to main thread"""
|
83
105
|
self.signals.stop.emit()
|
84
|
-
|
85
|
-
|
86
|
-
class PlayWorker(BaseWorker):
|
87
|
-
def __init__(self, *args, **kwargs):
|
88
|
-
super(PlayWorker, self).__init__()
|
89
|
-
self.signals = WorkerSignals()
|
90
|
-
self.args = args
|
91
|
-
self.kwargs = kwargs
|
92
|
-
self.window = None
|
93
|
-
self.path = None
|
94
|
-
|
95
|
-
@Slot()
|
96
|
-
def run(self):
|
97
|
-
from pygame import mixer
|
98
|
-
try:
|
99
|
-
if self.path:
|
100
|
-
mixer.init()
|
101
|
-
playback = mixer.Sound(self.path)
|
102
|
-
playback.play()
|
103
|
-
except Exception as e:
|
104
|
-
self.error(e)
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
@@ -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.
|
9
|
+
# Updated Date: 2024.11.25 02:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import os
|
@@ -20,7 +20,8 @@ from pygpt_net.item.ctx import CtxItem
|
|
20
20
|
from .config import Config
|
21
21
|
from .docker import Docker
|
22
22
|
from .builder import Builder
|
23
|
-
from .ipython import
|
23
|
+
from .ipython import LocalKernel
|
24
|
+
from .ipython import DockerKernel
|
24
25
|
from .output import Output
|
25
26
|
from .runner import Runner
|
26
27
|
from .worker import Worker
|
@@ -55,7 +56,8 @@ class Plugin(BasePlugin):
|
|
55
56
|
self.use_locale = True
|
56
57
|
self.docker = Docker(self)
|
57
58
|
self.runner = Runner(self)
|
58
|
-
self.
|
59
|
+
self.ipython_docker = DockerKernel(self)
|
60
|
+
self.ipython_local = LocalKernel(self)
|
59
61
|
self.builder = Builder(self)
|
60
62
|
self.output = Output(self)
|
61
63
|
self.worker = None
|
@@ -100,17 +102,20 @@ class Plugin(BasePlugin):
|
|
100
102
|
:param data: event data dict
|
101
103
|
"""
|
102
104
|
# get current working directory
|
103
|
-
|
104
|
-
ipython_data = os.path.join(
|
105
|
-
if self.get_option_value("sandbox_docker"):
|
106
|
-
cwd = "/data (in docker sandbox)"
|
105
|
+
legacy_data = self.window.core.config.get_user_dir('data')
|
106
|
+
ipython_data = os.path.join(legacy_data, 'ipython')
|
107
107
|
|
108
108
|
for item in self.allowed_cmds:
|
109
109
|
if self.has_cmd(item):
|
110
110
|
cmd = self.get_cmd(item)
|
111
|
-
if item
|
112
|
-
|
113
|
-
|
111
|
+
if item in ["ipython_execute", "ipython_execute_new"]:
|
112
|
+
if self.get_option_value("sandbox_ipython"):
|
113
|
+
cmd["instruction"] += ("\nIPython works in Docker container. Directory /data is the container's workdir - "
|
114
|
+
"directory is mapped as volume in host machine to: {}").format(ipython_data)
|
115
|
+
elif item in ["code_execute", "code_execute_file", "code_execute_all"]:
|
116
|
+
if self.get_option_value("sandbox_docker"):
|
117
|
+
cmd["instruction"] += ("\nPython works in Docker container. Directory /data is the container's workdir - "
|
118
|
+
"directory is mapped as volume in host machine to: {}").format(legacy_data)
|
114
119
|
data['cmd'].append(cmd) # append command
|
115
120
|
|
116
121
|
@Slot(object, str)
|
@@ -139,6 +144,16 @@ class Plugin(BasePlugin):
|
|
139
144
|
"""
|
140
145
|
self.window.tools.get("html_canvas").set_output(data)
|
141
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
|
142
157
|
|
143
158
|
def cmd(self, ctx: CtxItem, cmds: list, silent: bool = False):
|
144
159
|
"""
|
@@ -161,30 +176,31 @@ class Plugin(BasePlugin):
|
|
161
176
|
if not is_cmd:
|
162
177
|
return
|
163
178
|
|
164
|
-
ipython_commands = [
|
165
|
-
"ipython_execute_new",
|
166
|
-
"ipython_execute",
|
167
|
-
"ipython_kernel_restart",
|
168
|
-
]
|
169
179
|
# ipython
|
170
|
-
if
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
#
|
178
|
-
|
179
|
-
|
180
|
-
self.window.
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
180
|
+
if self.get_option_value("sandbox_ipython"):
|
181
|
+
ipython_commands = [
|
182
|
+
"ipython_execute_new",
|
183
|
+
"ipython_execute",
|
184
|
+
"ipython_kernel_restart",
|
185
|
+
]
|
186
|
+
if any(x in [x["cmd"] for x in my_commands] for x in ipython_commands):
|
187
|
+
# check for Docker installed
|
188
|
+
if not self.get_interpreter().is_docker_installed():
|
189
|
+
# snap version
|
190
|
+
if self.window.core.platforms.is_snap():
|
191
|
+
self.error(trans('ipython.docker.install.snap'))
|
192
|
+
self.window.update_status(trans('ipython.docker.install.snap'))
|
193
|
+
# other versions
|
194
|
+
else:
|
195
|
+
self.error(trans('ipython.docker.install'))
|
196
|
+
self.window.update_status(trans('ipython.docker.install'))
|
197
|
+
return
|
198
|
+
# check if image exists
|
199
|
+
if not self.get_interpreter().is_image():
|
200
|
+
self.error(trans('ipython.image.build'))
|
201
|
+
self.window.update_status(trans('ipython.docker.build.start'))
|
202
|
+
self.builder.build_image()
|
203
|
+
return
|
188
204
|
|
189
205
|
# legacy python
|
190
206
|
if self.get_option_value("sandbox_docker"):
|
@@ -227,7 +243,7 @@ class Plugin(BasePlugin):
|
|
227
243
|
worker.signals.clear.connect(self.handle_interpreter_clear)
|
228
244
|
worker.signals.html_output.connect(self.handle_html_output)
|
229
245
|
worker.signals.ipython_output.connect(self.handle_ipython_output)
|
230
|
-
self.
|
246
|
+
self.get_interpreter().attach_signals(worker.signals)
|
231
247
|
self.runner.attach_signals(worker.signals)
|
232
248
|
|
233
249
|
if not self.is_async(ctx) and not force:
|
@@ -250,7 +266,7 @@ class Plugin(BasePlugin):
|
|
250
266
|
# if self.is_threaded():
|
251
267
|
# return
|
252
268
|
# print(data)
|
253
|
-
cleaned_data = self.
|
269
|
+
cleaned_data = self.get_interpreter().remove_ansi(data)
|
254
270
|
self.window.tools.get("interpreter").append_output(cleaned_data)
|
255
271
|
if self.window.tools.get("interpreter").opened:
|
256
272
|
self.window.update_status("")
|
@@ -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.
|
9
|
+
# Updated Date: 2024.11.25 02:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from PySide6.QtCore import Slot, Signal, QObject
|
@@ -21,11 +21,20 @@ class Builder(QObject):
|
|
21
21
|
self.plugin = plugin
|
22
22
|
self.worker = None
|
23
23
|
|
24
|
-
def
|
25
|
-
"""Run IPython image build"""
|
24
|
+
def build_and_restart(self):
|
25
|
+
"""Run IPython image build and restart container"""
|
26
|
+
self.build_image(restart=True)
|
27
|
+
|
28
|
+
def build_image(self, restart: bool = False):
|
29
|
+
"""
|
30
|
+
Run IPython image build
|
31
|
+
|
32
|
+
:param restart: Restart container
|
33
|
+
"""
|
26
34
|
try:
|
27
35
|
self.worker = Worker()
|
28
36
|
self.worker.plugin = self.plugin
|
37
|
+
self.worker.restart = restart
|
29
38
|
self.worker.signals.build_finished.connect(self.handle_build_finished)
|
30
39
|
self.worker.signals.error.connect(self.handle_build_failed)
|
31
40
|
self.plugin.window.threadpool.start(self.worker)
|
@@ -60,11 +69,14 @@ class Worker(BaseWorker):
|
|
60
69
|
self.args = args
|
61
70
|
self.kwargs = kwargs
|
62
71
|
self.plugin = None
|
72
|
+
self.restart = False
|
63
73
|
|
64
74
|
@Slot()
|
65
75
|
def run(self):
|
66
76
|
try:
|
67
|
-
self.plugin.
|
77
|
+
self.plugin.get_interpreter().build_image()
|
78
|
+
if self.restart:
|
79
|
+
self.plugin.get_interpreter().restart()
|
68
80
|
self.signals.build_finished.emit()
|
69
81
|
except Exception as e:
|
70
82
|
self.signals.error.emit(e)
|
@@ -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.
|
9
|
+
# Updated Date: 2024.11.25 02:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from pygpt_net.plugin.base.config import BaseConfig, BasePlugin
|
@@ -23,35 +23,36 @@ class Config(BaseConfig):
|
|
23
23
|
|
24
24
|
:param plugin: plugin instance
|
25
25
|
"""
|
26
|
-
dockerfile = '
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
26
|
+
dockerfile = '''
|
27
|
+
# Tip: After making changes to this Dockerfile, you must rebuild the image to apply the changes(Menu -> Tools -> Rebuild IPython Docker Image)
|
28
|
+
|
29
|
+
FROM python:3.9
|
30
|
+
|
31
|
+
# You can customize the packages installed by default here:
|
32
|
+
# ========================================================
|
33
|
+
RUN pip install jupyter ipykernel
|
34
|
+
# ========================================================
|
35
|
+
|
36
|
+
RUN mkdir /data
|
37
|
+
|
38
|
+
# Expose the necessary ports for Jupyter kernel communication
|
39
|
+
EXPOSE 5555 5556 5557 5558 5559
|
40
|
+
|
41
|
+
# Data directory, bound as a volume to the local 'data/ipython' directory
|
42
|
+
WORKDIR /data
|
43
|
+
|
44
|
+
# Start the IPython kernel with specified ports and settings
|
45
|
+
CMD ["ipython", "kernel", \
|
46
|
+
"--ip=0.0.0.0", \
|
47
|
+
"--transport=tcp", \
|
48
|
+
"--shell=5555", \
|
49
|
+
"--iopub=5556", \
|
50
|
+
"--stdin=5557", \
|
51
|
+
"--control=5558", \
|
52
|
+
"--hb=5559", \
|
53
|
+
"--Session.key=19749810-8febfa748186a01da2f7b28c", \
|
54
|
+
"--Session.signature_scheme=hmac-sha256"]
|
55
|
+
'''
|
55
56
|
|
56
57
|
dockerfile_legacy = 'FROM python:3.9-alpine'
|
57
58
|
dockerfile_legacy += '\n\n'
|
@@ -60,6 +61,15 @@ class Config(BaseConfig):
|
|
60
61
|
dockerfile_legacy += '# Data directory, bound as a volume to the local \'data/\' directory'
|
61
62
|
dockerfile_legacy += '\nWORKDIR /data'
|
62
63
|
|
64
|
+
plugin.add_option(
|
65
|
+
"sandbox_ipython",
|
66
|
+
type="bool",
|
67
|
+
value=False,
|
68
|
+
label="Sandbox (docker container)",
|
69
|
+
description="Executes commands in sandbox (docker container). "
|
70
|
+
"Docker must be installed and running.",
|
71
|
+
tab="ipython",
|
72
|
+
)
|
63
73
|
plugin.add_option(
|
64
74
|
"ipython_dockerfile",
|
65
75
|
type="textarea",
|
@@ -131,6 +141,26 @@ class Config(BaseConfig):
|
|
131
141
|
tab="ipython",
|
132
142
|
)
|
133
143
|
"""
|
144
|
+
|
145
|
+
volumes_keys = {
|
146
|
+
"enabled": "bool",
|
147
|
+
"docker": "text",
|
148
|
+
"host": "text",
|
149
|
+
}
|
150
|
+
volumes_items = [
|
151
|
+
{
|
152
|
+
"enabled": True,
|
153
|
+
"docker": "/data",
|
154
|
+
"host": "{workdir}",
|
155
|
+
},
|
156
|
+
]
|
157
|
+
ports_keys = {
|
158
|
+
"enabled": "bool",
|
159
|
+
"docker": "text",
|
160
|
+
"host": "int",
|
161
|
+
}
|
162
|
+
ports_items = []
|
163
|
+
|
134
164
|
plugin.add_cmd(
|
135
165
|
"ipython_kernel_restart",
|
136
166
|
instruction="restart IPython kernel",
|
@@ -179,15 +209,6 @@ class Config(BaseConfig):
|
|
179
209
|
tab="ipython",
|
180
210
|
advanced=True,
|
181
211
|
)
|
182
|
-
|
183
|
-
plugin.add_option(
|
184
|
-
"python_cmd_tpl",
|
185
|
-
type="text",
|
186
|
-
value="python3 {filename}",
|
187
|
-
label="Python command template",
|
188
|
-
description="Python command template to execute, use {filename} for filename placeholder",
|
189
|
-
tab="python_legacy",
|
190
|
-
)
|
191
212
|
plugin.add_option(
|
192
213
|
"sandbox_docker",
|
193
214
|
type="bool",
|
@@ -197,6 +218,14 @@ class Config(BaseConfig):
|
|
197
218
|
"Docker must be installed and running.",
|
198
219
|
tab="python_legacy",
|
199
220
|
)
|
221
|
+
plugin.add_option(
|
222
|
+
"python_cmd_tpl",
|
223
|
+
type="text",
|
224
|
+
value="python3 {filename}",
|
225
|
+
label="Python command template",
|
226
|
+
description="Python command template to execute, use {filename} for filename placeholder",
|
227
|
+
tab="python_legacy",
|
228
|
+
)
|
200
229
|
plugin.add_option(
|
201
230
|
"dockerfile",
|
202
231
|
type="textarea",
|
@@ -220,6 +249,36 @@ class Config(BaseConfig):
|
|
220
249
|
label="Docker container name",
|
221
250
|
tab="python_legacy",
|
222
251
|
)
|
252
|
+
plugin.add_option(
|
253
|
+
"docker_entrypoint",
|
254
|
+
type="text",
|
255
|
+
value='tail -f /dev/null',
|
256
|
+
label="Docker run command",
|
257
|
+
tab="python_legacy",
|
258
|
+
advanced=True,
|
259
|
+
)
|
260
|
+
plugin.add_option(
|
261
|
+
"docker_volumes",
|
262
|
+
type="dict",
|
263
|
+
value=volumes_items,
|
264
|
+
label="Docker volumes",
|
265
|
+
description="Docker volumes mapping",
|
266
|
+
tooltip="Docker volumes mapping",
|
267
|
+
keys=volumes_keys,
|
268
|
+
tab="python_legacy",
|
269
|
+
advanced=True,
|
270
|
+
)
|
271
|
+
plugin.add_option(
|
272
|
+
"docker_ports",
|
273
|
+
type="dict",
|
274
|
+
value=ports_items,
|
275
|
+
label="Docker ports",
|
276
|
+
description="Docker ports mapping",
|
277
|
+
tooltip="Docker ports mapping",
|
278
|
+
keys=ports_keys,
|
279
|
+
tab="python_legacy",
|
280
|
+
advanced=True,
|
281
|
+
)
|
223
282
|
plugin.add_option(
|
224
283
|
"attach_output",
|
225
284
|
type="bool",
|
@@ -26,6 +26,10 @@ class Docker(BaseDocker):
|
|
26
26
|
"""Run image build"""
|
27
27
|
self.builder.build_image()
|
28
28
|
|
29
|
+
def build_and_restart(self):
|
30
|
+
"""Run image build and restart container"""
|
31
|
+
self.builder.build_image(restart=True)
|
32
|
+
|
29
33
|
def get_dockerfile(self) -> str:
|
30
34
|
"""
|
31
35
|
Get the Dockerfile
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# ================================================== #
|
4
|
+
# This file is a part of PYGPT package #
|
5
|
+
# Website: https://pygpt.net #
|
6
|
+
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
7
|
+
# MIT License #
|
8
|
+
# Created By : Marcin Szczygliński #
|
9
|
+
# Updated Date: 2024.11.25 02:00:00 #
|
10
|
+
# ================================================== #
|
11
|
+
|
12
|
+
from .local_kernel import LocalKernel
|
13
|
+
from .docker_kernel import DockerKernel
|
@@ -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.
|
9
|
+
# Updated Date: 2024.11.25 02:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import os
|
@@ -19,7 +19,7 @@ import tarfile
|
|
19
19
|
from jupyter_client import BlockingKernelClient
|
20
20
|
from docker.errors import DockerException
|
21
21
|
|
22
|
-
class
|
22
|
+
class DockerKernel:
|
23
23
|
def __init__(self, plugin = None):
|
24
24
|
self.plugin = plugin
|
25
25
|
self.kernel_file = ".interpreter.kernel.json"
|
@@ -96,6 +96,10 @@ class IPythonInterpreter:
|
|
96
96
|
except docker.errors.ImageNotFound:
|
97
97
|
return False
|
98
98
|
|
99
|
+
def restart(self):
|
100
|
+
"""Restart the container."""
|
101
|
+
self.restart_container(self.get_container_name())
|
102
|
+
|
99
103
|
def build_image(self):
|
100
104
|
"""Build the Docker image for the IPython kernel."""
|
101
105
|
client = self.get_docker_client()
|
@@ -231,6 +235,8 @@ class IPythonInterpreter:
|
|
231
235
|
|
232
236
|
# run the container
|
233
237
|
try:
|
238
|
+
print("Running container {}...".format(name))
|
239
|
+
self.prepare_conn()
|
234
240
|
local_data_dir = self.get_local_data_dir()
|
235
241
|
client.containers.run(
|
236
242
|
self.get_image_name(),
|
@@ -383,7 +389,8 @@ class IPythonInterpreter:
|
|
383
389
|
self.restart_container(self.get_container_name())
|
384
390
|
if self.client is not None:
|
385
391
|
self.client.stop_channels()
|
386
|
-
|
392
|
+
else:
|
393
|
+
self.client = BlockingKernelClient(connection_file=self.get_kernel_file_path())
|
387
394
|
self.client.load_connection_file()
|
388
395
|
self.client.start_channels()
|
389
396
|
self.client.wait_for_ready()
|