readio 0.2.2__tar.gz → 0.2.3__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.
- {readio-0.2.2 → readio-0.2.3}/.github/workflows/codecov.yml +1 -2
- readio-0.2.3/.github/workflows/python-publish.yml +49 -0
- {readio-0.2.2 → readio-0.2.3}/.github/workflows/tests.yml +25 -6
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/events/events.jsonl +5 -0
- readio-0.2.3/.ledger/releaseledger/data/ledgers/main/releases/v0.2.3/entries/entry-0001.md +29 -0
- readio-0.2.3/.ledger/releaseledger/data/ledgers/main/releases/v0.2.3/entries/entry-0002.md +27 -0
- readio-0.2.3/.ledger/releaseledger/data/ledgers/main/releases/v0.2.3/entries/entry-0003.md +27 -0
- readio-0.2.3/.ledger/releaseledger/data/ledgers/main/releases/v0.2.3/entries/entry-0004.md +30 -0
- readio-0.2.3/.ledger/releaseledger/data/ledgers/main/releases/v0.2.3/release.md +27 -0
- {readio-0.2.2/readio.egg-info → readio-0.2.3}/PKG-INFO +39 -7
- {readio-0.2.2 → readio-0.2.3}/README.md +36 -4
- {readio-0.2.2 → readio-0.2.3}/docs/changelog.md +20 -1
- {readio-0.2.2 → readio-0.2.3}/docs/index.md +23 -4
- {readio-0.2.2 → readio-0.2.3}/llm-guides/README.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/audio-drama.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/debate-pro-con.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/document-summary.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/dramatic-story.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/educational-explainer.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/funny-story.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/general-narration.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/guided-meditation.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/kids-story.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/language-learning.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/news-briefing.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/podcast-interview.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/podcast-roundtable.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/podcast-solo.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/llm-guides/ssmd/quiz-trivia.md +2 -2
- {readio-0.2.2 → readio-0.2.3}/pyproject.toml +2 -2
- {readio-0.2.2 → readio-0.2.3}/readio/audio.py +17 -0
- {readio-0.2.2 → readio-0.2.3}/readio/cli.py +131 -14
- {readio-0.2.2 → readio-0.2.3}/readio/config.py +57 -0
- {readio-0.2.2 → readio-0.2.3}/readio/formats.py +3 -0
- readio-0.2.3/readio/logging_config.py +50 -0
- {readio-0.2.2 → readio-0.2.3}/readio/models.py +27 -6
- {readio-0.2.2 → readio-0.2.3}/readio/plan.py +208 -10
- {readio-0.2.2 → readio-0.2.3}/readio/reader.py +66 -11
- {readio-0.2.2 → readio-0.2.3}/readio/spotify.py +5 -0
- {readio-0.2.2 → readio-0.2.3}/readio/spotify_cli.py +8 -0
- {readio-0.2.2 → readio-0.2.3}/readio/ssmd.py +33 -0
- {readio-0.2.2 → readio-0.2.3}/readio/synthesis.py +47 -1
- {readio-0.2.2 → readio-0.2.3/readio.egg-info}/PKG-INFO +39 -7
- {readio-0.2.2 → readio-0.2.3}/readio.egg-info/SOURCES.txt +9 -1
- {readio-0.2.2 → readio-0.2.3}/readio.egg-info/requires.txt +2 -2
- {readio-0.2.2 → readio-0.2.3}/readio.egg-info/scm_file_list.json +9 -1
- readio-0.2.3/readio.egg-info/scm_version.json +8 -0
- {readio-0.2.2 → readio-0.2.3}/skill/readio/SKILL.md +4 -2
- {readio-0.2.2 → readio-0.2.3}/skill/readio/references/cli.md +16 -2
- {readio-0.2.2 → readio-0.2.3}/skill/readio/references/troubleshooting.md +18 -3
- {readio-0.2.2 → readio-0.2.3}/tests/test_config.py +8 -1
- {readio-0.2.2 → readio-0.2.3}/tests/test_llm_guides.py +2 -2
- readio-0.2.3/tests/test_logging_cli.py +136 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_manifest.py +28 -0
- readio-0.2.3/tests/test_packaging_metadata.py +30 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_plan.py +2 -1
- {readio-0.2.2 → readio-0.2.3}/tests/test_pykokoro_09_contract.py +11 -7
- {readio-0.2.2 → readio-0.2.3}/tests/test_pykokoro_09_regressions.py +5 -5
- readio-0.2.3/tests/test_pykokoro_09_support.py +231 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_reader_synthesis.py +24 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_synthesis.py +1 -1
- readio-0.2.2/.github/workflows/python-publish.yml +0 -30
- readio-0.2.2/CHANGELOG.md +0 -18
- readio-0.2.2/readio.egg-info/scm_version.json +0 -8
- {readio-0.2.2 → readio-0.2.3}/.codecrate.toml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.github/workflows/pre-commit.yml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.gitignore +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/.ledger-project.toml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/config.toml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/.ledger-project.toml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/docs/docs-changelog-md-77f023b9.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/docs/docs-index-md-b4d68dc8.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/docs/readme-md-b3356305.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/scan.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/source-index.json +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/documentledger/data/storage.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/ledger.toml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/.ledger-project.toml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/config.toml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/.ledger-project.toml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/audit/commit-audit.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/entries/entry-0001.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/entries/entry-0002.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/entries/entry-0003.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/entries/entry-0004.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/entries/entry-0005.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.0/release.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.1/audit/commit-audit.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.1/entries/entry-0001.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.1/release.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.2/audit/commit-audit.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.2/entries/entry-0001.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.2/entries/entry-0002.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.2/entries/entry-0003.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.2/entries/entry-0004.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.2/release.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.3/audit/commit-audit.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.3/entries/entry-0001.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.3/entries/entry-0002.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.1.3/release.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/audit/commit-audit.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/entries/entry-0001.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/entries/entry-0002.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/entries/entry-0003.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/entries/entry-0004.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/entries/entry-0005.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/entries/entry-0006.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.0/release.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.1/audit/commit-audit.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.1/entries/entry-0001.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.1/release.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/audit/commit-audit.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0001.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0002.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0003.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0004.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0005.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0006.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/entries/entry-0007.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/data/ledgers/main/releases/v0.2.2/release.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/work/v0.2.0/audit-decisions.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/work/v0.2.0/audit.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/work/v0.2.0/entries.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/work/v0.2.0/evidence/4ecf165.patch +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/work/v0.2.0/evidence/manifest.json +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/work/v0.2.0/range.json +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/releaseledger/write.lock +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/taskledger/.ledger-project.toml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.ledger/taskledger/config.toml +0 -0
- {readio-0.2.2 → readio-0.2.3}/.pre-commit-config.yaml +0 -0
- {readio-0.2.2 → readio-0.2.3}/LICENSE +0 -0
- {readio-0.2.2 → readio-0.2.3}/docs/conf.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/docs/make.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/docs/requirements.txt +0 -0
- {readio-0.2.2 → readio-0.2.3}/examples/README.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/examples/readio-podcast.ssmd +0 -0
- {readio-0.2.2 → readio-0.2.3}/examples/readio-prosody.ssmd +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/__init__.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/__main__.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/document.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/errors.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/ingest.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/jsonutil.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/manifest.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/markdown.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/paths.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/progress.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/resources/__init__.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/resources/templates/__init__.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/resources/templates/briefing.ssmd +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/resources/templates/dialogue.ssmd +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/resources/templates/podcast.ssmd +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/ssmd_authoring.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/templates.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/text.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio/wave.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio.egg-info/dependency_links.txt +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio.egg-info/entry_points.txt +0 -0
- {readio-0.2.2 → readio-0.2.3}/readio.egg-info/top_level.txt +0 -0
- {readio-0.2.2 → readio-0.2.3}/setup.cfg +0 -0
- {readio-0.2.2 → readio-0.2.3}/skill/readio/references/input-formats.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/skill/readio/references/spotify.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/skill/readio/references/ssmd.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/conftest.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/fixtures/architecture-review.ssmd +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/fixtures/markdown/all-elements.md +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/fixtures/markdown/all-elements.txt +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_audio.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_audio_formats.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_chapters.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_cli.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_defaults_cli.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_doctor.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_document.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_examples.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_ffmpeg_sink.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_ingest.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_language_defaults_config.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_markdown.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_model_source_preference.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_models_cli.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_package_resources.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_paths.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_plan_cli.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_plan_no_tts_load.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_plan_validation.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_progress.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_reader_markdown.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_reader_selection.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_reader_ssmd.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_render_from_plan.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_render_manifest_cli.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_skill_integrity.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_spotify.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_spotify_cli.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_spotify_lifecycle.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_ssmd_cli.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_ssmd_integration.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_ssmd_model_roster.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_ssmd_preflight.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_ssmd_single_source.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_template_validate.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_templates.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_text.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_voice_resolution_workflow.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_voices_cli.py +0 -0
- {readio-0.2.2 → readio-0.2.3}/tests/test_wave.py +0 -0
|
@@ -16,8 +16,7 @@ jobs:
|
|
|
16
16
|
cache: pip
|
|
17
17
|
- name: Install Readio runtime dependencies
|
|
18
18
|
run: |
|
|
19
|
-
python -m pip install "
|
|
20
|
-
python -m pip install "pykokoro[playback] @ git+https://github.com/buchwandler/pykokoro.git@07fdd07f4cccff7ab58bbe1f5c801bebe8b41a85"
|
|
19
|
+
python -m pip install "pykokoro[playback]==0.9.4"
|
|
21
20
|
- name: Install project and coverage tools
|
|
22
21
|
run: |
|
|
23
22
|
python -m pip install --upgrade pip
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Build and publish Readio when a GitHub Release is published.
|
|
2
|
+
|
|
3
|
+
name: Upload Python Package
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
release:
|
|
7
|
+
types: [published]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
deploy:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Check out release
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.13"
|
|
22
|
+
- name: Install build tooling
|
|
23
|
+
run: python -m pip install --upgrade pip build twine
|
|
24
|
+
- name: Build package
|
|
25
|
+
run: python -m build
|
|
26
|
+
- name: Validate artifact metadata
|
|
27
|
+
run: python -m twine check dist/*
|
|
28
|
+
- name: Validate release version
|
|
29
|
+
env:
|
|
30
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
31
|
+
run: |
|
|
32
|
+
python - <<'PY'
|
|
33
|
+
import os
|
|
34
|
+
from pathlib import Path
|
|
35
|
+
from packaging.utils import parse_wheel_filename
|
|
36
|
+
|
|
37
|
+
expected = os.environ["RELEASE_TAG"].removeprefix("v")
|
|
38
|
+
wheels = list(Path("dist").glob("*.whl"))
|
|
39
|
+
assert len(wheels) == 1, f"expected one wheel, found {len(wheels)}"
|
|
40
|
+
_, version, _, _ = parse_wheel_filename(wheels[0].name)
|
|
41
|
+
assert str(version) == expected, (
|
|
42
|
+
f"wheel version {version} does not match release tag {expected}"
|
|
43
|
+
)
|
|
44
|
+
PY
|
|
45
|
+
- name: Publish package to PyPI
|
|
46
|
+
uses: pypa/gh-action-pypi-publish@v1.14.1
|
|
47
|
+
with:
|
|
48
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
49
|
+
attestations: false
|
|
@@ -25,8 +25,7 @@ jobs:
|
|
|
25
25
|
cache: pip
|
|
26
26
|
- name: Install Readio runtime dependencies
|
|
27
27
|
run: |
|
|
28
|
-
python -m pip install "
|
|
29
|
-
python -m pip install "pykokoro[playback] @ git+https://github.com/buchwandler/pykokoro.git@07fdd07f4cccff7ab58bbe1f5c801bebe8b41a85"
|
|
28
|
+
python -m pip install "pykokoro[playback]==0.9.4"
|
|
30
29
|
- name: Install project and test tools
|
|
31
30
|
run: |
|
|
32
31
|
python -m pip install --upgrade pip
|
|
@@ -34,6 +33,27 @@ jobs:
|
|
|
34
33
|
- name: Run test suite
|
|
35
34
|
run: python -m pytest -q
|
|
36
35
|
|
|
36
|
+
|
|
37
|
+
minimum-compatibility:
|
|
38
|
+
name: Minimum PyKokoro compatibility (Ubuntu, Python 3.10)
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
- name: Install PortAudio
|
|
43
|
+
run: sudo apt-get update && sudo apt-get install --yes portaudio19-dev
|
|
44
|
+
- name: Set up Python
|
|
45
|
+
uses: actions/setup-python@v5
|
|
46
|
+
with:
|
|
47
|
+
python-version: "3.10"
|
|
48
|
+
cache: pip
|
|
49
|
+
- name: Install minimum PyKokoro runtime
|
|
50
|
+
run: python -m pip install "pykokoro[playback]==0.9.4"
|
|
51
|
+
- name: Install project and test tools
|
|
52
|
+
run: |
|
|
53
|
+
python -m pip install --upgrade pip
|
|
54
|
+
python -m pip install -e ".[dev]"
|
|
55
|
+
- name: Run minimum-version test suite
|
|
56
|
+
run: python -m pytest -q
|
|
37
57
|
quality:
|
|
38
58
|
name: Static quality checks
|
|
39
59
|
runs-on: ubuntu-latest
|
|
@@ -48,8 +68,7 @@ jobs:
|
|
|
48
68
|
cache: pip
|
|
49
69
|
- name: Install Readio runtime dependencies
|
|
50
70
|
run: |
|
|
51
|
-
python -m pip install "
|
|
52
|
-
python -m pip install "pykokoro[playback] @ git+https://github.com/buchwandler/pykokoro.git@07fdd07f4cccff7ab58bbe1f5c801bebe8b41a85"
|
|
71
|
+
python -m pip install "pykokoro[playback]==0.9.4"
|
|
53
72
|
- name: Install development tools
|
|
54
73
|
run: python -m pip install -e ".[dev]"
|
|
55
74
|
- name: Ruff lint
|
|
@@ -81,9 +100,9 @@ jobs:
|
|
|
81
100
|
shell: bash
|
|
82
101
|
run: |
|
|
83
102
|
python -m venv "${RUNNER_TEMP}/readio-wheel-smoke"
|
|
84
|
-
"${RUNNER_TEMP}/readio-wheel-smoke/bin/python" -m pip install "
|
|
85
|
-
"${RUNNER_TEMP}/readio-wheel-smoke/bin/python" -m pip install "pykokoro[playback] @ git+https://github.com/buchwandler/pykokoro.git@07fdd07f4cccff7ab58bbe1f5c801bebe8b41a85"
|
|
103
|
+
"${RUNNER_TEMP}/readio-wheel-smoke/bin/python" -m pip install "pykokoro[playback]==0.9.4"
|
|
86
104
|
"${RUNNER_TEMP}/readio-wheel-smoke/bin/python" -m pip install dist/*.whl
|
|
105
|
+
"${RUNNER_TEMP}/readio-wheel-smoke/bin/python" -m pip check
|
|
87
106
|
cd "${RUNNER_TEMP}"
|
|
88
107
|
"${RUNNER_TEMP}/readio-wheel-smoke/bin/python" - <<'PY'
|
|
89
108
|
import importlib.metadata
|
|
@@ -55,3 +55,8 @@
|
|
|
55
55
|
{"data":{"kind":"quality","status":"accepted"},"entry_id":"entry-0005","event":"entry.added","event_id":"event-0055","record_revisions":{"entry:v0.2.2/entry-0005":1,"release:v0.2.2":9},"release_version":"v0.2.2","schema_version":2}
|
|
56
56
|
{"data":{"kind":"quality","status":"accepted"},"entry_id":"entry-0006","event":"entry.added","event_id":"event-0056","record_revisions":{"entry:v0.2.2/entry-0006":1,"release:v0.2.2":10},"release_version":"v0.2.2","schema_version":2}
|
|
57
57
|
{"data":{"kind":"internal","status":"accepted"},"entry_id":"entry-0007","event":"entry.added","event_id":"event-0057","record_revisions":{"entry:v0.2.2/entry-0007":1,"release:v0.2.2":11},"release_version":"v0.2.2","schema_version":2}
|
|
58
|
+
{"data":{"status":"planned"},"event":"release.created","event_id":"event-0058","record_revisions":{"release:v0.2.3":1},"release_version":"v0.2.3","schema_version":2}
|
|
59
|
+
{"data":{"kind":"changed","status":"accepted"},"entry_id":"entry-0001","event":"entry.added","event_id":"event-0059","record_revisions":{"entry:v0.2.3/entry-0001":1,"release:v0.2.3":2},"release_version":"v0.2.3","schema_version":2}
|
|
60
|
+
{"data":{"kind":"quality","status":"accepted"},"entry_id":"entry-0002","event":"entry.added","event_id":"event-0060","record_revisions":{"entry:v0.2.3/entry-0002":1,"release:v0.2.3":3},"release_version":"v0.2.3","schema_version":2}
|
|
61
|
+
{"data":{"kind":"changed","status":"accepted"},"entry_id":"entry-0003","event":"entry.added","event_id":"event-0061","record_revisions":{"entry:v0.2.3/entry-0003":1,"release:v0.2.3":4},"release_version":"v0.2.3","schema_version":2}
|
|
62
|
+
{"data":{"kind":"docs","status":"accepted"},"entry_id":"entry-0004","event":"entry.added","event_id":"event-0062","record_revisions":{"entry:v0.2.3/entry-0004":1,"release:v0.2.3":5},"release_version":"v0.2.3","schema_version":2}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 2
|
|
3
|
+
object_type: release_entry
|
|
4
|
+
versioning:
|
|
5
|
+
schema_version: 1
|
|
6
|
+
revision: 1
|
|
7
|
+
entry_id: entry-0001
|
|
8
|
+
release_version: v0.2.3
|
|
9
|
+
kind: changed
|
|
10
|
+
summary:
|
|
11
|
+
Aligned Readio dependency metadata and CI with released PyKokoro 0.9.4 and
|
|
12
|
+
SSMD 0.8.7+
|
|
13
|
+
status: accepted
|
|
14
|
+
audience: null
|
|
15
|
+
scopes: []
|
|
16
|
+
source_refs:
|
|
17
|
+
- tl:task-0019
|
|
18
|
+
paths:
|
|
19
|
+
- pyproject.toml
|
|
20
|
+
- .github/workflows/tests.yml
|
|
21
|
+
- .github/workflows/codecov.yml
|
|
22
|
+
issues: []
|
|
23
|
+
prs: []
|
|
24
|
+
sources: []
|
|
25
|
+
contributors: []
|
|
26
|
+
breaking: false
|
|
27
|
+
internal: false
|
|
28
|
+
order: 1
|
|
29
|
+
---
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 2
|
|
3
|
+
object_type: release_entry
|
|
4
|
+
versioning:
|
|
5
|
+
schema_version: 1
|
|
6
|
+
revision: 1
|
|
7
|
+
entry_id: entry-0002
|
|
8
|
+
release_version: v0.2.3
|
|
9
|
+
kind: quality
|
|
10
|
+
summary: Added bounded PyKokoro compatibility and package metadata regression coverage
|
|
11
|
+
status: accepted
|
|
12
|
+
audience: null
|
|
13
|
+
scopes: []
|
|
14
|
+
source_refs: []
|
|
15
|
+
paths:
|
|
16
|
+
- tests/test_pykokoro_09_contract.py
|
|
17
|
+
- tests/test_pykokoro_09_support.py
|
|
18
|
+
- tests/test_packaging_metadata.py
|
|
19
|
+
issues: []
|
|
20
|
+
prs: []
|
|
21
|
+
sources:
|
|
22
|
+
- tl:task-0019
|
|
23
|
+
contributors: []
|
|
24
|
+
breaking: false
|
|
25
|
+
internal: false
|
|
26
|
+
order: 2
|
|
27
|
+
---
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 2
|
|
3
|
+
object_type: release_entry
|
|
4
|
+
versioning:
|
|
5
|
+
schema_version: 1
|
|
6
|
+
revision: 1
|
|
7
|
+
entry_id: entry-0003
|
|
8
|
+
release_version: v0.2.3
|
|
9
|
+
kind: changed
|
|
10
|
+
summary:
|
|
11
|
+
Hardened package publishing with artifact checks and release-tag version
|
|
12
|
+
validation
|
|
13
|
+
status: accepted
|
|
14
|
+
audience: null
|
|
15
|
+
scopes: []
|
|
16
|
+
source_refs: []
|
|
17
|
+
paths:
|
|
18
|
+
- .github/workflows/python-publish.yml
|
|
19
|
+
issues: []
|
|
20
|
+
prs: []
|
|
21
|
+
sources:
|
|
22
|
+
- tl:task-0019
|
|
23
|
+
contributors: []
|
|
24
|
+
breaking: false
|
|
25
|
+
internal: false
|
|
26
|
+
order: 3
|
|
27
|
+
---
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 2
|
|
3
|
+
object_type: release_entry
|
|
4
|
+
versioning:
|
|
5
|
+
schema_version: 1
|
|
6
|
+
revision: 1
|
|
7
|
+
entry_id: entry-0004
|
|
8
|
+
release_version: v0.2.3
|
|
9
|
+
kind: docs
|
|
10
|
+
summary:
|
|
11
|
+
Documented the PyKokoro support floor, 0.9.4 tested target, and supported
|
|
12
|
+
SSMD API
|
|
13
|
+
status: accepted
|
|
14
|
+
audience: null
|
|
15
|
+
scopes: []
|
|
16
|
+
source_refs: []
|
|
17
|
+
paths:
|
|
18
|
+
- README.md
|
|
19
|
+
- docs/index.md
|
|
20
|
+
- skill/readio/SKILL.md
|
|
21
|
+
- llm-guides
|
|
22
|
+
issues: []
|
|
23
|
+
prs: []
|
|
24
|
+
sources:
|
|
25
|
+
- tl:task-0019
|
|
26
|
+
contributors: []
|
|
27
|
+
breaking: false
|
|
28
|
+
internal: false
|
|
29
|
+
order: 4
|
|
30
|
+
---
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 2
|
|
3
|
+
object_type: release
|
|
4
|
+
versioning:
|
|
5
|
+
schema_version: 1
|
|
6
|
+
revision: 5
|
|
7
|
+
version: v0.2.3
|
|
8
|
+
status: planned
|
|
9
|
+
history_state: curated
|
|
10
|
+
title: Readio v0.2.3
|
|
11
|
+
released_at: null
|
|
12
|
+
previous_version: v0.2.2
|
|
13
|
+
cancel_reason: null
|
|
14
|
+
superseded_by: null
|
|
15
|
+
changelog_file: null
|
|
16
|
+
boundary_ref: null
|
|
17
|
+
source_refs: []
|
|
18
|
+
source_count: null
|
|
19
|
+
entry_count: 4
|
|
20
|
+
artifact_count: 0
|
|
21
|
+
git_base_ref: null
|
|
22
|
+
git_base_sha: null
|
|
23
|
+
git_head_ref: null
|
|
24
|
+
git_head_sha: null
|
|
25
|
+
git_range: null
|
|
26
|
+
git_commit_count: null
|
|
27
|
+
---
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: readio
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Read text aloud in the terminal with streaming TTS and an Agent Skill for LLM invocation
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.10
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
License-File: LICENSE
|
|
9
|
-
Requires-Dist: pykokoro[playback]<0.10,>=0.9.
|
|
9
|
+
Requires-Dist: pykokoro[playback]<0.10,>=0.9.2
|
|
10
10
|
Requires-Dist: platformdirs>=4.0
|
|
11
11
|
Requires-Dist: soundfile>=0.12
|
|
12
12
|
Requires-Dist: tomli>=2.0; python_version < "3.11"
|
|
13
13
|
Requires-Dist: typing_extensions>=4.0
|
|
14
14
|
Requires-Dist: tomli-w>=1.0
|
|
15
15
|
Requires-Dist: PyYAML>=6.0
|
|
16
|
-
Requires-Dist: ssmd<0.9,>=0.8.
|
|
16
|
+
Requires-Dist: ssmd<0.9,>=0.8.7
|
|
17
17
|
Requires-Dist: markdown-it-py<5.0,>=3.0
|
|
18
18
|
Requires-Dist: mdit-py-plugins<1.0,>=0.4
|
|
19
19
|
Provides-Extra: cpu
|
|
@@ -95,7 +95,8 @@ The configuration contains reader settings, SSMD defaults, provider-specific voi
|
|
|
95
95
|
|
|
96
96
|
### Model discovery and language defaults
|
|
97
97
|
|
|
98
|
-
PyKokoro 0.9.
|
|
98
|
+
PyKokoro >=0.9.2,<0.10 is the runtime contract and owns the model, language, voice, quality, frontend, and named-lexicon catalog. Discovery is metadata-only and does not download model weights:
|
|
99
|
+
Readio v0.2.3 is tested against PyKokoro 0.9.4.
|
|
99
100
|
|
|
100
101
|
```bash
|
|
101
102
|
readio models list --language de --offline
|
|
@@ -116,11 +117,30 @@ readio defaults show de-at --json
|
|
|
116
117
|
readio render --lang de --file notes.md
|
|
117
118
|
```
|
|
118
119
|
|
|
119
|
-
When a model is selected, Readio fills its normalized source, default voice, and preferred quality, then validates language compatibility, voice roster, quality, named lexicons, and experimental frontend permission before saving. `--no-lexicons`
|
|
120
|
+
When a model is selected, Readio fills its normalized source, default voice, and preferred quality, then validates language compatibility, voice roster, quality, named lexicons, and experimental frontend permission before saving. `--no-lexicons` selects explicit provider-only pronunciation (`lexicons=[]`); `--auto-lexicons` returns to PyKokoro language defaults (`lexicons=null`). Repeat `--lexicon` to preserve ordered layered lookup.
|
|
120
121
|
|
|
121
|
-
Direct `speak`, `render`, and `spotify publish` options (`--model`, `--model-source`, `--quality`, repeatable `--lexicon`, `--no-lexicons`, and `--
|
|
122
|
+
Direct `speak`, `render`, and `spotify publish` options (`--model`, `--model-source`, `--quality`, repeatable `--lexicon`, `--no-lexicons`, `--auto-lexicons`, `--g2p-fallback`, `--lexicon-data-policy`, `--language-detection`, and repeatable `--detect-language`) override persisted defaults. Use `--json` for automation; JSON preserves `null` versus `[]` for lexicon selection.
|
|
122
123
|
`--model-source github|huggingface` selects the same distribution for discovery, validation, and runtime construction. Voices are model-scoped: the legacy global `reader.voice` is retained only for unchanged default-reader use; `--lang de` without a voice leaves PyKokoro free to choose the German model default.
|
|
123
124
|
|
|
125
|
+
Named lexicons use PyKokoro selectors, not backend asset IDs:
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
crane = named selection token
|
|
129
|
+
de-de:crane = language-qualified Lexphon asset resolved downstream
|
|
130
|
+
de-crane = separate acoustic model ID
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
For reproducible German synthesis:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
readio models show de-thorsten
|
|
137
|
+
readio defaults set de --model de-thorsten --lexicon crane --g2p-fallback espeak --lexicon-data-policy auto
|
|
138
|
+
readio plan --file article.md --lang de --json
|
|
139
|
+
readio render --file article.md --lang de --model de-thorsten --no-lexicons --g2p-fallback espeak --format mp3
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The plan also records optional PyKokoro language detection. SSMD documents may use `language_detection: {mode: auto, languages: [de, en]}`; this routes pronunciation fragments while retaining the selected acoustic language.
|
|
143
|
+
|
|
124
144
|
## Templates
|
|
125
145
|
|
|
126
146
|
Built-in templates are copied into the user template directory during initialization. They are user-owned and are not overwritten by normal initialization or package upgrades.
|
|
@@ -265,13 +285,25 @@ readio --json spotify status spotify:episode:abc --wait
|
|
|
265
285
|
```
|
|
266
286
|
|
|
267
287
|
Progress includes the current phase, completed units, elapsed time, approximate ETA for bounded renders, generated audio duration, and finalization. Live renders show cumulative units without a percentage or ETA. `--json` keeps stdout to one result object; automatic progress is disabled in JSON mode, while explicit `--progress` remains stderr-only.
|
|
288
|
+
|
|
289
|
+
## Verbose diagnostics
|
|
290
|
+
|
|
291
|
+
Use the global repeatable verbosity option for live operational diagnostics:
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
readio -v speak "Hello"
|
|
295
|
+
readio -vv render episode.ssmd -o episode.mp3
|
|
296
|
+
readio speak "literal --verbose" --
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
`-v` shows timestamped lifecycle records at INFO level. `-vv` enables DEBUG-level Readio and PyKokoro details; additional repetitions are clamped to DEBUG. Verbose records always go to stderr, so ordinary output and `--json` results remain on stdout and stay machine-parseable. `--progress` is a separate user-facing progress control. When verbose mode and progress are combined, progress uses line-oriented stderr records instead of in-place terminal rewriting. Logs can contain paths and model or voice identifiers, so review them before sharing and never treat verbose mode as permission to expose document text, audio, or credentials.
|
|
268
300
|
When `-o` is supplied, its `.wav`, `.mp3`, `.m4a`, or `.ogg` suffix selects the encoder. Use `--format` when the output path is omitted or to select the automatic filename suffix. An explicit format and suffix must agree. Extensionless output paths receive the selected suffix, and unsupported suffixes fail before synthesis. Automatic names use the configured output directory and never overwrite an existing file. Explicit output remains atomic and requires `--force` for replacement.
|
|
269
301
|
|
|
270
302
|
M4A output requires an `ffmpeg` executable on `PATH`. WAV uses PCM16, while MP3 and OGG use the installed SoundFile/libsndfile codecs.
|
|
271
303
|
|
|
272
304
|
## SSMD consumption and authoring checks
|
|
273
305
|
|
|
274
|
-
For `.ssmd` inputs, Readio parses the document through SSMD 0.8.
|
|
306
|
+
For `.ssmd` inputs, Readio parses the document through the supported SSMD 0.8.x API and passes a PyKokoro 0.9 `SSMDRenderConfig` containing only missing Readio role defaults. Document `voice_bindings` remain authoritative, invocation `--voice-bind` values override configured provider roles, and concrete targets must belong to the active model roster. Normal `speak`, `render`, and `spotify` commands do not invoke `ssmd create`, rewrite the source, or require generic round-trip validation.
|
|
275
307
|
|
|
276
308
|
Inspect a document before rendering:
|
|
277
309
|
|
|
@@ -68,7 +68,8 @@ The configuration contains reader settings, SSMD defaults, provider-specific voi
|
|
|
68
68
|
|
|
69
69
|
### Model discovery and language defaults
|
|
70
70
|
|
|
71
|
-
PyKokoro 0.9.
|
|
71
|
+
PyKokoro >=0.9.2,<0.10 is the runtime contract and owns the model, language, voice, quality, frontend, and named-lexicon catalog. Discovery is metadata-only and does not download model weights:
|
|
72
|
+
Readio v0.2.3 is tested against PyKokoro 0.9.4.
|
|
72
73
|
|
|
73
74
|
```bash
|
|
74
75
|
readio models list --language de --offline
|
|
@@ -89,11 +90,30 @@ readio defaults show de-at --json
|
|
|
89
90
|
readio render --lang de --file notes.md
|
|
90
91
|
```
|
|
91
92
|
|
|
92
|
-
When a model is selected, Readio fills its normalized source, default voice, and preferred quality, then validates language compatibility, voice roster, quality, named lexicons, and experimental frontend permission before saving. `--no-lexicons`
|
|
93
|
+
When a model is selected, Readio fills its normalized source, default voice, and preferred quality, then validates language compatibility, voice roster, quality, named lexicons, and experimental frontend permission before saving. `--no-lexicons` selects explicit provider-only pronunciation (`lexicons=[]`); `--auto-lexicons` returns to PyKokoro language defaults (`lexicons=null`). Repeat `--lexicon` to preserve ordered layered lookup.
|
|
93
94
|
|
|
94
|
-
Direct `speak`, `render`, and `spotify publish` options (`--model`, `--model-source`, `--quality`, repeatable `--lexicon`, `--no-lexicons`, and `--
|
|
95
|
+
Direct `speak`, `render`, and `spotify publish` options (`--model`, `--model-source`, `--quality`, repeatable `--lexicon`, `--no-lexicons`, `--auto-lexicons`, `--g2p-fallback`, `--lexicon-data-policy`, `--language-detection`, and repeatable `--detect-language`) override persisted defaults. Use `--json` for automation; JSON preserves `null` versus `[]` for lexicon selection.
|
|
95
96
|
`--model-source github|huggingface` selects the same distribution for discovery, validation, and runtime construction. Voices are model-scoped: the legacy global `reader.voice` is retained only for unchanged default-reader use; `--lang de` without a voice leaves PyKokoro free to choose the German model default.
|
|
96
97
|
|
|
98
|
+
Named lexicons use PyKokoro selectors, not backend asset IDs:
|
|
99
|
+
|
|
100
|
+
```text
|
|
101
|
+
crane = named selection token
|
|
102
|
+
de-de:crane = language-qualified Lexphon asset resolved downstream
|
|
103
|
+
de-crane = separate acoustic model ID
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
For reproducible German synthesis:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
readio models show de-thorsten
|
|
110
|
+
readio defaults set de --model de-thorsten --lexicon crane --g2p-fallback espeak --lexicon-data-policy auto
|
|
111
|
+
readio plan --file article.md --lang de --json
|
|
112
|
+
readio render --file article.md --lang de --model de-thorsten --no-lexicons --g2p-fallback espeak --format mp3
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The plan also records optional PyKokoro language detection. SSMD documents may use `language_detection: {mode: auto, languages: [de, en]}`; this routes pronunciation fragments while retaining the selected acoustic language.
|
|
116
|
+
|
|
97
117
|
## Templates
|
|
98
118
|
|
|
99
119
|
Built-in templates are copied into the user template directory during initialization. They are user-owned and are not overwritten by normal initialization or package upgrades.
|
|
@@ -238,13 +258,25 @@ readio --json spotify status spotify:episode:abc --wait
|
|
|
238
258
|
```
|
|
239
259
|
|
|
240
260
|
Progress includes the current phase, completed units, elapsed time, approximate ETA for bounded renders, generated audio duration, and finalization. Live renders show cumulative units without a percentage or ETA. `--json` keeps stdout to one result object; automatic progress is disabled in JSON mode, while explicit `--progress` remains stderr-only.
|
|
261
|
+
|
|
262
|
+
## Verbose diagnostics
|
|
263
|
+
|
|
264
|
+
Use the global repeatable verbosity option for live operational diagnostics:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
readio -v speak "Hello"
|
|
268
|
+
readio -vv render episode.ssmd -o episode.mp3
|
|
269
|
+
readio speak "literal --verbose" --
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
`-v` shows timestamped lifecycle records at INFO level. `-vv` enables DEBUG-level Readio and PyKokoro details; additional repetitions are clamped to DEBUG. Verbose records always go to stderr, so ordinary output and `--json` results remain on stdout and stay machine-parseable. `--progress` is a separate user-facing progress control. When verbose mode and progress are combined, progress uses line-oriented stderr records instead of in-place terminal rewriting. Logs can contain paths and model or voice identifiers, so review them before sharing and never treat verbose mode as permission to expose document text, audio, or credentials.
|
|
241
273
|
When `-o` is supplied, its `.wav`, `.mp3`, `.m4a`, or `.ogg` suffix selects the encoder. Use `--format` when the output path is omitted or to select the automatic filename suffix. An explicit format and suffix must agree. Extensionless output paths receive the selected suffix, and unsupported suffixes fail before synthesis. Automatic names use the configured output directory and never overwrite an existing file. Explicit output remains atomic and requires `--force` for replacement.
|
|
242
274
|
|
|
243
275
|
M4A output requires an `ffmpeg` executable on `PATH`. WAV uses PCM16, while MP3 and OGG use the installed SoundFile/libsndfile codecs.
|
|
244
276
|
|
|
245
277
|
## SSMD consumption and authoring checks
|
|
246
278
|
|
|
247
|
-
For `.ssmd` inputs, Readio parses the document through SSMD 0.8.
|
|
279
|
+
For `.ssmd` inputs, Readio parses the document through the supported SSMD 0.8.x API and passes a PyKokoro 0.9 `SSMDRenderConfig` containing only missing Readio role defaults. Document `voice_bindings` remain authoritative, invocation `--voice-bind` values override configured provider roles, and concrete targets must belong to the active model roster. Normal `speak`, `render`, and `spotify` commands do not invoke `ssmd create`, rewrite the source, or require generic round-trip validation.
|
|
248
280
|
|
|
249
281
|
Inspect a document before rendering:
|
|
250
282
|
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **Generated by releaseledger.** Manual edits may be overwritten. Update releaseledger entries and rebuild this file instead.
|
|
4
|
+
|
|
5
|
+
## [v0.2.3] - 2026-09-11
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Aligned Readio dependency metadata and CI with released PyKokoro 0.9.4 and SSMD 0.8.7+
|
|
10
|
+
- Hardened package publishing with artifact checks and release-tag version validation
|
|
11
|
+
|
|
12
|
+
### Documentation
|
|
13
|
+
|
|
14
|
+
- Documented the PyKokoro support floor, 0.9.4 tested target, and supported SSMD API
|
|
15
|
+
|
|
16
|
+
### Quality
|
|
17
|
+
|
|
18
|
+
- Added bounded PyKokoro compatibility and package metadata regression coverage
|
|
19
|
+
|
|
20
|
+
<!-- generated by releaseledger -->
|
|
4
21
|
|
|
5
22
|
## [v0.2.2] - 2026-09-05
|
|
6
23
|
|
|
@@ -85,3 +102,5 @@
|
|
|
85
102
|
- Added cross-platform CI, pre-commit, coverage, package publishing checks, and a podcast example
|
|
86
103
|
|
|
87
104
|
<!-- generated by releaseledger -->
|
|
105
|
+
|
|
106
|
+
<!-- releaseledger:generated-file -->
|
|
@@ -80,12 +80,19 @@ Synthesis options are available on all three commands:
|
|
|
80
80
|
```text
|
|
81
81
|
--voice VOICE PyKokoro voice ID
|
|
82
82
|
--lang LANGUAGE language code, such as en-us
|
|
83
|
+
--lexicon NAME named PyKokoro lexicon; repeat for ordered layers
|
|
84
|
+
--no-lexicons explicit provider-only pronunciation
|
|
85
|
+
--auto-lexicons restore automatic language-default lexicons
|
|
86
|
+
--g2p-fallback MODE none, espeak, or goruut
|
|
87
|
+
--lexicon-data-policy POLICY auto or installed-only
|
|
88
|
+
--language-detection MODE off or auto
|
|
89
|
+
--detect-language LANG repeatable pronunciation-routing language
|
|
83
90
|
--speed NUMBER speech speed multiplier
|
|
84
91
|
--pause-mode MODE tts, manual, or auto
|
|
85
92
|
--unit UNIT sentence or paragraph
|
|
86
93
|
```
|
|
87
94
|
|
|
88
|
-
Runtime discovery and per-language defaults are separate from legacy provider role configuration. Readio
|
|
95
|
+
Runtime discovery and per-language defaults are separate from legacy provider role configuration. Readio v0.2.x uses the PyKokoro >=0.9.2,<0.10 public discovery and tokenizer contract. Readio v0.2.3 is tested with PyKokoro 0.9.4:
|
|
89
96
|
|
|
90
97
|
```bash
|
|
91
98
|
readio models list --language de --offline
|
|
@@ -98,7 +105,7 @@ readio defaults show de-at --json
|
|
|
98
105
|
readio render --lang de --file notes.md
|
|
99
106
|
```
|
|
100
107
|
|
|
101
|
-
`models` reads PyKokoro's lightweight registry and supports `--offline`, `--refresh`, `--status`, and `--json`; it never loads model weights. `--refresh` updates metadata only and cannot be combined with `--offline`. Offline synthesis still needs cached model and voice assets. `
|
|
108
|
+
`models` reads PyKokoro's lightweight registry and supports `--offline`, `--refresh`, `--status`, and `--json`; it never loads model weights. `--refresh` updates metadata only and cannot be combined with `--offline`. Offline synthesis still needs cached model and voice assets. `--lexicon crane` selects a named lexicon; `de-de:crane` is the downstream Lexphon asset ID, while `de-crane` is an acoustic model ID.
|
|
102
109
|
`--model-source github|huggingface` drives both discovery and runtime selection. Voices are model-scoped. The legacy global `reader.voice` applies only to unchanged default-reader use; a language override such as `--lang de` leaves voice selection to the active PyKokoro model unless explicitly set. SSMD preflight uses that same resolved model roster.
|
|
103
110
|
|
|
104
111
|
## Synthesis planning
|
|
@@ -117,6 +124,8 @@ Keep the layers separate:
|
|
|
117
124
|
- **Planning** (`readio plan`, `render --dry-run`) resolves one concrete request — model, source, quality, voice, lexicons, SSMD cast with per-reference bindings, output format/backend/path — and records a decision (winning source) for every effective value. Generated output paths are allocated once by the plan and reused by the render.
|
|
118
125
|
- **Render result** executes the plan; a plan that fails validation (for example `model_language_incompatible`, `model_runtime_unavailable`, `ssmd_unresolved_voice`, `encoder_unavailable`) is printed with its diagnostics and no TTS model is loaded.
|
|
119
126
|
|
|
127
|
+
Plans preserve the tokenizer tri-state: `lexicons: null` means PyKokoro language defaults, `lexicons: []` means no static lexicon layers, and a non-empty list means ordered named layers. Fallback and lexicon data policy are also carried unchanged into `TokenizerConfig`; SSMD `language_detection` hints are resolved into the plan before execution.
|
|
128
|
+
|
|
120
129
|
Planning is deterministic: `--resolve-voices` is rejected during `plan`/`--dry-run` in favor of `--voice-bind ROLE=VOICE_ID` or persisted roles, and `plan` supports `--force` to mirror render output requests.
|
|
121
130
|
|
|
122
131
|
## Durable render manifests
|
|
@@ -143,6 +152,16 @@ readio render --file notes.md -o notes.mp3 --json --progress
|
|
|
143
152
|
|
|
144
153
|
Bounded renders show phases, completed/total units, percentage, elapsed time, approximate ETA, generated audio duration, and finalization. Live rendering shows elapsed time, cumulative units, and audio duration but no invented percentage or ETA.
|
|
145
154
|
|
|
155
|
+
## Verbose diagnostics
|
|
156
|
+
|
|
157
|
+
Use `-v` for timestamped INFO lifecycle records and `-vv` for DEBUG details from Readio and PyKokoro:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
readio -v speak "Hello"
|
|
161
|
+
readio -vv render episode.ssmd -o episode.mp3
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The option is global and may appear before or after a command. Logs are written only to stderr. Human results and JSON remain on stdout, so `readio -v doctor --json` still emits valid JSON. `--progress` and `--no-progress` remain independent; verbose mode makes progress line-oriented on a TTY. Review paths, model names, and voice identifiers before sharing diagnostics. Complete document text, raw audio, Spotify credentials, and authorization responses are not logged.
|
|
146
165
|
Playback-only options are `--queue-size` and `--device`. Audio rendering is streamed to an atomic output file through a bounded audio path rather than accumulated as one in-memory waveform.
|
|
147
166
|
|
|
148
167
|
## Configuration
|
|
@@ -162,8 +181,8 @@ readio config validate
|
|
|
162
181
|
- `[ssmd]`: the selected `voice_provider` and SSMD validation behavior.
|
|
163
182
|
- `[paths]`: user template, ingest, and audio output directories.
|
|
164
183
|
- `[voices.<provider>]`: concrete voice IDs and logical role mappings.
|
|
165
|
-
|
|
166
|
-
- `[
|
|
184
|
+
- `[languages.<locale>]`: validated model, source, quality, voice, ordered lexicons, `g2p_fallback`, and `lexicon_data_policy` defaults.
|
|
185
|
+
- `[reader]`: optional `language_detection` mode and ordered `detect_languages` routing hints.
|
|
167
186
|
Set values with dotted keys. Aliases `voice`, `lang`, and `speed` target the corresponding reader settings:
|
|
168
187
|
|
|
169
188
|
```bash
|
|
@@ -56,8 +56,8 @@ When file creation is unavailable, the guide instructs the LLM to return the com
|
|
|
56
56
|
The guides target the conservative authoring subset used by:
|
|
57
57
|
|
|
58
58
|
- Readio 0.2.x
|
|
59
|
-
- SSMD >=0.8.
|
|
60
|
-
- PyKokoro 0.9.
|
|
59
|
+
- SSMD >=0.8.7,<0.9
|
|
60
|
+
- PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
|
|
61
61
|
|
|
62
62
|
This is a compatibility target, not a claim that the authoring environment ran validation. A generated file should be checked on the destination system before rendering.
|
|
63
63
|
|
|
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
|
|
|
42
42
|
Generate conservative SSMD for this compatibility target:
|
|
43
43
|
|
|
44
44
|
- Readio 0.2.x
|
|
45
|
-
- SSMD >=0.8.
|
|
46
|
-
- PyKokoro 0.9.
|
|
45
|
+
- SSMD >=0.8.7,<0.9
|
|
46
|
+
- PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
|
|
47
47
|
|
|
48
48
|
These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
|
|
49
49
|
|
|
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
|
|
|
42
42
|
Generate conservative SSMD for this compatibility target:
|
|
43
43
|
|
|
44
44
|
- Readio 0.2.x
|
|
45
|
-
- SSMD >=0.8.
|
|
46
|
-
- PyKokoro 0.9.
|
|
45
|
+
- SSMD >=0.8.7,<0.9
|
|
46
|
+
- PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
|
|
47
47
|
|
|
48
48
|
These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
|
|
49
49
|
|
|
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
|
|
|
42
42
|
Generate conservative SSMD for this compatibility target:
|
|
43
43
|
|
|
44
44
|
- Readio 0.2.x
|
|
45
|
-
- SSMD >=0.8.
|
|
46
|
-
- PyKokoro 0.9.
|
|
45
|
+
- SSMD >=0.8.7,<0.9
|
|
46
|
+
- PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
|
|
47
47
|
|
|
48
48
|
These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
|
|
49
49
|
|
|
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
|
|
|
42
42
|
Generate conservative SSMD for this compatibility target:
|
|
43
43
|
|
|
44
44
|
- Readio 0.2.x
|
|
45
|
-
- SSMD >=0.8.
|
|
46
|
-
- PyKokoro 0.9.
|
|
45
|
+
- SSMD >=0.8.7,<0.9
|
|
46
|
+
- PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
|
|
47
47
|
|
|
48
48
|
These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
|
|
49
49
|
|
|
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
|
|
|
42
42
|
Generate conservative SSMD for this compatibility target:
|
|
43
43
|
|
|
44
44
|
- Readio 0.2.x
|
|
45
|
-
- SSMD >=0.8.
|
|
46
|
-
- PyKokoro 0.9.
|
|
45
|
+
- SSMD >=0.8.7,<0.9
|
|
46
|
+
- PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
|
|
47
47
|
|
|
48
48
|
These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
|
|
49
49
|
|
|
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
|
|
|
42
42
|
Generate conservative SSMD for this compatibility target:
|
|
43
43
|
|
|
44
44
|
- Readio 0.2.x
|
|
45
|
-
- SSMD >=0.8.
|
|
46
|
-
- PyKokoro 0.9.
|
|
45
|
+
- SSMD >=0.8.7,<0.9
|
|
46
|
+
- PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
|
|
47
47
|
|
|
48
48
|
These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
|
|
49
49
|
|
|
@@ -42,8 +42,8 @@ If downloadable file or artifact creation is unavailable:
|
|
|
42
42
|
Generate conservative SSMD for this compatibility target:
|
|
43
43
|
|
|
44
44
|
- Readio 0.2.x
|
|
45
|
-
- SSMD >=0.8.
|
|
46
|
-
- PyKokoro 0.9.
|
|
45
|
+
- SSMD >=0.8.7,<0.9
|
|
46
|
+
- PyKokoro >=0.9.2,<0.10 (Readio v0.2.3 tested with 0.9.4)
|
|
47
47
|
|
|
48
48
|
These are authoring instructions, not a requirement to install or execute the runtime. They must work without Python, a Readio installation, the Readio Agent Skill, local SSMD tooling, or local model discovery. The generated file can be checked and rendered later on a Readio-capable system.
|
|
49
49
|
|