vrex-flow-engine 0.3.0__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/PKG-INFO +1 -1
  2. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/bridge/flow_rpc.py +22 -0
  3. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/bridge/flow_sdk.py +47 -4
  4. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/catalog.py +3 -4
  5. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/jobs.py +1 -0
  6. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/openai/videos.py +15 -9
  7. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/pyproject.toml +1 -1
  8. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/vrex_flow_engine.egg-info/PKG-INFO +1 -1
  9. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/PYPI_README.md +0 -0
  10. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/__init__.py +0 -0
  11. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/bridge/__init__.py +0 -0
  12. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/bridge/flow_client.py +0 -0
  13. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/bridge/ws_server.py +0 -0
  14. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/cli/__init__.py +0 -0
  15. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/cli/app.py +0 -0
  16. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/cli/config.py +0 -0
  17. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/cli/dashboard.py +0 -0
  18. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/cli/health.py +0 -0
  19. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/cli/processes.py +0 -0
  20. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/cli/supervisor.py +0 -0
  21. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/config.py +0 -0
  22. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/ingest.py +0 -0
  23. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/job_store.py +0 -0
  24. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/main.py +0 -0
  25. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/media.py +0 -0
  26. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/media_store.py +0 -0
  27. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/openai/__init__.py +0 -0
  28. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/openai/_util.py +0 -0
  29. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/openai/images.py +0 -0
  30. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/openai/models.py +0 -0
  31. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/openai/uploads.py +0 -0
  32. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/pool.py +0 -0
  33. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/posthog_client.py +0 -0
  34. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/session.py +0 -0
  35. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/video_context.py +0 -0
  36. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/flow_engine/video_context_store.py +0 -0
  37. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/setup.cfg +0 -0
  38. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/vrex_flow_engine.egg-info/SOURCES.txt +0 -0
  39. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/vrex_flow_engine.egg-info/dependency_links.txt +0 -0
  40. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/vrex_flow_engine.egg-info/entry_points.txt +0 -0
  41. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/vrex_flow_engine.egg-info/requires.txt +0 -0
  42. {vrex_flow_engine-0.3.0 → vrex_flow_engine-0.3.2}/vrex_flow_engine.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vrex-flow-engine
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Launcher + supervisor and OpenAI-compatible image/video generation service (Vrex Flow Engine).
5
5
  Author: Vrex
6
6
  License: Proprietary
@@ -29,6 +29,7 @@ RPC_GENERATE_IMAGE = "ogiZ0b"
29
29
  RPC_GENERATE_VIDEO_T2V = "YhhmEf"
30
30
  RPC_GENERATE_VIDEO_I2V = "eb1hJf"
31
31
  RPC_GENERATE_VIDEO_R2V = "MZZa6b"
32
+ RPC_GENERATE_VIDEO_INTERPOLATION = "nprQif"
32
33
  RPC_GENERATE_VIDEO = RPC_GENERATE_VIDEO_T2V # historical alias
33
34
  RPC_CHECK_MEDIA = "jwpduf"
34
35
  RPC_GET_MEDIA = "as29s"
@@ -169,6 +170,27 @@ def video_request_item_i2v(
169
170
  ]
170
171
 
171
172
 
173
+ def video_request_item_interpolation(
174
+ prompt: str,
175
+ model_key: str,
176
+ aspect_enum: int,
177
+ start_media_id: str,
178
+ end_media_id: str,
179
+ seed: Optional[int] = None,
180
+ crop: Optional[list[Any]] = None,
181
+ ) -> list[Any]:
182
+ """Frames-to-video item (``nprQif``): the i2v item with the end frame in
183
+ the slot before the metadata — ``[textInput, modelKey, aspect, seed,
184
+ startImage, endImage, metadata]``. Passing the same media id for both
185
+ frames yields a clip that ends where it began (a seamless loop)."""
186
+ return [
187
+ _text_input(prompt), model_key, aspect_enum, seed,
188
+ [None, start_media_id, None, None, None, crop],
189
+ [None, end_media_id, None, None, None, crop],
190
+ _item_metadata(),
191
+ ]
192
+
193
+
172
194
  def video_request_item_r2v(
173
195
  prompt: str,
174
196
  model_key: str,
@@ -5,10 +5,10 @@ and the job debug endpoint can inspect Flow's payload when a shape drifts.
5
5
 
6
6
  Wired from flow.google.com captures (2026-09): project list/create, model
7
7
  catalog, credits/tier, preset voices, image upload (inline) and resumable
8
- video upload, image generation (sync), text-/image-/reference-to-video,
9
- media status polling and signed URL resolution. Frame interpolation, extend
10
- and edit still need their batchexecute payload captured — the videos route
11
- answers 501 for them instead of guessing array positions.
8
+ video upload, image generation (sync), text-/image-/reference-to-video and
9
+ frames-to-video (interpolation), media status polling and signed URL
10
+ resolution. Extend and edit still need their batchexecute payload captured —
11
+ the videos route answers 501 for them instead of guessing array positions.
12
12
  """
13
13
  from __future__ import annotations
14
14
 
@@ -350,6 +350,49 @@ class FlowSDK:
350
350
  ]
351
351
  return await self._dispatch_video(flow_rpc.RPC_GENERATE_VIDEO_I2V, items, project_id, scene_id)
352
352
 
353
+ async def gen_video_interpolation(
354
+ self,
355
+ prompt: str,
356
+ project_id: str,
357
+ start_media_ids: list[str],
358
+ end_media_ids: Optional[list[str]] = None,
359
+ aspect_ratio: str = "VIDEO_ASPECT_RATIO_LANDSCAPE",
360
+ paygate_tier: Optional[int] = None,
361
+ seed: Optional[int] = None,
362
+ model_key: Optional[str] = None,
363
+ scene_id: Optional[str] = None,
364
+ ) -> dict[str, Any]:
365
+ """Frames-to-video: motion between a start and an end frame, one clip
366
+ per pair. ``end_media_ids`` defaults to ``start_media_ids`` — the
367
+ seamless-loop case; when both are given they are zipped pairwise and
368
+ must be the same length."""
369
+ if paygate_tier is None:
370
+ raise ValueError("paygate_tier is required — resolve the account first")
371
+ if not model_key:
372
+ return {"raw": None, "error": "interpolation_model_key_required"}
373
+ aspect_enum = flow_rpc.VIDEO_ASPECT_ENUM.get(aspect_ratio)
374
+ if aspect_enum is None:
375
+ return {"raw": None, "error": f"interpolation_aspect_unsupported_{aspect_ratio}"}
376
+ starts = [m for m in (start_media_ids or []) if isinstance(m, str) and m]
377
+ if not starts:
378
+ return {"raw": None, "error": "missing_start_media_id"}
379
+ ends = [m for m in (end_media_ids or []) if isinstance(m, str) and m] or list(starts)
380
+ if len(ends) != len(starts):
381
+ return {
382
+ "raw": None,
383
+ "error": (
384
+ f"start/end frame count mismatch: {len(starts)} start vs "
385
+ f"{len(ends)} end — pass equal-length lists or omit end frames"
386
+ ),
387
+ }
388
+ items = [
389
+ flow_rpc.video_request_item_interpolation(prompt, model_key, aspect_enum, s, e, seed=seed)
390
+ for s, e in list(zip(starts, ends))[:MAX_VARIANT_COUNT]
391
+ ]
392
+ return await self._dispatch_video(
393
+ flow_rpc.RPC_GENERATE_VIDEO_INTERPOLATION, items, project_id, scene_id
394
+ )
395
+
353
396
  async def gen_video_r2v(
354
397
  self,
355
398
  prompt: str,
@@ -33,10 +33,9 @@ _CACHE_FILE = STORAGE_DIR / "catalog.json"
33
33
  _CACHE_VERSION = 2
34
34
 
35
35
  # Modes whose batchexecute payload has been captured and verified. Other modes
36
- # (interpolation, extension, edit, upsample) still resolve a key so the error
37
- # can name it, but resolve() reports them as not dispatchable and the route
38
- # answers 501.
39
- _DISPATCHABLE_MODES: frozenset[str] = frozenset({"t2v", "i2v", "r2v"})
36
+ # (extension, edit, upsample) still resolve a key so the error can name it,
37
+ # but resolve() reports them as not dispatchable and the route answers 501.
38
+ _DISPATCHABLE_MODES: frozenset[str] = frozenset({"t2v", "i2v", "r2v", "interpolation"})
40
39
 
41
40
 
42
41
  class _Catalog:
@@ -60,6 +60,7 @@ _DISPATCH = {
60
60
  "t2v": "gen_video_t2v",
61
61
  "i2v": "gen_video",
62
62
  "r2v": "gen_video_r2v",
63
+ "interpolation": "gen_video_interpolation",
63
64
  }
64
65
 
65
66
 
@@ -15,10 +15,9 @@ The generation MODE is inferred from the inputs you provide:
15
15
  - ``start_media_ids`` / ``start_images`` → image-to-video (i2v, "Frames")
16
16
  - neither → text-to-video (t2v, prompt only)
17
17
 
18
- Text-, image- and reference-to-video have captured flow.google.com payloads.
19
- Interpolation (end frames / ``loop``), ``mode: extend|edit`` and r2v
20
- ``reference_audio`` answer HTTP 501 until their request is recorded and
21
- ported (see flow-engine/README.md).
18
+ Text-, image-, reference- and frames-to-video have captured flow.google.com
19
+ payloads. ``mode: extend|edit`` and r2v ``reference_audio`` answer HTTP 501
20
+ until their request is recorded and ported (see flow-engine/README.md).
22
21
  """
23
22
  from __future__ import annotations
24
23
 
@@ -39,7 +38,7 @@ router = APIRouter(prefix="/v1/videos", tags=["videos"])
39
38
  ALLOWED_VIDEO_MODEL = "veo_3_1_lite_low_priority"
40
39
 
41
40
  # Modes with a verified flow.google.com payload.
42
- SUPPORTED_MODES = frozenset({"t2v", "i2v", "r2v"})
41
+ SUPPORTED_MODES = frozenset({"t2v", "i2v", "r2v", "interpolation"})
43
42
 
44
43
 
45
44
  class VideoRequest(BaseModel):
@@ -70,8 +69,9 @@ class VideoRequest(BaseModel):
70
69
  source_seconds: Optional[int] = None # edit: source clip length (→ frames)
71
70
 
72
71
 
73
- def _infer_mode(req: VideoRequest) -> str:
74
- """Pick the generation mode from the request shape (explicit ``mode`` wins)."""
72
+ def _select_mode(req: VideoRequest) -> str:
73
+ """Pick the generation mode from the request shape (explicit ``mode`` wins).
74
+ ``loop`` is sugar for "end frame is the start frame", i.e. interpolation."""
75
75
  explicit = (req.mode or "").lower().strip()
76
76
  if explicit in ("extend", "extension"):
77
77
  return "extension"
@@ -129,7 +129,7 @@ async def create_video(
129
129
  detail=f"only model={ALLOWED_VIDEO_MODEL!r} is supported",
130
130
  )
131
131
 
132
- mode = _infer_mode(req)
132
+ mode = _select_mode(req)
133
133
  if mode not in SUPPORTED_MODES or (mode == "r2v" and req.reference_audio):
134
134
  # Decided before any upload so a caller never pays for reference
135
135
  # ingestion on a request that cannot be dispatched.
@@ -166,10 +166,16 @@ async def create_video(
166
166
  ref_ids = list(req.ref_media_ids or [])
167
167
  ref_ids += await ingest.resolve_image_inputs(sdk, project_id, req.ref_images)
168
168
  kwargs["ref_media_ids"] = ref_ids
169
- elif mode == "i2v":
169
+ elif mode in ("i2v", "interpolation"):
170
170
  start_ids = list(req.start_media_ids or [])
171
171
  start_ids += await ingest.resolve_image_inputs(sdk, project_id, req.start_images)
172
172
  kwargs["start_media_ids"] = start_ids
173
+ if mode == "interpolation":
174
+ end_ids = list(req.end_media_ids or [])
175
+ end_ids += await ingest.resolve_image_inputs(sdk, project_id, req.end_images)
176
+ # `loop` = end frame is the start frame; gen_video_interpolation
177
+ # defaults to that when no end frames are given.
178
+ kwargs["end_media_ids"] = end_ids or None
173
179
 
174
180
  try:
175
181
  job = jobs.start_video_job(
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vrex-flow-engine"
3
- version = "0.3.0"
3
+ version = "0.3.2"
4
4
  description = "Launcher + supervisor and OpenAI-compatible image/video generation service (Vrex Flow Engine)."
5
5
  # Neutral public description (the in-repo README.md carries the full internal docs).
6
6
  readme = "PYPI_README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vrex-flow-engine
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Launcher + supervisor and OpenAI-compatible image/video generation service (Vrex Flow Engine).
5
5
  Author: Vrex
6
6
  License: Proprietary