Spaces:
Running
Running
| from __future__ import annotations | |
| import tempfile | |
| from pathlib import Path | |
| from typing import Tuple | |
| import gradio as gr | |
| import modal | |
| TITLE = "EraEcho" | |
| DESCRIPTION = "Transpose modern music into the style of any historical decade." | |
| DECADES = [f"{year}s" for year in range(1920, 2030, 10)] | |
| def transform(audio_path: str | None, decade: str) -> Tuple[str | None, str]: | |
| if not audio_path: | |
| return None, "Please upload an audio file first." | |
| try: | |
| fn = modal.Function.from_name("eraecho", "transform_with_era_ai") | |
| with open(audio_path, "rb") as file: | |
| audio_bytes = file.read() | |
| transformed_bytes, report = fn.remote(audio_bytes, Path(audio_path).name, decade) | |
| output = tempfile.NamedTemporaryFile(delete=False, suffix=f"_{decade}_eraecho.wav") | |
| output.write(transformed_bytes) | |
| output.close() | |
| return output.name, report | |
| except Exception as exc: | |
| return None, f"Error calling Modal backend: {exc}" | |
| with gr.Blocks(theme=gr.themes.Soft(), title=TITLE) as demo: | |
| gr.Markdown(f"# {TITLE}\n{DESCRIPTION}") | |
| gr.Markdown( | |
| "Upload a song, choose a decade, and EraEcho returns a historically flavored audio pass plus a fidelity report. " | |
| "Processing is handled by Modal (Qwen3-14B + DSP)." | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| audio = gr.Audio(label="Upload music", type="filepath") | |
| decade = gr.Dropdown(DECADES, value="1950s", label="Target decade") | |
| button = gr.Button("Transpose through time", variant="primary") | |
| with gr.Column(): | |
| output_audio = gr.Audio(label="EraEcho transformed audio", type="filepath") | |
| report = gr.Markdown(label="Historical fidelity report") | |
| button.click(transform, inputs=[audio, decade], outputs=[output_audio, report]) | |
| if __name__ == "__main__": | |
| demo.launch() | |