import React, { useState, useEffect, useRef } from 'react';
import { Search, Zap, Shield, Activity, Share2, Globe, Cpu, ChevronRight, Shuffle, AlertCircle, Database, TrendingUp, Upload, Link2, FileText, X, CheckCircle2 } from 'lucide-react';
// ==========================================
// API CONFIGURATION (Import from config.js)
// ==========================================
// Note: In actual projects, should import from config.js
// Here we inline config for compatibility
// If config.js is loaded, window.API_CONFIG will be set
const getAPIConfig = () => {
if (typeof window !== 'undefined' && window.API_CONFIG) {
return window.API_CONFIG;
}
// Default configuration (consistent with config.js)
const defaultConfig = {
baseURL: typeof window !== 'undefined' ? window.location.origin : '',
wsURL: (() => {
if (typeof window === 'undefined') return '';
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
return `${protocol}//${window.location.host}`;
})(),
endpoints: {
search: '/api/search',
feedback: '/api/feedback',
trending: '/api/trending',
feed: '/api/feed',
item: '/api/item',
upload: {
url: '/api/upload/url',
text: '/api/upload/text',
image: '/api/upload/image'
}
},
getURL: function(endpoint) {
if (endpoint.startsWith('http://') || endpoint.startsWith('https://')) {
return endpoint;
}
return `${this.baseURL}${endpoint}`;
},
getWebSocketURL: function(path = '/ws') {
return `${this.wsURL}${path}`;
}
};
return defaultConfig;
};
// ==========================================
// COMPONENT: 3D PARTICLE NETWORK BACKGROUND
// ==========================================
const ParticleNetwork = () => {
const canvasRef = useRef(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
let animationFrameId;
let width, height;
let particles = [];
const particleCount = 60;
const connectionDistance = 150;
const mouseDistance = 200;
let mouse = { x: null, y: null };
const resize = () => {
width = window.innerWidth;
height = window.innerHeight;
canvas.width = width;
canvas.height = height;
initParticles();
};
class Particle {
constructor() {
this.x = Math.random() * width;
this.y = Math.random() * height;
this.vx = (Math.random() - 0.5) * 0.5;
this.vy = (Math.random() - 0.5) * 0.5;
this.size = Math.random() * 2 + 1;
this.color = `rgba(${Math.random() * 50 + 100}, ${Math.random() * 100 + 155}, 255, ${Math.random() * 0.5 + 0.2})`;
}
update() {
this.x += this.vx;
this.y += this.vy;
if (this.x < 0 || this.x > width) this.vx *= -1;
if (this.y < 0 || this.y > height) this.vy *= -1;
if (mouse.x != null) {
let dx = mouse.x - this.x;
let dy = mouse.y - this.y;
let distance = Math.sqrt(dx * dx + dy * dy);
if (distance < mouseDistance) {
const forceDirectionX = dx / distance;
const forceDirectionY = dy / distance;
const force = (mouseDistance - distance) / mouseDistance;
this.vx += forceDirectionX * force * 0.6;
this.vy += forceDirectionY * force * 0.6;
}
}
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
}
const initParticles = () => {
particles = [];
for (let i = 0; i < particleCount; i++) {
particles.push(new Particle());
}
};
const animate = () => {
ctx.clearRect(0, 0, width, height);
for (let i = 0; i < particles.length; i++) {
for (let j = i + 1; j < particles.length; j++) {
let dx = particles[i].x - particles[j].x;
let dy = particles[i].y - particles[j].y;
let distance = Math.sqrt(dx * dx + dy * dy);
if (distance < connectionDistance) {
ctx.beginPath();
ctx.strokeStyle = `rgba(100, 200, 255, ${1 - distance / connectionDistance})`;
ctx.lineWidth = 0.5;
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[j].x, particles[j].y);
ctx.stroke();
}
}
}
particles.forEach(particle => {
particle.update();
particle.draw();
});
animationFrameId = requestAnimationFrame(animate);
};
const handleMouseMove = (e) => {
mouse.x = e.x;
mouse.y = e.y;
};
window.addEventListener('resize', resize);
window.addEventListener('mousemove', handleMouseMove);
resize();
animate();
return () => {
window.removeEventListener('resize', resize);
window.removeEventListener('mousemove', handleMouseMove);
cancelAnimationFrame(animationFrameId);
};
}, []);
return (
);
};
// ==========================================
// COMPONENT: ALGORITHM VISUALIZER
// ==========================================
const AlgorithmStep = ({ label, active, completed, icon: Icon, color }) => (
{label}
{active && (
Processing...
)}
);
// ==========================================
// COMPONENT: SEARCH RESULT CARD
// ==========================================
const ResultCard = ({ item, index, onItemClick, onRecordInteraction }) => {
const isExploration = item.is_exploration;
const isHighTrust = item.pr > 0.8;
const handleClick = (e) => {
e.preventDefault();
if (onRecordInteraction) {
onRecordInteraction(item.id, item.url);
}
if (onItemClick) {
onItemClick(item.id);
}
};
return (
{isExploration && (
Serendipity
)}
{isHighTrust && (
High Trust
)}
SIM:
{((item.score || 0) * 100).toFixed(1)}%
{item.url || 'Untitled Neural Node'}
{item.url}
$1'
)
: (item.content || "No neural trace available for this node.")
}}
/>
ID: {item.id ? item.id.substring(0,6) : 'N/A'}
);
};
// ==========================================
// COMPONENT: PROGRESS TOAST
// ==========================================
const ProgressToast = ({ visible, count, message, onClose }) => {
if (!visible) return null;
return (
Ingesting Knowledge...
{count} items
{message || 'Processing...'}
);
};
// ==========================================
// COMPONENT: NOTIFICATION TOAST
// ==========================================
const NotificationToast = ({ visible, message, onClose }) => {
if (!visible) return null;
return (
);
};
// ==========================================
// COMPONENT: EDUCATIONAL CARDS
// ==========================================
const EducationalCards = () => (
Knowledge Commons
The raw data layer where all crawled information resides. It serves as the foundation for semantic retrieval.
Curated Core
A curated layer of "Novelty Anchors". Only unique, high-entropy knowledge is promoted here to form the network's backbone.
Transitive Trust
Authority flows through user navigation. If you trust A, and A links to B, then B gains trust.
);
// ==========================================
// COMPONENT: KNOWLEDGE INJECTION PANEL
// ==========================================
const KnowledgeInjectionPanel = ({ apiConfig, onNotification }) => {
const [urlInput, setUrlInput] = useState('');
const [urlPassword, setUrlPassword] = useState('');
const [textInput, setTextInput] = useState('');
const [isUploading, setIsUploading] = useState(false);
const handleUploadUrl = async () => {
if (!urlInput.trim()) {
if (onNotification) {
onNotification("Please enter URL", "error");
}
return;
}
if (!urlPassword.trim()) {
if (onNotification) {
onNotification("Please enter password", "error");
}
return;
}
setIsUploading(true);
try {
const formData = new FormData();
formData.append('url', urlInput);
formData.append('password', urlPassword);
const response = await fetch(apiConfig.getURL(apiConfig.endpoints.upload.url), {
method: 'POST',
body: formData
});
const result = await response.json();
if (response.ok) {
setUrlInput('');
setUrlPassword('');
if (onNotification) {
onNotification(result.message || "URL injected into the cortex. Processing...");
}
} else {
if (onNotification) {
onNotification(result.detail || "Incorrect password, crawl rejected", "error");
}
}
} catch (e) {
console.error("Failed to upload URL", e);
if (onNotification) {
onNotification("Upload failed: " + e.message, "error");
}
} finally {
setIsUploading(false);
}
};
const handleUploadText = async () => {
if (!textInput.trim()) return;
setIsUploading(true);
try {
const formData = new FormData();
formData.append('text', textInput);
await fetch(apiConfig.getURL(apiConfig.endpoints.upload.text), {
method: 'POST',
body: formData
});
setTextInput('');
if (onNotification) {
onNotification("Text fragment absorbed. Processing...");
}
} catch (e) {
console.error("Failed to upload text", e);
} finally {
setIsUploading(false);
}
};
return (
);
};
// ==========================================
// COMPONENT: TRENDING SECTION
// ==========================================
const TrendingSection = ({ apiConfig, onItemClick, onRecordInteraction }) => {
const [trending, setTrending] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const loadTrending = async () => {
try {
const response = await fetch(apiConfig.getURL(`${apiConfig.endpoints.trending}?limit=3`));
const data = await response.json();
if (data.results) {
setTrending(data.results);
}
} catch (e) {
console.error("Failed to load trending", e);
} finally {
setLoading(false);
}
};
loadTrending();
}, [apiConfig]);
if (loading) {
return (
🔥 Trending Now
Loading hot topics...
);
}
if (trending.length === 0) {
return (
🔥 Trending Now
No trending topics yet. Start exploring!
);
}
return (
🔥 Trending Now
{trending.map((item, index) => {
const p = item.payload || {};
return (
{
if (onRecordInteraction) onRecordInteraction(item.id, p.url);
if (onItemClick) onItemClick(item.id);
}}
className="bg-gradient-to-br from-orange-900/30 to-slate-800/40 p-5 rounded-xl border border-orange-500/30 shadow-sm hover:shadow-md transition-all relative overflow-hidden cursor-pointer backdrop-blur-md"
>
#{index + 1}
Hot Topic
{p.url || 'Untitled'}
{p.content_preview || ''}
{item.clicks || 0} Clicks
);
})}
);
};
// ==========================================
// COMPONENT: FEED SECTION
// ==========================================
const FeedSection = ({ apiConfig, onItemClick, onRecordInteraction }) => {
const [feed, setFeed] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const loadFeed = async () => {
try {
const response = await fetch(apiConfig.getURL(`${apiConfig.endpoints.feed}?limit=6`));
const data = await response.json();
if (data.points) {
setFeed(data.points);
}
} catch (e) {
console.error("Failed to load feed", e);
} finally {
setLoading(false);
}
};
loadFeed();
}, [apiConfig]);
if (loading) {
return (
Recent Knowledge Ingestions
Loading feed...
);
}
if (feed.length === 0) {
return (
Recent Knowledge Ingestions
No knowledge found in the Commons.
);
}
return (
Recent Knowledge Ingestions
{feed.map((pt) => {
const p = pt.payload || {};
return (
{
if (onRecordInteraction) onRecordInteraction(pt.id, p.url);
if (onItemClick) onItemClick(pt.id);
}}
className="bg-slate-800/40 backdrop-blur-md p-5 rounded-lg border border-slate-700 shadow-sm hover:shadow-md transition-all cursor-pointer"
>
{p.type || 'Unknown'}
{p.url || 'Untitled'}
{p.content_preview || ''}
ID: {pt.id ? pt.id.substring(0, 6) : 'N/A'}...
);
})}
);
};
// ==========================================
// MAIN APP COMPONENT
// ==========================================
export default function App() {
const [query, setQuery] = useState("");
const [isSearching, setIsSearching] = useState(false);
const [results, setResults] = useState([]);
const [searchStep, setSearchStep] = useState(0);
const [showIntro, setShowIntro] = useState(true);
const [progressToast, setProgressToast] = useState({ visible: false, count: 0, message: '' });
const [notification, setNotification] = useState({ visible: false, message: '' });
const [ws, setWs] = useState(null);
const apiConfig = getAPIConfig();
// WebSocket connection
useEffect(() => {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = apiConfig.getWebSocketURL();
const websocket = new WebSocket(wsUrl);
websocket.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'progress') {
setProgressToast({
visible: true,
count: data.count || 0,
message: data.message || data.details || 'Processing...'
});
} else if (data.type === 'system_update') {
setProgressToast({
visible: true,
count: 'Done',
message: data.message || 'Synchronization Complete.'
});
setTimeout(() => {
setProgressToast({ visible: false, count: 0, message: '' });
}, 5000);
// Refresh feed and trending
window.location.reload();
} else if (data.type === 'error') {
setNotification({
visible: true,
message: `System Error: ${data.message}`
});
}
};
websocket.onerror = (error) => {
console.error('WebSocket error:', error);
};
setWs(websocket);
return () => {
websocket.close();
};
}, [apiConfig]);
// Record user interaction
const recordInteraction = async (itemId, url) => {
try {
const formData = new FormData();
formData.append('item_id', itemId);
formData.append('action', 'click');
await fetch(apiConfig.getURL(apiConfig.endpoints.feedback), {
method: 'POST',
body: formData,
keepalive: true
});
console.log("Interaction recorded for", itemId);
} catch (e) {
console.error("Failed to record interaction", e);
}
};
// Navigate to detail page
const handleItemClick = (itemId) => {
window.location.href = `/view/${itemId}`;
};
// Show notification
const showNotification = (message) => {
setNotification({ visible: true, message });
setTimeout(() => {
setNotification({ visible: false, message: '' });
}, 5000);
};
// Search functionality
const handleSearch = async (e) => {
e?.preventDefault();
if (!query.trim()) return;
setIsSearching(true);
setShowIntro(false);
setResults([]);
setSearchStep(1);
setTimeout(() => {
setSearchStep(2);
setTimeout(() => {
setSearchStep(3);
setTimeout(async () => {
try {
const res = await fetch(apiConfig.getURL(`${apiConfig.endpoints.search}?q=${encodeURIComponent(query)}`));
if (!res.ok) throw new Error("Backend offline");
const data = await res.json();
setResults(data.results || []);
} catch (err) {
console.warn("Backend unavailable, using mock data.");
setResults([]);
}
setSearchStep(4);
setIsSearching(false);
}, 800);
}, 800);
}, 800);
};
return (
{showIntro && (
<>
Query the
Collective Intelligence
Access the high-dimensional knowledge vector space of TUM.
Powered by CLIP embeddings, consistency checks, and serendipity algorithms.
>
)}
{(isSearching || searchStep > 0) && (
)}
{!showIntro && searchStep === 4 && (
Neural Responses
{results.length} NODES ACTIVATED
{results.map((item, idx) => (
))}
{results.length === 0 && (
No convergent nodes found in the vector space.
)}
)}
{showIntro && (
<>
>
)}
setProgressToast({ visible: false, count: 0, message: '' })}
/>
setNotification({ visible: false, message: '' })}
/>
);
}