""" ╔═══════════════════════════════════════════════════════════════╗ ║ GHOST — Private Intelligence Layer ║ ║ Build Small Hackathon 2026 · HuggingFace · Backyard AI ║ ║ Model : microsoft/Phi-3-mini-4k-instruct (3.8 B) ║ ╚═══════════════════════════════════════════════════════════════╝ """ import gradio as gr from huggingface_hub import InferenceClient import datetime, os, time # ───────────────────────────────────────────────────────────── # MODEL # ───────────────────────────────────────────────────────────── MODEL_ID = "microsoft/Phi-3-mini-4k-instruct" CLIENT = InferenceClient(MODEL_ID, token=os.environ.get("HF_TOKEN")) def ts(): return datetime.datetime.now().strftime("%H:%M:%S") def logline(icon, msg): return f"[{ts()}] {icon} {msg}" def call_llm(system, user, temperature=0.35, max_tokens=700): resp = CLIENT.chat_completion( messages=[{"role":"system","content":system}, {"role":"user", "content":user}], max_tokens=max_tokens, temperature=temperature, ) return resp.choices[0].message.content.strip() def stream_text(text, chunk=6): out = "" for i in range(0, len(text), chunk): out += text[i:i+chunk] yield out # ───────────────────────────────────────────────────────────── # HEADER HTML — cinematic ghost + starfield + emotion system # ───────────────────────────────────────────────────────────── HEADER = r"""
💜
💙
🩷
💧
GHOST · 3.8B · PRIVATE

G H O S T

Your private intelligence layer.
No cloud. No logs. Just you.

📋 Chief of Staff 💌 Unsent Letter 🔍 Reality Check
✦ Phi-3-mini · 3.8B parameters · Tiny Titan eligible
""" # ───────────────────────────────────────────────────────────── # CSS # ───────────────────────────────────────────────────────────── CSS = """ @import url('https://fonts.googleapis.com/css2?family=Syne:wght@300;400;600;700;800&family=Space+Mono:wght@400;700&display=swap'); :root{ --gc :#a78bfa; --bg :#000008; --glass :rgba(255,255,255,.025); --border :rgba(139,92,246,.18); --text :#f1f5f9; --muted :#374151; --mono :'Space Mono',monospace; --sans :'Syne',sans-serif; --r :16px; --ease :cubic-bezier(.16,1,.3,1); } *,*::before,*::after{box-sizing:border-box;margin:0;padding:0;} ::-webkit-scrollbar{width:3px;} ::-webkit-scrollbar-track{background:transparent;} ::-webkit-scrollbar-thumb{background:rgba(139,92,246,.4);border-radius:99px;} body,.gradio-container{ background:var(--bg) !important; font-family:var(--sans) !important; color:var(--text) !important; } .gradio-container{max-width:1060px !important;margin:0 auto !important;} .gradio-container>div,.gr-block{background:transparent !important;} /* ════ HEADER ════ */ #gh-root{ position:relative;overflow:hidden; background:linear-gradient(168deg,#0e0e26 0%,#070714 55%,var(--bg) 100%); border-bottom:1px solid rgba(139,92,246,.14); min-height:210px; } #gh-bg{ position:absolute;inset:0; width:100%;height:100%; pointer-events:none; } #gh-wrap{ position:relative;z-index:3; display:flex;align-items:center;gap:44px; padding:46px 54px 38px;flex-wrap:wrap; } /* Stage */ #gh-stage{ position:relative;flex-shrink:0; width:170px;height:178px; display:flex;align-items:center;justify-content:center; } #gh-svg{ width:110px;height:132px; position:relative;z-index:5; filter: drop-shadow(0 0 36px color-mix(in srgb,var(--gc) 60%,transparent)) drop-shadow(0 0 12px color-mix(in srgb,var(--gc) 30%,transparent)); animation:ghFloat 3.4s ease-in-out infinite; transition:filter .7s ease; } #gh-glow{ position:absolute;top:50%;left:50%; transform:translate(-50%,-50%); width:128px;height:128px;border-radius:50%; background:radial-gradient(circle, color-mix(in srgb,var(--gc) 22%,transparent),transparent 72%); animation:haloPulse 2.8s ease-in-out infinite; transition:background .7s ease;z-index:2; } /* Rings */ .ring{ position:absolute;top:50%;left:50%; border-radius:50%; border:1px solid rgba(167,139,250,.1); } .r1{width:132px;height:132px;animation:spinCW 12s linear infinite;} .r2{width:166px;height:166px;border-style:dashed; border-color:rgba(167,139,250,.06);animation:spinCCW 18s linear infinite;} .r3{width:206px;height:206px;border-color:rgba(96,165,250,.04); animation:spinCW 25s linear infinite;} .rdot{ position:absolute;width:7px;height:7px;border-radius:50%; top:-3px;left:50%;transform:translateX(-50%); background:var(--gc);box-shadow:0 0 10px var(--gc); transition:background .7s,box-shadow .7s; } .rd2{top:auto;bottom:-3px;background:#60a5fa;box-shadow:0 0 10px #60a5fa;} #gh-acc{position:absolute;inset:0;z-index:6;pointer-events:none;} #gh-particles{ position:absolute;top:50%;left:50%; transform:translate(-50%,-50%); width:340px;height:340px; pointer-events:none;z-index:7; } /* Copy */ #gh-copy{flex:1;min-width:240px;} #gh-badge{ display:inline-flex;align-items:center;gap:8px; font-family:var(--mono);font-size:10px; color:var(--gc);letter-spacing:.1em; background:color-mix(in srgb,var(--gc) 10%,transparent); border:1px solid color-mix(in srgb,var(--gc) 32%,transparent); border-radius:100px;padding:5px 15px;margin-bottom:16px; transition:all .7s ease; } .bdot{ width:7px;height:7px;border-radius:50%; background:var(--gc);box-shadow:0 0 8px var(--gc); animation:blink 1.3s ease infinite; transition:background .7s,box-shadow .7s; } #gh-title{ font-size:70px;font-weight:800; letter-spacing:-.05em;line-height:1; margin-bottom:12px;display:flex; } .gl{ display:inline-block; background:linear-gradient(135deg,#fff 0%,#c4b5fd 40%,#818cf8 66%,#60a5fa 100%); -webkit-background-clip:text;-webkit-text-fill-color:transparent; background-clip:text; animation:letterWave 5s ease-in-out infinite; animation-delay:calc(var(--i) * .14s); } #gh-sub{font-size:14px;color:#4b5563;line-height:1.7;margin-bottom:20px;} #gh-chips{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px;} .chip{ font-size:11px;font-family:var(--mono);letter-spacing:.04em; padding:6px 15px;border-radius:100px;border:1px solid; cursor:pointer;transition:all .22s var(--ease);user-select:none; } .chip:hover{transform:translateY(-3px);} .chip-p{color:#a78bfa;background:rgba(167,139,250,.08);border-color:rgba(167,139,250,.26);} .chip-p:hover{background:rgba(167,139,250,.18);box-shadow:0 4px 16px rgba(167,139,250,.2);} .chip-b{color:#60a5fa;background:rgba(96,165,250,.08);border-color:rgba(96,165,250,.26);} .chip-b:hover{background:rgba(96,165,250,.18);box-shadow:0 4px 16px rgba(96,165,250,.2);} .chip-g{color:#34d399;background:rgba(52,211,153,.08);border-color:rgba(52,211,153,.26);} .chip-g:hover{background:rgba(52,211,153,.18);box-shadow:0 4px 16px rgba(52,211,153,.2);} #gh-model{font-family:var(--mono);font-size:10px;color:#1f2937;letter-spacing:.08em;} /* ════ SECTION LABEL ════ */ .slabel{ font-family:var(--mono);font-size:9px; color:#1f2937;letter-spacing:.18em;text-transform:uppercase; padding:22px 26px 8px; } /* ════ INPUTS ════ */ textarea,input[type=text]{ background:var(--glass) !important; border:1px solid var(--border) !important; border-radius:var(--r) !important; color:var(--text) !important; font-family:var(--sans) !important; font-size:14px !important;line-height:1.78 !important; padding:18px 20px !important; transition:border-color .25s,box-shadow .25s !important; resize:none !important; backdrop-filter:blur(14px) !important; -webkit-backdrop-filter:blur(14px) !important; } textarea:focus,input[type=text]:focus{ border-color:color-mix(in srgb,var(--gc) 75%,transparent) !important; box-shadow:0 0 0 3px color-mix(in srgb,var(--gc) 10%,transparent), 0 0 30px color-mix(in srgb,var(--gc) 7%,transparent) !important; outline:none !important; } /* ════ LABELS ════ */ label>span:first-child{ color:#374151 !important;font-size:10px !important; font-family:var(--mono) !important; letter-spacing:.14em !important;text-transform:uppercase !important; } /* ════ BUTTON ════ */ button.lg{ position:relative !important;overflow:hidden !important; background:linear-gradient(135deg, color-mix(in srgb,var(--gc) 90%,#000) 0%, color-mix(in srgb,var(--gc) 60%,#4f46e5) 100%) !important; border:none !important;border-radius:14px !important; color:#fff !important;font-family:var(--sans) !important; font-size:15px !important;font-weight:700 !important; padding:18px 26px !important;cursor:pointer !important; letter-spacing:.02em !important;width:100% !important; box-shadow:0 4px 30px color-mix(in srgb,var(--gc) 45%,transparent), 0 0 0 1px rgba(255,255,255,.07) inset !important; transition:all .28s var(--ease) !important; } button.lg::before{ content:'';position:absolute; top:0;left:-120%;width:60%;height:100%; background:linear-gradient(90deg,transparent,rgba(255,255,255,.14),transparent); animation:shimmer 3.2s ease infinite; } button.lg:hover{ transform:translateY(-3px) !important; box-shadow:0 12px 48px color-mix(in srgb,var(--gc) 65%,transparent), 0 0 0 1px rgba(255,255,255,.12) inset !important; } button.lg:active{transform:translateY(-1px) !important;} /* ════ OUTPUT BOX ════ */ .out-box textarea{ background:color-mix(in srgb,var(--gc) 3%,transparent) !important; border-color:color-mix(in srgb,var(--gc) 25%,transparent) !important; line-height:1.9 !important; transition:border-color .7s,background .7s !important; } /* ════ LOG BOX ════ */ .log-box textarea{ background:rgba(0,0,0,.72) !important; border-color:rgba(52,211,153,.16) !important; color:#34d399 !important; font-family:var(--mono) !important; font-size:11px !important;letter-spacing:.04em !important; line-height:2 !important; text-shadow:0 0 12px rgba(52,211,153,.35) !important; } /* ════ RADIO ════ */ .tone-wrap fieldset{border:none !important;padding:0 !important;} .tone-wrap label{ background:var(--glass) !important; border:1px solid var(--border) !important; border-radius:10px !important;color:#6b7280 !important; font-size:11px !important;font-family:var(--mono) !important; padding:8px 16px !important;cursor:pointer !important; transition:all .22s var(--ease) !important; margin:0 4px 4px 0 !important; display:inline-flex !important;align-items:center !important; backdrop-filter:blur(8px) !important; } .tone-wrap label:hover{ border-color:color-mix(in srgb,var(--gc) 50%,transparent) !important; color:var(--gc) !important;transform:translateY(-2px) !important; } .tone-wrap label:has(input:checked){ background:color-mix(in srgb,var(--gc) 14%,transparent) !important; border-color:color-mix(in srgb,var(--gc) 55%,transparent) !important; color:var(--gc) !important; box-shadow:0 0 18px color-mix(in srgb,var(--gc) 18%,transparent) !important; } /* ════ TABS ════ */ .tabs>.tab-nav{ background:rgba(0,0,0,.38) !important; border-bottom:1px solid rgba(139,92,246,.1) !important; padding:0 26px !important; backdrop-filter:blur(10px) !important; } .tab-nav button{ color:#374151 !important;font-family:var(--mono) !important; font-size:11px !important;letter-spacing:.1em !important; text-transform:uppercase !important;padding:14px 22px !important; background:transparent !important;border:none !important; border-bottom:2px solid transparent !important; transition:all .22s var(--ease) !important;cursor:pointer !important; } .tab-nav button:hover{color:#6b7280 !important;} .tab-nav button.selected{ color:var(--gc) !important; border-bottom-color:var(--gc) !important; text-shadow:0 0 22px color-mix(in srgb,var(--gc) 70%,transparent) !important; transition:color .7s,border-bottom-color .7s,text-shadow .7s !important; } /* ════ FOOTER ════ */ #gh-footer{ display:flex;align-items:center;justify-content:center; gap:10px;padding:20px 40px;flex-wrap:wrap; background:rgba(0,0,0,.3); border-top:1px solid rgba(139,92,246,.07); backdrop-filter:blur(10px); } /* ════ ANIMATIONS ════ */ @keyframes ghFloat{ 0%,100%{transform:translateY(0) rotate(-1.8deg) scale(1);} 33% {transform:translateY(-14px) rotate(2deg) scale(1.02);} 66% {transform:translateY(-6px) rotate(-1deg) scale(1.008);} } @keyframes haloPulse{ 0%,100%{opacity:.38;transform:translate(-50%,-50%) scale(1);} 50% {opacity:.92;transform:translate(-50%,-50%) scale(1.26);} } @keyframes spinCW{ from{transform:translate(-50%,-50%) rotate(0deg);} to{transform:translate(-50%,-50%) rotate(360deg);} } @keyframes spinCCW{ from{transform:translate(-50%,-50%) rotate(0deg);} to{transform:translate(-50%,-50%) rotate(-360deg);} } @keyframes blink{0%,100%{opacity:1;}50%{opacity:.12;}} @keyframes letterWave{ 0%,100%{transform:translateY(0);} 50%{transform:translateY(-4px);} } @keyframes shimmer{ 0%{left:-120%;}60%{left:160%;}100%{left:160%;} } @keyframes blushPulse{ 0%,100%{opacity:.25;transform:scale(1);} 50%{opacity:.5;transform:scale(1.18);} } """ # ───────────────────────────────────────────────────────────── # PROMPTS # ───────────────────────────────────────────────────────────── SYS_CHIEF = "You are GHOST, a razor-sharp private executive assistant. Extract only what matters. Be direct and specific." SYS_LETTER = "You are GHOST. Help people say what they have always meant to say. Write in their voice — completely human, never robotic." SYS_REAL = "You are GHOST, a sharp-eyed private advisor. Find what others miss. Be direct and specific." TONE_MAP = { "Warm & Loving": "warm, loving, deeply heartfelt", "Professional": "professional, respectful, clear", "Honest & Direct": "honest, direct, quietly courageous", "Apologetic": "sincere, remorseful, genuinely healing", } def p_chief(text): return f"""Analyze this. Respond EXACTLY in this format: SUMMARY: [2 sentences max. What it's really about. No fluff.] DEADLINES: [Every date/time/urgency. Quote them. If none: None found.] COMMITMENTS: [What's been promised by whom. If none: None found.] NEXT ACTIONS: 1. [Most urgent] 2. [Second] 3. [Third] Document: --- {text.strip()} ---""" def p_letter(rough, tone): return f"""Turn this rough idea into a beautiful letter. Tone: {tone} Rules: Sound completely human. No clichés. Every sentence earns its place. Write the letter directly — no preamble. What they want to say: --- {rough.strip()} --- Write the letter:""" def p_real(text): return f"""Reality-check this. Be ruthlessly direct. CONTRADICTIONS: [Conflicting claims. Quote them. If none: None found.] MISSING CONTEXT: [Absent/assumed info. If none: None found.] RISKY COMMITMENTS: [Problematic promises. If none: None found.] RED FLAGS: [Vague language, manipulation, inconsistency. If none: None found.] VERDICT: [One sentence: trust it, revise it, or reject it — and why.] Text: --- {text.strip()} ---""" # ───────────────────────────────────────────────────────────── # STREAMING FUNCTIONS # ───────────────────────────────────────────────────────────── def chief_of_staff(text): if not text.strip(): yield "Paste a document above to begin.", logline("⚠","No input"); return yield "👻 Ghost is reading your document...", logline("👁","Reading...") time.sleep(.35) yield "🧠 Extracting what actually matters...", logline("🧠","Analyzing...") try: result = call_llm(SYS_CHIEF, p_chief(text), temperature=0.22, max_tokens=660) out="" for chunk in (result[i:i+7] for i in range(0,len(result),7)): out+=chunk; yield out, logline("📝","Writing..."); time.sleep(.008) yield result, "\n".join([ logline("👁","Document read"), logline("🧠","Analysis complete"), logline("📋","Deadlines & commitments extracted"), logline("✅","Done — review and edit above"), ]) except Exception as e: yield f"⚠ Error: {e}\n\nTip: wait 30s and retry.", logline("❌",str(e)) def unsent_letter(rough, tone): if not rough.strip(): yield "Describe what you want to say above.", logline("⚠","No input"); return tone_desc = TONE_MAP.get(tone,"warm and genuine") yield "👻 Ghost is listening...", logline("👻","Listening...") time.sleep(.35) yield "💜 Understanding what you really mean...", logline("💜","Processing...") try: result = call_llm(SYS_LETTER, p_letter(rough,tone_desc), temperature=0.82, max_tokens=740) out="" for chunk in (result[i:i+6] for i in range(0,len(result),6)): out+=chunk; yield out, logline("✍","Writing in your voice..."); time.sleep(.008) yield result, "\n".join([ logline("👻","Ghost listened"), logline("💜","Real meaning understood"), logline("✍",f"Written — tone: {tone}"), logline("✅","Done — read it, edit it, send it"), ]) except Exception as e: yield f"⚠ Error: {e}", logline("❌",str(e)) def reality_check(text): if not text.strip(): yield "Paste a message or document above.", logline("⚠","No input"); return yield "👁 Ghost is reading very carefully...", logline("👁","Reading...") time.sleep(.35) yield "🔍 Scanning for contradictions...", logline("🔍","Scanning...") try: result = call_llm(SYS_REAL, p_real(text), temperature=0.22, max_tokens=660) out="" for chunk in (result[i:i+7] for i in range(0,len(result),7)): out+=chunk; yield out, logline("⚡","Checking..."); time.sleep(.008) yield result, "\n".join([ logline("👁","Read carefully"), logline("🔍","Contradictions checked"), logline("⚡","Risky commitments flagged"), logline("🛡","Reality check complete"), ]) except Exception as e: yield f"⚠ Error: {e}", logline("❌",str(e)) # ───────────────────────────────────────────────────────────── # UI # ───────────────────────────────────────────────────────────── with gr.Blocks( css=CSS, title="GHOST — Private Intelligence Layer", theme=gr.themes.Base( primary_hue="violet", neutral_hue="slate", font=gr.themes.GoogleFont("Syne"), font_mono=gr.themes.GoogleFont("Space Mono"), ), ) as demo: gr.HTML(HEADER) with gr.Tabs(): # ── CHIEF OF STAFF ── with gr.Tab("📋 Chief of Staff"): gr.HTML('
Paste any email, contract or meeting notes — Ghost extracts what actually matters
') with gr.Row(equal_height=False): with gr.Column(scale=1): c1i = gr.Textbox(label="EMAIL / DOCUMENT", placeholder="Paste any email, contract, or document here...\n\nGhost will extract:\n→ What it's really about\n→ Every deadline\n→ All commitments made\n→ Your 3 most important next actions", lines=16) c1b = gr.Button("👻 Analyze It", size="lg") with gr.Column(scale=1): c1o = gr.Textbox(label="GHOST'S ANALYSIS (editable)", placeholder="SUMMARY · DEADLINES · COMMITMENTS · NEXT ACTIONS\nwill stream here...", lines=16, interactive=True, elem_classes=["out-box"]) c1l = gr.Textbox(label="ACTION LOG", lines=4, interactive=False, elem_classes=["log-box"]) c1b.click(fn=chief_of_staff, inputs=c1i, outputs=[c1o,c1l]) # ── UNSENT LETTER ── with gr.Tab("💌 Unsent Letter"): gr.HTML('
Say what you\'ve always meant to say — Ghost writes it beautifully in your voice
') with gr.Row(equal_height=False): with gr.Column(scale=1): c2i = gr.Textbox(label="WHAT YOU WANT TO SAY", placeholder='Just describe it roughly — Ghost does the rest.\n\nExample:\n"My dad sacrificed everything for my education.\nI never told him what that means to me.\nI want him to feel proud — and know it wasn\'t wasted."', lines=10) c2t = gr.Radio(choices=["Warm & Loving","Professional","Honest & Direct","Apologetic"], value="Warm & Loving", label="TONE", elem_classes=["tone-wrap"]) c2b = gr.Button("👻 Write It", size="lg") with gr.Column(scale=1): c2o = gr.Textbox(label="YOUR LETTER (editable)", placeholder="Ghost will write your letter here.\n\nRead it.\nEdit anything that doesn't feel right.\nThen send it.", lines=16, interactive=True, elem_classes=["out-box"]) c2l = gr.Textbox(label="ACTION LOG", lines=4, interactive=False, elem_classes=["log-box"]) c2b.click(fn=unsent_letter, inputs=[c2i,c2t], outputs=[c2o,c2l]) # ── REALITY CHECK ── with gr.Tab("🔍 Reality Check"): gr.HTML('
Paste any message or document — Ghost spots what you might miss
') with gr.Row(equal_height=False): with gr.Column(scale=1): c3i = gr.Textbox(label="MESSAGE / DOCUMENT TO CHECK", placeholder="Paste any message, contract, email, or document...\n\nGhost will find:\n→ Contradictions\n→ Missing context\n→ Risky commitments\n→ Red flags\n→ Final verdict", lines=16) c3b = gr.Button("👻 Reality Check", size="lg") with gr.Column(scale=1): c3o = gr.Textbox(label="GHOST'S VERDICT (editable)", placeholder="Contradictions · Missing context\nRisky commitments · Red flags · Verdict\n\nwill stream here...", lines=16, interactive=True, elem_classes=["out-box"]) c3l = gr.Textbox(label="ACTION LOG", lines=4, interactive=False, elem_classes=["log-box"]) c3b.click(fn=reality_check, inputs=c3i, outputs=[c3o,c3l]) gr.HTML(""" """) demo.queue().launch()