waygate-open 1.6.14 → 1.6.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/package.json +1 -1
- package/server/dist/api/overview.service.js +9 -0
- package/server/dist/proxy/quota/quota-parse.js +9 -4
- package/server/dist/version.js +1 -1
- package/server/package.json +1 -1
- package/web/dist/assets/{ApiKeysPage-LOAdUyHT.js → ApiKeysPage-Ck0Gry6E.js} +3 -3
- package/web/dist/assets/{ClientMetricTip-D-pXFJpS.js → ClientMetricTip-C2VuiT4-.js} +1 -1
- package/web/dist/assets/ClientsPage-Dy68uQDl.js +1 -0
- package/web/dist/assets/LandingPage-B2hMgbmZ.css +1 -0
- package/web/dist/assets/LandingPage-P2QNDFaP.js +15 -0
- package/web/dist/assets/OverviewPage-BgBo_XhF.js +1 -0
- package/web/dist/assets/RequestsPage-CVB0wpCH.js +5 -0
- package/web/dist/assets/{Select-BxZGnteq.js → Select-G6AhT0TA.js} +1 -1
- package/web/dist/assets/SettingsPage-B4Mew-7b.js +5 -0
- package/web/dist/assets/UsagePage-cxZ-GnpO.js +1 -0
- package/web/dist/assets/index-CEoe20BF.css +1 -0
- package/web/dist/assets/index-nQeRK3kW.js +2 -0
- package/web/dist/assets/sharedWindow-FDfq75PI.js +1 -0
- package/web/dist/index.html +2 -2
- package/web/dist/assets/ClientsPage-D3z8xy1H.js +0 -1
- package/web/dist/assets/LandingPage-BXVLs2Ni.js +0 -15
- package/web/dist/assets/LandingPage-DIP_XFhP.css +0 -1
- package/web/dist/assets/OverviewPage-xTsnlyEP.js +0 -1
- package/web/dist/assets/RequestsPage-B2ThbdoO.js +0 -5
- package/web/dist/assets/SettingsPage-CfuPWZ4_.js +0 -3
- package/web/dist/assets/UsagePage-UatftkHb.js +0 -1
- package/web/dist/assets/index-BtuqaoxX.css +0 -1
- package/web/dist/assets/index-VH6Gc3-s.js +0 -2
package/web/dist/index.html
CHANGED
|
@@ -56,9 +56,9 @@
|
|
|
56
56
|
}
|
|
57
57
|
})();
|
|
58
58
|
</script>
|
|
59
|
-
<script type="module" crossorigin src="./assets/index-
|
|
59
|
+
<script type="module" crossorigin src="./assets/index-nQeRK3kW.js"></script>
|
|
60
60
|
<link rel="modulepreload" crossorigin href="./assets/vendor-befEYGHM.js">
|
|
61
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
61
|
+
<link rel="stylesheet" crossorigin href="./assets/index-CEoe20BF.css">
|
|
62
62
|
</head>
|
|
63
63
|
<body>
|
|
64
64
|
<div id="root"></div>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{H as e,I as t,J as n,L as r,Q as i,S as a,U as o,a as s,it as c,m as l,n as u,tt as d,z as f}from"./vendor-befEYGHM.js";import{M as p,_ as m,f as h,h as g,i as _,j as v,k as y,n as b,s as x,t as S}from"./index-VH6Gc3-s.js";import{a as C,c as w,n as T,r as E,s as D,t as O}from"./Select-BxZGnteq.js";import{t as k}from"./Modal-B-rIrvXS.js";import{t as A}from"./PageSkeleton-DG-Dj4_9.js";import{t as j}from"./Drawer-CleQGhRU.js";import{t as M}from"./Switch-0KA1AbiV.js";var N=c(),P=d();function F({rows:e,byProvider:t,busyId:n,onEdit:r,onModels:a,onSignin:o,onGrowthRun:c,onOauthImport:d,onActivate:f,onDeactivate:p,onDelete:v}){let y=()=>new Intl.DateTimeFormat(`en-CA`,{timeZone:`Asia/Shanghai`,year:`numeric`,month:`2-digit`,day:`2-digit`}).format(new Date),b=new Map((t??[]).map(e=>[e.providerId??``,e]));return(0,P.jsx)(`div`,{className:`tbl-scroll`,children:(0,P.jsxs)(`table`,{className:`tbl`,children:[(0,P.jsxs)(`caption`,{className:`sr-only`,children:[`提供商列表,共 `,e.length,` 家提供商`]}),(0,P.jsx)(`thead`,{children:(0,P.jsxs)(`tr`,{children:[(0,P.jsx)(`th`,{scope:`col`,children:`提供商`}),(0,P.jsx)(`th`,{scope:`col`,children:`密钥`}),(0,P.jsx)(`th`,{scope:`col`,className:`r`,children:`请求次数`}),(0,P.jsx)(`th`,{scope:`col`,className:`r`,children:`消耗积分`}),(0,P.jsx)(`th`,{scope:`col`,className:`r`,children:`最后活跃`}),(0,P.jsx)(`th`,{scope:`col`,className:`r`,children:`操作`})]})}),(0,P.jsx)(`tbody`,{children:e.map(t=>{let x=n===t.id;return(0,P.jsxs)(`tr`,{className:`prov-row`,children:[(0,P.jsxs)(`td`,{className:`td-strong`,children:[t.name,t.active?(0,P.jsx)(w,{tone:`live`,children:`已启用`}):(0,P.jsx)(w,{tone:`ghost`,children:`未启用`}),t.protocol===`anthropic`?(0,P.jsx)(_,{content:`Anthropic Messages 方言(mavis 网关):模型目录用内置清单,凭证为 refresh token 自动换新`,children:(0,P.jsx)(`span`,{className:`pill pill-ghost`,children:`Anthropic`})}):t.protocol===`qoder`?(0,P.jsx)(_,{content:`Qoder CN 网关(COSY 协议):免费档 billable:false 实扣 0;目录从网关 /model/list 拉取;凭证为客户端身份 JSON(不自动刷新)`,children:(0,P.jsx)(`span`,{className:`pill pill-ghost`,children:`Qoder`})}):null,(0,P.jsx)(`div`,{className:`td-sub td-mono`,children:(0,P.jsx)(_,{content:(0,P.jsx)(P.Fragment,{children:(0,P.jsxs)(`div`,{className:`client-model-tip`,children:[(0,P.jsxs)(`div`,{className:`client-model-tip-head`,children:[(0,P.jsxs)(`div`,{className:`client-model-tip-title`,children:[(0,P.jsx)(`strong`,{children:t.name}),(0,P.jsx)(`span`,{children:t.baseUrl})]}),(0,P.jsx)(`span`,{className:`client-model-tip-tag`,children:t.active?`已启用`:`未启用`})]}),(0,P.jsxs)(`div`,{className:`client-model-tip-summary`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`span`,{children:`模型总数`}),(0,P.jsx)(`b`,{children:g(t.modelCount??0)})]}),(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`span`,{children:`已启用`}),(0,P.jsx)(`b`,{children:g(t.modelEnabled??0)})]})]}),t.credits?.available?(0,P.jsxs)(`div`,{className:`client-metric-tip-total`,children:[(0,P.jsx)(`span`,{children:`剩余积分`}),(0,P.jsxs)(`b`,{children:[h(t.credits.remaining??0),` `,(0,P.jsxs)(`em`,{children:[`已用 `,h(t.credits.consumed??0)]})]})]}):null,t.credits?.stale?(0,P.jsx)(`div`,{className:`client-model-tip-note`,children:`⚠ 积分数据偏旧(账本快照超时)`}):null]})}),children:(0,P.jsxs)(`span`,{className:`prov-model-count`,children:[g(t.modelCount??0),` 个模型`]})})})]}),(0,P.jsxs)(`td`,{className:`td-cred`,children:[(0,P.jsx)(_,{content:`供应商访问密钥(掩码显示;全量只存在服务器上)`,children:(0,P.jsx)(`span`,{className:`cred-mask`,children:t.credentialMask})}),(0,P.jsx)(`span`,{className:`up-badge${t.configured?``:` warn`}`,children:t.configured?`有效`:`未配置`})]}),(0,P.jsx)(`td`,{className:`r td-mono`,children:t.active?g(b.get(t.id)?.requests??0):`—`}),(0,P.jsx)(`td`,{className:`r td-mono`,children:t.active?h(b.get(t.id)?.credits??0):`—`}),(0,P.jsx)(`td`,{className:`r td-mono`,children:t.active?m(b.get(t.id)?.lastSeenAt??null):`—`}),(0,P.jsx)(`td`,{className:`r`,children:(0,P.jsxs)(`span`,{className:`prov-row-actions`,children:[(0,P.jsx)(_,{content:`改名称与上游地址;凭证可在抽屉内「重新导入授权」`,children:(0,P.jsxs)(`button`,{type:`button`,className:`mini-pill`,disabled:x,onClick:()=>r(t),children:[(0,P.jsx)(u,{size:12}),`配置`]})}),(0,P.jsx)(_,{content:`查看这家自己的模型清单(启停只作用于该提供商分区)`,children:(0,P.jsxs)(`button`,{type:`button`,className:`mini-pill`,"aria-disabled":x||!t.active,onClick:()=>{!x&&t.active&&a(t)},children:[(0,P.jsx)(l,{size:12}),`模型列表`]})}),t.credKind===`oauth_minimax`||t.protocol===`qoder`?(0,P.jsx)(_,{content:(()=>{let e=t.protocol===`qoder`?`10:05`:`08:05`,n=t.signin?.checkedOn?`最近签到 ${t.signin.checkedOn}${t.signin.lastPoints?` · +${t.signin.lastPoints} 积分`:``}(relay 每天 ${e} 自动签)`:`今天还没签到 —— 点一下立即签(relay 每天 ${e} 也会自动签)`;return t.protocol===`qoder`?(0,P.jsxs)(P.Fragment,{children:[n,(0,P.jsx)(`br`,{}),`Qoder 官方标注:每日 10:00(UTC+8)刷新,领取后 30 天有效。`]}):n})(),children:(0,P.jsxs)(`button`,{type:`button`,className:`mini-pill`,"aria-disabled":x||t.signin?.checkedOn===y(),onClick:()=>{x||t.signin?.checkedOn===y()||o(t)},children:[(0,P.jsx)(i,{size:12}),t.signin?.checkedOn===y()?`已签到`:`签到`]})}):null,t.protocol===`openai`?t.wbOAuth?.configured?(0,P.jsx)(_,{content:t.wbSignin?.checkedOn===y()?`今天已签到过(明天 08:05 自动跑;任务面板在设置 → 提供商健康)`:`立即签到 + 顺带跑一轮成长任务与连登兑换(每天 08:05 也会自动跑)。转发不受影响。`,children:(0,P.jsxs)(`button`,{type:`button`,className:`mini-pill`,"aria-disabled":x||t.wbSignin?.checkedOn===y(),onClick:()=>{!x&&t.wbSignin?.checkedOn!==y()&&c(t)},children:[(0,P.jsx)(i,{size:12}),t.wbSignin?.checkedOn===y()?`已签到`:`签到`]})}):(0,P.jsx)(_,{content:`导入桌面端 OAuth 凭证后可代领签到/任务(上游不允许 API 密钥代领)。粘贴 tools/wb-oauth-export.mjs 的输出;转发仍走 API 密钥。`,children:(0,P.jsxs)(`button`,{type:`button`,className:`mini-pill`,"aria-disabled":x,onClick:()=>{x||d(t)},children:[(0,P.jsx)(i,{size:12}),`导入OAuth`]})}):null,t.active?(0,P.jsx)(_,{content:`退出出站路由(目录与凭证保留,可再启用)`,children:(0,P.jsx)(`button`,{type:`button`,className:`mini-pill`,"aria-disabled":x,onClick:()=>{x||p(t)},children:`停用`})}):(0,P.jsx)(`button`,{type:`button`,className:`mini-pill`,disabled:x,onClick:()=>f(t),children:`启用`}),(0,P.jsx)(_,{content:t.active?`不能删除已启用的提供商 —— 先停用它`:e.length<=1?`至少保留一个提供商`:`删除这个提供商(凭证文件一并删除)`,children:(0,P.jsxs)(`button`,{type:`button`,className:`mini-pill danger`,"aria-disabled":x||t.active||e.length<=1,onClick:()=>{!x&&!t.active&&e.length>1&&v(t)},children:[(0,P.jsx)(s,{size:12}),`删除`]})})]})})]},t.id)})})]})})}function I({command:e}){let[t,r]=(0,N.useState)(!1);if(!e)return null;let i=async()=>{try{await navigator.clipboard.writeText(e),r(!0),setTimeout(()=>r(!1),2e3)}catch{r(!1)}};return(0,P.jsxs)(`div`,{className:`cred-guide-cmd`,children:[(0,P.jsx)(`code`,{children:e}),(0,P.jsxs)(`button`,{type:`button`,className:`copy`,"aria-label":t?`已复制命令`:`复制命令`,onClick:()=>void i(),children:[t?(0,P.jsx)(n,{size:13}):(0,P.jsx)(f,{size:13}),t?`已复制`:`复制`]})]})}var L=[{protocol:`openai`,label:`WorkBuddy`,desc:`OpenAI 方言`,needsAuth:!0},{protocol:`anthropic`,label:`MiniMax Code`,desc:`Anthropic 方言`,needsAuth:!0},{protocol:`qoder`,label:`Qoder CN`,desc:`COSY 协议`,needsAuth:!0}],R={openai:`https://copilot.tencent.com`,anthropic:`https://agent.minimax.cn`,qoder:`https://gateway.qoder.com.cn`},z=2500,B=3e5;function V({provider:e,onClose:n,onImported:r}){let i=S(),[o,s]=(0,N.useState)(e?`confirm`:`pick`),[c,l]=(0,N.useState)(e?.protocol??`anthropic`),[u,d]=(0,N.useState)(e?.name??``),[f,m]=(0,N.useState)(``),[h,g]=(0,N.useState)(``),[_,v]=(0,N.useState)(!1),[y,C]=(0,N.useState)(null),w=(0,N.useRef)(e?.id??null),T=(0,N.useRef)(!1),D=(0,N.useRef)(!1),O=L.find(e=>e.protocol===c);(0,N.useEffect)(()=>()=>{D.current=!0;let e=w.current;e&&x.providerImportDeviceCancel(e).catch(()=>void 0)},[]);let A=(0,N.useCallback)(async()=>{v(!0),C(null);try{let e=w.current;e||(e=(await x.createProvider({name:u.trim()||O.label,baseUrl:R[c]??R.openai,credential:``,protocol:c})).item.id,w.current=e,T.current=!0);let t=await x.providerImportDeviceStart(e);if(!t.ok||!t.authUrl){C(new p(t.message??`申请授权失败`,0,0)),s(`confirm`),v(!1);return}m(t.authUrl),g(t.userCode??``),window.open(t.authUrl,`_blank`,`noopener`),s(`waiting`),v(!1);let n=Date.now()+B;for(;!D.current&&Date.now()<n;){if(await new Promise(e=>setTimeout(e,z)),D.current)return;let t=await x.providerImportDevicePoll(e);if(D.current)return;if(t.status===`done`){s(`done`),i.push({tone:`success`,message:`${u.trim()||O.label} 授权已导入。`}),r();return}if(t.status===`error`){C(new p(t.message??`授权失败`,0,0)),s(`confirm`);return}}D.current||(C(new p(`授权超时(5 分钟)—— 请重新发起导入。`,0,0)),s(`confirm`))}catch(e){C(e instanceof p?e:new p(String(e),0,0)),s(`confirm`),v(!1)}},[O.label,u,r,c,i]);if(o===`done`)return(0,P.jsxs)(k,{title:`授权已导入`,onClose:n,footer:(0,P.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,onClick:n,children:`完成`}),children:[(0,P.jsx)(b,{tone:`success`,children:(0,P.jsxs)(`span`,{children:[u.trim()||O.label,` 的授权已通过官方通道导入。`]})}),e?null:(0,P.jsxs)(`p`,{className:`ov-sub`,style:{marginTop:12},children:[`回到列表点`,(0,P.jsx)(`b`,{children:`试通`}),`确认可用,再按需启用(启用后它才参与出站路由)。`]})]});if(o===`waiting`)return(0,P.jsx)(k,{title:`等待你完成授权`,onClose:n,children:(0,P.jsxs)(`div`,{className:`cred-guide`,children:[(0,P.jsxs)(`div`,{className:`cred-guide-note`,children:[`已为你打开 `,(0,P.jsx)(`b`,{children:O.label}),` 的授权页 —— `,(0,P.jsx)(`b`,{children:`请在浏览器里完成授权`}),`, 本窗口会自动检测结果,无需回到终端。`]}),h?(0,P.jsxs)(`div`,{className:`cred-guide-note`,children:[`若页面要求输入短码:`,(0,P.jsx)(`span`,{className:`code-chip`,children:h})]}):null,(0,P.jsx)(I,{command:f}),(0,P.jsxs)(`div`,{className:`cred-guide-note`,style:{display:`flex`,alignItems:`center`,gap:8},children:[(0,P.jsx)(a,{size:14}),`正在等待授权完成…(最多 5 分钟;没弹出浏览器就点上面的链接)`]}),y?(0,P.jsx)(b,{tone:`error`,children:E(y)}):null]})});let j=o===`confirm`;return(0,P.jsx)(k,{title:e?`重新导入授权 · ${e.name}`:`导入客户端`,onClose:n,footer:(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:n,children:`取消`}),(0,P.jsxs)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,disabled:_,onClick:()=>{if(!j){s(`confirm`);return}A()},children:[_?(0,P.jsx)(a,{size:14}):(0,P.jsx)(t,{size:14}),_?`正在申请授权…`:j?`确定,前往授权页`:`导入`]})]}),children:j?(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(b,{tone:`warn`,children:(0,P.jsxs)(`span`,{children:[`即将跳转至 `,(0,P.jsx)(`b`,{children:O.label}),` 的授权页面(`,(0,P.jsx)(`b`,{children:`新标签页`}),`)。 请在页面里登录并完成授权,授权完成后本窗口会自动检测。`]})}),(0,P.jsxs)(`div`,{className:`cred-guide-note`,style:{marginTop:12},children:[`授权只用于取本工具的凭证;令牌保存在`,(0,P.jsx)(`b`,{children:`本机服务端`}),`(0600),不会回传到浏览器。`]}),c===`anthropic`?(0,P.jsxs)(`div`,{className:`cred-guide-note`,style:{marginTop:8},children:[`⚠️ MiniMax 的凭证是`,(0,P.jsx)(`b`,{children:`同账号单会话`}),`:请用`,(0,P.jsx)(`b`,{children:`专用账号`}),`, 否则会与日常客户端互相顶下线。`]}):null,y?(0,P.jsx)(b,{tone:`error`,children:E(y)}):null]}):(0,P.jsxs)(P.Fragment,{children:[(0,P.jsxs)(`p`,{className:`ov-sub`,children:[`选一个客户端,用它的`,(0,P.jsx)(`b`,{children:`官方授权`}),`拿到凭证(凭证在客户端登录态里,用户拿不到、无需手填)。`]}),(0,P.jsxs)(`div`,{className:`ov-field`,children:[(0,P.jsx)(`label`,{children:`客户端类型`}),(0,P.jsx)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:6},children:L.map(e=>(0,P.jsxs)(`label`,{style:{display:`flex`,alignItems:`center`,gap:8,cursor:`pointer`},children:[(0,P.jsx)(`input`,{type:`radio`,name:`import-client`,checked:c===e.protocol,onChange:()=>l(e.protocol)}),(0,P.jsxs)(`span`,{children:[(0,P.jsx)(`b`,{children:e.label}),(0,P.jsx)(`span`,{className:`ov-hint`,style:{marginLeft:8},children:e.desc})]})]},e.protocol))})]}),(0,P.jsxs)(`div`,{className:`ov-field`,children:[(0,P.jsx)(`label`,{htmlFor:`imp-name`,children:`名称(可留空)`}),(0,P.jsx)(`input`,{id:`imp-name`,className:`field-input text`,style:{width:`100%`},value:u,placeholder:O.label,onChange:e=>d(e.target.value)})]})]})})}var H={upstream:`上游`,seed:`种子`,manual:`手工`},U={upstream:`从上游模型目录拉取到的`,seed:`来自本地种子清单(上游拉取失败时的回落)`,manual:`人工添加的`};function W({catalog:t,catalogLoading:n,catalogMsg:r,catalogError:i,onCatalogRefresh:s,onCatalogReload:c,onModelToggled:u}){let[d,f]=(0,N.useState)(null),p=async e=>{f(e.id);try{await u(e.id,!e.enabled)}finally{f(null)}};return(0,P.jsxs)(`div`,{className:`up-col`,children:[(0,P.jsxs)(`div`,{className:`up-models-head`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`b`,{children:`可用模型`}),(0,P.jsx)(`span`,{children:t?`${t.models.length} 个 · ${t.models.filter(e=>e.enabled).length} 个已启用`:`尚未获取`})]}),(0,P.jsx)(`div`,{className:`up-models-actions`,children:n?(0,P.jsxs)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,disabled:!0,children:[(0,P.jsx)(a,{size:14,className:`spin`,style:{animation:`spin 1s linear infinite`}}),`正在实测模型…`]}):(0,P.jsxs)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:s,children:[(0,P.jsx)(l,{size:14}),`获取模型`]})})]}),n?(0,P.jsxs)(`div`,{className:`up-progress`,role:`status`,children:[(0,P.jsx)(a,{size:14,className:`spin`,style:{animation:`spin 1s linear infinite`},"aria-hidden":!0}),(0,P.jsxs)(`span`,{children:[`正在逐个实测模型(每个 1 token)…这一步会真打上游,`,(0,P.jsx)(`b`,{children:`可能要几十秒`}),`,请不要关掉页面; 完成后结果会出现在这里,模型清单也会自动刷新。`]})]}):null,r?(0,P.jsx)(b,{tone:r.kind===`error`?`error`:r.kind===`partial`?`warn`:`success`,children:r.text}):null,i?(0,P.jsx)(T,{kind:`error`,title:`模型清单没拉到`,detail:E(i),onRetry:c}):n&&!t?(0,P.jsx)(T,{kind:`loading`,title:`正在向上游获取模型…`}):!t||t.models.length===0?(0,P.jsx)(T,{kind:`empty`,title:`还没有模型清单`,detail:`启用提供商后会自动同步一次它自己的模型清单;这里也可以手动点「获取模型」逐项实测是否真的能调通。`}):(0,P.jsx)(`div`,{className:`up-models`,children:t.models.map(t=>(0,P.jsxs)(`div`,{className:`up-model${t.enabled?``:` off`}`,children:[(0,P.jsxs)(`div`,{className:`um-info`,children:[(0,P.jsxs)(`b`,{children:[(0,P.jsx)(`span`,{className:`um-k`,children:`模型名:`}),t.displayName,(0,P.jsx)(_,{content:U[t.source],children:(0,P.jsx)(`span`,{className:`um-src src-${t.source}`,children:H[t.source]})}),t.tag?(0,P.jsx)(_,{content:`上游计价标签,随目录同步更新`,children:(0,P.jsx)(`span`,{className:`mu-tag`,children:t.tag})}):null]}),(0,P.jsxs)(`i`,{className:`code-chip`,children:[(0,P.jsx)(`span`,{className:`um-k`,children:`模型ID:`}),t.id]})]}),(0,P.jsxs)(`div`,{className:`um-meta`,children:[t.verified?(0,P.jsx)(_,{content:`实测可调通`,children:(0,P.jsxs)(`span`,{className:`um-ok`,children:[(0,P.jsx)(o,{size:12}),`可用`]})}):(0,P.jsx)(_,{content:`实测未通过(可能未订阅)`,children:(0,P.jsxs)(`span`,{className:`um-bad`,children:[(0,P.jsx)(e,{size:12}),`未通过`]})}),t.multiplier==null?(0,P.jsx)(_,{content:`接口与本地快照都没有该模型的倍率 —— 不编造`,children:(0,P.jsx)(`span`,{className:`um-mult unknown`,children:`倍率未知`})}):(0,P.jsx)(_,{content:t.source===`upstream`?`倍率取自上游 /v3/config 接口实时值,随目录刷新与每日同步更新。`:`接口未覆盖该模型,倍率为内置快照,可能随官方调价过期。`,children:(0,P.jsxs)(`span`,{className:`um-mult`,children:[`×`,t.multiplier]})}),(0,P.jsx)(M,{checked:t.enabled,disabled:d===t.id,label:`${t.enabled?`停用`:`启用`} ${t.displayName}`,onChange:()=>void p(t)})]})]},t.id))}),(0,P.jsxs)(`div`,{className:`up-foot`,children:[`实测会真打上游、消耗少量积分(每模型 1 token)。上游不接受的模型会标「未通过」, 但`,(0,P.jsx)(`b`,{children:`不删除`}),` —— 订阅以后可能又开,随时可以再拉一次。 倍率以 /v3/config 接口实时值为准(目录刷新与每日自动同步都会更新), 接口未覆盖的模型回落内置快照。`,(0,P.jsx)(`br`,{}),`启用提供商时会同步这家自己的清单;已有提供商的目录互不覆盖,启用/停用选择也分别保留。`]})]})}function G({window:e}){let t=v(()=>x.providers(),[],{cacheKey:`providers`}),[n,i]=(0,N.useState)(null),o=v(()=>x.catalog(n?.id),[n?.id],{cacheKey:n?.id?`catalog:${n.id}`:`catalog`}),s=v(()=>x.clients(e),[e],{cacheKey:`clients:${e}`}),[c,l]=(0,N.useState)(!1),[u,d]=(0,N.useState)(null),[f,m]=(0,N.useState)(null),[h,g]=(0,N.useState)(null),[y,D]=(0,N.useState)(null),[O,M]=(0,N.useState)(null),[I,L]=(0,N.useState)(null),[R,z]=(0,N.useState)(!1),B=S(),H=t.data?.items??[],U=s.data?.byProvider??[],G=()=>{t.reload(),o.reload(),s.reload()},q=async e=>{m(e.id),M(null);try{await x.activateProvider(e.id),L(null),G()}catch(e){M(e instanceof p?e:new p(String(e),0,0))}finally{m(null)}},J=async e=>{m(e.id),M(null);try{await x.deactivateProvider(e.id),G()}catch(e){M(e instanceof p?e:new p(String(e),0,0))}finally{m(null)}},Y=async e=>{m(e.id),M(null);try{let n=await x.providerSigninNow(e.id);L({kind:n.ok?`ok`:`error`,text:n.message}),n.ok?B.push(n.outcome===`none`?{tone:`info`,message:`${e.name}:${n.message}`}:{tone:`success`,message:`${e.name} 签到成功${n.points?` · +${n.points} 积分`:``}。`}):B.push({tone:`error`,message:`${e.name} 签到失败:${n.message}`}),t.reload()}catch(t){let n=t instanceof p?t:new p(String(t),0,0);M(n),B.push({tone:`error`,message:`${e.name} 签到失败:${n.message||`请求未完成`}`})}finally{m(null)}},X=async e=>{m(e.id),M(null);try{let n=await x.providerGrowthRun(e.id),r=n.tasks?.filter(e=>e.outcome===`claimed`).length??0,i=n.tasks?.filter(e=>e.outcome===`already`).length??0,a=n.tasks?.filter(e=>e.outcome===`skipped`).length??0,o=n.ok?`领取完成:签到 ${n.signin?.points??0} 积分;任务新领 ${r}、已领过 ${i}、待完成 ${a};本轮合计 +${n.creditsGained??0}。`:n.message??`领取失败。`;L({kind:n.ok?`ok`:`error`,text:o}),B.push(n.ok?{tone:`success`,message:`${e.name}:${o}`}:{tone:`error`,message:`${e.name} 领取失败:${n.message??`未知原因`}`}),t.reload()}catch(t){let n=t instanceof p?t:new p(String(t),0,0);M(n),B.push({tone:`error`,message:`${e.name} 领取失败:${n.message||`请求未完成`}`})}finally{m(null)}},Z=async e=>{let n=globalThis.prompt?.(`粘贴 WorkBuddy OAuth 凭证 JSON(tools/wb-oauth-export.mjs 的输出):`,``)??null;if(!n)return;let r;try{r=JSON.parse(n)}catch{L({kind:`error`,text:`不是合法 JSON —— 请完整复制导出文件内容。`});return}m(e.id),M(null);try{let n=await x.providerOauthImport(e.id,r);L({kind:n.ok?`ok`:`error`,text:n.message}),t.reload()}catch(e){M(e instanceof p?e:new p(String(e),0,0))}finally{m(null)}},Q=async()=>{if(!y||f)return;let e=y;m(e.id),M(null);try{await x.deleteProvider(e.id),D(null),G()}catch(e){M(e instanceof p?e:new p(String(e),0,0)),D(null)}finally{m(null)}},ee=async()=>{if(!R){z(!0),L(null),M(null);try{let e=await x.refreshCatalog(),r=e.configPulled===!1?` 倍率未从接口取到,沿用本地快照。`:e.multipliersUpdated?` 倍率已按接口同步(${e.multipliersUpdated} 项有更新)。`:``,i=e.perProvider?.find(e=>e.id===n?.id),a=i?.checked??e.checked,s=i?.ok??e.ok,c=i?.failed.length??e.failed.length;L(c>0?{kind:`partial`,text:`已实测 ${a} 个模型:${s} 个可用、${c} 个未通过(可能未订阅)。未通过的不会删除,订阅后可再拉一次。${r}`}:{kind:`ok`,text:`已实测 ${a} 个模型,全部可用。${r}`}),o.reload(),t.reload()}catch(e){let t=e instanceof p?e:new p(String(e),0,0);L({kind:`error`,text:`获取模型失败:${E(t)}`})}finally{z(!1)}}},te=async(e,t)=>{M(null);try{await x.setModelEnabled(e,t,n?.id),o.reload()}catch(e){M(e instanceof p?e:new p(String(e),0,0))}},$=H.filter(e=>e.active).length;return(0,P.jsxs)(P.Fragment,{children:[O?(0,P.jsx)(b,{tone:`error`,children:E(O)}):null,s.error?(0,P.jsxs)(b,{tone:`error`,actions:(0,P.jsx)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:s.reload,children:`重试`}),children:[`提供商用量没取到:`,E(s.error)]}):null,(0,P.jsxs)(C,{title:`提供商`,aside:(0,P.jsxs)(`span`,{className:`panel-aside-row`,children:[$>0?(0,P.jsxs)(w,{tone:`live`,dot:!0,children:[`已启用 `,$,` 家`]}):null,(0,P.jsx)(_,{content:`选一个客户端(WorkBuddy / MiniMax Code / Qoder CN),用它的官方授权导入凭证`,children:(0,P.jsxs)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,onClick:()=>l(!0),children:[(0,P.jsx)(r,{size:14}),`导入客户端`]})})]}),padded:!1,children:[t.initial&&t.loading?(0,P.jsx)(`div`,{style:{padding:`0 20px 18px`},children:(0,P.jsx)(A,{})}):t.error?(0,P.jsx)(`div`,{style:{padding:`0 20px 18px`},children:(0,P.jsx)(T,{kind:`error`,title:`提供商列表没取到`,detail:E(t.error),onRetry:t.reload})}):H.length===0?(0,P.jsx)(`div`,{style:{padding:`0 20px 18px`},children:(0,P.jsx)(T,{kind:`empty`,title:`还没有任何提供商`,detail:`先登记一个上游,再按需启用它的出站路由。`})}):(0,P.jsx)(F,{rows:H,byProvider:U,busyId:f,onEdit:g,onSignin:e=>void Y(e),onGrowthRun:e=>void X(e),onOauthImport:e=>void Z(e),onModels:e=>{L(null),i(e)},onActivate:e=>void q(e),onDeactivate:e=>void J(e),onDelete:D}),(0,P.jsxs)(`div`,{className:`footer-note`,style:{padding:`0 20px 18px`},children:[`启用提供商会让它加入出站路由,并同步它自己的模型清单;已启用的提供商可以并行生效,模型按各自目录路由。 三家凭证都来自各客户端的`,(0,P.jsx)(`b`,{children:`官方授权`}),`(用户无需也无法手填)——点「重新导入授权」即可换账号或刷新令牌; 令牌只存在服务端,任何接口都读不回完整值。`,(0,P.jsx)(`br`,{}),`行内三列用量按`,(0,P.jsx)(`b`,{children:`提供商`}),`归属:由「模型 id → 生效目录的提供商」解析(请求记录本身没有 provider 维度)。模型不属于任何生效目录的行归到「未归属」,不冒充某一家。`]})]}),c?(0,P.jsx)(V,{onClose:()=>{l(!1),G()},onImported:()=>G()}):null,u?(0,P.jsx)(V,{provider:{id:u.id,name:u.name,protocol:u.protocol},onClose:()=>{d(null),G()},onImported:()=>G()}):null,h?(0,P.jsx)(K,{provider:h,onClose:()=>g(null),onSaved:()=>{g(null),G()},onReimport:()=>{let e=h;g(null),e&&d(e)}}):null,n?(0,P.jsx)(j,{title:`模型列表 · ${n.name}`,subtitle:n.baseUrl,onClose:()=>i(null),children:(0,P.jsx)(`div`,{className:`drawer-body`,children:(0,P.jsx)(W,{catalog:o.data,catalogLoading:R,catalogMsg:I,catalogError:o.error,onCatalogRefresh:()=>void ee(),onCatalogReload:o.reload,onModelToggled:te})})}):null,y?(0,P.jsx)(k,{title:`删除这个提供商?`,onClose:()=>{f||D(null)},footer:(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,disabled:!!f,onClick:()=>D(null),children:`取消(保留)`}),(0,P.jsxs)(`button`,{type:`button`,className:`btn btn-danger btn-sm`,disabled:!!f,onClick:()=>void Q(),children:[f?(0,P.jsx)(a,{size:14,className:`spin`}):null,f?`删除中…`:`确认删除`]})]}),children:(0,P.jsxs)(`div`,{className:`ov-lose`,children:[(0,P.jsx)(`b`,{children:`会失去什么:`}),`提供商「`,y.name,`」(`,y.baseUrl,`)的登记与它的凭证文件一并删除, 需要重新登记并填一次 ck_ 密钥。此操作不可撤销。`]})}):null]})}function K({provider:e,onClose:t,onSaved:i,onReimport:o}){let[s,c]=(0,N.useState)(e.name),[l,u]=(0,N.useState)(e.baseUrl),[d,f]=(0,N.useState)(!1),[m,h]=(0,N.useState)(!1),[g,v]=(0,N.useState)(null),[y,S]=(0,N.useState)(null),[C,w]=(0,N.useState)(!1),[T,D]=(0,N.useState)(null),O=async()=>{if(!C){w(!0),D(null),v(null);try{let t=await x.providerImportLocal(e.id);if(t.ok)D({kind:`ok`,text:t.message+(t.detail?`\n${t.detail}`:``)}),i();else if(t.outcome===`unavailable`){let t=e.protocol===`qoder`?`qoder`:`minimax`;D({kind:`unavailable`,text:`本服务所在机器上读不到客户端登录态(远程部署的正常情形)。`,command:`node tools/import-credential-push.mjs ${location.origin} ${t} --provider ${e.id}`})}else D({kind:`error`,text:t.message+(t.detail?`\n${t.detail}`:``)})}catch(e){v(e instanceof p?e:new p(String(e),0,0))}finally{w(!1)}}},k=async t=>{if(t.preventDefault(),!d){f(!0),v(null);try{let t={};s.trim()!==e.name&&(t.name=s.trim()),l.trim()!==e.baseUrl&&(t.baseUrl=l.trim()),Object.keys(t).length>0&&await x.patchProvider(e.id,t),i()}catch(e){v(e instanceof p?e:new p(String(e),0,0))}finally{f(!1)}}},A=async()=>{if(!m){h(!0),v(null),S(null);try{S(await x.testProvider(e.id,void 0))}catch(e){v(e instanceof p?e:new p(String(e),0,0))}finally{h(!1)}}};return(0,P.jsx)(j,{title:`配置提供商 · ${e.name}`,subtitle:e.baseUrl,onClose:t,children:(0,P.jsxs)(`div`,{className:`drawer-body`,children:[g?(0,P.jsx)(b,{tone:`error`,children:E(g)}):null,(0,P.jsxs)(`form`,{onSubmit:e=>void k(e),className:`prov-edit`,style:{marginTop:6},children:[(0,P.jsxs)(`div`,{className:`up-row`,children:[(0,P.jsx)(`div`,{className:`up-lab`,children:`名称`}),(0,P.jsx)(`input`,{className:`field-input text`,style:{width:`100%`},value:s,onChange:e=>c(e.target.value),"aria-label":`提供商名称`})]}),(0,P.jsxs)(`div`,{className:`up-row`,children:[(0,P.jsx)(`div`,{className:`up-lab`,children:`地址`}),(0,P.jsx)(`input`,{className:`field-input text`,style:{width:`100%`},value:l,placeholder:`https://api.example.com`,onChange:e=>u(e.target.value),"aria-label":`提供商地址`})]}),(0,P.jsxs)(`div`,{className:`up-row`,children:[(0,P.jsx)(`div`,{className:`up-lab`,children:`凭证`}),(0,P.jsxs)(`div`,{className:`cred-guide`,children:[(0,P.jsx)(`div`,{className:`cred-guide-note`,children:e.protocol===`openai`?(0,P.jsxs)(P.Fragment,{children:[`凭证来自 WorkBuddy `,(0,P.jsx)(`b`,{children:`官方 OAuth 授权`}),`(桌面端 / 插件同一条通道),无需手填。`]}):e.protocol===`anthropic`?(0,P.jsxs)(P.Fragment,{children:[`凭证是客户端登录态里的 `,(0,P.jsx)(`span`,{className:`code-chip`,children:`mmort_…`}),` refresh token。 请用`,(0,P.jsx)(`b`,{children:`专用账号`}),`(与桌面端共用会互相顶下线)。`]}):(0,P.jsxs)(P.Fragment,{children:[`凭证来自 Qoder 客户端登录态(一段`,(0,P.jsx)(`b`,{children:`身份 JSON`}),`)。桌面客户端与它`,(0,P.jsx)(`b`,{children:`互不影响`}),`。`]})}),(0,P.jsxs)(`div`,{className:`cred-guide-actions`,children:[(0,P.jsxs)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,disabled:d,onClick:()=>o(),children:[(0,P.jsx)(r,{size:14}),`重新导入授权`]}),(0,P.jsxs)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,disabled:C,onClick:()=>void O(),children:[C?(0,P.jsx)(a,{size:14}):(0,P.jsx)(r,{size:14}),`从本机客户端读取`]})]}),T?(0,P.jsx)(b,{tone:T.kind===`ok`?`success`:T.kind===`unavailable`?`warn`:`error`,children:(0,P.jsxs)(`span`,{children:[T.text,T.command?(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(`br`,{}),`在`,(0,P.jsx)(`b`,{children:`装了客户端的那台机器`}),`的仓库目录下跑:`,(0,P.jsx)(I,{command:T.command})]}):null]})}):null,e.protocol===`qoder`?(0,P.jsxs)(`div`,{className:`cred-guide-note`,children:[`本服务`,(0,P.jsx)(`b`,{children:`不自动刷新`}),` Qoder 令牌;过期后重跑一次导入即可。`]}):null]})]}),(0,P.jsxs)(`div`,{className:`up-actions`,children:[(0,P.jsxs)(`button`,{type:`submit`,className:`btn btn-primary btn-sm`,disabled:d,children:[d?(0,P.jsx)(a,{size:14}):(0,P.jsx)(n,{size:14}),`保存`]}),(0,P.jsx)(_,{content:`用已导入的授权测这家上游是否还通`,children:(0,P.jsxs)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,disabled:m,onClick:()=>void A(),children:[m?(0,P.jsx)(a,{size:14}):null,`测试`]})})]})]}),y?(0,P.jsx)(b,{tone:y.ok?`success`:`warn`,children:(0,P.jsx)(`span`,{children:y.ok?(0,P.jsxs)(P.Fragment,{children:[`通了:`,e.name,` 接受了这次 1 token 探测(`,y.elapsedMs,`ms)。`]}):y.httpStatus===null?(0,P.jsxs)(P.Fragment,{children:[`没连上(网络层):`,y.reason??`未知原因`,`。先查地址与出网,再看凭证。`]}):(0,P.jsxs)(P.Fragment,{children:[`连上了但被拒(HTTP `,y.httpStatus,y.upstreamCode===null?``:` · 业务码 ${y.upstreamCode}`,`)。`,y.upstreamCode===11102?`业务码 11102 = 账号没订阅这个模型。key 可能是好的,换个模型再测或直接切换。`:`通常是凭证问题;换一把再测。`]})})}):null,(0,P.jsx)(`div`,{className:`up-note`,style:{marginTop:18},children:(0,P.jsxs)(`span`,{children:[`凭证只存在`,(0,P.jsx)(`b`,{children:`服务端`}),`:界面只显示账号摘要或掩码,任何接口都读不回完整值。`]})})]})})}function q(){let[e,t]=(0,N.useState)(`today`);return(0,P.jsxs)(`div`,{className:`view on`,children:[(0,P.jsx)(D,{title:`提供商管理`,actions:(0,P.jsx)(O,{value:e,options:y,onChange:t,width:148})}),(0,P.jsx)(`div`,{className:`view-body stack`,children:(0,P.jsx)(G,{window:e})})]})}export{q as ClientsPage};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import{b as e,it as t,t as n,tt as r}from"./vendor-befEYGHM.js";import{a as i,b as a,o,r as s,s as c}from"./index-VH6Gc3-s.js";import{t as l}from"./accessUrl-DbL5DLDz.js";var u=t(),d=`1.6.14`,f={totalTokens:193e4,cacheHitRate:62.4,requestsToday:1284,successRate:99.7};function p(e,t=0){let n=e.toFixed(t).split(`.`);return n[0]=n[0].replace(/\B(?=(\d{3})+(?!\d))/g,`,`),n.join(`.`)}function m(e,t=1){return e==null?`—`:`${e.toFixed(t)}%`}function h(e){if(e&&typeof e==`object`){let t=e;return{ok:t.ok!==!1,version:typeof t.version==`string`?t.version:void 0}}return{ok:!0}}function g(){let e=o(),[t,n]=(0,u.useState)(!0),[r,i]=(0,u.useState)(d),[a,s]=(0,u.useState)(f),[l,p]=(0,u.useState)(!1);return(0,u.useEffect)(()=>{let e=!0,t=async()=>{try{let t=await fetch(`/healthz`,{headers:{Accept:`application/json`}});if(!t.ok)throw Error(`healthz ${t.status}`);let r=h(await t.json());if(!e)return;n(r.ok),r.version&&i(r.version)}catch{e&&n(!1)}};t();let r=window.setInterval(()=>void t(),3e4);return()=>{e=!1,window.clearInterval(r)}},[]),(0,u.useEffect)(()=>{if(e.status!==`authed`){p(!1),s(f);return}let t=!0;return c.overview(`24h`).then(e=>{t&&(s({totalTokens:e.metrics.totalTokens,cacheHitRate:e.metrics.cacheHitRate*100,requestsToday:e.metrics.requests,successRate:e.metrics.successRate*100}),p(!0))}).catch(()=>{t&&(p(!1),s(f))}),()=>{t=!1}},[e.status]),{online:t,version:r,real:l,numbers:a}}function _(){var e=window.matchMedia(`(prefers-reduced-motion: reduce)`).matches,t=!0,n=[],r=[],i={totalTokens:`本窗口 tokens`,cacheHitRate:`缓存命中率`,requestsToday:`今日请求`,successRate:`今日成功率`};function a(){var e=window.RelayDemo;if(e&&e.summary){var t=[];[].forEach.call(document.querySelectorAll(`[data-demo]`),function(n){var r=n.getAttribute(`data-demo`),a=e.summary[r];if(typeof a==`number`){var o=parseInt(n.getAttribute(`data-dec`)||`0`,10),s=n.textContent.trim().replace(/,/g,``);s!==``&&Math.abs(parseFloat(s)-a)>10**-o/2&&t.push((i[r]||r)+`:页面上写的 `+s+`,数据层是 `+a),n.setAttribute(`data-count`,a),n.textContent=p(a,o)}}),t.length&&window.console&&console.warn(`[page] 首页演示数字与 demo-data 不一致(已按数据层显示):
|
|
2
|
-
· `+t.join(`
|
|
3
|
-
· `))}}function o(e){var t=!1;return function(){t||(t=!0,requestAnimationFrame(function(){t=!1,e()}))}}function s(){var e=[].slice.call(document.querySelectorAll(`.reveal`));if(e.length){if(!(`IntersectionObserver`in window)){e.forEach(function(e){e.classList.add(`in`)});return}var t=new IntersectionObserver(function(e){e.forEach(function(e){e.isIntersecting&&(e.target.classList.add(`in`),t.unobserve(e.target))})},{rootMargin:`0px 0px -10% 0px`,threshold:.1});r.push(t),e.forEach(function(e){t.observe(e)})}}var c=document.querySelector(`.nav`);function l(){c&&c.classList.toggle(`stuck`,window.pageYOffset>28)}var u=[].slice.call(document.querySelectorAll(`.rail a`)),d=u.map(function(e){return document.querySelector(e.getAttribute(`href`))});function f(){if(u.length){for(var e=window.pageYOffset+window.innerHeight*.42,t=0,n=0;n<d.length;n+=1){var r=d[n];r&&r.offsetTop<=e&&(t=n)}for(var i=0;i<u.length;i+=1)u[i].classList.toggle(`on`,i===t)}}function p(e,t){var n=e.toFixed(t).split(`.`);return n[0]=n[0].replace(/\B(?=(\d{3})+(?!\d))/g,`,`),n.join(`.`)}function m(e){var n=parseFloat(e.getAttribute(`data-count`));if(isNaN(n))return;var r=parseInt(e.getAttribute(`data-dec`)||`0`,10),i=1500,a=0;function o(s){if(t){a||=s;var c=Math.min(1,(s-a)/i);e.textContent=p(n*(c===1?1:1-2**(-10*c)),r),c<1?requestAnimationFrame(o):e.textContent=p(n,r)}}requestAnimationFrame(o)}function h(){var t=[].slice.call(document.querySelectorAll(`[data-count]`));if(t.length){if(e||!(`IntersectionObserver`in window)){t.forEach(function(e){var t=parseFloat(e.getAttribute(`data-count`)),n=parseInt(e.getAttribute(`data-dec`)||`0`,10);isNaN(t)||(e.textContent=p(t,n))});return}var n=new IntersectionObserver(function(e){e.forEach(function(e){e.isIntersecting&&(m(e.target),n.unobserve(e.target))})},{threshold:.6});r.push(n),t.forEach(function(e){n.observe(e)})}}function g(){var i=[].slice.call(document.querySelectorAll(`[data-type]`));if(i.length&&!e&&`IntersectionObserver`in window){var a=new IntersectionObserver(function(e){e.forEach(function(e){if(e.isIntersecting){var r=e.target;a.unobserve(r);var i=r.getAttribute(`data-type`),o=0;r.textContent=``,r.classList.add(`typing`),(function e(){if(t){if(o>i.length){r.classList.remove(`typing`);return}r.textContent=i.slice(0,o),o+=1,n.push(window.setTimeout(e,34))}})()}})},{threshold:.8});r.push(a),i.forEach(function(e){a.observe(e)})}}var _=o(function(){l(),f()}),v=o(function(){f()}),y=function(){l(),f()};return a(),s(),h(),g(),l(),f(),window.addEventListener(`scroll`,_,{passive:!0}),window.addEventListener(`resize`,v),window.addEventListener(`load`,y),function(){t=!1,window.removeEventListener(`scroll`,_),window.removeEventListener(`resize`,v),window.removeEventListener(`load`,y),r.forEach(function(e){e.disconnect()}),n.forEach(function(e){clearTimeout(e)}),r=[],n=[]}}function v(e){var t=e&&typeof e.querySelectorAll==`function`?e:document,n=document.documentElement,r={};function i(e,t){r[e]!==t&&(r[e]=t,n.style.setProperty(e,t))}var a=window.matchMedia(`(prefers-reduced-motion: reduce)`).matches,o=!0,s=[`x`,`y`,`z`,`rx`,`ry`,`rz`,`fog`,`dim`],c={x:0,y:0,z:0,rx:0,ry:0,rz:0,fog:.18,dim:1},l={x:`px`,y:`px`,z:`px`,rx:`deg`,ry:`deg`,rz:`deg`},u={x:`--cam-x`,y:`--cam-y`,z:`--cam-z`,rx:`--cam-rx`,ry:`--cam-ry`,rz:`--cam-rz`,fog:`--fog`,dim:`--scene-dim`};function d(e){return function(){e|=0,e=e+1831565813|0;var t=Math.imul(e^e>>>15,1|e);return t=t+Math.imul(t^t>>>7,61|t)^t,((t^t>>>14)>>>0)/4294967296}}var f=[{sel:`.dust.d3`,count:14,min:.9,max:1.5,seed:20261004},{sel:`.dust.d2`,count:10,min:1.3,max:2,seed:77110203},{sel:`.dust.d1`,count:6,min:1.8,max:2.8,seed:31415926}];function p(){f.forEach(function(e){for(var n=t.querySelectorAll(e.sel),r=0;r<n.length;r+=1){n[r].innerHTML=``;for(var i=d(e.seed),a=document.createDocumentFragment(),o=0;o<e.count;o+=1){var s=document.createElement(`i`),c=e.min+i()*(e.max-e.min);s.style.left=(i()*100).toFixed(2)+`%`,s.style.top=(i()*100).toFixed(2)+`%`,s.style.width=c.toFixed(2)+`px`,s.style.height=c.toFixed(2)+`px`,s.style.animationDelay=(i()*3200).toFixed(0)+`ms`,a.appendChild(s)}n[r].appendChild(a)}})}var m=[];function h(e){var t=e.getBoundingClientRect();return t.top+window.pageYOffset+t.height/2}function g(){m=[].slice.call(t.querySelectorAll(`[data-cam]`)).map(function(e){var t={},n=e.getAttribute(`data-cam`);if(n)try{t=JSON.parse(n)}catch{console.warn(`[scene] data-cam 不是合法 JSON,已忽略:`,e,n),t={}}return{at:h(e),cam:t}}),m.sort(function(e,t){return e.at-t.at})}function _(e){return e<.5?2*e*e:1-(-2*e+2)**2/2}function v(e){if(!m.length)return Object.assign({},c);for(var t=0;t<m.length-1&&e>m[t+1].at;)t+=1;var n=m[t],r=m[t+1],i=r?e<=n.at?0:(e-n.at)/(r.at-n.at):1;i=Math.max(0,Math.min(1,i));for(var a=_(i),o={},l=0;l<s.length;l+=1){var u=s[l],d=n.cam[u]===void 0?c[u]:n.cam[u];o[u]=d+((r&&r.cam[u]!==void 0?r.cam[u]:d)-d)*a}return o}var y=.16,b=null,x=null,S=0,C=0;function w(e){for(var t=0;t<s.length;t+=1){var n=s[t],r=l[n]||``;i(u[n],e[n].toFixed(3)+r)}}function T(e){var t=S?Math.min((e-S)/1e3,.12):.016;S=e,b||=Object.assign({},x);for(var n=a?1:1-Math.exp(-t/y),r=!0,i=0;i<s.length;i+=1){var o=s[i],c=x[o]-b[o];b[o]+=c*n;var l=Math.max(.0015,Math.abs(x[o])*.0012);Math.abs(c)>l&&(r=!1)}if(w(b),r){b=Object.assign({},x),w(x),C=0,S=0;return}C=requestAnimationFrame(T)}function E(){C||=(S=0,requestAnimationFrame(T))}function D(){if(o){var e=document.documentElement,t=Math.max(1,e.scrollHeight-window.innerHeight);i(`--scroll-p`,(window.pageYOffset/t).toFixed(4)),x=v(window.pageYOffset+window.innerHeight/2),E()}}var O={tx:0,ty:0,x:0,y:0},k=0,A=0,j=window.matchMedia(`(hover: hover) and (pointer: fine)`).matches;function M(){i(`--look-x`,O.x.toFixed(4)),i(`--look-y`,O.y.toFixed(4))}function N(e){var t=A?Math.min((e-A)/1e3,.12):.016;A=e;var n=1-Math.exp(-t/y);O.x+=(O.tx-O.x)*n,O.y+=(O.ty-O.y)*n,M(),Math.abs(O.tx-O.x)>8e-4||Math.abs(O.ty-O.y)>8e-4?k=requestAnimationFrame(N):(O.x=O.tx,O.y=O.ty,M(),k=0,A=0)}function P(e){document.hidden||(O.tx=(e.clientX/window.innerWidth-.5)*2,O.ty=(e.clientY/window.innerHeight-.5)*2,k||=(A=0,requestAnimationFrame(N)))}function F(){O.tx=0,O.ty=0,k||=(A=0,requestAnimationFrame(N))}function I(){!a&&j&&(window.addEventListener(`pointermove`,P,{passive:!0}),document.addEventListener(`pointerleave`,F))}var L=null,R=null,z=null;function B(){if(p(),g(),!m.length){n.setAttribute(`data-scene-ready`,`static`);return}D(),I();var e=!1;L=function(){e||(e=!0,requestAnimationFrame(function(){e=!1,D()}))},R=function(){o&&(g(),D())},z=function(){o&&(g(),D())},window.addEventListener(`scroll`,L,{passive:!0}),window.addEventListener(`resize`,R),window.addEventListener(`load`,z),document.fonts&&document.fonts.ready&&document.fonts.ready.then(function(){o&&(g(),D())}),n.setAttribute(`data-scene-ready`,`1`)}function V(){o=!1,L&&window.removeEventListener(`scroll`,L),R&&window.removeEventListener(`resize`,R),z&&window.removeEventListener(`load`,z),window.removeEventListener(`pointermove`,P),document.removeEventListener(`pointerleave`,F),C&&cancelAnimationFrame(C),k&&cancelAnimationFrame(k),C=0,k=0,[].slice.call(t.querySelectorAll(`.dust`)).forEach(function(e){e.innerHTML=``}),Object.keys(u).forEach(function(e){n.style.removeProperty(u[e])}),n.style.removeProperty(`--scroll-p`),n.style.removeProperty(`--look-x`),n.style.removeProperty(`--look-y`),r={},n.removeAttribute(`data-scene-ready`)}return B(),V}var y=r(),b=e=>e,x=[{tint:`var(--iris)`,a:`0deg`,r:`430px`,y:`-40px`,w:`300px`,h:`520px`,z:`-18deg`,x:`16deg`,o:`.95`,e:`.70`,hot:`.26`,dof:`0px`,dur:`15s`,delay:`0s`},{tint:`var(--accent-cyan)`,a:`72deg`,r:`448px`,y:`10px`,w:`255px`,h:`470px`,z:`12deg`,x:`-22deg`,o:`.82`,e:`.18`,hot:`.05`,dof:`0px`,dur:`19s`,delay:`3s`},{tint:`var(--brand-500)`,a:`144deg`,r:`424px`,y:`-60px`,w:`325px`,h:`560px`,z:`-24deg`,x:`19deg`,o:`.90`,e:`.52`,hot:`.18`,dof:`0px`,dur:`17s`,delay:`6.5s`},{tint:`var(--brand-400)`,a:`216deg`,r:`456px`,y:`20px`,w:`270px`,h:`490px`,z:`16deg`,x:`-14deg`,o:`.76`,e:`.14`,hot:`.04`,dof:`0px`,dur:`21s`,delay:`10s`},{tint:`var(--accent-blue)`,a:`288deg`,r:`436px`,y:`-30px`,w:`310px`,h:`535px`,z:`-14deg`,x:`24deg`,o:`.88`,e:`.30`,hot:`.12`,dof:`0px`,dur:`18s`,delay:`13.5s`},{tint:`var(--brand-500)`,a:`36deg`,r:`860px`,y:`40px`,w:`400px`,h:`560px`,z:`-22deg`,x:`26deg`,o:`.62`,e:`.20`,hot:`.06`,dof:`2.6px`,dur:`26s`,delay:`2s`,soft:!0},{tint:`var(--accent-cyan)`,a:`126deg`,r:`900px`,y:`-20px`,w:`360px`,h:`520px`,z:`18deg`,x:`-28deg`,o:`.52`,e:`.10`,hot:`.03`,dof:`2.6px`,dur:`30s`,delay:`9s`,soft:!0},{tint:`var(--iris)`,a:`216deg`,r:`840px`,y:`60px`,w:`440px`,h:`620px`,z:`-28deg`,x:`20deg`,o:`.58`,e:`.30`,hot:`.09`,dof:`2.6px`,dur:`24s`,delay:`15s`,soft:!0},{tint:`var(--brand-400)`,a:`306deg`,r:`890px`,y:`-10px`,w:`380px`,h:`540px`,z:`14deg`,x:`-24deg`,o:`.48`,e:`.08`,hot:`.03`,dof:`2.6px`,dur:`33s`,delay:`19s`,soft:!0}];function S(){return(0,y.jsxs)(`div`,{className:`scene`,"aria-hidden":`true`,children:[(0,y.jsxs)(`div`,{className:`rig`,children:[(0,y.jsx)(`div`,{className:`tilt`,children:(0,y.jsx)(`div`,{className:`stage`,children:x.map((e,t)=>(0,y.jsx)(`i`,{className:e.soft?`pl soft`:`pl`,style:b({"--tint":e.tint,"--a":e.a,"--r":e.r,"--y":e.y,"--w":e.w,"--h":e.h,"--z":e.z,"--x":e.x,"--o":e.o,"--e":e.e,"--hot":e.hot,"--dof":e.dof,"--sheen-dur":e.dur,"--sheen-delay":e.delay})},t))})}),(0,y.jsx)(`div`,{className:`dust d3`}),(0,y.jsx)(`div`,{className:`dust d2`}),(0,y.jsx)(`div`,{className:`dust d1`})]}),(0,y.jsx)(`div`,{className:`core`}),(0,y.jsx)(`div`,{className:`nucleus`}),(0,y.jsx)(`div`,{className:`beam b1`}),(0,y.jsx)(`div`,{className:`beam b2`}),(0,y.jsx)(`div`,{className:`fog`}),(0,y.jsx)(`div`,{className:`dimmer`}),(0,y.jsx)(`div`,{className:`vignette`}),(0,y.jsx)(`div`,{className:`noise`})]})}function C(){return(0,u.useEffect)(()=>v(document),[]),(0,y.jsx)(S,{})}var w=[{href:`#top`,label:`概览`},{href:`#ways`,label:`运行`},{href:`#quickstart`,label:`上手`},{href:`#clients`,label:`客户端`},{href:`#status`,label:`状态`},{href:`#cta`,label:`开始`}];function T(){return(0,y.jsx)(`nav`,{className:`rail`,"aria-label":`章节`,children:w.map(e=>(0,y.jsxs)(`a`,{href:e.href,children:[(0,y.jsx)(`i`,{}),(0,y.jsx)(`b`,{children:e.label})]},e.href))})}function E({version:t}){let[r,a]=(0,u.useState)(!1),o=()=>a(!1);return(0,y.jsxs)(`nav`,{className:`nav${r?` menu-open`:``}`,children:[(0,y.jsxs)(`a`,{className:`brand`,href:`#top`,onClick:o,children:[(0,y.jsx)(i,{size:28,id:`relay-mark-nav`}),(0,y.jsx)(`b`,{children:`途关`}),(0,y.jsx)(`span`,{children:`Waygate`})]}),(0,y.jsxs)(`div`,{className:`nav-links`,children:[(0,y.jsx)(`a`,{href:`#ways`,onClick:o,children:`运行方式`}),(0,y.jsx)(`a`,{href:`#quickstart`,onClick:o,children:`快速开始`}),(0,y.jsx)(`a`,{href:`#clients`,onClick:o,children:`客户端配置`}),(0,y.jsx)(`a`,{href:`#status`,onClick:o,children:`运行状态`})]}),(0,y.jsxs)(`div`,{className:`nav-right`,style:{display:`flex`,alignItems:`center`,gap:14,marginLeft:`auto`},children:[(0,y.jsxs)(`span`,{className:`pill pill-brand`,children:[`v`,t]}),(0,y.jsx)(`a`,{className:`btn btn-primary btn-sm`,href:s(),children:`打开控制台`}),(0,y.jsx)(`button`,{type:`button`,className:`nav-menu-toggle`,"aria-label":r?`关闭导航菜单`:`打开导航菜单`,"aria-controls":`landing-mobile-nav`,"aria-expanded":r,onClick:()=>a(e=>!e),children:r?(0,y.jsx)(n,{size:18,"aria-hidden":`true`}):(0,y.jsx)(e,{size:18,"aria-hidden":`true`})})]}),(0,y.jsxs)(`div`,{id:`landing-mobile-nav`,className:`mobile-nav`,"aria-hidden":!r,children:[(0,y.jsx)(`a`,{href:`#ways`,onClick:o,children:`运行方式`}),(0,y.jsx)(`a`,{href:`#quickstart`,onClick:o,children:`快速开始`}),(0,y.jsx)(`a`,{href:`#clients`,onClick:o,children:`客户端配置`}),(0,y.jsx)(`a`,{href:`#status`,onClick:o,children:`运行状态`})]})]})}function D(e,t=0,n){if(e==null)return{children:`—`};let r={"data-count":e,children:p(e,t)};return t&&(r[`data-dec`]=t),n&&(r[`data-demo`]=n),r}var O={live:`var(--signal-live)`,offline:`var(--warn-amber)`};function k(e=window.location.hostname){return/^\d{1,3}(\.\d{1,3}){3}$/.test(e)||e.includes(`:`)}function A(e){return k(e)?`自签证书`:`公共 CA`}var j=e=>e;function M({text:e,className:t,label:n,idle:r=`复制`,done:i=`已复制`}){let[a,o]=(0,u.useState)(!1),s=(0,u.useRef)(null);(0,u.useEffect)(()=>()=>{s.current&&window.clearTimeout(s.current)},[]);let c=(0,u.useCallback)(()=>{let t=navigator.clipboard;t&&typeof t.writeText==`function`&&t.writeText(e).then(()=>{o(!0),s.current&&window.clearTimeout(s.current),s.current=window.setTimeout(()=>o(!1),1200)},()=>void 0)},[e]);return(0,y.jsx)(`button`,{className:t,type:`button`,"aria-label":n,onClick:c,children:a?i:r})}var N=`{"x":0,"y":0,"z":0,"rx":0,"ry":0,"rz":0,"fog":0.16,"dim":0.90}`,P=[`# Ubuntu + systemd(TLS 由 nginx 终止)`,`sudo systemctl start relay`,`sudo systemctl status relay`,`sudo systemctl restart relay`].join(`
|
|
4
|
-
`);function F({status:e}){let{online:t,real:n,numbers:r}=e,i=l(),o=r.totalTokens==null?`—`:a(r.totalTokens),s=t?void 0:j({color:`var(--warn-amber)`,background:`color-mix(in srgb, var(--warn-amber) 7%, transparent)`,borderColor:`var(--warn-amber-line)`});return(0,y.jsxs)(`header`,{className:`hero`,id:`top`,"data-cam":N,children:[(0,y.jsxs)(`div`,{className:`wrap`,children:[(0,y.jsxs)(`div`,{className:`hero-grid`,children:[(0,y.jsxs)(`div`,{className:`hero-inner`,children:[(0,y.jsxs)(`div`,{className:`hero-badge reveal`,style:s,children:[(0,y.jsx)(`i`,{className:t?`dot dot-live`:`dot`,style:{color:t?O.live:O.offline}}),t?`服务运行中`:`服务离线`,` · 本窗口 tokens`,` `,(0,y.jsx)(`span`,{className:`n`,children:o}),n?null:`(示例)`]}),(0,y.jsxs)(`div`,{className:`hero-title reveal`,children:[(0,y.jsxs)(`h1`,{className:`hero-h1 display-1`,children:[(0,y.jsx)(`span`,{className:`rv-line`,children:(0,y.jsx)(`span`,{style:j({"--i":0}),children:`把自己的订阅积分`})}),(0,y.jsx)(`span`,{className:`rv-line`,children:(0,y.jsxs)(`span`,{style:j({"--i":1}),children:[`变成一个 `,(0,y.jsx)(`span`,{className:`mk grad-text`,children:`base_url`})]})})]}),(0,y.jsx)(`div`,{className:`hero-flip`,"aria-hidden":`true`,children:(0,y.jsxs)(`h1`,{className:`hero-h1 display-1`,children:[`把自己的订阅积分`,(0,y.jsx)(`br`,{}),`变成一个 `,(0,y.jsx)(`span`,{className:`mk grad-text`,children:`base_url`})]})})]}),(0,y.jsx)(`p`,{className:`hero-sub reveal`,style:j({"--i":3}),children:`部署在你自己机器上,把 WorkBuddy 订阅积分暴露成 OpenAI 兼容接口。 IDE、聊天客户端、手机、脚本共用同一个 Key,积分消耗实时可见。`}),(0,y.jsxs)(`div`,{className:`hero-acts reveal`,style:j({"--i":4}),children:[(0,y.jsx)(M,{className:`btn btn-primary`,text:P,label:`复制部署命令`,idle:`复制部署命令`}),(0,y.jsx)(`a`,{className:`btn btn-ghost`,href:`#clients`,children:`查看客户端配置`})]}),(0,y.jsxs)(`div`,{className:`trust reveal`,style:j({"--i":5}),children:[(0,y.jsx)(`span`,{children:`只监听本机回环`}),(0,y.jsx)(`span`,{children:`外发直连上游,无中转`}),(0,y.jsx)(`span`,{children:`请求日志保存在本地`})]})]}),(0,y.jsx)(`aside`,{className:`hero-side reveal`,style:j({"--i":2}),children:(0,y.jsxs)(`div`,{className:`glass access`,children:[(0,y.jsxs)(`div`,{className:`access-h`,children:[(0,y.jsx)(`span`,{className:`eyebrow`,style:j({"--c":`var(--text-ghost)`}),children:`接入地址`}),(0,y.jsxs)(`span`,{className:t?`pill pill-live`:`pill pill-amber`,children:[(0,y.jsx)(`i`,{className:t?`dot dot-live`:`dot`}),t?`可用`:`离线`]})]}),(0,y.jsxs)(`div`,{className:`access-url`,children:[(0,y.jsx)(`code`,{children:i}),(0,y.jsx)(M,{className:`copy`,text:i,label:`复制接入地址`})]}),(0,y.jsx)(`div`,{className:`access-note`,children:`把它填进任何支持 OpenAI 兼容协议的工具`}),(0,y.jsxs)(`dl`,{className:`kv`,children:[(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`dt`,{children:`协议`}),(0,y.jsx)(`dd`,{children:`OpenAI v1 · Anthropic`})]}),(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`dt`,{children:`日志保留`}),(0,y.jsx)(`dd`,{children:`默认 30 天`})]}),(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`dt`,{children:`TLS`}),(0,y.jsx)(`dd`,{children:A()})]}),(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`dt`,{children:`部署形态`}),(0,y.jsx)(`dd`,{children:`systemd + nginx`})]})]})]})})]}),(0,y.jsxs)(`div`,{className:`panel-wrap glass reveal`,style:j({"--i":6}),children:[(0,y.jsxs)(`div`,{className:`panel-left`,children:[(0,y.jsxs)(`div`,{className:`winbar`,children:[(0,y.jsx)(`i`,{style:{background:`var(--danger-red)`}}),(0,y.jsx)(`i`,{style:{background:`var(--warn-amber)`}}),(0,y.jsx)(`i`,{style:{background:`var(--signal-live)`}}),(0,y.jsx)(`span`,{className:`fname`,children:`deploy.sh`}),(0,y.jsx)(`span`,{className:`wtag`,children:`SHELL`}),(0,y.jsx)(`span`,{className:`wsp`}),(0,y.jsx)(M,{className:`wbtn`,text:P})]}),(0,y.jsxs)(`div`,{className:`panel-code`,children:[(0,y.jsxs)(`div`,{className:`cl`,children:[(0,y.jsx)(`i`,{children:`1`}),(0,y.jsx)(`span`,{children:(0,y.jsx)(`span`,{className:`c`,children:`# Ubuntu + systemd(TLS 由 nginx 终止)`})})]}),(0,y.jsxs)(`div`,{className:`cl`,children:[(0,y.jsx)(`i`,{children:`2`}),(0,y.jsx)(`span`,{children:(0,y.jsx)(`span`,{className:`fn`,children:`$ sudo systemctl start relay`})})]}),(0,y.jsxs)(`div`,{className:`cl`,children:[(0,y.jsx)(`i`,{children:`3`}),(0,y.jsx)(`span`,{children:(0,y.jsx)(`span`,{className:`fn`,children:`$ sudo systemctl status relay`})})]}),(0,y.jsxs)(`div`,{className:`cl`,children:[(0,y.jsx)(`i`,{children:`4`}),(0,y.jsx)(`span`,{children:(0,y.jsx)(`span`,{className:`fn`,children:`$ sudo systemctl restart relay`})})]}),(0,y.jsxs)(`div`,{className:`cl hl`,children:[(0,y.jsx)(`i`,{children:`5`}),(0,y.jsx)(`span`,{children:(0,y.jsx)(`span`,{className:`c`,children:`# 首次启动打印管理口令(仅此一次)`})})]}),(0,y.jsxs)(`div`,{className:`cl`,children:[(0,y.jsx)(`i`,{children:`6`}),(0,y.jsx)(`span`,{children:(0,y.jsx)(`span`,{className:`c`,children:`# API Key 在控制台「客户端与密钥」页新建`})})]})]})]}),(0,y.jsxs)(`div`,{className:`panel-right`,children:[(0,y.jsxs)(`div`,{className:`pr-head`,children:[(0,y.jsx)(`h4`,{children:`连接状态`}),(0,y.jsx)(`span`,{className:`pr-count`,children:`示例 · 3 个客户端`})]}),(0,y.jsxs)(`div`,{className:`conn`,children:[(0,y.jsx)(`i`,{className:`dot dot-live`,style:{color:O.live}}),(0,y.jsx)(`span`,{className:`cname`,children:`Claude Code`}),(0,y.jsx)(`span`,{className:`dev`,children:`本机`}),(0,y.jsx)(`span`,{className:`lat`,children:`12ms`}),(0,y.jsx)(`span`,{className:`pill pill-live`,children:`在线`})]}),(0,y.jsxs)(`div`,{className:`conn`,children:[(0,y.jsx)(`i`,{className:`dot dot-live`,style:{color:O.live}}),(0,y.jsx)(`span`,{className:`cname`,children:`Cherry Studio`}),(0,y.jsx)(`span`,{className:`dev`,children:`桌面`}),(0,y.jsx)(`span`,{className:`lat`,children:`48ms`}),(0,y.jsx)(`span`,{className:`pill pill-live`,children:`在线`})]}),(0,y.jsxs)(`div`,{className:`conn`,children:[(0,y.jsx)(`i`,{className:`dot`,style:{color:O.offline}}),(0,y.jsx)(`span`,{className:`cname`,children:`Cursor`}),(0,y.jsx)(`span`,{className:`dev`,children:`笔记本`}),(0,y.jsx)(`span`,{className:`lat`,children:`—`}),(0,y.jsx)(`span`,{className:`pill pill-amber`,children:`待机`})]}),(0,y.jsxs)(`div`,{className:`panel-metrics`,children:[(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`div`,{className:`k`,children:`本窗口 tokens`}),(0,y.jsx)(`div`,{className:`v num live`,style:{color:O.live},children:o})]}),(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`div`,{className:`k`,children:`缓存命中率`}),(0,y.jsx)(`div`,{className:`v num`,children:m(r.cacheHitRate)})]}),(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`div`,{className:`k`,children:`今日请求`}),(0,y.jsx)(`div`,{className:`v num`,children:r.requestsToday==null?`—`:p(r.requestsToday)})]})]})]})]})]}),(0,y.jsxs)(`div`,{className:`scroll-cue`,children:[(0,y.jsx)(`span`,{className:`tick`}),`SCROLL`]})]})}var I=`{"x":-26,"y":-16,"z":-150,"rx":2.5,"ry":3,"rz":0,"fog":0.30,"dim":0.44}`;function L(){return(0,y.jsx)(`section`,{className:`strip`,"data-cam":I,children:(0,y.jsxs)(`div`,{className:`wrap reveal`,children:[(0,y.jsxs)(`div`,{className:`cap`,children:[`任何支持 `,(0,y.jsx)(`b`,{children:`OpenAI 兼容协议`}),` 的工具,填上地址就能用`]}),(0,y.jsxs)(`div`,{className:`logos`,children:[(0,y.jsx)(`span`,{children:`Claude Code`}),(0,y.jsx)(`span`,{children:`Cursor`}),(0,y.jsx)(`span`,{children:`Cherry Studio`}),(0,y.jsx)(`span`,{children:`ChatBox`}),(0,y.jsx)(`span`,{children:`LobeChat`}),(0,y.jsx)(`span`,{children:`Continue`}),(0,y.jsx)(`span`,{className:`cn`,children:`你的脚本`})]})]})})}var R=`{"x":-118,"y":-38,"z":-310,"rx":5,"ry":7,"rz":-1.5,"fog":0.44,"dim":0.40}`,z={color:`var(--accent-cyan)`},B={fill:`none`,stroke:`currentColor`,strokeWidth:1.6};function V(){return(0,y.jsx)(`section`,{className:`section`,id:`ways`,"data-cam":R,children:(0,y.jsx)(`div`,{className:`wrap`,children:(0,y.jsxs)(`div`,{className:`split`,children:[(0,y.jsxs)(`div`,{className:`split-l reveal`,children:[(0,y.jsxs)(`div`,{className:`eyebrow`,children:[(0,y.jsx)(`span`,{className:`idx`,children:`02`}),`运行方式`]}),(0,y.jsxs)(`h2`,{className:`display-2`,children:[`一个进程,`,(0,y.jsx)(`br`,{}),`管住所有客户端的积分`]}),(0,y.jsx)(`p`,{children:`不用为每个客户端单独登录、单独算积分。服务跑在你自己的机器上,所有请求走同一个出口。`})]}),(0,y.jsxs)(`ul`,{className:`linelist`,children:[(0,y.jsxs)(`li`,{className:`reveal`,children:[(0,y.jsx)(`span`,{className:`ll-ico`,children:(0,y.jsxs)(`svg`,{width:`20`,height:`20`,viewBox:`0 0 20 20`,"aria-hidden":`true`,style:z,...B,children:[(0,y.jsx)(`circle`,{cx:`6.5`,cy:`10`,r:`3.5`}),(0,y.jsx)(`path`,{d:`M10 10h8M15 10v3M17.5 10v3`,strokeLinecap:`round`})]})}),(0,y.jsxs)(`span`,{className:`ll-tx`,children:[(0,y.jsx)(`b`,{children:`一个 Key,多端共用`}),(0,y.jsx)(`i`,{children:`桌面客户端、IDE、手机、脚本共用同一个密钥,控制台按客户端拆开看用量。`})]})]}),(0,y.jsxs)(`li`,{className:`reveal`,style:j({"--i":1}),children:[(0,y.jsx)(`span`,{className:`ll-ico`,children:(0,y.jsxs)(`svg`,{width:`20`,height:`20`,viewBox:`0 0 20 20`,"aria-hidden":`true`,style:z,...B,children:[(0,y.jsx)(`path`,{d:`M4 10h4M12 10h4`,strokeLinecap:`round`}),(0,y.jsx)(`circle`,{cx:`10`,cy:`10`,r:`2`}),(0,y.jsx)(`path`,{d:`M12 10V5.5M12 10v4.5`,strokeLinecap:`round`})]})}),(0,y.jsxs)(`span`,{className:`ll-tx`,children:[(0,y.jsx)(`b`,{children:`请求只在你自己的机器上流转`}),(0,y.jsx)(`i`,{children:`应用默认只监听本机回环,对外由你自己的 nginx 暴露,没有第三方中转。`})]})]}),(0,y.jsxs)(`li`,{className:`reveal`,style:j({"--i":2}),children:[(0,y.jsx)(`span`,{className:`ll-ico`,children:(0,y.jsxs)(`svg`,{width:`20`,height:`20`,viewBox:`0 0 20 20`,"aria-hidden":`true`,style:z,...B,children:[(0,y.jsx)(`rect`,{x:`2`,y:`4.5`,width:`16`,height:`11`,rx:`2.5`}),(0,y.jsx)(`path`,{d:`M2 8.5h16`}),(0,y.jsx)(`path`,{d:`M4.5 13h4`,strokeLinecap:`round`})]})}),(0,y.jsxs)(`span`,{className:`ll-tx`,children:[(0,y.jsx)(`b`,{children:`用量与消耗实时同步`}),(0,y.jsx)(`i`,{children:`本窗口总 tokens、缓存命中率、每条请求消耗多少积分,控制台里一眼看清。`})]})]}),(0,y.jsxs)(`li`,{className:`reveal`,style:j({"--i":3}),children:[(0,y.jsx)(`span`,{className:`ll-ico`,children:(0,y.jsx)(`svg`,{width:`20`,height:`20`,viewBox:`0 0 20 20`,"aria-hidden":`true`,style:z,...B,children:(0,y.jsx)(`path`,{d:`M10 2.5 16.5 5v5c0 4-2.8 6.4-6.5 7.5C6.3 16.4 3.5 14 3.5 10V5L10 2.5Z`,strokeLinejoin:`round`})})}),(0,y.jsxs)(`span`,{className:`ll-tx`,children:[(0,y.jsx)(`b`,{children:`请求日志与超限保护`}),(0,y.jsx)(`i`,{children:`每条请求都落库、可回溯;超过并发上限时直接回 429,失败不会被静默吞掉。`})]})]})]})]})})})}var H=`{"x":58,"y":-70,"z":-480,"rx":10,"ry":-5,"rz":1.5,"fog":0.52,"dim":0.36}`;function U({version:e}){return(0,y.jsx)(`section`,{className:`section`,id:`quickstart`,"data-cam":H,children:(0,y.jsxs)(`div`,{className:`wrap`,children:[(0,y.jsxs)(`div`,{className:`sec-head reveal`,children:[(0,y.jsxs)(`div`,{children:[(0,y.jsxs)(`div`,{className:`eyebrow`,children:[(0,y.jsx)(`span`,{className:`idx`,children:`03`}),`快速开始`]}),(0,y.jsx)(`h2`,{className:`display-2`,style:{marginTop:20},children:`三步,十分钟内跑起来`})]}),(0,y.jsx)(`p`,{className:`lead`,children:`自己的一台机器就够。首次启动打印管理口令(只显示一次),客户端的 Key 在控制台新建。`})]}),(0,y.jsxs)(`ol`,{className:`steps`,children:[(0,y.jsxs)(`li`,{className:`reveal`,children:[(0,y.jsx)(`div`,{className:`st-n`,children:`01`}),(0,y.jsx)(`h3`,{children:`部署服务`}),(0,y.jsx)(`p`,{children:`在 Ubuntu 上装成 systemd 服务,nginx 在外层终止 TLS。首次启动即打印管理口令。`})]}),(0,y.jsxs)(`li`,{className:`reveal`,style:j({"--i":1}),children:[(0,y.jsx)(`div`,{className:`st-n`,children:`02`}),(0,y.jsx)(`h3`,{children:`生成密钥`}),(0,y.jsx)(`p`,{children:`在控制台「客户端与密钥」页新建密钥,按客户端命名,可以随时停用或删除。`}),(0,y.jsx)(`div`,{className:`cmd`,children:`控制台 → 客户端与密钥 → 新建密钥`})]}),(0,y.jsxs)(`li`,{className:`reveal`,style:j({"--i":2}),children:[(0,y.jsx)(`div`,{className:`st-n`,children:`03`}),(0,y.jsx)(`h3`,{children:`填进客户端`}),(0,y.jsx)(`p`,{children:`把 base_url 填成控制台的同源地址,模型名照抄,其余代码不用改。`})]})]}),(0,y.jsxs)(`div`,{className:`term reveal`,children:[(0,y.jsxs)(`div`,{className:`term-bar`,children:[(0,y.jsx)(`i`,{className:`dot dot-live`,style:{color:`var(--signal-live)`}}),(0,y.jsx)(`span`,{children:`首次启动输出`}),(0,y.jsxs)(`span`,{className:`term-tag`,children:[`relay · v`,e]})]}),(0,y.jsxs)(`div`,{className:`term-body`,children:[(0,y.jsxs)(`div`,{className:`tl`,children:[(0,y.jsx)(`span`,{className:`pr`,children:`$`}),` sudo systemctl start relay`]}),(0,y.jsx)(`div`,{className:`tl out`,children:`Waygate · 首次启动,已生成管理口令(此口令只显示这一次)`}),(0,y.jsxs)(`div`,{className:`tl out`,children:[`口令:`,(0,y.jsx)(`span`,{className:`hl`,children:`••••••••••••••••`})]}),(0,y.jsx)(`div`,{className:`tl out`,children:`请立即复制保存。忘记口令时:控制台「设置 → 管理口令」重置。`}),(0,y.jsx)(`div`,{className:`tl ok`,children:`Waygate 已在 http://127.0.0.1:8787 就绪(默认仅回环,不对公网直接暴露)`})]})]})]})})}var W=`{"x":148,"y":-94,"z":-630,"rx":6,"ry":-11,"rz":-2.5,"fog":0.60,"dim":0.34}`,G=`sk-waygate-4f9c2a7e1b83d04f391c7a2e`,K=l(),q=l().replace(/\/v1$/,``),J=[{k:`兼容协议`,v:`OpenAI v1 · Anthropic`},{k:`接入方式`,v:`HTTPS · ${A()}`},{k:`统计口径`,v:`本机日志聚合`},{k:`日志存储`,v:`本地`}];function Y(){return(0,y.jsx)(`section`,{className:`section`,id:`clients`,"data-cam":W,children:(0,y.jsxs)(`div`,{className:`wrap`,children:[(0,y.jsxs)(`div`,{className:`sec-head reveal`,children:[(0,y.jsxs)(`div`,{children:[(0,y.jsxs)(`div`,{className:`eyebrow`,children:[(0,y.jsx)(`span`,{className:`idx`,children:`04`}),`客户端配置`]}),(0,y.jsx)(`h2`,{className:`display-2`,style:{marginTop:20},children:`四处填好,立刻能用`})]}),(0,y.jsx)(`p`,{className:`lead`,children:`所有客户端都只需要一个地址加一个密钥。下面是最常见的四种接法。`})]}),(0,y.jsxs)(`div`,{className:`grid-3`,children:[(0,y.jsxs)(`div`,{className:`glass glass-soft cfg reveal`,children:[(0,y.jsx)(`h3`,{children:`编程工具 / IDE`}),(0,y.jsx)(`div`,{className:`sub`,children:`Continue · Cline · 任意 OpenAI 兼容插件`}),(0,y.jsxs)(`div`,{className:`code`,children:[`OPENAI_BASE_URL=`,(0,y.jsx)(`span`,{className:`s`,children:K}),`
|
|
5
|
-
OPENAI_API_KEY=`,(0,y.jsx)(`span`,{className:`s`,children:G}),`
|
|
6
|
-
OPENAI_MODEL=`,(0,y.jsx)(`span`,{className:`s`,children:`kimi-k3`})]})]}),(0,y.jsxs)(`div`,{className:`glass glass-soft cfg reveal`,style:j({"--i":1}),children:[(0,y.jsx)(`h3`,{children:`桌面聊天客户端`}),(0,y.jsx)(`div`,{className:`sub`,children:`Cherry Studio · LobeChat`}),(0,y.jsxs)(`div`,{className:`code`,children:[`base_url = `,(0,y.jsx)(`span`,{className:`s`,children:K}),`
|
|
7
|
-
api_key = `,(0,y.jsx)(`span`,{className:`s`,children:G}),`
|
|
8
|
-
model = 从下拉列表选择
|
|
9
|
-
`,(0,y.jsx)(`span`,{className:`c`,children:`# 图形界面里填这三格`})]})]}),(0,y.jsxs)(`div`,{className:`glass glass-soft cfg reveal`,style:j({"--i":2}),children:[(0,y.jsx)(`h3`,{children:`自己的代码 / 脚本`}),(0,y.jsx)(`div`,{className:`sub`,children:`任意 OpenAI 兼容 SDK`}),(0,y.jsxs)(`div`,{className:`code`,children:[(0,y.jsx)(`span`,{className:`k`,children:`from`}),` openai `,(0,y.jsx)(`span`,{className:`k`,children:`import`}),` OpenAI
|
|
10
|
-
client = OpenAI(
|
|
11
|
-
base_url=`,(0,y.jsxs)(`span`,{className:`s`,children:[`"`,K,`"`]}),`,
|
|
12
|
-
api_key=`,(0,y.jsxs)(`span`,{className:`s`,children:[`"`,G,`"`]}),`)`]})]}),(0,y.jsxs)(`div`,{className:`glass glass-soft cfg reveal`,style:j({"--i":3}),children:[(0,y.jsx)(`h3`,{children:`Anthropic 兼容`}),(0,y.jsx)(`div`,{className:`sub`,children:`Claude Code · 任意 Anthropic 兼容客户端`}),(0,y.jsxs)(`div`,{className:`code`,children:[`ANTHROPIC_BASE_URL=`,(0,y.jsx)(`span`,{className:`s`,children:q}),`
|
|
13
|
-
ANTHROPIC_API_KEY=`,(0,y.jsx)(`span`,{className:`s`,children:G}),`
|
|
14
|
-
ANTHROPIC_MODEL=`,(0,y.jsx)(`span`,{className:`s`,children:`deepseek-v4.1-flash`}),`
|
|
15
|
-
`,(0,y.jsx)(`span`,{className:`c`,children:`# base 不带 /v1;鉴权头 x-api-key(也兼容 Authorization: Bearer)`})]})]})]}),(0,y.jsxs)(`div`,{className:`cfg-note reveal`,style:j({"--i":4}),children:[(0,y.jsxs)(`div`,{className:`cfg-note-row`,children:[(0,y.jsx)(`span`,{className:`k`,children:`OpenAI 兼容`}),(0,y.jsx)(`code`,{children:`POST /v1/chat/completions`}),(0,y.jsxs)(`span`,{className:`v`,children:[`base 填 `,(0,y.jsx)(`b`,{children:K}),`(`,(0,y.jsx)(`b`,{children:`带`}),` /v1)`]})]}),(0,y.jsxs)(`div`,{className:`cfg-note-row`,children:[(0,y.jsx)(`span`,{className:`k`,children:`Anthropic 兼容`}),(0,y.jsx)(`code`,{children:`POST /v1/messages`}),(0,y.jsxs)(`span`,{className:`v`,children:[`base 填 `,(0,y.jsx)(`b`,{children:q}),`(`,(0,y.jsx)(`b`,{children:`不带`}),` /v1,SDK 自己拼 /v1/messages)`]})]}),(0,y.jsxs)(`p`,{className:`cfg-note-foot`,children:[`两者是`,(0,y.jsx)(`b`,{children:`同一批模型`}),`的两个入口,模型 ID 沿用同一批(如 deepseek-v4.1-flash),不是 claude-*。 错误体为 Anthropic 形状:`,(0,y.jsx)(`code`,{children:`{"type":"error","error":{"type":"…","message":"…"}}`}),`。`,` `,`证书由外层 nginx 终止:走域名是`,(0,y.jsx)(`b`,{children:`公共 CA`}),`(无需导入任何根证书); 走 `,(0,y.jsx)(`b`,{children:`IP 直连`}),`是`,(0,y.jsx)(`b`,{children:`自签证书`}),`(需先信任 CA,或改用域名访问)。`]}),(0,y.jsxs)(`p`,{className:`cfg-note-foot`,children:[`说明:Anthropic 这侧是本服务`,(0,y.jsx)(`b`,{children:`新增的翻译层`}),`(Anthropic 形状 ⇄ 上游的 Chat Completions)——`,(0,y.jsx)(`b`,{children:`上游订阅本身只有 Chat Completions`}),`,我们实测 `,(0,y.jsx)(`code`,{children:`POST /v2/messages`}),` 是 404。 这里只承诺「提供 Anthropic Messages 兼容端点」,不保证任何具体客户端的全部功能。`]})]}),(0,y.jsx)(`div`,{className:`specbar reveal`,style:j({"--i":5}),children:J.map(e=>(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`div`,{className:`k`,children:e.k}),(0,y.jsx)(`div`,{className:`v`,children:e.v})]},e.k))})]})})}var X=`{"x":18,"y":-128,"z":-390,"rx":-7,"ry":-3,"rz":0,"fog":0.46,"dim":0.46}`;function Z({status:e}){let{real:t,numbers:n}=e,r=n.totalTokens==null?`—`:a(n.totalTokens);return(0,y.jsx)(`section`,{className:`section band`,id:`status`,"data-cam":X,children:(0,y.jsxs)(`div`,{className:`wrap`,children:[(0,y.jsxs)(`div`,{className:`reveal`,style:{display:`flex`,justifyContent:`center`,position:`relative`},children:[(0,y.jsxs)(`div`,{className:`eyebrow`,children:[(0,y.jsx)(`span`,{className:`idx`,children:`05`}),`当前运行状态`]}),t?null:(0,y.jsx)(`span`,{className:`pill pill-amber`,style:{position:`absolute`,right:0,top:0},children:`示例数据`})]}),(0,y.jsx)(`div`,{style:{height:44}}),(0,y.jsxs)(`div`,{className:`status-strip reveal`,children:[(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`div`,{className:`v num live`,children:r}),(0,y.jsx)(`div`,{className:`k`,children:`本窗口 tokens`})]}),(0,y.jsxs)(`div`,{children:[(0,y.jsxs)(`div`,{className:`v num`,children:[(0,y.jsx)(`span`,{...D(n.cacheHitRate,1,`cacheHitRate`)}),(0,y.jsx)(`span`,{className:`unit`,children:`%`})]}),(0,y.jsx)(`div`,{className:`k`,children:`缓存命中率`})]}),(0,y.jsxs)(`div`,{children:[(0,y.jsx)(`div`,{className:`v num`,...D(n.requestsToday,0,`requestsToday`)}),(0,y.jsx)(`div`,{className:`k`,children:`今日请求数`})]}),(0,y.jsxs)(`div`,{children:[(0,y.jsxs)(`div`,{className:`v num`,children:[(0,y.jsx)(`span`,{...D(n.successRate,1,`successRate`)}),(0,y.jsx)(`span`,{className:`unit`,children:`%`})]}),(0,y.jsx)(`div`,{className:`k`,children:`今日成功率`})]})]})]})})}var Q=`{"x":0,"y":-96,"z":-130,"rx":-3,"ry":0,"rz":0,"fog":0.30,"dim":0.92}`,$=`sudo systemctl start relay`;function ee(){return(0,y.jsx)(`section`,{className:`cta`,id:`cta`,"data-cam":Q,children:(0,y.jsxs)(`div`,{className:`wrap`,children:[(0,y.jsx)(`h2`,{className:`display-2 reveal`,children:`一条命令,起在你自己机器上`}),(0,y.jsxs)(`div`,{className:`cmdbox reveal`,style:j({"--i":1}),children:[(0,y.jsx)(`span`,{className:`pr`,children:`$`}),(0,y.jsx)(`span`,{"data-type":$,children:$})]}),(0,y.jsx)(`p`,{className:`note reveal`,style:j({"--i":2}),children:`首次启动打印管理口令(只显示一次),之后可在控制台重置。客户端用的 API Key 在控制台新建。`}),(0,y.jsxs)(`div`,{className:`acts reveal`,style:j({"--i":3}),children:[(0,y.jsx)(M,{className:`btn btn-primary`,text:$,label:`复制部署命令`,idle:`复制部署命令`}),(0,y.jsx)(`a`,{className:`btn btn-ghost`,href:s(),children:`打开控制台`})]}),(0,y.jsxs)(`div`,{className:`trust reveal`,style:j({"--i":4}),children:[(0,y.jsx)(`span`,{children:`Ubuntu + systemd`}),(0,y.jsx)(`span`,{children:`nginx 终止 TLS`}),(0,y.jsx)(`span`,{children:`请求日志留在本机`})]})]})})}var te=`{"x":0,"y":-50,"z":-370,"rx":4,"ry":0,"rz":0,"fog":0.66,"dim":0.26}`,ne={fontFamily:`var(--font-display)`,fontWeight:700,fontSize:18,color:`var(--text-primary)`},re={fontFamily:`var(--font-mono)`,fontSize:11,letterSpacing:`var(--track-eyebrow)`,color:`var(--text-ghost)`};function ie({status:e}){let{online:t,version:n}=e;return(0,y.jsx)(`footer`,{className:`footer`,"data-cam":te,children:(0,y.jsxs)(`div`,{className:`wrap`,children:[(0,y.jsxs)(`div`,{className:`foot-top`,children:[(0,y.jsxs)(`div`,{className:`foot-brand`,children:[(0,y.jsxs)(`div`,{className:`brand`,style:{display:`flex`,alignItems:`center`,gap:11},children:[(0,y.jsx)(i,{size:26,id:`relay-mark-footer`}),(0,y.jsx)(`b`,{style:ne,children:`途关`}),(0,y.jsx)(`span`,{style:re})]}),(0,y.jsxs)(`p`,{children:[`自用反代:把 WorkBuddy 订阅积分`,(0,y.jsx)(`br`,{}),`变成任何客户端都能用的 OpenAI 接口。`]}),(0,y.jsxs)(`span`,{className:t?`pill pill-live`:`pill pill-amber`,children:[(0,y.jsx)(`i`,{className:t?`dot dot-live`:`dot`}),t?`服务运行中`:`服务离线`]})]}),(0,y.jsxs)(`div`,{className:`foot-col`,children:[(0,y.jsx)(`h5`,{children:`开始`}),(0,y.jsx)(`a`,{href:`#quickstart`,children:`快速开始`}),(0,y.jsx)(`a`,{href:`#clients`,children:`客户端配置`}),(0,y.jsx)(`a`,{href:`#status`,children:`运行状态`})]}),(0,y.jsxs)(`div`,{className:`foot-col`,children:[(0,y.jsx)(`h5`,{children:`控制台`}),(0,y.jsx)(`a`,{href:s(`requests`),children:`请求日志`}),(0,y.jsx)(`a`,{href:s(`keys`),children:`API Keys`}),(0,y.jsx)(`a`,{href:s(`settings`),children:`设置`})]})]}),(0,y.jsxs)(`div`,{className:`foot-bar`,children:[(0,y.jsx)(`span`,{children:`Waygate · 本地部署,数据不外发`}),(0,y.jsx)(`span`,{children:`个人自用工具,与 WorkBuddy / 腾讯无隶属关系`}),(0,y.jsxs)(`span`,{children:[`v`,n,` · MIT License`]})]})]})})}var ae=`Waygate — 把自己的订阅积分变成一个 base_url`,oe=`Waygate — 在本地把 WorkBuddy 订阅积分暴露成 OpenAI 兼容接口,一个 Key 走所有客户端。`;function se(e){let t=document.title;document.title=ae;let n=document.querySelector(`meta[name="description"]`),r=!n;n||(n=document.createElement(`meta`),n.setAttribute(`name`,`description`),document.head.appendChild(n));let i=n.getAttribute(`content`);return n.setAttribute(`content`,e),()=>{document.title=t,r?n?.remove():i!=null&&n.setAttribute(`content`,i)}}function ce(){let e=g();return(0,u.useEffect)(()=>{let e=document.documentElement;e.classList.add(`relay-landing`);let t=se(oe);return()=>{e.classList.remove(`relay-landing`),t()}},[]),(0,u.useEffect)(()=>_(),[]),(0,y.jsxs)(`div`,{className:`landing`,children:[(0,y.jsx)(C,{}),(0,y.jsx)(`div`,{className:`progress`,"aria-hidden":`true`,children:(0,y.jsx)(`i`,{})}),(0,y.jsxs)(`div`,{className:`shell`,children:[(0,y.jsx)(E,{version:e.version}),(0,y.jsx)(F,{status:e}),(0,y.jsx)(L,{}),(0,y.jsx)(V,{}),(0,y.jsx)(U,{version:e.version}),(0,y.jsx)(Y,{}),(0,y.jsx)(Z,{status:e}),(0,y.jsx)(ee,{}),(0,y.jsx)(ie,{status:e})]}),(0,y.jsx)(T,{})]})}export{ce as LandingPage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.landing .scene{--scene-bg:linear-gradient(168deg, #0a0919 0%, #120e2a 46%, #070611 100%);z-index:0;pointer-events:none;perspective:var(--prism-persp);perspective-origin:50% 46%;background:var(--scene-bg);position:fixed;inset:0;overflow:clip}.landing .rig{transform-style:preserve-3d;transform-origin:50% 46%;will-change:transform;transform:translate3d(calc(var(--cam-x) * .4 + var(--look-x) * 26px), calc(var(--cam-y) * .34 + var(--look-y) * 18px), calc(var(--cam-z) * .2)) rotateX(calc(var(--cam-rx) * .45)) rotateY(calc(var(--cam-ry) * .6)) rotateZ(calc(var(--cam-rz) * .5));position:absolute;inset:0}.landing .rig>*{position:absolute}.landing .tilt{transform-style:preserve-3d;transform-origin:50% 46%;position:absolute;inset:0;transform:rotateX(-7deg)rotate(1.6deg)}.landing .stage{left:var(--prism-anchor-x);top:var(--prism-anchor-y);width:0;height:0;transform-style:preserve-3d;animation:prism-turn var(--prism-turn) linear infinite;position:absolute}@keyframes prism-turn{0%{transform:rotateY(0)}to{transform:rotateY(360deg)}}.landing .pl{width:var(--w);height:var(--h);margin-left:calc(var(--w) * -.5);margin-top:calc(var(--h) * -.5);--tint:var(--iris);opacity:var(--o);backface-visibility:visible;transform:rotateY(var(--a)) translateZ(var(--r)) translateY(var(--y)) rotateZ(var(--z,0deg)) rotateX(var(--x,0deg));background:radial-gradient(36% 24% at 8% 3%, rgba(255, 255, 255, var(--hot,.2)), transparent 68%), linear-gradient(146deg, color-mix(in srgb, var(--bg-surface-3) 58%, transparent) 0%, color-mix(in srgb, var(--bg-code) 44%, transparent) 32%, color-mix(in srgb, var(--bg-page) 30%, transparent) 66%, color-mix(in srgb, var(--bg-page) 10%, transparent) 100%), linear-gradient(170deg, color-mix(in srgb, var(--tint) 18%, transparent) 0%, color-mix(in srgb, var(--tint) 5%, transparent) 36%, transparent 64%);box-shadow:inset 0 1px 0 rgba(255, 255, 255, var(--e,.5)), inset 1px 0 0 rgba(255, 255, 255, calc(var(--e,.5) * .38)), inset -1px 0 0 color-mix(in srgb, var(--tint) 34%, transparent), inset 0 -1px 0 color-mix(in srgb, var(--tint) 16%, transparent), inset 0 0 0 1px color-mix(in srgb, var(--tint) 18%, transparent), 0 0 40px -20px color-mix(in srgb, var(--tint) 48%, transparent);border-radius:2px;position:absolute;top:0;left:0}.landing .pl.soft{filter:blur(var(--dof,var(--prism-dof-mid)))}.landing .pl:before{content:"";background:linear-gradient(180deg, rgba(255, 255, 255, calc(var(--e,.5) * .13)), transparent 28%), linear-gradient(0deg, color-mix(in srgb, var(--tint) 16%, transparent), transparent 20%);position:absolute;inset:0}.landing .pl:after{content:"";mix-blend-mode:screen;background:linear-gradient(112deg, transparent 40%, #ffffff4d 47%, color-mix(in srgb, var(--glow-ice) 62%, transparent) 50%, #ffffff4d 53%, transparent 60%);opacity:0;animation:p-sheen var(--sheen-dur,16s) var(--ease-in-out) infinite;animation-delay:var(--sheen-delay,0s);background-size:300% 100%;position:absolute;inset:0}@keyframes p-sheen{0%{opacity:0;background-position:135% 0}14%{opacity:.85}52%{opacity:0;background-position:-35% 0}to{opacity:0;background-position:-35% 0}}.landing .core{left:var(--prism-anchor-x);top:var(--prism-anchor-y);mix-blend-mode:screen;background:linear-gradient(180deg, transparent 0%, color-mix(in srgb, var(--glow-pale) 38%, transparent) 24%, color-mix(in srgb, var(--glow-white) 92%, transparent) 50%, color-mix(in srgb, var(--glow-frost) 55%, transparent) 62%, color-mix(in srgb, var(--glow-violet) 22%, transparent) 78%, transparent 100%);filter:blur(5px);opacity:.8;width:4px;height:54%;transform:translateY(-50%) translate3d(calc(var(--cam-x) * .3 + var(--look-x) * 14px), calc(var(--cam-y) * .26 + var(--look-y) * 10px), 0);position:absolute}.landing .core:after{content:"";mix-blend-mode:screen;background:radial-gradient(closest-side, color-mix(in srgb, var(--glow-violet) 50%, transparent), color-mix(in srgb, var(--brand-500) 18%, transparent) 44%, transparent 74%);filter:blur(26px);width:720px;height:720px;animation:core-breathe 9s var(--ease-in-out) infinite;margin:-360px 0 0 -360px;position:absolute;top:50%;left:50%}@keyframes core-breathe{0%,to{opacity:.74;transform:scale(1)}50%{opacity:1;transform:scale(1.09)}}.landing .nucleus{left:var(--prism-anchor-x);top:var(--prism-anchor-y);mix-blend-mode:screen;width:15px;height:15px;box-shadow:0 0 22px 7px color-mix(in srgb, var(--glow-cyan) 78%, transparent), 0 0 84px 26px color-mix(in srgb, var(--brand-500) 42%, transparent), 0 0 190px 70px color-mix(in srgb, var(--accent-cyan) 16%, transparent);animation:nucleus-breathe 6.4s var(--ease-in-out) infinite;transform:translate3d(calc(var(--cam-x) * .34 + var(--look-x) * 18px), calc(var(--cam-y) * .3 + var(--look-y) * 12px), 0);background:#fff;border-radius:50%;margin:-7.5px 0 0 -7.5px;position:absolute}@keyframes nucleus-breathe{0%,to{opacity:.82}50%{opacity:1}}.landing .beam{mix-blend-mode:screen;filter:blur(52px);will-change:transform;position:absolute}.landing .beam.b1{background:linear-gradient(180deg, transparent, color-mix(in srgb, var(--glow-cyan) 20%, transparent) 46%, transparent);width:300px;height:170%;transform:rotate(18deg) translate3d(calc(var(--cam-x) * .5), calc(var(--cam-y) * .4), 0);animation:beam-drift 34s var(--ease-in-out) infinite alternate;top:-30%;left:44%}.landing .beam.b2{background:linear-gradient(180deg, transparent, color-mix(in srgb, var(--iris) 26%, transparent) 50%, transparent);width:200px;height:170%;transform:rotate(-13deg) translate3d(calc(var(--cam-x) * .62), calc(var(--cam-y) * .5), 0);animation:beam-drift 46s var(--ease-in-out) infinite alternate-reverse;top:-34%;right:14%}@keyframes beam-drift{to{opacity:.55}}.landing .dust{position:absolute;inset:-10%}.landing .dust i{opacity:0;animation:dust-in 3.2s var(--ease-out) forwards;background:#dce6ff;border-radius:50%;position:absolute}@keyframes dust-in{to{opacity:.22}}.landing .dust.d2 i{background:#cfe6ff}.landing .dust.d1 i{background:#fff}.landing .fog{mix-blend-mode:screen;background:radial-gradient(116% 72% at 50% 46%, transparent 26%, var(--fog-far) 100%);opacity:calc(.14 + var(--fog) * .72);position:absolute;inset:0}.landing .dimmer{background:var(--scene-bg);opacity:calc(1 - var(--scene-dim));pointer-events:none;position:absolute;inset:0}.landing .vignette{background:radial-gradient(124% 90% at 50% 46%, transparent 34%, color-mix(in srgb, var(--bg-band) 56%, transparent) 76%, var(--bg-band) 100%), linear-gradient(94deg, color-mix(in srgb, var(--bg-band) 84%, transparent) 0%, color-mix(in srgb, var(--bg-band) 58%, transparent) 28%, color-mix(in srgb, var(--bg-band) 20%, transparent) 50%, transparent 72%);position:absolute;inset:0}.landing .noise{opacity:.034;mix-blend-mode:overlay;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");position:absolute;inset:0}@media (prefers-reduced-motion:reduce){.landing .stage,.landing .core:after,.landing .nucleus,.landing .beam{animation:none!important}.landing .pl:after{opacity:.34;background-position:46% 0;animation:none!important}.landing .dust i{opacity:.18;animation:none!important}}@media (max-width:900px){.landing .scene{perspective:2000px}.landing .stage,.landing .core,.landing .nucleus{top:31%;left:72%}.landing .tilt{transform-origin:72% 31%}.landing .pl{opacity:calc(var(--o) * .4)}.landing .pl.soft{display:none}.landing .core{opacity:.38}.landing .nucleus{opacity:.5}}.landing,.landing *,.landing :before,.landing :after{box-sizing:border-box}html.relay-landing{scroll-behavior:smooth;-webkit-text-size-adjust:100%}@media (prefers-reduced-motion:reduce){html.relay-landing{scroll-behavior:auto}}.landing{background:var(--bg-page);color:var(--text-secondary);font-family:var(--font-body);font-size:var(--fs-body);line-height:var(--lh-body);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;margin:0;overflow-x:hidden}.landing h1,.landing h2,.landing h3,.landing h4{font-family:var(--font-display);color:var(--text-primary);margin:0;font-weight:700}.landing p{margin:0}.landing a{color:inherit;text-decoration:none}.landing button{font:inherit;color:inherit}.landing code,.landing kbd{font-family:var(--font-mono);font-size:.92em}html.relay-landing ::-webkit-scrollbar{width:10px;height:10px}html.relay-landing ::-webkit-scrollbar-track{background:0 0}html.relay-landing ::-webkit-scrollbar-thumb{background:color-mix(in srgb, var(--iris) 22%, transparent);background-clip:content-box;border:2px solid #0000;border-radius:6px}.landing ::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb, var(--iris) 38%, transparent);background-clip:content-box}.landing .shell{z-index:1;position:relative}.landing .wrap{width:100%;max-width:var(--maxw);padding-inline:var(--gutter);margin:0 auto}.landing .nav{z-index:40;align-items:center;gap:var(--space-6);padding:18px var(--gutter);transition:background var(--d-panel) var(--ease-out), border-color var(--d-panel) var(--ease-out), backdrop-filter var(--d-panel) var(--ease-out), padding var(--d-panel) var(--ease-out);border-bottom:1px solid #0000;display:flex;position:fixed;top:0;left:0;right:0}.landing .nav.stuck{background:color-mix(in srgb, var(--bg-page) 72%, transparent);border-bottom-color:var(--border-subtle);-webkit-backdrop-filter:blur(16px)saturate(140%);padding-block:12px}.landing .nav .brand{align-items:center;gap:11px;display:flex}.landing .nav .brand b{font-family:var(--font-display);letter-spacing:var(--track-tight);color:var(--text-primary);font-size:15px;font-weight:700}.landing .nav .brand span{font-family:var(--font-mono);letter-spacing:var(--track-eyebrow);color:var(--text-ghost);text-transform:uppercase;font-size:9.5px}.landing .nav-links{align-items:center;gap:26px;margin-left:auto;display:flex}.landing .nav-links a{color:var(--text-muted);transition:color var(--d-hover) var(--ease-out);font-size:13px;position:relative}.landing .nav-links a:hover{color:var(--text-primary)}.landing .nav-links a:after{content:"";background:var(--gradient-brand);transform-origin:0;height:1px;transition:transform var(--d-panel) var(--ease-out);position:absolute;bottom:-5px;left:0;right:0;transform:scaleX(0)}.landing .nav-links a:hover:after{transform:scaleX(1)}.landing .nav-menu-toggle,.landing .mobile-nav{display:none}@media (max-width:860px){.landing .nav-links{display:none}.landing .nav-menu-toggle{border:1px solid var(--border-subtle);border-radius:var(--radius-sm);background:color-mix(in srgb, var(--bg-surface) 66%, transparent);width:36px;height:36px;color:var(--text-secondary);cursor:pointer;justify-content:center;align-items:center;padding:0;display:inline-flex}.landing .nav-menu-toggle:hover{color:var(--text-primary);border-color:var(--border-strong)}.landing .nav-menu-toggle:focus-visible{color:var(--brand-400);box-shadow:0 0 0 3px var(--brand-tint);outline:none}.landing .mobile-nav{top:calc(100% + 8px);left:var(--gutter);right:var(--gutter);border:1px solid var(--border-default);border-radius:var(--radius-md);background:color-mix(in srgb, var(--bg-elevated) 94%, transparent);box-shadow:var(--shadow-float);-webkit-backdrop-filter:blur(16px)saturate(140%);backdrop-filter:blur(16px)saturate(140%);gap:4px;padding:8px;display:grid;position:absolute}.landing .mobile-nav[aria-hidden=true]{display:none}.landing .mobile-nav a{border-radius:var(--radius-sm);color:var(--text-secondary);padding:11px 12px;font-size:13px}.landing .mobile-nav a:hover,.landing .mobile-nav a:focus-visible{color:var(--text-primary);background:var(--brand-tint);outline:none}}.landing .display-1{font-size:var(--fs-display-1);line-height:var(--lh-display);letter-spacing:var(--track-display);font-weight:700}.landing .display-2{font-size:var(--fs-display-2);letter-spacing:var(--track-display);font-weight:700;line-height:1.14}.landing .display-3{font-size:var(--fs-display-3);line-height:var(--lh-title);letter-spacing:var(--track-tight);font-weight:600}.landing .lead{font-size:var(--fs-lead);color:var(--text-muted);max-width:62ch;line-height:1.7}.landing .grad-text{background:var(--gradient-text);-webkit-text-fill-color:transparent;color:#0000;background-size:220% 100%;-webkit-background-clip:text;background-clip:text;animation:9s linear infinite lg-grad-sweep}@keyframes lg-grad-sweep{to{background-position:220% 0}}.landing .eyebrow{font-family:var(--font-mono);font-size:var(--fs-micro);letter-spacing:var(--track-eyebrow);text-transform:uppercase;color:var(--c,var(--accent-cyan));align-items:center;gap:12px;display:inline-flex}.landing .eyebrow:before{content:"";opacity:.5;background:currentColor;width:26px;height:1px}.landing .eyebrow .idx{color:var(--text-ghost)}.landing .mono{font-family:var(--font-mono)}.landing .dim{color:var(--text-ghost)}.landing .btn{border-radius:var(--radius-md);cursor:pointer;white-space:nowrap;height:44px;transition:transform var(--d-tap) var(--ease-out), box-shadow var(--d-hover) var(--ease-out), border-color var(--d-hover) var(--ease-out), background var(--d-hover) var(--ease-out);border:1px solid #0000;align-items:center;gap:9px;padding:0 22px;font-size:14px;font-weight:500;display:inline-flex}.landing .btn:active{transform:translateY(1px)}.landing .btn-primary{background:var(--brand-500);color:#fff;box-shadow:0 8px 26px -8px color-mix(in srgb, var(--brand-500) 70%, transparent)}.landing .btn-primary:hover{box-shadow:0 12px 34px -8px color-mix(in srgb, var(--brand-500) 90%, transparent);background:#7c6bff}.landing .btn-ghost{color:var(--text-secondary);border-color:var(--border-default);background:#ffffff08}.landing .btn-ghost:hover{border-color:var(--border-strong);color:var(--text-primary);background:#ffffff0e}.landing .btn-sm{height:34px;padding:0 15px;font-size:12.5px}.landing .glass{background:var(--glass-bg);border:1px solid var(--glass-border);border-radius:var(--radius-xl);-webkit-backdrop-filter:blur(var(--glass-blur)) saturate(150%);box-shadow:var(--shadow-float);position:relative;overflow:hidden}.landing .glass:before{content:"";pointer-events:none;background:var(--edge-light);position:absolute;inset:0}.landing .glass-soft{background:var(--glass-bg-soft);-webkit-backdrop-filter:blur(calc(var(--glass-blur) * .6));box-shadow:none}.landing .section{padding-block:clamp(62px,8.4vh,122px);position:relative}.landing .section:before,.landing .strip:before{content:"";z-index:-1;pointer-events:none;background:linear-gradient(180deg, transparent 0%, color-mix(in srgb, var(--bg-band) 84%, transparent) 6%, color-mix(in srgb, var(--bg-band) 88%, transparent) 50%, color-mix(in srgb, var(--bg-band) 84%, transparent) 94%, transparent 100%);position:absolute;inset:0}.landing .sec-head{gap:var(--space-6) var(--space-8);margin-bottom:var(--space-8);grid-template-columns:minmax(0,7fr) minmax(0,5fr);align-items:end;display:grid}.landing .sec-head .lead{padding-bottom:6px}@media (max-width:900px){.landing .sec-head{grid-template-columns:1fr;align-items:start}}.landing .rule{background:var(--border-subtle);border:0;height:1px;margin:0}.landing .reveal{opacity:0;transition:opacity .9s var(--ease-out), transform .9s var(--ease-out);transition-delay:calc(var(--i,0) * 80ms);transform:translateY(22px)}.landing .reveal.in{opacity:1;transform:none}@media (prefers-reduced-motion:reduce){.landing .reveal{opacity:1!important;transform:none!important}}.landing .rail{z-index:30;flex-direction:column;align-items:center;gap:9px;display:flex;position:fixed;top:50%;right:22px;transform:translateY(-50%)}.landing .rail i{background:var(--border-default);transform-origin:50% 0;width:1px;height:26px;display:block}.landing .rail i.on{background:var(--gradient-brand);box-shadow:0 0 12px 1px color-mix(in srgb, var(--brand-500) 60%, transparent)}@media (max-width:1180px){.landing .rail{display:none}}.landing .code{background:var(--bg-code);border:1px solid var(--border-subtle);border-radius:var(--radius-lg);font-family:var(--font-mono);color:var(--text-tertiary);white-space:pre;padding:18px 20px;font-size:12.5px;line-height:1.9;position:relative;overflow-x:auto;-webkit-mask-image:none}.landing .code .c{color:var(--text-faint)}.landing .code .k{color:var(--accent-cyan)}.landing .code .s{color:var(--signal-live)}.landing .code .v{color:var(--brand-400)}.landing .code .fn{color:var(--text-primary);font-weight:500}.landing .footer{z-index:1;border-top:1px solid var(--border-subtle);background:var(--bg-band);color:var(--text-ghost);padding-block:40px;font-size:12.5px;position:relative}.landing .footer .row{flex-wrap:wrap;align-items:center;gap:14px 28px;display:flex}.landing .footer .row .sp{margin-left:auto}.landing .grid-2{gap:var(--space-5);grid-template-columns:repeat(2,minmax(0,1fr));display:grid}.landing .grid-3{gap:var(--space-5);grid-template-columns:repeat(3,minmax(0,1fr));display:grid}.landing .grid-4{gap:var(--space-5);grid-template-columns:repeat(4,minmax(0,1fr));display:grid}@media (max-width:1100px){.landing .grid-3,.landing .grid-4{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:720px){.landing .grid-2,.landing .grid-3,.landing .grid-4{grid-template-columns:1fr}}.landing .card{background:var(--bg-surface-grad);border:1px solid var(--border-subtle);border-radius:var(--radius-lg);position:relative}.landing .card-2{background:var(--bg-surface-2-grad)}.landing .dot{background:currentColor;border-radius:50%;flex:0 0 7px;width:7px;height:7px;display:inline-block;box-shadow:0 0 10px 1px}.landing .dot-live{animation:dot-pulse 2.6s var(--ease-in-out) infinite}@keyframes dot-pulse{0%,to{box-shadow:0 0 10px 1px}50%{box-shadow:0 0 16px 3px}}.landing .pill{height:22px;font-family:var(--font-mono);letter-spacing:.02em;color:var(--text-tertiary);border:1px solid var(--border-default);white-space:nowrap;background:#ffffff08;border-radius:999px;align-items:center;gap:6px;padding:0 9px;font-size:11.5px;display:inline-flex}.landing .pill-live{color:var(--signal-live);border-color:var(--signal-live-track);background:color-mix(in srgb, var(--signal-live) 7%, transparent)}.landing .pill-amber{color:var(--warn-amber);border-color:var(--warn-amber-line);background:color-mix(in srgb, var(--warn-amber) 7%, transparent)}.landing .pill-brand{color:var(--brand-400);border-color:color-mix(in srgb, var(--iris) 28%, transparent);background:var(--brand-tint)}.landing .num{font-family:var(--font-display);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;letter-spacing:var(--track-display);font-weight:700}.landing .unit{color:var(--text-faint);letter-spacing:0;margin-left:3px;font-size:.42em;font-weight:600}@media (prefers-reduced-motion:reduce){.landing .dot-live,.landing .grad-text{animation:none!important}}.landing [id]{scroll-margin-top:104px}.landing .progress{z-index:60;pointer-events:none;height:2px;position:fixed;top:0;left:0;right:0}.landing .progress i{height:100%;transform:scaleX(var(--scroll-p,0));transform-origin:0;background:var(--gradient-brand);box-shadow:0 0 14px 1px color-mix(in srgb, var(--brand-500) 55%, transparent);will-change:transform;display:block}.landing .hero{padding-block:clamp(140px,16vh,196px) clamp(56px,8vh,96px);position:relative}.landing .hero-grid{grid-template-columns:minmax(0,1.55fr) minmax(0,.85fr);align-items:start;gap:clamp(28px,3.6vw,64px);display:grid}.landing .hero-inner{max-width:940px}.landing .hero-side{padding-top:clamp(34px,4.4vh,58px)}@media (max-width:1080px){.landing .hero-grid{grid-template-columns:1fr}.landing .hero-side{display:none}}.landing .hero-badge{background:color-mix(in srgb, var(--signal-live) 7%, transparent);border:1px solid var(--signal-live-track);color:var(--signal-live);font-size:12.5px;font-family:var(--font-mono);letter-spacing:.01em;border-radius:999px;align-items:center;gap:9px;margin-bottom:32px;padding:7px 15px;display:inline-flex}.landing .hero-badge .n{font-variant-numeric:tabular-nums}.landing .hero-title{position:relative}.landing .hero-h1{margin:0}.landing .hero-h1 .mk{font-family:var(--font-mono);letter-spacing:-.03em;font-weight:700}.landing .hero-flip{pointer-events:none;-webkit-user-select:none;user-select:none;opacity:.26;filter:blur(.8px);width:100%;height:clamp(44px,5.6vh,72px);position:absolute;top:100%;left:0;overflow:hidden;-webkit-mask-image:linear-gradient(#0000006b 0%,#0000001a 40%,#0000 82%);mask-image:linear-gradient(#0000006b 0%,#0000001a 40%,#0000 82%)}.landing .hero-flip>.hero-h1{transform-origin:50% 100%;width:100%;position:absolute;bottom:100%;left:0;transform:scaleY(-1)}.landing .hero-flip .grad-text{background-position:30% 0;animation:none}.landing .hero-sub{max-width:600px;font-size:var(--fs-lead);color:var(--text-muted);margin-top:clamp(62px,7.6vh,92px);line-height:1.78}.landing .hero-acts{flex-wrap:wrap;gap:14px;margin-top:38px;display:flex}.landing .trust{color:var(--text-faint);font-size:12.5px;font-family:var(--font-mono);letter-spacing:.01em;flex-wrap:wrap;gap:12px 26px;margin-top:28px;display:flex}.landing .trust span{align-items:center;gap:8px;display:inline-flex}.landing .trust span:before{content:"";background:var(--brand-400);opacity:.8;flex:0 0 5px;width:5px;height:5px;transform:rotate(45deg)}.landing .rv-line{display:block;overflow:hidden}.landing .rv-line>span{transition:transform 1.15s var(--ease-out);transition-delay:calc(var(--i,0) * .11s);display:block;transform:translateY(106%)}.landing .reveal.in .rv-line>span{transform:none}@media (prefers-reduced-motion:reduce){.landing .rv-line>span{transform:none!important}}.landing .scroll-cue{left:var(--gutter);font-family:var(--font-mono);letter-spacing:var(--track-eyebrow);text-transform:uppercase;color:var(--text-ghost);opacity:max(0, calc(1 - var(--scroll-p) * 22));align-items:center;gap:12px;font-size:9.5px;transition:opacity .2s linear;display:flex;position:absolute;bottom:34px}.landing .scroll-cue .tick{background:linear-gradient(180deg, var(--border-strong), transparent);width:1px;height:40px;position:relative;overflow:hidden}.landing .scroll-cue .tick:after{content:"";background:var(--accent-cyan);width:1px;height:14px;box-shadow:0 0 8px 1px var(--glow-cyan-mid);animation:cue-run 2.4s var(--ease-in-out) infinite;position:absolute;left:0}@keyframes cue-run{0%{opacity:0;top:-14px}25%{opacity:1}75%{opacity:1}to{opacity:0;top:40px}}@media (max-width:900px){.landing .scroll-cue{display:none}}.landing .access{border-radius:var(--radius-xl);background:linear-gradient(180deg, color-mix(in srgb, var(--bg-section-b) 96%, transparent) 0%, color-mix(in srgb, var(--bg-section-a) 94%, transparent) 100%);padding:20px 22px 22px}.landing .access-h{justify-content:space-between;align-items:center;gap:12px;display:flex}.landing .access-url{background:color-mix(in srgb, var(--bg-band) 62%, transparent);border:1px solid var(--border-default);border-radius:var(--radius-md);align-items:center;gap:12px;margin-top:14px;padding:11px 12px 11px 14px;display:flex}.landing .access-url code{min-width:0;font-family:var(--font-mono);color:var(--accent-cyan);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:12.5px;overflow:hidden}.landing .access-url .copy{height:26px;font-family:var(--font-mono);color:var(--text-muted);cursor:pointer;border:1px solid var(--border-default);border-radius:var(--radius-xs);transition:color var(--d-hover) var(--ease-out), border-color var(--d-hover) var(--ease-out);background:#ffffff0a;flex:none;padding:0 10px;font-size:11px}.landing .access-url .copy:hover{color:var(--text-primary);border-color:var(--border-strong)}.landing .access-note{color:var(--text-ghost);margin-top:12px;font-size:12px;line-height:1.7}.landing .kv{margin:18px 0 0;padding:0}.landing .kv>div{border-top:1px solid var(--border-subtle);justify-content:space-between;align-items:baseline;gap:12px;padding:9px 0;display:flex}.landing .kv>div:last-child{border-bottom:1px solid var(--border-subtle)}.landing .kv dt{color:var(--text-muted);font-size:12.5px}.landing .kv dd{font-family:var(--font-mono);color:var(--text-secondary);font-variant-numeric:tabular-nums;margin:0;font-size:12.5px}.landing .panel-wrap{border-radius:var(--radius-2xl);grid-template-columns:minmax(0,1.3fr) minmax(0,.9fr);margin-top:clamp(52px,7vh,88px);display:grid}.landing .panel-left{min-width:0}.landing .winbar{border-bottom:1px solid var(--border-subtle);background:color-mix(in srgb, var(--bg-page) 40%, transparent);align-items:center;gap:8px;padding:12px 14px 12px 18px;display:flex}.landing .winbar>i{border-radius:50%;width:10px;height:10px;display:block}.landing .winbar .fname{font-family:var(--font-mono);color:var(--text-faint);margin-left:10px;font-size:11.5px}.landing .winbar .wtag{border-radius:var(--radius-xs);font-family:var(--font-mono);letter-spacing:.1em;color:var(--text-ghost);border:1px solid var(--border-subtle);background:#ffffff0a;padding:2px 6px;font-size:9.5px}.landing .winbar .wsp{flex:1}.landing .winbar .wbtn{cursor:pointer;height:24px;font-family:var(--font-mono);color:var(--text-muted);border:1px solid var(--border-subtle);border-radius:var(--radius-xs);transition:color var(--d-hover) var(--ease-out), border-color var(--d-hover) var(--ease-out);background:#ffffff09;padding:0 10px;font-size:10.5px}.landing .winbar .wbtn:hover{color:var(--text-primary);border-color:var(--border-strong)}.landing .panel-code{font-family:var(--font-mono);padding:12px 0 16px;font-size:12.5px;line-height:1.9}.landing .cl{grid-template-columns:46px minmax(0,1fr);padding-right:20px;display:grid}.landing .cl>i{text-align:right;color:var(--text-ghost);opacity:.42;-webkit-user-select:none;user-select:none;padding-right:16px;font-style:normal}.landing .cl>span{white-space:pre;color:var(--text-tertiary);overflow-x:auto}.landing .cl.hl{background:color-mix(in srgb, var(--brand-500) 8.5%, transparent);box-shadow:inset 2px 0 0 var(--brand-500)}.landing .cl.hl>i{opacity:.72;color:var(--brand-400)}.landing .panel-code .k{color:var(--accent-cyan)}.landing .panel-code .s{color:var(--signal-live)}.landing .panel-code .c{color:var(--text-faint)}.landing .panel-code .fn{color:var(--text-primary);font-weight:500}.landing .panel-right{border-left:1px solid var(--border-subtle);background:color-mix(in srgb, var(--bg-page) 40%, transparent);padding:16px 20px 20px}.landing .pr-head{justify-content:space-between;align-items:baseline;gap:12px;padding-bottom:12px;display:flex}.landing .panel-right h4{font-family:var(--font-mono);letter-spacing:var(--track-eyebrow);text-transform:uppercase;color:var(--text-ghost);font-size:10.5px;font-weight:500}.landing .pr-count{font-family:var(--font-mono);color:var(--text-ghost);font-size:10.5px}.landing .conn{border-top:1px solid var(--border-subtle);align-items:center;gap:10px;padding:12px 0;font-size:12.5px;display:flex}.landing .conn .cname{min-width:0;color:var(--text-secondary);text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.landing .conn .dev{color:var(--text-ghost);font-size:10.5px;font-family:var(--font-mono)}.landing .conn .lat{text-align:right;font-family:var(--font-mono);color:var(--text-faint);font-variant-numeric:tabular-nums;flex:0 0 40px;font-size:10.5px}.landing .panel-metrics{border-top:1px solid var(--border-subtle);grid-template-columns:repeat(3,1fr);gap:14px;margin-top:16px;padding-top:16px;display:grid}.landing .panel-metrics .k{color:var(--text-ghost);margin-bottom:7px;font-size:10.5px}.landing .panel-metrics .v{color:var(--text-primary);font-size:19px}@media (max-width:900px){.landing .panel-wrap{grid-template-columns:1fr}.landing .panel-right{border-left:none;border-top:1px solid var(--border-subtle)}.landing .winbar .wtag,.landing .winbar .wbtn{display:none}}.landing .strip{padding-block:clamp(34px,5vh,52px);position:relative}.landing .strip .cap{color:var(--text-muted);margin-bottom:20px;font-size:13.5px}.landing .strip .cap b{color:var(--text-secondary);font-weight:600}.landing .logos{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:18px 30px;display:flex}.landing .logos span{font-family:var(--font-display);color:var(--text-faint);letter-spacing:.01em;transition:color var(--d-panel) var(--ease-out);font-size:16px;font-weight:600}.landing .logos span:hover{color:var(--text-tertiary)}.landing .logos span.cn{font-family:var(--font-body);color:var(--text-muted);font-size:15px;font-weight:500}.landing .split{grid-template-columns:440px minmax(0,1fr);align-items:start;gap:clamp(40px,5vw,76px);display:grid}.landing .split-l{position:sticky;top:124px}.landing .split-l .display-2{margin:20px 0 18px;font-size:clamp(26px,2.6vw,40px)}.landing .split-l p{color:var(--text-muted);font-size:14px;line-height:1.8}@media (max-width:980px){.landing .split{grid-template-columns:1fr;gap:32px}.landing .split-l{position:static}}.landing .linelist{margin:0;padding:0;list-style:none}.landing .linelist li{border-top:1px solid var(--border-subtle);gap:20px;padding:28px 0;display:flex}.landing .linelist li:last-child{border-bottom:1px solid var(--border-subtle)}.landing .linelist li:first-child{border-top-color:var(--border-default)}.landing .ll-ico{border-radius:var(--radius-md);background:var(--bg-surface-2-grad);border:1px solid var(--border-default);flex:0 0 40px;justify-content:center;align-items:center;width:40px;height:40px;display:flex}.landing .ll-tx b{color:var(--text-primary);margin-bottom:8px;font-size:15.5px;font-weight:600;display:block}.landing .ll-tx i{color:var(--text-tertiary);font-size:13.5px;font-style:normal;line-height:1.75}.landing .steps{grid-template-columns:repeat(3,1fr);margin:0;padding:0;list-style:none;display:grid}.landing .steps li{padding-right:44px;position:relative}.landing .steps li:before{content:"";background:linear-gradient(90deg, color-mix(in srgb, var(--iris) 34%, transparent) 0%, color-mix(in srgb, var(--iris) 34%, transparent) 36%, var(--glow-cyan-core) 50%, color-mix(in srgb, var(--accent-cyan) 30%, transparent) 64%, color-mix(in srgb, var(--accent-cyan) 30%, transparent) 100%);height:1px;animation:4.6s linear infinite step-flow;animation-delay:calc(var(--i,0) * .55s);background-size:280% 100%;position:absolute;top:23px;left:56px;right:12px}.landing .steps li:after{content:"";background:color-mix(in srgb, var(--iris) 70%, transparent);border-radius:50%;width:5px;height:5px;position:absolute;top:20.5px;left:56px}.landing .steps li:last-child:before,.landing .steps li:last-child:after{display:none}@keyframes step-flow{0%{background-position:140% 0}to{background-position:-140% 0}}.landing .st-n{z-index:1;border-radius:var(--radius-lg);width:46px;height:46px;font-family:var(--font-mono);color:var(--brand-400);background:var(--bg-surface-2-grad);border:1px solid var(--border-default);font-variant-numeric:tabular-nums;justify-content:center;align-items:center;font-size:14px;display:flex;position:relative}.landing .steps h3{color:var(--text-primary);margin:22px 0 10px;font-size:16px;font-weight:600}.landing .steps p{color:var(--text-muted);font-size:13.5px;line-height:1.75}.landing .steps .cmd{font-family:var(--font-mono);color:var(--accent-cyan);background:var(--bg-code);border:1px solid var(--border-default);border-radius:var(--radius-sm);white-space:nowrap;margin-top:16px;padding:10px 12px;font-size:11.5px;overflow-x:auto}@media (max-width:900px){.landing .steps{grid-template-columns:1fr;gap:34px}.landing .steps li{padding-right:0}.landing .steps li:before,.landing .steps li:after{display:none}}.landing .term{border:1px solid var(--border-subtle);border-radius:var(--radius-lg);background:color-mix(in srgb, var(--bg-band) 66%, transparent);margin-top:clamp(38px,5vh,62px);overflow:hidden}.landing .term-bar{border-bottom:1px solid var(--border-subtle);background:color-mix(in srgb, var(--bg-page) 52%, transparent);font-family:var(--font-mono);letter-spacing:.02em;color:var(--text-faint);align-items:center;gap:9px;padding:12px 18px;font-size:11px;display:flex}.landing .term-tag{color:var(--text-ghost);margin-left:auto}.landing .term-body{font-family:var(--font-mono);padding:15px 20px 17px;font-size:12.5px;line-height:2.05}.landing .tl{color:var(--text-tertiary)}.landing .tl .pr{color:var(--brand-400);margin-right:9px}.landing .tl.out{color:var(--text-muted)}.landing .tl.ok,.landing .tl .hl{color:var(--signal-live)}@media (max-width:720px){.landing .term-body{font-size:11.5px;line-height:1.95}.landing .tl{word-break:break-all}}.landing .cfg{flex-direction:column;padding:22px;display:flex}.landing .cfg h3{margin-bottom:7px;font-size:16px;font-weight:600}.landing .cfg .sub{color:var(--text-faint);font-size:11.5px;font-family:var(--font-mono);white-space:nowrap;text-overflow:ellipsis;margin-bottom:18px;overflow:hidden}.landing .cfg .code{white-space:pre-wrap;overflow-wrap:anywhere;flex:1;font-size:10.5px;line-height:1.8}.landing .specbar{background:var(--bg-surface);border:1px solid var(--border-subtle);border-radius:var(--radius-lg);grid-template-columns:repeat(4,1fr);margin-top:22px;display:grid;overflow:hidden}.landing .specbar>div{border-right:1px solid var(--border-subtle);padding:17px 20px}.landing .specbar>div:last-child{border-right:none}.landing .specbar .k{color:var(--text-muted);margin-bottom:9px;font-size:11.5px}.landing .specbar .v{font-family:var(--font-mono);color:var(--text-primary);font-size:14px}@media (max-width:720px){.landing .specbar{grid-template-columns:repeat(2,1fr)}.landing .specbar>div:nth-child(2){border-right:none}.landing .specbar>div:nth-child(-n+2){border-bottom:1px solid var(--border-subtle)}}.landing .cfg-note{background:var(--bg-surface);border:1px solid var(--border-subtle);border-radius:var(--radius-lg);margin-top:18px;padding:16px 20px}.landing .cfg-note-row{border-bottom:1px solid var(--border-subtle);grid-template-columns:132px 1fr;align-items:baseline;gap:6px 14px;padding:9px 0;display:grid}.landing .cfg-note-row .k{color:var(--text-muted);font-size:12.5px}.landing .cfg-note-row code{font-family:var(--font-mono);color:var(--text-primary);font-size:12.5px}.landing .cfg-note-row .v{color:var(--text-tertiary);grid-column:2;font-size:12px}.landing .cfg-note-row .v b{color:var(--text-primary);font-weight:600}.landing .cfg-note-foot{color:var(--text-tertiary);margin-top:12px;font-size:12px;line-height:1.7}.landing .cfg-note-foot:first-of-type{margin-top:14px}.landing .cfg-note-foot code{font-family:var(--font-mono);color:var(--text-primary);overflow-wrap:anywhere;font-size:11.5px}.landing .cfg-note-foot b{color:var(--text-secondary);font-weight:600}@media (max-width:720px){.landing .cfg-note-row{grid-template-columns:1fr}.landing .cfg-note-row .v{grid-column:1}}.landing .band{background:linear-gradient(180deg, transparent 0%, color-mix(in srgb, var(--bg-page) 62%, transparent) 18%, color-mix(in srgb, var(--bg-page) 62%, transparent) 82%, transparent 100%);position:relative}.landing .status-strip{text-align:center;grid-template-columns:repeat(4,1fr);display:grid}.landing .status-strip>div{padding:6px 12px;position:relative}.landing .status-strip>div+div:before{content:"";background:var(--border-subtle);width:1px;position:absolute;top:12%;bottom:12%;left:0}.landing .status-strip .v{color:var(--text-primary);font-size:clamp(34px,4vw,54px);line-height:1}.landing .status-strip .v.live{color:var(--signal-live)}.landing .status-strip .k{color:var(--text-muted);margin-top:14px;font-size:12.5px}@media (max-width:720px){.landing .status-strip{grid-template-columns:repeat(2,1fr);gap:30px 0}.landing .status-strip>div:nth-child(odd):before{display:none}}.landing .cta{text-align:center;padding-block:clamp(96px,15vh,172px);position:relative}.landing .cta:before{content:"";background:radial-gradient(58% 66% at 50% 50%, color-mix(in srgb, var(--bg-band) 88%, transparent) 0%, color-mix(in srgb, var(--bg-band) 55%, transparent) 46%, transparent 76%);pointer-events:none;position:absolute;inset:0}.landing .cta>.wrap{position:relative}.landing .cta h2{max-width:720px;margin:0 auto}.landing .cta .cmdbox{background:color-mix(in srgb, var(--bg-band) 70%, transparent);border:1px solid var(--border-strong);border-radius:var(--radius-lg);font-family:var(--font-mono);color:var(--signal-live);box-shadow:0 0 0 1px color-mix(in srgb, var(--signal-live) 6%, transparent), 0 24px 60px -34px color-mix(in srgb, var(--signal-live) 50%, transparent);align-items:center;gap:12px;margin:32px auto 26px;padding:15px 28px;font-size:15px;display:inline-flex}.landing .cta .cmdbox .pr{color:var(--text-ghost)}.landing .cmdbox .typing:after{content:"";vertical-align:-2px;background:var(--accent-cyan);width:7px;height:1em;margin-left:3px;animation:1s step-end infinite caret;display:inline-block}@keyframes caret{50%{opacity:0}}@media (prefers-reduced-motion:reduce){.landing .cmdbox .typing:after{animation:none}}.landing .cta p.note{color:var(--text-muted);max-width:620px;margin:0 auto;font-size:14px;line-height:1.8}.landing .cta .acts{flex-wrap:wrap;justify-content:center;gap:14px;margin-top:32px;display:flex}.landing .cta .trust{justify-content:center}.landing .footer{padding-block:72px 40px}.landing .foot-top{grid-template-columns:minmax(0,1.6fr) minmax(0,1fr) minmax(0,1fr);gap:44px;display:grid}.landing .foot-brand p{color:var(--text-muted);max-width:340px;margin:20px 0 22px;font-size:13.5px;line-height:1.85}.landing .foot-col h5{color:var(--text-muted);font-size:11.5px;font-weight:500;font-family:var(--font-mono);letter-spacing:var(--track-eyebrow);text-transform:uppercase;margin-bottom:18px}.landing .foot-col a{color:var(--text-faint);transition:color var(--d-hover) var(--ease-out);font-size:13px;line-height:2.2;display:block}.landing .foot-col a:hover{color:var(--text-secondary)}.landing .foot-bar{border-top:1px solid var(--border-subtle);color:var(--text-ghost);flex-wrap:wrap;justify-content:space-between;gap:10px 28px;margin-top:56px;padding-top:24px;font-size:12px;display:flex}@media (max-width:900px){.landing .foot-top{grid-template-columns:1fr 1fr}.landing .foot-brand{grid-column:1/-1}}.landing .rail{align-items:flex-end}.landing .rail a{flex-direction:row-reverse;align-items:center;gap:9px;display:flex}.landing .rail a b{font-family:var(--font-mono);letter-spacing:var(--track-eyebrow);text-transform:uppercase;color:#0000;white-space:nowrap;transition:color var(--d-panel) var(--ease-out);font-size:9.5px}.landing .rail a:hover b,.landing .rail a.on b{color:var(--text-faint)}.landing .rail a i{transition:background var(--d-panel) var(--ease-out), box-shadow var(--d-panel) var(--ease-out)}html.relay-landing{overflow-x:hidden}.landing{overflow-x:visible}.landing .nav{height:auto;box-shadow:none;-webkit-backdrop-filter:none;backdrop-filter:none;background:0 0}.landing .nav:before,.landing .nav:after{content:none}.landing .section{padding-inline:0}.landing .section:after{content:none}.landing .eyebrow{margin-bottom:0;font-weight:400}.landing .pill{font-weight:400}.landing .note{background:0 0;border:0;padding:0;display:block}.landing .btn:hover{transform:none}.landing h5{margin:revert}.landing .glass{-webkit-backdrop-filter:blur(var(--glass-blur)) saturate(150%);backdrop-filter:blur(var(--glass-blur)) saturate(150%)}.landing .glass-soft{-webkit-backdrop-filter:blur(calc(var(--glass-blur) * .6));backdrop-filter:blur(calc(var(--glass-blur) * .6))}.landing .nav.stuck{-webkit-backdrop-filter:blur(16px)saturate(140%);backdrop-filter:blur(16px)saturate(140%)}.landing .nav{justify-content:normal}.landing .nav-links{color:var(--text-secondary)}.landing .hero>.wrap{z-index:auto;position:static}.landing .note{border-radius:0;gap:normal}.landing .btn{justify-content:normal}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{B as e,N as t,U as n,_ as r,et as i,i as a,it as o,o as s,r as c,tt as l}from"./vendor-befEYGHM.js";import{O as u,_ as d,b as f,f as p,g as m,h,i as g,j as _,k as v,m as y,n as b,p as x,s as S}from"./index-VH6Gc3-s.js";import{a as C,c as w,i as T,n as E,r as D,s as O,t as k}from"./Select-BxZGnteq.js";import{r as A}from"./PageSkeleton-DG-Dj4_9.js";import{t as j}from"./useFx-xcrp_LHB.js";import{n as M,r as N,t as P}from"./ClientMetricTip-D-pXFJpS.js";var F=o(),I=l();function L({navigate:o}){let[l,L]=(0,F.useState)(`today`),R=_(()=>S.overview(l),[l],{cacheKey:`overview:${l}`});j(`overview-${l}-${R.data?`ready`:`pending`}`);let z=R.data,B={today:(()=>{let e=new Date;return e.getHours()*60+e.getMinutes()||1})(),"1h":60,"24h":1440,"7d":10080,"30d":43200},V=z?B[z.window]:null,H=z&&V?z.metrics.requests/V:null,U=z&&V?z.metrics.totalTokens/V:null,W=e=>{if(!z||z.byClient.length===0)return;let t=[...z.byClient].sort((t,n)=>(n[e]??0)-(t[e]??0));return(0,I.jsx)(P,{rows:t,metric:e,windowLabel:u[z.window],total:e===`credits`?z.metrics.creditsUsed:z.metrics.requests,totalCount:t.length})};return(0,I.jsxs)(`div`,{className:`view on`,children:[(0,I.jsx)(O,{title:`概览`,status:z?(0,I.jsxs)(w,{tone:`live`,dot:!0,children:[`本机日志聚合 · `,d(z.generatedAt)]}):null,actions:(0,I.jsxs)(I.Fragment,{children:[(0,I.jsx)(k,{value:l,options:v,onChange:L,width:148}),(0,I.jsxs)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,onClick:()=>o(`keys`),children:[(0,I.jsx)(r,{size:14}),`新建密钥`]})]})}),(0,I.jsx)(`div`,{className:`view-body stack`,children:R.initial&&R.loading?(0,I.jsx)(A,{}):R.error?(0,I.jsx)(C,{children:(0,I.jsx)(E,{kind:`error`,title:`概览数据没取到`,detail:D(R.error),onRetry:R.reload})}):z?(0,I.jsxs)(I.Fragment,{children:[z.alerts.channelReject.count>=z.alerts.channelReject.threshold?(0,I.jsxs)(b,{tone:`warn`,children:[(0,I.jsx)(c,{size:14,"aria-hidden":!0}),`最近 1 小时出现 `,(0,I.jsxs)(`b`,{children:[z.alerts.channelReject.count,` 次`]}),`上游渠道校验拒绝(11128): 请求的 system 提示命中了上游的第三方客户端指纹。本服务会自动改写模板行、被拒时降级重试, 连续失败说明出现了新的指纹变体。请到「请求日志」筛 note 含 upstream_11128 的行排查。`]}):null,(0,I.jsx)(N,{metrics:z.metrics}),(0,I.jsxs)(`div`,{className:`metric-row`,children:[(0,I.jsx)(T,{label:`请求数`,value:h(z.metrics.requests),detail:`窗口:${u[z.window]}`,tone:`cyan`,icon:(0,I.jsx)(i,{size:14}),tip:W(`requests`),tipPos:`down`}),(0,I.jsx)(T,{label:`平均 RPM`,value:H===null?`—`:h(Math.round(H)),detail:`每分钟请求 · ${u[z.window]}`,tone:`violet`,icon:(0,I.jsx)(t,{size:14})}),(0,I.jsx)(T,{label:`平均 TPM`,value:U===null?`—`:f(Math.round(U)),detail:`每分钟 tokens · ${u[z.window]}`,tone:`green`,icon:(0,I.jsx)(a,{size:14})}),(0,I.jsx)(T,{label:`已消耗积分`,value:p(z.metrics.creditsUsed),detail:z.metrics.creditsUnknownCount>0?`上游实扣 · 另 ${h(z.metrics.creditsUnknownCount)} 条上游未回报,未计入`:`上游实扣 · 全部请求均已回报`,tone:`amber`,icon:(0,I.jsx)(e,{size:14}),tip:W(`credits`),tipPos:`down`}),(0,I.jsx)(T,{label:`请求成功率`,value:m(z.metrics.successRate),detail:`重试后成功按 200 计入`,tone:z.metrics.successRate<.95?`warn`:`blue`,icon:(0,I.jsx)(n,{size:14})}),(0,I.jsx)(T,{label:`平均耗时`,value:y(z.metrics.avgLatencyMs),detail:`${h(z.metrics.activeClients)} 个密钥活跃`,tone:`rose`,icon:(0,I.jsx)(s,{size:14})})]}),z.creditLedgers.length>0?(0,I.jsxs)(C,{title:`积分账本`,aside:(0,I.jsx)(w,{children:`上游账本 · 精确到 0.01`}),children:[(0,I.jsx)(`div`,{className:`tbl-scroll`,children:(0,I.jsxs)(`table`,{className:`tbl`,children:[(0,I.jsx)(`thead`,{children:(0,I.jsxs)(`tr`,{children:[(0,I.jsx)(`th`,{scope:`col`,children:`提供商`}),(0,I.jsx)(`th`,{scope:`col`,className:`r`,children:`剩余积分`}),(0,I.jsx)(`th`,{scope:`col`,className:`r`,children:`已消耗`}),(0,I.jsx)(`th`,{scope:`col`,className:`r`,children:`累计发放`}),(0,I.jsx)(`th`,{scope:`col`,children:`最近过期`})]})}),(0,I.jsx)(`tbody`,{children:z.creditLedgers.map(e=>(0,I.jsxs)(`tr`,{children:[(0,I.jsxs)(`td`,{className:`td-strong`,children:[e.providerName,e.stale?(0,I.jsx)(w,{tone:`ghost`,children:`数据偏旧`}):null]}),(0,I.jsx)(`td`,{className:`r td-mono`,children:e.remaining===null?`—`:p(e.remaining)}),(0,I.jsx)(`td`,{className:`r td-mono`,children:e.consumed===null?`—`:p(e.consumed)}),(0,I.jsx)(`td`,{className:`r td-mono`,children:e.granted===null?`—`:p(e.granted)}),(0,I.jsx)(`td`,{className:`td-sub td-mono`,children:e.nextExpireAt?x(e.nextExpireAt):`—`})]},e.providerId))})]})}),(0,I.jsxs)(`div`,{className:`footer-note`,children:[`各家口径不同:`,(0,I.jsx)(`b`,{children:`MiniMax`}),` 来自 credit/details(余额/已用/发放齐全,精确到 0.01);`,(0,I.jsx)(`b`,{children:`WorkBuddy`}),` 来自资源包聚合(get-user-resource,剩余/发放为包级真实数);`,(0,I.jsx)(`b`,{children:`Qoder`}),` 来自 me/usage(套餐内 + 资源包合计,签到赠送进资源包)—— 到期时刻上游不提供,该列显示「—」。三家都含官方客户端直连的消耗,比「已消耗积分」卡的逐条统计更全。`]})]}):null,(0,I.jsx)(C,{title:`提供商用量摘要`,aside:(0,I.jsxs)(w,{children:[z.byClient.length,` 个提供商 · 按 Token 排序`]}),children:z.byClient.length>0?(0,I.jsx)(`div`,{className:`tbl-scroll`,children:(0,I.jsxs)(`table`,{className:`tbl`,children:[(0,I.jsxs)(`caption`,{className:`sr-only`,children:[`提供商用量摘要,共 `,z.byClient.length,` 个提供商`]}),(0,I.jsx)(`thead`,{children:(0,I.jsxs)(`tr`,{children:[(0,I.jsx)(`th`,{scope:`col`,children:`提供商`}),(0,I.jsx)(`th`,{scope:`col`,className:`r`,children:`请求次数`}),(0,I.jsx)(`th`,{scope:`col`,className:`r`,children:`Token 消耗`}),(0,I.jsx)(`th`,{scope:`col`,className:`r`,children:`消耗积分`}),(0,I.jsx)(`th`,{scope:`col`,className:`r`,children:`Token 占比`}),(0,I.jsx)(`th`,{scope:`col`,children:`分布`})]})}),(0,I.jsx)(`tbody`,{children:[...z.byClient].sort((e,t)=>(t.tokens??0)-(e.tokens??0)).slice(0,6).map(e=>(0,I.jsxs)(`tr`,{children:[(0,I.jsx)(`td`,{className:`td-strong`,children:(0,I.jsx)(g,{content:(0,I.jsx)(M,{row:e}),children:(0,I.jsx)(`span`,{children:e.client??`未识别`})})}),(0,I.jsx)(`td`,{className:`r td-mono`,children:h(e.requests)}),(0,I.jsx)(`td`,{className:`r td-mono`,children:f(e.tokens??0)}),(0,I.jsx)(`td`,{className:`r td-mono`,children:p(e.credits)}),(0,I.jsx)(`td`,{className:`r td-mono`,children:m(e.share)}),(0,I.jsx)(`td`,{children:(0,I.jsx)(`div`,{className:`ov-bar-track`,children:(0,I.jsx)(`div`,{className:`ov-bar-fill`,style:{width:`${Math.max(2,Math.round((e.share??0)*100))}%`}})})})]},e.clientId??e.client??`unknown`))})]})}):(0,I.jsxs)(`div`,{className:`empty-note`,style:{padding:`24px 0`},children:[u[z.window],`没有提供商消耗记录。`]})}),(0,I.jsxs)(C,{title:`模型用量摘要`,aside:(0,I.jsxs)(w,{children:[z.byModel.length,` 个模型 · 按 Token 排序`]}),children:[z.byModel.length>0?(0,I.jsx)(`div`,{className:`tbl-scroll`,children:(0,I.jsxs)(`table`,{className:`tbl`,children:[(0,I.jsxs)(`caption`,{className:`sr-only`,children:[`模型用量摘要,共 `,z.byModel.length,` 个模型`]}),(0,I.jsx)(`thead`,{children:(0,I.jsxs)(`tr`,{children:[(0,I.jsx)(`th`,{scope:`col`,children:`模型`}),(0,I.jsx)(`th`,{scope:`col`,className:`r`,children:`请求次数`}),(0,I.jsx)(`th`,{scope:`col`,className:`r`,children:`Token 消耗`}),(0,I.jsx)(`th`,{scope:`col`,className:`r`,children:`消耗积分`}),(0,I.jsx)(`th`,{scope:`col`,className:`r`,children:`Token 占比`}),(0,I.jsx)(`th`,{scope:`col`,children:`分布`})]})}),(0,I.jsx)(`tbody`,{children:[...z.byModel].sort((e,t)=>(t.tokens??0)-(e.tokens??0)).slice(0,8).map(e=>{let t=e.displayName??e.model??`未知`;return(0,I.jsxs)(`tr`,{children:[(0,I.jsx)(`td`,{className:`td-strong`,children:t}),(0,I.jsx)(`td`,{className:`r td-mono`,children:h(e.requests)}),(0,I.jsx)(`td`,{className:`r td-mono`,children:f(e.tokens??0)}),(0,I.jsx)(`td`,{className:`r td-mono`,children:p(e.credits)}),(0,I.jsx)(`td`,{className:`r td-mono`,children:m(e.share)}),(0,I.jsx)(`td`,{children:(0,I.jsx)(`div`,{className:`ov-bar-track`,children:(0,I.jsx)(`div`,{className:`ov-bar-fill`,style:{width:`${Math.max(2,Math.round((e.share??0)*100))}%`}})})})]},e.model??t)})})]})}):(0,I.jsxs)(`div`,{className:`empty-note`,style:{padding:`24px 0`},children:[u[z.window],`没有模型消耗记录。`]}),(0,I.jsx)(`div`,{className:`footer-note`,children:`这一页只留结论。详细构成去「积分与用量」,逐条请求去「请求日志」。`})]}),(0,I.jsx)(`div`,{className:`footer-note`,style:{marginTop:0},children:z.provenance.note})]}):null})]})}export{L as OverviewPage};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import{B as e,C as t,D as n,G as r,K as i,M as a,N as o,R as s,V as c,W as l,X as u,Z as d,et as f,it as p,j as m,o as h,q as g,tt as _,u as ee}from"./vendor-befEYGHM.js";import{C as v,E as y,M as te,S as b,T as x,c as S,d as C,f as w,g as ne,h as T,i as E,j as D,m as O,n as re,p as k,s as A,w as j,x as ie,y as M}from"./index-VH6Gc3-s.js";import{a as N,c as P,n as F,o as ae,r as I,s as oe,t as L}from"./Select-BxZGnteq.js";import{i as se}from"./PageSkeleton-DG-Dj4_9.js";import{t as ce}from"./Drawer-CleQGhRU.js";import{t as le}from"./useFx-xcrp_LHB.js";var R=p();function ue(e,t=320){let[n,r]=(0,R.useState)(e);return(0,R.useEffect)(()=>{let n=window.setTimeout(()=>r(e),t);return()=>window.clearTimeout(n)},[e,t]),n}var z=_(),B=[20,50,100];function de({page:e,limit:t,total:n,onPage:a,onLimit:o}){let s=Math.max(1,Math.ceil(n/t)),c=[],l=e=>{c[c.length-1]!==e&&c.push(e)},u=[1,e-1,e,e+1,s].filter(e=>e>=1&&e<=s).sort((e,t)=>e-t),d=0;return u.forEach(e=>{e-d>1&&l(`…`),l(e),d=e}),(0,z.jsxs)(`div`,{className:`pager`,children:[(0,z.jsxs)(`span`,{className:`txt`,children:[`第 `,e,` / `,s,` 页 · 每页 `,t,` 条,共 `,T(n),` 条`]}),(0,z.jsxs)(`span`,{className:`btns`,children:[(0,z.jsx)(L,{value:String(t),options:B.map(e=>({value:String(e),label:`${e} / 页`})),onChange:e=>o(Number(e)),size:`sm`,width:92,ariaLabel:`每页条数`}),(0,z.jsx)(`button`,{type:`button`,className:`pg`,disabled:e<=1,onClick:()=>a(e-1),"aria-label":`上一页`,children:(0,z.jsx)(r,{size:13})}),c.map((t,n)=>t===`…`?(0,z.jsx)(`span`,{className:`pg`,style:{cursor:`default`,background:`transparent`,border:`none`},children:`…`},`gap-${n}`):(0,z.jsx)(`button`,{type:`button`,className:`pg${t===e?` on`:``}`,onClick:()=>a(t),children:t},t)),(0,z.jsx)(`button`,{type:`button`,className:`pg`,disabled:e>=s,onClick:()=>a(e+1),"aria-label":`下一页`,children:(0,z.jsx)(i,{size:13})})]})]})}function V(e){let t=e.toLowerCase();return t.includes(`python`)||t.includes(`httpx`)||t.includes(`aiohttp`)?`python`:t.includes(`node`)||t.includes(`deno`)||t.includes(`bun`)||t.includes(`axios`)||t.includes(`undici`)?`node`:t.includes(`curl`)||t.includes(`wget`)||t.includes(`http`)?`terminal`:t.includes(`sdk`)?`sdk`:`cli`}var H=`M11.9 0C8.7 0 8.4 1.7 8.4 1.7v2.4h3.6v.7H5.3S2.4 4.5 2.4 8.4c0 3.8 2.5 3.7 2.5 3.7h1.5v-2.2s-.1-2.5 2.6-2.5h3.6s2.6 0 2.6-2.5V2.1S15.4 0 11.9 0zM9.3 1.5a.9.9 0 1 1 0 1.7.9.9 0 0 1 0-1.7zm6.3 3.4v2.3s.1 2.6-2.6 2.6H9.4s-2.5 0-2.5 2.5v4.4s-.2 2.7 4.8 2.7 4.7-2.3 4.7-2.3v-2.1h-3.6v-.7h6.7s3.2.3 3.2-3.7c0-4-2.8-3.8-2.8-3.8h-1.6v2.3s.1 2.6-2.6 2.6h-3.5s-2.4 0-2.4 2.4v4.1s-.4 2.4 4.4 2.4 4.5-2.1 4.5-2.1v-2h-3.4v-.7h6.6s3.4.4 3.4-3.9c0-4.3-2.9-4.1-2.9-4.1zM14.6 21.9a.9.9 0 1 1 0 1.8.9.9 0 0 1 0-1.8z`,U=`M12 1.5c-.3 0-.6.1-.9.3L3.4 6.4c-.5.3-.9.9-.9 1.5v8.2c0 .6.4 1.2.9 1.5l2 1.2c1 .5 1.8.1 1.8-1v-9c0-.7.5-1.2 1.2-1.2h7c.7 0 1.2.5 1.2 1.2v9c0 1.1.8 1.5 1.8 1l2-1.2c.5-.3.9-.9.9-1.5V7.9c0-.6-.4-1.2-.9-1.5L12.9 1.8c-.3-.2-.6-.3-.9-.3zm5.1 6c-.6 0-1.1.5-1.1 1.1v6.8c0 .6.5 1.1 1.1 1.1h5.2l-1.9 3.3 2.7-1.6c.5-.3.9-.9.9-1.5V7.9c0-.6-.4-1.2-.9-1.5l-7.7-4.6`,W=`M5 7l5 5-5 5m7 0h7`,G=`M14.7 6.3a5 5 0 0 0-6.9 6l-6.1 6.1a2 2 0 1 0 2.8 2.8l6.1-6.1a5 5 0 0 0 6-6.9l-3.2 3.2-2.8-2.8 3.1-3.1z`,K=`M8 6l-6 6 6 6m8-12l6 6-6 6`;function q({tool:e,size:t=14,style:n}){let r=e?V(e):`none`;if(r===`none`)return(0,z.jsxs)(`svg`,{width:t,height:t,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`1.8`,strokeLinecap:`round`,strokeLinejoin:`round`,className:`ua-ico ${r}`,style:n,"aria-hidden":`true`,children:[(0,z.jsx)(`circle`,{cx:`12`,cy:`12`,r:`10`}),(0,z.jsx)(`path`,{d:`M2 12h20`}),(0,z.jsx)(`path`,{d:`M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z`})]});if(r===`python`||r===`node`){let e=r===`python`?H:U;return(0,z.jsx)(`svg`,{width:t,height:t,viewBox:`0 0 24 24`,fill:`currentColor`,className:`ua-ico ${r}`,style:n,"aria-hidden":`true`,children:(0,z.jsx)(`path`,{d:e})})}let i=r===`terminal`?W:r===`sdk`?G:K;return(0,z.jsx)(`svg`,{width:t,height:t,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`1.8`,strokeLinecap:`round`,strokeLinejoin:`round`,className:`ua-ico ${r}`,style:n,"aria-hidden":`true`,children:(0,z.jsx)(`path`,{d:i})})}var J={live:`var(--text-tertiary)`,warn:`var(--warn-amber)`,fatal:`var(--danger-red)`,muted:`var(--text-faint)`},Y={live:`var(--signal-live)`,warn:`var(--warn-amber)`,fatal:`var(--danger-red)`,muted:`var(--text-faint)`};function X(e,t){if(!e)return!1;let n=e=>e.toLowerCase().replace(/[^a-z0-9]/g,``),r=n(e.trim().split(/[\s/]/)[0]??``);return r?t.split(/[\s.\-_/]+/).map(n).filter(e=>e.length>=3).some(e=>r.includes(e)):!1}function Z(e){let t=new Date(e);return Number.isNaN(t.getTime())?`--`:t.toLocaleDateString(`zh-CN`)}function fe({rows:t,activeId:r,onOpen:l,resolveClientName:u,modelTagOf:d,providerOfModel:p}){return(0,z.jsx)(`div`,{className:`tbl-scroll`,children:(0,z.jsxs)(`table`,{className:`tbl`,children:[(0,z.jsxs)(`caption`,{className:`sr-only`,children:[`请求日志,共 `,t.length,` 条当前筛选结果`]}),(0,z.jsx)(`thead`,{children:(0,z.jsxs)(`tr`,{children:[(0,z.jsx)(`th`,{"aria-hidden":`true`}),(0,z.jsxs)(`th`,{scope:`col`,children:[(0,z.jsx)(c,{size:12}),`请求时间`]}),(0,z.jsxs)(`th`,{scope:`col`,children:[(0,z.jsx)(n,{size:12}),`令牌`]}),(0,z.jsxs)(`th`,{scope:`col`,children:[(0,z.jsx)(s,{size:12}),`模型 / 提供商`]}),(0,z.jsxs)(`th`,{scope:`col`,children:[(0,z.jsx)(m,{size:12}),`User Agent`]}),(0,z.jsxs)(`th`,{scope:`col`,className:`r`,children:[(0,z.jsx)(f,{size:12}),`状态`]}),(0,z.jsxs)(`th`,{scope:`col`,className:`r`,children:[(0,z.jsx)(h,{size:12}),`耗时`]}),(0,z.jsxs)(`th`,{scope:`col`,className:`r`,children:[(0,z.jsx)(o,{size:12}),`输出速度`]}),(0,z.jsxs)(`th`,{scope:`col`,className:`r`,children:[(0,z.jsx)(e,{size:12}),`Tokens`]}),(0,z.jsxs)(`th`,{scope:`col`,className:`r`,children:[(0,z.jsx)(a,{size:12}),`积分`]})]})}),(0,z.jsx)(`tbody`,{children:t.map(e=>{let t=x(e.status,e.note),n=v(e.note),a=e.modelDisplay||e.model;return(0,z.jsxs)(`tr`,{onClick:()=>l(e),className:r===e.id?`row-on`:void 0,style:{cursor:`pointer`,background:r===e.id?`var(--brand-tint)`:t===`fatal`?`color-mix(in srgb, var(--danger-red) 5%, transparent)`:void 0},children:[(0,z.jsx)(`td`,{className:`row-x-td`,children:(0,z.jsx)(`button`,{type:`button`,className:`row-open`,"aria-label":`打开 ${Z(e.ts)} ${C(e.ts)} 的请求详情`,onClick:t=>{t.stopPropagation(),l(e)},children:(0,z.jsx)(i,{size:14,className:`row-x`,"aria-hidden":`true`})})}),(0,z.jsxs)(`td`,{children:[(0,z.jsx)(`div`,{className:`cell-date`,children:Z(e.ts)}),(0,z.jsx)(`div`,{className:`td-mono`,style:{color:`var(--text-ghost)`},children:C(e.ts)})]}),(0,z.jsx)(`td`,{className:`td-mono`,style:{color:`var(--text-tertiary)`},children:(0,z.jsx)(E,{content:`密钥 ${e.keyHint}`,placement:`below`,children:(0,z.jsx)(`span`,{children:e.keyHint})})}),(0,z.jsxs)(`td`,{children:[(0,z.jsx)(`div`,{className:`td-strong`,children:a}),(0,z.jsxs)(`div`,{className:`model-meta`,children:[(0,z.jsx)(E,{content:`提供商:${p(e.model)??u(e)}(按模型目录归属解析)`,children:(0,z.jsx)(`span`,{className:`prov-pill`,children:p(e.model)??u(e)})}),d(e.model)?(0,z.jsx)(`span`,{className:`mu-tag`,children:d(e.model)}):null]})]}),(0,z.jsx)(`td`,{className:`td-ua`,children:e.ua?(0,z.jsx)(E,{content:e.ua,children:(0,z.jsxs)(`span`,{style:{display:`block`},children:[(0,z.jsxs)(`span`,{className:`ua-raw`,children:[(0,z.jsx)(q,{tool:e.tool,size:14,style:{marginRight:5,verticalAlign:-2}}),e.ua]}),e.tool&&!X(e.ua,e.tool)?(0,z.jsx)(`div`,{className:`ua-tool`,children:e.tool}):e.tool?null:(0,z.jsx)(`div`,{className:`ua-tool`,children:(0,z.jsx)(`span`,{style:{color:`var(--text-ghost)`},children:`未识别`})})]})}):(0,z.jsxs)(z.Fragment,{children:[(0,z.jsx)(`span`,{className:`ua-raw`,style:{color:`var(--text-ghost)`},children:`未采集`}),e.tool?(0,z.jsx)(`div`,{className:`ua-tool`,children:e.tool}):(0,z.jsx)(`div`,{className:`ua-tool`,children:(0,z.jsx)(`span`,{style:{color:`var(--text-ghost)`},children:`未识别`})})]})}),(0,z.jsx)(`td`,{className:`r td-mono`,style:{color:J[t]},children:n.length>0?(0,z.jsx)(E,{content:n.join(` · `),children:(0,z.jsxs)(`span`,{children:[(0,z.jsx)(`span`,{className:`dotc`,style:{background:Y[t]},"aria-hidden":`true`}),e.status]})}):(0,z.jsxs)(z.Fragment,{children:[(0,z.jsx)(`span`,{className:`dotc`,style:{background:Y[t]},"aria-hidden":`true`}),e.status]})}),(0,z.jsxs)(`td`,{className:`r td-mono`,children:[(0,z.jsx)(`div`,{children:(0,z.jsx)(E,{content:`首字耗时 —— 从发出请求到收到第一个内容块的等待
|
|
2
|
-
(含上游排队与思考时间;失败行没有首字)`,children:(0,z.jsx)(`span`,{className:`cell-sub`,children:e.firstByteMs===null?`无首字`:`首字 ${O(e.firstByteMs)}`})})}),(0,z.jsx)(`div`,{children:(0,z.jsx)(E,{content:`总耗时 —— 从发出请求到流结束`,children:(0,z.jsxs)(`span`,{children:[`耗时 `,O(e.ms)]})})})]}),(0,z.jsx)(`td`,{className:`r td-mono`,children:(0,z.jsx)(E,{content:`输出速度 = 输出 tokens ÷ 生成时长(总耗时 − 首字)
|
|
3
|
-
上游不回报生成时长,此值由本服务按两端观测推算;
|
|
4
|
-
失败行或首字即结束的请求没有生成过程,显示 --`,children:(0,z.jsx)(`span`,{children:M(j(e.completionTokens,e.ms,e.firstByteMs))})})}),(0,z.jsxs)(`td`,{className:`r td-mono`,children:[(0,z.jsx)(`div`,{children:(0,z.jsx)(E,{content:`输入 ${T(e.promptTokens)} tokens / 输出 ${T(e.completionTokens)} tokens`,children:(0,z.jsxs)(`span`,{children:[T(e.promptTokens),`/`,T(e.completionTokens)]})})}),e.cachedTokens>0?(0,z.jsx)(`div`,{children:(0,z.jsx)(E,{content:`输入中命中缓存 ${T(e.cachedTokens)} tokens\n上游按缓存价计费(已体现在积分里)`,children:(0,z.jsxs)(`span`,{className:`cell-cached`,children:[`+`,T(e.cachedTokens)]})})}):null]}),(0,z.jsx)(`td`,{className:`r td-mono`,children:e.credits===null?(0,z.jsx)(E,{content:`上游未回报该次费用(未知)
|
|
5
|
-
本服务不估算 —— 账户级真实消耗见概览「积分账本」`,children:(0,z.jsx)(`span`,{children:w(e.credits)})}):w(e.credits)})]},e.id)})})]})})}var Q={live:`var(--signal-live)`,warn:`var(--warn-amber)`,fatal:`var(--danger-red)`,muted:`var(--text-faint)`},$={1:`显式声明`,2:`密钥归属`,3:`User-Agent`,4:`未识别`};function pe({row:e,reasoningOpen:n,onToggleReasoning:r,resolveClientName:i,modelTagOf:a,providerOfModel:o}){let s=e.ms-e.queuedMs,c=y(e),u=x(e.status,e.note),d=e.assistantPreview??``,f=e.queuedMs>0;return(0,z.jsxs)(`div`,{className:`drawer-body`,children:[(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`时间`}),(0,z.jsx)(`span`,{className:`v`,children:k(e.ts)})]}),(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`提供商`}),(0,z.jsxs)(`span`,{className:`v`,children:[o(e.model)??i(e),(0,z.jsx)(`span`,{className:`code-chip`,style:{marginLeft:8},children:$[e.clientRule]??`规则 ${e.clientRule}`})]})]}),(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`工具`}),(0,z.jsx)(`span`,{className:`v`,children:e.tool?e.tool:(0,z.jsxs)(z.Fragment,{children:[(0,z.jsx)(`span`,{style:{color:`var(--text-faint)`},children:`未识别`}),e.ua?(0,z.jsx)(`span`,{className:`code-chip`,style:{marginLeft:8},children:e.ua}):null]})})]}),e.tool&&e.ua?(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`User-Agent`}),(0,z.jsx)(E,{content:e.ua,children:(0,z.jsx)(`span`,{className:`v`,children:e.ua})})]}):null,e.remoteIp?(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`来源 IP`}),(0,z.jsx)(`span`,{className:`v`,children:e.remoteIp})]}):null,(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`密钥`}),(0,z.jsx)(`span`,{className:`v`,children:e.keyHint})]}),(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`模型`}),(0,z.jsxs)(`span`,{className:`v`,children:[e.modelDisplay||e.model,e.modelDisplay&&e.modelDisplay!==e.model?(0,z.jsx)(`span`,{className:`code-chip`,style:{marginLeft:8},children:e.model}):null,a(e.model)?(0,z.jsx)(`span`,{className:`mu-tag`,children:a(e.model)}):null]})]}),(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`状态`}),(0,z.jsxs)(`span`,{className:`v`,style:{color:Q[u]},children:[e.status,` `,v(e.note).length>0?v(e.note).map((e,t)=>(0,z.jsx)(`span`,{className:`code-chip`,style:{marginRight:4},children:e},t)):(0,z.jsx)(`span`,{className:`code-chip`,children:`-`})]})]}),(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`耗时`}),(0,z.jsxs)(`span`,{className:`v`,children:[f?`排队 ${O(e.queuedMs)} · `:`不排队(并发超限直接 429) · `,`上游 `,O(s),` ·`,` `,e.firstByteMs===null?`无首字`:`首字 ${O(e.firstByteMs)}`]})]}),(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`tokens`}),(0,z.jsxs)(`span`,{className:`v`,children:[T(e.promptTokens),` in / `,T(e.completionTokens),` out`,e.reasoningTokens>0?(0,z.jsxs)(z.Fragment,{children:[` `,(0,z.jsx)(E,{content:`输出中属于思考(reasoning)的部分,已计入 out`,children:(0,z.jsxs)(`span`,{className:`code-chip`,children:[`思考 `,T(e.reasoningTokens)]})})]}):null,e.cachedTokens>0?(0,z.jsxs)(z.Fragment,{children:[` `,(0,z.jsx)(E,{content:`输入中命中缓存的部分(上游按缓存价计费,已体现在实扣积分里)—— 这是这条便宜的来源`,children:(0,z.jsxs)(`span`,{className:`code-chip`,children:[`缓存 `,T(e.cachedTokens)]})})]}):null]})]}),(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`消耗积分`}),(0,z.jsx)(`span`,{className:`v`,children:w(e.credits)})]}),(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`流式 / 重试`}),(0,z.jsxs)(`span`,{className:`v`,children:[e.stream?`SSE`:`非流式`,` · 重试 `,e.retryCount,` 次`]})]}),(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`请求 ID`}),(0,z.jsxs)(`span`,{className:`v`,children:[`req_`,e.id.toString(16)]})]}),c?(0,z.jsx)(`div`,{className:`dnote`,style:{marginTop:14},children:c}):null,(0,z.jsxs)(`div`,{className:`drawer-sec`,children:[(0,z.jsx)(`h4`,{children:`上游响应`}),(0,z.jsx)(`div`,{className:`upstream${u===`fatal`?` fatal`:``}`,children:e.assistantPreview?`HTTP ${e.status}\nnote: ${e.note}\nupstream: ${e.modelDisplay}`:`HTTP ${e.status}\nnote: ${e.note}\n上游未返回内容(${b(e.note)})`})]}),d?(0,z.jsxs)(`div`,{className:`drawer-sec`,children:[(0,z.jsx)(`h4`,{children:`应答预览`}),(0,z.jsxs)(`div`,{className:`reason-box`,children:[(0,z.jsxs)(`button`,{type:`button`,onClick:r,"aria-expanded":n,children:[(0,z.jsx)(t,{size:14}),(0,z.jsx)(`span`,{style:{flex:1},children:n?`收起推理内容(reasoning_content)`:`展开推理内容(reasoning_content)`}),n?(0,z.jsx)(l,{size:14}):(0,z.jsx)(g,{size:14})]}),n?(0,z.jsx)(`div`,{className:`rz-body`,children:d}):null]})]}):null,(0,z.jsxs)(`div`,{className:`drawer-sec`,children:[(0,z.jsx)(`h4`,{children:`请求消息`}),e.messages.length===0?(0,z.jsx)(`div`,{className:`empty-note`,children:`该请求未记录消息体(logs.recordRequestBody 关闭)。`}):(0,z.jsx)(`div`,{className:`msg-list`,children:e.messages.map((e,t)=>(0,z.jsxs)(`div`,{className:`msg`,children:[(0,z.jsx)(`div`,{className:`role`,children:e.role}),(0,z.jsx)(`div`,{className:`content`,children:e.content})]},`${e.role}-${t}`))})]})]})}var me=[{value:`all`,label:`全部状态`},{value:`success`,label:`仅成功`},{value:`error`,label:`仅异常`},{value:S,label:`上游访问密钥失效`},{value:`429`,label:`429 限流`},{value:`504`,label:`504 上游超时`}],he=18e5;function ge({until:e,onExpire:t}){let[n,r]=(0,R.useState)(()=>Math.max(0,e-Date.now())),i=(0,R.useRef)(t);return i.current=t,(0,R.useEffect)(()=>{let t=()=>{let t=e-Date.now();return t<=0?(i.current(),!0):(r(t),!1)};if(t())return;let n=setInterval(()=>{t()&&clearInterval(n)},1e3);return()=>clearInterval(n)},[e]),(0,z.jsx)(z.Fragment,{children:`取证中 ${Math.floor(n/6e4)}:${String(Math.floor(n%6e4/1e3)).padStart(2,`0`)} · 点击关闭`})}function _e(){let[e,t]=(0,R.useState)(1),[n,r]=(0,R.useState)({key:``,map:{}}),[i,a]=(0,R.useState)(20),[o,s]=(0,R.useState)(`all`),[c,l]=(0,R.useState)(()=>new URLSearchParams(window.location.hash.split(`?`)[1]??``).get(`clientId`)??`all`);(0,R.useEffect)(()=>{let e=()=>{l(new URLSearchParams(window.location.hash.split(`?`)[1]??``).get(`clientId`)??`all`),t(1)};return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]);let[f,p]=(0,R.useState)(``),m=ue(f),[h,g]=(0,R.useState)(null),[_,v]=(0,R.useState)(!1),y=D(()=>A.keys(),[],{cacheKey:`keys`}),b=D(()=>A.catalog(),[],{cacheKey:`catalog`}),x=(0,R.useMemo)(()=>{let e=new Map;for(let t of b.data?.models??[])t.tag&&e.set(t.id,t.tag);return e},[b.data]),C=e=>x.get(e)??null,w=(0,R.useMemo)(()=>{let e=new Map;for(let t of b.data?.models??[])e.has(t.id)||e.set(t.id,t.provider);return e},[b.data]),O=e=>w.get(e)??null,k=(0,R.useMemo)(()=>[{value:`all`,label:`全部 API Key`},...(y.data??[]).map(e=>({value:e.id,label:e.name}))],[y.data]),j=(0,R.useMemo)(()=>{let e=new Map;return(y.data??[]).forEach(t=>e.set(t.id,t.name)),e},[y.data]),M=e=>j.get(e.clientId)??e.client,B=o===S,V=`${i}|${o}|${c}|${m}`,H=(0,R.useMemo)(()=>({page:e,limit:i,cursor:e>1&&n.key===V?n.map[e]:void 0,status:o===`all`||o===`upstream_credential_invalid`?void 0:o,clientId:c===`all`?void 0:c,q:o===`upstream_credential_invalid`?S:m||void 0}),[e,i,o,c,m,n,V]),U=D(()=>A.requests(H),[H.page,H.cursor,H.limit,H.status,H.clientId,H.q]),W=D(()=>A.requestDetail(h),[h],{enabled:h!==null});le(`requests-${U.initial?`load`:`ok`}`);let G=U.data?.items??[],K=U.data?.total??0,q=e=>{v(!1),g(e.id)},J=e=>{e(),t(1)},Y=n=>{let i=U.data?.nextCursor;n===e+1&&i&&!U.loading&&U.data?.page===e&&r(e=>({key:V,map:{...e.key===V?e.map:{},[n]:i}})),t(n)},[X,Z]=(0,R.useState)(null),[Q,$]=(0,R.useState)(null);(0,R.useEffect)(()=>{A.settings().then(e=>{let t=e.groups.find(e=>e.id===`logs`)?.items??[],n=t.find(e=>e.key===`logs.recordRequestBody`)?.value===!0,r=t.find(e=>e.key===`logs.recordBodyUntil`)?.value;n&&typeof r==`number`&&r>Date.now()?Z(r):n&&r==null&&Z(2**53-1)}).catch(()=>{})},[]);let _e=(0,R.useCallback)(()=>{Z(null),A.putSettings([{key:`logs.recordRequestBody`,value:!1}]).catch(()=>{})},[]),ve=async()=>{$(null);try{if(X!==null)await A.putSettings([{key:`logs.recordRequestBody`,value:!1},{key:`logs.recordBodyUntil`,value:null}]),Z(null);else{let e=Date.now()+he;await A.putSettings([{key:`logs.recordRequestBody`,value:!0},{key:`logs.recordBodyUntil`,value:e}]),Z(e)}}catch(e){$(e instanceof te?e.message:String(e))}},ye=X===null?`取证 30 分钟`:X===2**53-1?`取证中(不限时)· 点击关闭`:(0,z.jsx)(ge,{until:X,onExpire:_e});return(0,z.jsxs)(`div`,{className:`view on`,children:[(0,z.jsx)(oe,{title:`请求日志`,status:U.data?(0,z.jsxs)(P,{tone:`live`,dot:!0,children:[`共 `,T(K),` 条`]}):null,actions:(0,z.jsx)(z.Fragment,{children:(0,z.jsx)(E,{content:`开启后,接下来 30 分钟内经本服务转发的请求体会写入本地库(详情页可查看原始请求)。到点自动关闭。`,children:(0,z.jsxs)(`button`,{type:`button`,className:`btn btn-sm ${X===null?`btn-quiet`:`btn-primary`}`,onClick:()=>void ve(),children:[X===null?(0,z.jsx)(u,{size:14}):(0,z.jsx)(d,{size:14}),ye]})})})}),Q?(0,z.jsx)(`div`,{className:`view-body stack`,style:{paddingTop:0},children:(0,z.jsxs)(re,{tone:`error`,children:[`取证开关没切成功:`,Q]})}):null,(0,z.jsxs)(`div`,{className:`view-body stack`,children:[U.initial&&U.loading?(0,z.jsx)(se,{}):(0,z.jsxs)(z.Fragment,{children:[(0,z.jsxs)(`div`,{className:`filters`,children:[(0,z.jsx)(L,{value:o,options:me,onChange:e=>J(()=>s(e))}),(0,z.jsx)(L,{value:c,options:k,onChange:e=>J(()=>l(e))}),(0,z.jsxs)(`label`,{className:`search`,style:{gridColumn:`span 3`},children:[(0,z.jsx)(ee,{size:14,color:`var(--text-faint)`,"aria-hidden":!0}),B?(0,z.jsx)(E,{className:`tooltip-fill`,content:`「上游访问密钥失效」本身就是一个筛选条件;清除它才能再按文本搜索。`,children:(0,z.jsx)(`input`,{value:f,placeholder:`已按「上游访问密钥失效」筛选`,disabled:!0,onChange:e=>J(()=>p(e.target.value)),style:{flex:1,minWidth:0,background:`transparent`,border:`none`,outline:`none`,color:`var(--text-primary)`,font:`inherit`,fontSize:12.5}})}):(0,z.jsx)(`input`,{value:f,placeholder:`搜索模型、客户端或标记`,onChange:e=>J(()=>p(e.target.value)),style:{flex:1,minWidth:0,background:`transparent`,border:`none`,outline:`none`,color:`var(--text-primary)`,font:`inherit`,fontSize:12.5}})]})]}),(0,z.jsx)(ae,{items:[{label:`当前筛选命中`,value:T(K),detail:`当前筛选全部命中`},{label:`本页条数`,value:T(G.length),tone:`live`,detail:`每页 ${i} 条`},{label:`当前页异常`,value:T(G.filter(e=>e.status>=400).length),detail:`status ≥ 400`},{label:`上游访问密钥失效`,value:T(G.filter(e=>ie(e.note)).length),tone:`amber`,detail:`注 token`}]}),(0,z.jsxs)(N,{title:`请求流`,aside:(0,z.jsxs)(P,{children:[ne(K?G.filter(e=>e.status<400).length/Math.max(1,G.length):null,1),` 本页成功率`]}),padded:!1,children:[(0,z.jsx)(`div`,{style:{padding:`0 20px`},children:U.error?(0,z.jsx)(F,{kind:`error`,title:`日志没取到`,detail:I(U.error),onRetry:U.reload}):G.length===0?(0,z.jsx)(F,{kind:`empty`,title:`没有匹配的请求`,detail:`换个状态或清空搜索词试试。如果一条都没有,说明服务还没收到过 /v1/* 请求。`}):(0,z.jsx)(fe,{rows:G,activeId:h,onOpen:q,resolveClientName:M,modelTagOf:C,providerOfModel:O})}),G.length>0?(0,z.jsx)(de,{page:e,limit:i,total:K,onPage:Y,onLimit:e=>J(()=>a(e))}):null]})]}),(0,z.jsxs)(N,{title:`读取口径`,aside:(0,z.jsx)(P,{children:`本地聚合`}),children:[(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`异常定义`}),(0,z.jsx)(`span`,{className:`v`,children:`status ≥ 400`})]}),(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`重试计入`}),(0,z.jsx)(`span`,{className:`v`,children:`仅首次尝试`})]}),(0,z.jsxs)(`div`,{className:`detail-row`,children:[(0,z.jsx)(`span`,{className:`k`,children:`积分口径`}),(0,z.jsx)(`span`,{className:`v`,children:`经转发 · 上游实扣(未回报即未知,不估算)`})]}),(0,z.jsxs)(`div`,{className:`footer-note`,children:[`上游访问密钥失效是这套方案唯一会让服务停摆的状态 —— 所有提供商共用同一把上游访问密钥,它一失效即整体不可用。`,`这类失败在日志里`,(0,z.jsx)(`b`,{children:`不是`}),` 401:状态码是 502,标记为「上游访问密钥失效」。出现时去「提供商管理 → 提供商」的「修改」里换新。`,`筛选框选「上游访问密钥失效」即按 note 里的 `,(0,z.jsx)(`code`,{children:`upstream_credential_invalid`}),` 匹配。`]})]})]}),h===null?null:(0,z.jsx)(ce,{title:W.data?`请求详情 · ${W.data.model}`:`请求详情`,subtitle:W.data?`req_${W.data.id.toString(16)} · ${M(W.data)}`:void 0,onClose:()=>g(null),children:W.initial&&W.loading?(0,z.jsx)(F,{kind:`loading`,title:`正在读取详情…`}):W.error?(0,z.jsx)(F,{kind:`error`,title:`详情没取到`,detail:I(W.error),onRetry:W.reload}):W.data?(0,z.jsx)(pe,{row:W.data,reasoningOpen:_,onToggleReasoning:()=>v(e=>!e),resolveClientName:M,modelTagOf:C,providerOfModel:O}):null})]})}export{_e as RequestsPage};
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{D as e,J as t,S as n,f as r,it as i,l as a,p as o,tt as s,w as c,z as l}from"./vendor-befEYGHM.js";import{M as u,f as d,h as f,i as p,j as m,n as h,s as g}from"./index-VH6Gc3-s.js";import{t as _}from"./accessUrl-DbL5DLDz.js";import{a as v,c as y,l as b,n as x,r as S,s as C,t as w}from"./Select-BxZGnteq.js";import{t as T}from"./Modal-B-rIrvXS.js";import{t as E}from"./Drawer-CleQGhRU.js";import{t as D}from"./Switch-0KA1AbiV.js";var O=i(),k=s();function A({item:e,value:t,disabled:n,onChange:r}){if(e.type===`switch`)return(0,k.jsx)(D,{checked:!!t,disabled:n||e.readonly,label:e.label,onChange:e=>r(e)});if(e.type===`badge`)return(0,k.jsx)(b,{tone:`live`,children:String(t)});if(e.type===`select`){let i=(e.options??[]).map(e=>({value:e.value,label:e.label}));return(0,k.jsx)(w,{value:String(t),options:i,disabled:n||e.readonly,onChange:e=>r(e),width:188})}return e.type===`number`?(0,k.jsx)(`input`,{className:`field-input num`,type:`number`,value:t==null?``:String(t),disabled:n||e.readonly,onChange:e=>r(e.target.value===``?``:Number(e.target.value)),"aria-label":e.label}):e.type===`mapping`?null:(0,k.jsx)(`input`,{className:`field-input text`,value:t==null?``:String(t),disabled:n||e.readonly,onChange:e=>r(e.target.value),"aria-label":e.label})}function j(){let e=_(),[n,r]=(0,O.useState)(!1),i=async()=>{try{await navigator.clipboard.writeText(e),r(!0),window.setTimeout(()=>r(!1),1200)}catch{}};return(0,k.jsxs)(`div`,{className:`card access-card`,children:[(0,k.jsxs)(`div`,{className:`access-head`,children:[(0,k.jsxs)(`span`,{className:`access-title`,children:[(0,k.jsx)(c,{size:13,"aria-hidden":!0}),`接入地址`]}),(0,k.jsx)(`span`,{className:`access-sub`,children:`客户端与 API 同源 —— 这就是你当前访问控制台的地址`})]}),(0,k.jsxs)(`div`,{className:`key-plain access-url`,children:[(0,k.jsx)(`code`,{children:e}),(0,k.jsxs)(`button`,{type:`button`,className:`copy`,"aria-label":n?`已复制接入地址`:`复制接入地址`,onClick:()=>void i(),children:[n?(0,k.jsx)(t,{size:13}):(0,k.jsx)(l,{size:13}),n?`已复制`:`复制`]})]}),(0,k.jsxs)(`p`,{className:`chain-note`,children:[`客户端里要填两组值:`,(0,k.jsx)(`b`,{children:`base_url`}),` 就是上面这串;`,(0,k.jsx)(`b`,{children:`API Key`}),` 用你在本页`,(0,k.jsx)(`b`,{children:`新建的那把`}),(0,k.jsx)(`span`,{className:`code-chip`,children:`sk-waygate-…`}),`(明文只在创建时显示一次,丢了只能删掉重建)。`]}),(0,k.jsxs)(`div`,{className:`cred-note access-cert`,children:[(0,k.jsx)(a,{size:14,"aria-hidden":!0}),(0,k.jsxs)(`span`,{children:[`本服务的 TLS 是`,(0,k.jsx)(`b`,{children:`自签证书`}),`:客户端得先信任它的根证书,否则会以「证书错误」失败 —— 那`,(0,k.jsx)(`b`,{children:`不是`}),`地址填错。把根证书装进系统信任库,或让客户端通过`,(0,k.jsx)(`span`,{className:`code-chip`,children:`NODE_EXTRA_CA_CERTS`}),` /`,(0,k.jsx)(`span`,{className:`code-chip`,children:`SSL_CERT_FILE`}),`指向随部署产出的`,(0,k.jsx)(`span`,{className:`code-chip`,children:`relay-ca.crt`}),`。`]})]})]})}var M=8,N=128;function P({onClose:r,onDone:i}){let[o,s]=(0,O.useState)(`reset`),[c,d]=(0,O.useState)(`warn`),[f,p]=(0,O.useState)(``),[m,_]=(0,O.useState)(!1),[v,y]=(0,O.useState)(null),[b,x]=(0,O.useState)(null),[C,w]=(0,O.useState)(!1),[E,D]=(0,O.useState)(``),[A,j]=(0,O.useState)(``),[P,I]=(0,O.useState)(null),L=f===`确认`,R=async()=>{if(L&&!m){_(!0),y(null);try{let e=await g.resetAdminPassword();x(e),d(`result`)}catch(e){y(e instanceof u?S(e):String(e))}finally{_(!1)}}},z=async()=>{if(b)try{await navigator.clipboard.writeText(b.password),w(!0),window.setTimeout(()=>w(!1),2e3)}catch{y(`浏览器拒绝了剪贴板访问,请手动选中口令复制。`)}},B=()=>{x(null),D(``),j(``),i?.(),r()},V=async()=>{if(m)return;let e=E.trim();if(e.length===0){y(`管理口令不能为空或纯空白。`);return}if(e.length<M){y(`管理口令至少 ${M} 个字符,当前 ${e.length} 个。`);return}if(E.length>N){y(`管理口令最多 ${N} 个字符,当前 ${E.length} 个。`);return}if(E!==A){y(`两次输入不一致,请重新确认。`);return}_(!0),y(null);try{let e=await g.setAdminPassword(E);D(``),j(``),I(e.persisted?`已生效,下次登录用新口令。当前会话不受影响。`:`已生效(仅内存),下次登录用新口令 —— 但服务端数据库不可写,重启后会回到上一个口令。`)}catch(e){y(e instanceof u?S(e):String(e))}finally{_(!1)}};if(o===`manual`&&P)return(0,k.jsxs)(T,{title:`管理口令已更新`,onClose:B,footer:(0,k.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,onClick:B,children:`知道了`}),children:[(0,k.jsx)(`div`,{className:`pw-note`,children:P}),(0,k.jsxs)(`p`,{className:`ov-sub`,style:{marginTop:12},children:[`服务端只存了口令的 scrypt 哈希,`,(0,k.jsx)(`b`,{children:`回不出明文`}),`。请确保你已经记住了刚才输入的口令。`]})]});if(o===`manual`){let t=E.trim().length>0&&E.trim().length<M,i=A.length>0&&E!==A;return(0,k.jsxs)(T,{title:`手动设定管理口令`,onClose:r,footer:(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:r,children:`取消`}),(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,disabled:m||t||i||E.trim().length===0,onClick:()=>void V(),children:[m?(0,k.jsx)(n,{size:14}):(0,k.jsx)(e,{size:14}),m?`保存中…`:`保存并生效`]})]}),children:[(0,k.jsxs)(`p`,{className:`ov-sub`,children:[`设定一个你自己方便记忆的管理口令(至少 `,M,` 个字符)。 保存后`,(0,k.jsx)(`b`,{children:`立即生效、无需重启`}),`,当前会话不会被打断。`]}),(0,k.jsxs)(`div`,{className:`ov-field`,children:[(0,k.jsx)(`label`,{htmlFor:`pw-new`,children:`新管理口令`}),(0,k.jsx)(`input`,{id:`pw-new`,type:`password`,className:`field-input text`,style:{width:`100%`},value:E,autoFocus:!0,autoComplete:`new-password`,placeholder:`至少 ${M} 个字符`,onChange:e=>{D(e.target.value),y(null)}}),t?(0,k.jsxs)(`div`,{className:`ov-hint`,style:{color:`var(--warn-amber)`},children:[`至少 `,M,` 个字符,当前 `,E.trim().length,` 个。`]}):null]}),(0,k.jsxs)(`div`,{className:`ov-field`,children:[(0,k.jsx)(`label`,{htmlFor:`pw-new-confirm`,children:`再次输入`}),(0,k.jsx)(`input`,{id:`pw-new-confirm`,type:`password`,className:`field-input text`,style:{width:`100%`},value:A,autoComplete:`new-password`,placeholder:`重复上面输入的口令`,onChange:e=>{j(e.target.value),y(null)}}),i?(0,k.jsx)(`div`,{className:`ov-hint`,style:{color:`var(--warn-amber)`},children:`两次输入不一致。`}):null]}),(0,k.jsxs)(`div`,{className:`ov-lose`,children:[(0,k.jsx)(`b`,{children:`请记住它:`}),`设定后旧口令立即失效,且本产品没有「忘记口令」的找回通道。 口令明文不会保存在浏览器任何位置,也不会被回显。`]}),v?(0,k.jsx)(h,{tone:`error`,children:(0,k.jsx)(`span`,{style:{display:`block`,marginTop:14},children:v})}):null]})}return c===`result`&&b?(0,k.jsxs)(T,{title:`新管理口令`,onClose:B,footer:(0,k.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,onClick:B,children:`我已保存,关闭`}),children:[(0,k.jsxs)(`div`,{className:`pw-once`,children:[(0,k.jsxs)(`div`,{className:`pw-once-head`,children:[(0,k.jsx)(a,{size:16}),(0,k.jsx)(`b`,{children:`这是唯一一次显示`})]}),(0,k.jsx)(`div`,{className:`pw-once-body`,children:`关闭这个窗口后,服务端也回不出这份明文 —— 库里只存了它的 scrypt 哈希。 请现在就复制并保存到你的密码管理器里。`})]}),(0,k.jsxs)(`div`,{className:`pw-plain`,children:[(0,k.jsx)(`code`,{children:b.password}),(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:()=>void z(),children:[C?(0,k.jsx)(t,{size:14}):(0,k.jsx)(l,{size:14}),C?`已复制`:`复制`]})]}),b.persisted?(0,k.jsxs)(`div`,{className:`pw-note`,children:[`已写入服务端数据库,`,(0,k.jsx)(`b`,{children:`立即生效、无需重启`}),`,并会随每日备份一起保存。 下次登录请使用新口令。`]}):(0,k.jsx)(h,{tone:`warn`,children:(0,k.jsxs)(`span`,{style:{display:`block`,marginTop:14},children:[`服务端数据库不可写,新口令`,(0,k.jsx)(`b`,{children:`仅本次运行有效`}),`:重启后会回到旧口令。 请先修好数据目录权限,再重置一次。`]})}),v?(0,k.jsx)(h,{tone:`error`,children:(0,k.jsx)(`span`,{style:{display:`block`,marginTop:14},children:v})}):null]}):c===`confirm`?(0,k.jsxs)(T,{title:`确认重置管理口令?`,onClose:r,footer:(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,onClick:r,children:`取消(保持现状)`}),(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-danger btn-sm`,disabled:!L||m,onClick:()=>void R(),children:[m?(0,k.jsx)(n,{size:14}):null,m?`重置中…`:`确认重置`]})]}),children:[(0,k.jsxs)(`p`,{className:`ov-sub`,children:[`重置后,`,(0,k.jsx)(`b`,{children:`当前口令立即失效`}),`。你正在使用的这个会话不会被打断,但下次登录必须用新口令。`]}),(0,k.jsxs)(`div`,{className:`ov-lose`,children:[(0,k.jsx)(`b`,{children:`会失去什么:`}),`旧口令的所有副本(笔记、密码管理器里的旧条目)都会变成无效值。本产品没有「忘记口令」的找回通道。`]}),(0,k.jsxs)(`div`,{className:`ov-field`,children:[(0,k.jsxs)(`label`,{htmlFor:`pw-confirm`,children:[`输入 `,(0,k.jsx)(`b`,{style:{color:`var(--text-secondary)`,fontWeight:500},children:`确认`}),` 以继续`]}),(0,k.jsx)(`input`,{id:`pw-confirm`,className:`field-input text`,style:{width:`100%`,fontFamily:`var(--font-mono)`},value:f,autoFocus:!0,placeholder:`确认`,onChange:e=>p(e.target.value)}),(0,k.jsx)(`div`,{className:`ov-hint`,children:`打错一个字就没法继续。重置入口凭证值得这一步。`})]}),v?(0,k.jsx)(h,{tone:`error`,children:v}):null]}):(0,k.jsxs)(T,{title:`重置管理口令`,onClose:r,footer:(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:r,children:`取消`}),(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-danger btn-sm`,onClick:()=>d(`confirm`),children:[(0,k.jsx)(e,{size:14}),`我明白,继续`]})]}),children:[(0,k.jsx)(F,{mode:o,onChange:e=>{s(e),y(null)}}),(0,k.jsxs)(`p`,{className:`ov-sub`,children:[`服务端会生成一个新的 16 位随机口令。`,(0,k.jsx)(`b`,{children:`新口令只显示一次`}),`,请准备好记录工具。`]}),(0,k.jsxs)(`div`,{className:`pw-warn-list`,children:[(0,k.jsxs)(`div`,{children:[(0,k.jsx)(`span`,{className:`pw-dot`}),(0,k.jsxs)(`span`,{children:[(0,k.jsx)(`b`,{children:`当前口令立即失效`}),` —— 但已登录的会话`,(0,k.jsx)(`b`,{children:`不受影响`}),`:会话由独立密钥 (RELAY_SECRET)签名,与口令本身无关。包括其它浏览器标签页在内的登录态, 都会保持有效直到各自过期。本版本未提供「改密强制所有会话下线」。`]})]}),(0,k.jsxs)(`div`,{children:[(0,k.jsx)(`span`,{className:`pw-dot`}),(0,k.jsxs)(`span`,{children:[(0,k.jsx)(`b`,{children:`没有找回通道`}),` —— 忘记新口令后,只能上服务器删除数据结构后重新引导。`]})]}),(0,k.jsxs)(`div`,{children:[(0,k.jsx)(`span`,{className:`pw-dot`}),(0,k.jsxs)(`span`,{children:[(0,k.jsx)(`b`,{children:`立即生效、无需重启`}),` —— 哈希写进数据库后立刻对后续登录起作用。`]})]})]}),(0,k.jsx)(`div`,{className:`ov-hint`,style:{marginTop:12},children:`想用自己的口令?切到上方「手动设定」—— 随机口令更安全,手动口令更好记,按需选择。`})]})}function F({mode:e,onChange:t}){return(0,k.jsxs)(`span`,{className:`seg-tabs`,role:`group`,"aria-label":`口令变更方式`,style:{marginBottom:14},children:[(0,k.jsx)(`button`,{type:`button`,className:e===`reset`?`on`:``,"aria-pressed":e===`reset`,onClick:()=>t(`reset`),children:`随机重置`}),(0,k.jsx)(`button`,{type:`button`,className:e===`manual`?`on`:``,"aria-pressed":e===`manual`,onClick:()=>t(`manual`),children:`手动设定`})]})}function I({spec:e,onClose:t,onDone:r}){let[i,a]=(0,O.useState)(``),[o,s]=(0,O.useState)(!1),[c,l]=(0,O.useState)(null),d=i===`确认`,f=async()=>{if(d&&!o){s(!0),l(null);try{r(await g.danger(e.action,i))}catch(e){l(e instanceof u?e:new u(String(e),0,0)),s(!1)}}};return(0,k.jsxs)(T,{title:e.title,onClose:t,footer:(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,onClick:t,children:`取消(保持现状)`}),(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-danger btn-sm`,disabled:!d||o,onClick:()=>void f(),children:[o?(0,k.jsx)(n,{size:14}):null,o?`执行中…`:e.ok]})]}),children:[(0,k.jsx)(`p`,{className:`ov-sub`,children:e.body}),(0,k.jsxs)(`div`,{className:`ov-lose`,children:[(0,k.jsx)(`b`,{children:`会失去什么:`}),e.lose]}),(0,k.jsxs)(`div`,{className:`ov-field`,children:[(0,k.jsxs)(`label`,{htmlFor:`danger-confirm`,children:[`输入 `,(0,k.jsx)(`b`,{style:{color:`var(--text-secondary)`,fontWeight:500},children:`确认`}),` 以继续`]}),(0,k.jsx)(`input`,{id:`danger-confirm`,className:`field-input text`,style:{width:`100%`,fontFamily:`var(--font-mono)`},value:i,autoFocus:!0,placeholder:`确认`,onChange:e=>a(e.target.value)}),(0,k.jsx)(`div`,{className:`ov-hint`,children:`打错一个字就没法继续。破坏性操作值得这一步。`})]}),c?(0,k.jsx)(h,{tone:`error`,children:S(c)}):null]})}var L={"danger.clearLogs":{action:`clearLogs`,title:`清空全部日志?`,body:`删除后「按模型 / 按客户端」明细会一并归零。剩余积分不受影响,服务也不中断。`,lose:`将删除本机全部请求日志,覆盖保留天数内的所有记录,没有备份入口。`,ok:`确认清空`},"danger.resetKeys":{action:`resetKeys`,title:`重置全部密钥?`,body:`所有密钥会立即失效,每个客户端都要重新填一次。已消耗的积分不受影响。`,lose:`将失效全部 sk-waygate- 密钥,正在使用它们的客户端会立刻收到 401。`,ok:`确认重置`},"danger.restoreDefaults":{action:`restoreDefaults`,title:`恢复默认配置?`,body:`会用默认值覆盖 ~/.relay/config.yml。你改过的端口、并发、日志保留天数都会回到出厂值。`,lose:`将覆盖所有自定义配置,服务重启后生效。`,ok:`确认恢复`}},R={openai:`OpenAI 方言`,anthropic:`Anthropic 方言`,qoder:`COSY 协议`};function z(){let e=m(()=>g.providers(),[],{cacheKey:`providers`}),t=e.data?.items??[],[n,r]=(0,O.useState)(null),i=m(()=>g.providerGrowthPanel(n.id),[n?.id],{enabled:n!==null});return(0,k.jsxs)(v,{title:`提供商健康`,aside:(0,k.jsxs)(y,{children:[t.length,` 家 · 只读总览`]}),children:[e.initial&&e.loading?(0,k.jsx)(`div`,{className:`empty-note`,style:{padding:`8px 0`},children:`正在读取提供商…`}):e.error?(0,k.jsx)(`div`,{className:`empty-note`,style:{padding:`8px 0`},children:`提供商列表没取到,稍后重试。`}):t.length===0?(0,k.jsx)(`div`,{className:`empty-note`,style:{padding:`8px 0`},children:`还没有登记任何提供商 —— 到「提供商管理 → 提供商」新增。`}):(0,k.jsx)(`div`,{className:`tbl-scroll`,children:(0,k.jsxs)(`table`,{className:`tbl`,children:[(0,k.jsx)(`caption`,{className:`sr-only`,children:`各提供商的健康状态`}),(0,k.jsx)(`thead`,{children:(0,k.jsxs)(`tr`,{children:[(0,k.jsx)(`th`,{scope:`col`,children:`提供商`}),(0,k.jsx)(`th`,{scope:`col`,children:`协议`}),(0,k.jsx)(`th`,{scope:`col`,children:`凭证`}),(0,k.jsx)(`th`,{scope:`col`,children:`状态`}),(0,k.jsx)(`th`,{scope:`col`,className:`r`,children:`模型数`}),(0,k.jsx)(`th`,{scope:`col`,children:`积分 / 签到`})]})}),(0,k.jsx)(`tbody`,{children:t.map(e=>(0,k.jsxs)(`tr`,{children:[(0,k.jsx)(`td`,{className:`td-strong`,children:e.name}),(0,k.jsx)(`td`,{className:`td-sub`,children:R[e.protocol]??e.protocol}),(0,k.jsx)(`td`,{children:(0,k.jsx)(`span`,{className:`up-badge${e.configured?``:` warn`}`,children:e.configured?`有效`:`未配置`})}),(0,k.jsx)(`td`,{children:e.active?(0,k.jsx)(y,{tone:`live`,children:`已启用`}):(0,k.jsx)(y,{tone:`ghost`,children:`未启用`})}),(0,k.jsx)(`td`,{className:`r td-mono`,children:f(e.modelCount??0)}),(0,k.jsx)(`td`,{className:`td-sub td-mono`,children:e.credits?.available?(0,k.jsxs)(k.Fragment,{children:[`剩余 `,d(e.credits.remaining??0),e.credits.stale?`(偏旧)`:``]}):e.qoderCredits?(0,k.jsxs)(k.Fragment,{children:[e.qoderCredits.remaining===null?`余额未知`:`剩余 ${d(e.qoderCredits.remaining)}`,e.qoderCredits.lifetimeConsumed!==null&&e.qoderCredits.lifetimeConsumed!==void 0?(0,k.jsxs)(k.Fragment,{children:[` `,(0,k.jsx)(p,{content:`累计消耗 —— 这个账号近一年在该平台消耗掉的 credits 总量(账号级)。
|
|
2
|
-
它不是当前余额,也不是本服务转发的那部分:含官方客户端直连的用量。
|
|
3
|
-
数值等于每日消耗热力图近 371 天之和。`,children:(0,k.jsxs)(`span`,{className:`credit-aside`,children:[`累计消耗 `,d(e.qoderCredits.lifetimeConsumed)]})})]}):null,e.qoderCredits.stale?`(偏旧)`:``,e.signin?.streak?`(连续活跃 ${f(e.signin.streak)} 天)`:``]}):e.wbCredits?(0,k.jsxs)(k.Fragment,{children:[`剩余 `,d(e.wbCredits.remaining??0),e.wbSignin?.streak?`(连签 ${f(e.wbSignin.streak)} 天)`:``]}):e.signin?.checkedOn?(0,k.jsxs)(k.Fragment,{children:[`今日已签到`,e.signin.lastPoints?` +${f(e.signin.lastPoints)}`:``]}):e.wbSignin?.checkedOn?(0,k.jsxs)(k.Fragment,{children:[`今日已签到`,e.wbSignin.lastPoints?` +${f(e.wbSignin.lastPoints)}`:``]}):`—`}),(0,k.jsx)(`td`,{children:e.protocol===`openai`&&e.wbOAuth?.configured?(0,k.jsx)(p,{content:`查看成长任务的完成情况(进度/奖励/状态,只读)`,children:(0,k.jsx)(`button`,{type:`button`,className:`mini-pill`,onClick:()=>r(e),children:`任务`})}):(0,k.jsx)(`span`,{className:`td-sub`,children:`—`})})]},e.id))})]})}),(0,k.jsxs)(`ul`,{className:`ph-notes`,children:[(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`积分口径(三家各不同)`}),`:本表「积分」列都取`,(0,k.jsx)(`b`,{children:`上游真实余额`}),`,非本地推算。 MiniMax Code 来自 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`credit/details`}),`(余额/已用/累计发放齐全,精确到 0.01); WorkBuddy 来自资源包聚合 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`get-user-resource`}),`(剩余/发放为包级真实数); Qoder CN 来自 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`v2/me/usage`}),`(套餐内 + 资源包合计 —— 签到赠送的 Credits 进资源包,故签完此处会上涨)。`,(0,k.jsx)(`b`,{children:`到期时刻仅 Qoder 不提供`}),`(上游无此字段), 概览「积分账本」对应列显示 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`—`}),`。 另一种「累计消耗」是`,(0,k.jsx)(`b`,{children:`账号级近一年消耗总量`}),`(含官方客户端直连),与余额不是一回事, 两者不混算。`]}),(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`每日签到`}),`:MiniMax Code 由本服务每天 08:05 后自动代签(OAuth 链)。WorkBuddy 分两档: 已导入桌面端 OAuth 凭证的(提供商管理 → 提供商 → 导入OAuth)每天 08:05 `,(0,k.jsx)(`b`,{children:`自动代领`}),`签到 + 成长任务 + 连登兑换;未导入的只做状态同步(上游不允许 API 密钥代领,403 实证)。 OAuth 与转发用的 API 密钥互不影响(实验实证多会话共存,桌面端不受干扰)。成长任务的 完成情况点本表「任务」查看(未完成的需在官方客户端真实使用后才能领)。`]}),(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`凭证口径(两家不同)`}),`:`,(0,k.jsx)(`b`,{children:`MiniMax Code 是真互斥`}),` —— refresh token 一次性,且「同一账号同时只有一个有效会话」, 桌面客户端登录会把本服务顶下线,反之亦然;`,(0,k.jsx)(`b`,{children:`建议给本服务用专用账号`}),`。`,(0,k.jsx)(`b`,{children:`Qoder CN 不互斥`}),` —— 支持多会话并存,本服务与桌面客户端可同时用同一账号(实测 2026-10-16),`,(0,k.jsx)(`b`,{children:`无需`}),`专用账号。任一凭证失效时到「提供商管理 → 提供商」重新导入。`]}),(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`Qoder 零内容断流自动重试`}),`:Qoder 网关在大上下文时偶发「返回 200 但零字节即断开」, 本服务会自动重发一次(最多 1 次,对客户端无感 —— 重试发生在响应提交之前)。 请求日志里记 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`retry_count`}),` 与 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`retried`}),`。`]}),(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`提供商归属的已知限制`}),`:请求表不记录「这条走的是哪家」,提供商归属按`,(0,k.jsx)(`b`,{children:`模型 id → 目录`}),`推断。因此同名的模型 id 分属两家时归属可能不准; 请求日志的「提供商」列也是用同一推断口径。`]})]}),n?(0,k.jsx)(E,{title:`成长任务 · ${n.name}`,subtitle:`完成态与奖励(上游实时只读;未完成的需在官方客户端真实使用后才能领)`,onClose:()=>r(null),children:(0,k.jsxs)(`div`,{className:`drawer-body`,children:[i.initial&&i.loading?(0,k.jsx)(`div`,{className:`empty-note`,children:`正在读取任务面板…`}):i.error||!i.data?.ok?(0,k.jsx)(`div`,{className:`empty-note`,children:i.error?.message??i.data?.message??`任务面板没取到,稍后重试。`}):(0,k.jsx)(`div`,{style:{maxHeight:`min(68vh, 640px)`,overflow:`auto`},children:(0,k.jsxs)(`table`,{className:`tbl`,style:{minWidth:480},children:[(0,k.jsx)(`caption`,{className:`sr-only`,children:`成长任务完成情况`}),(0,k.jsx)(`thead`,{children:(0,k.jsxs)(`tr`,{children:[(0,k.jsx)(`th`,{scope:`col`,children:`任务`}),(0,k.jsx)(`th`,{scope:`col`,style:{width:56},children:`进度`}),(0,k.jsx)(`th`,{scope:`col`,className:`r`,style:{width:84},children:`奖励`}),(0,k.jsx)(`th`,{scope:`col`,style:{width:72},children:`状态`})]})}),(0,k.jsx)(`tbody`,{children:i.data.tasks.map(e=>(0,k.jsxs)(`tr`,{children:[(0,k.jsx)(`td`,{style:{maxWidth:104},children:(0,k.jsx)(p,{content:e.desc?`${e.title??e.code} —— ${e.desc}`:e.title??e.code,children:(0,k.jsx)(`span`,{className:`td-strong`,style:{display:`inline-block`,maxWidth:`100%`,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`,verticalAlign:`bottom`},children:e.title??e.code})})}),(0,k.jsx)(`td`,{className:`td-mono`,children:e.progress?`${e.progress.current}/${e.progress.target}`:`—`}),(0,k.jsx)(`td`,{className:`r td-mono`,children:e.rewardCredit?`${e.rewardCredit} 积分`:`—`}),(0,k.jsx)(`td`,{children:e.status===`claimed`?(0,k.jsx)(y,{tone:`live`,children:`已领取`}):e.status===`in_progress`?(0,k.jsx)(y,{tone:`amber`,children:`进行中`}):e.locked?(0,k.jsx)(y,{tone:`ghost`,children:`未解锁`}):(0,k.jsx)(y,{tone:`ghost`,children:`待完成`})})]},e.code))})]})}),(0,k.jsx)(`div`,{className:`footer-note`,children:`每天 08:05 自动代领一轮(签到 + 已完成的任务 + 连登兑换);这里的数据来自上游任务面板,实时只读。`})]})}):null]})}var B=new Set([`credential.source`,`credential.status`]),V={service:`ghost`,credential:`cyan`,quota:`amber`,limits:`rose`,logs:`ghost`,password:`amber`,danger:`amber`,mapping:`cyan`};function H(){let t=m(()=>g.settings(),[],{cacheKey:`settings`}),[n,i]=(0,O.useState)({}),[a,s]=(0,O.useState)(!1),[c,l]=(0,O.useState)(null),[d,f]=(0,O.useState)(null),[p,_]=(0,O.useState)(null),[b,w]=(0,O.useState)(null),[T,E]=(0,O.useState)(!1),[D,A]=(0,O.useState)(null),[M,N]=(0,O.useState)(`access`),F=t.data?.groups??[],R=(0,O.useMemo)(()=>{let e=[{id:`access`,label:`接入地址`,tone:`cyan`}];for(let t of F)t.id!==`mapping`&&e.push({id:t.id,label:t.label,tone:V[t.id]??`ghost`});return e.push({id:`password`,label:`管理口令`,tone:`amber`}),e.push({id:`mapping`,label:`键位映射`,tone:`cyan`}),e},[F]),H=(0,O.useMemo)(()=>{let e={};for(let t of F){let r=0;for(let e of t.items)B.has(e.key)||e.readonly||e.type===`action`||e.type===`mapping`||e.key in n&&n[e.key]!==e.value&&(r+=1);r>0&&(e[t.id]=r)}return e},[F,n]),W=(e,t)=>e in n?n[e]:t,G=(0,O.useMemo)(()=>{if(!t.data)return[];let e=[];return t.data.groups.forEach(t=>t.items.forEach(t=>{B.has(t.key)||t.readonly||t.type===`action`||t.type===`mapping`||t.key in n&&n[t.key]!==t.value&&e.push({key:t.key,value:n[t.key]})})),e},[t.data,n]),K=async()=>{if(!(G.length===0||a)){s(!0),l(null),f(null);try{let e=await g.putSettings(G);i({}),f(e.requiresRestart?`已应用 ${e.applied} 项,配置版本 → v${e.version}。其中含需重启才生效的项。`:`已应用 ${e.applied} 项,配置版本 → v${e.version}。`),t.reload()}catch(e){l(e instanceof u?e:new u(String(e),0,0))}finally{s(!1)}}},q=e=>{let n=e.affected.logs??e.affected.keys??0;w(`操作已完成,影响 ${n} 条记录。`),_(null),t.reload()},J=F.find(e=>e.id===`mapping`)?.items[0],Y=F.find(e=>e.id===M),X=F.find(e=>e.id===`danger`)?.items??[];return(0,k.jsxs)(`div`,{className:`view on`,children:[(0,k.jsx)(C,{title:`设置`,status:t.data?(0,k.jsx)(y,{tone:G.length?`amber`:`ghost`,dot:G.length>0,children:G.length?`${G.length} 项待保存`:`配置版本 v${t.data.version}`}):null,actions:(0,k.jsxs)(k.Fragment,{children:[G.length?(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,onClick:()=>i({}),children:[(0,k.jsx)(o,{size:14}),`放弃改动`]}):null,(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-primary btn-sm`,disabled:G.length===0||a,onClick:()=>void K(),children:[(0,k.jsx)(r,{size:14}),a?`保存中…`:`保存`]})]})}),(0,k.jsxs)(`div`,{className:`view-body stack`,children:[c?(0,k.jsx)(h,{tone:`error`,children:S(c)}):null,d?(0,k.jsx)(h,{tone:`success`,children:d}):null,b?(0,k.jsx)(h,{tone:`success`,children:b}):null,D?(0,k.jsx)(h,{tone:`success`,children:D}):null,(0,k.jsxs)(`div`,{className:`settings-split`,children:[(0,k.jsx)(`nav`,{className:`settings-nav`,"aria-label":`设置分组`,children:R.map(e=>{let t=H[e.id]??0;return(0,k.jsxs)(`button`,{type:`button`,className:`settings-nav-i${M===e.id?` on`:``}`,"aria-current":M===e.id?`page`:void 0,onClick:()=>N(e.id),children:[(0,k.jsx)(`span`,{className:`settings-nav-label`,children:e.label}),t>0?(0,k.jsx)(`span`,{className:`settings-nav-dirty`,children:t}):null]},e.id)})}),(0,k.jsx)(`div`,{className:`settings-content`,children:t.initial&&t.loading?(0,k.jsx)(v,{children:(0,k.jsx)(x,{kind:`loading`,title:`正在读取配置…`})}):t.error?(0,k.jsx)(v,{children:(0,k.jsx)(x,{kind:`error`,title:`配置没取到`,detail:S(t.error),onRetry:t.reload})}):(0,k.jsxs)(k.Fragment,{children:[M===`access`?(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(j,{}),(0,k.jsx)(z,{})]}):null,M===`password`?(0,k.jsxs)(`div`,{className:`card`,children:[(0,k.jsxs)(`div`,{className:`group-head`,children:[(0,k.jsxs)(`h3`,{children:[(0,k.jsx)(e,{size:14,style:{verticalAlign:-2,marginRight:6}}),`管理口令`]}),(0,k.jsx)(`p`,{children:`控制台的唯一入口凭证`})]}),(0,k.jsxs)(`div`,{className:`set-row`,children:[(0,k.jsxs)(`div`,{className:`info`,children:[(0,k.jsx)(`b`,{children:`管理口令`}),(0,k.jsxs)(`span`,{children:[`两种改法:`,(0,k.jsx)(`b`,{children:`随机重置`}),`由服务端生成 16 位新口令(更强,但需当场保存);`,(0,k.jsx)(`b`,{children:`手动设定`}),`由你输入一个方便记忆的口令(至少 8 个字符)。 两种都立即生效、无需重启;新口令不回显、不落浏览器任何位置。`]})]}),(0,k.jsx)(`div`,{className:`ctl`,children:(0,k.jsxs)(`button`,{type:`button`,className:`btn btn-quiet btn-sm`,disabled:a,onClick:()=>E(!0),children:[(0,k.jsx)(e,{size:13}),`修改`]})})]})]}):null,M===`danger`?(0,k.jsxs)(`div`,{className:`card danger-zone`,children:[(0,k.jsxs)(`div`,{className:`group-head`,children:[(0,k.jsx)(`h3`,{style:{color:`var(--warn-amber)`},children:`危险操作`}),(0,k.jsx)(`p`,{children:`不可撤销,需二次确认`})]}),X.map(e=>(0,k.jsxs)(`div`,{className:`set-row`,children:[(0,k.jsxs)(`div`,{className:`info`,children:[(0,k.jsx)(`b`,{children:e.label}),(0,k.jsx)(`span`,{children:e.why})]}),(0,k.jsx)(`div`,{className:`ctl`,children:(0,k.jsx)(`button`,{type:`button`,className:`mini-pill danger`,disabled:a,onClick:()=>_(L[e.key]??null),children:e.label})})]},e.key))]}):null,M===`mapping`&&J?.type===`mapping`?(0,k.jsxs)(v,{title:J.label,aside:(0,k.jsx)(y,{children:`config.yml`}),children:[(0,k.jsx)(`div`,{className:`code`,style:{fontSize:12},children:Object.entries(J.value??{}).map(([e,t])=>(0,k.jsxs)(`div`,{children:[(0,k.jsx)(`span`,{className:`k`,children:e}),` → `,(0,k.jsx)(`span`,{className:`st`,children:t})]},e))}),(0,k.jsx)(`div`,{className:`footer-note`,children:J.why})]}):null,Y&&Y.id!==`danger`&&Y.id!==`mapping`?(0,k.jsx)(U,{group:Y,saving:a,valueOf:W,onChange:(e,t)=>i(n=>({...n,[e]:t}))}):null]})})]})]}),p?(0,k.jsx)(I,{spec:p,onClose:()=>_(null),onDone:q}):null,T?(0,k.jsx)(P,{onClose:()=>E(!1),onDone:()=>{A(`管理口令已更新并立即生效。下次登录请使用新口令。`),t.reload()}}):null]})}function U({group:e,saving:t,valueOf:n,onChange:r}){let i=e.items.filter(e=>!B.has(e.key));if(i.length===0)return null;let a=i.filter(e=>!e.noop),o=i.filter(e=>e.noop);return(0,k.jsxs)(`div`,{className:`card`,children:[(0,k.jsxs)(`div`,{className:`group-head`,children:[(0,k.jsx)(`h3`,{children:e.label}),(0,k.jsx)(`p`,{children:W(e.id)})]}),a.map(e=>(0,k.jsx)(G,{item:e,value:n(e.key,e.value),saving:t,onChange:t=>r(e.key,t)},e.key)),o.length>0?(0,k.jsxs)(`details`,{className:`dormant`,children:[(0,k.jsxs)(`summary`,{children:[o.length,` 项暂未生效`,(0,k.jsx)(`span`,{children:`改了不会有任何变化 —— 依赖的功能未实现或上游未供货`})]}),o.map(e=>(0,k.jsx)(G,{item:e,value:n(e.key,e.value),saving:t,onChange:t=>r(e.key,t)},e.key))]}):null]})}function W(e){return{service:`进程监听与启动方式`,credential:`跨提供商的全局策略(部分项仅对 WorkBuddy 生效)`,quota:`积分口径与额度轮询(仅 WorkBuddy;MiniMax 走独立账本,Qoder 无端点)`,signin:`每日 08:05 自动签到(WorkBuddy 可关;MiniMax 恒开,Qoder 无签到)`,limits:`自用场景的保护,而非配额限制`,logs:`留在本机,不参与同步`}[e]??``}function G({item:e,value:t,saving:n,onChange:r}){return(0,k.jsxs)(`div`,{className:`set-row`,children:[(0,k.jsxs)(`div`,{className:`info`,children:[(0,k.jsxs)(`b`,{children:[e.label,e.requiresRestart?(0,k.jsx)(`span`,{style:{marginLeft:8,fontSize:10.5,color:`var(--warn-amber)`},children:`需重启`}):null]}),(0,k.jsx)(`span`,{children:e.why})]}),(0,k.jsx)(`div`,{className:`ctl`,children:(0,k.jsx)(A,{item:e,value:t,disabled:n,onChange:r})})]})}export{H as SettingsPage};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as e,E as t,it as n,r,tt as i}from"./vendor-befEYGHM.js";import{O as a,_ as o,b as s,f as c,g as l,h as u,i as d,j as f,k as p,l as m,s as h}from"./index-VH6Gc3-s.js";import{a as g,c as _,n as v,o as y,r as b,s as x,t as S}from"./Select-BxZGnteq.js";import{a as C}from"./PageSkeleton-DG-Dj4_9.js";import{t as w}from"./useFx-xcrp_LHB.js";import{n as T,r as E,t as D}from"./ClientMetricTip-D-pXFJpS.js";var O=n(),k=i(),A={tokens:`消耗 tokens`,requests:`请求次数`};function j({points:e,metric:t,avg:n}){let[r,i]=(0,O.useState)(null),[a,o]=(0,O.useState)(null),c=(0,O.useRef)(null),l=(0,O.useRef)(null),[d,f]=(0,O.useState)(null);(0,O.useLayoutEffect)(()=>{let t=l.current,n=c.current;if(!t||!n||r===null||e.length===0){f(null);return}let i=()=>{let i=(r+.5)/e.length*n.clientWidth,a=n.getBoundingClientRect(),o=t.getBoundingClientRect(),s=i-(o.left-a.left);f(Math.max(12,Math.min(s,o.width-12)))};return i(),window.addEventListener(`resize`,i),()=>window.removeEventListener(`resize`,i)},[r,t,e.length]);let p=(0,O.useMemo)(()=>e.map((n,r)=>{let i=r>0?e[r-1]:null,a=i?t===`tokens`?n.tokens-i.tokens:n.requests-i.requests:null,o=/T\d{2}$/.test(n.bucket),c=(n.models??[]).slice(0,5).map(e=>`${e.model} ${s(e.tokens)} tokens`).join(`、`),l=a===null?``:` · 较${o?`上一小时`:`昨日`} ${a>0?`增加`:a<0?`减少`:`持平`}${a===0?``:` ${u(Math.abs(a))}`}`;return`${m(n.bucket)} · ${u(n.requests)} 次请求 · ${s(n.tokens)} tokens`+(n.errors>0?` · ${u(n.errors)} 次失败`:``)+(c?` · 模型:${c}`:``)+l}),[e,t]);if(e.length===0)return(0,k.jsx)(`div`,{className:`empty-note`,style:{padding:`24px 0`},children:`该窗口内没有请求记录。`});let h=e.map(e=>t===`tokens`?e.tokens:e.requests),g=Math.max(1,...h),_=u,v=n===null?null:Math.round(Math.min(1,Math.max(0,n/g))*1e4)/1e4,y=Math.ceil(e.length/5),b=a??e.length-1,x=t=>{let n=e.length-1,r;if(t.key===`ArrowRight`)r=Math.min(n,b+1);else if(t.key===`ArrowLeft`)r=Math.max(0,b-1);else if(t.key===`Home`)r=0;else if(t.key===`End`)r=n;else return;t.preventDefault(),o(r),i(r),(c.current?.querySelector(`[data-idx="${r}"]`)??void 0)?.focus()},S=r===null?null:e[r],C=S?/T\d{2}$/.test(S.bucket):!1,w=S&&r!==null&&r>0?e[r-1]:null,T=S&&w?t===`tokens`?S.tokens-w.tokens:S.requests-w.requests:null;return(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)(`div`,{className:`avgline`,style:{"--avg":v??0},children:[v===null?null:(0,k.jsxs)(`span`,{className:`avg-row`,children:[(0,k.jsxs)(`span`,{className:`avg-tag`,children:[`日均 `,_(n)]}),(0,k.jsx)(`i`,{className:`avg-rule`})]}),(0,k.jsxs)(`div`,{className:`bars30 js-grow`,ref:c,onKeyDown:x,onMouseLeave:()=>i(null),children:[(0,k.jsxs)(`span`,{className:`grid`,"aria-hidden":`true`,children:[(0,k.jsx)(`i`,{className:`base`}),(0,k.jsx)(`i`,{className:`mid`}),(0,k.jsx)(`i`,{className:`q1`})]}),e.map((n,a)=>{let o=t===`tokens`?n.tokens:n.requests,s=a===e.length-1?`today`:o>=g?`peak`:``,c=n.errors>0,l=p[a];return(0,k.jsx)(`div`,{"data-idx":a,className:`bcol${a===r?` on`:``}`,role:`img`,"aria-label":l,tabIndex:a===b?0:-1,onMouseEnter:()=>i(a),onFocus:()=>i(a),onBlur:()=>i(e=>e===a?null:e),children:(0,k.jsx)(`div`,{className:`b ${s}`.trim()+(c?` err`:``),style:{height:`${Math.max(2,Math.round(o/g*100))}%`},children:c?(0,k.jsx)(`span`,{className:`err-dot`,"aria-hidden":`true`}):null})},n.bucket)}),S?(()=>{let n=r!==null&&e.length>0?(r+.5)/e.length*100:50;return(0,k.jsxs)(`div`,{ref:l,className:`bar-tip${n<12?` tip-left`:n>88?` tip-right`:``}`,style:{"--tip-x":`${n}%`,"--tip-arrow":d===null?void 0:`${d}px`},"aria-hidden":`true`,children:[(0,k.jsxs)(`div`,{className:`bt-head`,children:[(0,k.jsx)(`b`,{children:m(S.bucket)}),r===e.length-1?(0,k.jsx)(`span`,{className:`bt-tag`,children:`最新`}):null]}),(0,k.jsxs)(`div`,{className:`bt-row${t===`tokens`?` hot`:``}`,children:[(0,k.jsx)(`span`,{children:`消耗 tokens`}),(0,k.jsx)(`i`,{children:s(S.tokens)})]}),(S.models??[]).length>0?(0,k.jsx)(`div`,{className:`bt-models`,children:(S.models??[]).map(e=>(0,k.jsxs)(`div`,{className:`bt-model`,children:[(0,k.jsx)(`span`,{className:`bt-model-name`,children:e.model}),(0,k.jsxs)(`i`,{children:[s(e.tokens),(0,k.jsx)(`em`,{children:` · ${S.tokens>0?Math.round(e.tokens/S.tokens*100):0}%`})]})]},e.model))}):null,(0,k.jsxs)(`div`,{className:`bt-row${t===`requests`?` hot`:``}`,children:[(0,k.jsx)(`span`,{children:`请求次数`}),(0,k.jsx)(`i`,{children:u(S.requests)})]}),S.errors>0?(0,k.jsxs)(`div`,{className:`bt-row bt-err`,children:[(0,k.jsx)(`span`,{children:`失败`}),(0,k.jsxs)(`i`,{children:[u(S.errors),(0,k.jsxs)(`em`,{children:[` `,`(`,u(S.requests)===`--`||S.requests===0?`—`:`${(S.errors/S.requests*100).toFixed(1)}%`,`)`]})]})]}):null,T===null?null:(0,k.jsxs)(`div`,{className:`bt-delta${T>0?` up`:T<0?` down`:` flat`}`,children:[`较`,C?`上一小时`:`昨日`,T>0?` ▲`:T<0?` ▼`:` — `,T>0||T<0?u(Math.abs(T)):`持平`]})]})})():null]})]}),(0,k.jsx)(`div`,{className:`axis`,children:e.map((t,n)=>(0,k.jsx)(`span`,{children:n%y===0||n===e.length-1?m(t.bucket):``},t.bucket))})]})}function M({items:e,windowLabel:t}){if(e.length===0)return(0,k.jsxs)(`div`,{className:`empty-note`,children:[t,`没有可拆分的请求。`]});let n=Math.max(1,...e.map(e=>e.value)),r=e=>e?void 0:{fontFamily:`var(--font-body)`};return(0,k.jsx)(`div`,{className:`dist js-stagger js-grow`,children:e.map(e=>(0,k.jsxs)(`div`,{className:`d-row`,children:[e.tip?(0,k.jsx)(d,{content:e.tip,children:(0,k.jsx)(`span`,{className:`d-name`,style:r(e.mono),children:e.label})}):(0,k.jsx)(`span`,{className:`d-name`,style:r(e.mono),children:e.label}),(0,k.jsxs)(`span`,{className:`d-val`,children:[e.format===`credits`?c(e.value):u(e.value),` · `,e.trailing]}),(0,k.jsx)(`span`,{className:`d-track`,children:(0,k.jsx)(`i`,{style:{width:`${Math.max(2,Math.round(e.value/n*100))}%`}})})]},e.key))})}function N({items:e,windowLabel:t}){return e.length===0?(0,k.jsxs)(`div`,{className:`empty-note`,style:{padding:`8px 0`},children:[t,`没有按模型的消耗记录。`]}):(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(`div`,{className:`tbl-scroll`,children:(0,k.jsxs)(`table`,{className:`tbl`,children:[(0,k.jsxs)(`caption`,{className:`sr-only`,children:[`按模型的 token 消耗明细,共 `,e.length,` 个模型`]}),(0,k.jsx)(`thead`,{children:(0,k.jsxs)(`tr`,{children:[(0,k.jsx)(`th`,{scope:`col`,children:`模型`}),(0,k.jsx)(`th`,{scope:`col`,className:`r`,children:`请求次数`}),(0,k.jsx)(`th`,{scope:`col`,className:`r`,children:`Token 消耗`}),(0,k.jsx)(`th`,{scope:`col`,className:`r`,children:`Token 占比`}),(0,k.jsx)(`th`,{scope:`col`,className:`r`,children:`消耗积分`}),(0,k.jsx)(`th`,{scope:`col`,className:`r`,children:`平均单次 Token`})]})}),(0,k.jsx)(`tbody`,{children:e.map(e=>{let t=e.displayName??e.model??`未知模型`;return(0,k.jsxs)(`tr`,{children:[(0,k.jsxs)(`td`,{className:`td-strong`,children:[t,e.tag?(0,k.jsx)(`span`,{className:`mu-tag`,children:e.tag}):null,e.multiplier==null?(0,k.jsx)(d,{content:`接口与本地快照都缺此模型倍率 —— 该行积分按中性倍率估算,不是上游真实计费`,children:(0,k.jsx)(`span`,{className:`mu-unknown`,children:`倍率未知`})}):null]}),(0,k.jsx)(`td`,{className:`r td-mono`,children:u(e.requests)}),(0,k.jsx)(`td`,{className:`r td-mono`,children:s(e.tokens??0)}),(0,k.jsx)(`td`,{className:`r td-mono`,children:l(e.share)}),(0,k.jsx)(`td`,{className:`r td-mono`,children:e.credits===null?(0,k.jsx)(d,{content:e.creditsUnknownCount?`本窗口 ${u(e.creditsUnknownCount)} 条请求上游均未回报单次费用(该上游只在账本给累计值)。真实消耗见上方「积分账本」。`:`上游未回报单次费用。真实消耗见上方「积分账本」。`,children:(0,k.jsx)(`span`,{className:`cred-unknown`,children:`--`})}):c(e.credits)}),(0,k.jsx)(`td`,{className:`r td-mono`,children:e.requests>0?s(Math.round((e.tokens??0)/e.requests)):`--`})]},e.model??t)})})]})}),(0,k.jsxs)(`div`,{className:`footer-note`,children:[`平均单次 = Token 消耗 ÷ 请求次数。接口不提供按模型的耗时,「较昨日」与「本计费周期」也无对应字段 —— 这三样一律留空而不是补一个看着合理的数。`,(0,k.jsx)(`br`,{}),`标着`,(0,k.jsx)(`b`,{children:`「倍率未知」`}),`的行,是 /v3/config 接口与本地快照都没有的模型:`,(0,k.jsx)(`b`,{children:`该行积分是按中性倍率估算的,不是上游真实计费`}),`。`]})]})}var P={ok:`额度接口正常`,quota_endpoint_not_configured:`未配置额度端点`,quota_endpoint_error:`额度端点拉取失败`};function F({quota:n,provenance:i,windowLabel:a}){let o=n.available&&n.remain!==null;return(0,k.jsxs)(g,{title:`配额数据来源`,aside:(0,k.jsx)(_,{tone:n.available?`live`:`amber`,dot:!0,children:P[n.reason]}),children:[(0,k.jsxs)(`div`,{className:`src-grid`,children:[(0,k.jsxs)(`div`,{className:`src-col`,children:[(0,k.jsxs)(`div`,{className:`src-head`,children:[(0,k.jsx)(t,{size:13,"aria-hidden":!0}),`来自上游额度接口`,(0,k.jsx)(`span`,{className:`tag tag-live`,children:`官方口径`})]}),(0,k.jsxs)(`ul`,{children:[(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`剩余积分`}),(0,k.jsx)(`i`,{children:`quota.remain`})]}),(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`总量`}),(0,k.jsx)(`i`,{children:`quota.total`})]}),(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`重置时间`}),(0,k.jsx)(`i`,{children:`quota.resetAt`})]})]}),(0,k.jsx)(`div`,{className:`src-state`,children:o?n.stale?(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(r,{size:13,"aria-hidden":!0}),`上次拉取失败,当前显示的是上一次成功值(不会清空)。`]}):`已接入,随配额端点轮询刷新。`:(0,k.jsxs)(k.Fragment,{children:[`未接入 —— 上面三项显示 `,(0,k.jsx)(`i`,{children:`--`}),`。服务端不做估算,前端更不会替它编一个。`]})})]}),(0,k.jsxs)(`div`,{className:`src-col`,children:[(0,k.jsxs)(`div`,{className:`src-head`,children:[(0,k.jsx)(e,{size:13,"aria-hidden":!0}),`本机按请求累计`,(0,k.jsx)(`span`,{className:`tag tag-off`,children:`非官方口径`})]}),(0,k.jsxs)(`ul`,{children:[(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`已消耗积分`}),(0,k.jsx)(`i`,{children:`仅统计经本服务转发的请求,按上游实扣累加(官方客户端直连不计入)`})]}),(0,k.jsxs)(`li`,{children:[(0,k.jsxs)(`b`,{children:[a,`趋势`]}),(0,k.jsx)(`i`,{children:`本机日志按天聚合`})]}),(0,k.jsxs)(`li`,{children:[(0,k.jsx)(`b`,{children:`按模型 / 按提供商消耗`}),(0,k.jsx)(`i`,{children:`同一次聚合的一体两面`})]})]}),(0,k.jsx)(`div`,{className:`src-state`,children:`这些数即时产生,不等额度接口 —— 也正是它和「剩余积分」会对不齐的原因。`})]})]}),n.message?(0,k.jsx)(`div`,{className:`footer-note`,children:n.message}):null,(0,k.jsx)(`div`,{className:`footer-note`,children:i.note}),(0,k.jsxs)(`div`,{className:`footer-note`,children:[`官方额度接口按 `,(0,k.jsx)(`span`,{className:`code-chip`,children:`quota.pollSeconds`}),`(默认 `,(0,k.jsx)(`b`,{children:`30 秒`}),`)轮询, 所以「剩余积分」最多滞后 30 秒;本机累计的消耗是即时的。 两者最多相差 `,(0,k.jsx)(`b`,{children:`30 秒内的消耗量`}),` —— 这是取样时刻不同,不是账对不上。 来源标记:已消耗积分 `,(0,k.jsx)(`span`,{className:`code-chip`,children:i.creditsUsed}),` · `,`剩余积分 `,(0,k.jsx)(`span`,{className:`code-chip`,children:i.quotaRemain}),`。`]})]})}var I=`today`,L={today:null,"1h":null,"24h":null,"7d":7,"30d":30};function R(){let[e,t]=(0,O.useState)(I),n=f(()=>h.overview(e),[e],{cacheKey:`overview:${e}`});w(`usage-${e}-${n.data?`ready`:`pending`}`);let[r,i]=(0,O.useState)(`tokens`),d=n.data,m=L[e],P=d&&m?d.metrics.creditsUsed/m:null,R=d&&m?d.metrics.requests/m:null,z=d&&m?d.metrics.totalTokens/m:null,B=d?[...d.byModel].sort((e,t)=>(t.tokens??0)-(e.tokens??0)):[],V=d?[...d.byClient].sort((e,t)=>(t.tokens??0)-(e.tokens??0)):[],H=d&&d.quota.available&&d.quota.remain!==null&&P!==null&&P>0?Math.floor(d.quota.remain/P):null,U=d?d.quota.available?P===null||P<=0?`${a[d.window]}无消耗记录`:`按日均 ${c(P)} 积分估算`:`需要额度接口`:void 0,W=e=>{if(!d||d.byClient.length===0)return;let t=[...d.byClient].sort((t,n)=>(n[e]??0)-(t[e]??0));return(0,k.jsx)(D,{rows:t,metric:e,windowLabel:a[d.window],total:e===`credits`?d.metrics.creditsUsed:e===`tokens`?d.metrics.totalTokens:d.metrics.requests,totalCount:t.length})};return(0,k.jsxs)(`div`,{className:`view on`,children:[(0,k.jsx)(x,{title:`积分与用量`,status:d?(0,k.jsxs)(_,{tone:`live`,dot:!0,children:[a[d.window],` · `,o(d.generatedAt)]}):null,actions:(0,k.jsx)(S,{value:e,options:p,onChange:t,width:148})}),(0,k.jsx)(`div`,{className:`view-body stack`,children:n.initial&&n.loading?(0,k.jsx)(C,{}):n.error?(0,k.jsx)(g,{children:(0,k.jsx)(v,{kind:`error`,title:`用量数据没取到`,detail:b(n.error),onRetry:n.reload})}):d?(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(E,{metrics:d.metrics}),(0,k.jsx)(y,{items:[{label:`${a[d.window]}消耗`,value:c(d.metrics.creditsUsed),detail:`经本服务转发 · 上游实扣累计`,tip:W(`credits`),tipPos:`down`},{label:`${a[d.window]}请求`,value:u(d.metrics.requests),detail:`${u(d.metrics.activeClients)} 个密钥活跃`,tip:W(`requests`),tipPos:`down`},...P===null?[{label:`本窗口总 tokens`,value:s(d.metrics.totalTokens),detail:`输入 ${s(d.metrics.promptTokens)} · 输出 ${s(d.metrics.completionTokens)}`,tip:W(`tokens`),tipPos:`down`}]:[{label:`日均消耗`,value:c(P),detail:`${a[d.window]}消耗 ÷ ${m} 天`,tip:W(`credits`),tipPos:`down`},{label:`按当前速度可用天数`,value:H===null?`—`:u(H),detail:U,tone:d.quota.available?void 0:`amber`}]]}),(0,k.jsx)(g,{title:`${a[d.window]}趋势`,aside:(0,k.jsxs)(`span`,{className:`panel-aside-row`,children:[(0,k.jsx)(`span`,{className:`seg-tabs`,role:`group`,"aria-label":`趋势口径`,children:[`tokens`,`requests`].map(e=>(0,k.jsx)(`button`,{type:`button`,className:r===e?`on`:``,"aria-pressed":r===e,onClick:()=>i(e),children:e===`tokens`?`Token`:`请求数`},e))}),(0,k.jsxs)(_,{children:[`单位:`,A[r],` `,e===`1h`||e===`24h`||e===`today`?`/ 小时`:`/ 天`]})]}),padded:!1,children:(0,k.jsx)(`div`,{style:{padding:`0 20px 18px`},children:(0,k.jsx)(j,{points:d.trend,metric:r,avg:r===`tokens`?z:R})})}),(0,k.jsx)(g,{title:`按模型消耗明细`,aside:(0,k.jsx)(_,{children:`按 Token 排序`}),padded:!1,children:(0,k.jsx)(`div`,{style:{padding:`0 20px 18px`},children:(0,k.jsx)(N,{items:B,windowLabel:a[d.window]})})}),(0,k.jsxs)(g,{title:`按提供商消耗`,aside:(0,k.jsx)(_,{children:`按 Token 排序`}),children:[(0,k.jsx)(M,{windowLabel:a[d.window],items:V.map(e=>({key:e.clientId??`—`,label:e.client??`未识别`,value:e.tokens??0,format:`int`,trailing:`${l(e.share)} · ${c(e.credits)} 积分 · ${u(e.requests)} 次`,tip:(0,k.jsx)(T,{row:e})}))}),(0,k.jsx)(`div`,{className:`footer-note`,children:`「未识别」是正常的识别分支,不是错误 —— 没绑定密钥又没匹配到特征时归到这里。`})]}),(0,k.jsx)(F,{quota:d.quota,provenance:d.provenance,windowLabel:a[d.window]})]}):null})]})}export{R as UsagePage};
|