Skip to content

Automate transcriber publication and fix the blocked ONNX runtime#131

Merged
YurMil merged 3 commits into
mainfrom
feat/whisper-transcriber-pipeline
Jul 21, 2026
Merged

Automate transcriber publication and fix the blocked ONNX runtime#131
YurMil merged 3 commits into
mainfrom
feat/whisper-transcriber-pipeline

Conversation

@YurMil

@YurMil YurMil commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Follow-up to #130, which was merged after only its first commit. This carries the rest of that work: the publication pipeline and a user-visible fix — the transcriber currently fails on production.

1. Fix: transcription fails with MODEL_DOWNLOAD_FAILED

The artifact on main lets Transformers.js load ONNX Runtime from jsDelivr, which the site CSP blocks:

Loading the script 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.8.1/dist/ort-wasm-simd-threaded.jsep.mjs'
violates the following Content Security Policy directive: "script-src 'self' …"

Transformers.js defaults ORT's wasmPaths to a CDN URL, which also overrode the runtime copies we already ship — the 21 MB .wasm in the artifact was never used. The source now clears that default (YurMil/ws-speech-text#2) and the artifact here is rebuilt from it.

No CSP change: widening script-src to a third-party CDN to fetch a file we already host would be the wrong trade.

Verified by serving the published artifact with the exact headers from vercel.json and running a real transcription:

Runtime Result Model preparation
auto → WebGPU transcription complete, no console errors 15.0 s
wasm only transcription complete, no console errors 4.4 s

The only third-party request left at runtime is the pinned model download from the Hugging Face Hub.

2. Automated publication pipeline

.github/workflows/sync-whisper-transcriber.yml reacts to a whisper-transcriber-release repository_dispatch from YurMil/ws-speech-text (or runs manually with a tag): it downloads the release archive, refuses it unless the SHA-256 matches, republishes the artifact through scripts/sync-whisper-transcriber.mjs, runs typecheck/lint/build, and opens a pull request. Nothing deploys without review, and this repository still never builds the app or downloads model weights.

Supporting changes to the sync script:

  • an --archive … --sha256 … mode — the checksum is verified before anything is extracted, then the existing file audit runs unchanged;
  • the manifest takes its build time from the source build rather than now(), so republishing an unchanged release produces no diff and the workflow can skip opening a PR;
  • change detection uses git status --porcelain, since git diff would miss a release that only adds a newly hashed asset.

Requires: the SITE_DISPATCH_TOKEN secret in YurMil/ws-speech-text — a fine-grained PAT scoped to this repository with Contents: read and write. Optional here: SOURCE_RELEASE_TOKEN, only needed if the source repository becomes private.

Merge order

Merge YurMil/ws-speech-text#2 first so the source matches the artifact published here; the artifact in this PR is already built from that fix.

Verification

npm run typecheck, npm run lint (0 errors) and a six-locale npm run build pass. The archive path was exercised with a matching checksum (byte-identical republish) and with a deliberate mismatch (rejected, exit 1, target untouched).

🤖 Generated with Claude Code

YurMil and others added 3 commits July 21, 2026 19:05
Releases in YurMil/ws-speech-text now notify this repository, which republishes
the artifact and opens a pull request for review. Nothing deploys unreviewed,
and the site still never builds the app or downloads model weights.

- sync-whisper-transcriber.mjs gains an --archive/--sha256 mode: the checksum is
  verified before anything is extracted, then the existing audit runs unchanged;
- the manifest takes its build time from the source build rather than now(), so
  republishing an unchanged release produces no diff and CI can skip the PR;
- .github/workflows/sync-whisper-transcriber.yml wires it together and can also
  be run manually with a tag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
git diff misses untracked files, so a release that only adds a newly hashed
asset would have looked unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The previous bundle let Transformers.js load ONNX Runtime from jsDelivr, which
the site CSP blocks: transcription failed with MODEL_DOWNLOAD_FAILED and a
blocked script-src for ort-wasm-simd-threaded.jsep.mjs. The source now pins the
runtime to the copies shipped inside the artifact.

Verified by serving this artifact with the exact headers from vercel.json: both
the WebGPU and the WASM-only paths prepare the model and transcribe with no
console errors, so the only third-party request left is the pinned model
download from the Hugging Face Hub.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cadautoscript-com Ready Ready Preview, Comment Jul 21, 2026 4:09pm

@supabase

supabase Bot commented Jul 21, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project bkcimygtsnckzexbfqxh because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@YurMil
YurMil merged commit cd2448b into main Jul 21, 2026
7 of 8 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an automated pipeline to sync and publish the Whisper Transcriber app from its own repository as a static artifact, updating the sync script to support verifying and extracting release archives. The review feedback highlights three key areas for improvement: addressing a cross-platform compatibility issue on Linux runners where GNU tar cannot extract .zip archives, hardening the command-line flag parser to prevent misinterpreting adjacent flags as values, and adding defensive checks to ensure the parsed build-info JSON is a valid object before accessing its properties.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread scripts/sync-whisper-transcriber.mjs
Comment on lines +47 to +50
function readFlag(name) {
const index = process.argv.indexOf(name);
return index === -1 ? undefined : process.argv[index + 1];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The readFlag function currently returns the next argument in process.argv without verifying if it is another flag. If a flag is passed without a value (or if flags are passed in a different order), this can lead to unexpected behavior (e.g., treating --sha256 as the archive path).

Adding a check to ensure the value does not start with a hyphen (-) makes the argument parsing more robust.

Suggested change
function readFlag(name) {
const index = process.argv.indexOf(name);
return index === -1 ? undefined : process.argv[index + 1];
}
function readFlag(name) {
const index = process.argv.indexOf(name);
if (index === -1) return undefined;
const value = process.argv[index + 1];
return value && !value.startsWith('-') ? value : undefined;
}

Comment on lines +152 to 154
if (!info.buildId || !info.version || !info.buildTime) {
fail('build-info.json is missing version, buildId or buildTime.');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Defensive programming: JSON.parse can theoretically return null or non-object values if the JSON file is malformed or empty. Accessing properties like buildId on null will throw a TypeError and crash the script with an unhelpful error message.

Adding a check to ensure info is a non-null object before accessing its properties provides better safety.

Suggested change
if (!info.buildId || !info.version || !info.buildTime) {
fail('build-info.json is missing version, buildId or buildTime.');
}
if (!info || typeof info !== 'object' || !info.buildId || !info.version || !info.buildTime) {
fail('build-info.json is missing version, buildId or buildTime.');
}

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7a237da974

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


scratchDir = fs.mkdtempSync(path.join(os.tmpdir(), 'whisper-transcriber-'));
// bsdtar reads zip archives and is present on Windows, macOS and the runners.
run('tar', ['-xf', path.resolve(archive), '-C', scratchDir]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Extract release ZIPs with a ZIP-capable tool

The workflow downloads whisper-transcriber-${TAG}.zip and passes it to this --archive path, but on ubuntu-latest tar is GNU tar rather than bsdtar; I checked the CLI behavior (tar --version reports tar (GNU tar) 1.35) and tar -xf on a ZIP exits with This does not look like a tar archive. As a result, repository_dispatch/manual syncs for the advertised ZIP release will fail here immediately after checksum verification, before the artifact can be republished or a PR opened.

Useful? React with 👍 / 👎.

@YurMil

YurMil commented Jul 21, 2026

Copy link
Copy Markdown
Owner Author

Added: mobile support, and a leak that would have shipped

This branch now also carries the mobile work (source: YurMil/ws-speech-text#3), because it republishes the same artifact and would otherwise conflict.

What was wrong. A mobile-optimization branch had been prepared separately. Its engineering direction was right — fp16 instead of fp32, WASM by default on phones, tighter conveyor windows — but the audit found two things that could not ship:

  • Its new stylesheet @imported a web font from Google. Our CSP blocks it, so the typeface never loaded — and every page load still announced the visitor's IP to a third party. That contradicts the privacy claim in the docs of all six locales. Same class of bug as the jsDelivr one above, one layer down.
  • It added a second UI as a fork of the first, ~600 duplicated lines, and made it the default for everyone — silently replacing the published interface that the six-locale documentation describes.

Both fixed: the font is gone (system stack, zero requests), and there is now one interface, mobile-first, with the editable transcript restored.

Guard. pnpm verify in the source repo now fails on any absolute URL in CSS and ratchets JS origins against a reviewed allowlist. The previous audit only inspected the entry HTML, which is precisely why this reached review. Regression-tested against the exact bug.

Docs. Updated in all six locales: per-device download size (41 MB WASM / 77 MB WebGPU) instead of one wrong number for both paths, control names matching the interface, conveyor windows documented per platform, and a new "on a phone" section.

Verified under the exact headers from vercel.json: zero external requests, no console errors, transcription completes on WebGPU/fp16 (9.9 s prep) and WASM/q8 (4.3 s), layout holds at 375 px.

Merge order: YurMil/ws-speech-text#2, then #3, then this — the artifact here is built from #3.

Still unverified: a real iPhone. The tab-kill that started this is device behaviour I cannot reproduce locally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant