"""Gradio entry point. PITCHIN_PREVIEW_ONLY=1 starts an explicitly marked UI preview.""" import os from pathlib import Path os.environ.setdefault("GRADIO_ANALYTICS_ENABLED", "False") import gradio as gr from audio_input import DEFAULT_QUESTION, MAX_SECONDS, prepare_input APP_DIR = Path(__file__).resolve().parent CSS = (APP_DIR / "gradio-embed.css").read_text(encoding="utf-8") EMBED_JS = (APP_DIR / "embed-resize.js").read_text(encoding="utf-8") def build_demo(engine=None): def respond(audio, question): try: wave, question = prepare_input(audio, question) except ValueError as exc: raise gr.Error(str(exc)) from None if engine is None: raise gr.Error("This is a UI preview. Model inference is not connected yet.") try: return engine.generate(wave, question) except Exception: # Never return internal paths, tokens, or uploaded content in errors. raise gr.Error("Could not finish this request. The GPU may be busy; try a shorter clip or try again shortly.") from None with gr.Blocks( title="PitchIn · Singing feedback", theme=gr.themes.Soft(primary_hue="teal", neutral_hue="slate"), css=CSS, js=EMBED_JS, analytics_enabled=False, delete_cache=(300, 3600), ) as demo: gr.Markdown("# PitchIn\nListen to your singing. Ask a question. Explore the feedback.\n\n" "Natural-language singing coaching from community feedback.", elem_id="intro") if engine is None: gr.Markdown("**UI preview — model inference is not connected.**") with gr.Row(): with gr.Column(scale=1): audio = gr.Audio(sources=["upload", "microphone"], type="filepath", label="Your singing", max_length=MAX_SECONDS) gr.Markdown("Upload or record **1–60 seconds** of singing (up to 30 MB). Clear vocals work best.") question = gr.Textbox(label="What would you like feedback on?", value=DEFAULT_QUESTION, lines=3, max_lines=6, max_length=1000) gr.Examples(examples=[ [DEFAULT_QUESTION], ["What should I focus on improving first?"], ["How is my pitch accuracy?"], ["What practice exercise would you suggest?"], ], inputs=[question], label="Try a question") run = gr.Button("Get feedback", variant="primary") with gr.Column(scale=1): answer = gr.Textbox(label="PitchIn-Q feedback", placeholder="Your feedback will appear here.", lines=15, interactive=False, elem_id="answer") status = gr.Markdown() with gr.Accordion("About this demo", open=False): gr.Markdown("PitchIn-Q adapts Qwen2.5-Omni-7B using Focused QA and Overall Feedback targets " "reconstructed from community feedback. English questions are recommended. " "Each request uses the current clip and question; previous requests are not conversation history.\n\n" "This is a research model. It can miss or misidentify issues in a recording. " "Generated feedback does not establish an improvement in singing ability.\n\n" "Uploads are processed for your request. This app does not add them to a training dataset " "or save a response history. Temporary Gradio files are scheduled for cleanup after one hour.") run.click(respond, inputs=[audio, question], outputs=[answer, status], api_name="coach", concurrency_limit=1, concurrency_id="pitchin") return demo.queue(max_size=12, default_concurrency_limit=1) if __name__ == "__main__": engine = None if os.environ.get("PITCHIN_PREVIEW_ONLY") != "1": from inference import PitchIn engine = PitchIn() # Load on startup, outside ZeroGPU's decorated function. build_demo(engine).launch( server_name=os.environ.get("GRADIO_SERVER_NAME", "127.0.0.1"), server_port=int(os.environ.get("GRADIO_SERVER_PORT", "7860")), share=False, show_error=False, max_file_size="30mb", ssr_mode=False, # Use the validated client renderer for iframe embedding. )