python-voiceio 1.9.1__tar.gz → 1.9.2__tar.gz
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-1.9.1/python_voiceio.egg-info → python_voiceio-1.9.2}/PKG-INFO +1 -1
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/pyproject.toml +1 -1
- {python_voiceio-1.9.1 → python_voiceio-1.9.2/python_voiceio.egg-info}/PKG-INFO +1 -1
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_streaming.py +62 -0
- python_voiceio-1.9.2/voiceio/__init__.py +1 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/config.py +6 -6
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/streaming.py +65 -26
- python_voiceio-1.9.1/voiceio/__init__.py +0 -1
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/LICENSE +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/README.md +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/python_voiceio.egg-info/SOURCES.txt +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/python_voiceio.egg-info/dependency_links.txt +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/python_voiceio.egg-info/entry_points.txt +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/python_voiceio.egg-info/requires.txt +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/python_voiceio.egg-info/top_level.txt +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/setup.cfg +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_app_wiring.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_audio_quality.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_audio_source.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_backend_probes.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_cancel.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_cli.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_clipboard_read.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_clipboard_typer.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_commands.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_concurrency_lockdown.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_config.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_context_terms.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_corrections.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_decoders.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_engine.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_evdev_uaccess.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_fallback.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_fcitx_bridge.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_feedback_stream.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_focus.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_health.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_hints.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_history.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_hotkey_modes.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_engine_limits.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_engine_listener.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_pending.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_pids.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_ping.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_session.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_textlimit.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_typer.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_idle_audio.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_clean.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_import.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_language.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_metrics.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_pipeline.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_quiet.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_review.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_targets.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_llm.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_llm_api.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_modifier_guard.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_numbers.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_paste_last.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_pipeline.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_platform.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_postcorrect.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_postprocess.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_prebuffer.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_prompt.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_quiet_audio.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_recorder_integration.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_retention.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_robustness.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_security_hardening.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_server.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_service.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_setup.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_suggest.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_tokens.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_transcriber.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_tts.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_typer_manager.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_vad.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_vocabulary.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_wordfreq.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_worker_decode.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/__main__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/app.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/audio_source.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/backends.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/configcmd.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/corrections.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/doctor.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/history.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/learn.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/models.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/servicecmd.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/uninstall.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/vocab.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/clipboard_read.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/commands.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/consent.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/context_terms.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/bias.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/base.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/catalog.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/faster_whisper/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/faster_whisper/worker.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/lanes.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/sherpa.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/whispercpp.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/engine.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/pipeline.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/corrections.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/data/60-voiceio-uaccess.rules +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/data/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/demo.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/display.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/feedback.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/focus.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/health.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hints.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/history.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hotkeys/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hotkeys/base.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hotkeys/chain.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hotkeys/evdev.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hotkeys/pynput_backend.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hotkeys/socket_backend.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ibus/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ibus/engine.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ibus/install.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ibus/pending.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ibus/session.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ibus/textlimit.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/idle_audio.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/augment.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/clean.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/evaluate.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/importer.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/metrics.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/quiet.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/review.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/store.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/teacher.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/train.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/llm.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/llm_api.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/models/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/models/silero_vad.onnx +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/numbers.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/pidlock.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/platform.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/postcorrect.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/postprocess.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/power.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/privacy.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/prompt.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/quiet_audio.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/recorder.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/retention.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/server/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/server/__main__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/server/app.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/server/config.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/server/runtime.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/service.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/configfile.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/extras.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/hotkey.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/noninteractive.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/speech.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/steps.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/system.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/ui.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/sounds/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/sounds/commit.wav +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/sounds/start.wav +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/sounds/stop.wav +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/suggest.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tokens.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tray/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tray/_icons.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tray/_indicator.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tray/_pystray.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/base.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/chain.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/edge_engine.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/espeak.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/piper_engine.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/player.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/__init__.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/base.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/chain.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/clipboard.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/collecting.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/fcitx_bridge.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/ibus.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/manager.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/modifier_guard.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/paste.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/pynput_type.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/wtype.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/xdotool.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/ydotool.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ui.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/vad.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/vocab_stats.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/vocabulary.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/watchdog.py +0 -0
- {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/wordfreq.py +0 -0
|
@@ -693,6 +693,67 @@ class TestSegmentFreeze:
|
|
|
693
693
|
# Display untouched: interim text already covers this audio
|
|
694
694
|
s._display.typer.type_text.assert_not_called()
|
|
695
695
|
|
|
696
|
+
def test_pause_freezes_tail_up_to_the_reported_pause(self):
|
|
697
|
+
from voiceio.streaming import _PAUSE_CUT_BACKOFF_SECS
|
|
698
|
+
s, tr, rec = self._make_session(freeze_secs=8.0)
|
|
699
|
+
audio = np.concatenate([_loud(4.5), _silent(0.7)])
|
|
700
|
+
rec.get_audio_so_far.return_value = audio
|
|
701
|
+
s._on_vad_pause() # the recorder's VAD heard a pause here
|
|
702
|
+
rec.get_audio_so_far.return_value = np.concatenate([audio, _loud(0.5)])
|
|
703
|
+
tr.transcribe.return_value = "hello there friend"
|
|
704
|
+
s._transcribe_and_apply()
|
|
705
|
+
# Frozen long before freeze_secs, cut inside the pause
|
|
706
|
+
assert s._frozen_samples == len(audio) - int(_PAUSE_CUT_BACKOFF_SECS * SR)
|
|
707
|
+
assert s._frozen_raw == "hello there friend"
|
|
708
|
+
assert tr.transcribe.call_args.kwargs["final"] is True
|
|
709
|
+
assert len(tr.transcribe.call_args.args[0]) == s._frozen_samples
|
|
710
|
+
assert s.trace[-1]["cut"] == "pause"
|
|
711
|
+
s._display.typer.type_text.assert_not_called()
|
|
712
|
+
|
|
713
|
+
def test_pause_freeze_ignores_backpressure(self):
|
|
714
|
+
s, tr, rec = self._make_session(freeze_secs=8.0)
|
|
715
|
+
audio = np.concatenate([_loud(4.5), _silent(0.7)])
|
|
716
|
+
rec.get_audio_so_far.return_value = audio
|
|
717
|
+
s._last_decode_end = len(audio) # an interim just covered all of it
|
|
718
|
+
s._last_decode_secs = 5.0
|
|
719
|
+
s._on_vad_pause()
|
|
720
|
+
tr.transcribe.return_value = "hello there friend"
|
|
721
|
+
s._transcribe_and_apply()
|
|
722
|
+
assert s._frozen_raw == "hello there friend"
|
|
723
|
+
|
|
724
|
+
def test_pause_after_too_little_speech_is_not_frozen(self):
|
|
725
|
+
from voiceio.streaming import _PAUSE_FREEZE_MIN_SECS
|
|
726
|
+
s, tr, rec = self._make_session(freeze_secs=8.0)
|
|
727
|
+
rec.get_audio_so_far.return_value = np.concatenate(
|
|
728
|
+
[_loud(_PAUSE_FREEZE_MIN_SECS - 1), _silent(0.7)])
|
|
729
|
+
s._on_vad_pause()
|
|
730
|
+
tr.transcribe.return_value = "hello"
|
|
731
|
+
s._transcribe_and_apply()
|
|
732
|
+
assert s._frozen_samples == 0
|
|
733
|
+
assert tr.transcribe.call_args.kwargs["final"] is False # an interim
|
|
734
|
+
assert s._pause_at is None # consumed: a later pause is judged afresh
|
|
735
|
+
|
|
736
|
+
def test_no_pause_freeze_when_freezing_disabled(self):
|
|
737
|
+
s, tr, rec = self._make_session(freeze_secs=0)
|
|
738
|
+
rec.get_audio_so_far.return_value = np.concatenate([_loud(6), _silent(0.7)])
|
|
739
|
+
s._on_vad_pause()
|
|
740
|
+
tr.transcribe.return_value = "hello there friend"
|
|
741
|
+
s._transcribe_and_apply()
|
|
742
|
+
assert s._frozen_samples == 0
|
|
743
|
+
|
|
744
|
+
def test_stop_after_pause_freeze_decodes_only_the_rest(self):
|
|
745
|
+
s, tr, rec = self._make_session(freeze_secs=8.0)
|
|
746
|
+
audio = np.concatenate([_loud(4.5), _silent(0.7)])
|
|
747
|
+
rec.get_audio_so_far.return_value = audio
|
|
748
|
+
s._on_vad_pause()
|
|
749
|
+
tr.transcribe.return_value = "hello there friend"
|
|
750
|
+
s._transcribe_and_apply()
|
|
751
|
+
final_audio = np.concatenate([audio, _loud(1.0)])
|
|
752
|
+
tr.transcribe.return_value = "bye"
|
|
753
|
+
s.stop(final_audio)
|
|
754
|
+
assert len(tr.transcribe.call_args.args[0]) == len(final_audio) - s._frozen_samples
|
|
755
|
+
assert s.raw_final_text == "hello there friend bye"
|
|
756
|
+
|
|
696
757
|
def test_no_freeze_when_tail_is_speech(self):
|
|
697
758
|
s, tr, rec = self._make_session(freeze_secs=2.0)
|
|
698
759
|
rec.get_audio_so_far.return_value = _loud(3)
|
|
@@ -1073,3 +1134,4 @@ def test_stop_decodes_tail_in_parallel_with_inflight_freeze():
|
|
|
1073
1134
|
release_freeze.set()
|
|
1074
1135
|
stopper.join(5)
|
|
1075
1136
|
assert ("result", "frozen part tail part") in calls
|
|
1137
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.9.2"
|
|
@@ -144,12 +144,12 @@ class OutputConfig:
|
|
|
144
144
|
# On by default: nobody wants "um" in their notes. Set false for verbatim.
|
|
145
145
|
remove_disfluencies: bool = True
|
|
146
146
|
voice_input_prefix: str = "" # e.g. "[voice]" — empty disables
|
|
147
|
-
# Incremental finalization:
|
|
148
|
-
#
|
|
149
|
-
#
|
|
150
|
-
#
|
|
151
|
-
#
|
|
152
|
-
#
|
|
147
|
+
# Incremental finalization: during recording the audio is beam-decoded
|
|
148
|
+
# and frozen in chunks — at each speech pause the VAD reports, and,
|
|
149
|
+
# when no pause comes, once the un-finalized tail grows past this many
|
|
150
|
+
# seconds (cut at its quietest interior point) — so interim passes and
|
|
151
|
+
# the stop-time final decode only cover the short remaining tail.
|
|
152
|
+
# 0 disables both (full re-decode at stop).
|
|
153
153
|
streaming_freeze_secs: float = 8.0
|
|
154
154
|
# Mirror transcribed text to the system clipboard so it can be pasted:
|
|
155
155
|
# "off" — never
|
|
@@ -46,6 +46,15 @@ _FREEZE_SILENCE_FLOOR = 1e-4 # digital silence is always quiet
|
|
|
46
46
|
# spot beats re-decoding an ever-growing tail at stop (observed: 17 long
|
|
47
47
|
# dictations never froze, one decoding 121s of audio after stop).
|
|
48
48
|
_FREEZE_SEARCH_SECS = 8.0
|
|
49
|
+
# Pause freezes: when the recorder reports a speech pause (its VAD heard
|
|
50
|
+
# silence_duration of non-speech), the tail up to that pause is frozen as soon
|
|
51
|
+
# as it holds this much audio, rather than waiting for freeze_secs. Stop then
|
|
52
|
+
# decodes only the speech after the last pause instead of up to
|
|
53
|
+
# freeze_secs + search span of it.
|
|
54
|
+
_PAUSE_FREEZE_MIN_SECS = 4.0
|
|
55
|
+
# The pause is reported once the silence has lasted a while: cut this far
|
|
56
|
+
# before that point so the cut sits inside the silence, not at its edge.
|
|
57
|
+
_PAUSE_CUT_BACKOFF_SECS = 0.3
|
|
49
58
|
# Whisper conditions on ~224 prompt tokens; more frozen context is wasted.
|
|
50
59
|
_FREEZE_CONTEXT_CHARS = 400
|
|
51
60
|
|
|
@@ -197,6 +206,8 @@ class StreamingSession:
|
|
|
197
206
|
# been beam-decoded into _frozen_raw and is never decoded again.
|
|
198
207
|
# Interim and final passes only decode the tail after this offset.
|
|
199
208
|
self._freeze_secs = freeze_secs
|
|
209
|
+
# Sample offset of the latest speech pause the recorder reported.
|
|
210
|
+
self._pause_at: int | None = None
|
|
200
211
|
self._frozen_samples = 0
|
|
201
212
|
self._frozen_raw = ""
|
|
202
213
|
self._frozen_segments: list[dict] = []
|
|
@@ -318,7 +329,12 @@ class StreamingSession:
|
|
|
318
329
|
return None
|
|
319
330
|
|
|
320
331
|
def _on_vad_pause(self) -> None:
|
|
321
|
-
"""Called from audio thread on speech pause. Signals worker
|
|
332
|
+
"""Called from audio thread on speech pause. Signals worker, and
|
|
333
|
+
remembers where the pause is: a clean place to freeze."""
|
|
334
|
+
recorder = self._recorder
|
|
335
|
+
audio = recorder.get_audio_so_far() if recorder is not None else None
|
|
336
|
+
if audio is not None:
|
|
337
|
+
self._pause_at = len(audio)
|
|
322
338
|
self._pending.set()
|
|
323
339
|
|
|
324
340
|
def _worker_loop(self) -> None:
|
|
@@ -353,7 +369,28 @@ class StreamingSession:
|
|
|
353
369
|
context = self._frozen_raw[-_FREEZE_CONTEXT_CHARS:] if self._frozen_raw else None
|
|
354
370
|
return self._bias.with_context(context)
|
|
355
371
|
|
|
356
|
-
def
|
|
372
|
+
def _pause_cut(self, tail_len: int) -> int | None:
|
|
373
|
+
"""Tail offset to freeze at: the latest reported speech pause, once
|
|
374
|
+
the speech before it is long enough to decode on its own."""
|
|
375
|
+
pause, self._pause_at = self._pause_at, None
|
|
376
|
+
if self._freeze_secs <= 0 or pause is None:
|
|
377
|
+
return None
|
|
378
|
+
# Cut inside the pause, not at its end: speech may resume right there.
|
|
379
|
+
cut = pause - self._frozen_samples - int(_PAUSE_CUT_BACKOFF_SECS * self._sample_rate)
|
|
380
|
+
if cut < _PAUSE_FREEZE_MIN_SECS * self._sample_rate or cut > tail_len:
|
|
381
|
+
return None
|
|
382
|
+
return cut
|
|
383
|
+
|
|
384
|
+
def _long_tail_cut(self, tail: np.ndarray) -> int | None:
|
|
385
|
+
"""Tail offset to freeze at once the tail outgrows freeze_secs: its
|
|
386
|
+
quietest interior window (see _find_freeze_cut)."""
|
|
387
|
+
if self._freeze_secs <= 0 or len(tail) < self._freeze_secs * self._sample_rate:
|
|
388
|
+
return None
|
|
389
|
+
# Past the whole search span with no pause found: force a cut.
|
|
390
|
+
force = len(tail) >= (self._freeze_secs + _FREEZE_SEARCH_SECS) * self._sample_rate
|
|
391
|
+
return _find_freeze_cut(tail, self._sample_rate, self._freeze_secs, force=force)
|
|
392
|
+
|
|
393
|
+
def _freeze_chunk(self, audio: np.ndarray, chunk: np.ndarray, cut: str = "long") -> None:
|
|
357
394
|
"""Beam-decode `chunk` (the tail up to a pause cut) and freeze it.
|
|
358
395
|
|
|
359
396
|
On decode failure the boundary is left untouched — the audio will be
|
|
@@ -375,6 +412,7 @@ class StreamingSession:
|
|
|
375
412
|
self.trace.append({
|
|
376
413
|
"t": round(time.monotonic() - self._t0, 2),
|
|
377
414
|
"kind": "freeze",
|
|
415
|
+
"cut": cut,
|
|
378
416
|
"frozen_secs": round(self._frozen_samples / self._sample_rate, 2),
|
|
379
417
|
"tail_secs": round(len(chunk) / self._sample_rate, 2),
|
|
380
418
|
"secs": round(t_decode, 3),
|
|
@@ -411,30 +449,31 @@ class StreamingSession:
|
|
|
411
449
|
tail = audio[self._frozen_samples:]
|
|
412
450
|
if not final and len(tail) < self._sample_rate * min_seconds:
|
|
413
451
|
return # not enough new audio since the last freeze
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
#
|
|
419
|
-
# pause
|
|
420
|
-
#
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
452
|
+
|
|
453
|
+
# Freeze: cut the tail at a speech pause and beam-decode ONLY that
|
|
454
|
+
# chunk (its text is never decoded again). The freeze pass does not
|
|
455
|
+
# touch the display — the interim text already covers this audio;
|
|
456
|
+
# the next interim refreshes it.
|
|
457
|
+
# A pause the recorder reported is frozen even under backpressure:
|
|
458
|
+
# it shrinks every later decode, the stop-time one included.
|
|
459
|
+
cut = None if final else self._pause_cut(len(tail))
|
|
460
|
+
reason = "pause"
|
|
461
|
+
if cut is None and not final:
|
|
462
|
+
grown_secs = (len(audio) - self._last_decode_end) / self._sample_rate
|
|
463
|
+
if grown_secs < max(min_seconds, self._last_decode_secs):
|
|
464
|
+
return # backpressure: don't decode faster than we can keep up
|
|
465
|
+
cut, reason = self._long_tail_cut(tail), "long"
|
|
466
|
+
if cut is not None:
|
|
467
|
+
with self._freeze_lock:
|
|
468
|
+
# Stop may have won the race for the lock and already
|
|
469
|
+
# finalized from the current boundary.
|
|
470
|
+
if not self._stop_event.is_set():
|
|
471
|
+
self._freeze_pending_end = self._frozen_samples + cut
|
|
472
|
+
try:
|
|
473
|
+
self._freeze_chunk(audio, tail[:cut], reason)
|
|
474
|
+
finally:
|
|
475
|
+
self._freeze_pending_end = None
|
|
476
|
+
return
|
|
438
477
|
|
|
439
478
|
tail_text = ""
|
|
440
479
|
tail_segments: list[dict] = []
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.9.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/faster_whisper/__init__.py
RENAMED
|
File without changes
|
{python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/faster_whisper/worker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|