latterworks commited on
Commit
ce13058
·
verified ·
1 Parent(s): 2ac66e6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +194 -397
app.py CHANGED
@@ -1,408 +1,205 @@
1
  import gradio as gr
2
- import subprocess
3
- import os
4
- import tempfile
5
- import librosa
6
- import librosa.display
7
- import matplotlib.pyplot as plt
8
- import numpy as np
9
- import scipy.ndimage
10
  from pathlib import Path
 
11
  import logging
12
- import warnings
 
 
 
13
  import shutil
14
- from typing import Tuple, Optional, Dict, Any
15
-
16
- # Configure matplotlib for web display
17
- plt.switch_backend('Agg')
18
- warnings.filterwarnings('ignore')
19
-
20
- # Setup logging
21
- logging.basicConfig(
22
- level=logging.INFO,
23
- format="%(asctime)s - %(levelname)s - %(message)s",
24
- handlers=[logging.StreamHandler()]
25
- )
26
- logger = logging.getLogger(__name__)
27
-
28
- class AudioAnalyzer:
29
- """Core class for audio analysis with modular feature extraction methods."""
30
-
31
- def __init__(self, temp_dir: Optional[str] = None):
32
- """Initialize with a temporary directory for file storage."""
33
- self.temp_dir = Path(temp_dir or tempfile.mkdtemp())
34
- self.temp_dir.mkdir(exist_ok=True)
35
- self.plot_files = [] # Track plot files for cleanup
36
- logger.info(f"Initialized temporary directory: {self.temp_dir}")
37
-
38
- def cleanup(self) -> None:
39
- """Remove temporary directory and plot files."""
40
- for plot_file in self.plot_files:
41
- if Path(plot_file).exists():
42
- try:
43
- Path(plot_file).unlink()
44
- logger.info(f"Removed plot file: {plot_file}")
45
- except Exception as e:
46
- logger.warning(f"Failed to remove plot file {plot_file}: {str(e)}")
47
- if self.temp_dir.exists():
48
- shutil.rmtree(self.temp_dir, ignore_errors=True)
49
- logger.info(f"Cleaned up temporary directory: {self.temp_dir}")
50
-
51
- def download_youtube_audio(self, video_url: str, progress=gr.Progress()) -> Tuple[Optional[str], str]:
52
- """Download audio from YouTube using yt-dlp."""
53
- if not video_url:
54
- return None, "Please provide a valid YouTube URL"
55
-
56
- progress(0.1, desc="Initializing download...")
57
- output_dir = self.temp_dir / "downloaded_audio"
58
- output_dir.mkdir(exist_ok=True)
59
- output_file = output_dir / "audio.mp3"
60
-
61
- command = [
62
- "yt-dlp",
63
- "-x",
64
- "--audio-format", "mp3",
65
- "-o", str(output_file),
66
- "--no-playlist",
67
- "--restrict-filenames",
68
- video_url
69
- ]
70
-
71
- try:
72
- progress(0.3, desc="Downloading audio...")
73
- subprocess.run(command, check=True, capture_output=True, text=True)
74
- progress(1.0, desc="Download complete!")
75
- return str(output_file), f"Successfully downloaded audio: {output_file.name}"
76
- except FileNotFoundError:
77
- return None, "yt-dlp not found. Install it with: pip install yt-dlp"
78
- except subprocess.CalledProcessError as e:
79
- return None, f"Download failed: {e.stderr}"
80
- except Exception as e:
81
- logger.error(f"Unexpected error during download: {str(e)}")
82
- return None, f"Error: {str(e)}"
83
-
84
- def save_plot(self, fig, filename: str) -> Optional[str]:
85
- """Save matplotlib figure to a temporary file and verify existence."""
86
- try:
87
- # Use NamedTemporaryFile to ensure persistence
88
- with tempfile.NamedTemporaryFile(suffix='.png', delete=False, dir=self.temp_dir) as tmp_file:
89
- plot_path = tmp_file.name
90
- fig.savefig(plot_path, dpi=300, bbox_inches='tight', format='png')
91
- plt.close(fig)
92
- if not Path(plot_path).exists():
93
- logger.error(f"Plot file not created: {plot_path}")
94
- return None
95
- self.plot_files.append(plot_path)
96
- logger.info(f"Saved plot: {plot_path}")
97
- return str(plot_path)
98
- except Exception as e:
99
- logger.error(f"Error saving plot {filename}: {str(e)}")
100
- plt.close(fig)
101
- return None
102
-
103
- def extract_basic_features(self, audio_path: str, sr: int = 16000, max_duration: float = 60.0,
104
- progress=gr.Progress()) -> Tuple[Optional[str], Optional[str], Optional[str]]:
105
- """Extract basic audio features and generate visualizations."""
106
- if not audio_path or not Path(audio_path).exists():
107
- return None, None, "Invalid or missing audio file"
108
-
109
- try:
110
- progress(0.1, desc="Loading audio...")
111
- y, sr = librosa.load(audio_path, sr=sr)
112
- duration = librosa.get_duration(y=y, sr=sr)
113
-
114
- if duration > max_duration:
115
- y = y[:int(sr * max_duration)]
116
- duration = max_duration
117
-
118
- progress(0.3, desc="Computing features...")
119
- features: Dict[str, Any] = {
120
- 'duration': duration,
121
- 'sample_rate': sr,
122
- 'samples': len(y),
123
- 'tempo': float(librosa.beat.beat_track(y=y, sr=sr)[0]), # Convert to float
124
- 'mfcc': librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13),
125
- 'spectral_centroid': librosa.feature.spectral_centroid(y=y, sr=sr)[0],
126
- 'spectral_rolloff': librosa.feature.spectral_rolloff(y=y, sr=sr)[0],
127
- 'zero_crossing_rate': librosa.feature.zero_crossing_rate(y)[0]
128
- }
129
-
130
- progress(0.5, desc="Computing mel spectrogram...")
131
- hop_length = 512
132
- S_mel = librosa.feature.melspectrogram(y=y, sr=sr, hop_length=hop_length, n_mels=80)
133
- S_dB = librosa.power_to_db(S_mel, ref=np.max)
134
-
135
- progress(0.8, desc="Creating visualizations...")
136
- fig, axes = plt.subplots(2, 2, figsize=(15, 10))
137
-
138
- time_axis = np.linspace(0, duration, len(y))
139
- axes[0, 0].plot(time_axis, y)
140
- axes[0, 0].set_title('Waveform')
141
- axes[0, 0].set_xlabel('Time (s)')
142
- axes[0, 0].set_ylabel('Amplitude')
143
-
144
- librosa.display.specshow(S_dB, sr=sr, hop_length=hop_length,
145
- x_axis='time', y_axis='mel', ax=axes[0, 1])
146
- axes[0, 1].set_title('Mel Spectrogram')
147
-
148
- librosa.display.specshow(features['mfcc'], sr=sr, x_axis='time', ax=axes[1, 0])
149
- axes[1, 0].set_title('MFCC')
150
-
151
- times = librosa.frames_to_time(range(len(features['spectral_centroid'])), sr=sr, hop_length=hop_length)
152
- axes[1, 1].plot(times, features['spectral_centroid'], label='Spectral Centroid')
153
- axes[1, 1].plot(times, features['spectral_rolloff'], label='Spectral Rolloff')
154
- axes[1, 1].set_title('Spectral Features')
155
- axes[1, 1].set_xlabel('Time (s)')
156
- axes[1, 1].legend()
157
-
158
- plt.tight_layout()
159
- plot_path = self.save_plot(fig, "basic_features")
160
- if not plot_path:
161
- return None, None, "Failed to save feature visualizations"
162
-
163
- # Validate feature shapes
164
- for key in ['mfcc', 'spectral_centroid', 'spectral_rolloff', 'zero_crossing_rate']:
165
- if not isinstance(features[key].shape, tuple):
166
- logger.error(f"Invalid shape for {key}: {features[key].shape}")
167
- return None, None, f"Invalid feature shape for {key}"
168
-
169
- summary = f"""
170
- **Audio Summary:**
171
- - Duration: {duration:.2f} seconds
172
- - Sample Rate: {sr} Hz
173
- - Estimated Tempo: {features['tempo']:.1f} BPM
174
- - Number of Samples: {features['samples']:,}
175
-
176
- **Feature Shapes:**
177
- - MFCC: {features['mfcc'].shape}
178
- - Spectral Centroid: {features['spectral_centroid'].shape}
179
- - Spectral Rolloff: {features['spectral_rolloff'].shape}
180
- - Zero Crossing Rate: {features['zero_crossing_rate'].shape}
181
- """
182
-
183
- progress(1.0, desc="Analysis complete!")
184
- return plot_path, summary, None
185
-
186
- except Exception as e:
187
- logger.error(f"Error processing audio: {str(e)}")
188
- return None, None, f"Error processing audio: {str(e)}"
189
-
190
- def extract_chroma_features(self, audio_path: str, sr: int = 16000, max_duration: float = 30.0,
191
- progress=gr.Progress()) -> Tuple[Optional[str], Optional[str], Optional[str]]:
192
- """Extract and visualize enhanced chroma features."""
193
- if not audio_path or not Path(audio_path).exists():
194
- return None, None, "Invalid or missing audio file"
195
-
196
- try:
197
- progress(0.1, desc="Loading audio...")
198
- y, sr = librosa.load(audio_path, sr=sr)
199
- if len(y) > sr * max_duration:
200
- y = y[:int(sr * max_duration)]
201
-
202
- progress(0.3, desc="Computing chroma variants...")
203
- chroma_orig = librosa.feature.chroma_cqt(y=y, sr=sr)
204
- y_harm = librosa.effects.harmonic(y=y, margin=8)
205
- chroma_harm = librosa.feature.chroma_cqt(y=y_harm, sr=sr)
206
- chroma_filter = np.minimum(chroma_harm,
207
- librosa.decompose.nn_filter(chroma_harm,
208
- aggregate=np.median,
209
- metric='cosine'))
210
- chroma_smooth = scipy.ndimage.median_filter(chroma_filter, size=(1, 9))
211
- chroma_stft = librosa.feature.chroma_stft(y=y, sr=sr)
212
- chroma_cens = librosa.feature.chroma_cens(y=y, sr=sr)
213
-
214
- progress(0.8, desc="Creating visualizations...")
215
- fig, axes = plt.subplots(3, 2, figsize=(15, 12))
216
- axes = axes.flatten()
217
-
218
- for i, (chroma, title) in enumerate([
219
- (chroma_orig, 'Original Chroma (CQT)'),
220
- (chroma_harm, 'Harmonic Chroma'),
221
- (chroma_filter, 'Non-local Filtered'),
222
- (chroma_smooth, 'Median Filtered'),
223
- (chroma_stft, 'Chroma (STFT)'),
224
- (chroma_cens, 'CENS Features')
225
- ]):
226
- librosa.display.specshow(chroma, y_axis='chroma', x_axis='time', ax=axes[i])
227
- axes[i].set_title(title)
228
-
229
- plt.tight_layout()
230
- plot_path = self.save_plot(fig, "chroma_features")
231
- if not plot_path:
232
- return None, None, "Failed to save chroma visualizations"
233
-
234
- summary = "Chroma feature analysis complete! Visualizations show different chroma extraction methods for harmonic analysis."
235
- progress(1.0, desc="Chroma analysis complete!")
236
- return plot_path, summary, None
237
-
238
- except Exception as e:
239
- logger.error(f"Error processing chroma features: {str(e)}")
240
- return None, None, f"Error processing chroma features: {str(e)}"
241
-
242
- def generate_patches(self, audio_path: str, sr: int = 16000, patch_duration: float = 5.0,
243
- hop_duration: float = 1.0, progress=gr.Progress()) -> Tuple[Optional[str], Optional[str], Optional[str]]:
244
- """Generate fixed-duration patches for transformer input."""
245
- if not audio_path or not Path(audio_path).exists():
246
- return None, None, "Invalid or missing audio file"
247
-
248
  try:
249
- progress(0.1, desc="Loading audio...")
250
- y, sr = librosa.load(audio_path, sr=sr)
251
-
252
- progress(0.3, desc="Computing mel spectrogram...")
253
- hop_length = 512
254
- S_mel = librosa.feature.melspectrogram(y=y, sr=sr, hop_length=hop_length, n_mels=80)
255
- S_dB = librosa.power_to_db(S_mel, ref=np.max)
256
-
257
- progress(0.5, desc="Generating patches...")
258
- patch_frames = librosa.time_to_frames(patch_duration, sr=sr, hop_length=hop_length)
259
- hop_frames = librosa.time_to_frames(hop_duration, sr=sr, hop_length=hop_length)
260
- patches = librosa.util.frame(S_dB, frame_length=patch_frames, hop_length=hop_frames)
261
-
262
- progress(0.8, desc="Creating visualizations...")
263
- num_patches_to_show = min(6, patches.shape[-1])
264
- fig, axes = plt.subplots(2, 3, figsize=(18, 8))
265
- axes = axes.flatten()
266
-
267
- for i in range(num_patches_to_show):
268
- librosa.display.specshow(patches[..., i], y_axis='mel', x_axis='time',
269
- ax=axes[i], sr=sr, hop_length=hop_length)
270
- axes[i].set_title(f'Patch {i+1}')
271
-
272
- for i in range(num_patches_to_show, len(axes)):
273
- axes[i].set_visible(False)
274
-
275
- plt.tight_layout()
276
- plot_path = self.save_plot(fig, "patches")
277
- if not plot_path:
278
- return None, None, "Failed to save patch visualizations"
279
-
280
- summary = f"""
281
- **Patch Generation Summary:**
282
- - Total patches generated: {patches.shape[-1]}
283
- - Patch duration: {patch_duration:.1f} seconds
284
- - Hop duration: {hop_duration:.1f} seconds
285
- - Patch shape (mels, time, patches): {patches.shape}
286
- - Each patch covers {patch_frames} time frames
287
- """
288
-
289
- progress(1.0, desc="Patch generation complete!")
290
- return plot_path, summary, None
291
-
292
  except Exception as e:
293
- logger.error(f"Error generating patches: {str(e)}")
294
- return None, None, f"Error generating patches: {str(e)}"
295
-
296
- def create_gradio_interface() -> gr.Blocks:
297
- """Create a modular Gradio interface for audio analysis."""
298
- analyzer = AudioAnalyzer()
299
-
300
- with gr.Blocks(title="🎵 Audio Analysis Suite", theme=gr.themes.Soft()) as demo:
301
- gr.Markdown("""
302
- # 🎵 Audio Analysis Suite
303
-
304
- Analyze audio from YouTube videos or uploaded files. Extract features or generate transformer patches for deep learning applications.
305
-
306
- **Features:**
307
- - 📊 **Basic Features**: Waveform, Mel Spectrogram, MFCC, Spectral Analysis, Tempo Detection
308
- - 🎼 **Chroma Features**: Harmonic content analysis with multiple extraction methods
309
- - 🧩 **Transformer Patches**: Fixed-duration patches for deep learning
310
-
311
- **Requirements**: Dependencies are automatically installed in Hugging Face Spaces via `requirements.txt`.
312
- """)
313
 
314
- with gr.Row():
315
- with gr.Column(scale=1):
316
- gr.Markdown("### 📁 Audio Input")
317
- with gr.Group():
318
- gr.Markdown("**Download from YouTube** (Supported formats: MP3, WAV, etc.)")
319
- youtube_url = gr.Textbox(
320
- label="YouTube URL",
321
- placeholder="https://www.youtube.com/watch?v=...",
322
- )
323
- download_btn = gr.Button("📥 Download Audio", variant="primary")
324
- download_status = gr.Textbox(label="Download Status", interactive=False)
325
-
326
- with gr.Group():
327
- gr.Markdown("**Or upload audio file** (Supported formats: MP3, WAV, FLAC, etc.)")
328
- audio_file = gr.Audio(
329
- label="Upload Audio File",
330
- type="filepath",
331
- )
332
-
333
- with gr.Column(scale=2):
334
- gr.Markdown("### 🔍 Analysis Results")
335
- with gr.Tabs():
336
- with gr.Tab("📊 Basic Features"):
337
- basic_plot = gr.Image(label="Feature Visualizations")
338
- basic_summary = gr.Markdown(label="Feature Summary")
339
- basic_btn = gr.Button("🔍 Analyze Basic Features", variant="secondary")
340
-
341
- with gr.Tab("🎼 Chroma Features"):
342
- chroma_plot = gr.Image(label="Chroma Visualizations")
343
- chroma_summary = gr.Markdown(label="Chroma Summary")
344
- chroma_btn = gr.Button("🎼 Analyze Chroma Features", variant="secondary")
345
-
346
- with gr.Tab("🧩 Transformer Patches"):
347
- with gr.Row():
348
- patch_duration = gr.Slider(
349
- label="Patch Duration (seconds)",
350
- minimum=1.0, maximum=10.0, value=5.0, step=0.5,
351
- )
352
- hop_duration = gr.Slider(
353
- label="Hop Duration (seconds)",
354
- minimum=0.1, maximum=5.0, value=1.0, step=0.1,
355
- )
356
- patches_plot = gr.Image(label="Generated Patches")
357
- patches_summary = gr.Markdown(label="Patch Summary")
358
- patches_btn = gr.Button("🧩 Generate Patches", variant="secondary")
359
-
360
- error_output = gr.Textbox(label="Error Messages", interactive=False)
361
-
362
- gr.Markdown("""
363
- ### ℹ️ Usage Tips
364
- - **Processing Limits**: 60s for basic features, 30s for chroma features for fast response
365
- - **YouTube Downloads**: Ensure URLs are valid and respect YouTube's terms of service
366
- - **Visualizations**: High-quality, suitable for research and education
367
- - **Storage**: Temporary files are cleaned up when the interface closes
368
- - **Support**: For issues, check the [GitHub repository](https://github.com/your-repo)
369
- """)
370
-
371
- # Event handlers
372
- download_btn.click(
373
- fn=analyzer.download_youtube_audio,
374
- inputs=[youtube_url],
375
- outputs=[audio_file, download_status]
376
- )
377
-
378
- basic_btn.click(
379
- fn=analyzer.extract_basic_features,
380
- inputs=[audio_file],
381
- outputs=[basic_plot, basic_summary, error_output]
382
- )
383
-
384
- chroma_btn.click(
385
- fn=analyzer.extract_chroma_features,
386
- inputs=[audio_file],
387
- outputs=[chroma_plot, chroma_summary, error_output]
388
- )
389
-
390
- patches_btn.click(
391
- fn=analyzer.generate_patches,
392
- inputs=[audio_file, patch_duration, hop_duration],
393
- outputs=[patches_plot, patches_summary, error_output]
394
- )
395
-
396
- audio_file.change(
397
- fn=analyzer.extract_basic_features,
398
- inputs=[audio_file],
399
- outputs=[basic_plot, basic_summary, error_output]
400
- )
401
 
402
- demo.unload(fn=analyzer.cleanup)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
403
 
404
- return demo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
405
 
406
  if __name__ == "__main__":
407
- demo = create_gradio_interface()
408
- demo.launch()
 
1
  import gradio as gr
 
 
 
 
 
 
 
 
2
  from pathlib import Path
3
+ import yt_dlp
4
  import logging
5
+ import librosa
6
+ import numpy as np
7
+ from PIL import Image
8
+ import ffmpeg
9
  import shutil
10
+ import tempfile
11
+ import time
12
+
13
+ # Set up logging for debugging
14
+ logging.basicConfig(level=logging.DEBUG)
15
+
16
+ def analyze_audio(youtube_url, input_text, input_image=None, slider_value=50, checkbox_value=False):
17
+ """
18
+ Downloads YouTube audio, performs automatic audio feature analysis with librosa, and processes inputs.
19
+ Automatically handles file and folder management.
20
+
21
+ Args:
22
+ youtube_url (str): YouTube video URL (optional).
23
+ input_text (str): Text input for processing.
24
+ input_image (PIL.Image, optional): Image input for processing.
25
+ slider_value (float): Numerical parameter (e.g., analysis threshold).
26
+ checkbox_value (bool): Toggle for enhanced analysis.
27
+
28
+ Returns:
29
+ tuple: (processed_text, output_image_display, output_audio, extra_info)
30
+ """
31
+ # Create a unique temporary directory for this run
32
+ temp_dir = Path(tempfile.mkdtemp(prefix="audio_analysis_"))
33
+ output_dir = temp_dir / "downloaded_media"
34
+ output_dir.mkdir(parents=True, exist_ok=True)
35
+ logging.debug(f"Created temporary directory: {temp_dir}, output directory: {output_dir}")
36
+
37
+ try:
38
+ # Initialize outputs
39
+ processed_text = f"Processed: '{input_text}'."
40
+ output_image_display = input_image
41
+ output_audio = None
42
+ extra_info = f"Threshold: {slider_value/100:.2f}"
43
+
44
+ # Handle YouTube download if URL is provided
45
+ if youtube_url:
46
+ try:
47
+ # Validate YouTube URL
48
+ if not youtube_url.startswith(("https://www.youtube.com/", "https://youtu.be/")):
49
+ return "Error: Invalid YouTube URL", None, None, "Processing failed."
50
+
51
+ # YouTube download options (audio only)
52
+ ydl_opts = {
53
+ 'format': 'bestaudio/best',
54
+ 'outtmpl': str(output_dir / '%(title)s.%(ext)s'),
55
+ 'postprocessors': [{
56
+ 'key': 'FFmpegExtractAudio',
57
+ 'preferredcodec': 'mp3',
58
+ 'preferredquality': '192',
59
+ }],
60
+ 'restrictfilenames': True,
61
+ 'noplaylist': True,
62
+ }
63
+
64
+ # Download audio
65
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
66
+ info = ydl.extract_info(youtube_url, download=True)
67
+ audio_file = output_dir / f"{info['title']}.mp3"
68
+ logging.debug(f"Downloaded audio: {audio_file}")
69
+ output_audio = str(audio_file)
70
+
71
+ # Perform automatic audio feature analysis with librosa
72
+ y, sr = librosa.load(audio_file)
73
+ hop_length = 512 # Valid hop_length to fix "Invalid hop_length: 0" error
74
+ logging.debug(f"Using hop_length: {hop_length}")
75
+
76
+ # Extract features
77
+ mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13, hop_length=hop_length)
78
+ spectral_centroid = librosa.feature.spectral_centroid(y=y, sr=sr, hop_length=hop_length)
79
+ tempo, _ = librosa.beat.beat_track(y=y, sr=sr, hop_length=hop_length)
80
+
81
+ # Aggregate features
82
+ mfcc_mean = np.mean(mfcc, axis=1).tolist()[:3] # Mean of first 3 MFCC coefficients
83
+ spectral_centroid_mean = np.mean(spectral_centroid)
84
+ features_summary = (
85
+ f"Audio Features: MFCC (mean of first 3 coeffs): {mfcc_mean}, "
86
+ f"Spectral Centroid: {spectral_centroid_mean:.2f} Hz, "
87
+ f"Tempo: {tempo:.2f} BPM"
88
+ )
89
+
90
+ processed_text += f" {features_summary}."
91
+ extra_info += f", Audio: {audio_file.name}"
92
+
93
+ except Exception as e:
94
+ logging.error(f"YouTube download or audio processing error: {str(e)}")
95
+ processed_text += f" Error processing YouTube audio: {str(e)}."
96
+
97
+ # Handle image processing if provided
98
+ if input_image is not None:
99
+ from PIL import ImageEnhance
100
+ enhancer = ImageEnhance.Brightness(input_image)
101
+ output_image_display = enhancer.enhance(1.5)
102
+ processed_text += " Image processed (brightened)."
103
+ else:
104
+ processed_text += " No image provided."
105
+
106
+ # Incorporate slider and checkbox
107
+ processed_text += f" Slider: {slider_value}, Enhanced Analysis: {checkbox_value}."
108
+ if checkbox_value:
109
+ processed_text += " Enhanced analysis enabled."
110
+ if youtube_url and slider_value > 50:
111
+ processed_text += f" High threshold ({slider_value}) applied for deeper analysis."
112
+
113
+ return processed_text, output_image_display, output_audio, extra_info
114
+
115
+ except Exception as e:
116
+ logging.error(f"Error in analyze_audio: {str(e)}")
117
+ return f"Error: {str(e)}", None, None, "Processing failed."
118
+
119
+ finally:
120
+ # Clean up temporary directory after a delay to ensure file access
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  try:
122
+ time.sleep(1) # Brief delay to ensure Gradio can serve the audio file
123
+ if temp_dir.exists():
124
+ shutil.rmtree(temp_dir)
125
+ logging.debug(f"Cleaned up temporary directory: {temp_dir}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  except Exception as e:
127
+ logging.error(f"Error cleaning up temporary directory: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
+ # Define input components
130
+ input_youtube_url = gr.Textbox(
131
+ label="YouTube Video URL",
132
+ placeholder="e.g., https://www.youtube.com/watch?v=dQw4w9WgXcQ",
133
+ info="Optional: Enter a YouTube URL to download and analyze audio."
134
+ )
135
+ input_text_component = gr.Textbox(
136
+ label="Input Text",
137
+ placeholder="e.g., Analyze this audio track",
138
+ info="Type a description or query for processing."
139
+ )
140
+ input_image_component = gr.Image(
141
+ type="pil",
142
+ label="Upload Image (Optional)",
143
+ sources=["upload", "webcam", "clipboard"]
144
+ )
145
+ input_slider_component = gr.Slider(
146
+ minimum=0,
147
+ maximum=100,
148
+ value=50,
149
+ step=1,
150
+ label="Analysis Threshold",
151
+ info="Adjusts sensitivity of audio feature analysis."
152
+ )
153
+ input_checkbox_component = gr.Checkbox(
154
+ label="Enable Enhanced Analysis",
155
+ info="Toggle for deeper audio feature extraction."
156
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
+ # Define output components
159
+ output_text_component = gr.Textbox(
160
+ label="Analysis Results",
161
+ info="Text results including audio feature analysis."
162
+ )
163
+ output_image_component = gr.Image(
164
+ label="Processed Image (if any)",
165
+ info="Processed image output (if provided)."
166
+ )
167
+ output_audio_component = gr.Audio(
168
+ label="Downloaded Audio",
169
+ type="filepath",
170
+ info="Audio downloaded from YouTube."
171
+ )
172
+ output_label_component = gr.Label(
173
+ label="Analysis Summary",
174
+ info="Feature analysis details and processing info."
175
+ )
176
 
177
+ # Create the Gradio interface
178
+ iface = gr.Interface(
179
+ fn=analyze_audio,
180
+ inputs=[
181
+ input_youtube_url,
182
+ input_text_component,
183
+ input_image_component,
184
+ input_slider_component,
185
+ input_checkbox_component
186
+ ],
187
+ outputs=[
188
+ output_text_component,
189
+ output_image_component,
190
+ output_audio_component,
191
+ output_label_component
192
+ ],
193
+ title="YouTube Audio Feature Analysis",
194
+ description="Download YouTube audio, analyze features with librosa, and process text/image inputs. Customize with slider and checkbox.",
195
+ examples=[
196
+ ["https://www.youtube.com/watch?v=dQw4w9WgXcQ", "Analyze this track", None, 75, True],
197
+ [None, "Describe a music track", None, 30, False],
198
+ ["https://www.youtube.com/watch?v=9bZkp7q19f0", "Extract audio features", None, 60, True]
199
+ ],
200
+ allow_flagging="never",
201
+ theme=gr.themes.Soft()
202
+ )
203
 
204
  if __name__ == "__main__":
205
+ iface.launch()