Skip to content

fix(stories): preview 404 — route through job-less /generate - #176

Merged
debpalash merged 1 commit into
mainfrom
fix/stories-preview-404
May 30, 2026
Merged

fix(stories): preview 404 — route through job-less /generate#176
debpalash merged 1 commit into
mainfrom
fix/stories-preview-404

Conversation

@debpalash

@debpalash debpalash commented May 30, 2026

Copy link
Copy Markdown
Owner

The Stories Editor's per-line Preview failed with Preview HTTP 404 (seen live in dev: Failed to load resource: 404 (__stories__)).

Cause: it POSTed to a bare relative /api/dub/preview-segment/__stories__ — that dub route requires a real dub job (__stories__ → 404), and the relative URL also skipped the API base + PIN header.

Fix: route preview through the standalone job-less /generate endpoint via the shared generateSpeech client (same-origin + PIN-aware). Both the simple and [pause]/[voice:] marker-chained preview paths now work.

Verify: typecheck ✓, build ✓, vitest 107/107. This is Task 1 of docs/superpowers/plans/2026-05-30-stories-editor.md; the rest of the "full polish" plan (export, persistence, cast, drag-reorder, i18n) is still available to execute.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Improved reliability of speech preview generation by switching to the standardized audio generation API client.

Review Change Stack

…view-segment/__stories__)

The Stories Editor preview POSTed to a relative /api/dub/preview-segment/__stories__
URL: that dub route requires a real dub job ("__stories__" -> 404) and the bare
relative path skipped the API base + PIN header entirely. Route through the
standalone /generate endpoint via the shared api client (generateSpeech), which
is same-origin and PIN-aware. Per-line and marker-chained preview now work.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a3be79ca-875a-4810-95f0-4d3f4b258121

📥 Commits

Reviewing files that changed from the base of the PR and between e69dcbb and 4515109.

📒 Files selected for processing (1)
  • frontend/src/components/StoriesEditor.jsx

📝 Walkthrough

Walkthrough

StoriesEditor.jsx migrates speech preview generation from the deprecated /api/dub/preview-segment/__stories__ endpoint to the standalone generateSpeech API client. The function now constructs a FormData request with text, speed, and optional profile ID instead of a JSON body, and routes through the new client with added explanatory comments.

Changes

Speech Preview API Migration

Layer / File(s) Summary
Migrate to generateSpeech API client
frontend/src/components/StoriesEditor.jsx
Import generateSpeech from the API module and update fetchChunkAudio to build FormData payloads with text, speed, and profile ID, then call generateSpeech instead of the prior JSON-based fetch to the deprecated endpoint. Inline comments document the migration and previous failure mode.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is detailed and well-structured but lacks alignment with the required template structure including formal sections like Summary, Changes, Type checkboxes, Testing, and Checklist. Restructure the description to follow the provided template with formal sections: Summary, Changes (bulleted list), Type checkbox, Testing section, and complete the checklist items.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the fix for the Stories Editor preview 404 issue by specifying the solution route through the job-less /generate endpoint.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/stories-preview-404

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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.

@greptile-apps

greptile-apps Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes the per-line Preview button in the Stories Editor, which was 404-ing because it posted to /api/dub/preview-segment/__stories__ — a dub route that requires a real job ID — and used a bare relative URL that bypassed the API base URL and PIN header entirely. The fix routes preview requests through generateSpeech from the shared ../api/generate client, which correctly constructs the full URL via apiFetch and attaches the LAN PIN header when one is set.

  • Core fix: fetchChunkAudio now calls generateSpeech(fd) (FormData POST to /generate) instead of a raw fetch to the broken dub segment route; both simple and marker-chained preview paths benefit.
  • Minor leftover: the if (!res.ok) guard after await generateSpeech(fd) is now dead code — apiFetch always throws an ApiError before returning a non-ok Response, so the Preview HTTP ${res.status} message can never surface; errors still propagate correctly to the surrounding try/catch.

Confidence Score: 4/5

Safe to merge; the core routing fix is correct and the only leftover is an unreachable guard that doesn't affect runtime behaviour.

The routing fix is straightforward and well-targeted: generateSpeech correctly builds the full URL, attaches the PIN header, and the /generate endpoint accepts all the FormData fields passed (text, speed, profile_id). The one leftover is the if (!res.ok) check, which can never be true because apiFetch throws before returning a non-ok Response — the track's spinner will still reset correctly via the catch block, but the intended "Preview HTTP ..." error string is silently swallowed.

frontend/src/components/StoriesEditor.jsx — the dead res.ok guard at line 158 is worth cleaning up.

Important Files Changed

Filename Overview
frontend/src/components/StoriesEditor.jsx Replaces 404-producing bare relative fetch with generateSpeech (PIN-aware, correct base URL); the post-call res.ok guard is now dead code since apiFetch throws on non-ok responses.

Fix All in Claude Code

Reviews (1): Last reviewed commit: "fix(stories): preview via job-less /gene..." | Re-trigger Greptile

fd.append('speed', '1.0');
if (profileId) fd.append('profile_id', profileId);
const res = await generateSpeech(fd);
if (!res.ok) throw new Error(`Preview HTTP ${res.status}`);

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.

P2 Dead res.ok guard

apiFetch (called by generateSpeech) always throws an ApiError before returning on any non-2xx response — it never resolves with an error Response. So !res.ok is unreachable: every failure surfaces as a thrown ApiError, which is correctly caught in the parent try/catch in previewTrack. The Preview HTTP ${res.status} string is therefore never shown to the user; the actual message the catch block receives is the ApiError message from apiFetch.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

@debpalash
debpalash merged commit 762f5bf into main May 30, 2026
15 checks passed
@debpalash
debpalash deleted the fix/stories-preview-404 branch May 30, 2026 15:57
debpalash added a commit that referenced this pull request May 30, 2026
…istence, reorder, i18n (#177)

* docs(spec): Stories Editor pro-studio design (line cards, auto-cast, pro output, projects)

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

* feat(stories): Phase 1 — real audiobook output, cast, persistence, reorder, i18n

First phase of the pro-studio Stories Editor (spec:
docs/superpowers/specs/2026-05-30-stories-editor-studio-design.md). Makes the
editor actually produce audiobooks and remember your work:

- Persistence: storiesSlice (tracks + cast) via zustand persist -> localStorage;
  transient fields (generating/audioUrl) stripped on persist; id counter reseeds
  from persisted tracks. Dropped the hardcoded sample seed -> clean empty state.
- Cast: editable CastMember[] (name, color, voice) with a Cast panel; each line
  picks a character and inherits its voice (per-line override still available).
- Real Generate: exportStoryAudio() stitches every line + [pause] gaps into one
  WAV via the Web Audio API (job-less /generate per chunk) with a % progress
  indicator and download. Per-line preview already shipped (#176).
- Reorder: native HTML5 drag-and-drop (pure reorder() helper).
- i18n: all Stories strings via t('stories.*') (en + zh-CN).
- Tests: storiesSlice reducers, storyCast resolution, storyExport WAV/concat/
  silence, storyReorder. 18 new unit tests.

No DB/alembic; localStorage only. Same-origin + PIN-safe synth (apiFetch). No
new deps. Cross-platform-identical default behavior.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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