pygpt-net 2.4.52__py3-none-any.whl → 2.4.54__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 +9 -0
- README.md +17 -1
- pygpt_net/CHANGELOG.txt +9 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/dialogs/info.py +7 -5
- pygpt_net/core/audio/capture.py +2 -1
- pygpt_net/data/config/config.json +3 -3
- pygpt_net/data/config/models.json +3 -3
- pygpt_net/data/config/modes.json +3 -3
- pygpt_net/data/win32/USER-LICENSE.rtf +0 -0
- pygpt_net/plugin/audio_input/simple.py +14 -2
- pygpt_net/plugin/audio_input/worker.py +8 -5
- pygpt_net/plugin/audio_output/__init__.py +47 -12
- pygpt_net/plugin/audio_output/worker.py +114 -20
- pygpt_net/ui/__init__.py +2 -1
- pygpt_net/ui/dialog/snap.py +3 -2
- pygpt_net/ui/layout/chat/input.py +4 -1
- pygpt_net/ui/widget/audio/bar.py +103 -0
- pygpt_net/ui/widget/audio/input_button.py +5 -46
- pygpt_net/ui/widget/dialog/snap.py +37 -6
- {pygpt_net-2.4.52.dist-info → pygpt_net-2.4.54.dist-info}/METADATA +18 -2
- {pygpt_net-2.4.52.dist-info → pygpt_net-2.4.54.dist-info}/RECORD +25 -24
- {pygpt_net-2.4.52.dist-info → pygpt_net-2.4.54.dist-info}/LICENSE +0 -0
- {pygpt_net-2.4.52.dist-info → pygpt_net-2.4.54.dist-info}/WHEEL +0 -0
- {pygpt_net-2.4.52.dist-info → pygpt_net-2.4.54.dist-info}/entry_points.txt +0 -0
CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 2.4.54 (2025-01-18)
|
4
|
+
|
5
|
+
- Audio output switched from PyGame to PyAudio. It may be necessary to manually connect Alsa in Snap version with: "sudo snap connect pygpt:alsa".
|
6
|
+
- Added audio output volume progress bar.
|
7
|
+
|
8
|
+
## 2.4.53 (2025-01-17)
|
9
|
+
|
10
|
+
- Fix: issue #89
|
11
|
+
|
3
12
|
## 2.4.52 (2025-01-17)
|
4
13
|
|
5
14
|
- Improved audio input button visibility toggle.
|
README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[](https://snapcraft.io/pygpt)
|
4
4
|
|
5
|
-
Release: **2.4.
|
5
|
+
Release: **2.4.54** | build: **2025.01.18** | Python: **>=3.10, <3.13**
|
6
6
|
|
7
7
|
> Official website: https://pygpt.net | Documentation: https://pygpt.readthedocs.io
|
8
8
|
>
|
@@ -121,6 +121,13 @@ sudo snap connect pygpt:audio-record :audio-record
|
|
121
121
|
sudo snap connect pygpt:alsa
|
122
122
|
```
|
123
123
|
|
124
|
+
**Using audio output:** to use audio output in Snap version you must connect the audio with:
|
125
|
+
|
126
|
+
```commandline
|
127
|
+
sudo snap connect pygpt:audio-playback
|
128
|
+
sudo snap connect pygpt:alsa
|
129
|
+
```
|
130
|
+
|
124
131
|
**Connecting IPython in Docker in Snap version**:
|
125
132
|
|
126
133
|
To use IPython in the Snap version, you must connect PyGPT to the Docker daemon:
|
@@ -3953,6 +3960,15 @@ may consume additional tokens that are not displayed in the main window.
|
|
3953
3960
|
|
3954
3961
|
## Recent changes:
|
3955
3962
|
|
3963
|
+
**2.4.54 (2025-01-18)**
|
3964
|
+
|
3965
|
+
- Audio output switched from PyGame to PyAudio. It may be necessary to manually connect Alsa in Snap version with: "sudo snap connect pygpt:alsa".
|
3966
|
+
- Added audio output volume progress bar.
|
3967
|
+
|
3968
|
+
**2.4.53 (2025-01-17)**
|
3969
|
+
|
3970
|
+
- Fix: issue #89
|
3971
|
+
|
3956
3972
|
**2.4.52 (2025-01-17)**
|
3957
3973
|
|
3958
3974
|
- Improved audio input button visibility toggle.
|
pygpt_net/CHANGELOG.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
2.4.54 (2025-01-18)
|
2
|
+
|
3
|
+
- Audio output switched from PyGame to PyAudio. It may be necessary to manually connect Alsa in Snap version with: "sudo snap connect pygpt:alsa".
|
4
|
+
- Added audio output volume progress bar.
|
5
|
+
|
6
|
+
2.4.53 (2025-01-17)
|
7
|
+
|
8
|
+
- Fix: issue #89
|
9
|
+
|
1
10
|
2.4.52 (2025-01-17)
|
2
11
|
|
3
12
|
- Improved audio input button visibility toggle.
|
pygpt_net/__init__.py
CHANGED
@@ -6,15 +6,15 @@
|
|
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.18 03:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
__author__ = "Marcin Szczygliński"
|
13
13
|
__copyright__ = "Copyright 2025, Marcin Szczygliński"
|
14
14
|
__credits__ = ["Marcin Szczygliński"]
|
15
15
|
__license__ = "MIT"
|
16
|
-
__version__ = "2.4.
|
17
|
-
__build__ = "2025.01.
|
16
|
+
__version__ = "2.4.54"
|
17
|
+
__build__ = "2025.01.18"
|
18
18
|
__maintainer__ = "Marcin Szczygliński"
|
19
19
|
__github__ = "https://github.com/szczyglis-dev/py-gpt"
|
20
20
|
__report__ = "https://github.com/szczyglis-dev/py-gpt/issues"
|
@@ -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 13:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import webbrowser
|
@@ -113,7 +113,9 @@ class Info:
|
|
113
113
|
def update_menu(self):
|
114
114
|
"""Update info menu"""
|
115
115
|
for id in self.ids:
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
116
|
+
item = 'info.' + id
|
117
|
+
if item in self.window.ui.menu:
|
118
|
+
if id in self.active and self.active[id]:
|
119
|
+
self.window.ui.menu[item].setChecked(True)
|
120
|
+
else:
|
121
|
+
self.window.ui.menu[item].setChecked(False)
|
pygpt_net/core/audio/capture.py
CHANGED
@@ -333,10 +333,10 @@ class Capture:
|
|
333
333
|
:return: True if working
|
334
334
|
"""
|
335
335
|
import pyaudio
|
336
|
+
p = pyaudio.PyAudio()
|
336
337
|
try:
|
337
338
|
rate = 44100
|
338
339
|
channels = 1
|
339
|
-
p = pyaudio.PyAudio()
|
340
340
|
stream = p.open(format=pyaudio.paInt16,
|
341
341
|
channels=channels,
|
342
342
|
rate=rate,
|
@@ -346,4 +346,5 @@ class Capture:
|
|
346
346
|
p.terminate()
|
347
347
|
return True
|
348
348
|
except Exception as e:
|
349
|
+
p.terminate()
|
349
350
|
return False
|
@@ -1,8 +1,8 @@
|
|
1
1
|
{
|
2
2
|
"__meta__": {
|
3
|
-
"version": "2.4.
|
4
|
-
"app.version": "2.4.
|
5
|
-
"updated_at": "2025-01-
|
3
|
+
"version": "2.4.54",
|
4
|
+
"app.version": "2.4.54",
|
5
|
+
"updated_at": "2025-01-18T00:00:00"
|
6
6
|
},
|
7
7
|
"access.audio.event.speech": false,
|
8
8
|
"access.audio.event.speech.disabled": [],
|
pygpt_net/data/config/modes.json
CHANGED
Binary file
|
@@ -61,6 +61,19 @@ class Simple:
|
|
61
61
|
|
62
62
|
:param force: True to force recording
|
63
63
|
"""
|
64
|
+
# display snap warning if not displayed yet
|
65
|
+
if (not self.plugin.window.core.config.get("audio.input.snap", False)
|
66
|
+
or not self.plugin.window.core.config.has("audio.input.snap")):
|
67
|
+
if self.plugin.window.core.platforms.is_snap():
|
68
|
+
self.plugin.window.ui.dialogs.open(
|
69
|
+
'snap_audio_input',
|
70
|
+
width=400,
|
71
|
+
height=200
|
72
|
+
)
|
73
|
+
self.plugin.window.core.config.set("audio.input.snap", True)
|
74
|
+
self.plugin.window.core.config.save()
|
75
|
+
return
|
76
|
+
|
64
77
|
# enable continuous mode if notepad tab is active
|
65
78
|
self.plugin.window.core.audio.capture.stop_callback = self.on_stop
|
66
79
|
continuous_enabled = self.plugin.window.core.config.get('audio.input.continuous', False)
|
@@ -71,8 +84,7 @@ class Simple:
|
|
71
84
|
|
72
85
|
try:
|
73
86
|
# stop audio output if playing
|
74
|
-
|
75
|
-
self.plugin.window.controller.audio.stop_output()
|
87
|
+
self.plugin.window.controller.audio.stop_output()
|
76
88
|
|
77
89
|
# set audio volume bar
|
78
90
|
self.plugin.window.core.audio.capture.set_bar(
|
@@ -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.18 03:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import os.path
|
@@ -16,6 +16,7 @@ import audioop
|
|
16
16
|
|
17
17
|
from PySide6.QtCore import Slot, Signal
|
18
18
|
|
19
|
+
from pygpt_net.core.tabs import Tab
|
19
20
|
from pygpt_net.utils import trans
|
20
21
|
from pygpt_net.plugin.base.worker import BaseWorker, BaseSignals
|
21
22
|
|
@@ -76,10 +77,12 @@ class Worker(BaseWorker):
|
|
76
77
|
self.status(trans('audio.speak.wait'))
|
77
78
|
|
78
79
|
# if multimodal audio, then only return path to audio file and do not transcribe
|
79
|
-
|
80
|
-
|
81
|
-
self.
|
82
|
-
|
80
|
+
tab = self.window.controller.ui.tabs.get_current_tab()
|
81
|
+
if tab.type == Tab.TAB_CHAT:
|
82
|
+
if self.plugin.window.controller.chat.audio.enabled():
|
83
|
+
self.signals.on_realtime.emit(self.path)
|
84
|
+
self.status('')
|
85
|
+
return
|
83
86
|
|
84
87
|
# transcribe audio
|
85
88
|
transcript = self.plugin.get_provider().transcribe(self.path)
|
@@ -6,9 +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:
|
9
|
+
# Updated Date: 2025.01.18 03:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
|
+
from typing import Any
|
13
|
+
|
12
14
|
from PySide6.QtCore import Slot
|
13
15
|
|
14
16
|
from pygpt_net.core.types import MODE_AUDIO
|
@@ -35,6 +37,7 @@ class Plugin(BasePlugin):
|
|
35
37
|
self.use_locale = True
|
36
38
|
self.output_file = "output.mp3"
|
37
39
|
self.config = Config(self)
|
40
|
+
self.worker = None
|
38
41
|
|
39
42
|
def init_options(self):
|
40
43
|
"""Initialize options"""
|
@@ -171,10 +174,12 @@ class Plugin(BasePlugin):
|
|
171
174
|
# check for audio read allowed. Prevents reading audio in commands, results, etc.
|
172
175
|
if name == Event.CTX_AFTER:
|
173
176
|
if not ctx.audio_read_allowed():
|
174
|
-
return
|
175
|
-
|
177
|
+
return # abort if audio read is not allowed (commands, results, etc.)
|
178
|
+
|
176
179
|
try:
|
177
180
|
if text is not None and len(text) > 0:
|
181
|
+
self.stop_audio()
|
182
|
+
|
178
183
|
worker = Worker()
|
179
184
|
worker.from_defaults(self)
|
180
185
|
worker.ctx = ctx
|
@@ -185,13 +190,16 @@ class Plugin(BasePlugin):
|
|
185
190
|
|
186
191
|
# signals
|
187
192
|
worker.signals.playback.connect(self.handle_playback)
|
193
|
+
worker.signals.error_playback.connect(self.handle_playback_error)
|
188
194
|
worker.signals.stop.connect(self.handle_stop)
|
195
|
+
worker.signals.volume_changed.connect(self.handle_volume)
|
189
196
|
|
190
197
|
worker.run_async()
|
198
|
+
self.worker = worker
|
191
199
|
|
192
200
|
# only for manual reading
|
193
201
|
if name == Event.AUDIO_READ_TEXT:
|
194
|
-
self.window.controller.audio.on_begin(worker.text)
|
202
|
+
self.window.controller.audio.on_begin(self.worker.text)
|
195
203
|
|
196
204
|
except Exception as e:
|
197
205
|
self.error(e)
|
@@ -202,8 +210,10 @@ class Plugin(BasePlugin):
|
|
202
210
|
|
203
211
|
:param ctx: CtxItem
|
204
212
|
:param event: Event
|
205
|
-
"""
|
213
|
+
"""
|
206
214
|
try:
|
215
|
+
self.stop_audio()
|
216
|
+
|
207
217
|
worker = Worker()
|
208
218
|
worker.from_defaults(self)
|
209
219
|
worker.audio_file = event.data["audio_file"]
|
@@ -211,9 +221,12 @@ class Plugin(BasePlugin):
|
|
211
221
|
|
212
222
|
# signals
|
213
223
|
worker.signals.playback.connect(self.handle_playback)
|
224
|
+
worker.signals.error_playback.connect(self.handle_playback_error)
|
214
225
|
worker.signals.stop.connect(self.handle_stop)
|
226
|
+
worker.signals.volume_changed.connect(self.handle_volume)
|
215
227
|
|
216
228
|
worker.run_async()
|
229
|
+
self.worker = worker
|
217
230
|
|
218
231
|
except Exception as e:
|
219
232
|
self.error(e)
|
@@ -250,22 +263,44 @@ class Plugin(BasePlugin):
|
|
250
263
|
|
251
264
|
Stop playing the audio
|
252
265
|
"""
|
253
|
-
if self.
|
254
|
-
self.
|
255
|
-
|
266
|
+
if self.worker is not None:
|
267
|
+
self.worker.stop()
|
268
|
+
self.handle_volume(0.0)
|
256
269
|
|
257
|
-
@Slot(object
|
258
|
-
def
|
270
|
+
@Slot(object)
|
271
|
+
def handle_playback_error(self, err: Any):
|
272
|
+
"""
|
273
|
+
Send error message to logger and alert dialog
|
274
|
+
|
275
|
+
:param err: error message
|
276
|
+
"""
|
277
|
+
self.error(err)
|
278
|
+
if self.window.core.platforms.is_snap():
|
279
|
+
self.window.ui.dialogs.open(
|
280
|
+
'snap_audio_output',
|
281
|
+
width=400,
|
282
|
+
height=200
|
283
|
+
)
|
284
|
+
|
285
|
+
@Slot(str)
|
286
|
+
def handle_playback(self, event: str):
|
259
287
|
"""
|
260
288
|
Handle thread playback object
|
261
289
|
|
262
|
-
:param playback: playback object
|
263
290
|
:param event: event name
|
264
291
|
"""
|
265
|
-
self.playback = playback
|
266
292
|
self.window.controller.audio.on_play(event)
|
267
293
|
|
268
294
|
@Slot()
|
269
295
|
def handle_stop(self):
|
270
296
|
"""Handle thread playback stop"""
|
271
297
|
self.stop_audio()
|
298
|
+
|
299
|
+
@Slot(float)
|
300
|
+
def handle_volume(self, volume: float):
|
301
|
+
"""
|
302
|
+
Handle thread playback volume
|
303
|
+
|
304
|
+
:param volume: volume level
|
305
|
+
"""
|
306
|
+
self.window.ui.plugin_addon['audio.output.bar'].setLevel(volume)
|
@@ -6,18 +6,26 @@
|
|
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.18 03:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import time
|
13
|
+
import pyaudio
|
14
|
+
import wave
|
15
|
+
import numpy as np
|
16
|
+
import io
|
17
|
+
from pydub import AudioSegment
|
13
18
|
|
14
19
|
from PySide6.QtCore import Slot, Signal
|
20
|
+
|
15
21
|
from pygpt_net.plugin.base.worker import BaseWorker, BaseSignals
|
16
22
|
|
17
23
|
|
18
24
|
class WorkerSignals(BaseSignals):
|
19
|
-
|
25
|
+
volume_changed = Signal(float) # Emits the volume level
|
26
|
+
playback = Signal(str)
|
20
27
|
stop = Signal()
|
28
|
+
error_playback = Signal(object)
|
21
29
|
|
22
30
|
|
23
31
|
class Worker(BaseWorker):
|
@@ -32,6 +40,9 @@ class Worker(BaseWorker):
|
|
32
40
|
self.cache_file = None # path to cache file
|
33
41
|
self.mode = "generate" # generate|playback
|
34
42
|
self.audio_file = None
|
43
|
+
self.is_stopped = False
|
44
|
+
self.p = None
|
45
|
+
self.stream = None
|
35
46
|
|
36
47
|
@Slot()
|
37
48
|
def run(self):
|
@@ -44,35 +55,118 @@ class Worker(BaseWorker):
|
|
44
55
|
self.error(e)
|
45
56
|
|
46
57
|
def generate(self):
|
47
|
-
"""
|
48
|
-
Generate and play audio file
|
49
|
-
"""
|
58
|
+
"""Generate and play audio file"""
|
50
59
|
if self.text is None or self.text == "":
|
51
60
|
time.sleep(0.2) # wait
|
52
61
|
return
|
53
62
|
path = self.plugin.get_provider().speech(self.text)
|
54
63
|
if path:
|
55
|
-
|
56
|
-
mixer.init()
|
57
|
-
playback = mixer.Sound(path)
|
58
|
-
self.stop_playback() # stop previous playback
|
59
|
-
playback.play()
|
60
|
-
self.send(playback) # send playback object to main thread to allow force stop
|
61
|
-
|
64
|
+
self.play_audio(path)
|
62
65
|
# store in cache if enabled
|
63
66
|
if self.cache_file:
|
64
67
|
self.cache_audio_file(path, self.cache_file)
|
65
68
|
|
66
69
|
def play(self):
|
70
|
+
"""Play audio file only"""
|
71
|
+
if self.audio_file:
|
72
|
+
self.play_audio(self.audio_file)
|
73
|
+
|
74
|
+
def play_audio(self, audio_file: str):
|
67
75
|
"""
|
68
|
-
Play audio file
|
76
|
+
Play audio file using PyAudio
|
77
|
+
|
78
|
+
:param audio_file: audio file path
|
69
79
|
"""
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
80
|
+
try:
|
81
|
+
self.signals.playback.emit(self.event)
|
82
|
+
audio = AudioSegment.from_file(audio_file)
|
83
|
+
audio = audio.set_frame_rate(44100) # resample to 44.1 kHz
|
84
|
+
wav_io = io.BytesIO()
|
85
|
+
audio.export(wav_io, format='wav')
|
86
|
+
wav_io.seek(0)
|
87
|
+
wf = wave.open(wav_io, 'rb')
|
88
|
+
self.p = pyaudio.PyAudio()
|
89
|
+
self.stream = self.p.open(format=self.p.get_format_from_width(wf.getsampwidth()),
|
90
|
+
channels=wf.getnchannels(),
|
91
|
+
rate=wf.getframerate(),
|
92
|
+
output=True)
|
93
|
+
|
94
|
+
sample_width = wf.getsampwidth()
|
95
|
+
format = self.p.get_format_from_width(sample_width)
|
96
|
+
|
97
|
+
if format == pyaudio.paInt8:
|
98
|
+
dtype = np.int8
|
99
|
+
max_value = 2 ** 7 - 1 # 127
|
100
|
+
offset = 0
|
101
|
+
elif format == pyaudio.paInt16:
|
102
|
+
dtype = np.int16
|
103
|
+
max_value = 2 ** 15 - 1 # 32767
|
104
|
+
offset = 0
|
105
|
+
elif format == pyaudio.paInt32:
|
106
|
+
dtype = np.int32
|
107
|
+
max_value = 2 ** 31 - 1 # 2147483647
|
108
|
+
offset = 0
|
109
|
+
elif format == pyaudio.paUInt8:
|
110
|
+
dtype = np.uint8
|
111
|
+
max_value = 2 ** 8 - 1 # 255
|
112
|
+
offset = 128 # center unsigned data
|
113
|
+
else:
|
114
|
+
raise ValueError(f"Unsupported format: {format}")
|
115
|
+
|
116
|
+
chunk_size = 512
|
117
|
+
data = wf.readframes(chunk_size)
|
118
|
+
|
119
|
+
while data != b'' and not self.is_stopped:
|
120
|
+
self.stream.write(data)
|
121
|
+
|
122
|
+
audio_data = np.frombuffer(data, dtype=dtype)
|
123
|
+
if len(audio_data) > 0:
|
124
|
+
audio_data = audio_data.astype(np.float32)
|
125
|
+
if dtype == np.uint8:
|
126
|
+
audio_data -= offset
|
127
|
+
|
128
|
+
# compute RMS
|
129
|
+
rms = np.sqrt(np.mean(audio_data ** 2))
|
130
|
+
|
131
|
+
if rms > 0:
|
132
|
+
# RMS to decibels
|
133
|
+
db = 20 * np.log10(rms / max_value)
|
134
|
+
|
135
|
+
# define minimum and maximum dB levels
|
136
|
+
min_db = -60 # adjust as needed
|
137
|
+
max_db = 0
|
138
|
+
|
139
|
+
# clamp the db value to the range [min_db, max_db]
|
140
|
+
if db < min_db:
|
141
|
+
db = min_db
|
142
|
+
elif db > max_db:
|
143
|
+
db = max_db
|
144
|
+
|
145
|
+
# map decibel value to volume percentage
|
146
|
+
volume_percentage = ((db - min_db) / (max_db - min_db)) * 100
|
147
|
+
else:
|
148
|
+
volume_percentage = 0
|
149
|
+
|
150
|
+
# emit volume signal
|
151
|
+
self.signals.volume_changed.emit(volume_percentage)
|
152
|
+
else:
|
153
|
+
# if empty audio_data
|
154
|
+
self.signals.volume_changed.emit(0)
|
155
|
+
|
156
|
+
data = wf.readframes(chunk_size)
|
157
|
+
|
158
|
+
# close the stream
|
159
|
+
if self.stream is not None:
|
160
|
+
if self.stream.is_active():
|
161
|
+
self.stream.stop_stream()
|
162
|
+
self.stream.close()
|
163
|
+
if self.p is not None:
|
164
|
+
self.p.terminate()
|
165
|
+
wf.close()
|
166
|
+
self.signals.volume_changed.emit(0)
|
167
|
+
except Exception as e:
|
168
|
+
self.signals.volume_changed.emit(0)
|
169
|
+
self.signals.error_playback.emit(e)
|
76
170
|
|
77
171
|
def cache_audio_file(self, src: str, dst: str):
|
78
172
|
"""
|
@@ -102,4 +196,4 @@ class Worker(BaseWorker):
|
|
102
196
|
|
103
197
|
def stop(self):
|
104
198
|
"""Send stop signal to main thread"""
|
105
|
-
self.
|
199
|
+
self.is_stopped = True
|
pygpt_net/ui/__init__.py
CHANGED
@@ -91,7 +91,8 @@ class UI:
|
|
91
91
|
|
92
92
|
# FIRST RUN: initial sizes if not set yet
|
93
93
|
if not self.window.core.config.has("layout.splitters") \
|
94
|
-
or self.window.core.config.get("layout.splitters") == {}
|
94
|
+
or self.window.core.config.get("layout.splitters") == {}\
|
95
|
+
or self.window.core.config.get("license.accepted") == False:
|
95
96
|
self.set_initial_size()
|
96
97
|
|
97
98
|
# menus
|
pygpt_net/ui/dialog/snap.py
CHANGED
@@ -6,10 +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:
|
9
|
+
# Updated Date: 2025.01.18 05:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
|
-
from pygpt_net.ui.widget.dialog.snap import SnapDialogCamera, SnapDialogAudioInput
|
12
|
+
from pygpt_net.ui.widget.dialog.snap import SnapDialogCamera, SnapDialogAudioInput, SnapDialogAudioOutput
|
13
13
|
|
14
14
|
|
15
15
|
class Snap:
|
@@ -25,3 +25,4 @@ class Snap:
|
|
25
25
|
"""Setup snap dialog"""
|
26
26
|
self.window.ui.dialog['snap_camera'] = SnapDialogCamera(self.window)
|
27
27
|
self.window.ui.dialog['snap_audio_input'] = SnapDialogAudioInput(self.window)
|
28
|
+
self.window.ui.dialog['snap_audio_output'] = SnapDialogAudioOutput(self.window)
|
@@ -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.18 03:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from PySide6.QtCore import Qt
|
@@ -18,6 +18,7 @@ from pygpt_net.ui.layout.chat.attachments import Attachments
|
|
18
18
|
from pygpt_net.ui.layout.chat.attachments_uploaded import AttachmentsUploaded
|
19
19
|
from pygpt_net.ui.layout.chat.attachments_ctx import AttachmentsCtx
|
20
20
|
from pygpt_net.ui.layout.status import Status
|
21
|
+
from pygpt_net.ui.widget.audio.bar import OutputBar
|
21
22
|
from pygpt_net.ui.widget.audio.input import AudioInput
|
22
23
|
from pygpt_net.ui.widget.audio.input_button import AudioInputButton
|
23
24
|
from pygpt_net.ui.widget.element.labels import HelpLabel
|
@@ -176,8 +177,10 @@ class Input:
|
|
176
177
|
|
177
178
|
:return: QHBoxLayout
|
178
179
|
"""
|
180
|
+
self.window.ui.plugin_addon['audio.output.bar'] = OutputBar(self.window)
|
179
181
|
layout = QHBoxLayout()
|
180
182
|
layout.addLayout(self.status.setup())
|
183
|
+
layout.addWidget(self.window.ui.plugin_addon['audio.output.bar'], alignment=Qt.AlignCenter)
|
181
184
|
layout.addLayout(self.setup_buttons())
|
182
185
|
layout.setContentsMargins(2, 0, 2, 0)
|
183
186
|
|
@@ -0,0 +1,103 @@
|
|
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: 2025.01.18 03:00:00 #
|
10
|
+
# ================================================== #
|
11
|
+
|
12
|
+
from PySide6.QtCore import Qt
|
13
|
+
from PySide6.QtGui import QPainter, QPalette
|
14
|
+
from PySide6.QtWidgets import QWidget
|
15
|
+
|
16
|
+
import pygpt_net.icons_rc
|
17
|
+
|
18
|
+
class InputBar(QWidget):
|
19
|
+
def __init__(self, parent=None):
|
20
|
+
super().__init__(parent)
|
21
|
+
self._level = 0.0 # level from 0.0 to 100.0
|
22
|
+
self.setFixedSize(200, 5) # bar size
|
23
|
+
|
24
|
+
def setLevel(self, level):
|
25
|
+
"""
|
26
|
+
Set volume level
|
27
|
+
|
28
|
+
:param level: level
|
29
|
+
"""
|
30
|
+
self._level = level
|
31
|
+
self.update()
|
32
|
+
|
33
|
+
def paintEvent(self, event):
|
34
|
+
"""
|
35
|
+
Paint event
|
36
|
+
|
37
|
+
:param event: event
|
38
|
+
"""
|
39
|
+
palette = self.palette()
|
40
|
+
painter = QPainter(self)
|
41
|
+
painter.fillRect(self.rect(), Qt.transparent)
|
42
|
+
level_width = (self._level / 100.0) * self.width()
|
43
|
+
painter.setBrush(palette.color(QPalette.ButtonText))
|
44
|
+
painter.setPen(Qt.NoPen)
|
45
|
+
painter.drawRect(0, 0, level_width, self.height())
|
46
|
+
|
47
|
+
"""
|
48
|
+
# --- bar from center ---
|
49
|
+
def paintEvent(self, event):
|
50
|
+
painter = QPainter(self)
|
51
|
+
painter.fillRect(self.rect(), Qt.transparent)
|
52
|
+
level_width = (self._level / 100.0) * self.width()
|
53
|
+
half_level_width = level_width / 2
|
54
|
+
center_x = self.width() / 2
|
55
|
+
rect_x = center_x - half_level_width
|
56
|
+
painter.setBrush(Qt.green)
|
57
|
+
painter.setPen(Qt.NoPen)
|
58
|
+
painter.drawRect(rect_x, 0, level_width, self.height())
|
59
|
+
"""
|
60
|
+
|
61
|
+
|
62
|
+
class OutputBar(QWidget):
|
63
|
+
def __init__(self, parent=None):
|
64
|
+
super().__init__(parent)
|
65
|
+
self._level = 0.0 # level from 0.0 to 100.0
|
66
|
+
self.setFixedSize(200, 5) # bar size
|
67
|
+
|
68
|
+
def setLevel(self, level):
|
69
|
+
"""
|
70
|
+
Set volume level
|
71
|
+
|
72
|
+
:param level: level
|
73
|
+
"""
|
74
|
+
self._level = level
|
75
|
+
self.update()
|
76
|
+
|
77
|
+
def paintEvent(self, event):
|
78
|
+
"""
|
79
|
+
Paint event
|
80
|
+
|
81
|
+
:param event: event
|
82
|
+
"""
|
83
|
+
palette = self.palette()
|
84
|
+
painter = QPainter(self)
|
85
|
+
painter.fillRect(self.rect(), Qt.transparent)
|
86
|
+
level_width = (self._level / 100.0) * self.width()
|
87
|
+
painter.setBrush(palette.color(QPalette.ButtonText))
|
88
|
+
painter.setPen(Qt.NoPen)
|
89
|
+
painter.drawRect(0, 0, level_width, self.height())
|
90
|
+
|
91
|
+
"""
|
92
|
+
# --- bar from center ---
|
93
|
+
def paintEvent(self, event):
|
94
|
+
painter = QPainter(self)
|
95
|
+
painter.fillRect(self.rect(), Qt.transparent)
|
96
|
+
level_width = (self._level / 100.0) * self.width()
|
97
|
+
half_level_width = level_width / 2
|
98
|
+
center_x = self.width() / 2
|
99
|
+
rect_x = center_x - half_level_width
|
100
|
+
painter.setBrush(Qt.green)
|
101
|
+
painter.setPen(Qt.NoPen)
|
102
|
+
painter.drawRect(rect_x, 0, level_width, self.height())
|
103
|
+
"""
|
@@ -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.18 03:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
from PySide6.QtCore import Qt
|
@@ -16,6 +16,8 @@ from PySide6.QtWidgets import QLabel, QHBoxLayout, QWidget, QPushButton, QVBoxLa
|
|
16
16
|
from pygpt_net.core.events import Event, AppEvent
|
17
17
|
from pygpt_net.ui.widget.option.toggle_label import ToggleLabel
|
18
18
|
from pygpt_net.utils import trans
|
19
|
+
from .bar import InputBar
|
20
|
+
|
19
21
|
import pygpt_net.icons_rc
|
20
22
|
|
21
23
|
class VoiceControlButton(QWidget):
|
@@ -34,7 +36,7 @@ class VoiceControlButton(QWidget):
|
|
34
36
|
self.btn_toggle.setCursor(Qt.PointingHandCursor)
|
35
37
|
self.btn_toggle.setMinimumWidth(200)
|
36
38
|
|
37
|
-
self.bar =
|
39
|
+
self.bar = InputBar(self)
|
38
40
|
self.bar.setLevel(0)
|
39
41
|
|
40
42
|
# status
|
@@ -89,7 +91,7 @@ class AudioInputButton(QWidget):
|
|
89
91
|
self.btn_toggle.setCursor(Qt.PointingHandCursor)
|
90
92
|
self.btn_toggle.setMinimumWidth(200)
|
91
93
|
|
92
|
-
self.bar =
|
94
|
+
self.bar = InputBar(self)
|
93
95
|
self.bar.setLevel(0)
|
94
96
|
|
95
97
|
btn_layout = QVBoxLayout()
|
@@ -133,46 +135,3 @@ class AudioInputButton(QWidget):
|
|
133
135
|
"""Toggle recording"""
|
134
136
|
event = Event(Event.AUDIO_INPUT_RECORD_TOGGLE)
|
135
137
|
self.window.dispatch(event)
|
136
|
-
|
137
|
-
|
138
|
-
class LevelBar(QWidget):
|
139
|
-
def __init__(self, parent=None):
|
140
|
-
super().__init__(parent)
|
141
|
-
self._level = 0.0 # level from 0.0 to 100.0
|
142
|
-
self.setFixedSize(200, 5) # bar size
|
143
|
-
|
144
|
-
def setLevel(self, level):
|
145
|
-
"""
|
146
|
-
Set volume level
|
147
|
-
|
148
|
-
:param level: level
|
149
|
-
"""
|
150
|
-
self._level = level
|
151
|
-
self.update()
|
152
|
-
|
153
|
-
def paintEvent(self, event):
|
154
|
-
"""
|
155
|
-
Paint event
|
156
|
-
|
157
|
-
:param event: event
|
158
|
-
"""
|
159
|
-
painter = QPainter(self)
|
160
|
-
painter.fillRect(self.rect(), Qt.transparent)
|
161
|
-
level_width = (self._level / 100.0) * self.width()
|
162
|
-
painter.setBrush(Qt.green)
|
163
|
-
painter.setPen(Qt.NoPen)
|
164
|
-
painter.drawRect(0, 0, level_width, self.height())
|
165
|
-
|
166
|
-
"""
|
167
|
-
# --- bar from center ---
|
168
|
-
def paintEvent(self, event):
|
169
|
-
painter = QPainter(self)
|
170
|
-
painter.fillRect(self.rect(), Qt.transparent)
|
171
|
-
level_width = (self._level / 100.0) * self.width()
|
172
|
-
half_level_width = level_width / 2
|
173
|
-
center_x = self.width() / 2
|
174
|
-
rect_x = center_x - half_level_width
|
175
|
-
painter.setBrush(Qt.green)
|
176
|
-
painter.setPen(Qt.NoPen)
|
177
|
-
painter.drawRect(rect_x, 0, level_width, self.height())
|
178
|
-
"""
|
@@ -24,7 +24,7 @@ class SnapDialogCamera(QDialog):
|
|
24
24
|
super(SnapDialogCamera, self).__init__(window)
|
25
25
|
self.window = window
|
26
26
|
self.setParent(window)
|
27
|
-
self.setWindowTitle("Snap detected")
|
27
|
+
self.setWindowTitle("Snap version detected")
|
28
28
|
self.cmd = CmdLabel(self.window, "sudo snap connect pygpt:camera")
|
29
29
|
|
30
30
|
self.btn = QPushButton("OK")
|
@@ -34,8 +34,8 @@ class SnapDialogCamera(QDialog):
|
|
34
34
|
# layout
|
35
35
|
self.layout = QVBoxLayout()
|
36
36
|
self.message = QLabel(
|
37
|
-
"Camera
|
38
|
-
"Run the following command to enable the camera:")
|
37
|
+
"Camera not connected? It must be connected in the Snap environment.\n"
|
38
|
+
"Run the following command to enable the camera and restart the application:")
|
39
39
|
self.message.setStyleSheet("margin: 10px 0px 10px 0px;")
|
40
40
|
self.layout.addWidget(self.message)
|
41
41
|
self.layout.addWidget(self.cmd)
|
@@ -54,7 +54,7 @@ class SnapDialogAudioInput(QDialog):
|
|
54
54
|
super(SnapDialogAudioInput, self).__init__(window)
|
55
55
|
self.window = window
|
56
56
|
self.setParent(window)
|
57
|
-
self.setWindowTitle("Snap is detected")
|
57
|
+
self.setWindowTitle("Snap version is detected")
|
58
58
|
self.cmd = CmdLabel(self.window, "sudo snap connect pygpt:alsa && sudo snap connect pygpt:audio-record :audio-record")
|
59
59
|
|
60
60
|
self.btn = QPushButton("OK")
|
@@ -64,8 +64,39 @@ class SnapDialogAudioInput(QDialog):
|
|
64
64
|
# layout
|
65
65
|
self.layout = QVBoxLayout()
|
66
66
|
self.message = QLabel(
|
67
|
-
"Microphone
|
68
|
-
"
|
67
|
+
"Tip: Microphone must be manually connected in the Snap environment.\n"
|
68
|
+
"If it is connected, click on the OK button, and this warning will not be displayed again.\n"
|
69
|
+
"If it is NOT connected yet, run the following command and restart the application:")
|
70
|
+
self.message.setStyleSheet("margin: 10px 0px 10px 0px;")
|
71
|
+
self.layout.addWidget(self.message)
|
72
|
+
self.layout.addWidget(self.cmd)
|
73
|
+
self.layout.addWidget(self.btn)
|
74
|
+
self.layout.addStretch()
|
75
|
+
self.setLayout(self.layout)
|
76
|
+
|
77
|
+
|
78
|
+
class SnapDialogAudioOutput(QDialog):
|
79
|
+
def __init__(self, window=None):
|
80
|
+
"""
|
81
|
+
Snap dialog for audio output
|
82
|
+
|
83
|
+
:param window: main window
|
84
|
+
"""
|
85
|
+
super(SnapDialogAudioOutput, self).__init__(window)
|
86
|
+
self.window = window
|
87
|
+
self.setParent(window)
|
88
|
+
self.setWindowTitle("Snap version is detected")
|
89
|
+
self.cmd = CmdLabel(self.window, "sudo snap connect pygpt:alsa && sudo snap connect pygpt:audio-playback")
|
90
|
+
|
91
|
+
self.btn = QPushButton("OK")
|
92
|
+
self.btn.clicked.connect(self.accept)
|
93
|
+
self.btn.setStyleSheet("margin: 10px 0px 0px 0px;")
|
94
|
+
|
95
|
+
# layout
|
96
|
+
self.layout = QVBoxLayout()
|
97
|
+
self.message = QLabel(
|
98
|
+
"Audio Device not connected? It must be connected in the Snap environment.\n"
|
99
|
+
"Run the following command to enable the audio output and restart the application:")
|
69
100
|
self.message.setStyleSheet("margin: 10px 0px 10px 0px;")
|
70
101
|
self.layout.addWidget(self.message)
|
71
102
|
self.layout.addWidget(self.cmd)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pygpt-net
|
3
|
-
Version: 2.4.
|
3
|
+
Version: 2.4.54
|
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.54** | build: **2025.01.18** | Python: **>=3.10, <3.13**
|
97
97
|
|
98
98
|
> Official website: https://pygpt.net | Documentation: https://pygpt.readthedocs.io
|
99
99
|
>
|
@@ -212,6 +212,13 @@ sudo snap connect pygpt:audio-record :audio-record
|
|
212
212
|
sudo snap connect pygpt:alsa
|
213
213
|
```
|
214
214
|
|
215
|
+
**Using audio output:** to use audio output in Snap version you must connect the audio with:
|
216
|
+
|
217
|
+
```commandline
|
218
|
+
sudo snap connect pygpt:audio-playback
|
219
|
+
sudo snap connect pygpt:alsa
|
220
|
+
```
|
221
|
+
|
215
222
|
**Connecting IPython in Docker in Snap version**:
|
216
223
|
|
217
224
|
To use IPython in the Snap version, you must connect PyGPT to the Docker daemon:
|
@@ -4044,6 +4051,15 @@ may consume additional tokens that are not displayed in the main window.
|
|
4044
4051
|
|
4045
4052
|
## Recent changes:
|
4046
4053
|
|
4054
|
+
**2.4.54 (2025-01-18)**
|
4055
|
+
|
4056
|
+
- Audio output switched from PyGame to PyAudio. It may be necessary to manually connect Alsa in Snap version with: "sudo snap connect pygpt:alsa".
|
4057
|
+
- Added audio output volume progress bar.
|
4058
|
+
|
4059
|
+
**2.4.53 (2025-01-17)**
|
4060
|
+
|
4061
|
+
- Fix: issue #89
|
4062
|
+
|
4047
4063
|
**2.4.52 (2025-01-17)**
|
4048
4064
|
|
4049
4065
|
- Improved audio input button visibility toggle.
|
@@ -1,9 +1,9 @@
|
|
1
|
-
CHANGELOG.md,sha256=
|
2
|
-
README.md,sha256=
|
1
|
+
CHANGELOG.md,sha256=9kJiaQVA08r9redE_iYTETXGixl9cryuw61GQveLdqQ,81710
|
2
|
+
README.md,sha256=4YCoQAqxVyAhDdD9opXn0-M7zqUjDlPHSGr1c0QdbxQ,162714
|
3
3
|
icon.png,sha256=CzcINJaU23a9hNjsDlDNbyuiEvKZ4Wg6DQVYF6SpuRg,13970
|
4
|
-
pygpt_net/CHANGELOG.txt,sha256=
|
4
|
+
pygpt_net/CHANGELOG.txt,sha256=xWt9AnWkqD1C--Zh8yv7kq9_LtMMaFf03IQ5VHD8Kng,80212
|
5
5
|
pygpt_net/LICENSE,sha256=dz9sfFgYahvu2NZbx4C1xCsVn9GVer2wXcMkFRBvqzY,1146
|
6
|
-
pygpt_net/__init__.py,sha256=
|
6
|
+
pygpt_net/__init__.py,sha256=J52ofbEM6kTMBSYGxEXT_LggHYzeNSGBnF_0DNlsn0k,1307
|
7
7
|
pygpt_net/app.py,sha256=i02M96uLngAs_XZCS1Mi84vb3Okx8ZZewbTdhCqFolM,16029
|
8
8
|
pygpt_net/config.py,sha256=Qc1FOBtTf3O6A6-6KoqUGtoJ0u8hXQeowvCVbZFwtik,16405
|
9
9
|
pygpt_net/container.py,sha256=BemiVZPpPNIzfB-ZvnZeeBPFu-AcX2c30OqYFylEjJc,4023
|
@@ -60,7 +60,7 @@ pygpt_net/controller/debug/__init__.py,sha256=Dn12CfDYml_n4Xq3mWkafUrM-UVXFEU1mD
|
|
60
60
|
pygpt_net/controller/dialogs/__init__.py,sha256=sJHyZxkAn9QKTegUqx_xETesN2ecMBkrtf-VsCubr2w,1008
|
61
61
|
pygpt_net/controller/dialogs/confirm.py,sha256=EpLYx4cAyb3S723-ACU-nCvcx0lH9tj4upLnjPiekF8,15875
|
62
62
|
pygpt_net/controller/dialogs/debug.py,sha256=v6E85vyCwfaDG9XZysxhBjRwlrDkbYC-NxUnDamNRpk,5980
|
63
|
-
pygpt_net/controller/dialogs/info.py,sha256=
|
63
|
+
pygpt_net/controller/dialogs/info.py,sha256=cK7CR2_l11GAepKDN6J2paKYfk5vSjZHQijacsLkm2Q,3410
|
64
64
|
pygpt_net/controller/files.py,sha256=1Zm9L8-rhLG-GjRQDaOCkAFocAAobTQj-D3ILxLUGn4,16135
|
65
65
|
pygpt_net/controller/finder.py,sha256=4jl8EzTVR1Wc0dJkVwacAdvBiuF1CyOSKB4Qewju0Jw,4955
|
66
66
|
pygpt_net/controller/idx/__init__.py,sha256=oY6clG2YANYB_wJumnOl78ugU3V5c_sG1WIwRyBCVOo,10161
|
@@ -125,7 +125,7 @@ pygpt_net/core/attachments/__init__.py,sha256=bUqvfPqlpdXiGf3GvS1kTE45A0Q1Eo3kpU
|
|
125
125
|
pygpt_net/core/attachments/context.py,sha256=tQM3z_gLI99Ox47XZtVcUnOdfaPYKQwXhm1EJaNikvE,25057
|
126
126
|
pygpt_net/core/attachments/worker.py,sha256=_aUCyi5-Mbz0IGfgY6QKBZ6MFz8aKRDfKasbBVXg7kU,1341
|
127
127
|
pygpt_net/core/audio/__init__.py,sha256=uszH6pqMToDzL0WpPeUvVlyJ8RN4gFmQbsL4GFYMIdc,4521
|
128
|
-
pygpt_net/core/audio/capture.py,sha256=
|
128
|
+
pygpt_net/core/audio/capture.py,sha256=cR3PsnbxJ8yPE5oirHFAieAIaDGXynUxA4aitocXkgY,11223
|
129
129
|
pygpt_net/core/audio/context.py,sha256=2XpXWhDC09iUvc0FRMq9BF2_rnQ60ZG4Js6LbO5MohY,1115
|
130
130
|
pygpt_net/core/audio/whisper.py,sha256=WZ_fNQ06s1NBxyoYB-lTFqDO6ARcnq9MZFekRaTNxTo,993
|
131
131
|
pygpt_net/core/bridge/__init__.py,sha256=ezS02_2wUrnV6eTF33wfob8rVWM5snfY92-PF_i15uQ,9568
|
@@ -247,9 +247,9 @@ pygpt_net/css_rc.py,sha256=i13kX7irhbYCWZ5yJbcMmnkFp_UfS4PYnvRFSPF7XXo,11349
|
|
247
247
|
pygpt_net/data/audio/click_off.mp3,sha256=aNiRDP1pt-Jy7ija4YKCNFBwvGWbzU460F4pZWZDS90,65201
|
248
248
|
pygpt_net/data/audio/click_on.mp3,sha256=qfdsSnthAEHVXzeyN4LlC0OvXuyW8p7stb7VXtlvZ1k,65201
|
249
249
|
pygpt_net/data/audio/ok.mp3,sha256=LTiV32pEBkpUGBkKkcOdOFB7Eyt_QoP2Nv6c5AaXftk,32256
|
250
|
-
pygpt_net/data/config/config.json,sha256=
|
251
|
-
pygpt_net/data/config/models.json,sha256=
|
252
|
-
pygpt_net/data/config/modes.json,sha256=
|
250
|
+
pygpt_net/data/config/config.json,sha256=BLBW_HrLqQZJ73e0ZuIBs2dZZwyoMM7-kvHlfKUojEU,19805
|
251
|
+
pygpt_net/data/config/models.json,sha256=BFVoxYzgJAnhvoPh7BM43eS8HSyUsilD1gJNFuIq5lM,61940
|
252
|
+
pygpt_net/data/config/modes.json,sha256=kcA7fM9AeHGKJ3IiCNaNuBV8UQLnIto3eG_2CoBblgU,1923
|
253
253
|
pygpt_net/data/config/presets/agent_openai.json,sha256=vMTR-soRBiEZrpJJHuFLWyx8a3Ez_BqtqjyXgxCAM_Q,733
|
254
254
|
pygpt_net/data/config/presets/agent_openai_assistant.json,sha256=awJw9lNTGpKML6SJUShVn7lv8AXh0oic7wBeyoN7AYs,798
|
255
255
|
pygpt_net/data/config/presets/agent_planner.json,sha256=a6Rv58Bnm2STNWB0Rw_dGhnsz6Lb3J8_GwsUVZaTIXc,742
|
@@ -1657,7 +1657,7 @@ pygpt_net/data/locale/plugin.voice_control.zh.ini,sha256=SZNVNOtJedH0IaH44YB4ekv
|
|
1657
1657
|
pygpt_net/data/logo.png,sha256=asjkGb9cP7vjVx9Hdne2bI2GcSlcQ8r_3LBp_znVZj4,19418
|
1658
1658
|
pygpt_net/data/prompts.csv,sha256=dmSg9d3TFPJKvcU7_2hBjA9q1qxjEX-lIPjx1j9rxsM,83051
|
1659
1659
|
pygpt_net/data/win32/README.rtf,sha256=lfvT7Vselk49tRr3hj7Txi6zQP4OTyDU7FmPm8h0qhM,7650
|
1660
|
-
pygpt_net/data/win32/USER-LICENSE.rtf,sha256=
|
1660
|
+
pygpt_net/data/win32/USER-LICENSE.rtf,sha256=WSDcVtNF_7aqTx4FGGEMkA4KrFVQ15gjGlRhjynse-c,2043
|
1661
1661
|
pygpt_net/data/win32/banner.bmp,sha256=eWMV8GTSSWXBDn9VfNkMsEVkuVr_Nk1YqQG_50-_Dt8,85894
|
1662
1662
|
pygpt_net/data/win32/banner_welcome.bmp,sha256=jKUlzecxdq8uWUOhBsAer4GGASO3tAStIfntcUGOsIA,461814
|
1663
1663
|
pygpt_net/data/win32/pygpt.aip,sha256=JeMToDAs7EHPlwvZDM66T8Sxy5h_lCC7s-2FihcVtcI,87160
|
@@ -1701,11 +1701,11 @@ pygpt_net/plugin/agent/__init__.py,sha256=GPbnpS9djcfzuPRxM2mu0hpUPRa51KtUR27Al6
|
|
1701
1701
|
pygpt_net/plugin/agent/config.py,sha256=V4M0boutzxFVWTQxM8UA7HgKUR4v_Y-5dX_XfeLzzL8,9792
|
1702
1702
|
pygpt_net/plugin/audio_input/__init__.py,sha256=vGwDtsPkwCEwiz2ePnzW48Tuhr0VHEc7kQua11VE7tI,15714
|
1703
1703
|
pygpt_net/plugin/audio_input/config.py,sha256=x57IVxBapJp9rwos327T6U0jTFSPeRJ6BorqfYxJ4u0,9197
|
1704
|
-
pygpt_net/plugin/audio_input/simple.py,sha256=
|
1705
|
-
pygpt_net/plugin/audio_input/worker.py,sha256=
|
1706
|
-
pygpt_net/plugin/audio_output/__init__.py,sha256=
|
1704
|
+
pygpt_net/plugin/audio_input/simple.py,sha256=z9YCLGca8dV_i6pOBIAWWQRvp3euL_VDbCNbQVdhsiw,6747
|
1705
|
+
pygpt_net/plugin/audio_input/worker.py,sha256=O-boo_flpqS72GLHlD4YgLvmRe4asgu1HTY5nBXVGrs,11996
|
1706
|
+
pygpt_net/plugin/audio_output/__init__.py,sha256=OnuHRhtzoOkMA5i_TOVqojP_D1j-_pj6-OYYnBoWxfM,8915
|
1707
1707
|
pygpt_net/plugin/audio_output/config.py,sha256=IA2K-9fQMZSwYGyi30Uh5qAlYwuqwaHo3dtDJ13vQdo,1208
|
1708
|
-
pygpt_net/plugin/audio_output/worker.py,sha256=
|
1708
|
+
pygpt_net/plugin/audio_output/worker.py,sha256=Rm13dQEp3h9zzKQEfUBw1Gz-OxGdKsid3iJqHJBNZFw,6546
|
1709
1709
|
pygpt_net/plugin/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1710
1710
|
pygpt_net/plugin/base/config.py,sha256=q5WAcF-h3KZH4bJFYANasM7UmV1v1c43fF1EZ05iF7Y,848
|
1711
1711
|
pygpt_net/plugin/base/plugin.py,sha256=nbBTNh9nuaLcLdWfmcePpPeZeKJElgmOOP5o1uOZJdc,14103
|
@@ -1995,7 +1995,7 @@ pygpt_net/tools/text_editor/__init__.py,sha256=NXgKl9XkA6ecRSn3q154KLsu4FHCz4XL9
|
|
1995
1995
|
pygpt_net/tools/text_editor/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1996
1996
|
pygpt_net/tools/text_editor/ui/dialogs.py,sha256=lOgogExJgnLzq0KdbcHli-HslEZ2uivCI1dFFzEpsRA,2906
|
1997
1997
|
pygpt_net/tools/text_editor/ui/widgets.py,sha256=K_yxkyMyLfBfXXZ8iOczci10tPlsBJ5JlUDxrzObm0s,2754
|
1998
|
-
pygpt_net/ui/__init__.py,sha256=
|
1998
|
+
pygpt_net/ui/__init__.py,sha256=RZmxge47FcBXfjpD8W5K-QcwnTirFDBmRxKQHAUafa0,9225
|
1999
1999
|
pygpt_net/ui/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2000
2000
|
pygpt_net/ui/base/config_dialog.py,sha256=92CnUmDFv74BQ6mbwhHjn3L_s7IYhJX3sChFqAD_5Vo,9255
|
2001
2001
|
pygpt_net/ui/base/context_menu.py,sha256=Mq2UPWBwc9eaHc9qVOMQEQ7a2343wsrMrMnEzYdvs6Q,3245
|
@@ -2021,7 +2021,7 @@ pygpt_net/ui/dialog/preset_plugins.py,sha256=ynqc0aWjU7MTL4jxcVKaRH_tC9uzeWJCUzU
|
|
2021
2021
|
pygpt_net/ui/dialog/profile.py,sha256=Xk9NNQmr1A5pRUxdedu7ePEBq5OYhLT8UInuRWYBktU,4105
|
2022
2022
|
pygpt_net/ui/dialog/rename.py,sha256=Spb7cUVq1ivy3Zg28SBACJ7p_GwJ1gm82Oz9Ld_a_FU,973
|
2023
2023
|
pygpt_net/ui/dialog/settings.py,sha256=XZQiNI-AbrUBT-mMo8wdQGJS9bOunaY6dYKAFdzDiUI,15725
|
2024
|
-
pygpt_net/ui/dialog/snap.py,sha256=
|
2024
|
+
pygpt_net/ui/dialog/snap.py,sha256=LQlDsF4E-ernI8GFL1T-q9wZnoo57xyYpg5HKmeSbg4,1065
|
2025
2025
|
pygpt_net/ui/dialog/start.py,sha256=wHGKD6d4XGaKzDDvUCZOe_fK1aCaD21Vi_8R2td7-Zk,2459
|
2026
2026
|
pygpt_net/ui/dialog/update.py,sha256=wJDe2D55XqlAd30vHLeWAuGmgaElwhTd82GIxzvqf4w,842
|
2027
2027
|
pygpt_net/ui/dialog/url.py,sha256=SziMn4Wzyld7Os6b4QdaYAxjwcIWfydmorhTSG7WeUo,949
|
@@ -2034,7 +2034,7 @@ pygpt_net/ui/layout/chat/attachments_ctx.py,sha256=qyidK2bbTufWX-crtEhat2i3-Juqq
|
|
2034
2034
|
pygpt_net/ui/layout/chat/attachments_uploaded.py,sha256=8xKa9xwU56ESSfBN5ybwT_BUZEwgij-tjHbhhzNuV2U,5462
|
2035
2035
|
pygpt_net/ui/layout/chat/calendar.py,sha256=Vc6ztv4S_gO2ceqO-SekXyqI4V7cbf-JN_sZ5dwbl34,5812
|
2036
2036
|
pygpt_net/ui/layout/chat/explorer.py,sha256=VGWS6JhXSJV2ry1pIY1Ijme6DvYHfsnKwfrieVXHc3U,1280
|
2037
|
-
pygpt_net/ui/layout/chat/input.py,sha256=
|
2037
|
+
pygpt_net/ui/layout/chat/input.py,sha256=54Kd3KJNgN41vyydSsRtr9554BS_IDkymPQGiYEkaYY,10907
|
2038
2038
|
pygpt_net/ui/layout/chat/markdown.py,sha256=hjYY8Da1z0IZZD086_csMcDY1wwagpuQTDZ-XfgeNgs,18656
|
2039
2039
|
pygpt_net/ui/layout/chat/output.py,sha256=4a_BCzk2MKt5z-KYKD8iaapiS4Kj1R7Gj-8v-5R4BLs,9887
|
2040
2040
|
pygpt_net/ui/layout/chat/painter.py,sha256=2yGU9GET5PpcGteGyWcHTtodKqAL7rxrqxhQ10vhodM,5471
|
@@ -2073,8 +2073,9 @@ pygpt_net/ui/widget/__init__.py,sha256=X9-pucLqQF9_ocDV-qNY6EQAJ_4dubGb-7TcWIzCX
|
|
2073
2073
|
pygpt_net/ui/widget/anims/loader.py,sha256=PzxHraeABUyMIZlg4Rk_tbJnUPmiwxlhdcHaCkURWWw,5989
|
2074
2074
|
pygpt_net/ui/widget/anims/toggles.py,sha256=_L2533IYyDkbnPCok9XBriIaKM5E9sHSznrwVWpKOOs,5755
|
2075
2075
|
pygpt_net/ui/widget/audio/__init__.py,sha256=8HT4tQFqQogEEpGYTv2RplKBthlsFKcl5egnv4lzzEw,488
|
2076
|
+
pygpt_net/ui/widget/audio/bar.py,sha256=7i8zxSa1UDjYdXVY84ixJv1FMX-tVCrZSfB6bjxZ9z0,3198
|
2076
2077
|
pygpt_net/ui/widget/audio/input.py,sha256=t9VAhP15HkSOvNV2crI3Kg6AgrQDj-wSQiiYTMlvK60,1721
|
2077
|
-
pygpt_net/ui/widget/audio/input_button.py,sha256=
|
2078
|
+
pygpt_net/ui/widget/audio/input_button.py,sha256=xNK3dFN5BC-2RTsBRY7RDKSKqrKMdckei6Oavr0_XWE,4514
|
2078
2079
|
pygpt_net/ui/widget/audio/output.py,sha256=UxkiCnVT9DNFeByDGTFW_CK0LW8xSvhEK1zygtHvx4k,1586
|
2079
2080
|
pygpt_net/ui/widget/calendar/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2080
2081
|
pygpt_net/ui/widget/calendar/select.py,sha256=vSEaQZmyeDhmyOfptWv6me_6IaYpQb5Jgc_mGDIe_4U,9051
|
@@ -2101,7 +2102,7 @@ pygpt_net/ui/widget/dialog/profile.py,sha256=vMYf-9c6HKAOqtSuw-HpBEUgmCSxEQuIrGl
|
|
2101
2102
|
pygpt_net/ui/widget/dialog/rename.py,sha256=HcImKH_gUHcyB1k5llwStmrlXvcSpxgR2V6IuEdMuCU,2191
|
2102
2103
|
pygpt_net/ui/widget/dialog/settings.py,sha256=fKzbme2tdxzTSiQMNnCEgyD3lwCzFjLi85ikWulisGw,1614
|
2103
2104
|
pygpt_net/ui/widget/dialog/settings_plugin.py,sha256=Kf1ZK_RY9CAnfeuzPoQ4wgsFb2yQl7X-VKzsYETA55o,1696
|
2104
|
-
pygpt_net/ui/widget/dialog/snap.py,sha256=
|
2105
|
+
pygpt_net/ui/widget/dialog/snap.py,sha256=4JojKDrDECFbNBnsE0505z336xLVskFz9TK3XF02Mtk,4074
|
2105
2106
|
pygpt_net/ui/widget/dialog/update.py,sha256=aAmk-unSaGie3VXMaXmorza-p9Isrm06d0iSYnfcq3U,6900
|
2106
2107
|
pygpt_net/ui/widget/dialog/url.py,sha256=7I17Pp9P2c3G1pODEY5dum_AF0nFnu2BMfbWTgEES-M,8765
|
2107
2108
|
pygpt_net/ui/widget/dialog/workdir.py,sha256=D-C3YIt-wCoI-Eh7z--Z4R6P1UvtpkxeiaVcI-ycFck,1523
|
@@ -2175,8 +2176,8 @@ pygpt_net/ui/widget/textarea/web.py,sha256=9FoL02QY6mOxtc4t4fe8X7fVDIdPn9Sb_fwsv
|
|
2175
2176
|
pygpt_net/ui/widget/vision/__init__.py,sha256=8HT4tQFqQogEEpGYTv2RplKBthlsFKcl5egnv4lzzEw,488
|
2176
2177
|
pygpt_net/ui/widget/vision/camera.py,sha256=T8b5cmK6uhf_WSSxzPt_Qod8JgMnst6q8sQqRvgQiSA,2584
|
2177
2178
|
pygpt_net/utils.py,sha256=Gsh_mITVke3bb8o-Ke57l__xA5a9Wv4t7tlsnSQULj8,6655
|
2178
|
-
pygpt_net-2.4.
|
2179
|
-
pygpt_net-2.4.
|
2180
|
-
pygpt_net-2.4.
|
2181
|
-
pygpt_net-2.4.
|
2182
|
-
pygpt_net-2.4.
|
2179
|
+
pygpt_net-2.4.54.dist-info/LICENSE,sha256=rbPqNB_xxANH8hKayJyIcTwD4bj4Y2G-Mcm85r1OImM,1126
|
2180
|
+
pygpt_net-2.4.54.dist-info/METADATA,sha256=0fJiXhGHCcQEGca03Bc5_3Vdan85g85lZsU99qR-tn4,167593
|
2181
|
+
pygpt_net-2.4.54.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
2182
|
+
pygpt_net-2.4.54.dist-info/entry_points.txt,sha256=qvpII6UHIt8XfokmQWnCYQrTgty8FeJ9hJvOuUFCN-8,43
|
2183
|
+
pygpt_net-2.4.54.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|