- Removed TTS server status popup from main frontend interface - Commented out checkTtsServer() function and all its calls - Removed TTS configuration UI elements from index.html - Added comprehensive TTS server monitoring to admin dashboard: - Configuration status (URL, API key) - Server health monitoring - Available voices display - Usage statistics and performance metrics - Real-time status updates - Enhanced system health check to include TTS server - Created dedicated /api/tts/status endpoint for detailed info The TTS functionality remains fully operational for users, but status monitoring is now exclusive to the admin dashboard for cleaner UX. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
261 lines
9.5 KiB
JavaScript
261 lines
9.5 KiB
JavaScript
// Admin Dashboard JavaScript
|
|
$(document).ready(function() {
|
|
// Load initial data
|
|
loadOverviewStats();
|
|
loadSystemHealth();
|
|
loadTTSStatus();
|
|
loadRequestChart('hour');
|
|
loadOperationStats();
|
|
loadLanguagePairs();
|
|
loadRecentErrors();
|
|
loadActiveSessions();
|
|
|
|
// Set up auto-refresh
|
|
setInterval(loadOverviewStats, 30000); // Every 30 seconds
|
|
setInterval(loadSystemHealth, 60000); // Every minute
|
|
setInterval(loadTTSStatus, 60000); // Every minute
|
|
|
|
// Set up real-time updates if available
|
|
initializeEventStream();
|
|
});
|
|
|
|
// Charts
|
|
let charts = {
|
|
request: null,
|
|
operations: null,
|
|
language: null,
|
|
performance: null,
|
|
errors: null
|
|
};
|
|
|
|
// Load overview statistics
|
|
function loadOverviewStats() {
|
|
$.ajax({
|
|
url: '/admin/api/stats/overview',
|
|
method: 'GET',
|
|
success: function(data) {
|
|
// Update request stats
|
|
$('#total-requests').text(data.requests.total.toLocaleString());
|
|
$('#today-requests').text(data.requests.today.toLocaleString());
|
|
$('#hourly-requests').text(data.requests.hour.toLocaleString());
|
|
|
|
// Update operation stats
|
|
$('#total-translations').text(data.translations.total.toLocaleString());
|
|
$('#today-translations').text(data.translations.today.toLocaleString());
|
|
|
|
$('#total-transcriptions').text(data.transcriptions.total.toLocaleString());
|
|
$('#today-transcriptions').text(data.transcriptions.today.toLocaleString());
|
|
|
|
// Update other metrics
|
|
$('#active-sessions').text(data.active_sessions.toLocaleString());
|
|
$('#error-rate').text(data.error_rate.toFixed(2) + '%');
|
|
$('#cache-hit-rate').text(data.cache_hit_rate.toFixed(2) + '%');
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('Failed to load overview stats:', error);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Load system health status
|
|
function loadSystemHealth() {
|
|
$.ajax({
|
|
url: '/admin/api/health',
|
|
method: 'GET',
|
|
success: function(data) {
|
|
// Update overall status
|
|
const overallStatus = $('#overall-status');
|
|
overallStatus.removeClass('text-success text-warning text-danger');
|
|
|
|
if (data.status === 'healthy') {
|
|
overallStatus.addClass('text-success').html('<i class="fas fa-check-circle"></i> All Systems Operational');
|
|
} else if (data.status === 'degraded') {
|
|
overallStatus.addClass('text-warning').html('<i class="fas fa-exclamation-triangle"></i> Degraded Performance');
|
|
} else {
|
|
overallStatus.addClass('text-danger').html('<i class="fas fa-times-circle"></i> System Issues');
|
|
}
|
|
|
|
// Update component statuses
|
|
updateComponentStatus('redis', data.components.redis);
|
|
updateComponentStatus('postgresql', data.components.postgresql);
|
|
updateComponentStatus('ml', data.components.tts || { status: 'healthy' });
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('Failed to load system health:', error);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Update component status badge
|
|
function updateComponentStatus(component, data) {
|
|
const badge = $(`#${component}-status`);
|
|
badge.removeClass('bg-success bg-warning bg-danger bg-secondary');
|
|
|
|
if (data.status === 'healthy') {
|
|
badge.addClass('bg-success').text('Healthy');
|
|
} else if (data.status === 'not_configured') {
|
|
badge.addClass('bg-secondary').text('Not Configured');
|
|
} else if (data.status === 'unreachable') {
|
|
badge.addClass('bg-warning').text('Unreachable');
|
|
} else {
|
|
badge.addClass('bg-danger').text('Unhealthy');
|
|
}
|
|
|
|
// Update TTS details if applicable
|
|
if (component === 'ml' && data.status) {
|
|
const details = $('#tts-details');
|
|
if (data.status === 'healthy') {
|
|
details.text('TTS Server Connected');
|
|
} else if (data.status === 'not_configured') {
|
|
details.text('No TTS Server');
|
|
} else if (data.status === 'unreachable') {
|
|
details.text('Cannot reach TTS server');
|
|
} else {
|
|
details.text('TTS Server Error');
|
|
}
|
|
}
|
|
}
|
|
|
|
// Load detailed TTS status
|
|
function loadTTSStatus() {
|
|
$.ajax({
|
|
url: '/admin/api/tts/status',
|
|
method: 'GET',
|
|
success: function(data) {
|
|
// Configuration status
|
|
if (data.configured) {
|
|
$('#tts-config-status').removeClass().addClass('badge bg-success').text('Configured');
|
|
$('#tts-server-url').text(data.server_url || '-');
|
|
$('#tts-api-key-status').text(data.api_key_configured ? 'Configured' : 'Not Set');
|
|
} else {
|
|
$('#tts-config-status').removeClass().addClass('badge bg-secondary').text('Not Configured');
|
|
$('#tts-server-url').text('-');
|
|
$('#tts-api-key-status').text('-');
|
|
}
|
|
|
|
// Health status
|
|
const healthBadge = $('#tts-health-status');
|
|
healthBadge.removeClass();
|
|
|
|
if (data.status === 'healthy') {
|
|
healthBadge.addClass('badge bg-success').text('Healthy');
|
|
$('#tts-error-message').text('-');
|
|
} else if (data.status === 'unreachable') {
|
|
healthBadge.addClass('badge bg-warning').text('Unreachable');
|
|
$('#tts-error-message').text(data.details.error || 'Cannot connect');
|
|
} else if (data.status === 'not_configured') {
|
|
healthBadge.addClass('badge bg-secondary').text('Not Configured');
|
|
$('#tts-error-message').text('-');
|
|
} else {
|
|
healthBadge.addClass('badge bg-danger').text('Error');
|
|
$('#tts-error-message').text(data.details.error || 'Unknown error');
|
|
}
|
|
|
|
// Voice count and list
|
|
if (data.details && data.details.voice_count !== undefined) {
|
|
$('#tts-voice-count').text(data.details.voice_count);
|
|
|
|
// Show voice list if available
|
|
if (data.details.available_voices && data.details.available_voices.length > 0) {
|
|
$('#tts-voices-container').show();
|
|
const voicesList = $('#tts-voices-list');
|
|
voicesList.empty();
|
|
|
|
data.details.available_voices.forEach(function(voice) {
|
|
voicesList.append(`<span class="badge bg-primary">${voice}</span>`);
|
|
});
|
|
}
|
|
} else {
|
|
$('#tts-voice-count').text('-');
|
|
$('#tts-voices-container').hide();
|
|
}
|
|
|
|
// Usage statistics
|
|
if (data.usage) {
|
|
$('#tts-usage-today').text(data.usage.today.toLocaleString());
|
|
$('#tts-usage-total').text(data.usage.total.toLocaleString());
|
|
} else {
|
|
$('#tts-usage-today').text('-');
|
|
$('#tts-usage-total').text('-');
|
|
}
|
|
|
|
// Performance metrics
|
|
if (data.performance) {
|
|
$('#tts-avg-response').text(data.performance.avg_response_time + ' ms');
|
|
} else {
|
|
$('#tts-avg-response').text('-');
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('Failed to load TTS status:', error);
|
|
$('#tts-config-status').removeClass().addClass('badge bg-danger').text('Error');
|
|
$('#tts-health-status').removeClass().addClass('badge bg-danger').text('Error');
|
|
$('#tts-error-message').text('Failed to load status');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Load request chart
|
|
function loadRequestChart(timeframe) {
|
|
// Implementation would go here
|
|
console.log('Loading request chart for timeframe:', timeframe);
|
|
}
|
|
|
|
// Load operation statistics
|
|
function loadOperationStats() {
|
|
// Implementation would go here
|
|
console.log('Loading operation stats');
|
|
}
|
|
|
|
// Load language pairs
|
|
function loadLanguagePairs() {
|
|
// Implementation would go here
|
|
console.log('Loading language pairs');
|
|
}
|
|
|
|
// Load recent errors
|
|
function loadRecentErrors() {
|
|
// Implementation would go here
|
|
console.log('Loading recent errors');
|
|
}
|
|
|
|
// Load active sessions
|
|
function loadActiveSessions() {
|
|
// Implementation would go here
|
|
console.log('Loading active sessions');
|
|
}
|
|
|
|
// Initialize event stream for real-time updates
|
|
function initializeEventStream() {
|
|
if (typeof(EventSource) === "undefined") {
|
|
console.log("Server-sent events not supported");
|
|
return;
|
|
}
|
|
|
|
const source = new EventSource('/admin/api/stream/updates');
|
|
|
|
source.onmessage = function(event) {
|
|
const data = JSON.parse(event.data);
|
|
|
|
// Update real-time metrics
|
|
if (data.requests_per_minute !== undefined) {
|
|
$('#realtime-rpm').text(data.requests_per_minute);
|
|
}
|
|
if (data.active_sessions !== undefined) {
|
|
$('#active-sessions').text(data.active_sessions);
|
|
}
|
|
if (data.recent_errors !== undefined) {
|
|
$('#recent-errors-count').text(data.recent_errors);
|
|
}
|
|
};
|
|
|
|
source.onerror = function(error) {
|
|
console.error('EventSource error:', error);
|
|
};
|
|
}
|
|
|
|
// Show toast notification
|
|
function showToast(message, type = 'info') {
|
|
// Implementation would go here
|
|
console.log(`Toast [${type}]: ${message}`);
|
|
} |