vrex-flow-engine 0.2.0__py3-none-any.whl

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.
@@ -0,0 +1,77 @@
1
+ """Per-video generation context, captured for extend/edit.
2
+
3
+ Extend and edit need more than a media id. Extend wants the source clip's
4
+ *scene id* and its *operation/generation id* (``video.operation.name`` — which
5
+ differs from the media name); edit wants the source's *workflow id* and *frame
6
+ count*. None of that is recoverable from a bare media id, and there's no
7
+ media→scene reverse lookup, so we capture it as each video job completes and key
8
+ it by the media id flow_engine hands back to the client.
9
+
10
+ In-memory, single process — same model as the media registry. A restart forgets
11
+ it; callers can still drive extend/edit by passing the context explicitly
12
+ (``scene_id`` / ``workflow_id`` on the request). Context is only available for
13
+ videos polled via the workflow schema (low-priority / extend / edit) — that poll
14
+ hits ``/v1/media/<id>`` which carries the workflow/operation/scene fields;
15
+ operation-mode (Lite/Fast/Quality) polls go through ``batchCheckAsync`` and
16
+ don't expose them.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import threading
21
+ from dataclasses import dataclass
22
+ from typing import Optional
23
+
24
+
25
+ @dataclass
26
+ class VideoContext:
27
+ media_id: str
28
+ workflow_id: Optional[str] = None
29
+ operation_id: Optional[str] = None # video.operation.name — extend's source ref
30
+ scene_id: Optional[str] = None
31
+ duration_sec: Optional[float] = None
32
+
33
+
34
+ _registry: dict[str, VideoContext] = {}
35
+ _lock = threading.Lock()
36
+
37
+
38
+ def remember(
39
+ media_id: Optional[str],
40
+ *,
41
+ workflow_id: Optional[str] = None,
42
+ operation_id: Optional[str] = None,
43
+ scene_id: Optional[str] = None,
44
+ duration_sec: Optional[float] = None,
45
+ ) -> None:
46
+ """Record (or merge) what we learned about a generated video. Only non-None
47
+ fields overwrite, so a later, richer poll can fill gaps left by an earlier
48
+ one."""
49
+ if not isinstance(media_id, str) or not media_id:
50
+ return
51
+ with _lock:
52
+ ctx = _registry.get(media_id) or VideoContext(media_id=media_id)
53
+ if workflow_id:
54
+ ctx.workflow_id = workflow_id
55
+ if operation_id:
56
+ ctx.operation_id = operation_id
57
+ if scene_id:
58
+ ctx.scene_id = scene_id
59
+ if duration_sec:
60
+ ctx.duration_sec = duration_sec
61
+ _registry[media_id] = ctx
62
+
63
+
64
+ def get(media_id: str) -> Optional[VideoContext]:
65
+ with _lock:
66
+ return _registry.get(media_id)
67
+
68
+
69
+ def parse_seconds(length: Optional[str]) -> Optional[float]:
70
+ """Parse a Flow duration string like ``"8s"`` into seconds."""
71
+ if not isinstance(length, str):
72
+ return None
73
+ s = length.strip().rstrip("s")
74
+ try:
75
+ return float(s)
76
+ except ValueError:
77
+ return None
@@ -0,0 +1,49 @@
1
+ """Per-instance video context store.
2
+
3
+ Extracted from the module-level ``_registry`` dict in video_context.py so
4
+ each pool instance owns an isolated namespace — video context from account A
5
+ is never accessible to account B.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import threading
10
+ from typing import Optional
11
+
12
+ from flow_engine.video_context import VideoContext
13
+
14
+
15
+ class VideoContextStore:
16
+ """Thread-safe dict-backed video context registry, one per PoolInstance."""
17
+
18
+ def __init__(self) -> None:
19
+ self._registry: dict[str, VideoContext] = {}
20
+ self._lock = threading.Lock()
21
+
22
+ def remember(
23
+ self,
24
+ media_id: Optional[str],
25
+ *,
26
+ workflow_id: Optional[str] = None,
27
+ operation_id: Optional[str] = None,
28
+ scene_id: Optional[str] = None,
29
+ duration_sec: Optional[float] = None,
30
+ ) -> None:
31
+ """Record (or merge) what we learned about a generated video. Only
32
+ non-None fields overwrite, so a later, richer poll can fill gaps."""
33
+ if not isinstance(media_id, str) or not media_id:
34
+ return
35
+ with self._lock:
36
+ ctx = self._registry.get(media_id) or VideoContext(media_id=media_id)
37
+ if workflow_id:
38
+ ctx.workflow_id = workflow_id
39
+ if operation_id:
40
+ ctx.operation_id = operation_id
41
+ if scene_id:
42
+ ctx.scene_id = scene_id
43
+ if duration_sec:
44
+ ctx.duration_sec = duration_sec
45
+ self._registry[media_id] = ctx
46
+
47
+ def get(self, media_id: str) -> Optional[VideoContext]:
48
+ with self._lock:
49
+ return self._registry.get(media_id)
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.4
2
+ Name: vrex-flow-engine
3
+ Version: 0.2.0
4
+ Summary: Launcher + supervisor and OpenAI-compatible image/video generation service (Vrex Flow Engine).
5
+ Author: Vrex
6
+ License: Proprietary
7
+ Project-URL: Homepage, https://getvrex.com
8
+ Keywords: vrex,flow-engine,cli,supervisor,image-generation,video-generation
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: POSIX
13
+ Classifier: Topic :: Multimedia :: Video
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: fastapi>=0.110
17
+ Requires-Dist: uvicorn[standard]>=0.27
18
+ Requires-Dist: httpx>=0.27
19
+ Requires-Dist: websockets>=12.0
20
+ Requires-Dist: pydantic>=2.5
21
+ Requires-Dist: python-multipart>=0.0.9
22
+ Requires-Dist: posthog>=3.8
23
+ Requires-Dist: rich>=13.7
24
+
25
+ # vrex-flow-engine
26
+
27
+ One-command launcher + supervisor for the **Vrex Flow Engine** — a self-hosted
28
+ service that exposes OpenAI-compatible image/video generation endpoints.
29
+
30
+ `vrex-flow-engine start` stores your engine key + Cloudflare tunnel token,
31
+ launches the engine and the tunnel as supervised child processes (with
32
+ crash-restart), and renders a live status dashboard.
33
+
34
+ ## Quickstart
35
+
36
+ ```bash
37
+ uvx vrex-flow-engine start
38
+ ```
39
+
40
+ First run prompts for the engine API key and the Cloudflare tunnel token (saved
41
+ to `~/.vrex-flow/config.json`, chmod 600), then brings up the engine + tunnel.
42
+ Ctrl-C stops both cleanly.
43
+
44
+ ## Commands
45
+
46
+ | Command | What it does |
47
+ |---|---|
48
+ | `vrex-flow-engine start` | Run engine + tunnel with a live dashboard. `--no-tunnel` runs the engine only. |
49
+ | `vrex-flow-engine setup` | Store the engine key + tunnel token. |
50
+ | `vrex-flow-engine doctor` | Check prerequisites and probe a running engine. |
51
+ | `vrex-flow-engine serve` | Run just the engine in the foreground. |
52
+
53
+ The short alias `flow-engine` is installed for the same commands.
54
+
55
+ ## Requirements
56
+
57
+ - Python 3.10+
58
+ - [`cloudflared`](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/)
59
+ (for the tunnel; `--no-tunnel` skips it)
60
+ - Access to a Vrex Flow Engine deployment.
61
+
62
+ Internal Vrex tooling.
@@ -0,0 +1,36 @@
1
+ flow_engine/__init__.py,sha256=bJWwmRl8Qu9j0osEFNf3NBfLC0LRP8EdT-nYE6MwTQA,169
2
+ flow_engine/catalog.py,sha256=_Q4FCgeLtxIcf5Udcsi8XWD_LfkKoWaONNotNmXn_ds,12978
3
+ flow_engine/config.py,sha256=QbvUksexrzFt-JNdzfc2poXK_JPk6BzasKu831l3hYE,2092
4
+ flow_engine/ingest.py,sha256=Xf3drEF9gyTHWBUSa1pJOlu8Wx_gyYe8sguGtRkU3DY,6421
5
+ flow_engine/job_store.py,sha256=0Au6I_q7einhhFCO5Oc4Jjc2dtAAdSfWKWSX4A0WWhA,722
6
+ flow_engine/jobs.py,sha256=uy4U5On7tIO8ml1MZlHjdx1Kd3-MvpNGfp_eOevfkX0,8571
7
+ flow_engine/main.py,sha256=MjOcWFflDePiChUVLCBodrDLARZRFxIq0jxSCHeG7VA,6457
8
+ flow_engine/media.py,sha256=Rm_JH2GEEVJCPgZRbq3vtcjTwiDXq9YADsKfW8p-YQY,7650
9
+ flow_engine/media_store.py,sha256=tgDYyCVpWvxJBkJ1kX-1atT_SahMAsCyDWnI2Irwcro,8028
10
+ flow_engine/pool.py,sha256=wwmv9h7S3mOkJdLtCVaGFklRTyoKgLDh99v7FDwmLQs,5680
11
+ flow_engine/posthog_client.py,sha256=8FPH74rxOgm6vYKyO3RwLBeNW6UxfYZnxkk1DcxQfb4,3672
12
+ flow_engine/session.py,sha256=bv59PsVPPFZl9ygRflVAQCCMyQPr_38pBj6LK2K2qhk,3456
13
+ flow_engine/video_context.py,sha256=u7HNEdsn95EtCitt23stNtie4FFGs8bCUzSW-EM9_Pw,2682
14
+ flow_engine/video_context_store.py,sha256=-5_Sr-lcTSFwjLcNxObwk2PECQE7PbeXuoVqFJH8Pjw,1664
15
+ flow_engine/bridge/__init__.py,sha256=VjD9zKm_UAX0rmHHtNi4lDlZCIb4Lg6o6iEo5rlYtXQ,300
16
+ flow_engine/bridge/flow_client.py,sha256=2mpJY6DXCPz7NGvc70ddl19eq-PRjEWTT5FUQdPEAqc,18889
17
+ flow_engine/bridge/flow_sdk.py,sha256=ynHjY48ms75n2QTnzBn5j2H7ewtOrOYPS9v36GhF7l8,76278
18
+ flow_engine/bridge/ws_server.py,sha256=JFq4Iv5ReVau78z2bxEZWN4XC3GGWkePg3Gq63nDh28,2879
19
+ flow_engine/cli/__init__.py,sha256=xETN-IChMvfTFjcW9vYyZ56UOsS6eIAMh3rNYxywU6w,76
20
+ flow_engine/cli/app.py,sha256=elV35tWQE7kkbHqA4BdLgeeVXLdpkqhgihMwag3yxmI,5694
21
+ flow_engine/cli/config.py,sha256=engG_4HC0E2gDd-pzIiifZAOsYoBbJOfVwL1jfNmdmA,2833
22
+ flow_engine/cli/dashboard.py,sha256=EwIRNaTlIdjy2hwwfoCM4wGybD0hiNnWjgKr7olMRoc,4851
23
+ flow_engine/cli/health.py,sha256=75ObJ-Y7uwYKt1FwZcWrTLSp4Y_Q6EUO5T7oqdm6cQI,1596
24
+ flow_engine/cli/processes.py,sha256=Nem-Z2yhwuYct1nRVvo5yXD2wFTYwil33iXenkFgk8k,3924
25
+ flow_engine/cli/supervisor.py,sha256=WrSbEwac2I1ZxNSkyIOtccNvSk9UcZ5uhluJp7QgjV8,7163
26
+ flow_engine/openai/__init__.py,sha256=KWlJNwXmYcxUPlOoSzwN-FcaWci3_7rKsuA7wMP1ePc,73
27
+ flow_engine/openai/_util.py,sha256=IbB4v8JgaOzvTRU45EJgRqsdD24vfQnVAvEuXLouJ1k,2175
28
+ flow_engine/openai/images.py,sha256=hP1vP_7ysXU-YfavsWzO_PWOJKFeazzbq4XrBOUWvvI,4874
29
+ flow_engine/openai/models.py,sha256=7S0pZ-IAZ4gwrX7ui3DUUilHseEjC2umEOzAdpUGzEY,1240
30
+ flow_engine/openai/uploads.py,sha256=ZFmX0J5BItys4JVbpVk1mc6kgdJPnzZ0x-9BOVzlNHg,2720
31
+ flow_engine/openai/videos.py,sha256=45DkN5gUmCtYqASpbF_MG-gQ5C_dNB7Xd_pjxkQMitg,10505
32
+ vrex_flow_engine-0.2.0.dist-info/METADATA,sha256=_r23P_tWo85zGcvuD_q4UCDXj9tdLwsA5WO9u7uzurw,2151
33
+ vrex_flow_engine-0.2.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
34
+ vrex_flow_engine-0.2.0.dist-info/entry_points.txt,sha256=H022OlR20lq-INQQo1Dp15XJgCJ6H2KfplwEJXayjV0,101
35
+ vrex_flow_engine-0.2.0.dist-info/top_level.txt,sha256=h2-ndJR-ki0pQZt_P2X9s58wpkRdAA-IKPqn4x3R6eA,12
36
+ vrex_flow_engine-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ flow-engine = flow_engine.cli.app:main
3
+ vrex-flow-engine = flow_engine.cli.app:main
@@ -0,0 +1 @@
1
+ flow_engine