import os import numpy as np import pandas as pd import gradio as gr from sentence_transformers import SentenceTransformer from sklearn.metrics.pairwise import cosine_similarity # ========================= # 1. ASSETS & CONFIG # ========================= MODEL_ID = "sentence-transformers/all-MiniLM-L6-v2" DATA_FILE = "synthetic_analyst_notes_10k.csv" EMBED_FILE = "embeddings.npy" # ========================= # 2. WALL STREET STYLING (CSS) - FINAL POLISH # ========================= CSS = r""" :root{ --bg:#0b1220; --panel:#0f1a2f; --text:#e7eefc; --muted:#9db0d0; --accent:#2b76ff; --accent2:#00c2ff; --good:#18d38a; --bad:#ff4d5e; --border:rgba(255,255,255,.10); --shadow:0 22px 70px rgba(0,0,0,.55); } *{box-sizing:border-box;} html,body{background:var(--bg); color:var(--text);} .gradio-container{max-width:1200px !important; background:var(--bg) !important; color:var(--text) !important;} h1,h2,h3,h4, label, .label, .wrap, .prose, .markdown, .md{color:var(--text) !important;} /* --- FINAL NAV BAR FIX (ALL WHITE) --- */ .nav{ position:sticky; top:0; z-index:50; display:flex; align-items:center; gap:16px; padding:14px 18px; background:rgba(11,18,32,.95); backdrop-filter: blur(10px); border-bottom:1px solid rgba(255,255,255,.15); } /* Force all text inside nav to be white */ .nav * { color: #ffffff !important; } .brand{display:flex; align-items:center; gap:10px; font-weight:900; letter-spacing:.4px;} .brand .logo{width:22px; height:22px; border-radius:7px; background:linear-gradient(135deg, var(--accent), var(--accent2)); box-shadow:0 16px 55px rgba(43,118,255,.28);} .links{display:flex; gap:14px; font-size:13px; font-weight: 500;} .links div { opacity: 0.9; cursor: pointer; } .links div:hover { opacity: 1; text-decoration: underline; } .spacer{flex:1;} .pill{border:1px solid rgba(255,255,255,.30); border-radius:999px; padding:7px 10px; font-size:12px; background:rgba(255,255,255,.15);} .kpi{display:flex; align-items:center; gap:10px; font-size:12px;} .dot{width:7px; height:7px; border-radius:999px; background:rgba(24,211,138,.95); box-shadow:0 0 18px rgba(24,211,138,.30);} /* HERO & SECTIONS */ .hero{margin:18px; border-radius:22px; overflow:hidden; position:relative; min-height:260px; background:radial-gradient(1100px 420px at 20% 10%, rgba(43,118,255,.34), transparent 62%), radial-gradient(900px 380px at 80% 30%, rgba(0,194,255,.16), transparent 60%), linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,0)); border:1px solid rgba(255,255,255,.08); box-shadow:var(--shadow);} .hero-inner{position:relative; padding:30px 32px 22px 32px; display:grid; grid-template-columns: 1.25fr .75fr; gap:18px; align-items:end;} .hero h1{margin:0; font-size:38px; line-height:1.06;} .hero p{margin:10px 0 0 0; color:var(--muted); max-width:62ch; font-size:14px;} .tagrow{display:flex; gap:10px; flex-wrap:wrap; justify-content:flex-end; padding-bottom:6px;} .tag{font-size:12px; color:var(--muted); border:1px solid rgba(255,255,255,.10); background:rgba(255,255,255,.04); padding:7px 10px; border-radius:999px;} .section{margin:18px; border:1px solid rgba(255,255,255,.08); background:rgba(255,255,255,.03); border-radius:18px; box-shadow:0 18px 55px rgba(0,0,0,.35); overflow:hidden;} .section-head{padding:14px 16px; border-bottom:1px solid rgba(255,255,255,.06); display:flex; align-items:baseline; justify-content:space-between; gap:10px;} .pad{padding:14px 16px;} .whitepanel{background:#ffffff !important; color:#111111 !important; border-radius:16px !important; border:1px solid rgba(0,0,0,.08) !important;} .whitepanel *{color:#111111 !important;} .gr-textbox textarea{background:#ffffff !important; color:#111111 !important; border:1px solid rgba(0,0,0,.10) !important; border-radius:16px !important;} /* BUTTONS UNIFORMITY */ button { height: 100% !important; min-height: 50px !important; } .runbtn{border:1px solid rgba(43,118,255,.55) !important; background:linear-gradient(135deg, rgba(43,118,255,.95), rgba(0,194,255,.70)) !important; color:#ffffff !important; box-shadow:0 18px 45px rgba(43,118,255,.22) !important; font-weight: bold !important;} .quick{border:1px solid rgba(0,0,0,.12) !important; background:#f0f2f5 !important; color:#111111 !important;} .quick:hover{border-color:rgba(43,118,255,.35) !important; background:#ffffff !important;} /* CARDS */ .cards{display:grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap:12px;} @media (max-width: 980px){.cards{grid-template-columns: 1fr;}} .card{border-radius:16px; border:1px solid rgba(0,0,0,.10); background:#ffffff; padding:12px; box-shadow:0 14px 40px rgba(0,0,0,.10);} .card .top{display:flex; align-items:center; justify-content:space-between; gap:10px; margin-bottom:8px;} .badge{font-size:11px; font-weight:800; padding:6px 8px; border-radius:999px; background:rgba(43,118,255,.10); border:1px solid rgba(43,118,255,.35); color:#111111;} .sym{font-weight:900; letter-spacing:.2px; font-size:18px;} .meta{color:#333; font-size:12px; display:flex; gap:10px; flex-wrap:wrap; margin-bottom:10px;} .note{font-size:13px; line-height:1.35; color:#111; white-space:pre-wrap;} """ NAV_HTML = """
""" HERO_HTML = """Describe your investment thesis (e.g., "Aggressive tech growth but with debt risks"). The AI performs Semantic Search to find grounded historical cases and generates a top pick.