python-voiceio 0.9.2__py3-none-any.whl → 0.9.3__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.
- {python_voiceio-0.9.2.dist-info → python_voiceio-0.9.3.dist-info}/METADATA +1 -1
- {python_voiceio-0.9.2.dist-info → python_voiceio-0.9.3.dist-info}/RECORD +10 -10
- voiceio/__init__.py +1 -1
- voiceio/app.py +22 -2
- voiceio/config.py +5 -0
- voiceio/recorder.py +22 -3
- {python_voiceio-0.9.2.dist-info → python_voiceio-0.9.3.dist-info}/WHEEL +0 -0
- {python_voiceio-0.9.2.dist-info → python_voiceio-0.9.3.dist-info}/entry_points.txt +0 -0
- {python_voiceio-0.9.2.dist-info → python_voiceio-0.9.3.dist-info}/licenses/LICENSE +0 -0
- {python_voiceio-0.9.2.dist-info → python_voiceio-0.9.3.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
python_voiceio-0.9.
|
|
2
|
-
voiceio/__init__.py,sha256=
|
|
1
|
+
python_voiceio-0.9.3.dist-info/licenses/LICENSE,sha256=Gz61o8jFTAvZUZyB3nWDB3DQQVuipjfPkVu9W8hBHM0,1072
|
|
2
|
+
voiceio/__init__.py,sha256=xKd3pzbczuMsdB08eLAOqZDUd_q1IRxwZ_ccAFL4c4A,22
|
|
3
3
|
voiceio/__main__.py,sha256=xT5QCGGreYMisHO7Lh_Y-xAQ2TOzG2D7npKknGNcWSY,53
|
|
4
|
-
voiceio/app.py,sha256=
|
|
4
|
+
voiceio/app.py,sha256=8xS_MySy6cvpxXDcd0-6YwQK6KW_iT8Vdf6FqzYUXpI,74743
|
|
5
5
|
voiceio/audit.py,sha256=p4F2BBX4wEC9eS8MSplzfXL52XC2dyIKbgrRvR-WbTU,15802
|
|
6
6
|
voiceio/autocorrect.py,sha256=jGsglEYwAHWk2uWedeEZzyAMW2LWO_8nQGZgrWYy4Dc,26552
|
|
7
7
|
voiceio/autocorrect_state.py,sha256=BNzdHP5slcOV_-OU4MlaKE7xgVJzrPncsYFK30JWTs8,6858
|
|
@@ -9,7 +9,7 @@ voiceio/backends.py,sha256=-rs1YhPblub4NjFb6qCD7Ih9FqBRXtPuvjVv9bQoQ1w,368
|
|
|
9
9
|
voiceio/cli.py,sha256=QE8N7N3d1O7r9-u_jbYMAH9gw0ILX7dSxDZZYj83lIs,78969
|
|
10
10
|
voiceio/clipboard_read.py,sha256=lz75CkRGh7pyvO6xvoUmxJDl-Gwie1xlXQHK70PO84I,4261
|
|
11
11
|
voiceio/commands.py,sha256=Vhtn8s5G5OcCbRN44YZ-_14Fa85ISXl_3Ix-KqSHs2A,4694
|
|
12
|
-
voiceio/config.py,sha256=
|
|
12
|
+
voiceio/config.py,sha256=IxXfs780V4eMhbfoyHZAUER7cmjg950Lp1wsvm9aEIU,15563
|
|
13
13
|
voiceio/consent.py,sha256=jtdp1TkTbicUSTCDmV4qo4SdbS4kQpYzy1Kjc_7pJVw,1883
|
|
14
14
|
voiceio/corrections.py,sha256=7moKhkVvo5CZU1mZobV2-MajkcHiwliKBY1dSBFh0w0,7445
|
|
15
15
|
voiceio/demo.py,sha256=QRNJuNObXCsjwGD-Cz3dh81cfb21xiuSeVyyU720U9Q,8673
|
|
@@ -26,7 +26,7 @@ voiceio/platform.py,sha256=f_8MmC5q1sCEuEPyKjRqlVvV9FExuGmwn_aJXhkpiEk,11809
|
|
|
26
26
|
voiceio/postcorrect.py,sha256=iyO7MPIR4a4XIASEGOs9Y3iUXVTfwtVkhVOWj2vY1lk,11201
|
|
27
27
|
voiceio/postprocess.py,sha256=9grkq3I6XgiQV6ZQbIw2_fOUe57tzC7GBPvLXqhhdTs,2979
|
|
28
28
|
voiceio/prompt.py,sha256=9iza8KoQxvO_U9NPMJ8Ep7j-zkIs9nW8N5sacCRpsEk,2904
|
|
29
|
-
voiceio/recorder.py,sha256=
|
|
29
|
+
voiceio/recorder.py,sha256=x3WG-3GXvqHb0yagXXVeDgjD5PnG6xv6MyRHMTnB68w,13885
|
|
30
30
|
voiceio/retention.py,sha256=i_VWPCyykT4kQ1uKilTplpiIrACTYljn09BU1vL71A0,6019
|
|
31
31
|
voiceio/service.py,sha256=1YhnDPHnu0Aw66uwsp05TWfs18bf3io_h6r8eNla7nA,12525
|
|
32
32
|
voiceio/snapshots.py,sha256=bm-lzIeYucDUDlPBZiFiWd-jyB2I6Ft1jRANZCO6go4,2351
|
|
@@ -74,8 +74,8 @@ voiceio/typers/pynput_type.py,sha256=DTtkT59M-EKOAlTNkvcZrRvf_Fq52OpI8S5t_8S-QAY
|
|
|
74
74
|
voiceio/typers/wtype.py,sha256=d1wG-HZdYDQxXIysV_Xvk9HixDpaJgl3VEoKbP5vhIs,1786
|
|
75
75
|
voiceio/typers/xdotool.py,sha256=dh1zhPqUT8ihJahJ7ZKm6PtfYY087UAzADx664DvQOM,1356
|
|
76
76
|
voiceio/typers/ydotool.py,sha256=dt0W9ot__W8LQG2so8vZLGIw9leK2Q6g3i-Voo0LXE4,5327
|
|
77
|
-
python_voiceio-0.9.
|
|
78
|
-
python_voiceio-0.9.
|
|
79
|
-
python_voiceio-0.9.
|
|
80
|
-
python_voiceio-0.9.
|
|
81
|
-
python_voiceio-0.9.
|
|
77
|
+
python_voiceio-0.9.3.dist-info/METADATA,sha256=h-f14EX3kSMP26A2Y12MJbprM_03l0TkRSm0wIYWrao,15877
|
|
78
|
+
python_voiceio-0.9.3.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
79
|
+
python_voiceio-0.9.3.dist-info/entry_points.txt,sha256=U64fA65zxzyLoC8bgbn2ztQVWHLsc0o0H0qCk1J9DMc,218
|
|
80
|
+
python_voiceio-0.9.3.dist-info/top_level.txt,sha256=piwtn309lD6uexQyXdZ-efAVBJF9y6Wfr48Z-8zkNhg,8
|
|
81
|
+
python_voiceio-0.9.3.dist-info/RECORD,,
|
voiceio/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.9.
|
|
1
|
+
__version__ = "0.9.3"
|
voiceio/app.py
CHANGED
|
@@ -283,8 +283,28 @@ class VoiceIO:
|
|
|
283
283
|
self._last_hotkey = now
|
|
284
284
|
self._toggle()
|
|
285
285
|
|
|
286
|
-
def _on_auto_stop(self) -> None:
|
|
287
|
-
"""Called from audio thread when
|
|
286
|
+
def _on_auto_stop(self, reason: str = "silence") -> None:
|
|
287
|
+
"""Called from the audio thread when the recorder auto-stops.
|
|
288
|
+
|
|
289
|
+
reason="silence": spoke, then went quiet — a normal end of dictation.
|
|
290
|
+
reason="no_speech": nothing was heard the whole time — a muted mic or a
|
|
291
|
+
hotkey pressed by accident. Surface it so it isn't a silent failure
|
|
292
|
+
(today's Discord-mute confusion: recording ran, nothing was captured,
|
|
293
|
+
and there was no sign why).
|
|
294
|
+
"""
|
|
295
|
+
if reason == "no_speech":
|
|
296
|
+
from voiceio import feedback
|
|
297
|
+
if not self.recorder.has_signal():
|
|
298
|
+
feedback.notify(
|
|
299
|
+
"VoiceIO: microphone is muted",
|
|
300
|
+
"Stopped — no audio is reaching voiceio. Check your mic's "
|
|
301
|
+
"mute button and that the right input device is selected.",
|
|
302
|
+
)
|
|
303
|
+
else:
|
|
304
|
+
feedback.notify(
|
|
305
|
+
"VoiceIO: stopped — no speech detected",
|
|
306
|
+
"Recording auto-stopped after silence.",
|
|
307
|
+
)
|
|
288
308
|
threading.Thread(target=self._request_stop, daemon=True).start()
|
|
289
309
|
|
|
290
310
|
def _request_stop(self) -> None:
|
voiceio/config.py
CHANGED
|
@@ -71,6 +71,11 @@ class AudioConfig:
|
|
|
71
71
|
silence_threshold: float = 0.01
|
|
72
72
|
silence_duration: float = 0.6
|
|
73
73
|
auto_stop_silence_secs: float = 5.0
|
|
74
|
+
# Safety net for a muted mic or a forgotten hotkey: if NO speech is heard
|
|
75
|
+
# for this long from the start, stop and notify. The 5s auto-stop above
|
|
76
|
+
# only fires once speech has been heard, so it can't catch a dead mic.
|
|
77
|
+
# 0 disables.
|
|
78
|
+
auto_stop_no_speech_secs: float = 20.0
|
|
74
79
|
vad_backend: str = "silero" # "silero" | "rms"
|
|
75
80
|
vad_threshold: float = 0.5 # Silero speech probability threshold
|
|
76
81
|
|
voiceio/recorder.py
CHANGED
|
@@ -108,9 +108,12 @@ class AudioRecorder:
|
|
|
108
108
|
|
|
109
109
|
# Auto-stop on sustained silence
|
|
110
110
|
self._auto_stop_secs = cfg.auto_stop_silence_secs
|
|
111
|
+
self._no_speech_secs = cfg.auto_stop_no_speech_secs
|
|
111
112
|
self._sustained_silence = 0.0
|
|
112
113
|
self._heard_speech = False
|
|
113
|
-
|
|
114
|
+
# Called with a reason: "silence" (spoke then paused) or "no_speech"
|
|
115
|
+
# (nothing ever heard — a muted mic or a forgotten hotkey).
|
|
116
|
+
self._on_auto_stop: Callable[[str], None] | None = None
|
|
114
117
|
|
|
115
118
|
# Heartbeat: updated by _callback, checked by health watchdog
|
|
116
119
|
self._last_callback_time: float = 0.0
|
|
@@ -260,7 +263,7 @@ class AudioRecorder:
|
|
|
260
263
|
"""Set/clear the speech pause callback (used by streaming session)."""
|
|
261
264
|
self._on_speech_pause = callback
|
|
262
265
|
|
|
263
|
-
def set_on_auto_stop(self, callback: Callable[[], None] | None) -> None:
|
|
266
|
+
def set_on_auto_stop(self, callback: Callable[[str], None] | None) -> None:
|
|
264
267
|
"""Set/clear the auto-stop callback (fires after sustained silence)."""
|
|
265
268
|
self._on_auto_stop = callback
|
|
266
269
|
|
|
@@ -340,4 +343,20 @@ class AudioRecorder:
|
|
|
340
343
|
self._on_auto_stop = None
|
|
341
344
|
self._sustained_silence = 0.0
|
|
342
345
|
log.info("Auto-stopping after %.0fs of silence", self._auto_stop_secs)
|
|
343
|
-
cb()
|
|
346
|
+
cb("silence")
|
|
347
|
+
|
|
348
|
+
# Safety net: nothing heard at all for a long time. Because speech
|
|
349
|
+
# resets _sustained_silence AND is gated out by not-_heard_speech, this
|
|
350
|
+
# measures continuous silence from the very start of the recording — a
|
|
351
|
+
# muted mic (all zeros) or a hotkey pressed by accident. Distinct reason
|
|
352
|
+
# so the app can surface it instead of failing silently.
|
|
353
|
+
elif (self._on_auto_stop is not None
|
|
354
|
+
and self._no_speech_secs > 0
|
|
355
|
+
and not self._heard_speech
|
|
356
|
+
and self._sustained_silence >= self._no_speech_secs):
|
|
357
|
+
cb = self._on_auto_stop
|
|
358
|
+
self._on_auto_stop = None
|
|
359
|
+
self._sustained_silence = 0.0
|
|
360
|
+
log.info("Auto-stopping: no speech heard in %.0fs (mic muted?)",
|
|
361
|
+
self._no_speech_secs)
|
|
362
|
+
cb("no_speech")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|