Spaces:
Running on Zero
Running on Zero
Restore run.py with enhance_prompt binding (was overwritten by bad upload)
Browse files
run.py
CHANGED
|
@@ -17,8 +17,11 @@ import os
|
|
| 17 |
os.environ.setdefault("PYTORCH_ALLOC_CONF", "backend:cudaMallocAsync")
|
| 18 |
os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "backend:cudaMallocAsync")
|
| 19 |
|
|
|
|
| 20 |
import random
|
| 21 |
import tempfile
|
|
|
|
|
|
|
| 22 |
|
| 23 |
import gradio as gr
|
| 24 |
import PIL.Image
|
|
@@ -247,6 +250,38 @@ def _generate_gpu(prompt, image_path, height, width, num_frames, seed, decoder,
|
|
| 247 |
return path, num_frames
|
| 248 |
|
| 249 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 250 |
def _extract_path(image_value):
|
| 251 |
"""Image ports arrive from the canvas as a {path|url} dict, a path string, or None."""
|
| 252 |
if isinstance(image_value, dict):
|
|
@@ -254,6 +289,45 @@ def _extract_path(image_value):
|
|
| 254 |
return image_value or None
|
| 255 |
|
| 256 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
def generate_video(prompt, image_path=None, height=1472, width=832, duration_s=2,
|
| 258 |
seed=42, decoder="conv", auto_len=False, randomize_seed=True):
|
| 259 |
"""Workflow-facing wrapper, bound as a `fn` operator. CPU work (seed, frame
|
|
@@ -282,7 +356,7 @@ def generate_video(prompt, image_path=None, height=1472, width=832, duration_s=2
|
|
| 282 |
|
| 283 |
demo = gr.Workflow(
|
| 284 |
graph="workflow.json",
|
| 285 |
-
bind={"generate_video": generate_video},
|
| 286 |
)
|
| 287 |
|
| 288 |
if __name__ == "__main__":
|
|
|
|
| 17 |
os.environ.setdefault("PYTORCH_ALLOC_CONF", "backend:cudaMallocAsync")
|
| 18 |
os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "backend:cudaMallocAsync")
|
| 19 |
|
| 20 |
+
import hashlib
|
| 21 |
import random
|
| 22 |
import tempfile
|
| 23 |
+
import time
|
| 24 |
+
from collections import OrderedDict
|
| 25 |
|
| 26 |
import gradio as gr
|
| 27 |
import PIL.Image
|
|
|
|
| 250 |
return path, num_frames
|
| 251 |
|
| 252 |
|
| 253 |
+
# -----------------------------------------------------------------------------
|
| 254 |
+
# Prompt enhancement — same mechanism and Space as the original demo (Gemma-4 on
|
| 255 |
+
# a separate ZeroGPU Space). Authenticated with this Space's HF_TOKEN, so no
|
| 256 |
+
# anonymous rate-limit bucket. Client rebuilt past a TTL: the ZeroGPU proxy
|
| 257 |
+
# token it carries expires.
|
| 258 |
+
# -----------------------------------------------------------------------------
|
| 259 |
+
ENHANCER_SPACE = "diffusers-internal-dev/LTX-2.4-Prompt-Enhancer"
|
| 260 |
+
_enh = {"client": None, "built_at": 0.0}
|
| 261 |
+
_ENH_CLIENT_TTL_S = 900
|
| 262 |
+
|
| 263 |
+
_ENH_CACHE: OrderedDict[tuple[str, str | None], str] = OrderedDict()
|
| 264 |
+
_ENH_CACHE_MAX = 64
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
def _image_key(path: str | None) -> str | None:
|
| 268 |
+
if not path:
|
| 269 |
+
return None
|
| 270 |
+
with open(path, "rb") as fh:
|
| 271 |
+
return hashlib.sha256(fh.read()).hexdigest()[:16]
|
| 272 |
+
|
| 273 |
+
|
| 274 |
+
def _enhancer_client(fresh: bool = False):
|
| 275 |
+
from gradio_client import Client
|
| 276 |
+
|
| 277 |
+
if fresh or _enh["client"] is None or (time.monotonic() - _enh["built_at"]) > _ENH_CLIENT_TTL_S:
|
| 278 |
+
_enh["client"] = Client(
|
| 279 |
+
ENHANCER_SPACE, token=HF_TOKEN, httpx_kwargs={"timeout": 300.0}
|
| 280 |
+
)
|
| 281 |
+
_enh["built_at"] = time.monotonic()
|
| 282 |
+
return _enh["client"]
|
| 283 |
+
|
| 284 |
+
|
| 285 |
def _extract_path(image_value):
|
| 286 |
"""Image ports arrive from the canvas as a {path|url} dict, a path string, or None."""
|
| 287 |
if isinstance(image_value, dict):
|
|
|
|
| 289 |
return image_value or None
|
| 290 |
|
| 291 |
|
| 292 |
+
def enhance_prompt(prompt, image_path=None, do_enhance=True):
|
| 293 |
+
"""CPU step (runs before any GPU is acquired): rewrite the prompt into a
|
| 294 |
+
detailed LTX-2.5-style caption via the enhancer Space. Falls back to the
|
| 295 |
+
raw prompt if the enhancer is unavailable. Bound as a `fn` operator."""
|
| 296 |
+
if not prompt or not str(prompt).strip():
|
| 297 |
+
raise gr.Error("Please enter a prompt.")
|
| 298 |
+
prompt = str(prompt).strip()
|
| 299 |
+
image_path = _extract_path(image_path)
|
| 300 |
+
if not do_enhance:
|
| 301 |
+
return prompt
|
| 302 |
+
|
| 303 |
+
key = (prompt, _image_key(image_path))
|
| 304 |
+
cached = _ENH_CACHE.get(key)
|
| 305 |
+
if cached is not None:
|
| 306 |
+
_ENH_CACHE.move_to_end(key)
|
| 307 |
+
return cached
|
| 308 |
+
|
| 309 |
+
from gradio_client import handle_file
|
| 310 |
+
|
| 311 |
+
args = (prompt, handle_file(image_path) if image_path else None)
|
| 312 |
+
try:
|
| 313 |
+
try:
|
| 314 |
+
enhanced = _enhancer_client().predict(*args, api_name="/enhance")
|
| 315 |
+
except Exception as first: # noqa: BLE001
|
| 316 |
+
# Usually an expired ZeroGPU proxy token; retry once with a fresh client.
|
| 317 |
+
print(f"[enhance] first attempt failed ({first!r}); fresh client retry", flush=True)
|
| 318 |
+
enhanced = _enhancer_client(fresh=True).predict(*args, api_name="/enhance")
|
| 319 |
+
except Exception as e: # noqa: BLE001
|
| 320 |
+
print(f"[enhance] failed, using raw prompt: {e!r}", flush=True)
|
| 321 |
+
gr.Warning(f"Prompt enhancement unavailable ({type(e).__name__}) — using your prompt as written.")
|
| 322 |
+
return prompt
|
| 323 |
+
|
| 324 |
+
enhanced = enhanced or prompt
|
| 325 |
+
_ENH_CACHE[key] = enhanced
|
| 326 |
+
while len(_ENH_CACHE) > _ENH_CACHE_MAX:
|
| 327 |
+
_ENH_CACHE.popitem(last=False)
|
| 328 |
+
return enhanced
|
| 329 |
+
|
| 330 |
+
|
| 331 |
def generate_video(prompt, image_path=None, height=1472, width=832, duration_s=2,
|
| 332 |
seed=42, decoder="conv", auto_len=False, randomize_seed=True):
|
| 333 |
"""Workflow-facing wrapper, bound as a `fn` operator. CPU work (seed, frame
|
|
|
|
| 356 |
|
| 357 |
demo = gr.Workflow(
|
| 358 |
graph="workflow.json",
|
| 359 |
+
bind={"enhance_prompt": enhance_prompt, "generate_video": generate_video},
|
| 360 |
)
|
| 361 |
|
| 362 |
if __name__ == "__main__":
|