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.
Files changed (216) hide show
  1. {python_voiceio-1.9.1/python_voiceio.egg-info → python_voiceio-1.9.2}/PKG-INFO +1 -1
  2. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/pyproject.toml +1 -1
  3. {python_voiceio-1.9.1 → python_voiceio-1.9.2/python_voiceio.egg-info}/PKG-INFO +1 -1
  4. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_streaming.py +62 -0
  5. python_voiceio-1.9.2/voiceio/__init__.py +1 -0
  6. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/config.py +6 -6
  7. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/streaming.py +65 -26
  8. python_voiceio-1.9.1/voiceio/__init__.py +0 -1
  9. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/LICENSE +0 -0
  10. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/README.md +0 -0
  11. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/python_voiceio.egg-info/SOURCES.txt +0 -0
  12. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/python_voiceio.egg-info/dependency_links.txt +0 -0
  13. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/python_voiceio.egg-info/entry_points.txt +0 -0
  14. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/python_voiceio.egg-info/requires.txt +0 -0
  15. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/python_voiceio.egg-info/top_level.txt +0 -0
  16. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/setup.cfg +0 -0
  17. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_app_wiring.py +0 -0
  18. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_audio_quality.py +0 -0
  19. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_audio_source.py +0 -0
  20. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_backend_probes.py +0 -0
  21. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_cancel.py +0 -0
  22. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_cli.py +0 -0
  23. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_clipboard_read.py +0 -0
  24. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_clipboard_typer.py +0 -0
  25. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_commands.py +0 -0
  26. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_concurrency_lockdown.py +0 -0
  27. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_config.py +0 -0
  28. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_context_terms.py +0 -0
  29. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_corrections.py +0 -0
  30. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_decoders.py +0 -0
  31. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_engine.py +0 -0
  32. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_evdev_uaccess.py +0 -0
  33. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_fallback.py +0 -0
  34. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_fcitx_bridge.py +0 -0
  35. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_feedback_stream.py +0 -0
  36. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_focus.py +0 -0
  37. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_health.py +0 -0
  38. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_hints.py +0 -0
  39. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_history.py +0 -0
  40. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_hotkey_modes.py +0 -0
  41. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_engine_limits.py +0 -0
  42. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_engine_listener.py +0 -0
  43. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_pending.py +0 -0
  44. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_pids.py +0 -0
  45. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_ping.py +0 -0
  46. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_session.py +0 -0
  47. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_textlimit.py +0 -0
  48. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_ibus_typer.py +0 -0
  49. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_idle_audio.py +0 -0
  50. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_clean.py +0 -0
  51. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_import.py +0 -0
  52. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_language.py +0 -0
  53. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_metrics.py +0 -0
  54. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_pipeline.py +0 -0
  55. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_quiet.py +0 -0
  56. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_review.py +0 -0
  57. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_learn_targets.py +0 -0
  58. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_llm.py +0 -0
  59. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_llm_api.py +0 -0
  60. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_modifier_guard.py +0 -0
  61. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_numbers.py +0 -0
  62. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_paste_last.py +0 -0
  63. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_pipeline.py +0 -0
  64. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_platform.py +0 -0
  65. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_postcorrect.py +0 -0
  66. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_postprocess.py +0 -0
  67. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_prebuffer.py +0 -0
  68. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_prompt.py +0 -0
  69. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_quiet_audio.py +0 -0
  70. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_recorder_integration.py +0 -0
  71. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_retention.py +0 -0
  72. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_robustness.py +0 -0
  73. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_security_hardening.py +0 -0
  74. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_server.py +0 -0
  75. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_service.py +0 -0
  76. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_setup.py +0 -0
  77. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_suggest.py +0 -0
  78. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_tokens.py +0 -0
  79. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_transcriber.py +0 -0
  80. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_tts.py +0 -0
  81. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_typer_manager.py +0 -0
  82. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_vad.py +0 -0
  83. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_vocabulary.py +0 -0
  84. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_wordfreq.py +0 -0
  85. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/tests/test_worker_decode.py +0 -0
  86. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/__main__.py +0 -0
  87. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/app.py +0 -0
  88. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/audio_source.py +0 -0
  89. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/backends.py +0 -0
  90. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/__init__.py +0 -0
  91. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/configcmd.py +0 -0
  92. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/corrections.py +0 -0
  93. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/doctor.py +0 -0
  94. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/history.py +0 -0
  95. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/learn.py +0 -0
  96. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/models.py +0 -0
  97. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/servicecmd.py +0 -0
  98. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/uninstall.py +0 -0
  99. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/cli/vocab.py +0 -0
  100. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/clipboard_read.py +0 -0
  101. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/commands.py +0 -0
  102. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/consent.py +0 -0
  103. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/context_terms.py +0 -0
  104. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/__init__.py +0 -0
  105. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/bias.py +0 -0
  106. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/__init__.py +0 -0
  107. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/base.py +0 -0
  108. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/catalog.py +0 -0
  109. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/faster_whisper/__init__.py +0 -0
  110. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/faster_whisper/worker.py +0 -0
  111. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/lanes.py +0 -0
  112. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/sherpa.py +0 -0
  113. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/decoders/whispercpp.py +0 -0
  114. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/engine.py +0 -0
  115. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/core/pipeline.py +0 -0
  116. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/corrections.py +0 -0
  117. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/data/60-voiceio-uaccess.rules +0 -0
  118. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/data/__init__.py +0 -0
  119. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/demo.py +0 -0
  120. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/display.py +0 -0
  121. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/feedback.py +0 -0
  122. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/focus.py +0 -0
  123. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/health.py +0 -0
  124. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hints.py +0 -0
  125. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/history.py +0 -0
  126. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hotkeys/__init__.py +0 -0
  127. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hotkeys/base.py +0 -0
  128. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hotkeys/chain.py +0 -0
  129. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hotkeys/evdev.py +0 -0
  130. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hotkeys/pynput_backend.py +0 -0
  131. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/hotkeys/socket_backend.py +0 -0
  132. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ibus/__init__.py +0 -0
  133. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ibus/engine.py +0 -0
  134. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ibus/install.py +0 -0
  135. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ibus/pending.py +0 -0
  136. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ibus/session.py +0 -0
  137. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ibus/textlimit.py +0 -0
  138. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/idle_audio.py +0 -0
  139. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/__init__.py +0 -0
  140. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/augment.py +0 -0
  141. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/clean.py +0 -0
  142. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/evaluate.py +0 -0
  143. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/importer.py +0 -0
  144. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/metrics.py +0 -0
  145. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/quiet.py +0 -0
  146. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/review.py +0 -0
  147. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/store.py +0 -0
  148. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/teacher.py +0 -0
  149. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/learn/train.py +0 -0
  150. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/llm.py +0 -0
  151. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/llm_api.py +0 -0
  152. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/models/__init__.py +0 -0
  153. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/models/silero_vad.onnx +0 -0
  154. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/numbers.py +0 -0
  155. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/pidlock.py +0 -0
  156. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/platform.py +0 -0
  157. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/postcorrect.py +0 -0
  158. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/postprocess.py +0 -0
  159. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/power.py +0 -0
  160. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/privacy.py +0 -0
  161. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/prompt.py +0 -0
  162. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/quiet_audio.py +0 -0
  163. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/recorder.py +0 -0
  164. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/retention.py +0 -0
  165. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/server/__init__.py +0 -0
  166. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/server/__main__.py +0 -0
  167. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/server/app.py +0 -0
  168. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/server/config.py +0 -0
  169. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/server/runtime.py +0 -0
  170. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/service.py +0 -0
  171. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/__init__.py +0 -0
  172. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/configfile.py +0 -0
  173. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/extras.py +0 -0
  174. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/hotkey.py +0 -0
  175. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/noninteractive.py +0 -0
  176. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/speech.py +0 -0
  177. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/steps.py +0 -0
  178. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/system.py +0 -0
  179. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/setup/ui.py +0 -0
  180. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/sounds/__init__.py +0 -0
  181. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/sounds/commit.wav +0 -0
  182. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/sounds/start.wav +0 -0
  183. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/sounds/stop.wav +0 -0
  184. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/suggest.py +0 -0
  185. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tokens.py +0 -0
  186. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tray/__init__.py +0 -0
  187. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tray/_icons.py +0 -0
  188. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tray/_indicator.py +0 -0
  189. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tray/_pystray.py +0 -0
  190. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/__init__.py +0 -0
  191. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/base.py +0 -0
  192. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/chain.py +0 -0
  193. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/edge_engine.py +0 -0
  194. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/espeak.py +0 -0
  195. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/piper_engine.py +0 -0
  196. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/tts/player.py +0 -0
  197. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/__init__.py +0 -0
  198. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/base.py +0 -0
  199. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/chain.py +0 -0
  200. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/clipboard.py +0 -0
  201. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/collecting.py +0 -0
  202. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/fcitx_bridge.py +0 -0
  203. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/ibus.py +0 -0
  204. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/manager.py +0 -0
  205. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/modifier_guard.py +0 -0
  206. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/paste.py +0 -0
  207. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/pynput_type.py +0 -0
  208. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/wtype.py +0 -0
  209. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/xdotool.py +0 -0
  210. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/typers/ydotool.py +0 -0
  211. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/ui.py +0 -0
  212. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/vad.py +0 -0
  213. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/vocab_stats.py +0 -0
  214. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/vocabulary.py +0 -0
  215. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/watchdog.py +0 -0
  216. {python_voiceio-1.9.1 → python_voiceio-1.9.2}/voiceio/wordfreq.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-voiceio
3
- Version: 1.9.1
3
+ Version: 1.9.2
4
4
  Summary: Voice dictation for Linux. Speak → text, locally, instantly.
5
5
  Author: Hugo Montenegro
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-voiceio"
7
- version = "1.9.1"
7
+ version = "1.9.2"
8
8
  description = "Voice dictation for Linux. Speak → text, locally, instantly."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-voiceio
3
- Version: 1.9.1
3
+ Version: 1.9.2
4
4
  Summary: Voice dictation for Linux. Speak → text, locally, instantly.
5
5
  Author: Hugo Montenegro
6
6
  License-Expression: MIT
@@ -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: once the un-finalized audio tail grows past
148
- # this many seconds, it is cut at the nearest interior speech pause,
149
- # beam-decoded and frozen during recording, so interim passes and the
150
- # stop-time final decode only cover the short remaining tail. Smaller
151
- # chunks decode faster (less worker blocking) at slightly more boundary
152
- # risk. 0 disables (full re-decode at stop).
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 _freeze_chunk(self, audio: np.ndarray, chunk: np.ndarray) -> None:
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
- grown_secs = (len(audio) - self._last_decode_end) / self._sample_rate
415
- if not final and grown_secs < max(min_seconds, self._last_decode_secs):
416
- return # backpressure: don't decode faster than we can keep up
417
-
418
- # Freeze: once the tail is long enough, cut it at an interior speech
419
- # pause and beam-decode ONLY that chunk (its text is never decoded
420
- # again). The freeze pass does not touch the display — the interim
421
- # text already covers this audio; the next interim refreshes it.
422
- if (not final and self._freeze_secs > 0
423
- and len(tail) >= self._freeze_secs * self._sample_rate):
424
- # Past the whole search span with no pause found: force a cut.
425
- force = len(tail) >= (self._freeze_secs + _FREEZE_SEARCH_SECS) * self._sample_rate
426
- cut = _find_freeze_cut(tail, self._sample_rate, self._freeze_secs, force=force)
427
- if cut is not None:
428
- with self._freeze_lock:
429
- # Stop may have won the race for the lock and already
430
- # finalized from the current boundary.
431
- if not self._stop_event.is_set():
432
- self._freeze_pending_end = self._frozen_samples + cut
433
- try:
434
- self._freeze_chunk(audio, tail[:cut])
435
- finally:
436
- self._freeze_pending_end = None
437
- return
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