multimodalart HF Staff commited on
Commit
5f82f10
·
verified ·
1 Parent(s): c551a63

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +24 -47
app.py CHANGED
@@ -1,53 +1,32 @@
1
- import asyncio
2
- import numpy as np
3
  import gradio as gr
 
4
  import spaces
5
- from fastrtc import WebRTC, get_turn_credentials, AsyncStreamHandler
6
- from fastrtc.utils import wait_for_item
7
 
8
- class FrameFlipperHandler(AsyncStreamHandler):
 
9
  """
10
- A persistent, reactive handler for flipping video frames.
11
-
12
- This class creates a long-running process for each user connection.
13
- - The `receive` method is called by the backend whenever a new frame arrives from the user.
14
- - The `emit` method is called by the backend in a loop to get processed frames to send back.
15
- - An internal `asyncio.Queue` connects these two methods for reactive, low-latency processing.
16
  """
17
- def __init__(self):
18
- super().__init__()
19
- self.frame_queue = asyncio.Queue()
20
-
21
- async def receive(self, frame: tuple[int, np.ndarray]) -> None:
22
- """Called for each frame received from the client's webcam."""
23
- # This is non-blocking and instantly puts the frame into our processing queue.
24
- self.frame_queue.put_nowait(frame)
25
 
26
- @spaces.GPU
27
- async def emit(self):
28
- """Called in a loop to get the next frame to send to the client."""
29
- # This waits for a frame to be available in the queue with a small timeout.
30
- frame_data = await wait_for_item(self.frame_queue, timeout=0.01)
31
-
32
- if frame_data:
33
- _rate, frame_array = frame_data
34
- if frame_array is not None:
35
- # Flip the frame both vertically and horizontally
36
- flipped_frame = np.flip(frame_array, axis=(0, 1))
37
- return (None, flipped_frame) # The sample rate is ignored for video
38
-
39
- return None
40
-
41
- def copy(self):
42
- """Creates a new instance of this handler for each new connection."""
43
- return FrameFlipperHandler()
44
-
45
 
46
  # --- Gradio UI Layout ---
47
- with gr.Blocks(theme=gr.themes.Soft(), title="FastRTC Webcam Double Flipper") as demo:
48
- gr.Markdown("# 🚀 FastRTC Webcam Double Flipper (Reactive)")
49
  gr.Markdown(
50
- "*This version uses a persistent `AsyncStreamHandler` for low-latency, reactive streaming, ideal for environments like ZeroGPU.*"
51
  )
52
 
53
  with gr.Row():
@@ -72,13 +51,11 @@ with gr.Blocks(theme=gr.themes.Soft(), title="FastRTC Webcam Double Flipper") as
72
  height=480,
73
  rtc_configuration=get_turn_credentials(),
74
  )
75
-
76
- # Instantiate our custom handler
77
- handler = FrameFlipperHandler()
78
-
79
- # Pass the handler instance to the stream method
80
  webcam_input.stream(
81
- fn=handler,
82
  inputs=[webcam_input],
83
  outputs=[video_output],
84
  time_limit=120,
 
 
 
1
  import gradio as gr
2
+ import numpy as np
3
  import spaces
4
+ from fastrtc import WebRTC, get_turn_credentials
 
5
 
6
+ @spaces.GPU
7
+ def process_frames_on_gpu(frame_stream):
8
  """
9
+ This function runs as a persistent process on the GPU.
10
+ It iterates over incoming frames, processes them, and yields the results.
 
 
 
 
11
  """
12
+ print("🚀 GPU Frame processing loop started.")
 
 
 
 
 
 
 
13
 
14
+ # This loop will block until a new frame is available, making it reactive.
15
+ for frame in frame_stream:
16
+ if frame is not None:
17
+ # This is where your GPU-intensive work would happen.
18
+ flipped_frame = np.flip(frame, axis=(0, 1))
19
+
20
+ # Yield the processed frame to the output stream.
21
+ yield flipped_frame
22
+
23
+ print("🛑 GPU Frame processing loop finished.")
 
 
 
 
 
 
 
 
 
24
 
25
  # --- Gradio UI Layout ---
26
+ with gr.Blocks(theme=gr.themes.Soft(), title="FastRTC ZeroGPU Flipper") as demo:
27
+ gr.Markdown("# 🚀 FastRTC Webcam Flipper for ZeroGPU")
28
  gr.Markdown(
29
+ "*This version uses Gradio's native stream iterator pattern. The `process_frames_on_gpu` function is a single, decorated process that receives and yields frames, making it ideal for ZeroGPU.*"
30
  )
31
 
32
  with gr.Row():
 
51
  height=480,
52
  rtc_configuration=get_turn_credentials(),
53
  )
54
+
55
+ # When webcam_input is used as a streaming input, the `process_frames_on_gpu`
56
+ # function receives an iterator that it can loop over.
 
 
57
  webcam_input.stream(
58
+ fn=process_frames_on_gpu,
59
  inputs=[webcam_input],
60
  outputs=[video_output],
61
  time_limit=120,