Skip to content

Assemble video-link import: async pipeline, premium gate, cost controls#89

Merged
windoze95 merged 1 commit into
mainfrom
feat/video-import-assembly
Jun 30, 2026
Merged

Assemble video-link import: async pipeline, premium gate, cost controls#89
windoze95 merged 1 commit into
mainfrom
feat/video-import-assembly

Conversation

@windoze95

Copy link
Copy Markdown
Owner

What this is

PR2c — the final assembly of the video-link import feature (Phase 2.5). It wires the three merged foundation PRs into a working end-to-end pipeline behind a paywall:

A user pastes a TikTok/Instagram/YouTube/Facebook/Pinterest link; we pull the caption + transcript + a downloadable copy of the video, sample representative frames, and run a single multimodal Claude extraction over frames + transcript/caption together to reconstruct the recipe.

Pipeline (async)

POST /v1/recipes/import/video → premium gate → create job → return 202 {job}.
Goroutine: FetchVideoper-video cache checkdaily-budget kill switch → SSRF-guard the scraper media URL → Sample frames → ExtractRecipesFromMedia(frames, transcript+caption) → save recipe → cache the extraction.
GET /v1/recipes/import/video/:id → owner-only status poll (returns recipe_id when done).

Cost controls ("don't let users bleed me")

  • Process-once cache (VideoExtractionCache, keyed platform:video_id): a viral video is extracted once; every later importer is served from cache at $0.
  • Per-user monthly quota: free 2 / premium 20 (CanUseVideoImport).
  • Global daily-budget kill switch: fresh extractions stop once SUM(cost_usd) since UTC-midnight reaches VIDEO_IMPORT_DAILY_BUDGET_USD (default $25).
  • Feature flag: the endpoint returns 503 until SCRAPECREATORS_API_KEY is configured — ships dark.
  • Frame count is the master cost dial (~$0.0048/frame on Sonnet); cost is over-estimated so the kill switch trips early.

Notable decisions

  • Interface ripple: VisionProvider.ExtractRecipesFromMedia gained a contextText arg (transcript/caption); ImportFromFiles passes "".
  • SSRF: the scraper-supplied media URL is validated with the existing ValidateExternalURL before the sampler fetches it. Follow-up: harden the sampler's HTTP client against redirect-hop rebinding (the validator is TOCTOU-imperfect on its own).
  • Quota on accept: usage is incremented when a job is accepted (not on completion) and cache hits still count — a deliberate product/cost choice; documented for review.
  • Bug fix: monthly usage reset now also zeroes VideoImportsUsed in-memory.

Tests

All offline and race-clean (go test ./... -race):

  • Service: fresh extraction, cache hit (no sample/extract), budget-exceeded (fails before sampling), fetch-failure, not-configured, unsupported platform.
  • Handler: gate 403, unconfigured 503, bad platform 400, accept 202 + poll → done, non-owner 404.

Deploy note (not in this PR)

At deploy, add SCRAPECREATORS_API_KEY to the prod ECS task definition to switch the feature on, then run a real TikTok end-to-end check. Only TikTok is implemented in the client so far; IG/YouTube/Facebook/Pinterest detect but return "not yet supported".

🤖 Generated with Claude Code

https://claude.ai/code/session_01BU4UWZutHd1AnK3XAf7H19

Wire the merged video foundation (cache/quota/config #86, ScrapeCreators
client #87, ffmpeg frame sampler #88) into a working end-to-end import:

- VisionProvider.ExtractRecipesFromMedia now takes a contextText arg so a
  video's transcript+caption are extracted alongside the sampled frames.
- ImportService.StartVideoImport accepts a social/video URL, creates an
  async VideoImport job, and processes it in a goroutine: fetch meta ->
  per-video cache check -> daily-budget kill switch -> SSRF-guard the
  scraper media URL -> sample frames -> multimodal extract (frames +
  transcript/caption) -> save recipe -> cache for the next importer.
- Cost controls: process-once VideoExtractionCache (viral videos cost $0
  after the first), per-user monthly quota (free 2 / premium 20), a global
  daily-budget kill switch, and a feature flag that keeps the endpoint dark
  until SCRAPECREATORS_API_KEY is set.
- Endpoints: POST /v1/recipes/import/video (premium-gated, returns a queued
  job) and GET /v1/recipes/import/video/:id (owner-only status poll).
- Fix: monthly usage reset now also zeroes VideoImportsUsed in-memory; mock
  user repo handles the video_imports_used column for parity with prod.

Tests: service-level orchestration (fresh/cache-hit/budget/fetch-fail) and
handler-level (gate 403, unconfigured 503, bad platform 400, accept+poll
202->done, non-owner 404), all offline and race-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BU4UWZutHd1AnK3XAf7H19
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@windoze95 windoze95 merged commit 5816bc8 into main Jun 30, 2026
1 check passed
@windoze95 windoze95 deleted the feat/video-import-assembly branch June 30, 2026 03:37
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