librechat-analytics/public/index.html
DJP 3d3c8a1a54 feat: Add Visits and Unique Users cards to overview
Visits counts total conversations created in the timeframe (from
conversations collection). Unique Users counts distinct users who
created at least one conversation in the period.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 13:48:46 -04:00

221 lines
8.8 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LibreChat Analytics</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/style.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
<script src="https://unpkg.com/lucide@latest"></script>
</head>
<body>
<div id="app">
<!-- Sidebar -->
<nav class="sidebar">
<div class="sidebar-header">
<svg class="logo-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 12V7H5a2 2 0 0 1 0-4h14v4"/>
<path d="M3 5v14a2 2 0 0 0 2 2h16v-5"/>
<path d="M18 12a2 2 0 0 0 0 4h4v-4Z"/>
</svg>
<span class="logo-text">Analytics</span>
</div>
<ul class="nav-links">
<li class="active" data-tab="overview">
<i data-lucide="bar-chart-3" style="width:20px;height:20px"></i>
Overview
</li>
<li data-tab="users">
<i data-lucide="users" style="width:20px;height:20px"></i>
Users
</li>
<li data-tab="models">
<i data-lucide="cpu" style="width:20px;height:20px"></i>
Models
</li>
<li data-tab="conversations">
<i data-lucide="message-circle" style="width:20px;height:20px"></i>
Conversations
</li>
<li data-tab="agents">
<i data-lucide="bot" style="width:20px;height:20px"></i>
Agents
</li>
</ul>
<div class="sidebar-footer">
Auto-refresh: 60s
</div>
</nav>
<!-- Main Content -->
<main class="content">
<div class="top-bar">
<h1>LibreChat Analytics</h1>
</div>
<!-- Filter Bar -->
<div class="filter-bar">
<div class="period-selector">
<button class="period-btn active" data-period="24h">24H</button>
<button class="period-btn" data-period="7d">7D</button>
<button class="period-btn" data-period="30d">30D</button>
<button class="period-btn" data-period="custom">Custom</button>
</div>
<div class="date-range-picker" id="dateRangePicker" style="display:none">
<input type="date" id="startDate">
<span class="date-separator">to</span>
<input type="date" id="endDate">
</div>
<span class="refresh-info" id="lastRefresh"></span>
</div>
<!-- Overview Tab -->
<div class="tab-content active" id="tab-overview">
<div class="tab-title-row">
<div></div>
<button class="btn-export" onclick="exportOverview()"><i data-lucide="download" style="width:16px;height:16px"></i> Export CSV</button>
</div>
<div class="stats-grid" id="summaryCards">
<div class="stat-card">
<div class="stat-icon cost"><i data-lucide="dollar-sign"></i></div>
<div><span class="stat-label">Total Cost</span><span class="stat-value" id="totalCost">--</span></div>
</div>
<div class="stat-card">
<div class="stat-icon tokens"><i data-lucide="zap"></i></div>
<div><span class="stat-label">Total Tokens</span><span class="stat-value" id="totalTokens">--</span></div>
</div>
<div class="stat-card">
<div class="stat-icon users"><i data-lucide="users"></i></div>
<div><span class="stat-label">Active Users</span><span class="stat-value" id="activeUsers">--</span></div>
</div>
<div class="stat-card">
<div class="stat-icon convos"><i data-lucide="message-square"></i></div>
<div><span class="stat-label">Conversations</span><span class="stat-value" id="conversations">--</span></div>
</div>
<div class="stat-card">
<div class="stat-icon visits"><i data-lucide="log-in"></i></div>
<div><span class="stat-label">Visits</span><span class="stat-value" id="visits">--</span></div>
</div>
<div class="stat-card">
<div class="stat-icon unique"><i data-lucide="user-check"></i></div>
<div><span class="stat-label">Unique Users</span><span class="stat-value" id="uniqueUsers">--</span></div>
</div>
</div>
<div class="charts-grid">
<div class="chart-container chart-wide">
<h3>Usage Over Time</h3>
<canvas id="usageChart"></canvas>
</div>
<div class="chart-container">
<h3>Cost by Model</h3>
<canvas id="costByModelChart"></canvas>
</div>
<div class="chart-container">
<h3>Cost Breakdown (Input vs Output)</h3>
<canvas id="costBreakdownChart"></canvas>
</div>
</div>
</div>
<!-- Users Tab -->
<div class="tab-content" id="tab-users">
<div class="table-container">
<div class="table-header"><h3>Top Users by Cost</h3><button class="btn-export" onclick="exportUsers()"><i data-lucide="download" style="width:16px;height:16px"></i> Export CSV</button></div>
<table>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Email</th>
<th class="text-right">Tokens</th>
<th class="text-right">Cost</th>
<th class="text-right">Conversations</th>
</tr>
</thead>
<tbody id="usersTableBody"></tbody>
</table>
</div>
</div>
<!-- Models Tab -->
<div class="tab-content" id="tab-models">
<div class="table-container">
<div class="table-header"><h3>Top Models by Cost</h3><button class="btn-export" onclick="exportModels()"><i data-lucide="download" style="width:16px;height:16px"></i> Export CSV</button></div>
<table>
<thead>
<tr>
<th>#</th>
<th>Model</th>
<th class="text-right">Prompt Tokens</th>
<th class="text-right">Completion Tokens</th>
<th class="text-right">Prompt Cost</th>
<th class="text-right">Completion Cost</th>
<th class="text-right">Total Cost</th>
</tr>
</thead>
<tbody id="modelsTableBody"></tbody>
</table>
</div>
<div class="charts-grid">
<div class="chart-container chart-wide">
<h3>Model Cost Comparison (Input vs Output)</h3>
<canvas id="modelCostChart"></canvas>
</div>
</div>
</div>
<!-- Conversations Tab -->
<div class="tab-content" id="tab-conversations">
<div class="table-container">
<div class="table-header">
<h3 id="conversationsTitle">Most Expensive Conversations</h3>
<div style="display:flex;gap:0.75rem;align-items:center">
<button class="btn-export btn-filter-user" id="clearUserFilter" onclick="clearUserFilter()" style="display:none"><i data-lucide="x" style="width:14px;height:14px"></i> Clear filter</button>
<button class="btn-export" onclick="exportConversations()"><i data-lucide="download" style="width:16px;height:16px"></i> Export CSV</button>
</div>
</div>
<table>
<thead>
<tr>
<th>#</th>
<th>Title</th>
<th>User</th>
<th>Models</th>
<th class="text-right">Input Tokens</th>
<th class="text-right">Output Tokens</th>
<th class="text-right">Total Cost</th>
</tr>
</thead>
<tbody id="conversationsTableBody"></tbody>
</table>
</div>
</div>
<!-- Agents Tab -->
<div class="tab-content" id="tab-agents">
<div class="table-container">
<div class="table-header"><h3>Top Agents by Cost</h3><button class="btn-export" onclick="exportAgents()"><i data-lucide="download" style="width:16px;height:16px"></i> Export CSV</button></div>
<table>
<thead>
<tr>
<th>#</th>
<th>Agent Name</th>
<th>Underlying Model</th>
<th>Provider</th>
<th class="text-right">Tokens</th>
<th class="text-right">Cost</th>
<th class="text-right">Conversations</th>
</tr>
</thead>
<tbody id="agentsTableBody"></tbody>
</table>
</div>
</div>
</main>
</div>
<script src="js/app.js"></script>
</body>
</html>