218 lines
10 KiB
HTML
218 lines
10 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>LLM 速度测试台</title>
|
||
<link rel="stylesheet" href="/css/style.css">
|
||
</head>
|
||
<body>
|
||
<header class="topbar">
|
||
<div class="brand">
|
||
<span class="logo">⚡</span>
|
||
<h1>LLM 速度测试台</h1>
|
||
<span class="sub">大模型推理性能基准 · 预填充 / 首字 / 解码</span>
|
||
</div>
|
||
<div class="status-badge" id="run-status"><span class="dot"></span>空闲</div>
|
||
</header>
|
||
|
||
<main class="layout">
|
||
<!-- 左侧:配置 -->
|
||
<aside class="config-panel">
|
||
<section class="card">
|
||
<h2>🔌 大模型接口配置</h2>
|
||
<div class="field">
|
||
<label>提供商类型</label>
|
||
<select id="cfg-provider">
|
||
<option value="openai">OpenAI 兼容(OpenAI / DeepSeek / 火山方舟…)</option>
|
||
<option value="anthropic">Anthropic(Claude)</option>
|
||
<option value="google">Google Gemini</option>
|
||
</select>
|
||
</div>
|
||
<div class="field">
|
||
<label>已保存配置</label>
|
||
<div class="row">
|
||
<select id="cfg-list"><option value="">— 选择配置加载 —</option></select>
|
||
<button class="btn small" id="btn-load-config" title="加载选中配置">载入</button>
|
||
<button class="btn small primary" id="btn-save-config" title="保存当前输入">保存</button>
|
||
<button class="btn small danger" id="btn-del-config" title="删除选中配置">删除</button>
|
||
</div>
|
||
</div>
|
||
<div class="field">
|
||
<label>配置名称</label>
|
||
<div class="icon-input"><span class="icon">📛</span><input id="cfg-name" placeholder="例如:DeepSeek-V4"></div>
|
||
</div>
|
||
<div class="field">
|
||
<label>Base URL</label>
|
||
<div class="icon-input"><span class="icon">🌐</span><input id="cfg-baseurl" placeholder="留空使用官方默认地址"></div>
|
||
<div class="hint" id="cfg-default-url"></div>
|
||
</div>
|
||
<div class="field">
|
||
<label>API Key</label>
|
||
<div class="row">
|
||
<input id="cfg-apikey" type="password" placeholder="sk-... / key...">
|
||
<button class="btn small" id="btn-toggle-key" title="显示/隐藏">👁</button>
|
||
</div>
|
||
</div>
|
||
<div class="field">
|
||
<label>模型名称</label>
|
||
<div class="icon-input"><span class="icon">🤖</span><input id="cfg-model" placeholder="如 gpt-4o / deepseek-chat / claude-sonnet-4"></div>
|
||
</div>
|
||
<div class="field">
|
||
<label>温度 Temperature <b id="tmp-val">0.7</b></label>
|
||
<input id="cfg-temp" type="range" min="0" max="2" step="0.1" value="0.7">
|
||
</div>
|
||
<button class="btn block" id="btn-test-conn">🔍 测试连接</button>
|
||
<div class="conn-result" id="conn-result" hidden></div>
|
||
</section>
|
||
|
||
<section class="card">
|
||
<h2>🚀 速度测试配置</h2>
|
||
<div class="field">
|
||
<label>测试名称(主题)</label>
|
||
<input id="gen-name" type="text" placeholder="如:DeepSeek-V4 不同上下文长度速度对比">
|
||
</div>
|
||
<div class="field">
|
||
<label>上下文长度(tokens,点击切换启停)</label>
|
||
<div class="chips" id="gen-contexts"></div>
|
||
<div class="row" style="margin-top:6px">
|
||
<input id="gen-context-add" type="number" min="16" step="16" placeholder="自定义长度(≥16)">
|
||
<button class="btn small" id="btn-context-add">+ 添加</button>
|
||
</div>
|
||
</div>
|
||
<div class="field">
|
||
<label>解码输出长度(max tokens)</label>
|
||
<input id="gen-max-tokens" type="number" min="1" step="1" value="128">
|
||
</div>
|
||
<div class="field">
|
||
<label>每个长度×并发采样次数</label>
|
||
<input id="gen-samples" type="number" min="1" max="50" value="2">
|
||
</div>
|
||
<div class="field">
|
||
<label>并发数(同时请求流数,默认单流)</label>
|
||
<div class="chips" id="gen-concurrency"></div>
|
||
<div class="row" style="margin-top:6px">
|
||
<input id="gen-conc-add" type="number" min="1" max="64" placeholder="自定义并发数(≥1)">
|
||
<button class="btn small" id="btn-conc-add">+ 添加</button>
|
||
</div>
|
||
<div class="hint">选中多个并发数时,同一测试会分别跑各并发档并放在一起对比</div>
|
||
</div>
|
||
<div class="field switch-field">
|
||
<label>测试前预热<span class="hint-inline">空转不计速度,避免冷启动偏差</span></label>
|
||
<label class="switch">
|
||
<input type="checkbox" id="gen-warmup" checked>
|
||
<span class="slider"></span>
|
||
</label>
|
||
</div>
|
||
<div class="field switch-field">
|
||
<label>避免缓存<span class="hint-inline">随机前缀,测真实预填充</span></label>
|
||
<label class="switch">
|
||
<input type="checkbox" id="gen-avoid-cache" checked>
|
||
<span class="slider"></span>
|
||
</label>
|
||
</div>
|
||
<div class="btn-group">
|
||
<button class="btn primary block" id="btn-start">▶ 开始测试</button>
|
||
<button class="btn danger block" id="btn-cancel" disabled>■ 停止</button>
|
||
</div>
|
||
</section>
|
||
<section class="card">
|
||
<h2>📤 评测站同步</h2>
|
||
<div class="field">
|
||
<label>评测站地址</label>
|
||
<div class="icon-input"><span class="icon">🌐</span><input id="eval-url" placeholder="http://127.0.0.1:16066"></div>
|
||
</div>
|
||
<div class="field">
|
||
<label>评测站账号(结果挂到该账号下)</label>
|
||
<div class="icon-input"><span class="icon">👥</span><input id="eval-account" placeholder="如:性能评测组"></div>
|
||
</div>
|
||
<div class="field">
|
||
<label>硬件 / GPU(自动探测可修改,随结果一并发送)</label>
|
||
<div class="row">
|
||
<div class="icon-input"><span class="icon">🖥</span><input id="eval-hardware" placeholder="如:NVIDIA A100 80G"></div>
|
||
<button class="btn small" id="btn-detect-gpu" title="自动探测本机GPU">🔍 探测</button>
|
||
</div>
|
||
</div>
|
||
<button class="btn block" id="btn-eval-test">🔗 测试连接</button>
|
||
<div class="conn-result" id="eval-result" hidden></div>
|
||
<div class="hint" style="margin-top:6px">测试完成后,在历史列表或详情里点「📤 发送到评测站」,一键把结果发布到模型评测网站(端口 16066)对应账号下。</div>
|
||
</section>
|
||
</aside>
|
||
|
||
<!-- 右侧:指标 + 日志 + 历史 -->
|
||
<section class="main">
|
||
<div class="metrics">
|
||
<div class="metric-card"><div class="m-label">首字延迟</div><div class="m-value" id="m-ttft">—</div><div class="m-unit" id="m-ttft-u">ms</div></div>
|
||
<div class="metric-card"><div class="m-label">预填充速度</div><div class="m-value" id="m-prefill">—</div><div class="m-unit">tok/s</div></div>
|
||
<div class="metric-card"><div class="m-label">解码速度</div><div class="m-value" id="m-decode">—</div><div class="m-unit">tok/s</div></div>
|
||
<div class="metric-card"><div class="m-label">上文 Tokens</div><div class="m-value" id="m-prompts">—</div><div class="m-unit">tok</div></div>
|
||
<div class="metric-card"><div class="m-label">输出 Tokens</div><div class="m-value" id="m-outputs">—</div><div class="m-unit">tok</div></div>
|
||
<div class="metric-card"><div class="m-label">总耗时</div><div class="m-value" id="m-total">—</div><div class="m-unit">ms</div></div>
|
||
</div>
|
||
|
||
<div class="card log-card">
|
||
<div class="card-head">
|
||
<h2>📋 测试日志</h2>
|
||
<div class="log-actions">
|
||
<span class="hint" id="log-count"></span>
|
||
<button class="btn small" id="btn-clear-console">清屏</button>
|
||
<button class="btn small" id="btn-export-log" title="导出当前测试完整日志">导出日志</button>
|
||
</div>
|
||
</div>
|
||
<div class="console" id="console"></div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-head">
|
||
<h2>🗂 测试历史</h2>
|
||
<div class="log-actions">
|
||
<span class="hint" id="hist-selected"></span>
|
||
<button class="btn small primary" id="btn-compare">⚖️ 对比所选</button>
|
||
<button class="btn small" id="btn-refresh-history">刷新</button>
|
||
</div>
|
||
</div>
|
||
<div class="table-wrap">
|
||
<table class="history" id="history">
|
||
<thead><tr>
|
||
<th class="chk-col"><input type="checkbox" id="hist-check-all" title="全选"></th>
|
||
<th>#</th><th>时间</th><th>名称</th><th>提供商</th><th>模型</th><th>并发</th><th>采样</th>
|
||
<th>首字 ms</th><th>预填充 tok/s</th><th>解码 tok/s</th><th>状态</th><th>操作</th>
|
||
</tr></thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<!-- 详情弹窗 -->
|
||
<div class="modal-mask" id="detail-mask" hidden>
|
||
<div class="modal">
|
||
<div class="modal-head">
|
||
<h2>测试详情 #<span id="dt-id"></span></h2>
|
||
<div>
|
||
<button class="btn small primary" id="dt-send-eval">📤 发送到评测站</button>
|
||
<button class="btn small primary" id="dt-export-xlsx">⬇ 导出 Excel</button>
|
||
<button class="btn small primary" id="dt-export">导出 JSON</button>
|
||
<button class="btn small" id="dt-close">✕</button>
|
||
</div>
|
||
</div>
|
||
<div class="modal-body" id="dt-body"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 多测试对比弹窗 -->
|
||
<div class="modal-mask" id="cmp-mask" hidden>
|
||
<div class="modal">
|
||
<div class="modal-head">
|
||
<h2>⚖️ 多测试结果对比</h2>
|
||
<button class="btn small" id="cmp-close">✕</button>
|
||
</div>
|
||
<div class="modal-body" id="cmp-body"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="/js/app.js"></script>
|
||
</body>
|
||
</html>
|