Files
writing-agent/web/stats.html
T
chenmoranzhi e2413b0677 主题与字号从页面顶栏搬进设置页的「外观」,顶部导航加上预设入口。
顶栏那套汉堡菜单在每页都要单独挂载、样式也重复,收进设置页后只剩一处改;顺手把「整组都没有曾用型号」的配置组整组收起,不再留空卡片。
2026-10-26 01:09:43 +08:00

193 lines
8.4 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Token 统计 · Writing Agent</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;600;700&family=Noto+Serif+SC:wght@500;600;700&display=swap"
rel="stylesheet"
/>
<script src="/theme-init.js"></script>
<link rel="stylesheet" href="/settings.css" />
<link rel="stylesheet" href="/stats.css" />
</head>
<body class="settings-page stats-page">
<header class="st-top">
<a class="st-brand" href="/">Writing Agent</a>
<nav class="st-nav" aria-label="主导航">
<a href="/">对话</a>
<a href="/chat.html">直聊</a>
<a href="/modules.html">技能</a>
<a href="/libraries.html">库</a>
<a href="/stats.html" aria-current="page">Token</a>
<a href="/presets.html">预设</a>
<a href="/settings.html">设置</a>
</nav>
</header>
<div class="st-shell stats-shell">
<main class="st-main stats-main">
<header class="st-main-head">
<div>
<h1>Token 统计</h1>
<p class="st-sub">按时间筛选本机调用。OpenRouter 价格在下面手动拉取,只保留 DeepSeek、Claude、GLM、Gemini、GPT、Grok 的当前档。</p>
</div>
</header>
<div class="stats-toolbar" role="search" aria-label="筛选条件">
<div class="stats-toolbar-fields">
<label class="stats-field">
从
<input type="datetime-local" id="from" />
</label>
<label class="stats-field">
到
<input type="datetime-local" id="to" />
</label>
<label class="stats-field">
上限条数
<input type="number" id="limit" value="200" min="10" max="5000" step="10" />
</label>
</div>
<div class="stats-toolbar-actions">
<div class="stats-range" role="group" aria-label="快捷区间">
<button type="button" class="btn-secondary" id="btn-today">今天</button>
<button type="button" class="btn-secondary" id="btn-7d">近 7 天</button>
</div>
<button type="button" class="btn-primary" id="btn-load">查询</button>
</div>
</div>
<section class="stats-pricing" aria-label="价格来源">
<div class="stats-pricing-head">
<p class="stats-section-label">价格来源</p>
<p class="stats-pricing-hint">
厂商官方价目(含高峰/闲时)仍可粘贴文档。OpenRouter 用下方按钮拉取。
</p>
</div>
<form class="stats-pricing-add" id="pricing-form">
<label class="stats-field stats-field-url">
官方文档 URL
<input
type="url"
id="pricing-url"
placeholder="https://api-docs.deepseek.com/quick_start/pricing"
autocomplete="off"
/>
</label>
<button type="submit" class="btn-primary" id="btn-add-pricing">从文档计算</button>
</form>
<div class="stats-pricing-suggested" id="pricing-suggested"></div>
<ul class="stats-pricing-list" id="pricing-sources"></ul>
<p class="stats-pricing-status" id="pricing-status" hidden aria-live="polite"></p>
</section>
<section class="stats-compare" aria-label="模型价格对比">
<div class="stats-compare-head">
<div>
<p class="stats-section-label">价格对比</p>
<p class="stats-pricing-hint">
一行一个型号。前三列是每百万 token 的通常单价,最后一列是按最近 100 次调用重估的花费。
</p>
</div>
<button type="button" class="btn-primary" id="btn-pull-openrouter">拉取 OpenRouter 价格</button>
</div>
<div class="stats-table-wrap stats-compare-wrap">
<table class="stats-table stats-compare-table" id="compare-table">
<thead>
<tr>
<th scope="col" aria-sort="none">
<div class="stats-compare-model-col">
<button type="button" class="stats-sort" data-sort="model" data-label="型号" title="按型号排序">型号</button>
<input
type="search"
id="compare-filter"
class="stats-compare-filter"
placeholder="筛选型号"
aria-label="按型号筛选"
autocomplete="off"
spellcheck="false"
/>
</div>
</th>
<th scope="col" class="num" aria-sort="none">
<button type="button" class="stats-sort" data-sort="input" data-label="输入" title="按输入单价排序">输入</button>
</th>
<th scope="col" class="num" aria-sort="none">
<button type="button" class="stats-sort" data-sort="cached" data-label="缓存" title="按缓存单价排序">缓存</button>
</th>
<th scope="col" class="num" aria-sort="none">
<button type="button" class="stats-sort" data-sort="output" data-label="输出" title="按输出单价排序">输出</button>
</th>
<th scope="col" aria-sort="ascending">
<button type="button" class="stats-sort" data-sort="projected" data-label="近 100 次" title="按近 100 次花费排序">近 100 次 ↑</button>
</th>
</tr>
</thead>
<tbody id="compare-list"></tbody>
</table>
</div>
<p class="stats-compare-status" id="compare-status" hidden aria-live="polite"></p>
</section>
<div class="stats-summary" id="summary" aria-live="polite"></div>
<p class="stats-status" id="status" data-state="idle" aria-live="polite"></p>
<section class="stats-by-model" aria-label="按模型花销">
<p class="stats-section-label">按模型</p>
<div class="stats-table-wrap stats-table-wrap-model">
<table class="stats-table" id="model-table">
<thead>
<tr>
<th scope="col">model</th>
<th scope="col" class="num">调用</th>
<th scope="col" class="num">prompt</th>
<th scope="col" class="num">completion</th>
<th scope="col" class="num">cached</th>
<th scope="col" class="num">当前单价</th>
<th scope="col" class="num">估算花销</th>
<th scope="col">来源</th>
</tr>
</thead>
<tbody id="model-rows"></tbody>
</table>
<div class="stats-empty" id="model-empty" hidden>
<strong>没有可汇总的型号</strong>
先查出调用记录;OpenRouter 会自动同步单价,其他渠道可手动添加价目。
</div>
</div>
</section>
<p class="stats-section-label">调用记录</p>
<div class="stats-table-wrap">
<table class="stats-table" id="call-table">
<thead>
<tr>
<th scope="col">时间</th>
<th scope="col">步骤</th>
<th scope="col">caller</th>
<th scope="col">model</th>
<th scope="col" class="num">prompt</th>
<th scope="col" class="num">未缓存</th>
<th scope="col" class="num">cached</th>
<th scope="col">断开</th>
<th scope="col" class="num">花销</th>
</tr>
</thead>
<tbody id="rows"></tbody>
</table>
<div class="stats-empty" id="empty" hidden>
<strong>这段时间没有调用记录</strong>
换个区间,或先在对话里跑一轮再回来。
</div>
</div>
</main>
</div>
<script type="module" src="/stats.js"></script>
</body>
</html>