import os, json, sys, numpy as np, gradio as gr import matplotlib; matplotlib.use("Agg"); import matplotlib.pyplot as plt from huggingface_hub import snapshot_download PRIVATE = os.environ.get("MODEL_REPO", "") d = snapshot_download(PRIVATE, token=os.environ.get("HF_TOKEN")) if PRIVATE else os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, d) import keep_audio_core as K cfg = json.load(open(os.path.join(d, "config.json"))) if os.path.exists(os.path.join(d, "config.json")) else {} R = K.Recognizer(os.path.join(d, "audio2b_KEEP_graine0.pt"), os.path.join(d, "audio2b_normalisation.pt"), gain=cfg.get("gain", "peak")) TAU, MIN_FRAME = 0.95, 10 # Voice-first shell: pure black canvas, one narrow column, no cards, no boxes. # The result is a stage (huge word + bars), the waveform is the visual centerpiece. CSS = """ @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&display=swap'); html, body { background: #000000 !important; } .gradio-container { --body-background-fill: #000000; --background-fill-primary: #000000; --background-fill-secondary: #000000; --block-background-fill: transparent; --block-border-color: transparent; --block-label-background-fill: transparent; --block-label-text-color: #8A8A93; --block-title-text-color: #F5F5F7; --body-text-color: #F5F5F7; --body-text-color-subdued: #8A8A93; --button-primary-background-fill: #F5F5F7; --button-primary-background-fill-hover: #FFFFFF; --button-primary-text-color: #000000; --button-secondary-background-fill: transparent; --button-secondary-background-fill-hover: #1A1A1E; --button-secondary-text-color: #F5F5F7; --button-secondary-border-color: rgba(255,255,255,.22); --input-background-fill: transparent; --input-border-color: rgba(255,255,255,.22); --input-text-color: #F5F5F7; --input-placeholder-color: #6E6E73; max-width: 560px !important; margin: 0 auto !important; padding: 26px 22px 44px !important; background: #000000 !important; color: #F5F5F7 !important; font-family: 'Space Grotesk', system-ui, sans-serif !important; } .gradio-container .block, .gradio-container .form, .gradio-container .wrap, .gradio-container .panel, .gradio-container .component, .gradio-container .audio, .gradio-container .plot, .gradio-container .input, .gradio-container .output { background: transparent !important; border: none !important; box-shadow: none !important; border-radius: 0 !important; } .gradio-container label span { color: #8A8A93 !important; font-size: 11px !important; font-weight: 500 !important; letter-spacing: 2.5px !important; text-transform: uppercase !important; } .gradio-container .prose { color: #C7C7CC !important; } .gradio-container .prose strong { color: #F5F5F7 !important; } .topbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } .brand { font-weight: 700; font-size: 19px; letter-spacing: -.5px; } .brand i { color: #E5C15D; font-style: normal; } .ondevice { font-size: 12px; color: #8A8A93; border: 1px solid rgba(255,255,255,.18); border-radius: 999px; padding: 5px 12px; } .stage { text-align: center; padding: 34px 0 6px; } .stage .eyebrow { font-size: 11px; letter-spacing: 3px; text-transform: uppercase; color: #8A8A93; margin-bottom: 16px; } .stage .word { font-size: 78px; font-weight: 700; letter-spacing: -3px; line-height: 1; margin: 6px 0 0; } .stage .word.dim { color: #333338; } .stage .conf { font-size: 15px; color: #E5C15D; margin-top: 14px; } .stage .top3 { margin-top: 20px; display: flex; flex-direction: column; gap: 8px; } .stage .top3 .row { display: flex; align-items: center; gap: 12px; font-size: 14px; color: #C7C7CC; } .stage .top3 .row b { width: 62px; text-align: right; font-weight: 500; color: #F5F5F7; } .stage .top3 .bar { flex: 1; height: 5px; background: #1C1C1F; border-radius: 99px; overflow: hidden; } .stage .top3 .bar i { display: block; height: 100%; background: linear-gradient(90deg, #C9A227, #F5D98B); border-radius: 99px; } .stage .top3 .pct { width: 46px; text-align: left; color: #8A8A93; } .eq { display: flex; justify-content: center; align-items: flex-end; gap: 5px; height: 46px; margin: 6px 0 10px; } .eq i { display: block; width: 5px; border-radius: 99px; background: linear-gradient(180deg, #F5D98B, #C9A227); animation: eqpulse 1.15s ease-in-out infinite; transform-origin: bottom; } @keyframes eqpulse { 0%, 100% { transform: scaleY(.22); } 50% { transform: scaleY(1); } } .hairline { height: 1px; background: rgba(255,255,255,.10); margin: 30px 0; } .chips { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; } .chip { font-size: 14px; color: #C7C7CC; background: #141416; border-radius: 999px; padding: 9px 15px; } .quiet { color: #8A8A93 !important; font-size: 13.5px !important; line-height: 1.65 !important; } .quiet strong { color: #C7C7CC !important; } .gradio-container button.primary { border-radius: 999px !important; height: 56px !important; font-size: 17px !important; font-weight: 700 !important; } .gradio-container button:not(.primary) { border-radius: 999px !important; } .gradio-container .audio button { border-radius: 999px !important; background: #141416 !important; border: 1px solid rgba(255,255,255,.14) !important; } .gradio-container label[data-testid$="-radio-label"] { border-radius: 999px !important; border: 1px solid rgba(255,255,255,.14) !important; padding: 7px 15px !important; background: transparent !important; color: #8A8A93 !important; } .gradio-container label[data-testid$="-radio-label"].selected { border-color: #E5C15D !important; color: #F5F5F7 !important; } .gradio-container label[data-testid$="-radio-label"] span { color: inherit !important; background: transparent !important; letter-spacing: 0 !important; text-transform: none !important; font-size: 14px !important; } .footer { opacity: .45; } """ TOPBAR = """
""" def _eq(): heights = [22, 34, 18, 40, 28, 46, 26, 36, 20, 30, 42, 24, 32, 18, 38] return "".join(f'' for i, h in enumerate(heights)) def stage_empty(): return f"""Say a word
{word}
""" f"""{conf:.0%} confident