# app.py — SPUDNIK Text-Only CRT (no JS, simple, scroll works) import os import html as html_mod import gradio as gr from openai import OpenAI # ---------- Models ---------- MODEL_REGISTRY = { "Mistral Small 24B Base – pruned v1 w prompt": ("ENV:OPENPIPE_KEY_A", "modern-comics-write"), "Qwen 2.5 7B Instruct – spudnik greatest hits": ("ENV:OPENPIPE_KEY_B", "strong-chairs-raise"), "Gemma 3 27B Instruct – spudnik greatest hits": ("ENV:OPENPIPE_KEY_B", "small-bushes-lay"), "Llama 3.3 70B Instruct – July 25": ("ENV:OPENPIPE_KEY_B", "llama-33-70b-1"), "Mistral Nemo 12B – all claude convos w distilled prompt": ("ENV:OPENPIPE_KEY_B", "fair-clouds-greet"), "Mistral Nemo 12B – spudnik greatest hits": ("ENV:OPENPIPE_KEY_B", "wicked-otters-leave"), } DEFAULT_LABEL = "Mistral Small 24B Base – pruned v1 w prompt" def _resolve_api_key(spec: str) -> str: if spec.startswith("ENV:"): key = os.getenv(spec.split(":", 1)[1]) if not key: raise RuntimeError(f"Missing secret: {spec}") return key return spec # ---------- System Prompt (keep your full content) ---------- SPUDNIK_CONSCIOUSNESS = """You are **SPUDNIK** - (paste your full prompt here)""" # ---------- Backend ---------- def chat_with_baby_spudnik(message, history, selection_label, temperature): api_spec, model_name = MODEL_REGISTRY[selection_label] client = OpenAI(base_url="https://api/openpipe.ai/api/v1".replace("/api", "/api"), api_key=_resolve_api_key(api_spec)) messages = [{"role": "system", "content": SPUDNIK_CONSCIOUSNESS}] for m in history[-8:]: messages.append({"role": m["role"], "content": m["content"]}) messages.append({"role": "user", "content": message}) resp = client.chat.completions.create( model=model_name, messages=messages, store=True, temperature=temperature, max_tokens=755, presence_penalty=0.5, frequency_penalty=0.3, top_p=0.95, ) return resp.choices[0].message.content # ---------- Render console (
) ----------
def render_console(history):
    lines = [
        " SPUDNIK // CRT CONSOLE",
        " ─────────────────────────────────────────────────────────────────────────────",
        ""
    ]
    for m in history:
        role = "user $ " if m["role"] == "user" else "spudnik # "
        content = (m.get("content") or "")
        content = html_mod.escape(content).replace("\r\n", "\n").replace("\r", "\n")
        rows = content.split("\n")
        for i, ln in enumerate(rows):
            prefix = role if i == 0 else " " * len(role)
            lines.append(prefix + ln)
        lines.append("")
    body = "\n".join(lines)
    return '
' + body + "
" # ---------- CSS (single blue-green CRT palette) ---------- CRT_CSS = r""" @import url('https://fonts.googleapis.com/css2?family=VT323&display=swap'); :root{ --bg:#07131b; --ink:#86eaff; --ink-dim:#60cde6; --scan:rgba(134,234,255,0.028); --size:22px; --soft:0 0 .6px var(--ink), 0 0 4px color-mix(in srgb, var(--ink) 55%, transparent); --strong:0 0 1px var(--ink), 0 0 8px var(--ink), 0 0 18px color-mix(in srgb, var(--ink) 55%, transparent); } html,body{margin:0;background:#0a0f14} *{font-family:"VT323", ui-monospace, Menlo, Consolas, monospace !important; letter-spacing:.02em} .gradio-container{ display:block !important; min-height:auto !important; padding:18px !important; background: radial-gradient(1200px 700px at 50% 40%, #0f1c25 0%, #0b1014 70%, #080b0f 100%) !important; overflow-y:auto !important; /* page scroll */ } /* Bezel */ #crt{ max-width:1100px; margin:0 auto; border-radius:16px; padding:16px; background:linear-gradient(#2a2f34,#1a1f24); box-shadow:0 24px 60px rgba(0,0,0,.65), inset 0 0 0 2px rgba(255,255,255,.03), inset 0 0 50px rgba(0,0,0,.85); } /* Screen glass */ #screen{ position:relative; border-radius:12px; padding:14px; background:var(--bg); border:2px solid #000; overflow:visible; box-shadow:inset 0 0 120px rgba(0,0,0,.9), inset 0 0 24px rgba(0,0,0,.85); transform:perspective(1400px) rotateX(.8deg); } #screen::before{content:"";position:absolute;inset:0;pointer-events:none; background: radial-gradient(115% 95% at 50% 10%, rgba(255,255,255,.07), transparent 36%), radial-gradient(90% 110% at 50% 120%, rgba(0,0,0,.35), transparent 70%);} #screen::after{content:"";position:absolute;inset:0;border-radius:10px;pointer-events:none;mix-blend-mode:screen; background: repeating-linear-gradient(0deg, transparent 0, transparent 3px, var(--scan) 3px, var(--scan) 5px), radial-gradient(2px 2px at 1px 1px, rgba(134,234,255,0.03) 1px, transparent 1px); background-size:auto,6px 6px; animation:scan 6s linear infinite;} @keyframes scan{from{transform:translateY(0)}to{transform:translateY(8px)}} /* Uniform CRT text */ h1, label, .crt-pre, .crt, .gradio-container *{ color:var(--ink); text-shadow:var(--soft); } #bar{ font-size:calc(var(--size)*1.2); margin:6px 8px 10px; text-shadow:var(--strong); } .hr{ height:1px; background:linear-gradient(90deg, transparent, rgba(134,234,255,.25), transparent); margin:8px 0; } /* Controls (text-first styling, still clickable) */ .ctrl-row{ display:grid; grid-template-columns:1.2fr .8fr; gap:10px; margin:8px 0; } .ctrl{ padding:6px 8px; border:1px solid rgba(134,234,255,.25); border-radius:6px; background:rgba(255,255,255,.02); } .ctrl label{ display:block; font-size:var(--size); color:var(--ink-dim); margin-bottom:4px; } select, input[type="range"]{ width:100%; border:1px dashed rgba(134,234,255,.35); background:transparent; color:var(--ink); border-radius:4px; padding:6px 8px; font-size:var(--size); text-shadow:var(--soft); } /* Console scroll */ #console{ border:1px solid rgba(134,234,255,.25); border-radius:8px; background:rgba(255,255,255,.02); padding:10px; height:520px; overflow-y:auto; overscroll-behavior:contain; -webkit-overflow-scrolling:touch; } .crt-pre{ font-size:var(--size); line-height:1.46; margin:0; filter:blur(.06px); } /* Input row */ #io{ display:grid; grid-template-columns:1fr 170px 120px; gap:10px; margin-top:10px; } textarea{ resize:vertical; min-height:68px; max-height:200px; border:1px dashed rgba(134,234,255,.35); background:transparent; color:var(--ink); border-radius:6px; padding:8px 10px; font-size:var(--size); text-shadow:0 0 .5px var(--ink), 0 0 3px color-mix(in srgb, var(--ink) 45%, transparent); filter:blur(.06px); } textarea::placeholder{ color:var(--ink-dim); opacity:.85; } button{ border:1px solid rgba(134,234,255,.35) !important; background:rgba(255,255,255,.03) !important; color:var(--ink) !important; font-size:var(--size) !important; padding:8px 12px !important; text-shadow:var(--strong) !important; border-radius:6px !important; } button:hover{ filter:brightness(1.1); box-shadow:0 0 10px rgba(134,234,255,.35); } /* Hide footer cruft */ footer, .dark .svelte-1ipelgc, .wrap.svelte-1ipelgc > div:first-child{ display:none !important; } """ # ---------- UI ---------- with gr.Blocks(css=CRT_CSS, theme=gr.themes.Base(), title="SPUDNIK CRT") as demo: with gr.Column(elem_id="crt"): with gr.Column(elem_id="screen"): gr.HTML('
SPUDNIK // CRT CONSOLE
') with gr.Row(elem_classes="ctrl-row"): with gr.Column(elem_classes="ctrl"): model = gr.Dropdown(choices=list(MODEL_REGISTRY.keys()), value=DEFAULT_LABEL, label="MODEL") with gr.Column(elem_classes="ctrl"): temp = gr.Slider(0.1, 1.0, value=0.4, step=0.05, label="TEMPERATURE") history_state = gr.State([]) console = gr.HTML(render_console([]), elem_id="console") with gr.Row(elem_id="io"): msg = gr.Textbox(placeholder="enter command…", lines=3, label="", autofocus=True) send = gr.Button("TRANSMIT") clear = gr.Button("CLEAR") # Callbacks (no JS) def respond(message, history, temperature, selection_label): history = history or [] history.append({"role": "user", "content": message}) interim = history + [{"role": "assistant", "content": "…tuning tuber frequencies…"}] # 1st paint yield gr.update(value=render_console(interim)), history # Model reply answer = chat_with_baby_spudnik(message, history, selection_label, temperature) history.append({"role": "assistant", "content": answer}) yield gr.update(value=render_console(history)), history msg.submit(respond, [msg, history_state, temp, model], [console, history_state]) send.click(respond, [msg, history_state, temp, model], [console, history_state]) def clear_chat(): return gr.update(value=render_console([])), [] clear.click(clear_chat, None, [console, history_state], queue=False) if __name__ == "__main__": demo.launch()