python-voiceio 1.8.2__tar.gz → 1.8.3__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 (214) hide show
  1. {python_voiceio-1.8.2/python_voiceio.egg-info → python_voiceio-1.8.3}/PKG-INFO +1 -1
  2. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/pyproject.toml +1 -1
  3. {python_voiceio-1.8.2 → python_voiceio-1.8.3/python_voiceio.egg-info}/PKG-INFO +1 -1
  4. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/python_voiceio.egg-info/SOURCES.txt +1 -0
  5. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_cancel.py +5 -2
  6. python_voiceio-1.8.3/tests/test_learn_language.py +39 -0
  7. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_postprocess.py +15 -2
  8. python_voiceio-1.8.3/voiceio/__init__.py +1 -0
  9. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/cli/learn.py +14 -1
  10. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/learn/teacher.py +1 -1
  11. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/postprocess.py +32 -3
  12. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/wordfreq.py +15 -3
  13. python_voiceio-1.8.2/voiceio/__init__.py +0 -1
  14. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/LICENSE +0 -0
  15. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/README.md +0 -0
  16. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/python_voiceio.egg-info/dependency_links.txt +0 -0
  17. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/python_voiceio.egg-info/entry_points.txt +0 -0
  18. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/python_voiceio.egg-info/requires.txt +0 -0
  19. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/python_voiceio.egg-info/top_level.txt +0 -0
  20. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/setup.cfg +0 -0
  21. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_app_wiring.py +0 -0
  22. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_audio_quality.py +0 -0
  23. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_audio_source.py +0 -0
  24. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_backend_probes.py +0 -0
  25. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_cli.py +0 -0
  26. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_clipboard_read.py +0 -0
  27. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_clipboard_typer.py +0 -0
  28. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_commands.py +0 -0
  29. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_concurrency_lockdown.py +0 -0
  30. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_config.py +0 -0
  31. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_corrections.py +0 -0
  32. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_decoders.py +0 -0
  33. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_engine.py +0 -0
  34. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_evdev_uaccess.py +0 -0
  35. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_fallback.py +0 -0
  36. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_fcitx_bridge.py +0 -0
  37. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_feedback_stream.py +0 -0
  38. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_focus.py +0 -0
  39. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_health.py +0 -0
  40. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_hints.py +0 -0
  41. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_history.py +0 -0
  42. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_hotkey_modes.py +0 -0
  43. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_ibus_engine_limits.py +0 -0
  44. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_ibus_engine_listener.py +0 -0
  45. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_ibus_pending.py +0 -0
  46. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_ibus_pids.py +0 -0
  47. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_ibus_ping.py +0 -0
  48. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_ibus_session.py +0 -0
  49. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_ibus_textlimit.py +0 -0
  50. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_ibus_typer.py +0 -0
  51. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_idle_audio.py +0 -0
  52. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_learn_clean.py +0 -0
  53. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_learn_import.py +0 -0
  54. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_learn_metrics.py +0 -0
  55. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_learn_pipeline.py +0 -0
  56. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_learn_quiet.py +0 -0
  57. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_learn_review.py +0 -0
  58. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_learn_targets.py +0 -0
  59. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_llm.py +0 -0
  60. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_llm_api.py +0 -0
  61. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_modifier_guard.py +0 -0
  62. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_numbers.py +0 -0
  63. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_paste_last.py +0 -0
  64. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_pipeline.py +0 -0
  65. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_platform.py +0 -0
  66. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_postcorrect.py +0 -0
  67. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_prebuffer.py +0 -0
  68. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_prompt.py +0 -0
  69. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_quiet_audio.py +0 -0
  70. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_recorder_integration.py +0 -0
  71. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_retention.py +0 -0
  72. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_robustness.py +0 -0
  73. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_security_hardening.py +0 -0
  74. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_server.py +0 -0
  75. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_service.py +0 -0
  76. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_setup.py +0 -0
  77. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_streaming.py +0 -0
  78. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_suggest.py +0 -0
  79. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_tokens.py +0 -0
  80. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_transcriber.py +0 -0
  81. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_tts.py +0 -0
  82. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_typer_manager.py +0 -0
  83. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_vad.py +0 -0
  84. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_vocabulary.py +0 -0
  85. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_wordfreq.py +0 -0
  86. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/tests/test_worker_decode.py +0 -0
  87. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/__main__.py +0 -0
  88. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/app.py +0 -0
  89. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/audio_source.py +0 -0
  90. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/backends.py +0 -0
  91. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/cli/__init__.py +0 -0
  92. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/cli/configcmd.py +0 -0
  93. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/cli/corrections.py +0 -0
  94. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/cli/doctor.py +0 -0
  95. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/cli/history.py +0 -0
  96. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/cli/models.py +0 -0
  97. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/cli/servicecmd.py +0 -0
  98. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/cli/uninstall.py +0 -0
  99. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/cli/vocab.py +0 -0
  100. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/clipboard_read.py +0 -0
  101. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/commands.py +0 -0
  102. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/config.py +0 -0
  103. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/consent.py +0 -0
  104. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/core/__init__.py +0 -0
  105. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/core/bias.py +0 -0
  106. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/core/decoders/__init__.py +0 -0
  107. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/core/decoders/base.py +0 -0
  108. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/core/decoders/catalog.py +0 -0
  109. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/core/decoders/faster_whisper/__init__.py +0 -0
  110. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/core/decoders/faster_whisper/worker.py +0 -0
  111. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/core/decoders/lanes.py +0 -0
  112. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/core/decoders/sherpa.py +0 -0
  113. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/core/decoders/whispercpp.py +0 -0
  114. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/core/engine.py +0 -0
  115. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/core/pipeline.py +0 -0
  116. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/corrections.py +0 -0
  117. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/data/60-voiceio-uaccess.rules +0 -0
  118. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/data/__init__.py +0 -0
  119. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/demo.py +0 -0
  120. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/display.py +0 -0
  121. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/feedback.py +0 -0
  122. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/focus.py +0 -0
  123. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/health.py +0 -0
  124. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/hints.py +0 -0
  125. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/history.py +0 -0
  126. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/hotkeys/__init__.py +0 -0
  127. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/hotkeys/base.py +0 -0
  128. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/hotkeys/chain.py +0 -0
  129. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/hotkeys/evdev.py +0 -0
  130. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/hotkeys/pynput_backend.py +0 -0
  131. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/hotkeys/socket_backend.py +0 -0
  132. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/ibus/__init__.py +0 -0
  133. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/ibus/engine.py +0 -0
  134. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/ibus/install.py +0 -0
  135. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/ibus/pending.py +0 -0
  136. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/ibus/session.py +0 -0
  137. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/ibus/textlimit.py +0 -0
  138. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/idle_audio.py +0 -0
  139. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/learn/__init__.py +0 -0
  140. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/learn/augment.py +0 -0
  141. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/learn/clean.py +0 -0
  142. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/learn/evaluate.py +0 -0
  143. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/learn/importer.py +0 -0
  144. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/learn/metrics.py +0 -0
  145. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/learn/quiet.py +0 -0
  146. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/learn/review.py +0 -0
  147. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/learn/store.py +0 -0
  148. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/learn/train.py +0 -0
  149. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/llm.py +0 -0
  150. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/llm_api.py +0 -0
  151. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/models/__init__.py +0 -0
  152. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/models/silero_vad.onnx +0 -0
  153. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/numbers.py +0 -0
  154. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/pidlock.py +0 -0
  155. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/platform.py +0 -0
  156. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/postcorrect.py +0 -0
  157. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/power.py +0 -0
  158. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/privacy.py +0 -0
  159. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/prompt.py +0 -0
  160. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/quiet_audio.py +0 -0
  161. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/recorder.py +0 -0
  162. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/retention.py +0 -0
  163. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/server/__init__.py +0 -0
  164. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/server/__main__.py +0 -0
  165. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/server/app.py +0 -0
  166. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/server/config.py +0 -0
  167. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/server/runtime.py +0 -0
  168. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/service.py +0 -0
  169. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/setup/__init__.py +0 -0
  170. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/setup/configfile.py +0 -0
  171. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/setup/extras.py +0 -0
  172. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/setup/hotkey.py +0 -0
  173. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/setup/noninteractive.py +0 -0
  174. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/setup/speech.py +0 -0
  175. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/setup/steps.py +0 -0
  176. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/setup/system.py +0 -0
  177. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/setup/ui.py +0 -0
  178. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/sounds/__init__.py +0 -0
  179. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/sounds/commit.wav +0 -0
  180. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/sounds/start.wav +0 -0
  181. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/sounds/stop.wav +0 -0
  182. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/streaming.py +0 -0
  183. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/suggest.py +0 -0
  184. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/tokens.py +0 -0
  185. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/tray/__init__.py +0 -0
  186. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/tray/_icons.py +0 -0
  187. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/tray/_indicator.py +0 -0
  188. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/tray/_pystray.py +0 -0
  189. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/tts/__init__.py +0 -0
  190. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/tts/base.py +0 -0
  191. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/tts/chain.py +0 -0
  192. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/tts/edge_engine.py +0 -0
  193. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/tts/espeak.py +0 -0
  194. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/tts/piper_engine.py +0 -0
  195. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/tts/player.py +0 -0
  196. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/__init__.py +0 -0
  197. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/base.py +0 -0
  198. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/chain.py +0 -0
  199. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/clipboard.py +0 -0
  200. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/collecting.py +0 -0
  201. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/fcitx_bridge.py +0 -0
  202. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/ibus.py +0 -0
  203. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/manager.py +0 -0
  204. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/modifier_guard.py +0 -0
  205. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/paste.py +0 -0
  206. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/pynput_type.py +0 -0
  207. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/wtype.py +0 -0
  208. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/xdotool.py +0 -0
  209. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/typers/ydotool.py +0 -0
  210. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/ui.py +0 -0
  211. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/vad.py +0 -0
  212. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/vocab_stats.py +0 -0
  213. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/vocabulary.py +0 -0
  214. {python_voiceio-1.8.2 → python_voiceio-1.8.3}/voiceio/watchdog.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-voiceio
3
- Version: 1.8.2
3
+ Version: 1.8.3
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.8.2"
7
+ version = "1.8.3"
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.8.2
3
+ Version: 1.8.3
4
4
  Summary: Voice dictation for Linux. Speak → text, locally, instantly.
5
5
  Author: Hugo Montenegro
6
6
  License-Expression: MIT
@@ -41,6 +41,7 @@ tests/test_ibus_typer.py
41
41
  tests/test_idle_audio.py
42
42
  tests/test_learn_clean.py
43
43
  tests/test_learn_import.py
44
+ tests/test_learn_language.py
44
45
  tests/test_learn_metrics.py
45
46
  tests/test_learn_pipeline.py
46
47
  tests/test_learn_quiet.py
@@ -156,14 +156,17 @@ def test_cancel_too_late_changes_nothing(tmp_path):
156
156
  session = MagicMock()
157
157
  session.cancel.return_value = False # final text already typed
158
158
  session.stop.side_effect = lambda audio: (in_stop.set(), release.wait(5), "words")[2]
159
+ # The finalizer goes on to copy the text from its own thread; left real, it
160
+ # lands on whatever clipboard a later test has patched in.
161
+ vio._copy_result_async = MagicMock()
159
162
  _finalizing(vio, tmp_path, session)
160
163
  assert in_stop.wait(5)
161
164
  gen = vio._generation
162
165
  vio.cancel()
163
166
  assert vio._state == _State.FINALIZING and vio._generation == gen
164
167
  release.set()
165
- for _ in range(200):
166
- if vio._state == _State.IDLE:
168
+ for _ in range(500):
169
+ if vio._state == _State.IDLE and not vio._outputs:
167
170
  break
168
171
  time.sleep(0.01)
169
172
  vio.engine.commit.assert_called_once()
@@ -0,0 +1,39 @@
1
+ """Fine-tuning and labeling follow the dictation language."""
2
+ from __future__ import annotations
3
+
4
+ import pytest
5
+
6
+ from voiceio.cli import learn as learn_cli
7
+ from voiceio.config import Config
8
+
9
+
10
+ def _with_language(monkeypatch, lang):
11
+ cfg = Config()
12
+ cfg.model.language = lang
13
+ monkeypatch.setattr(learn_cli, "_cfg", lambda: cfg)
14
+
15
+
16
+ def test_training_uses_the_dictation_language(monkeypatch):
17
+ """A Spanish voice trained under the "en" token learned the wrong prompt."""
18
+ _with_language(monkeypatch, "es")
19
+ assert learn_cli._train_language() == "es"
20
+
21
+
22
+ def test_training_refuses_auto_with_a_hint(monkeypatch):
23
+ _with_language(monkeypatch, "auto")
24
+ with pytest.raises(SystemExit, match="model.language"):
25
+ learn_cli._train_language()
26
+
27
+
28
+ def test_teacher_detects_when_language_is_auto(monkeypatch):
29
+ from voiceio.learn import teacher
30
+ monkeypatch.setattr("voiceio.core.decoders.faster_whisper.worker.load_model", lambda *a, **k: object())
31
+ assert teacher.WhisperTeacher("tiny", language="auto")._language is None
32
+ assert teacher.WhisperTeacher("tiny", language="es")._language == "es"
33
+
34
+
35
+ def test_word_frequency_survives_auto_and_unknown_languages():
36
+ """language = "auto" raised LookupError in vocabulary biasing."""
37
+ from voiceio.wordfreq import is_common, is_known
38
+ assert is_common("house", "auto") and is_known("casa", "es")
39
+ assert not is_common("house", "xx")
@@ -102,7 +102,20 @@ class TestCapitalization:
102
102
  assert cleanup("hello world") == "Hello world"
103
103
 
104
104
  def test_after_period(self):
105
- assert cleanup("hello. world") == "Hello. World"
105
+ assert cleanup("hello? world") == "Hello? World"
106
+ assert cleanup("Hello. World") == "Hello. World"
107
+
108
+ def test_lowercase_after_a_segment_stop_is_a_comma(self):
109
+ # Whisper ends each segment with "." and continues the sentence in
110
+ # lowercase; capitalizing it made a false stop permanent.
111
+ assert cleanup("a bit bigger. and remove the latch.") == "A bit bigger, and remove the latch."
112
+ assert cleanup("hello. world") == "Hello, world"
113
+
114
+ def test_abbreviations_and_dotted_names_keep_their_dot(self):
115
+ assert cleanup("pears etc. and more") == "Pears etc. and more"
116
+ assert cleanup("use e.g. this one") == "Use e.g. this one"
117
+ assert cleanup("go to hugo0.com. and then") == "Go to hugo0.com. and then"
118
+ assert cleanup("I paused... and then") == "I paused... and then"
106
119
 
107
120
  def test_after_question_mark(self):
108
121
  assert cleanup("really? yes") == "Really? Yes"
@@ -184,7 +197,7 @@ class TestEdgeCases:
184
197
  assert result == "..."
185
198
 
186
199
  def test_unicode_accents(self):
187
- assert cleanup("café. résumé") == "Café. Résumé"
200
+ assert cleanup("café? résumé") == "Café? Résumé"
188
201
 
189
202
 
190
203
  class TestWordMatchCompatibility:
@@ -0,0 +1 @@
1
+ __version__ = "1.8.3"
@@ -417,6 +417,16 @@ def cmd_train(args: argparse.Namespace) -> None:
417
417
  f" (compare with the current model, then `voiceio learn promote {run.name}`)")
418
418
 
419
419
 
420
+ def _train_language() -> str:
421
+ """The language a fine-tune is trained under: the one dictation decodes
422
+ with. "auto" has no single answer, so it has to be set first."""
423
+ lang = _cfg().model.language or "en"
424
+ if lang == "auto":
425
+ raise SystemExit("Fine-tuning needs one language: set it with "
426
+ "`voiceio config set model.language es` (your dictation language).")
427
+ return lang
428
+
429
+
420
430
  def _train(ds: Path, *, base: str = "small", epochs: int = 4, synthetic_share: float = 0.3,
421
431
  full: bool = False, remote: bool = False) -> Path | None:
422
432
  """Export `ds` and fine-tune on it; returns the run dir (None for --remote)."""
@@ -433,8 +443,11 @@ def _train(ds: Path, *, base: str = "small", epochs: int = 4, synthetic_share: f
433
443
  return None
434
444
  train.require_train_deps()
435
445
  hotwords = (folder / train.HOTWORDS_FILE).read_text(encoding="utf-8")
446
+ # The language token the model is trained under must be the one it decodes
447
+ # with: training a Spanish voice under "en" taught it the wrong prompt.
436
448
  hf = train.train(folder, run, train.TrainConfig(
437
- base=base, epochs=epochs, decoder_only=False if full else None, hotwords=hotwords))
449
+ base=base, epochs=epochs, decoder_only=False if full else None, hotwords=hotwords,
450
+ language=_train_language()))
438
451
  train.convert(hf, run / "ct2")
439
452
  return run
440
453
 
@@ -45,7 +45,7 @@ class WhisperTeacher:
45
45
  # A background batch job (see cli.learn._yield_cpu): use every core idle.
46
46
  self._model = load_model(model, device=device, compute_type=compute_type,
47
47
  cpu_threads=max(4, (os.cpu_count() or 8) // 2))
48
- self._language = language
48
+ self._language = None if language in ("", "auto") else language # None: detect
49
49
  terms = [t for t in vocabulary if t]
50
50
  # Prompt, not hotwords: hotwords are capped at 223 tokens; a prompt
51
51
  # of the most important terms still biases spelling. The tokenizer
@@ -23,6 +23,21 @@ _NO_CASE_LANGUAGES = frozenset({"zh", "ja", "ko", "ar", "he", "th", "hi", "bn",
23
23
  _FILLER_RE = re.compile(
24
24
  r"[^\S\n]*,?[^\S\n]*\b(?:[Uu]h[-\s]?huh|[Mm]hm|[Uu]h+m*|[Uu]m+|[Hh]m{2,})\b[^\S\n]*,?[^\S\n]*",
25
25
  )
26
+ # A word (2+ letters, not part of a dotted name or an ellipsis) ending in "."
27
+ # and followed by a lowercase word: a segment boundary, not a sentence end.
28
+ _SEGMENT_STOP_RE = re.compile(r"(?<![.\w])([A-Za-zÀ-ɏ]{2,})\.(\s+)(?=[a-zà-ÿ])")
29
+ _ABBREVIATIONS = frozenset({
30
+ "etc", "vs", "approx", "cf", "al", "mr", "mrs", "ms", "dr", "st", "jr", "sr",
31
+ "inc", "ltd", "co", "fig", "eq", "vol", "no", "pp", "ca", "min", "max", "sec",
32
+ })
33
+
34
+
35
+ def _not_an_ending(word: str) -> bool:
36
+ """The word before a "." is an abbreviation or a dotted name, not a
37
+ sentence's last word."""
38
+ return "." in word or word.lower() in _ABBREVIATIONS
39
+
40
+
26
41
  # A re-decode artifact is a whole duplicated sentence; require this many words
27
42
  # so emphatic short repeats ("No. No.", "Stop. Stop.") are preserved.
28
43
  _MIN_DEDUP_WORDS = 4
@@ -95,14 +110,28 @@ def cleanup(text: str, language: str = "en") -> str:
95
110
  text = re.sub(r"\s+([.,;:?!])", r"\1", text)
96
111
 
97
112
  if language not in _NO_CASE_LANGUAGES:
113
+ # Whisper closes every segment with "." even mid-sentence, and the next
114
+ # segment then carries on in lowercase ("a bit bigger. and remove the
115
+ # latch"): on real dictation that was 1 in 4 notes. A lowercase
116
+ # continuation means the sentence did not end, so it gets a comma —
117
+ # before the capitalization below would make the false stop permanent.
118
+ text = _SEGMENT_STOP_RE.sub(
119
+ lambda m: m.group(0) if m.group(1).lower() in _ABBREVIATIONS
120
+ else m.group(1) + "," + m.group(2),
121
+ text,
122
+ )
123
+
124
+
98
125
  # Capitalize first character
99
126
  text = text[0].upper() + text[1:]
100
127
 
101
128
  # Capitalize after sentence-ending punctuation (an ellipsis is a
102
- # pause, not an ending)
129
+ # pause, not an ending, and so is the dot of "etc.", "e.g." or a name
130
+ # like "hugo0.com")
103
131
  text = re.sub(
104
- r"(?<!\.\.)([.?!]\s+)([a-z\u00E0-\u00FF])",
105
- lambda m: m.group(1) + m.group(2).upper(),
132
+ r"(\S*)(?<!\.\.)([.?!]\s+)([a-z\u00E0-\u00FF])",
133
+ lambda m: m.group(0) if m.group(2)[0] == "." and _not_an_ending(m.group(1))
134
+ else m.group(1) + m.group(2) + m.group(3).upper(),
106
135
  text,
107
136
  )
108
137
 
@@ -41,14 +41,26 @@ _CONTRACTIONS = frozenset({
41
41
  })
42
42
 
43
43
 
44
+ def _zipf(word: str, language: str) -> float:
45
+ """Zipf frequency, 0.0 for a language wordfreq has no list for. "auto"
46
+ (detect per dictation) has no single list either: score it as English,
47
+ which is where the jargon in a vocabulary list usually comes from."""
48
+ if language in ("", "auto"):
49
+ language = "en"
50
+ try:
51
+ return zipf_frequency(word.lower(), language)
52
+ except LookupError:
53
+ return 0.0
54
+
55
+
44
56
  def is_common(word: str, language: str = "en", threshold: float = _ZIPF_COMMON_THRESHOLD) -> bool:
45
57
  """Check if a word is common (high frequency). Used for suggesting corrections."""
46
- return zipf_frequency(word.lower(), language) >= threshold
58
+ return _zipf(word, language) >= threshold
47
59
 
48
60
 
49
61
  def rank(word: str, language: str = "en") -> int | None:
50
62
  """Get approximate frequency rank. None if not found."""
51
- z = zipf_frequency(word.lower(), language)
63
+ z = _zipf(word, language)
52
64
  if z == 0.0:
53
65
  return None
54
66
  # Convert zipf to approximate rank (higher zipf = lower rank number)
@@ -61,7 +73,7 @@ def is_known(word: str, language: str = "en") -> bool:
61
73
  wl = word.lower()
62
74
  if wl in _CONTRACTIONS:
63
75
  return True
64
- return zipf_frequency(wl, language) >= _ZIPF_KNOWN_THRESHOLD
76
+ return _zipf(wl, language) >= _ZIPF_KNOWN_THRESHOLD
65
77
 
66
78
 
67
79
  def extract_words(text: str) -> list[str]:
@@ -1 +0,0 @@
1
- __version__ = "1.8.2"
File without changes
File without changes
File without changes