Skip to content

feat(video): 1080p and 4K delivery via Flow's upsampler - #6

Merged
kodelyx merged 1 commit into
kodelyx:mainfrom
nicolasmg-pr:feat/video-upsample-1080p-4k
Aug 28, 2026
Merged

feat(video): 1080p and 4K delivery via Flow's upsampler#6
kodelyx merged 1 commit into
kodelyx:mainfrom
nicolasmg-pr:feat/video-upsample-1080p-4k

Conversation

@nicolasmg-pr

Copy link
Copy Markdown
Contributor

Summary

Flow generates video at 720p only. The high-resolution download in the Flow UI is a second upsampler pass over the finished media. This PR exposes that pass across the CLI, HTTP API, and MCP server, so 1080p and 4K delivery is available without leaving the tool.

What changed

  • flow_engine/generators/upsample.py (new) — submits POST /v1/video:batchAsyncGenerateVideoUpsampleVideo with videoModelKey: veo_3_1_upsampler_{1080p,4k}, videoInput.mediaId, and a resolution enum. Captcha action is the ordinary VIDEO_GENERATION; polling reuses batchCheckAsyncVideoGenerationStatus.
  • POST /v1/videos/upsample — upsample an already-generated video by media ID or by a local path already in history. Returns the same pollable job shape as generation, polled through GET /v1/videos/generations/{job_id}.
  • resolution on POST /v1/videos/generations"720p" | "1080p" | "4k". When the request upsamples, the response leads with the upsampled entry so clients that treat data[0] as "the" output (the CLI's --output) get the high-resolution file. The 720p original stays in data and in history.json. Entries now carry resolution, and upsampled ones carry source_media_id.
  • CLIflow upsample <media_id|path> --resolution {1080p,4k} and flow video --resolution.
  • MCP — new upsample_flow_video tool; generate_flow_video gains resolution.
  • Docs — README covers the resolution flow, the new endpoint and tool, the env overrides, and a troubleshooting entry for "asked for 1080p, got 720p".

Handling an undocumented endpoint

The upsample endpoint is not published, so the resolution enum spelling is a guess that Google can change. Rather than hardcode it:

  • Model keys and enums are env-overridable — VIDEO_UPSAMPLER_1080P_MODEL, VIDEO_UPSAMPLER_4K_MODEL, VIDEO_UPSAMPLE_ENUM_1080P, VIDEO_UPSAMPLE_ENUM_4K.
  • A request rejected for its shape is retried with the other known enum spelling, then with the field omitted entirely (the model key alone already encodes the target). Only shape rejections retry — a real failure raises immediately, so the ladder cannot start two generations and double-charge.
  • python -m flow_server.sniff remains the way to re-derive the wire format if Google changes it.

Money

Generation spends real credits, so this follows the existing invariants:

  • 1080p upsampling is free. 4K costs credits and is gated by _ensure_upsample_credits, which refuses with HTTP 402 when the balance cannot cover it — before anything is submitted.
  • A failed upsample still delivers the 720p video with a note, rather than failing the whole generation and wasting the spend.
  • Upsample jobs go through the existing idempotency and durable-job persistence.

Tests

tests/test_video_upsample.py (new) covers the enum retry ladder, the credit gate, response ordering, and the degrade-to-720p path.

74 passed

Three failures in tests/test_ext_http_api.py are environmental — OSError: [Errno 48] Address already in use, a local backend holding :8001 during the run. They pass on a free port and are untouched by this branch.

ruff check . --select F,E9 reports 4 pre-existing F401s in t2v.py, v2v.py, and batch.py. This branch does not touch those files, so they were left alone to keep the diff scoped — happy to fold the cleanup in if you'd prefer.

Verification

Exercised end-to-end against a live signed-in Flow session through the MCP server: backend serves /v1/videos/upsample, the CLI exposes flow upsample, and both MCP tools advertise resolution.

🤖 Generated with Claude Code

Flow generates video at 720p only; the Flow UI's high-resolution download
is a second pass over the finished media against an upsampler model. This
exposes that pass across the CLI, HTTP API, and MCP server.

- flow_engine/generators/upsample.py: submits
  POST /v1/video:batchAsyncGenerateVideoUpsampleVideo with
  videoModelKey veo_3_1_upsampler_{1080p,4k}, polled through the ordinary
  batchCheckAsyncVideoGenerationStatus endpoint.
- The endpoint is undocumented, so model keys and the resolution enum are
  env-overridable (VIDEO_UPSAMPLER_*_MODEL, VIDEO_UPSAMPLE_ENUM_*), and a
  request rejected for its shape is retried with the other known enum
  spelling and then with the field omitted. Only shape rejections retry;
  a real failure raises immediately, so the ladder cannot double-charge.
- POST /v1/videos/upsample and a `resolution` field on
  POST /v1/videos/generations both route through the generator. When
  generation upsamples, the response leads with the upsampled entry so
  clients that treat data[0] as "the" output get the high-resolution file;
  the 720p original stays in data and in history. Entries carry
  `resolution` and, for upsampled files, `source_media_id`.
- 1080p is free. 4K costs credits and is gated by _ensure_upsample_credits,
  which refuses with HTTP 402 when the balance cannot cover it.
- A failed upsample still delivers the 720p video with a note rather than
  failing the whole generation.
- CLI: `flow upsample <media_id|path>` and `flow video --resolution`.
- MCP: new `upsample_flow_video` tool; `generate_flow_video` gains
  `resolution`.

Tests in tests/test_video_upsample.py cover the enum retry ladder, the
credit gate, response ordering, and the degrade-to-720p path.

Co-Authored-By: Claude Opus 5 <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.

2 participants