V3 Phase 1: small-red-book production fixes from day58#9
Merged
Conversation
Apple Silicon now auto-selects mlx-whisper (Metal-accelerated) and maps `large-v3-turbo` to `mlx-community/whisper-large-v3-turbo`. Brings the repo in line with the version that has been running in ~/.codex/skills/video-editing/ since day58 production. Also lands the V3 implementation plan at docs/plans/. - scripts/transcribe.py: +mlx-whisper engine branch + model mapping - scripts/utils.py: Apple Silicon auto-detect prefers mlx-whisper - SKILL.md: M1/M2/M3/M4 install line → pip install mlx-whisper - tests/test_transcribe_mlx.py: smoke tests (3 passing)
Adds _internal_text_guard.check_visible_text() that rejects speed multipliers (1.25x, 2X), whisper engine/model names, ffmpeg filter names, debug markers, and tempfile markers from any text destined for drawtext or ASS rendering. Wired into render_final.py (config title/subtitle/chapters/badges/ end-cards, before clip resolution so it fails fast) and into generate_cover.py (--title argument). Catches the day58 production accident where "1.25x" leaked into the top-of-frame title overlay. 12 unit tests + 2 integration tests, all passing.
…ideo Day58 production rendered with Hiragino W3 (too thin) by default. New preference order on macOS: 1. Source Han Sans SC Heavy (user lib) 2. Smiley Sans (user lib) 3. STHeiti Medium (system) 4. PingFang SC (system, Semibold name hint) Adds source-han-sans-sc-heavy + smiley-sans to FONT_CATALOG so the auto-downloader can fetch them on demand. The default download for fresh installs is now Source Han Sans Heavy, not Noto Sans SC Regular. _guess_font_name() also recognises Source Han Sans variants so ASS gets a weight-aware font name. 3 new tests assert the picker never falls back to a thin-weight name (W3/Light/Thin/ExtraLight) and that on macOS the medium-weight path wins over PingFang Regular.
Day58 caught this regression: after applying atempo=1.25 the mid section became noticeably quiet because no per-segment loudness normalisation ran in the default render path. The manual fix at the time was to chain dynaudnorm + acompressor + loudnorm, and it worked. Now that's the default. Disable with --no-loudnorm for music-heavy edits or pre-mastered voiceovers where double-normalisation would over-pump. Filter order in af_parts: atempo → dynaudnorm (per-segment EQ) → acompressor (peak control) → loudnorm (EBU R128 target -16 LUFS) → adelay (cover silence stays at -inf, not pumped up). 3 tests cover --help flag, presence of all three filters in source, and that the chain is gated by args.no_loudnorm.
Previously --speed N rendered both a 1.0× base AND an N× variant. Day58 wanted 1.25× to BE the deliverable, with no 1.0× sidecar. New --primary-speed N flag sets the rate of the main output directly. The render loop now writes the first all_speeds entry to the requested --output path regardless of its rate; --speed values become extras. Compatible with the existing --speed flag (passing only --speed keeps 1.0 as primary, same as before).
There was a problem hiding this comment.
Pull request overview
Phase 1 (V3.0) production-regression fixes for the “day58 small-red-book” workflow, bringing the public repo in sync with the previously working local Codex install (with accompanying tests).
Changes:
- Add MLX Whisper support (auto-detect + CLI engine option) and update install/docs accordingly.
- Introduce a visible-text guard to block pipeline-internal tokens (speed/model/engine/filter/debug/temp markers) from being rendered onto frames; wire it into render and cover generation.
- Improve output defaults: heavier CJK font selection, default speech loudness normalization chain (opt-out flag), and
--primary-speedas the first-class main output speed.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/transcribe.py |
Adds mlx-whisper engine option and MLX model mapping/dispatch. |
scripts/utils.py |
Prefers MLX Whisper on Apple Silicon; adjusts recommended model/device logic; updates font preference & catalog. |
scripts/_internal_text_guard.py |
New guard module to detect/reject internal tokens in any frame-visible text. |
scripts/render_final.py |
Adds guard checks, default loudness chain (--no-loudnorm), and --primary-speed output behavior. |
scripts/generate_cover.py |
Adds visible-text guard check for cover title before rendering. |
tests/test_transcribe_mlx.py |
Smoke tests for MLX engine being surfaced + utils diagnostics. |
tests/test_internal_text_guard.py |
Unit tests for the internal visible-text guard patterns. |
tests/test_render_guard_integration.py |
Integration smoke tests ensuring render aborts early on internal-token text. |
tests/test_default_font.py |
Tests to ensure default font selection avoids thin weights on macOS. |
tests/test_audio_chain.py |
Smoke tests asserting default loudness chain + opt-out flag presence. |
tests/test_primary_speed.py |
Smoke tests for --primary-speed help text and source-level invariants. |
SKILL.md |
Updates Whisper install guidance and documents new font-default behavior. |
docs/plans/2026-05-17-v3-xhs-improvements.md |
Adds the V3 phased roadmap/plan document. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
300
to
306
| if gpu_info.get("mps"): | ||
| # faster-whisper doesn't support MPS yet; use CPU with int8 | ||
| engine = detect_whisper_engine() | ||
| if engine == "mlx-whisper": | ||
| return "mlx", "float16" | ||
| if engine == "openai-whisper": | ||
| return "cpu", "float32" # openai-whisper on Mac | ||
| return "cpu", "int8" # faster-whisper CPU |
Comment on lines
+438
to
+446
| "smiley-sans": { | ||
| "name": "Smiley Sans", | ||
| "filename": "SmileySans-Oblique.ttf", | ||
| "urls": [ | ||
| "https://github.com/atelier-anchor/smiley-sans/releases/latest/download/smiley-sans.zip", | ||
| ], | ||
| "urls_cn": [ | ||
| "https://cdn.jsdelivr.net/gh/atelier-anchor/smiley-sans@main/fonts/ttf/SmileySans-Oblique.ttf", | ||
| ], |
| # Whisper model names | ||
| (r"\bwhisper[-_]?(?:large|medium|small|base|tiny|turbo)", "whisper model name"), | ||
| # FFmpeg filter / audio chain internal names | ||
| (r"\b(?:atempo|dynaudnorm|loudnorm|acompressor|drawtext|ass=)\b", "ffmpeg filter name"), |
| # --primary-speed lets the main output be sped-up (or slowed down) directly, | ||
| # without rendering a 1.0× version first. Day58 wanted 1.25× as the only output. | ||
| primary = args.primary_speed | ||
| all_speeds = [primary] + [s for s in args.speed if s != primary] |
This was referenced May 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Five Phase 1 fixes for the production regressions surfaced during day58
small-red-book video production. All five have working code that has been
running in
~/.codex/skills/video-editing/(Codex local install) since2026-05-16; this PR brings the public repo up to that state with tests.
The full V3 roadmap (Phase 1–5) lives at
docs/plans/2026-05-17-v3-xhs-improvements.md.
What's in this PR
--primary-speedfirst-classTotal: 26 passing tests, all green.
Day58 regressions this fixes
1.25x(pipeline-internal token leak)→ Task 2--speed 1.25渲染了 1.0× + 1.25× 两份 → Task 5Test plan
pytest tests/— all 26 tests pass locallypython3 scripts/transcribe.py --helpshowsmlx-whisperengine choicepython3 scripts/render_final.py --helpshows both--primary-speedand--no-loudnormpython3 scripts/utils.pyreportsWhisper engine: mlx-whisperon Apple Silicon with mlx-whisper installedInternalTextLeak--primary-speed 1.25and verify the output is 1.25× speed at the requested path (no_1_25xsuffix)ffprobe -hide_banner -i out.mp4peak should be ≤ -1.5 dBTPWhat's NOT in this PR
Phase 2 (Content Guard + Story Engine), Phase 3 (Auto-Enrich pipeline),
Phase 4 (Cover/Multi-platform/Caption), Phase 5 (Docs). All outlined in
the plan doc; each phase will be a separate PR.