Spaces:
Running on Zero
Running on Zero
| from __future__ import annotations | |
| import json | |
| import tempfile | |
| import uuid | |
| from pathlib import Path | |
| import gradio as gr | |
| import soundfile as sf | |
| try: | |
| import spaces | |
| except ImportError: | |
| 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) | |
| return args[0] | |
| from pyharp import ModelCard, build_endpoint | |
| from music2emo_runtime import analyze_music | |
| MIN_AUDIO_SECONDS = 1 | |
| MAX_AUDIO_SECONDS = 60 | |
| OUTPUT_ROOT = Path(tempfile.gettempdir()) / "music2emo_outputs" | |
| model_card = ModelCard( | |
| name="Music2Emo", | |
| description=( | |
| "Recognize music emotion as mood tags and continuous " | |
| "valence-arousal scores." | |
| ), | |
| author="AMAAI Lab", | |
| tags=[ | |
| "music-information-retrieval", | |
| "music-emotion-recognition", | |
| "mood-tagging", | |
| "valence", | |
| "arousal", | |
| ], | |
| ) | |
| def _validate_audio(path: str | None) -> str: | |
| if not path: | |
| raise gr.Error("Please upload an audio file.") | |
| try: | |
| duration = sf.info(path).duration | |
| except Exception as exc: | |
| raise gr.Error(f"Could not read the audio file: {exc}") from exc | |
| if duration < MIN_AUDIO_SECONDS: | |
| raise gr.Error("Audio must be at least 1 second long.") | |
| if duration > MAX_AUDIO_SECONDS: | |
| raise gr.Error( | |
| f"Audio must be no longer than {MAX_AUDIO_SECONDS} seconds. " | |
| f"Received {duration:.1f} seconds." | |
| ) | |
| return path | |
| def process_fn(audio_path: str | None, threshold: float) -> str: | |
| audio_path = _validate_audio(audio_path) | |
| try: | |
| result = analyze_music(audio_path, threshold) | |
| except Exception as exc: | |
| raise gr.Error(f"Music2Emo inference failed: {exc}") from exc | |
| output_dir = OUTPUT_ROOT / uuid.uuid4().hex | |
| output_dir.mkdir(parents=True, exist_ok=True) | |
| output_path = output_dir / "music2emo_analysis.json" | |
| output_path.write_text(json.dumps(result, indent=2) + "\n", encoding="utf-8") | |
| return str(output_path) | |
| with gr.Blocks(title="Music2Emo") as demo: | |
| input_components = [ | |
| gr.Audio(type="filepath", label="Music Audio") | |
| .harp_required(True) | |
| .set_info("Music clip between 1 and 60 seconds."), | |
| gr.Slider( | |
| minimum=0.1, | |
| maximum=0.9, | |
| value=0.5, | |
| step=0.05, | |
| label="Mood Threshold", | |
| ).set_info("Minimum probability for a mood tag to be returned."), | |
| ] | |
| output_components = [ | |
| gr.File( | |
| type="filepath", | |
| file_types=[".json"], | |
| label="Emotion Analysis", | |
| ).set_info("Mood probabilities and valence-arousal scores."), | |
| ] | |
| build_endpoint( | |
| model_card=model_card, | |
| input_components=input_components, | |
| output_components=output_components, | |
| process_fn=process_fn, | |
| ) | |
| if __name__ == "__main__": | |
| demo.queue(default_concurrency_limit=1).launch(show_error=True, pwa=True) | |