Files
sitemente/components/temple-of-ai/TempleOfAIDashboard.tsx
T
horus 45af56d9cf feat(mission-control): restore MC tabs - temple, office, memory, claude, pdf-viewer, resume, resume-upload, temple-3d, demos
Also added:
- Memory API endpoints
- Briefs API endpoints
- AnveVoice stats API
- Claude spawn API
- TTS proxy
- Cleopatra voice widget
- api-auth middleware
2026-03-23 16:30:44 +01:00

547 lines
27 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useState, useEffect } from "react";
interface Agent {
id: string;
name: string;
role: string;
symbol: string;
status: "active" | "idle" | "busy" | "offline";
currentTask: string;
location: string;
templeArea: string;
tasksCompleted: number;
}
interface TempleRoom {
id: string;
name: string;
agent: Agent | null;
status: "active" | "inactive";
description: string;
}
const ANVEVOICE_API_KEY = "anvk_6a217415c671b8e613df1f0b37f72c492a91b625";
const CLEOPATRA_BOT_ID = "022ae3d3-ed11-45a9-b663-f4a6dfa34f77";
export default function TempleOfAIDashboard() {
const [activeRoom, setActiveRoom] = useState<string>("sanctuary");
const [anvevoiceStats, setAnvevoiceStats] = useState<any>(null);
const [isLoading, setIsLoading] = useState(false);
// Egyptian Agents
const agents: Agent[] = [
{ id: "horus", name: "Horus", role: "Master Orchestrator", symbol: "👁️", status: "active", currentTask: "Monitoring all systems", location: "Sanctuary", templeArea: "Head", tasksCompleted: 847 },
{ id: "cleopatra", name: "Cleopatra", role: "Voice AI / Sales", symbol: "👑", status: "active", currentTask: "Conversing with visitor", location: "Hall 2", templeArea: "Voice Lab", tasksCompleted: 234 },
{ id: "anubis", name: "Anubis", role: "Outreach / Lead Gen", symbol: "🐕", status: "busy", currentTask: "Qualifying lead #4521", location: "Entrance", templeArea: "Reception", tasksCompleted: 156 },
{ id: "thoth", name: "Thoth", role: "Research / Strategy", symbol: "🐦", status: "idle", currentTask: "Analyzing market trends", location: "Pylon 2", templeArea: "Research", tasksCompleted: 89 },
{ id: "ptah", name: "Ptah", role: "Development / Ops", symbol: "🔨", status: "active", currentTask: "Deploying SiteMente v2.1", location: "Courtyard", templeArea: "Workspace", tasksCompleted: 312 },
{ id: "seshat", name: "Seshat", role: "Content / SEO", symbol: "📝", status: "idle", currentTask: "Writing blog post", location: "Courtyard", templeArea: "Workspace", tasksCompleted: 445 },
{ id: "sekhmet", name: "Sekhmet", role: "Trading / Risk", symbol: "🦁", status: "active", currentTask: "Monitoring BTC position", location: "Courtyard", templeArea: "Trading", tasksCompleted: 67 },
{ id: "maat", name: "Maat", role: "Quality Assurance", symbol: "⚖️", status: "idle", currentTask: "Reviewing code quality", location: "Pylon 3", templeArea: "QA Lab", tasksCompleted: 198 },
];
const templeRooms: TempleRoom[] = [
{ id: "sanctuary", name: "Holy of Holies", agent: agents[0], status: "active", description: "Horus commands from the golden throne. The Eye of Providence sees all." },
{ id: "hall2", name: "Hall of Queens", agent: agents[1], status: "active", description: "Cleopatra's voice echoes through the halls. Visitors feel welcomed." },
{ id: "pylon3", name: "Pylon of Maat", agent: agents[7], status: "active", description: "The Feather of Truth guards quality standards." },
{ id: "pylon2", name: "Pylon of Thoth", agent: agents[3], status: "active", description: "Sacred knowledge flows through ibis-headed archives." },
{ id: "hypostyle", name: "Hypostyle Hall", agent: null, status: "active", description: "The great meeting hall. Columns reach to heaven." },
{ id: "courtyard", name: "Courtyard", agent: null, status: "active", description: "Ptah builds, Seshat writes, Sekhmet trades. The heart beats strong." },
{ id: "entrance", name: "Avenue of Sphinxes", agent: agents[2], status: "active", description: "Anubis greets visitors. No soul passes unseen." },
];
const getStatusColor = (status: string) => {
switch(status) {
case "active": return "bg-green-500";
case "busy": return "bg-yellow-500";
case "idle": return "bg-blue-500";
case "offline": return "bg-gray-500";
default: return "bg-gray-500";
}
};
const getStatusText = (status: string) => {
switch(status) {
case "active": return "Working";
case "busy": return "On Task";
case "idle": return "Ready";
case "offline": return "Offline";
default: return status;
}
};
useEffect(() => {
// Fetch AnveVoice stats
const fetchStats = async () => {
try {
const res = await fetch("/api/anvevoice-stats");
if (res.ok) {
const data = await res.json();
setAnvevoiceStats(data);
}
} catch (e) {
console.error("Failed to fetch AnveVoice stats");
}
};
fetchStats();
}, []);
return (
<div className="min-h-screen bg-gradient-to-br from-amber-950 via-stone-900 to-amber-950 p-6">
{/* Header */}
<div className="text-center mb-8">
<h1 className="text-4xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-amber-200 via-yellow-400 to-amber-200 mb-2">
🏛 TEMPLE OF AI
</h1>
<p className="text-amber-300/80 text-lg">
Where Ancient Wisdom Meets Machine Intelligence
</p>
<div className="flex justify-center gap-4 mt-4">
<span className="px-4 py-1 bg-amber-500/20 text-amber-300 rounded-full text-sm border border-amber-500/30">
🟢 {agents.filter(a => a.status === "active").length} Active
</span>
<span className="px-4 py-1 bg-yellow-500/20 text-yellow-300 rounded-full text-sm border border-yellow-500/30">
🟡 {agents.filter(a => a.status === "busy").length} Busy
</span>
<span className="px-4 py-1 bg-blue-500/20 text-blue-300 rounded-full text-sm border border-blue-500/30">
🔵 {agents.filter(a => a.status === "idle").length} Ready
</span>
</div>
</div>
{/* Temple Visualization */}
<div className="max-w-7xl mx-auto grid lg:grid-cols-3 gap-6">
{/* Left Column - Temple Map */}
<div className="lg:col-span-1">
<div className="bg-stone-900/80 backdrop-blur rounded-2xl border border-amber-500/20 p-6">
<h2 className="text-xl font-bold text-amber-200 mb-4 flex items-center gap-2">
🗺 Temple Map
</h2>
{/* Vertical Temple Layout */}
<div className="space-y-2">
{/* Sanctuary */}
<div
onClick={() => setActiveRoom("sanctuary")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "sanctuary"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl">👁</span>
<div>
<p className="font-bold text-amber-200">HOLY OF HOLIES</p>
<p className="text-xs text-amber-400/60">{agents[0].name} - {agents[0].role}</p>
</div>
<span className={`w-3 h-3 rounded-full ${getStatusColor(agents[0].status)} ml-auto`}></span>
</div>
</div>
{/* Hall 2 */}
<div className="flex items-center justify-center">
<div className="w-0 h-0 border-l-8 border-r-8 border-t-8 border-l-transparent border-r-transparent border-t-amber-600"></div>
</div>
<div
onClick={() => setActiveRoom("hall2")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "hall2"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl">👑</span>
<div>
<p className="font-bold text-amber-200">HALL OF QUEENS</p>
<p className="text-xs text-amber-400/60">{agents[1].name} - Voice AI</p>
</div>
<span className={`w-3 h-3 rounded-full ${getStatusColor(agents[1].status)} ml-auto`}></span>
</div>
</div>
{/* Pylon 3 */}
<div className="flex items-center justify-center">
<div className="w-8 h-4 bg-amber-800 rounded-sm"></div>
</div>
<div
onClick={() => setActiveRoom("pylon3")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "pylon3"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl"></span>
<div>
<p className="font-bold text-amber-200">PYLON OF MAAT</p>
<p className="text-xs text-amber-400/60">{agents[7].name} - Quality</p>
</div>
<span className={`w-3 h-3 rounded-full ${getStatusColor(agents[7].status)} ml-auto`}></span>
</div>
</div>
{/* Pylon 2 */}
<div className="flex items-center justify-center">
<div className="w-8 h-4 bg-amber-800 rounded-sm"></div>
</div>
<div
onClick={() => setActiveRoom("pylon2")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "pylon2"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl">🐦</span>
<div>
<p className="font-bold text-amber-200">PYLON OF THOTH</p>
<p className="text-xs text-amber-400/60">{agents[3].name} - Research</p>
</div>
<span className={`w-3 h-3 rounded-full ${getStatusColor(agents[3].status)} ml-auto`}></span>
</div>
</div>
{/* Hypostyle Hall */}
<div className="flex items-center justify-center">
<div className="w-8 h-4 bg-amber-700 rounded-sm"></div>
</div>
<div
onClick={() => setActiveRoom("hypostyle")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "hypostyle"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl"></span>
<div>
<p className="font-bold text-amber-200">HYPOSTYLE HALL</p>
<p className="text-xs text-amber-400/60">Conference - Standups</p>
</div>
<span className="w-3 h-3 rounded-full bg-green-500 ml-auto"></span>
</div>
</div>
{/* Courtyard */}
<div className="flex items-center justify-center">
<div className="w-8 h-4 bg-amber-600 rounded-sm"></div>
</div>
<div
onClick={() => setActiveRoom("courtyard")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "courtyard"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl">🏛</span>
<div>
<p className="font-bold text-amber-200">COURTYARD</p>
<p className="text-xs text-amber-400/60">Ptah 🔨 | Seshat 📝 | Sekhmet 🦁</p>
</div>
<span className="w-3 h-3 rounded-full bg-green-500 ml-auto"></span>
</div>
</div>
{/* Entrance */}
<div className="flex items-center justify-center">
<div className="w-8 h-4 bg-amber-500 rounded-sm"></div>
</div>
<div
onClick={() => setActiveRoom("entrance")}
className={`p-3 rounded-xl border-2 cursor-pointer transition-all ${
activeRoom === "entrance"
? "border-yellow-400 bg-yellow-500/20"
: "border-amber-700/50 bg-stone-800/50 hover:border-amber-500"
}`}
>
<div className="flex items-center gap-3">
<span className="text-2xl">🐕</span>
<div>
<p className="font-bold text-amber-200">AVENUE OF SPHINXES</p>
<p className="text-xs text-amber-400/60">{agents[2].name} - Reception</p>
</div>
<span className={`w-3 h-3 rounded-full ${getStatusColor(agents[2].status)} ml-auto`}></span>
</div>
</div>
</div>
</div>
</div>
{/* Center Column - Active Room Details */}
<div className="lg:col-span-1">
<div className="bg-stone-900/80 backdrop-blur rounded-2xl border border-amber-500/20 p-6">
<h2 className="text-xl font-bold text-amber-200 mb-4">
{templeRooms.find(r => r.id === activeRoom)?.name}
</h2>
<div className="space-y-4">
{activeRoom === "sanctuary" && (
<>
<div className="text-center py-8">
<span className="text-8xl">👁</span>
<h3 className="text-2xl font-bold text-yellow-400 mt-4">HORUS</h3>
<p className="text-amber-300">Master Orchestrator</p>
</div>
<div className="bg-yellow-500/10 rounded-xl p-4 border border-yellow-500/30">
<p className="text-yellow-200 font-medium">🗣 Current Task:</p>
<p className="text-amber-300 mt-1">{agents[0].currentTask}</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="bg-stone-800/50 rounded-lg p-3 text-center">
<p className="text-2xl font-bold text-yellow-400">847</p>
<p className="text-xs text-amber-400/60">Tasks Done</p>
</div>
<div className="bg-stone-800/50 rounded-lg p-3 text-center">
<p className="text-2xl font-bold text-green-400">99.9%</p>
<p className="text-xs text-amber-400/60">Uptime</p>
</div>
</div>
</>
)}
{activeRoom === "hall2" && (
<>
<div className="text-center py-8">
<span className="text-8xl">👑</span>
<h3 className="text-2xl font-bold text-yellow-400 mt-4">CLEOPATRA</h3>
<p className="text-amber-300">Voice AI / Sales</p>
<div className="mt-2 inline-flex items-center gap-2 px-3 py-1 bg-green-500/20 rounded-full border border-green-500/30">
<span className="w-2 h-2 bg-green-400 rounded-full animate-pulse"></span>
<span className="text-green-300 text-sm">Live on AnveVoice</span>
</div>
</div>
<div className="bg-purple-500/10 rounded-xl p-4 border border-purple-500/30">
<p className="text-purple-200 font-medium">🗣 Welcome Message:</p>
<p className="text-amber-300 mt-1 italic">"Hola! Soy Cleopatra, tu asistente de ventas de HostPioneers. Como puedo ayudarte hoy?"</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="bg-stone-800/50 rounded-lg p-3 text-center">
<p className="text-2xl font-bold text-purple-400">234</p>
<p className="text-xs text-amber-400/60">Conversations</p>
</div>
<div className="bg-stone-800/50 rounded-lg p-3 text-center">
<p className="text-2xl font-bold text-green-400">89%</p>
<p className="text-xs text-amber-400/60">Lead Capture</p>
</div>
</div>
<a
href="https://anvevoice.com/dashboard"
target="_blank"
className="block w-full py-3 bg-purple-600 hover:bg-purple-500 text-center rounded-xl font-bold text-white transition-colors"
>
📊 View AnveVoice Dashboard
</a>
</>
)}
{activeRoom === "courtyard" && (
<>
<div className="text-center py-4">
<span className="text-6xl">🏛</span>
<h3 className="text-xl font-bold text-yellow-400 mt-4">THE WORKING HEART</h3>
<p className="text-amber-300">Where the heart beats strong</p>
</div>
<div className="space-y-3">
<div className="flex items-center gap-3 bg-stone-800/50 rounded-lg p-3">
<span className="text-2xl">🔨</span>
<div className="flex-1">
<p className="font-bold text-amber-200">Ptah - Dev/Ops</p>
<p className="text-xs text-amber-400/60">{agents[5].currentTask}</p>
</div>
<span className={`w-2 h-2 rounded-full ${getStatusColor(agents[5].status)}`}></span>
</div>
<div className="flex items-center gap-3 bg-stone-800/50 rounded-lg p-3">
<span className="text-2xl">📝</span>
<div className="flex-1">
<p className="font-bold text-amber-200">Seshat - Content</p>
<p className="text-xs text-amber-400/60">{agents[6].currentTask}</p>
</div>
<span className={`w-2 h-2 rounded-full ${getStatusColor(agents[6].status)}`}></span>
</div>
<div className="flex items-center gap-3 bg-stone-800/50 rounded-lg p-3">
<span className="text-2xl">🦁</span>
<div className="flex-1">
<p className="font-bold text-amber-200">Sekhmet - Trading</p>
<p className="text-xs text-amber-400/60">{agents[7].currentTask}</p>
</div>
<span className={`w-2 h-2 rounded-full ${getStatusColor(agents[7].status)}`}></span>
</div>
</div>
</>
)}
{activeRoom === "hypostyle" && (
<>
<div className="text-center py-8">
<span className="text-8xl"></span>
<h3 className="text-2xl font-bold text-yellow-400 mt-4">MEETING HALL</h3>
<p className="text-amber-300">Where decisions are made</p>
</div>
<div className="bg-stone-800/50 rounded-xl p-4">
<h4 className="text-amber-200 font-medium mb-3">📅 Next Standup</h4>
<div className="flex items-center gap-3">
<span className="text-2xl"></span>
<div>
<p className="text-white font-medium">9:00 AM - Daily Standup</p>
<p className="text-amber-400/60 text-sm">All agents gather</p>
</div>
</div>
</div>
<div className="bg-stone-800/50 rounded-xl p-4">
<h4 className="text-amber-200 font-medium mb-3">📋 Sprint Status</h4>
<div className="space-y-2">
<div className="flex justify-between">
<span className="text-amber-300">Progress</span>
<span className="text-green-400">72%</span>
</div>
<div className="w-full bg-stone-700 rounded-full h-2">
<div className="bg-green-500 h-2 rounded-full" style={{ width: "72%" }}></div>
</div>
</div>
</div>
</>
)}
{activeRoom === "entrance" && (
<>
<div className="text-center py-8">
<span className="text-8xl">🐕</span>
<h3 className="text-2xl font-bold text-yellow-400 mt-4">ANUBIS</h3>
<p className="text-amber-300">Guardian of Leads</p>
</div>
<div className="bg-stone-800/50 rounded-xl p-4">
<h4 className="text-amber-200 font-medium mb-3">🎯 Lead Pipeline</h4>
<div className="space-y-2">
<div className="flex justify-between">
<span className="text-amber-300">New Today</span>
<span className="text-yellow-400">23</span>
</div>
<div className="flex justify-between">
<span className="text-amber-300">Qualified</span>
<span className="text-green-400">8</span>
</div>
<div className="flex justify-between">
<span className="text-amber-300">Conversion</span>
<span className="text-blue-400">34%</span>
</div>
</div>
</div>
</>
)}
{(activeRoom === "pylon2" || activeRoom === "pylon3") && (
<>
<div className="text-center py-8">
<span className="text-8xl">{activeRoom === "pylon2" ? "🐦" : "⚖️"}</span>
<h3 className="text-2xl font-bold text-yellow-400 mt-4">
{activeRoom === "pylon2" ? "THOTH" : "MAAT"}
</h3>
<p className="text-amber-300">
{activeRoom === "pylon2" ? "Knowledge Keeper" : "Quality Guardian"}
</p>
</div>
<div className="bg-stone-800/50 rounded-xl p-4">
<h4 className="text-amber-200 font-medium mb-3">
{activeRoom === "pylon2" ? "🔬 Research" : "✓ Quality Metrics"}
</h4>
<div className="space-y-2">
{activeRoom === "pylon2" ? (
<>
<div className="flex justify-between">
<span className="text-amber-300">Market Analysis</span>
<span className="text-green-400">Complete</span>
</div>
<div className="flex justify-between">
<span className="text-amber-300">Competitor Report</span>
<span className="text-yellow-400">In Progress</span>
</div>
</>
) : (
<>
<div className="flex justify-between">
<span className="text-amber-300">Code Coverage</span>
<span className="text-green-400">94%</span>
</div>
<div className="flex justify-between">
<span className="text-amber-300">Bugs Fixed</span>
<span className="text-blue-400">12</span>
</div>
</>
)}
</div>
</div>
</>
)}
</div>
</div>
</div>
{/* Right Column - All Agents */}
<div className="lg:col-span-1">
<div className="bg-stone-900/80 backdrop-blur rounded-2xl border border-amber-500/20 p-6">
<h2 className="text-xl font-bold text-amber-200 mb-4">
👥 Divine Council
</h2>
<div className="space-y-3">
{agents.map(agent => (
<div
key={agent.id}
className="bg-stone-800/50 rounded-xl p-3 hover:bg-stone-700/50 transition-colors cursor-pointer"
onClick={() => setActiveRoom(agent.location === "Entrance" ? "entrance" : agent.location === "Hall 2" ? "hall2" : agent.location === "Pylon 2" ? "pylon2" : agent.location === "Pylon 3" ? "pylon3" : agent.location === "Courtyard" ? "courtyard" : "sanctuary")}
>
<div className="flex items-center gap-3">
<span className="text-2xl">{agent.symbol}</span>
<div className="flex-1">
<p className="font-bold text-amber-200">{agent.name}</p>
<p className="text-xs text-amber-400/60">{agent.role}</p>
</div>
<div className="text-right">
<span className={`w-2 h-2 rounded-full ${getStatusColor(agent.status)} inline-block`}></span>
<p className="text-xs text-amber-400/60 mt-1">{getStatusText(agent.status)}</p>
</div>
</div>
<p className="text-xs text-amber-300/60 mt-2 ml-9 truncate">
{agent.currentTask}
</p>
</div>
))}
</div>
{/* Cleopatra's Voice Widget */}
<div className="mt-6 pt-6 border-t border-amber-500/20">
<h3 className="text-lg font-bold text-purple-300 mb-3">🎙 Cleopatra Voice</h3>
<div className="bg-purple-900/30 rounded-xl p-4 border border-purple-500/20">
<p className="text-purple-200 text-sm mb-3">Test Cleopatra's voice AI on AnveVoice:</p>
<a
href="https://anvevoice.com/dashboard"
target="_blank"
className="block w-full py-2 bg-purple-600 hover:bg-purple-500 text-center rounded-lg font-medium text-white text-sm transition-colors"
>
Open Voice Dashboard
</a>
</div>
</div>
</div>
</div>
</div>
{/* Footer */}
<div className="text-center mt-8 text-amber-400/40 text-sm">
<p>🏛 Temple of AI - Ancient Wisdom Meets Machine Intelligence</p>
<p className="mt-1">Powered by HostPioneers | Built on OpenClaw & AnveVoice</p>
</div>
</div>
);
}