python-voiceio 1.15.0__tar.gz → 1.15.1__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 (233) hide show
  1. {python_voiceio-1.15.0/python_voiceio.egg-info → python_voiceio-1.15.1}/PKG-INFO +1 -1
  2. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/pyproject.toml +1 -1
  3. {python_voiceio-1.15.0 → python_voiceio-1.15.1/python_voiceio.egg-info}/PKG-INFO +1 -1
  4. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/python_voiceio.egg-info/SOURCES.txt +1 -0
  5. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_health.py +26 -0
  6. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_report.py +19 -1
  7. python_voiceio-1.15.1/tests/test_tray.py +58 -0
  8. python_voiceio-1.15.1/voiceio/__init__.py +1 -0
  9. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/health.py +13 -1
  10. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/report.py +11 -2
  11. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/setup/steps.py +2 -1
  12. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tray/__init__.py +15 -1
  13. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tray/_pystray.py +3 -0
  14. python_voiceio-1.15.0/voiceio/__init__.py +0 -1
  15. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/LICENSE +0 -0
  16. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/README.md +0 -0
  17. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/python_voiceio.egg-info/dependency_links.txt +0 -0
  18. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/python_voiceio.egg-info/entry_points.txt +0 -0
  19. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/python_voiceio.egg-info/requires.txt +0 -0
  20. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/python_voiceio.egg-info/top_level.txt +0 -0
  21. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/setup.cfg +0 -0
  22. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_announce.py +0 -0
  23. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_app_wiring.py +0 -0
  24. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_audio_quality.py +0 -0
  25. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_audio_source.py +0 -0
  26. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_backend_probes.py +0 -0
  27. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_cancel.py +0 -0
  28. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_cli.py +0 -0
  29. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_clipboard_read.py +0 -0
  30. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_clipboard_typer.py +0 -0
  31. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_commands.py +0 -0
  32. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_concurrency_lockdown.py +0 -0
  33. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_config.py +0 -0
  34. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_context_terms.py +0 -0
  35. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_corrections.py +0 -0
  36. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_dead_mic.py +0 -0
  37. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_decoders.py +0 -0
  38. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_engine.py +0 -0
  39. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_evdev_uaccess.py +0 -0
  40. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_fallback.py +0 -0
  41. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_fcitx_bridge.py +0 -0
  42. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_feedback_stream.py +0 -0
  43. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_focus.py +0 -0
  44. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_hints.py +0 -0
  45. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_history.py +0 -0
  46. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_hotkey_modes.py +0 -0
  47. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_ibus_engine_limits.py +0 -0
  48. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_ibus_engine_listener.py +0 -0
  49. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_ibus_pending.py +0 -0
  50. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_ibus_pids.py +0 -0
  51. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_ibus_ping.py +0 -0
  52. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_ibus_session.py +0 -0
  53. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_ibus_textlimit.py +0 -0
  54. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_ibus_typer.py +0 -0
  55. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_idle_audio.py +0 -0
  56. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_learn_clean.py +0 -0
  57. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_learn_import.py +0 -0
  58. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_learn_language.py +0 -0
  59. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_learn_metrics.py +0 -0
  60. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_learn_pipeline.py +0 -0
  61. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_learn_quiet.py +0 -0
  62. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_learn_resume.py +0 -0
  63. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_learn_review.py +0 -0
  64. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_learn_targets.py +0 -0
  65. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_llm.py +0 -0
  66. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_llm_api.py +0 -0
  67. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_mic_gain.py +0 -0
  68. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_modifier_guard.py +0 -0
  69. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_numbers.py +0 -0
  70. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_paste_last.py +0 -0
  71. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_pipeline.py +0 -0
  72. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_platform.py +0 -0
  73. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_postcorrect.py +0 -0
  74. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_postprocess.py +0 -0
  75. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_prebuffer.py +0 -0
  76. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_presence.py +0 -0
  77. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_prompt.py +0 -0
  78. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_quiet_audio.py +0 -0
  79. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_recorder_integration.py +0 -0
  80. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_retention.py +0 -0
  81. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_robustness.py +0 -0
  82. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_security_hardening.py +0 -0
  83. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_server.py +0 -0
  84. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_service.py +0 -0
  85. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_setup.py +0 -0
  86. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_sherpa.py +0 -0
  87. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_spool.py +0 -0
  88. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_streaming.py +0 -0
  89. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_suggest.py +0 -0
  90. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_tokens.py +0 -0
  91. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_transcriber.py +0 -0
  92. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_tts.py +0 -0
  93. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_typer_manager.py +0 -0
  94. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_vad.py +0 -0
  95. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_vocabulary.py +0 -0
  96. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_wordfreq.py +0 -0
  97. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/tests/test_worker_decode.py +0 -0
  98. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/__main__.py +0 -0
  99. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/announce.py +0 -0
  100. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/app.py +0 -0
  101. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/audio_source.py +0 -0
  102. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/backends.py +0 -0
  103. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/cli/__init__.py +0 -0
  104. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/cli/configcmd.py +0 -0
  105. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/cli/corrections.py +0 -0
  106. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/cli/doctor.py +0 -0
  107. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/cli/history.py +0 -0
  108. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/cli/learn.py +0 -0
  109. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/cli/models.py +0 -0
  110. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/cli/servicecmd.py +0 -0
  111. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/cli/uninstall.py +0 -0
  112. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/cli/vocab.py +0 -0
  113. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/clipboard_read.py +0 -0
  114. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/commands.py +0 -0
  115. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/config.py +0 -0
  116. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/consent.py +0 -0
  117. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/context_terms.py +0 -0
  118. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/__init__.py +0 -0
  119. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/bias.py +0 -0
  120. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/decoders/__init__.py +0 -0
  121. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/decoders/base.py +0 -0
  122. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/decoders/catalog.py +0 -0
  123. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/decoders/faster_whisper/__init__.py +0 -0
  124. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/decoders/faster_whisper/worker.py +0 -0
  125. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/decoders/fetch.py +0 -0
  126. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/decoders/lanes.py +0 -0
  127. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/decoders/sherpa.py +0 -0
  128. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/decoders/whispercpp.py +0 -0
  129. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/engine.py +0 -0
  130. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/core/pipeline.py +0 -0
  131. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/corrections.py +0 -0
  132. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/data/60-voiceio-uaccess.rules +0 -0
  133. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/data/__init__.py +0 -0
  134. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/demo.py +0 -0
  135. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/display.py +0 -0
  136. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/feedback.py +0 -0
  137. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/focus.py +0 -0
  138. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/hints.py +0 -0
  139. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/history.py +0 -0
  140. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/hotkeys/__init__.py +0 -0
  141. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/hotkeys/base.py +0 -0
  142. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/hotkeys/chain.py +0 -0
  143. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/hotkeys/evdev.py +0 -0
  144. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/hotkeys/pynput_backend.py +0 -0
  145. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/hotkeys/socket_backend.py +0 -0
  146. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/ibus/__init__.py +0 -0
  147. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/ibus/engine.py +0 -0
  148. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/ibus/install.py +0 -0
  149. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/ibus/pending.py +0 -0
  150. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/ibus/session.py +0 -0
  151. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/ibus/textlimit.py +0 -0
  152. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/idle_audio.py +0 -0
  153. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/learn/__init__.py +0 -0
  154. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/learn/augment.py +0 -0
  155. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/learn/clean.py +0 -0
  156. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/learn/evaluate.py +0 -0
  157. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/learn/importer.py +0 -0
  158. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/learn/metrics.py +0 -0
  159. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/learn/quiet.py +0 -0
  160. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/learn/review.py +0 -0
  161. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/learn/store.py +0 -0
  162. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/learn/teacher.py +0 -0
  163. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/learn/train.py +0 -0
  164. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/llm.py +0 -0
  165. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/llm_api.py +0 -0
  166. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/mic_gain.py +0 -0
  167. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/models/__init__.py +0 -0
  168. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/models/silero_vad.onnx +0 -0
  169. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/numbers.py +0 -0
  170. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/pidlock.py +0 -0
  171. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/platform.py +0 -0
  172. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/postcorrect.py +0 -0
  173. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/postprocess.py +0 -0
  174. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/power.py +0 -0
  175. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/presence.py +0 -0
  176. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/privacy.py +0 -0
  177. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/prompt.py +0 -0
  178. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/quiet_audio.py +0 -0
  179. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/recorder.py +0 -0
  180. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/retention.py +0 -0
  181. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/server/__init__.py +0 -0
  182. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/server/__main__.py +0 -0
  183. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/server/app.py +0 -0
  184. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/server/config.py +0 -0
  185. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/server/runtime.py +0 -0
  186. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/service.py +0 -0
  187. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/setup/__init__.py +0 -0
  188. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/setup/configfile.py +0 -0
  189. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/setup/extras.py +0 -0
  190. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/setup/hotkey.py +0 -0
  191. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/setup/noninteractive.py +0 -0
  192. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/setup/speech.py +0 -0
  193. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/setup/system.py +0 -0
  194. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/setup/ui.py +0 -0
  195. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/sounds/__init__.py +0 -0
  196. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/sounds/alert.wav +0 -0
  197. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/sounds/commit.wav +0 -0
  198. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/sounds/start.wav +0 -0
  199. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/sounds/stop.wav +0 -0
  200. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/spool.py +0 -0
  201. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/streaming.py +0 -0
  202. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/suggest.py +0 -0
  203. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tokens.py +0 -0
  204. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tray/_icons.py +0 -0
  205. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tray/_indicator.py +0 -0
  206. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tts/__init__.py +0 -0
  207. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tts/base.py +0 -0
  208. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tts/chain.py +0 -0
  209. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tts/edge_engine.py +0 -0
  210. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tts/espeak.py +0 -0
  211. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tts/piper_engine.py +0 -0
  212. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tts/player.py +0 -0
  213. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/tts/supertonic_engine.py +0 -0
  214. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/__init__.py +0 -0
  215. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/base.py +0 -0
  216. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/chain.py +0 -0
  217. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/clipboard.py +0 -0
  218. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/collecting.py +0 -0
  219. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/fcitx_bridge.py +0 -0
  220. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/ibus.py +0 -0
  221. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/manager.py +0 -0
  222. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/modifier_guard.py +0 -0
  223. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/paste.py +0 -0
  224. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/pynput_type.py +0 -0
  225. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/wtype.py +0 -0
  226. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/xdotool.py +0 -0
  227. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/typers/ydotool.py +0 -0
  228. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/ui.py +0 -0
  229. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/vad.py +0 -0
  230. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/vocab_stats.py +0 -0
  231. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/vocabulary.py +0 -0
  232. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/watchdog.py +0 -0
  233. {python_voiceio-1.15.0 → python_voiceio-1.15.1}/voiceio/wordfreq.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-voiceio
3
- Version: 1.15.0
3
+ Version: 1.15.1
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.15.0"
7
+ version = "1.15.1"
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.15.0
3
+ Version: 1.15.1
4
4
  Summary: Voice dictation for Linux. Speak → text, locally, instantly.
5
5
  Author: Hugo Montenegro
6
6
  License-Expression: MIT
@@ -79,6 +79,7 @@ tests/test_streaming.py
79
79
  tests/test_suggest.py
80
80
  tests/test_tokens.py
81
81
  tests/test_transcriber.py
82
+ tests/test_tray.py
82
83
  tests/test_tts.py
83
84
  tests/test_typer_manager.py
84
85
  tests/test_vad.py
@@ -123,3 +123,29 @@ def test_learning_status_and_tips(monkeypatch):
123
123
  assert st["Voice model"] == "fine-tuned on you (v0001-small-x)"
124
124
  assert st["Recordings"].startswith("on (") and st["Scheduled learning"] == "off"
125
125
  assert any("learn schedule on" in t for t in _accuracy_tips(st))
126
+
127
+
128
+ def test_silent_ibus_engine_is_not_a_warning_while_voiceio_is_stopped():
129
+ from voiceio.health import HealthReport, IBusStatus
130
+ p = Platform(os="linux", display_server="wayland", desktop="kde")
131
+ ib = IBusStatus(component_installed=True, daemon_running=True, voiceio_running=False)
132
+ text = format_report(HealthReport(platform=p, ibus_checks=ib))
133
+ line = next(ln for ln in text.splitlines() if "Engine answers" in ln)
134
+ assert "⚠" not in line and "isn't running" in line
135
+ ib.voiceio_running = True
136
+ line = next(ln for ln in format_report(HealthReport(platform=p, ibus_checks=ib)).splitlines()
137
+ if "Engine answers" in ln)
138
+ assert "⚠" in line and "service restart" in line
139
+
140
+
141
+ def test_check_ibus_asks_about_voiceio_only_when_the_engine_is_silent():
142
+ from voiceio import health
143
+ with patch("voiceio.ibus.install.component_installed", return_value=True), \
144
+ patch("voiceio.ibus.install.daemon_running", return_value=True), \
145
+ patch("voiceio.ibus.ping_engine", return_value=False), \
146
+ patch("voiceio.pidlock.daemon_alive", return_value=False) as alive:
147
+ assert health._check_ibus().voiceio_running is False
148
+ with patch("voiceio.ibus.ping_engine", return_value=True):
149
+ alive.reset_mock()
150
+ assert health._check_ibus().voiceio_running is True
151
+ alive.assert_not_called()
@@ -9,7 +9,7 @@ import pytest
9
9
 
10
10
  from voiceio import report
11
11
  from voiceio.config import Config
12
- from voiceio.health import BackendStatus, HealthReport
12
+ from voiceio.health import BackendStatus, HealthReport, IBusStatus
13
13
  from voiceio.platform import Platform
14
14
 
15
15
  FAKE_HOME = "/home/zelda-tester"
@@ -104,6 +104,16 @@ def test_report_lists_failures_and_warnings():
104
104
  assert "insecure permissions on 2 file(s)" in text
105
105
 
106
106
 
107
+ def test_silent_ibus_engine_is_expected_while_voiceio_is_stopped():
108
+ # Two 1.15.0 reports warned "ibus engine ping" only because voiceio wasn't running.
109
+ ib = IBusStatus(component_installed=True, daemon_running=True, env_persisted=True)
110
+ stopped = report.build_report(_health(ibus_checks=IBusStatus(**{**vars(ib), "voiceio_running": False})),
111
+ cfg=Config())
112
+ assert "engine ping" not in stopped and "voiceio not running" in stopped
113
+ running = report.build_report(_health(ibus_checks=ib), cfg=Config())
114
+ assert "ibus engine ping" in running and "voiceio not running" not in running
115
+
116
+
107
117
  def test_comment_is_one_bounded_line():
108
118
  text = report.build_report(_health(), comment="a\nb\tc " + "x" * 1000, cfg=Config())
109
119
  line = next(ln for ln in text.splitlines() if ln.startswith("comment:"))
@@ -111,6 +121,14 @@ def test_comment_is_one_bounded_line():
111
121
  assert len(line) <= len("comment: ") + report.MAX_COMMENT
112
122
 
113
123
 
124
+ def test_comment_drops_terminal_escapes():
125
+ # A real 1.15.0 report arrived with "comment: \x1bv" (Alt+V at the prompt).
126
+ text = report.build_report(_health(), comment="\x1bv", cfg=Config())
127
+ assert "comment:" not in text and "\x1b" not in text
128
+ text = report.build_report(_health(), comment="works\x1b[D\x1b[C great\x07", cfg=Config())
129
+ assert "comment: works great" in text.splitlines()
130
+
131
+
114
132
  # ── posting ──
115
133
 
116
134
  class _Resp(io.BytesIO):
@@ -0,0 +1,58 @@
1
+ """Tray backend probing: what doctor/setup promise must match what start() does."""
2
+ from __future__ import annotations
3
+
4
+ import builtins
5
+ import sys
6
+ from pathlib import Path
7
+ from unittest.mock import patch
8
+
9
+ import pytest
10
+
11
+ from voiceio import tray
12
+ from voiceio.tray import _pystray
13
+
14
+ linux = pytest.mark.skipif(not sys.platform.startswith("linux"), reason="linux probe")
15
+
16
+
17
+ @linux
18
+ def test_appindicator_wins():
19
+ with patch.object(tray, "_find_system_python", return_value="/usr/bin/python3"):
20
+ assert tray.probe_availability() == (True, "AppIndicator3 available", "")
21
+
22
+
23
+ @linux
24
+ def test_pystray_xembed_fallback_counts_as_a_tray():
25
+ # KDE/LXQt users without python3-gi got "no tray" though start() falls back to pystray.
26
+ with patch.object(tray, "_find_system_python", return_value=None), \
27
+ patch.object(tray, "_pystray_backend", return_value="xorg"):
28
+ ok, reason, hint = tray.probe_availability()
29
+ assert ok and "no menu" in reason and "for the full menu" in hint
30
+
31
+
32
+ @linux
33
+ def test_no_backend_at_all():
34
+ with patch.object(tray, "_find_system_python", return_value=None), \
35
+ patch.object(tray, "_pystray_backend", return_value=None):
36
+ ok, reason, hint = tray.probe_availability()
37
+ assert not ok and "AppIndicator3" in reason and hint.startswith("install:")
38
+
39
+
40
+ def _import_raising(exc):
41
+ real = builtins.__import__
42
+
43
+ def fake(name, *a, **kw):
44
+ if name == "pystray":
45
+ raise exc
46
+ return real(name, *a, **kw)
47
+ return fake
48
+
49
+
50
+ class _DisplayNameError(Exception):
51
+ """Stands in for Xlib.error.DisplayNameError (no DISPLAY): not an ImportError."""
52
+
53
+
54
+ def test_pystray_without_x_display_does_not_raise(monkeypatch):
55
+ monkeypatch.delitem(sys.modules, "pystray", raising=False)
56
+ with patch("builtins.__import__", _import_raising(_DisplayNameError(":0"))):
57
+ assert tray._pystray_backend() is None
58
+ assert _pystray.start(lambda: None, Path("idle.png"), []) is False
@@ -0,0 +1 @@
1
+ __version__ = "1.15.1"
@@ -25,6 +25,8 @@ class IBusStatus:
25
25
  component_installed: bool = False
26
26
  daemon_running: bool = False
27
27
  socket_reachable: bool = False
28
+ # The engine runs while voiceio does, so a silent one only matters then.
29
+ voiceio_running: bool = True
28
30
  gnome_source_configured: bool = False
29
31
  env_persisted: bool = False
30
32
 
@@ -301,6 +303,10 @@ def _check_ibus() -> IBusStatus:
301
303
  # Ping, not exists(): an engine can hold a socket file yet be deaf.
302
304
  from voiceio.ibus import ping_engine
303
305
  status.socket_reachable = ping_engine(timeout=1.0)
306
+ if not status.socket_reachable:
307
+ from voiceio.config import PID_PATH
308
+ from voiceio.pidlock import daemon_alive
309
+ status.voiceio_running = daemon_alive(PID_PATH)
304
310
 
305
311
  # Check GNOME input source
306
312
  try:
@@ -433,7 +439,9 @@ def format_report(report: HealthReport) -> str:
433
439
  lines.append(_check_line("Tray icon", report.tray_ok,
434
440
  report.tray_reason if not report.tray_ok else "",
435
441
  warn=not report.tray_ok))
436
- if report.tray_fix_hint and not report.tray_ok:
442
+ if report.tray_ok and report.tray_fix_hint: # works, but degraded
443
+ lines[-1] += f" {DIM}{report.tray_reason}{RESET}"
444
+ if report.tray_fix_hint:
437
445
  lines.append(f" {DIM}→ {report.tray_fix_hint}{RESET}")
438
446
 
439
447
  # IBus pipeline
@@ -448,6 +456,10 @@ def format_report(report: HealthReport) -> str:
448
456
  ("GNOME input source", ibus.gnome_source_configured, "voiceio setup"),
449
457
  ("Env persisted (reboot-safe)", ibus.env_persisted, "voiceio setup"),
450
458
  ]:
459
+ if label == "Engine answers" and not ok and not ibus.voiceio_running:
460
+ lines.append(f" {DIM}–{RESET} {label} "
461
+ f"{DIM}starts with voiceio, which isn't running{RESET}")
462
+ continue
451
463
  lines.append(_check_line(label, ok, hint if not ok else "",
452
464
  warn=not ok))
453
465
 
@@ -30,6 +30,8 @@ TIMEOUT_SECS = 8.0
30
30
  MAX_COMMENT = 300
31
31
  MAX_DETAIL = 90
32
32
 
33
+ # A terminal escape: CSI sequences (arrow keys) or ESC plus one key (Alt+key).
34
+ _ESCAPE = re.compile(r"\x1b(?:\[[0-?]*[ -/]*[@-~]|.)?", re.S)
33
35
  _IPV4 = re.compile(r"\b(?:\d{1,3}\.){3}\d{1,3}\b")
34
36
  _IPV6 = re.compile(r"\b(?:[0-9a-f]{1,4}:){3,7}[0-9a-f]{1,4}\b", re.I)
35
37
  _MAC = re.compile(r"\b(?:[0-9a-f]{2}[:-]){5}[0-9a-f]{2}\b", re.I)
@@ -155,7 +157,7 @@ def build_report(
155
157
  if health.ibus_checks is not None:
156
158
  ib = health.ibus_checks
157
159
  for label, ok in (("component", ib.component_installed), ("daemon", ib.daemon_running),
158
- ("engine ping", ib.socket_reachable),
160
+ ("engine ping", ib.socket_reachable or not ib.voiceio_running),
159
161
  ("env persisted", ib.env_persisted)):
160
162
  if not ok:
161
163
  warned.append(f"ibus {label}")
@@ -178,7 +180,9 @@ def build_report(
178
180
  f"python {_py_platform.python_version()}",
179
181
  f"backends: hotkey {hotkey.name if hotkey else 'none'} · "
180
182
  f"typer {typer.name if typer else 'none'} · audio {audio} "
181
- f"(vad {cfg.audio.vad_backend})",
183
+ f"(vad {cfg.audio.vad_backend})"
184
+ + (" · voiceio not running" if health.ibus_checks is not None
185
+ and not health.ibus_checks.voiceio_running else ""),
182
186
  f"model: {_model_label(cfg.model.name)}",
183
187
  ]
184
188
  if unavailable:
@@ -186,6 +190,7 @@ def build_report(
186
190
  lines.append("failed: " + "; ".join(failed) if failed else "failed: none")
187
191
  if warned:
188
192
  lines.append("warnings: " + "; ".join(warned))
193
+ comment = "".join(c if c.isprintable() else " " for c in _ESCAPE.sub("", comment))
189
194
  comment = " ".join(comment.split())[:MAX_COMMENT]
190
195
  if comment:
191
196
  lines.append(f"comment: {comment}")
@@ -233,6 +238,10 @@ def _interactive() -> bool:
233
238
 
234
239
 
235
240
  def _ask(prompt: str) -> str:
241
+ try:
242
+ import readline # noqa: F401 line editing, so arrow keys don't type escapes
243
+ except ImportError:
244
+ pass
236
245
  try:
237
246
  return input(prompt)
238
247
  except (EOFError, KeyboardInterrupt):
@@ -184,7 +184,8 @@ def _print_tray_check() -> bool:
184
184
  from voiceio.tray import probe_availability
185
185
  tray_ok, tray_reason, tray_fix_hint = probe_availability()
186
186
  if tray_ok:
187
- _print_check("Tray icon", True, "system tray indicator available")
187
+ _print_check("Tray icon", True, f"{tray_reason}; {tray_fix_hint}" if tray_fix_hint
188
+ else "system tray indicator available")
188
189
  else:
189
190
  _print_check("Tray icon", False,
190
191
  tray_fix_hint if tray_fix_hint else tray_reason,
@@ -59,11 +59,16 @@ def probe_availability() -> tuple[bool, str, str]:
59
59
  if py:
60
60
  return True, "AppIndicator3 available", ""
61
61
  from voiceio.platform import pkg_install
62
+ hint = f"install: {pkg_install('python3-gi', 'gir1.2-ayatanaappindicator3-0.1')}"
63
+ if _pystray_backend() == "xorg":
64
+ # What start() falls back to: an XEmbed icon (KDE and LXQt show
65
+ # it), animated, but without the menu.
66
+ return True, "basic icon (pystray, no menu)", f"for the full menu, {hint}"
62
67
  return (
63
68
  False,
64
69
  "no python3 with GTK3/AppIndicator3 bindings "
65
70
  "(set VOICEIO_SYSTEM_PYTHON to override)",
66
- f"install: {pkg_install('python3-gi', 'gir1.2-ayatanaappindicator3-0.1')}",
71
+ hint,
67
72
  )
68
73
  elif sys.platform == "darwin":
69
74
  try:
@@ -82,6 +87,15 @@ def probe_availability() -> tuple[bool, str, str]:
82
87
  return False, "unsupported platform", ""
83
88
 
84
89
 
90
+ def _pystray_backend() -> str | None:
91
+ """The backend pystray picks here ("xorg", "appindicator", ...), or None."""
92
+ try:
93
+ import pystray
94
+ except Exception: # ImportError, or Xlib errors when there's no X display
95
+ return None
96
+ return pystray.Icon.__module__.rsplit("._", 1)[-1]
97
+
98
+
85
99
  def _start_indicator(
86
100
  theme_dir: Path,
87
101
  icon_names: list[str],
@@ -35,6 +35,9 @@ def start(
35
35
  except ImportError:
36
36
  log.warning("pystray/Pillow not installed, tray icon disabled")
37
37
  return False
38
+ except Exception as e: # Linux import opens an X display: none means Xlib errors
39
+ log.warning("pystray unusable (%s), tray icon disabled", e)
40
+ return False
38
41
 
39
42
  _idle_img = Image.open(idle_path)
40
43
  _recording_frames = [Image.open(p) for p in frame_paths]
@@ -1 +0,0 @@
1
- __version__ = "1.15.0"
File without changes