Chaitanya-aitf commited on
Commit
dda8532
·
verified ·
1 Parent(s): 84bf8bd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -91
app.py CHANGED
@@ -22,16 +22,18 @@ try:
22
  from utils.logger import setup_logging, get_logger
23
  setup_logging(log_level="INFO", log_to_console=True)
24
  logger = get_logger("app")
25
- except Exception as e:
26
  import logging
27
  logging.basicConfig(level=logging.INFO)
28
  logger = logging.getLogger("app")
29
- logger.warning(f"Custom logger failed, using basic: {e}")
30
 
31
 
32
  def process_video(video_file, domain, num_clips, clip_duration, reference_image, custom_prompt):
33
  """Main processing function."""
34
 
 
 
 
35
  log_messages = []
36
 
37
  def log(msg):
@@ -39,14 +41,8 @@ def process_video(video_file, domain, num_clips, clip_duration, reference_image,
39
  logger.info(msg)
40
 
41
  try:
42
- # Validate inputs
43
- log("Validating inputs...")
44
-
45
- if not video_file:
46
- return None, "❌ Error: No video file provided", "\n".join(log_messages)
47
-
48
  video_path = Path(video_file)
49
- log(f"Video: {video_path.name}")
50
 
51
  # Import here to avoid issues at startup
52
  from utils.helpers import validate_video_file, validate_image_file, format_duration
@@ -54,19 +50,17 @@ def process_video(video_file, domain, num_clips, clip_duration, reference_image,
54
 
55
  validation = validate_video_file(video_file)
56
  if not validation.is_valid:
57
- return None, f"Error: {validation.error_message}", "\n".join(log_messages)
58
 
59
  log(f"Video size: {validation.file_size / (1024*1024):.1f} MB")
60
 
61
  # Validate reference image if provided
62
  ref_path = None
63
- if reference_image:
64
  ref_validation = validate_image_file(reference_image)
65
  if ref_validation.is_valid:
66
  ref_path = reference_image
67
  log(f"Reference image: {Path(reference_image).name}")
68
- else:
69
- log(f"Warning: Invalid reference image - {ref_validation.error_message}")
70
 
71
  # Map domain string
72
  domain_map = {
@@ -82,14 +76,13 @@ def process_video(video_file, domain, num_clips, clip_duration, reference_image,
82
 
83
  # Create output directory
84
  output_dir = Path(tempfile.mkdtemp(prefix="shortsmith_output_"))
85
- log(f"Output directory: {output_dir}")
86
 
87
  # Initialize pipeline
88
  log("Initializing pipeline...")
89
  pipeline = PipelineOrchestrator()
90
 
91
  # Process video
92
- log(f"Processing: {num_clips} clips @ {clip_duration}s each")
93
 
94
  result = pipeline.process(
95
  video_path=video_path,
@@ -97,12 +90,12 @@ def process_video(video_file, domain, num_clips, clip_duration, reference_image,
97
  clip_duration=float(clip_duration),
98
  domain=domain_value,
99
  reference_image=ref_path,
100
- custom_prompt=custom_prompt if custom_prompt and custom_prompt.strip() else None,
101
  )
102
 
103
  # Handle result
104
  if result.success:
105
- log(f"Processing complete in {result.processing_time:.1f}s")
106
 
107
  clip_paths = []
108
  for i, clip in enumerate(result.clips):
@@ -110,84 +103,50 @@ def process_video(video_file, domain, num_clips, clip_duration, reference_image,
110
  output_path = output_dir / f"highlight_{i+1}.mp4"
111
  shutil.copy2(clip.clip_path, output_path)
112
  clip_paths.append(str(output_path))
113
- log(f" Clip {i+1}: {format_duration(clip.start_time)} - {format_duration(clip.end_time)} (score: {clip.hype_score:.2f})")
114
-
115
- status = f"✅ Successfully extracted {len(clip_paths)} highlight clips!\nProcessing time: {result.processing_time:.1f}s"
116
 
 
117
  pipeline.cleanup()
118
- return clip_paths if clip_paths else None, status, "\n".join(log_messages)
 
 
 
 
119
  else:
120
- log(f"❌ Processing failed: {result.error_message}")
121
  pipeline.cleanup()
122
- return None, f"Error: {result.error_message}", "\n".join(log_messages)
123
 
124
  except Exception as e:
125
- error_msg = f"Unexpected error: {str(e)}"
126
- log(f"❌ {error_msg}")
127
  log(traceback.format_exc())
128
- return None, f" {error_msg}", "\n".join(log_messages)
129
-
130
-
131
- # Create interface
132
- with gr.Blocks(title="ShortSmith v2", theme=gr.themes.Soft()) as demo:
133
- gr.Markdown("""
134
- # 🎬 ShortSmith v2
135
- ### AI-Powered Video Highlight Extractor
136
-
137
- Upload a video and extract the most engaging highlight clips automatically.
138
- """)
139
-
140
- with gr.Row():
141
- with gr.Column(scale=1):
142
- gr.Markdown("### 📤 Input")
143
-
144
- video_input = gr.Video(label="Upload Video")
145
-
146
- domain_dropdown = gr.Dropdown(
147
- choices=["Sports", "Vlogs", "Music Videos", "Podcasts", "Gaming", "General"],
148
- value="General",
149
- label="Content Domain",
150
- )
151
-
152
- with gr.Row():
153
- num_clips_slider = gr.Slider(
154
- minimum=1, maximum=10, value=3, step=1,
155
- label="Number of Clips",
156
- )
157
- duration_slider = gr.Slider(
158
- minimum=5, maximum=30, value=15, step=1,
159
- label="Clip Duration (seconds)",
160
- )
161
-
162
- with gr.Accordion("👤 Person Filtering (Optional)", open=False):
163
- reference_image = gr.Image(label="Reference Image", type="filepath")
164
-
165
- with gr.Accordion("📝 Custom Instructions (Optional)", open=False):
166
- custom_prompt = gr.Textbox(
167
- label="Additional Instructions",
168
- placeholder="E.g., 'Focus on crowd reactions'",
169
- lines=2,
170
- )
171
-
172
- process_btn = gr.Button("🚀 Extract Highlights", variant="primary", size="lg")
173
-
174
- with gr.Column(scale=1):
175
- gr.Markdown("### 📥 Output")
176
-
177
- status_output = gr.Textbox(label="Status", lines=3, interactive=False)
178
- clip_files = gr.Files(label="Extracted Clips")
179
-
180
- with gr.Accordion("📋 Processing Log", open=False):
181
- log_output = gr.Textbox(label="Log", lines=10, interactive=False)
182
-
183
- gr.Markdown("---\n**ShortSmith v2** | Powered by Qwen2-VL, InsightFace, and Librosa")
184
-
185
- process_btn.click(
186
- fn=process_video,
187
- inputs=[video_input, domain_dropdown, num_clips_slider, duration_slider, reference_image, custom_prompt],
188
- outputs=[clip_files, status_output, log_output],
189
- )
190
-
191
- if __name__ == "__main__":
192
- demo.queue()
193
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
22
  from utils.logger import setup_logging, get_logger
23
  setup_logging(log_level="INFO", log_to_console=True)
24
  logger = get_logger("app")
25
+ except Exception:
26
  import logging
27
  logging.basicConfig(level=logging.INFO)
28
  logger = logging.getLogger("app")
 
29
 
30
 
31
  def process_video(video_file, domain, num_clips, clip_duration, reference_image, custom_prompt):
32
  """Main processing function."""
33
 
34
+ if video_file is None:
35
+ return None, "Please upload a video first.", ""
36
+
37
  log_messages = []
38
 
39
  def log(msg):
 
41
  logger.info(msg)
42
 
43
  try:
 
 
 
 
 
 
44
  video_path = Path(video_file)
45
+ log(f"Processing video: {video_path.name}")
46
 
47
  # Import here to avoid issues at startup
48
  from utils.helpers import validate_video_file, validate_image_file, format_duration
 
50
 
51
  validation = validate_video_file(video_file)
52
  if not validation.is_valid:
53
+ return None, f"Error: {validation.error_message}", "\n".join(log_messages)
54
 
55
  log(f"Video size: {validation.file_size / (1024*1024):.1f} MB")
56
 
57
  # Validate reference image if provided
58
  ref_path = None
59
+ if reference_image is not None:
60
  ref_validation = validate_image_file(reference_image)
61
  if ref_validation.is_valid:
62
  ref_path = reference_image
63
  log(f"Reference image: {Path(reference_image).name}")
 
 
64
 
65
  # Map domain string
66
  domain_map = {
 
76
 
77
  # Create output directory
78
  output_dir = Path(tempfile.mkdtemp(prefix="shortsmith_output_"))
 
79
 
80
  # Initialize pipeline
81
  log("Initializing pipeline...")
82
  pipeline = PipelineOrchestrator()
83
 
84
  # Process video
85
+ log(f"Processing: {int(num_clips)} clips @ {int(clip_duration)}s each")
86
 
87
  result = pipeline.process(
88
  video_path=video_path,
 
90
  clip_duration=float(clip_duration),
91
  domain=domain_value,
92
  reference_image=ref_path,
93
+ custom_prompt=custom_prompt if custom_prompt else None,
94
  )
95
 
96
  # Handle result
97
  if result.success:
98
+ log(f"Processing complete in {result.processing_time:.1f}s")
99
 
100
  clip_paths = []
101
  for i, clip in enumerate(result.clips):
 
103
  output_path = output_dir / f"highlight_{i+1}.mp4"
104
  shutil.copy2(clip.clip_path, output_path)
105
  clip_paths.append(str(output_path))
106
+ log(f"Clip {i+1}: {format_duration(clip.start_time)} - {format_duration(clip.end_time)}")
 
 
107
 
108
+ status = f"Successfully extracted {len(clip_paths)} clips in {result.processing_time:.1f}s"
109
  pipeline.cleanup()
110
+
111
+ if clip_paths:
112
+ return clip_paths, status, "\n".join(log_messages)
113
+ else:
114
+ return None, "No clips extracted", "\n".join(log_messages)
115
  else:
116
+ log(f"Failed: {result.error_message}")
117
  pipeline.cleanup()
118
+ return None, f"Error: {result.error_message}", "\n".join(log_messages)
119
 
120
  except Exception as e:
121
+ log(f"Error: {str(e)}")
 
122
  log(traceback.format_exc())
123
+ return None, f"Error: {str(e)}", "\n".join(log_messages)
124
+
125
+
126
+ # Create simple interface
127
+ demo = gr.Interface(
128
+ fn=process_video,
129
+ inputs=[
130
+ gr.Video(label="Upload Video"),
131
+ gr.Dropdown(
132
+ choices=["Sports", "Vlogs", "Music Videos", "Podcasts", "Gaming", "General"],
133
+ value="General",
134
+ label="Content Domain"
135
+ ),
136
+ gr.Slider(minimum=1, maximum=10, value=3, step=1, label="Number of Clips"),
137
+ gr.Slider(minimum=5, maximum=30, value=15, step=1, label="Clip Duration (seconds)"),
138
+ gr.Image(label="Reference Image (Optional)", type="filepath"),
139
+ gr.Textbox(label="Custom Instructions (Optional)", placeholder="E.g., Focus on crowd reactions"),
140
+ ],
141
+ outputs=[
142
+ gr.Files(label="Extracted Clips"),
143
+ gr.Textbox(label="Status"),
144
+ gr.Textbox(label="Processing Log"),
145
+ ],
146
+ title="ShortSmith v2",
147
+ description="AI-Powered Video Highlight Extractor. Upload a video and extract the most engaging clips automatically.",
148
+ allow_flagging="never",
149
+ )
150
+
151
+ demo.queue()
152
+ demo.launch()