Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <meta name="theme-color" content="#0a0a0b" /> | |
| <title>JobTracker classifier — runs in your browser</title> | |
| <meta name="description" content="A fine-tuned 3-layer email classifier — rules, e5 embeddings, SetFit — running entirely in your browser via quantized ONNX. No server. 0.979 macro-F1, CI-gated at 0.95." /> | |
| <style> | |
| :root{color-scheme:dark;--bg:#0a0a0b;--surface:#0f1011;--surface2:#141517;--fg:#d6d8db;--strong:#f7f8f8;--muted:#8a8f98;--dim:#63666c;--line:rgb(255 255 255/.09);--line-soft:rgb(255 255 255/.055);--line-strong:rgb(255 255 255/.2);--green:#4ade80;--amber:#f59e0b;--mono:ui-monospace,'SF Mono',Menlo,monospace} | |
| *{box-sizing:border-box} | |
| body{margin:0;background:var(--bg);color:var(--fg);font-family:ui-sans-serif,system-ui,-apple-system,sans-serif;-webkit-font-smoothing:antialiased} | |
| .wrap{max-width:1060px;margin:0 auto;padding:0 20px 60px} | |
| header{display:flex;align-items:center;justify-content:space-between;height:56px;border-bottom:1px solid var(--line-soft)} | |
| .brand{font-family:var(--mono);font-weight:600;font-size:.9rem;color:var(--strong)} | |
| .brand em{font-style:normal;color:var(--dim)} | |
| .pill{display:inline-flex;align-items:center;gap:.5rem;border:1px solid var(--line);border-radius:999px;padding:.3rem .8rem;font-family:var(--mono);font-size:.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:.06em} | |
| .dot{width:6px;height:6px;border-radius:99px;background:var(--dim)} | |
| .dot[data-on]{background:var(--green);box-shadow:0 0 8px rgb(74 222 128/.5)} | |
| h1{margin:2.4rem 0 .6rem;font-size:clamp(1.8rem,4.5vw,2.6rem);letter-spacing:-.02em;color:var(--strong);text-wrap:balance} | |
| h1 span{color:var(--muted)} | |
| .sub{margin:0 0 1.8rem;max-width:640px;color:var(--muted);line-height:1.6} | |
| .label{font-family:var(--mono);font-size:.66rem;letter-spacing:.09em;text-transform:uppercase;color:var(--muted)} | |
| .frame{border:1px solid var(--line);border-radius:14px;background:var(--surface);overflow:hidden;box-shadow:0 28px 110px rgb(0 0 0/.5)} | |
| .titlebar{display:flex;flex-wrap:wrap;gap:.5rem 1rem;align-items:center;justify-content:space-between;padding:.7rem 1.1rem;border-bottom:1px solid var(--line-soft);background:rgb(19 20 22/.65);font-family:var(--mono);font-size:.74rem;color:var(--muted)} | |
| .grid{display:grid;grid-template-columns:1.1fr .9fr} | |
| .grid>div{padding:1.3rem} | |
| .grid>div:first-child{border-right:1px solid var(--line-soft)} | |
| input,textarea{width:100%;border:1px solid var(--line);border-radius:10px;background:#0c0d0e;color:var(--strong);padding:.65rem .8rem;font:inherit;font-size:.92rem} | |
| textarea{min-height:150px;resize:vertical} | |
| input:focus,textarea:focus{outline:none;border-color:var(--line-strong)} | |
| .btn{display:inline-flex;align-items:center;gap:.4rem;margin-top:.8rem;border:0;border-radius:9px;background:linear-gradient(180deg,#f7f8f8,#e2e2e2);color:#0a0a0b;font-weight:600;font-size:.92rem;padding:.6rem 1.2rem;cursor:pointer;transition:transform .16s} | |
| .btn:hover{transform:translateY(-1px)} | |
| .btn:disabled{opacity:.4;cursor:not-allowed;transform:none} | |
| .ghost{display:inline-block;border:1px solid var(--line);border-radius:8px;background:none;color:var(--muted);font-family:var(--mono);font-size:.68rem;letter-spacing:.04em;text-transform:uppercase;padding:.4rem .7rem;margin:.25rem .25rem 0 0;cursor:pointer;transition:color .16s,border-color .16s} | |
| .ghost:hover{color:var(--strong);border-color:var(--line-strong)} | |
| .verdict{display:grid;place-items:center;gap:.2rem;min-height:7.4rem;border:1px solid var(--line-soft);border-radius:10px;background:rgb(255 255 255/.02);padding:1rem;text-align:center} | |
| .verdict b{font-size:1.9rem;letter-spacing:-.02em;color:var(--strong);text-transform:capitalize} | |
| .verdict small{font-family:var(--mono);font-size:.78rem;color:var(--muted)} | |
| .trace{display:grid;gap:.4rem;margin-top:1rem} | |
| .trow{display:flex;align-items:baseline;gap:.6rem;border:1px solid var(--line-soft);border-radius:9px;padding:.55rem .8rem;font-family:var(--mono);font-size:.76rem;color:var(--muted)} | |
| .trow b{color:var(--strong);font-weight:600} | |
| .trow[data-state=answered]{border-color:rgb(74 222 128/.35)} | |
| .trow[data-state=answered] .st{color:var(--green)} | |
| .trow[data-state=skipped]{opacity:.55} | |
| .trow .ms{margin-left:auto;color:var(--dim)} | |
| .review{color:var(--amber)} | |
| .progress{height:4px;border-radius:99px;background:rgb(255 255 255/.06);overflow:hidden;margin-top:.6rem} | |
| .progress i{display:block;height:100%;width:0;background:var(--strong);transition:width .2s} | |
| .facts{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--line-soft);background:rgb(19 20 22/.65)} | |
| .facts div{padding:.8rem 1.1rem;border-right:1px solid var(--line-soft)} | |
| .facts div:last-child{border-right:0} | |
| .facts dt{font-family:var(--mono);font-size:.62rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)} | |
| .facts dd{margin:.2rem 0 0;font-family:var(--mono);font-size:.8rem;font-weight:600;color:var(--strong)} | |
| footer{margin-top:2.2rem;font-family:var(--mono);font-size:.7rem;color:var(--dim);line-height:1.8} | |
| footer a{color:var(--muted)} | |
| @media(max-width:760px){.grid{grid-template-columns:1fr}.grid>div:first-child{border-right:0;border-bottom:1px solid var(--line-soft)}.facts{grid-template-columns:repeat(2,1fr)}} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="wrap"> | |
| <header> | |
| <span class="brand">job<em>_</em>tracker <em>/</em> classifier</span> | |
| <span class="pill"><i class="dot" id="dot"></i><span id="state">loading model</span></span> | |
| </header> | |
| <h1>The classifier left the server.<br/><span>It runs here, in your browser.</span></h1> | |
| <p class="sub">The 3-layer pipeline behind JobTracker — regex rules, fine-tuned e5 embeddings, a SetFit head — | |
| ported to quantized ONNX and executing on your machine. Nothing you paste leaves this page. Verified | |
| output-identical to the Python pipeline; 0.979 macro-F1 on the committed eval set, CI-gated at 0.95.</p> | |
| <div class="frame"> | |
| <div class="titlebar"> | |
| <span>paste an email · classified locally</span> | |
| <span id="timing"></span> | |
| </div> | |
| <div class="grid"> | |
| <div> | |
| <div class="label" style="margin-bottom:.5rem">01 · email</div> | |
| <input id="subject" placeholder="Subject — e.g. Interview availability" /> | |
| <div style="height:.6rem"></div> | |
| <textarea id="body" placeholder="Body — paste any job-pipeline email…"></textarea> | |
| <div class="progress" id="prog" hidden><i id="progbar"></i></div> | |
| <button class="btn" id="go" disabled>Classify</button> | |
| <div style="margin-top:.9rem" class="label">or a synthetic example</div> | |
| <div id="examples"></div> | |
| </div> | |
| <div> | |
| <div class="label" style="margin-bottom:.5rem">02 · verdict</div> | |
| <div class="verdict" id="verdict"><b style="opacity:.4">?</b><small>the model downloads once (22.8MB), then everything is local</small></div> | |
| <div class="label" style="margin:1rem 0 .4rem">03 · three layers, in order</div> | |
| <div class="trace" id="trace"></div> | |
| </div> | |
| </div> | |
| <dl class="facts"> | |
| <div><dt>macro-F1</dt><dd>0.979 / gate 0.95</dd></div> | |
| <div><dt>model</dt><dd>e5-small · int8</dd></div> | |
| <div><dt>weights</dt><dd>22.8MB once</dd></div> | |
| <div><dt>server calls</dt><dd>zero</dd></div> | |
| </dl> | |
| </div> | |
| <footer> | |
| Same rules, same fine-tuned embeddings, same SetFit head as production — exported, quantized, and verified | |
| output-identical (6/6 agreement suite). Model card: <a href="https://huggingface.co/yadava5/jobtracker-setfit-classifier">yadava5/jobtracker-setfit-classifier</a>. | |
| Part of JobTracker by Ayush Yadav · no inbox is read, nothing leaves your browser. | |
| </footer> | |
| </div> | |
| <script type="module" src="./app.js"></script> | |
| </body> | |
| </html> | |