From d1af7bceb8490fa1d379071d9505615cd86bb7f9 Mon Sep 17 00:00:00 2001 From: Masahiko AMANO Date: Thu, 4 Jun 2026 21:00:29 +0300 Subject: [PATCH] feat(app): show generation progress and rename app heading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Disable the run button and show a "Генерация…" status while a request is processing, then re-enable it. Repeated generations previously gave no visible feedback once the model was cached, so it was unclear whether a request was running. - Append elapsed time to the final status so identical re-runs differ visibly. - Rename the H1 heading and browser/tab title to "генератор аккордовых последовательностей". Co-Authored-By: Claude Opus 4.8 --- app.py | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/app.py b/app.py index c900861..6eb050f 100644 --- a/app.py +++ b/app.py @@ -22,6 +22,7 @@ import tempfile from dataclasses import replace from functools import lru_cache from pathlib import Path +from time import perf_counter from uuid import uuid4 import gradio as gr @@ -106,6 +107,7 @@ def generate( tempo: int, ): """Run one generation and return (status, bar grid, .chord path, .mid path).""" + t0 = perf_counter() try: model = _load_model(checkpoint) except Exception as exc: # noqa: BLE001 — surface any load error to the UI @@ -160,15 +162,37 @@ def generate( write_chord_file(period, chord_path) chord_file_to_midi(chord_path, midi_path, tempo=int(tempo)) + elapsed = perf_counter() - t0 status = ( f"✅ Готово — {len(period.bars)} тактов · {target_key} · " - f"модель: {checkpoint} · seed: {seed_val if seed_val is not None else 'random'}" + f"модель: {checkpoint} · seed: {seed_val if seed_val is not None else 'random'} · " + f"{elapsed:.2f} с" ) if truncated: status += f" · обрезано до {MAX_PERIOD_BARS} тактов (период ≤ 16)" return status, _format_bars(period), str(chord_path), str(midi_path) +# --------------------------------------------------------------------------- +# Button-state helpers — give immediate, persistent feedback while generating. +# Gradio's built-in spinner barely flashes once the model is cached, so we also +# disable the button and show a "generating" status until the work completes. +# --------------------------------------------------------------------------- + +def _begin_generation(): + """Show a busy state the instant the button is clicked (runs before generate).""" + return ( + gr.update(value="⏳ Генерация…", interactive=False), # run button + "⏳ Генерация…", # status message + "", # clear the previous grid + ) + + +def _end_generation(): + """Restore the run button after generation finishes (success or handled error).""" + return gr.update(value="Сгенерировать", interactive=True) + + # --------------------------------------------------------------------------- # Russian instructions (rendered inline) # --------------------------------------------------------------------------- @@ -220,9 +244,9 @@ def build_ui() -> gr.Blocks: checkpoints[0] if checkpoints else "finetuned" ) - with gr.Blocks(title="hamori — генератор гармонии") as demo: + with gr.Blocks(title="hamori — генератор аккордовых последовательностей") as demo: gr.Markdown( - "# hamori 🎶 — генератор гармонических периодов\n" + "# hamori 🎶 — генератор аккордовых последовательностей\n" "Заполните форму и нажмите **Сгенерировать**. " "Подробности — в разделе «Инструкция» внизу." ) @@ -255,7 +279,7 @@ def build_ui() -> gr.Blocks: subdivision = gr.Radio([4, 8], value=4, label="Subdivision") with gr.Row(): - auto_bars = gr.Checkbox(value=False, label="Авто (длина сама)") + auto_bars = gr.Checkbox(value=False, label="Авто") n_bars = gr.Slider(4, 16, value=8, step=1, label="Число тактов") with gr.Accordion("Сэмплирование", open=True): @@ -290,6 +314,10 @@ def build_ui() -> gr.Blocks: gr.Markdown(INSTRUCTIONS_RU) run.click( + fn=_begin_generation, + inputs=None, + outputs=[run, status, bars_out], + ).then( fn=generate, inputs=[ checkpoint, mode, key, style, function, time, subdivision, @@ -297,6 +325,10 @@ def build_ui() -> gr.Blocks: tonic_anchor, prefix_text, seed, tempo, ], outputs=[status, bars_out, chord_file, midi_file], + ).then( + fn=_end_generation, + inputs=None, + outputs=[run], ) return demo