Download app.py from dkappe/AISong: direct link, hf CLI and curl.
- Browser
- Download file 5.88 kB
-
https://huggingface.co/spaces/dkappe/AISong/resolve/main/app.py
- Command line
-
hf download hf://spaces/dkappe/AISong/app.py
-
curl -L -o app.py https://huggingface.co/spaces/dkappe/AISong/resolve/main/app.py
5.88 kB
| import gradio as gr | |
| import matplotlib.pyplot as plt | |
| import librosa | |
| import torch | |
| import librosa.display | |
| import numpy as np | |
| import torch.nn as nn | |
| import os | |
| # ---- CR2NN Model ---- | |
| class CR2NNModel(nn.Module): | |
| def __init__(self, num_classes=2, lr=1e-3): | |
| super(CR2NNModel, self).__init__() | |
| self.lr = lr | |
| # Convolutional feature extractor: | |
| # Input shape: (batch, 1, n_mels, time) | |
| self.conv = nn.Sequential( | |
| nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1), # (batch, 32, n_mels, time) | |
| nn.BatchNorm2d(32), | |
| nn.ReLU(), | |
| nn.MaxPool2d(kernel_size=(2, 2)), # (batch, 32, n_mels/2, time/2) | |
| nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1), # (batch, 64, n_mels/2, time/2) | |
| nn.BatchNorm2d(64), | |
| nn.ReLU(), | |
| nn.MaxPool2d(kernel_size=(2, 2)) # (batch, 64, n_mels/4, time/4) | |
| ) | |
| # For example, if n_mels=256 and fixed_length (time dimension) = 1400, | |
| # after pooling the output becomes roughly (batch, 64, 64, 350). | |
| # Averaging over the frequency dimension (n_mels/4) yields a sequence of length 350 with 64 features. | |
| # GRU: Now stacking two layers instead of one. | |
| # Using num_layers=2 applies dropout (if specified) between layers. | |
| self.gru = nn.GRU(input_size=64, hidden_size=128, num_layers=2, | |
| batch_first=True, bidirectional=True, dropout=0.5) | |
| # The output of a bidirectional GRU with hidden_size=128 is 256 per time step. | |
| self.fc = nn.Linear(128 * 2, num_classes) # Maps 256 features to num_classes | |
| def forward(self, x): | |
| # x: (batch, 1, n_mels, time) | |
| conv_out = self.conv(x) # (batch, 64, n_mels/4, time/4) | |
| conv_out = conv_out.mean(dim=2) # Average over the frequency axis: (batch, 64, time/4) | |
| conv_out = conv_out.permute(0, 2, 1) # (batch, time/4, 64) | |
| gru_out, _ = self.gru(conv_out) # (batch, time/4, 256) | |
| last_out = gru_out[:, -1, :] # Use the output from the last time step: (batch, 256) | |
| logits = self.fc(last_out) # (batch, num_classes) | |
| return logits | |
| # Function to preprocess the audio file | |
| def preprocess_audio(file_path, sr=22050, fixed_length=1400): | |
| # Load audio file | |
| # audio, _ = load_audio_with_skip(file_path, sr=sr, skip_seconds = 5) | |
| audio, _ = librosa.load(file_path, sr=sr) | |
| # Generate Mel spectrogram | |
| #mel_spec = librosa.feature.melspectrogram(y=audio, sr=sr, n_mels=128, fmax=8000) | |
| mel_spec = librosa.feature.melspectrogram( | |
| y=audio, | |
| sr=sr, | |
| n_fft=4096, # Higher frequency resolution | |
| hop_length=256, # Higher time resolution | |
| n_mels=256, # More Mel bins for finer frequency detail | |
| fmax=8000 | |
| ) | |
| mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max) | |
| # Normalize the spectrogram | |
| mel_spec_db = (mel_spec_db - mel_spec_db.min()) / (mel_spec_db.max() - mel_spec_db.min()) | |
| # Pad or truncate to fixed length | |
| if mel_spec_db.shape[1] < fixed_length: | |
| pad_width = fixed_length - mel_spec_db.shape[1] | |
| mel_spec_db = np.pad(mel_spec_db, ((0, 0), (0, pad_width)), mode='constant') | |
| else: | |
| mel_spec_db = mel_spec_db[:, :fixed_length] | |
| # Add channel dimension and convert to PyTorch tensor | |
| mel_spec_db = np.expand_dims(mel_spec_db, axis=0) # Add channel dimension | |
| mel_spec_db = torch.tensor(mel_spec_db, dtype=torch.float32).unsqueeze(0) # Add batch dimension | |
| return mel_spec_db | |
| # Function to classify the audio file | |
| def classify_audio(file_path, model, device): | |
| # Preprocess the audio file | |
| input_tensor = preprocess_audio(file_path).to(device) | |
| # Perform inference | |
| model.eval() | |
| with torch.no_grad(): | |
| logits = model(input_tensor) | |
| probabilities = torch.nn.functional.softmax(logits, dim=1) | |
| human_percent = probabilities[0,0].item() * 100 | |
| ai_percent = probabilities[0,1].item() * 100 | |
| # Map prediction to labels | |
| return {"Human" : human_percent, "AI" : ai_percent} | |
| def load_model(): | |
| # Construct the model file path using a relative path | |
| model_path = os.path.join(os.path.dirname(__file__), "model", "model.pth") | |
| # Load the model (adjust loading code as needed for your model type) | |
| model = CR2NNModel(num_classes=2) | |
| model.load_state_dict(torch.load(model_path, map_location="cpu")) | |
| model.eval() # Set the model to evaluation mode | |
| return model | |
| def analyze_mp3(file_path): | |
| # Load the MP3 file. This returns the audio data and sampling rate. | |
| try: | |
| audio, sr = librosa.load(file_path, sr=None) | |
| duration = librosa.get_duration(y=audio, sr=sr) | |
| except Exception as e: | |
| # If there is an error loading the file, assume a default duration. | |
| duration = 0 | |
| # load the model | |
| model = load_model() | |
| # Replace this with your own logic/model to determine the percentages. | |
| result = classify_audio(file_path, model, "cpu") | |
| ai_percentage = result['AI'] | |
| human_percentage = result['Human'] | |
| # Create a pie chart with fixed labels: "AI" and "Human" | |
| labels = ['AI', 'Human'] | |
| sizes = [ai_percentage, human_percentage] | |
| fig, ax = plt.subplots() | |
| ax.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90) | |
| ax.axis('equal') # Ensure that the pie is drawn as a circle. | |
| plt.close(fig) | |
| return fig | |
| # Create the Gradio interface | |
| iface = gr.Interface( | |
| fn=analyze_mp3, | |
| inputs=gr.Audio(type="filepath", label="Upload MP3"), | |
| outputs=gr.Plot(label="Analysis Pie Chart"), | |
| title="MP3 Analysis Pie Chart", | |
| description="Upload an MP3 file to generate a pie chart with AI and Human labels." | |
| ) | |
| iface.launch() | |