Files

500 lines
30 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{define "about"}}{{if not .Site}}<!doctype html>
<html lang="{{lang}}"><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="{{t "about.meta.description"}}">
{{end}}<title>llmgw</title>
{{if .Site}}<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:wdth,wght@112,600;125,800&family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap">
{{end}}<style>
{{if not .Site}}@font-face{font-family:"Archivo";font-weight:600 800;font-stretch:112% 125%;font-display:swap;src:url("{{asset "fonts/archivo-latin.woff2"}}") format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"Archivo";font-weight:600 800;font-stretch:112% 125%;font-display:swap;src:url("{{asset "fonts/archivo-latin-ext.woff2"}}") format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"IBM Plex Sans";font-weight:100 700;font-display:swap;src:url("{{asset "fonts/plex-sans-latin.woff2"}}") format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"IBM Plex Sans";font-weight:100 700;font-display:swap;src:url("{{asset "fonts/plex-sans-latin-ext.woff2"}}") format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"IBM Plex Mono";font-weight:400;font-display:swap;src:url("{{asset "fonts/plex-mono-400-latin.woff2"}}") format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"IBM Plex Mono";font-weight:400;font-display:swap;src:url("{{asset "fonts/plex-mono-400-latin-ext.woff2"}}") format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"IBM Plex Mono";font-weight:500;font-display:swap;src:url("{{asset "fonts/plex-mono-500-latin.woff2"}}") format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"IBM Plex Mono";font-weight:500;font-display:swap;src:url("{{asset "fonts/plex-mono-500-latin-ext.woff2"}}") format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
{{end}}:root{
--bg:#F3F5F5; --surface:#FFFFFF; --ink:#142023; --muted:#56696C; --line:#D3DCDC;
--fiber:#0B7F7D; --fiber-soft:#DDEFEE; --om1:#C4621A; --om1-soft:#F6E6D9;
--code-bg:#15201F; --code-ink:#DCEAE8; --code-dim:#7F9A97;
--display:"Archivo","Arial Narrow",system-ui,sans-serif;
--body:"IBM Plex Sans",system-ui,-apple-system,"Segoe UI",sans-serif;
--mono:"IBM Plex Mono",ui-monospace,"SFMono-Regular",Menlo,monospace;
}
@media (prefers-color-scheme:dark){
:root:not([data-theme="light"]){
--bg:#0E1617; --surface:#152022; --ink:#E2ECEB; --muted:#8FA5A4; --line:#26383A;
--fiber:#3FC2BC; --fiber-soft:#133634; --om1:#EE9350; --om1-soft:#3A2717;
--code-bg:#0A1011; --code-ink:#D5E5E3; --code-dim:#6E8886;
color-scheme:dark;
}
}
:root[data-theme="dark"]{
--bg:#0E1617; --surface:#152022; --ink:#E2ECEB; --muted:#8FA5A4; --line:#26383A;
--fiber:#3FC2BC; --fiber-soft:#133634; --om1:#EE9350; --om1-soft:#3A2717;
--code-bg:#0A1011; --code-ink:#D5E5E3; --code-dim:#6E8886;
color-scheme:dark;
}
*{box-sizing:border-box}
body{background:var(--bg);color:var(--ink);font:400 16px/1.6 var(--body);margin:0;padding-inline:20px;padding-block:0}
.wrap{max-width:1080px;margin:0 auto}
a{color:var(--fiber);text-underline-offset:3px}
a:focus-visible,button:focus-visible,input:focus-visible+label{outline:2px solid var(--fiber);outline-offset:3px;border-radius:4px}
h1,h2,h3{font-family:var(--display);text-wrap:balance;margin:0}
h2{font-size:clamp(1.6rem,3.2vw,2.1rem);font-variation-settings:"wdth" 112;font-weight:600;letter-spacing:-.01em}
h3{font-size:1.05rem;font-variation-settings:"wdth" 112;font-weight:600}
p{margin:0}
code,pre{font-family:var(--mono);font-size:.875rem}
:not(pre)>code{background:var(--fiber-soft);padding:.1em .35em;border-radius:4px;font-size:.85em}
.eyebrow{font:500 .75rem/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
/* top bar */
.bar{display:flex;align-items:center;justify-content:space-between;gap:16px;padding-block:22px;border-bottom:1px solid var(--line)}
.mark{font:800 1.25rem/1 var(--display);font-variation-settings:"wdth" 125;letter-spacing:-.02em;color:var(--ink);text-decoration:none;display:flex;align-items:center;gap:10px}
.mark svg{flex:none}
.bar nav{display:flex;gap:20px;flex-wrap:wrap;font-size:.9rem}
.bar nav a{color:var(--muted);text-decoration:none}
.bar nav a:hover{color:var(--ink)}
/* hero */
.hero{display:grid;grid-template-columns:1.05fr .95fr;gap:48px;align-items:center;padding-block:64px 56px}
.hero h1{font-size:clamp(2.5rem,6vw,4.4rem);line-height:.98;font-weight:800;font-variation-settings:"wdth" 125;letter-spacing:-.03em}
.hero h1 em{font-style:normal;color:var(--fiber)}
.lede{margin-top:22px;font-size:1.12rem;color:var(--muted);max-width:34em}
.cta{display:flex;flex-wrap:wrap;gap:12px;margin-top:30px}
.btn{display:inline-flex;align-items:center;gap:8px;font:600 .95rem/1 var(--body);padding:13px 18px;border-radius:8px;text-decoration:none;border:1px solid var(--fiber);background:var(--fiber);color:var(--bg)}
.btn.ghost{background:transparent;color:var(--ink);border-color:var(--line)}
.btn.ghost:hover{border-color:var(--ink)}
.oneline{margin-top:26px;display:flex;align-items:center;gap:10px;background:var(--code-bg);color:var(--code-ink);border-radius:8px;padding:12px 12px 12px 16px;max-width:100%}
.oneline code{flex:1;min-width:0;overflow-x:auto;white-space:nowrap;background:none;padding:0;font-size:.9rem;color:var(--code-ink)}
.oneline .p{color:var(--code-dim);user-select:none}
/* schematic */
figure{margin:0}
.schem{background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:18px}
.schem svg{display:block;width:100%;height:auto}
.schem figcaption{margin-top:12px;font-size:.85rem;color:var(--muted)}
.s-label{font:500 11px var(--mono);fill:var(--muted)}
.s-strong{font:600 13px var(--body);fill:var(--ink)}
.s-box{fill:var(--bg);stroke:var(--line)}
.s-gw{fill:var(--fiber-soft);stroke:var(--fiber);stroke-width:1.5}
.s-fab{fill:none;stroke:var(--line);stroke-dasharray:5 4}
.s-link{fill:none;stroke:var(--line);stroke-width:2}
.s-gpu-a{fill:var(--fiber)} .s-gpu-b{fill:var(--om1)}
.s-gpu-idle{fill:var(--line)}
.pulse{fill:var(--fiber)}
.pulse.b{fill:var(--om1)}
@media (prefers-reduced-motion:reduce){.pulse{display:none}}
/* sections */
section{padding-block:56px;border-top:1px solid var(--line)}
.sec-head{display:grid;grid-template-columns:260px 1fr;gap:40px}
.sec-head .intro{color:var(--muted);margin-top:12px;font-size:.95rem}
.facts{display:grid;grid-template-columns:1fr 1fr;gap:28px 40px}
.fact h3{display:flex;gap:10px;align-items:baseline}
.fact h3::before{content:"";width:10px;height:10px;border-radius:2px;background:var(--fiber);flex:none;transform:translateY(-1px)}
.fact p{margin-top:6px;color:var(--muted);font-size:.95rem;max-width:36em}
/* steps */
.steps{list-style:none;margin:0;padding:0;display:grid;gap:28px;counter-reset:s}
.steps li{display:grid;grid-template-columns:44px 1fr;gap:4px 16px;counter-increment:s}
.steps li>*{grid-column:2}
.steps li::before{content:counter(s);grid-column:1;grid-row:span 4;font:800 1.5rem/1.1 var(--display);font-variation-settings:"wdth" 125;color:var(--fiber)}
.steps p{color:var(--muted);font-size:.95rem;max-width:40em}
.code{position:relative;margin-top:10px;background:var(--code-bg);color:var(--code-ink);border-radius:8px;min-width:0}
.code pre{margin:0;padding:16px 18px;overflow-x:auto;line-height:1.55}
.code .c{color:var(--code-dim)}
.copy{position:absolute;top:8px;right:8px;font:500 .75rem/1 var(--body);padding:7px 10px;border-radius:6px;border:1px solid #2d4442;background:#1c2b2a;color:var(--code-ink);cursor:pointer}
.copy:hover{border-color:var(--code-dim)}
/* nodes table in step */
.term{margin-top:10px;background:var(--code-bg);color:var(--code-ink);border-radius:8px;overflow-x:auto}
.term pre{margin:0;padding:14px 18px;font-size:.8rem;line-height:1.6}
.term .ok{color:#6FD3A6}
/* proxy tabs */
.tabs{min-width:0}
.tabs input{position:absolute;opacity:0;pointer-events:none}
.tablist{display:flex;gap:4px;border-bottom:1px solid var(--line)}
.tablist label{cursor:pointer;padding:10px 16px;font:600 .9rem/1 var(--body);color:var(--muted);border-bottom:2px solid transparent;margin-bottom:-1px}
#t-caddy:checked~.tablist label[for="t-caddy"],#t-nginx:checked~.tablist label[for="t-nginx"]{color:var(--ink);border-color:var(--fiber)}
.panel{display:none;margin-top:16px}
#t-caddy:checked~.p-caddy,#t-nginx:checked~.p-nginx{display:block}
.panel .meta{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px 16px;font-size:.88rem;color:var(--muted)}
.panel .code pre{max-height:460px}
.rules{margin-top:28px;display:grid;grid-template-columns:1fr 1fr;gap:18px 32px;padding:0;list-style:none}
.rules li{font-size:.92rem;color:var(--muted);padding-left:16px;border-left:2px solid var(--om1)}
.rules strong{color:var(--ink);font-weight:600;display:block}
/* downloads */
.dl{width:100%;border-collapse:collapse;font-size:.92rem}
.dl-wrap{overflow-x:auto;border:1px solid var(--line);border-radius:10px;background:var(--surface)}
.dl th{text-align:left;font:500 .72rem/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--muted);padding:14px 16px;border-bottom:1px solid var(--line)}
.dl td{padding:12px 16px;border-bottom:1px solid var(--line);vertical-align:top}
.dl tr:last-child td{border-bottom:0}
.dl td:first-child{white-space:nowrap;font-weight:500}
.dl code{background:none;padding:0;font-size:.85rem}
.dl .note{color:var(--muted)}
.ver{display:flex;flex-wrap:wrap;gap:10px 24px;align-items:baseline;margin-bottom:18px}
.tag{font:500 .8rem/1 var(--mono);padding:6px 9px;border-radius:5px;background:var(--fiber-soft);color:var(--fiber)}
/* status */
.status{display:grid;grid-template-columns:1fr 1fr;gap:32px}
.status h3{margin-bottom:10px}
.status ul{margin:0;padding:0;list-style:none;display:grid;gap:10px}
.status li{font-size:.93rem;color:var(--muted);display:grid;grid-template-columns:18px 1fr;gap:8px}
.status li::before{font:600 .9rem/1.6 var(--mono)}
.proven li::before{content:"✓";color:var(--fiber)}
.open li::before{content:"○";color:var(--om1)}
.next{font:500 .66rem/1 var(--mono);letter-spacing:.08em;text-transform:uppercase;padding:4px 6px;border-radius:4px;background:var(--om1-soft);color:var(--om1);white-space:nowrap;align-self:center}
.fab-grid{display:grid;grid-template-columns:1fr;gap:28px;min-width:0}
.term .warn{color:#E9B35A} .term .fail{color:#F07C6C} .term .dim{color:var(--code-dim)}
.watch{display:grid;grid-template-columns:1fr 1fr;gap:18px 32px;padding:0;margin:0;list-style:none}
.watch li{font-size:.92rem;color:var(--muted);padding-left:16px;border-left:2px solid var(--fiber)}
.watch strong{color:var(--ink);font-weight:600;display:block}
.watch code{font-size:.8em}
.order{display:grid;grid-template-columns:repeat(3,1fr);gap:0;border:1px solid var(--line);border-radius:10px;background:var(--surface);overflow:hidden}
.order div{padding:16px 18px;border-right:1px solid var(--line)}
.order div:last-child{border-right:0}
.order b{display:block;font:800 1.4rem/1 var(--display);font-variation-settings:"wdth" 125;color:var(--fiber);margin-bottom:8px}
.order b.x{color:var(--om1)}
.order h3{font-size:.95rem}
.order p{font-size:.88rem;color:var(--muted);margin-top:4px}
footer{border-top:1px solid var(--line);padding-block:28px 40px;display:flex;flex-wrap:wrap;justify-content:space-between;gap:12px;font-size:.85rem;color:var(--muted)}
footer a{color:var(--muted)}
@media (max-width:860px){
.hero{grid-template-columns:1fr;gap:36px;padding-block:44px 40px}
.sec-head{grid-template-columns:1fr;gap:20px}
.facts,.rules,.status,.watch,.order{grid-template-columns:1fr}
.order div{border-right:0;border-bottom:1px solid var(--line)}
.order div:last-child{border-bottom:0}
.bar nav{display:none}
}
</style>
{{if not .Site}}</head><body>{{end}}
<div class="wrap">
<header class="bar">
<a class="mark" href="#top" aria-label="{{t "about.home_label"}}">
<svg width="26" height="26" viewBox="0 0 26 26" aria-hidden="true">
<rect x="1" y="1" width="24" height="24" rx="6" fill="none" stroke="currentColor" stroke-width="2"/>
<path d="M7 9h12M7 13h12M7 17h12" stroke="var(--fiber)" stroke-width="2" stroke-linecap="round"/>
</svg>
llmgw
</a>
<nav aria-label="{{t "about.nav.label"}}">
<a href="#what">{{t "about.nav.what"}}</a>
<a href="#fabrics">{{t "about.nav.fabrics"}}</a>
<a href="#install">{{t "about.nav.install"}}</a>
<a href="#proxy">{{t "about.nav.proxy"}}</a>
<a href="#download">{{t "about.nav.download"}}</a>
<a href="https://gitea.mynodes.xyz/ilker/llmgw">{{t "about.nav.source"}}</a>
{{if not .Site}}<a href="/">{{t "about.nav.gateway"}}</a>{{end}}
</nav>
</header>
<div class="hero" id="top">
<div>
<p class="eyebrow">{{t "about.hero.eyebrow" .Version}}</p>
<h1 style="margin-top:14px">{{th "about.hero.title"}}</h1>
<p class="lede">{{t "about.hero.lede"}}</p>
<div class="cta">
<a class="btn" href="#download">{{t "about.hero.download"}}{{with .Release}} {{.}}{{end}}</a>
<a class="btn ghost" href="https://gitea.mynodes.xyz/ilker/llmgw/src/branch/main/docs/quick-install.md">{{t "about.hero.guide"}}</a>
</div>
<div class="oneline" aria-label="{{t "about.hero.oneline_label"}}">
<code><span class="p">$ </span>sudo llmgw server init --admin you@example.com</code>
<button class="copy" style="position:static" data-copy="sudo llmgw server init --admin you@example.com" type="button">{{t "about.copy"}}</button>
</div>
</div>
<figure class="schem">
<svg viewBox="0 0 440 250" role="img" aria-labelledby="schem-t">
<title id="schem-t">{{t "about.schem.title"}}</title>
<!-- clients -->
<g>
<rect class="s-box" x="4" y="58" width="92" height="30" rx="6"/>
<text class="s-label" x="50" y="77" text-anchor="middle" translate="no">openai sdk</text>
<rect class="s-box" x="4" y="110" width="92" height="30" rx="6"/>
<text class="s-label" x="50" y="129" text-anchor="middle">{{t "about.schem.editor"}}</text>
<rect class="s-box" x="4" y="162" width="92" height="30" rx="6"/>
<text class="s-label" x="50" y="181" text-anchor="middle" translate="no">curl</text>
</g>
<path id="c1" class="s-link" d="M96 73 C130 73 130 118 160 118"/>
<path id="c2" class="s-link" d="M96 125 H160"/>
<path id="c3" class="s-link" d="M96 177 C130 177 130 132 160 132"/>
<!-- gateway -->
<rect class="s-gw" x="160" y="96" width="84" height="58" rx="8"/>
<text class="s-strong" x="202" y="122" text-anchor="middle">llmgw</text>
<text class="s-label" x="202" y="139" text-anchor="middle">:8080</text>
<path id="fa" class="s-link" d="M244 114 C272 114 272 62 300 62"/>
<path id="fb" class="s-link" d="M244 136 C272 136 272 188 300 188"/>
<!-- fabric a -->
<rect class="s-fab" x="300" y="14" width="136" height="98" rx="10"/>
<text class="s-label" x="312" y="32" translate="no">nvl72 · gb200</text>
<g transform="translate(312 42)">
<rect class="s-gpu-a" width="22" height="22" rx="3"/><rect class="s-gpu-a" x="28" width="22" height="22" rx="3"/>
<rect class="s-gpu-a" x="56" width="22" height="22" rx="3"/><rect class="s-gpu-a" x="84" width="22" height="22" rx="3"/>
<rect class="s-gpu-a" y="28" width="22" height="22" rx="3"/><rect class="s-gpu-a" x="28" y="28" width="22" height="22" rx="3"/>
<rect class="s-gpu-idle" x="56" y="28" width="22" height="22" rx="3"/><rect class="s-gpu-idle" x="84" y="28" width="22" height="22" rx="3"/>
</g>
<!-- fabric b -->
<rect class="s-fab" x="300" y="138" width="136" height="98" rx="10"/>
<text class="s-label" x="312" y="156" translate="no">ib-b · h100-80g</text>
<g transform="translate(312 166)">
<rect class="s-gpu-b" width="22" height="22" rx="3"/><rect class="s-gpu-b" x="28" width="22" height="22" rx="3"/>
<rect class="s-gpu-idle" x="56" width="22" height="22" rx="3"/><rect class="s-gpu-idle" x="84" width="22" height="22" rx="3"/>
<rect class="s-gpu-idle" y="28" width="22" height="22" rx="3"/><rect class="s-gpu-idle" x="28" y="28" width="22" height="22" rx="3"/>
<rect class="s-gpu-idle" x="56" y="28" width="22" height="22" rx="3"/><rect class="s-gpu-idle" x="84" y="28" width="22" height="22" rx="3"/>
</g>
<!-- requests in flight -->
<circle class="pulse" r="4"><animateMotion dur="2.4s" repeatCount="indefinite"><mpath href="#c1"/></animateMotion></circle>
<circle class="pulse" r="4"><animateMotion dur="2.4s" begin="0.8s" repeatCount="indefinite"><mpath href="#c2"/></animateMotion></circle>
<circle class="pulse" r="4"><animateMotion dur="2.4s" begin="1.6s" repeatCount="indefinite"><mpath href="#c3"/></animateMotion></circle>
<circle class="pulse" r="4"><animateMotion dur="2.4s" begin="1.2s" repeatCount="indefinite"><mpath href="#fa"/></animateMotion></circle>
<circle class="pulse b" r="4"><animateMotion dur="2.4s" begin="2s" repeatCount="indefinite"><mpath href="#fb"/></animateMotion></circle>
</svg>
<figcaption>{{t "about.schem.caption"}}</figcaption>
</figure>
</div>
<section id="what">
<div class="sec-head">
<div>
<h2>{{t "about.what.title"}}</h2>
<p class="intro">{{t "about.what.intro"}}</p>
</div>
<div class="facts">
<div class="fact"><h3>{{t "about.what.api.title"}}</h3>
<p>{{th "about.what.api.text"}}</p></div>
<div class="fact"><h3>{{t "about.what.placement.title"}}</h3>
<p>{{t "about.what.placement.text"}}</p></div>
<div class="fact"><h3>{{t "about.what.ondemand.title"}}</h3>
<p>{{t "about.what.ondemand.text"}}</p></div>
<div class="fact"><h3>{{t "about.what.keys.title"}}</h3>
<p>{{t "about.what.keys.text"}}</p></div>
<div class="fact"><h3>{{t "about.what.editors.title"}}</h3>
<p>{{t "about.what.editors.text"}}</p></div>
<div class="fact"><h3>{{t "about.what.chat.title"}}</h3>
<p>{{t "about.what.chat.text"}}</p></div>
<div class="fact"><h3>{{t "about.what.mirror.title"}}</h3>
<p>{{t "about.what.mirror.text"}}</p></div>
<div class="fact"><h3>{{t "about.what.engines.title"}}</h3>
<p>{{t "about.what.engines.text"}}</p></div>
<div class="fact"><h3>{{t "about.what.upgrades.title"}}</h3>
<p>{{t "about.what.upgrades.text"}}</p></div>
<div class="fact"><h3>{{t "about.what.dashboard.title"}}</h3>
<p>{{th "about.what.dashboard.text"}}</p></div>
</div>
</div>
</section>
<section id="fabrics">
<div class="sec-head">
<div>
<h2>{{t "about.fabrics.title"}}</h2>
<p class="intro">{{t "about.fabrics.intro"}}</p>
<p class="intro"><a href="https://gitea.mynodes.xyz/ilker/llmgw/src/branch/main/docs/fabrics.md">{{t "about.fabrics.guide"}}</a></p>
</div>
<div class="fab-grid">
<div class="order" aria-label="{{t "about.fabrics.order_label"}}">
<div><b>1</b><h3>{{t "about.fabrics.nvlink.title"}}</h3><p>{{th "about.fabrics.nvlink.text"}}</p></div>
<div><b>2</b><h3>{{t "about.fabrics.ib.title"}}</h3><p>{{t "about.fabrics.ib.text"}}</p></div>
<div><b class="x">×</b><h3>{{t "about.fabrics.never.title"}}</h3><p>{{t "about.fabrics.never.text"}}</p></div>
</div>
<div>
<h3>{{t "about.fabrics.doctor"}}</h3>
<div class="term" aria-label="{{t "about.fabrics.doctor_label"}}"><pre>$ sudo llmgw doctor
<span class="fail">FAIL</span> nvlink this machine has NVSwitch but nvidia-fabricmanager is inactive
<span class="dim">→ systemctl enable --now nvidia-fabricmanager</span>
<span class="warn">WARN</span> fabric nvidia_peermem is not loaded: GPUDirect RDMA is off
<span class="dim">→ modprobe nvidia_peermem</span>
<span class="ok">OK</span> gpu 8 GPUs: 8× NVIDIA H100 80GB HBM3
<span class="ok">OK</span> nvlink NVLink groups: [0 1 2 3 4 5 6 7]
<span class="ok">OK</span> fabric mlx5_0/1 ACTIVE at 400 Gb/s (InfiniBand), subnet manager 0x248a07030030f0c0
<span class="ok">OK</span> fabric subnet managers: 0x…f0c0 (master, priority 15), 0x…f1d4 (standby, priority 14)
<span class="ok">OK</span> agent NCCL bootstraps over ens3 (10.1.0.21)</pre></div>
</div>
<ul class="watch">
<li><strong>{{t "about.fabrics.sm.title"}}</strong>{{t "about.fabrics.sm.text"}}</li>
<li><strong>{{t "about.fabrics.map.title"}}</strong>{{th "about.fabrics.map.text"}}</li>
<li><strong>{{t "about.fabrics.racks.title"}}</strong>{{th "about.fabrics.racks.text"}}</li>
<li><strong>{{t "about.fabrics.ports.title"}}</strong>{{t "about.fabrics.ports.text"}}</li>
</ul>
</div>
</div>
</section>
<section id="install">
<div class="sec-head">
<div>
<h2>{{t "about.install.title"}}</h2>
<p class="intro">{{t "about.install.intro"}}</p>
<p class="intro">{{th "about.install.guide"}}</p>
</div>
<ol class="steps">
<li>
<h3>{{t "about.install.binary.title"}}</h3>
<p>{{t "about.install.binary.text"}}</p>
<div class="code"><button class="copy" type="button">{{t "about.copy"}}</button><pre><code>VERSION={{or .Release "vX.Y.Z"}}{{if not .Release}} <span class="c"># from the releases page</span>{{end}}
U=https://gitea.mynodes.xyz/ilker/llmgw/releases/download/$VERSION
curl -fsSLO $U/llmgw-$VERSION-linux-amd64
curl -fsSL $U/checksums.txt | sha256sum -c --ignore-missing
sudo install -m0755 llmgw-$VERSION-linux-amd64 /usr/local/bin/llmgw</code></pre></div>
</li>
<li>
<h3>{{t "about.install.server.title"}}</h3>
<p>{{th "about.install.server.text"}}</p>
<div class="code"><button class="copy" type="button">{{t "about.copy"}}</button><pre><code>sudo llmgw server init --admin you@example.com</code></pre></div>
</li>
<li>
<h3>{{t "about.install.node.title"}}</h3>
<p>{{t "about.install.node.text"}}</p>
<div class="code"><button class="copy" type="button">{{t "about.copy"}}</button><pre><code>deploy/bootstrap/onboard-node.sh --node gpu01 --addr 10.0.0.141 \
--server https://10.0.0.140:7443 --fabric ib-a:mlx5_0,mlx5_1</code></pre></div>
<div class="term" aria-label="{{t "about.install.node.output_label"}}"><pre>$ llmgw ctl nodes
NODE STATE GPUS MEM CLASSES FABRICS REPLICAS LAST SEEN
gpu01 <span class="ok">ready</span> 8/8 free 503G h100-80g ib-a 0 2s</pre></div>
</li>
<li>
<h3>{{t "about.install.model.title"}}</h3>
<p>{{th "about.install.model.text"}}</p>
<div class="code"><button class="copy" type="button">{{t "about.copy"}}</button><pre><code>llmgw ctl model add -f qwen-coder-3b.yaml
curl https://llm.example.com/v1/chat/completions \
-H "Authorization: Bearer $LLMGW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "coder", "messages": [{"role": "user", "content": "hello"}]}'</code></pre></div>
</li>
</ol>
</div>
</section>
<section id="proxy">
<div class="sec-head">
<div>
<h2>{{t "about.proxy.title"}}</h2>
<p class="intro">{{t "about.proxy.intro"}}</p>
<p class="intro">{{th "about.proxy.loopback"}}</p>
</div>
<div class="tabs">
<input type="radio" name="proxy" id="t-caddy" checked>
<input type="radio" name="proxy" id="t-nginx">
<div class="tablist" role="presentation" translate="no">
<label for="t-caddy">Caddy</label>
<label for="t-nginx">nginx</label>
</div>
<div class="panel p-caddy">
<p class="meta"><span>{{th "about.proxy.caddy"}}</span>
<a href="{{.Download}}/Caddyfile" translate="no">Caddyfile</a></p>
<div class="code"><button class="copy" type="button">{{t "about.copy"}}</button><pre><code>{{.Caddy}}</code></pre></div>
</div>
<div class="panel p-nginx">
<p class="meta"><span>{{th "about.proxy.nginx"}}</span>
<a href="{{.Download}}/nginx.conf" translate="no">nginx.conf</a></p>
<div class="code"><button class="copy" type="button">{{t "about.copy"}}</button><pre><code>{{.Nginx}}</code></pre></div>
</div>
<ul class="rules">
<li><strong>{{t "about.proxy.stream.title"}}</strong>{{t "about.proxy.stream.text"}}</li>
<li><strong>{{t "about.proxy.timeout.title"}}</strong>{{t "about.proxy.timeout.text"}}</li>
<li><strong>{{t "about.proxy.headers.title"}}</strong>{{th "about.proxy.headers.text"}}</li>
<li><strong>{{t "about.proxy.body.title"}}</strong>{{t "about.proxy.body.text"}}</li>
</ul>
</div>
</div>
</section>
<section id="download">
<div class="sec-head">
<div>
<h2>{{t "about.download.title"}}</h2>
<p class="intro">{{th "about.download.intro"}}</p>
</div>
<div>
{{if .Release}}
<div class="ver"><span class="tag">{{.Release}}</span>{{with .Date}}<span class="eyebrow">{{t "about.download.released" .}}</span>{{end}}</div>
<div class="dl-wrap">
<table class="dl">
<thead><tr><th>{{t "about.download.col.for"}}</th><th>{{t "about.download.col.file"}}</th><th>{{t "about.download.col.notes"}}</th></tr></thead>
<tbody>
<tr><td translate="no">Linux x86-64</td><td><a href="{{$.Download}}/llmgw-{{$.Release}}-linux-amd64"><code>llmgw-{{$.Release}}-linux-amd64</code></a></td><td class="note">{{t "about.download.static_any"}}</td></tr>
<tr><td translate="no">Linux ARM64</td><td><a href="{{$.Download}}/llmgw-{{$.Release}}-linux-arm64"><code>llmgw-{{$.Release}}-linux-arm64</code></a></td><td class="note">{{t "about.download.static"}}</td></tr>
<tr><td translate="no">Linux x86-64, NVLink</td><td><a href="{{$.Download}}/llmgw-{{$.Release}}-linux-amd64-nvml"><code>llmgw-{{$.Release}}-linux-amd64-nvml</code></a></td><td class="note">{{t "about.download.nvml"}}</td></tr>
<tr><td>{{t "about.download.mac_arm"}}</td><td><a href="{{$.Download}}/llmgw-{{$.Release}}-darwin-arm64"><code>llmgw-{{$.Release}}-darwin-arm64</code></a></td><td class="note">{{th "about.download.mac_note"}}</td></tr>
<tr><td translate="no">macOS Intel</td><td><a href="{{$.Download}}/llmgw-{{$.Release}}-darwin-amd64"><code>llmgw-{{$.Release}}-darwin-amd64</code></a></td><td class="note"></td></tr>
<tr><td translate="no">Caddy</td><td><a href="{{$.Download}}/Caddyfile"><code>Caddyfile</code></a></td><td class="note">{{t "about.download.proxy_note"}}</td></tr>
<tr><td translate="no">nginx</td><td><a href="{{$.Download}}/nginx.conf"><code>nginx.conf</code></a></td><td class="note">{{t "about.download.proxy_note"}}</td></tr>
<tr><td>{{t "about.download.checksums"}}</td><td><a href="{{$.Download}}/checksums.txt"><code>checksums.txt</code></a></td><td class="note">{{t "about.download.checksums_note"}}</td></tr>
</tbody>
</table>
</div>
{{else}}
<p class="intro" style="margin-top:0">{{th "about.download.dev" .Version}}</p>
{{end}}
</div>
</div>
</section>
<section id="status">
<div class="sec-head">
<div>
<h2>{{t "about.status.title"}}</h2>
<p class="intro">{{t "about.status.intro"}}</p>
</div>
<div class="status">
<div class="proven">
<h3>{{t "about.status.proven"}}</h3>
<ul>
<li>{{t "about.status.proven.single"}}</li>
<li>{{t "about.status.proven.ondemand"}}</li>
<li>{{t "about.status.proven.keys"}}</li>
<li>{{t "about.status.proven.upgrades"}}</li>
<li>{{t "about.status.proven.stores"}}</li>
<li>{{t "about.status.proven.chat"}}</li>
</ul>
</div>
<div class="open">
<h3>{{t "about.status.open"}}</h3>
<ul>
<li>{{th "about.status.open.fabrics"}}</li>
<li>{{t "about.status.open.planes"}}</li>
<li>{{t "about.status.open.weights"}}</li>
</ul>
</div>
</div>
</div>
</section>
<footer>
<span>llmgw {{.Version}}</span>
<span><a href="https://gitea.mynodes.xyz/ilker/llmgw">{{t "about.nav.source"}}</a> ·
<a href="https://gitea.mynodes.xyz/ilker/llmgw/src/branch/main/CHANGELOG.md">{{t "about.footer.changelog"}}</a> ·
<a href="https://gitea.mynodes.xyz/ilker/llmgw/src/branch/main/docs/reference.md">{{t "about.footer.reference"}}</a></span>{{if not .Site}}{{template "langs"}}{{end}}
</footer>
</div>
<script>
var say = { copy: {{t "about.copy"}}, copied: {{t "about.copied"}}, selected: {{t "about.selected"}} };
document.querySelectorAll('.copy').forEach(function (b) {
b.addEventListener('click', function () {
var text = b.dataset.copy || b.parentElement.querySelector('pre').innerText;
var done = function (label) { b.textContent = label; setTimeout(function () { b.textContent = say.copy; }, 1600); };
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function () { done(say.copied); }, function () { select(); });
} else { select(); }
function select() {
var el = b.dataset.copy ? b.parentElement.querySelector('code') : b.parentElement.querySelector('pre');
var r = document.createRange(); r.selectNodeContents(el);
var s = window.getSelection(); s.removeAllRanges(); s.addRange(r);
done(say.selected);
}
});
});
</script>
{{if not .Site}}</body></html>{{end}}{{end}}