Spaces:
Running
on
A100
Running
on
A100
initial test
Browse files
app.py
CHANGED
@@ -3,10 +3,12 @@ import json
|
|
3 |
import gradio as gr
|
4 |
import tempfile
|
5 |
from PIL import Image, ImageDraw, ImageFont
|
|
|
6 |
from typing import Tuple, Optional
|
|
|
7 |
from pathlib import Path
|
|
|
8 |
|
9 |
-
# Import your highlight detection code
|
10 |
from video_highlight_detector import (
|
11 |
load_model,
|
12 |
BatchedVideoHighlightDetector,
|
@@ -14,12 +16,10 @@ from video_highlight_detector import (
|
|
14 |
)
|
15 |
|
16 |
def load_examples(json_path: str) -> dict:
|
17 |
-
"""Load pre-computed examples from JSON file"""
|
18 |
with open(json_path, 'r') as f:
|
19 |
return json.load(f)
|
20 |
|
21 |
def format_duration(seconds: int) -> str:
|
22 |
-
"""Convert seconds to MM:SS or HH:MM:SS format"""
|
23 |
hours = seconds // 3600
|
24 |
minutes = (seconds % 3600) // 60
|
25 |
secs = seconds % 60
|
@@ -28,7 +28,6 @@ def format_duration(seconds: int) -> str:
|
|
28 |
return f"{minutes}:{secs:02d}"
|
29 |
|
30 |
def add_watermark(video_path: str, output_path: str):
|
31 |
-
"""Add watermark to video using ffmpeg"""
|
32 |
watermark_text = "🤗 SmolVLM2 Highlight"
|
33 |
command = f"""ffmpeg -i {video_path} -vf \
|
34 |
"drawtext=text='{watermark_text}':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:\
|
@@ -40,48 +39,33 @@ def process_video(
|
|
40 |
video_path: str,
|
41 |
progress = gr.Progress()
|
42 |
) -> Tuple[str, str, str, str]:
|
43 |
-
"""
|
44 |
-
Process video and return paths to:
|
45 |
-
- Processed video with watermark
|
46 |
-
- Video description
|
47 |
-
- Highlight types
|
48 |
-
- Error message (if any)
|
49 |
-
"""
|
50 |
try:
|
51 |
-
# Check video duration
|
52 |
duration = get_video_duration_seconds(video_path)
|
53 |
if duration > 1200: # 20 minutes
|
54 |
return None, None, None, "Video must be shorter than 20 minutes"
|
55 |
|
56 |
-
# Load model (could be cached)
|
57 |
progress(0.1, desc="Loading model...")
|
58 |
model, processor = load_model()
|
59 |
detector = BatchedVideoHighlightDetector(model, processor)
|
60 |
|
61 |
-
# Analyze video content
|
62 |
progress(0.2, desc="Analyzing video content...")
|
63 |
video_description = detector.analyze_video_content(video_path)
|
64 |
|
65 |
-
# Determine highlights
|
66 |
progress(0.3, desc="Determining highlight types...")
|
67 |
highlight_types = detector.determine_highlights(video_description)
|
68 |
|
69 |
-
# Create highlight video
|
70 |
progress(0.4, desc="Detecting and extracting highlights...")
|
71 |
with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as tmp_file:
|
72 |
temp_output = tmp_file.name
|
73 |
|
74 |
detector.create_highlight_video(video_path, temp_output)
|
75 |
|
76 |
-
# Add watermark
|
77 |
progress(0.9, desc="Adding watermark...")
|
78 |
output_path = temp_output.replace('.mp4', '_watermark.mp4')
|
79 |
add_watermark(temp_output, output_path)
|
80 |
|
81 |
-
# Cleanup
|
82 |
os.unlink(temp_output)
|
83 |
|
84 |
-
# Truncate description and highlights if too long
|
85 |
video_description = video_description[:500] + "..." if len(video_description) > 500 else video_description
|
86 |
highlight_types = highlight_types[:500] + "..." if len(highlight_types) > 500 else highlight_types
|
87 |
|
@@ -90,24 +74,20 @@ def process_video(
|
|
90 |
except Exception as e:
|
91 |
return None, None, None, f"Error processing video: {str(e)}"
|
92 |
|
93 |
-
|
94 |
def create_ui(examples_path: str):
|
95 |
-
"""Create the Gradio interface with optional thumbnails"""
|
96 |
examples_data = load_examples(examples_path)
|
97 |
|
98 |
with gr.Blocks() as app:
|
99 |
gr.Markdown("# Video Highlight Generator")
|
100 |
gr.Markdown("Upload a video (max 20 minutes) and get an automated highlight reel!")
|
101 |
|
102 |
-
# Pre-computed examples section
|
103 |
with gr.Row():
|
104 |
gr.Markdown("## Example Results")
|
105 |
|
106 |
for example in examples_data["examples"]:
|
107 |
with gr.Row():
|
108 |
with gr.Column():
|
109 |
-
|
110 |
-
video_component = gr.Video(
|
111 |
example["original"]["url"],
|
112 |
label=f"Original ({format_duration(example['original']['duration_seconds'])})",
|
113 |
)
|
@@ -122,15 +102,13 @@ def create_ui(examples_path: str):
|
|
122 |
gr.Markdown(example["analysis"]["video_description"])
|
123 |
gr.Markdown(example["analysis"]["highlight_types"])
|
124 |
|
125 |
-
# Upload section
|
126 |
gr.Markdown("## Try It Yourself!")
|
127 |
with gr.Row():
|
128 |
input_video = gr.Video(
|
129 |
label="Upload your video (max 20 minutes)",
|
130 |
-
|
131 |
)
|
132 |
|
133 |
-
# Results section (initially hidden)
|
134 |
with gr.Row(visible=False) as results_row:
|
135 |
with gr.Column():
|
136 |
video_description = gr.Markdown(label="Video Analysis")
|
@@ -141,10 +119,8 @@ def create_ui(examples_path: str):
|
|
141 |
output_video = gr.Video(label="Highlight Video")
|
142 |
download_btn = gr.Button("Download Highlights")
|
143 |
|
144 |
-
# Error message
|
145 |
error_msg = gr.Markdown(visible=False)
|
146 |
|
147 |
-
# Process video when uploaded
|
148 |
def on_upload(video):
|
149 |
results_row.visible = False
|
150 |
output_row.visible = False
|
@@ -172,7 +148,6 @@ def create_ui(examples_path: str):
|
|
172 |
outputs=[output_video, video_description, highlight_types, error_msg]
|
173 |
)
|
174 |
|
175 |
-
# Download button
|
176 |
download_btn.click(
|
177 |
lambda x: x,
|
178 |
inputs=[output_video],
|
@@ -183,4 +158,4 @@ def create_ui(examples_path: str):
|
|
183 |
|
184 |
if __name__ == "__main__":
|
185 |
app = create_ui("video_spec.json")
|
186 |
-
app.launch()
|
|
|
3 |
import gradio as gr
|
4 |
import tempfile
|
5 |
from PIL import Image, ImageDraw, ImageFont
|
6 |
+
import cv2
|
7 |
from typing import Tuple, Optional
|
8 |
+
import torch
|
9 |
from pathlib import Path
|
10 |
+
import time
|
11 |
|
|
|
12 |
from video_highlight_detector import (
|
13 |
load_model,
|
14 |
BatchedVideoHighlightDetector,
|
|
|
16 |
)
|
17 |
|
18 |
def load_examples(json_path: str) -> dict:
|
|
|
19 |
with open(json_path, 'r') as f:
|
20 |
return json.load(f)
|
21 |
|
22 |
def format_duration(seconds: int) -> str:
|
|
|
23 |
hours = seconds // 3600
|
24 |
minutes = (seconds % 3600) // 60
|
25 |
secs = seconds % 60
|
|
|
28 |
return f"{minutes}:{secs:02d}"
|
29 |
|
30 |
def add_watermark(video_path: str, output_path: str):
|
|
|
31 |
watermark_text = "🤗 SmolVLM2 Highlight"
|
32 |
command = f"""ffmpeg -i {video_path} -vf \
|
33 |
"drawtext=text='{watermark_text}':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:\
|
|
|
39 |
video_path: str,
|
40 |
progress = gr.Progress()
|
41 |
) -> Tuple[str, str, str, str]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
try:
|
|
|
43 |
duration = get_video_duration_seconds(video_path)
|
44 |
if duration > 1200: # 20 minutes
|
45 |
return None, None, None, "Video must be shorter than 20 minutes"
|
46 |
|
|
|
47 |
progress(0.1, desc="Loading model...")
|
48 |
model, processor = load_model()
|
49 |
detector = BatchedVideoHighlightDetector(model, processor)
|
50 |
|
|
|
51 |
progress(0.2, desc="Analyzing video content...")
|
52 |
video_description = detector.analyze_video_content(video_path)
|
53 |
|
|
|
54 |
progress(0.3, desc="Determining highlight types...")
|
55 |
highlight_types = detector.determine_highlights(video_description)
|
56 |
|
|
|
57 |
progress(0.4, desc="Detecting and extracting highlights...")
|
58 |
with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as tmp_file:
|
59 |
temp_output = tmp_file.name
|
60 |
|
61 |
detector.create_highlight_video(video_path, temp_output)
|
62 |
|
|
|
63 |
progress(0.9, desc="Adding watermark...")
|
64 |
output_path = temp_output.replace('.mp4', '_watermark.mp4')
|
65 |
add_watermark(temp_output, output_path)
|
66 |
|
|
|
67 |
os.unlink(temp_output)
|
68 |
|
|
|
69 |
video_description = video_description[:500] + "..." if len(video_description) > 500 else video_description
|
70 |
highlight_types = highlight_types[:500] + "..." if len(highlight_types) > 500 else highlight_types
|
71 |
|
|
|
74 |
except Exception as e:
|
75 |
return None, None, None, f"Error processing video: {str(e)}"
|
76 |
|
|
|
77 |
def create_ui(examples_path: str):
|
|
|
78 |
examples_data = load_examples(examples_path)
|
79 |
|
80 |
with gr.Blocks() as app:
|
81 |
gr.Markdown("# Video Highlight Generator")
|
82 |
gr.Markdown("Upload a video (max 20 minutes) and get an automated highlight reel!")
|
83 |
|
|
|
84 |
with gr.Row():
|
85 |
gr.Markdown("## Example Results")
|
86 |
|
87 |
for example in examples_data["examples"]:
|
88 |
with gr.Row():
|
89 |
with gr.Column():
|
90 |
+
gr.Video(
|
|
|
91 |
example["original"]["url"],
|
92 |
label=f"Original ({format_duration(example['original']['duration_seconds'])})",
|
93 |
)
|
|
|
102 |
gr.Markdown(example["analysis"]["video_description"])
|
103 |
gr.Markdown(example["analysis"]["highlight_types"])
|
104 |
|
|
|
105 |
gr.Markdown("## Try It Yourself!")
|
106 |
with gr.Row():
|
107 |
input_video = gr.Video(
|
108 |
label="Upload your video (max 20 minutes)",
|
109 |
+
interactive=True
|
110 |
)
|
111 |
|
|
|
112 |
with gr.Row(visible=False) as results_row:
|
113 |
with gr.Column():
|
114 |
video_description = gr.Markdown(label="Video Analysis")
|
|
|
119 |
output_video = gr.Video(label="Highlight Video")
|
120 |
download_btn = gr.Button("Download Highlights")
|
121 |
|
|
|
122 |
error_msg = gr.Markdown(visible=False)
|
123 |
|
|
|
124 |
def on_upload(video):
|
125 |
results_row.visible = False
|
126 |
output_row.visible = False
|
|
|
148 |
outputs=[output_video, video_description, highlight_types, error_msg]
|
149 |
)
|
150 |
|
|
|
151 |
download_btn.click(
|
152 |
lambda x: x,
|
153 |
inputs=[output_video],
|
|
|
158 |
|
159 |
if __name__ == "__main__":
|
160 |
app = create_ui("video_spec.json")
|
161 |
+
app.launch()
|