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.
Files changed (102) hide show
  1. pygpt_net/CHANGELOG.txt +9 -0
  2. pygpt_net/LICENSE +1 -1
  3. pygpt_net/__init__.py +3 -3
  4. pygpt_net/config.py +15 -1
  5. pygpt_net/controller/chat/common.py +5 -4
  6. pygpt_net/controller/chat/image.py +3 -3
  7. pygpt_net/controller/chat/stream.py +76 -41
  8. pygpt_net/controller/chat/stream_worker.py +3 -3
  9. pygpt_net/controller/ctx/extra.py +3 -1
  10. pygpt_net/controller/dialogs/debug.py +37 -8
  11. pygpt_net/controller/kernel/kernel.py +3 -7
  12. pygpt_net/controller/lang/custom.py +25 -12
  13. pygpt_net/controller/lang/lang.py +45 -3
  14. pygpt_net/controller/lang/mapping.py +15 -2
  15. pygpt_net/controller/notepad/notepad.py +68 -25
  16. pygpt_net/controller/presets/editor.py +5 -1
  17. pygpt_net/controller/presets/presets.py +17 -5
  18. pygpt_net/controller/theme/theme.py +11 -2
  19. pygpt_net/controller/ui/tabs.py +1 -1
  20. pygpt_net/core/ctx/output.py +38 -12
  21. pygpt_net/core/db/database.py +4 -2
  22. pygpt_net/core/debug/console/console.py +30 -2
  23. pygpt_net/core/debug/context.py +2 -1
  24. pygpt_net/core/debug/ui.py +26 -4
  25. pygpt_net/core/filesystem/filesystem.py +6 -2
  26. pygpt_net/core/notepad/notepad.py +2 -2
  27. pygpt_net/core/tabs/tabs.py +79 -19
  28. pygpt_net/data/config/config.json +3 -3
  29. pygpt_net/data/config/models.json +3 -3
  30. pygpt_net/data/config/settings.json +12 -0
  31. pygpt_net/data/locale/locale.ar.ini +1833 -0
  32. pygpt_net/data/locale/locale.bg.ini +1833 -0
  33. pygpt_net/data/locale/locale.cs.ini +1833 -0
  34. pygpt_net/data/locale/locale.da.ini +1833 -0
  35. pygpt_net/data/locale/locale.de.ini +4 -1
  36. pygpt_net/data/locale/locale.en.ini +70 -67
  37. pygpt_net/data/locale/locale.es.ini +4 -1
  38. pygpt_net/data/locale/locale.fi.ini +1833 -0
  39. pygpt_net/data/locale/locale.fr.ini +4 -1
  40. pygpt_net/data/locale/locale.he.ini +1833 -0
  41. pygpt_net/data/locale/locale.hi.ini +1833 -0
  42. pygpt_net/data/locale/locale.hu.ini +1833 -0
  43. pygpt_net/data/locale/locale.it.ini +4 -1
  44. pygpt_net/data/locale/locale.ja.ini +1833 -0
  45. pygpt_net/data/locale/locale.ko.ini +1833 -0
  46. pygpt_net/data/locale/locale.nl.ini +1833 -0
  47. pygpt_net/data/locale/locale.no.ini +1833 -0
  48. pygpt_net/data/locale/locale.pl.ini +5 -2
  49. pygpt_net/data/locale/locale.pt.ini +1833 -0
  50. pygpt_net/data/locale/locale.ro.ini +1833 -0
  51. pygpt_net/data/locale/locale.ru.ini +1833 -0
  52. pygpt_net/data/locale/locale.sk.ini +1833 -0
  53. pygpt_net/data/locale/locale.sv.ini +1833 -0
  54. pygpt_net/data/locale/locale.tr.ini +1833 -0
  55. pygpt_net/data/locale/locale.uk.ini +4 -1
  56. pygpt_net/data/locale/locale.zh.ini +4 -1
  57. pygpt_net/item/notepad.py +8 -2
  58. pygpt_net/migrations/Version20260121190000.py +25 -0
  59. pygpt_net/migrations/Version20260122140000.py +25 -0
  60. pygpt_net/migrations/__init__.py +5 -1
  61. pygpt_net/preload.py +246 -3
  62. pygpt_net/provider/api/__init__.py +16 -2
  63. pygpt_net/provider/api/anthropic/__init__.py +21 -7
  64. pygpt_net/provider/api/google/__init__.py +21 -7
  65. pygpt_net/provider/api/google/image.py +89 -2
  66. pygpt_net/provider/api/google/video.py +2 -2
  67. pygpt_net/provider/api/openai/__init__.py +26 -11
  68. pygpt_net/provider/api/openai/image.py +79 -3
  69. pygpt_net/provider/api/openai/responses.py +11 -31
  70. pygpt_net/provider/api/openai/video.py +2 -2
  71. pygpt_net/provider/api/x_ai/__init__.py +21 -7
  72. pygpt_net/provider/core/notepad/db_sqlite/storage.py +53 -10
  73. pygpt_net/tools/agent_builder/ui/dialogs.py +2 -1
  74. pygpt_net/tools/audio_transcriber/ui/dialogs.py +2 -1
  75. pygpt_net/tools/code_interpreter/ui/dialogs.py +2 -1
  76. pygpt_net/tools/html_canvas/ui/dialogs.py +2 -1
  77. pygpt_net/tools/image_viewer/ui/dialogs.py +3 -5
  78. pygpt_net/tools/indexer/ui/dialogs.py +2 -1
  79. pygpt_net/tools/media_player/ui/dialogs.py +2 -1
  80. pygpt_net/tools/translator/ui/dialogs.py +2 -1
  81. pygpt_net/tools/translator/ui/widgets.py +6 -2
  82. pygpt_net/ui/dialog/about.py +2 -2
  83. pygpt_net/ui/dialog/db.py +2 -1
  84. pygpt_net/ui/dialog/debug.py +169 -6
  85. pygpt_net/ui/dialog/logger.py +6 -2
  86. pygpt_net/ui/dialog/models.py +36 -3
  87. pygpt_net/ui/dialog/preset.py +5 -1
  88. pygpt_net/ui/dialog/remote_store.py +2 -1
  89. pygpt_net/ui/main.py +3 -2
  90. pygpt_net/ui/widget/dialog/editor_file.py +2 -1
  91. pygpt_net/ui/widget/lists/debug.py +12 -7
  92. pygpt_net/ui/widget/option/checkbox.py +2 -8
  93. pygpt_net/ui/widget/option/combo.py +10 -2
  94. pygpt_net/ui/widget/textarea/console.py +156 -7
  95. pygpt_net/ui/widget/textarea/highlight.py +66 -0
  96. pygpt_net/ui/widget/textarea/input.py +624 -57
  97. pygpt_net/ui/widget/textarea/notepad.py +294 -27
  98. {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.dist-info}/LICENSE +1 -1
  99. {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.dist-info}/METADATA +11 -64
  100. {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.dist-info}/RECORD +102 -81
  101. {pygpt_net-2.7.9.dist-info → pygpt_net-2.7.10.dist-info}/WHEEL +0 -0
  102. {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: 2025.08.24 23:00:00 #
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 15:00:00 #
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: 2025.08.11 18:00:00 #
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
- handled = False
35
- if event.key() in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
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
- if not handled:
40
- super(ConsoleInput, self).keyPressEvent(event)
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)