pygpt-net 2.6.20__py3-none-any.whl → 2.6.22__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.
- pygpt_net/CHANGELOG.txt +13 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +3 -1
- pygpt_net/controller/__init__.py +4 -8
- pygpt_net/controller/access/voice.py +2 -2
- pygpt_net/controller/agent/agent.py +130 -2
- pygpt_net/controller/agent/experts.py +93 -96
- pygpt_net/controller/agent/llama.py +2 -1
- pygpt_net/controller/assistant/assistant.py +18 -1
- pygpt_net/controller/assistant/batch.py +2 -3
- pygpt_net/controller/assistant/editor.py +2 -2
- pygpt_net/controller/assistant/files.py +2 -3
- pygpt_net/controller/assistant/store.py +2 -2
- pygpt_net/controller/attachment/attachment.py +17 -1
- pygpt_net/controller/audio/audio.py +2 -2
- pygpt_net/controller/camera/camera.py +15 -7
- pygpt_net/controller/chat/chat.py +2 -2
- pygpt_net/controller/chat/common.py +50 -33
- pygpt_net/controller/chat/image.py +67 -77
- pygpt_net/controller/chat/input.py +94 -166
- pygpt_net/controller/chat/output.py +83 -140
- pygpt_net/controller/chat/response.py +83 -102
- pygpt_net/controller/chat/text.py +116 -149
- pygpt_net/controller/ctx/common.py +2 -1
- pygpt_net/controller/ctx/ctx.py +87 -6
- pygpt_net/controller/files/files.py +13 -1
- pygpt_net/controller/idx/idx.py +26 -2
- pygpt_net/controller/idx/indexer.py +85 -76
- pygpt_net/controller/kernel/reply.py +53 -66
- pygpt_net/controller/kernel/stack.py +16 -16
- pygpt_net/controller/lang/lang.py +52 -34
- pygpt_net/controller/model/importer.py +3 -2
- pygpt_net/controller/model/model.py +62 -3
- pygpt_net/controller/notepad/notepad.py +86 -84
- pygpt_net/controller/plugins/settings.py +3 -4
- pygpt_net/controller/settings/editor.py +4 -4
- pygpt_net/controller/settings/profile.py +105 -124
- pygpt_net/controller/theme/menu.py +154 -57
- pygpt_net/controller/theme/nodes.py +51 -44
- pygpt_net/controller/theme/theme.py +33 -9
- pygpt_net/controller/tools/tools.py +2 -2
- pygpt_net/controller/ui/tabs.py +2 -3
- pygpt_net/controller/ui/ui.py +16 -2
- pygpt_net/core/agents/observer/evaluation.py +3 -3
- pygpt_net/core/agents/provider.py +25 -3
- pygpt_net/core/agents/runner.py +4 -1
- pygpt_net/core/agents/runners/llama_workflow.py +19 -7
- pygpt_net/core/agents/runners/loop.py +3 -1
- pygpt_net/core/agents/runners/openai_workflow.py +17 -3
- pygpt_net/core/agents/tools.py +4 -1
- pygpt_net/core/bridge/context.py +34 -37
- pygpt_net/core/ctx/container.py +13 -12
- pygpt_net/core/ctx/ctx.py +1 -1
- pygpt_net/core/ctx/output.py +7 -4
- pygpt_net/core/db/database.py +2 -2
- pygpt_net/core/debug/console/console.py +2 -2
- pygpt_net/core/debug/debug.py +12 -1
- pygpt_net/core/dispatcher/dispatcher.py +24 -1
- pygpt_net/core/events/app.py +7 -7
- pygpt_net/core/events/control.py +26 -26
- pygpt_net/core/events/event.py +6 -3
- pygpt_net/core/events/kernel.py +2 -2
- pygpt_net/core/events/render.py +13 -13
- pygpt_net/core/experts/experts.py +76 -82
- pygpt_net/core/experts/worker.py +12 -12
- pygpt_net/core/filesystem/actions.py +1 -2
- pygpt_net/core/models/models.py +5 -1
- pygpt_net/core/models/ollama.py +14 -5
- pygpt_net/core/render/plain/helpers.py +2 -5
- pygpt_net/core/render/plain/renderer.py +26 -30
- pygpt_net/core/render/web/body.py +1 -1
- pygpt_net/core/render/web/helpers.py +2 -2
- pygpt_net/core/render/web/renderer.py +4 -4
- pygpt_net/core/settings/settings.py +43 -13
- pygpt_net/core/tabs/tabs.py +20 -13
- pygpt_net/core/types/__init__.py +2 -1
- pygpt_net/core/types/agent.py +4 -4
- pygpt_net/core/types/base.py +19 -0
- pygpt_net/core/types/console.py +6 -6
- pygpt_net/core/types/mode.py +8 -8
- pygpt_net/core/types/multimodal.py +3 -3
- pygpt_net/core/types/openai.py +2 -1
- pygpt_net/data/config/config.json +5 -5
- pygpt_net/data/config/models.json +19 -3
- pygpt_net/data/config/settings.json +14 -14
- pygpt_net/data/locale/locale.de.ini +4 -1
- pygpt_net/data/locale/locale.en.ini +6 -3
- pygpt_net/data/locale/locale.es.ini +4 -1
- pygpt_net/data/locale/locale.fr.ini +4 -1
- pygpt_net/data/locale/locale.it.ini +4 -1
- pygpt_net/data/locale/locale.pl.ini +5 -4
- pygpt_net/data/locale/locale.uk.ini +4 -1
- pygpt_net/data/locale/locale.zh.ini +4 -1
- pygpt_net/item/ctx.py +256 -240
- pygpt_net/item/model.py +59 -116
- pygpt_net/item/preset.py +122 -105
- pygpt_net/plugin/twitter/plugin.py +2 -2
- pygpt_net/provider/agents/llama_index/workflow/planner.py +3 -3
- pygpt_net/provider/agents/openai/agent.py +4 -12
- pygpt_net/provider/agents/openai/agent_b2b.py +10 -15
- pygpt_net/provider/agents/openai/agent_planner.py +4 -4
- pygpt_net/provider/agents/openai/agent_with_experts.py +3 -7
- pygpt_net/provider/agents/openai/agent_with_experts_feedback.py +4 -8
- pygpt_net/provider/agents/openai/agent_with_feedback.py +4 -8
- pygpt_net/provider/agents/openai/bot_researcher.py +2 -18
- pygpt_net/provider/agents/openai/bots/__init__.py +0 -0
- pygpt_net/provider/agents/openai/bots/research_bot/__init__.py +0 -0
- pygpt_net/provider/agents/openai/bots/research_bot/agents/__init__.py +0 -0
- pygpt_net/provider/agents/openai/bots/research_bot/agents/planner_agent.py +1 -1
- pygpt_net/provider/agents/openai/bots/research_bot/agents/search_agent.py +1 -0
- pygpt_net/provider/agents/openai/bots/research_bot/agents/writer_agent.py +1 -1
- pygpt_net/provider/agents/openai/bots/research_bot/manager.py +1 -10
- pygpt_net/provider/agents/openai/evolve.py +5 -9
- pygpt_net/provider/agents/openai/supervisor.py +4 -8
- pygpt_net/provider/core/config/patch.py +10 -3
- pygpt_net/provider/core/ctx/db_sqlite/utils.py +43 -43
- pygpt_net/provider/core/model/patch.py +11 -1
- pygpt_net/provider/core/preset/json_file.py +47 -49
- pygpt_net/provider/gpt/agents/experts.py +2 -2
- pygpt_net/tools/audio_transcriber/ui/dialogs.py +44 -54
- pygpt_net/tools/code_interpreter/body.py +1 -2
- pygpt_net/tools/code_interpreter/tool.py +7 -4
- pygpt_net/tools/code_interpreter/ui/html.py +1 -3
- pygpt_net/tools/code_interpreter/ui/widgets.py +2 -3
- pygpt_net/tools/html_canvas/ui/widgets.py +1 -3
- pygpt_net/tools/image_viewer/ui/dialogs.py +40 -37
- pygpt_net/tools/indexer/ui/widgets.py +2 -4
- pygpt_net/tools/media_player/tool.py +2 -5
- pygpt_net/tools/media_player/ui/widgets.py +60 -36
- pygpt_net/tools/text_editor/ui/widgets.py +18 -19
- pygpt_net/tools/translator/ui/widgets.py +39 -35
- pygpt_net/ui/base/context_menu.py +9 -4
- pygpt_net/ui/dialog/db.py +1 -3
- pygpt_net/ui/dialog/models.py +1 -3
- pygpt_net/ui/dialog/models_importer.py +2 -4
- pygpt_net/ui/dialogs.py +34 -30
- pygpt_net/ui/layout/chat/attachments.py +72 -84
- pygpt_net/ui/layout/chat/attachments_ctx.py +40 -44
- pygpt_net/ui/layout/chat/attachments_uploaded.py +36 -39
- pygpt_net/ui/layout/chat/calendar.py +100 -70
- pygpt_net/ui/layout/chat/chat.py +23 -17
- pygpt_net/ui/layout/chat/input.py +95 -118
- pygpt_net/ui/layout/chat/output.py +100 -162
- pygpt_net/ui/layout/chat/painter.py +89 -61
- pygpt_net/ui/layout/ctx/ctx_list.py +43 -52
- pygpt_net/ui/layout/status.py +23 -14
- pygpt_net/ui/layout/toolbox/agent.py +27 -38
- pygpt_net/ui/layout/toolbox/agent_llama.py +42 -45
- pygpt_net/ui/layout/toolbox/assistants.py +42 -38
- pygpt_net/ui/layout/toolbox/computer_env.py +32 -23
- pygpt_net/ui/layout/toolbox/footer.py +13 -16
- pygpt_net/ui/layout/toolbox/image.py +18 -21
- pygpt_net/ui/layout/toolbox/indexes.py +46 -89
- pygpt_net/ui/layout/toolbox/mode.py +20 -7
- pygpt_net/ui/layout/toolbox/model.py +12 -10
- pygpt_net/ui/layout/toolbox/presets.py +68 -52
- pygpt_net/ui/layout/toolbox/prompt.py +31 -58
- pygpt_net/ui/layout/toolbox/toolbox.py +25 -21
- pygpt_net/ui/layout/toolbox/vision.py +20 -22
- pygpt_net/ui/main.py +2 -4
- pygpt_net/ui/menu/about.py +64 -84
- pygpt_net/ui/menu/audio.py +87 -63
- pygpt_net/ui/menu/config.py +121 -127
- pygpt_net/ui/menu/debug.py +69 -76
- pygpt_net/ui/menu/file.py +32 -35
- pygpt_net/ui/menu/menu.py +2 -3
- pygpt_net/ui/menu/plugins.py +69 -33
- pygpt_net/ui/menu/theme.py +45 -46
- pygpt_net/ui/menu/tools.py +56 -60
- pygpt_net/ui/menu/video.py +20 -25
- pygpt_net/ui/tray.py +1 -2
- pygpt_net/ui/widget/audio/bar.py +1 -3
- pygpt_net/ui/widget/audio/input_button.py +3 -4
- pygpt_net/ui/widget/calendar/select.py +1 -2
- pygpt_net/ui/widget/dialog/base.py +12 -9
- pygpt_net/ui/widget/dialog/editor_file.py +20 -23
- pygpt_net/ui/widget/dialog/find.py +25 -24
- pygpt_net/ui/widget/dialog/profile.py +57 -53
- pygpt_net/ui/widget/draw/painter.py +62 -93
- pygpt_net/ui/widget/element/button.py +42 -30
- pygpt_net/ui/widget/element/checkbox.py +23 -15
- pygpt_net/ui/widget/element/group.py +6 -5
- pygpt_net/ui/widget/element/labels.py +1 -2
- pygpt_net/ui/widget/filesystem/explorer.py +93 -102
- pygpt_net/ui/widget/image/display.py +1 -2
- pygpt_net/ui/widget/lists/assistant.py +1 -2
- pygpt_net/ui/widget/lists/attachment.py +1 -2
- pygpt_net/ui/widget/lists/attachment_ctx.py +1 -2
- pygpt_net/ui/widget/lists/context.py +2 -4
- pygpt_net/ui/widget/lists/index.py +1 -2
- pygpt_net/ui/widget/lists/model.py +1 -2
- pygpt_net/ui/widget/lists/model_editor.py +1 -2
- pygpt_net/ui/widget/lists/model_importer.py +1 -2
- pygpt_net/ui/widget/lists/preset.py +1 -2
- pygpt_net/ui/widget/lists/preset_plugins.py +1 -2
- pygpt_net/ui/widget/lists/profile.py +1 -2
- pygpt_net/ui/widget/lists/uploaded.py +1 -2
- pygpt_net/ui/widget/option/checkbox.py +2 -4
- pygpt_net/ui/widget/option/checkbox_list.py +1 -4
- pygpt_net/ui/widget/option/cmd.py +1 -4
- pygpt_net/ui/widget/option/dictionary.py +25 -28
- pygpt_net/ui/widget/option/input.py +1 -3
- pygpt_net/ui/widget/tabs/Input.py +16 -12
- pygpt_net/ui/widget/tabs/body.py +5 -3
- pygpt_net/ui/widget/tabs/layout.py +36 -25
- pygpt_net/ui/widget/tabs/output.py +96 -74
- pygpt_net/ui/widget/textarea/calendar_note.py +1 -2
- pygpt_net/ui/widget/textarea/editor.py +41 -73
- pygpt_net/ui/widget/textarea/find.py +11 -10
- pygpt_net/ui/widget/textarea/html.py +3 -6
- pygpt_net/ui/widget/textarea/input.py +63 -64
- pygpt_net/ui/widget/textarea/notepad.py +54 -38
- pygpt_net/ui/widget/textarea/output.py +65 -54
- pygpt_net/ui/widget/textarea/search_input.py +5 -4
- pygpt_net/ui/widget/textarea/web.py +2 -4
- pygpt_net/ui/widget/vision/camera.py +2 -31
- {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/METADATA +25 -154
- {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/RECORD +218 -217
- {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/entry_points.txt +0 -0
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date:
|
|
9
|
+
# Updated Date: 2025.08.24 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
|
-
from PySide6.QtGui import QAction
|
|
12
|
+
from PySide6.QtGui import QAction, QActionGroup
|
|
13
13
|
|
|
14
14
|
from pygpt_net.utils import trans, trans_reload
|
|
15
|
+
|
|
15
16
|
from .custom import Custom
|
|
16
17
|
from .mapping import Mapping
|
|
17
18
|
from .plugins import Plugins
|
|
@@ -31,28 +32,48 @@ class Lang:
|
|
|
31
32
|
self.plugins = Plugins(window)
|
|
32
33
|
self.settings = Settings(window)
|
|
33
34
|
self.loaded = False
|
|
35
|
+
self._lang_group = None
|
|
36
|
+
|
|
37
|
+
def _on_lang_triggered(self, action):
|
|
38
|
+
"""
|
|
39
|
+
Handle language change triggered by menu action
|
|
40
|
+
|
|
41
|
+
:param action: QAction instance
|
|
42
|
+
"""
|
|
43
|
+
self.window.controller.lang.toggle(action.data())
|
|
34
44
|
|
|
35
45
|
def setup(self):
|
|
36
46
|
"""Setup language menu"""
|
|
37
|
-
# get files from locale directory
|
|
38
47
|
if not self.loaded:
|
|
39
|
-
|
|
48
|
+
w = self.window
|
|
49
|
+
menu = w.ui.menu
|
|
50
|
+
if self._lang_group is None:
|
|
51
|
+
self._lang_group = QActionGroup(w)
|
|
52
|
+
self._lang_group.setExclusive(True)
|
|
53
|
+
self._lang_group.triggered.connect(self._on_lang_triggered)
|
|
54
|
+
|
|
55
|
+
langs = w.core.config.get_available_langs()
|
|
56
|
+
menu_lang = menu['lang']
|
|
57
|
+
menu_root = menu['menu.lang']
|
|
40
58
|
for lang in langs:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
59
|
+
act = QAction(lang.upper(), w, checkable=True)
|
|
60
|
+
act.setData(lang)
|
|
61
|
+
menu_lang[lang] = act
|
|
62
|
+
self._lang_group.addAction(act)
|
|
63
|
+
menu_root.addAction(act)
|
|
46
64
|
self.loaded = True
|
|
47
65
|
self.update()
|
|
48
66
|
|
|
49
67
|
def update(self):
|
|
50
68
|
"""Update language menu"""
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if
|
|
55
|
-
|
|
69
|
+
menu_lang = self.window.ui.menu['lang']
|
|
70
|
+
current = self.window.core.config.get('lang')
|
|
71
|
+
act = menu_lang.get(current)
|
|
72
|
+
if act is not None:
|
|
73
|
+
act.setChecked(True)
|
|
74
|
+
else:
|
|
75
|
+
for a in menu_lang.values():
|
|
76
|
+
a.setChecked(False)
|
|
56
77
|
|
|
57
78
|
def reload_config(self):
|
|
58
79
|
"""Reload language config"""
|
|
@@ -64,37 +85,34 @@ class Lang:
|
|
|
64
85
|
|
|
65
86
|
:param id: language code to toggle
|
|
66
87
|
"""
|
|
67
|
-
self.window
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
self.update() # update menu
|
|
72
|
-
self.mapping.apply() # nodes mapping
|
|
73
|
-
self.custom.apply() # custom nodes
|
|
88
|
+
w = self.window
|
|
89
|
+
c = w.controller
|
|
90
|
+
conf = w.core.config
|
|
74
91
|
|
|
75
|
-
|
|
76
|
-
|
|
92
|
+
conf.set('lang', id)
|
|
93
|
+
conf.save()
|
|
94
|
+
trans('', True)
|
|
77
95
|
|
|
78
|
-
|
|
79
|
-
self.
|
|
96
|
+
self.update()
|
|
97
|
+
self.mapping.apply()
|
|
98
|
+
self.custom.apply()
|
|
80
99
|
|
|
81
|
-
|
|
100
|
+
c.ui.tabs.reload_titles()
|
|
101
|
+
c.calendar.note.update_current()
|
|
82
102
|
self.settings.apply()
|
|
83
103
|
|
|
84
|
-
# plugins
|
|
85
104
|
try:
|
|
86
105
|
self.plugins.apply()
|
|
87
106
|
except Exception as e:
|
|
88
107
|
print("Error updating plugin locale", e)
|
|
89
|
-
|
|
108
|
+
w.core.debug.log(e)
|
|
90
109
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
self.window.update_status('') # clear status
|
|
110
|
+
w.controller.ctx.common.update_label_by_current()
|
|
111
|
+
w.controller.ctx.update(True, False)
|
|
112
|
+
w.controller.ui.update()
|
|
113
|
+
w.update_status('')
|
|
96
114
|
|
|
97
115
|
def reload(self):
|
|
98
116
|
"""Reload language"""
|
|
99
117
|
self.reload_config()
|
|
100
|
-
self.setup()
|
|
118
|
+
self.setup()
|
|
@@ -6,14 +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: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.24 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
13
13
|
import os
|
|
14
14
|
from typing import List, Dict, Optional, Any
|
|
15
15
|
|
|
16
|
-
from
|
|
16
|
+
from PySide6.QtWidgets import QApplication
|
|
17
17
|
|
|
18
18
|
from pygpt_net.core.events import Event
|
|
19
19
|
from pygpt_net.core.types import (
|
|
@@ -475,6 +475,7 @@ class Importer:
|
|
|
475
475
|
MODE_LLAMA_INDEX,
|
|
476
476
|
MODE_AGENT,
|
|
477
477
|
MODE_AGENT_LLAMA,
|
|
478
|
+
MODE_AGENT_OPENAI,
|
|
478
479
|
MODE_EXPERT,
|
|
479
480
|
]
|
|
480
481
|
m.provider = 'ollama'
|
|
@@ -6,18 +6,20 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.08.15
|
|
9
|
+
# Updated Date: 2025.08.23 15:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
|
+
import os
|
|
12
13
|
from typing import Optional
|
|
13
14
|
|
|
14
|
-
from pygpt_net.core.events import Event, AppEvent
|
|
15
|
+
from pygpt_net.core.events import Event, AppEvent, BaseEvent
|
|
16
|
+
from pygpt_net.core.types import MODE_LLAMA_INDEX, MODE_CHAT
|
|
15
17
|
from pygpt_net.item.model import ModelItem
|
|
18
|
+
from pygpt_net.utils import trans
|
|
16
19
|
|
|
17
20
|
from .editor import Editor
|
|
18
21
|
from .importer import Importer
|
|
19
22
|
|
|
20
|
-
|
|
21
23
|
class Model:
|
|
22
24
|
def __init__(self, window=None):
|
|
23
25
|
"""
|
|
@@ -32,6 +34,63 @@ class Model:
|
|
|
32
34
|
def _ensure_current_model_map(self):
|
|
33
35
|
return self.window.core.config.data.setdefault('current_model', {})
|
|
34
36
|
|
|
37
|
+
def handle(self, event: BaseEvent):
|
|
38
|
+
"""
|
|
39
|
+
Handle events
|
|
40
|
+
|
|
41
|
+
:param event: BaseEvent: Event to handle
|
|
42
|
+
"""
|
|
43
|
+
name = event.name
|
|
44
|
+
mode = self.window.core.config.get("mode")
|
|
45
|
+
|
|
46
|
+
# on input begin
|
|
47
|
+
if name == Event.INPUT_BEGIN:
|
|
48
|
+
force = event.data.get("force", False)
|
|
49
|
+
stop = event.data.get("stop", False)
|
|
50
|
+
if not force and not stop:
|
|
51
|
+
# check ollama model
|
|
52
|
+
model = self.window.core.config.get('model')
|
|
53
|
+
if model:
|
|
54
|
+
model_data = self.window.core.models.get(model)
|
|
55
|
+
if model_data is not None and model_data.is_ollama():
|
|
56
|
+
if (mode == MODE_LLAMA_INDEX or
|
|
57
|
+
(
|
|
58
|
+
mode == MODE_CHAT and not model_data.is_openai_supported() and model_data.is_ollama()
|
|
59
|
+
)
|
|
60
|
+
):
|
|
61
|
+
model_id = model_data.get_ollama_model()
|
|
62
|
+
|
|
63
|
+
# load ENV vars first
|
|
64
|
+
if ('env' in model_data.llama_index
|
|
65
|
+
and model_data.llama_index['env'] is not None):
|
|
66
|
+
for item in model_data.llama_index['env']:
|
|
67
|
+
key = item.get('name', '').strip()
|
|
68
|
+
value = item.get('value', '').strip()
|
|
69
|
+
os.environ[key] = value
|
|
70
|
+
status = self.window.core.models.ollama.check_model(model_id)
|
|
71
|
+
is_installed = status.get('is_installed', False)
|
|
72
|
+
is_model = status.get('is_model', False)
|
|
73
|
+
if not is_installed:
|
|
74
|
+
event.data["stop"] = True # stop flow
|
|
75
|
+
self.window.ui.dialogs.alert(trans("dialog.ollama.not_installed"))
|
|
76
|
+
return
|
|
77
|
+
if not is_model:
|
|
78
|
+
event.data["stop"] = True # stop flow
|
|
79
|
+
self.window.ui.dialogs.alert(
|
|
80
|
+
trans("dialog.ollama.model_not_found").replace("{model}", model_id))
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
# on input before
|
|
84
|
+
elif name == Event.INPUT_BEFORE:
|
|
85
|
+
# check API key, show monit if no API key for current provider
|
|
86
|
+
model = self.window.core.config.get('model')
|
|
87
|
+
if model:
|
|
88
|
+
model_data = self.window.core.models.get(model)
|
|
89
|
+
if not self.window.controller.chat.common.check_api_key(mode=mode, model=model_data, monit=False):
|
|
90
|
+
self.window.controller.chat.common.check_api_key(mode=mode, model=model_data, monit=True)
|
|
91
|
+
event.data["stop"] = True # stop flow
|
|
92
|
+
return
|
|
93
|
+
|
|
35
94
|
def select(self, model: str):
|
|
36
95
|
"""
|
|
37
96
|
Select model
|
|
@@ -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: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.24 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import Optional, Tuple
|
|
@@ -20,8 +20,6 @@ from pygpt_net.ui.widget.tabs.body import TabBody
|
|
|
20
20
|
from pygpt_net.ui.widget.textarea.notepad import NotepadWidget
|
|
21
21
|
from pygpt_net.utils import trans
|
|
22
22
|
|
|
23
|
-
import pygpt_net.icons_rc
|
|
24
|
-
|
|
25
23
|
|
|
26
24
|
class Notepad:
|
|
27
25
|
def __init__(self, window=None):
|
|
@@ -32,8 +30,7 @@ class Notepad:
|
|
|
32
30
|
"""
|
|
33
31
|
self.window = window
|
|
34
32
|
self.opened_once = False
|
|
35
|
-
self.opened_idx =
|
|
36
|
-
|
|
33
|
+
self.opened_idx = set()
|
|
37
34
|
|
|
38
35
|
def get_next_suffix(self) -> int:
|
|
39
36
|
"""
|
|
@@ -41,13 +38,16 @@ class Notepad:
|
|
|
41
38
|
|
|
42
39
|
:return: next notepad suffix
|
|
43
40
|
"""
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
tabs_core = self.window.core.tabs
|
|
42
|
+
tabs = tabs_core.get_tabs_by_type(Tab.TAB_NOTEPAD)
|
|
43
|
+
idx = tabs_core.count_by_type(Tab.TAB_NOTEPAD)
|
|
44
|
+
for tab in tabs:
|
|
45
|
+
title = tab.title or ""
|
|
46
46
|
try:
|
|
47
|
-
num = int(
|
|
48
|
-
if num
|
|
47
|
+
num = int(title.rsplit(" ", 1)[-1])
|
|
48
|
+
if num > idx:
|
|
49
49
|
idx = num
|
|
50
|
-
except ValueError:
|
|
50
|
+
except (ValueError, IndexError):
|
|
51
51
|
continue
|
|
52
52
|
return idx + 1
|
|
53
53
|
|
|
@@ -58,12 +58,7 @@ class Notepad:
|
|
|
58
58
|
:return: next available notepad index
|
|
59
59
|
"""
|
|
60
60
|
tabs = self.window.core.tabs.get_tabs_by_type(Tab.TAB_NOTEPAD)
|
|
61
|
-
|
|
62
|
-
for tab in tabs:
|
|
63
|
-
if tab.data_id == idx:
|
|
64
|
-
opened = True
|
|
65
|
-
break
|
|
66
|
-
return opened
|
|
61
|
+
return any(tab.data_id == idx for tab in tabs)
|
|
67
62
|
|
|
68
63
|
def create(
|
|
69
64
|
self,
|
|
@@ -77,27 +72,30 @@ class Notepad:
|
|
|
77
72
|
:param tab: existing tab to use (optional)
|
|
78
73
|
:return: notepad widget (TabBody)
|
|
79
74
|
"""
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
else:
|
|
84
|
-
suffix = self.get_next_suffix()
|
|
75
|
+
tabs_core = self.window.core.tabs
|
|
76
|
+
existing_tabs = tabs_core.get_tabs_by_type(Tab.TAB_NOTEPAD)
|
|
77
|
+
used_ids = {t.data_id for t in existing_tabs}
|
|
85
78
|
|
|
86
|
-
|
|
79
|
+
if idx is None:
|
|
80
|
+
idx = 1
|
|
81
|
+
while idx in used_ids:
|
|
87
82
|
idx += 1
|
|
88
|
-
|
|
83
|
+
|
|
84
|
+
suffix = self.get_next_suffix()
|
|
89
85
|
|
|
90
86
|
data_id = idx
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
87
|
+
widget = NotepadWidget(self.window)
|
|
88
|
+
widget.id = idx
|
|
89
|
+
widget.textarea.id = idx
|
|
90
|
+
self.window.ui.notepad[data_id] = widget
|
|
91
|
+
|
|
92
|
+
title = trans('output.tab.notepad') + " " + str(suffix)
|
|
96
93
|
if tab:
|
|
97
94
|
if not tab.title:
|
|
98
95
|
tab.title = title
|
|
99
|
-
|
|
100
|
-
child
|
|
96
|
+
|
|
97
|
+
child = tabs_core.from_widget(widget)
|
|
98
|
+
child.on_delete = self.on_delete
|
|
101
99
|
return child, idx, data_id
|
|
102
100
|
|
|
103
101
|
def on_delete(self, body: TabBody):
|
|
@@ -115,6 +113,8 @@ class Notepad:
|
|
|
115
113
|
if idx in self.window.ui.notepad:
|
|
116
114
|
self.window.ui.notepad[idx].on_delete()
|
|
117
115
|
del self.window.ui.notepad[idx]
|
|
116
|
+
if idx in self.opened_idx:
|
|
117
|
+
self.opened_idx.discard(idx)
|
|
118
118
|
self.update()
|
|
119
119
|
|
|
120
120
|
def load(self):
|
|
@@ -130,9 +130,10 @@ class Notepad:
|
|
|
130
130
|
items[idx] = item
|
|
131
131
|
|
|
132
132
|
if num_notepads > 0:
|
|
133
|
-
for idx in items:
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
for idx, item in items.items():
|
|
134
|
+
widget = self.window.ui.notepad.get(idx)
|
|
135
|
+
if widget is not None:
|
|
136
|
+
widget.setText(item.content)
|
|
136
137
|
|
|
137
138
|
def get_notepad_name(self, idx: int):
|
|
138
139
|
"""
|
|
@@ -159,17 +160,19 @@ class Notepad:
|
|
|
159
160
|
|
|
160
161
|
:param idx: notepad idx
|
|
161
162
|
"""
|
|
162
|
-
|
|
163
|
+
core_notepad = self.window.core.notepad
|
|
164
|
+
item = core_notepad.get_by_id(idx)
|
|
163
165
|
if item is None:
|
|
164
166
|
item = NotepadItem()
|
|
165
167
|
item.idx = idx
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if
|
|
172
|
-
|
|
168
|
+
core_notepad.items[idx] = item
|
|
169
|
+
|
|
170
|
+
widget = self.window.ui.notepad.get(idx)
|
|
171
|
+
if widget is not None:
|
|
172
|
+
text = widget.toPlainText()
|
|
173
|
+
if item.content != text:
|
|
174
|
+
item.content = text
|
|
175
|
+
core_notepad.update(item)
|
|
173
176
|
self.update()
|
|
174
177
|
|
|
175
178
|
def save_all(self):
|
|
@@ -177,16 +180,18 @@ class Notepad:
|
|
|
177
180
|
items = self.window.core.notepad.get_all()
|
|
178
181
|
num_notepads = self.get_num_notepads()
|
|
179
182
|
if num_notepads > 0:
|
|
180
|
-
|
|
181
|
-
for tab in tabs:
|
|
183
|
+
ui_notepad = self.window.ui.notepad
|
|
184
|
+
for tab in self.window.core.tabs.get_tabs_by_type(Tab.TAB_NOTEPAD):
|
|
182
185
|
idx = tab.data_id
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
widget = ui_notepad.get(idx)
|
|
187
|
+
if widget is None:
|
|
188
|
+
continue
|
|
189
|
+
if idx in items:
|
|
190
|
+
prev_content = str(items[idx].content)
|
|
191
|
+
text = widget.toPlainText()
|
|
192
|
+
if prev_content != text:
|
|
193
|
+
items[idx].content = text
|
|
194
|
+
self.window.core.notepad.update(items[idx])
|
|
190
195
|
self.update()
|
|
191
196
|
|
|
192
197
|
def setup(self):
|
|
@@ -200,21 +205,19 @@ class Notepad:
|
|
|
200
205
|
:param text: text to append
|
|
201
206
|
:param idx: notepad idx
|
|
202
207
|
"""
|
|
203
|
-
|
|
208
|
+
widget = self.window.ui.notepad.get(idx)
|
|
209
|
+
if widget is None:
|
|
204
210
|
return
|
|
205
|
-
dt = ""
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
new_text = prev_text + dt + text.strip()
|
|
211
|
-
self.window.ui.notepad[idx].setText(new_text)
|
|
212
|
-
self.save(idx)
|
|
213
|
-
|
|
214
|
-
# move cursor to end
|
|
215
|
-
cursor = self.window.ui.notepad[idx].textarea.textCursor()
|
|
211
|
+
dt = ""
|
|
212
|
+
prev_text = widget.toPlainText()
|
|
213
|
+
need_nl = prev_text.strip() != ""
|
|
214
|
+
textarea = widget.textarea
|
|
215
|
+
cursor = textarea.textCursor()
|
|
216
216
|
cursor.movePosition(QTextCursor.End)
|
|
217
|
-
|
|
217
|
+
to_insert = (("\n" if need_nl else "") + dt + text.strip())
|
|
218
|
+
cursor.insertText(to_insert)
|
|
219
|
+
textarea.setTextCursor(cursor)
|
|
220
|
+
self.save(idx)
|
|
218
221
|
|
|
219
222
|
def get_num_notepads(self) -> int:
|
|
220
223
|
"""
|
|
@@ -230,8 +233,9 @@ class Notepad:
|
|
|
230
233
|
|
|
231
234
|
:return: current notepad index
|
|
232
235
|
"""
|
|
236
|
+
tabs_ctrl = self.window.controller.ui.tabs
|
|
233
237
|
if self.is_active():
|
|
234
|
-
tab =
|
|
238
|
+
tab = tabs_ctrl.get_current_tab()
|
|
235
239
|
if tab is not None:
|
|
236
240
|
return tab.data_id
|
|
237
241
|
return 1
|
|
@@ -246,17 +250,14 @@ class Notepad:
|
|
|
246
250
|
|
|
247
251
|
def open(self):
|
|
248
252
|
"""Open notepad"""
|
|
249
|
-
# if notepad disabled, do nothing
|
|
250
253
|
if self.get_num_notepads() == 0:
|
|
251
254
|
return
|
|
252
|
-
|
|
253
|
-
# switch to first notepad tab if current tab is not notepad
|
|
254
|
-
tabs = self.window.ui.layout.get_active_tabs()
|
|
255
255
|
if self.window.controller.ui.tabs.get_current_type() != Tab.TAB_NOTEPAD:
|
|
256
256
|
idx = self.window.core.tabs.get_min_idx_by_type(Tab.TAB_NOTEPAD)
|
|
257
257
|
if idx is not None:
|
|
258
|
+
tabs = self.window.ui.layout.get_active_tabs()
|
|
258
259
|
tabs.setCurrentIndex(idx)
|
|
259
|
-
self.window.activateWindow()
|
|
260
|
+
self.window.activateWindow()
|
|
260
261
|
|
|
261
262
|
def update(self):
|
|
262
263
|
"""Update notepads UI"""
|
|
@@ -299,9 +300,8 @@ class Notepad:
|
|
|
299
300
|
:return: current notepad text
|
|
300
301
|
"""
|
|
301
302
|
idx = self.get_current_active()
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
return ""
|
|
303
|
+
widget = self.window.ui.notepad.get(idx)
|
|
304
|
+
return widget.toPlainText() if widget is not None else ""
|
|
305
305
|
|
|
306
306
|
def get_notepad_text(self, idx: int) -> str:
|
|
307
307
|
"""
|
|
@@ -310,9 +310,8 @@ class Notepad:
|
|
|
310
310
|
:param idx: notepad index
|
|
311
311
|
:return: notepad text
|
|
312
312
|
"""
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
return ""
|
|
313
|
+
widget = self.window.ui.notepad.get(idx)
|
|
314
|
+
return widget.toPlainText() if widget is not None else ""
|
|
316
315
|
|
|
317
316
|
def clear(self, idx: int) -> bool:
|
|
318
317
|
"""
|
|
@@ -320,8 +319,9 @@ class Notepad:
|
|
|
320
319
|
|
|
321
320
|
:param idx: notepad idx
|
|
322
321
|
"""
|
|
323
|
-
|
|
324
|
-
|
|
322
|
+
widget = self.window.ui.notepad.get(idx)
|
|
323
|
+
if widget is not None:
|
|
324
|
+
widget.textarea.clear()
|
|
325
325
|
self.save(idx)
|
|
326
326
|
return True
|
|
327
327
|
return False
|
|
@@ -342,10 +342,12 @@ class Notepad:
|
|
|
342
342
|
return
|
|
343
343
|
if tab.type == Tab.TAB_NOTEPAD:
|
|
344
344
|
idx = tab.data_id
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
345
|
+
widget = self.window.ui.notepad.get(idx)
|
|
346
|
+
if widget is None:
|
|
347
|
+
return
|
|
348
|
+
if idx not in self.opened_idx:
|
|
349
|
+
QTimer.singleShot(0, widget.scroll_to_bottom)
|
|
350
|
+
if not widget.opened:
|
|
351
|
+
widget.opened = True
|
|
352
|
+
if idx not in self.opened_idx:
|
|
353
|
+
self.opened_idx.add(idx)
|
|
@@ -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: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.24 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from typing import Any
|
|
@@ -138,10 +138,9 @@ class Settings:
|
|
|
138
138
|
window.controller.plugins.presets.save_current()
|
|
139
139
|
window.core.config.save()
|
|
140
140
|
self.close()
|
|
141
|
-
window.update_status(trans('info.settings.saved'))
|
|
142
141
|
|
|
143
|
-
|
|
144
|
-
window.dispatch(
|
|
142
|
+
window.update_status(trans('info.settings.saved'))
|
|
143
|
+
window.dispatch(Event(Event.PLUGIN_SETTINGS_CHANGED))
|
|
145
144
|
window.controller.ui.update_tokens()
|
|
146
145
|
|
|
147
146
|
def close(self):
|
|
@@ -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: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.24 02:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import copy
|
|
@@ -67,7 +67,7 @@ class Editor:
|
|
|
67
67
|
self.window.ui.add_hook("update.config.notepad.num", self.hook_update)
|
|
68
68
|
self.window.ui.add_hook("update.config.render.code_syntax", self.hook_update)
|
|
69
69
|
self.window.ui.add_hook("update.config.theme.style", self.hook_update)
|
|
70
|
-
self.window.ui.add_hook("update.config.
|
|
70
|
+
self.window.ui.add_hook("update.config.agent.output.render.all", self.hook_update)
|
|
71
71
|
self.window.ui.add_hook("update.config.audio.input.backend", self.hook_update)
|
|
72
72
|
self.window.ui.add_hook("update.config.audio.output.backend", self.hook_update)
|
|
73
73
|
# self.window.ui.add_hook("llama.idx.storage", self.hook_update) # vector store update
|
|
@@ -204,7 +204,7 @@ class Editor:
|
|
|
204
204
|
if self.config_changed('ctx.sources') or self.config_changed('ctx.audio'):
|
|
205
205
|
self.window.controller.ctx.refresh()
|
|
206
206
|
|
|
207
|
-
if self.config_changed('
|
|
207
|
+
if self.config_changed('agent.output.render.all'):
|
|
208
208
|
self.window.controller.chat.render.reload()
|
|
209
209
|
|
|
210
210
|
# update global shortcuts
|
|
@@ -294,7 +294,7 @@ class Editor:
|
|
|
294
294
|
self.window.core.config.set(key, value)
|
|
295
295
|
self.window.controller.ctx.update()
|
|
296
296
|
|
|
297
|
-
elif key == "
|
|
297
|
+
elif key == "agent.output.render.all":
|
|
298
298
|
self.window.core.config.set(key, value)
|
|
299
299
|
self.window.controller.chat.render.reload()
|
|
300
300
|
|