Vansh Chugh
guard launch call for clean importability
44cbb43
Raw
History Blame Contribute Delete
5.18 kB
import sys
sys.stdout.reconfigure(line_buffering=True)
try:
import spaces
except ImportError:
# keep @spaces.GPU usable as a no-op; ZeroGPU requires this exact name.
class spaces:
class GPU:
def __init__(self, func=None, duration=60):
self.func = func
def __call__(self, *args, **kwargs):
if self.func is not None:
return self.func(*args, **kwargs)
func = args[0]
return func
import gradio as gr
import torch
import librosa
import numpy as np
import soundfile as sf
# adapted from AI-Music-Detection-HFSpace/app.py: torchaudio 2.9+ routes
# torchaudio.load through load_with_torchcodec, which isn't installed here.
# Loading via librosa/soundfile instead sidesteps that dependency entirely.
import torchaudio
def _patched_load(filepath, *args, **kwargs):
frame_offset = kwargs.pop("frame_offset", 0)
num_frames = kwargs.pop("num_frames", -1)
channels_first = kwargs.pop("channels_first", True)
if len(args) >= 1:
frame_offset = args[0]
if len(args) >= 2:
num_frames = args[1]
data, sample_rate = librosa.load(str(filepath), sr=None, mono=False)
if data.ndim == 1:
data = data[np.newaxis, :]
if frame_offset and int(frame_offset) > 0:
data = data[:, int(frame_offset):]
if num_frames and int(num_frames) > 0:
data = data[:, : int(num_frames)]
duration_s = data.shape[-1] / max(sample_rate, 1)
if duration_s < 1.5:
raise RuntimeError(
f"Audio is too short ({duration_s:.2f} s). "
"Please upload a clip of at least 2 seconds (a few seconds of music works best)."
)
waveform = torch.from_numpy(np.ascontiguousarray(data)).float()
if not channels_first:
waveform = waveform.transpose(0, 1).contiguous()
return waveform, sample_rate
torchaudio.load = _patched_load
class _AudioInfo:
__slots__ = ("sample_rate", "num_frames", "num_channels", "bits_per_sample", "encoding")
def _patched_info(filepath, *args, **kwargs):
info = sf.info(str(filepath))
out = _AudioInfo()
out.sample_rate = info.samplerate
out.num_frames = info.frames
out.num_channels = info.channels
out.bits_per_sample = 0
out.encoding = info.format
return out
torchaudio.info = _patched_info
import tempfile
import threading
from pathlib import Path
from huggingface_hub import hf_hub_download
from pyharp import ModelCard, build_endpoint
from inference import inference
CHECKPOINT_REPO = "teamup-tech/FST-AI-Music-Detection-checkpoints"
CHECKPOINT_DIR = Path("checkpoints")
checkpoints_loading = True
checkpoint_error = None
def download_checkpoints():
"""Fetch the Stage-1 and Stage-2 checkpoints so inference.py finds them
already on disk instead of downloading ~1.3 GB on the first request."""
global checkpoints_loading, checkpoint_error
try:
CHECKPOINT_DIR.mkdir(exist_ok=True)
for filename in ("Stage-1.ckpt", "Stage-2.ckpt"):
hf_hub_download(repo_id=CHECKPOINT_REPO, filename=filename, local_dir=str(CHECKPOINT_DIR))
print("Checkpoints ready.")
except Exception as e:
checkpoint_error = str(e)
print(f"Checkpoint download error: {e}")
finally:
checkpoints_loading = False
threading.Thread(target=download_checkpoints, daemon=True).start()
model_card = ModelCard(
name="Fusion Segment Transformer",
description=(
"Detects AI-generated music by fusing MERT audio embeddings with a "
"structural, downbeat-segmented view of the track. Submitted to ICASSP 2026."
),
author="Yumin Kim, Seonghyeon Go",
tags=["music", "classification", "ai-detection"],
)
@spaces.GPU
@torch.inference_mode()
def process_fn(audio_path: str) -> str:
"""Runs the two-stage detector on an uploaded track and writes the verdict to a text file."""
if checkpoints_loading:
raise gr.Error("Model checkpoints are still downloading, please wait a moment and try again.")
if checkpoint_error:
raise gr.Error(f"Failed to download checkpoints: {checkpoint_error}")
result = inference(audio_path)
prediction = result.get("prediction", "Unknown")
confidence = result.get("confidence", "0.00")
input_name = Path(audio_path).name
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
f.write(f"{input_name}\n\nAI-Detection Results\nPrediction: {prediction} ({confidence}% confidence)\n")
out_path = f.name
return out_path
with gr.Blocks() as demo:
input_components = [
gr.Audio(type="filepath", label="Input Audio").harp_required(True),
]
output_components = [
gr.File(type="filepath", label="Detection Result", file_types=[".txt"]).set_info(
"Prediction (Real/Fake) and confidence, as a text file."
),
]
build_endpoint(
model_card=model_card,
input_components=input_components,
output_components=output_components,
process_fn=process_fn,
)
if __name__ == "__main__":
demo.queue().launch(pwa=True)