pygpt-net 2.7.9__py3-none-any.whl → 2.7.10__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 +9 -0
- pygpt_net/LICENSE +1 -1
- pygpt_net/__init__.py +3 -3
- pygpt_net/config.py +15 -1
- pygpt_net/controller/chat/common.py +5 -4
- pygpt_net/controller/chat/image.py +3 -3
- pygpt_net/controller/chat/stream.py +76 -41
- pygpt_net/controller/chat/stream_worker.py +3 -3
- pygpt_net/controller/ctx/extra.py +3 -1
- pygpt_net/controller/dialogs/debug.py +37 -8
- pygpt_net/controller/kernel/kernel.py +3 -7
- pygpt_net/controller/lang/custom.py +25 -12
- pygpt_net/controller/lang/lang.py +45 -3
- pygpt_net/controller/lang/mapping.py +15 -2
- pygpt_net/controller/notepad/notepad.py +68 -25
- pygpt_net/controller/presets/editor.py +5 -1
- pygpt_net/controller/presets/presets.py +17 -5
- pygpt_net/controller/theme/theme.py +11 -2
- pygpt_net/controller/ui/tabs.py +1 -1
- pygpt_net/core/ctx/output.py +38 -12
- pygpt_net/core/db/database.py +4 -2
- pygpt_net/core/debug/console/console.py +30 -2
- pygpt_net/core/debug/context.py +2 -1
- pygpt_net/core/debug/ui.py +26 -4
- pygpt_net/core/filesystem/filesystem.py +6 -2
- pygpt_net/core/notepad/notepad.py +2 -2
- pygpt_net/core/tabs/tabs.py +79 -19
- pygpt_net/data/config/config.json +3 -3
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/settings.json +12 -0
- pygpt_net/data/locale/locale.ar.ini +1833 -0
- pygpt_net/data/locale/locale.bg.ini +1833 -0
- pygpt_net/data/locale/locale.cs.ini +1833 -0
- pygpt_net/data/locale/locale.da.ini +1833 -0
- pygpt_net/data/locale/locale.de.ini +4 -1
- pygpt_net/data/locale/locale.en.ini +70 -67
- pygpt_net/data/locale/locale.es.ini +4 -1
- pygpt_net/data/locale/locale.fi.ini +1833 -0
- pygpt_net/data/locale/locale.fr.ini +4 -1
- pygpt_net/data/locale/locale.he.ini +1833 -0
- pygpt_net/data/locale/locale.hi.ini +1833 -0
- pygpt_net/data/locale/locale.hu.ini +1833 -0
- pygpt_net/data/locale/locale.it.ini +4 -1
- pygpt_net/data/locale/locale.ja.ini +1833 -0
- pygpt_net/data/locale/locale.ko.ini +1833 -0
- pygpt_net/data/locale/locale.nl.ini +1833 -0
- pygpt_net/data/locale/locale.no.ini +1833 -0
- pygpt_net/data/locale/locale.pl.ini +5 -2
- pygpt_net/data/locale/locale.pt.ini +1833 -0
- pygpt_net/data/locale/locale.ro.ini +1833 -0
- pygpt_net/data/locale/locale.ru.ini +1833 -0
- pygpt_net/data/locale/locale.sk.ini +1833 -0
- pygpt_net/data/locale/locale.sv.ini +1833 -0
- pygpt_net/data/locale/locale.tr.ini +1833 -0
- pygpt_net/data/locale/locale.uk.ini +4 -1
- pygpt_net/data/locale/locale.zh.ini +4 -1
- pygpt_net/item/notepad.py +8 -2
- pygpt_net/migrations/Version20260121190000.py +25 -0
- pygpt_net/migrations/Version20260122140000.py +25 -0
- pygpt_net/migrations/__init__.py +5 -1
- pygpt_net/preload.py +246 -3
- pygpt_net/provider/api/__init__.py +16 -2
- pygpt_net/provider/api/anthropic/__init__.py +21 -7
- pygpt_net/provider/api/google/__init__.py +21 -7
- pygpt_net/provider/api/google/image.py +89 -2
- pygpt_net/provider/api/google/video.py +2 -2
- pygpt_net/provider/api/openai/__init__.py +26 -11
- pygpt_net/provider/api/openai/image.py +79 -3
- pygpt_net/provider/api/openai/responses.py +11 -31
- pygpt_net/provider/api/openai/video.py +2 -2
- pygpt_net/provider/api/x_ai/__init__.py +21 -7
- pygpt_net/provider/core/notepad/db_sqlite/storage.py +53 -10
- pygpt_net/tools/agent_builder/ui/dialogs.py +2 -1
- pygpt_net/tools/audio_transcriber/ui/dialogs.py +2 -1
- pygpt_net/tools/code_interpreter/ui/dialogs.py +2 -1
- pygpt_net/tools/html_canvas/ui/dialogs.py +2 -1
- pygpt_net/tools/image_viewer/ui/dialogs.py +3 -5
- pygpt_net/tools/indexer/ui/dialogs.py +2 -1
- pygpt_net/tools/media_player/ui/dialogs.py +2 -1
- pygpt_net/tools/translator/ui/dialogs.py +2 -1
- pygpt_net/tools/translator/ui/widgets.py +6 -2
- pygpt_net/ui/dialog/about.py +2 -2
- pygpt_net/ui/dialog/db.py +2 -1
- pygpt_net/ui/dialog/debug.py +169 -6
- pygpt_net/ui/dialog/logger.py +6 -2
- pygpt_net/ui/dialog/models.py +36 -3
- pygpt_net/ui/dialog/preset.py +5 -1
- pygpt_net/ui/dialog/remote_store.py +2 -1
- pygpt_net/ui/main.py +3 -2
- pygpt_net/ui/widget/dialog/editor_file.py +2 -1
- pygpt_net/ui/widget/lists/debug.py +12 -7
- pygpt_net/ui/widget/option/checkbox.py +2 -8
- pygpt_net/ui/widget/option/combo.py +10 -2
- pygpt_net/ui/widget/textarea/console.py +156 -7
- pygpt_net/ui/widget/textarea/highlight.py +66 -0
- pygpt_net/ui/widget/textarea/input.py +624 -57
- pygpt_net/ui/widget/textarea/notepad.py +294 -27
- {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.dist-info}/LICENSE +1 -1
- {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.dist-info}/METADATA +11 -64
- {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.dist-info}/RECORD +102 -81
- {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.dist-info}/WHEEL +0 -0
- {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.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:
|
|
9
|
+
# Updated Date: 2026.01.21 01:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtGui import QIcon
|
|
@@ -54,7 +54,6 @@ class OptionCheckbox(QWidget):
|
|
|
54
54
|
if "real_time" in self.option:
|
|
55
55
|
self.real_time = self.option["real_time"]
|
|
56
56
|
|
|
57
|
-
# self.box = QCheckBox(self.title, self.window)
|
|
58
57
|
self.box = AnimToggle('', self.window)
|
|
59
58
|
if self.value is not None:
|
|
60
59
|
self.box.setChecked(self.value)
|
|
@@ -77,17 +76,11 @@ class OptionCheckbox(QWidget):
|
|
|
77
76
|
ico.setPixmap(pixmap)
|
|
78
77
|
self.layout.addWidget(ico)
|
|
79
78
|
|
|
80
|
-
|
|
81
79
|
self.layout.addWidget(self.label)
|
|
82
80
|
self.layout.addStretch()
|
|
83
81
|
self.layout.setContentsMargins(0, 0, 0, 0)
|
|
84
82
|
self.setLayout(self.layout)
|
|
85
83
|
|
|
86
|
-
# self.layout = QHBoxLayout()
|
|
87
|
-
#self.layout.addWidget(self.box)
|
|
88
|
-
|
|
89
|
-
#self.setLayout(self.layout)
|
|
90
|
-
|
|
91
84
|
def trans_or_not(self, label: str):
|
|
92
85
|
"""
|
|
93
86
|
Translate label or return it as is if translation is not available
|
|
@@ -116,6 +109,7 @@ class OptionCheckbox(QWidget):
|
|
|
116
109
|
|
|
117
110
|
:param text: text
|
|
118
111
|
"""
|
|
112
|
+
self.title = text
|
|
119
113
|
self.label.setText(text)
|
|
120
114
|
|
|
121
115
|
def setChecked(self, state: bool):
|
|
@@ -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: 2026.01.01
|
|
9
|
+
# Updated Date: 2026.01.21 01:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
import sys
|
|
12
12
|
|
|
@@ -1649,4 +1649,12 @@ class OptionCombo(QWidget):
|
|
|
1649
1649
|
|
|
1650
1650
|
def fit_to_content(self):
|
|
1651
1651
|
"""Fit to content"""
|
|
1652
|
-
self.combo.setSizeAdjustPolicy(QComboBox.AdjustToContents)
|
|
1652
|
+
self.combo.setSizeAdjustPolicy(QComboBox.AdjustToContents)
|
|
1653
|
+
|
|
1654
|
+
def setText(self, title: str):
|
|
1655
|
+
"""
|
|
1656
|
+
Set label text
|
|
1657
|
+
|
|
1658
|
+
:param text: text
|
|
1659
|
+
"""
|
|
1660
|
+
self.title = title
|
|
@@ -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:
|
|
9
|
+
# Updated Date: 2026.01.20 21:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6 import QtCore
|
|
13
|
-
from PySide6.QtWidgets import QLineEdit
|
|
13
|
+
from PySide6.QtWidgets import QLineEdit, QApplication
|
|
14
|
+
|
|
14
15
|
|
|
15
16
|
class ConsoleInput(QLineEdit):
|
|
16
17
|
def __init__(self, window=None):
|
|
@@ -25,16 +26,164 @@ class ConsoleInput(QLineEdit):
|
|
|
25
26
|
self.setProperty('class', 'text-editor')
|
|
26
27
|
self.setFocus()
|
|
27
28
|
|
|
29
|
+
# command history storage
|
|
30
|
+
self._history = []
|
|
31
|
+
self._history_index = 0 # points to position after the last item
|
|
32
|
+
self._buffer_before_history = "" # stores current line when entering history navigation
|
|
33
|
+
self._in_history_mode = False
|
|
34
|
+
|
|
35
|
+
# supported commands for TAB auto-completion
|
|
36
|
+
self._commands = []
|
|
37
|
+
|
|
38
|
+
def set_commands(self, commands):
|
|
39
|
+
"""
|
|
40
|
+
Set supported commands for auto-completion.
|
|
41
|
+
|
|
42
|
+
:param commands: list of command strings
|
|
43
|
+
"""
|
|
44
|
+
if isinstance(commands, (list, tuple)):
|
|
45
|
+
self._commands = list(commands)
|
|
46
|
+
|
|
47
|
+
def add_to_history(self, cmd: str):
|
|
48
|
+
"""
|
|
49
|
+
Add command to history.
|
|
50
|
+
|
|
51
|
+
:param cmd: command string
|
|
52
|
+
"""
|
|
53
|
+
if not cmd:
|
|
54
|
+
return
|
|
55
|
+
# avoid adding the same command twice in a row
|
|
56
|
+
if len(self._history) == 0 or self._history[-1] != cmd:
|
|
57
|
+
self._history.append(cmd)
|
|
58
|
+
# reset navigation state
|
|
59
|
+
self._history_index = len(self._history)
|
|
60
|
+
self._in_history_mode = False
|
|
61
|
+
self._buffer_before_history = ""
|
|
62
|
+
|
|
63
|
+
def _history_prev(self):
|
|
64
|
+
"""Navigate to previous history item (Up)."""
|
|
65
|
+
if not self._history:
|
|
66
|
+
QApplication.beep()
|
|
67
|
+
return
|
|
68
|
+
if not self._in_history_mode:
|
|
69
|
+
self._buffer_before_history = self.text()
|
|
70
|
+
self._in_history_mode = True
|
|
71
|
+
if self._history_index > 0:
|
|
72
|
+
self._history_index -= 1
|
|
73
|
+
self.setText(self._history[self._history_index])
|
|
74
|
+
self.end(False)
|
|
75
|
+
else:
|
|
76
|
+
QApplication.beep()
|
|
77
|
+
|
|
78
|
+
def _history_next(self):
|
|
79
|
+
"""Navigate to next history item (Down)."""
|
|
80
|
+
if not self._history:
|
|
81
|
+
QApplication.beep()
|
|
82
|
+
return
|
|
83
|
+
if not self._in_history_mode:
|
|
84
|
+
QApplication.beep()
|
|
85
|
+
return
|
|
86
|
+
if self._history_index < len(self._history) - 1:
|
|
87
|
+
self._history_index += 1
|
|
88
|
+
self.setText(self._history[self._history_index])
|
|
89
|
+
self.end(False)
|
|
90
|
+
else:
|
|
91
|
+
# move past the last item: restore buffer and exit history mode
|
|
92
|
+
self._history_index = len(self._history)
|
|
93
|
+
self.setText(self._buffer_before_history)
|
|
94
|
+
self.end(False)
|
|
95
|
+
self._in_history_mode = False
|
|
96
|
+
self._buffer_before_history = ""
|
|
97
|
+
|
|
98
|
+
def _longest_common_prefix(self, strings):
|
|
99
|
+
"""Compute longest common prefix for a list of strings."""
|
|
100
|
+
if not strings:
|
|
101
|
+
return ""
|
|
102
|
+
s1 = min(strings)
|
|
103
|
+
s2 = max(strings)
|
|
104
|
+
for i, c in enumerate(s1):
|
|
105
|
+
if c != s2[i]:
|
|
106
|
+
return s1[:i]
|
|
107
|
+
return s1
|
|
108
|
+
|
|
109
|
+
def _try_autocomplete(self) -> bool:
|
|
110
|
+
"""
|
|
111
|
+
Try to auto-complete the current text based on supported commands.
|
|
112
|
+
|
|
113
|
+
:return: True if something was completed, False otherwise
|
|
114
|
+
"""
|
|
115
|
+
if not self._commands:
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
text = self.text()
|
|
119
|
+
# only complete first token; do not attempt when there is a space
|
|
120
|
+
if not text or " " in text.strip():
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
prefix = text.strip()
|
|
124
|
+
# case-insensitive matching, but insert canonical command form
|
|
125
|
+
matches = [cmd for cmd in self._commands if cmd.lower().startswith(prefix.lower())]
|
|
126
|
+
|
|
127
|
+
if len(matches) == 1:
|
|
128
|
+
self.setText(matches[0])
|
|
129
|
+
self.end(False)
|
|
130
|
+
return True
|
|
131
|
+
|
|
132
|
+
if len(matches) > 1:
|
|
133
|
+
# complete to the longest common prefix if it extends current prefix
|
|
134
|
+
lcp = self._longest_common_prefix(matches)
|
|
135
|
+
if len(lcp) > len(prefix):
|
|
136
|
+
self.setText(lcp)
|
|
137
|
+
self.end(False)
|
|
138
|
+
return True
|
|
139
|
+
|
|
140
|
+
return False
|
|
141
|
+
|
|
28
142
|
def keyPressEvent(self, event):
|
|
29
143
|
"""
|
|
30
144
|
Key press event
|
|
31
145
|
|
|
32
146
|
:param event: key event
|
|
33
147
|
"""
|
|
34
|
-
|
|
35
|
-
|
|
148
|
+
key = event.key()
|
|
149
|
+
|
|
150
|
+
# Enter/Return sends the command
|
|
151
|
+
if key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
|
|
36
152
|
self.window.core.debug.console.on_send()
|
|
37
|
-
handled = True
|
|
38
153
|
self.setFocus()
|
|
39
|
-
|
|
40
|
-
|
|
154
|
+
event.accept()
|
|
155
|
+
return
|
|
156
|
+
|
|
157
|
+
# Up/Down for history navigation
|
|
158
|
+
if key == QtCore.Qt.Key_Up:
|
|
159
|
+
self._history_prev()
|
|
160
|
+
event.accept()
|
|
161
|
+
return
|
|
162
|
+
|
|
163
|
+
if key == QtCore.Qt.Key_Down:
|
|
164
|
+
self._history_next()
|
|
165
|
+
event.accept()
|
|
166
|
+
return
|
|
167
|
+
|
|
168
|
+
# TAB or SHIFT+TAB for command auto-completion
|
|
169
|
+
if key in (QtCore.Qt.Key_Tab, QtCore.Qt.Key_Backtab):
|
|
170
|
+
completed = self._try_autocomplete()
|
|
171
|
+
if not completed:
|
|
172
|
+
QApplication.beep()
|
|
173
|
+
event.accept() # prevent focus traversal
|
|
174
|
+
return
|
|
175
|
+
|
|
176
|
+
# Any other key exits history navigation mode
|
|
177
|
+
if self._in_history_mode:
|
|
178
|
+
self._in_history_mode = False
|
|
179
|
+
self._history_index = len(self._history)
|
|
180
|
+
self._buffer_before_history = ""
|
|
181
|
+
|
|
182
|
+
super(ConsoleInput, self).keyPressEvent(event)
|
|
183
|
+
|
|
184
|
+
def focusNextPrevChild(self, next):
|
|
185
|
+
"""
|
|
186
|
+
Disable focus traversal with TAB for this widget.
|
|
187
|
+
This prevents Qt from moving focus to other widgets when TAB/SHIFT+TAB is pressed.
|
|
188
|
+
"""
|
|
189
|
+
return False
|
|
@@ -0,0 +1,66 @@
|
|
|
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: 2026.01.21 20:00:00 #
|
|
10
|
+
# ================================================== #
|
|
11
|
+
|
|
12
|
+
from PySide6.QtGui import (
|
|
13
|
+
QTextCharFormat,
|
|
14
|
+
QSyntaxHighlighter,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MarkerHighlighter(QSyntaxHighlighter):
|
|
19
|
+
def __init__(self, document, ranges_provider, colors_provider):
|
|
20
|
+
"""
|
|
21
|
+
Syntax highlighter for marking ranges.
|
|
22
|
+
|
|
23
|
+
:param document: QTextDocument
|
|
24
|
+
:param ranges_provider: callable returning list of (start, length)
|
|
25
|
+
:param colors_provider: callable returning (text_color: QColor|None, bg_color: QColor|None)
|
|
26
|
+
"""
|
|
27
|
+
super().__init__(document)
|
|
28
|
+
self._ranges_provider = ranges_provider
|
|
29
|
+
self._colors_provider = colors_provider
|
|
30
|
+
|
|
31
|
+
def set_colors_provider(self, colors_provider):
|
|
32
|
+
"""Set a new provider for highlight colors"""
|
|
33
|
+
self._colors_provider = colors_provider
|
|
34
|
+
self.rehighlight()
|
|
35
|
+
|
|
36
|
+
def highlightBlock(self, text: str):
|
|
37
|
+
"""Apply formatting to ranges intersecting current block"""
|
|
38
|
+
ranges = self._ranges_provider() or []
|
|
39
|
+
if not ranges:
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
text_color, bg_color = (None, None)
|
|
43
|
+
try:
|
|
44
|
+
text_color, bg_color = self._colors_provider()
|
|
45
|
+
except Exception:
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
fmt = QTextCharFormat()
|
|
49
|
+
if bg_color is not None:
|
|
50
|
+
fmt.setBackground(bg_color)
|
|
51
|
+
if text_color is not None:
|
|
52
|
+
fmt.setForeground(text_color)
|
|
53
|
+
|
|
54
|
+
block_start = self.currentBlock().position()
|
|
55
|
+
block_len = len(text)
|
|
56
|
+
for s, l in ranges:
|
|
57
|
+
if l <= 0:
|
|
58
|
+
continue
|
|
59
|
+
rel_start = s - block_start
|
|
60
|
+
rel_end = (s + l) - block_start
|
|
61
|
+
if rel_end <= 0 or rel_start >= block_len:
|
|
62
|
+
continue
|
|
63
|
+
rel_start = max(0, rel_start)
|
|
64
|
+
length = min(block_len - rel_start, rel_end - rel_start)
|
|
65
|
+
if length > 0:
|
|
66
|
+
self.setFormat(rel_start, length, fmt)
|