| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> |
| <title>Claude2API</title> |
| <style> |
| :root { |
| --bg: #0b0908; |
| --bg-soft: #151210; |
| --panel: rgba(24, 20, 18, 0.82); |
| --panel-strong: rgba(34, 28, 25, 0.92); |
| --line: rgba(241, 231, 220, 0.11); |
| --line-strong: rgba(241, 231, 220, 0.2); |
| --text: #f1e7dc; |
| --muted: #b7a898; |
| --accent: #e3c9a5; |
| --accent-strong: #f3e0c4; |
| --shadow: 0 28px 84px rgba(0, 0, 0, 0.42); |
| --radius: 30px; |
| } |
| |
| * { |
| box-sizing: border-box; |
| } |
| |
| html { |
| color-scheme: dark; |
| } |
| |
| body { |
| margin: 0; |
| min-height: 100vh; |
| color: var(--text); |
| font-family: "Helvetica Neue", "Segoe UI", ui-sans-serif, sans-serif; |
| background: |
| radial-gradient(circle at 14% 12%, rgba(227, 201, 165, 0.14), transparent 24%), |
| radial-gradient(circle at 88% 10%, rgba(140, 98, 59, 0.18), transparent 18%), |
| linear-gradient(180deg, #15110f 0%, var(--bg-soft) 38%, var(--bg) 100%); |
| } |
| |
| body::before { |
| content: ""; |
| position: fixed; |
| inset: 0; |
| pointer-events: none; |
| opacity: 0.08; |
| background-image: linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px); |
| background-size: 100% 3px; |
| mix-blend-mode: soft-light; |
| } |
| |
| a { |
| color: inherit; |
| text-decoration: none; |
| } |
| |
| code, |
| pre { |
| font-family: "JetBrains Mono", "SFMono-Regular", ui-monospace, monospace; |
| } |
| |
| h1, |
| h2 { |
| font-family: "Baskerville", "Times New Roman", Georgia, serif; |
| letter-spacing: -0.04em; |
| } |
| |
| .page { |
| width: min(1080px, calc(100vw - 28px)); |
| margin: 0 auto; |
| padding: 22px 0 34px; |
| } |
| |
| .frame { |
| position: relative; |
| overflow: hidden; |
| border: 1px solid var(--line); |
| border-radius: var(--radius); |
| background: linear-gradient(180deg, rgba(35, 29, 25, 0.94), rgba(19, 16, 14, 0.93)); |
| box-shadow: var(--shadow); |
| backdrop-filter: blur(18px); |
| } |
| |
| .frame::after { |
| content: ""; |
| position: absolute; |
| inset: auto -10% 0; |
| height: 1px; |
| background: linear-gradient(90deg, transparent, rgba(243, 224, 196, 0.22), transparent); |
| } |
| |
| .masthead { |
| display: grid; |
| grid-template-columns: minmax(0, 1.2fr) minmax(280px, 0.8fr); |
| gap: 22px; |
| padding: 32px; |
| } |
| |
| .tag { |
| display: inline-flex; |
| align-items: center; |
| padding: 8px 14px; |
| border-radius: 999px; |
| border: 1px solid rgba(227, 201, 165, 0.16); |
| background: rgba(227, 201, 165, 0.08); |
| color: var(--accent); |
| font-size: 11px; |
| font-weight: 700; |
| letter-spacing: 0.18em; |
| text-transform: uppercase; |
| } |
| |
| h1 { |
| margin: 18px 0 12px; |
| font-size: clamp(3rem, 8vw, 5.6rem); |
| line-height: 0.92; |
| } |
| |
| .lede { |
| max-width: 680px; |
| margin: 0; |
| color: var(--muted); |
| font-size: 1.03rem; |
| line-height: 1.86; |
| } |
| |
| .actions { |
| display: flex; |
| flex-wrap: wrap; |
| gap: 12px; |
| margin-top: 28px; |
| } |
| |
| .button { |
| display: inline-flex; |
| align-items: center; |
| justify-content: center; |
| min-width: 150px; |
| min-height: 46px; |
| padding: 0 18px; |
| border-radius: 999px; |
| border: 1px solid var(--line); |
| background: rgba(255, 255, 255, 0.04); |
| color: var(--text); |
| font-size: 14px; |
| font-weight: 600; |
| transition: |
| transform 0.16s ease, |
| border-color 0.16s ease, |
| background 0.16s ease; |
| } |
| |
| .button:hover { |
| transform: translateY(-1px); |
| border-color: var(--line-strong); |
| } |
| |
| .button.primary { |
| border-color: transparent; |
| background: linear-gradient(135deg, var(--accent-strong), var(--accent)); |
| color: #1a140f; |
| } |
| |
| .rail { |
| display: grid; |
| gap: 12px; |
| align-content: start; |
| } |
| |
| .glance { |
| padding: 18px; |
| border-radius: 22px; |
| border: 1px solid var(--line); |
| background: rgba(255, 255, 255, 0.03); |
| } |
| |
| .glance span { |
| display: block; |
| margin-bottom: 8px; |
| color: var(--muted); |
| font-size: 11px; |
| font-weight: 700; |
| letter-spacing: 0.14em; |
| text-transform: uppercase; |
| } |
| |
| .glance strong { |
| display: block; |
| font-size: 1rem; |
| line-height: 1.65; |
| } |
| |
| .content { |
| display: grid; |
| gap: 18px; |
| margin-top: 18px; |
| } |
| |
| .section { |
| padding: 26px 28px; |
| } |
| |
| .section-head { |
| display: flex; |
| flex-wrap: wrap; |
| align-items: flex-end; |
| justify-content: space-between; |
| gap: 12px; |
| margin-bottom: 18px; |
| } |
| |
| .section-head h2 { |
| margin: 0; |
| font-size: 2rem; |
| } |
| |
| .section-head p, |
| .note, |
| .route p, |
| .aside p { |
| margin: 0; |
| color: var(--muted); |
| line-height: 1.78; |
| } |
| |
| .routes { |
| display: grid; |
| grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); |
| gap: 14px; |
| } |
| |
| .route, |
| .aside { |
| padding: 18px; |
| border-radius: 22px; |
| border: 1px solid var(--line); |
| background: rgba(255, 255, 255, 0.03); |
| } |
| |
| .route h3 { |
| margin: 0 0 10px; |
| font-size: 1.06rem; |
| } |
| |
| .route code, |
| .aside code { |
| color: var(--accent-strong); |
| } |
| |
| .split { |
| display: grid; |
| grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr); |
| gap: 18px; |
| } |
| |
| .code { |
| margin: 0; |
| padding: 18px; |
| overflow: auto; |
| border-radius: 22px; |
| border: 1px solid var(--line); |
| background: #0e0a08; |
| color: #f6ecdf; |
| line-height: 1.72; |
| } |
| |
| .aside-stack { |
| display: grid; |
| gap: 14px; |
| } |
| |
| .note { |
| margin-top: 16px; |
| } |
| |
| @media (max-width: 900px) { |
| .masthead, |
| .split { |
| grid-template-columns: 1fr; |
| } |
| } |
| |
| @media (max-width: 720px) { |
| .page { |
| width: min(100vw - 18px, 1080px); |
| padding-top: 14px; |
| } |
| |
| .masthead, |
| .section { |
| padding: 22px; |
| } |
| |
| h1 { |
| font-size: clamp(2.6rem, 13vw, 4.2rem); |
| } |
| } |
| </style> |
| </head> |
| <body> |
| <main class="page"> |
| <section class="frame masthead"> |
| <div> |
| <div class="tag">Hugging Face wrapper</div> |
| <h1>Claude2API</h1> |
| <p class="lede"> |
| Claude.ai sessions, surfaced as an Anthropic-compatible API. This root page exists to |
| make the Space legible at first glance; the actual admin dashboard, health probe, and |
| API behavior still come from the upstream <code>claude2api</code> runtime. |
| </p> |
| <div class="actions"> |
| <a class="button primary" href="/admin">Open Admin</a> |
| <a class="button" href="/health">Health</a> |
| </div> |
| </div> |
|
|
| <aside class="rail"> |
| <div class="glance"> |
| <span>Root</span> |
| <strong>Static landing page served by the wrapper.</strong> |
| </div> |
| <div class="glance"> |
| <span>Runtime</span> |
| <strong>All non-root routes pass through to the upstream service.</strong> |
| </div> |
| <div class="glance"> |
| <span>Access</span> |
| <strong>Private Space auth and app-level API keys can both apply.</strong> |
| </div> |
| </aside> |
| </section> |
|
|
| <div class="content"> |
| <section class="frame section"> |
| <div class="section-head"> |
| <div> |
| <h2>Where to go</h2> |
| </div> |
| <p> |
| The wrapper fixes the root experience only. It does not replace upstream routing, |
| persistence, or configuration semantics. |
| </p> |
| </div> |
|
|
| <div class="routes"> |
| <article class="route"> |
| <h3><code>/admin</code></h3> |
| <p>Upstream dashboard for accounts, model mapping, proxy settings, and API key changes.</p> |
| </article> |
| <article class="route"> |
| <h3><code>/health</code></h3> |
| <p>Direct passthrough to the upstream health endpoint, kept simple for probes and checks.</p> |
| </article> |
| <article class="route"> |
| <h3><code>/v1/messages</code></h3> |
| <p>Anthropic-compatible request path. Auth and streaming semantics remain upstream-defined.</p> |
| </article> |
| </div> |
| </section> |
|
|
| <section class="frame section"> |
| <div class="section-head"> |
| <div> |
| <h2>Quick request</h2> |
| </div> |
| <p> |
| Use the Space URL as the base URL. If the Space is private, Hugging Face must allow the |
| request before the app can evaluate its own token checks. |
| </p> |
| </div> |
|
|
| <div class="split"> |
| <pre class="code"><code>curl https://YOUR-SPACE.hf.space/v1/messages \ |
| -H "Content-Type: application/json" \ |
| -H "Authorization: Bearer $CLAUDE_API_KEY" \ |
| -d '{ |
| "model": "claude-sonnet-4-6", |
| "max_tokens": 128, |
| "messages": [ |
| {"role": "user", "content": "hello"} |
| ] |
| }'</code></pre> |
|
|
| <div class="aside-stack"> |
| <div class="aside"> |
| <p> |
| Runtime edits made in <code>/admin</code> do not mean Hugging Face Secrets were |
| updated. Treat wrapper config, Secrets, and any upstream persistence layer as |
| separate concerns. |
| </p> |
| </div> |
| <div class="aside"> |
| <p> |
| This page intentionally avoids live status, mutable controls, and any secret-derived |
| values. It is an entrance, not a console. |
| </p> |
| </div> |
| </div> |
| </div> |
|
|
| <p class="note"> |
| For stable persisted settings after restart, rely on upstream-supported storage and verify |
| the behavior explicitly instead of assuming the wrapper can override startup precedence. |
| </p> |
| </section> |
| </div> |
| </main> |
| </body> |
| </html> |
|
|