Repository navigation
feat(infra): transcribe a stored video by id and write its captions - #4134
Merged
Merged
Conversation
|
Sandchest reviewed Sandchest reviews every change for vulnerabilities an attacker could use · 7 credits · Review details |
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Member
Author
|
hey @greptileai, please re-review the PR |
Member
Author
|
hey @greptileai, please re-review the PR |
This was referenced Nov 13, 2026
…ions # Conflicts: # apps/web/workflows/developer-transcribe.ts # packages/database/migrations/meta/0056_snapshot.json # packages/database/migrations/meta/_journal.json # packages/database/schema.ts
Member
Author
|
hey @greptileai, please re-review the PR |
Member
Author
|
hey @greptileai, please re-review the PR |
This was referenced Nov 13, 2026
Merged
This branch was successfully deployed
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.

A developer can now transcribe a video their app already stores by sending its ID, and every such transcript produces a WebVTT caption file for that video. This is the transcript half of captions. The player and playback routes are not touched here.
Migration 0057, to ship before merge
packages/database/migrations/0057_developer_transcript_video.sql, additive only. It was generated with drizzle-kit after #4142's 0056, chains its snapshot to 0056, and its journalwhenis above every entry on main. It was applied only to scratch databases.The code selects
videoIdandrequestedAt, so both columns have to exist before this deploys. Every existing row keepsNULLin both and behaves as before.requestedAtis written only for video transcripts and orders their captions to the millisecond.What a developer gets
POST /api/developer/v1/transcriptsacceptsvideoIdinstead ofurl. Exactly one of the two: both, or neither, is400 invalid_request. The body is still strict.ready. Otherwise404 video_not_found(unknown, deleted, or another app's) or409 video_not_ready(still uploading or processing, or failed with no file to transcribe).name(defaults to the video's name),language,userId,metadataandIdempotency-Keywork as they do for a URL. A replay with a differentvideoIdis refused and names the field.videoId(nullfor every other transcript) andsource.typeisvideo. The agent API's transcript carriesvideoIdtoo.Captions
When a video transcript completes with speech, a WebVTT file is written at
developer/<appId>/<videoId>/captions/<language>.vtt.&,<and>are escaped, so an arrow in the text cannot end a cue. Control characters and line breaks inside a word become spaces.lib/developer-video-purge.tsdeletes as a whole, so that code needed no change. A test pins that the key is inside that folder and that an encode cleanup leaves it alone.Interface for the playback side
apps/web/lib/developer-video-captions.tsSELECT DISTINCT languageon the new index. No storage listing.[]for a video with no transcripts.labelis the language's English name.keyis the storage key of the caption file.undwith the labelCaptions.Proof
The real database suite includes the existing 23 cases, which never set
videoId, so they run with itNULLon every row.Query plans on the scratch database, in an app with 3,005 transcripts across 60 videos:
developerVideoCaptionsrefondev_transcripts_app_video_idx, 5 rows examinedrefondev_transcripts_app_video_idx, backward index scan, no filesortLocal end to end, no browser: the local web server, a scratch database, the local object store, local ffmpeg and a stub in place of the speech service. A stored video was seeded directly as a
readyrow with its MP4 in the object store, because the encode pipeline is not part of this change. 25 of 25 checks pass:Not covered
developerVideoCaptionsanswers from the database. If a caption write failed after its transcript completed, a file would be listed that does not exist. The write is a workflow step and is retried.videoIdyet. They reportvideoIdon transcripts.After review
404. The decision re-reads the row afterdeletedAtis written, so a transcript that completed during the delete is handled.(status, updatedAt)index.requestedAtand indexes it in place ofcreatedAt(SQL above). It has only run on dropped scratch databases.videoIdis held to the ceiling of 20 queued or processing transcripts per app, like URL and upload transcripts. A repeat of an admitted request is still let through.packages/database/migrate.tson an empty scratch database applies all 58 migrations, and a second run applies nothing.

Confidence Score: 5/5
The PR appears safe to merge once migration `0057` has been applied.Summary
Adds transcription by stored
videoIdand writes WebVTT captions from completed transcripts.richiemcilroy acknowledges that a failed caption write can leave a listed file missing and states that the workflow step retries the write.
Reviews (7) · Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." · Reviewed by Greptile