midmid3 / app.py
markury's picture
add example and new viz
fa8dc8b
"""midmid3: Guitar Hero Chart Generator Demo"""
import json
import os
from pathlib import Path
import gradio as gr
# ZeroGPU: import spaces if available (no-op locally)
try:
import spaces
ON_ZEROGPU = True
except ImportError:
ON_ZEROGPU = False
from pipeline import generate_chart
from visualizer import build_visualizer_html
EXAMPLES_DIR = Path(__file__).parent / "examples"
def _load_example():
"""Load pre-computed demo - no GPU needed."""
chart_path = EXAMPLES_DIR / "hot_mess.json"
zip_path = EXAMPLES_DIR / "Hot Mess - Friday Pilots Club.zip"
audio_path = EXAMPLES_DIR / "hot_mess_input.ogg"
with open(chart_path) as f:
chart_json = json.load(f)
viz_html = build_visualizer_html(chart_json)
return (
str(audio_path), # audio_input
"Hot Mess", # title
"Friday Pilots Club", # artist
"", # album
"2022", # year
"rock", # genre
viz_html, # viz_output
str(zip_path), # zip_output
)
PLACEHOLDER_HTML = """
<div style="font-family: system-ui, sans-serif; background: #111; border-radius: 12px;
padding: 60px 20px; text-align: center; color: #666; max-width: 900px; margin: 0 auto;">
<div style="font-size: 48px; margin-bottom: 12px;">🎸</div>
<div style="font-size: 16px;">Upload a song and hit Generate to see your chart here</div>
</div>
"""
def _generate_wrapper(audio_path, title, artist, album, year, genre, progress=gr.Progress()):
"""Gradio-facing wrapper with validation and progress."""
if not audio_path:
raise gr.Error("Please upload an audio file.")
if not title or not title.strip():
raise gr.Error("Song title is required.")
if not artist or not artist.strip():
raise gr.Error("Artist name is required.")
zip_path, chart_json = generate_chart(
audio_path=audio_path,
title=title.strip(),
artist=artist.strip(),
album=album.strip() if album else "",
year=year.strip() if year else "",
genre=genre.strip() if genre else "rock",
progress_cb=progress,
)
html = build_visualizer_html(chart_json)
return html, zip_path
# Apply ZeroGPU decorator if running on HF Spaces
if ON_ZEROGPU:
_generate_wrapper = spaces.GPU(duration=180)(_generate_wrapper)
# --- UI ---
with gr.Blocks(
title="midmid3: Guitar Hero Chart Generator",
) as demo:
gr.Markdown(
"# midmid3: Guitar Hero Chart Generator\n"
"Upload a song, get a playable chart with 4 difficulty levels. "
"Preview it here, then download the mod folder ready for GHWT:DE."
)
with gr.Row():
with gr.Column(scale=1, min_width=280):
audio_input = gr.Audio(
label="Upload audio",
type="filepath",
sources=["upload"],
)
title_input = gr.Textbox(label="Song title *", placeholder="e.g. Through the Fire and Flames")
artist_input = gr.Textbox(label="Artist *", placeholder="e.g. DragonForce")
with gr.Row():
album_input = gr.Textbox(label="Album", placeholder="(optional)")
year_input = gr.Textbox(label="Year", placeholder="2026")
genre_input = gr.Textbox(label="Genre", placeholder="rock", value="rock")
generate_btn = gr.Button("Generate Chart", variant="primary", elem_id="generate-btn")
example_btn = gr.Button("Load Example", variant="secondary", size="sm")
zip_output = gr.File(label="Download song package (.zip)")
with gr.Column(scale=3):
viz_output = gr.HTML(value=PLACEHOLDER_HTML, label="Chart Preview")
generate_btn.click(
fn=_generate_wrapper,
inputs=[audio_input, title_input, artist_input, album_input, year_input, genre_input],
outputs=[viz_output, zip_output],
)
example_btn.click(
fn=_load_example,
inputs=[],
outputs=[audio_input, title_input, artist_input, album_input, year_input, genre_input, viz_output, zip_output],
)
gr.Markdown(
"---\n"
"*Powered by [midmid3](https://huggingface.co/markury/midmid3-19m-0326) — "
"a 19M-parameter masked-prediction transformer by Markury.*"
)
gr.HTML(
'<div style="display:flex; justify-content:center; gap:8px; padding:8px 0;">'
'<a href="https://github.com/markuryy/midmid"><img src="https://img.shields.io/badge/GitHub-midmid-181717?logo=github&logoColor=white" alt="GitHub"></a>'
'<a href="https://huggingface.co/markury/midmid3-19m-0326"><img src="https://img.shields.io/badge/%F0%9F%A4%97%20Model-midmid3--19m--0326-yellow" alt="Model"></a>'
'<a href="https://huggingface.co/spaces/markury/midmid3"><img src="https://img.shields.io/badge/%F0%9F%A4%97%20Demo-midmid3-blue" alt="Demo"></a>'
'</div>'
)
if __name__ == "__main__":
demo.launch(
theme=gr.themes.Base(primary_hue="purple", neutral_hue="gray"),
css="#generate-btn { min-height: 48px; font-size: 16px; }",
)