支持gimini格式,优化debug日志

This commit is contained in:
h88782481 2026-03-14 09:27:15 +08:00
parent e726f11bad
commit 4de6db13f9
16 changed files with 1783 additions and 55 deletions

View file

@ -59,6 +59,7 @@ main{padding:28px 0 60px}
.tag-anthropic{background:rgba(249,115,22,.15);color:#fb923c}
.tag-openai{background:rgba(16,185,129,.15);color:#34d399}
.tag-responses{background:rgba(59,130,246,.15);color:#60a5fa}
.tag-gemini{background:rgba(66,133,244,.15);color:#4285f4}
.tag-auto{background:rgba(139,92,246,.15);color:#a78bfa}
.tag-override{background:rgba(59,130,246,.1);color:var(--primary)}
.tag-instructions{background:rgba(234,179,8,.15);color:var(--yellow)}
@ -66,6 +67,11 @@ main{padding:28px 0 60px}
.mapping-actions{margin-left:auto;display:flex;gap:6px}
.empty{text-align:center;padding:40px;color:var(--muted)}
.stats-table{width:100%;border-collapse:collapse;font-size:13px}
.stats-table th{text-align:left;color:var(--muted);font-weight:500;padding:8px 12px;border-bottom:1px solid var(--border)}
.stats-table td{padding:8px 12px;border-bottom:1px solid var(--border)}
.stats-table tr:hover{background:var(--surface)}
.modal-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:100;align-items:center;justify-content:center}
.modal-overlay.active{display:flex}
.modal{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:28px;width:520px;max-width:90vw;max-height:85vh;overflow-y:auto;box-shadow:0 20px 60px rgba(0,0,0,.5)}

View file

@ -70,6 +70,15 @@
</div>
<div id="mappingList"></div>
</div>
<!-- 用量统计 -->
<div class="card">
<div class="card-header">
<h2>用量统计</h2>
<button class="btn btn-ghost btn-sm" onclick="loadStats()">刷新</button>
</div>
<div id="statsContent"><div class="empty">加载中…</div></div>
</div>
</main>
</div>
@ -95,13 +104,15 @@
<option value="anthropic">Anthropic (/v1/messages)</option>
<option value="openai">OpenAI (/v1/chat/completions)</option>
<option value="responses">OpenAI Responses (/v1/responses)</option>
<option value="gemini">Gemini (generateContent)</option>
</select>
</div>
<div class="hint">
<b>anthropic</b>:转换为 Anthropic Messages 格式 — 适用于中转站通过 <code>/v1/messages</code> 提供 Claude 模型<br>
<b>openai</b>:保持 OpenAI Chat Completions 格式 — 适用于 GPT、DeepSeek、Codex 或通过 <code>/v1/chat/completions</code> 提供所有模型的中转站<br>
<b>responses</b>:保持 OpenAI Responses 格式 — 适用于中转站仅通过 <code>/v1/responses</code> 提供模型能力<br>
<b>自动检测</b>:根据上游模型名判断(含 claude → anthropic其他 → openai
<b>gemini</b>:转换为 Gemini Contents 格式 — 适用于 Google Gemini API 或兼容的中转站<br>
<b>自动检测</b>:根据上游模型名判断(含 claude → anthropic含 gemini → gemini其他 → openai
</div>
</div>
<div class="field">

View file

@ -70,11 +70,39 @@ async function loadDashboard() {
document.getElementById('envKey').textContent = s.env_api_key ? '环境变量: (已配置)' : '环境变量: (未设置)';
await loadMappings();
checkHealth();
loadStats();
} catch (e) {
toast('加载设置失败: ' + e.message, false);
}
}
async function loadStats() {
const el = document.getElementById('statsContent');
try {
const data = await api('/api/admin/stats');
const models = data.models || {};
const keys = Object.keys(models);
if (!keys.length) {
el.innerHTML = '<div class="empty">暂无请求统计数据</div>';
return;
}
const uptime = data.uptime_seconds || 0;
const h = Math.floor(uptime / 3600);
const m = Math.floor((uptime % 3600) / 60);
let html = '<div class="hint" style="margin-bottom:12px">运行时长: ' + h + '小时' + m + '分钟</div>';
html += '<table class="stats-table"><thead><tr><th>模型</th><th>请求数</th><th>输入 Tokens</th><th>输出 Tokens</th><th>总 Tokens</th></tr></thead><tbody>';
keys.sort((a, b) => models[b].request_count - models[a].request_count);
for (const name of keys) {
const s = models[name];
html += '<tr><td>' + esc(name) + '</td><td>' + s.request_count + '</td><td>' + s.input_tokens.toLocaleString() + '</td><td>' + s.output_tokens.toLocaleString() + '</td><td>' + s.total_tokens.toLocaleString() + '</td></tr>';
}
html += '</tbody></table>';
el.innerHTML = html;
} catch (e) {
el.innerHTML = '<div class="empty">加载统计失败</div>';
}
}
async function checkHealth() {
try {
const r = await fetch(API + '/health');
@ -130,7 +158,9 @@ async function loadMappings() {
? 'tag-responses'
: backend === 'openai'
? 'tag-openai'
: 'tag-auto';
: backend === 'gemini'
? 'tag-gemini'
: 'tag-auto';
const tagLabel = backend === 'auto'
? '自动'
: backend === 'responses'