pygpt-net 2.4.53__py3-none-any.whl → 2.4.55__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 +10 -0
- README.md +18 -1
- pygpt_net/CHANGELOG.txt +10 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/controller/lang/mapping.py +2 -1
- pygpt_net/core/audio/capture.py +2 -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 +24 -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 +4 -1
- pygpt_net/data/locale/locale.uk.ini +3 -0
- pygpt_net/data/locale/locale.zh.ini +3 -0
- pygpt_net/data/win32/USER-LICENSE.rtf +0 -0
- pygpt_net/plugin/audio_input/simple.py +23 -7
- 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/provider/core/config/patch.py +9 -1
- 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.53.dist-info → pygpt_net-2.4.55.dist-info}/METADATA +19 -2
- {pygpt_net-2.4.53.dist-info → pygpt_net-2.4.55.dist-info}/RECORD +35 -34
- {pygpt_net-2.4.53.dist-info → pygpt_net-2.4.55.dist-info}/LICENSE +0 -0
- {pygpt_net-2.4.53.dist-info → pygpt_net-2.4.55.dist-info}/WHEEL +0 -0
- {pygpt_net-2.4.53.dist-info → pygpt_net-2.4.55.dist-info}/entry_points.txt +0 -0
@@ -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
|
@@ -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 16:00:00 #
|
10
10
|
# ================================================== #
|
11
11
|
|
12
12
|
import copy
|
@@ -1811,6 +1811,14 @@ class Patch:
|
|
1811
1811
|
if 'audio.input.continuous' not in data:
|
1812
1812
|
data["audio.input.continuous"] = False
|
1813
1813
|
|
1814
|
+
# < 2.4.55
|
1815
|
+
if old < parse_version("2.4.55"):
|
1816
|
+
print("Migrating config from < 2.4.55...")
|
1817
|
+
if 'audio.input.timeout' not in data:
|
1818
|
+
data["audio.input.timeout"] = 120
|
1819
|
+
if 'audio.input.timeout.continuous' not in data:
|
1820
|
+
data["audio.input.timeout.continuous"] = False
|
1821
|
+
|
1814
1822
|
# update file
|
1815
1823
|
migrated = False
|
1816
1824
|
if updated:
|
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.55
|
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.55** | 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,16 @@ may consume additional tokens that are not displayed in the main window.
|
|
4044
4051
|
|
4045
4052
|
## Recent changes:
|
4046
4053
|
|
4054
|
+
**2.4.55 (2025-01-18)**
|
4055
|
+
|
4056
|
+
- Added a new option in settings: Audio -> Recording timeout.
|
4057
|
+
- Added a new option in settings: Audio -> Enable timeout in continuous mode.
|
4058
|
+
|
4059
|
+
**2.4.54 (2025-01-18)**
|
4060
|
+
|
4061
|
+
- Audio output switched from PyGame to PyAudio. It may be necessary to manually connect Alsa in Snap version with: "sudo snap connect pygpt:alsa".
|
4062
|
+
- Added audio output volume progress bar.
|
4063
|
+
|
4047
4064
|
**2.4.53 (2025-01-17)**
|
4048
4065
|
|
4049
4066
|
- Fix: issue #89
|