Skip to main content
Glama
index.html16.4 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Adaptive Recommendations - AgentDB</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; padding: 2rem; } .container { max-width: 1200px; margin: 0 auto; } header { background: white; border-radius: 12px; padding: 2rem; margin-bottom: 2rem; box-shadow: 0 10px 30px rgba(0,0,0,0.2); } h1 { color: #333; margin-bottom: 0.5rem; } .subtitle { color: #666; } .grid { display: grid; grid-template-columns: 2fr 1fr; gap: 2rem; } .card { background: white; border-radius: 12px; padding: 2rem; box-shadow: 0 10px 30px rgba(0,0,0,0.2); } .card h2 { color: #333; margin-bottom: 1rem; } .content-card { background: linear-gradient(135deg, #667eea15 0%, #764ba215 100%); border: 2px solid #e0e0e0; border-radius: 8px; padding: 1.5rem; margin-bottom: 1rem; cursor: pointer; transition: all 0.2s ease; } .content-card:hover { border-color: #667eea; transform: translateY(-2px); } .content-card.shown { border-color: #28a745; background: #d4edda22; } .content-header { display: flex; justify-content: space-between; align-items: start; margin-bottom: 0.75rem; } .content-title { font-weight: 600; color: #333; font-size: 1.1rem; } .content-score { background: #667eea; color: white; padding: 0.25rem 0.75rem; border-radius: 12px; font-size: 0.85rem; font-weight: 600; } .content-description { color: #666; line-height: 1.6; margin-bottom: 0.75rem; } .content-tags { display: flex; flex-wrap: wrap; gap: 0.5rem; } .tag { background: #f0f0f0; padding: 0.25rem 0.75rem; border-radius: 12px; font-size: 0.85rem; color: #666; } .feedback-buttons { display: flex; gap: 0.5rem; margin-top: 1rem; } .feedback-btn { flex: 1; padding: 0.5rem; border: none; border-radius: 6px; font-weight: 600; cursor: pointer; transition: all 0.2s ease; } .feedback-btn.like { background: #28a745; color: white; } .feedback-btn.dislike { background: #dc3545; color: white; } .feedback-btn:hover { opacity: 0.8; } .stat-card { background: #f8f9fa; border-radius: 6px; padding: 1rem; margin-bottom: 0.5rem; } .stat-label { color: #666; font-size: 0.9rem; } .stat-value { color: #333; font-size: 1.5rem; font-weight: bold; margin-top: 0.25rem; } .algorithm-info { background: #e3f2fd; border-left: 4px solid #2196f3; padding: 1rem; border-radius: 4px; margin-top: 1rem; } .algorithm-info h3 { color: #2196f3; margin-bottom: 0.5rem; font-size: 1rem; } .algorithm-info p { color: #666; font-size: 0.9rem; line-height: 1.5; } .progress-indicator { margin-top: 1rem; } .progress-label { display: flex; justify-content: space-between; margin-bottom: 0.5rem; font-size: 0.9rem; color: #666; } .progress-bar { width: 100%; height: 8px; background: #e0e0e0; border-radius: 4px; overflow: hidden; } .progress-fill { height: 100%; background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); transition: width 0.3s ease; } </style> </head> <body> <div class="container"> <header> <h1>🎨 Adaptive Recommendation System</h1> <p class="subtitle">Multi-Armed Bandit with Thompson Sampling - Real-time Learning</p> </header> <div class="grid"> <div class="card"> <h2>Content Feed</h2> <p style="color: #666; margin-bottom: 1rem;"> Click on content to view. Like or dislike to help the system learn your preferences! </p> <div id="contentFeed"></div> </div> <div> <div class="card" style="margin-bottom: 1rem;"> <h2>Learning Stats</h2> <div class="stat-card"> <div class="stat-label">Content Viewed</div> <div class="stat-value" id="viewedCount">0</div> </div> <div class="stat-card"> <div class="stat-label">Positive Feedback</div> <div class="stat-value" id="likeCount">0</div> </div> <div class="stat-card"> <div class="stat-label">Learning Rate</div> <div class="stat-value" id="learningRate">0%</div> </div> <div class="stat-card"> <div class="stat-label">Exploration Rate</div> <div class="stat-value" id="exploreRate">50%</div> </div> </div> <div class="card"> <h2>Category Preferences</h2> <div id="categoryStats"></div> </div> </div> </div> <div class="card" style="margin-top: 2rem;"> <h2>How It Works</h2> <div class="algorithm-info"> <h3>🎰 Multi-Armed Bandit (Thompson Sampling)</h3> <p> This system uses Thompson Sampling to balance exploration (trying new content categories) and exploitation (showing categories you've liked before). It maintains a Beta distribution for each category and samples from it to decide what to recommend next. Your feedback updates the distributions in real-time, making recommendations increasingly personalized. </p> </div> </div> </div> <script type="module"> const CONTENT_POOL = [ { id: 1, category: 'tech', title: 'Latest AI Breakthroughs', description: 'Discover cutting-edge developments in artificial intelligence', tags: ['AI', 'Research', 'Innovation'] }, { id: 2, category: 'tech', title: 'Cloud Computing Guide', description: 'Complete guide to modern cloud architecture', tags: ['Cloud', 'DevOps', 'Architecture'] }, { id: 3, category: 'tech', title: 'Quantum Computing 101', description: 'Introduction to quantum computing principles', tags: ['Quantum', 'Physics', 'Computing'] }, { id: 4, category: 'business', title: 'Startup Success Stories', description: 'Learn from founders who built billion-dollar companies', tags: ['Startup', 'Entrepreneurship'] }, { id: 5, category: 'business', title: 'Marketing Strategies 2024', description: 'Latest trends in digital marketing', tags: ['Marketing', 'Strategy', 'Growth'] }, { id: 6, category: 'business', title: 'Leadership Best Practices', description: 'How to build and lead high-performing teams', tags: ['Leadership', 'Management'] }, { id: 7, category: 'science', title: 'Space Exploration Update', description: 'Recent discoveries from Mars missions', tags: ['Space', 'Mars', 'Exploration'] }, { id: 8, category: 'science', title: 'Climate Change Research', description: 'Latest findings on climate science', tags: ['Climate', 'Environment', 'Research'] }, { id: 9, category: 'science', title: 'Neuroscience Insights', description: 'How the brain processes information', tags: ['Neuroscience', 'Brain', 'Psychology'] }, { id: 10, category: 'lifestyle', title: 'Healthy Living Tips', description: 'Science-backed health and wellness advice', tags: ['Health', 'Wellness', 'Fitness'] }, { id: 11, category: 'lifestyle', title: 'Travel Destinations 2024', description: 'Must-visit places around the world', tags: ['Travel', 'Adventure', 'Culture'] }, { id: 12, category: 'lifestyle', title: 'Mindfulness Practices', description: 'Meditation and stress reduction techniques', tags: ['Mindfulness', 'Mental Health'] }, ]; let viewedContent = new Set(); let categoryBandits = { tech: { alpha: 1, beta: 1 }, business: { alpha: 1, beta: 1 }, science: { alpha: 1, beta: 1 }, lifestyle: { alpha: 1, beta: 1 } }; let feedbackHistory = []; function betaSample(alpha, beta) { // Approximate Beta distribution sampling using gamma distributions const x = gammaSample(alpha, 1); const y = gammaSample(beta, 1); return x / (x + y); } function gammaSample(shape, scale) { // Marsaglia and Tsang method for gamma sampling if (shape < 1) { return gammaSample(shape + 1, scale) * Math.pow(Math.random(), 1 / shape); } const d = shape - 1/3; const c = 1 / Math.sqrt(9 * d); while (true) { let x, v; do { x = normalSample(0, 1); v = 1 + c * x; } while (v <= 0); v = v * v * v; x = x * x; const u = Math.random(); if (u < 1 - 0.0331 * x * x) { return scale * d * v; } if (Math.log(u) < 0.5 * x + d * (1 - v + Math.log(v))) { return scale * d * v; } } } function normalSample(mean, variance) { // Box-Muller transform const u1 = Math.random(); const u2 = Math.random(); const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2); return mean + Math.sqrt(variance) * z; } function selectCategory() { const samples = {}; Object.entries(categoryBandits).forEach(([category, { alpha, beta }]) => { samples[category] = betaSample(alpha, beta); }); return Object.entries(samples).reduce((a, b) => a[1] > b[1] ? a : b)[0]; } function getRandomContent(category) { const available = CONTENT_POOL.filter(c => c.category === category && !viewedContent.has(c.id)); if (available.length === 0) { viewedContent.clear(); return getRandomContent(category); } return available[Math.floor(Math.random() * available.length)]; } function renderFeed() { const feed = document.getElementById('contentFeed'); const category = selectCategory(); const content = getRandomContent(category); const card = document.createElement('div'); card.className = 'content-card'; card.innerHTML = ` <div class="content-header"> <div class="content-title">${content.title}</div> <div class="content-score">${category}</div> </div> <div class="content-description">${content.description}</div> <div class="content-tags"> ${content.tags.map(tag => `<span class="tag">${tag}</span>`).join('')} </div> <div class="feedback-buttons"> <button class="feedback-btn like">👍 Like</button> <button class="feedback-btn dislike">👎 Not Interested</button> </div> `; card.querySelector('.like').addEventListener('click', (e) => { e.stopPropagation(); handleFeedback(content, true); card.classList.add('shown'); setTimeout(renderFeed, 500); }); card.querySelector('.dislike').addEventListener('click', (e) => { e.stopPropagation(); handleFeedback(content, false); card.classList.add('shown'); setTimeout(renderFeed, 500); }); feed.insertBefore(card, feed.firstChild); while (feed.children.length > 5) { feed.removeChild(feed.lastChild); } viewedContent.add(content.id); updateStats(); } function handleFeedback(content, liked) { feedbackHistory.push({ content: content, liked: liked, timestamp: Date.now() }); // Update bandit if (liked) { categoryBandits[content.category].alpha += 1; } else { categoryBandits[content.category].beta += 1; } updateStats(); renderCategoryStats(); } function updateStats() { document.getElementById('viewedCount').textContent = feedbackHistory.length; const likes = feedbackHistory.filter(f => f.liked).length; document.getElementById('likeCount').textContent = likes; if (feedbackHistory.length > 0) { const rate = (likes / feedbackHistory.length * 100).toFixed(0); document.getElementById('learningRate').textContent = `${rate}%`; } // Calculate exploration rate (entropy of category distribution) const totalFeedback = Object.values(categoryBandits).reduce((sum, b) => sum + b.alpha + b.beta, 0); const entropy = Object.values(categoryBandits).reduce((sum, b) => { const prob = (b.alpha + b.beta) / totalFeedback; return sum - (prob > 0 ? prob * Math.log2(prob) : 0); }, 0); const maxEntropy = Math.log2(Object.keys(categoryBandits).length); const exploreRate = ((entropy / maxEntropy) * 100).toFixed(0); document.getElementById('exploreRate').textContent = `${exploreRate}%`; } function renderCategoryStats() { const container = document.getElementById('categoryStats'); container.innerHTML = Object.entries(categoryBandits) .map(([category, { alpha, beta }]) => { const total = alpha + beta; const mean = alpha / total; const percentage = (mean * 100).toFixed(0); return ` <div class="progress-indicator"> <div class="progress-label"> <span>${category.charAt(0).toUpperCase() + category.slice(1)}</span> <span>${percentage}%</span> </div> <div class="progress-bar"> <div class="progress-fill" style="width: ${percentage}%"></div> </div> </div> `; }).join(''); } // Initialize renderFeed(); renderCategoryStats(); </script> </body> </html>

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/airmcp-com/mcp-standards'

If you have feedback or need assistance with the MCP directory API, please join our Discord server