This commit introduces major enhancements to Talk2Me: ## Database Integration - PostgreSQL support with SQLAlchemy ORM - Redis integration for caching and real-time analytics - Automated database initialization scripts - Migration support infrastructure ## User Authentication System - JWT-based API authentication - Session-based web authentication - API key authentication for programmatic access - User roles and permissions (admin/user) - Login history and session tracking - Rate limiting per user with customizable limits ## Admin Dashboard - Real-time analytics and monitoring - User management interface (create, edit, delete users) - System health monitoring - Request/error tracking - Language pair usage statistics - Performance metrics visualization ## Key Features - Dual authentication support (token + user accounts) - Graceful fallback for missing services - Non-blocking analytics middleware - Comprehensive error handling - Session management with security features ## Bug Fixes - Fixed rate limiting bypass for admin routes - Added missing email validation method - Improved error handling for missing database tables - Fixed session-based authentication for API endpoints 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
277 lines
9.5 KiB
HTML
277 lines
9.5 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Dashboard - Talk2Me Admin{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- Quick Actions -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card bg-light">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Quick Actions</h5>
|
|
<div class="btn-group" role="group">
|
|
<a href="{{ url_for('admin.users') }}" class="btn btn-primary">
|
|
<i class="fas fa-users"></i> Manage Users
|
|
</a>
|
|
<button onclick="exportData('all')" class="btn btn-secondary">
|
|
<i class="fas fa-download"></i> Export Data
|
|
</button>
|
|
<button onclick="clearCache()" class="btn btn-warning">
|
|
<i class="fas fa-trash"></i> Clear Cache
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Overview Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3 mb-3">
|
|
<div class="card text-white bg-primary">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Total Requests</h5>
|
|
<h2 class="card-text" id="total-requests">
|
|
<div class="spinner-border spinner-border-sm" role="status"></div>
|
|
</h2>
|
|
<p class="card-text"><small>Today: <span id="today-requests">-</span></small></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3 mb-3">
|
|
<div class="card text-white bg-success">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Active Sessions</h5>
|
|
<h2 class="card-text" id="active-sessions">
|
|
<div class="spinner-border spinner-border-sm" role="status"></div>
|
|
</h2>
|
|
<p class="card-text"><small>Live users</small></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3 mb-3">
|
|
<div class="card text-white bg-warning">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Error Rate</h5>
|
|
<h2 class="card-text" id="error-rate">
|
|
<div class="spinner-border spinner-border-sm" role="status"></div>
|
|
</h2>
|
|
<p class="card-text"><small>Last 24 hours</small></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3 mb-3">
|
|
<div class="card text-white bg-info">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Cache Hit Rate</h5>
|
|
<h2 class="card-text" id="cache-hit-rate">
|
|
<div class="spinner-border spinner-border-sm" role="status"></div>
|
|
</h2>
|
|
<p class="card-text"><small>Performance metric</small></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- System Health Status -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0"><i class="fas fa-heartbeat"></i> System Health</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<div class="d-flex align-items-center">
|
|
<i class="fas fa-database fa-2x me-3"></i>
|
|
<div>
|
|
<h6 class="mb-0">Redis</h6>
|
|
<span class="badge" id="redis-status">Checking...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="d-flex align-items-center">
|
|
<i class="fas fa-server fa-2x me-3"></i>
|
|
<div>
|
|
<h6 class="mb-0">PostgreSQL</h6>
|
|
<span class="badge" id="postgresql-status">Checking...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="d-flex align-items-center">
|
|
<i class="fas fa-microphone fa-2x me-3"></i>
|
|
<div>
|
|
<h6 class="mb-0">Whisper/TTS</h6>
|
|
<span class="badge" id="ml-status">Checking...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Charts Row 1 -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-8">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Request Volume</h5>
|
|
<div class="btn-group btn-group-sm float-end" role="group">
|
|
<button type="button" class="btn btn-outline-primary active" onclick="updateRequestChart('minute')">Minute</button>
|
|
<button type="button" class="btn btn-outline-primary" onclick="updateRequestChart('hour')">Hour</button>
|
|
<button type="button" class="btn btn-outline-primary" onclick="updateRequestChart('day')">Day</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="requestChart" height="100"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Language Pairs</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="languageChart" height="200"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Charts Row 2 -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Operations</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="operationsChart" height="120"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Response Times (ms)</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="responseTimeChart" height="120"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Error Analysis -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Error Types</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="errorTypeChart" height="150"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Recent Errors</h5>
|
|
</div>
|
|
<div class="card-body" style="max-height: 300px; overflow-y: auto;">
|
|
<div id="recent-errors-list">
|
|
<div class="text-center">
|
|
<div class="spinner-border" role="status"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Performance Metrics -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">Performance Metrics</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Operation</th>
|
|
<th>Average (ms)</th>
|
|
<th>95th Percentile (ms)</th>
|
|
<th>99th Percentile (ms)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="performance-table">
|
|
<tr>
|
|
<td colspan="4" class="text-center">
|
|
<div class="spinner-border" role="status"></div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Real-time Updates Status -->
|
|
<div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1000">
|
|
<div class="toast" id="update-toast" role="alert">
|
|
<div class="toast-header">
|
|
<i class="fas fa-sync-alt me-2"></i>
|
|
<strong class="me-auto">Real-time Updates</strong>
|
|
<small id="last-update">Just now</small>
|
|
<button type="button" class="btn-close" data-bs-dismiss="toast"></button>
|
|
</div>
|
|
<div class="toast-body">
|
|
<span id="update-status">Connected</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
// Initialize dashboard
|
|
$(document).ready(function() {
|
|
initializeDashboard();
|
|
|
|
// Start real-time updates
|
|
startRealtimeUpdates();
|
|
|
|
// Load initial data
|
|
loadOverviewStats();
|
|
loadRequestChart('minute');
|
|
loadOperationStats();
|
|
loadErrorStats();
|
|
loadPerformanceStats();
|
|
|
|
// Refresh data periodically
|
|
setInterval(loadOverviewStats, 10000); // Every 10 seconds
|
|
setInterval(function() {
|
|
loadRequestChart(currentTimeframe);
|
|
}, 30000); // Every 30 seconds
|
|
});
|
|
</script>
|
|
{% endblock %} |