textflowkit 0.1.10__tar.gz → 0.1.11__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 (217) hide show
  1. {textflowkit-0.1.10 → textflowkit-0.1.11}/CHANGELOG.md +38 -1
  2. {textflowkit-0.1.10 → textflowkit-0.1.11}/CONTRIBUTING.md +7 -1
  3. {textflowkit-0.1.10 → textflowkit-0.1.11}/PKG-INFO +62 -25
  4. {textflowkit-0.1.10 → textflowkit-0.1.11}/README.md +55 -24
  5. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/adapters.md +45 -3
  6. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/architecture.md +27 -1
  7. textflowkit-0.1.11/docs/assets/live-streaming-flow.svg +50 -0
  8. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/index.html +12 -7
  9. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/install.md +21 -2
  10. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/release-checklist.md +25 -1
  11. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/roadmap.md +16 -1
  12. textflowkit-0.1.11/docs/streaming.md +514 -0
  13. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/user-manual.md +43 -8
  14. {textflowkit-0.1.10 → textflowkit-0.1.11}/pyproject.toml +8 -2
  15. textflowkit-0.1.11/src/textflowkit/__init__.py +41 -0
  16. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/adapters/http_server.py +258 -2
  17. textflowkit-0.1.11/src/textflowkit/adapters/streaming_ws.py +1276 -0
  18. textflowkit-0.1.11/src/textflowkit/core/stream_worker.py +227 -0
  19. textflowkit-0.1.11/src/textflowkit/core/streaming.py +1198 -0
  20. textflowkit-0.1.11/src/textflowkit/core/streaming_assets.py +542 -0
  21. textflowkit-0.1.11/src/textflowkit/core/streaming_events.py +330 -0
  22. textflowkit-0.1.11/src/textflowkit/core/streaming_process.py +520 -0
  23. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/ui/app.py +134 -2
  24. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/ui/launcher.py +25 -0
  25. textflowkit-0.1.11/src/textflowkit/ui/static/streaming-capture-worklet.js +156 -0
  26. textflowkit-0.1.11/src/textflowkit/ui/static/streaming-example.html +699 -0
  27. textflowkit-0.1.11/tests/test_streaming_assets.py +320 -0
  28. textflowkit-0.1.11/tests/test_streaming_browser_lifecycle.py +1347 -0
  29. textflowkit-0.1.11/tests/test_streaming_core.py +654 -0
  30. textflowkit-0.1.11/tests/test_streaming_example.py +371 -0
  31. textflowkit-0.1.11/tests/test_streaming_repairs.py +950 -0
  32. textflowkit-0.1.11/tests/test_streaming_transport.py +837 -0
  33. textflowkit-0.1.11/tests/test_streaming_u5_repairs.py +917 -0
  34. textflowkit-0.1.11/tests/test_streaming_ui_integration.py +190 -0
  35. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_ui_packaging.py +13 -2
  36. textflowkit-0.1.10/src/textflowkit/__init__.py +0 -8
  37. {textflowkit-0.1.10 → textflowkit-0.1.11}/.dockerignore +0 -0
  38. {textflowkit-0.1.10 → textflowkit-0.1.11}/.env.example +0 -0
  39. {textflowkit-0.1.10 → textflowkit-0.1.11}/.gitattributes +0 -0
  40. {textflowkit-0.1.10 → textflowkit-0.1.11}/.github/dependabot.yml +0 -0
  41. {textflowkit-0.1.10 → textflowkit-0.1.11}/.github/workflows/ci.yml +0 -0
  42. {textflowkit-0.1.10 → textflowkit-0.1.11}/.github/workflows/publish-pypi.yml +0 -0
  43. {textflowkit-0.1.10 → textflowkit-0.1.11}/.gitignore +0 -0
  44. {textflowkit-0.1.10 → textflowkit-0.1.11}/.pre-commit-config.yaml +0 -0
  45. {textflowkit-0.1.10 → textflowkit-0.1.11}/Dockerfile +0 -0
  46. {textflowkit-0.1.10 → textflowkit-0.1.11}/LEGAL.md +0 -0
  47. {textflowkit-0.1.10 → textflowkit-0.1.11}/LICENSE +0 -0
  48. {textflowkit-0.1.10 → textflowkit-0.1.11}/SECURITY.md +0 -0
  49. {textflowkit-0.1.10 → textflowkit-0.1.11}/compose.yaml +0 -0
  50. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/.nojekyll +0 -0
  51. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/404.html +0 -0
  52. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/assets/architecture-overview.svg +0 -0
  53. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/assets/local-ui-flow.svg +0 -0
  54. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/assets/whistle-resume.svg +0 -0
  55. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/site-deployment.md +0 -0
  56. {textflowkit-0.1.10 → textflowkit-0.1.11}/docs/sources.md +0 -0
  57. {textflowkit-0.1.10 → textflowkit-0.1.11}/scripts/fetch_published_fonts.py +0 -0
  58. {textflowkit-0.1.10 → textflowkit-0.1.11}/scripts/smoke_installed_wheel.py +0 -0
  59. {textflowkit-0.1.10 → textflowkit-0.1.11}/scripts/smoke_live_youtube.py +0 -0
  60. {textflowkit-0.1.10 → textflowkit-0.1.11}/scripts/verify_readme_release.py +0 -0
  61. {textflowkit-0.1.10 → textflowkit-0.1.11}/scripts/verify_release_ci.py +0 -0
  62. {textflowkit-0.1.10 → textflowkit-0.1.11}/scripts/verify_release_versions.py +0 -0
  63. {textflowkit-0.1.10 → textflowkit-0.1.11}/scripts/write_release_manifest.py +0 -0
  64. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/adapters/__init__.py +0 -0
  65. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/adapters/mcp_server.py +0 -0
  66. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/assets/README.md +0 -0
  67. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/assets/selftest-speech.wav +0 -0
  68. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/cli.py +0 -0
  69. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/__init__.py +0 -0
  70. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/batch.py +0 -0
  71. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/bind.py +0 -0
  72. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/cancel.py +0 -0
  73. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/checkpoint.py +0 -0
  74. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/diarize.py +0 -0
  75. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/engine.py +0 -0
  76. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/executor.py +0 -0
  77. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/jobs.py +0 -0
  78. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/model.py +0 -0
  79. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/paths.py +0 -0
  80. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/pipeline.py +0 -0
  81. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/retrieval.py +0 -0
  82. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/runner.py +0 -0
  83. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/service.py +0 -0
  84. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/sqlite_store.py +0 -0
  85. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/startup.py +0 -0
  86. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/submission.py +0 -0
  87. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/timeutil.py +0 -0
  88. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/translate.py +0 -0
  89. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/whistle.py +0 -0
  90. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/core/whistle_assets.py +0 -0
  91. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/render/__init__.py +0 -0
  92. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/render/_cue_layout.py +0 -0
  93. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/render/_cue_text.py +0 -0
  94. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/render/_rename_excl.py +0 -0
  95. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/render/_rename_noreplace.py +0 -0
  96. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/render/docx.py +0 -0
  97. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/render/markdown.py +0 -0
  98. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/render/pdf.py +0 -0
  99. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/render/srt.py +0 -0
  100. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/render/txt.py +0 -0
  101. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/render/vtt.py +0 -0
  102. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/sources/__init__.py +0 -0
  103. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/sources/acquire.py +0 -0
  104. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/sources/detect.py +0 -0
  105. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/sources/scratch.py +0 -0
  106. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/ui/__init__.py +0 -0
  107. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/ui/capabilities.py +0 -0
  108. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/ui/ownership.py +0 -0
  109. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/ui/paths.py +0 -0
  110. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/ui/security.py +0 -0
  111. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/ui/static/app.css +0 -0
  112. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/ui/static/app.js +0 -0
  113. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/ui/static/index.html +0 -0
  114. {textflowkit-0.1.10 → textflowkit-0.1.11}/src/textflowkit/ui/uploads.py +0 -0
  115. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/__init__.py +0 -0
  116. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/ollama_stub.py +0 -0
  117. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_acquire.py +0 -0
  118. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_adapters.py +0 -0
  119. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_admission_ownership.py +0 -0
  120. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_atomic_resume.py +0 -0
  121. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_atomic_resume_aba.py +0 -0
  122. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_batch.py +0 -0
  123. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_batch_item_boundary.py +0 -0
  124. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_batch_resume_shared.py +0 -0
  125. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_bind.py +0 -0
  126. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_cancellation_finalization.py +0 -0
  127. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_checkpoint.py +0 -0
  128. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_checkpoint_single_copy.py +0 -0
  129. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_cli.py +0 -0
  130. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_cli_batch_feedback.py +0 -0
  131. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_cli_owning_recovery.py +0 -0
  132. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_cli_resume_batch.py +0 -0
  133. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_cli_stage_feedback.py +0 -0
  134. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_cli_stdout_format.py +0 -0
  135. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_confined_decoder_boundary.py +0 -0
  136. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_confined_indirect_media.py +0 -0
  137. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_confined_resume_boundary.py +0 -0
  138. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_container_example.py +0 -0
  139. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_cue_layout.py +0 -0
  140. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_diarize.py +0 -0
  141. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_diarize_example_flags.py +0 -0
  142. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_diarize_token_docs.py +0 -0
  143. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_docx_publication_identity.py +0 -0
  144. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_done_output_integrity.py +0 -0
  145. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_empty_formats_resume.py +0 -0
  146. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_engine_adapters.py +0 -0
  147. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_engine_cache.py +0 -0
  148. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_engine_faster.py +0 -0
  149. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_engine_quiet.py +0 -0
  150. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_executor.py +0 -0
  151. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_executor_store_failure.py +0 -0
  152. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_export.py +0 -0
  153. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_export_file_mode.py +0 -0
  154. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_export_preflight.py +0 -0
  155. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_faster_whisper_docs.py +0 -0
  156. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_fetch_published_fonts.py +0 -0
  157. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_font_notices.py +0 -0
  158. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_http_host_boundary.py +0 -0
  159. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_http_trusted_proxy.py +0 -0
  160. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_job_progress.py +0 -0
  161. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_jobs.py +0 -0
  162. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_landing_commands.py +0 -0
  163. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_landing_page.py +0 -0
  164. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_legal_summary.py +0 -0
  165. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_linux_no_hardlink.py +0 -0
  166. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_live_smoke_script.py +0 -0
  167. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_macos_no_hardlink.py +0 -0
  168. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_mcp_batch_cookie_docs.py +0 -0
  169. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_mcp_http_boundary.py +0 -0
  170. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_mcp_protocol_cleanliness.py +0 -0
  171. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_mcp_terminal_guidance.py +0 -0
  172. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_mcp_tool_descriptions.py +0 -0
  173. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_mcp_work_root.py +0 -0
  174. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_model.py +0 -0
  175. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_partial_output_resume.py +0 -0
  176. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_partial_pdf_resume.py +0 -0
  177. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_paths.py +0 -0
  178. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_pipeline_integrity.py +0 -0
  179. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_pipeline_resume_setup.py +0 -0
  180. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_production_browser_cookies.py +0 -0
  181. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_publish_ci_gate.py +0 -0
  182. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_publish_fonts_wiring.py +0 -0
  183. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_publish_manifest_wiring.py +0 -0
  184. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_publish_workflow_gate.py +0 -0
  185. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_readme_layout.py +0 -0
  186. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_readme_release_guard.py +0 -0
  187. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_release_boundaries.py +0 -0
  188. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_release_manifest.py +0 -0
  189. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_release_surfaces.py +0 -0
  190. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_render.py +0 -0
  191. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_retrieval.py +0 -0
  192. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_sdist_allowlist.py +0 -0
  193. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_service_profile.py +0 -0
  194. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_site_not_found.py +0 -0
  195. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_sources.py +0 -0
  196. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_stage_reuse_resume.py +0 -0
  197. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_startup_recovery.py +0 -0
  198. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_stdio_protocol.py +0 -0
  199. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_submission.py +0 -0
  200. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_submission_validation.py +0 -0
  201. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_translate.py +0 -0
  202. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_translate_completeness.py +0 -0
  203. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_ui_assets_and_capabilities.py +0 -0
  204. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_ui_consoleless_logging.py +0 -0
  205. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_ui_existing_routes_unchanged.py +0 -0
  206. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_ui_launcher.py +0 -0
  207. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_ui_ownership_and_shutdown.py +0 -0
  208. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_ui_real_serve.py +0 -0
  209. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_ui_security.py +0 -0
  210. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_ui_submission_and_download.py +0 -0
  211. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_ui_uploads.py +0 -0
  212. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_verify_release_versions.py +0 -0
  213. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_whistle_assets.py +0 -0
  214. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_whistle_defaults.py +0 -0
  215. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_whistle_engine.py +0 -0
  216. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_whistle_job_resume.py +0 -0
  217. {textflowkit-0.1.10 → textflowkit-0.1.11}/tests/test_windows_no_hardlink.py +0 -0
@@ -1,5 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.1.11 — 2026-10-06
4
+
5
+ Optional native live streaming supports **Windows x86_64 only**. Core version:
6
+ 0.1.11; unchanged optional fonts: 0.1.6. Existing standalone Whistle defaults,
7
+ file/URL jobs, CLI, and MCP behavior are unchanged. The public site remains static
8
+ documentation and serves no streams. Local source validation does not establish
9
+ published-package verification or cross-platform live support.
10
+
11
+
12
+ ### Added
13
+
14
+ - **Public `StreamingSession` API.** Bounded PCM feed, typed incremental events,
15
+ flush/finish, cancellation, canonical final `Transcript`, and context-manager
16
+ cleanup. One owned native child per session binds directly to the separately
17
+ pinned `libneedle3.dll`; no upstream Python SDK or telemetry module is loaded.
18
+ Live sessions are ephemeral, with no replay or durable resume.
19
+ - **Live microphone streaming (opt-in, loopback-only).** When
20
+ `TEXTFLOWKIT_STREAMING=1` is set, the developer HTTP app serves a `/stream`
21
+ WebSocket and the local UI serves `/api/stream`, both transcribing audio as it
22
+ arrives. A runnable, self-hosted browser example is at `/streaming-example`
23
+ (and `/api/streaming-example` under the UI); its `AudioWorklet` resamples any
24
+ device rate to 16 kHz mono with continuous phase. Off by default: with the
25
+ switch unset the endpoint does not exist. The standalone `textflowkit` CLI is
26
+ unaffected — it does not open a microphone or a streaming socket. Requires the
27
+ new `streaming` extra (`pip install "textflowkit[streaming]"`), which adds the
28
+ `websockets` dependency. Auth is fail-closed: the UI accepts only its own origin
29
+ and capability, the standalone API requires the API token (even in developer
30
+ mode), and a separate origin may stream only if the operator lists it in
31
+ `TEXTFLOWKIT_STREAMING_ORIGINS` (a browser needs its own origin listed, including
32
+ the standalone example's). See [docs/streaming.md](docs/streaming.md).
33
+ **Bounded live runs verified on this machine's native engine** — 65 s and 300 s
34
+ through the product core on Windows x86_64. A separate assembled UI WebSocket
35
+ run fed prerecorded PCM at real time for 12 s. Browser lifecycle and resampling
36
+ checks used fake audio; **physical microphone capture was not verified**. Only
37
+ English was measured natively; the other six accepted languages and live
38
+ Linux/macOS were not exercised. No public remote streaming is provided.
39
+
3
40
  ## v0.1.10 — 2026-10-06
4
41
 
5
42
  **The local browser interface ships.** The loopback-only browser workspace
@@ -51,7 +88,7 @@ security boundaries. A **native Windows** machine, in a real browser, proved the
51
88
  workspace end to end (drop a file, submit, download, stop). That is one platform's
52
89
  browser proof, **not** a live Linux or macOS UI run — those platforms are covered
53
90
  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
91
+ release gate. **No live optional-backend (translation or
55
92
  diarization) run through the UI is claimed.** The engine and packaging changes of
56
93
  v0.1.9 are unchanged by this release.
57
94
 
@@ -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.11
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.11](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.11).**
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.11/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.11, 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.11"
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 ·
@@ -296,7 +328,7 @@ textflowkit export ./transcript.json --format vtt
296
328
  needs no PyTorch, so a fresh `pip install textflowkit` stays small and pulls no
297
329
  torch; `openai-whisper` is an explicitly selectable opt-in engine.
298
330
 
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)
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)
300
332
 
301
333
  - **CPU only, no torch.** It runs a pinned native binary and downloads one pinned
302
334
  model on first use. Naming a GPU device is refused rather than silently
@@ -313,7 +345,7 @@ torch; `openai-whisper` is an explicitly selectable opt-in engine.
313
345
  of context on each side, so every standalone clip is ≤ 30 seconds (the native
314
346
  CLI's limit). Overlap words are selected by core midpoint rather than text
315
347
  deduplication, so repeated spoken phrases are preserved.
316
- - **Streaming is not used.** The native `--audio-stream` mode failed its
348
+ - **Standalone streaming is not used.** The native `--audio-stream` mode failed its
317
349
  coverage and is never passed; only the committed standalone output is parsed.
318
350
  - **Durable block resume.** With `TEXTFLOWKIT_DB` set, a long run writes partial
319
351
  per-block checkpoints; a resume checks the source and decoded-WAV hashes and the
@@ -407,7 +439,7 @@ its own beyond the `http` extra. It ships with the core package as of v0.1.10:
407
439
  a regular install of the current release carries it.
408
440
 
409
441
  ```bash
410
- python -m pip install 'textflowkit[http,export]==0.1.10'
442
+ python -m pip install 'textflowkit[http,export]==0.1.11'
411
443
  textflowkit-ui
412
444
  ```
413
445
 
@@ -478,29 +510,34 @@ browser interface share the job contract without blocking a request.
478
510
 
479
511
  ## Status
480
512
 
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.
513
+ **v0.1.11 release.** Optional live streaming adds a transport-neutral
514
+ `StreamingSession` Python API, incremental transcript events, and authenticated
515
+ loopback WebSockets (`/stream` on the developer HTTP API and `/api/stream` on the
516
+ local UI), with a packaged browser microphone example. The native live capability
517
+ supports **Windows x86_64 only** and uses one owned child with a separately pinned
518
+ `libneedle3.dll`. The `streaming` extra supplies the WebSocket dependency;
519
+ `TEXTFLOWKIT_STREAMING=1` enables the server routes. Streaming is off by default.
520
+
521
+ Existing file and URL transcription, CLI, MCP, durable jobs, and local browser
522
+ workspace defaults remain unchanged. Whistle stays the CPU-only standalone default;
523
+ `openai-whisper` remains an explicit opt-in engine. The local browser workspace
524
+ introduced in v0.1.10 still needs only the `http` extra for its ordinary job flow.
525
+ Fonts remain 0.1.6. Live sessions are ephemeral and have no durable resume.
526
+
527
+ **Streaming evidence.** Local English PCM runs exercised the native core for 65 s
528
+ and 300 s; a separate assembled UI WebSocket run fed prerecorded PCM at real time
529
+ for 12 s and returned incremental events and a final transcript. Browser lifecycle
530
+ and resampling checks used fake audio. Physical browser microphone capture, live
531
+ Linux/macOS, and the six other accepted languages were not verified. The public
532
+ website remains static documentation and serves no streaming endpoint. Local source
533
+ validation does not establish published-package or exact-commit CI results.
497
534
 
498
535
  **Verification limit.** The local browser interface is covered by an automated
499
536
  suite, and the UI's behavior was proved on a **native Windows** machine in a real
500
537
  browser. No live optional-backend (translation/diarization) run through the UI is
501
538
  claimed, and **no live Linux or macOS UI run was performed here** — those
502
539
  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
540
+ macOS is a separate release gate. Release publication uses the tag
504
541
  workflow, which requires successful exact-commit main CI before PyPI uploads and
505
542
  creates the public GitHub release only afterward. Check the linked release for
506
543
  artifacts and workflow status; local source verification is not a fresh
@@ -517,7 +554,7 @@ MCP speech, seven-format exports and completed resume; the v0.1.8 runtime fixes
517
554
  were independently checked through fresh-process CLI restart probes, real SQLite
518
555
  setup-failure tests, and the full Windows test suite. Those checks are not new
519
556
  individual-harness receipts. That is the previous releases' record, not evidence
520
- for v0.1.10.
557
+ for v0.1.11.
521
558
 
522
559
  The v0.1.6 release was the post-v0.1.5 review repair set: security hardening
523
560
  for media acquisition and the HTTP and MCP adapters, safer subtitle wrapping and
@@ -536,7 +573,7 @@ and both [core](https://pypi.org/project/textflowkit/0.1.6/) and
536
573
  [fonts](https://pypi.org/project/textflowkit-fonts/0.1.6/) PyPI projects are
537
574
  live — that is the v0.1.6 release's evidence, not a receipt for a later release.
538
575
  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.
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.
540
577
  Merged-main CI passed 16/16 on the tagged commit; the published wheel and
541
578
  sdist digests match the GitHub release assets and their SHA-256 list; and a fresh
542
579
  Windows Python 3.12 install of `textflowkit[export,mcp,http]==0.1.6` from PyPI
@@ -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.10](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.10).**
11
+ **Current release: [v0.1.11](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.11).**
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.10/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.11/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
@@ -91,6 +91,32 @@ means writing one source adapter, not another tool.
91
91
  For the job lifecycle, process ownership, checkpoints, and output publication,
92
92
  see [docs/architecture.md](https://github.com/scottconverse/textflowkit/blob/main/docs/architecture.md).
93
93
 
94
+ ## Live microphone streaming (opt-in)
95
+
96
+ In v0.1.11, live streaming supports **Windows x86_64 only**. When
97
+ `TEXTFLOWKIT_STREAMING=1` is set, the developer HTTP app serves a `/stream`
98
+ WebSocket and the local UI serves `/api/stream`, both transcribing a live microphone
99
+ as you speak. A **runnable, self-hosted browser example** ships at
100
+ `/streaming-example` (and `/api/streaming-example` under the UI): it captures with an
101
+ `AudioWorklet`, resamples any device rate to 16 kHz mono, and shows the transcript.
102
+ No CDN, no analytics, no external fetch. Requires the `streaming` extra:
103
+
104
+ ```bash
105
+ python -m pip install "textflowkit[streaming]==0.1.11"
106
+ ```
107
+
108
+ It is **off by default** — with the switch unset the endpoint does not exist — and
109
+ **loopback-only**: auth is fail-closed, so the UI accepts only its own origin and
110
+ capability, the standalone API requires `TEXTFLOWKIT_API_TOKEN` (even in developer
111
+ mode), and a separate origin — including the standalone browser example's own origin —
112
+ may stream only if listed in `TEXTFLOWKIT_STREAMING_ORIGINS`. The standalone
113
+ `textflowkit` CLI is unaffected: it does not open a microphone or a streaming socket.
114
+ **Bounded live runs are verified on the native engine here** — 65 s and 300 s
115
+ end-to-end on Windows x86_64; the transport and the browser resampler are covered by
116
+ tests, and a physical browser microphone has not yet been captured (the browser proof
117
+ drives the page against a fake audio device). See
118
+ [docs/streaming.md](https://github.com/scottconverse/textflowkit/blob/main/docs/streaming.md).
119
+
94
120
  ## Recognized sources
95
121
 
96
122
  YouTube · TikTok · Facebook · Instagram · Vimeo · Twitch · Bilibili · Rumble ·
@@ -237,7 +263,7 @@ textflowkit export ./transcript.json --format vtt
237
263
  needs no PyTorch, so a fresh `pip install textflowkit` stays small and pulls no
238
264
  torch; `openai-whisper` is an explicitly selectable opt-in engine.
239
265
 
240
- ![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)
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)
241
267
 
242
268
  - **CPU only, no torch.** It runs a pinned native binary and downloads one pinned
243
269
  model on first use. Naming a GPU device is refused rather than silently
@@ -254,7 +280,7 @@ torch; `openai-whisper` is an explicitly selectable opt-in engine.
254
280
  of context on each side, so every standalone clip is ≤ 30 seconds (the native
255
281
  CLI's limit). Overlap words are selected by core midpoint rather than text
256
282
  deduplication, so repeated spoken phrases are preserved.
257
- - **Streaming is not used.** The native `--audio-stream` mode failed its
283
+ - **Standalone streaming is not used.** The native `--audio-stream` mode failed its
258
284
  coverage and is never passed; only the committed standalone output is parsed.
259
285
  - **Durable block resume.** With `TEXTFLOWKIT_DB` set, a long run writes partial
260
286
  per-block checkpoints; a resume checks the source and decoded-WAV hashes and the
@@ -348,7 +374,7 @@ its own beyond the `http` extra. It ships with the core package as of v0.1.10:
348
374
  a regular install of the current release carries it.
349
375
 
350
376
  ```bash
351
- python -m pip install 'textflowkit[http,export]==0.1.10'
377
+ python -m pip install 'textflowkit[http,export]==0.1.11'
352
378
  textflowkit-ui
353
379
  ```
354
380
 
@@ -419,29 +445,34 @@ browser interface share the job contract without blocking a request.
419
445
 
420
446
  ## Status
421
447
 
422
- **v0.1.10 release.** Core, CLI, MCP, HTTP, and the local browser interface have
423
- automated coverage. This release **ships the local browser interface**
424
- (`textflowkit-ui`) in the core package: a loopback-only workspace that reuses the
425
- same pipeline, submission contract, and job store, with a durable store, cancel
426
- and resume, and a Windows desktop shortcut (`textflowkit-ui --create-shortcut`).
427
- It adds **no new dependency** beyond the existing `http` extra, so a regular
428
- `pip install 'textflowkit[http,export]==0.1.10'` carries it. The engine, CLI,
429
- Python, MCP, and HTTP surfaces are unchanged and there is **no endpoint-breaking
430
- change**. It builds on v0.1.9, which made **Whistle the default engine** — a
431
- native CPU-only transcriber that needs no PyTorch — and moved `openai-whisper` to
432
- the optional `whisper` extra, selected explicitly with `--engine whisper` or
433
- `engine="whisper"`. Legacy engine aliases are preserved, so older saved jobs and
434
- `transcribe()` calls still decode. Whistle refuses an unsupported platform,
435
- language, or GPU request instead of silently falling back; its engine's
436
- verification boundary is in [Whistle (default engine)](#whistle-default-engine)
437
- above.
448
+ **v0.1.11 release.** Optional live streaming adds a transport-neutral
449
+ `StreamingSession` Python API, incremental transcript events, and authenticated
450
+ loopback WebSockets (`/stream` on the developer HTTP API and `/api/stream` on the
451
+ local UI), with a packaged browser microphone example. The native live capability
452
+ supports **Windows x86_64 only** and uses one owned child with a separately pinned
453
+ `libneedle3.dll`. The `streaming` extra supplies the WebSocket dependency;
454
+ `TEXTFLOWKIT_STREAMING=1` enables the server routes. Streaming is off by default.
455
+
456
+ Existing file and URL transcription, CLI, MCP, durable jobs, and local browser
457
+ workspace defaults remain unchanged. Whistle stays the CPU-only standalone default;
458
+ `openai-whisper` remains an explicit opt-in engine. The local browser workspace
459
+ introduced in v0.1.10 still needs only the `http` extra for its ordinary job flow.
460
+ Fonts remain 0.1.6. Live sessions are ephemeral and have no durable resume.
461
+
462
+ **Streaming evidence.** Local English PCM runs exercised the native core for 65 s
463
+ and 300 s; a separate assembled UI WebSocket run fed prerecorded PCM at real time
464
+ for 12 s and returned incremental events and a final transcript. Browser lifecycle
465
+ and resampling checks used fake audio. Physical browser microphone capture, live
466
+ Linux/macOS, and the six other accepted languages were not verified. The public
467
+ website remains static documentation and serves no streaming endpoint. Local source
468
+ validation does not establish published-package or exact-commit CI results.
438
469
 
439
470
  **Verification limit.** The local browser interface is covered by an automated
440
471
  suite, and the UI's behavior was proved on a **native Windows** machine in a real
441
472
  browser. No live optional-backend (translation/diarization) run through the UI is
442
473
  claimed, and **no live Linux or macOS UI run was performed here** — those
443
474
  platforms are covered by automated tests only, and CI across Windows, Linux, and
444
- macOS is the coordinator's separate step. Release publication uses the tag
475
+ macOS is a separate release gate. Release publication uses the tag
445
476
  workflow, which requires successful exact-commit main CI before PyPI uploads and
446
477
  creates the public GitHub release only afterward. Check the linked release for
447
478
  artifacts and workflow status; local source verification is not a fresh
@@ -458,7 +489,7 @@ MCP speech, seven-format exports and completed resume; the v0.1.8 runtime fixes
458
489
  were independently checked through fresh-process CLI restart probes, real SQLite
459
490
  setup-failure tests, and the full Windows test suite. Those checks are not new
460
491
  individual-harness receipts. That is the previous releases' record, not evidence
461
- for v0.1.10.
492
+ for v0.1.11.
462
493
 
463
494
  The v0.1.6 release was the post-v0.1.5 review repair set: security hardening
464
495
  for media acquisition and the HTTP and MCP adapters, safer subtitle wrapping and
@@ -477,7 +508,7 @@ and both [core](https://pypi.org/project/textflowkit/0.1.6/) and
477
508
  [fonts](https://pypi.org/project/textflowkit-fonts/0.1.6/) PyPI projects are
478
509
  live — that is the v0.1.6 release's evidence, not a receipt for a later release.
479
510
  Everything from here to the end of this section is the v0.1.6 release's
480
- historical record as published: it is not re-verified for v0.1.10, whose separate release evidence is not supplied by these historical paragraphs.
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.
481
512
  Merged-main CI passed 16/16 on the tagged commit; the published wheel and
482
513
  sdist digests match the GitHub release assets and their SHA-256 list; and a fresh
483
514
  Windows Python 3.12 install of `textflowkit[export,mcp,http]==0.1.6` from PyPI
@@ -1,6 +1,6 @@
1
1
  # Developer and integration manual
2
2
 
3
- Current release: [v0.1.10](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.10).
3
+ Current release: [v0.1.11](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.11).
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.
@@ -8,7 +8,8 @@ the version of TextFlowKit currently published.
8
8
  textflowkit has one core and several thin doors. Nothing is duplicated between
9
9
  them: the CLI, the MCP server, the HTTP API, and the local browser
10
10
  interface (`textflowkit-ui`) all call `textflowkit.core.submission` and share one
11
- job model.
11
+ job model for file and URL transcription. The optional live `StreamingSession`
12
+ API and WebSockets are ephemeral and bypass durable job submission.
12
13
 
13
14
  ![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.](assets/architecture-overview.svg)
14
15
 
@@ -506,6 +507,47 @@ agree. So if you do leave it on, put it behind a proxy that appends its own
506
507
  observation rather than forwarding the caller's header, and keep
507
508
  `FORWARDED_ALLOW_IPS` narrow.
508
509
 
510
+ ## Live microphone streaming (`/stream`, opt-in)
511
+
512
+ In v0.1.11, native live streaming supports **Windows x86_64 only**. Other live
513
+ platforms are unsupported; existing standalone defaults and platform support are
514
+ unchanged. Physical browser microphone capture was not verified. The public site
515
+ is static documentation and serves no streams. Both local server surfaces can
516
+ carry a live microphone stream when
517
+ `TEXTFLOWKIT_STREAMING=1` is set: the developer HTTP app at `/stream`, and the UI at
518
+ `/api/stream`. It is **off by default** - with the switch unset the route does not
519
+ exist and a connection is refused before any session is allocated - and it needs the
520
+ `streaming` extra (`websockets`).
521
+
522
+ ```powershell
523
+ python -m pip install "textflowkit[streaming]==0.1.11"
524
+ # Native Windows PowerShell:
525
+ $env:TEXTFLOWKIT_API_TOKEN="choose-a-long-random-token"
526
+ $env:TEXTFLOWKIT_STREAMING="1"
527
+ textflowkit-http --streaming # ws://127.0.0.1:8767/stream
528
+ # or the documented import target directly - the WS bounds are NOT automatic here,
529
+ # the plain uvicorn line above would keep uvicorn's larger defaults and deflate on:
530
+ uvicorn textflowkit.adapters.http_server:app --host 127.0.0.1 --port 8767 `
531
+ --ws-max-size 32768 --ws-max-queue 5 --ws-per-message-deflate false --no-proxy-headers
532
+ ```
533
+
534
+ The launcher (`textflowkit-http --streaming`) applies those bounds for you; a direct
535
+ ASGI invocation only has them when the flags are passed. `--no-proxy-headers` keeps
536
+ a proxy header from rewriting the peer address the loopback check reads (the same
537
+ switch the proxy-identity section above discusses).
538
+
539
+ The endpoint is a plain version-1 JSON + PCM WebSocket: one `start`, binary audio
540
+ (16 kHz mono s16le, ≤ 32000 bytes/frame), then `finish` or `cancel`; the server sends
541
+ `ready`, `event`s, and exactly one terminal `final` or `error`. Sessions are
542
+ ephemeral - no job row, no resume, no reconnect. Auth is fail-closed and there is no
543
+ anonymous path: a non-browser client sends `Authorization: Bearer` (or `token` in the
544
+ start JSON); a browser the UI served sends the UI capability. The standalone
545
+ `/stream` may additionally admit exact extra origins from
546
+ `TEXTFLOWKIT_STREAMING_ORIGINS` (token-authenticated); the UI's own origin is never
547
+ widened by that list. Streaming is loopback-only even under
548
+ `TEXTFLOWKIT_ALLOW_REMOTE`. The full contract, lifecycle, limits, and a generic
549
+ integration recipe are in [streaming.md](streaming.md).
550
+
509
551
  ## Local browser interface (`textflowkit-ui`)
510
552
 
511
553
  `textflowkit-ui` is a fourth thin door beside the CLI, MCP, and HTTP entry
@@ -518,7 +560,7 @@ supplies FastAPI and uvicorn, and adds no new dependency). It has no public site
518
560
  of its own: it is a local app, not a hosted service.
519
561
 
520
562
  ```bash
521
- python -m pip install 'textflowkit[http,export]==0.1.10'
563
+ python -m pip install 'textflowkit[http,export]==0.1.11'
522
564
  textflowkit-ui # serve on 127.0.0.1 and open a browser
523
565
  textflowkit-ui --no-browser --port 8901
524
566
  ```
@@ -1,4 +1,4 @@
1
- # Architecture and job lifecycle
1
+ # Architecture and job lifecycle — v0.1.11
2
2
 
3
3
  This guide describes how textflowkit is put together and how a job moves through
4
4
  it. It is orientation for maintainers and integrators; it is not a deployment
@@ -26,6 +26,20 @@ a streamed upload, and a capability endpoint. It **ships in the core package as
26
26
  of v0.1.10** and adds no new dependency beyond the `http` extra. It is a local
27
27
  app: the published website is static documentation and never runs the pipeline.
28
28
 
29
+ Live streaming added in v0.1.11 is an optional **Windows x86_64 only** path:
30
+ `StreamingSession` drives one owned native child through direct `ctypes` bindings
31
+ to a separately pinned `libneedle3.dll`. Authenticated loopback WebSockets and a
32
+ packaged browser example sit above that core; no job row or resume is created.
33
+ Server routes are off unless `TEXTFLOWKIT_STREAMING=1` is set and need the
34
+ `streaming` extra. The existing standalone Whistle default and ordinary file/URL
35
+ job paths are unchanged. Physical microphone capture and live Linux/macOS were
36
+ not verified; the static public site does not run this path.
37
+
38
+ ![Optional Windows x86_64 streaming: bounded PCM passes through an authenticated loopback WebSocket to an ephemeral StreamingSession and one owned native child; incremental events return, finish flushes to a canonical Transcript, and cancel releases the session. No durable job or resume; off by default; physical microphone capture not verified; the public site serves no streams.](assets/live-streaming-flow.svg)
39
+
40
+ This separate live path bypasses durable job submission; the file/URL job
41
+ diagrams describe the existing standalone workflow.
42
+
29
43
  ### One owner per database
30
44
 
31
45
  The durable SQLite store is owned by exactly one process. `textflowkit-ui`
@@ -88,8 +102,19 @@ flowchart LR
88
102
  TR --> RENDER[Render and publish files]
89
103
  RUN --> STORE
90
104
  STORE --> READ[Shared paging and search]
105
+ MIC[Browser mic or programmatic client] -. opt-in .-> WS[WebSocket /stream or /api/stream]
106
+ WS --> SESSION[core.streaming StreamingSession]
107
+ SESSION --> WPROC[Owned stream_worker child, libneedle3]
108
+ WPROC --> SESSION
109
+ SESSION -. events .-> WS
91
110
  ```
92
111
 
112
+ Streaming is the one path that does **not** go through `core.submission`: a live
113
+ session is ephemeral, owns no job row, and is driven by its own transport-neutral
114
+ `StreamingSession`. It is off unless `TEXTFLOWKIT_STREAMING=1`. The dotted edges are
115
+ that opt-in, loopback-only path, running in parallel with the batch pipeline above
116
+ and sharing only the native engine library, never a job row.
117
+
93
118
  ## Components
94
119
 
95
120
  | Component | Source | Responsibility |
@@ -106,6 +131,7 @@ flowchart LR
106
131
  | Postprocessing | `core/diarize.py`, `core/translate.py` | Optional speaker assignment and translation |
107
132
  | Output | `render/` | Human-readable formats and canonical JSON; atomic file publication |
108
133
  | Retrieval | `core/retrieval.py` | Hidden filtering, time selection, paging, substring search |
134
+ | Live streaming | `core/streaming.py`, `core/stream_worker.py`, `adapters/streaming_ws.py` | Opt-in, loopback-only microphone stream: a transport-neutral session drives one owned native child over line JSON, fed by a guarded WebSocket. No job row, no resume. See [streaming.md](streaming.md). |
109
135
 
110
136
  ## Job lifecycle
111
137
 
@@ -0,0 +1,50 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1180 490" width="1180" height="490" role="img" aria-labelledby="streamTitle streamDesc" font-family="Inter, ui-sans-serif, system-ui, 'Segoe UI', sans-serif">
2
+ <title id="streamTitle">TextFlowKit v0.1.11 optional local live streaming</title>
3
+ <desc id="streamDesc">Windows x86_64 only, off by default. A browser AudioWorklet or programmatic PCM client feeds signed 16-bit little-endian mono 16000 Hz audio into an authenticated loopback WebSocket: /stream on the developer HTTP API or /api/stream on the UI. Origin, Host and peer checks guard the transport. StreamingSession bounds audio backlog at five seconds and defaults to one native session per process. One owned child binds directly to a separately pinned libneedle3.dll. Incremental committed text and a replacement provisional tail return to the client. Finish flushes accepted audio and returns a canonical Transcript; cancel or disconnect cleans up the owned child. No durable job, replay or resume. Existing standalone Whistle defaults remain unchanged. The public site serves no streams; physical microphone capture was not verified.</desc>
4
+ <defs><marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M 0 0 L 10 5 L 0 10 z" fill="#3b556e"/></marker></defs>
5
+ <style>
6
+ .title {fill:#14303f;font-size:24px;font-weight:700}
7
+ .head {fill:#14303f;font-size:18px;font-weight:700}
8
+ .body {fill:#3b556e;font-size:15px}
9
+ .note {fill:#5b7186;font-size:14px}
10
+ .edge {fill:none;stroke:#3b556e;stroke-width:2;marker-end:url(#arrow)}
11
+ </style>
12
+ <rect x="1" y="1" width="1178" height="488" rx="18" fill="#f7fafc" stroke="#d5e0e9"/>
13
+ <text x="30" y="42" class="title">Optional local live streaming — v0.1.11</text>
14
+ <text x="30" y="70" class="body">Windows x86_64 only · streaming extra + TEXTFLOWKIT_STREAMING=1 · off by default</text>
15
+ <rect x="30" y="105" width="250" height="150" rx="12" fill="#e0e7f8" stroke="#b8c7df"/>
16
+ <text x="46" y="133" class="head">Browser or PCM client</text>
17
+ <text x="46" y="161" class="body">AudioWorklet resampling</text>
18
+ <text x="46" y="186" class="body">16 kHz mono · s16le</text>
19
+ <text x="46" y="211" class="body">≤ 32000 bytes per frame</text>
20
+ <text x="46" y="236" class="body">Explicit Start / Stop / Cancel</text>
21
+ <path d="M 282 180 H 313" class="edge"/>
22
+ <rect x="315" y="105" width="250" height="150" rx="12" fill="#eef4f8" stroke="#b8c7df"/>
23
+ <text x="331" y="133" class="head">Loopback WebSocket</text>
24
+ <text x="331" y="161" class="body">/stream or /api/stream</text>
25
+ <text x="331" y="186" class="body">Token / UI capability auth</text>
26
+ <text x="331" y="211" class="body">Exact origin + Host + peer</text>
27
+ <text x="331" y="236" class="body">Bounded queues and sends</text>
28
+ <path d="M 567 180 H 598" class="edge"/>
29
+ <rect x="600" y="105" width="250" height="150" rx="12" fill="#dff3ea" stroke="#a6cdbc"/>
30
+ <text x="616" y="133" class="head">StreamingSession</text>
31
+ <text x="616" y="161" class="body">Transport-neutral core API</text>
32
+ <text x="616" y="186" class="body">≤ 5 s unprocessed audio</text>
33
+ <text x="616" y="211" class="body">Bounded events and history</text>
34
+ <text x="616" y="236" class="body">Default: 1 session / process</text>
35
+ <path d="M 852 180 H 883" class="edge"/>
36
+ <rect x="885" y="105" width="265" height="150" rx="12" fill="#dff3ea" stroke="#a6cdbc"/>
37
+ <text x="901" y="133" class="head">One owned native child</text>
38
+ <text x="901" y="161" class="body">Pinned libneedle3.dll</text>
39
+ <text x="901" y="186" class="body">Direct ctypes · shared model</text>
40
+ <text x="901" y="211" class="body">No upstream Python SDK</text>
41
+ <text x="901" y="236" class="body">Cleanup on cancel / disconnect</text>
42
+ <path d="M 1017 258 V 306 H 155 V 258" class="edge"/>
43
+ <rect x="235" y="284" width="700" height="39" rx="10" fill="#f7fafc"/>
44
+ <text x="250" y="309" class="body">Incremental events: append committed text + replace the provisional tail</text>
45
+ <rect x="30" y="347" width="1120" height="64" rx="12" fill="#fff8ea" stroke="#e2cc9e"/>
46
+ <text x="46" y="373" class="body">Finish: flush accepted PCM → canonical Transcript. Cancel / disconnect: release the owned session.</text>
47
+ <text x="46" y="397" class="body">Ephemeral stream: no durable job row, replay or resume. Existing standalone Whistle defaults stay unchanged.</text>
48
+ <text x="30" y="442" class="note">Evidence: 65 s / 300 s native core PCM runs; separate 12 s UI WebSocket PCM run. Physical mic not verified.</text>
49
+ <text x="30" y="466" class="note">This is a local app capability. The public website is static documentation and serves no streams.</text>
50
+ </svg>