Spaces:
Sleeping
Sleeping
| # 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 (<pre>) ---------- | |
| 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 '<pre class="crt-pre" id="console-pre">' + body + "</pre>" | |
| # ---------- 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('<div id="bar" class="crt">SPUDNIK // CRT CONSOLE</div><div class="hr"></div>') | |
| 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() | |