python-voiceio 0.9.11__tar.gz → 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. python_voiceio-1.0.0/PKG-INFO +314 -0
  2. python_voiceio-1.0.0/README.md +261 -0
  3. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/pyproject.toml +34 -19
  4. python_voiceio-1.0.0/python_voiceio.egg-info/PKG-INFO +314 -0
  5. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/python_voiceio.egg-info/SOURCES.txt +79 -17
  6. python_voiceio-1.0.0/python_voiceio.egg-info/entry_points.txt +3 -0
  7. python_voiceio-1.0.0/python_voiceio.egg-info/requires.txt +42 -0
  8. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_app_wiring.py +83 -143
  9. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_audio_quality.py +4 -4
  10. python_voiceio-1.0.0/tests/test_audio_source.py +232 -0
  11. python_voiceio-1.0.0/tests/test_cli.py +71 -0
  12. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_commands.py +46 -61
  13. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_concurrency_lockdown.py +85 -91
  14. python_voiceio-1.0.0/tests/test_config.py +156 -0
  15. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_corrections.py +41 -0
  16. python_voiceio-1.0.0/tests/test_decoders.py +124 -0
  17. python_voiceio-1.0.0/tests/test_engine.py +97 -0
  18. python_voiceio-1.0.0/tests/test_evdev_uaccess.py +85 -0
  19. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_fallback.py +6 -0
  20. python_voiceio-1.0.0/tests/test_fcitx_bridge.py +49 -0
  21. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_health.py +34 -0
  22. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_ibus_engine_limits.py +33 -1
  23. python_voiceio-1.0.0/tests/test_ibus_engine_listener.py +77 -0
  24. python_voiceio-1.0.0/tests/test_ibus_pids.py +35 -0
  25. python_voiceio-1.0.0/tests/test_ibus_session.py +536 -0
  26. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_ibus_typer.py +82 -23
  27. python_voiceio-1.0.0/tests/test_learn_clean.py +42 -0
  28. python_voiceio-1.0.0/tests/test_learn_import.py +37 -0
  29. python_voiceio-1.0.0/tests/test_learn_metrics.py +38 -0
  30. python_voiceio-1.0.0/tests/test_learn_pipeline.py +294 -0
  31. python_voiceio-1.0.0/tests/test_learn_review.py +20 -0
  32. python_voiceio-1.0.0/tests/test_learn_targets.py +52 -0
  33. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_llm.py +30 -28
  34. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_llm_api.py +3 -3
  35. python_voiceio-1.0.0/tests/test_numbers.py +141 -0
  36. python_voiceio-1.0.0/tests/test_pipeline.py +67 -0
  37. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_platform.py +77 -0
  38. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_postcorrect.py +32 -8
  39. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_postprocess.py +33 -13
  40. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_retention.py +15 -0
  41. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_robustness.py +116 -116
  42. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_security_hardening.py +8 -8
  43. python_voiceio-1.0.0/tests/test_server.py +575 -0
  44. python_voiceio-1.0.0/tests/test_service.py +25 -0
  45. python_voiceio-0.9.11/tests/test_wizard.py → python_voiceio-1.0.0/tests/test_setup.py +58 -32
  46. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_streaming.py +143 -23
  47. python_voiceio-1.0.0/tests/test_suggest.py +173 -0
  48. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_tokens.py +1 -1
  49. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_transcriber.py +94 -47
  50. python_voiceio-1.0.0/tests/test_tts.py +425 -0
  51. python_voiceio-1.0.0/tests/test_typer_manager.py +39 -0
  52. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_vocabulary.py +12 -12
  53. python_voiceio-1.0.0/tests/test_worker_decode.py +62 -0
  54. python_voiceio-1.0.0/voiceio/__init__.py +1 -0
  55. python_voiceio-1.0.0/voiceio/app.py +716 -0
  56. python_voiceio-1.0.0/voiceio/audio_source.py +217 -0
  57. python_voiceio-1.0.0/voiceio/cli/__init__.py +191 -0
  58. python_voiceio-1.0.0/voiceio/cli/configcmd.py +77 -0
  59. python_voiceio-1.0.0/voiceio/cli/corrections.py +102 -0
  60. python_voiceio-1.0.0/voiceio/cli/doctor.py +191 -0
  61. python_voiceio-1.0.0/voiceio/cli/history.py +37 -0
  62. python_voiceio-1.0.0/voiceio/cli/learn.py +490 -0
  63. python_voiceio-1.0.0/voiceio/cli/models.py +106 -0
  64. python_voiceio-1.0.0/voiceio/cli/servicecmd.py +81 -0
  65. python_voiceio-1.0.0/voiceio/cli/uninstall.py +215 -0
  66. python_voiceio-1.0.0/voiceio/cli/vocab.py +101 -0
  67. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/commands.py +48 -20
  68. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/config.py +118 -47
  69. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/consent.py +1 -1
  70. python_voiceio-1.0.0/voiceio/core/__init__.py +6 -0
  71. python_voiceio-1.0.0/voiceio/core/bias.py +98 -0
  72. python_voiceio-1.0.0/voiceio/core/decoders/__init__.py +60 -0
  73. python_voiceio-1.0.0/voiceio/core/decoders/base.py +105 -0
  74. python_voiceio-1.0.0/voiceio/core/decoders/catalog.py +59 -0
  75. python_voiceio-0.9.11/voiceio/transcriber.py → python_voiceio-1.0.0/voiceio/core/decoders/faster_whisper/__init__.py +84 -57
  76. python_voiceio-1.0.0/voiceio/core/decoders/faster_whisper/worker.py +195 -0
  77. python_voiceio-1.0.0/voiceio/core/decoders/lanes.py +43 -0
  78. python_voiceio-1.0.0/voiceio/core/decoders/sherpa.py +108 -0
  79. python_voiceio-1.0.0/voiceio/core/decoders/whispercpp.py +93 -0
  80. python_voiceio-1.0.0/voiceio/core/engine.py +206 -0
  81. python_voiceio-1.0.0/voiceio/core/pipeline.py +213 -0
  82. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/corrections.py +99 -39
  83. python_voiceio-1.0.0/voiceio/data/60-voiceio-uaccess.rules +5 -0
  84. python_voiceio-1.0.0/voiceio/data/__init__.py +1 -0
  85. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/demo.py +13 -14
  86. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/feedback.py +6 -1
  87. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/health.py +147 -26
  88. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/history.py +4 -1
  89. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/hotkeys/evdev.py +71 -9
  90. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/hotkeys/pynput_backend.py +2 -1
  91. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/ibus/__init__.py +31 -0
  92. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/ibus/engine.py +71 -14
  93. python_voiceio-1.0.0/voiceio/ibus/install.py +305 -0
  94. python_voiceio-1.0.0/voiceio/ibus/session.py +673 -0
  95. python_voiceio-1.0.0/voiceio/learn/__init__.py +14 -0
  96. python_voiceio-1.0.0/voiceio/learn/augment.py +105 -0
  97. python_voiceio-1.0.0/voiceio/learn/clean.py +145 -0
  98. python_voiceio-1.0.0/voiceio/learn/evaluate.py +291 -0
  99. python_voiceio-1.0.0/voiceio/learn/importer.py +101 -0
  100. python_voiceio-1.0.0/voiceio/learn/metrics.py +147 -0
  101. python_voiceio-1.0.0/voiceio/learn/review.py +114 -0
  102. python_voiceio-1.0.0/voiceio/learn/store.py +347 -0
  103. python_voiceio-1.0.0/voiceio/learn/teacher.py +87 -0
  104. python_voiceio-1.0.0/voiceio/learn/train.py +374 -0
  105. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/llm.py +11 -22
  106. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/llm_api.py +6 -6
  107. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/numbers.py +106 -5
  108. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/platform.py +194 -4
  109. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/postcorrect.py +70 -14
  110. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/postprocess.py +11 -66
  111. python_voiceio-1.0.0/voiceio/privacy.py +13 -0
  112. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/recorder.py +21 -13
  113. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/retention.py +11 -1
  114. python_voiceio-1.0.0/voiceio/server/__init__.py +44 -0
  115. python_voiceio-1.0.0/voiceio/server/__main__.py +51 -0
  116. python_voiceio-1.0.0/voiceio/server/app.py +389 -0
  117. python_voiceio-1.0.0/voiceio/server/config.py +108 -0
  118. python_voiceio-1.0.0/voiceio/server/runtime.py +301 -0
  119. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/service.py +21 -55
  120. python_voiceio-1.0.0/voiceio/setup/__init__.py +10 -0
  121. python_voiceio-1.0.0/voiceio/setup/configfile.py +129 -0
  122. python_voiceio-1.0.0/voiceio/setup/extras.py +246 -0
  123. python_voiceio-1.0.0/voiceio/setup/hotkey.py +171 -0
  124. python_voiceio-1.0.0/voiceio/setup/noninteractive.py +209 -0
  125. python_voiceio-1.0.0/voiceio/setup/speech.py +227 -0
  126. python_voiceio-1.0.0/voiceio/setup/steps.py +632 -0
  127. python_voiceio-1.0.0/voiceio/setup/system.py +166 -0
  128. python_voiceio-1.0.0/voiceio/setup/ui.py +357 -0
  129. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/streaming.py +120 -90
  130. python_voiceio-1.0.0/voiceio/suggest.py +138 -0
  131. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/tokens.py +7 -0
  132. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/tray/__init__.py +26 -41
  133. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/tts/chain.py +22 -2
  134. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/tts/edge_engine.py +1 -1
  135. python_voiceio-1.0.0/voiceio/tts/piper_engine.py +99 -0
  136. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/typers/__init__.py +3 -0
  137. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/typers/chain.py +16 -13
  138. python_voiceio-1.0.0/voiceio/typers/collecting.py +79 -0
  139. python_voiceio-1.0.0/voiceio/typers/fcitx_bridge.py +70 -0
  140. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/typers/ibus.py +12 -269
  141. python_voiceio-1.0.0/voiceio/typers/manager.py +329 -0
  142. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/typers/pynput_type.py +2 -1
  143. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/typers/ydotool.py +12 -0
  144. python_voiceio-1.0.0/voiceio/ui.py +18 -0
  145. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/vocab_stats.py +1 -1
  146. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/vocabulary.py +21 -23
  147. python_voiceio-1.0.0/voiceio/watchdog.py +195 -0
  148. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/wordfreq.py +22 -1
  149. python_voiceio-0.9.11/PKG-INFO +0 -318
  150. python_voiceio-0.9.11/README.md +0 -270
  151. python_voiceio-0.9.11/python_voiceio.egg-info/PKG-INFO +0 -318
  152. python_voiceio-0.9.11/python_voiceio.egg-info/entry_points.txt +0 -6
  153. python_voiceio-0.9.11/python_voiceio.egg-info/requires.txt +0 -36
  154. python_voiceio-0.9.11/tests/test_adjudicate.py +0 -301
  155. python_voiceio-0.9.11/tests/test_audit.py +0 -297
  156. python_voiceio-0.9.11/tests/test_autocorrect.py +0 -527
  157. python_voiceio-0.9.11/tests/test_autocorrect_state.py +0 -51
  158. python_voiceio-0.9.11/tests/test_cli.py +0 -264
  159. python_voiceio-0.9.11/tests/test_config.py +0 -76
  160. python_voiceio-0.9.11/tests/test_correct_batch.py +0 -229
  161. python_voiceio-0.9.11/tests/test_evaluate.py +0 -198
  162. python_voiceio-0.9.11/tests/test_numbers.py +0 -101
  163. python_voiceio-0.9.11/tests/test_snapshots.py +0 -54
  164. python_voiceio-0.9.11/tests/test_tts.py +0 -158
  165. python_voiceio-0.9.11/voiceio/__init__.py +0 -1
  166. python_voiceio-0.9.11/voiceio/app.py +0 -1720
  167. python_voiceio-0.9.11/voiceio/audit.py +0 -430
  168. python_voiceio-0.9.11/voiceio/autocorrect.py +0 -713
  169. python_voiceio-0.9.11/voiceio/autocorrect_state.py +0 -184
  170. python_voiceio-0.9.11/voiceio/cli.py +0 -1835
  171. python_voiceio-0.9.11/voiceio/evaluate.py +0 -322
  172. python_voiceio-0.9.11/voiceio/snapshots.py +0 -78
  173. python_voiceio-0.9.11/voiceio/tts/piper_engine.py +0 -91
  174. python_voiceio-0.9.11/voiceio/wizard.py +0 -1997
  175. python_voiceio-0.9.11/voiceio/worker.py +0 -98
  176. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/LICENSE +0 -0
  177. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/python_voiceio.egg-info/dependency_links.txt +0 -0
  178. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/python_voiceio.egg-info/top_level.txt +0 -0
  179. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/setup.cfg +0 -0
  180. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_backend_probes.py +0 -0
  181. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_clipboard_read.py +0 -0
  182. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_hints.py +0 -0
  183. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_history.py +0 -0
  184. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_ibus_pending.py +0 -0
  185. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_ibus_ping.py +0 -0
  186. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_ibus_textlimit.py +0 -0
  187. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_prebuffer.py +0 -0
  188. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_prompt.py +0 -0
  189. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_recorder_integration.py +0 -0
  190. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_vad.py +0 -0
  191. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/tests/test_wordfreq.py +0 -0
  192. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/__main__.py +0 -0
  193. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/backends.py +0 -0
  194. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/clipboard_read.py +0 -0
  195. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/hints.py +0 -0
  196. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/hotkeys/__init__.py +0 -0
  197. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/hotkeys/base.py +0 -0
  198. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/hotkeys/chain.py +0 -0
  199. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/hotkeys/socket_backend.py +0 -0
  200. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/ibus/pending.py +0 -0
  201. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/ibus/textlimit.py +0 -0
  202. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/models/__init__.py +0 -0
  203. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/models/silero_vad.onnx +0 -0
  204. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/pidlock.py +0 -0
  205. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/prompt.py +0 -0
  206. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/sounds/__init__.py +0 -0
  207. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/sounds/commit.wav +0 -0
  208. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/sounds/start.wav +0 -0
  209. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/sounds/stop.wav +0 -0
  210. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/tray/_icons.py +0 -0
  211. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/tray/_indicator.py +0 -0
  212. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/tray/_pystray.py +0 -0
  213. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/tts/__init__.py +0 -0
  214. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/tts/base.py +0 -0
  215. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/tts/espeak.py +0 -0
  216. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/tts/player.py +0 -0
  217. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/typers/base.py +0 -0
  218. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/typers/clipboard.py +0 -0
  219. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/typers/wtype.py +0 -0
  220. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/typers/xdotool.py +0 -0
  221. {python_voiceio-0.9.11 → python_voiceio-1.0.0}/voiceio/vad.py +0 -0
@@ -0,0 +1,314 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-voiceio
3
+ Version: 1.0.0
4
+ Summary: Voice dictation for Linux. Speak → text, locally, instantly.
5
+ Author: Hugo Montenegro
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Hugo0/voiceio
8
+ Project-URL: Repository, https://github.com/Hugo0/voiceio
9
+ Project-URL: Issues, https://github.com/Hugo0/voiceio/issues
10
+ Project-URL: Changelog, https://github.com/Hugo0/voiceio/releases
11
+ Keywords: voice,speech-to-text,whisper,linux,dictation,wayland,ibus
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: X11 Applications
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
18
+ Requires-Python: >=3.11
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: faster-whisper>=1.0.0
22
+ Requires-Dist: numpy>=1.24.0
23
+ Requires-Dist: onnxruntime>=1.16.0
24
+ Requires-Dist: wordfreq>=3.0
25
+ Provides-Extra: desktop
26
+ Requires-Dist: sounddevice>=0.4.6; extra == "desktop"
27
+ Requires-Dist: evdev>=1.6.0; sys_platform == "linux" and extra == "desktop"
28
+ Requires-Dist: pynput>=1.7.6; extra == "desktop"
29
+ Requires-Dist: pystray>=0.19; extra == "desktop"
30
+ Requires-Dist: Pillow>=10.0; extra == "desktop"
31
+ Provides-Extra: linux
32
+ Requires-Dist: sounddevice>=0.4.6; extra == "linux"
33
+ Requires-Dist: evdev>=1.6.0; sys_platform == "linux" and extra == "linux"
34
+ Requires-Dist: pynput>=1.7.6; extra == "linux"
35
+ Requires-Dist: pystray>=0.19; extra == "linux"
36
+ Requires-Dist: Pillow>=10.0; extra == "linux"
37
+ Provides-Extra: server
38
+ Requires-Dist: aiohttp>=3.9; extra == "server"
39
+ Provides-Extra: tts
40
+ Requires-Dist: piper-tts>=1.3.0; extra == "tts"
41
+ Requires-Dist: edge-tts>=6.1.0; extra == "tts"
42
+ Provides-Extra: train
43
+ Requires-Dist: torch>=2.2; extra == "train"
44
+ Requires-Dist: transformers>=4.40; extra == "train"
45
+ Requires-Dist: peft>=0.10; extra == "train"
46
+ Provides-Extra: sherpa
47
+ Requires-Dist: sherpa-onnx>=1.12; extra == "sherpa"
48
+ Provides-Extra: dev
49
+ Requires-Dist: pytest>=7.0; extra == "dev"
50
+ Requires-Dist: pytest-mock; extra == "dev"
51
+ Requires-Dist: ruff<0.18,>=0.15; extra == "dev"
52
+ Dynamic: license-file
53
+
54
+ # voiceio
55
+
56
+ [![CI](https://github.com/Hugo0/voiceio/actions/workflows/ci.yml/badge.svg)](https://github.com/Hugo0/voiceio/actions/workflows/ci.yml)
57
+ [![PyPI](https://img.shields.io/pypi/v/python-voiceio)](https://pypi.org/project/python-voiceio/)
58
+ [![Python](https://img.shields.io/pypi/pyversions/python-voiceio)](https://pypi.org/project/python-voiceio/)
59
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
60
+
61
+ **Voice dictation that learns you.** Local, open source, private — and it fine-tunes itself on your own voice, on your own machine.
62
+
63
+ Off-the-shelf speech models stumble on exactly the words you say most: your colleagues' names, your project, your jargon. voiceio keeps (with your permission) the audio of what you dictate, has a bigger model transcribe it overnight, and trains a personal model from it — nothing uploaded, no GPU required. On the author's dictation, one overnight run on a laptop CPU cut word errors from **12.1% to 5.0%** on held-out clips and recognized more of the author's vocabulary, at the same speed. Every model is scored on clips it never trained on, and it only replaces the current one when it wins.
64
+
65
+ https://github.com/user-attachments/assets/9cf5d1ac-b4bb-4cf8-b775-7a66dc16b376
66
+
67
+ Press a hotkey, speak, and the text streams into whatever app has focus. Press again to commit.
68
+
69
+ - **Learns you.** `voiceio learn` fine-tunes a model on your own voice; a vocabulary steers it toward new names right away; corrections fix the rest. See [Make it yours](#make-it-yours).
70
+ - **Local.** Speech is decoded on-device ([faster-whisper](https://github.com/SYSTRAN/faster-whisper) by default). Audio never leaves the machine and there is no telemetry. Two optional, off-by-default features send *text* (never audio) to an LLM endpoint you configure: final-transcript polish (`[postcorrect]`) and an optional local Ollama cleanup (`[llm]`).
71
+ - **Yours.** History, retained audio, corrections, vocabulary and fine-tuned models are plain local files. See [Your data](#your-data).
72
+ - **Linux-first.** Wayland and X11, GNOME, KDE, Hyprland, sway and i3. Backends are picked by probing what works. See [Linux support](#linux-support).
73
+
74
+
75
+ > **Upgrading from 0.x?** See [UPGRADING.md](UPGRADING.md) — 1.0 renames a few commands and moves desktop dependencies to the `[desktop]` extra.
76
+
77
+ ## Quickstart
78
+
79
+ ```bash
80
+ # 1. System packages: a C toolchain (evdev has no wheel), PortAudio, IBus + GObject bindings
81
+ sudo apt install pipx build-essential python3-dev portaudio19-dev ibus gir1.2-ibus-1.0 python3-gi # Debian/Ubuntu
82
+ sudo dnf install pipx gcc gcc-c++ make python3-devel portaudio-devel ibus ibus-libs python3-gobject # Fedora
83
+ sudo pacman -S python-pipx base-devel portaudio ibus python-gobject # Arch
84
+
85
+ # 2. voiceio with the desktop extra (microphone, hotkeys, tray)
86
+ pipx install 'python-voiceio[desktop]'
87
+
88
+ # 3. Guided setup: model download, hotkey, autostart
89
+ voiceio setup
90
+ ```
91
+
92
+ Then press **Ctrl+Alt+V**, speak, and press it again. `voiceio doctor` tells you what is working and `voiceio doctor --fix` repairs what it can.
93
+
94
+ NixOS users: see [NixOS](#nixos). Agents installing voiceio non-interactively: see [INSTALL.md](INSTALL.md).
95
+
96
+ <details>
97
+ <summary><strong>Extras</strong></summary>
98
+
99
+ The base package (`pip install python-voiceio`) is headless transcription only: no microphone, hotkeys or display needed.
100
+
101
+ | Extra | Adds |
102
+ |---|---|
103
+ | `desktop` | The dictation app: microphone (sounddevice), hotkeys (evdev, pynput), tray icon |
104
+ | `server` | HTTP/WebSocket transcription server: `python -m voiceio.server` |
105
+ | `tts` | Text-to-speech: piper (local), edge-tts (cloud) |
106
+ | `sherpa` | sherpa-onnx runtime for non-Whisper models (experimental) |
107
+ | `train` | `voiceio learn train`: LoRA fine-tuning (torch, transformers, peft) |
108
+
109
+ </details>
110
+
111
+ <details>
112
+ <summary><strong>From source</strong></summary>
113
+
114
+ ```bash
115
+ git clone https://github.com/Hugo0/voiceio && cd voiceio
116
+ uv sync --extra desktop --extra dev
117
+ uv run voiceio setup # also links voiceio into ~/.local/bin
118
+ ```
119
+
120
+ </details>
121
+
122
+ ## Commands
123
+
124
+ > **Note:** the CLI is being restructured for v1.0. This list is the target layout. Check it against `voiceio --help` before release.
125
+
126
+ | Command | What it does |
127
+ |---|---|
128
+ | `voiceio run` | Start the dictation daemon in the foreground (the systemd unit runs this) |
129
+ | `voiceio toggle` | Start/stop recording on the running daemon. Bind it to a key if you don't use evdev |
130
+ | `voiceio setup` | Guided setup (`--defaults` / `--answers '{json}'` for scripts) |
131
+ | `voiceio doctor [--fix]` | Check every backend; `--fix` repairs what it can, asking before anything that needs sudo |
132
+ | `voiceio service install\|uninstall\|start\|stop\|restart\|status\|logs` | systemd user unit: start on login, restart on crash; `logs -f` follows |
133
+ | `voiceio models list\|bench\|use` | See, compare and pick speech models ([Choose a model](#choose-a-model)) |
134
+ | `voiceio vocab` | Manage the vocabulary that steers the decoder |
135
+ | `voiceio corrections` | Manage find/replace rules for words it still gets wrong |
136
+ | `voiceio learn …` | Personalize: label → review → augment → build → eval → train → promote |
137
+ | `voiceio history` | Search what you have dictated |
138
+ | `voiceio config` | Show or set config values |
139
+ | `voiceio uninstall` | Remove the service, IBus component, shortcuts and symlinks (asks before deleting your data) |
140
+
141
+ ## Your data
142
+
143
+ Everything voiceio keeps is in three directories (they follow `XDG_CONFIG_HOME`, `XDG_STATE_HOME` and `XDG_DATA_HOME`). Files are created `0600`, directories `0700`. Nothing is uploaded.
144
+
145
+ | Path | Holds | Retention |
146
+ |---|---|---|
147
+ | **`~/.config/voiceio/`** | *Settings and what it has learned about your words* | |
148
+ | `config.toml` | All settings | — |
149
+ | `vocabulary.txt` | Your terms, one per line, used as decoder hotwords | Never pruned; rarely used terms rank lower |
150
+ | `vocab_stats.json` | Per-term usage counts used to rank the vocabulary | Rebuilt as you dictate |
151
+ | `corrections.json` | Find/replace rules (`post grass` → `PostgreSQL`) | — |
152
+ | `flagged.txt` | Words flagged with the "correct that" voice command, for review | — |
153
+ | `snapshots/` | Copies of corrections + vocabulary from before 1.0's cleanup (safe to delete) | Last 8 kept |
154
+ | `consent.json` | Whether you allowed cloud LLM calls (text only) | — |
155
+ | `hints.json` | Which CLI tips you have already seen | — |
156
+ | **`~/.local/state/voiceio/`** | *What you said* | |
157
+ | `history.jsonl` | Every committed transcript: time, raw and final text, focused-window title | `[history] enabled`, `max_entries`, `max_age_days` (0 = keep forever) |
158
+ | `recordings/*.wav` | The audio of each utterance, for `voiceio learn` | `[data] retain_audio`, `max_audio_mb` (default 4096), `min_free_gb` (default 5) |
159
+ | `streaming_trace.jsonl`, `postcorrect_pairs.jsonl` | Per-pass decode traces and LLM before/after pairs | `[data] capture_intermediates`; each capped at 64 MB |
160
+ | `corrections_audit.jsonl` | When each correction rule fired (shows which rules earn their keep) | — |
161
+ | `voiceio.log`, `worker.log`, `ibus-engine-stderr.log` | Logs | `voiceio.log` rotates at 2 MB × 3 |
162
+ | **`~/.local/share/voiceio/learn/`** | *Personalization corpus* (only exists once you run `voiceio learn`) | Never pruned; delete freely |
163
+ | `labels.jsonl` | Reference transcripts from the teacher model or your review | — |
164
+ | `augment/` | Synthetic TTS clips of your hard words | — |
165
+ | `datasets/vNNNN/` | Frozen train/dev/test splits | — |
166
+ | `exports/` | Datasets packed for training on another machine | — |
167
+ | `models/<run>/` | Your fine-tuned models, plus `promotions.jsonl` | — |
168
+ | `runs/` | Evaluation results | — |
169
+
170
+ Set `[data] capture_context = false` to stop recording window titles. `voiceio uninstall` offers to delete the config and state directories; delete `~/.local/share/voiceio` yourself.
171
+
172
+ ## Make it yours
173
+
174
+ Most dictation errors are proper nouns and jargon: `PostgreSQL` heard as `post grass`, a colleague's name spelled three ways. There are three tools for that, from cheapest to most powerful.
175
+
176
+ **1. Vocabulary.** Put your names and terms in `~/.config/voiceio/vocabulary.txt` (or use `voiceio vocab`). They are passed to Whisper as *hotwords* on every decode, ranked by how often you use them. One honest limit: Whisper's hotword channel is capped at 223 tokens, and a proper noun costs 5 to 7 tokens, so only about **35 terms** steer each decode. The rest are kept and ranked, but they do nothing until they rank high enough. This ceiling comes from the model, not from voiceio. [CONTRIBUTING.md](CONTRIBUTING.md#model-choice-why-whisper-and-what-would-change-it) explains why we still use Whisper.
177
+
178
+ **2. Corrections.** Find/replace rules for what still comes out wrong (`voiceio corrections add WRONG RIGHT`, or say "correct that" right after a mistake and review with `voiceio corrections flagged`). `voiceio vocab suggest` lists unusual words from your history — offline — so you can add the real names to your vocabulary and turn the mishearings into corrections.
179
+
180
+ **3. Fine-tuning with `voiceio learn`.** This is how you get past the 35-term ceiling: teach the model your vocabulary directly, from your own retained audio.
181
+
182
+ ```bash
183
+ voiceio learn import DIR --source phone # optional: add your own recordings from elsewhere
184
+ voiceio learn label # a stronger teacher model (large-v3-turbo) transcribes your clips
185
+ voiceio learn review # fix the teacher where it matters: your names and terms
186
+ voiceio learn review --test # once: verify the held-out clips, so eval scores against the truth
187
+ voiceio learn augment # synthesize extra examples of rare terms with local TTS
188
+ voiceio learn build # freeze a versioned train/dev/test dataset (the test split never trains)
189
+ voiceio learn eval # score the current model on your held-out clips: WER and term recall
190
+ # --streaming replays them through live dictation and times stop→text
191
+ voiceio learn train # LoRA fine-tune (needs the `train` extra; decoder-only on CPU, --full on a GPU)
192
+ voiceio learn promote <run> # dictate with the fine-tune; `voiceio learn rollback` undoes it
193
+ voiceio learn maintain # later: label what's new, and once 50+ clips piled up, retrain and compare
194
+ ```
195
+
196
+ Labeling, training and offline eval run in an idle-priority cgroup, so they never slow dictation down. Everything stays on your machine unless you choose `train --remote`.
197
+
198
+ `voiceio learn status` shows where you are, each model's scores, and suggests `promote` only when a fine-tune wins on everything. `promote` itself refuses a model that hasn't, and reports how many clips got better or worse with a confidence interval — a few dozen test clips can move an average by luck.
199
+
200
+ **Is it actually helping?** Once some clips are labeled, measure instead of guessing:
201
+
202
+ ```bash
203
+ voiceio learn eval --pipeline # what each text stage (numbers, commands, corrections, cloud
204
+ # postcorrect…) did to your past dictations, and its commonest edits
205
+ voiceio corrections audit # rules your own audio contradicts, and ones that look risky
206
+ voiceio learn eval --streaming # accuracy *and* stop→text, replaying clips through live dictation
207
+ ```
208
+
209
+ On the author's data these found a correction that kept turning "composable" into "comparable", a number rule writing "no one" as "no 1", and a cloud pass that never fixed a single vocabulary term.
210
+
211
+ ## Choose a model
212
+
213
+ ```bash
214
+ voiceio models list # known models, your fine-tunes, and which is active
215
+ voiceio models bench # score candidates on your held-out clips (after `voiceio learn build`)
216
+ voiceio models use medium # switch
217
+ ```
218
+
219
+ | Model | Runtime | License | Notes |
220
+ |---|---|---|---|
221
+ | `small` | faster-whisper | MIT | Default. About 5× realtime on a laptop CPU |
222
+ | `medium` | faster-whisper | MIT | Better on names, about 2.5× slower |
223
+ | `large-v3-turbo` | faster-whisper | MIT | Best Whisper for dictation; wants a GPU. Also the default `learn` teacher |
224
+ | `distil-large-v3` | faster-whisper | MIT | English only |
225
+ | `sherpa:parakeet-tdt-0.6b-v3` | sherpa-onnx | CC-BY-4.0 | Experimental. Fast, but no vocabulary biasing yet |
226
+ | `whispercpp:http://…` | whisper.cpp server | depends on the model | Experimental. E.g. a Vulkan build on an AMD iGPU |
227
+
228
+ Pick on your own audio, not leaderboards: for dictation full of names, how well a model can be *biased* matters more than its benchmark WER.
229
+
230
+ **Licenses.** voiceio ships no model weights. Each model is downloaded from its own source on first use, under its own license. The defaults are permissive (MIT). A fine-tune you make with `voiceio learn` inherits the license of the base model it was trained from.
231
+
232
+ ## Dictate from your phone
233
+
234
+ `python -m voiceio.server` (the `server` extra) serves the same engine over HTTP and WebSocket, for a phone or any other client: `POST /transcribe` with an audio file, or stream PCM over `/ws/transcribe` for live partials. It binds `127.0.0.1` by default; put it behind your VPN or a reverse proxy and set `VOICE_TOKEN` (bearer token) and `VOICE_ALLOWED_ORIGINS` when it is reachable from elsewhere. `VOICE_MODEL`, `VOICE_LANES`, `VOICE_HOST`/`VOICE_PORT` override the rest.
235
+
236
+ The server reads its own machine's voiceio config, so it gets your vocabulary and corrections once you copy them over:
237
+
238
+ ```bash
239
+ scripts/sync_personalization.sh myserver # vocabulary + corrections
240
+ scripts/sync_personalization.sh myserver --model # …and your promoted fine-tune
241
+ ```
242
+
243
+ To fine-tune on what you dictate from the phone too, opt in on the server with `[data] retain_audio = true` in its `config.toml`, then bring the clips home: `scripts/pull_phone_dictation.sh myserver` (an `rsync` over SSH followed by `voiceio learn import`). Only your own voice should go in: the model learns whoever is speaking.
244
+
245
+ ## Linux support
246
+
247
+ | | Text injection | Streaming preview | Hotkey | Status |
248
+ |---|---|---|---|---|
249
+ | GNOME (Wayland) | IBus, ydotool fallback | Yes (IBus preedit) | evdev, or a GNOME shortcut set up by `setup` | Tested daily |
250
+ | GNOME (X11) | IBus, xdotool fallback | Yes | evdev, pynput | Supported |
251
+ | KDE Plasma (Wayland) | IBus, ydotool fallback | Yes with IBus | evdev | Should work |
252
+ | Hyprland, incl. Omarchy | IBus, else wtype → ydotool | Yes with IBus; with fcitx5 (Omarchy's default), words are typed as you speak, without the in-place preview | evdev, or `bind = CTRL ALT, V, exec, voiceio toggle` | Should work |
253
+ | sway | IBus, else wtype → ydotool | As Hyprland | evdev, or `bindsym` + `voiceio toggle` | Should work |
254
+ | i3 / other X11 | IBus, xdotool | Yes with IBus | pynput, evdev | Should work |
255
+ | NixOS | as above | as above | evdev via the flake's udev rule | Flake provided, unbuilt ([NixOS](#nixos)) |
256
+
257
+ **Input methods.** IBus is the only way to get a live, underlined preview that is corrected in place on Wayland. voiceio installs its own IBus engine and only activates it while you dictate. If fcitx5 is your input method, voiceio leaves it alone and types the final text with wtype or ydotool. Terminals that ignore input methods get the clipboard.
258
+
259
+ **Hotkeys without the `input` group.** The evdev backend reads keyboards from `/dev/input`. `voiceio doctor --fix` installs a udev rule, `/etc/udev/rules.d/60-voiceio-uaccess.rules`, that grants the logged-in user access to keyboard devices. It works immediately, without logging out. The old route still works as a fallback: `sudo usermod -aG input $USER`, then log out and back in. You can also skip evdev and bind `voiceio toggle` in your compositor.
260
+
261
+ **ydotool** needs write access to `/dev/uinput`; `voiceio doctor --fix` installs a uaccess rule for that too.
262
+
263
+ ### NixOS
264
+
265
+ The repository is a flake. **It has not been built yet**; please report fixes.
266
+
267
+ ```nix
268
+ # flake inputs: voiceio.url = "github:Hugo0/voiceio";
269
+ # NixOS: package, uinput, and the keyboard uaccess rule
270
+ imports = [ voiceio.nixosModules.default ];
271
+ programs.voiceio.enable = true;
272
+
273
+ # Home Manager: config.toml from Nix + a systemd user service
274
+ imports = [ voiceio.homeManagerModules.default ];
275
+ services.voiceio = {
276
+ enable = true;
277
+ settings.model.name = "small";
278
+ };
279
+ ```
280
+
281
+ For the streaming preview, enable IBus as your input method: `i18n.inputMethod = { enable = true; type = "ibus"; };`.
282
+
283
+ ### Windows and macOS
284
+
285
+ There is a best-effort pynput path for both (hotkeys and typing, no live preview). It is untested and unmaintained, with no installers or CI. Patches are welcome; bug reports will likely sit.
286
+
287
+ ## Troubleshooting
288
+
289
+ | Problem | Fix |
290
+ |---|---|
291
+ | Nothing is typed | `voiceio doctor --fix`; usually the IBus component or the GNOME input source |
292
+ | Hotkey does nothing on Wayland | `voiceio doctor --fix` installs the keyboard udev rule, or bind `voiceio toggle` in your compositor |
293
+ | `sounddevice is not installed` | You installed without the desktop extra: `pipx install --force 'python-voiceio[desktop]'` |
294
+ | evdev fails to build | Install a C toolchain and Python headers (see Quickstart), then reinstall |
295
+ | Too slow | `voiceio doctor` shows your real stop→text; turn off cloud postcorrect, or `voiceio models use small` (or a GPU with `large-v3-turbo`) |
296
+ | Words come out wrong in a pattern | `voiceio learn eval --pipeline` and `voiceio corrections audit` show which stage or rule did it |
297
+ | Start over | `voiceio uninstall`, then `voiceio setup` |
298
+
299
+ Logs: `journalctl --user -u voiceio` or `~/.local/state/voiceio/voiceio.log`.
300
+
301
+ ## Roadmap
302
+
303
+ - **A landing page** — voiceio as local, open-source, private dictation that learns from you.
304
+ - **Continuous learning** — `learn maintain` on a timer: label new dictation while idle, retrain when enough piles up, and promote only what wins on your held-out clips.
305
+ - **Unbounded vocabulary** — move to a decoder whose biasing has no token cap (see [model choice](CONTRIBUTING.md#model-choice-why-whisper-and-what-would-change-it)).
306
+ - **One model everywhere** — sync your fine-tune to your phone server and laptops, peer to peer.
307
+
308
+ ## Contributing
309
+
310
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the architecture, conventions and the reasoning behind the model choice. Please open an issue before a large PR.
311
+
312
+ ## License
313
+
314
+ MIT. Model weights are not part of voiceio and carry their own licenses (see [Choose a model](#choose-a-model)).
@@ -0,0 +1,261 @@
1
+ # voiceio
2
+
3
+ [![CI](https://github.com/Hugo0/voiceio/actions/workflows/ci.yml/badge.svg)](https://github.com/Hugo0/voiceio/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/python-voiceio)](https://pypi.org/project/python-voiceio/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/python-voiceio)](https://pypi.org/project/python-voiceio/)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
+
8
+ **Voice dictation that learns you.** Local, open source, private — and it fine-tunes itself on your own voice, on your own machine.
9
+
10
+ Off-the-shelf speech models stumble on exactly the words you say most: your colleagues' names, your project, your jargon. voiceio keeps (with your permission) the audio of what you dictate, has a bigger model transcribe it overnight, and trains a personal model from it — nothing uploaded, no GPU required. On the author's dictation, one overnight run on a laptop CPU cut word errors from **12.1% to 5.0%** on held-out clips and recognized more of the author's vocabulary, at the same speed. Every model is scored on clips it never trained on, and it only replaces the current one when it wins.
11
+
12
+ https://github.com/user-attachments/assets/9cf5d1ac-b4bb-4cf8-b775-7a66dc16b376
13
+
14
+ Press a hotkey, speak, and the text streams into whatever app has focus. Press again to commit.
15
+
16
+ - **Learns you.** `voiceio learn` fine-tunes a model on your own voice; a vocabulary steers it toward new names right away; corrections fix the rest. See [Make it yours](#make-it-yours).
17
+ - **Local.** Speech is decoded on-device ([faster-whisper](https://github.com/SYSTRAN/faster-whisper) by default). Audio never leaves the machine and there is no telemetry. Two optional, off-by-default features send *text* (never audio) to an LLM endpoint you configure: final-transcript polish (`[postcorrect]`) and an optional local Ollama cleanup (`[llm]`).
18
+ - **Yours.** History, retained audio, corrections, vocabulary and fine-tuned models are plain local files. See [Your data](#your-data).
19
+ - **Linux-first.** Wayland and X11, GNOME, KDE, Hyprland, sway and i3. Backends are picked by probing what works. See [Linux support](#linux-support).
20
+
21
+
22
+ > **Upgrading from 0.x?** See [UPGRADING.md](UPGRADING.md) — 1.0 renames a few commands and moves desktop dependencies to the `[desktop]` extra.
23
+
24
+ ## Quickstart
25
+
26
+ ```bash
27
+ # 1. System packages: a C toolchain (evdev has no wheel), PortAudio, IBus + GObject bindings
28
+ sudo apt install pipx build-essential python3-dev portaudio19-dev ibus gir1.2-ibus-1.0 python3-gi # Debian/Ubuntu
29
+ sudo dnf install pipx gcc gcc-c++ make python3-devel portaudio-devel ibus ibus-libs python3-gobject # Fedora
30
+ sudo pacman -S python-pipx base-devel portaudio ibus python-gobject # Arch
31
+
32
+ # 2. voiceio with the desktop extra (microphone, hotkeys, tray)
33
+ pipx install 'python-voiceio[desktop]'
34
+
35
+ # 3. Guided setup: model download, hotkey, autostart
36
+ voiceio setup
37
+ ```
38
+
39
+ Then press **Ctrl+Alt+V**, speak, and press it again. `voiceio doctor` tells you what is working and `voiceio doctor --fix` repairs what it can.
40
+
41
+ NixOS users: see [NixOS](#nixos). Agents installing voiceio non-interactively: see [INSTALL.md](INSTALL.md).
42
+
43
+ <details>
44
+ <summary><strong>Extras</strong></summary>
45
+
46
+ The base package (`pip install python-voiceio`) is headless transcription only: no microphone, hotkeys or display needed.
47
+
48
+ | Extra | Adds |
49
+ |---|---|
50
+ | `desktop` | The dictation app: microphone (sounddevice), hotkeys (evdev, pynput), tray icon |
51
+ | `server` | HTTP/WebSocket transcription server: `python -m voiceio.server` |
52
+ | `tts` | Text-to-speech: piper (local), edge-tts (cloud) |
53
+ | `sherpa` | sherpa-onnx runtime for non-Whisper models (experimental) |
54
+ | `train` | `voiceio learn train`: LoRA fine-tuning (torch, transformers, peft) |
55
+
56
+ </details>
57
+
58
+ <details>
59
+ <summary><strong>From source</strong></summary>
60
+
61
+ ```bash
62
+ git clone https://github.com/Hugo0/voiceio && cd voiceio
63
+ uv sync --extra desktop --extra dev
64
+ uv run voiceio setup # also links voiceio into ~/.local/bin
65
+ ```
66
+
67
+ </details>
68
+
69
+ ## Commands
70
+
71
+ > **Note:** the CLI is being restructured for v1.0. This list is the target layout. Check it against `voiceio --help` before release.
72
+
73
+ | Command | What it does |
74
+ |---|---|
75
+ | `voiceio run` | Start the dictation daemon in the foreground (the systemd unit runs this) |
76
+ | `voiceio toggle` | Start/stop recording on the running daemon. Bind it to a key if you don't use evdev |
77
+ | `voiceio setup` | Guided setup (`--defaults` / `--answers '{json}'` for scripts) |
78
+ | `voiceio doctor [--fix]` | Check every backend; `--fix` repairs what it can, asking before anything that needs sudo |
79
+ | `voiceio service install\|uninstall\|start\|stop\|restart\|status\|logs` | systemd user unit: start on login, restart on crash; `logs -f` follows |
80
+ | `voiceio models list\|bench\|use` | See, compare and pick speech models ([Choose a model](#choose-a-model)) |
81
+ | `voiceio vocab` | Manage the vocabulary that steers the decoder |
82
+ | `voiceio corrections` | Manage find/replace rules for words it still gets wrong |
83
+ | `voiceio learn …` | Personalize: label → review → augment → build → eval → train → promote |
84
+ | `voiceio history` | Search what you have dictated |
85
+ | `voiceio config` | Show or set config values |
86
+ | `voiceio uninstall` | Remove the service, IBus component, shortcuts and symlinks (asks before deleting your data) |
87
+
88
+ ## Your data
89
+
90
+ Everything voiceio keeps is in three directories (they follow `XDG_CONFIG_HOME`, `XDG_STATE_HOME` and `XDG_DATA_HOME`). Files are created `0600`, directories `0700`. Nothing is uploaded.
91
+
92
+ | Path | Holds | Retention |
93
+ |---|---|---|
94
+ | **`~/.config/voiceio/`** | *Settings and what it has learned about your words* | |
95
+ | `config.toml` | All settings | — |
96
+ | `vocabulary.txt` | Your terms, one per line, used as decoder hotwords | Never pruned; rarely used terms rank lower |
97
+ | `vocab_stats.json` | Per-term usage counts used to rank the vocabulary | Rebuilt as you dictate |
98
+ | `corrections.json` | Find/replace rules (`post grass` → `PostgreSQL`) | — |
99
+ | `flagged.txt` | Words flagged with the "correct that" voice command, for review | — |
100
+ | `snapshots/` | Copies of corrections + vocabulary from before 1.0's cleanup (safe to delete) | Last 8 kept |
101
+ | `consent.json` | Whether you allowed cloud LLM calls (text only) | — |
102
+ | `hints.json` | Which CLI tips you have already seen | — |
103
+ | **`~/.local/state/voiceio/`** | *What you said* | |
104
+ | `history.jsonl` | Every committed transcript: time, raw and final text, focused-window title | `[history] enabled`, `max_entries`, `max_age_days` (0 = keep forever) |
105
+ | `recordings/*.wav` | The audio of each utterance, for `voiceio learn` | `[data] retain_audio`, `max_audio_mb` (default 4096), `min_free_gb` (default 5) |
106
+ | `streaming_trace.jsonl`, `postcorrect_pairs.jsonl` | Per-pass decode traces and LLM before/after pairs | `[data] capture_intermediates`; each capped at 64 MB |
107
+ | `corrections_audit.jsonl` | When each correction rule fired (shows which rules earn their keep) | — |
108
+ | `voiceio.log`, `worker.log`, `ibus-engine-stderr.log` | Logs | `voiceio.log` rotates at 2 MB × 3 |
109
+ | **`~/.local/share/voiceio/learn/`** | *Personalization corpus* (only exists once you run `voiceio learn`) | Never pruned; delete freely |
110
+ | `labels.jsonl` | Reference transcripts from the teacher model or your review | — |
111
+ | `augment/` | Synthetic TTS clips of your hard words | — |
112
+ | `datasets/vNNNN/` | Frozen train/dev/test splits | — |
113
+ | `exports/` | Datasets packed for training on another machine | — |
114
+ | `models/<run>/` | Your fine-tuned models, plus `promotions.jsonl` | — |
115
+ | `runs/` | Evaluation results | — |
116
+
117
+ Set `[data] capture_context = false` to stop recording window titles. `voiceio uninstall` offers to delete the config and state directories; delete `~/.local/share/voiceio` yourself.
118
+
119
+ ## Make it yours
120
+
121
+ Most dictation errors are proper nouns and jargon: `PostgreSQL` heard as `post grass`, a colleague's name spelled three ways. There are three tools for that, from cheapest to most powerful.
122
+
123
+ **1. Vocabulary.** Put your names and terms in `~/.config/voiceio/vocabulary.txt` (or use `voiceio vocab`). They are passed to Whisper as *hotwords* on every decode, ranked by how often you use them. One honest limit: Whisper's hotword channel is capped at 223 tokens, and a proper noun costs 5 to 7 tokens, so only about **35 terms** steer each decode. The rest are kept and ranked, but they do nothing until they rank high enough. This ceiling comes from the model, not from voiceio. [CONTRIBUTING.md](CONTRIBUTING.md#model-choice-why-whisper-and-what-would-change-it) explains why we still use Whisper.
124
+
125
+ **2. Corrections.** Find/replace rules for what still comes out wrong (`voiceio corrections add WRONG RIGHT`, or say "correct that" right after a mistake and review with `voiceio corrections flagged`). `voiceio vocab suggest` lists unusual words from your history — offline — so you can add the real names to your vocabulary and turn the mishearings into corrections.
126
+
127
+ **3. Fine-tuning with `voiceio learn`.** This is how you get past the 35-term ceiling: teach the model your vocabulary directly, from your own retained audio.
128
+
129
+ ```bash
130
+ voiceio learn import DIR --source phone # optional: add your own recordings from elsewhere
131
+ voiceio learn label # a stronger teacher model (large-v3-turbo) transcribes your clips
132
+ voiceio learn review # fix the teacher where it matters: your names and terms
133
+ voiceio learn review --test # once: verify the held-out clips, so eval scores against the truth
134
+ voiceio learn augment # synthesize extra examples of rare terms with local TTS
135
+ voiceio learn build # freeze a versioned train/dev/test dataset (the test split never trains)
136
+ voiceio learn eval # score the current model on your held-out clips: WER and term recall
137
+ # --streaming replays them through live dictation and times stop→text
138
+ voiceio learn train # LoRA fine-tune (needs the `train` extra; decoder-only on CPU, --full on a GPU)
139
+ voiceio learn promote <run> # dictate with the fine-tune; `voiceio learn rollback` undoes it
140
+ voiceio learn maintain # later: label what's new, and once 50+ clips piled up, retrain and compare
141
+ ```
142
+
143
+ Labeling, training and offline eval run in an idle-priority cgroup, so they never slow dictation down. Everything stays on your machine unless you choose `train --remote`.
144
+
145
+ `voiceio learn status` shows where you are, each model's scores, and suggests `promote` only when a fine-tune wins on everything. `promote` itself refuses a model that hasn't, and reports how many clips got better or worse with a confidence interval — a few dozen test clips can move an average by luck.
146
+
147
+ **Is it actually helping?** Once some clips are labeled, measure instead of guessing:
148
+
149
+ ```bash
150
+ voiceio learn eval --pipeline # what each text stage (numbers, commands, corrections, cloud
151
+ # postcorrect…) did to your past dictations, and its commonest edits
152
+ voiceio corrections audit # rules your own audio contradicts, and ones that look risky
153
+ voiceio learn eval --streaming # accuracy *and* stop→text, replaying clips through live dictation
154
+ ```
155
+
156
+ On the author's data these found a correction that kept turning "composable" into "comparable", a number rule writing "no one" as "no 1", and a cloud pass that never fixed a single vocabulary term.
157
+
158
+ ## Choose a model
159
+
160
+ ```bash
161
+ voiceio models list # known models, your fine-tunes, and which is active
162
+ voiceio models bench # score candidates on your held-out clips (after `voiceio learn build`)
163
+ voiceio models use medium # switch
164
+ ```
165
+
166
+ | Model | Runtime | License | Notes |
167
+ |---|---|---|---|
168
+ | `small` | faster-whisper | MIT | Default. About 5× realtime on a laptop CPU |
169
+ | `medium` | faster-whisper | MIT | Better on names, about 2.5× slower |
170
+ | `large-v3-turbo` | faster-whisper | MIT | Best Whisper for dictation; wants a GPU. Also the default `learn` teacher |
171
+ | `distil-large-v3` | faster-whisper | MIT | English only |
172
+ | `sherpa:parakeet-tdt-0.6b-v3` | sherpa-onnx | CC-BY-4.0 | Experimental. Fast, but no vocabulary biasing yet |
173
+ | `whispercpp:http://…` | whisper.cpp server | depends on the model | Experimental. E.g. a Vulkan build on an AMD iGPU |
174
+
175
+ Pick on your own audio, not leaderboards: for dictation full of names, how well a model can be *biased* matters more than its benchmark WER.
176
+
177
+ **Licenses.** voiceio ships no model weights. Each model is downloaded from its own source on first use, under its own license. The defaults are permissive (MIT). A fine-tune you make with `voiceio learn` inherits the license of the base model it was trained from.
178
+
179
+ ## Dictate from your phone
180
+
181
+ `python -m voiceio.server` (the `server` extra) serves the same engine over HTTP and WebSocket, for a phone or any other client: `POST /transcribe` with an audio file, or stream PCM over `/ws/transcribe` for live partials. It binds `127.0.0.1` by default; put it behind your VPN or a reverse proxy and set `VOICE_TOKEN` (bearer token) and `VOICE_ALLOWED_ORIGINS` when it is reachable from elsewhere. `VOICE_MODEL`, `VOICE_LANES`, `VOICE_HOST`/`VOICE_PORT` override the rest.
182
+
183
+ The server reads its own machine's voiceio config, so it gets your vocabulary and corrections once you copy them over:
184
+
185
+ ```bash
186
+ scripts/sync_personalization.sh myserver # vocabulary + corrections
187
+ scripts/sync_personalization.sh myserver --model # …and your promoted fine-tune
188
+ ```
189
+
190
+ To fine-tune on what you dictate from the phone too, opt in on the server with `[data] retain_audio = true` in its `config.toml`, then bring the clips home: `scripts/pull_phone_dictation.sh myserver` (an `rsync` over SSH followed by `voiceio learn import`). Only your own voice should go in: the model learns whoever is speaking.
191
+
192
+ ## Linux support
193
+
194
+ | | Text injection | Streaming preview | Hotkey | Status |
195
+ |---|---|---|---|---|
196
+ | GNOME (Wayland) | IBus, ydotool fallback | Yes (IBus preedit) | evdev, or a GNOME shortcut set up by `setup` | Tested daily |
197
+ | GNOME (X11) | IBus, xdotool fallback | Yes | evdev, pynput | Supported |
198
+ | KDE Plasma (Wayland) | IBus, ydotool fallback | Yes with IBus | evdev | Should work |
199
+ | Hyprland, incl. Omarchy | IBus, else wtype → ydotool | Yes with IBus; with fcitx5 (Omarchy's default), words are typed as you speak, without the in-place preview | evdev, or `bind = CTRL ALT, V, exec, voiceio toggle` | Should work |
200
+ | sway | IBus, else wtype → ydotool | As Hyprland | evdev, or `bindsym` + `voiceio toggle` | Should work |
201
+ | i3 / other X11 | IBus, xdotool | Yes with IBus | pynput, evdev | Should work |
202
+ | NixOS | as above | as above | evdev via the flake's udev rule | Flake provided, unbuilt ([NixOS](#nixos)) |
203
+
204
+ **Input methods.** IBus is the only way to get a live, underlined preview that is corrected in place on Wayland. voiceio installs its own IBus engine and only activates it while you dictate. If fcitx5 is your input method, voiceio leaves it alone and types the final text with wtype or ydotool. Terminals that ignore input methods get the clipboard.
205
+
206
+ **Hotkeys without the `input` group.** The evdev backend reads keyboards from `/dev/input`. `voiceio doctor --fix` installs a udev rule, `/etc/udev/rules.d/60-voiceio-uaccess.rules`, that grants the logged-in user access to keyboard devices. It works immediately, without logging out. The old route still works as a fallback: `sudo usermod -aG input $USER`, then log out and back in. You can also skip evdev and bind `voiceio toggle` in your compositor.
207
+
208
+ **ydotool** needs write access to `/dev/uinput`; `voiceio doctor --fix` installs a uaccess rule for that too.
209
+
210
+ ### NixOS
211
+
212
+ The repository is a flake. **It has not been built yet**; please report fixes.
213
+
214
+ ```nix
215
+ # flake inputs: voiceio.url = "github:Hugo0/voiceio";
216
+ # NixOS: package, uinput, and the keyboard uaccess rule
217
+ imports = [ voiceio.nixosModules.default ];
218
+ programs.voiceio.enable = true;
219
+
220
+ # Home Manager: config.toml from Nix + a systemd user service
221
+ imports = [ voiceio.homeManagerModules.default ];
222
+ services.voiceio = {
223
+ enable = true;
224
+ settings.model.name = "small";
225
+ };
226
+ ```
227
+
228
+ For the streaming preview, enable IBus as your input method: `i18n.inputMethod = { enable = true; type = "ibus"; };`.
229
+
230
+ ### Windows and macOS
231
+
232
+ There is a best-effort pynput path for both (hotkeys and typing, no live preview). It is untested and unmaintained, with no installers or CI. Patches are welcome; bug reports will likely sit.
233
+
234
+ ## Troubleshooting
235
+
236
+ | Problem | Fix |
237
+ |---|---|
238
+ | Nothing is typed | `voiceio doctor --fix`; usually the IBus component or the GNOME input source |
239
+ | Hotkey does nothing on Wayland | `voiceio doctor --fix` installs the keyboard udev rule, or bind `voiceio toggle` in your compositor |
240
+ | `sounddevice is not installed` | You installed without the desktop extra: `pipx install --force 'python-voiceio[desktop]'` |
241
+ | evdev fails to build | Install a C toolchain and Python headers (see Quickstart), then reinstall |
242
+ | Too slow | `voiceio doctor` shows your real stop→text; turn off cloud postcorrect, or `voiceio models use small` (or a GPU with `large-v3-turbo`) |
243
+ | Words come out wrong in a pattern | `voiceio learn eval --pipeline` and `voiceio corrections audit` show which stage or rule did it |
244
+ | Start over | `voiceio uninstall`, then `voiceio setup` |
245
+
246
+ Logs: `journalctl --user -u voiceio` or `~/.local/state/voiceio/voiceio.log`.
247
+
248
+ ## Roadmap
249
+
250
+ - **A landing page** — voiceio as local, open-source, private dictation that learns from you.
251
+ - **Continuous learning** — `learn maintain` on a timer: label new dictation while idle, retrain when enough piles up, and promote only what wins on your held-out clips.
252
+ - **Unbounded vocabulary** — move to a decoder whose biasing has no token cap (see [model choice](CONTRIBUTING.md#model-choice-why-whisper-and-what-would-change-it)).
253
+ - **One model everywhere** — sync your fine-tune to your phone server and laptops, peer to peer.
254
+
255
+ ## Contributing
256
+
257
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the architecture, conventions and the reasoning behind the model choice. Please open an issue before a large PR.
258
+
259
+ ## License
260
+
261
+ MIT. Model weights are not part of voiceio and carry their own licenses (see [Choose a model](#choose-a-model)).