AnimeOverlord commited on
Commit
aebeae1
·
1 Parent(s): f47cc76

still initial commit

Browse files
Files changed (1) hide show
  1. app.py +27 -50
app.py CHANGED
@@ -1,5 +1,4 @@
1
  import os
2
- import asyncio
3
  import gradio as gr
4
  import cv2
5
  import numpy as np
@@ -16,27 +15,28 @@ if not has_tokens:
16
 
17
 
18
  # ── Thread-Safe Client Resolver ─────────────────────────────────────────────
 
 
19
  def get_modal_backend():
20
- """Resolves the Modal method safely on the active worker thread."""
 
21
  if not has_tokens:
22
  return None
23
- try:
24
- VoxelModelCls = modal.Cls.from_name("flux-klein-voxel-backend", "VoxelModel")
25
- return VoxelModelCls().process_frame
26
- except Exception as e:
27
- print(f"❌ Failed to resolve Modal class: {e}")
28
- return None
29
-
30
-
31
- # ── Sync Execution Core (Isolated) ─────────────────────────────────────────
32
- def _execute_remote_call(backend, payload_bytes: bytes) -> bytes:
33
- """The raw network request executed completely outside the event loop."""
34
- return backend.remote(payload_bytes)
35
 
36
 
37
- # ── Core Async Wrapper ──────────────────────────────────────────────────────
38
- async def run_modal_backend(frame: np.ndarray) -> np.ndarray:
39
- """Compresses the frame and uses to_thread to bypass event loop deadlocks."""
40
  backend = get_modal_backend()
41
  if backend is None:
42
  return frame
@@ -47,10 +47,8 @@ async def run_modal_backend(frame: np.ndarray) -> np.ndarray:
47
  return frame
48
 
49
  try:
50
- # CRITICAL: asyncio.to_thread completely bypasses Python 3.13 loop deadlocks!
51
- processed_bytes = await asyncio.to_thread(
52
- _execute_remote_call, backend, encoded.tobytes()
53
- )
54
 
55
  # Decode the returning bytes back into an OpenCV image
56
  result = cv2.imdecode(np.frombuffer(processed_bytes, dtype=np.uint8), cv2.IMREAD_COLOR)
@@ -63,40 +61,19 @@ async def run_modal_backend(frame: np.ndarray) -> np.ndarray:
63
  return err_frame
64
 
65
 
66
- # ── Activation & Pre-Warming Logic ──────────────────────────────────────────
67
- async def start_and_warmup_container():
68
- """Forces the Modal container to start up via an isolated worker thread."""
69
- print("🚀 [START CLICKED] Waking up Modal container to prevent cold-start lag...")
70
-
71
- backend = get_modal_backend()
72
- if backend is not None:
73
- try:
74
- # Create a tiny 1x1 blank image payload
75
- dummy_frame = np.zeros((1, 1, 3), dtype=np.uint8)
76
- success, encoded = cv2.imencode(".jpg", dummy_frame)
77
- if success:
78
- print("⏳ Sending ignition payload to remote container...")
79
- # Fire the warmup safely on its own isolated thread context
80
- await asyncio.to_thread(_execute_remote_call, backend, encoded.tobytes())
81
- print("✅ [CONTAINER READY] Modal container is hot and ready for frames.")
82
- except Exception as e:
83
- print(f"ℹ️ [CONTAINER NOTIFICATION] Warmup call dispatched: {e}")
84
-
85
- return True
86
-
87
-
88
  # ── Streaming Logic ─────────────────────────────────────────────────────────
89
- async def process_video_stream(frame: np.ndarray, mode: str, is_running: bool) -> np.ndarray:
90
  """Handles the webcam feed and respects the Start/Stop toggle."""
91
  if frame is None:
92
  return None
93
 
94
- # CRITICAL: If the user hasn't clicked Start, do NOT send to Modal.
 
95
  if not is_running:
96
  return frame
97
 
98
- # 1. Process the frame through our async-safe Modal bridge
99
- processed = await run_modal_backend(frame)
100
 
101
  # 2. Format the output based on the selected UI mode
102
  if mode == "Minecraft Filter":
@@ -140,11 +117,11 @@ with gr.Blocks(title="⛏️ Minecraft Spatial Voxel Filter") as demo:
140
  input_stream = gr.Image(sources=["webcam"], streaming=True, label="Live Webcam Input")
141
  output_stream = gr.Image(interactive=False, label="Voxel Output Viewport")
142
 
143
- # Wire buttons to manage state and trigger container wakeup
144
- start_btn.click(fn=start_and_warmup_container, inputs=None, outputs=is_running)
145
  stop_btn.click(fn=lambda: False, inputs=None, outputs=is_running)
146
 
147
- # Main non-blocking stream loop
148
  input_stream.stream(
149
  fn=process_video_stream,
150
  inputs=[input_stream, mode_dropdown, is_running],
 
1
  import os
 
2
  import gradio as gr
3
  import cv2
4
  import numpy as np
 
15
 
16
 
17
  # ── Thread-Safe Client Resolver ─────────────────────────────────────────────
18
+ _backend_cache = None
19
+
20
  def get_modal_backend():
21
+ """Resolves the Modal method lazily and caches it for standard threads."""
22
+ global _backend_cache
23
  if not has_tokens:
24
  return None
25
+
26
+ if _backend_cache is None:
27
+ try:
28
+ VoxelModelCls = modal.Cls.from_name("flux-klein-voxel-backend", "VoxelModel")
29
+ _backend_cache = VoxelModelCls().process_frame
30
+ except Exception as e:
31
+ print(f"❌ Failed to resolve Modal class: {e}")
32
+ return None
33
+
34
+ return _backend_cache
 
 
35
 
36
 
37
+ # ── Core Sync Execution (No Async/Await!) ───────────────────────────────────
38
+ def run_modal_backend(frame: np.ndarray) -> np.ndarray:
39
+ """Compresses the frame and executes strictly synchronously."""
40
  backend = get_modal_backend()
41
  if backend is None:
42
  return frame
 
47
  return frame
48
 
49
  try:
50
+ # PURE SYNCHRONOUS CALL: Gradio's background threadpool handles this perfectly safely
51
+ processed_bytes = backend.remote(encoded.tobytes())
 
 
52
 
53
  # Decode the returning bytes back into an OpenCV image
54
  result = cv2.imdecode(np.frombuffer(processed_bytes, dtype=np.uint8), cv2.IMREAD_COLOR)
 
61
  return err_frame
62
 
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  # ── Streaming Logic ─────────────────────────────────────────────────────────
65
+ def process_video_stream(frame: np.ndarray, mode: str, is_running: bool) -> np.ndarray:
66
  """Handles the webcam feed and respects the Start/Stop toggle."""
67
  if frame is None:
68
  return None
69
 
70
+ # CRITICAL: If the user hasn't clicked Start, just return the raw webcam feed.
71
+ # No dummy frames, no early wakeups.
72
  if not is_running:
73
  return frame
74
 
75
+ # 1. Process the actual webcam frame synchronously
76
+ processed = run_modal_backend(frame)
77
 
78
  # 2. Format the output based on the selected UI mode
79
  if mode == "Minecraft Filter":
 
117
  input_stream = gr.Image(sources=["webcam"], streaming=True, label="Live Webcam Input")
118
  output_stream = gr.Image(interactive=False, label="Voxel Output Viewport")
119
 
120
+ # Wire buttons to simply toggle the boolean. The video stream loop handles the rest.
121
+ start_btn.click(fn=lambda: True, inputs=None, outputs=is_running)
122
  stop_btn.click(fn=lambda: False, inputs=None, outputs=is_running)
123
 
124
+ # Main stream loop
125
  input_stream.stream(
126
  fn=process_video_stream,
127
  inputs=[input_stream, mode_dropdown, is_running],