textflowkit 0.1.10__tar.gz → 0.1.12__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 (231) hide show
  1. {textflowkit-0.1.10 → textflowkit-0.1.12}/CHANGELOG.md +95 -1
  2. {textflowkit-0.1.10 → textflowkit-0.1.12}/CONTRIBUTING.md +7 -1
  3. {textflowkit-0.1.10 → textflowkit-0.1.12}/PKG-INFO +184 -25
  4. {textflowkit-0.1.10 → textflowkit-0.1.12}/README.md +177 -24
  5. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/adapters.md +111 -3
  6. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/architecture.md +89 -1
  7. textflowkit-0.1.12/docs/assets/live-streaming-flow.svg +50 -0
  8. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/index.html +73 -8
  9. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/install.md +74 -2
  10. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/release-checklist.md +31 -1
  11. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/roadmap.md +25 -1
  12. textflowkit-0.1.12/docs/streaming.md +514 -0
  13. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/user-manual.md +183 -8
  14. textflowkit-0.1.12/packaging/windows/README.md +71 -0
  15. textflowkit-0.1.12/packaging/windows/THIRD-PARTY-NOTICES.txt +34 -0
  16. textflowkit-0.1.12/packaging/windows/assets.lock.json +56 -0
  17. textflowkit-0.1.12/packaging/windows/launch.py +140 -0
  18. textflowkit-0.1.12/packaging/windows/source-materials.json +20 -0
  19. textflowkit-0.1.12/packaging/windows/textflowkit.iss +77 -0
  20. {textflowkit-0.1.10 → textflowkit-0.1.12}/pyproject.toml +9 -2
  21. textflowkit-0.1.12/scripts/build_windows_installer.py +160 -0
  22. textflowkit-0.1.12/scripts/prepare_windows_payload.py +992 -0
  23. textflowkit-0.1.12/src/textflowkit/__init__.py +41 -0
  24. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/adapters/http_server.py +258 -2
  25. textflowkit-0.1.12/src/textflowkit/adapters/streaming_ws.py +1276 -0
  26. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/service.py +3 -0
  27. textflowkit-0.1.12/src/textflowkit/core/stream_worker.py +227 -0
  28. textflowkit-0.1.12/src/textflowkit/core/streaming.py +1198 -0
  29. textflowkit-0.1.12/src/textflowkit/core/streaming_assets.py +542 -0
  30. textflowkit-0.1.12/src/textflowkit/core/streaming_events.py +330 -0
  31. textflowkit-0.1.12/src/textflowkit/core/streaming_process.py +521 -0
  32. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/whistle.py +3 -0
  33. textflowkit-0.1.12/src/textflowkit/core/windows_process.py +24 -0
  34. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/sources/acquire.py +4 -1
  35. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/ui/app.py +235 -2
  36. textflowkit-0.1.12/src/textflowkit/ui/cleanup.py +306 -0
  37. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/ui/launcher.py +28 -0
  38. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/ui/static/app.css +7 -0
  39. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/ui/static/app.js +6 -0
  40. textflowkit-0.1.12/src/textflowkit/ui/static/cleanup.js +151 -0
  41. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/ui/static/index.html +23 -0
  42. textflowkit-0.1.12/src/textflowkit/ui/static/streaming-capture-worklet.js +156 -0
  43. textflowkit-0.1.12/src/textflowkit/ui/static/streaming-example.html +699 -0
  44. textflowkit-0.1.12/tests/test_streaming_assets.py +320 -0
  45. textflowkit-0.1.12/tests/test_streaming_browser_lifecycle.py +1347 -0
  46. textflowkit-0.1.12/tests/test_streaming_core.py +654 -0
  47. textflowkit-0.1.12/tests/test_streaming_example.py +371 -0
  48. textflowkit-0.1.12/tests/test_streaming_repairs.py +950 -0
  49. textflowkit-0.1.12/tests/test_streaming_transport.py +837 -0
  50. textflowkit-0.1.12/tests/test_streaming_u5_repairs.py +917 -0
  51. textflowkit-0.1.12/tests/test_streaming_ui_integration.py +190 -0
  52. textflowkit-0.1.12/tests/test_ui_cleanup.py +452 -0
  53. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_ui_packaging.py +18 -4
  54. textflowkit-0.1.12/tests/test_windows_installer.py +512 -0
  55. textflowkit-0.1.12/tests/test_windows_payload.py +413 -0
  56. textflowkit-0.1.10/src/textflowkit/__init__.py +0 -8
  57. {textflowkit-0.1.10 → textflowkit-0.1.12}/.dockerignore +0 -0
  58. {textflowkit-0.1.10 → textflowkit-0.1.12}/.env.example +0 -0
  59. {textflowkit-0.1.10 → textflowkit-0.1.12}/.gitattributes +0 -0
  60. {textflowkit-0.1.10 → textflowkit-0.1.12}/.github/dependabot.yml +0 -0
  61. {textflowkit-0.1.10 → textflowkit-0.1.12}/.github/workflows/ci.yml +0 -0
  62. {textflowkit-0.1.10 → textflowkit-0.1.12}/.github/workflows/publish-pypi.yml +0 -0
  63. {textflowkit-0.1.10 → textflowkit-0.1.12}/.gitignore +0 -0
  64. {textflowkit-0.1.10 → textflowkit-0.1.12}/.pre-commit-config.yaml +0 -0
  65. {textflowkit-0.1.10 → textflowkit-0.1.12}/Dockerfile +0 -0
  66. {textflowkit-0.1.10 → textflowkit-0.1.12}/LEGAL.md +0 -0
  67. {textflowkit-0.1.10 → textflowkit-0.1.12}/LICENSE +0 -0
  68. {textflowkit-0.1.10 → textflowkit-0.1.12}/SECURITY.md +0 -0
  69. {textflowkit-0.1.10 → textflowkit-0.1.12}/compose.yaml +0 -0
  70. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/.nojekyll +0 -0
  71. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/404.html +0 -0
  72. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/assets/architecture-overview.svg +0 -0
  73. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/assets/local-ui-flow.svg +0 -0
  74. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/assets/whistle-resume.svg +0 -0
  75. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/site-deployment.md +0 -0
  76. {textflowkit-0.1.10 → textflowkit-0.1.12}/docs/sources.md +0 -0
  77. {textflowkit-0.1.10 → textflowkit-0.1.12}/scripts/fetch_published_fonts.py +0 -0
  78. {textflowkit-0.1.10 → textflowkit-0.1.12}/scripts/smoke_installed_wheel.py +0 -0
  79. {textflowkit-0.1.10 → textflowkit-0.1.12}/scripts/smoke_live_youtube.py +0 -0
  80. {textflowkit-0.1.10 → textflowkit-0.1.12}/scripts/verify_readme_release.py +0 -0
  81. {textflowkit-0.1.10 → textflowkit-0.1.12}/scripts/verify_release_ci.py +0 -0
  82. {textflowkit-0.1.10 → textflowkit-0.1.12}/scripts/verify_release_versions.py +0 -0
  83. {textflowkit-0.1.10 → textflowkit-0.1.12}/scripts/write_release_manifest.py +0 -0
  84. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/adapters/__init__.py +0 -0
  85. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/adapters/mcp_server.py +0 -0
  86. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/assets/README.md +0 -0
  87. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/assets/selftest-speech.wav +0 -0
  88. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/cli.py +0 -0
  89. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/__init__.py +0 -0
  90. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/batch.py +0 -0
  91. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/bind.py +0 -0
  92. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/cancel.py +0 -0
  93. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/checkpoint.py +0 -0
  94. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/diarize.py +0 -0
  95. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/engine.py +0 -0
  96. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/executor.py +0 -0
  97. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/jobs.py +0 -0
  98. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/model.py +0 -0
  99. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/paths.py +0 -0
  100. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/pipeline.py +0 -0
  101. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/retrieval.py +0 -0
  102. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/runner.py +0 -0
  103. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/sqlite_store.py +0 -0
  104. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/startup.py +0 -0
  105. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/submission.py +0 -0
  106. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/timeutil.py +0 -0
  107. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/translate.py +0 -0
  108. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/core/whistle_assets.py +0 -0
  109. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/render/__init__.py +0 -0
  110. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/render/_cue_layout.py +0 -0
  111. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/render/_cue_text.py +0 -0
  112. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/render/_rename_excl.py +0 -0
  113. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/render/_rename_noreplace.py +0 -0
  114. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/render/docx.py +0 -0
  115. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/render/markdown.py +0 -0
  116. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/render/pdf.py +0 -0
  117. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/render/srt.py +0 -0
  118. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/render/txt.py +0 -0
  119. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/render/vtt.py +0 -0
  120. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/sources/__init__.py +0 -0
  121. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/sources/detect.py +0 -0
  122. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/sources/scratch.py +0 -0
  123. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/ui/__init__.py +0 -0
  124. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/ui/capabilities.py +0 -0
  125. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/ui/ownership.py +0 -0
  126. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/ui/paths.py +0 -0
  127. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/ui/security.py +0 -0
  128. {textflowkit-0.1.10 → textflowkit-0.1.12}/src/textflowkit/ui/uploads.py +0 -0
  129. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/__init__.py +0 -0
  130. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/ollama_stub.py +0 -0
  131. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_acquire.py +0 -0
  132. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_adapters.py +0 -0
  133. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_admission_ownership.py +0 -0
  134. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_atomic_resume.py +0 -0
  135. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_atomic_resume_aba.py +0 -0
  136. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_batch.py +0 -0
  137. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_batch_item_boundary.py +0 -0
  138. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_batch_resume_shared.py +0 -0
  139. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_bind.py +0 -0
  140. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_cancellation_finalization.py +0 -0
  141. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_checkpoint.py +0 -0
  142. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_checkpoint_single_copy.py +0 -0
  143. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_cli.py +0 -0
  144. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_cli_batch_feedback.py +0 -0
  145. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_cli_owning_recovery.py +0 -0
  146. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_cli_resume_batch.py +0 -0
  147. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_cli_stage_feedback.py +0 -0
  148. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_cli_stdout_format.py +0 -0
  149. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_confined_decoder_boundary.py +0 -0
  150. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_confined_indirect_media.py +0 -0
  151. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_confined_resume_boundary.py +0 -0
  152. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_container_example.py +0 -0
  153. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_cue_layout.py +0 -0
  154. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_diarize.py +0 -0
  155. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_diarize_example_flags.py +0 -0
  156. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_diarize_token_docs.py +0 -0
  157. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_docx_publication_identity.py +0 -0
  158. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_done_output_integrity.py +0 -0
  159. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_empty_formats_resume.py +0 -0
  160. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_engine_adapters.py +0 -0
  161. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_engine_cache.py +0 -0
  162. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_engine_faster.py +0 -0
  163. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_engine_quiet.py +0 -0
  164. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_executor.py +0 -0
  165. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_executor_store_failure.py +0 -0
  166. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_export.py +0 -0
  167. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_export_file_mode.py +0 -0
  168. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_export_preflight.py +0 -0
  169. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_faster_whisper_docs.py +0 -0
  170. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_fetch_published_fonts.py +0 -0
  171. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_font_notices.py +0 -0
  172. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_http_host_boundary.py +0 -0
  173. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_http_trusted_proxy.py +0 -0
  174. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_job_progress.py +0 -0
  175. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_jobs.py +0 -0
  176. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_landing_commands.py +0 -0
  177. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_landing_page.py +0 -0
  178. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_legal_summary.py +0 -0
  179. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_linux_no_hardlink.py +0 -0
  180. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_live_smoke_script.py +0 -0
  181. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_macos_no_hardlink.py +0 -0
  182. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_mcp_batch_cookie_docs.py +0 -0
  183. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_mcp_http_boundary.py +0 -0
  184. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_mcp_protocol_cleanliness.py +0 -0
  185. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_mcp_terminal_guidance.py +0 -0
  186. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_mcp_tool_descriptions.py +0 -0
  187. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_mcp_work_root.py +0 -0
  188. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_model.py +0 -0
  189. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_partial_output_resume.py +0 -0
  190. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_partial_pdf_resume.py +0 -0
  191. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_paths.py +0 -0
  192. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_pipeline_integrity.py +0 -0
  193. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_pipeline_resume_setup.py +0 -0
  194. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_production_browser_cookies.py +0 -0
  195. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_publish_ci_gate.py +0 -0
  196. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_publish_fonts_wiring.py +0 -0
  197. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_publish_manifest_wiring.py +0 -0
  198. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_publish_workflow_gate.py +0 -0
  199. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_readme_layout.py +0 -0
  200. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_readme_release_guard.py +0 -0
  201. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_release_boundaries.py +0 -0
  202. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_release_manifest.py +0 -0
  203. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_release_surfaces.py +0 -0
  204. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_render.py +0 -0
  205. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_retrieval.py +0 -0
  206. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_sdist_allowlist.py +0 -0
  207. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_service_profile.py +0 -0
  208. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_site_not_found.py +0 -0
  209. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_sources.py +0 -0
  210. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_stage_reuse_resume.py +0 -0
  211. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_startup_recovery.py +0 -0
  212. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_stdio_protocol.py +0 -0
  213. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_submission.py +0 -0
  214. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_submission_validation.py +0 -0
  215. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_translate.py +0 -0
  216. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_translate_completeness.py +0 -0
  217. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_ui_assets_and_capabilities.py +0 -0
  218. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_ui_consoleless_logging.py +0 -0
  219. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_ui_existing_routes_unchanged.py +0 -0
  220. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_ui_launcher.py +0 -0
  221. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_ui_ownership_and_shutdown.py +0 -0
  222. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_ui_real_serve.py +0 -0
  223. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_ui_security.py +0 -0
  224. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_ui_submission_and_download.py +0 -0
  225. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_ui_uploads.py +0 -0
  226. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_verify_release_versions.py +0 -0
  227. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_whistle_assets.py +0 -0
  228. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_whistle_defaults.py +0 -0
  229. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_whistle_engine.py +0 -0
  230. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_whistle_job_resume.py +0 -0
  231. {textflowkit-0.1.10 → textflowkit-0.1.12}/tests/test_windows_no_hardlink.py +0 -0
@@ -1,5 +1,99 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.1.12 — 2026-10-17
4
+
5
+ Core: 0.1.12; unchanged optional fonts: 0.1.6. The native Windows installer has been built and tested locally. The installer recipe ships in v0.1.12; the EXE remains local-only until unresolved corresponding-source compliance review is cleared. No public installer download link is available.
6
+
7
+ ### Optional local UI proofreading (v0.1.12)
8
+
9
+ - Add explicit post-transcription local Ollama proofreading with an installed-tag
10
+ picker; prefer `qwen3.5:9b` only when installed (size/performance fit unverified),
11
+ otherwise require selection.
12
+ No model downloads, cloud tags, paid provider, telemetry or new package dependency.
13
+ - Preserve original jobs and exports; persist a separate original-hash-bound AI
14
+ variant with provider/model/time provenance, source segment IDs/timestamps, no
15
+ inherited word alignment, comparison/original-only views and corrected TXT/copy.
16
+ - Bound background work and validate complete JSON/segment coverage atomically.
17
+ One cleanup at a time; fail without partial output. Normal shutdown drains work;
18
+ interrupted leases expire. AI corrections require human review.
19
+
20
+ - Validation history: the first cold full-UI attempt ended in a generic error; a
21
+ later hot 39-segment run returned zero edits despite clear spelling errors.
22
+ Final cold run (model explicitly unloaded first) completed all 39 segments in
23
+ three chunks with four changed segments at 2026-10-16 17:39:52 UTC. The original
24
+ SQLite JSON/source and IDs/timestamps matched; visible side-by-side review and
25
+ corrected TXT save were verified, with the saved file hash matching the variant.
26
+ This proves workflow completion for one run, not accuracy; “fundamental” and
27
+ “victims” were plausible guesses not verified against audio. Review against audio.
28
+
29
+ ### Native Windows installer
30
+
31
+ - Package the existing local browser UI in a native per-user installer for core
32
+ v0.1.12. Built and tested locally; public EXE publication remains gated on
33
+ corresponding-source compliance review. No public installer link is available.
34
+ - Bundle: private embeddable CPython, the UI and HTTP, export, and
35
+ streaming dependencies, the pinned Whistle model and runtime, and ffmpeg,
36
+ ffprobe, and Node. The installer is designed to need no separate Python, WSL,
37
+ or Docker installation.
38
+ - Prebundled Whistle assets and media binaries mean local file jobs need no
39
+ first-use asset download. URL media still needs network access. The default
40
+ Whistle engine supports only these seven advertised languages: `en`, `de`,
41
+ `fr`, `es`, `it`, `nl`, and `pl`.
42
+ - Per-user setup with a Start Menu entry and optional desktop shortcut; launch
43
+ starts the loopback server and opens the existing UI in the browser. It normally
44
+ needs no administrator rights, changes no global `PATH`, and has no automatic
45
+ updates.
46
+ - Keep UI data outside the app install directory and preserve it on upgrade and
47
+ uninstall. Stop server and wait before upgrade or uninstall; the candidate will
48
+ block while it is running rather than force-kill active jobs. Stop server drains
49
+ jobs, so cancel one first if it should not finish.
50
+ - Do not bundle optional `openai-whisper` or diarization dependencies; their
51
+ documented optional paths remain available through the Python package. Bundled
52
+ streaming dependencies do not change the opt-in default; physical browser
53
+ microphone capture remains unverified.
54
+ - The installer bundle includes third-party license and notice files,
55
+ including FFmpeg LGPL notices and corresponding-source information. Verify
56
+ exact notices and source-distribution details against final binaries before
57
+ publication.
58
+ - The candidate is unsigned, so Windows may show a SmartScreen warning.
59
+
60
+ ## v0.1.11 — 2026-10-06
61
+
62
+ Optional native live streaming supports **Windows x86_64 only**. Core version:
63
+ 0.1.11; unchanged optional fonts: 0.1.6. Existing standalone Whistle defaults,
64
+ file/URL jobs, CLI, and MCP behavior are unchanged. The public site remains static
65
+ documentation and serves no streams. Local source validation does not establish
66
+ published-package verification or cross-platform live support.
67
+
68
+
69
+ ### Added
70
+
71
+ - **Public `StreamingSession` API.** Bounded PCM feed, typed incremental events,
72
+ flush/finish, cancellation, canonical final `Transcript`, and context-manager
73
+ cleanup. One owned native child per session binds directly to the separately
74
+ pinned `libneedle3.dll`; no upstream Python SDK or telemetry module is loaded.
75
+ Live sessions are ephemeral, with no replay or durable resume.
76
+ - **Live microphone streaming (opt-in, loopback-only).** When
77
+ `TEXTFLOWKIT_STREAMING=1` is set, the developer HTTP app serves a `/stream`
78
+ WebSocket and the local UI serves `/api/stream`, both transcribing audio as it
79
+ arrives. A runnable, self-hosted browser example is at `/streaming-example`
80
+ (and `/api/streaming-example` under the UI); its `AudioWorklet` resamples any
81
+ device rate to 16 kHz mono with continuous phase. Off by default: with the
82
+ switch unset the endpoint does not exist. The standalone `textflowkit` CLI is
83
+ unaffected — it does not open a microphone or a streaming socket. Requires the
84
+ new `streaming` extra (`pip install "textflowkit[streaming]"`), which adds the
85
+ `websockets` dependency. Auth is fail-closed: the UI accepts only its own origin
86
+ and capability, the standalone API requires the API token (even in developer
87
+ mode), and a separate origin may stream only if the operator lists it in
88
+ `TEXTFLOWKIT_STREAMING_ORIGINS` (a browser needs its own origin listed, including
89
+ the standalone example's). See [docs/streaming.md](docs/streaming.md).
90
+ **Bounded live runs verified on this machine's native engine** — 65 s and 300 s
91
+ through the product core on Windows x86_64. A separate assembled UI WebSocket
92
+ run fed prerecorded PCM at real time for 12 s. Browser lifecycle and resampling
93
+ checks used fake audio; **physical microphone capture was not verified**. Only
94
+ English was measured natively; the other six accepted languages and live
95
+ Linux/macOS were not exercised. No public remote streaming is provided.
96
+
3
97
  ## v0.1.10 — 2026-10-06
4
98
 
5
99
  **The local browser interface ships.** The loopback-only browser workspace
@@ -51,7 +145,7 @@ security boundaries. A **native Windows** machine, in a real browser, proved the
51
145
  workspace end to end (drop a file, submit, download, stop). That is one platform's
52
146
  browser proof, **not** a live Linux or macOS UI run — those platforms are covered
53
147
  by automated tests only, and cross-platform CI (Windows/Linux/macOS) is a separate
54
- step run by the coordinator. **No live optional-backend (translation or
148
+ release gate. **No live optional-backend (translation or
55
149
  diarization) run through the UI is claimed.** The engine and packaging changes of
56
150
  v0.1.9 are unchanged by this release.
57
151
 
@@ -14,9 +14,15 @@ python -m venv .venv
14
14
  # Windows: .venv\Scripts\activate
15
15
  # POSIX: source .venv/bin/activate
16
16
  pip install ./packages/textflowkit-fonts # local optional PDF font companion
17
- pip install -e ".[dev,mcp,http,export]"
17
+ pip install -e ".[dev,mcp,http,streaming,export,whisper]"
18
18
  ```
19
19
 
20
+ The full suite needs both `streaming` (WebSocket transport) and `whisper`
21
+ (optional standalone engine) dependencies. Use a development environment; for
22
+ an existing AMD ROCm torch stack, follow [the install guide](docs/install.md)
23
+ to preserve that stack. Native live streaming supports Windows x86_64 only;
24
+ ordinary standalone platform support and defaults remain unchanged.
25
+
20
26
  ## Test and lint — the commands CI runs
21
27
 
22
28
  ```bash
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: textflowkit
3
- Version: 0.1.10
3
+ Version: 0.1.12
4
4
  Summary: Cross-platform media transcription toolkit: URL or file in, timestamped transcripts and subtitle files out.
5
5
  Project-URL: Homepage, https://www.textflowkit.org/
6
6
  Project-URL: Issues, https://github.com/scottconverse/textflowkit/issues
@@ -32,6 +32,7 @@ Requires-Dist: python-docx>=1.1; extra == 'all'
32
32
  Requires-Dist: reportlab>=4.0; extra == 'all'
33
33
  Requires-Dist: textflowkit-fonts<0.2,>=0.1.5; extra == 'all'
34
34
  Requires-Dist: uvicorn>=0.30; extra == 'all'
35
+ Requires-Dist: websockets<16,>=15; extra == 'all'
35
36
  Provides-Extra: dev
36
37
  Requires-Dist: build>=1.2; extra == 'dev'
37
38
  Requires-Dist: hatchling>=1.25; extra == 'dev'
@@ -53,6 +54,11 @@ Requires-Dist: pydantic>=2.7; extra == 'http'
53
54
  Requires-Dist: uvicorn>=0.30; extra == 'http'
54
55
  Provides-Extra: mcp
55
56
  Requires-Dist: mcp>=2.0; extra == 'mcp'
57
+ Provides-Extra: streaming
58
+ Requires-Dist: fastapi>=0.115; extra == 'streaming'
59
+ Requires-Dist: pydantic>=2.7; extra == 'streaming'
60
+ Requires-Dist: uvicorn>=0.30; extra == 'streaming'
61
+ Requires-Dist: websockets<16,>=15; extra == 'streaming'
56
62
  Provides-Extra: whisper
57
63
  Requires-Dist: openai-whisper>=20240930; extra == 'whisper'
58
64
  Description-Content-Type: text/markdown
@@ -67,7 +73,7 @@ Cross-platform media transcription toolkit. **One core, one CLI, thin adapters.*
67
73
  [User manual](https://github.com/scottconverse/textflowkit/blob/main/docs/user-manual.md) ·
68
74
  [Developer and integration manual](https://github.com/scottconverse/textflowkit/blob/main/docs/adapters.md)
69
75
 
70
- **Current release: [v0.1.10](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.10).**
76
+ **Current release: [v0.1.12](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.12).**
71
77
 
72
78
  The [static site deployment](https://github.com/scottconverse/textflowkit/blob/main/docs/site-deployment.md) is hosted on Cloudflare
73
79
  Pages. GitHub remains the source and CI host; the website does not run the
@@ -128,7 +134,7 @@ DOCX and PDF are available through the optional `export` extra.
128
134
 
129
135
  ## Architecture
130
136
 
131
- ![TextFlowKit shared-core architecture: five thin entry points feed one core. The CLI, Python API, MCP, HTTP API, and the local browser UI (a fifth door that mounts the existing HTTP app under /api and shares the same job store, adding transport only, not a new pipeline) sit above one core that acquires and decodes media, transcribes with the default Whistle engine or an explicitly selected openai-whisper, keeps job state and resume checkpoints in an optional SQLite store, adds optional speaker or translation postprocessing, and publishes TXT, SRT, VTT, JSON, Markdown, and optional DOCX/PDF exports.](https://raw.githubusercontent.com/scottconverse/textflowkit/v0.1.10/docs/assets/architecture-overview.svg)
137
+ ![TextFlowKit shared-core architecture: five thin entry points feed one core. The CLI, Python API, MCP, HTTP API, and the local browser UI (a fifth door that mounts the existing HTTP app under /api and shares the same job store, adding transport only, not a new pipeline) sit above one core that acquires and decodes media, transcribes with the default Whistle engine or an explicitly selected openai-whisper, keeps job state and resume checkpoints in an optional SQLite store, adds optional speaker or translation postprocessing, and publishes TXT, SRT, VTT, JSON, Markdown, and optional DOCX/PDF exports.](https://raw.githubusercontent.com/scottconverse/textflowkit/v0.1.12/docs/assets/architecture-overview.svg)
132
138
 
133
139
  The design principle is **one shared core, thin doors**. Everything of substance
134
140
  lives in the core; the interfaces are thin — the local browser UI is a fifth door
@@ -150,6 +156,32 @@ means writing one source adapter, not another tool.
150
156
  For the job lifecycle, process ownership, checkpoints, and output publication,
151
157
  see [docs/architecture.md](https://github.com/scottconverse/textflowkit/blob/main/docs/architecture.md).
152
158
 
159
+ ## Live microphone streaming (opt-in)
160
+
161
+ In v0.1.12, live streaming supports **Windows x86_64 only**. When
162
+ `TEXTFLOWKIT_STREAMING=1` is set, the developer HTTP app serves a `/stream`
163
+ WebSocket and the local UI serves `/api/stream`, both transcribing a live microphone
164
+ as you speak. A **runnable, self-hosted browser example** ships at
165
+ `/streaming-example` (and `/api/streaming-example` under the UI): it captures with an
166
+ `AudioWorklet`, resamples any device rate to 16 kHz mono, and shows the transcript.
167
+ No CDN, no analytics, no external fetch. Requires the `streaming` extra:
168
+
169
+ ```bash
170
+ python -m pip install "textflowkit[streaming]==0.1.12"
171
+ ```
172
+
173
+ It is **off by default** — with the switch unset the endpoint does not exist — and
174
+ **loopback-only**: auth is fail-closed, so the UI accepts only its own origin and
175
+ capability, the standalone API requires `TEXTFLOWKIT_API_TOKEN` (even in developer
176
+ mode), and a separate origin — including the standalone browser example's own origin —
177
+ may stream only if listed in `TEXTFLOWKIT_STREAMING_ORIGINS`. The standalone
178
+ `textflowkit` CLI is unaffected: it does not open a microphone or a streaming socket.
179
+ **Bounded live runs are verified on the native engine here** — 65 s and 300 s
180
+ end-to-end on Windows x86_64; the transport and the browser resampler are covered by
181
+ tests, and a physical browser microphone has not yet been captured (the browser proof
182
+ drives the page against a fake audio device). See
183
+ [docs/streaming.md](https://github.com/scottconverse/textflowkit/blob/main/docs/streaming.md).
184
+
153
185
  ## Recognized sources
154
186
 
155
187
  YouTube · TikTok · Facebook · Instagram · Vimeo · Twitch · Bilibili · Rumble ·
@@ -201,6 +233,38 @@ installs `textflowkit-fonts` for offline multilingual PDF rendering:
201
233
  python -m pip install 'textflowkit[export]'
202
234
  ```
203
235
 
236
+ ## Windows desktop installer (v0.1.12; public EXE pending)
237
+
238
+ An installer for the existing local browser workspace accompanies core v0.1.12. The native Windows installer has been built and tested locally. The installer recipe ships in v0.1.12; the EXE remains local-only until unresolved corresponding-source compliance review is cleared. No public installer download link is available. The Python package remains supported for developers and integrations.
239
+
240
+ The candidate is designed to run without a separately installed Python, WSL, or
241
+ Docker. Its bundle includes a private embeddable CPython runtime, the
242
+ browser UI and HTTP, export, and streaming dependencies, the pinned Whistle model
243
+ and runtime, and ffmpeg, ffprobe, and Node. The setup installs per user,
244
+ creates a Start Menu shortcut, and offers an optional desktop shortcut. Opening
245
+ the shortcut will start the local server and open the existing browser UI at
246
+ localhost. It is designed to need no administrator rights in normal use, change
247
+ no global `PATH`, and avoid automatic updates.
248
+
249
+ The pinned Whistle assets and media binaries are prebundled, so local file jobs
250
+ need no first-use asset download. URL sources still need their normal network
251
+ access. The default Whistle engine supports only these seven advertised languages:
252
+ `en`, `de`, `fr`, `es`, `it`, `nl`, and `pl`. Optional `openai-whisper` and diarization dependencies are not
253
+ bundled; those features remain documented for the Python package when separately
254
+ installed and configured. Streaming dependencies are bundled, but live streaming
255
+ remains opt-in and physical browser microphone capture has not been verified.
256
+
257
+ The candidate is designed to keep UI data outside the application install
258
+ directory and preserve it on upgrades and uninstall. Stop the UI server with
259
+ **Stop server** and wait for it to exit before upgrading or uninstalling; the
260
+ installer will block while it is running rather than force-killing active jobs.
261
+ Cancel a job first if it should not drain to completion. The bundle also
262
+ includes third-party license and notice files, including FFmpeg's LGPL notices
263
+ and corresponding-source information. Check exact notices and source-distribution
264
+ details against the final bundled binaries before publication. The candidate is
265
+ unsigned, so Windows may show a SmartScreen warning. See the [installer candidate
266
+ notes](docs/install.md#windows-desktop-installer-v0112-public-exe-pending).
267
+
204
268
  ## Python API
205
269
 
206
270
  The same pipeline used by the CLI and adapters is available to Python callers:
@@ -296,7 +360,7 @@ textflowkit export ./transcript.json --format vtt
296
360
  needs no PyTorch, so a fresh `pip install textflowkit` stays small and pulls no
297
361
  torch; `openai-whisper` is an explicitly selectable opt-in engine.
298
362
 
299
- ![Whistle bounded block run and durable resume: a decoded PCM WAV is split into 26-second cores with up to 2 seconds of context (each clip ≤ 30 s), each core runs as one owned child with forced telemetry-off flags, a partial checkpoint is written after each core, and a resume validates the source and decoded-WAV hashes then re-runs only the unfinished cores.](https://raw.githubusercontent.com/scottconverse/textflowkit/v0.1.10/docs/assets/whistle-resume.svg)
363
+ ![Whistle bounded block run and durable resume: a decoded PCM WAV is split into 26-second cores with up to 2 seconds of context (each clip ≤ 30 s), each core runs as one owned child with forced telemetry-off flags, a partial checkpoint is written after each core, and a resume validates the source and decoded-WAV hashes then re-runs only the unfinished cores.](https://raw.githubusercontent.com/scottconverse/textflowkit/v0.1.12/docs/assets/whistle-resume.svg)
300
364
 
301
365
  - **CPU only, no torch.** It runs a pinned native binary and downloads one pinned
302
366
  model on first use. Naming a GPU device is refused rather than silently
@@ -313,7 +377,7 @@ torch; `openai-whisper` is an explicitly selectable opt-in engine.
313
377
  of context on each side, so every standalone clip is ≤ 30 seconds (the native
314
378
  CLI's limit). Overlap words are selected by core midpoint rather than text
315
379
  deduplication, so repeated spoken phrases are preserved.
316
- - **Streaming is not used.** The native `--audio-stream` mode failed its
380
+ - **Standalone streaming is not used.** The native `--audio-stream` mode failed its
317
381
  coverage and is never passed; only the committed standalone output is parsed.
318
382
  - **Durable block resume.** With `TEXTFLOWKIT_DB` set, a long run writes partial
319
383
  per-block checkpoints; a resume checks the source and decoded-WAV hashes and the
@@ -407,7 +471,7 @@ its own beyond the `http` extra. It ships with the core package as of v0.1.10:
407
471
  a regular install of the current release carries it.
408
472
 
409
473
  ```bash
410
- python -m pip install 'textflowkit[http,export]==0.1.10'
474
+ python -m pip install 'textflowkit[http,export]==0.1.12'
411
475
  textflowkit-ui
412
476
  ```
413
477
 
@@ -478,29 +542,37 @@ browser interface share the job contract without blocking a request.
478
542
 
479
543
  ## Status
480
544
 
481
- **v0.1.10 release.** Core, CLI, MCP, HTTP, and the local browser interface have
482
- automated coverage. This release **ships the local browser interface**
483
- (`textflowkit-ui`) in the core package: a loopback-only workspace that reuses the
484
- same pipeline, submission contract, and job store, with a durable store, cancel
485
- and resume, and a Windows desktop shortcut (`textflowkit-ui --create-shortcut`).
486
- It adds **no new dependency** beyond the existing `http` extra, so a regular
487
- `pip install 'textflowkit[http,export]==0.1.10'` carries it. The engine, CLI,
488
- Python, MCP, and HTTP surfaces are unchanged and there is **no endpoint-breaking
489
- change**. It builds on v0.1.9, which made **Whistle the default engine** — a
490
- native CPU-only transcriber that needs no PyTorch — and moved `openai-whisper` to
491
- the optional `whisper` extra, selected explicitly with `--engine whisper` or
492
- `engine="whisper"`. Legacy engine aliases are preserved, so older saved jobs and
493
- `transcribe()` calls still decode. Whistle refuses an unsupported platform,
494
- language, or GPU request instead of silently falling back; its engine's
495
- verification boundary is in [Whistle (default engine)](#whistle-default-engine)
496
- above.
545
+ **v0.1.12 release.** Adds optional UI-only local Ollama proofreading and native
546
+ Windows installer packaging; public EXE distribution remains gated on unresolved
547
+ corresponding-source compliance review, with no public installer download link.
548
+ Existing optional live streaming provides a transport-neutral
549
+ `StreamingSession` Python API, incremental transcript events, and authenticated
550
+ loopback WebSockets (`/stream` on the developer HTTP API and `/api/stream` on the
551
+ local UI), with a packaged browser microphone example. The native live capability
552
+ supports **Windows x86_64 only** and uses one owned child with a separately pinned
553
+ `libneedle3.dll`. The `streaming` extra supplies the WebSocket dependency;
554
+ `TEXTFLOWKIT_STREAMING=1` enables the server routes. Streaming is off by default.
555
+
556
+ Existing file and URL transcription, CLI, MCP, durable jobs, and local browser
557
+ workspace defaults remain unchanged. Whistle stays the CPU-only standalone default;
558
+ `openai-whisper` remains an explicit opt-in engine. The local browser workspace
559
+ introduced in v0.1.10 still needs only the `http` extra for its ordinary job flow.
560
+ Fonts remain 0.1.6. Live sessions are ephemeral and have no durable resume.
561
+
562
+ **Streaming evidence.** Local English PCM runs exercised the native core for 65 s
563
+ and 300 s; a separate assembled UI WebSocket run fed prerecorded PCM at real time
564
+ for 12 s and returned incremental events and a final transcript. Browser lifecycle
565
+ and resampling checks used fake audio. Physical browser microphone capture, live
566
+ Linux/macOS, and the six other accepted languages were not verified. The public
567
+ website remains static documentation and serves no streaming endpoint. Local source
568
+ validation does not establish published-package or exact-commit CI results.
497
569
 
498
570
  **Verification limit.** The local browser interface is covered by an automated
499
571
  suite, and the UI's behavior was proved on a **native Windows** machine in a real
500
572
  browser. No live optional-backend (translation/diarization) run through the UI is
501
573
  claimed, and **no live Linux or macOS UI run was performed here** — those
502
574
  platforms are covered by automated tests only, and CI across Windows, Linux, and
503
- macOS is the coordinator's separate step. Release publication uses the tag
575
+ macOS is a separate release gate. Release publication uses the tag
504
576
  workflow, which requires successful exact-commit main CI before PyPI uploads and
505
577
  creates the public GitHub release only afterward. Check the linked release for
506
578
  artifacts and workflow status; local source verification is not a fresh
@@ -517,7 +589,7 @@ MCP speech, seven-format exports and completed resume; the v0.1.8 runtime fixes
517
589
  were independently checked through fresh-process CLI restart probes, real SQLite
518
590
  setup-failure tests, and the full Windows test suite. Those checks are not new
519
591
  individual-harness receipts. That is the previous releases' record, not evidence
520
- for v0.1.10.
592
+ for v0.1.12.
521
593
 
522
594
  The v0.1.6 release was the post-v0.1.5 review repair set: security hardening
523
595
  for media acquisition and the HTTP and MCP adapters, safer subtitle wrapping and
@@ -536,7 +608,7 @@ and both [core](https://pypi.org/project/textflowkit/0.1.6/) and
536
608
  [fonts](https://pypi.org/project/textflowkit-fonts/0.1.6/) PyPI projects are
537
609
  live — that is the v0.1.6 release's evidence, not a receipt for a later release.
538
610
  Everything from here to the end of this section is the v0.1.6 release's
539
- historical record as published: it is not re-verified for v0.1.10, whose separate release evidence is not supplied by these historical paragraphs.
611
+ historical record as published: it is not re-verified for v0.1.12, whose separate release evidence is not supplied by these historical paragraphs.
540
612
  Merged-main CI passed 16/16 on the tagged commit; the published wheel and
541
613
  sdist digests match the GitHub release assets and their SHA-256 list; and a fresh
542
614
  Windows Python 3.12 install of `textflowkit[export,mcp,http]==0.1.6` from PyPI
@@ -573,3 +645,90 @@ limitation of liability.
573
645
 
574
646
  Issues and PRs welcome. Please read [LEGAL.md](https://github.com/scottconverse/textflowkit/blob/main/LEGAL.md) before adding a source
575
647
  adapter.
648
+
649
+
650
+ ## Optional local AI transcript cleanup (v0.1.12)
651
+
652
+ v0.1.12 adds **opt-in proofreading in the local browser UI only**. After a transcription finishes, choose an
653
+ installed local Ollama model and click **Proofread with local AI**. Cleanup never
654
+ runs automatically. Ollama and cleanup models are not bundled in the installer.
655
+ The optional default preference is `qwen3.5:9b` only if already installed; its
656
+ size/performance fit has not been verified. Otherwise choose an installed local
657
+ model explicitly, such as `qwen3.8:27b-q4_K_M`. Larger models are never silently
658
+ selected. Install a model yourself through Ollama when needed; TextFlowKit does
659
+ not pull models, enable cloud tags, or use a paid provider.
660
+
661
+ The original transcript, job JSON, original copy button, search, and all existing
662
+ exports remain unchanged. Choose **Original only** or compare **source original
663
+ (left) / AI corrected (right)** in timestamp-anchored rows. Use **Copy corrected
664
+ text** or **Save corrected TXT** for the separate AI variant. The comparison
665
+ proofreads original source speech, not an optional translation. AI can make
666
+ plausible but wrong corrections, including names and facts: review against the
667
+ original and audio before using it. Prompt instructions reduce errors but do not
668
+ guarantee accuracy or resistance to instructions embedded in speech.
669
+
670
+ Corrected segments retain source start/end timestamps and stable zero-based
671
+ original segment indices. They have no inherited word alignment or translation;
672
+ **corrected word timing is not verified**. A separate persisted variant records
673
+ local provider, requested/returned model, UTC completion time, endpoint, successful
674
+ `done_reason=stop`, policy version and original SHA-256. If original job JSON
675
+ changes, its correction is invalidated. No partial replacement is published: bad,
676
+ truncated, missing, duplicated, reordered or extra segments fail the entire attempt.
677
+ A failed retry retains an earlier fully validated variant only if its original
678
+ hash still matches.
679
+
680
+ Cleanup uses a separate SQLite file named `<job database filename>.cleanup.sqlite3`
681
+ beside `TEXTFLOWKIT_DB` (or the UI default database). Include it when backing up UI
682
+ data; it contains transcript text and provenance. The canonical job store is never
683
+ updated by cleanup. Reloading/reopening a completed job retrieves its saved variant,
684
+ even if Ollama is offline. Model selection is per attempt; it is not a global
685
+ transcription/translation model setting.
686
+
687
+ Configuration is process-local environment, consistent with the existing UI:
688
+
689
+ - `TEXTFLOWKIT_CLEANUP_OLLAMA_URL`: default `http://127.0.0.1:11434`; only HTTP on
690
+ a literal loopback IP and explicit port is accepted (IPv6 `[::1]` also works).
691
+ DNS names, credentials, other paths, remote hosts and redirects are refused;
692
+ proxy environment variables are ignored by the cleanup client.
693
+ - `TEXTFLOWKIT_CLEANUP_MODEL`: optional preferred installed local tag; defaults
694
+ to `qwen3.5:9b`. If absent from installed tags, explicit selection is required.
695
+ Cloud tags and Ollama remote-model metadata are refused.
696
+
697
+ One cleanup runs at a time; the browser polls a background worker and remains
698
+ usable. Limits: 2,000 segments, 120,000 source characters, 60 chunks, at most
699
+ 1,000 UTF-8 encoded bytes per chunk and 40 segments per chunk. A small read-only
700
+ neighboring context helps with sentences spanning segments without merging them.
701
+ Generation requests use temperature 0, thinking disabled, context 8,192 and at
702
+ most 4,096 generated tokens per chunk. Requests have a 180-second socket timeout,
703
+ bounded response reads (1 MiB), and strict 64 KiB model JSON limits. The overall
704
+ work budget remains 600 seconds, checked between requests and reads; a blocking
705
+ socket operation can take up to its remaining request timeout before failure is
706
+ observed. Oversize or timeout failures leave the original available.
707
+
708
+ Normal UI shutdown drains an active cleanup (it can take several minutes); there
709
+ is no cleanup cancellation button. Abrupt process exit leaves no partial variant;
710
+ an interrupted running lease becomes retryable after at most 785 seconds from its
711
+ start. Cleanup does not restart Ollama or stop/unload other models. Model text is
712
+ rendered with DOM text nodes, never HTML. Cleanup adds no Python dependency,
713
+ telemetry, cloud provider or network destination beyond the configured local
714
+ Ollama service. Existing media acquisition/translation network behavior is separate.
715
+
716
+ ### Candidate validation status
717
+
718
+ The first cold full-UI attempt ended with a generic error and produced no variant;
719
+ the original remained intact. A subsequent hot 39-segment run returned zero text
720
+ edits despite clear source spelling errors, so it was not useful cleanup-quality
721
+ evidence. The final cold run began with the model explicitly unloaded and
722
+ completed all 39 segments in three chunks at
723
+ 2026-10-16 17:39:52 UTC. It used matching requested/returned
724
+ `qwen3.8:27b-q4_K_M` and changed four segments. The original SQLite JSON matched
725
+ the source file, with segment IDs and timestamps preserved. The in-app-browser
726
+ side-by-side comparison was visible, and **Save corrected TXT** produced a
727
+ 2,516-byte file whose SHA-256 matched the validated variant.
728
+
729
+ Observed edits included “guardrails,” “precludes,” and punctuation. “Fundamental”
730
+ and “victims” were plausible guesses, not verified against the audio. This is
731
+ measured evidence that the local full workflow completed and saved its separate
732
+ variant for this run; it does not establish transcription accuracy or general
733
+ cleanup quality. Review every correction against the audio. This is local workflow evidence,
734
+ not an audio-accuracy certification.