pygpt-net 2.4.50__py3-none-any.whl → 2.4.52__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 +12 -62
- pygpt_net/CHANGELOG.txt +11 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/audio/__init__.py +86 -1
- pygpt_net/controller/lang/custom.py +2 -1
- pygpt_net/controller/plugins/__init__.py +5 -30
- pygpt_net/controller/ui/tabs.py +14 -3
- pygpt_net/core/audio/capture.py +19 -1
- pygpt_net/data/config/config.json +5 -3
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/modes.json +3 -3
- pygpt_net/data/config/settings.json +13 -0
- pygpt_net/data/locale/locale.de.ini +3 -0
- pygpt_net/data/locale/locale.en.ini +3 -0
- pygpt_net/data/locale/locale.es.ini +3 -0
- pygpt_net/data/locale/locale.fr.ini +3 -0
- pygpt_net/data/locale/locale.it.ini +3 -0
- pygpt_net/data/locale/locale.pl.ini +3 -0
- pygpt_net/data/locale/locale.uk.ini +3 -0
- pygpt_net/data/locale/locale.zh.ini +3 -0
- pygpt_net/plugin/audio_input/simple.py +31 -8
- pygpt_net/plugin/cmd_files/worker.py +37 -1
- pygpt_net/provider/core/config/patch.py +9 -1
- pygpt_net/ui/__init__.py +4 -2
- pygpt_net/ui/layout/chat/input.py +0 -12
- pygpt_net/ui/menu/__init__.py +4 -3
- pygpt_net/ui/widget/audio/input_button.py +31 -23
- {pygpt_net-2.4.50.dist-info → pygpt_net-2.4.52.dist-info}/LICENSE +1 -1
- {pygpt_net-2.4.50.dist-info → pygpt_net-2.4.52.dist-info}/METADATA +13 -63
- {pygpt_net-2.4.50.dist-info → pygpt_net-2.4.52.dist-info}/RECORD +33 -33
- {pygpt_net-2.4.50.dist-info → pygpt_net-2.4.52.dist-info}/WHEEL +0 -0
- {pygpt_net-2.4.50.dist-info → pygpt_net-2.4.52.dist-info}/entry_points.txt +0 -0
@@ -136,6 +136,7 @@ audio.control.btn = 语音控制
|
|
136
136
|
audio.magic_word.detected = 檢測到魔法詞!
|
137
137
|
audio.magic_word.invalid= 不是魔法詞 :(
|
138
138
|
audio.magic_word.please= 請說出魔法詞...
|
139
|
+
audio.speak.btn.continuous = 连续录音
|
139
140
|
audio.speak.btn.stop = 停止
|
140
141
|
audio.speak.btn.stop.tooltip = 點擊停止麥克風聆聽
|
141
142
|
audio.speak.btn.tooltip = 點擊開始麥克風聆聽
|
@@ -875,6 +876,8 @@ settings.audio.input.device = 音频输入设备
|
|
875
876
|
settings.audio.input.device.desc = 选择用于麦克风输入的音频设备。
|
876
877
|
settings.audio.input.rate = 采样率
|
877
878
|
settings.audio.input.rate.desc = 采样率,默认: 44100
|
879
|
+
settings.audio.input.stop_interval = 连续录音自动转录间隔
|
880
|
+
settings.audio.input.stop_interval.desc = 自动转录音频片段的间隔(以秒为单位),默认:10
|
878
881
|
settings.check_updates = 啟動時檢查更新
|
879
882
|
settings.check_updates.bg = 在後台檢查更新
|
880
883
|
settings.cmd.field.desc = 启用 `{cmd}` 工具。
|
@@ -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.01.
|
9
|
+
# Updated Date: 2025.01.17 02:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import os
|
@@ -14,6 +14,7 @@ import os
|
|
14
14
|
from PySide6.QtCore import QTimer
|
15
15
|
|
16
16
|
from pygpt_net.core.events import AppEvent
|
17
|
+
from pygpt_net.core.tabs.tab import Tab
|
17
18
|
from pygpt_net.utils import trans
|
18
19
|
|
19
20
|
|
@@ -54,8 +55,20 @@ class Simple:
|
|
54
55
|
"""Stop timeout"""
|
55
56
|
self.stop_recording(timeout=True)
|
56
57
|
|
57
|
-
def start_recording(self):
|
58
|
-
"""
|
58
|
+
def start_recording(self, force: bool = False):
|
59
|
+
"""
|
60
|
+
Start recording
|
61
|
+
|
62
|
+
:param force: True to force recording
|
63
|
+
"""
|
64
|
+
# enable continuous mode if notepad tab is active
|
65
|
+
self.plugin.window.core.audio.capture.stop_callback = self.on_stop
|
66
|
+
continuous_enabled = self.plugin.window.core.config.get('audio.input.continuous', False)
|
67
|
+
if continuous_enabled and self.plugin.window.controller.ui.tabs.get_current_type() == Tab.TAB_NOTEPAD:
|
68
|
+
self.plugin.window.core.audio.capture.loop = True # set loop
|
69
|
+
else:
|
70
|
+
self.plugin.window.core.audio.capture.loop = False
|
71
|
+
|
59
72
|
try:
|
60
73
|
# stop audio output if playing
|
61
74
|
if self.plugin.window.controller.audio.is_playing():
|
@@ -72,11 +85,12 @@ class Simple:
|
|
72
85
|
self.timer.timeout.connect(self.stop_timeout)
|
73
86
|
self.timer.start(self.TIMEOUT_SECONDS * 1000)
|
74
87
|
|
75
|
-
if not
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
88
|
+
if not force:
|
89
|
+
if not self.plugin.window.core.audio.capture.check_audio_input():
|
90
|
+
raise Exception("Audio input not working.")
|
91
|
+
# IMPORTANT!!!!
|
92
|
+
# Stop here if audio input not working!
|
93
|
+
# This prevents the app from freezing when audio input is not working!
|
80
94
|
|
81
95
|
self.is_recording = True
|
82
96
|
self.switch_btn_stop()
|
@@ -128,3 +142,12 @@ class Simple:
|
|
128
142
|
self.plugin.handle_thread(True) # handle transcription in simple mode
|
129
143
|
else:
|
130
144
|
self.plugin.window.update_status("")
|
145
|
+
|
146
|
+
|
147
|
+
def on_stop(self):
|
148
|
+
"""Handle auto-transcribe"""
|
149
|
+
path = os.path.join(self.plugin.window.core.config.path, self.plugin.input_file)
|
150
|
+
self.plugin.window.core.audio.capture.set_path(path)
|
151
|
+
self.plugin.window.core.audio.capture.stop()
|
152
|
+
self.plugin.window.core.audio.capture.start()
|
153
|
+
self.plugin.handle_thread(True)
|
@@ -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: 2025.01.17 13:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import fnmatch
|
@@ -160,6 +160,8 @@ class Worker(BaseWorker):
|
|
160
160
|
:return: response item
|
161
161
|
"""
|
162
162
|
try:
|
163
|
+
if "path" not in item["params"] or "data" not in item["params"]:
|
164
|
+
return self.make_response(item, "Path or data not provided")
|
163
165
|
path = self.prepare_path(item["params"]['path'])
|
164
166
|
data = item["params"]['data']
|
165
167
|
self.msg = "Saving file: {}".format(path)
|
@@ -180,6 +182,8 @@ class Worker(BaseWorker):
|
|
180
182
|
:return: response item
|
181
183
|
"""
|
182
184
|
try:
|
185
|
+
if "path" not in item["params"] or "data" not in item["params"]:
|
186
|
+
return self.make_response(item, "Path or data not provided")
|
183
187
|
path = self.prepare_path(item["params"]['path'])
|
184
188
|
data = item["params"]['data']
|
185
189
|
self.msg = "Appending file: {}".format(path)
|
@@ -201,6 +205,8 @@ class Worker(BaseWorker):
|
|
201
205
|
"""
|
202
206
|
context_result = ""
|
203
207
|
try:
|
208
|
+
if "path" not in item["params"]:
|
209
|
+
return self.make_response(item, "Path not provided")
|
204
210
|
self.msg = "Reading file: {}".format(item["params"]['path'])
|
205
211
|
self.log(self.msg)
|
206
212
|
path = item["params"]['path']
|
@@ -232,6 +238,8 @@ class Worker(BaseWorker):
|
|
232
238
|
context = None
|
233
239
|
query = None
|
234
240
|
try:
|
241
|
+
if "path" not in item["params"]:
|
242
|
+
return self.make_response(item, "Path not provided")
|
235
243
|
path = self.prepare_path(item["params"]['path'])
|
236
244
|
self.msg = "Reading path: {}".format(path)
|
237
245
|
self.log(self.msg)
|
@@ -283,6 +291,8 @@ class Worker(BaseWorker):
|
|
283
291
|
:return: response item
|
284
292
|
"""
|
285
293
|
try:
|
294
|
+
if "path" not in item["params"]:
|
295
|
+
return self.make_response(item, "Path not provided")
|
286
296
|
path = self.prepare_path(item["params"]['path'])
|
287
297
|
self.msg = "Deleting file: {}".format(path)
|
288
298
|
self.log(self.msg)
|
@@ -372,6 +382,8 @@ class Worker(BaseWorker):
|
|
372
382
|
:return: response item
|
373
383
|
"""
|
374
384
|
try:
|
385
|
+
if "path" not in item["params"]:
|
386
|
+
return self.make_response(item, "Path not provided")
|
375
387
|
path = self.prepare_path(item["params"]['path'])
|
376
388
|
self.msg = "Creating directory: {}".format(path)
|
377
389
|
self.log(self.msg)
|
@@ -394,6 +406,8 @@ class Worker(BaseWorker):
|
|
394
406
|
:return: response item
|
395
407
|
"""
|
396
408
|
try:
|
409
|
+
if "path" not in item["params"]:
|
410
|
+
return self.make_response(item, "Path not provided")
|
397
411
|
path = self.prepare_path(item["params"]['path'])
|
398
412
|
self.msg = "Deleting directory: {}".format(path)
|
399
413
|
self.log(self.msg)
|
@@ -416,6 +430,8 @@ class Worker(BaseWorker):
|
|
416
430
|
:return: response item
|
417
431
|
"""
|
418
432
|
try:
|
433
|
+
if "src" not in item["params"] or "dst" not in item["params"]:
|
434
|
+
return self.make_response(item, "Source or destination not provided")
|
419
435
|
dst = self.prepare_path(item["params"]['dst'])
|
420
436
|
self.msg = "Downloading file: {} into {}".format(item["params"]['src'], dst)
|
421
437
|
self.log(self.msg)
|
@@ -468,6 +484,8 @@ class Worker(BaseWorker):
|
|
468
484
|
:return: response item
|
469
485
|
"""
|
470
486
|
try:
|
487
|
+
if "src" not in item["params"] or "dst" not in item["params"]:
|
488
|
+
return self.make_response(item, "Source or destination not provided")
|
471
489
|
src = self.prepare_path(item["params"]['src'])
|
472
490
|
dst = self.prepare_path(item["params"]['dst'])
|
473
491
|
self.msg = "Copying file: {} into {}".format(src, dst)
|
@@ -487,6 +505,8 @@ class Worker(BaseWorker):
|
|
487
505
|
:return: response item
|
488
506
|
"""
|
489
507
|
try:
|
508
|
+
if "src" not in item["params"] or "dst" not in item["params"]:
|
509
|
+
return self.make_response(item, "Source or destination not provided")
|
490
510
|
src = self.prepare_path(item["params"]['src'])
|
491
511
|
dst = self.prepare_path(item["params"]['dst'])
|
492
512
|
self.msg = "Copying directory: {} into {}".format(src, dst)
|
@@ -506,6 +526,8 @@ class Worker(BaseWorker):
|
|
506
526
|
:return: response item
|
507
527
|
"""
|
508
528
|
try:
|
529
|
+
if "src" not in item["params"] or "dst" not in item["params"]:
|
530
|
+
return self.make_response(item, "Source or destination not provided")
|
509
531
|
src = self.prepare_path(item["params"]['src'])
|
510
532
|
dst = self.prepare_path(item["params"]['dst'])
|
511
533
|
self.msg = "Moving: {} into {}".format(src, dst)
|
@@ -525,6 +547,8 @@ class Worker(BaseWorker):
|
|
525
547
|
:return: response item
|
526
548
|
"""
|
527
549
|
try:
|
550
|
+
if "path" not in item["params"]:
|
551
|
+
return self.make_response(item, "Path not provided")
|
528
552
|
path = self.prepare_path(item["params"]['path'])
|
529
553
|
self.msg = "Checking if directory exists: {}".format(path)
|
530
554
|
self.log(self.msg)
|
@@ -546,6 +570,8 @@ class Worker(BaseWorker):
|
|
546
570
|
:return: response item
|
547
571
|
"""
|
548
572
|
try:
|
573
|
+
if "path" not in item["params"]:
|
574
|
+
return self.make_response(item, "Path not provided")
|
549
575
|
path = self.prepare_path(item["params"]['path'])
|
550
576
|
self.msg = "Checking if file exists: {}".format(path)
|
551
577
|
self.log(self.msg)
|
@@ -567,6 +593,8 @@ class Worker(BaseWorker):
|
|
567
593
|
:return: response item
|
568
594
|
"""
|
569
595
|
try:
|
596
|
+
if "path" not in item["params"]:
|
597
|
+
return self.make_response(item, "Path not provided")
|
570
598
|
path = self.prepare_path(item["params"]['path'])
|
571
599
|
self.msg = "Checking if path exists: {}".format(path)
|
572
600
|
self.log(self.msg)
|
@@ -588,6 +616,8 @@ class Worker(BaseWorker):
|
|
588
616
|
:return: response item
|
589
617
|
"""
|
590
618
|
try:
|
619
|
+
if "path" not in item["params"]:
|
620
|
+
return self.make_response(item, "Path not provided")
|
591
621
|
path = self.prepare_path(item["params"]['path'])
|
592
622
|
self.msg = "Checking file size: {}".format(path)
|
593
623
|
self.log(self.msg)
|
@@ -613,6 +643,8 @@ class Worker(BaseWorker):
|
|
613
643
|
:return: response item
|
614
644
|
"""
|
615
645
|
try:
|
646
|
+
if "path" not in item["params"]:
|
647
|
+
return self.make_response(item, "Path not provided")
|
616
648
|
path = self.prepare_path(item["params"]['path'])
|
617
649
|
self.msg = "Checking file info: {}".format(path)
|
618
650
|
self.log(self.msg)
|
@@ -666,6 +698,8 @@ class Worker(BaseWorker):
|
|
666
698
|
:return: response item
|
667
699
|
"""
|
668
700
|
try:
|
701
|
+
if "path" not in item["params"]:
|
702
|
+
return self.make_response(item, "Path not provided")
|
669
703
|
path = self.prepare_path(item["params"]['path'])
|
670
704
|
self.msg = "Adding attachment: {}".format(path)
|
671
705
|
self.log(self.msg)
|
@@ -728,6 +762,8 @@ class Worker(BaseWorker):
|
|
728
762
|
:return: response item
|
729
763
|
"""
|
730
764
|
try:
|
765
|
+
if "pattern" not in item["params"]:
|
766
|
+
return self.make_response(item, "Search pattern not provided")
|
731
767
|
recursive = True
|
732
768
|
path = self.plugin.window.core.config.get_user_dir('data')
|
733
769
|
pattern = item["params"]['pattern']
|
@@ -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: 2025.01.17 02:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import copy
|
@@ -1803,6 +1803,14 @@ class Patch:
|
|
1803
1803
|
data["api_key_hugging_face"] = ""
|
1804
1804
|
updated = True
|
1805
1805
|
|
1806
|
+
# < 2.4.51
|
1807
|
+
if old < parse_version("2.4.51"):
|
1808
|
+
print("Migrating config from < 2.4.51...")
|
1809
|
+
if 'audio.input.stop_interval' not in data:
|
1810
|
+
data["audio.input.stop_interval"] = 10
|
1811
|
+
if 'audio.input.continuous' not in data:
|
1812
|
+
data["audio.input.continuous"] = False
|
1813
|
+
|
1806
1814
|
# update file
|
1807
1815
|
migrated = False
|
1808
1816
|
if updated:
|
pygpt_net/ui/__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:
|
9
|
+
# Updated Date: 2025.01.17 13:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import os
|
@@ -109,9 +109,10 @@ class UI:
|
|
109
109
|
def set_initial_size(self):
|
110
110
|
"""Set default sizes"""
|
111
111
|
def set_initial_splitter_height():
|
112
|
+
"""Set initial splitter height"""
|
112
113
|
total_height = self.window.ui.splitters['main.output'].size().height()
|
113
114
|
if total_height > 0:
|
114
|
-
size_output = int(total_height * 0.
|
115
|
+
size_output = int(total_height * 0.9)
|
115
116
|
size_input = total_height - size_output
|
116
117
|
self.window.ui.splitters['main.output'].setSizes([size_output, size_input])
|
117
118
|
else:
|
@@ -119,6 +120,7 @@ class UI:
|
|
119
120
|
QTimer.singleShot(0, set_initial_splitter_height)
|
120
121
|
|
121
122
|
def set_initial_splitter_width():
|
123
|
+
"""Set initial splitter width"""
|
122
124
|
total_width = self.window.ui.splitters['main'].size().width()
|
123
125
|
if total_width > 0:
|
124
126
|
size_output = int(total_width * 0.7)
|
@@ -160,24 +160,12 @@ class Input:
|
|
160
160
|
|
161
161
|
grid = QGridLayout()
|
162
162
|
|
163
|
-
#left_layout = QHBoxLayout()
|
164
|
-
#left_layout.addWidget(self.window.ui.nodes['input.label'])
|
165
|
-
#left_layout.addWidget(self.window.ui.nodes['inline.vision'])
|
166
|
-
#left_layout.addStretch(1)
|
167
|
-
|
168
163
|
center_layout = QHBoxLayout()
|
169
164
|
center_layout.addStretch()
|
170
165
|
center_layout.addWidget(self.window.ui.plugin_addon['audio.input'])
|
171
166
|
center_layout.addWidget(self.window.ui.plugin_addon['audio.input.btn'])
|
172
167
|
center_layout.addStretch()
|
173
|
-
|
174
|
-
#right_layout = QHBoxLayout()
|
175
|
-
#right_layout.addStretch(1)
|
176
|
-
#right_layout.addWidget(self.window.ui.nodes['input.counter'])
|
177
|
-
|
178
|
-
#grid.addLayout(left_layout, 0, 0)
|
179
168
|
grid.addLayout(center_layout, 0, 1, alignment=Qt.AlignCenter)
|
180
|
-
#grid.addLayout(right_layout, 0, 2, alignment=Qt.AlignRight)
|
181
169
|
|
182
170
|
grid.setContentsMargins(0, 0, 0, 0)
|
183
171
|
return grid
|
pygpt_net/ui/menu/__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: 2025.01.
|
9
|
+
# Updated Date: 2025.01.17 02:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from .about import About
|
@@ -50,15 +50,16 @@ class Menu:
|
|
50
50
|
self.audio.setup()
|
51
51
|
self.video.setup()
|
52
52
|
self.config.setup()
|
53
|
-
self.about.setup()
|
54
53
|
|
55
54
|
def post_setup(self):
|
56
55
|
"""Post setup menus"""
|
57
56
|
# tools menu
|
58
57
|
self.tools.setup()
|
59
|
-
self.
|
58
|
+
self.about.setup()
|
60
59
|
|
61
60
|
# debug menu
|
62
61
|
show = self.window.core.config.get('debug')
|
63
62
|
self.debug.setup()
|
64
63
|
self.window.ui.menu['menu.debug'].menuAction().setVisible(show)
|
64
|
+
|
65
|
+
self.donate.setup()
|
@@ -6,15 +6,17 @@
|
|
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.01.
|
9
|
+
# Updated Date: 2025.01.17 02:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from PySide6.QtCore import Qt
|
13
|
-
from PySide6.QtGui import QPainter
|
13
|
+
from PySide6.QtGui import QPainter, QIcon
|
14
14
|
from PySide6.QtWidgets import QLabel, QHBoxLayout, QWidget, QPushButton, QVBoxLayout
|
15
15
|
|
16
16
|
from pygpt_net.core.events import Event, AppEvent
|
17
|
+
from pygpt_net.ui.widget.option.toggle_label import ToggleLabel
|
17
18
|
from pygpt_net.utils import trans
|
19
|
+
import pygpt_net.icons_rc
|
18
20
|
|
19
21
|
class VoiceControlButton(QWidget):
|
20
22
|
def __init__(self, window=None):
|
@@ -26,7 +28,7 @@ class VoiceControlButton(QWidget):
|
|
26
28
|
super(VoiceControlButton, self).__init__(window)
|
27
29
|
self.window = window
|
28
30
|
|
29
|
-
self.btn_toggle = QPushButton(trans('audio.control.btn'))
|
31
|
+
self.btn_toggle = QPushButton(QIcon(":/icons/mic.svg"), trans('audio.control.btn'))
|
30
32
|
self.btn_toggle.clicked.connect(self.toggle_recording)
|
31
33
|
self.btn_toggle.setToolTip(trans('audio.speak.btn.tooltip'))
|
32
34
|
self.btn_toggle.setCursor(Qt.PointingHandCursor)
|
@@ -81,7 +83,7 @@ class AudioInputButton(QWidget):
|
|
81
83
|
super(AudioInputButton, self).__init__(window)
|
82
84
|
self.window = window
|
83
85
|
|
84
|
-
self.btn_toggle = QPushButton(trans('audio.speak.btn'))
|
86
|
+
self.btn_toggle = QPushButton(QIcon(":/icons/mic.svg"), trans('audio.speak.btn'))
|
85
87
|
self.btn_toggle.clicked.connect(self.toggle_recording)
|
86
88
|
self.btn_toggle.setToolTip(trans('audio.speak.btn.tooltip'))
|
87
89
|
self.btn_toggle.setCursor(Qt.PointingHandCursor)
|
@@ -90,20 +92,34 @@ class AudioInputButton(QWidget):
|
|
90
92
|
self.bar = LevelBar(self)
|
91
93
|
self.bar.setLevel(0)
|
92
94
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
95
|
+
btn_layout = QVBoxLayout()
|
96
|
+
btn_layout.addWidget(self.btn_toggle)
|
97
|
+
btn_layout.addWidget(self.bar)
|
98
|
+
btn_layout.setContentsMargins(0, 0, 0, 0)
|
99
|
+
btn_widget = QWidget()
|
100
|
+
btn_widget.setLayout(btn_layout)
|
97
101
|
|
98
|
-
self.
|
99
|
-
self.
|
100
|
-
|
101
|
-
|
102
|
+
self.continuous = ToggleLabel(trans('audio.speak.btn.continuous'), label_position="right")
|
103
|
+
self.continuous.box.stateChanged.connect(
|
104
|
+
lambda: self.window.controller.audio.toggle_continuous(
|
105
|
+
self.continuous.box.isChecked())
|
106
|
+
)
|
107
|
+
|
108
|
+
self.notepad_layout = QHBoxLayout()
|
109
|
+
self.notepad_layout.addWidget(self.continuous)
|
110
|
+
self.notepad_layout.setContentsMargins(0, 0, 0, 0)
|
111
|
+
|
112
|
+
self.notepad_footer = QWidget()
|
113
|
+
self.notepad_footer.setLayout(self.notepad_layout)
|
114
|
+
|
115
|
+
self.layout = QHBoxLayout()
|
116
|
+
self.layout.addWidget(btn_widget)
|
117
|
+
self.layout.addWidget(self.notepad_footer)
|
118
|
+
self.layout.setContentsMargins(0, 0, 0, 0)
|
102
119
|
|
103
|
-
# self.layout.addWidget(self.stop)
|
104
|
-
self.layout.setAlignment(Qt.AlignCenter)
|
105
120
|
self.setLayout(self.layout)
|
106
|
-
|
121
|
+
btn_widget.setMaximumHeight(80)
|
122
|
+
self.setMaximumHeight(120)
|
107
123
|
|
108
124
|
def add_widget(self, widget):
|
109
125
|
"""
|
@@ -113,14 +129,6 @@ class AudioInputButton(QWidget):
|
|
113
129
|
"""
|
114
130
|
self.layout.addWidget(widget)
|
115
131
|
|
116
|
-
def set_status(self, text):
|
117
|
-
"""
|
118
|
-
Set status text
|
119
|
-
|
120
|
-
:param text: text
|
121
|
-
"""
|
122
|
-
self.status.setText(text)
|
123
|
-
|
124
132
|
def toggle_recording(self):
|
125
133
|
"""Toggle recording"""
|
126
134
|
event = Event(Event.AUDIO_INPUT_RECORD_TOGGLE)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pygpt-net
|
3
|
-
Version: 2.4.
|
3
|
+
Version: 2.4.52
|
4
4
|
Summary: Desktop AI Assistant powered by models: OpenAI o1, GPT-4o, GPT-4, GPT-4 Vision, GPT-3.5, DALL-E 3, Llama 3, Mistral, Gemini, Claude, Bielik, and other models supported by Langchain, Llama Index, and Ollama. Features include chatbot, text completion, image generation, vision analysis, speech-to-text, internet access, file handling, command execution and more.
|
5
5
|
Home-page: https://pygpt.net
|
6
6
|
License: MIT
|
@@ -93,7 +93,7 @@ Description-Content-Type: text/markdown
|
|
93
93
|
|
94
94
|
[](https://snapcraft.io/pygpt)
|
95
95
|
|
96
|
-
Release: **2.4.
|
96
|
+
Release: **2.4.52** | build: **2025.01.17** | Python: **>=3.10, <3.13**
|
97
97
|
|
98
98
|
> Official website: https://pygpt.net | Documentation: https://pygpt.readthedocs.io
|
99
99
|
>
|
@@ -4044,6 +4044,17 @@ may consume additional tokens that are not displayed in the main window.
|
|
4044
4044
|
|
4045
4045
|
## Recent changes:
|
4046
4046
|
|
4047
|
+
**2.4.52 (2025-01-17)**
|
4048
|
+
|
4049
|
+
- Improved audio input button visibility toggle.
|
4050
|
+
- Fix: check for required arguments - issue #88.
|
4051
|
+
- UI Fixes.
|
4052
|
+
|
4053
|
+
**2.4.51 (2025-01-17)**
|
4054
|
+
|
4055
|
+
- Added a "Continuous recording" mode under Audio Input in the Notepad tab, allowing for recording long voice notes and real-time auto-transcription. (beta)
|
4056
|
+
- A new option has been added in Settings -> Audio -> Continuous recording auto-transcribe interval.
|
4057
|
+
|
4047
4058
|
**2.4.50 (2025-01-16)**
|
4048
4059
|
|
4049
4060
|
- Refactored audio input core.
|
@@ -4074,67 +4085,6 @@ may consume additional tokens that are not displayed in the main window.
|
|
4074
4085
|
- Introduced a new mode in "Chat with Files": "Retrieve Only", which allows for retrieving raw documents from the index.
|
4075
4086
|
- Fixed a bug related to tool calls in the Gemini provider when using Chat with Files mode.
|
4076
4087
|
|
4077
|
-
**2.4.45 (2024-12-16)**
|
4078
|
-
|
4079
|
-
- Enhanced web data loaders UI.
|
4080
|
-
|
4081
|
-
**2.4.44 (2024-12-16)**
|
4082
|
-
|
4083
|
-
- Enhanced web data loaders.
|
4084
|
-
- Web loaders have been added to attachments, allowing external web content to be attached to context via the "+Web" button in the Attachments tab.
|
4085
|
-
- Improved handling of attachments in groups and added an attachment icon when a group contains attachments.
|
4086
|
-
|
4087
|
-
**2.4.43 (2024-12-15)**
|
4088
|
-
|
4089
|
-
- Fix: Bug on attachment upload.
|
4090
|
-
- Added: Attachments uploaded in groups are now available for all contexts in the group (beta).
|
4091
|
-
|
4092
|
-
**2.4.42 (2024-12-15)**
|
4093
|
-
|
4094
|
-
- Added Mailer plugin, which allows sending and retrieving emails from the server, and reading them. It currently supports only SMTP.
|
4095
|
-
- Added 'web_request' command to the Web Search plugin, enabling GET/POST/PUT and other connections to any address and API endpoint. It also supports sending POST data, files, headers, cookies, and more.
|
4096
|
-
- Improved audio output.
|
4097
|
-
- Enhanced visibility of the Video menu.
|
4098
|
-
- Other fixes.
|
4099
|
-
|
4100
|
-
**2.4.41 (2024-12-14)**
|
4101
|
-
|
4102
|
-
- Improved switching between columns on a split screen.
|
4103
|
-
- Added visual identification of the active column.
|
4104
|
-
|
4105
|
-
**2.4.40 (2024-12-13)**
|
4106
|
-
|
4107
|
-
- Enhanced Split Screen mode, now promoted from beta to stable.
|
4108
|
-
- Python Code Interpreter tool added to the Tabs.
|
4109
|
-
- HTML/JS Canvas tool added to the Tabs.
|
4110
|
-
- Added attachment icon to the context list if context has attachments.
|
4111
|
-
- Improved audio playback.
|
4112
|
-
- Improved web search.
|
4113
|
-
- Added a thumbnail image to web search results.
|
4114
|
-
- Added a new commands to web search: "extract_images" and "extract_links".
|
4115
|
-
- Added the option "Use raw content (without summarization)" to the web search plugin, which provides a more detailed result to the main model.
|
4116
|
-
- Extended the default maximum result characters to 50,000 in the web search plugin.
|
4117
|
-
|
4118
|
-
**2.4.39 (2024-12-09)**
|
4119
|
-
|
4120
|
-
- Added "Split Screen" mode (accessible via the switch in the bottom-right corner of the screen), which allows you to work in two windows simultaneously. It is currently experimental (beta). Future updates will include Code Interpreter and Canvas running in tabs.
|
4121
|
-
|
4122
|
-
- Fixed: Language switch.
|
4123
|
-
|
4124
|
-
**2.4.38 (2024-12-08)**
|
4125
|
-
|
4126
|
-
- Added the ability to select a style for chat display between: Blocks, ChatGPT-like, and ChatGPT-like Wide. New option in the menu: Config -> Theme -> Style...
|
4127
|
-
- Added configuration options for audio input in Settings -> Audio -> Audio Input Device, Channels, and Sampling rate.
|
4128
|
-
|
4129
|
-
**2.4.37 (2024-11-30)**
|
4130
|
-
|
4131
|
-
- The `Query only` mode in `Uploaded` tab has been renamed to `RAG`.
|
4132
|
-
- New options have been added under `Settings -> Files and Attachments`:
|
4133
|
-
- `Use history in RAG query`: When enabled, the content of the entire conversation will be used when preparing a query if the mode is set to RAG or Summary.
|
4134
|
-
- `RAG limit`: This option is applicable only if 'Use history in RAG query' is enabled. It specifies the limit on how many recent entries in the conversation will be used when generating a query for RAG. A value of 0 indicates no limit.
|
4135
|
-
- Cache: dynamic parts of the system prompt (from plugins) have been moved to the very end of the prompt stack to enable the use of prompt cache mechanisms in OpenAI.
|
4136
|
-
|
4137
|
-
|
4138
4088
|
# Credits and links
|
4139
4089
|
|
4140
4090
|
**Official website:** <https://pygpt.net>
|