Files
sub2api/docs/design-drafts/v2/Docs.html
puro design 3a16b3ecde
Some checks failed
CI / test (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled
docs: archive Claude Design v2 output [CI SKIP]
10 HTML pages + puro.css + HANDOFF.md + 2 images (~810KB total).
Reference artifacts for Stage 3 Vue 3 translation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 18:05:27 +08:00

624 lines
21 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="color-scheme" content="dark">
<title>Docs — PURO AI</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="puro.css">
<style>
.docs-layout {
display: grid;
grid-template-columns: 240px 1fr 220px;
max-width: 1440px;
margin: 0 auto;
gap: 48px;
padding: 40px 32px 80px;
}
/* left nav */
.docs-nav {
position: sticky; top: 32px; align-self: flex-start;
font-size: 13px;
max-height: calc(100vh - 64px);
overflow-y: auto;
}
.docs-nav .brand-line {
padding: 4px 10px 24px;
font-size: 11px;
font-family: var(--font-mono);
color: var(--text-3);
letter-spacing: 0.1em;
text-transform: uppercase;
border-bottom: 1px solid var(--border);
margin-bottom: 18px;
}
.docs-nav .nav-search {
margin-bottom: 18px; position: relative;
}
.docs-nav .nav-search input {
width: 100%; height: 32px;
padding: 0 10px 0 32px;
background: rgba(2, 6, 23, 0.5);
border: 1px solid var(--border);
border-radius: var(--r-sm);
color: var(--text-1); font-size: 12px;
outline: none; font-family: inherit;
}
.docs-nav .nav-search::before {
content: ""; position: absolute; left: 10px; top: 50%;
width: 12px; height: 12px; transform: translateY(-50%);
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='7'/><path d='m20 20-3.5-3.5'/></svg>");
background-repeat: no-repeat;
}
.docs-nav-section {
margin-bottom: 18px;
}
.docs-nav-label {
font-family: var(--font-mono); font-size: 10px;
color: var(--text-3); letter-spacing: 0.14em;
text-transform: uppercase;
padding: 0 10px 8px;
}
.docs-nav-item {
display: block;
padding: 5px 10px;
color: var(--text-2);
border-radius: var(--r-sm);
transition: all .1s;
font-size: 13px;
}
.docs-nav-item:hover { color: var(--text-0); background: rgba(255,255,255,0.02); }
.docs-nav-item.active {
color: var(--cyan);
background: rgba(34, 211, 238, 0.06);
font-weight: 500;
}
/* content */
.docs-body { min-width: 0; }
.docs-crumbs {
font-family: var(--font-mono); font-size: 11px;
color: var(--text-3);
margin-bottom: 14px;
letter-spacing: 0.08em;
}
.docs-crumbs .sep { color: var(--border-2); margin: 0 6px; }
.docs-crumbs .current { color: var(--cyan); }
.docs-body h1 {
font-size: 38px; font-weight: 700;
letter-spacing: -0.02em; margin-bottom: 14px;
}
.docs-body .lede {
font-size: 16px; color: var(--text-2);
line-height: 1.6;
margin-bottom: 32px;
max-width: 640px;
}
.docs-body h2 {
font-size: 22px; font-weight: 700;
letter-spacing: -0.01em;
margin: 44px 0 12px;
padding-top: 14px;
display: flex; align-items: center; gap: 12px;
}
.docs-body h2::before {
content: "";
width: 3px; height: 22px; background: var(--cyan);
border-radius: 2px;
}
.docs-body h3 {
font-size: 16px; font-weight: 600;
margin: 22px 0 8px;
}
.docs-body p {
color: var(--text-1);
line-height: 1.72;
margin-bottom: 14px;
font-size: 14px;
}
.docs-body p code, .docs-body li code, .docs-body td code {
font-family: var(--font-mono);
font-size: 12.5px;
padding: 2px 6px;
background: rgba(2, 6, 23, 0.6);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--cyan);
}
.docs-body ul { margin-bottom: 14px; padding-left: 20px; }
.docs-body li {
color: var(--text-1); line-height: 1.7; font-size: 14px;
margin-bottom: 6px;
}
/* callout */
.callout {
padding: 14px 18px;
border: 1px solid var(--border);
border-left: 3px solid var(--cyan);
border-radius: 0 var(--r-md) var(--r-md) 0;
background: rgba(34, 211, 238, 0.04);
margin: 18px 0;
font-size: 13px;
display: flex; gap: 10px; align-items: flex-start;
}
.callout .icon { color: var(--cyan); flex-shrink: 0; margin-top: 2px; }
.callout.amber { border-left-color: var(--amber); background: rgba(251,191,36,0.04); }
.callout.amber .icon { color: var(--amber); }
/* tabs */
.tabs {
display: flex; gap: 2px;
border-bottom: 1px solid var(--border);
margin-bottom: 0;
}
.tab {
padding: 8px 14px;
font-size: 12px;
font-family: var(--font-mono);
color: var(--text-3);
border-bottom: 2px solid transparent;
margin-bottom: -1px;
cursor: pointer;
transition: all .12s;
}
.tab:hover { color: var(--text-1); }
.tab.active {
color: var(--cyan);
border-bottom-color: var(--cyan);
}
/* code frame in docs */
.code-panel {
border: 1px solid var(--border);
border-radius: var(--r-md);
background: var(--bg-code);
overflow: hidden;
margin-bottom: 18px;
}
.code-panel .panel-tabs {
padding: 0 4px;
background: rgba(15, 23, 42, 0.5);
border-bottom: 1px solid var(--border);
display: flex; align-items: center;
justify-content: space-between;
}
.code-panel .panel-tabs .tabs-inner {
display: flex;
}
.code-panel .panel-tabs .tabs-inner button {
padding: 8px 14px;
font-size: 11px;
font-family: var(--font-mono);
color: var(--text-3);
transition: color .12s;
}
.code-panel .panel-tabs .tabs-inner button.active { color: var(--cyan); }
.code-panel .copy-code {
padding: 6px 12px;
font-size: 11px;
color: var(--text-3);
font-family: var(--font-mono);
border-radius: 4px;
cursor: pointer;
transition: all .12s;
}
.code-panel .copy-code:hover { color: var(--cyan); background: rgba(34,211,238,0.08); }
.code-panel pre {
padding: 16px 20px;
font-family: var(--font-mono);
font-size: 13px;
line-height: 1.75;
color: var(--text-1);
overflow-x: auto;
}
.code-panel pre .com { color: #64748b; font-style: italic; }
.code-panel pre .kw { color: #f472b6; }
.code-panel pre .str { color: #86efac; }
.code-panel pre .fn { color: #fcd34d; }
.code-panel pre .prop { color: #93c5fd; }
.code-panel pre .num { color: #fb923c; }
/* quick start grid */
.quick-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin-bottom: 24px;
}
.quick-card {
padding: 18px 20px;
border: 1px solid var(--border);
border-radius: var(--r-lg);
background: rgba(15, 23, 42, 0.5);
transition: all .15s;
cursor: pointer;
}
.quick-card:hover {
border-color: var(--cyan);
transform: translateY(-2px);
}
.quick-card .num {
font-family: var(--font-mono);
font-size: 11px;
color: var(--cyan);
letter-spacing: 0.14em;
margin-bottom: 10px;
}
.quick-card h4 {
font-size: 14px; font-weight: 600; margin-bottom: 4px;
}
.quick-card p {
font-size: 12px !important; color: var(--text-3) !important;
margin: 0 !important;
}
/* models table */
.models-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 22px;
border: 1px solid var(--border);
border-radius: var(--r-md);
overflow: hidden;
}
.models-table th, .models-table td {
padding: 10px 14px;
text-align: left;
border-bottom: 1px solid var(--border);
font-size: 13px;
}
.models-table th {
background: rgba(2, 6, 23, 0.5);
color: var(--text-3);
font-family: var(--font-mono);
font-size: 10px;
text-transform: uppercase;
letter-spacing: 0.14em;
font-weight: 500;
}
.models-table td { color: var(--text-1); }
.models-table tr:last-child td { border-bottom: none; }
.models-table tr:hover td { background: rgba(255,255,255,0.02); }
.models-table .mono { font-family: var(--font-mono); font-size: 12px; }
/* TOC on right */
.docs-toc {
position: sticky; top: 32px; align-self: flex-start;
font-size: 12px;
}
.docs-toc-label {
font-family: var(--font-mono); font-size: 10px;
color: var(--text-3); letter-spacing: 0.14em;
text-transform: uppercase;
margin-bottom: 10px;
}
.docs-toc a {
display: block;
padding: 4px 10px;
color: var(--text-2);
border-left: 2px solid transparent;
transition: all .1s;
}
.docs-toc a:hover { color: var(--text-0); }
.docs-toc a.active {
color: var(--cyan);
border-left-color: var(--cyan);
background: rgba(34,211,238,0.03);
}
.docs-toc a.sub { padding-left: 20px; font-size: 11.5px; }
/* top nav (reuse landing nav) */
.docs-top {
border-bottom: 1px solid var(--border);
background: rgba(2, 6, 23, 0.7);
backdrop-filter: blur(12px);
position: sticky; top: 0; z-index: 10;
}
/* footer nav */
.page-foot {
margin-top: 64px;
padding-top: 28px;
border-top: 1px solid var(--border);
display: flex; justify-content: space-between;
gap: 16px;
}
.foot-link {
flex: 1;
padding: 14px 18px;
border: 1px solid var(--border);
border-radius: var(--r-md);
background: rgba(15, 23, 42, 0.5);
transition: all .12s;
}
.foot-link:hover { border-color: var(--cyan); }
.foot-link .dir {
font-family: var(--font-mono); font-size: 11px;
color: var(--text-3); margin-bottom: 4px;
}
.foot-link .title { font-size: 14px; font-weight: 600; color: var(--text-0); }
.foot-link.next { text-align: right; }
</style>
</head>
<body>
<div class="bg-glow soft"></div>
<nav class="nav docs-top">
<div class="container nav-inner">
<a class="brand" href="Landing.html">
<svg class="hex" viewBox="0 0 24 24" fill="none">
<path d="M12 2L21 7V17L12 22L3 17V7L12 2Z" stroke="currentColor" stroke-width="1.8" fill="rgba(34, 211, 238, 0.08)"/>
<path d="M12 7L17 9.5V14.5L12 17L7 14.5V9.5L12 7Z" fill="currentColor"/>
</svg>
PURO AI
</a>
<div class="nav-links">
<a href="Landing.html">产品</a>
<a href="Pricing.html">定价</a>
<a href="#" class="active">文档</a>
<a href="Design System.html">设计系统</a>
</div>
<div class="nav-cta">
<a href="Dashboard.html" class="btn btn-ghost">Dashboard</a>
<a href="Register.html" class="btn btn-primary">开始使用</a>
</div>
</div>
</nav>
<div class="docs-layout">
<!-- LEFT NAV -->
<aside class="docs-nav">
<div class="brand-line">// docs · v1</div>
<div class="nav-search">
<input placeholder="搜索文档…">
</div>
<div class="docs-nav-section">
<div class="docs-nav-label">Getting Started</div>
<a class="docs-nav-item active" href="#">快速开始</a>
<a class="docs-nav-item" href="#">产品概念</a>
<a class="docs-nav-item" href="#">绑定你的订阅</a>
<a class="docs-nav-item" href="#">创建 API Key</a>
</div>
<div class="docs-nav-section">
<div class="docs-nav-label">API Reference</div>
<a class="docs-nav-item" href="#">Endpoints 总览</a>
<a class="docs-nav-item" href="#">/v1/chat/completions</a>
<a class="docs-nav-item" href="#">/v1/messages</a>
<a class="docs-nav-item" href="#">/v1/generateContent</a>
<a class="docs-nav-item" href="#">模型列表</a>
<a class="docs-nav-item" href="#">错误码</a>
</div>
<div class="docs-nav-section">
<div class="docs-nav-label">Integrations</div>
<a class="docs-nav-item" href="#">Claude Code</a>
<a class="docs-nav-item" href="#">Cursor · Continue</a>
<a class="docs-nav-item" href="#">Cline · Roo Code</a>
<a class="docs-nav-item" href="#">OpenAI SDK</a>
<a class="docs-nav-item" href="#">Anthropic SDK</a>
</div>
<div class="docs-nav-section">
<div class="docs-nav-label">Advanced</div>
<a class="docs-nav-item" href="#">调度与 failover</a>
<a class="docs-nav-item" href="#">速率限制与配额</a>
<a class="docs-nav-item" href="#">流式响应</a>
<a class="docs-nav-item" href="#">Function Calling</a>
<a class="docs-nav-item" href="#">数据隐私</a>
</div>
</aside>
<!-- MAIN -->
<main class="docs-body">
<div class="docs-crumbs">
Docs <span class="sep">/</span>
Getting Started <span class="sep">/</span>
<span class="current">快速开始</span>
</div>
<h1>快速开始</h1>
<p class="lede">
PURO AI 提供一个统一的 OpenAI 兼容端点 —— 你已有的 SDK 代码只需要改 <code>base_url</code><code>api_key</code> 两行,就能用上你绑定的 Claude / ChatGPT / Gemini 订阅。整个过程通常不超过 5 分钟。
</p>
<!-- quick links -->
<div class="quick-grid">
<div class="quick-card">
<div class="num">STEP 01</div>
<h4>绑定订阅</h4>
<p>授权你的 Claude / ChatGPT 账号加入池。</p>
</div>
<div class="quick-card">
<div class="num">STEP 02</div>
<h4>创建 API Key</h4>
<p>为每个客户端生成独立的 sk-puro-* key。</p>
</div>
<div class="quick-card">
<div class="num">STEP 03</div>
<h4>切换 base_url</h4>
<p>改两行代码,剩下和官方 SDK 一模一样。</p>
</div>
</div>
<h2 id="install">① 绑定你的订阅</h2>
<p>
进入 <code>Dashboard → 订阅账号 → 绑定新订阅</code>,选择平台后通过 OAuth 一键授权。每个订阅都会被加入对应的"池",同一池内的请求会自动做负载均衡、限流回退和故障转移。
</p>
<div class="callout">
<span class="icon">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="11" x="3" y="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
</span>
<div>
凭证通过 AES-256 加密存储在隔离的 KMS 中。我们只会用它代理你发出的请求 —— 不会进入训练数据、不会做二次分发。详见 <a href="#">数据隐私</a>
</div>
</div>
<h2 id="key">② 创建 API Key</h2>
<p>
<code>Dashboard → API Keys → 创建 Key</code> 生成一个 <code>sk-puro-*</code> 的 key。建议每个客户端 / 环境单独一个 key,泄漏时可以直接吊销而不影响其他场景。
</p>
<h2 id="request">③ 发送第一个请求</h2>
<p>PURO AI 同时兼容 OpenAI 和 Anthropic 的 API 格式。按你原来在用的 SDK 风格选择对应的代码示例即可:</p>
<div class="code-panel">
<div class="panel-tabs">
<div class="tabs-inner">
<button class="active">Python</button>
<button>Node.js</button>
<button>cURL</button>
<button>Anthropic SDK</button>
</div>
<span class="copy-code">⧉ 复制</span>
</div>
<pre><span class="com"># pip install openai</span>
<span class="kw">from</span> openai <span class="kw">import</span> OpenAI
client = <span class="fn">OpenAI</span>(
<span class="prop">base_url</span>=<span class="str">"https://ai.puro.im/v1"</span>,
<span class="prop">api_key</span>=<span class="str">"sk-puro-YOUR_KEY"</span>,
)
resp = client.chat.completions.<span class="fn">create</span>(
<span class="prop">model</span>=<span class="str">"claude-sonnet-4-5"</span>, <span class="com"># 可直接写任意平台的模型名</span>
<span class="prop">messages</span>=[
{<span class="prop">"role"</span>: <span class="str">"user"</span>, <span class="prop">"content"</span>: <span class="str">"hi, who am I talking to?"</span>}
],
)
<span class="fn">print</span>(resp.choices[<span class="num">0</span>].message.content)
</pre>
</div>
<p>返回结构完全符合 OpenAI 格式,可以无缝对接任何基于 OpenAI SDK 的应用(Cursor / Continue / Cline / Roo Code / Open WebUI …)。</p>
<h2 id="models">可用模型</h2>
<p>绑定后,下列模型都可以直接用 model 字段调用 —— PURO 会根据模型自动路由到对应的订阅池。</p>
<table class="models-table">
<thead>
<tr>
<th>MODEL</th>
<th>PROVIDER</th>
<th></th>
<th>上下文</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr>
<td class="mono text-cyan">claude-sonnet-4-5</td>
<td><span class="provider claude"><span class="dot"></span>Claude</span></td>
<td>Pro / Max</td>
<td class="mono">200k</td>
<td><span class="badge green">OK</span></td>
</tr>
<tr>
<td class="mono text-cyan">claude-opus-4</td>
<td><span class="provider claude"><span class="dot"></span>Claude</span></td>
<td>Max</td>
<td class="mono">200k</td>
<td><span class="badge green">OK</span></td>
</tr>
<tr>
<td class="mono text-cyan">claude-haiku-4-5</td>
<td><span class="provider claude"><span class="dot"></span>Claude</span></td>
<td>Pro / Max</td>
<td class="mono">200k</td>
<td><span class="badge green">OK</span></td>
</tr>
<tr>
<td class="mono text-cyan">gpt-5</td>
<td><span class="provider gpt"><span class="dot"></span>ChatGPT</span></td>
<td>Plus / Pro</td>
<td class="mono">128k</td>
<td><span class="badge green">OK</span></td>
</tr>
<tr>
<td class="mono text-cyan">gpt-5-codex</td>
<td><span class="provider gpt"><span class="dot"></span>ChatGPT</span></td>
<td>Plus / Pro</td>
<td class="mono">128k</td>
<td><span class="badge green">OK</span></td>
</tr>
<tr>
<td class="mono text-cyan">gemini-2.5-pro</td>
<td><span class="provider gemini"><span class="dot"></span>Gemini</span></td>
<td>Advanced</td>
<td class="mono">1M</td>
<td><span class="badge amber">BETA</span></td>
</tr>
<tr>
<td class="mono text-cyan">gemini-2.5-flash</td>
<td><span class="provider gemini"><span class="dot"></span>Gemini</span></td>
<td>Advanced</td>
<td class="mono">1M</td>
<td><span class="badge green">OK</span></td>
</tr>
</tbody>
</table>
<h2 id="base-urls">支持的 base_url</h2>
<p>每种格式都提供独立的 base_url —— 如果你在用原生 Anthropic / Google SDK,请选择对应格式以获得最完整的字段兼容:</p>
<ul>
<li><code>https://ai.puro.im/v1</code> — OpenAI 兼容格式(推荐,覆盖 95% 场景)</li>
<li><code>https://ai.puro.im/anthropic</code> — Anthropic Messages 格式(原生 Claude SDK)</li>
<li><code>https://ai.puro.im/google</code> — Google GenAI 格式(原生 Gemini SDK)</li>
</ul>
<div class="callout amber">
<span class="icon">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><path d="M12 9v4M12 17h.01"/></svg>
</span>
<div>
一个 <code>sk-puro-*</code> 可以同时用于三种 base_url —— 鉴权和计费是统一的,你不需要为不同 SDK 维护多个 key。
</div>
</div>
<h2 id="next">下一步</h2>
<p>把 PURO 接入到你常用的工具:</p>
<ul>
<li><a href="#"><b>Claude Code</b> 中使用 PURO</a><code>ANTHROPIC_BASE_URL</code> 环境变量一行搞定</li>
<li><a href="#"><b>Cursor</b> 中使用 PURO</a> — 自定义模型 + 自定义 base_url</li>
<li><a href="#"><b>Cline / Roo Code</b> 中使用 PURO</a> — 选择 "OpenAI compatible"</li>
<li><a href="#"><b>Continue</b> 中使用 PURO</a> — config.yaml 添加 provider</li>
</ul>
<!-- pager -->
<div class="page-foot">
<a class="foot-link" href="#">
<div class="dir">← 上一页</div>
<div class="title">产品概念</div>
</a>
<a class="foot-link next" href="#">
<div class="dir">下一页 →</div>
<div class="title">绑定你的订阅</div>
</a>
</div>
</main>
<!-- RIGHT TOC -->
<aside class="docs-toc">
<div class="docs-toc-label">On this page</div>
<a href="#install" class="active">① 绑定订阅</a>
<a href="#key">② 创建 API Key</a>
<a href="#request">③ 第一个请求</a>
<a href="#models">可用模型</a>
<a href="#base-urls">支持的 base_url</a>
<a href="#next">下一步</a>
</aside>
</div>
</body>
</html>