textflowkit 0.1.8__tar.gz → 0.1.10__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.
- {textflowkit-0.1.8 → textflowkit-0.1.10}/.github/workflows/ci.yml +6 -2
- {textflowkit-0.1.8 → textflowkit-0.1.10}/CHANGELOG.md +123 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/Dockerfile +6 -4
- {textflowkit-0.1.8 → textflowkit-0.1.10}/PKG-INFO +193 -21
- {textflowkit-0.1.8 → textflowkit-0.1.10}/README.md +189 -19
- {textflowkit-0.1.8 → textflowkit-0.1.10}/compose.yaml +4 -3
- {textflowkit-0.1.8 → textflowkit-0.1.10}/docs/adapters.md +95 -12
- {textflowkit-0.1.8 → textflowkit-0.1.10}/docs/architecture.md +69 -8
- textflowkit-0.1.10/docs/assets/architecture-overview.svg +213 -0
- textflowkit-0.1.10/docs/assets/local-ui-flow.svg +155 -0
- textflowkit-0.1.10/docs/assets/whistle-resume.svg +164 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/docs/index.html +55 -9
- {textflowkit-0.1.8 → textflowkit-0.1.10}/docs/install.md +114 -27
- {textflowkit-0.1.8 → textflowkit-0.1.10}/docs/release-checklist.md +35 -8
- {textflowkit-0.1.8 → textflowkit-0.1.10}/docs/roadmap.md +42 -1
- {textflowkit-0.1.8 → textflowkit-0.1.10}/docs/site-deployment.md +10 -2
- textflowkit-0.1.10/docs/user-manual.md +470 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/pyproject.toml +20 -5
- textflowkit-0.1.10/scripts/smoke_installed_wheel.py +436 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/scripts/smoke_live_youtube.py +28 -9
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/__init__.py +1 -1
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/adapters/http_server.py +7 -5
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/adapters/mcp_server.py +29 -19
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/cli.py +158 -39
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/checkpoint.py +226 -23
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/engine.py +201 -62
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/pipeline.py +149 -14
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/runner.py +3 -2
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/submission.py +73 -6
- textflowkit-0.1.10/src/textflowkit/core/whistle.py +1198 -0
- textflowkit-0.1.10/src/textflowkit/core/whistle_assets.py +505 -0
- textflowkit-0.1.10/src/textflowkit/ui/__init__.py +13 -0
- textflowkit-0.1.10/src/textflowkit/ui/app.py +579 -0
- textflowkit-0.1.10/src/textflowkit/ui/capabilities.py +195 -0
- textflowkit-0.1.10/src/textflowkit/ui/launcher.py +686 -0
- textflowkit-0.1.10/src/textflowkit/ui/ownership.py +602 -0
- textflowkit-0.1.10/src/textflowkit/ui/paths.py +179 -0
- textflowkit-0.1.10/src/textflowkit/ui/security.py +200 -0
- textflowkit-0.1.10/src/textflowkit/ui/static/app.css +285 -0
- textflowkit-0.1.10/src/textflowkit/ui/static/app.js +756 -0
- textflowkit-0.1.10/src/textflowkit/ui/static/index.html +226 -0
- textflowkit-0.1.10/src/textflowkit/ui/uploads.py +247 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_adapters.py +9 -5
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_admission_ownership.py +2 -2
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_atomic_resume.py +9 -9
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_atomic_resume_aba.py +3 -3
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_batch.py +5 -2
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_batch_item_boundary.py +2 -2
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_batch_resume_shared.py +3 -2
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_checkpoint.py +77 -5
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_checkpoint_single_copy.py +9 -3
- textflowkit-0.1.10/tests/test_cli.py +228 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_cli_owning_recovery.py +5 -5
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_cli_stage_feedback.py +2 -2
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_diarize.py +3 -3
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_docx_publication_identity.py +2 -1
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_done_output_integrity.py +6 -2
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_empty_formats_resume.py +3 -2
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_engine_adapters.py +14 -14
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_engine_faster.py +20 -10
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_landing_commands.py +28 -11
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_partial_output_resume.py +3 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_partial_pdf_resume.py +1 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_pipeline_resume_setup.py +5 -1
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_release_boundaries.py +10 -7
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_stage_reuse_resume.py +1 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_submission.py +7 -2
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_submission_validation.py +13 -7
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_translate.py +3 -3
- textflowkit-0.1.10/tests/test_ui_assets_and_capabilities.py +294 -0
- textflowkit-0.1.10/tests/test_ui_consoleless_logging.py +88 -0
- textflowkit-0.1.10/tests/test_ui_existing_routes_unchanged.py +86 -0
- textflowkit-0.1.10/tests/test_ui_launcher.py +224 -0
- textflowkit-0.1.10/tests/test_ui_ownership_and_shutdown.py +477 -0
- textflowkit-0.1.10/tests/test_ui_packaging.py +153 -0
- textflowkit-0.1.10/tests/test_ui_real_serve.py +88 -0
- textflowkit-0.1.10/tests/test_ui_security.py +168 -0
- textflowkit-0.1.10/tests/test_ui_submission_and_download.py +260 -0
- textflowkit-0.1.10/tests/test_ui_uploads.py +201 -0
- textflowkit-0.1.10/tests/test_whistle_assets.py +490 -0
- textflowkit-0.1.10/tests/test_whistle_defaults.py +661 -0
- textflowkit-0.1.10/tests/test_whistle_engine.py +1027 -0
- textflowkit-0.1.10/tests/test_whistle_job_resume.py +620 -0
- textflowkit-0.1.8/docs/user-manual.md +0 -290
- textflowkit-0.1.8/scripts/smoke_installed_wheel.py +0 -219
- textflowkit-0.1.8/tests/test_cli.py +0 -105
- {textflowkit-0.1.8 → textflowkit-0.1.10}/.dockerignore +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/.env.example +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/.gitattributes +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/.github/dependabot.yml +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/.github/workflows/publish-pypi.yml +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/.gitignore +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/.pre-commit-config.yaml +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/CONTRIBUTING.md +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/LEGAL.md +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/LICENSE +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/SECURITY.md +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/docs/.nojekyll +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/docs/404.html +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/docs/sources.md +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/scripts/fetch_published_fonts.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/scripts/verify_readme_release.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/scripts/verify_release_ci.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/scripts/verify_release_versions.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/scripts/write_release_manifest.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/adapters/__init__.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/assets/README.md +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/assets/selftest-speech.wav +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/__init__.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/batch.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/bind.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/cancel.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/diarize.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/executor.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/jobs.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/model.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/paths.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/retrieval.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/service.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/sqlite_store.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/startup.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/timeutil.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/core/translate.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/render/__init__.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/render/_cue_layout.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/render/_cue_text.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/render/_rename_excl.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/render/_rename_noreplace.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/render/docx.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/render/markdown.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/render/pdf.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/render/srt.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/render/txt.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/render/vtt.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/sources/__init__.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/sources/acquire.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/sources/detect.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/src/textflowkit/sources/scratch.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/__init__.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/ollama_stub.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_acquire.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_bind.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_cancellation_finalization.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_cli_batch_feedback.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_cli_resume_batch.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_cli_stdout_format.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_confined_decoder_boundary.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_confined_indirect_media.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_confined_resume_boundary.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_container_example.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_cue_layout.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_diarize_example_flags.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_diarize_token_docs.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_engine_cache.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_engine_quiet.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_executor.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_executor_store_failure.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_export.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_export_file_mode.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_export_preflight.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_faster_whisper_docs.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_fetch_published_fonts.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_font_notices.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_http_host_boundary.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_http_trusted_proxy.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_job_progress.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_jobs.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_landing_page.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_legal_summary.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_linux_no_hardlink.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_live_smoke_script.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_macos_no_hardlink.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_mcp_batch_cookie_docs.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_mcp_http_boundary.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_mcp_protocol_cleanliness.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_mcp_terminal_guidance.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_mcp_tool_descriptions.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_mcp_work_root.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_model.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_paths.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_pipeline_integrity.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_production_browser_cookies.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_publish_ci_gate.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_publish_fonts_wiring.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_publish_manifest_wiring.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_publish_workflow_gate.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_readme_layout.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_readme_release_guard.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_release_manifest.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_release_surfaces.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_render.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_retrieval.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_sdist_allowlist.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_service_profile.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_site_not_found.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_sources.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_startup_recovery.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_stdio_protocol.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_translate_completeness.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_verify_release_versions.py +0 -0
- {textflowkit-0.1.8 → textflowkit-0.1.10}/tests/test_windows_no_hardlink.py +0 -0
|
@@ -58,7 +58,11 @@ jobs:
|
|
|
58
58
|
run: |
|
|
59
59
|
python -m pip install --upgrade pip
|
|
60
60
|
python -m pip install ./packages/textflowkit-fonts
|
|
61
|
-
|
|
61
|
+
# `whisper` is installed here because the existing engine tests
|
|
62
|
+
# (openai-whisper's verbose/quiet contract, model-name validation)
|
|
63
|
+
# genuinely need the openai-whisper package present. It is an optional
|
|
64
|
+
# extra now that Whistle is the default engine, so it must be named.
|
|
65
|
+
python -m pip install -e ".[dev,mcp,http,export,whisper]"
|
|
62
66
|
|
|
63
67
|
- name: Show ffmpeg version
|
|
64
68
|
shell: bash
|
|
@@ -86,6 +90,6 @@ jobs:
|
|
|
86
90
|
python -m pip install "setuptools>=83" "build>=1.2"
|
|
87
91
|
python -m build --wheel
|
|
88
92
|
python -m build --wheel --outdir dist packages/textflowkit-fonts
|
|
89
|
-
- name: Smoke all
|
|
93
|
+
- name: Smoke all four installed entry points (CLI, MCP, HTTP, served UI)
|
|
90
94
|
shell: bash
|
|
91
95
|
run: python scripts/smoke_installed_wheel.py dist/textflowkit-*.whl dist/textflowkit_fonts-*.whl
|
|
@@ -1,5 +1,128 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.1.10 — 2026-10-06
|
|
4
|
+
|
|
5
|
+
**The local browser interface ships.** The loopback-only browser workspace
|
|
6
|
+
(`textflowkit-ui`) is now part of the core package rather than source-only, so a
|
|
7
|
+
regular install of this release carries the command. Core version: 0.1.10;
|
|
8
|
+
unchanged optional fonts: 0.1.6.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Local browser interface in the core package.** `textflowkit-ui` serves a
|
|
13
|
+
point-and-click workspace on **this machine only**: it binds `127.0.0.1` (never
|
|
14
|
+
off the machine, whatever `TEXTFLOWKIT_ALLOW_REMOTE` is set to) and opens a
|
|
15
|
+
browser once serving. It mounts the existing developer HTTP app under `/api`
|
|
16
|
+
**unchanged** — the same routes, submission contract, and job store — and adds
|
|
17
|
+
only transport: a loopback session layer, a streamed upload, a fixed-format
|
|
18
|
+
download, in-workspace playback, and a capability endpoint. It adds **no new
|
|
19
|
+
dependency** beyond the existing `http` extra (FastAPI + uvicorn).
|
|
20
|
+
- **Durable jobs, cancel and resume in the workspace.** Jobs and checkpoints are
|
|
21
|
+
stored durably under the per-user data directory unless
|
|
22
|
+
`TEXTFLOWKIT_DB` / `TEXTFLOWKIT_WORK_ROOT` / `TEXTFLOWKIT_OUTPUT_ROOT` is set.
|
|
23
|
+
A dropped file is streamed and capped at **2 GiB** by default
|
|
24
|
+
(`TEXTFLOWKIT_UI_MAX_UPLOAD_BYTES` overrides it). A running job can be
|
|
25
|
+
cancelled, and a durable job resumed.
|
|
26
|
+
- **Windows desktop shortcut.** `textflowkit-ui --create-shortcut` creates a Start
|
|
27
|
+
Menu entry that launches with `pythonw` (no console) and needs no `pywin32`.
|
|
28
|
+
Under `pythonw` a startup failure is logged under the per-user data directory
|
|
29
|
+
and shown in a message box rather than failing silently.
|
|
30
|
+
- **Controlled shutdown that drains.** **Stop server** asks this process's own
|
|
31
|
+
uvicorn server to exit through its supported `should_exit` flag; the normal
|
|
32
|
+
lifespan teardown **waits for current jobs to finish** before draining the
|
|
33
|
+
worker pool rather than interrupting them, so a running job's saved progress
|
|
34
|
+
survives and is resumable. It never sends a signal to a pid.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- **Documentation surfaces.** README, user manual, install notes, developer
|
|
39
|
+
manual, architecture guide, roadmap, release checklist, site deployment, the
|
|
40
|
+
landing page, and the checked-in SVG diagrams now describe the local browser
|
|
41
|
+
interface as a shipped feature and a fifth door, and remove the earlier
|
|
42
|
+
"unreleased candidate / install from source only" wording.
|
|
43
|
+
- **No endpoint-breaking change.** The CLI, Python API, MCP server, and JSON HTTP
|
|
44
|
+
adapter are unchanged in this release; the optional engines, diarization, and
|
|
45
|
+
translation keep their documented dependency requirements.
|
|
46
|
+
|
|
47
|
+
### Verification boundary
|
|
48
|
+
|
|
49
|
+
Automated coverage runs the UI's routes, packaging, ownership/shutdown, and
|
|
50
|
+
security boundaries. A **native Windows** machine, in a real browser, proved the
|
|
51
|
+
workspace end to end (drop a file, submit, download, stop). That is one platform's
|
|
52
|
+
browser proof, **not** a live Linux or macOS UI run — those platforms are covered
|
|
53
|
+
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
|
|
55
|
+
diarization) run through the UI is claimed.** The engine and packaging changes of
|
|
56
|
+
v0.1.9 are unchanged by this release.
|
|
57
|
+
|
|
58
|
+
## v0.1.9 — 2026-10-05
|
|
59
|
+
|
|
60
|
+
**Whistle is now the default engine.** This release ships the Whistle integration
|
|
61
|
+
prepared on the `feat/whistle-primary` branch.
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- **Whistle is the default engine; openai-whisper becomes an explicit opt-in.**
|
|
66
|
+
Whistle is a CPU-only native CLI that needs no PyTorch, so a fresh
|
|
67
|
+
`pip install textflowkit` no longer pulls the torch stack. `openai-whisper`
|
|
68
|
+
moves to a new optional `whisper` extra and is selected with `--engine whisper`
|
|
69
|
+
(or `engine="whisper"` on the Python/MCP/HTTP surfaces); the `all` extra still
|
|
70
|
+
includes it. A saved request or checkpoint from before this change keeps running
|
|
71
|
+
on the engine it names, so legacy Whisper work is never silently migrated, and
|
|
72
|
+
legacy engine aliases are preserved so older decoders keep working.
|
|
73
|
+
- **Engine selection is never silent.** An unknown engine name, an unsupported
|
|
74
|
+
language, or a non-CPU device for Whistle is refused at request construction —
|
|
75
|
+
before any media is fetched — and the message names `--engine whisper` as the
|
|
76
|
+
GPU alternative. The engine is not switched to satisfy a request.
|
|
77
|
+
|
|
78
|
+
### Added
|
|
79
|
+
|
|
80
|
+
- **Whistle engine.** Seven advertised languages (`en`, `de`, `fr`, `es`, `it`,
|
|
81
|
+
`nl`, `pl`); native Windows x86-64/arm64, Linux x86-64/arm64, and Apple Silicon
|
|
82
|
+
(an Intel Mac is refused and pointed at the explicit Whisper engine); no WSL.
|
|
83
|
+
One pinned native binary and one pinned model are downloaded and hash-verified
|
|
84
|
+
on first use, outside the package. Long audio is split into 26-second cores with
|
|
85
|
+
up to 2 seconds of context (each clip ≤ 30 s); a word is owned by the clip whose
|
|
86
|
+
core contains its midpoint, so repeated phrases are preserved. Native
|
|
87
|
+
`--audio-stream` is never used.
|
|
88
|
+
- **Durable per-block resume for Whistle.** A long run persists a partial
|
|
89
|
+
checkpoint after each core; a resume validates the source and decoded-WAV
|
|
90
|
+
hashes and the configuration, then re-runs only the unfinished blocks and adopts
|
|
91
|
+
the rest. A partial body is Whistle-only. Reuses the existing single SQLite
|
|
92
|
+
store and its one-owning-process model.
|
|
93
|
+
- **Prompt, bounded cancellation.** A running Whistle run polls for cancellation
|
|
94
|
+
between clips and terminates its exact owned child process, bounded by a
|
|
95
|
+
per-clip timeout and a bounded stdout cap. A single long `openai-whisper` model
|
|
96
|
+
call is still cancellable only at its next stage boundary.
|
|
97
|
+
- **Telemetry off, unconditionally.** Every Whistle child process forces
|
|
98
|
+
`NEEDLE_TELEMETRY=0`, `DO_NOT_TRACK=1`, and `CI=1`, overriding a parent that
|
|
99
|
+
opted in, and there is no opt-in setting. The product adds no analytics, usage
|
|
100
|
+
SDK, anonymous ids, or events. `TEXTFLOWKIT_OFFLINE` refuses downloads and
|
|
101
|
+
`TEXTFLOWKIT_MODELS_DIR` chooses the asset directory; the pinned first-use
|
|
102
|
+
asset/model download is not telemetry.
|
|
103
|
+
|
|
104
|
+
### Documentation
|
|
105
|
+
|
|
106
|
+
- README, user manual, install/adapter/architecture/roadmap/release docs and the
|
|
107
|
+
website source now describe Whistle as the shipped default. ROCm (and the
|
|
108
|
+
torch-pinning caveat) is scoped to the explicit `whisper` engine and
|
|
109
|
+
diarization, never to Whistle.
|
|
110
|
+
- Self-contained checked-in SVG architecture drawings were added under
|
|
111
|
+
`docs/assets` and embedded in the README, both manuals (`user-manual.md` and the
|
|
112
|
+
renamed **Developer and integration manual**, `adapters.md`), the architecture
|
|
113
|
+
guide, and the landing page.
|
|
114
|
+
- The live YouTube release smoke pins `--engine whisper --model tiny` so its
|
|
115
|
+
measured default-clip word stays reproducible across the default-engine change.
|
|
116
|
+
|
|
117
|
+
### Verification boundary
|
|
118
|
+
|
|
119
|
+
Local evidence only: a 4-hour (14,407-second) CPU run produced 555
|
|
120
|
+
clips / 34,596 words / 2,875 segments in 731 seconds, offline with telemetry
|
|
121
|
+
forced off, and a separate two-process run proved durable block resume. These are
|
|
122
|
+
first local test numbers on one machine — not a universal performance claim, and
|
|
123
|
+
not a claim that Whistle's accuracy equals Whisper's. No human-scored
|
|
124
|
+
word-error rate is claimed.
|
|
125
|
+
|
|
3
126
|
## v0.1.8 — 2026-10-02
|
|
4
127
|
|
|
5
128
|
The 2026-10-02 audit-lite repair release. Core version: 0.1.8; unchanged optional fonts: 0.1.6. It carries the four fixes for the post-release audit-lite of 2026-10-01 (findings AL-001 – AL-004). Release artifacts and publication status are recorded on [GitHub Releases](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.8). Local source-candidate verification does not establish installed-package or individual harness compatibility.
|
|
@@ -77,11 +77,13 @@ RUN set -eux; \
|
|
|
77
77
|
WORKDIR /app
|
|
78
78
|
COPY pyproject.toml README.md LICENSE ./
|
|
79
79
|
COPY src ./src
|
|
80
|
-
# The base dependencies are yt-dlp
|
|
81
|
-
#
|
|
82
|
-
#
|
|
80
|
+
# The base dependencies are yt-dlp alone: the default engine (Whistle) is a
|
|
81
|
+
# native CPU binary fetched on first use, so this image does not pull a torch
|
|
82
|
+
# build. Selecting the openai-whisper engine needs the `whisper` extra named
|
|
83
|
+
# here; the image installs it because the container is meant to serve the
|
|
84
|
+
# Whisper stack too, and openai-whisper is what pulls the torch build.
|
|
83
85
|
RUN python -m pip install --no-cache-dir --upgrade pip \
|
|
84
|
-
&& python -m pip install --no-cache-dir ".[http]"
|
|
86
|
+
&& python -m pip install --no-cache-dir ".[http,whisper]"
|
|
85
87
|
|
|
86
88
|
# Non-secret defaults only. The roots are the directories created above; Compose
|
|
87
89
|
# repeats them so the volumes it mounts land on the paths the service reads.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: textflowkit
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.10
|
|
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
|
|
@@ -21,11 +21,11 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
21
21
|
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
|
|
22
22
|
Classifier: Topic :: Text Processing
|
|
23
23
|
Requires-Python: >=3.10
|
|
24
|
-
Requires-Dist: openai-whisper>=20240930
|
|
25
24
|
Requires-Dist: yt-dlp>=2025.1.1
|
|
26
25
|
Provides-Extra: all
|
|
27
26
|
Requires-Dist: fastapi>=0.115; extra == 'all'
|
|
28
27
|
Requires-Dist: mcp>=2.0; extra == 'all'
|
|
28
|
+
Requires-Dist: openai-whisper>=20240930; extra == 'all'
|
|
29
29
|
Requires-Dist: pyannote-audio>=4.0; extra == 'all'
|
|
30
30
|
Requires-Dist: pydantic>=2.7; extra == 'all'
|
|
31
31
|
Requires-Dist: python-docx>=1.1; extra == 'all'
|
|
@@ -53,6 +53,8 @@ Requires-Dist: pydantic>=2.7; extra == 'http'
|
|
|
53
53
|
Requires-Dist: uvicorn>=0.30; extra == 'http'
|
|
54
54
|
Provides-Extra: mcp
|
|
55
55
|
Requires-Dist: mcp>=2.0; extra == 'mcp'
|
|
56
|
+
Provides-Extra: whisper
|
|
57
|
+
Requires-Dist: openai-whisper>=20240930; extra == 'whisper'
|
|
56
58
|
Description-Content-Type: text/markdown
|
|
57
59
|
|
|
58
60
|
# textflowkit
|
|
@@ -62,9 +64,10 @@ Cross-platform media transcription toolkit. **One core, one CLI, thin adapters.*
|
|
|
62
64
|
[Project landing page](https://www.textflowkit.org/) ·
|
|
63
65
|
[PyPI package](https://pypi.org/project/textflowkit/) ·
|
|
64
66
|
[GitHub releases](https://github.com/scottconverse/textflowkit/releases) ·
|
|
65
|
-
[User manual](https://github.com/scottconverse/textflowkit/blob/main/docs/user-manual.md)
|
|
67
|
+
[User manual](https://github.com/scottconverse/textflowkit/blob/main/docs/user-manual.md) ·
|
|
68
|
+
[Developer and integration manual](https://github.com/scottconverse/textflowkit/blob/main/docs/adapters.md)
|
|
66
69
|
|
|
67
|
-
**Current release: [v0.1.
|
|
70
|
+
**Current release: [v0.1.10](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.10).**
|
|
68
71
|
|
|
69
72
|
The [static site deployment](https://github.com/scottconverse/textflowkit/blob/main/docs/site-deployment.md) is hosted on Cloudflare
|
|
70
73
|
Pages. GitHub remains the source and CI host; the website does not run the
|
|
@@ -111,7 +114,7 @@ URL or file ─► detect platform ─► acquire media ─► ffmpeg
|
|
|
111
114
|
│
|
|
112
115
|
┌───────────────────────────┘
|
|
113
116
|
▼
|
|
114
|
-
|
|
117
|
+
speech-to-text (Whistle default; Whisper on request)
|
|
115
118
|
│
|
|
116
119
|
▼
|
|
117
120
|
canonical transcript (JSON)
|
|
@@ -125,8 +128,11 @@ DOCX and PDF are available through the optional `export` extra.
|
|
|
125
128
|
|
|
126
129
|
## Architecture
|
|
127
130
|
|
|
128
|
-
The
|
|
129
|
-
|
|
131
|
+

|
|
132
|
+
|
|
133
|
+
The design principle is **one shared core, thin doors**. Everything of substance
|
|
134
|
+
lives in the core; the interfaces are thin — the local browser UI is a fifth door
|
|
135
|
+
that adds only transport over the existing HTTP app and shared job store.
|
|
130
136
|
|
|
131
137
|
| Layer | Path | Responsibility |
|
|
132
138
|
|---|---|---|
|
|
@@ -136,6 +142,7 @@ the core; the interfaces are thin.
|
|
|
136
142
|
| **CLI** | `src/textflowkit/cli.py` | Reference interface (subprocess-friendly) |
|
|
137
143
|
| **MCP** | `src/textflowkit/adapters/mcp_server.py` | stdio + Streamable HTTP, for AI harnesses |
|
|
138
144
|
| **HTTP** | `src/textflowkit/adapters/http_server.py` | JSON API, for software products and web frontends |
|
|
145
|
+
| **Local UI** | `src/textflowkit/ui` | Loopback-only browser workspace over the same HTTP app and job store |
|
|
139
146
|
|
|
140
147
|
Because the core owns the pipeline, adding a door is cheap — and adding a platform
|
|
141
148
|
means writing one source adapter, not another tool.
|
|
@@ -164,6 +171,22 @@ python -m pip install textflowkit
|
|
|
164
171
|
textflowkit doctor
|
|
165
172
|
```
|
|
166
173
|
|
|
174
|
+
The default engine is **Whistle**: a native CPU-only transcription CLI that
|
|
175
|
+
needs no PyTorch. It downloads one pinned model (about 17 MB) and a small pinned
|
|
176
|
+
binary on first use; a fresh default install therefore stays small and pulls no
|
|
177
|
+
torch. To use the `openai-whisper` engine instead — the ROCm/CUDA/CPU torch
|
|
178
|
+
stack — install the `whisper` extra and name it explicitly:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
python -m pip install 'textflowkit[whisper]'
|
|
182
|
+
textflowkit transcribe meeting.mp4 --engine whisper --model small
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
See [Whistle (default engine)](#whistle-default-engine) for platform and
|
|
186
|
+
language coverage, and the [install guide](https://github.com/scottconverse/textflowkit/blob/main/docs/install.md)
|
|
187
|
+
for the AMD ROCm path, which applies to the explicit `whisper` engine and
|
|
188
|
+
diarization.
|
|
189
|
+
|
|
167
190
|
For MCP or the JSON HTTP adapter, install the matching extra:
|
|
168
191
|
|
|
169
192
|
```bash
|
|
@@ -187,7 +210,6 @@ from textflowkit import transcribe
|
|
|
187
210
|
|
|
188
211
|
result = transcribe(
|
|
189
212
|
"meeting.mp4", # also accepts supported URLs
|
|
190
|
-
model="small",
|
|
191
213
|
formats=["json", "srt", "txt"],
|
|
192
214
|
output_dir="transcripts", # omit to return the transcript without writing files
|
|
193
215
|
)
|
|
@@ -200,6 +222,10 @@ for segment in result.transcript.segments:
|
|
|
200
222
|
print(" ", word.start, word.end, word.text)
|
|
201
223
|
```
|
|
202
224
|
|
|
225
|
+
`engine` defaults to the product default (Whistle) and `model=None` resolves to
|
|
226
|
+
that engine's own model. To use the Whisper-family engines, name one and its
|
|
227
|
+
model explicitly: `transcribe("meeting.mp4", engine="whisper", model="small")`.
|
|
228
|
+
|
|
203
229
|
`transcribe()` returns `TranscribeResult` with a canonical `Transcript` and
|
|
204
230
|
written output paths. `Transcript.to_dict()` / `.to_json()` preserve segment and
|
|
205
231
|
word timing; older transcript JSON without `words` remains readable. Pass
|
|
@@ -264,6 +290,60 @@ does **not** assert that the remote bytes are still identical.
|
|
|
264
290
|
textflowkit export ./transcript.json --format vtt
|
|
265
291
|
```
|
|
266
292
|
|
|
293
|
+
## Whistle (default engine)
|
|
294
|
+
|
|
295
|
+
**Whistle is the default engine** as of v0.1.9. It is a native CPU-only CLI that
|
|
296
|
+
needs no PyTorch, so a fresh `pip install textflowkit` stays small and pulls no
|
|
297
|
+
torch; `openai-whisper` is an explicitly selectable opt-in engine.
|
|
298
|
+
|
|
299
|
+

|
|
300
|
+
|
|
301
|
+
- **CPU only, no torch.** It runs a pinned native binary and downloads one pinned
|
|
302
|
+
model on first use. Naming a GPU device is refused rather than silently
|
|
303
|
+
ignored: a GPU request names the explicit `whisper` engine as the alternative,
|
|
304
|
+
and the engine is never switched for you.
|
|
305
|
+
- **Seven advertised languages:** `en`, `de`, `fr`, `es`, `it`, `nl`, `pl`. A
|
|
306
|
+
request for another language is refused at request construction, before any
|
|
307
|
+
media is fetched.
|
|
308
|
+
- **Native platforms:** Windows x86-64 and arm64, Linux x86-64 and arm64, and
|
|
309
|
+
Apple Silicon. **Intel Macs are not supported**; a request there is refused
|
|
310
|
+
with a message that names the explicit `whisper` engine instead. No WSL layer
|
|
311
|
+
is involved.
|
|
312
|
+
- **How it works:** long audio is split into 26-second cores with up to 2 seconds
|
|
313
|
+
of context on each side, so every standalone clip is ≤ 30 seconds (the native
|
|
314
|
+
CLI's limit). Overlap words are selected by core midpoint rather than text
|
|
315
|
+
deduplication, so repeated spoken phrases are preserved.
|
|
316
|
+
- **Streaming is not used.** The native `--audio-stream` mode failed its
|
|
317
|
+
coverage and is never passed; only the committed standalone output is parsed.
|
|
318
|
+
- **Durable block resume.** With `TEXTFLOWKIT_DB` set, a long run writes partial
|
|
319
|
+
per-block checkpoints; a resume checks the source and decoded-WAV hashes and the
|
|
320
|
+
config, then re-runs only the blocks that were not finished. The durable store
|
|
321
|
+
still assumes one owning process.
|
|
322
|
+
- **Cancellation.** A running Whistle run terminates its exact owned child
|
|
323
|
+
process bounded by a per-clip timeout. A single long `openai-whisper` model call
|
|
324
|
+
is still only cancellable at its next stage boundary, as documented for the
|
|
325
|
+
Whisper engine.
|
|
326
|
+
- **Telemetry is off, unconditionally.** Every Whistle child process forces
|
|
327
|
+
`NEEDLE_TELEMETRY=0`, `DO_NOT_TRACK=1`, and `CI=1`, overriding a parent that
|
|
328
|
+
opted in. The product ships no analytics, usage SDK, anonymous ids, or events,
|
|
329
|
+
and there is no opt-in setting. This applies the upstream documented gate; it
|
|
330
|
+
is **not** a claim that the upstream binary's tracking code is physically
|
|
331
|
+
removed.
|
|
332
|
+
- **Offline and downloads.** Set `TEXTFLOWKIT_OFFLINE` to refuse any download, and
|
|
333
|
+
`TEXTFLOWKIT_MODELS_DIR` to choose the asset directory. The Whistle asset helper
|
|
334
|
+
downloads only pinned runtime/model assets; media acquisition and optional
|
|
335
|
+
translation may independently use the network. These downloads are not
|
|
336
|
+
telemetry.
|
|
337
|
+
|
|
338
|
+
**Verification boundary.** A local run transcribed a 4-hour (14,407 s)
|
|
339
|
+
recording on CPU into 555 clips / 34,596 words / 2,875 segments in 731 s, with
|
|
340
|
+
telemetry forced off and offline mode on; a separate run proved durable block
|
|
341
|
+
resume across two processes. These are **first local test numbers**, not a
|
|
342
|
+
promise of universal performance or of accuracy equal to Whisper — no
|
|
343
|
+
human-scored word-error rate is claimed. See the
|
|
344
|
+
[user manual](https://github.com/scottconverse/textflowkit/blob/main/docs/user-manual.md)
|
|
345
|
+
and [install guide](https://github.com/scottconverse/textflowkit/blob/main/docs/install.md).
|
|
346
|
+
|
|
267
347
|
## Use as an MCP server
|
|
268
348
|
|
|
269
349
|
```bash
|
|
@@ -319,11 +399,71 @@ contract checks cover it, and running an actual build is deliberately out of
|
|
|
319
399
|
scope here, so no image is claimed to build or start. See
|
|
320
400
|
[the container example](https://github.com/scottconverse/textflowkit/blob/main/docs/adapters.md#container-example-dockerfile-and-compose).
|
|
321
401
|
|
|
402
|
+
## Local browser interface
|
|
403
|
+
|
|
404
|
+
For point-and-click use there is a local browser workspace that runs on **this
|
|
405
|
+
machine only**, reuses the same pipeline and job store, and adds no dependency of
|
|
406
|
+
its own beyond the `http` extra. It ships with the core package as of v0.1.10:
|
|
407
|
+
a regular install of the current release carries it.
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
python -m pip install 'textflowkit[http,export]==0.1.10'
|
|
411
|
+
textflowkit-ui
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
On Windows you can create a desktop shortcut when you want one:
|
|
415
|
+
|
|
416
|
+
```powershell
|
|
417
|
+
textflowkit-ui --create-shortcut # Start Menu entry (pythonw, no console)
|
|
418
|
+
textflowkit-ui --create-shortcut --shortcut-dir 'C:\path\to\folder'
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
The shortcut is created only on request and needs no `pywin32`. Under `pythonw`
|
|
422
|
+
there is no console, so a startup failure is written to a log file under the
|
|
423
|
+
per-user data directory and shown in a message box rather than failing silently.
|
|
424
|
+
The normal operator path is to launch from that shortcut; the console command
|
|
425
|
+
above is equivalent.
|
|
426
|
+
|
|
427
|
+
**This is a local app, not a public website.** The [landing page](https://www.textflowkit.org/)
|
|
428
|
+
is static documentation served by Cloudflare Pages; it does **not** run the
|
|
429
|
+
transcription engine and offers no upload form. The browser workspace exists only
|
|
430
|
+
on the machine that installed it.
|
|
431
|
+
|
|
432
|
+
- **Loopback only.** It binds `127.0.0.1` (never off the machine, whatever
|
|
433
|
+
`TEXTFLOWKIT_ALLOW_REMOTE` is set to) and opens a browser once it is serving.
|
|
434
|
+
- **One owner per database.** A second launch against the same database opens the
|
|
435
|
+
UI already running rather than starting a competing server. **Stop server** in
|
|
436
|
+
the workspace shuts the local server down without a terminal, waiting for the
|
|
437
|
+
current jobs to finish rather than interrupting them. Shutdown **drains** — it
|
|
438
|
+
lets in-flight jobs complete; it does **not** auto-cancel them. Cancel a job
|
|
439
|
+
first to stop it early.
|
|
440
|
+
- **Durable jobs with cancel and resume.** Jobs and checkpoints are stored
|
|
441
|
+
durably under the per-user data directory unless you set `TEXTFLOWKIT_DB` /
|
|
442
|
+
`TEXTFLOWKIT_WORK_ROOT` / `TEXTFLOWKIT_OUTPUT_ROOT`. A dropped file is capped
|
|
443
|
+
at **2 GiB** by default (`TEXTFLOWKIT_UI_MAX_UPLOAD_BYTES` overrides it).
|
|
444
|
+
In-workspace playback uses the browser's native player on the **currently
|
|
445
|
+
selected** media, so it depends on what that browser can decode; it is a
|
|
446
|
+
convenience preview, not a format guarantee.
|
|
447
|
+
- **No UI analytics.** The page loads no CDN asset and no analytics, and the
|
|
448
|
+
session token lives only in the page — never in a URL, cookie, or log line.
|
|
449
|
+
- **What uses the network.** The page itself loads nothing remote. A **URL
|
|
450
|
+
source** is downloaded from the internet; an engine's **model** may be
|
|
451
|
+
downloaded on first use; and **remote or cloud translation** (an advanced
|
|
452
|
+
option) sends transcript text to that backend. With local media and a local
|
|
453
|
+
translation model, no transcript leaves the machine.
|
|
454
|
+
- `--port`, `--no-browser`, and `--version` are available.
|
|
455
|
+
|
|
456
|
+
The other doors are unchanged: the CLI, Python API, MCP, and HTTP adapters keep
|
|
457
|
+
their existing behavior, and the optional engines, diarization, and translation
|
|
458
|
+
retain their documented dependency requirements. See the
|
|
459
|
+
[user manual](https://github.com/scottconverse/textflowkit/blob/main/docs/user-manual.md#7-local-browser-interface)
|
|
460
|
+
and [architecture guide](https://github.com/scottconverse/textflowkit/blob/main/docs/architecture.md#one-owner-per-database).
|
|
461
|
+
|
|
322
462
|
## Durable, bounded, cancellable
|
|
323
463
|
|
|
324
464
|
```bash
|
|
325
465
|
TEXTFLOWKIT_DB=./jobs.db # job state survives restart (SQLite)
|
|
326
|
-
TEXTFLOWKIT_MAX_CONCURRENCY=1 # default;
|
|
466
|
+
TEXTFLOWKIT_MAX_CONCURRENCY=1 # default; bounded job worker pool
|
|
327
467
|
```
|
|
328
468
|
|
|
329
469
|
`cancel_job` stops a queued job immediately, or a running job at its next stage
|
|
@@ -333,19 +473,51 @@ boundary. See [docs/adapters.md](https://github.com/scottconverse/textflowkit/bl
|
|
|
333
473
|
|
|
334
474
|
The MCP and HTTP adapters are **job-based**: submission returns a job id
|
|
335
475
|
immediately and clients poll for completion. The CLI uses the same core but
|
|
336
|
-
waits for the result. This lets AI harnesses, software products, and
|
|
337
|
-
|
|
476
|
+
waits for the result. This lets AI harnesses, software products, and the local
|
|
477
|
+
browser interface share the job contract without blocking a request.
|
|
338
478
|
|
|
339
479
|
## Status
|
|
340
480
|
|
|
341
|
-
**v0.1.
|
|
342
|
-
coverage. This release
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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.
|
|
497
|
+
|
|
498
|
+
**Verification limit.** The local browser interface is covered by an automated
|
|
499
|
+
suite, and the UI's behavior was proved on a **native Windows** machine in a real
|
|
500
|
+
browser. No live optional-backend (translation/diarization) run through the UI is
|
|
501
|
+
claimed, and **no live Linux or macOS UI run was performed here** — those
|
|
502
|
+
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
|
|
504
|
+
workflow, which requires successful exact-commit main CI before PyPI uploads and
|
|
505
|
+
creates the public GitHub release only afterward. Check the linked release for
|
|
506
|
+
artifacts and workflow status; local source verification is not a fresh
|
|
507
|
+
PyPI-install or individual-harness receipt.
|
|
508
|
+
|
|
509
|
+
The v0.1.8 release carried four fixes for the 2026-10-01 post-release audit-lite
|
|
510
|
+
(findings AL-001 – AL-004): CLI owning-process startup recovery so an interrupted
|
|
511
|
+
run's saved work can be resumed instead of being refused as "already active",
|
|
512
|
+
preservation of the completed transcript across resume setup failures, a
|
|
513
|
+
correction to the MCP batch cookie capability, and corrected roadmap evidence
|
|
514
|
+
receipts. It built on the v0.1.7 audit repair set and the v0.1.6 review repairs
|
|
515
|
+
that precede it. The v0.1.7 source candidate was verified with real CLI, HTTP and
|
|
516
|
+
MCP speech, seven-format exports and completed resume; the v0.1.8 runtime fixes
|
|
517
|
+
were independently checked through fresh-process CLI restart probes, real SQLite
|
|
518
|
+
setup-failure tests, and the full Windows test suite. Those checks are not new
|
|
519
|
+
individual-harness receipts. That is the previous releases' record, not evidence
|
|
520
|
+
for v0.1.10.
|
|
349
521
|
|
|
350
522
|
The v0.1.6 release was the post-v0.1.5 review repair set: security hardening
|
|
351
523
|
for media acquisition and the HTTP and MCP adapters, safer subtitle wrapping and
|
|
@@ -362,9 +534,9 @@ The v0.1.6 release is public: the
|
|
|
362
534
|
[v0.1.6 GitHub release](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.6)
|
|
363
535
|
and both [core](https://pypi.org/project/textflowkit/0.1.6/) and
|
|
364
536
|
[fonts](https://pypi.org/project/textflowkit-fonts/0.1.6/) PyPI projects are
|
|
365
|
-
live — that is the
|
|
537
|
+
live — that is the v0.1.6 release's evidence, not a receipt for a later release.
|
|
366
538
|
Everything from here to the end of this section is the v0.1.6 release's
|
|
367
|
-
historical record as published: it is not re-verified for v0.1.
|
|
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.
|
|
368
540
|
Merged-main CI passed 16/16 on the tagged commit; the published wheel and
|
|
369
541
|
sdist digests match the GitHub release assets and their SHA-256 list; and a fresh
|
|
370
542
|
Windows Python 3.12 install of `textflowkit[export,mcp,http]==0.1.6` from PyPI
|