hugpy-video 0.2.3__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 (165) hide show
  1. hugpy_video-0.2.3/LICENSE +41 -0
  2. hugpy_video-0.2.3/PKG-INFO +104 -0
  3. hugpy_video-0.2.3/README.md +53 -0
  4. hugpy_video-0.2.3/pyproject.toml +81 -0
  5. hugpy_video-0.2.3/setup.cfg +4 -0
  6. hugpy_video-0.2.3/src/hugpy_video/__init__.py +33 -0
  7. hugpy_video-0.2.3/src/hugpy_video/chat_video/__init__.py +1 -0
  8. hugpy_video-0.2.3/src/hugpy_video/chat_video/video_analyzer.py +174 -0
  9. hugpy_video-0.2.3/src/hugpy_video/cli.py +130 -0
  10. hugpy_video-0.2.3/src/hugpy_video/config.py +79 -0
  11. hugpy_video-0.2.3/src/hugpy_video/hooks.py +152 -0
  12. hugpy_video-0.2.3/src/hugpy_video/intel/__init__.py +10 -0
  13. hugpy_video-0.2.3/src/hugpy_video/intel/audio_schema.py +44 -0
  14. hugpy_video-0.2.3/src/hugpy_video/intel/chains.py +174 -0
  15. hugpy_video-0.2.3/src/hugpy_video/intel/crop_schema.py +53 -0
  16. hugpy_video-0.2.3/src/hugpy_video/intel/ffprobe.py +28 -0
  17. hugpy_video-0.2.3/src/hugpy_video/intel/frame_schema.py +81 -0
  18. hugpy_video-0.2.3/src/hugpy_video/intel/gen_schema.py +132 -0
  19. hugpy_video-0.2.3/src/hugpy_video/intel/identity_from_video_schema.py +118 -0
  20. hugpy_video-0.2.3/src/hugpy_video/intel/identity_profiles.py +2182 -0
  21. hugpy_video-0.2.3/src/hugpy_video/intel/identity_reconstruction_schema.py +567 -0
  22. hugpy_video-0.2.3/src/hugpy_video/intel/identity_video_extract_schema.py +180 -0
  23. hugpy_video-0.2.3/src/hugpy_video/intel/job_bridge.py +345 -0
  24. hugpy_video-0.2.3/src/hugpy_video/intel/job_lifecycle.py +1188 -0
  25. hugpy_video-0.2.3/src/hugpy_video/intel/job_schema.py +149 -0
  26. hugpy_video-0.2.3/src/hugpy_video/intel/media_bus.py +2496 -0
  27. hugpy_video-0.2.3/src/hugpy_video/intel/media_schema.py +98 -0
  28. hugpy_video-0.2.3/src/hugpy_video/intel/media_store.py +216 -0
  29. hugpy_video-0.2.3/src/hugpy_video/intel/mlt_render_schema.py +215 -0
  30. hugpy_video-0.2.3/src/hugpy_video/intel/movie_schema.py +325 -0
  31. hugpy_video-0.2.3/src/hugpy_video/intel/net.py +16 -0
  32. hugpy_video-0.2.3/src/hugpy_video/intel/placement.py +203 -0
  33. hugpy_video-0.2.3/src/hugpy_video/intel/plane.py +39 -0
  34. hugpy_video-0.2.3/src/hugpy_video/intel/presets.py +645 -0
  35. hugpy_video-0.2.3/src/hugpy_video/intel/prompt_intent.py +234 -0
  36. hugpy_video-0.2.3/src/hugpy_video/intel/prompt_seeds.py +256 -0
  37. hugpy_video-0.2.3/src/hugpy_video/intel/prompt_spread.py +880 -0
  38. hugpy_video-0.2.3/src/hugpy_video/intel/reservation/__init__.py +67 -0
  39. hugpy_video-0.2.3/src/hugpy_video/intel/reservation/engine.py +832 -0
  40. hugpy_video-0.2.3/src/hugpy_video/intel/reservation/registry.py +348 -0
  41. hugpy_video-0.2.3/src/hugpy_video/intel/reservation/templates.py +467 -0
  42. hugpy_video-0.2.3/src/hugpy_video/intel/result_schema.py +67 -0
  43. hugpy_video-0.2.3/src/hugpy_video/intel/runners/__init__.py +81 -0
  44. hugpy_video-0.2.3/src/hugpy_video/intel/runners/_gpu_guard.py +119 -0
  45. hugpy_video-0.2.3/src/hugpy_video/intel/runners/_img2img.py +137 -0
  46. hugpy_video-0.2.3/src/hugpy_video/intel/runners/ffmpeg_audio.py +96 -0
  47. hugpy_video-0.2.3/src/hugpy_video/intel/runners/ffmpeg_crop.py +120 -0
  48. hugpy_video-0.2.3/src/hugpy_video/intel/runners/ffmpeg_frames.py +148 -0
  49. hugpy_video-0.2.3/src/hugpy_video/intel/runners/identity_from_video.py +386 -0
  50. hugpy_video-0.2.3/src/hugpy_video/intel/runners/identity_mesh.py +221 -0
  51. hugpy_video-0.2.3/src/hugpy_video/intel/runners/identity_reconstruction.py +337 -0
  52. hugpy_video-0.2.3/src/hugpy_video/intel/runners/identity_render_client.py +298 -0
  53. hugpy_video-0.2.3/src/hugpy_video/intel/runners/identity_render_relay.py +657 -0
  54. hugpy_video-0.2.3/src/hugpy_video/intel/runners/identity_video_extract_relay.py +439 -0
  55. hugpy_video-0.2.3/src/hugpy_video/intel/runners/imagegen.py +293 -0
  56. hugpy_video-0.2.3/src/hugpy_video/intel/runners/mlt_render.py +472 -0
  57. hugpy_video-0.2.3/src/hugpy_video/intel/runners/movie.py +622 -0
  58. hugpy_video-0.2.3/src/hugpy_video/intel/runners/scene.py +693 -0
  59. hugpy_video-0.2.3/src/hugpy_video/intel/runners/sidecar.py +28 -0
  60. hugpy_video-0.2.3/src/hugpy_video/intel/runners/studio_i2v.py +1116 -0
  61. hugpy_video-0.2.3/src/hugpy_video/intel/runners/studio_movie.py +1348 -0
  62. hugpy_video-0.2.3/src/hugpy_video/intel/runners/studio_placement.py +221 -0
  63. hugpy_video-0.2.3/src/hugpy_video/intel/runners/studio_tester.py +26 -0
  64. hugpy_video-0.2.3/src/hugpy_video/intel/runners/tts_chatterbox.py +85 -0
  65. hugpy_video-0.2.3/src/hugpy_video/intel/scene_schema.py +161 -0
  66. hugpy_video-0.2.3/src/hugpy_video/intel/shot_intent.py +127 -0
  67. hugpy_video-0.2.3/src/hugpy_video/intel/studio/__init__.py +114 -0
  68. hugpy_video-0.2.3/src/hugpy_video/intel/studio/artifacts.py +25 -0
  69. hugpy_video-0.2.3/src/hugpy_video/intel/studio/editor_handoff.py +171 -0
  70. hugpy_video-0.2.3/src/hugpy_video/intel/studio/enums.py +173 -0
  71. hugpy_video-0.2.3/src/hugpy_video/intel/studio/env.py +77 -0
  72. hugpy_video-0.2.3/src/hugpy_video/intel/studio/errors.py +170 -0
  73. hugpy_video-0.2.3/src/hugpy_video/intel/studio/job.py +469 -0
  74. hugpy_video-0.2.3/src/hugpy_video/intel/studio/manifest.py +567 -0
  75. hugpy_video-0.2.3/src/hugpy_video/intel/studio/models_seed.py +538 -0
  76. hugpy_video-0.2.3/src/hugpy_video/intel/studio/movie_plan.py +314 -0
  77. hugpy_video-0.2.3/src/hugpy_video/intel/studio/presence.py +97 -0
  78. hugpy_video-0.2.3/src/hugpy_video/intel/studio/presets.py +707 -0
  79. hugpy_video-0.2.3/src/hugpy_video/intel/studio/produce.py +355 -0
  80. hugpy_video-0.2.3/src/hugpy_video/intel/studio/registry.py +283 -0
  81. hugpy_video-0.2.3/src/hugpy_video/intel/studio/router.py +486 -0
  82. hugpy_video-0.2.3/src/hugpy_video/intel/studio/runners/__init__.py +20 -0
  83. hugpy_video-0.2.3/src/hugpy_video/intel/studio/runners/cancel.py +18 -0
  84. hugpy_video-0.2.3/src/hugpy_video/intel/studio/runners/ffmpeg_enhance.py +362 -0
  85. hugpy_video-0.2.3/src/hugpy_video/intel/studio/runners/ltx_upscale.py +134 -0
  86. hugpy_video-0.2.3/src/hugpy_video/intel/studio/runners/rife_interpolate.py +117 -0
  87. hugpy_video-0.2.3/src/hugpy_video/intel/studio/runners/source.py +10 -0
  88. hugpy_video-0.2.3/src/hugpy_video/intel/studio/runners/synthetic.py +524 -0
  89. hugpy_video-0.2.3/src/hugpy_video/intel/studio/runners/wan_i2v.py +2026 -0
  90. hugpy_video-0.2.3/src/hugpy_video/intel/studio/runners/wan_t2v.py +61 -0
  91. hugpy_video-0.2.3/src/hugpy_video/intel/studio/runners/wan_vace.py +696 -0
  92. hugpy_video-0.2.3/src/hugpy_video/intel/studio/schemas.py +515 -0
  93. hugpy_video-0.2.3/src/hugpy_video/intel/studio/storage.py +40 -0
  94. hugpy_video-0.2.3/src/hugpy_video/intel/studio/tester.py +542 -0
  95. hugpy_video-0.2.3/src/hugpy_video/intel/studio_movie_schema.py +699 -0
  96. hugpy_video-0.2.3/src/hugpy_video/intel/studio_presets.py +512 -0
  97. hugpy_video-0.2.3/src/hugpy_video/jobs.py +74 -0
  98. hugpy_video-0.2.3/src/hugpy_video/plugin.py +61 -0
  99. hugpy_video-0.2.3/src/hugpy_video/plugin_builders.py +54 -0
  100. hugpy_video-0.2.3/src/hugpy_video/py.typed +0 -0
  101. hugpy_video-0.2.3/src/hugpy_video/schemas/__init__.py +0 -0
  102. hugpy_video-0.2.3/src/hugpy_video/schemas/video_schemas.py +45 -0
  103. hugpy_video-0.2.3/src/hugpy_video/selftest.py +92 -0
  104. hugpy_video-0.2.3/src/hugpy_video/state.py +111 -0
  105. hugpy_video-0.2.3/src/hugpy_video/studio_assist_log.py +434 -0
  106. hugpy_video-0.2.3/src/hugpy_video/video_gen/__init__.py +9 -0
  107. hugpy_video-0.2.3/src/hugpy_video/video_gen/schemas.py +71 -0
  108. hugpy_video-0.2.3/src/hugpy_video/video_gen/video_gen_runner.py +100 -0
  109. hugpy_video-0.2.3/src/hugpy_video.egg-info/PKG-INFO +104 -0
  110. hugpy_video-0.2.3/src/hugpy_video.egg-info/SOURCES.txt +163 -0
  111. hugpy_video-0.2.3/src/hugpy_video.egg-info/dependency_links.txt +1 -0
  112. hugpy_video-0.2.3/src/hugpy_video.egg-info/entry_points.txt +5 -0
  113. hugpy_video-0.2.3/src/hugpy_video.egg-info/requires.txt +30 -0
  114. hugpy_video-0.2.3/src/hugpy_video.egg-info/scm_file_list.json +159 -0
  115. hugpy_video-0.2.3/src/hugpy_video.egg-info/scm_version.json +8 -0
  116. hugpy_video-0.2.3/src/hugpy_video.egg-info/top_level.txt +1 -0
  117. hugpy_video-0.2.3/tests/conftest.py +59 -0
  118. hugpy_video-0.2.3/tests/test_cli.py +60 -0
  119. hugpy_video-0.2.3/tests/test_clip_length.py +632 -0
  120. hugpy_video-0.2.3/tests/test_generate_image_worker_jail_ingest.py +255 -0
  121. hugpy_video-0.2.3/tests/test_hooks.py +83 -0
  122. hugpy_video-0.2.3/tests/test_id_lock_never_silently_drops.py +101 -0
  123. hugpy_video-0.2.3/tests/test_identity_cleanup_prompt_schema.py +136 -0
  124. hugpy_video-0.2.3/tests/test_identity_cleanup_prompt_wiring.py +237 -0
  125. hugpy_video-0.2.3/tests/test_identity_video_extract_schema.py +203 -0
  126. hugpy_video-0.2.3/tests/test_import_policy.py +108 -0
  127. hugpy_video-0.2.3/tests/test_invariants_conformance.py +404 -0
  128. hugpy_video-0.2.3/tests/test_job_lifecycle.py +638 -0
  129. hugpy_video-0.2.3/tests/test_jobs_api.py +89 -0
  130. hugpy_video-0.2.3/tests/test_k120_continuity_refresh.py +164 -0
  131. hugpy_video-0.2.3/tests/test_media_bus_fork_reset.py +85 -0
  132. hugpy_video-0.2.3/tests/test_media_bus_reaper.py +328 -0
  133. hugpy_video-0.2.3/tests/test_media_bus_stale_handle.py +71 -0
  134. hugpy_video-0.2.3/tests/test_media_placement.py +166 -0
  135. hugpy_video-0.2.3/tests/test_media_stage_timeline.py +232 -0
  136. hugpy_video-0.2.3/tests/test_model_battery.py +396 -0
  137. hugpy_video-0.2.3/tests/test_movie_presets_selftest.py +74 -0
  138. hugpy_video-0.2.3/tests/test_placement_need.py +730 -0
  139. hugpy_video-0.2.3/tests/test_plugin.py +40 -0
  140. hugpy_video-0.2.3/tests/test_presets.py +876 -0
  141. hugpy_video-0.2.3/tests/test_prompt_seeds.py +128 -0
  142. hugpy_video-0.2.3/tests/test_refuse_not_route.py +516 -0
  143. hugpy_video-0.2.3/tests/test_reservation_admission.py +386 -0
  144. hugpy_video-0.2.3/tests/test_reservation_engine.py +228 -0
  145. hugpy_video-0.2.3/tests/test_reservation_media_bus.py +129 -0
  146. hugpy_video-0.2.3/tests/test_reservation_registry.py +130 -0
  147. hugpy_video-0.2.3/tests/test_reservation_templates.py +128 -0
  148. hugpy_video-0.2.3/tests/test_studio_assist_log.py +131 -0
  149. hugpy_video-0.2.3/tests/test_studio_cancel.py +282 -0
  150. hugpy_video-0.2.3/tests/test_studio_conformance.py +773 -0
  151. hugpy_video-0.2.3/tests/test_studio_device_budget.py +112 -0
  152. hugpy_video-0.2.3/tests/test_studio_hot_weights.py +214 -0
  153. hugpy_video-0.2.3/tests/test_studio_movie_offload.py +544 -0
  154. hugpy_video-0.2.3/tests/test_studio_placement.py +287 -0
  155. hugpy_video-0.2.3/tests/test_studio_prompt.py +322 -0
  156. hugpy_video-0.2.3/tests/test_studio_runner_gate.py +339 -0
  157. hugpy_video-0.2.3/tests/test_studio_sampler_defaults.py +535 -0
  158. hugpy_video-0.2.3/tests/test_studio_t2v.py +401 -0
  159. hugpy_video-0.2.3/tests/test_tester_settings.py +51 -0
  160. hugpy_video-0.2.3/tests/test_video_gen_runner.py +73 -0
  161. hugpy_video-0.2.3/tests/test_video_legacy_chain.py +157 -0
  162. hugpy_video-0.2.3/tests/test_video_movie.py +624 -0
  163. hugpy_video-0.2.3/tests/test_video_progress_archive.py +337 -0
  164. hugpy_video-0.2.3/tests/test_video_start_image_required.py +195 -0
  165. hugpy_video-0.2.3/tests/test_wan_i2v_shape_incident.py +381 -0
@@ -0,0 +1,41 @@
1
+ hugpy — Source-Available License
2
+
3
+ Copyright (c) 2026 putkoff (hugpy.ai). All rights reserved.
4
+
5
+ Permission is granted, free of charge, to use this software ("hugpy") for
6
+ personal and non-commercial purposes, and for time-limited commercial
7
+ evaluation, subject to the following conditions:
8
+
9
+ 1. Non-commercial use means use by an individual for personal purposes, or
10
+ use by a non-profit or educational institution for its own internal
11
+ purposes. Any use by, for, or on behalf of a for-profit business or in
12
+ connection with revenue-generating activity is commercial use — including
13
+ internal business use, use in producing goods or services, and use on
14
+ paid engagements.
15
+
16
+ 2. Commercial use requires a commercial license from the copyright holder.
17
+ Exception: a business may evaluate the software internally for up to
18
+ thirty (30) days free of charge; continued use after that requires a
19
+ commercial license.
20
+
21
+ 3. Redistribution of this software, in source or binary form, modified or
22
+ unmodified, is not permitted without prior written permission from the
23
+ copyright holder. Downloading the software from an official distribution
24
+ channel (PyPI, npm, hugpy.ai) is not redistribution.
25
+
26
+ 4. Modification for personal use or internal evaluation is permitted;
27
+ distribution of modified versions is not.
28
+
29
+ 5. This notice must be retained in all copies or substantial portions of
30
+ the software.
31
+
32
+ 6. Any use outside these terms automatically terminates this license.
33
+
34
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING
38
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
39
+ IN THE SOFTWARE.
40
+
41
+ For commercial licensing or redistribution permission: https://hugpy.ai
@@ -0,0 +1,104 @@
1
+ Metadata-Version: 2.4
2
+ Name: hugpy-video
3
+ Version: 0.2.3
4
+ Summary: Hugpy video: media library and job bus, ffmpeg, synthetic and studio runners, reservations and studio sessions for video intelligence
5
+ Author-email: putkoff <support@hugpy.ai>
6
+ License-Expression: LicenseRef-Proprietary
7
+ Project-URL: Homepage, https://hugpy.ai
8
+ Project-URL: Documentation, https://github.com/hugpy/hugpy/blob/main/py/cinema/hugpy_video/README.md
9
+ Project-URL: Repository, https://github.com/hugpy/hugpy
10
+ Project-URL: Source, https://github.com/hugpy/hugpy/tree/main/py/cinema/hugpy_video
11
+ Project-URL: Issues, https://github.com/hugpy/hugpy/issues
12
+ Project-URL: Changelog, https://github.com/hugpy/hugpy/releases
13
+ Project-URL: Architecture, https://github.com/hugpy/hugpy/blob/main/PARTITION.md
14
+ Keywords: hugpy,llm,self-hosted,video,ffmpeg,video-generation,media-intelligence
15
+ Classifier: Development Status :: 3 - Alpha
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: hugpy-platform
25
+ Requires-Dist: hugpy-control
26
+ Requires-Dist: hugpy-engine
27
+ Requires-Dist: hugpy-media
28
+ Requires-Dist: pydantic>=2
29
+ Requires-Dist: abstract-essentials
30
+ Provides-Extra: render
31
+ Requires-Dist: numpy; extra == "render"
32
+ Requires-Dist: Pillow; extra == "render"
33
+ Requires-Dist: requests; extra == "render"
34
+ Provides-Extra: studio
35
+ Requires-Dist: torch; extra == "studio"
36
+ Requires-Dist: diffusers; extra == "studio"
37
+ Requires-Dist: transformers; extra == "studio"
38
+ Requires-Dist: numpy; extra == "studio"
39
+ Requires-Dist: Pillow; extra == "studio"
40
+ Requires-Dist: opencv-python-headless; extra == "studio"
41
+ Requires-Dist: imageio; extra == "studio"
42
+ Requires-Dist: imageio-ffmpeg; extra == "studio"
43
+ Requires-Dist: requests; extra == "studio"
44
+ Provides-Extra: identity
45
+ Requires-Dist: abstract-identity; extra == "identity"
46
+ Requires-Dist: requests; extra == "identity"
47
+ Provides-Extra: test
48
+ Requires-Dist: pytest>=8; extra == "test"
49
+ Requires-Dist: pytest-timeout; extra == "test"
50
+ Dynamic: license-file
51
+
52
+ # hugpy-video
53
+
54
+ Execution and artifacts for Hugpy video work, extracted from the monolith's
55
+ `abstract_hugpy_dev.video_intel` (+ `managers/video`, `managers/video_gen`,
56
+ `comms/studio_assist_log`). Import name `hugpy_video`.
57
+
58
+ **Status: extracted.** Runtime code lives here; the package imports with the
59
+ monolith blocked and with no optional stack (torch/diffusers/ffmpeg bindings)
60
+ installed. Allowed ecosystem imports: `hugpy_platform`, `hugpy_control`,
61
+ `hugpy_engine`, `hugpy_media`. Never `hugpy_oracle`, `hugpy_fleet`,
62
+ `hugpy_server` (see `py/partition.toml`, `PARTITION.md`).
63
+
64
+ ## Layout
65
+ - `intel/` — media references + jail (`media_store`), sqlite media job bus
66
+ (`media_bus`) and its control-plane bridge (`job_bridge`), frozen job specs
67
+ and registry (`job_schema`), presets, GPU reservation engine
68
+ (`reservation/`), runners (ffmpeg, diffusers plane, studio, identity relays,
69
+ MLT), the studio spine (`studio/`).
70
+ - `chat_video/` — chat-side frame analysis over a `hugpy_media` vision runner.
71
+ - `video_gen/` — `StudioVideoRunner` / `VideoGenRequest`: the engine task
72
+ runner for text-to-video / image-to-video.
73
+ - `plugin.py` — `hugpy_engine.tasks` entry point (`hugpy_video.plugin:register`);
74
+ import-light, runner resolved lazily.
75
+ - `hooks.py` — `PromptCoordinator` protocol (oracle installs its implementation;
76
+ no-op default). `jobs.py` — public bus API incl. `register_job` for
77
+ upper-layer jobs (the oracle's `video_performance`).
78
+ - `state.py` — injectable state roots (`HUGPY_VIDEO_STATE_DIR`,
79
+ `HUGPY_MEDIA_JOBS_DB`, `HUGPY_RESERVATIONS_DB`, platform storage roots).
80
+ - `intel/plane.py` — the one seam onto the engine's `execute_prompt`.
81
+ - `cli.py` — `hugpy-video --help | jobs list | jobs registry | selftest | state`.
82
+ - `hugpy-video models audit [--json]` inventories every declared model's
83
+ runner gaps, weight pin and minimum VRAM without loading weights.
84
+ - `config.py` — canonical `HUGPY_API_KEY` / `HUGPY_BASE` loader.
85
+
86
+ Extras: `render` (numpy/Pillow/requests), `studio` (torch/diffusers zoo),
87
+ `identity` (abstract-identity client), `test`.
88
+
89
+ The `identity` extra installs the separate `abstract-identity` distribution.
90
+ The central video runner relays mesh and char360 jobs to its service using
91
+ `IDENTITY_RENDER_URL` and `IDENTITY_RENDER_TOKEN`; installing the extra alone
92
+ does not start a GPU service. Studio model sweeps use
93
+ `POST /video/studio/tester`; each attempt records its model, input image,
94
+ sampler settings, frame count and negative prompt in the battery log.
95
+
96
+ ## Rules (inherited from char360 / hugpy-agent)
97
+ - Heavy imports lazy — must import on a CPU-only box.
98
+ - Version single-sourced from pyproject (importlib.metadata; no hardcoded `__version__`).
99
+ - Credentials only via `hugpy_video.config.load_config` — canonical names
100
+ `HUGPY_API_KEY` / `HUGPY_BASE`; legacy aliases accepted but recorded in
101
+ `Config.deprecations`.
102
+ - Build: `python -m build`; publish = copy dists (console dir needs the sha256
103
+ sidecar; the pypi index computes hashes itself, dir name must be the
104
+ normalized dashed name `hugpy-video`).
@@ -0,0 +1,53 @@
1
+ # hugpy-video
2
+
3
+ Execution and artifacts for Hugpy video work, extracted from the monolith's
4
+ `abstract_hugpy_dev.video_intel` (+ `managers/video`, `managers/video_gen`,
5
+ `comms/studio_assist_log`). Import name `hugpy_video`.
6
+
7
+ **Status: extracted.** Runtime code lives here; the package imports with the
8
+ monolith blocked and with no optional stack (torch/diffusers/ffmpeg bindings)
9
+ installed. Allowed ecosystem imports: `hugpy_platform`, `hugpy_control`,
10
+ `hugpy_engine`, `hugpy_media`. Never `hugpy_oracle`, `hugpy_fleet`,
11
+ `hugpy_server` (see `py/partition.toml`, `PARTITION.md`).
12
+
13
+ ## Layout
14
+ - `intel/` — media references + jail (`media_store`), sqlite media job bus
15
+ (`media_bus`) and its control-plane bridge (`job_bridge`), frozen job specs
16
+ and registry (`job_schema`), presets, GPU reservation engine
17
+ (`reservation/`), runners (ffmpeg, diffusers plane, studio, identity relays,
18
+ MLT), the studio spine (`studio/`).
19
+ - `chat_video/` — chat-side frame analysis over a `hugpy_media` vision runner.
20
+ - `video_gen/` — `StudioVideoRunner` / `VideoGenRequest`: the engine task
21
+ runner for text-to-video / image-to-video.
22
+ - `plugin.py` — `hugpy_engine.tasks` entry point (`hugpy_video.plugin:register`);
23
+ import-light, runner resolved lazily.
24
+ - `hooks.py` — `PromptCoordinator` protocol (oracle installs its implementation;
25
+ no-op default). `jobs.py` — public bus API incl. `register_job` for
26
+ upper-layer jobs (the oracle's `video_performance`).
27
+ - `state.py` — injectable state roots (`HUGPY_VIDEO_STATE_DIR`,
28
+ `HUGPY_MEDIA_JOBS_DB`, `HUGPY_RESERVATIONS_DB`, platform storage roots).
29
+ - `intel/plane.py` — the one seam onto the engine's `execute_prompt`.
30
+ - `cli.py` — `hugpy-video --help | jobs list | jobs registry | selftest | state`.
31
+ - `hugpy-video models audit [--json]` inventories every declared model's
32
+ runner gaps, weight pin and minimum VRAM without loading weights.
33
+ - `config.py` — canonical `HUGPY_API_KEY` / `HUGPY_BASE` loader.
34
+
35
+ Extras: `render` (numpy/Pillow/requests), `studio` (torch/diffusers zoo),
36
+ `identity` (abstract-identity client), `test`.
37
+
38
+ The `identity` extra installs the separate `abstract-identity` distribution.
39
+ The central video runner relays mesh and char360 jobs to its service using
40
+ `IDENTITY_RENDER_URL` and `IDENTITY_RENDER_TOKEN`; installing the extra alone
41
+ does not start a GPU service. Studio model sweeps use
42
+ `POST /video/studio/tester`; each attempt records its model, input image,
43
+ sampler settings, frame count and negative prompt in the battery log.
44
+
45
+ ## Rules (inherited from char360 / hugpy-agent)
46
+ - Heavy imports lazy — must import on a CPU-only box.
47
+ - Version single-sourced from pyproject (importlib.metadata; no hardcoded `__version__`).
48
+ - Credentials only via `hugpy_video.config.load_config` — canonical names
49
+ `HUGPY_API_KEY` / `HUGPY_BASE`; legacy aliases accepted but recorded in
50
+ `Config.deprecations`.
51
+ - Build: `python -m build`; publish = copy dists (console dir needs the sha256
52
+ sidecar; the pypi index computes hashes itself, dir name must be the
53
+ normalized dashed name `hugpy-video`).
@@ -0,0 +1,81 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "setuptools-scm>=8"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "hugpy-video"
7
+ dynamic = ["version"]
8
+ description = "Hugpy video: media library and job bus, ffmpeg, synthetic and studio runners, reservations and studio sessions for video intelligence"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "LicenseRef-Proprietary"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "putkoff", email = "support@hugpy.ai" }]
14
+ keywords = [
15
+ "hugpy",
16
+ "llm",
17
+ "self-hosted",
18
+ "video",
19
+ "ffmpeg",
20
+ "video-generation",
21
+ "media-intelligence",
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 3 - Alpha",
25
+ "Intended Audience :: Developers",
26
+ "Operating System :: OS Independent",
27
+ "Programming Language :: Python :: 3",
28
+ "Programming Language :: Python :: 3 :: Only",
29
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
30
+ ]
31
+ # Heavy engine deps (torch, wan, ltx, rife, opencv, ...) are deliberately NOT
32
+ # listed: declare only what import-time needs and keep every heavy import
33
+ # lazy inside the function that uses it so the package imports on a CPU-only box.
34
+ dependencies = [
35
+ "hugpy-platform",
36
+ "hugpy-control",
37
+ "hugpy-engine",
38
+ "hugpy-media",
39
+ "pydantic>=2",
40
+ "abstract-essentials",
41
+ ]
42
+
43
+ [project.urls]
44
+ Homepage = "https://hugpy.ai"
45
+ Documentation = "https://github.com/hugpy/hugpy/blob/main/py/cinema/hugpy_video/README.md"
46
+ Repository = "https://github.com/hugpy/hugpy"
47
+ Source = "https://github.com/hugpy/hugpy/tree/main/py/cinema/hugpy_video"
48
+ Issues = "https://github.com/hugpy/hugpy/issues"
49
+ Changelog = "https://github.com/hugpy/hugpy/releases"
50
+ Architecture = "https://github.com/hugpy/hugpy/blob/main/PARTITION.md"
51
+
52
+ [project.optional-dependencies]
53
+ # ffmpeg/diffusers-plane runners and the identity relays (HTTP).
54
+ render = ["numpy", "Pillow", "requests"]
55
+ # The studio spine's GPU zoo (Wan / VACE / LTX / RIFE).
56
+ studio = ["torch", "diffusers", "transformers", "numpy", "Pillow", "opencv-python-headless", "imageio", "imageio-ffmpeg", "requests"]
57
+ # Identity rendering stays behind the external abstract-identity service client.
58
+ identity = ["abstract-identity", "requests"]
59
+ test = ["pytest>=8", "pytest-timeout"]
60
+
61
+ [project.scripts]
62
+ hugpy-video = "hugpy_video.cli:main"
63
+
64
+ [project.entry-points."hugpy_engine.tasks"]
65
+ video = "hugpy_video.plugin:register"
66
+
67
+ [tool.setuptools.packages.find]
68
+ where = ["src"]
69
+
70
+ [tool.setuptools.package-data]
71
+ hugpy_video = ["py.typed", "**/*.json", "**/*.md", "**/*.txt"]
72
+
73
+ # ---------------------------------------------------------------------------
74
+ # Lockstep workspace version (2026-09-22): every in-tree hugpy-* distribution
75
+ # takes ONE version from the workspace git tag (vX.Y.Z at the repo root), so a
76
+ # release is a tag and a build always carries the commit it came from
77
+ # (X.Y.Z.devN+g<sha>[.dirty] between tags). A checkout without git metadata
78
+ # builds as 0.0.0+unknown, which central refuses to advertise to workers.
79
+ [tool.setuptools_scm]
80
+ root = "../../.."
81
+ fallback_version = "0.0.0+unknown"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,33 @@
1
+ """hugpy-video: execution and artifacts for Hugpy video work.
2
+
3
+ Owns the media library jail, the sqlite media job bus and its lifecycle
4
+ bridge, the frozen job specs and presets, the GPU reservation engine, the
5
+ ffmpeg/diffusers/studio/identity runners and the studio spine
6
+ (``intel``), the chat-side video analyzer (``chat_video``), the engine
7
+ task runner for text-/image-to-video (``video_gen``) and the studio assist
8
+ log. Decisions and plans belong to ``hugpy_oracle``, which plugs in through
9
+ ``hugpy_video.hooks`` (prompt coordination) and ``hugpy_video.jobs``
10
+ (``register_job``) — this package never imports the oracle, the fleet or
11
+ the server.
12
+
13
+ Import-light: nothing here pulls torch/ffmpeg/studio stacks. Sub-modules are
14
+ imported explicitly by callers (``hugpy_video.jobs``, ``hugpy_video.hooks``,
15
+ ``hugpy_video.plugin``, ``hugpy_video.state``, ``hugpy_video.config``).
16
+
17
+ Version is single-sourced from pyproject.toml via importlib.metadata.
18
+ """
19
+
20
+ from importlib.metadata import PackageNotFoundError, version
21
+
22
+ try:
23
+ __version__ = version("hugpy-video")
24
+ except PackageNotFoundError: # running from a checkout without install
25
+ __version__ = "0.0.0+unknown"
26
+
27
+ from hugpy_video.config import Config, load_config # stdlib-only, cheap
28
+
29
+ __all__ = [
30
+ "__version__",
31
+ "Config",
32
+ "load_config",
33
+ ]
@@ -0,0 +1 @@
1
+ """Chat-side video helpers (old ``managers/video``). Import-light; see ``video_analyzer``."""
@@ -0,0 +1,174 @@
1
+ """Frame-by-frame video analysis over a vision runner (chat-side helper).
2
+
3
+ Import-light: the vision runner/schemas come from ``hugpy_media`` (allowed),
4
+ the no-think helpers from ``hugpy_engine`` (lazy, inside the loop).
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import copy
9
+ import os.path as osp
10
+ import time
11
+ import uuid
12
+ from typing import Any, Union
13
+
14
+ from abstract_essentials import safe_dump_to_file, safe_load_from_json
15
+ from hugpy_media.vision.schemas import VisionRequest
16
+ from hugpy_media.vision.vision_runner import VisionRunner
17
+ from hugpy_platform.utils import get_base_64_image, require_file
18
+
19
+ from hugpy_video.schemas.video_schemas import (
20
+ FrameAnalysis,
21
+ VideoAnalysisConfig,
22
+ VideoAnalysisSummary,
23
+ )
24
+
25
+ def _resolve_manifest_path(source: Union[str, Any]) -> str:
26
+ if isinstance(source, str):
27
+ return source
28
+ p = getattr(source, "manifest_path", None)
29
+ if isinstance(p, str):
30
+ return p
31
+ raise TypeError(
32
+ f"expected manifest path str or object with .manifest_path, "
33
+ f"got {type(source).__name__}"
34
+ )
35
+
36
+ def _build_prompt(user_prompt: str, frame_context: dict) -> str:
37
+ return (
38
+ "-----------prompt---------\n"
39
+ f"{user_prompt}\n"
40
+ "-----------frame context---------\n"
41
+ f"{frame_context}\n"
42
+ )
43
+
44
+
45
+ async def analyze_video(
46
+ source: Union[str, Any],
47
+ runner: VisionRunner,
48
+ config: VideoAnalysisConfig,
49
+ ) -> VideoAnalysisSummary:
50
+ manifest_path = require_file(_resolve_manifest_path(source), "manifest_path")
51
+ manifest_data = safe_load_from_json(manifest_path)
52
+ if not isinstance(manifest_data, dict):
53
+ raise ValueError(f"manifest is not a dict: {manifest_path}")
54
+
55
+ workspace_dir = manifest_data.get("workspace_dir")
56
+ if not workspace_dir or not osp.isdir(workspace_dir):
57
+ raise FileNotFoundError(f"workspace_dir invalid: {workspace_dir!r}")
58
+
59
+ files = manifest_data.get("files") or {}
60
+ frame_context_path = require_file(files.get("frame_context"), "files.frame_context")
61
+
62
+ frame_contexts = safe_load_from_json(frame_context_path)
63
+ if not isinstance(frame_contexts, list) or not frame_contexts:
64
+ raise ValueError(
65
+ f"frame_context must be a non-empty list, "
66
+ f"got {type(frame_contexts).__name__}"
67
+ )
68
+
69
+ total_frames = len(frame_contexts)
70
+ last = frame_contexts[-1]
71
+ total_video_length = last.get("timestamp") if isinstance(last, dict) else None
72
+
73
+ analysis_json_path = osp.join(workspace_dir, "analysis.json")
74
+ manifest_data.setdefault("files", {})["analysis_json"] = analysis_json_path
75
+ safe_dump_to_file(data=manifest_data, file_path=manifest_path)
76
+
77
+ # Resume keyed by frame_path so reruns are idempotent.
78
+ done_by_frame: dict[str, dict] = {}
79
+ if config.resume and osp.isfile(analysis_json_path):
80
+ prior = safe_load_from_json(analysis_json_path) or []
81
+ for entry in prior:
82
+ fp = entry.get("frame_path")
83
+ if fp and entry.get("error") is None:
84
+ done_by_frame[fp] = entry
85
+
86
+ records: list[dict] = list(done_by_frame.values())
87
+ model_key = runner.cfg.model_key # runner is the source of truth
88
+
89
+ for i, raw_ctx in enumerate(frame_contexts):
90
+ if not isinstance(raw_ctx, dict):
91
+ records.append({
92
+ "frame_index": i,
93
+ "error": f"frame_context[{i}] is not a dict",
94
+ })
95
+ continue
96
+
97
+ ctx = copy.deepcopy(raw_ctx) # never mutate caller's data
98
+ frame_path = ctx.get("frame_path")
99
+
100
+ if not frame_path or not osp.isfile(frame_path):
101
+ err = f"frame_path missing or not found: {frame_path!r}"
102
+ if config.raise_on_frame_error:
103
+ raise FileNotFoundError(err)
104
+ ctx.update({"frame_index": i, "error": err})
105
+ records.append(ctx)
106
+ continue
107
+
108
+ if frame_path in done_by_frame:
109
+ continue
110
+
111
+ ctx["frame_index"] = i
112
+ ctx["total_frames"] = total_frames
113
+ ctx["total_video_length"] = total_video_length
114
+ # NO-THINK (utils/no_think.py). Every frame's `analysis` is VALIDATED and
115
+ # PERSISTED to analysis.json — a monologue here poisons the whole dataset,
116
+ # and nothing downstream re-reads the frame to notice. The reasoning is
117
+ # kept alongside (FrameAnalysis is extra="allow") rather than discarded.
118
+ from hugpy_engine.utils.no_think import with_no_think, strip_think
119
+ rendered_prompt = with_no_think(_build_prompt(config.prompt, ctx))
120
+ image_b64 = get_base_64_image(frame_path)
121
+ req = VisionRequest(
122
+ request_id=f"frame-{i}-{uuid.uuid4().hex[:8]}",
123
+ model_key=model_key,
124
+ prompt=rendered_prompt,
125
+ max_new_tokens=config.max_new_tokens,
126
+ max_tokens=config.max_tokens,
127
+ image_b64=image_b64,
128
+ )
129
+
130
+ t0 = time.time()
131
+ try:
132
+ vresult = await runner.run(req)
133
+ text, err = vresult.text, vresult.error
134
+ except Exception as e:
135
+ if config.raise_on_frame_error:
136
+ raise
137
+ text, err = None, f"{type(e).__name__}: {e}"
138
+ duration = time.time() - t0
139
+
140
+ reasoning = ""
141
+ if text:
142
+ text, reasoning = strip_think(text)
143
+ if not text:
144
+ # Nothing but thinking — record it as an error rather than
145
+ # persisting an empty analysis that reads like a clean run.
146
+ err = err or ("model returned only reasoning and no analysis "
147
+ "(ignored the no-think directive)")
148
+
149
+ ctx.update({
150
+ "analysis_prompt": rendered_prompt,
151
+ "analysis": text,
152
+ "analysis_reasoning": reasoning,
153
+ "model_key": model_key,
154
+ "analysis_duration": duration,
155
+ "error": err,
156
+ })
157
+
158
+ # Validate-on-write: schema drift fails fast, not three days from now
159
+ FrameAnalysis.model_validate(ctx)
160
+ records.append(ctx)
161
+
162
+ if (i + 1) % config.save_every == 0 or (i + 1) == total_frames:
163
+ safe_dump_to_file(data=records, file_path=analysis_json_path)
164
+
165
+ succeeded = sum(1 for r in records if r.get("error") is None)
166
+ failed = sum(1 for r in records if r.get("error") is not None)
167
+
168
+ return VideoAnalysisSummary(
169
+ manifest_path=manifest_path,
170
+ analysis_json_path=analysis_json_path,
171
+ frames_total=total_frames,
172
+ frames_succeeded=succeeded,
173
+ frames_failed=failed,
174
+ )
@@ -0,0 +1,130 @@
1
+ """``hugpy-video`` command line (minimal; the console script in pyproject).
2
+
3
+ hugpy-video --help
4
+ hugpy-video jobs list [--all] [--limit N] [--json]
5
+ hugpy-video jobs registry
6
+ hugpy-video selftest # in-process checks, no GPU/service
7
+ hugpy-video models audit --json # declared model roster and readiness gates
8
+
9
+ Everything heavy is imported inside the sub-command that needs it.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import argparse
15
+ import json
16
+ import sys
17
+ from typing import List, Optional
18
+
19
+
20
+ def _cmd_jobs_list(args) -> int:
21
+ from hugpy_video import jobs
22
+
23
+ rows = jobs.list_jobs(include_terminal=args.all, limit=args.limit)
24
+ if args.json:
25
+ print(json.dumps(rows, indent=2, default=str))
26
+ return 0
27
+ if not rows:
28
+ print("no jobs")
29
+ return 0
30
+ for r in rows:
31
+ print(f"{r.get('job_id','?'):34} {r.get('name','?'):26} {r.get('status','?')}")
32
+ return 0
33
+
34
+
35
+ def _cmd_jobs_registry(args) -> int:
36
+ from hugpy_video import jobs
37
+
38
+ for name, spec in sorted(jobs.registered_jobs().items()):
39
+ print(f"{name:26} {spec.runner_key[0]}/{spec.runner_key[1]:18} "
40
+ f"queue={spec.queue} timeout={spec.timeout_s}s")
41
+ return 0
42
+
43
+
44
+ def _cmd_selftest(args) -> int:
45
+ from hugpy_video.selftest import run_selftest
46
+
47
+ failures = run_selftest(verbose=True)
48
+ return 1 if failures else 0
49
+
50
+
51
+ def _cmd_state(args) -> int:
52
+ from dataclasses import asdict
53
+
54
+ from hugpy_video.state import get_state_roots
55
+
56
+ print(json.dumps(asdict(get_state_roots()), indent=2))
57
+ return 0
58
+
59
+
60
+ def _cmd_models_audit(args) -> int:
61
+ """Inventory every declared model without loading weights or allocating a GPU."""
62
+ from hugpy_video.intel.studio.registry import MODEL_REGISTRY, model_gate_reasons
63
+
64
+ rows = []
65
+ for model_id, cfg in sorted(MODEL_REGISTRY.items()):
66
+ precision_gb = {precision.value: gb for precision, gb in cfg.vram.per_precision}
67
+ rows.append({
68
+ "model_id": model_id,
69
+ "family": cfg.family.value,
70
+ "capabilities": sorted(cap.value for cap in cfg.capabilities),
71
+ "tasks": sorted(task.value for task in cfg.tasks),
72
+ "minimum_vram_gb": min(precision_gb.values()) if precision_gb else None,
73
+ "vram_by_precision_gb": precision_gb,
74
+ "weights_pinned": cfg.weight_hash is not None,
75
+ "runner_gaps": model_gate_reasons(model_id),
76
+ })
77
+ if args.json:
78
+ print(json.dumps({"models": rows}, indent=2, sort_keys=True))
79
+ else:
80
+ for row in rows:
81
+ status = ", ".join(row["runner_gaps"].values()) or "runner present"
82
+ pin = "pinned" if row["weights_pinned"] else "unpinned"
83
+ print(f"{row['model_id']:32} {row['minimum_vram_gb']!s:>6} GB {pin:8} {status}")
84
+ print(f"{len(rows)} declared models; audit does not prove installed weights or GPU readiness")
85
+ return 0
86
+
87
+
88
+ def build_parser() -> argparse.ArgumentParser:
89
+ from hugpy_video import __version__
90
+
91
+ p = argparse.ArgumentParser(prog="hugpy-video",
92
+ description="Hugpy video: media job bus, runners, studio.")
93
+ p.add_argument("--version", action="version", version=f"hugpy-video {__version__}")
94
+ sub = p.add_subparsers(dest="cmd")
95
+
96
+ jobs = sub.add_parser("jobs", help="media job bus")
97
+ jsub = jobs.add_subparsers(dest="jobs_cmd")
98
+ ls = jsub.add_parser("list", help="list jobs")
99
+ ls.add_argument("--all", action="store_true", help="include terminal jobs")
100
+ ls.add_argument("--limit", type=int, default=50)
101
+ ls.add_argument("--json", action="store_true")
102
+ ls.set_defaults(func=_cmd_jobs_list)
103
+ reg = jsub.add_parser("registry", help="registered job names and runner keys")
104
+ reg.set_defaults(func=_cmd_jobs_registry)
105
+
106
+ st = sub.add_parser("selftest", help="in-process self checks (no GPU, no service)")
107
+ st.set_defaults(func=_cmd_selftest)
108
+
109
+ state = sub.add_parser("state", help="print the resolved state roots")
110
+ state.set_defaults(func=_cmd_state)
111
+ models = sub.add_parser("models", help="studio model inventory")
112
+ msub = models.add_subparsers(dest="models_cmd")
113
+ audit = msub.add_parser("audit", help="report runner, pin and VRAM requirements")
114
+ audit.add_argument("--json", action="store_true")
115
+ audit.set_defaults(func=_cmd_models_audit)
116
+ return p
117
+
118
+
119
+ def main(argv: Optional[List[str]] = None) -> int:
120
+ parser = build_parser()
121
+ args = parser.parse_args(argv)
122
+ func = getattr(args, "func", None)
123
+ if func is None:
124
+ parser.print_help()
125
+ return 0
126
+ return int(func(args) or 0)
127
+
128
+
129
+ if __name__ == "__main__": # pragma: no cover
130
+ sys.exit(main())