232 lines
12 KiB
HTML
232 lines
12 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>LLM Proxy - 后台管理</title>
|
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3E🔄%3C/text%3E%3C/svg%3E">
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link href="https://cdn.jsdelivr.net/npm/remixicon@3.5.0/fonts/remixicon.css" rel="stylesheet">
|
|
<style>
|
|
.gradient-bg { background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); }
|
|
</style>
|
|
</head>
|
|
<body class="bg-gray-50 min-h-screen">
|
|
<div class="flex">
|
|
<!-- 侧边栏 -->
|
|
<aside class="w-64 bg-slate-800 min-h-screen fixed left-0 top-0">
|
|
<div class="p-6">
|
|
<h1 class="text-white text-xl font-bold flex items-center gap-2">
|
|
<i class="ri-route-line text-2xl text-purple-400"></i>
|
|
LLM Proxy
|
|
</h1>
|
|
<p class="text-slate-400 text-sm mt-1">后台管理</p>
|
|
</div>
|
|
<nav class="mt-6">
|
|
<a href="/admin" class="flex items-center gap-3 px-6 py-3 bg-slate-700 text-white">
|
|
<i class="ri-dashboard-line"></i><span>仪表盘</span>
|
|
</a>
|
|
<a href="/admin/providers" class="flex items-center gap-3 px-6 py-3 text-slate-300 hover:bg-slate-700 hover:text-white">
|
|
<i class="ri-server-line"></i><span>提供商管理</span>
|
|
</a>
|
|
<a href="/admin/models" class="flex items-center gap-3 px-6 py-3 text-slate-300 hover:bg-slate-700 hover:text-white">
|
|
<i class="ri-cpu-line"></i><span>模型管理</span>
|
|
</a>
|
|
<a href="/admin/auto-profiles" class="flex items-center gap-3 px-6 py-3 text-slate-300 hover:bg-slate-700 hover:text-white">
|
|
<i class="ri-shuffle-line"></i><span>Auto配置</span>
|
|
</a>
|
|
<a href="/admin/chat" class="flex items-center gap-3 px-6 py-3 text-slate-300 hover:bg-slate-700 hover:text-white">
|
|
<i class="ri-chat-3-line"></i><span>对话</span>
|
|
</a>
|
|
<a href="/admin/logs" class="flex items-center gap-3 px-6 py-3 text-slate-300 hover:bg-slate-700 hover:text-white">
|
|
<i class="ri-file-list-line"></i><span>日志查看</span>
|
|
</a>
|
|
<a href="/admin/config" class="flex items-center gap-3 px-6 py-3 text-slate-300 hover:bg-slate-700 hover:text-white">
|
|
<i class="ri-settings-3-line"></i><span>系统配置</span>
|
|
</a>
|
|
</nav>
|
|
<div class="absolute bottom-0 left-0 right-0 p-4 border-t border-slate-700">
|
|
<a href="http://localhost:19007" target="_blank" class="text-slate-400 hover:text-white text-sm flex items-center gap-2">
|
|
<i class="ri-external-link-line"></i> 访问API
|
|
</a>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- 主内容 -->
|
|
<main class="ml-64 flex-1 p-8">
|
|
<!-- 统计卡片 -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
|
<div class="bg-white rounded-xl p-6 shadow-sm border border-gray-100">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-gray-500 text-sm">总请求数</p>
|
|
<p class="text-3xl font-bold text-gray-800 mt-2" id="stat-requests">-</p>
|
|
</div>
|
|
<div class="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center">
|
|
<i class="ri-send-plane-line text-2xl text-purple-600"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-white rounded-xl p-6 shadow-sm border border-gray-100">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-gray-500 text-sm">成功率</p>
|
|
<p class="text-3xl font-bold text-green-600 mt-2" id="stat-success">-</p>
|
|
</div>
|
|
<div class="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center">
|
|
<i class="ri-check-double-line text-2xl text-green-600"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-white rounded-xl p-6 shadow-sm border border-gray-100">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-gray-500 text-sm">提供商状态</p>
|
|
<p class="text-3xl font-bold text-gray-800 mt-2" id="stat-providers">-</p>
|
|
</div>
|
|
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center">
|
|
<i class="ri-server-line text-2xl text-blue-600"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-white rounded-xl p-6 shadow-sm border border-gray-100">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-gray-500 text-sm">支持模型</p>
|
|
<p class="text-3xl font-bold text-gray-800 mt-2" id="stat-models">-</p>
|
|
</div>
|
|
<div class="w-12 h-12 bg-orange-100 rounded-lg flex items-center justify-center">
|
|
<i class="ri-cpu-line text-2xl text-orange-600"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 提供商状态 -->
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
|
<h2 class="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2">
|
|
<i class="ri-server-line text-purple-500"></i>
|
|
提供商状态
|
|
</h2>
|
|
<div id="providerList" class="space-y-3">
|
|
<p class="text-gray-500">加载中...</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
|
<h2 class="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2">
|
|
<i class="ri-route-line text-blue-500"></i>
|
|
调用流程
|
|
</h2>
|
|
<div class="space-y-4 text-sm">
|
|
<div class="flex items-center gap-3 p-3 bg-purple-50 rounded-lg">
|
|
<span class="w-6 h-6 bg-purple-500 text-white rounded-full flex items-center justify-center text-xs">1</span>
|
|
<div>
|
|
<p class="font-medium text-gray-800">客户端请求</p>
|
|
<p class="text-gray-500">POST /v1/chat/completions</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center gap-3 p-3 bg-blue-50 rounded-lg">
|
|
<span class="w-6 h-6 bg-blue-500 text-white rounded-full flex items-center justify-center text-xs">2</span>
|
|
<div>
|
|
<p class="font-medium text-gray-800">解析模型名</p>
|
|
<p class="text-gray-500">model="auto" → 按优先级选择</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center gap-3 p-3 bg-green-50 rounded-lg">
|
|
<span class="w-6 h-6 bg-green-500 text-white rounded-full flex items-center justify-center text-xs">3</span>
|
|
<div>
|
|
<p class="font-medium text-gray-800">转发请求</p>
|
|
<p class="text-gray-500">调用高优先级提供商</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center gap-3 p-3 bg-orange-50 rounded-lg">
|
|
<span class="w-6 h-6 bg-orange-500 text-white rounded-full flex items-center justify-center text-xs">4</span>
|
|
<div>
|
|
<p class="font-medium text-gray-800">故障切换</p>
|
|
<p class="text-gray-500">失败自动切换备用提供商</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 最近请求 -->
|
|
<div class="mt-6 bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
|
<h2 class="text-lg font-semibold text-gray-800 mb-4 flex items-center gap-2">
|
|
<i class="ri-time-line text-green-500"></i>
|
|
快速操作
|
|
</h2>
|
|
<div class="flex gap-4">
|
|
<a href="/admin/providers" class="px-4 py-2 gradient-bg text-white rounded-lg text-sm">
|
|
<i class="ri-server-line mr-1"></i> 管理提供商
|
|
</a>
|
|
<a href="http://localhost:19007/status" target="_blank" class="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg text-sm hover:bg-gray-50">
|
|
<i class="ri-eye-line mr-1"></i> 查看API状态
|
|
</a>
|
|
<a href="/admin/logs" class="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg text-sm hover:bg-gray-50">
|
|
<i class="ri-file-list-line mr-1"></i> 查看日志
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<script>
|
|
async function loadStats() {
|
|
const res = await fetch('/api/admin/stats');
|
|
const data = await res.json();
|
|
|
|
document.getElementById('stat-requests').textContent = data.total_requests;
|
|
document.getElementById('stat-models').textContent = data.models_count;
|
|
|
|
const successRate = data.total_requests > 0
|
|
? Math.round(data.total_success / data.total_requests * 100) + '%'
|
|
: '0%';
|
|
document.getElementById('stat-success').textContent = successRate;
|
|
|
|
document.getElementById('stat-providers').textContent =
|
|
`${data.available_providers}/${data.providers_count}`;
|
|
}
|
|
|
|
async function loadProviders() {
|
|
const res = await fetch('/api/admin/providers');
|
|
const providers = await res.json();
|
|
|
|
const container = document.getElementById('providerList');
|
|
|
|
if (providers.length === 0) {
|
|
container.innerHTML = '<p class="text-gray-500">暂无提供商</p>';
|
|
return;
|
|
}
|
|
|
|
container.innerHTML = providers.map(p => `
|
|
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
|
<div class="flex items-center gap-3">
|
|
<span class="w-8 h-8 ${p.available ? 'bg-green-500' : 'bg-red-500'} text-white rounded-full flex items-center justify-center text-xs font-bold">
|
|
${p.priority}
|
|
</span>
|
|
<div>
|
|
<p class="font-medium text-gray-800">${p.name}</p>
|
|
<p class="text-xs text-gray-500">${p.models.length} 个模型</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<span class="px-2 py-1 rounded text-xs ${p.available ? 'bg-green-100 text-green-600' : 'bg-red-100 text-red-600'}">
|
|
${p.available ? '可用' : '不可用'}
|
|
</span>
|
|
<span class="text-xs text-gray-400">${p.request_count} 请求</span>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
}
|
|
|
|
loadStats();
|
|
loadProviders();
|
|
</script>
|
|
</body>
|
|
</html> |