dashboard.js•12.1 kB
/**
* MemOS 迷你Dashboard JavaScript
* 负责数据获取、更新和用户交互
*/
// 配置
const CONFIG = {
API_BASE_URL: 'http://localhost:8000', // API服务器地址
AUTO_REFRESH_INTERVAL: 30000, // 30秒自动刷新
REQUEST_TIMEOUT: 10000 // 10秒请求超时
};
// 全局状态
let autoRefreshTimer = null;
let isLoading = false;
/**
* 初始化Dashboard
*/
document.addEventListener('DOMContentLoaded', function() {
console.log('🚀 MemOS Dashboard 初始化中...');
// 首次加载数据
refreshAllData();
// 设置键盘快捷键
document.addEventListener('keydown', function(e) {
if (e.key === 'F5' || (e.ctrlKey && e.key === 'r')) {
e.preventDefault();
refreshAllData();
}
});
console.log('✅ Dashboard 初始化完成');
});
/**
* 发起API请求
*/
async function apiRequest(endpoint, options = {}) {
const url = `${CONFIG.API_BASE_URL}${endpoint}`;
const defaultOptions = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
timeout: CONFIG.REQUEST_TIMEOUT
};
try {
const response = await fetch(url, { ...defaultOptions, ...options });
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error(`API请求失败 [${endpoint}]:`, error);
throw error;
}
}
/**
* 刷新所有数据
*/
async function refreshAllData() {
if (isLoading) {
console.log('⏳ 数据正在加载中,跳过本次刷新');
return;
}
isLoading = true;
console.log('🔄 开始刷新所有数据...');
// 添加加载状态
document.body.classList.add('loading');
try {
// 并行获取所有数据
const promises = [
loadSystemStatus(),
loadMemoryStats(),
loadPerformanceMetrics(),
loadCapacityInfo(),
loadTopicDriftInfo(),
loadRecentActivity()
];
await Promise.allSettled(promises);
// 更新最后更新时间
updateLastUpdateTime();
console.log('✅ 所有数据刷新完成');
} catch (error) {
console.error('❌ 数据刷新失败:', error);
showError('数据刷新失败,请检查API服务器状态');
} finally {
isLoading = false;
document.body.classList.remove('loading');
}
}
/**
* 加载系统状态
*/
async function loadSystemStatus() {
try {
const response = await apiRequest('/health');
if (response.success) {
updateElement('serviceStatus', `
<span class="status-indicator status-online"></span>在线
`);
// 获取详细状态
const statusResponse = await apiRequest('/status');
if (statusResponse.success && statusResponse.data) {
const data = statusResponse.data;
updateElement('runningMode', data.mode || '增强版');
updateElement('uptime', formatUptime(data.uptime || 0));
updateElement('apiVersion', data.version || 'v1.0.0');
}
} else {
throw new Error(response.message || '健康检查失败');
}
} catch (error) {
console.error('系统状态加载失败:', error);
updateElement('serviceStatus', `
<span class="status-indicator status-offline"></span>离线
`);
updateElement('runningMode', '未知');
updateElement('uptime', '未知');
updateElement('apiVersion', '未知');
}
}
/**
* 加载记忆统计
*/
async function loadMemoryStats() {
try {
const response = await apiRequest('/memories/stats');
if (response.success && response.data) {
const data = response.data;
updateElement('totalMemories', formatNumber(data.total_memories || 0));
updateElement('todayAdded', formatNumber(data.today_added || 0));
updateElement('recentSearches', formatNumber(data.recent_searches || 0));
updateElement('avgScore', formatScore(data.average_score || 0));
} else {
throw new Error(response.message || '记忆统计获取失败');
}
} catch (error) {
console.error('记忆统计加载失败:', error);
updateElement('totalMemories', '错误');
updateElement('todayAdded', '错误');
updateElement('recentSearches', '错误');
updateElement('avgScore', '错误');
}
}
/**
* 加载性能指标
*/
async function loadPerformanceMetrics() {
try {
const response = await apiRequest('/metrics');
if (response.success && response.data) {
const data = response.data;
updateElement('avgResponseTime', formatTime(data.avg_response_time || 0));
updateElement('searchSuccessRate', formatPercentage(data.search_success_rate || 0));
updateElement('memoryUsage', formatBytes(data.memory_usage || 0));
updateElement('cacheHitRate', formatPercentage(data.cache_hit_rate || 0));
} else {
throw new Error(response.message || '性能指标获取失败');
}
} catch (error) {
console.error('性能指标加载失败:', error);
updateElement('avgResponseTime', '错误');
updateElement('searchSuccessRate', '错误');
updateElement('memoryUsage', '错误');
updateElement('cacheHitRate', '错误');
}
}
/**
* 加载容量信息
*/
async function loadCapacityInfo() {
try {
const response = await apiRequest('/capacity/report');
if (response.success && response.data) {
const data = response.data;
updateElement('workingMemory', formatCapacity(data.working_memory || {}));
updateElement('userMemory', formatCapacity(data.user_memory || {}));
updateElement('longTermMemory', formatCapacity(data.long_term_memory || {}));
updateElement('compressionStatus', data.compression_status || '正常');
} else {
throw new Error(response.message || '容量信息获取失败');
}
} catch (error) {
console.error('容量信息加载失败:', error);
updateElement('workingMemory', '错误');
updateElement('userMemory', '错误');
updateElement('longTermMemory', '错误');
updateElement('compressionStatus', '错误');
}
}
/**
* 加载主题漂移信息
*/
async function loadTopicDriftInfo() {
try {
const response = await apiRequest('/dashboard/topic-drift');
if (response.success && response.data) {
const data = response.data;
updateElement('totalQueries', formatNumber(data.total_queries || 0));
updateElement('driftCount', formatNumber(data.drift_count || 0));
updateElement('driftRate', data.drift_rate || '0.0%');
updateElement('windowSize', data.window_size || 5);
} else {
throw new Error(response.message || '主题漂移统计获取失败');
}
} catch (error) {
console.error('主题漂移信息加载失败:', error);
// 如果API调用失败,使用模拟数据
updateElement('totalQueries', '0');
updateElement('driftCount', '0');
updateElement('driftRate', '0.0%');
updateElement('windowSize', '5');
}
}
/**
* 加载最近活动
*/
async function loadRecentActivity() {
try {
// 模拟最近活动数据
const activityHtml = `
<div style="padding: 10px; font-size: 0.9em;">
<div style="margin-bottom: 8px;">
<span style="color: #4CAF50;">✓</span>
<span>15:32 - 成功检索"Python编程"相关记忆</span>
</div>
<div style="margin-bottom: 8px;">
<span style="color: #ff9800;">⚠</span>
<span>15:28 - 检测到主题漂移</span>
</div>
<div style="margin-bottom: 8px;">
<span style="color: #4CAF50;">✓</span>
<span>15:25 - 添加新记忆"机器学习基础"</span>
</div>
<div style="margin-bottom: 8px;">
<span style="color: #2196F3;">ℹ</span>
<span>15:20 - 系统自动压缩完成</span>
</div>
<div>
<span style="color: #4CAF50;">✓</span>
<span>15:15 - 用户反馈记忆评分</span>
</div>
</div>
`;
updateElement('recentActivity', activityHtml);
} catch (error) {
console.error('最近活动加载失败:', error);
updateElement('recentActivity', '<div class="error">加载失败</div>');
}
}
/**
* 更新元素内容
*/
function updateElement(id, content) {
const element = document.getElementById(id);
if (element) {
element.innerHTML = content;
}
}
/**
* 格式化数字
*/
function formatNumber(num) {
if (typeof num !== 'number') return '0';
return num.toLocaleString();
}
/**
* 格式化分数
*/
function formatScore(score) {
if (typeof score !== 'number') return '0.000';
return score.toFixed(3);
}
/**
* 格式化时间
*/
function formatTime(ms) {
if (typeof ms !== 'number') return '0ms';
if (ms < 1000) return `${ms.toFixed(0)}ms`;
return `${(ms / 1000).toFixed(2)}s`;
}
/**
* 格式化百分比
*/
function formatPercentage(value) {
if (typeof value !== 'number') return '0%';
return `${(value * 100).toFixed(1)}%`;
}
/**
* 格式化字节
*/
function formatBytes(bytes) {
if (typeof bytes !== 'number') return '0B';
const sizes = ['B', 'KB', 'MB', 'GB'];
if (bytes === 0) return '0B';
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return `${(bytes / Math.pow(1024, i)).toFixed(1)}${sizes[i]}`;
}
/**
* 格式化容量信息
*/
function formatCapacity(capacity) {
if (!capacity || typeof capacity !== 'object') return '0/0';
const used = capacity.used || 0;
const total = capacity.total || 0;
const percentage = total > 0 ? ((used / total) * 100).toFixed(1) : 0;
return `${used}/${total} (${percentage}%)`;
}
/**
* 格式化运行时间
*/
function formatUptime(seconds) {
if (typeof seconds !== 'number') return '0秒';
const days = Math.floor(seconds / 86400);
const hours = Math.floor((seconds % 86400) / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
if (days > 0) return `${days}天${hours}小时`;
if (hours > 0) return `${hours}小时${minutes}分钟`;
return `${minutes}分钟`;
}
/**
* 更新最后更新时间
*/
function updateLastUpdateTime() {
const now = new Date();
const timeString = now.toLocaleTimeString('zh-CN');
updateElement('lastUpdate', timeString);
}
/**
* 显示错误信息
*/
function showError(message) {
console.error('Dashboard错误:', message);
// 可以在这里添加更友好的错误显示
}
/**
* 切换自动刷新
*/
function toggleAutoRefresh() {
const checkbox = document.getElementById('autoRefresh');
if (checkbox.checked) {
// 启用自动刷新
autoRefreshTimer = setInterval(refreshAllData, CONFIG.AUTO_REFRESH_INTERVAL);
console.log('✅ 自动刷新已启用');
} else {
// 禁用自动刷新
if (autoRefreshTimer) {
clearInterval(autoRefreshTimer);
autoRefreshTimer = null;
}
console.log('❌ 自动刷新已禁用');
}
}
// 导出函数供HTML调用
window.refreshAllData = refreshAllData;
window.toggleAutoRefresh = toggleAutoRefresh;