pygpt-net 2.4.37__py3-none-any.whl → 2.4.39__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 +11 -0
- README.md +24 -5
- pygpt_net/CHANGELOG.txt +11 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/__init__.py +3 -1
- pygpt_net/controller/calendar/__init__.py +3 -1
- pygpt_net/controller/chat/render.py +8 -5
- pygpt_net/controller/config/placeholder.py +29 -0
- pygpt_net/controller/ctx/__init__.py +32 -24
- pygpt_net/controller/ctx/common.py +3 -2
- pygpt_net/controller/dialogs/confirm.py +2 -2
- pygpt_net/controller/lang/custom.py +2 -7
- pygpt_net/controller/lang/mapping.py +2 -2
- pygpt_net/controller/layout.py +2 -2
- pygpt_net/controller/notepad.py +8 -5
- pygpt_net/controller/settings/editor.py +6 -0
- pygpt_net/controller/theme/__init__.py +33 -8
- pygpt_net/controller/theme/common.py +22 -1
- pygpt_net/controller/theme/markdown.py +26 -14
- pygpt_net/controller/theme/menu.py +26 -5
- pygpt_net/controller/ui/tabs.py +201 -58
- pygpt_net/core/attachments/context.py +14 -12
- pygpt_net/core/audio/__init__.py +59 -1
- pygpt_net/core/ctx/__init__.py +11 -1
- pygpt_net/core/ctx/container.py +16 -9
- pygpt_net/core/ctx/output.py +86 -67
- pygpt_net/core/debug/tabs.py +3 -2
- pygpt_net/core/filesystem/__init__.py +5 -19
- pygpt_net/core/filesystem/url.py +7 -3
- pygpt_net/core/render/base.py +14 -3
- pygpt_net/core/render/markdown/renderer.py +3 -1
- pygpt_net/core/render/plain/renderer.py +3 -3
- pygpt_net/core/render/web/body.py +39 -17
- pygpt_net/core/render/web/renderer.py +7 -5
- pygpt_net/core/tabs/__init__.py +180 -71
- pygpt_net/core/tabs/tab.py +13 -4
- pygpt_net/data/config/config.json +14 -4
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/modes.json +3 -3
- pygpt_net/data/config/settings.json +55 -10
- pygpt_net/data/config/settings_section.json +3 -0
- pygpt_net/data/css/style.light.css +1 -0
- pygpt_net/data/css/{web.css → web-blocks.css} +144 -133
- pygpt_net/data/css/web-chatgpt.css +342 -0
- pygpt_net/data/css/web-chatgpt.dark.css +64 -0
- pygpt_net/data/css/web-chatgpt.light.css +75 -0
- pygpt_net/data/css/web-chatgpt_wide.css +342 -0
- pygpt_net/data/css/web-chatgpt_wide.dark.css +64 -0
- pygpt_net/data/css/web-chatgpt_wide.light.css +75 -0
- pygpt_net/data/locale/locale.de.ini +12 -0
- pygpt_net/data/locale/locale.en.ini +14 -1
- pygpt_net/data/locale/locale.es.ini +12 -0
- pygpt_net/data/locale/locale.fr.ini +12 -0
- pygpt_net/data/locale/locale.it.ini +12 -0
- pygpt_net/data/locale/locale.pl.ini +12 -0
- pygpt_net/data/locale/locale.uk.ini +12 -0
- pygpt_net/data/locale/locale.zh.ini +12 -0
- pygpt_net/plugin/audio_input/simple.py +21 -5
- pygpt_net/provider/core/config/patch.py +22 -1
- pygpt_net/provider/core/ctx/base.py +4 -1
- pygpt_net/provider/core/ctx/db_sqlite/__init__.py +10 -1
- pygpt_net/provider/core/ctx/db_sqlite/storage.py +22 -1
- pygpt_net/ui/layout/chat/input.py +10 -18
- pygpt_net/ui/layout/chat/output.py +26 -44
- pygpt_net/ui/layout/toolbox/footer.py +18 -2
- pygpt_net/ui/menu/config.py +7 -11
- pygpt_net/ui/menu/theme.py +9 -2
- pygpt_net/ui/widget/lists/context.py +1 -0
- pygpt_net/ui/widget/tabs/layout.py +195 -0
- pygpt_net/ui/widget/tabs/output.py +124 -35
- pygpt_net/ui/widget/textarea/html.py +11 -1
- pygpt_net/ui/widget/textarea/output.py +10 -1
- pygpt_net/ui/widget/textarea/search_input.py +4 -1
- pygpt_net/ui/widget/textarea/web.py +49 -9
- {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/METADATA +25 -6
- {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/RECORD +81 -74
- /pygpt_net/data/css/{web.dark.css → web-blocks.dark.css} +0 -0
- /pygpt_net/data/css/{web.light.css → web-blocks.light.css} +0 -0
- {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/LICENSE +0 -0
- {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/WHEEL +0 -0
- {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.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.
|
9
|
+
# Updated Date: 2024.11.30 04:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import copy
|
@@ -119,6 +119,8 @@ class Context:
|
|
119
119
|
if ("type" not in file
|
120
120
|
or file["type"] not in ["local_file", "url"]):
|
121
121
|
continue
|
122
|
+
if not "uuid" in file:
|
123
|
+
continue
|
122
124
|
file_id = file["uuid"]
|
123
125
|
file_idx_path = os.path.join(meta_path, file_id)
|
124
126
|
text_path = os.path.join(file_idx_path, file_id + ".txt")
|
@@ -555,17 +557,6 @@ class Context:
|
|
555
557
|
if meta is not None:
|
556
558
|
self.delete_index(meta)
|
557
559
|
|
558
|
-
def reset_by_meta_id(self, meta_id: int, delete_files: bool = False):
|
559
|
-
"""
|
560
|
-
Delete all attachments for meta by id
|
561
|
-
|
562
|
-
:param meta_id: Meta id
|
563
|
-
:param delete_files: delete files
|
564
|
-
"""
|
565
|
-
meta = self.window.core.ctx.get_meta_by_id(meta_id)
|
566
|
-
if meta is not None:
|
567
|
-
self.reset_by_meta(meta, delete_files)
|
568
|
-
|
569
560
|
def reset_by_meta(self, meta: CtxMeta, delete_files: bool = False):
|
570
561
|
"""
|
571
562
|
Delete all attachments for meta
|
@@ -578,6 +569,17 @@ class Context:
|
|
578
569
|
if delete_files:
|
579
570
|
self.delete_index(meta)
|
580
571
|
|
572
|
+
def reset_by_meta_id(self, meta_id: int, delete_files: bool = False):
|
573
|
+
"""
|
574
|
+
Delete all attachments for meta by id
|
575
|
+
|
576
|
+
:param meta_id: Meta id
|
577
|
+
:param delete_files: delete files
|
578
|
+
"""
|
579
|
+
meta = self.window.core.ctx.get_meta_by_id(meta_id)
|
580
|
+
if meta is not None:
|
581
|
+
self.reset_by_meta(meta, delete_files)
|
582
|
+
|
581
583
|
def clear(self, meta: CtxMeta, delete_files: bool = False):
|
582
584
|
"""
|
583
585
|
Clear all attachments by ctx meta
|
pygpt_net/core/audio/__init__.py
CHANGED
@@ -6,10 +6,11 @@
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
7
7
|
# MIT License #
|
8
8
|
# Created By : Marcin Szczygliński #
|
9
|
-
# Updated Date: 2024.
|
9
|
+
# Updated Date: 2024.12.08 00:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import re
|
13
|
+
from bs4 import UnicodeDammit
|
13
14
|
|
14
15
|
from pygpt_net.provider.audio_input.base import BaseProvider as InputBaseProvider
|
15
16
|
from pygpt_net.provider.audio_output.base import BaseProvider as OutputBaseProvider
|
@@ -27,6 +28,55 @@ class Audio:
|
|
27
28
|
"input": {},
|
28
29
|
"output": {},
|
29
30
|
}
|
31
|
+
self.last_error = None
|
32
|
+
|
33
|
+
def get_input_devices(self) -> list:
|
34
|
+
"""
|
35
|
+
Get input devices
|
36
|
+
|
37
|
+
:return devices list: [(id, name)]
|
38
|
+
"""
|
39
|
+
import pyaudio
|
40
|
+
devices = []
|
41
|
+
try:
|
42
|
+
p = pyaudio.PyAudio()
|
43
|
+
num_devices = p.get_device_count()
|
44
|
+
for i in range(num_devices):
|
45
|
+
info = p.get_device_info_by_index(i)
|
46
|
+
if info["maxInputChannels"] > 0:
|
47
|
+
dammit = UnicodeDammit(info["name"])
|
48
|
+
devices.append((i, dammit.unicode_markup))
|
49
|
+
# print(f"Device ID {i}: {info['name']}")
|
50
|
+
p.terminate()
|
51
|
+
except Exception as e:
|
52
|
+
print(f"Audio input devices receive error: {e}")
|
53
|
+
return devices
|
54
|
+
|
55
|
+
def is_device_compatible(self, device_index) -> bool:
|
56
|
+
"""
|
57
|
+
Check if device is compatible
|
58
|
+
|
59
|
+
:param device_index: device index
|
60
|
+
:return: True if compatible
|
61
|
+
"""
|
62
|
+
import pyaudio
|
63
|
+
rate = int(self.window.core.config.get('audio.input.rate', 44100))
|
64
|
+
channels = int(self.window.core.config.get('audio.input.channels', 1))
|
65
|
+
p = pyaudio.PyAudio()
|
66
|
+
info = p.get_device_info_by_index(device_index)
|
67
|
+
supported = False
|
68
|
+
try:
|
69
|
+
p.is_format_supported(
|
70
|
+
rate=rate,
|
71
|
+
input_device=info['index'],
|
72
|
+
input_channels=channels,
|
73
|
+
input_format=pyaudio.paInt16)
|
74
|
+
supported = True
|
75
|
+
except ValueError as e:
|
76
|
+
self.last_error = str(e)
|
77
|
+
supported = False
|
78
|
+
p.terminate()
|
79
|
+
return supported
|
30
80
|
|
31
81
|
def is_registered(self, id: str, type: str = "output") -> bool:
|
32
82
|
"""
|
@@ -92,3 +142,11 @@ class Audio:
|
|
92
142
|
:return: cleaned text
|
93
143
|
"""
|
94
144
|
return re.sub(r'~###~.*?~###~', '', str(text))
|
145
|
+
|
146
|
+
def get_last_error(self) -> str:
|
147
|
+
"""
|
148
|
+
Return last error
|
149
|
+
|
150
|
+
:return: Error
|
151
|
+
"""
|
152
|
+
return self.last_error
|
pygpt_net/core/ctx/__init__.py
CHANGED
@@ -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.
|
9
|
+
# Updated Date: 2024.12.09 00:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import copy
|
@@ -490,6 +490,16 @@ class Ctx:
|
|
490
490
|
for item in self.get_items():
|
491
491
|
if item.id == id:
|
492
492
|
return item
|
493
|
+
return self.fetch_item_by_id(id) # if no item found, try to fetch from DB
|
494
|
+
|
495
|
+
def fetch_item_by_id(self, id: int) -> CtxItem:
|
496
|
+
"""
|
497
|
+
Fetch ctx item by id
|
498
|
+
|
499
|
+
:param id: item id
|
500
|
+
:return: context item
|
501
|
+
"""
|
502
|
+
return self.provider.get_item_by_id(id)
|
493
503
|
|
494
504
|
def get_meta(self, reload: bool = False) -> dict:
|
495
505
|
"""
|
pygpt_net/core/ctx/container.py
CHANGED
@@ -6,39 +6,44 @@
|
|
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.
|
9
|
+
# Updated Date: 2024.12.09 00:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from PySide6.QtWidgets import QVBoxLayout
|
13
13
|
|
14
14
|
from .bag import Bag
|
15
15
|
from pygpt_net.ui.widget.textarea.output import ChatOutput
|
16
|
+
from ..tabs import Tab
|
16
17
|
|
17
18
|
|
18
19
|
class Container:
|
19
20
|
def __init__(self, window=None):
|
20
21
|
"""
|
21
|
-
Context container
|
22
|
+
Context output container
|
23
|
+
|
24
|
+
:param window: Window
|
22
25
|
"""
|
23
26
|
self.window = window
|
24
27
|
self.bags = {}
|
25
28
|
self.bags[0] = Bag(window) # always create initial bag
|
26
29
|
|
27
|
-
def
|
30
|
+
def get(self, tab: Tab):
|
28
31
|
"""
|
29
|
-
Register output
|
32
|
+
Register and return output
|
30
33
|
|
31
|
-
:param
|
34
|
+
:param tab: Tab
|
32
35
|
:return: Widget
|
33
36
|
"""
|
34
37
|
# plain output
|
35
38
|
output_plain = ChatOutput(self.window)
|
39
|
+
output_plain.set_tab(tab)
|
36
40
|
|
37
41
|
# web
|
38
42
|
if self.window.core.config.get("render.engine") == "web":
|
39
43
|
from pygpt_net.ui.widget.textarea.web import ChatWebOutput, CustomWebEnginePage
|
40
44
|
# build output
|
41
45
|
output_html = ChatWebOutput(self.window)
|
46
|
+
output_html.set_tab(tab)
|
42
47
|
output_html.setPage(
|
43
48
|
CustomWebEnginePage(self.window, output_html)
|
44
49
|
)
|
@@ -48,13 +53,15 @@ class Container:
|
|
48
53
|
else:
|
49
54
|
# legacy
|
50
55
|
output_html = ChatOutput(self.window)
|
56
|
+
output_html.set_tab(tab)
|
51
57
|
|
52
58
|
if 'output_plain' not in self.window.ui.nodes:
|
53
59
|
self.window.ui.nodes['output_plain'] = {}
|
54
60
|
if 'output' not in self.window.ui.nodes:
|
55
61
|
self.window.ui.nodes['output'] = {}
|
56
|
-
|
57
|
-
self.window.ui.nodes['
|
62
|
+
|
63
|
+
self.window.ui.nodes['output_plain'][tab.pid] = output_plain
|
64
|
+
self.window.ui.nodes['output'][tab.pid] = output_html
|
58
65
|
|
59
66
|
# show/hide plain/html
|
60
67
|
if self.window.core.config.get("render.plain") is True:
|
@@ -66,8 +73,8 @@ class Container:
|
|
66
73
|
|
67
74
|
# build layout
|
68
75
|
layout = QVBoxLayout()
|
69
|
-
layout.addWidget(self.window.ui.nodes['output_plain'][
|
70
|
-
layout.addWidget(self.window.ui.nodes['output'][
|
76
|
+
layout.addWidget(self.window.ui.nodes['output_plain'][tab.pid])
|
77
|
+
layout.addWidget(self.window.ui.nodes['output'][tab.pid])
|
71
78
|
layout.setContentsMargins(0, 0, 0, 0)
|
72
79
|
widget = self.window.core.tabs.from_layout(layout)
|
73
80
|
return widget
|
pygpt_net/core/ctx/output.py
CHANGED
@@ -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.
|
9
|
+
# Updated Date: 2024.12.09 03:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from pygpt_net.item.ctx import CtxItem, CtxMeta
|
@@ -16,11 +16,28 @@ class Output:
|
|
16
16
|
def __init__(self, window=None):
|
17
17
|
"""
|
18
18
|
Context output mapping
|
19
|
+
|
20
|
+
:param window: Window
|
19
21
|
"""
|
20
22
|
self.window = window
|
21
|
-
self.mapping = {} # pid => meta.id
|
23
|
+
self.mapping = {} # [column_idx => [pid => meta.id]]
|
22
24
|
self.last_pids = {} # meta.id => pid
|
23
25
|
self.last_pid = 0 # last used PID
|
26
|
+
self.initialized = False
|
27
|
+
|
28
|
+
def init(self, force: bool = False):
|
29
|
+
"""
|
30
|
+
Initialize mappings
|
31
|
+
|
32
|
+
:param force: Force reinitialize
|
33
|
+
"""
|
34
|
+
if self.initialized and not force:
|
35
|
+
return
|
36
|
+
self.clear()
|
37
|
+
for n in range(0, self.window.core.tabs.NUM_COLS):
|
38
|
+
self.mapping[n] = {}
|
39
|
+
self.last_pids[n] = {}
|
40
|
+
self.initialized = True
|
24
41
|
|
25
42
|
def store(self, meta: CtxMeta) -> int:
|
26
43
|
"""
|
@@ -29,31 +46,20 @@ class Output:
|
|
29
46
|
:param meta: Meta
|
30
47
|
:return: PID
|
31
48
|
"""
|
49
|
+
self.init()
|
32
50
|
pid = self.window.core.tabs.get_active_pid()
|
33
|
-
# check if allowed tab
|
34
51
|
tab = self.window.core.tabs.get_tab_by_pid(pid)
|
35
52
|
if tab is None or tab.type != Tab.TAB_CHAT:
|
36
53
|
return 0
|
37
|
-
|
38
|
-
self.
|
54
|
+
col_idx = tab.column_idx
|
55
|
+
self.mapping[col_idx][pid] = meta.id
|
56
|
+
self.last_pids[col_idx][meta.id] = pid
|
39
57
|
self.last_pid = pid
|
40
58
|
tab = self.window.core.tabs.get_tab_by_pid(pid)
|
41
59
|
if tab is not None:
|
42
60
|
tab.data_id = meta.id # store meta id in tab data
|
43
61
|
return pid
|
44
62
|
|
45
|
-
def meta_id_in_tab(self, meta_id: int) -> bool:
|
46
|
-
"""
|
47
|
-
Check if meta id is in tab
|
48
|
-
|
49
|
-
:param meta_id: Meta ID
|
50
|
-
:return: bool
|
51
|
-
"""
|
52
|
-
for pid, mid in self.mapping.items():
|
53
|
-
if mid == meta_id:
|
54
|
-
return True
|
55
|
-
return False
|
56
|
-
|
57
63
|
def is_mapped(self, meta: CtxMeta) -> bool:
|
58
64
|
"""
|
59
65
|
Check if meta is mapped
|
@@ -61,19 +67,46 @@ class Output:
|
|
61
67
|
:param meta: Meta
|
62
68
|
:return: bool
|
63
69
|
"""
|
64
|
-
|
70
|
+
self.init()
|
71
|
+
for col_idx in self.mapping:
|
72
|
+
if meta.id in self.mapping[col_idx].values():
|
73
|
+
return True
|
74
|
+
return False
|
65
75
|
|
66
|
-
def get_meta(self, pid: int) ->
|
76
|
+
def get_meta(self, pid: int) -> int or None:
|
67
77
|
"""
|
68
78
|
Get meta by PID
|
69
79
|
|
70
80
|
:param pid: PID
|
71
|
-
:return:
|
81
|
+
:return: meta ID or None
|
72
82
|
"""
|
73
|
-
|
74
|
-
|
83
|
+
self.init()
|
84
|
+
for col_idx in self.mapping:
|
85
|
+
if pid in self.mapping[col_idx]:
|
86
|
+
return self.mapping[col_idx][pid]
|
75
87
|
return
|
76
88
|
|
89
|
+
def prepare_meta(self, tab: Tab) -> int or None:
|
90
|
+
"""
|
91
|
+
Get meta ID by PID
|
92
|
+
|
93
|
+
:param tab: Tab
|
94
|
+
:return: Meta ID or None
|
95
|
+
"""
|
96
|
+
self.init()
|
97
|
+
pid = tab.pid
|
98
|
+
col_idx = tab.column_idx
|
99
|
+
meta_id = None
|
100
|
+
if pid in self.mapping[col_idx]:
|
101
|
+
return self.mapping[col_idx][pid]
|
102
|
+
if meta_id is None:
|
103
|
+
meta_id = tab.data_id
|
104
|
+
if meta_id is not None:
|
105
|
+
self.mapping[col_idx][pid] = meta_id
|
106
|
+
self.last_pids[col_idx][meta_id] = pid
|
107
|
+
self.last_pid = pid
|
108
|
+
return meta_id
|
109
|
+
|
77
110
|
def get_mapped(self, meta: CtxMeta) -> int or None:
|
78
111
|
"""
|
79
112
|
Get PID by meta
|
@@ -81,75 +114,59 @@ class Output:
|
|
81
114
|
:param meta: Meta
|
82
115
|
:return: PID or None
|
83
116
|
"""
|
117
|
+
self.init()
|
84
118
|
all = []
|
85
119
|
pid = None
|
86
120
|
active_pid = self.window.core.tabs.get_active_pid()
|
87
|
-
|
121
|
+
tab = self.window.core.tabs.get_tab_by_pid(active_pid)
|
122
|
+
if tab is None:
|
123
|
+
return None
|
124
|
+
col_idx = tab.column_idx
|
125
|
+
for pid, meta_id in self.mapping[col_idx].items():
|
88
126
|
if meta_id == meta.id:
|
89
127
|
all.append(pid)
|
90
128
|
for pid in all:
|
91
|
-
if pid == active_pid: # at first check
|
129
|
+
if pid == active_pid: # at first check for current tab
|
92
130
|
return pid
|
93
131
|
return pid
|
94
132
|
|
95
|
-
def get_mapped_last(self, meta: CtxMeta) -> int or None:
|
96
|
-
"""
|
97
|
-
Get last PID by meta
|
98
|
-
|
99
|
-
:param meta: Meta
|
100
|
-
:return: PID or None
|
101
|
-
"""
|
102
|
-
active_pid = self.window.core.tabs.get_active_pid()
|
103
|
-
if self.mapping[active_pid] == meta.id:
|
104
|
-
return active_pid # return active PID at first
|
105
|
-
if meta.id in self.last_pids:
|
106
|
-
return self.last_pids[meta.id]
|
107
|
-
return
|
108
|
-
|
109
|
-
def prepare(self, meta: CtxMeta):
|
110
|
-
"""
|
111
|
-
Clear mapping
|
112
|
-
|
113
|
-
:param meta: meta to prepare
|
114
|
-
"""
|
115
|
-
active_pid = self.window.core.tabs.get_active_pid()
|
116
|
-
if active_pid in self.mapping:
|
117
|
-
del self.mapping[active_pid] # remove from mapping
|
118
|
-
|
119
|
-
def clear(self):
|
120
|
-
"""
|
121
|
-
Clear mapping
|
122
|
-
"""
|
123
|
-
self.mapping = {}
|
124
|
-
self.last_pids = {}
|
125
|
-
self.last_pid = 0
|
126
|
-
|
127
133
|
def is_empty(self) -> bool:
|
128
134
|
"""
|
129
135
|
Check if mapping is empty
|
130
136
|
|
131
137
|
:return: bool
|
132
138
|
"""
|
139
|
+
self.init()
|
133
140
|
active_pid = self.window.core.tabs.get_active_pid()
|
134
|
-
|
135
|
-
|
141
|
+
for col_idx in list(self.mapping.keys()):
|
142
|
+
if active_pid in self.mapping[col_idx]:
|
143
|
+
return False
|
136
144
|
return True
|
137
145
|
|
138
|
-
def get_pid(self, meta: CtxMeta = None) -> int:
|
146
|
+
def get_pid(self, meta: CtxMeta = None) -> int or None:
|
139
147
|
"""
|
140
148
|
Get PID by meta
|
141
149
|
|
142
150
|
:param meta: Meta
|
143
151
|
:return: PID
|
144
152
|
"""
|
153
|
+
self.init()
|
154
|
+
active_pid = self.window.core.tabs.get_active_pid()
|
145
155
|
if meta is None:
|
146
|
-
return
|
156
|
+
return None
|
147
157
|
if self.is_mapped(meta):
|
148
|
-
if
|
149
|
-
return
|
150
|
-
|
151
|
-
|
152
|
-
|
158
|
+
if active_pid == self.get_mapped(meta): # if loaded in current tab
|
159
|
+
return active_pid # return current
|
160
|
+
return self.store(meta)
|
161
|
+
|
162
|
+
def clear(self):
|
163
|
+
"""
|
164
|
+
Clear mapping
|
165
|
+
"""
|
166
|
+
self.mapping = {}
|
167
|
+
self.last_pids = {}
|
168
|
+
self.last_pid = 0
|
169
|
+
self.initialized = False
|
153
170
|
|
154
171
|
def get_current(self, meta: CtxMeta = None):
|
155
172
|
"""
|
@@ -176,7 +193,8 @@ class Output:
|
|
176
193
|
if pid in self.window.ui.nodes['output_plain']:
|
177
194
|
return self.window.ui.nodes['output_plain'][pid]
|
178
195
|
else:
|
179
|
-
|
196
|
+
for pid in self.window.ui.nodes['output_plain']:
|
197
|
+
return self.window.ui.nodes['output_plain'][pid]
|
180
198
|
|
181
199
|
def get_by_pid(self, pid = None):
|
182
200
|
"""
|
@@ -201,7 +219,8 @@ class Output:
|
|
201
219
|
if pid in self.window.ui.nodes['output_plain']:
|
202
220
|
return self.window.ui.nodes['output_plain'][pid]
|
203
221
|
else:
|
204
|
-
|
222
|
+
for pid in self.window.ui.nodes['output_plain']:
|
223
|
+
return self.window.ui.nodes['output_plain'][pid]
|
205
224
|
|
206
225
|
def get_all(self) -> list:
|
207
226
|
"""
|
pygpt_net/core/debug/tabs.py
CHANGED
@@ -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.
|
9
|
+
# Updated Date: 2024.12.09 00:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
class TabsDebug:
|
@@ -25,6 +25,7 @@ class TabsDebug:
|
|
25
25
|
self.window.core.debug.add(self.id, 'current PID', str(self.window.controller.ui.tabs.get_current_pid()))
|
26
26
|
self.window.core.debug.add(self.id, 'current IDX', str(self.window.controller.ui.tabs.get_current_idx()))
|
27
27
|
self.window.core.debug.add(self.id, 'current Type', str(self.window.controller.ui.tabs.get_current_type()))
|
28
|
+
self.window.core.debug.add(self.id, 'current Column', str(self.window.controller.ui.tabs.get_current_column_idx()))
|
28
29
|
self.window.core.debug.add(self.id, 'last_pid', str(self.window.core.tabs.last_pid))
|
29
30
|
self.window.core.debug.add(self.id, 'count(pids)', str(len(self.window.core.tabs.pids)))
|
30
31
|
self.window.core.debug.add(self.id, 'count(ctx bags)', str(len(self.window.core.ctx.container.bags)))
|
@@ -38,6 +39,6 @@ class TabsDebug:
|
|
38
39
|
|
39
40
|
# mapping PID => meta.id
|
40
41
|
self.window.core.debug.add(self.id, 'PID => meta.id', str(self.window.core.ctx.output.mapping))
|
41
|
-
self.window.core.debug.add(self.id, '(last)
|
42
|
+
self.window.core.debug.add(self.id, '(last) meta.id => PID', str(self.window.core.ctx.output.last_pids))
|
42
43
|
self.window.core.debug.add(self.id, '(last) PID', str(self.window.core.ctx.output.last_pid))
|
43
44
|
self.window.core.debug.end(self.id)
|
@@ -6,13 +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.
|
9
|
+
# Updated Date: 2024.12.07 21:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import os
|
13
13
|
import shutil
|
14
14
|
|
15
|
-
from datetime import datetime
|
16
15
|
from pathlib import PurePath
|
17
16
|
from uuid import uuid4
|
18
17
|
|
@@ -38,18 +37,6 @@ class Filesystem:
|
|
38
37
|
self.types = Types(window)
|
39
38
|
self.url = Url(window)
|
40
39
|
self.workdir_placeholder = "%workdir%"
|
41
|
-
self.styles = [
|
42
|
-
"style.css",
|
43
|
-
"style.dark.css",
|
44
|
-
"style.light.css",
|
45
|
-
"markdown.css",
|
46
|
-
"markdown.dark.css",
|
47
|
-
"markdown.light.css",
|
48
|
-
"web.css",
|
49
|
-
"web.dark.css",
|
50
|
-
"web.light.css",
|
51
|
-
"fix_windows.css",
|
52
|
-
]
|
53
40
|
|
54
41
|
def install(self):
|
55
42
|
"""Install provider data"""
|
@@ -77,9 +64,9 @@ class Filesystem:
|
|
77
64
|
|
78
65
|
src_dir = os.path.join(self.window.core.config.get_app_path(), 'data', 'css')
|
79
66
|
dst_dir = os.path.join(self.window.core.config.path, 'css')
|
80
|
-
|
67
|
+
app_styles = os.listdir(src_dir)
|
81
68
|
try:
|
82
|
-
for style in
|
69
|
+
for style in app_styles:
|
83
70
|
src = os.path.join(src_dir, style)
|
84
71
|
dst = os.path.join(dst_dir, style)
|
85
72
|
if (not os.path.exists(dst) or force) and os.path.exists(src):
|
@@ -91,7 +78,8 @@ class Filesystem:
|
|
91
78
|
"""Backup user custom css styles"""
|
92
79
|
css_dir = os.path.join(self.window.core.config.path, 'css')
|
93
80
|
backup_file_extension = '.backup'
|
94
|
-
|
81
|
+
user_styles = os.listdir(css_dir)
|
82
|
+
for style in user_styles:
|
95
83
|
src = os.path.join(css_dir, style)
|
96
84
|
dst = os.path.join(css_dir, style + backup_file_extension)
|
97
85
|
if os.path.exists(src):
|
@@ -457,5 +445,3 @@ class Filesystem:
|
|
457
445
|
else:
|
458
446
|
files = [os.path.join(path, f) for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]
|
459
447
|
return files
|
460
|
-
|
461
|
-
|
pygpt_net/core/filesystem/url.py
CHANGED
@@ -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.
|
9
|
+
# Updated Date: 2024.12.09 03:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from PySide6.QtCore import QUrl
|
@@ -38,14 +38,18 @@ class Url:
|
|
38
38
|
]
|
39
39
|
|
40
40
|
# JS bridge
|
41
|
-
if url.toString()
|
42
|
-
pid =
|
41
|
+
if url.toString().startswith('bridge://open_find'):
|
42
|
+
pid = int(url.toString().split(':')[2])
|
43
43
|
if pid in self.window.ui.nodes['output']:
|
44
44
|
self.window.ui.nodes['output'][pid].find_open()
|
45
45
|
return
|
46
46
|
elif url.toString() == 'bridge://escape':
|
47
47
|
self.window.controller.access.on_escape()
|
48
48
|
return
|
49
|
+
elif url.toString() == 'bridge://focus':
|
50
|
+
pid = self.window.controller.ui.tabs.get_current_pid()
|
51
|
+
if pid in self.window.ui.nodes['output']:
|
52
|
+
self.window.ui.nodes['output'][pid].on_focus_js()
|
49
53
|
|
50
54
|
# -------------
|
51
55
|
|
pygpt_net/core/render/base.py
CHANGED
@@ -6,9 +6,10 @@
|
|
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.
|
9
|
+
# Updated Date: 2024.12.09 00:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
|
+
from pygpt_net.core.tabs import Tab
|
12
13
|
from pygpt_net.item.ctx import CtxItem, CtxMeta
|
13
14
|
|
14
15
|
|
@@ -20,6 +21,15 @@ class BaseRenderer:
|
|
20
21
|
:param window: Window instance
|
21
22
|
"""
|
22
23
|
self.window = window
|
24
|
+
self.tab = None
|
25
|
+
|
26
|
+
def set_tab(self, tab: Tab):
|
27
|
+
"""
|
28
|
+
Append tab
|
29
|
+
|
30
|
+
:param tab: Tab
|
31
|
+
"""
|
32
|
+
self.tab = tab
|
23
33
|
|
24
34
|
def prepare(self):
|
25
35
|
"""
|
@@ -218,13 +228,14 @@ class BaseRenderer:
|
|
218
228
|
"""
|
219
229
|
pass
|
220
230
|
|
221
|
-
def on_page_loaded(self, meta: CtxMeta = None):
|
231
|
+
def on_page_loaded(self, meta: CtxMeta = None, tab: Tab = None):
|
222
232
|
"""
|
223
233
|
On page loaded callback
|
224
234
|
|
225
235
|
:param meta: context meta
|
236
|
+
:param tab: Tab
|
226
237
|
"""
|
227
|
-
|
238
|
+
self.tab = tab
|
228
239
|
|
229
240
|
def on_enable_edit(self, live: bool = True):
|
230
241
|
"""
|
@@ -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.
|
9
|
+
# Updated Date: 2024.12.09 00:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import re
|
@@ -50,6 +50,8 @@ class Renderer(BaseRenderer):
|
|
50
50
|
|
51
51
|
:param meta: context PID
|
52
52
|
"""
|
53
|
+
if self.tab is not None:
|
54
|
+
return self.tab.pid # get PID from tab if exists
|
53
55
|
return self.window.core.ctx.output.get_pid(meta)
|
54
56
|
|
55
57
|
def get_or_create_pid(self, meta: CtxMeta):
|