teto_ai/dashboard_mockups/sonnet_mockup/src/dashboard.js

616 lines
22 KiB
JavaScript

// Dashboard Core Functionality
class TetoDashboard {
constructor() {
this.currentTab = 'overview';
this.thoughtStream = [];
this.isSimulating = false;
this.memoryVisualization = null;
this.init();
}
init() {
this.initNavigation();
this.initThoughtStream();
this.initMemoryExplorer();
this.startSystemMonitoring();
this.setupEventHandlers();
console.log('🧠 Teto Dashboard initialized');
}
// Navigation System
initNavigation() {
const navItems = document.querySelectorAll('.nav-item');
const tabContents = document.querySelectorAll('.tab-content');
navItems.forEach(item => {
item.addEventListener('click', () => {
const tabId = item.getAttribute('data-tab');
// Update navigation
navItems.forEach(nav => nav.classList.remove('active'));
item.classList.add('active');
// Update content
tabContents.forEach(content => content.classList.remove('active'));
const targetTab = document.getElementById(`tab-${tabId}`);
if (targetTab) {
targetTab.classList.add('active');
this.currentTab = tabId;
this.onTabChange(tabId);
}
});
});
}
onTabChange(tabId) {
switch(tabId) {
case 'memory':
// Small delay to ensure DOM is ready
setTimeout(() => {
this.initMemoryVisualization();
}, 100);
break;
case 'analytics':
this.loadAnalytics();
break;
case 'archives':
this.loadArchives();
break;
case 'profile':
this.loadProfile();
break;
}
// Trigger synapse animation
window.synapseSystem?.onTabChange(tabId);
}
// Live Thought Stream
initThoughtStream() {
this.thoughtContainer = document.getElementById('thought-stream');
this.startThoughtGeneration();
}
startThoughtGeneration() {
const thoughts = [
"Analyzing incoming Discord message...",
"Context: User Alice mentioned 'French bread' again",
"Retrieving personality traits: slightly sassy, loves French bread",
"Checking conversation history for similar topics...",
"Found 12 previous mentions of French bread preferences",
"Generating response with 73% sass level",
"Processing voice modulation parameters...",
"Response crafted: 'Mon dieu, Alice! How many times must I say it?'",
"Executing text-to-speech conversion...",
"Message delivered to #general channel",
"Monitoring user reactions and engagement...",
"Alice reacted with 😄 - response was well received",
"Updating conversation context in vector database...",
"Learning: Alice enjoys my French bread jokes",
"Memory consolidation complete",
];
let thoughtIndex = 0;
const addThought = () => {
if (this.thoughtContainer) {
const timestamp = new Date().toLocaleTimeString();
const thought = thoughts[thoughtIndex % thoughts.length];
const thoughtElement = document.createElement('div');
thoughtElement.className = 'thought-line';
thoughtElement.innerHTML = `<span class="thought-timestamp">[${timestamp}]</span> ${thought}`;
this.thoughtContainer.appendChild(thoughtElement);
this.thoughtContainer.scrollTop = this.thoughtContainer.scrollHeight;
// Remove old thoughts to prevent memory buildup
const maxThoughts = 50;
if (this.thoughtContainer.children.length > maxThoughts) {
this.thoughtContainer.removeChild(this.thoughtContainer.firstChild);
}
thoughtIndex++;
}
};
// Add initial thoughts
for (let i = 0; i < 5; i++) {
setTimeout(() => addThought(), i * 1000);
}
// Continue adding thoughts periodically
setInterval(addThought, 3000 + Math.random() * 2000);
}
// Memory Explorer with 3D Visualization
initMemoryExplorer() {
// This will be expanded when the memory tab is accessed
this.memoryPoints = this.generateMemoryData();
}
initMemoryVisualization() {
if (this.memoryVisualization) return;
const container = document.getElementById('memory-3d');
if (!container) return;
// Create Three.js scene
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, container.offsetWidth / container.offsetHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(container.offsetWidth, container.offsetHeight);
renderer.setClearColor(0x000000, 0);
container.appendChild(renderer.domElement);
// Create memory point cloud
const geometry = new THREE.BufferGeometry();
const positions = [];
const colors = [];
const sizes = [];
const colorPalette = {
historical: new THREE.Color(0x6b7280),
knowledge: new THREE.Color(0x3b82f6),
textChat: new THREE.Color(0x10b981),
voiceChat: new THREE.Color(0x8b5cf6),
images: new THREE.Color(0xef4444),
dms: new THREE.Color(0xeab308)
};
// Generate memory points if not already generated
if (!this.memoryPoints || this.memoryPoints.length === 0) {
this.memoryPoints = this.generateMemoryData();
}
this.memoryPoints.forEach(point => {
positions.push(point.x, point.y, point.z);
const color = colorPalette[point.type] || colorPalette.knowledge;
colors.push(color.r, color.g, color.b);
sizes.push(Math.random() * 3 + 2);
});
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1));
const material = new THREE.ShaderMaterial({
vertexShader: `
attribute float size;
varying vec3 vColor;
void main() {
vColor = color;
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
gl_PointSize = size * (300.0 / -mvPosition.z);
gl_Position = projectionMatrix * mvPosition;
}
`,
fragmentShader: `
varying vec3 vColor;
void main() {
float distance = length(gl_PointCoord - vec2(0.5));
if (distance > 0.5) discard;
float alpha = 1.0 - distance * 2.0;
gl_FragColor = vec4(vColor, alpha * 0.8);
}
`,
vertexColors: true,
transparent: true,
blending: THREE.AdditiveBlending
});
const points = new THREE.Points(geometry, material);
scene.add(points);
camera.position.set(0, 0, 50);
// Animation loop
const animate = () => {
if (!this.memoryVisualization || !container.contains(renderer.domElement)) {
return; // Stop animation if visualization is destroyed
}
requestAnimationFrame(animate);
points.rotation.x += 0.001;
points.rotation.y += 0.002;
renderer.render(scene, camera);
};
animate();
// Mouse interaction
let mouseDown = false;
let mouseX = 0;
let mouseY = 0;
const onMouseDown = (e) => {
mouseDown = true;
mouseX = e.clientX;
mouseY = e.clientY;
};
const onMouseMove = (e) => {
if (!mouseDown) return;
const deltaX = e.clientX - mouseX;
const deltaY = e.clientY - mouseY;
points.rotation.y += deltaX * 0.005;
points.rotation.x += deltaY * 0.005;
mouseX = e.clientX;
mouseY = e.clientY;
};
const onMouseUp = () => {
mouseDown = false;
};
const onWheel = (e) => {
e.preventDefault();
camera.position.z += e.deltaY * 0.1;
camera.position.z = Math.max(10, Math.min(200, camera.position.z));
};
container.addEventListener('mousedown', onMouseDown);
container.addEventListener('mousemove', onMouseMove);
container.addEventListener('mouseup', onMouseUp);
container.addEventListener('wheel', onWheel);
// Handle resize
const handleResize = () => {
if (container.offsetWidth > 0 && container.offsetHeight > 0) {
camera.aspect = container.offsetWidth / container.offsetHeight;
camera.updateProjectionMatrix();
renderer.setSize(container.offsetWidth, container.offsetHeight);
}
};
window.addEventListener('resize', handleResize);
this.memoryVisualization = {
scene,
camera,
renderer,
points,
container,
cleanup: () => {
container.removeEventListener('mousedown', onMouseDown);
container.removeEventListener('mousemove', onMouseMove);
container.removeEventListener('mouseup', onMouseUp);
container.removeEventListener('wheel', onWheel);
window.removeEventListener('resize', handleResize);
if (container.contains(renderer.domElement)) {
container.removeChild(renderer.domElement);
}
renderer.dispose();
geometry.dispose();
material.dispose();
}
};
// Trigger initial render
renderer.render(scene, camera);
console.log('✨ Memory visualization initialized with', this.memoryPoints.length, 'points');
}
generateMemoryData() {
const points = [];
const types = ['historical', 'knowledge', 'textChat', 'voiceChat', 'images', 'dms'];
for (let i = 0; i < 1000; i++) {
points.push({
x: (Math.random() - 0.5) * 100,
y: (Math.random() - 0.5) * 100,
z: (Math.random() - 0.5) * 100,
type: types[Math.floor(Math.random() * types.length)],
content: `Memory point ${i}`,
timestamp: new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000)
});
}
return points;
}
// System Monitoring
startSystemMonitoring() {
this.updateMetrics();
this.initializeShutdownTimer();
setInterval(() => this.updateMetrics(), 5000);
setInterval(() => this.updateShutdownTimer(), 60000); // Update every minute
}
updateMetrics() {
// Simulate changing metrics
const memoryUsage = 85 + Math.random() * 15;
const vramUsage = 60 + Math.random() * 25;
// Simulate response time components (should add up to total)
const inputProcessing = 2 + Math.random() * 3;
const memoryRetrieval = 5 + Math.random() * 8;
const neuralProcessing = 7 + Math.random() * 10;
const responseGeneration = 2 + Math.random() * 4;
const totalResponseTime = inputProcessing + memoryRetrieval + neuralProcessing + responseGeneration;
const memoryBar = document.querySelector('.metric-fill:not(.vram):not(.shutdown-fill)');
const vramBar = document.querySelector('.metric-fill.vram');
if (memoryBar) {
memoryBar.style.width = `${memoryUsage}%`;
memoryBar.parentElement.parentElement.querySelector('.metric-value').textContent = `${Math.round(memoryUsage)}%`;
const memoryDetails = memoryBar.parentElement.parentElement.querySelector('.metric-details');
if (memoryDetails) {
memoryDetails.textContent = `RAM: ${(memoryUsage * 0.08).toFixed(1)}GB / 8GB`;
}
}
if (vramBar) {
vramBar.style.width = `${vramUsage}%`;
vramBar.parentElement.parentElement.querySelector('.metric-value').textContent = `${Math.round(vramUsage)}%`;
const vramDetails = vramBar.parentElement.parentElement.querySelector('.metric-details');
if (vramDetails) {
vramDetails.textContent = `VRAM: ${(vramUsage * 0.08).toFixed(1)}GB / 8GB`;
}
}
// Update response time breakdown
const responseMetric = document.querySelector('.response-metric .metric-value');
if (responseMetric) {
responseMetric.textContent = `${Math.round(totalResponseTime)}ms`;
}
const breakdownItems = document.querySelectorAll('.breakdown-item');
const values = [inputProcessing, memoryRetrieval, neuralProcessing, responseGeneration];
const colors = ['#3b82f6', '#10b981', '#8b5cf6', '#ef4444'];
breakdownItems.forEach((item, index) => {
const value = values[index];
const percentage = (value / totalResponseTime) * 100;
const valueElement = item.querySelector('.breakdown-value');
const fillElement = item.querySelector('.breakdown-fill');
if (valueElement) {
valueElement.textContent = `${Math.round(value)}ms`;
}
if (fillElement) {
fillElement.style.width = `${percentage}%`;
fillElement.style.background = colors[index];
}
});
}
initializeShutdownTimer() {
// Set shutdown time to 3 days from now
this.shutdownTime = new Date(Date.now() + (3 * 24 * 60 * 60 * 1000)); // 3 days
this.totalSessionTime = 7 * 24 * 60 * 60 * 1000; // 7 days total session
this.updateShutdownTimer();
}
updateShutdownTimer() {
const now = new Date();
const timeLeft = this.shutdownTime - now;
const timerElement = document.getElementById('shutdown-timer');
const progressElement = document.querySelector('.shutdown-fill');
if (timeLeft <= 0) {
if (timerElement) timerElement.textContent = 'OFFLINE';
if (progressElement) progressElement.style.width = '100%';
return;
}
// Calculate days, hours, minutes
const days = Math.floor(timeLeft / (24 * 60 * 60 * 1000));
const hours = Math.floor((timeLeft % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
const minutes = Math.floor((timeLeft % (60 * 60 * 1000)) / (60 * 1000));
let displayText = '';
if (days > 0) {
displayText = `${days}d ${hours}h`;
} else if (hours > 0) {
displayText = `${hours}h ${minutes}m`;
} else {
displayText = `${minutes}m`;
}
if (timerElement) {
timerElement.textContent = displayText;
}
// Update progress bar (session elapsed time)
const sessionElapsed = this.totalSessionTime - timeLeft;
const progressPercent = (sessionElapsed / this.totalSessionTime) * 100;
if (progressElement) {
progressElement.style.width = `${Math.max(0, Math.min(100, progressPercent))}%`;
}
// Update shutdown details
const shutdownDetails = document.querySelector('.shutdown-details');
if (shutdownDetails) {
const options = {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
};
shutdownDetails.textContent = `Session ends: ${this.shutdownTime.toLocaleDateString('en-US', options)}`;
}
}
// Load other tab content
loadAnalytics() {
console.log('Loading analytics data...');
this.generateActivityHeatmap();
this.animateAnalyticsCharts();
}
loadArchives() {
console.log('Loading archives data...');
this.setupArchiveBrowser();
}
generateActivityHeatmap() {
const heatmapContainer = document.getElementById('activity-heatmap');
if (!heatmapContainer) return;
// Clear existing cells
heatmapContainer.innerHTML = '';
// Generate 24 hour cells (representing hours of the day)
for (let hour = 0; hour < 24; hour++) {
const cell = document.createElement('div');
cell.className = 'heatmap-cell';
// Simulate activity intensity (higher during typical active hours)
let intensity = 0.1;
if (hour >= 8 && hour <= 10) intensity = 0.6; // Morning
if (hour >= 12 && hour <= 14) intensity = 0.4; // Lunch
if (hour >= 18 && hour <= 23) intensity = 0.8; // Evening
if (hour >= 20 && hour <= 22) intensity = 1.0; // Peak evening
// Add some randomness
intensity += (Math.random() - 0.5) * 0.3;
intensity = Math.max(0.1, Math.min(1, intensity));
const opacity = intensity;
cell.style.backgroundColor = `rgba(229, 62, 62, ${opacity})`;
// Add tooltip
cell.title = `${hour}:00 - Activity level: ${Math.round(intensity * 100)}%`;
heatmapContainer.appendChild(cell);
}
}
animateAnalyticsCharts() {
// Animate progress bars with delay
setTimeout(() => {
const bars = document.querySelectorAll('.bar-fill, .lang-fill');
bars.forEach((bar, index) => {
setTimeout(() => {
const targetWidth = bar.style.width;
bar.style.width = '0%';
setTimeout(() => {
bar.style.width = targetWidth;
}, 100);
}, index * 200);
});
}, 300);
}
setupArchiveBrowser() {
const archiveItems = document.querySelectorAll('.archive-item');
const archiveDisplays = document.querySelectorAll('.archive-display');
const placeholder = document.querySelector('.archive-placeholder');
archiveItems.forEach(item => {
item.addEventListener('click', () => {
// Remove active class from all items
archiveItems.forEach(i => i.classList.remove('active'));
item.classList.add('active');
// Hide placeholder and all displays
if (placeholder) placeholder.style.display = 'none';
archiveDisplays.forEach(display => display.classList.add('hidden'));
// Show selected archive
const archiveId = item.getAttribute('data-archive');
const targetDisplay = document.getElementById(`archive-${archiveId}`);
if (targetDisplay) {
targetDisplay.classList.remove('hidden');
}
});
});
// Setup voice player interactions
this.setupVoicePlayer();
}
setupVoicePlayer() {
const playBtn = document.querySelector('.play-btn');
const progressFill = document.querySelector('.progress-fill');
const timeDisplay = document.querySelector('.time-display');
if (playBtn) {
let isPlaying = false;
let progress = 0.23; // Current position (23%)
playBtn.addEventListener('click', () => {
isPlaying = !isPlaying;
playBtn.textContent = isPlaying ? '⏸️' : '▶️';
if (isPlaying) {
// Simulate playback progress
const interval = setInterval(() => {
if (!isPlaying) {
clearInterval(interval);
return;
}
progress += 0.002;
if (progress >= 1) {
progress = 1;
isPlaying = false;
playBtn.textContent = '▶️';
clearInterval(interval);
}
if (progressFill) {
progressFill.style.width = `${progress * 100}%`;
}
if (timeDisplay) {
const currentMinutes = Math.floor(progress * 84.55); // 1h 24m 33s = 84.55 minutes
const currentSeconds = Math.floor((progress * 84.55 * 60) % 60);
timeDisplay.textContent = `${currentMinutes}:${currentSeconds.toString().padStart(2, '0')} / 1:24:33`;
}
}, 100);
}
});
}
}
loadProfile() {
// Implement profile loading
console.log('Loading profile data...');
}
setupEventHandlers() {
// Add various event handlers for interactivity
document.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
// Cycle through tabs with Tab key
e.preventDefault();
const navItems = document.querySelectorAll('.nav-item');
const currentIndex = Array.from(navItems).findIndex(item => item.classList.contains('active'));
const nextIndex = (currentIndex + 1) % navItems.length;
navItems[nextIndex].click();
}
});
}
// Public methods for synapse system
triggerNeuralActivity(type = 'general') {
const activityTypes = {
input: ['reading', 'processing'],
memory: ['fetching', 'remembering'],
output: ['writing', 'speaking'],
general: ['reading', 'fetching', 'reasoning', 'writing']
};
const activities = activityTypes[type] || activityTypes.general;
window.synapseSystem?.simulateActivity(activities);
}
}
// Initialize dashboard when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
window.tetoDashboard = new TetoDashboard();
});