textflowkit 0.1.11__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 (230) hide show
  1. {textflowkit-0.1.11 → textflowkit-0.1.12}/CHANGELOG.md +57 -0
  2. {textflowkit-0.1.11 → textflowkit-0.1.12}/PKG-INFO +132 -10
  3. {textflowkit-0.1.11 → textflowkit-0.1.12}/README.md +131 -9
  4. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/adapters.md +70 -4
  5. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/architecture.md +63 -1
  6. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/index.html +70 -10
  7. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/install.md +57 -4
  8. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/release-checklist.md +11 -5
  9. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/roadmap.md +9 -0
  10. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/streaming.md +4 -4
  11. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/user-manual.md +149 -9
  12. textflowkit-0.1.12/packaging/windows/README.md +71 -0
  13. textflowkit-0.1.12/packaging/windows/THIRD-PARTY-NOTICES.txt +34 -0
  14. textflowkit-0.1.12/packaging/windows/assets.lock.json +56 -0
  15. textflowkit-0.1.12/packaging/windows/launch.py +140 -0
  16. textflowkit-0.1.12/packaging/windows/source-materials.json +20 -0
  17. textflowkit-0.1.12/packaging/windows/textflowkit.iss +77 -0
  18. {textflowkit-0.1.11 → textflowkit-0.1.12}/pyproject.toml +2 -1
  19. textflowkit-0.1.12/scripts/build_windows_installer.py +160 -0
  20. textflowkit-0.1.12/scripts/prepare_windows_payload.py +992 -0
  21. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/__init__.py +1 -1
  22. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/service.py +3 -0
  23. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/streaming_process.py +4 -3
  24. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/whistle.py +3 -0
  25. textflowkit-0.1.12/src/textflowkit/core/windows_process.py +24 -0
  26. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/sources/acquire.py +4 -1
  27. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/app.py +101 -0
  28. textflowkit-0.1.12/src/textflowkit/ui/cleanup.py +306 -0
  29. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/launcher.py +3 -0
  30. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/static/app.css +7 -0
  31. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/static/app.js +6 -0
  32. textflowkit-0.1.12/src/textflowkit/ui/static/cleanup.js +151 -0
  33. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/static/index.html +23 -0
  34. textflowkit-0.1.12/tests/test_ui_cleanup.py +452 -0
  35. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_ui_packaging.py +5 -2
  36. textflowkit-0.1.12/tests/test_windows_installer.py +512 -0
  37. textflowkit-0.1.12/tests/test_windows_payload.py +413 -0
  38. {textflowkit-0.1.11 → textflowkit-0.1.12}/.dockerignore +0 -0
  39. {textflowkit-0.1.11 → textflowkit-0.1.12}/.env.example +0 -0
  40. {textflowkit-0.1.11 → textflowkit-0.1.12}/.gitattributes +0 -0
  41. {textflowkit-0.1.11 → textflowkit-0.1.12}/.github/dependabot.yml +0 -0
  42. {textflowkit-0.1.11 → textflowkit-0.1.12}/.github/workflows/ci.yml +0 -0
  43. {textflowkit-0.1.11 → textflowkit-0.1.12}/.github/workflows/publish-pypi.yml +0 -0
  44. {textflowkit-0.1.11 → textflowkit-0.1.12}/.gitignore +0 -0
  45. {textflowkit-0.1.11 → textflowkit-0.1.12}/.pre-commit-config.yaml +0 -0
  46. {textflowkit-0.1.11 → textflowkit-0.1.12}/CONTRIBUTING.md +0 -0
  47. {textflowkit-0.1.11 → textflowkit-0.1.12}/Dockerfile +0 -0
  48. {textflowkit-0.1.11 → textflowkit-0.1.12}/LEGAL.md +0 -0
  49. {textflowkit-0.1.11 → textflowkit-0.1.12}/LICENSE +0 -0
  50. {textflowkit-0.1.11 → textflowkit-0.1.12}/SECURITY.md +0 -0
  51. {textflowkit-0.1.11 → textflowkit-0.1.12}/compose.yaml +0 -0
  52. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/.nojekyll +0 -0
  53. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/404.html +0 -0
  54. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/assets/architecture-overview.svg +0 -0
  55. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/assets/live-streaming-flow.svg +0 -0
  56. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/assets/local-ui-flow.svg +0 -0
  57. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/assets/whistle-resume.svg +0 -0
  58. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/site-deployment.md +0 -0
  59. {textflowkit-0.1.11 → textflowkit-0.1.12}/docs/sources.md +0 -0
  60. {textflowkit-0.1.11 → textflowkit-0.1.12}/scripts/fetch_published_fonts.py +0 -0
  61. {textflowkit-0.1.11 → textflowkit-0.1.12}/scripts/smoke_installed_wheel.py +0 -0
  62. {textflowkit-0.1.11 → textflowkit-0.1.12}/scripts/smoke_live_youtube.py +0 -0
  63. {textflowkit-0.1.11 → textflowkit-0.1.12}/scripts/verify_readme_release.py +0 -0
  64. {textflowkit-0.1.11 → textflowkit-0.1.12}/scripts/verify_release_ci.py +0 -0
  65. {textflowkit-0.1.11 → textflowkit-0.1.12}/scripts/verify_release_versions.py +0 -0
  66. {textflowkit-0.1.11 → textflowkit-0.1.12}/scripts/write_release_manifest.py +0 -0
  67. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/adapters/__init__.py +0 -0
  68. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/adapters/http_server.py +0 -0
  69. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/adapters/mcp_server.py +0 -0
  70. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/adapters/streaming_ws.py +0 -0
  71. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/assets/README.md +0 -0
  72. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/assets/selftest-speech.wav +0 -0
  73. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/cli.py +0 -0
  74. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/__init__.py +0 -0
  75. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/batch.py +0 -0
  76. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/bind.py +0 -0
  77. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/cancel.py +0 -0
  78. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/checkpoint.py +0 -0
  79. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/diarize.py +0 -0
  80. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/engine.py +0 -0
  81. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/executor.py +0 -0
  82. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/jobs.py +0 -0
  83. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/model.py +0 -0
  84. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/paths.py +0 -0
  85. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/pipeline.py +0 -0
  86. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/retrieval.py +0 -0
  87. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/runner.py +0 -0
  88. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/sqlite_store.py +0 -0
  89. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/startup.py +0 -0
  90. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/stream_worker.py +0 -0
  91. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/streaming.py +0 -0
  92. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/streaming_assets.py +0 -0
  93. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/streaming_events.py +0 -0
  94. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/submission.py +0 -0
  95. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/timeutil.py +0 -0
  96. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/translate.py +0 -0
  97. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/core/whistle_assets.py +0 -0
  98. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/render/__init__.py +0 -0
  99. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/render/_cue_layout.py +0 -0
  100. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/render/_cue_text.py +0 -0
  101. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/render/_rename_excl.py +0 -0
  102. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/render/_rename_noreplace.py +0 -0
  103. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/render/docx.py +0 -0
  104. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/render/markdown.py +0 -0
  105. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/render/pdf.py +0 -0
  106. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/render/srt.py +0 -0
  107. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/render/txt.py +0 -0
  108. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/render/vtt.py +0 -0
  109. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/sources/__init__.py +0 -0
  110. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/sources/detect.py +0 -0
  111. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/sources/scratch.py +0 -0
  112. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/__init__.py +0 -0
  113. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/capabilities.py +0 -0
  114. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/ownership.py +0 -0
  115. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/paths.py +0 -0
  116. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/security.py +0 -0
  117. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/static/streaming-capture-worklet.js +0 -0
  118. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/static/streaming-example.html +0 -0
  119. {textflowkit-0.1.11 → textflowkit-0.1.12}/src/textflowkit/ui/uploads.py +0 -0
  120. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/__init__.py +0 -0
  121. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/ollama_stub.py +0 -0
  122. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_acquire.py +0 -0
  123. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_adapters.py +0 -0
  124. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_admission_ownership.py +0 -0
  125. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_atomic_resume.py +0 -0
  126. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_atomic_resume_aba.py +0 -0
  127. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_batch.py +0 -0
  128. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_batch_item_boundary.py +0 -0
  129. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_batch_resume_shared.py +0 -0
  130. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_bind.py +0 -0
  131. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_cancellation_finalization.py +0 -0
  132. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_checkpoint.py +0 -0
  133. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_checkpoint_single_copy.py +0 -0
  134. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_cli.py +0 -0
  135. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_cli_batch_feedback.py +0 -0
  136. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_cli_owning_recovery.py +0 -0
  137. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_cli_resume_batch.py +0 -0
  138. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_cli_stage_feedback.py +0 -0
  139. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_cli_stdout_format.py +0 -0
  140. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_confined_decoder_boundary.py +0 -0
  141. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_confined_indirect_media.py +0 -0
  142. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_confined_resume_boundary.py +0 -0
  143. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_container_example.py +0 -0
  144. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_cue_layout.py +0 -0
  145. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_diarize.py +0 -0
  146. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_diarize_example_flags.py +0 -0
  147. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_diarize_token_docs.py +0 -0
  148. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_docx_publication_identity.py +0 -0
  149. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_done_output_integrity.py +0 -0
  150. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_empty_formats_resume.py +0 -0
  151. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_engine_adapters.py +0 -0
  152. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_engine_cache.py +0 -0
  153. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_engine_faster.py +0 -0
  154. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_engine_quiet.py +0 -0
  155. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_executor.py +0 -0
  156. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_executor_store_failure.py +0 -0
  157. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_export.py +0 -0
  158. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_export_file_mode.py +0 -0
  159. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_export_preflight.py +0 -0
  160. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_faster_whisper_docs.py +0 -0
  161. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_fetch_published_fonts.py +0 -0
  162. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_font_notices.py +0 -0
  163. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_http_host_boundary.py +0 -0
  164. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_http_trusted_proxy.py +0 -0
  165. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_job_progress.py +0 -0
  166. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_jobs.py +0 -0
  167. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_landing_commands.py +0 -0
  168. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_landing_page.py +0 -0
  169. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_legal_summary.py +0 -0
  170. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_linux_no_hardlink.py +0 -0
  171. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_live_smoke_script.py +0 -0
  172. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_macos_no_hardlink.py +0 -0
  173. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_mcp_batch_cookie_docs.py +0 -0
  174. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_mcp_http_boundary.py +0 -0
  175. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_mcp_protocol_cleanliness.py +0 -0
  176. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_mcp_terminal_guidance.py +0 -0
  177. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_mcp_tool_descriptions.py +0 -0
  178. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_mcp_work_root.py +0 -0
  179. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_model.py +0 -0
  180. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_partial_output_resume.py +0 -0
  181. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_partial_pdf_resume.py +0 -0
  182. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_paths.py +0 -0
  183. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_pipeline_integrity.py +0 -0
  184. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_pipeline_resume_setup.py +0 -0
  185. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_production_browser_cookies.py +0 -0
  186. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_publish_ci_gate.py +0 -0
  187. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_publish_fonts_wiring.py +0 -0
  188. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_publish_manifest_wiring.py +0 -0
  189. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_publish_workflow_gate.py +0 -0
  190. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_readme_layout.py +0 -0
  191. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_readme_release_guard.py +0 -0
  192. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_release_boundaries.py +0 -0
  193. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_release_manifest.py +0 -0
  194. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_release_surfaces.py +0 -0
  195. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_render.py +0 -0
  196. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_retrieval.py +0 -0
  197. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_sdist_allowlist.py +0 -0
  198. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_service_profile.py +0 -0
  199. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_site_not_found.py +0 -0
  200. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_sources.py +0 -0
  201. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_stage_reuse_resume.py +0 -0
  202. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_startup_recovery.py +0 -0
  203. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_stdio_protocol.py +0 -0
  204. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_streaming_assets.py +0 -0
  205. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_streaming_browser_lifecycle.py +0 -0
  206. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_streaming_core.py +0 -0
  207. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_streaming_example.py +0 -0
  208. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_streaming_repairs.py +0 -0
  209. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_streaming_transport.py +0 -0
  210. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_streaming_u5_repairs.py +0 -0
  211. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_streaming_ui_integration.py +0 -0
  212. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_submission.py +0 -0
  213. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_submission_validation.py +0 -0
  214. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_translate.py +0 -0
  215. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_translate_completeness.py +0 -0
  216. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_ui_assets_and_capabilities.py +0 -0
  217. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_ui_consoleless_logging.py +0 -0
  218. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_ui_existing_routes_unchanged.py +0 -0
  219. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_ui_launcher.py +0 -0
  220. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_ui_ownership_and_shutdown.py +0 -0
  221. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_ui_real_serve.py +0 -0
  222. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_ui_security.py +0 -0
  223. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_ui_submission_and_download.py +0 -0
  224. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_ui_uploads.py +0 -0
  225. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_verify_release_versions.py +0 -0
  226. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_whistle_assets.py +0 -0
  227. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_whistle_defaults.py +0 -0
  228. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_whistle_engine.py +0 -0
  229. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_whistle_job_resume.py +0 -0
  230. {textflowkit-0.1.11 → textflowkit-0.1.12}/tests/test_windows_no_hardlink.py +0 -0
@@ -1,5 +1,62 @@
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
+
3
60
  ## v0.1.11 — 2026-10-06
4
61
 
5
62
  Optional native live streaming supports **Windows x86_64 only**. Core version:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: textflowkit
3
- Version: 0.1.11
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
@@ -73,7 +73,7 @@ Cross-platform media transcription toolkit. **One core, one CLI, thin adapters.*
73
73
  [User manual](https://github.com/scottconverse/textflowkit/blob/main/docs/user-manual.md) ·
74
74
  [Developer and integration manual](https://github.com/scottconverse/textflowkit/blob/main/docs/adapters.md)
75
75
 
76
- **Current release: [v0.1.11](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.11).**
76
+ **Current release: [v0.1.12](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.12).**
77
77
 
78
78
  The [static site deployment](https://github.com/scottconverse/textflowkit/blob/main/docs/site-deployment.md) is hosted on Cloudflare
79
79
  Pages. GitHub remains the source and CI host; the website does not run the
@@ -134,7 +134,7 @@ DOCX and PDF are available through the optional `export` extra.
134
134
 
135
135
  ## Architecture
136
136
 
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.11/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)
138
138
 
139
139
  The design principle is **one shared core, thin doors**. Everything of substance
140
140
  lives in the core; the interfaces are thin — the local browser UI is a fifth door
@@ -158,7 +158,7 @@ see [docs/architecture.md](https://github.com/scottconverse/textflowkit/blob/mai
158
158
 
159
159
  ## Live microphone streaming (opt-in)
160
160
 
161
- In v0.1.11, live streaming supports **Windows x86_64 only**. When
161
+ In v0.1.12, live streaming supports **Windows x86_64 only**. When
162
162
  `TEXTFLOWKIT_STREAMING=1` is set, the developer HTTP app serves a `/stream`
163
163
  WebSocket and the local UI serves `/api/stream`, both transcribing a live microphone
164
164
  as you speak. A **runnable, self-hosted browser example** ships at
@@ -167,7 +167,7 @@ as you speak. A **runnable, self-hosted browser example** ships at
167
167
  No CDN, no analytics, no external fetch. Requires the `streaming` extra:
168
168
 
169
169
  ```bash
170
- python -m pip install "textflowkit[streaming]==0.1.11"
170
+ python -m pip install "textflowkit[streaming]==0.1.12"
171
171
  ```
172
172
 
173
173
  It is **off by default** — with the switch unset the endpoint does not exist — and
@@ -233,6 +233,38 @@ installs `textflowkit-fonts` for offline multilingual PDF rendering:
233
233
  python -m pip install 'textflowkit[export]'
234
234
  ```
235
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
+
236
268
  ## Python API
237
269
 
238
270
  The same pipeline used by the CLI and adapters is available to Python callers:
@@ -328,7 +360,7 @@ textflowkit export ./transcript.json --format vtt
328
360
  needs no PyTorch, so a fresh `pip install textflowkit` stays small and pulls no
329
361
  torch; `openai-whisper` is an explicitly selectable opt-in engine.
330
362
 
331
- ![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.11/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)
332
364
 
333
365
  - **CPU only, no torch.** It runs a pinned native binary and downloads one pinned
334
366
  model on first use. Naming a GPU device is refused rather than silently
@@ -439,7 +471,7 @@ its own beyond the `http` extra. It ships with the core package as of v0.1.10:
439
471
  a regular install of the current release carries it.
440
472
 
441
473
  ```bash
442
- python -m pip install 'textflowkit[http,export]==0.1.11'
474
+ python -m pip install 'textflowkit[http,export]==0.1.12'
443
475
  textflowkit-ui
444
476
  ```
445
477
 
@@ -510,7 +542,10 @@ browser interface share the job contract without blocking a request.
510
542
 
511
543
  ## Status
512
544
 
513
- **v0.1.11 release.** Optional live streaming adds a transport-neutral
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
514
549
  `StreamingSession` Python API, incremental transcript events, and authenticated
515
550
  loopback WebSockets (`/stream` on the developer HTTP API and `/api/stream` on the
516
551
  local UI), with a packaged browser microphone example. The native live capability
@@ -554,7 +589,7 @@ MCP speech, seven-format exports and completed resume; the v0.1.8 runtime fixes
554
589
  were independently checked through fresh-process CLI restart probes, real SQLite
555
590
  setup-failure tests, and the full Windows test suite. Those checks are not new
556
591
  individual-harness receipts. That is the previous releases' record, not evidence
557
- for v0.1.11.
592
+ for v0.1.12.
558
593
 
559
594
  The v0.1.6 release was the post-v0.1.5 review repair set: security hardening
560
595
  for media acquisition and the HTTP and MCP adapters, safer subtitle wrapping and
@@ -573,7 +608,7 @@ and both [core](https://pypi.org/project/textflowkit/0.1.6/) and
573
608
  [fonts](https://pypi.org/project/textflowkit-fonts/0.1.6/) PyPI projects are
574
609
  live — that is the v0.1.6 release's evidence, not a receipt for a later release.
575
610
  Everything from here to the end of this section is the v0.1.6 release's
576
- historical record as published: it is not re-verified for v0.1.11, 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.
577
612
  Merged-main CI passed 16/16 on the tagged commit; the published wheel and
578
613
  sdist digests match the GitHub release assets and their SHA-256 list; and a fresh
579
614
  Windows Python 3.12 install of `textflowkit[export,mcp,http]==0.1.6` from PyPI
@@ -610,3 +645,90 @@ limitation of liability.
610
645
 
611
646
  Issues and PRs welcome. Please read [LEGAL.md](https://github.com/scottconverse/textflowkit/blob/main/LEGAL.md) before adding a source
612
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.
@@ -8,7 +8,7 @@ Cross-platform media transcription toolkit. **One core, one CLI, thin adapters.*
8
8
  [User manual](https://github.com/scottconverse/textflowkit/blob/main/docs/user-manual.md) ·
9
9
  [Developer and integration manual](https://github.com/scottconverse/textflowkit/blob/main/docs/adapters.md)
10
10
 
11
- **Current release: [v0.1.11](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.11).**
11
+ **Current release: [v0.1.12](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.12).**
12
12
 
13
13
  The [static site deployment](https://github.com/scottconverse/textflowkit/blob/main/docs/site-deployment.md) is hosted on Cloudflare
14
14
  Pages. GitHub remains the source and CI host; the website does not run the
@@ -69,7 +69,7 @@ DOCX and PDF are available through the optional `export` extra.
69
69
 
70
70
  ## Architecture
71
71
 
72
- ![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.11/docs/assets/architecture-overview.svg)
72
+ ![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)
73
73
 
74
74
  The design principle is **one shared core, thin doors**. Everything of substance
75
75
  lives in the core; the interfaces are thin — the local browser UI is a fifth door
@@ -93,7 +93,7 @@ see [docs/architecture.md](https://github.com/scottconverse/textflowkit/blob/mai
93
93
 
94
94
  ## Live microphone streaming (opt-in)
95
95
 
96
- In v0.1.11, live streaming supports **Windows x86_64 only**. When
96
+ In v0.1.12, live streaming supports **Windows x86_64 only**. When
97
97
  `TEXTFLOWKIT_STREAMING=1` is set, the developer HTTP app serves a `/stream`
98
98
  WebSocket and the local UI serves `/api/stream`, both transcribing a live microphone
99
99
  as you speak. A **runnable, self-hosted browser example** ships at
@@ -102,7 +102,7 @@ as you speak. A **runnable, self-hosted browser example** ships at
102
102
  No CDN, no analytics, no external fetch. Requires the `streaming` extra:
103
103
 
104
104
  ```bash
105
- python -m pip install "textflowkit[streaming]==0.1.11"
105
+ python -m pip install "textflowkit[streaming]==0.1.12"
106
106
  ```
107
107
 
108
108
  It is **off by default** — with the switch unset the endpoint does not exist — and
@@ -168,6 +168,38 @@ installs `textflowkit-fonts` for offline multilingual PDF rendering:
168
168
  python -m pip install 'textflowkit[export]'
169
169
  ```
170
170
 
171
+ ## Windows desktop installer (v0.1.12; public EXE pending)
172
+
173
+ 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.
174
+
175
+ The candidate is designed to run without a separately installed Python, WSL, or
176
+ Docker. Its bundle includes a private embeddable CPython runtime, the
177
+ browser UI and HTTP, export, and streaming dependencies, the pinned Whistle model
178
+ and runtime, and ffmpeg, ffprobe, and Node. The setup installs per user,
179
+ creates a Start Menu shortcut, and offers an optional desktop shortcut. Opening
180
+ the shortcut will start the local server and open the existing browser UI at
181
+ localhost. It is designed to need no administrator rights in normal use, change
182
+ no global `PATH`, and avoid automatic updates.
183
+
184
+ The pinned Whistle assets and media binaries are prebundled, so local file jobs
185
+ need no first-use asset download. URL sources still need their normal network
186
+ access. The default Whistle engine supports only these seven advertised languages:
187
+ `en`, `de`, `fr`, `es`, `it`, `nl`, and `pl`. Optional `openai-whisper` and diarization dependencies are not
188
+ bundled; those features remain documented for the Python package when separately
189
+ installed and configured. Streaming dependencies are bundled, but live streaming
190
+ remains opt-in and physical browser microphone capture has not been verified.
191
+
192
+ The candidate is designed to keep UI data outside the application install
193
+ directory and preserve it on upgrades and uninstall. Stop the UI server with
194
+ **Stop server** and wait for it to exit before upgrading or uninstalling; the
195
+ installer will block while it is running rather than force-killing active jobs.
196
+ Cancel a job first if it should not drain to completion. The bundle also
197
+ includes third-party license and notice files, including FFmpeg's LGPL notices
198
+ and corresponding-source information. Check exact notices and source-distribution
199
+ details against the final bundled binaries before publication. The candidate is
200
+ unsigned, so Windows may show a SmartScreen warning. See the [installer candidate
201
+ notes](docs/install.md#windows-desktop-installer-v0112-public-exe-pending).
202
+
171
203
  ## Python API
172
204
 
173
205
  The same pipeline used by the CLI and adapters is available to Python callers:
@@ -263,7 +295,7 @@ textflowkit export ./transcript.json --format vtt
263
295
  needs no PyTorch, so a fresh `pip install textflowkit` stays small and pulls no
264
296
  torch; `openai-whisper` is an explicitly selectable opt-in engine.
265
297
 
266
- ![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.11/docs/assets/whistle-resume.svg)
298
+ ![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)
267
299
 
268
300
  - **CPU only, no torch.** It runs a pinned native binary and downloads one pinned
269
301
  model on first use. Naming a GPU device is refused rather than silently
@@ -374,7 +406,7 @@ its own beyond the `http` extra. It ships with the core package as of v0.1.10:
374
406
  a regular install of the current release carries it.
375
407
 
376
408
  ```bash
377
- python -m pip install 'textflowkit[http,export]==0.1.11'
409
+ python -m pip install 'textflowkit[http,export]==0.1.12'
378
410
  textflowkit-ui
379
411
  ```
380
412
 
@@ -445,7 +477,10 @@ browser interface share the job contract without blocking a request.
445
477
 
446
478
  ## Status
447
479
 
448
- **v0.1.11 release.** Optional live streaming adds a transport-neutral
480
+ **v0.1.12 release.** Adds optional UI-only local Ollama proofreading and native
481
+ Windows installer packaging; public EXE distribution remains gated on unresolved
482
+ corresponding-source compliance review, with no public installer download link.
483
+ Existing optional live streaming provides a transport-neutral
449
484
  `StreamingSession` Python API, incremental transcript events, and authenticated
450
485
  loopback WebSockets (`/stream` on the developer HTTP API and `/api/stream` on the
451
486
  local UI), with a packaged browser microphone example. The native live capability
@@ -489,7 +524,7 @@ MCP speech, seven-format exports and completed resume; the v0.1.8 runtime fixes
489
524
  were independently checked through fresh-process CLI restart probes, real SQLite
490
525
  setup-failure tests, and the full Windows test suite. Those checks are not new
491
526
  individual-harness receipts. That is the previous releases' record, not evidence
492
- for v0.1.11.
527
+ for v0.1.12.
493
528
 
494
529
  The v0.1.6 release was the post-v0.1.5 review repair set: security hardening
495
530
  for media acquisition and the HTTP and MCP adapters, safer subtitle wrapping and
@@ -508,7 +543,7 @@ and both [core](https://pypi.org/project/textflowkit/0.1.6/) and
508
543
  [fonts](https://pypi.org/project/textflowkit-fonts/0.1.6/) PyPI projects are
509
544
  live — that is the v0.1.6 release's evidence, not a receipt for a later release.
510
545
  Everything from here to the end of this section is the v0.1.6 release's
511
- historical record as published: it is not re-verified for v0.1.11, whose separate release evidence is not supplied by these historical paragraphs.
546
+ historical record as published: it is not re-verified for v0.1.12, whose separate release evidence is not supplied by these historical paragraphs.
512
547
  Merged-main CI passed 16/16 on the tagged commit; the published wheel and
513
548
  sdist digests match the GitHub release assets and their SHA-256 list; and a fresh
514
549
  Windows Python 3.12 install of `textflowkit[export,mcp,http]==0.1.6` from PyPI
@@ -545,3 +580,90 @@ limitation of liability.
545
580
 
546
581
  Issues and PRs welcome. Please read [LEGAL.md](https://github.com/scottconverse/textflowkit/blob/main/LEGAL.md) before adding a source
547
582
  adapter.
583
+
584
+
585
+ ## Optional local AI transcript cleanup (v0.1.12)
586
+
587
+ v0.1.12 adds **opt-in proofreading in the local browser UI only**. After a transcription finishes, choose an
588
+ installed local Ollama model and click **Proofread with local AI**. Cleanup never
589
+ runs automatically. Ollama and cleanup models are not bundled in the installer.
590
+ The optional default preference is `qwen3.5:9b` only if already installed; its
591
+ size/performance fit has not been verified. Otherwise choose an installed local
592
+ model explicitly, such as `qwen3.8:27b-q4_K_M`. Larger models are never silently
593
+ selected. Install a model yourself through Ollama when needed; TextFlowKit does
594
+ not pull models, enable cloud tags, or use a paid provider.
595
+
596
+ The original transcript, job JSON, original copy button, search, and all existing
597
+ exports remain unchanged. Choose **Original only** or compare **source original
598
+ (left) / AI corrected (right)** in timestamp-anchored rows. Use **Copy corrected
599
+ text** or **Save corrected TXT** for the separate AI variant. The comparison
600
+ proofreads original source speech, not an optional translation. AI can make
601
+ plausible but wrong corrections, including names and facts: review against the
602
+ original and audio before using it. Prompt instructions reduce errors but do not
603
+ guarantee accuracy or resistance to instructions embedded in speech.
604
+
605
+ Corrected segments retain source start/end timestamps and stable zero-based
606
+ original segment indices. They have no inherited word alignment or translation;
607
+ **corrected word timing is not verified**. A separate persisted variant records
608
+ local provider, requested/returned model, UTC completion time, endpoint, successful
609
+ `done_reason=stop`, policy version and original SHA-256. If original job JSON
610
+ changes, its correction is invalidated. No partial replacement is published: bad,
611
+ truncated, missing, duplicated, reordered or extra segments fail the entire attempt.
612
+ A failed retry retains an earlier fully validated variant only if its original
613
+ hash still matches.
614
+
615
+ Cleanup uses a separate SQLite file named `<job database filename>.cleanup.sqlite3`
616
+ beside `TEXTFLOWKIT_DB` (or the UI default database). Include it when backing up UI
617
+ data; it contains transcript text and provenance. The canonical job store is never
618
+ updated by cleanup. Reloading/reopening a completed job retrieves its saved variant,
619
+ even if Ollama is offline. Model selection is per attempt; it is not a global
620
+ transcription/translation model setting.
621
+
622
+ Configuration is process-local environment, consistent with the existing UI:
623
+
624
+ - `TEXTFLOWKIT_CLEANUP_OLLAMA_URL`: default `http://127.0.0.1:11434`; only HTTP on
625
+ a literal loopback IP and explicit port is accepted (IPv6 `[::1]` also works).
626
+ DNS names, credentials, other paths, remote hosts and redirects are refused;
627
+ proxy environment variables are ignored by the cleanup client.
628
+ - `TEXTFLOWKIT_CLEANUP_MODEL`: optional preferred installed local tag; defaults
629
+ to `qwen3.5:9b`. If absent from installed tags, explicit selection is required.
630
+ Cloud tags and Ollama remote-model metadata are refused.
631
+
632
+ One cleanup runs at a time; the browser polls a background worker and remains
633
+ usable. Limits: 2,000 segments, 120,000 source characters, 60 chunks, at most
634
+ 1,000 UTF-8 encoded bytes per chunk and 40 segments per chunk. A small read-only
635
+ neighboring context helps with sentences spanning segments without merging them.
636
+ Generation requests use temperature 0, thinking disabled, context 8,192 and at
637
+ most 4,096 generated tokens per chunk. Requests have a 180-second socket timeout,
638
+ bounded response reads (1 MiB), and strict 64 KiB model JSON limits. The overall
639
+ work budget remains 600 seconds, checked between requests and reads; a blocking
640
+ socket operation can take up to its remaining request timeout before failure is
641
+ observed. Oversize or timeout failures leave the original available.
642
+
643
+ Normal UI shutdown drains an active cleanup (it can take several minutes); there
644
+ is no cleanup cancellation button. Abrupt process exit leaves no partial variant;
645
+ an interrupted running lease becomes retryable after at most 785 seconds from its
646
+ start. Cleanup does not restart Ollama or stop/unload other models. Model text is
647
+ rendered with DOM text nodes, never HTML. Cleanup adds no Python dependency,
648
+ telemetry, cloud provider or network destination beyond the configured local
649
+ Ollama service. Existing media acquisition/translation network behavior is separate.
650
+
651
+ ### Candidate validation status
652
+
653
+ The first cold full-UI attempt ended with a generic error and produced no variant;
654
+ the original remained intact. A subsequent hot 39-segment run returned zero text
655
+ edits despite clear source spelling errors, so it was not useful cleanup-quality
656
+ evidence. The final cold run began with the model explicitly unloaded and
657
+ completed all 39 segments in three chunks at
658
+ 2026-10-16 17:39:52 UTC. It used matching requested/returned
659
+ `qwen3.8:27b-q4_K_M` and changed four segments. The original SQLite JSON matched
660
+ the source file, with segment IDs and timestamps preserved. The in-app-browser
661
+ side-by-side comparison was visible, and **Save corrected TXT** produced a
662
+ 2,516-byte file whose SHA-256 matched the validated variant.
663
+
664
+ Observed edits included “guardrails,” “precludes,” and punctuation. “Fundamental”
665
+ and “victims” were plausible guesses, not verified against the audio. This is
666
+ measured evidence that the local full workflow completed and saved its separate
667
+ variant for this run; it does not establish transcription accuracy or general
668
+ cleanup quality. Review every correction against the audio. This is local workflow evidence,
669
+ not an audio-accuracy certification.
@@ -1,6 +1,6 @@
1
1
  # Developer and integration manual
2
2
 
3
- Current release: [v0.1.11](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.11).
3
+ Current release: [v0.1.12](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.12).
4
4
  Start with the [user manual](user-manual.md) for everyday use. Harness versions
5
5
  in the compatibility table below identify **historical test sessions**, not
6
6
  the version of TextFlowKit currently published.
@@ -22,6 +22,48 @@ API and WebSockets are ephemeral and bypass durable job submission.
22
22
  HTTP ───────────►└──────────────────────┘
23
23
  ```
24
24
 
25
+ ## Windows desktop installer (v0.1.12; public EXE pending)
26
+
27
+ The Windows x86_64 installer packages the existing browser interface for 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. Its bundle includes private embeddable CPython, the UI and HTTP, export, and streaming dependencies, the pinned Whistle model and runtime, and ffmpeg, ffprobe, and Node. It requires no separately installed Python, WSL, or Docker. The Python package remains supported for developers and integrations; Docker remains a separate operator deployment example.
28
+
29
+ The setup installs per user, adds a Start Menu entry, and offers an
30
+ optional desktop shortcut. Launching it will start the local server and open the
31
+ existing UI at localhost. Administrator rights are not normally required; the
32
+ installer is designed not to change global `PATH` or auto-update. The prebundled
33
+ Whistle assets and media binaries mean local file jobs need no first-use asset
34
+ download; URL media still needs network access. The default Whistle engine
35
+ supports only these seven advertised languages: `en`, `de`, `fr`, `es`, `it`,
36
+ `nl`, and `pl`.
37
+
38
+ UI data is designed to stay outside the install directory and be preserved on
39
+ upgrade and uninstall. Before either operation, stop the UI server with **Stop
40
+ server** and wait for it to exit. The candidate will block while that server is
41
+ running rather than force-kill it; the stop action drains active jobs, so cancel a
42
+ job first if it should not finish. The installer does not bundle optional
43
+ `openai-whisper` or diarization dependencies; those documented optional features
44
+ remain available to Python package users who install and configure the required
45
+ dependencies separately. Streaming dependencies are bundled, but streaming
46
+ remains opt-in, and physical browser microphone capture has not been verified.
47
+ The installer bundle includes third-party license and notice files,
48
+ including FFmpeg's LGPL notices and corresponding-source information. The exact
49
+ notices and source-distribution details must be checked against the final binaries
50
+ before publication. The candidate is unsigned, so Windows may show a SmartScreen
51
+ warning.
52
+
53
+ ```mermaid
54
+ flowchart LR
55
+ Setup[Per-user Windows x86_64 installer candidate] --> Runtime[Private embeddable CPython and bundled components]
56
+ Shortcut[Start Menu or optional desktop shortcut] --> Server[Local server at 127.0.0.1]
57
+ Runtime --> Server
58
+ Server <--> Browser[Existing browser UI at localhost]
59
+ Server --> Core[Existing HTTP adapter and shared TextFlowKit core]
60
+ Core --> Data[Per-user jobs, uploads, transcripts, and outputs outside install folder]
61
+ ```
62
+
63
+ This is a locally built and tested packaging path for the local UI; it does not turn the public
64
+ static website into a hosted transcription service or change the developer API
65
+ contracts.
66
+
25
67
  ## Resuming and batching
26
68
 
27
69
  `textflowkit transcribe --resume` reuses completed work, and
@@ -509,7 +551,7 @@ observation rather than forwarding the caller's header, and keep
509
551
 
510
552
  ## Live microphone streaming (`/stream`, opt-in)
511
553
 
512
- In v0.1.11, native live streaming supports **Windows x86_64 only**. Other live
554
+ In v0.1.12, native live streaming supports **Windows x86_64 only**. Other live
513
555
  platforms are unsupported; existing standalone defaults and platform support are
514
556
  unchanged. Physical browser microphone capture was not verified. The public site
515
557
  is static documentation and serves no streams. Both local server surfaces can
@@ -520,7 +562,7 @@ exist and a connection is refused before any session is allocated - and it needs
520
562
  `streaming` extra (`websockets`).
521
563
 
522
564
  ```powershell
523
- python -m pip install "textflowkit[streaming]==0.1.11"
565
+ python -m pip install "textflowkit[streaming]==0.1.12"
524
566
  # Native Windows PowerShell:
525
567
  $env:TEXTFLOWKIT_API_TOKEN="choose-a-long-random-token"
526
568
  $env:TEXTFLOWKIT_STREAMING="1"
@@ -560,7 +602,7 @@ supplies FastAPI and uvicorn, and adds no new dependency). It has no public site
560
602
  of its own: it is a local app, not a hosted service.
561
603
 
562
604
  ```bash
563
- python -m pip install 'textflowkit[http,export]==0.1.11'
605
+ python -m pip install 'textflowkit[http,export]==0.1.12'
564
606
  textflowkit-ui # serve on 127.0.0.1 and open a browser
565
607
  textflowkit-ui --no-browser --port 8901
566
608
  ```
@@ -943,3 +985,27 @@ job id immediately means:
943
985
  By default the job store is in-memory and bounded (`max_jobs=200`, terminal
944
986
  jobs evicted first). Set `TEXTFLOWKIT_DB` to use the durable SQLite store for
945
987
  restart-safe jobs and checkpoints. The SQLite store assumes one owning process.
988
+
989
+ ## UI-only proofreading routes (v0.1.12)
990
+
991
+ These routes belong to the local UI session gate, not the developer HTTP or MCP
992
+ API. POST requires the existing `x-textflowkit-ui-capability` header. Host, peer
993
+ and Origin remain subject to the existing UI restrictions.
994
+
995
+ | Route | Behavior |
996
+ |---|---|
997
+ | `GET /ui/cleanup/models` | Installed local tags only; selected preference only if installed; never pulls models |
998
+ | `POST /ui/jobs/{id}/cleanup` | Body `{"model":"installed-local-tag"}` (max 4 KiB); completed jobs only; 202 admitted, 409 busy/not complete, 422 model/config/input error |
999
+ | `GET /ui/jobs/{id}/cleanup` | `none`, `running`, `done`, `error` or `stale`; fully validated separate variant and provenance when available |
1000
+ | `GET /ui/jobs/{id}/cleanup/download` | Valid current variant as plain TXT attachment; 409 if none/stale |
1001
+
1002
+ Cleanup does not modify existing `/api` routes, original job JSON or original
1003
+ downloads. Polling is background and job-scoped. There is no cancel endpoint.
1004
+ See the user manual for time/token/output limits, crash lease expiry, local-only
1005
+ endpoint rules and human review requirements.
1006
+
1007
+ A cold local full-UI verification (model unloaded before start) completed 39
1008
+ segments in three chunks; four segments changed. The original JSON and segment
1009
+ IDs/timestamps were preserved, and visible comparison plus corrected TXT save
1010
+ were verified. This validates one workflow run, not accuracy. Review against
1011
+ audio; AI guesses are not audio-verified.