Skip to content

fix(landing): API example + new /download page (no more dumping users on GitHub)#487

Merged
jamiepine merged 9 commits intomainfrom
fix/landing-api-example-engine
Apr 19, 2026
Merged

fix(landing): API example + new /download page (no more dumping users on GitHub)#487
jamiepine merged 9 commits intomainfrom
fix/landing-api-example-engine

Conversation

@jamiepine
Copy link
Copy Markdown
Owner

@jamiepine jamiepine commented Apr 19, 2026

Summary

Two fixes bundled:

1. API example correctness

  • Curl snippet in ApiSection.tsx previously showed engine: "qwen" alongside an instruct field, but base Qwen3-TTS has no instruct path — that's a Qwen CustomVoice feature. Swapped to engine: "qwen_custom_voice".
  • profile_id was a slug ("morgan-freeman"); profile IDs are str(uuid.uuid4()) per backend/services/profiles.py:175. Replaced with a realistic UUID.

2. New /download page

Users were clicking download on voicebox.sh, ending up on GitHub's releases page, and filing confused comments ("I ended up on some blog site called GitHub"). Every download CTA now routes through a dedicated /download page instead of dumping to a file URL or GitHub.

What the page does:

  • Auto-detects platform from ?platform=X or navigator.userAgent.
  • Auto-triggers the platform-specific download via a programmatic anchor click (navigation from the CTA counts as a user gesture, so modern browsers allow this).
  • Shows "Your download has started" hero with the app logo.
  • Platform-specific buttons visible as a fallback for "download not working" / manual pick.
  • Personal maintainer spiel + Buy Me a Coffee button.
  • Resources grid: Docs, DeepWiki ("Got questions? Ask AI"), GitHub source.
  • Never redirects to GitHub as a silent fallback — if the release API fails, the page explains and shows the manual buttons.

Routing changes:

  • Landing page download-section cards → /download?platform=macArm|macIntel|windows (Linux still → /linux-install).
  • /download/[platform] pretty URLs (used by README and docs) → redirect to /download?platform=X rather than straight to the asset. External links benefit from the new post-click page too.

Test plan

  • bun dev in landing/, visit /, confirm curl snippet reads engine: "qwen_custom_voice" with a UUID profile_id.
  • Click each Mac/Windows card — lands on /download?platform=X, download kicks off, "Your download has started" displays.
  • Visit /download directly on Mac/Win/Linux — confirm auto-detect picks the right platform.
  • Visit /download/mac-arm directly — redirects to /download?platform=macArm and auto-downloads.
  • Kill the GitHub API (e.g. block in devtools) and reload /download — page shows "couldn't reach release server" + disabled buttons, does NOT redirect to GitHub.
  • Verify donate + resources cards link correctly (buymeacoffee, docs.voicebox.sh, deepwiki.com/jamiepine/voicebox, github.com/jamiepine/voicebox).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Branded Download page with platform selection, automatic download initiation, donation prompt, and quick links to docs/AI Q&A/GitHub.
    • CTAs and navigation updated to use a unified /download flow with platform query parameters (Footer/Navbar updated accordingly).
  • Style

    • Refreshed platform icons for Apple, Linux, and Windows.
  • Documentation

    • REST API example payload now references the custom voice engine and a UUID-style profile identifier.
  • Chores

    • Added an icons runtime dependency.

…mVoice-only)

The curl snippet showed engine: "qwen" alongside an instruct field, but base
Qwen3-TTS has no instruct path — that's a Qwen CustomVoice feature.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 19, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Added a client-side DownloadPage and centralized download routing (/download), updated landing CTAs to point to the new route, replaced a static API cURL example payload, swapped some platform icon implementations, and added a simple redirect route for platform normalization. No exported API surface was introduced.

Changes

Cohort / File(s) Summary
API Example
landing/src/components/ApiSection.tsx
Updated static CURL_SNIPPET payload values: engine"qwen_custom_voice", profile_id"b3f1c2d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d". No runtime behavior changes.
Download Route
landing/src/app/download/[platform]/route.ts
Removed release-resolution and JSON error responses; now normalizes platform via PLATFORM_ALIAS, constructs /download?platform=..., and always issues a 307 redirect. Minor GET param rename.
Download Page (new)
landing/src/app/download/page.tsx
Added client-side DownloadPage: parses platform from query or UA, fetches /api/releases, auto-triggers download via hidden anchor, shows platform buttons, donation section, and resource cards.
Landing page CTA updates
landing/src/app/page.tsx
Replaced direct file/download CTAs with links to `/download?platform=macArm
Navbar & Footer links
landing/src/components/Navbar.tsx, landing/src/components/Footer.tsx
Changed “Download” links from in-page anchor (#download) to route path (/download).
Platform Icons
landing/src/components/PlatformIcons.tsx
Switched AppleIcon and LinuxIcon to @icons-pack/react-simple-icons components; simplified WindowsIcon SVG. Public props unchanged.
Deps
landing/package.json
Added runtime dependency @icons-pack/react-simple-icons@^13.13.0.

Sequence Diagram(s)

sequenceDiagram
  participant Browser as Browser (DownloadPage)
  participant App as App Server (route.ts)
  participant Releases as Releases API (/api/releases)
  participant External as External Host (GitHub/Storage)

  Browser->>App: GET /download/<platform>
  App-->>Browser: 307 Redirect → /download?platform=...
  Browser->>Browser: Render DownloadPage, parse platform (query/UA)
  Browser->>Releases: GET /api/releases
  Releases-->>Browser: JSON with download URLs (or error)
  Browser->>Browser: create hidden anchor(href=platform URL) and click
  Browser->>External: Follow download URL (direct) or route through App
  External-->>Browser: Serve file download
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I nudged a link and changed a name,
A little route to guide the game.
I clicked a hidden anchor with delight,
Downloads hopped off into the night. 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main changes: updating the API example (curl snippet) and adding a new /download page to improve the download experience.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/landing-api-example-engine

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

jamiepine and others added 2 commits April 18, 2026 22:57
Profile IDs are str(uuid.uuid4()), not slugs (see backend/services/profiles.py:175).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… GitHub

Users were clicking download, landing on the GitHub releases page, and filing
confused comments along the lines of "I ended up on some blog site called
GitHub." We now route every download CTA through a dedicated /download page
that auto-triggers the platform-specific download and gives users a polished
post-click experience with donate + docs + AI help prompts.

- New /download page:
  - Big app logo + "Your download has started" messaging.
  - Auto-detects platform from ?platform=X or navigator.userAgent.
  - Programmatically clicks a hidden anchor to trigger the file download
    without leaving the page.
  - Platform-specific buttons as a visible fallback for "download not
    working" / manual-pick.
  - Personal donate spiel + Buy Me a Coffee button.
  - Resources grid: docs, DeepWiki ("got questions? ask AI"), GitHub.
- Landing page download section cards now link to /download?platform=X
  instead of the asset URL directly.
- /download/[platform] (used by README/docs links) now redirects to the
  /download page rather than straight to the asset or to GitHub on error.
- Drops unused downloadLinks state from the landing page.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jamiepine jamiepine changed the title fix(landing): use qwen_custom_voice in API example fix(landing): API example + new /download page (no more dumping users on GitHub) Apr 19, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@landing/src/app/download/`[platform]/route.ts:
- Around line 10-24: PLATFORM_ALIAS currently maps only hyphenated keys
('mac-arm','mac-intel') so requests using canonical camelCase paths (e.g.,
/download/macArm or /download/macIntel) lose their platform param; update the
PLATFORM_ALIAS object to also include 'macArm': 'macArm' and 'macIntel':
'macIntel' (mapping those keys to the same normalized values used for the
hyphenated forms) so the existing GET function (uses PLATFORM_ALIAS and
normalized) will preserve platform query params for both alias styles.

In `@landing/src/app/download/page.tsx`:
- Around line 73-86: The fetch in the useEffect that calls
fetch('/api/releases') leaves links null on error so platform buttons become
disabled; update the error handler (the .catch in the useEffect that uses
setLinksError) to populate setLinks with a fallback DownloadLinks object (e.g.,
GitHub releases URLs for each platform) so manual download buttons remain
usable, and apply the same change to the other identical block around the
useEffect at lines ~181-192; reference the fetch('/api/releases') call, the
useEffect, the setLinks and setLinksError setters, and the DownloadLinks type
when implementing the fallback.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1100d080-e3d0-4e7d-a1cc-aae05f9d3c49

📥 Commits

Reviewing files that changed from the base of the PR and between 1ca0756 and 1392474.

📒 Files selected for processing (3)
  • landing/src/app/download/[platform]/route.ts
  • landing/src/app/download/page.tsx
  • landing/src/app/page.tsx

Comment thread landing/src/app/download/[platform]/route.ts
Comment on lines +73 to +86
useEffect(() => {
let cancelled = false;
fetch('/api/releases')
.then((r) => {
if (!r.ok) throw new Error(`releases ${r.status}`);
return r.json();
})
.then((data) => {
if (cancelled) return;
if (data.downloadLinks) setLinks(data.downloadLinks as DownloadLinks);
})
.catch(() => {
if (!cancelled) setLinksError(true);
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Keep manual downloads usable when /api/releases fails.

On fetch failure, links stays null, so every platform button resolves to # and is disabled, while the UI says users can “Pick your platform manually below.” Provide a fallback, e.g. GitHub releases, when release links cannot be loaded.

Proposed fix
       .then((data) => {
         if (cancelled) return;
-        if (data.downloadLinks) setLinks(data.downloadLinks as DownloadLinks);
+        if (!data.downloadLinks) throw new Error('missing downloadLinks');
+        setLinks(data.downloadLinks as DownloadLinks);
       })
       .catch(() => {
         if (!cancelled) setLinksError(true);
       });
             {PLATFORMS.map((meta) => {
-              const url = links?.[meta.key];
+              const directUrl = links?.[meta.key];
+              const url = directUrl ?? (linksError ? `${GITHUB_REPO}/releases` : undefined);
               const isActive = meta.key === platform;
               return (
                 <a
                   key={meta.key}
                   href={url ?? '#'}
-                  download
+                  download={directUrl ? true : undefined}
+                  target={directUrl ? undefined : '_blank'}
+                  rel={directUrl ? undefined : 'noopener noreferrer'}
                   aria-disabled={!url}
                   onClick={(e) => {
                     if (!url) e.preventDefault();
                   }}

Also applies to: 181-192

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@landing/src/app/download/page.tsx` around lines 73 - 86, The fetch in the
useEffect that calls fetch('/api/releases') leaves links null on error so
platform buttons become disabled; update the error handler (the .catch in the
useEffect that uses setLinksError) to populate setLinks with a fallback
DownloadLinks object (e.g., GitHub releases URLs for each platform) so manual
download buttons remain usable, and apply the same change to the other identical
block around the useEffect at lines ~181-192; reference the
fetch('/api/releases') call, the useEffect, the setLinks and setLinksError
setters, and the DownloadLinks type when implementing the fallback.

jamiepine and others added 2 commits April 18, 2026 23:12
The hand-rolled Linux SVG path wasn't actually Tux — it was a symmetric
placeholder shape. Apple/Windows were close but not canonical either.

- Apple + Linux: pulled from @icons-pack/react-simple-icons (SiApple, SiLinux).
- Windows: simple-icons drops the Microsoft mark over trademark policy, so
  the Windows 11 flag is inlined from Microsoft's public brand guidance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…anchor

Hero CTA, navbar link, and footer link were all scrolling to #download
(the section at the bottom of the page) instead of going to the new
/download page that triggers the actual download.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@landing/src/components/PlatformIcons.tsx`:
- Around line 17-23: The inline Windows SVG in PlatformIcons.tsx is missing an
accessible title; add a <title> element inside the <svg> (e.g., "Windows") and
wire it to the SVG via an accessible attribute (prefer aria-labelledby
referencing the title's id or aria-label if you prefer) and include role="img"
so the screen reader can announce it; update the <svg> that currently has
className, viewBox, fill, xmlns and the <path> (the Windows icon) to include the
title element and the appropriate aria-labelledby/id pairing (ensure the id is
unique or derived from a prop if necessary).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c019dc44-1a30-407e-a150-4864ccd6ee49

📥 Commits

Reviewing files that changed from the base of the PR and between 1392474 and d7285bf.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • landing/package.json
  • landing/src/components/PlatformIcons.tsx
✅ Files skipped from review due to trivial changes (1)
  • landing/package.json

Comment thread landing/src/components/PlatformIcons.tsx
jamiepine and others added 4 commits April 18, 2026 23:16
Bun runtime + Next 16 Turbopack dev server intermittently trips a
JavaScriptCore allocator panic ('pas panic: deallocation did fail ...
Alloc bit not set') after a few requests. Dropping --bun keeps Bun as
the package manager but runs next dev on Node, which is stable.

Build + start keep --bun since one-shot invocations don't exhibit the
allocator drift.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ng download

No prebuilt Linux binary exists yet (see /linux-install for build-from-source
instructions). The /download page previously treated Linux like the other
platforms — auto-triggering a non-existent AppImage and offering a dead
manual button.

- /download page: if platform resolves to 'linux' via ?platform or UA detect,
  window.location.replace('/linux-install') — never try to auto-download.
- Manual Linux card: label changed to "Build from source" and links to
  /linux-install (no download attribute, no asset URL).
- /download/linux pretty URL: 307s straight to /linux-install.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ates

- Delete docs/TROUBLESHOOTING.md; the canonical troubleshooting guide now
  lives under docs/content/docs/overview/troubleshooting.mdx so it's served
  from docs.voicebox.sh alongside the rest of the docs.
- CONTRIBUTING.md + README.md: repoint "Troubleshooting" references to the
  new MDX path. README gets a top-level callout so users hit the guide
  before filing an issue.
- PROJECT_STATUS.md: refresh issue/PR counts, document the flash-attn
  warning (cosmetic on all platforms; CUDA-only, fallback is PyTorch SDPA
  which is near-FA2 on Ampere+) with per-platform context + community
  Windows wheels + SageAttention/xformers alternatives, add WebAudio
  audio-session bug note (tracked separately in PR #486), and expand the
  Qwen 0.6B→1.7B MLX fallback explanation for triage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Preserve canonical camelCase platform aliases (macArm, macIntel) in the
  /download/[platform] redirect so those URLs don't lose their platform param.
- Add accessible title + role="img" to the inline Windows SVG so it passes
  Biome's a11y rule and announces to screen readers.
- On /api/releases fetch failure, show an explicit error state with a single
  intentional link to GitHub releases — no more silent GitHub fallback or
  disabled-button UX lie. Keeps normies off GitHub unless they opt in.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jamiepine jamiepine merged commit 27a5a62 into main Apr 19, 2026
2 checks passed
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