python-voiceio 1.14.0__tar.gz → 1.15.0__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.14.0/python_voiceio.egg-info → python_voiceio-1.15.0}/PKG-INFO +1 -1
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/pyproject.toml +1 -1
- {python_voiceio-1.14.0 → python_voiceio-1.15.0/python_voiceio.egg-info}/PKG-INFO +1 -1
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_learn_pipeline.py +26 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_presence.py +1 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_server.py +35 -7
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_sherpa.py +6 -1
- python_voiceio-1.15.0/voiceio/__init__.py +1 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/cli/learn.py +2 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/decoders/sherpa.py +5 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/presence.py +4 -1
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/server/__main__.py +1 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/server/app.py +25 -12
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/server/config.py +4 -0
- python_voiceio-1.14.0/voiceio/__init__.py +0 -1
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/LICENSE +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/README.md +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/python_voiceio.egg-info/SOURCES.txt +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/python_voiceio.egg-info/dependency_links.txt +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/python_voiceio.egg-info/entry_points.txt +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/python_voiceio.egg-info/requires.txt +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/python_voiceio.egg-info/top_level.txt +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/setup.cfg +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_announce.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_app_wiring.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_audio_quality.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_audio_source.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_backend_probes.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_cancel.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_cli.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_clipboard_read.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_clipboard_typer.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_commands.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_concurrency_lockdown.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_config.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_context_terms.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_corrections.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_dead_mic.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_decoders.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_engine.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_evdev_uaccess.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_fallback.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_fcitx_bridge.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_feedback_stream.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_focus.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_health.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_hints.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_history.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_hotkey_modes.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_ibus_engine_limits.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_ibus_engine_listener.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_ibus_pending.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_ibus_pids.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_ibus_ping.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_ibus_session.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_ibus_textlimit.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_ibus_typer.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_idle_audio.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_learn_clean.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_learn_import.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_learn_language.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_learn_metrics.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_learn_quiet.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_learn_resume.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_learn_review.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_learn_targets.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_llm.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_llm_api.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_mic_gain.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_modifier_guard.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_numbers.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_paste_last.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_pipeline.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_platform.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_postcorrect.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_postprocess.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_prebuffer.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_prompt.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_quiet_audio.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_recorder_integration.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_report.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_retention.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_robustness.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_security_hardening.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_service.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_setup.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_spool.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_streaming.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_suggest.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_tokens.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_transcriber.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_tts.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_typer_manager.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_vad.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_vocabulary.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_wordfreq.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/tests/test_worker_decode.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/__main__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/announce.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/app.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/audio_source.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/backends.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/cli/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/cli/configcmd.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/cli/corrections.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/cli/doctor.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/cli/history.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/cli/models.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/cli/servicecmd.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/cli/uninstall.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/cli/vocab.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/clipboard_read.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/commands.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/config.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/consent.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/context_terms.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/bias.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/decoders/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/decoders/base.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/decoders/catalog.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/decoders/faster_whisper/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/decoders/faster_whisper/worker.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/decoders/fetch.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/decoders/lanes.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/decoders/whispercpp.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/engine.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/core/pipeline.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/corrections.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/data/60-voiceio-uaccess.rules +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/data/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/demo.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/display.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/feedback.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/focus.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/health.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/hints.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/history.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/hotkeys/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/hotkeys/base.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/hotkeys/chain.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/hotkeys/evdev.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/hotkeys/pynput_backend.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/hotkeys/socket_backend.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/ibus/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/ibus/engine.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/ibus/install.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/ibus/pending.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/ibus/session.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/ibus/textlimit.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/idle_audio.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/learn/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/learn/augment.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/learn/clean.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/learn/evaluate.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/learn/importer.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/learn/metrics.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/learn/quiet.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/learn/review.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/learn/store.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/learn/teacher.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/learn/train.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/llm.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/llm_api.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/mic_gain.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/models/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/models/silero_vad.onnx +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/numbers.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/pidlock.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/platform.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/postcorrect.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/postprocess.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/power.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/privacy.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/prompt.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/quiet_audio.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/recorder.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/report.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/retention.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/server/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/server/runtime.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/service.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/setup/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/setup/configfile.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/setup/extras.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/setup/hotkey.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/setup/noninteractive.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/setup/speech.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/setup/steps.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/setup/system.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/setup/ui.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/sounds/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/sounds/alert.wav +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/sounds/commit.wav +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/sounds/start.wav +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/sounds/stop.wav +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/spool.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/streaming.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/suggest.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tokens.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tray/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tray/_icons.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tray/_indicator.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tray/_pystray.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tts/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tts/base.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tts/chain.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tts/edge_engine.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tts/espeak.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tts/piper_engine.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tts/player.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/tts/supertonic_engine.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/__init__.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/base.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/chain.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/clipboard.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/collecting.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/fcitx_bridge.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/ibus.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/manager.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/modifier_guard.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/paste.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/pynput_type.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/wtype.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/xdotool.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/typers/ydotool.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/ui.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/vad.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/vocab_stats.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/vocabulary.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/watchdog.py +0 -0
- {python_voiceio-1.14.0 → python_voiceio-1.15.0}/voiceio/wordfreq.py +0 -0
|
@@ -307,6 +307,32 @@ def test_status_shows_scores_and_suggests_a_winning_run(capsys):
|
|
|
307
307
|
assert "next: voiceio learn promote v0001-small-x" in out
|
|
308
308
|
|
|
309
309
|
|
|
310
|
+
def test_status_never_suggests_whisper_over_another_decoder(capsys):
|
|
311
|
+
import argparse
|
|
312
|
+
|
|
313
|
+
from voiceio import config
|
|
314
|
+
from voiceio.cli import learn as cli
|
|
315
|
+
config.CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
316
|
+
config.CONFIG_PATH.write_text('[model]\nname = "parakeet-tdt-0.6b-v2"\n')
|
|
317
|
+
_clip("s.wav", 3, "x")
|
|
318
|
+
store.add_label("s.wav", [Segment(0, 3, "hi")], "teacher:fake")
|
|
319
|
+
ds = store.build_dataset()
|
|
320
|
+
run = store.learn_dir() / "models" / "v0001-small-x"
|
|
321
|
+
(run / "ct2").mkdir(parents=True)
|
|
322
|
+
runs = store.learn_dir() / "runs"
|
|
323
|
+
runs.mkdir()
|
|
324
|
+
for i, (dec, wer, rec) in enumerate([("sherpa:parakeet-tdt-0.6b-v2", 0.10, 0.5),
|
|
325
|
+
(f"faster-whisper:{run / 'ct2'}", 0.08, 0.8)]):
|
|
326
|
+
(runs / f"eval-2026010{i}.json").write_text(json.dumps({
|
|
327
|
+
"decoder": dec, "dataset": ds.name, "mode": "offline", "wer": wer,
|
|
328
|
+
"term_recall": rec, "repetitions": 0, "clips": 5, "gold": 0,
|
|
329
|
+
"metrics": metrics.METRICS_VERSION}))
|
|
330
|
+
cli.cmd_status(argparse.Namespace())
|
|
331
|
+
out = capsys.readouterr().out
|
|
332
|
+
assert "parakeet-tdt-0.6b-v2 (active)" in out and "WER 10.0%" in out
|
|
333
|
+
assert "next: voiceio learn promote" not in out
|
|
334
|
+
|
|
335
|
+
|
|
310
336
|
def test_paired_comparison_reports_direction_and_uncertainty():
|
|
311
337
|
clips = [f"{i}.wav" for i in range(20)]
|
|
312
338
|
cur = {"per_clip": [{"file": f, "wer": 0.10} for f in clips]}
|
|
@@ -38,6 +38,7 @@ AWAY = 600
|
|
|
38
38
|
(Probe(idle=1800), False, "away 30 min"),
|
|
39
39
|
(Probe(idle=1800, inhibited=True), True, "keeping the session awake"), # a video
|
|
40
40
|
(Probe(idle=1800, inhibited=True, locked=True), False, "away"),
|
|
41
|
+
(Probe(idle=3 * 3600, inhibited=True), False, "away 180 min"), # an agent, not a viewer
|
|
41
42
|
# No idle monitor: logind decides, and "can't tell" means in use.
|
|
42
43
|
(Probe(), True, "can't tell"),
|
|
43
44
|
(Probe(session=SeatSession(exists=False)), False, "nobody is logged in"),
|
|
@@ -310,6 +310,7 @@ def test_ws_ready_partial_final_sequence():
|
|
|
310
310
|
assert final["text"] == "Hello world."
|
|
311
311
|
assert final["raw"] == "hello world raw"
|
|
312
312
|
assert isinstance(final["ms"], int)
|
|
313
|
+
assert final["cut_short"] is False and "why" not in final
|
|
313
314
|
assert engine.committed == ["Hello world."] # learned from; kept if opted in
|
|
314
315
|
|
|
315
316
|
|
|
@@ -348,8 +349,9 @@ def test_ws_client_disconnect_still_finalizes():
|
|
|
348
349
|
assert engine.sessions[0].stopped_with is not None
|
|
349
350
|
|
|
350
351
|
|
|
351
|
-
def
|
|
352
|
+
def test_ws_duration_cap_finalizes_what_fits_marked_cut_short():
|
|
352
353
|
cfg = ServerConfig(max_audio_secs=0.05) # 800 samples
|
|
354
|
+
engine = FakeEngine()
|
|
353
355
|
|
|
354
356
|
async def go(client):
|
|
355
357
|
ws = await client.ws_connect("/ws/transcribe")
|
|
@@ -361,11 +363,36 @@ def test_ws_enforces_the_duration_cap():
|
|
|
361
363
|
await ws.close()
|
|
362
364
|
return frames
|
|
363
365
|
|
|
364
|
-
frames = run_with_client(go, cfg=cfg)
|
|
365
|
-
|
|
366
|
-
assert "
|
|
367
|
-
#
|
|
368
|
-
assert
|
|
366
|
+
frames = run_with_client(go, cfg=cfg, engine=engine)
|
|
367
|
+
final = frames[-1]
|
|
368
|
+
assert final["type"] == "final" and final["text"] == "Hello world."
|
|
369
|
+
# The words are kept, and the client is told they are not the whole note.
|
|
370
|
+
assert final["cut_short"] is True and "limit" in final["why"]
|
|
371
|
+
assert len(engine.sessions[0].stopped_with) == 800 # only what fits is decoded
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def test_ws_stalled_stream_is_finalized_with_what_it_has():
|
|
375
|
+
"""A client that goes quiet without a stop (a starved or frozen sender)
|
|
376
|
+
still gets a transcript of the audio it sent."""
|
|
377
|
+
cfg = ServerConfig(stall_secs=0.2)
|
|
378
|
+
engine = FakeEngine()
|
|
379
|
+
|
|
380
|
+
async def go(client):
|
|
381
|
+
ws = await client.ws_connect("/ws/transcribe")
|
|
382
|
+
await ws.receive_json()
|
|
383
|
+
await ws.send_bytes(_pcm(800))
|
|
384
|
+
frames = []
|
|
385
|
+
async for msg in ws: # no stop: the server ends it
|
|
386
|
+
frames.append(json.loads(msg.data))
|
|
387
|
+
await ws.close()
|
|
388
|
+
return frames
|
|
389
|
+
|
|
390
|
+
frames = run_with_client(go, cfg=cfg, engine=engine)
|
|
391
|
+
final = frames[-1]
|
|
392
|
+
assert final["type"] == "final" and final["text"] == "Hello world."
|
|
393
|
+
assert final["cut_short"] is True and "no audio or stop" in final["why"]
|
|
394
|
+
assert len(engine.sessions[0].stopped_with) == 800
|
|
395
|
+
assert engine.committed == ["Hello world."]
|
|
369
396
|
|
|
370
397
|
|
|
371
398
|
def test_ws_second_concurrent_session_is_refused():
|
|
@@ -439,11 +466,12 @@ def test_config_from_env(monkeypatch):
|
|
|
439
466
|
monkeypatch.setenv("VOICE_MODEL", "base")
|
|
440
467
|
monkeypatch.setenv("VOICE_THREADS", "2")
|
|
441
468
|
monkeypatch.setenv("VOICE_MAX_SECS", "60")
|
|
469
|
+
monkeypatch.setenv("VOICE_STALL_SECS", "45")
|
|
442
470
|
monkeypatch.setenv("VOICE_TTS_ALLOW_NETWORK", "1")
|
|
443
471
|
cfg = ServerConfig.from_env()
|
|
444
472
|
assert (cfg.host, cfg.port, cfg.model) == ("0.0.0.0", 8790, "base")
|
|
445
473
|
assert cfg.threads == "2"
|
|
446
|
-
assert cfg.max_audio_secs == 60.0
|
|
474
|
+
assert (cfg.max_audio_secs, cfg.stall_secs) == (60.0, 45.0)
|
|
447
475
|
assert cfg.tts_allow_network is True
|
|
448
476
|
|
|
449
477
|
|
|
@@ -41,6 +41,10 @@ class FakeSherpa:
|
|
|
41
41
|
self.rec = {"hotwords": hotwords, "samples": 0}
|
|
42
42
|
fake.streams.append(self.rec)
|
|
43
43
|
|
|
44
|
+
def set_option(self, key, value):
|
|
45
|
+
assert isinstance(value, str)
|
|
46
|
+
self.rec[key] = value
|
|
47
|
+
|
|
44
48
|
def accept_waveform(self, sr, a):
|
|
45
49
|
assert sr == 16000 and a.dtype == np.float32
|
|
46
50
|
self.rec["samples"] = len(a)
|
|
@@ -114,6 +118,7 @@ def test_one_recognizer_and_per_stream_pretokenized_proper_nouns(fake, tmp_path)
|
|
|
114
118
|
assert out.text == "hello world"
|
|
115
119
|
# Lowercase (mined jargon) and unusable terms never become hotwords.
|
|
116
120
|
assert fake.streams[-1]["hotwords"] == "▁Kal shi/▁Hy per"
|
|
121
|
+
assert fake.streams[-1]["length_reward"] == "0.5" # per stream, as upstream reads it
|
|
117
122
|
dec.decode(_audio(2), bias=Bias(hotwords="Hyper"))
|
|
118
123
|
dec.decode(_audio(2), bias=Bias())
|
|
119
124
|
assert [s["hotwords"] for s in fake.streams[1:]] == ["▁Hy per", None]
|
|
@@ -135,7 +140,7 @@ def test_without_the_tdt_fix_decodes_greedy_and_unbiased(fake, monkeypatch, tmp_
|
|
|
135
140
|
assert dec.decode(_audio(1), bias=Bias(hotwords="Kalshi")).text == "hello world"
|
|
136
141
|
kw = fake.created[-1]
|
|
137
142
|
assert kw["decoding_method"] == "greedy_search" and "length_reward" not in kw
|
|
138
|
-
assert fake.streams[-1]["hotwords"] is None
|
|
143
|
+
assert fake.streams[-1]["hotwords"] is None and "length_reward" not in fake.streams[-1]
|
|
139
144
|
|
|
140
145
|
|
|
141
146
|
def test_long_audio_is_decoded_in_pieces_of_at_most_30s(fake, tmp_path):
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.15.0"
|
|
@@ -211,6 +211,8 @@ def cmd_status(args: argparse.Namespace) -> None:
|
|
|
211
211
|
print(f"note {unused}")
|
|
212
212
|
print(f"nightly {_schedule_state()}")
|
|
213
213
|
promotable = _print_scores(ds, active, runs) if ds else None
|
|
214
|
+
if unused: # a Whisper fine-tune can't replace another decoder on WER alone
|
|
215
|
+
promotable = None
|
|
214
216
|
if promotable:
|
|
215
217
|
nxt = f"promote {promotable}"
|
|
216
218
|
else:
|
|
@@ -236,6 +236,9 @@ class SherpaTransducer:
|
|
|
236
236
|
bpe_vocab=_bpe_vocab_file(self._dir, self._tokenizer))
|
|
237
237
|
if feats.length_reward:
|
|
238
238
|
kwargs.update(length_reward=length_reward)
|
|
239
|
+
# Upstream reads length_reward per stream (k2-fsa/sherpa-onnx#4084 after
|
|
240
|
+
# review); builds without that read ignore the option.
|
|
241
|
+
self._stream_reward = repr(float(length_reward)) if mbs and length_reward else ""
|
|
239
242
|
t0 = time.monotonic()
|
|
240
243
|
try:
|
|
241
244
|
self._rec = sherpa_onnx.OfflineRecognizer.from_transducer(**kwargs)
|
|
@@ -276,6 +279,8 @@ class SherpaTransducer:
|
|
|
276
279
|
for chunk in split_long(audio) if len(audio) else ():
|
|
277
280
|
stream = (self._rec.create_stream(hotwords) if hotwords
|
|
278
281
|
else self._rec.create_stream())
|
|
282
|
+
if self._stream_reward and hasattr(stream, "set_option"):
|
|
283
|
+
stream.set_option("length_reward", self._stream_reward)
|
|
279
284
|
stream.accept_waveform(SAMPLE_RATE, chunk)
|
|
280
285
|
self._rec.decode_stream(stream)
|
|
281
286
|
if text := stream.result.text.strip():
|
|
@@ -37,6 +37,9 @@ from dataclasses import dataclass
|
|
|
37
37
|
log = logging.getLogger(__name__)
|
|
38
38
|
|
|
39
39
|
_TIMEOUT = 3
|
|
40
|
+
# No input for this long is away even when an app keeps the session awake:
|
|
41
|
+
# past a film's length, the inhibitor is a long-running job, not a viewer.
|
|
42
|
+
INHIBITED_MAX = 2 * 3600
|
|
40
43
|
|
|
41
44
|
|
|
42
45
|
@dataclass(frozen=True)
|
|
@@ -144,7 +147,7 @@ def check(away_after: float, probe: SessionProbe | None = None) -> Presence:
|
|
|
144
147
|
if probe.screen_locked():
|
|
145
148
|
return Presence(False, "screen locked")
|
|
146
149
|
return Presence(True, f"in use (last input {_minutes(idle)} ago)")
|
|
147
|
-
if probe.idle_inhibited() and not probe.screen_locked():
|
|
150
|
+
if idle < INHIBITED_MAX and probe.idle_inhibited() and not probe.screen_locked():
|
|
148
151
|
return Presence(True, "an app is keeping the session awake (a video or a call?)")
|
|
149
152
|
return Presence(False, f"away {_minutes(idle)}")
|
|
150
153
|
session = probe.seat_session()
|
|
@@ -21,6 +21,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
21
21
|
" VOICE_COMPUTE, VOICE_DEVICE compute type / device\n"
|
|
22
22
|
" VOICE_THREADS CPU threads (default 4, 0=all)\n"
|
|
23
23
|
" VOICE_MAX_BYTES, VOICE_MAX_SECS request limits\n"
|
|
24
|
+
" VOICE_STALL_SECS end a stream silent this long (30 s; 0 never)\n"
|
|
24
25
|
" VOICE_TTS_ENGINE, VOICE_TTS_VOICE, VOICE_TTS_SPEED\n"
|
|
25
26
|
" VOICE_TTS_ALLOW_NETWORK 1 to permit cloud TTS (off)\n"
|
|
26
27
|
" VOICE_LOG_LEVEL default INFO\n"
|
|
@@ -122,12 +122,15 @@ async def handle_ws_transcribe(request: web.Request) -> web.WebSocketResponse:
|
|
|
122
122
|
Server → client (all JSON text frames):
|
|
123
123
|
{"type":"ready","sample_rate":16000,"format":"pcm_s16le","channels":1}
|
|
124
124
|
{"type":"partial","text":...,"audio_secs":...}
|
|
125
|
-
{"type":"final","text":...,"raw":...,"audio_secs":...,"ms"
|
|
125
|
+
{"type":"final","text":...,"raw":...,"audio_secs":...,"ms":...,
|
|
126
|
+
"cut_short":false}
|
|
126
127
|
{"type":"error","error":...}
|
|
127
128
|
|
|
128
|
-
The final frame is sent before the socket closes. A
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
The final frame is sent before the socket closes. A stream that sends
|
|
130
|
+
neither audio nor stop for `stall_secs`, or passes `max_audio_secs`, still
|
|
131
|
+
gets a final of the audio it sent, with "cut_short":true and a "why". A
|
|
132
|
+
client that simply disconnects still gets its audio finalized server-side
|
|
133
|
+
(for vocabulary statistics), it just is not around to read the result.
|
|
131
134
|
"""
|
|
132
135
|
runtime: ServerRuntime = request.app[RUNTIME]
|
|
133
136
|
cfg: ServerConfig = request.app[CONFIG]
|
|
@@ -190,17 +193,22 @@ async def _run_stream(ws, runtime: ServerRuntime, cfg: ServerConfig, app) -> Non
|
|
|
190
193
|
"model": runtime.model_cfg.name,
|
|
191
194
|
})
|
|
192
195
|
|
|
196
|
+
cut_short = "" # why the stream ended without a stop, if it did
|
|
193
197
|
overrun = False
|
|
194
198
|
try:
|
|
195
|
-
|
|
199
|
+
while True:
|
|
200
|
+
try:
|
|
201
|
+
msg = await ws.receive(timeout=cfg.stall_secs or None)
|
|
202
|
+
except TimeoutError:
|
|
203
|
+
cut_short = f"no audio or stop for {cfg.stall_secs:g} s"
|
|
204
|
+
break
|
|
205
|
+
if msg.type in (WSMsgType.CLOSE, WSMsgType.CLOSING, WSMsgType.CLOSED):
|
|
206
|
+
break
|
|
196
207
|
if msg.type == WSMsgType.BINARY:
|
|
197
208
|
total = source.feed(msg.data)
|
|
198
209
|
if total / SAMPLE_RATE > cfg.max_audio_secs:
|
|
199
210
|
overrun = True
|
|
200
|
-
|
|
201
|
-
"type": "error",
|
|
202
|
-
"error": f"audio exceeded {cfg.max_audio_secs:.0f}s limit",
|
|
203
|
-
})
|
|
211
|
+
cut_short = f"audio passed the {cfg.max_audio_secs:g} s limit"
|
|
204
212
|
break
|
|
205
213
|
elif msg.type == WSMsgType.TEXT:
|
|
206
214
|
try:
|
|
@@ -218,7 +226,9 @@ async def _run_stream(ws, runtime: ServerRuntime, cfg: ServerConfig, app) -> Non
|
|
|
218
226
|
finally:
|
|
219
227
|
source.close()
|
|
220
228
|
audio = source.get_audio_so_far()
|
|
221
|
-
|
|
229
|
+
if overrun and audio is not None: # the last frame may run far past the limit
|
|
230
|
+
audio = audio[:int(cfg.max_audio_secs * SAMPLE_RATE)]
|
|
231
|
+
secs = len(audio) / SAMPLE_RATE if audio is not None else 0.0
|
|
222
232
|
|
|
223
233
|
# stop() joins the worker thread through a final beam-search decode:
|
|
224
234
|
# seconds of CPU, and it must not block the event loop.
|
|
@@ -238,18 +248,21 @@ async def _run_stream(ws, runtime: ServerRuntime, cfg: ServerConfig, app) -> Non
|
|
|
238
248
|
outbox.put_nowait(None)
|
|
239
249
|
await pump_task
|
|
240
250
|
|
|
241
|
-
if not ws.closed
|
|
251
|
+
if not ws.closed:
|
|
242
252
|
await ws.send_json({
|
|
243
253
|
"type": "final",
|
|
244
254
|
"text": text,
|
|
245
255
|
"raw": session.raw_final_text or "",
|
|
246
256
|
"audio_secs": round(secs, 2),
|
|
247
257
|
"ms": round((time.monotonic() - t0) * 1000),
|
|
258
|
+
"cut_short": bool(cut_short),
|
|
259
|
+
**({"why": cut_short} if cut_short else {}),
|
|
248
260
|
})
|
|
249
261
|
if text: # after the reply: retention must not add to the user's wait
|
|
250
262
|
await loop.run_in_executor(app[EXECUTOR], runtime.commit, audio, text,
|
|
251
263
|
session.raw_final_text or "")
|
|
252
|
-
log.info("streaming %.1fs audio → %s", secs, describe_transcript(text)
|
|
264
|
+
log.info("streaming %.1fs audio → %s%s", secs, describe_transcript(text),
|
|
265
|
+
f" (cut short: {cut_short})" if cut_short else "")
|
|
253
266
|
if not ws.closed:
|
|
254
267
|
await ws.close()
|
|
255
268
|
|
|
@@ -59,6 +59,9 @@ class ServerConfig:
|
|
|
59
59
|
# max_audio_secs; this exists so a bad client cannot stream us to death.
|
|
60
60
|
max_bytes: int = 25 * 1024 * 1024
|
|
61
61
|
max_audio_secs: float = 120.0
|
|
62
|
+
# A stream that sends neither audio nor stop for this long is finalized
|
|
63
|
+
# with what it has (marked cut_short). 0 waits forever.
|
|
64
|
+
stall_secs: float = 30.0
|
|
62
65
|
|
|
63
66
|
# ── tts ──────────────────────────────────────────────────────────────
|
|
64
67
|
tts_engine: str = "auto"
|
|
@@ -97,6 +100,7 @@ class ServerConfig:
|
|
|
97
100
|
lanes=int(e(prefix, "LANES", "1")),
|
|
98
101
|
max_bytes=int(e(prefix, "MAX_BYTES", str(25 * 1024 * 1024))),
|
|
99
102
|
max_audio_secs=float(e(prefix, "MAX_SECS", "120")),
|
|
103
|
+
stall_secs=float(e(prefix, "STALL_SECS", "30")),
|
|
100
104
|
tts_engine=e(prefix, "TTS_ENGINE", "auto"),
|
|
101
105
|
tts_voice=e(prefix, "TTS_VOICE", ""),
|
|
102
106
|
tts_speed=float(e(prefix, "TTS_SPEED", "1.0")),
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.14.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_voiceio-1.14.0 → python_voiceio-1.15.0}/python_voiceio.egg-info/dependency_links.txt
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
|