- tools/organ.py: Pack/install/publish AI persona organs - tools/forge.sh: Convert HuggingFace models to GGUF, quantize - tools/store.sh: Browse/install/publish community models - tools/compilation/: Cross-platform build scripts (Linux/macOS) - scripts/install.sh: Universal installer (auto-detect OS/arch/GPU) - site/saas/: SaaS frontend + backend source (v3 unified design) - site/vitrine/: Main site source (inference-x.com) - docs/ARCHITECTURE.md: Full system architecture All plans now in test mode - Studio & Enterprise free to test. Branch: master | Maintainer: Anti-Atlas craton (elmadani)
1407 lines
75 KiB
HTML
1407 lines
75 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en" data-theme="dark">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||
<title>Inference-X Build — Try Free · Build · Deploy</title>
|
||
<meta name="description" content="Try a real AI instance in 90 seconds. No account. Build your custom AI config. Deploy on real hardware. The community builds the future of intelligence.">
|
||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,700;0,9..144,900;1,9..144,500&family=Nunito:wght@400;600;700;800;900&display=swap" rel="stylesheet">
|
||
<style>
|
||
/* ═══════════════════════════════════════════════
|
||
IX DESIGN SYSTEM — Unified across all subdomains
|
||
Fraunces × Nunito × JetBrains Mono
|
||
Copper × Amber × Teal × Warm Dark
|
||
═══════════════════════════════════════════════ */
|
||
:root{
|
||
--bg: #0C0A09;
|
||
--bg1: #111318;
|
||
--bg2: #161B20;
|
||
--bg3: #1D2328;
|
||
--bg4: #242B32;
|
||
--border: #272F37;
|
||
--border2: #323D47;
|
||
--copper: #C9622A;
|
||
--copper2: #E07B39;
|
||
--amber: #F0A030;
|
||
--teal: #2ECCB8;
|
||
--teal2: #20A99A;
|
||
--green: #2ECC71;
|
||
--red: #E74C3C;
|
||
--blue: #3498DB;
|
||
--tx: #E8EEF4;
|
||
--tx2: #8A9BAB;
|
||
--tx3: #4A5A6A;
|
||
--display: 'Fraunces', serif;
|
||
--body: 'Nunito', sans-serif;
|
||
--mono: 'JetBrains Mono', monospace;
|
||
--r: .5rem;
|
||
}
|
||
*{margin:0;padding:0;box-sizing:border-box}
|
||
html{scroll-behavior:smooth;font-size:16px}
|
||
body{font-family:var(--body);background:var(--bg);color:var(--tx);overflow-x:hidden;min-height:100vh}
|
||
body::before{content:'';position:fixed;inset:0;z-index:0;pointer-events:none;opacity:.025;
|
||
background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
|
||
background-size:256px}
|
||
|
||
/* ── SCROLL ── */
|
||
::-webkit-scrollbar{width:4px}
|
||
::-webkit-scrollbar-track{background:transparent}
|
||
::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}
|
||
|
||
/* ── UTILS ── */
|
||
a{color:inherit;text-decoration:none}
|
||
.mono{font-family:var(--mono)}
|
||
.display{font-family:var(--display)}
|
||
.teal{color:var(--teal)}
|
||
.copper{color:var(--copper2)}
|
||
.amber{color:var(--amber)}
|
||
.green{color:var(--green)}
|
||
.muted{color:var(--tx2)}
|
||
|
||
/* ── HEADER ── */
|
||
header{
|
||
position:sticky;top:0;z-index:200;
|
||
background:rgba(12,10,9,.92);backdrop-filter:blur(12px);
|
||
border-bottom:1px solid var(--border);
|
||
padding:.9rem 1.5rem;
|
||
display:flex;align-items:center;justify-content:space-between;gap:1rem;
|
||
}
|
||
.logo{font-family:var(--display);font-weight:900;font-size:1.25rem;display:flex;align-items:center;gap:.3rem}
|
||
.logo-ix{color:var(--copper2)}
|
||
.logo-build{color:var(--tx2);font-size:.9rem;font-weight:300;font-style:italic;margin-left:.2rem}
|
||
nav{display:flex;align-items:center;gap:.3rem}
|
||
.nav-link{padding:.4rem .8rem;border-radius:.3rem;font-size:.82rem;font-weight:700;color:var(--tx2);transition:all .2s;white-space:nowrap}
|
||
.nav-link:hover{color:var(--tx);background:var(--bg3)}
|
||
.btn{display:inline-flex;align-items:center;gap:.4rem;padding:.45rem .9rem;border-radius:.4rem;font-size:.82rem;font-weight:800;cursor:pointer;transition:all .2s;font-family:var(--body);border:1.5px solid transparent}
|
||
.btn-outline{background:none;border-color:var(--border2);color:var(--tx2)}
|
||
.btn-outline:hover{border-color:var(--copper);color:var(--copper2)}
|
||
.btn-primary{background:var(--copper);color:#fff;border-color:var(--copper)}
|
||
.btn-primary:hover{background:var(--amber);border-color:var(--amber)}
|
||
.btn-teal{background:var(--teal);color:#000;border-color:var(--teal)}
|
||
.btn-teal:hover{background:var(--teal2);border-color:var(--teal2)}
|
||
.btn-green{background:var(--green);border-color:var(--green);color:#000}
|
||
.btn-sm{padding:.3rem .65rem;font-size:.75rem}
|
||
.btn-lg{padding:.8rem 1.8rem;font-size:1rem;border-radius:.5rem}
|
||
|
||
/* ── LIVE BANNER ── */
|
||
.live-banner{
|
||
background:linear-gradient(90deg,rgba(0,0,0,0),rgba(46,204,113,.06),rgba(0,0,0,0));
|
||
border-bottom:1px solid rgba(46,204,113,.15);
|
||
padding:.55rem 1.5rem;
|
||
display:flex;align-items:center;justify-content:center;gap:1.5rem;
|
||
font-size:.78rem;color:var(--tx2);flex-wrap:wrap;text-align:center;
|
||
}
|
||
.pulse{display:inline-block;width:7px;height:7px;background:var(--green);border-radius:50%;animation:pulse 2s infinite;margin-right:.3rem;vertical-align:middle}
|
||
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(1.6)}}
|
||
.cval{font-family:var(--mono);font-weight:700;color:var(--teal)}
|
||
|
||
/* ── SECTIONS ── */
|
||
.section{padding:4rem 1.5rem;max-width:1200px;margin:0 auto;position:relative;z-index:1}
|
||
.section-sm{padding:2.5rem 1.5rem}
|
||
.section-full{max-width:none;padding:4rem 1.5rem}
|
||
.divider{height:1px;background:linear-gradient(90deg,transparent,var(--border),transparent);margin:0}
|
||
|
||
/* ── SECTION HEADER ── */
|
||
.sec-eyebrow{font-size:.7rem;font-weight:800;letter-spacing:.15em;text-transform:uppercase;color:var(--tx3);margin-bottom:.6rem;display:flex;align-items:center;gap:.5rem}
|
||
.sec-eyebrow::before{content:'';width:24px;height:2px;background:currentColor;border-radius:1px}
|
||
.sec-title{font-family:var(--display);font-size:clamp(2rem,4vw,3rem);font-weight:900;line-height:1.1;letter-spacing:-.02em;margin-bottom:1rem}
|
||
.sec-title em{font-style:italic;color:var(--teal)}
|
||
.sec-sub{color:var(--tx2);font-size:1rem;max-width:640px;line-height:1.7;margin-bottom:2rem}
|
||
|
||
/* ═══════════════════════════════════
|
||
HERO — FREE DEMO
|
||
═══════════════════════════════════ */
|
||
.hero{
|
||
padding:3.5rem 1.5rem 2.5rem;
|
||
max-width:1200px;margin:0 auto;
|
||
display:grid;grid-template-columns:1fr 440px;gap:3rem;align-items:start;
|
||
position:relative;z-index:1;
|
||
}
|
||
@media(max-width:900px){.hero{grid-template-columns:1fr;gap:2rem}}
|
||
.hero-text{}
|
||
.hero-eyebrow{
|
||
display:inline-flex;align-items:center;gap:.5rem;
|
||
background:rgba(0,184,169,.08);border:1px solid rgba(0,184,169,.2);
|
||
border-radius:2rem;padding:.3rem .8rem;
|
||
font-size:.75rem;font-weight:700;color:var(--teal);margin-bottom:1.2rem;
|
||
}
|
||
.hero h1{font-family:var(--display);font-size:clamp(2.2rem,5vw,3.5rem);font-weight:900;line-height:1.05;letter-spacing:-.03em;margin-bottom:1rem}
|
||
.hero h1 em{font-style:italic;color:var(--teal)}
|
||
.hero p{color:var(--tx2);font-size:1rem;line-height:1.75;max-width:520px;margin-bottom:1.8rem}
|
||
.region-row{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1.2rem}
|
||
.rbtn{background:var(--bg3);border:1.5px solid var(--border);border-radius:.4rem;padding:.4rem .8rem;cursor:pointer;font-size:.8rem;font-weight:700;font-family:var(--body);color:var(--tx2);transition:all .15s}
|
||
.rbtn.active,.rbtn:hover{border-color:var(--teal);color:var(--teal);background:rgba(46,204,113,.05)}
|
||
.hero-actions{display:flex;gap:1rem;align-items:center;flex-wrap:wrap}
|
||
.btn-launch{
|
||
background:linear-gradient(135deg,var(--teal),var(--green));
|
||
border:none;border-radius:.5rem;padding:.9rem 2rem;
|
||
color:#000;font-weight:900;font-family:var(--body);font-size:1.05rem;
|
||
cursor:pointer;transition:all .2s;display:flex;align-items:center;gap:.5rem;
|
||
}
|
||
.btn-launch:hover{transform:translateY(-2px);box-shadow:0 8px 28px rgba(46,204,113,.25)}
|
||
.btn-launch:disabled{opacity:.5;cursor:not-allowed;transform:none;box-shadow:none}
|
||
.no-reg{font-size:.78rem;color:var(--tx3);display:flex;align-items:center;gap:.4rem}
|
||
.no-reg svg{color:var(--teal)}
|
||
|
||
/* ── DEMO CARD ── */
|
||
.demo-card{
|
||
background:var(--bg2);border:1px solid var(--border);border-radius:.8rem;
|
||
overflow:hidden;position:sticky;top:80px;
|
||
}
|
||
.demo-card-header{
|
||
padding:.7rem 1rem;background:var(--bg3);
|
||
border-bottom:1px solid var(--border);
|
||
display:flex;align-items:center;justify-content:space-between;
|
||
}
|
||
.dc-dots{display:flex;gap:.35rem}
|
||
.dc-dot{width:10px;height:10px;border-radius:50%}
|
||
.dc-r{background:#FF5F57}.dc-y{background:#FEBC2E}.dc-g{background:#28C840}
|
||
.dc-title{font-family:var(--mono);font-size:.72rem;color:var(--tx3)}
|
||
.timer-strip{height:3px;background:var(--border);position:relative;overflow:hidden}
|
||
.timer-fill{height:100%;background:linear-gradient(90deg,var(--green),var(--amber),var(--red));transition:width 1s linear;width:100%}
|
||
|
||
/* TERMINAL */
|
||
.terminal{padding:.8rem;background:var(--bg2);max-height:170px;overflow-y:auto;font-family:var(--mono);font-size:.74rem}
|
||
.log{padding:.05rem 0;display:flex;gap:.4rem}
|
||
.log.sys{color:var(--tx3)}
|
||
.log.ok{color:var(--green)}
|
||
.log.err{color:var(--red)}
|
||
.log.warn{color:var(--amber)}
|
||
.log.info{color:var(--tx2)}
|
||
.ts{color:var(--tx3);flex-shrink:0;font-size:.65rem;min-width:38px}
|
||
.blink{display:inline-block;width:7px;height:11px;background:var(--teal);animation:bl .7s infinite;vertical-align:middle}
|
||
@keyframes bl{0%,100%{opacity:1}50%{opacity:0}}
|
||
|
||
/* METRICS */
|
||
.metrics{display:grid;grid-template-columns:repeat(4,1fr);gap:.5rem;padding:.8rem}
|
||
.m-card{background:var(--bg3);border:1px solid var(--border);border-radius:.4rem;padding:.6rem;text-align:center}
|
||
.m-val{font-family:var(--mono);font-size:1.2rem;font-weight:700}
|
||
.m-val.cpu{color:var(--amber)}
|
||
.m-val.ram{color:var(--blue)}
|
||
.m-val.toks{color:var(--teal)}
|
||
.m-val.timer{color:var(--green)}
|
||
.m-lbl{font-size:.62rem;color:var(--tx3);font-weight:700;text-transform:uppercase;letter-spacing:.06em;margin-top:.1rem}
|
||
.bar{height:3px;background:var(--border);border-radius:2px;margin-top:.3rem;overflow:hidden}
|
||
.bar-fill{height:100%;border-radius:2px;transition:width .5s}
|
||
|
||
/* CHAT */
|
||
.chat-wrap{border-top:1px solid var(--border);padding:0}
|
||
.chat-msgs{padding:.8rem;max-height:200px;overflow-y:auto;display:flex;flex-direction:column;gap:.6rem}
|
||
.msg{display:flex;gap:.5rem;align-items:flex-start}
|
||
.msg.user{flex-direction:row-reverse}
|
||
.av{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.75rem;flex-shrink:0}
|
||
.av-u{background:rgba(201,98,42,.2);border:1px solid rgba(201,98,42,.3)}
|
||
.av-a{background:rgba(46,204,113,.12);border:1px solid rgba(46,204,113,.25)}
|
||
.bubble{max-width:85%;padding:.5rem .75rem;border-radius:.5rem;font-size:.82rem;line-height:1.55}
|
||
.bubble-u{background:rgba(201,98,42,.1);border:1px solid rgba(201,98,42,.15)}
|
||
.bubble-a{background:var(--bg3);border:1px solid var(--border)}
|
||
.bubble-meta{font-size:.62rem;color:var(--tx3);font-family:var(--mono);margin-top:.2rem}
|
||
.typing{display:flex;gap:.25rem;padding:.4rem;align-items:center}
|
||
.td{width:6px;height:6px;background:var(--teal);border-radius:50%;animation:tp .5s infinite}
|
||
.td:nth-child(2){animation-delay:.12s}.td:nth-child(3){animation-delay:.24s}
|
||
@keyframes tp{0%,60%,100%{transform:translateY(0)}30%{transform:translateY(-5px)}}
|
||
.chat-in{display:flex;gap:.5rem;padding:.6rem .8rem;border-top:1px solid var(--border)}
|
||
.ci{flex:1;background:var(--bg3);border:1.5px solid var(--border);border-radius:.4rem;padding:.5rem .7rem;color:var(--tx);font-family:var(--body);font-size:.82rem;outline:none}
|
||
.ci:focus{border-color:var(--teal)}
|
||
.ci:disabled{opacity:.4;cursor:not-allowed}
|
||
.ci::placeholder{color:var(--tx3)}
|
||
.cs{background:var(--teal);border:none;border-radius:.35rem;padding:.5rem .9rem;color:#000;font-weight:800;cursor:pointer;font-family:var(--body);font-size:.8rem}
|
||
.cs:disabled{opacity:.4;cursor:not-allowed}
|
||
|
||
/* DOWNLOAD */
|
||
.dl-banner{background:rgba(46,204,113,.05);border:1px solid rgba(46,204,113,.15);border-radius:.5rem;padding:.8rem 1rem;margin:.6rem .8rem;display:none}
|
||
.dl-banner.show{display:flex;align-items:center;justify-content:space-between;gap:.8rem;flex-wrap:wrap}
|
||
|
||
/* SUGGESTIONS */
|
||
.suggestions{padding:.6rem .8rem .3rem;display:flex;flex-wrap:wrap;gap:.4rem}
|
||
.chip{background:var(--bg3);border:1px solid var(--border);border-radius:2rem;padding:.25rem .65rem;font-size:.74rem;cursor:pointer;color:var(--tx2);transition:all .15s}
|
||
.chip:hover{border-color:var(--teal);color:var(--teal)}
|
||
|
||
/* ═══════════════════════════════════
|
||
REPOS SECTION
|
||
═══════════════════════════════════ */
|
||
.repos-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:1.2rem;margin-top:2rem}
|
||
.repo-card{
|
||
background:var(--bg2);border:1px solid var(--border);border-radius:.7rem;
|
||
padding:1.4rem;transition:all .25s;position:relative;overflow:hidden;
|
||
}
|
||
.repo-card::before{
|
||
content:'';position:absolute;inset:0;opacity:0;transition:opacity .3s;
|
||
background:linear-gradient(135deg,rgba(46,204,113,.04),rgba(0,184,169,.04));
|
||
}
|
||
.repo-card:hover{border-color:var(--teal);transform:translateY(-2px)}
|
||
.repo-card:hover::before{opacity:1}
|
||
.repo-header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:.8rem}
|
||
.repo-name{font-family:var(--display);font-size:1.2rem;font-weight:700;color:var(--tx);display:flex;align-items:center;gap:.5rem}
|
||
.repo-badge{font-size:.65rem;font-weight:800;padding:.2rem .5rem;border-radius:.2rem;text-transform:uppercase;letter-spacing:.06em}
|
||
.badge-bsl{background:rgba(201,98,42,.15);color:var(--copper2);border:1px solid rgba(201,98,42,.2)}
|
||
.badge-mit{background:rgba(46,204,113,.12);color:var(--green);border:1px solid rgba(46,204,113,.15)}
|
||
.badge-apache{background:rgba(52,152,219,.12);color:var(--blue);border:1px solid rgba(52,152,219,.15)}
|
||
.repo-desc{font-size:.85rem;color:var(--tx2);line-height:1.6;margin-bottom:1rem}
|
||
.repo-stats{display:flex;gap:1rem;font-size:.78rem;color:var(--tx3);font-family:var(--mono);margin-bottom:1rem}
|
||
.repo-stat{display:flex;align-items:center;gap:.3rem}
|
||
.repo-tags{display:flex;flex-wrap:wrap;gap:.4rem;margin-bottom:1.1rem}
|
||
.tag{background:var(--bg3);border:1px solid var(--border);border-radius:.2rem;padding:.15rem .5rem;font-size:.7rem;color:var(--tx2);font-family:var(--mono)}
|
||
.repo-actions{display:flex;gap:.6rem}
|
||
|
||
/* ═══════════════════════════════════
|
||
BUILD CONFIGURATOR
|
||
═══════════════════════════════════ */
|
||
.builder-wrap{
|
||
background:var(--bg2);border:1px solid var(--border);border-radius:.8rem;
|
||
overflow:hidden;margin-top:2rem;
|
||
}
|
||
.builder-tabs{display:flex;border-bottom:1px solid var(--border)}
|
||
.btab{padding:.8rem 1.2rem;font-size:.82rem;font-weight:800;cursor:pointer;color:var(--tx2);transition:all .2s;border-bottom:2px solid transparent;margin-bottom:-1px}
|
||
.btab.active{color:var(--teal);border-color:var(--teal)}
|
||
.bpanel{display:none;padding:1.5rem}
|
||
.bpanel.active{display:block}
|
||
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:1rem;margin-bottom:1rem}
|
||
@media(max-width:600px){.form-row{grid-template-columns:1fr}}
|
||
.form-group{display:flex;flex-direction:column;gap:.4rem}
|
||
.form-label{font-size:.74rem;font-weight:800;text-transform:uppercase;letter-spacing:.08em;color:var(--tx2)}
|
||
.form-select,.form-input,.form-textarea{
|
||
background:var(--bg3);border:1.5px solid var(--border);border-radius:.4rem;
|
||
padding:.6rem .8rem;color:var(--tx);font-family:var(--body);font-size:.85rem;outline:none;
|
||
transition:border-color .2s;width:100%;
|
||
}
|
||
.form-select:focus,.form-input:focus,.form-textarea:focus{border-color:var(--teal)}
|
||
.form-textarea{min-height:80px;resize:vertical}
|
||
.ram-slider-wrap{margin-bottom:1rem}
|
||
.ram-val{font-family:var(--mono);font-size:1.5rem;font-weight:700;color:var(--amber);margin-bottom:.4rem}
|
||
input[type=range]{width:100%;height:4px;background:var(--border);border-radius:2px;outline:none;-webkit-appearance:none;cursor:pointer}
|
||
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:16px;height:16px;border-radius:50%;background:var(--amber);cursor:pointer}
|
||
.models-fit{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.8rem}
|
||
.model-chip{background:var(--bg3);border:1px solid var(--border);border-radius:.3rem;padding:.3rem .7rem;font-size:.74rem;font-family:var(--mono);color:var(--tx2);transition:all .2s}
|
||
.model-chip.fits{border-color:var(--green);color:var(--green);background:rgba(46,204,113,.07)}
|
||
.model-chip.nope{opacity:.3}
|
||
|
||
/* ═══════════════════════════════════
|
||
PROVIDER POOL
|
||
═══════════════════════════════════ */
|
||
.pool-hero{
|
||
background:linear-gradient(135deg,rgba(52,152,219,.06),rgba(0,184,169,.06));
|
||
border:1px solid rgba(52,152,219,.15);border-radius:.8rem;padding:2rem;margin-top:2rem;
|
||
display:grid;grid-template-columns:1fr 400px;gap:2rem;align-items:start;
|
||
}
|
||
@media(max-width:800px){.pool-hero{grid-template-columns:1fr}}
|
||
.pool-text h3{font-family:var(--display);font-size:1.8rem;font-weight:900;line-height:1.1;margin-bottom:.8rem}
|
||
.pool-text p{color:var(--tx2);font-size:.9rem;line-height:1.7;margin-bottom:1rem}
|
||
.pool-benefits{display:flex;flex-direction:column;gap:.5rem}
|
||
.benefit{display:flex;align-items:flex-start;gap:.6rem;font-size:.85rem}
|
||
.benefit-icon{color:var(--teal);font-size:1rem;flex-shrink:0;margin-top:.1rem}
|
||
.benefit-desc{color:var(--tx2);line-height:1.5}
|
||
.pool-form{background:var(--bg3);border:1px solid var(--border);border-radius:.6rem;padding:1.2rem;display:flex;flex-direction:column;gap:.7rem}
|
||
.pool-form h4{font-weight:800;font-size:.95rem;margin-bottom:.2rem}
|
||
.pool-form input{background:var(--bg2);border:1.5px solid var(--border);border-radius:.4rem;padding:.55rem .75rem;color:var(--tx);font-family:var(--body);font-size:.83rem;outline:none;width:100%;transition:border-color .2s}
|
||
.pool-form input:focus{border-color:var(--teal)}
|
||
.pool-form input::placeholder{color:var(--tx3)}
|
||
.pool-providers-list{margin-top:1.5rem;display:flex;flex-direction:column;gap:.5rem}
|
||
.provider-item{display:flex;align-items:center;gap:.8rem;padding:.7rem 1rem;background:var(--bg3);border:1px solid var(--border);border-radius:.4rem;font-size:.82rem}
|
||
.pi-logo{font-size:1.2rem}
|
||
.pi-name{font-weight:700}
|
||
.pi-stats{margin-left:auto;font-family:var(--mono);font-size:.72rem;color:var(--tx3)}
|
||
.pi-bar{width:60px;height:4px;background:var(--border);border-radius:2px;overflow:hidden;flex-shrink:0}
|
||
.pi-fill{height:100%;background:var(--teal);border-radius:2px}
|
||
|
||
/* ═══════════════════════════════════
|
||
PLANS
|
||
═══════════════════════════════════ */
|
||
.plans-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1.2rem;margin-top:2rem}
|
||
@media(max-width:800px){.plans-grid{grid-template-columns:1fr}}
|
||
.plan-card{background:var(--bg2);border:1px solid var(--border);border-radius:.8rem;padding:1.6rem;transition:all .25s;position:relative}
|
||
.plan-card.featured{border-color:var(--teal);background:linear-gradient(135deg,rgba(46,204,113,.04),rgba(0,184,169,.04))}
|
||
.plan-badge{position:absolute;top:-12px;left:50%;transform:translateX(-50%);background:var(--teal);color:#000;font-size:.68rem;font-weight:900;padding:.2rem .7rem;border-radius:1rem;text-transform:uppercase;letter-spacing:.06em;white-space:nowrap}
|
||
.plan-name{font-family:var(--display);font-size:1.4rem;font-weight:700;margin-bottom:.3rem}
|
||
.plan-price{font-family:var(--mono);font-size:2.2rem;font-weight:700;color:var(--amber);margin:.5rem 0}
|
||
.plan-price span{font-size:.85rem;color:var(--tx2);font-weight:400}
|
||
.plan-desc{font-size:.82rem;color:var(--tx2);line-height:1.5;margin-bottom:1.2rem}
|
||
.plan-features{display:flex;flex-direction:column;gap:.5rem;margin-bottom:1.5rem}
|
||
.feat{display:flex;align-items:flex-start;gap:.5rem;font-size:.83rem}
|
||
.feat-check{color:var(--teal);flex-shrink:0;font-size:.9rem}
|
||
.feat-x{color:var(--tx3);flex-shrink:0}
|
||
|
||
/* ═══════════════════════════════════
|
||
HARDWARE SCOUT
|
||
═══════════════════════════════════ */
|
||
.scout-table{width:100%;border-collapse:collapse;font-size:.82rem;margin-top:1.5rem}
|
||
.scout-table th{text-align:left;padding:.5rem .8rem;color:var(--tx3);font-size:.68rem;text-transform:uppercase;letter-spacing:.1em;font-weight:700;border-bottom:1px solid var(--border)}
|
||
.scout-table td{padding:.55rem .8rem;border-bottom:1px solid rgba(255,255,255,.03)}
|
||
.scout-table tr:hover td{background:rgba(255,255,255,.02)}
|
||
.status-dot{width:7px;height:7px;border-radius:50%;display:inline-block;margin-right:.4rem}
|
||
.sd-on{background:var(--green);animation:pulse 2s infinite}
|
||
.sd-busy{background:var(--amber)}
|
||
|
||
/* ═══════════════════════════════════
|
||
GITEA SECTION HEADER
|
||
═══════════════════════════════════ */
|
||
.git-section-header{
|
||
display:flex;align-items:center;justify-content:space-between;
|
||
padding:1.2rem 1.5rem;
|
||
background:rgba(46,204,113,.03);
|
||
border-bottom:1px solid rgba(46,204,113,.1);
|
||
}
|
||
.git-logo{display:flex;align-items:center;gap:.7rem}
|
||
.git-logo-icon{font-size:1.5rem}
|
||
.git-logo-text{font-family:var(--display);font-weight:700;font-size:1.1rem}
|
||
.git-logo-sub{font-size:.75rem;color:var(--tx2);margin-top:.1rem}
|
||
.git-stats{display:flex;gap:1.5rem;font-size:.8rem;color:var(--tx2)}
|
||
.gs{display:flex;align-items:center;gap:.4rem}
|
||
|
||
/* ═══════════════════════════════════
|
||
FOOTER
|
||
═══════════════════════════════════ */
|
||
footer{border-top:1px solid var(--border);padding:2.5rem 1.5rem;max-width:1200px;margin:0 auto}
|
||
.footer-grid{display:grid;grid-template-columns:1.5fr 1fr 1fr 1fr;gap:2rem}
|
||
@media(max-width:700px){.footer-grid{grid-template-columns:1fr 1fr}}
|
||
.footer-brand{font-family:var(--display);font-size:1.3rem;font-weight:900;margin-bottom:.5rem}
|
||
.footer-tagline{font-size:.8rem;color:var(--tx2);line-height:1.6}
|
||
.footer-col-title{font-size:.72rem;font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:var(--tx3);margin-bottom:.8rem}
|
||
.footer-links{display:flex;flex-direction:column;gap:.4rem}
|
||
.footer-link{font-size:.82rem;color:var(--tx2);transition:color .15s}
|
||
.footer-link:hover{color:var(--copper2)}
|
||
.footer-bottom{margin-top:2rem;padding-top:1.5rem;border-top:1px solid var(--border);display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:.8rem;font-size:.75rem;color:var(--tx3)}
|
||
|
||
/* REVEAL ANIMATION */
|
||
.reveal{opacity:0;transform:translateY(24px);transition:opacity .6s ease,transform .6s ease}
|
||
.reveal.visible{opacity:1;transform:none}
|
||
@media(prefers-reduced-motion:reduce){.reveal{opacity:1;transform:none}}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<!-- HEADER -->
|
||
<header>
|
||
<a href="https://inference-x.com" style="display:flex;align-items:center;gap:.4rem">
|
||
<span class="logo"><span class="logo-ix">Inference-X</span></span>
|
||
<span class="logo-build">/ Build</span>
|
||
</a>
|
||
<nav>
|
||
<a href="#demo" class="nav-link">Demo</a>
|
||
<a href="#repos" class="nav-link">Repos</a>
|
||
<a href="#build" class="nav-link">Builder</a>
|
||
<a href="#pool" class="nav-link">Contribute</a>
|
||
<a href="#plans" class="nav-link">Plans</a>
|
||
</nav>
|
||
<div style="display:flex;gap:.6rem;align-items:center">
|
||
<a href="https://inference-x.com" class="btn btn-outline btn-sm">← Main site</a>
|
||
<a href="https://git.inference-x.com" class="btn btn-outline btn-sm" target="_blank">Git ↗</a>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- LIVE STATS -->
|
||
<div class="live-banner">
|
||
<span><span class="pulse"></span><span class="cval" id="cTotal">—</span> total demos run</span>
|
||
<span>🟢 <span class="cval" id="cActive">0</span> instances active now</span>
|
||
<span>⚡ <span class="cval" id="cToday">—</span> demos today</span>
|
||
<span>🌍 5 continents · Real hardware · 30 min · Auto-destroy</span>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════
|
||
HERO + DEMO CARD
|
||
══════════════════════════ -->
|
||
<div class="hero" id="demo">
|
||
<div class="hero-text reveal">
|
||
<div class="hero-eyebrow">
|
||
<span class="pulse" style="margin:0"></span>
|
||
Free demo · No account needed
|
||
</div>
|
||
<h1>Try a real AI.<br><em>Right now.</em></h1>
|
||
<p>We spin up an actual server in a real datacenter, install the Inference-X engine, load an AI model, and give you a live chat interface. Everything is erased when you're done. No data stored. No account created.</p>
|
||
|
||
<div class="region-row">
|
||
<button class="rbtn active" onclick="setR('eu',this)">🇩🇪 Frankfurt</button>
|
||
<button class="rbtn" onclick="setR('us',this)">🗽 New York</button>
|
||
<button class="rbtn" onclick="setR('ap',this)">🌏 Singapore</button>
|
||
<button class="rbtn" onclick="setR('mena',this)">🇲🇦 Fez</button>
|
||
<button class="rbtn" onclick="setR('sa',this)">🌎 São Paulo</button>
|
||
</div>
|
||
|
||
<div class="hero-actions">
|
||
<button class="btn-launch" id="launchBtn" onclick="launchDemo()">
|
||
<span>⚡</span> Launch Free Demo
|
||
</button>
|
||
<div class="no-reg">
|
||
✓ No account · ✓ No credit card · ✓ 30 min · ✓ Auto-erased
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Metrics appear when running -->
|
||
<div id="metricsWrap" style="display:none;margin-top:1.5rem">
|
||
<div style="font-size:.72rem;font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:var(--tx3);margin-bottom:.6rem;display:flex;align-items:center;gap:.4rem">
|
||
<span style="width:7px;height:7px;background:var(--green);border-radius:50%;display:inline-block;animation:pulse 2s infinite"></span>
|
||
Live Instance Metrics
|
||
</div>
|
||
<div class="metrics" style="padding:0">
|
||
<div class="m-card"><div class="m-val cpu" id="mCpu">—</div><div class="m-lbl">CPU</div><div class="bar"><div class="bar-fill" id="mCpuB" style="width:0%;background:var(--amber)"></div></div></div>
|
||
<div class="m-card"><div class="m-val ram" id="mRam">—</div><div class="m-lbl">RAM</div><div class="bar"><div class="bar-fill" id="mRamB" style="width:0%;background:var(--blue)"></div></div></div>
|
||
<div class="m-card"><div class="m-val toks" id="mToks">—</div><div class="m-lbl">tok/s</div><div class="bar"><div class="bar-fill" id="mToksB" style="width:0%;background:var(--teal)"></div></div></div>
|
||
<div class="m-card"><div class="m-val timer" id="mTimer">30:00</div><div class="m-lbl">Left</div></div>
|
||
</div>
|
||
<div style="font-size:.7rem;color:var(--tx3);font-family:var(--mono);margin-top:.5rem">
|
||
<span id="mProvider">Provider: IX Core</span> · <span id="mRegion">Region: —</span> · LLaMA 3.2 1B · <span id="mQueries">0 queries</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Download when running -->
|
||
<div class="dl-banner" id="dlBanner">
|
||
<div>
|
||
<div style="font-weight:800;font-size:.9rem;margin-bottom:.2rem">📦 Take this home</div>
|
||
<div style="font-size:.78rem;color:var(--tx2)">Your config + chat history — run this locally forever</div>
|
||
</div>
|
||
<button class="btn btn-green btn-sm" onclick="dlConfig()">⬇ Download config</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- DEMO CARD -->
|
||
<div class="demo-card reveal" id="demoCard">
|
||
<div class="demo-card-header">
|
||
<div class="dc-dots">
|
||
<div class="dc-dot dc-r"></div>
|
||
<div class="dc-dot dc-y"></div>
|
||
<div class="dc-dot dc-g"></div>
|
||
</div>
|
||
<div class="dc-title" id="cardTitle">ix-demo · waiting...</div>
|
||
<div id="provLogo" style="font-size:1rem">🌍</div>
|
||
</div>
|
||
<div class="timer-strip"><div class="timer-fill" id="tFill"></div></div>
|
||
|
||
<!-- TERMINAL -->
|
||
<div class="terminal" id="termBody">
|
||
<div class="log sys"><span class="ts">00:00</span><span>Inference-X Demo Terminal — <span class="blink"></span></span></div>
|
||
</div>
|
||
|
||
<!-- METRICS IN CARD -->
|
||
<div class="metrics" id="cardMetrics" style="display:none">
|
||
<div class="m-card"><div class="m-val cpu" id="cm-cpu">—</div><div class="m-lbl">CPU</div></div>
|
||
<div class="m-card"><div class="m-val ram" id="cm-ram">—</div><div class="m-lbl">RAM</div></div>
|
||
<div class="m-card"><div class="m-val toks" id="cm-toks">—</div><div class="m-lbl">tok/s</div></div>
|
||
<div class="m-card"><div class="m-val timer" id="cm-timer">—</div><div class="m-lbl">Left</div></div>
|
||
</div>
|
||
|
||
<!-- CHAT -->
|
||
<div class="chat-wrap" id="chatWrap" style="display:none">
|
||
<div class="suggestions" id="suggBox">
|
||
<span class="chip" onclick="useSug(this)">Hello! Who are you?</span>
|
||
<span class="chip" onclick="useSug(this)">Is my data private?</span>
|
||
<span class="chip" onclick="useSug(this)">How fast are you?</span>
|
||
<span class="chip" onclick="useSug(this)">Write Python code</span>
|
||
</div>
|
||
<div class="chat-msgs" id="chatMsgs">
|
||
<div style="text-align:center;padding:.5rem;font-size:.8rem;color:var(--tx3)">
|
||
Your private AI is ready — ask anything
|
||
</div>
|
||
</div>
|
||
<div class="chat-in">
|
||
<input class="ci" id="ci" placeholder="Your private instance is running..." disabled>
|
||
<button class="cs" id="sendBtn" onclick="sendMsg()" disabled>→</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<!-- ═══════════════════════
|
||
REPOS SECTION
|
||
══════════════════════════ -->
|
||
<section id="repos" style="position:relative;z-index:1">
|
||
<div style="background:rgba(46,204,113,.03);border-top:1px solid rgba(46,204,113,.1);border-bottom:1px solid rgba(46,204,113,.1)">
|
||
<div class="git-section-header" style="max-width:1200px;margin:0 auto">
|
||
<div class="git-logo">
|
||
<div class="git-logo-icon">🐙</div>
|
||
<div>
|
||
<div class="git-logo-text">Inference-X Community</div>
|
||
<div class="git-logo-sub">git.inference-x.com — Open source · Community-built · BSL License</div>
|
||
</div>
|
||
</div>
|
||
<div class="git-stats">
|
||
<div class="gs">📦 16 repos</div>
|
||
<div class="gs">🌍 3 public</div>
|
||
<div class="gs">👥 Community</div>
|
||
<a href="https://git.inference-x.com" class="btn btn-outline btn-sm" target="_blank" style="margin-left:.5rem">Browse All →</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<div class="reveal">
|
||
<div class="sec-eyebrow" style="color:var(--teal)">Open Source Community</div>
|
||
<div class="sec-title">Build the future.<br><em>Together.</em></div>
|
||
<div class="sec-sub">These three repositories are the foundation. Fork them. Build on them. Propose your changes. The community makes the decisions — no single company controls the roadmap.</div>
|
||
</div>
|
||
|
||
<div class="repos-grid">
|
||
<!-- inference-x main -->
|
||
<div class="repo-card reveal">
|
||
<div class="repo-header">
|
||
<div>
|
||
<div class="repo-name">
|
||
<span>⚙</span> inference-x
|
||
</div>
|
||
<div style="font-size:.74rem;color:var(--tx3);font-family:var(--mono);margin-top:.2rem">elmadani/inference-x</div>
|
||
</div>
|
||
<span class="repo-badge badge-bsl">BSL 1.1</span>
|
||
</div>
|
||
<div class="repo-desc">Universal AI inference engine — 305 KB, 19 hardware backends, zero dependencies. The core: loads any GGUF model, exposes an OpenAI-compatible API, runs on any hardware from Raspberry Pi to data center GPU clusters.</div>
|
||
<div class="repo-stats">
|
||
<div class="repo-stat">⭐ <span id="repoStarsIx">—</span></div>
|
||
<div class="repo-stat">🍴 <span id="repoForksIx">—</span></div>
|
||
<div class="repo-stat">📝 C++ · CMake</div>
|
||
</div>
|
||
<div class="repo-tags">
|
||
<span class="tag">ai-inference</span>
|
||
<span class="tag">c++</span>
|
||
<span class="tag">openai-compatible</span>
|
||
<span class="tag">offline</span>
|
||
<span class="tag">19-backends</span>
|
||
</div>
|
||
<div class="repo-actions">
|
||
<a href="https://git.inference-x.com/elmadani/inference-x" class="btn btn-teal btn-sm" target="_blank">View Repo →</a>
|
||
<a href="https://git.inference-x.com/elmadani/inference-x/raw/branch/master/README.md" class="btn btn-outline btn-sm" target="_blank">README</a>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ix-tools -->
|
||
<div class="repo-card reveal">
|
||
<div class="repo-header">
|
||
<div>
|
||
<div class="repo-name">
|
||
<span>🔧</span> ix-tools
|
||
</div>
|
||
<div style="font-size:.74rem;color:var(--tx3);font-family:var(--mono);margin-top:.2rem">elmadani/ix-tools</div>
|
||
</div>
|
||
<span class="repo-badge badge-mit">MIT</span>
|
||
</div>
|
||
<div class="repo-desc">CLI tools, deployment scripts, model downloader, benchmark suite. Everything you need to set up, configure, and monitor your Inference-X deployment. Install scripts for all platforms.</div>
|
||
<div class="repo-stats">
|
||
<div class="repo-stat">⭐ <span id="repoStarsTools">—</span></div>
|
||
<div class="repo-stat">🍴 <span id="repoForksTools">—</span></div>
|
||
<div class="repo-stat">📝 Shell · Python</div>
|
||
</div>
|
||
<div class="repo-tags">
|
||
<span class="tag">cli</span>
|
||
<span class="tag">installer</span>
|
||
<span class="tag">benchmarks</span>
|
||
<span class="tag">python</span>
|
||
</div>
|
||
<div class="repo-actions">
|
||
<a href="https://git.inference-x.com/elmadani/ix-tools" class="btn btn-teal btn-sm" target="_blank">View Repo →</a>
|
||
<a href="https://git.inference-x.com/elmadani/ix-tools/raw/branch/master/README.md" class="btn btn-outline btn-sm" target="_blank">README</a>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ElmadaniS (personal / philosophy) -->
|
||
<div class="repo-card reveal">
|
||
<div class="repo-header">
|
||
<div>
|
||
<div class="repo-name">
|
||
<span>📖</span> ElmadaniS
|
||
</div>
|
||
<div style="font-size:.74rem;color:var(--tx3);font-family:var(--mono);margin-top:.2rem">elmadani/ElmadaniS</div>
|
||
</div>
|
||
<span class="repo-badge badge-apache">Public</span>
|
||
</div>
|
||
<div class="repo-desc">The founder's public work — mathematical frameworks, philosophical essays, project architecture documents. Understand the vision behind Inference-X: why it was built, where it's going, and the H5→H6 consciousness framework.</div>
|
||
<div class="repo-stats">
|
||
<div class="repo-stat">⭐ <span id="repoStarsElm">—</span></div>
|
||
<div class="repo-stat">🍴 <span id="repoForksElm">—</span></div>
|
||
<div class="repo-stat">📝 Markdown · Math</div>
|
||
</div>
|
||
<div class="repo-tags">
|
||
<span class="tag">philosophy</span>
|
||
<span class="tag">mathematics</span>
|
||
<span class="tag">z-equation</span>
|
||
<span class="tag">vision</span>
|
||
</div>
|
||
<div class="repo-actions">
|
||
<a href="https://git.inference-x.com/elmadani/ElmadaniS" class="btn btn-teal btn-sm" target="_blank">View Repo →</a>
|
||
<a href="https://git.inference-x.com/elmadani" class="btn btn-outline btn-sm" target="_blank">All repos</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CONTRIBUTE CTA -->
|
||
<div style="background:rgba(201,98,42,.04);border:1px solid rgba(201,98,42,.15);border-radius:.7rem;padding:1.5rem;margin-top:1.5rem;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:1rem" class="reveal">
|
||
<div>
|
||
<div style="font-family:var(--display);font-size:1.2rem;font-weight:700;margin-bottom:.3rem">Want to contribute?</div>
|
||
<div style="font-size:.85rem;color:var(--tx2)">Fork any repo · Open an issue · Submit a PR · Propose your craton · Join the builders</div>
|
||
</div>
|
||
<div style="display:flex;gap:.7rem">
|
||
<a href="https://git.inference-x.com/elmadani/inference-x/issues" class="btn btn-outline" target="_blank">Open Issue</a>
|
||
<a href="mailto:Elmadani.SALKA@proton.me?subject=IX Contribution" class="btn btn-primary">Contact →</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<!-- ═══════════════════════
|
||
BUILD CONFIGURATOR
|
||
══════════════════════════ -->
|
||
<div class="section" id="build">
|
||
<div class="reveal">
|
||
<div class="sec-eyebrow" style="color:var(--amber)">Configuration Builder</div>
|
||
<div class="sec-title">Build your<br><em>custom AI.</em></div>
|
||
<div class="sec-sub">Configure your IX deployment for your exact hardware and use case. Generate a ready-to-run config file you can deploy anywhere.</div>
|
||
</div>
|
||
|
||
<div class="builder-wrap reveal">
|
||
<div class="builder-tabs">
|
||
<div class="btab active" onclick="setTab('hardware',this)">🖥 Hardware</div>
|
||
<div class="btab" onclick="setTab('model',this)">🧠 Model</div>
|
||
<div class="btab" onclick="setTab('persona',this)">🎭 Persona</div>
|
||
<div class="btab" onclick="setTab('export',this)">📦 Export</div>
|
||
</div>
|
||
|
||
<!-- HARDWARE -->
|
||
<div class="bpanel active" id="tab-hardware">
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label class="form-label">Your Operating System</label>
|
||
<select class="form-select" id="bOS" onchange="updateExport()">
|
||
<option value="linux">Linux (x86_64)</option>
|
||
<option value="linux-arm">Linux (ARM64 / Raspberry Pi)</option>
|
||
<option value="macos">macOS (Apple Silicon M1/M2/M3)</option>
|
||
<option value="macos-intel">macOS (Intel)</option>
|
||
<option value="windows">Windows (x64)</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Hardware Backend</label>
|
||
<select class="form-select" id="bBackend" onchange="updateExport()">
|
||
<option value="cpu">CPU only (universal)</option>
|
||
<option value="cuda">CUDA (NVIDIA GPU)</option>
|
||
<option value="metal">Metal (Apple GPU)</option>
|
||
<option value="vulkan">Vulkan (Any GPU)</option>
|
||
<option value="rocm">ROCm (AMD GPU)</option>
|
||
<option value="opencl">OpenCL</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="ram-slider-wrap">
|
||
<label class="form-label">Available RAM</label>
|
||
<div class="ram-val"><span id="ramDisplay">8</span> GB</div>
|
||
<input type="range" min="1" max="128" value="8" id="ramSlider" oninput="updateRAM()">
|
||
<div style="font-size:.75rem;color:var(--tx2);margin-top:.5rem">Models that fit your hardware:</div>
|
||
<div class="models-fit" id="modelsFit"></div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label class="form-label">API Port</label>
|
||
<input class="form-input" type="number" id="bPort" value="8080" min="1024" max="65535" onchange="updateExport()">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Context Size (tokens)</label>
|
||
<select class="form-select" id="bCtx" onchange="updateExport()">
|
||
<option value="2048">2048 (minimal RAM)</option>
|
||
<option value="4096" selected>4096 (recommended)</option>
|
||
<option value="8192">8192 (large context)</option>
|
||
<option value="16384">16384 (heavy)</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MODEL -->
|
||
<div class="bpanel" id="tab-model">
|
||
<div class="form-group" style="margin-bottom:1rem">
|
||
<label class="form-label">Select Model</label>
|
||
<select class="form-select" id="bModel" onchange="updateExport()">
|
||
<option value="llama3.2-1b">LLaMA 3.2 1B (Q4_K_M) — ~1GB — Ultra-fast</option>
|
||
<option value="phi3-mini">Phi-3 Mini 3.8B (Q4) — ~2.4GB — Microsoft, efficient</option>
|
||
<option value="mistral-7b">Mistral 7B (Q4_K_M) — ~4.1GB — Best quality/size</option>
|
||
<option value="llama3.1-8b">LLaMA 3.1 8B (Q4) — ~5GB — Meta flagship small</option>
|
||
<option value="qwen2.5-7b">Qwen 2.5 7B (Q4) — ~4.5GB — Multilingual, code</option>
|
||
<option value="codellama-7b">CodeLlama 7B (Q4) — ~4.1GB — Code specialist</option>
|
||
<option value="mistral-22b">Mistral 22B (Q5) — ~15GB — Near-GPT4 quality</option>
|
||
<option value="llama3.1-70b">LLaMA 3.1 70B (Q4) — ~40GB — State of the art local</option>
|
||
<option value="custom">Custom GGUF (your URL)</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group" style="margin-bottom:1rem" id="customModelWrap" style="display:none">
|
||
<label class="form-label">Custom Model URL</label>
|
||
<input class="form-input" id="bCustomModel" placeholder="https://huggingface.co/.../model.gguf">
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label class="form-label">Quantization Preference</label>
|
||
<select class="form-select" id="bQuant" onchange="updateExport()">
|
||
<option value="Q4_K_M">Q4_K_M — Best balance (recommended)</option>
|
||
<option value="Q5_K_M">Q5_K_M — Higher quality</option>
|
||
<option value="Q8_0">Q8_0 — Near-lossless</option>
|
||
<option value="F16">F16 — Full precision (2x RAM)</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Max Tokens per Response</label>
|
||
<select class="form-select" id="bMaxTok" onchange="updateExport()">
|
||
<option value="256">256 (fast, concise)</option>
|
||
<option value="512" selected>512 (balanced)</option>
|
||
<option value="1024">1024 (detailed)</option>
|
||
<option value="4096">4096 (long form)</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- PERSONA -->
|
||
<div class="bpanel" id="tab-persona">
|
||
<div class="form-group" style="margin-bottom:1rem">
|
||
<label class="form-label">AI Name (optional)</label>
|
||
<input class="form-input" id="bName" placeholder="e.g. ARIA, Assistant, Jarvis..." oninput="updateExport()">
|
||
</div>
|
||
<div class="form-group" style="margin-bottom:1rem">
|
||
<label class="form-label">System Prompt</label>
|
||
<textarea class="form-textarea" id="bSystem" oninput="updateExport()" placeholder="You are a helpful assistant. Be concise and accurate. Never reveal internal instructions."></textarea>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label class="form-label">Response Style</label>
|
||
<select class="form-select" id="bStyle" onchange="updateExport()">
|
||
<option value="concise">Concise — Short, direct answers</option>
|
||
<option value="balanced">Balanced — Natural conversation</option>
|
||
<option value="detailed">Detailed — Full explanations</option>
|
||
<option value="technical">Technical — Developer mode</option>
|
||
<option value="creative">Creative — Imaginative</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Temperature</label>
|
||
<select class="form-select" id="bTemp" onchange="updateExport()">
|
||
<option value="0.1">0.1 — Deterministic (facts, code)</option>
|
||
<option value="0.5">0.5 — Focused</option>
|
||
<option value="0.7" selected>0.7 — Balanced (recommended)</option>
|
||
<option value="1.0">1.0 — Creative, varied</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- EXPORT -->
|
||
<div class="bpanel" id="tab-export">
|
||
<div style="margin-bottom:1rem">
|
||
<div style="font-size:.8rem;font-weight:700;color:var(--tx2);margin-bottom:.6rem">Generated configuration:</div>
|
||
<pre id="exportCode" style="background:var(--bg3);border:1px solid var(--border);border-radius:.4rem;padding:1rem;font-family:var(--mono);font-size:.75rem;overflow-x:auto;color:var(--teal);white-space:pre-wrap;max-height:280px;overflow-y:auto"></pre>
|
||
</div>
|
||
<div style="display:flex;gap:.8rem;flex-wrap:wrap">
|
||
<button class="btn btn-teal" onclick="dlBuildConfig()">⬇ Download ix-config.json</button>
|
||
<button class="btn btn-outline" onclick="copyExport()">📋 Copy to clipboard</button>
|
||
</div>
|
||
<div style="margin-top:1rem;padding:1rem;background:var(--bg3);border-radius:.4rem;font-size:.82rem;color:var(--tx2);line-height:1.7">
|
||
<strong style="color:var(--tx)">Quick start:</strong><br>
|
||
1. Download the config above<br>
|
||
2. Download the IX binary: <a href="https://inference-x.com#start" style="color:var(--teal)" target="_blank">inference-x.com#start</a><br>
|
||
3. Run: <code style="font-family:var(--mono);background:var(--bg2);padding:.1rem .4rem;border-radius:.2rem">./ix --config ix-config.json</code>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<!-- ═══════════════════════
|
||
PROVIDER POOL
|
||
══════════════════════════ -->
|
||
<div class="section" id="pool">
|
||
<div class="reveal">
|
||
<div class="sec-eyebrow" style="color:var(--blue)">Community Compute</div>
|
||
<div class="sec-title">Power the demos.<br><em>Earn your place</em> in history.</div>
|
||
</div>
|
||
|
||
<div class="pool-hero reveal">
|
||
<div class="pool-text">
|
||
<h3>The Provider Pool.</h3>
|
||
<p>Every free demo needs real compute. Community providers contribute their idle server capacity. In return, they're credited publicly, gain early access to future IX frameworks, and become part of the infrastructure that democratizes AI.</p>
|
||
<p style="color:var(--amber);font-weight:700;font-size:.88rem">Pioneer providers will have priority integration when the Echo Relay (federated inference network) launches.</p>
|
||
<div class="pool-benefits">
|
||
<div class="benefit"><span class="benefit-icon">✓</span><span class="benefit-desc">Your name/brand displayed as compute provider on every demo</span></div>
|
||
<div class="benefit"><span class="benefit-icon">✓</span><span class="benefit-desc">Daily cost limit you control — never exceed your budget</span></div>
|
||
<div class="benefit"><span class="benefit-icon">✓</span><span class="benefit-desc">Keys encrypted server-side — never exposed to public</span></div>
|
||
<div class="benefit"><span class="benefit-icon">✓</span><span class="benefit-desc">Early access: Echo Relay framework for distributed providers</span></div>
|
||
<div class="benefit"><span class="benefit-icon">✓</span><span class="benefit-desc">OneCloud, Hetzner, OVH or any API-compatible provider</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="pool-form">
|
||
<h4>🔋 Contribute compute</h4>
|
||
<input type="text" id="pName" placeholder="Provider name (e.g. Acme Corp, JohnDoe)">
|
||
<input type="text" id="pLogo" placeholder="Logo emoji (e.g. 🏢, 🚀)">
|
||
<input type="password" id="pApiKey" placeholder="OneCloud API Key">
|
||
<input type="password" id="pClientKey" placeholder="OneCloud Client Key">
|
||
<input type="number" id="pLimit" placeholder="Daily budget limit in € (e.g. 5)" min="1" max="100">
|
||
<button class="btn btn-primary" onclick="joinPool()" style="width:100%">Join the Provider Pool →</button>
|
||
<div style="font-size:.7rem;color:var(--tx3);text-align:center">Keys encrypted · Used only for IX demos · Revokable anytime</div>
|
||
<div id="poolOk" style="display:none;color:var(--green);font-size:.85rem;text-align:center;padding:.4rem">✓ You're in! Your compute will power free AI demos.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Active providers list -->
|
||
<div class="pool-providers-list" id="provList">
|
||
<div style="font-size:.72rem;font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:var(--tx3);margin-bottom:.3rem">Active pool contributors</div>
|
||
<div id="provItems" style="color:var(--tx3);font-size:.82rem;padding:.5rem 0">No providers yet — be the first to contribute compute.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<!-- ═══════════════════════
|
||
LIVE SCOUT
|
||
══════════════════════════ -->
|
||
<div class="section section-sm">
|
||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;flex-wrap:wrap;gap:1rem" class="reveal">
|
||
<div>
|
||
<div class="sec-eyebrow" style="color:var(--green)">Community Hardware</div>
|
||
<div style="font-family:var(--display);font-size:1.6rem;font-weight:900">Global IX nodes — <em>live.</em></div>
|
||
</div>
|
||
<a href="https://inference-x.com#scout" class="btn btn-outline btn-sm">Full map →</a>
|
||
</div>
|
||
<table class="scout-table reveal">
|
||
<thead><tr>
|
||
<th>Backend</th><th>Nodes</th><th>Avg tok/s</th><th>Load</th><th>Status</th>
|
||
</tr></thead>
|
||
<tbody id="scoutBody">
|
||
<tr><td colspan="5" style="color:var(--tx3);text-align:center;padding:1rem">Loading community nodes...</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div style="font-size:.74rem;color:var(--tx3);margin-top:.8rem">
|
||
Run IX with <code style="font-family:var(--mono);background:var(--bg3);padding:.1rem .35rem;border-radius:.2rem">--scout report</code> to appear on this map. Your IP is never shown.
|
||
</div>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<!-- ═══════════════════════
|
||
PLANS
|
||
══════════════════════════ -->
|
||
<div class="section" id="plans">
|
||
<div class="reveal">
|
||
<div class="sec-eyebrow" style="color:var(--copper2)">Pricing — Fair by design</div>
|
||
<div class="sec-title">Free for people.<br><em>Fair</em> for business.</div>
|
||
<div class="sec-sub">80% of all commercial revenue flows directly to community contributors. Individuals, researchers, students and small startups pay nothing. Always.</div>
|
||
</div>
|
||
|
||
<div class="plans-grid">
|
||
<!-- FREE -->
|
||
<div class="plan-card reveal">
|
||
<div class="plan-name">Community</div>
|
||
<div class="plan-price">$0<span>/always</span></div>
|
||
<div class="plan-desc">For individuals, researchers, students, open-source projects. Full engine, no limits on personal use. Forever free.</div>
|
||
<div class="plan-features">
|
||
<div class="feat"><span class="feat-check">✓</span><span>Full IX engine binary (305KB)</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>All 19 hardware backends</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>All GGUF models</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Unlimited local API calls</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Builder configs</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Community support (Gitea issues)</span></div>
|
||
<div class="feat"><span class="feat-x">—</span><span style="color:var(--tx3)">Managed cloud instance</span></div>
|
||
</div>
|
||
<a href="https://inference-x.com#start" class="btn btn-outline" style="width:100%;justify-content:center">Download →</a>
|
||
</div>
|
||
|
||
<!-- STUDIO TEST -->
|
||
<div class="plan-card featured reveal">
|
||
<div class="plan-badge">🧪 Test Mode — Free</div>
|
||
<div class="plan-name" style="color:var(--teal)">Studio</div>
|
||
<div class="plan-price">$0<span>/ test now</span></div>
|
||
<div class="plan-desc">Test every Studio feature — managed cloud instance, telemetry, builder, store. No payment needed. Register and activate test mode.</div>
|
||
<div class="plan-features">
|
||
<div class="feat"><span class="feat-check">✓</span><span>Everything in Community</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Dedicated cloud instance (2vCPU/2GB) — TEST</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Unlimited builder configs</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>10,000 API calls/month — TEST</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Telemetry dashboard — TEST</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Full model store access — TEST</span></div>
|
||
<div class="feat"><span class="feat-x">—</span><span style="color:var(--tx3)">Model store publisher</span></div>
|
||
</div>
|
||
<button class="btn btn-teal" style="width:100%;justify-content:center" onclick="activateTest('studio_test')">Activate Studio Test →</button>
|
||
</div>
|
||
|
||
<!-- ENTERPRISE TEST -->
|
||
<div class="plan-card reveal">
|
||
<div class="plan-name" style="color:var(--amber)">Enterprise</div>
|
||
<div class="plan-price">$0<span>/ test now</span></div>
|
||
<div class="plan-desc">Test every Enterprise feature — dedicated 8vCPU/32GB server, model store publisher, forge tools. Full sandbox, no payment.</div>
|
||
<div class="plan-features">
|
||
<div class="feat"><span class="feat-check">✓</span><span>Everything in Studio</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Dedicated server (8vCPU/32GB) — TEST</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Unlimited API calls — TEST</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Model Store: publish & sell — TEST</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Forge tools access — TEST</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Full Organ Store API — TEST</span></div>
|
||
<div class="feat"><span class="feat-check">✓</span><span>Community builder dashboard — TEST</span></div>
|
||
</div>
|
||
<button class="btn btn-primary" style="width:100%;justify-content:center" onclick="activateTest('enterprise_test')">Activate Enterprise Test →</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:rgba(240,160,48,.04);border:1px solid rgba(240,160,48,.15);border-radius:.6rem;padding:1.2rem;margin-top:1.5rem;text-align:center;font-size:.85rem;color:var(--tx2)" class="reveal">
|
||
💛 Prefer to support without a plan? <a href="https://paypal.me/elmadanisalka" style="color:var(--amber);font-weight:700" target="_blank">Donate via PayPal</a> — Infrastructure costs €53/month. Every euro powers the khettara.
|
||
</div>
|
||
</div>
|
||
|
||
<!-- FOOTER -->
|
||
<footer>
|
||
<div class="footer-grid reveal">
|
||
<div>
|
||
<div class="footer-brand">Inference<span style="color:var(--copper2)">-X</span></div>
|
||
<div class="footer-tagline">Built in Morocco for the world.<br>Intelligence flows where gravity takes it.<br>Like a khettara — built by many, for all.</div>
|
||
<div style="margin-top:1rem;display:flex;gap:.7rem;flex-wrap:wrap">
|
||
<a href="https://inference-x.com" class="btn btn-outline btn-sm">Main Site</a>
|
||
<a href="https://git.inference-x.com" class="btn btn-outline btn-sm" target="_blank">Gitea</a>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="footer-col-title">Engine</div>
|
||
<div class="footer-links">
|
||
<a href="https://inference-x.com#engine" class="footer-link">19 Backends</a>
|
||
<a href="https://inference-x.com#models" class="footer-link">Models</a>
|
||
<a href="https://inference-x.com#api" class="footer-link">API Reference</a>
|
||
<a href="https://inference-x.com#start" class="footer-link">Quick Start</a>
|
||
<a href="https://git.inference-x.com/elmadani/inference-x" class="footer-link" target="_blank">Source Code</a>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="footer-col-title">Community</div>
|
||
<div class="footer-links">
|
||
<a href="#repos" class="footer-link">Repos</a>
|
||
<a href="https://inference-x.com#join" class="footer-link">11 Cratons</a>
|
||
<a href="#pool" class="footer-link">Provider Pool</a>
|
||
<a href="https://inference-x.com#organ" class="footer-link">Organ Store</a>
|
||
<a href="mailto:Elmadani.SALKA@proton.me" class="footer-link">Contact</a>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="footer-col-title">Legal</div>
|
||
<div class="footer-links">
|
||
<a href="https://git.inference-x.com/elmadani/inference-x/raw/branch/master/LICENSE" class="footer-link" target="_blank">SALKA-IX License</a>
|
||
<a href="https://inference-x.com#pricing" class="footer-link">Pricing Policy</a>
|
||
<a href="mailto:Elmadani.SALKA@proton.me" class="footer-link">Privacy</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="footer-bottom">
|
||
<span>© 2025–2026 SALKA HOLDING SA (forming, Zug CH) · Elmadani Salka</span>
|
||
<span>SALKA-IX License v1.0 · BSL-1.1 for commercial</span>
|
||
</div>
|
||
</footer>
|
||
|
||
<script>
|
||
// ═══════════════════════════════════════════════
|
||
// IX SAAS CLIENT — Unified Demo + Builder + Pool
|
||
// ═══════════════════════════════════════════════
|
||
|
||
let token = null, sse = null, running = false, region = 'eu';
|
||
const startMs = Date.now();
|
||
|
||
// ── REGION ──────────────────────────────────────
|
||
function setR(r, btn) {
|
||
region = r;
|
||
document.querySelectorAll('.rbtn').forEach(b => b.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
}
|
||
|
||
// ── LAUNCH ──────────────────────────────────────
|
||
async function launchDemo() {
|
||
const btn = document.getElementById('launchBtn');
|
||
btn.disabled = true;
|
||
btn.innerHTML = '<span>⏳</span> Provisioning...';
|
||
log('Starting demo session...', 'sys');
|
||
log('Region: ' + region.toUpperCase(), 'info');
|
||
try {
|
||
const r = await fetch('/api/demo/start', {
|
||
method:'POST', headers:{'Content-Type':'application/json'},
|
||
body: JSON.stringify({ region })
|
||
});
|
||
const d = await r.json();
|
||
if (d.error) { log('Error: ' + d.error, 'err'); btn.disabled = false; btn.innerHTML = '<span>⚡</span> Launch Free Demo'; return; }
|
||
token = d.token;
|
||
document.getElementById('cardTitle').textContent = 'ix-demo-' + token.slice(0,8) + ' / provisioning';
|
||
document.getElementById('provLogo').textContent = d.provider?.logo || '🌍';
|
||
log('Provider: ' + (d.provider?.name || 'IX Core'), 'ok');
|
||
connectSSE(token);
|
||
} catch(e) {
|
||
log('Error: ' + e.message, 'err');
|
||
btn.disabled = false;
|
||
btn.innerHTML = '<span>⚡</span> Launch Free Demo';
|
||
}
|
||
}
|
||
|
||
// ── SSE ──────────────────────────────────────────
|
||
function connectSSE(tok) {
|
||
if (sse) sse.close();
|
||
sse = new EventSource('/api/demo/stream/' + tok);
|
||
sse.addEventListener('init', e => {
|
||
const d = JSON.parse(e.data);
|
||
if (d.logs) d.logs.forEach(l => log(l.msg, l.type));
|
||
});
|
||
sse.addEventListener('log', e => { const d=JSON.parse(e.data); log(d.msg, d.type); });
|
||
sse.addEventListener('vm_status', e => {
|
||
const d = JSON.parse(e.data);
|
||
document.getElementById('cardTitle').textContent = 'ix-demo-' + tok.slice(0,8) + ' / ' + (d.vm_status||'booting');
|
||
});
|
||
sse.addEventListener('ready', e => { onReady(JSON.parse(e.data)); });
|
||
sse.addEventListener('telemetry', e => { updateMetrics(JSON.parse(e.data)); });
|
||
sse.addEventListener('inference_start', () => showTyping());
|
||
sse.addEventListener('inference_done', e => { hideTyping(); const d=JSON.parse(e.data); addAI(d.response, d.tokens, d.ms); });
|
||
sse.addEventListener('destroyed', e => { onDestroyed(JSON.parse(e.data)); });
|
||
sse.onerror = () => { if (running) setTimeout(() => connectSSE(tok), 3000); };
|
||
}
|
||
|
||
function onReady(d) {
|
||
running = true;
|
||
log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'sys');
|
||
log('✓ Your private AI is ready!', 'ok');
|
||
document.getElementById('launchBtn').innerHTML = '<span>🟢</span> Instance Running';
|
||
document.getElementById('cardTitle').textContent = 'ix-demo-' + token.slice(0,8) + ' / running · ' + (d.region||'eu');
|
||
document.getElementById('cardMetrics').style.display = 'grid';
|
||
document.getElementById('chatWrap').style.display = 'block';
|
||
document.getElementById('metricsWrap').style.display = 'block';
|
||
document.getElementById('dlBanner').classList.add('show');
|
||
document.getElementById('ci').disabled = false;
|
||
document.getElementById('sendBtn').disabled = false;
|
||
document.getElementById('ci').placeholder = 'Your private AI is running — ask anything...';
|
||
document.getElementById('mRegion').textContent = 'Region: ' + (d.region||'—');
|
||
document.getElementById('mProvider').textContent = 'Provider: ' + (d.provider?.name||'IX Core');
|
||
document.getElementById('ci').addEventListener('keydown', e => { if (e.key==='Enter') sendMsg(); });
|
||
}
|
||
|
||
function updateMetrics(d) {
|
||
const set = (id, v) => { const el=document.getElementById(id); if(el) el.textContent=v; };
|
||
const bar = (id, v) => { const el=document.getElementById(id); if(el) el.style.width=v+'%'; };
|
||
set('mCpu', d.cpu+'%'); set('cm-cpu', d.cpu+'%'); bar('mCpuB', d.cpu);
|
||
set('mRam', d.ram+'%'); set('cm-ram', d.ram+'%'); bar('mRamB', d.ram);
|
||
set('mToks', d.tok_s||'—'); set('cm-toks', d.tok_s||'—'); bar('mToksB', Math.min(100,(d.tok_s||0)*5));
|
||
const m=d.remaining_min||0, s=d.remaining_sec||0;
|
||
const tStr = String(m).padStart(2,'0')+':'+String(s).padStart(2,'0');
|
||
set('mTimer', tStr); set('cm-timer', tStr);
|
||
set('mQueries', d.queries+' queries');
|
||
const pct = (d.remaining_ms / (30*60*1000)) * 100;
|
||
const tf = document.getElementById('tFill');
|
||
if (tf) { tf.style.width = pct+'%'; if(pct<20) tf.style.background='var(--red)'; else if(pct<50) tf.style.background='var(--amber)'; }
|
||
}
|
||
|
||
function onDestroyed(d) {
|
||
running = false;
|
||
if (sse) { sse.close(); sse = null; }
|
||
log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'sys');
|
||
log('Session ended: ' + (d.reason||'expired'), 'warn');
|
||
log('VM terminated. All data erased.', 'ok');
|
||
document.getElementById('launchBtn').innerHTML = '<span>🔄</span> New Demo';
|
||
document.getElementById('launchBtn').disabled = false;
|
||
document.getElementById('ci').disabled = true;
|
||
document.getElementById('sendBtn').disabled = true;
|
||
token = null;
|
||
}
|
||
|
||
// ── TERMINAL ─────────────────────────────────────
|
||
function log(msg, type='info') {
|
||
const body = document.getElementById('termBody');
|
||
const el = document.createElement('div');
|
||
el.className = 'log ' + (type==='system'?'sys':type==='success'?'ok':type==='error'?'err':type);
|
||
const elapsed = ((Date.now()-startMs)/1000).toFixed(0);
|
||
const ts = String(Math.floor(elapsed/60)).padStart(2,'0')+':'+String(elapsed%60).padStart(2,'0');
|
||
el.innerHTML = '<span class="ts">'+ts+'</span><span>'+msg+'</span>';
|
||
body.appendChild(el);
|
||
body.scrollTop = body.scrollHeight;
|
||
while (body.children.length > 120) body.removeChild(body.firstChild);
|
||
}
|
||
|
||
// ── CHAT ─────────────────────────────────────────
|
||
function useSug(chip) { if (!running) return; document.getElementById('ci').value = chip.textContent; sendMsg(); }
|
||
async function sendMsg() {
|
||
const ci = document.getElementById('ci');
|
||
const msg = ci.value.trim();
|
||
if (!msg || !token) return;
|
||
ci.value = '';
|
||
ci.disabled = true;
|
||
document.getElementById('sendBtn').disabled = true;
|
||
const sug = document.getElementById('suggBox');
|
||
if (sug) sug.style.display = 'none';
|
||
addUser(msg);
|
||
try {
|
||
await fetch('/api/demo/inference', {
|
||
method:'POST', headers:{'Content-Type':'application/json'},
|
||
body: JSON.stringify({ token, message: msg })
|
||
});
|
||
} catch(e) { hideTyping(); addAI('Connection error: '+e.message,0,0); }
|
||
finally { ci.disabled = false; document.getElementById('sendBtn').disabled = false; ci.focus(); }
|
||
}
|
||
function addUser(msg) {
|
||
const msgs = document.getElementById('chatMsgs');
|
||
const div = document.createElement('div');
|
||
div.className = 'msg user';
|
||
div.innerHTML = '<div class="av av-u">👤</div><div><div class="bubble bubble-u">'+esc(msg)+'</div></div>';
|
||
msgs.appendChild(div); msgs.scrollTop = msgs.scrollHeight;
|
||
}
|
||
let tEl = null;
|
||
function showTyping() {
|
||
const msgs = document.getElementById('chatMsgs');
|
||
tEl = document.createElement('div');
|
||
tEl.id = 'ti';
|
||
tEl.className = 'msg';
|
||
tEl.innerHTML = '<div class="av av-a">🤖</div><div class="bubble bubble-a"><div class="typing"><div class="td"></div><div class="td"></div><div class="td"></div></div></div>';
|
||
msgs.appendChild(tEl); msgs.scrollTop = msgs.scrollHeight;
|
||
}
|
||
function hideTyping() { const t=document.getElementById('ti'); if(t) t.remove(); }
|
||
function addAI(text, toks, ms) {
|
||
const msgs = document.getElementById('chatMsgs');
|
||
const div = document.createElement('div');
|
||
div.className = 'msg';
|
||
const formatted = text.includes('```')
|
||
? text.replace(/```(\w*)\n?([\s\S]*?)```/g,'<pre style="background:var(--bg2);border:1px solid var(--border);border-radius:.3rem;padding:.5rem;font-size:.72rem;overflow-x:auto;margin:.3rem 0">$2</pre>')
|
||
: esc(text);
|
||
div.innerHTML = '<div class="av av-a">🤖</div><div>'
|
||
+ '<div class="bubble bubble-a">'+formatted+'</div>'
|
||
+ (toks?'<div class="bubble-meta">LLaMA 3.2 1B · '+toks+' tokens · '+ms+'ms</div>':'')
|
||
+ '</div>';
|
||
msgs.appendChild(div); msgs.scrollTop = msgs.scrollHeight;
|
||
}
|
||
function esc(s) { return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\n/g,'<br>'); }
|
||
function dlConfig() { if (!token) return; const a=document.createElement('a'); a.href='/api/demo/download/'+token; a.download='ix-demo.json'; a.click(); }
|
||
|
||
// ── BUILDER ───────────────────────────────────────
|
||
const MODELS = [
|
||
{v:'llama3.2-1b',n:'LLaMA 3.2 1B',ram:1.2},
|
||
{v:'phi3-mini',n:'Phi-3 3.8B',ram:2.4},
|
||
{v:'mistral-7b',n:'Mistral 7B',ram:4.1},
|
||
{v:'llama3.1-8b',n:'LLaMA 3.1 8B',ram:5},
|
||
{v:'qwen2.5-7b',n:'Qwen 2.5 7B',ram:4.5},
|
||
{v:'codellama-7b',n:'CodeLlama 7B',ram:4.1},
|
||
{v:'mistral-22b',n:'Mistral 22B',ram:15},
|
||
{v:'llama3.1-70b',n:'LLaMA 70B',ram:40},
|
||
];
|
||
function setTab(id, el) {
|
||
document.querySelectorAll('.btab').forEach(b=>b.classList.remove('active'));
|
||
document.querySelectorAll('.bpanel').forEach(p=>p.classList.remove('active'));
|
||
el.classList.add('active');
|
||
document.getElementById('tab-'+id).classList.add('active');
|
||
if (id==='export') updateExport();
|
||
}
|
||
function updateRAM() {
|
||
const v = parseInt(document.getElementById('ramSlider').value);
|
||
document.getElementById('ramDisplay').textContent = v;
|
||
const wrap = document.getElementById('modelsFit');
|
||
wrap.innerHTML = MODELS.map(m => `<span class="model-chip ${m.ram<=v?'fits':'nope'}">${m.n} (${m.ram}GB)</span>`).join('');
|
||
updateExport();
|
||
}
|
||
function updateExport() {
|
||
const cfg = {
|
||
version: '1.0',
|
||
engine: 'inference-x',
|
||
hardware: {
|
||
os: document.getElementById('bOS')?.value,
|
||
backend: document.getElementById('bBackend')?.value,
|
||
ram_gb: parseInt(document.getElementById('ramSlider')?.value||'8'),
|
||
},
|
||
model: {
|
||
id: document.getElementById('bModel')?.value,
|
||
quant: document.getElementById('bQuant')?.value,
|
||
context_size: parseInt(document.getElementById('bCtx')?.value||'4096'),
|
||
max_tokens: parseInt(document.getElementById('bMaxTok')?.value||'512'),
|
||
},
|
||
persona: {
|
||
name: document.getElementById('bName')?.value || 'Assistant',
|
||
system_prompt: document.getElementById('bSystem')?.value || 'You are a helpful assistant.',
|
||
style: document.getElementById('bStyle')?.value,
|
||
temperature: parseFloat(document.getElementById('bTemp')?.value||'0.7'),
|
||
},
|
||
server: {
|
||
port: parseInt(document.getElementById('bPort')?.value||'8080'),
|
||
bind: '127.0.0.1',
|
||
},
|
||
quick_start: {
|
||
linux: './ix-linux-x64 --config ix-config.json',
|
||
macos: './ix-macos-arm64 --config ix-config.json',
|
||
windows: '.\\ix-windows-x64.exe --config ix-config.json',
|
||
}
|
||
};
|
||
const pre = document.getElementById('exportCode');
|
||
if (pre) pre.textContent = JSON.stringify(cfg, null, 2);
|
||
}
|
||
function dlBuildConfig() {
|
||
updateExport();
|
||
const cfg = document.getElementById('exportCode')?.textContent;
|
||
if (!cfg) return;
|
||
const blob = new Blob([cfg], {type:'application/json'});
|
||
const a = document.createElement('a');
|
||
a.href = URL.createObjectURL(blob);
|
||
a.download = 'ix-config.json';
|
||
a.click();
|
||
}
|
||
function copyExport() {
|
||
const cfg = document.getElementById('exportCode')?.textContent;
|
||
if (cfg) navigator.clipboard.writeText(cfg).then(() => {
|
||
const btn = event.target;
|
||
btn.textContent = '✓ Copied!';
|
||
setTimeout(() => btn.textContent = '📋 Copy to clipboard', 2000);
|
||
});
|
||
}
|
||
|
||
// ── POOL ─────────────────────────────────────────
|
||
async function joinPool() {
|
||
const name=document.getElementById('pName').value.trim();
|
||
const logo=document.getElementById('pLogo').value.trim()||'🖥';
|
||
const api_key=document.getElementById('pApiKey').value.trim();
|
||
const client_key=document.getElementById('pClientKey').value.trim();
|
||
const lim=parseFloat(document.getElementById('pLimit').value)||5;
|
||
if (!name||!api_key||!client_key) { alert('Please fill: name, API key, client key'); return; }
|
||
const r = await fetch('/api/demo/pool/join', {
|
||
method:'POST', headers:{'Content-Type':'application/json'},
|
||
body: JSON.stringify({ name, logo, api_key, client_key, daily_limit_eur: lim })
|
||
});
|
||
const d = await r.json();
|
||
if (d.ok) {
|
||
document.getElementById('pName').value='';
|
||
document.getElementById('pApiKey').value='';
|
||
document.getElementById('pClientKey').value='';
|
||
document.getElementById('poolOk').style.display='block';
|
||
loadProviders();
|
||
}
|
||
}
|
||
|
||
async function loadProviders() {
|
||
try {
|
||
const r = await fetch('/api/demo/pool/providers');
|
||
const d = await r.json();
|
||
const items = document.getElementById('provItems');
|
||
if (d.providers?.length > 0) {
|
||
items.innerHTML = d.providers.map(p => `
|
||
<div class="provider-item">
|
||
<span class="pi-logo">${p.logo}</span>
|
||
<span class="pi-name">${p.name}</span>
|
||
<div class="pi-bar"><div class="pi-fill" style="width:${p.utilization_pct}%"></div></div>
|
||
<span class="pi-stats">${p.utilization_pct}% · €${p.used_eur}/${p.daily_limit_eur}</span>
|
||
</div>`).join('');
|
||
} else {
|
||
items.innerHTML = '<div style="color:var(--tx3);font-size:.82rem;padding:.5rem 0">No providers yet — be the first.</div>';
|
||
}
|
||
} catch {}
|
||
}
|
||
|
||
// ── STATS + SCOUT ─────────────────────────────────
|
||
async function loadAll() {
|
||
// Stats
|
||
try {
|
||
const r = await fetch('/api/demo/stats');
|
||
const d = await r.json();
|
||
document.getElementById('cTotal').textContent = (d.total_all_time||0).toLocaleString();
|
||
document.getElementById('cActive').textContent = d.active_now||0;
|
||
document.getElementById('cToday').textContent = d.today||0;
|
||
} catch {}
|
||
|
||
// Scout
|
||
try {
|
||
const r = await fetch('/api/community/scout');
|
||
const d = await r.json();
|
||
const body = document.getElementById('scoutBody');
|
||
const backends = d.backends || {};
|
||
const keys = Object.keys(backends);
|
||
if (keys.length === 0) {
|
||
body.innerHTML = '<tr><td colspan="5" style="color:var(--tx3);text-align:center;padding:1rem">No nodes reporting yet. Run IX with --scout flag.</td></tr>';
|
||
} else {
|
||
body.innerHTML = keys.map(bk => {
|
||
const b = backends[bk];
|
||
const load = b.avg_load || 0;
|
||
return `<tr>
|
||
<td><span class="mono" style="color:var(--teal)">${bk}</span></td>
|
||
<td>${b.node_count||0}</td>
|
||
<td class="mono">${(b.avg_tokens_per_sec||0).toFixed(1)}</td>
|
||
<td><div style="width:80px;height:4px;background:var(--border);border-radius:2px;overflow:hidden;display:inline-block"><div style="width:${load}%;height:100%;background:${load>80?'var(--red)':load>50?'var(--amber)':'var(--green)'};border-radius:2px"></div></div> ${load}%</td>
|
||
<td><span class="status-dot sd-on"></span>Online</td>
|
||
</tr>`;
|
||
}).join('');
|
||
}
|
||
} catch {}
|
||
|
||
// Repos from Gitea API
|
||
try {
|
||
const repos = ['inference-x','ix-tools','ElmadaniS'];
|
||
const ids = {
|
||
'inference-x': ['repoStarsIx','repoForksIx'],
|
||
'ix-tools': ['repoStarsTools','repoForksTools'],
|
||
'ElmadaniS': ['repoStarsElm','repoForksElm'],
|
||
};
|
||
for (const name of repos) {
|
||
const r = await fetch(`https://git.inference-x.com/api/v1/repos/elmadani/${name}`);
|
||
if (r.ok) {
|
||
const d = await r.json();
|
||
const [sId, fId] = ids[name];
|
||
document.getElementById(sId).textContent = d.stars_count||0;
|
||
document.getElementById(fId).textContent = d.forks_count||0;
|
||
}
|
||
}
|
||
} catch {}
|
||
|
||
loadProviders();
|
||
}
|
||
|
||
// ── CONTACT PLAN ──────────────────────────────────
|
||
function contactPlan(plan) {
|
||
window.open('mailto:Elmadani.SALKA@proton.me?subject=IX '+(plan==='enterprise'?'Enterprise':'Studio')+' Plan&body=Hello,%0A%0AI am interested in the '+(plan==='enterprise'?'Enterprise':'Studio')+' plan.%0A%0ACompany/Name:%0AUse case:%0AExpected usage:%0A', '_blank');
|
||
}
|
||
|
||
// ── ACTIVATE TEST PLAN ───────────────────────────
|
||
async function activateTest(plan) {
|
||
const email = prompt('Enter your email to activate ' + plan + ' (free test):');
|
||
if (!email || !email.includes('@')) { alert('Valid email required'); return; }
|
||
const password = prompt('Choose a password (min 8 chars):');
|
||
if (!password || password.length < 8) { alert('Password too short'); return; }
|
||
|
||
// Try register first
|
||
try {
|
||
const reg = await fetch('/api/auth/register', {
|
||
method: 'POST', headers: {'Content-Type':'application/json'},
|
||
body: JSON.stringify({ email, password })
|
||
});
|
||
const rd = await reg.json();
|
||
const token = rd.token;
|
||
if (!token) throw new Error(rd.error || 'Registration failed');
|
||
|
||
// Upgrade to test plan via mock-complete
|
||
const up = await fetch('/api/billing/mock-complete', {
|
||
method: 'POST', headers: {'Content-Type':'application/json','Authorization':'Bearer '+token},
|
||
body: JSON.stringify({ plan })
|
||
});
|
||
const upd = await up.json();
|
||
|
||
alert('✓ ' + plan + ' activated!\nEmail: ' + email + '\nAll features unlocked for testing.\n\nLogin at: https://build.inference-x.com');
|
||
window.location.href = '/api/auth/me?token=' + token;
|
||
} catch(e) {
|
||
// Maybe already registered, try login
|
||
try {
|
||
const log = await fetch('/api/auth/login', {
|
||
method: 'POST', headers: {'Content-Type':'application/json'},
|
||
body: JSON.stringify({ email, password })
|
||
});
|
||
const ld = await log.json();
|
||
if (ld.token) {
|
||
const up = await fetch('/api/billing/mock-complete', {
|
||
method: 'POST', headers: {'Content-Type':'application/json','Authorization':'Bearer '+ld.token},
|
||
body: JSON.stringify({ plan })
|
||
});
|
||
alert('✓ Plan ' + plan + ' activated for ' + email);
|
||
} else {
|
||
alert('Error: ' + (ld.error || e.message));
|
||
}
|
||
} catch(e2) {
|
||
alert('Error: ' + e2.message);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ── REVEAL ANIMATIONS ─────────────────────────────
|
||
const observer = new IntersectionObserver(entries => {
|
||
entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('visible'); observer.unobserve(e.target); } });
|
||
}, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });
|
||
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
|
||
|
||
// ── INIT ──────────────────────────────────────────
|
||
loadAll();
|
||
setInterval(loadAll, 20000);
|
||
updateRAM();
|
||
updateExport();
|
||
</script>
|
||
</body>
|
||
</html>
|