Spaces:
Sleeping
Sleeping
| import os | |
| os.environ.setdefault("ASTRANEXUS_FINETUNED", "1") # run the SP3 fine-tuned encoder | |
| import astranexus.config # noqa: F401 — loads any HF Space secrets from env | |
| import os.path | |
| import gradio as gr | |
| from fastapi import FastAPI | |
| from fastapi.responses import HTMLResponse, FileResponse, JSONResponse | |
| from astranexus.ui.app import build_app, DARK | |
| app = FastAPI(title="AstraNexus") | |
| # 'Sign in with Google' web flow (live mode uses the Gmail REST API over 443, | |
| # because the Space firewalls outbound IMAP). No-op if the OAuth client secrets | |
| # aren't set, so the fixture demo still runs. | |
| from astranexus.web import google_oauth | |
| google_oauth.attach(app) | |
| LANDING = """<!doctype html><html><head><meta charset=utf-8> | |
| <meta name=viewport content="width=device-width,initial-scale=1"> | |
| <title>AstraNexus</title> | |
| <style> | |
| *{box-sizing:border-box} body{margin:0;background:#0a0e17;color:#c0caf5; | |
| font-family:system-ui,Segoe UI,Roboto,sans-serif;line-height:1.6} | |
| .wrap{max-width:860px;margin:0 auto;padding:64px 24px} | |
| h1{font-size:44px;margin:0 0 4px;color:#fff;letter-spacing:-.5px} | |
| .tag{color:#7aa2f7;font-size:18px;margin-bottom:28px} | |
| .cta{display:inline-block;margin:18px 0 36px;padding:14px 30px;border-radius:10px; | |
| background:#7aa2f7;color:#0a0e17;font-weight:700;text-decoration:none;font-size:16px} | |
| .cta:hover{background:#9eb8ff} | |
| .grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin:24px 0} | |
| .card{background:#0d1320;border:1px solid #29304a;border-radius:12px;padding:16px 18px} | |
| .card b{color:#fff} .k{color:#7aa2f7} | |
| .pills span{display:inline-block;background:#0d1320;border:1px solid #29304a; | |
| border-radius:20px;padding:4px 12px;margin:4px 6px 0 0;font-size:13px} | |
| a{color:#7aa2f7} .foot{margin-top:40px;opacity:.7;font-size:13px} | |
| </style></head><body><div class=wrap> | |
| <h1>✦ AstraNexus</h1> | |
| <div class=tag>Your inbox, as a navigable galaxy.</div> | |
| <p>Unsupervised email organizer. A <b>fine-tuned multimodal encoder</b> | |
| (MiniLM text + SigLIP vision, LoRA) embeds every email; HDBSCAN groups them into | |
| <b>constellations</b> that <b>NVIDIA Nemotron-3-Nano-4B</b> names and reasons over; | |
| threads spanning accounts surface as <b>wormholes</b>. No rules, no folders — | |
| the structure is discovered.</p> | |
| <a class=cta href="app/">Launch the demo →</a> | |
| <div class=grid> | |
| <div class=card><b>Color</b> — the <span class=k>constellation</span> (topic the | |
| encoder grouped it into). Each has a Nemotron-named hub star.</div> | |
| <div class=card><b>Size</b> — unread (big) vs read. <b>Brightness</b> ∝ urgency.</div> | |
| <div class=card><b>Gold halo</b> — the email carries an image (where the | |
| multimodal model earns its keep).</div> | |
| <div class=card><b>Pink dashed</b> — a wormhole: one thread across two accounts.</div> | |
| </div> | |
| <p><b>Under the hood:</b> the whole AI pipeline runs on a <b>Modal</b> GPU as a | |
| <b>LangGraph</b> agentic graph — | |
| fetch→embed→cluster→label→<b>judge</b>→serialize. An | |
| <b>LLM-as-judge</b> (Nemotron) scores the labels and loops back to relabel until they | |
| pass, then it writes an open agent trace — | |
| <a href="trace.json">view the latest trace.json →</a>. An in-app <b>A/B toggle</b> | |
| pits the fine-tuned encoder against off-the-shelf SigLIP; layered fallbacks | |
| (Modal → NIM-hosted Nemotron → keyword heuristic) keep it alive.</p> | |
| <p style="opacity:.75;font-size:14px"><b>About the data:</b> the default | |
| <b>fixture</b> is a <i>synthetic</i> dataset built only for demo/testing — no real | |
| email. Google restricts reading people's mail, so live Gmail is invite-only | |
| (approved test accounts / my own mailboxes); session-only, never stored.</p> | |
| <div class=pills> | |
| <span>🧠 Nemotron-3-Nano-4B</span><span>⚡ Modal GPU</span> | |
| <span>🕸 LangGraph + judge loop</span><span>🎯 Fine-tuned encoder + A/B</span> | |
| <span>📡 Open agent trace</span> | |
| </div> | |
| <p class=foot>Fine-tuned encoder: | |
| <a href="https://huggingface.co/DriptoBhattacharyya/astranexus-mm-encoder"> | |
| DriptoBhattacharyya/astranexus-mm-encoder</a> · built for the Build Small hackathon.</p> | |
| </div></body></html>""" | |
| def home(): | |
| return LANDING | |
| def trace(): | |
| # the LangGraph agent trace from the most recent map (Open Trace) | |
| if os.path.exists("trace.json"): | |
| return FileResponse("trace.json", media_type="application/json") | |
| return JSONResponse({"detail": "Run a map first to generate the agent trace."}, | |
| status_code=404) | |
| demo = build_app(theme=DARK) # custom dark Gradio mounted under /app | |
| app = gr.mount_gradio_app(app, demo, path="/app") | |