"""
╔═══════════════════════════════════════════════════════════════╗
║ 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()