pygpt-net 2.7.8__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 (112) hide show
  1. pygpt_net/CHANGELOG.txt +14 -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/realtime/realtime.py +13 -1
  19. pygpt_net/controller/theme/theme.py +11 -2
  20. pygpt_net/controller/ui/tabs.py +1 -1
  21. pygpt_net/core/ctx/output.py +38 -12
  22. pygpt_net/core/db/database.py +4 -2
  23. pygpt_net/core/debug/console/console.py +30 -2
  24. pygpt_net/core/debug/context.py +2 -1
  25. pygpt_net/core/debug/ui.py +26 -4
  26. pygpt_net/core/filesystem/filesystem.py +6 -2
  27. pygpt_net/core/notepad/notepad.py +2 -2
  28. pygpt_net/core/tabs/tabs.py +79 -19
  29. pygpt_net/data/config/config.json +4 -3
  30. pygpt_net/data/config/models.json +37 -22
  31. pygpt_net/data/config/settings.json +12 -0
  32. pygpt_net/data/locale/locale.ar.ini +1833 -0
  33. pygpt_net/data/locale/locale.bg.ini +1833 -0
  34. pygpt_net/data/locale/locale.cs.ini +1833 -0
  35. pygpt_net/data/locale/locale.da.ini +1833 -0
  36. pygpt_net/data/locale/locale.de.ini +4 -1
  37. pygpt_net/data/locale/locale.en.ini +70 -67
  38. pygpt_net/data/locale/locale.es.ini +4 -1
  39. pygpt_net/data/locale/locale.fi.ini +1833 -0
  40. pygpt_net/data/locale/locale.fr.ini +4 -1
  41. pygpt_net/data/locale/locale.he.ini +1833 -0
  42. pygpt_net/data/locale/locale.hi.ini +1833 -0
  43. pygpt_net/data/locale/locale.hu.ini +1833 -0
  44. pygpt_net/data/locale/locale.it.ini +4 -1
  45. pygpt_net/data/locale/locale.ja.ini +1833 -0
  46. pygpt_net/data/locale/locale.ko.ini +1833 -0
  47. pygpt_net/data/locale/locale.nl.ini +1833 -0
  48. pygpt_net/data/locale/locale.no.ini +1833 -0
  49. pygpt_net/data/locale/locale.pl.ini +5 -2
  50. pygpt_net/data/locale/locale.pt.ini +1833 -0
  51. pygpt_net/data/locale/locale.ro.ini +1833 -0
  52. pygpt_net/data/locale/locale.ru.ini +1833 -0
  53. pygpt_net/data/locale/locale.sk.ini +1833 -0
  54. pygpt_net/data/locale/locale.sv.ini +1833 -0
  55. pygpt_net/data/locale/locale.tr.ini +1833 -0
  56. pygpt_net/data/locale/locale.uk.ini +4 -1
  57. pygpt_net/data/locale/locale.zh.ini +4 -1
  58. pygpt_net/item/notepad.py +8 -2
  59. pygpt_net/migrations/Version20260121190000.py +25 -0
  60. pygpt_net/migrations/Version20260122140000.py +25 -0
  61. pygpt_net/migrations/__init__.py +5 -1
  62. pygpt_net/preload.py +246 -3
  63. pygpt_net/provider/api/__init__.py +16 -2
  64. pygpt_net/provider/api/anthropic/__init__.py +21 -7
  65. pygpt_net/provider/api/google/__init__.py +21 -7
  66. pygpt_net/provider/api/google/image.py +89 -2
  67. pygpt_net/provider/api/google/realtime/client.py +70 -24
  68. pygpt_net/provider/api/google/realtime/realtime.py +48 -12
  69. pygpt_net/provider/api/google/video.py +2 -2
  70. pygpt_net/provider/api/openai/__init__.py +26 -11
  71. pygpt_net/provider/api/openai/image.py +79 -3
  72. pygpt_net/provider/api/openai/realtime/realtime.py +26 -6
  73. pygpt_net/provider/api/openai/responses.py +11 -31
  74. pygpt_net/provider/api/openai/video.py +2 -2
  75. pygpt_net/provider/api/x_ai/__init__.py +21 -10
  76. pygpt_net/provider/api/x_ai/realtime/client.py +185 -146
  77. pygpt_net/provider/api/x_ai/realtime/realtime.py +30 -15
  78. pygpt_net/provider/api/x_ai/remote_tools.py +83 -0
  79. pygpt_net/provider/api/x_ai/tools.py +51 -0
  80. pygpt_net/provider/core/config/patch.py +12 -1
  81. pygpt_net/provider/core/model/patch.py +36 -1
  82. pygpt_net/provider/core/notepad/db_sqlite/storage.py +53 -10
  83. pygpt_net/tools/agent_builder/ui/dialogs.py +2 -1
  84. pygpt_net/tools/audio_transcriber/ui/dialogs.py +2 -1
  85. pygpt_net/tools/code_interpreter/ui/dialogs.py +2 -1
  86. pygpt_net/tools/html_canvas/ui/dialogs.py +2 -1
  87. pygpt_net/tools/image_viewer/ui/dialogs.py +3 -5
  88. pygpt_net/tools/indexer/ui/dialogs.py +2 -1
  89. pygpt_net/tools/media_player/ui/dialogs.py +2 -1
  90. pygpt_net/tools/translator/ui/dialogs.py +2 -1
  91. pygpt_net/tools/translator/ui/widgets.py +6 -2
  92. pygpt_net/ui/dialog/about.py +2 -2
  93. pygpt_net/ui/dialog/db.py +2 -1
  94. pygpt_net/ui/dialog/debug.py +169 -6
  95. pygpt_net/ui/dialog/logger.py +6 -2
  96. pygpt_net/ui/dialog/models.py +36 -3
  97. pygpt_net/ui/dialog/preset.py +5 -1
  98. pygpt_net/ui/dialog/remote_store.py +2 -1
  99. pygpt_net/ui/main.py +3 -2
  100. pygpt_net/ui/widget/dialog/editor_file.py +2 -1
  101. pygpt_net/ui/widget/lists/debug.py +12 -7
  102. pygpt_net/ui/widget/option/checkbox.py +2 -8
  103. pygpt_net/ui/widget/option/combo.py +10 -2
  104. pygpt_net/ui/widget/textarea/console.py +156 -7
  105. pygpt_net/ui/widget/textarea/highlight.py +66 -0
  106. pygpt_net/ui/widget/textarea/input.py +624 -57
  107. pygpt_net/ui/widget/textarea/notepad.py +294 -27
  108. {pygpt_net-2.7.8.dist-info → pygpt_net-2.7.10.dist-info}/LICENSE +1 -1
  109. {pygpt_net-2.7.8.dist-info → pygpt_net-2.7.10.dist-info}/METADATA +16 -64
  110. {pygpt_net-2.7.8.dist-info → pygpt_net-2.7.10.dist-info}/RECORD +112 -91
  111. {pygpt_net-2.7.8.dist-info → pygpt_net-2.7.10.dist-info}/WHEEL +0 -0
  112. {pygpt_net-2.7.8.dist-info → pygpt_net-2.7.10.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: 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)