|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>AI Model Playground</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
|
<style> |
|
|
.canvas-container { |
|
|
position: relative; |
|
|
width: 280px; |
|
|
height: 280px; |
|
|
background-color: #f3f4f6; |
|
|
border-radius: 0.5rem; |
|
|
box-shadow: inset 0 0 10px rgba(0,0,0,0.1); |
|
|
} |
|
|
canvas { |
|
|
position: absolute; |
|
|
top: 0; |
|
|
left: 0; |
|
|
cursor: crosshair; |
|
|
} |
|
|
.pixel-grid { |
|
|
display: grid; |
|
|
grid-template-columns: repeat(28, 1fr); |
|
|
grid-template-rows: repeat(28, 1fr); |
|
|
width: 280px; |
|
|
height: 280px; |
|
|
} |
|
|
.pixel { |
|
|
border: 1px solid rgba(0,0,0,0.05); |
|
|
background-color: white; |
|
|
} |
|
|
.pixel:hover { |
|
|
background-color: #e5e7eb !important; |
|
|
} |
|
|
.prediction-bar { |
|
|
transition: width 0.3s ease; |
|
|
} |
|
|
.gradient-bg { |
|
|
background: linear-gradient(135deg, #6b46c1 0%, #3b82f6 100%); |
|
|
} |
|
|
.typewriter { |
|
|
overflow: hidden; |
|
|
border-right: 2px solid #333; |
|
|
white-space: nowrap; |
|
|
letter-spacing: 0.15em; |
|
|
animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite; |
|
|
} |
|
|
@keyframes typing { |
|
|
from { width: 0 } |
|
|
to { width: 100% } |
|
|
} |
|
|
@keyframes blink-caret { |
|
|
from, to { border-color: transparent } |
|
|
50% { border-color: #333 } |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gray-50 min-h-screen"> |
|
|
<div class="gradient-bg text-white py-8 shadow-lg"> |
|
|
<div class="container mx-auto px-4"> |
|
|
<h1 class="text-4xl font-bold text-center mb-2"> |
|
|
<i class="fas fa-brain mr-3"></i>AI Model Playground |
|
|
</h1> |
|
|
<p class="text-xl text-center opacity-90"> |
|
|
Interactive MNIST Digit Classification & NLP Sentiment Analysis |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="container mx-auto px-4 py-12"> |
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-12"> |
|
|
|
|
|
<div class="bg-white rounded-xl shadow-lg overflow-hidden"> |
|
|
<div class="bg-indigo-600 text-white px-6 py-4"> |
|
|
<h2 class="text-2xl font-semibold flex items-center"> |
|
|
<i class="fas fa-digital-tachograph mr-3"></i>MNIST Digit Classifier |
|
|
</h2> |
|
|
<p class="text-indigo-100 mt-1">Draw a digit and see the neural network's prediction</p> |
|
|
</div> |
|
|
|
|
|
<div class="p-6"> |
|
|
<div class="flex flex-col md:flex-row gap-8 items-center md:items-start"> |
|
|
<div> |
|
|
<div class="canvas-container mb-4" id="canvasContainer"> |
|
|
<canvas id="drawingCanvas" width="280" height="280"></canvas> |
|
|
</div> |
|
|
<div class="flex justify-center gap-4"> |
|
|
<button id="clearBtn" class="px-4 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 transition"> |
|
|
<i class="fas fa-eraser mr-2"></i>Clear |
|
|
</button> |
|
|
<button id="predictBtn" class="px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 transition"> |
|
|
<i class="fas fa-magic mr-2"></i>Predict |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="w-full md:w-1/2"> |
|
|
<h3 class="text-xl font-semibold mb-4 text-gray-700">Prediction Results</h3> |
|
|
<div id="predictionResults" class="space-y-3"> |
|
|
<div class="text-center py-8 text-gray-400"> |
|
|
<i class="fas fa-draw-polygon text-4xl mb-2"></i> |
|
|
<p>Draw a digit to see predictions</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="mt-8"> |
|
|
<h3 class="text-xl font-semibold mb-4 text-gray-700">Model Information</h3> |
|
|
<div class="bg-gray-50 p-4 rounded-lg"> |
|
|
<div class="mb-3"> |
|
|
<span class="font-medium">Model Type:</span> Neural Network |
|
|
</div> |
|
|
<div class="mb-3"> |
|
|
<span class="font-medium">Architecture:</span> |
|
|
<span class="text-sm bg-gray-200 px-2 py-1 rounded">Flatten → Dense(128, ReLU) → Dense(10, Softmax)</span> |
|
|
</div> |
|
|
<div> |
|
|
<span class="font-medium">Test Accuracy:</span> ~98% |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="bg-white rounded-xl shadow-lg overflow-hidden"> |
|
|
<div class="bg-blue-600 text-white px-6 py-4"> |
|
|
<h2 class="text-2xl font-semibold flex items-center"> |
|
|
<i class="fas fa-comment-dots mr-3"></i>Sentiment Analyzer |
|
|
</h2> |
|
|
<p class="text-blue-100 mt-1">Enter text to analyze its sentiment (positive/negative)</p> |
|
|
</div> |
|
|
|
|
|
<div class="p-6"> |
|
|
<div class="mb-6"> |
|
|
<label for="textInput" class="block text-gray-700 font-medium mb-2">Enter your text:</label> |
|
|
<div class="relative"> |
|
|
<textarea id="textInput" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" placeholder="I love eating pizza..."></textarea> |
|
|
<button id="analyzeBtn" class="absolute right-2 bottom-2 px-4 py-1 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition"> |
|
|
<i class="fas fa-search mr-1"></i>Analyze |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="sentimentResults" class="bg-gray-50 p-6 rounded-lg min-h-40"> |
|
|
<div class="text-center py-6 text-gray-400"> |
|
|
<i class="fas fa-keyboard text-4xl mb-2"></i> |
|
|
<p>Enter some text to analyze sentiment</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="mt-8"> |
|
|
<h3 class="text-xl font-semibold mb-4 text-gray-700">Model Information</h3> |
|
|
<div class="bg-gray-50 p-4 rounded-lg"> |
|
|
<div class="mb-3"> |
|
|
<span class="font-medium">Model Type:</span> Naive Bayes Classifier |
|
|
</div> |
|
|
<div class="mb-3"> |
|
|
<span class="font-medium">Features:</span> |
|
|
<span class="text-sm bg-gray-200 px-2 py-1 rounded">Bag-of-words with CountVectorizer</span> |
|
|
</div> |
|
|
<div> |
|
|
<span class="font-medium">Training Data:</span> Custom sentiment examples |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mt-16 bg-white rounded-xl shadow-lg overflow-hidden"> |
|
|
<div class="bg-purple-600 text-white px-6 py-4"> |
|
|
<h2 class="text-2xl font-semibold flex items-center"> |
|
|
<i class="fas fa-cogs mr-3"></i>How It Works |
|
|
</h2> |
|
|
</div> |
|
|
|
|
|
<div class="p-6 grid grid-cols-1 md:grid-cols-3 gap-6"> |
|
|
<div class="bg-gray-50 p-6 rounded-lg"> |
|
|
<div class="text-purple-600 mb-4"> |
|
|
<i class="fas fa-project-diagram text-3xl"></i> |
|
|
</div> |
|
|
<h3 class="text-xl font-semibold mb-3 text-gray-800">MNIST Classifier</h3> |
|
|
<p class="text-gray-600"> |
|
|
The MNIST classifier uses a simple neural network with one hidden layer (128 neurons) trained on 60,000 handwritten digits. Draw a digit and see the model's prediction confidence for each digit (0-9). |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
<div class="bg-gray-50 p-6 rounded-lg"> |
|
|
<div class="text-blue-600 mb-4"> |
|
|
<i class="fas fa-language text-3xl"></i> |
|
|
</div> |
|
|
<h3 class="text-xl font-semibold mb-3 text-gray-800">Sentiment Analysis</h3> |
|
|
<p class="text-gray-600"> |
|
|
The sentiment analyzer uses a Naive Bayes classifier trained on example sentences. It analyzes the words in your text to predict whether the sentiment is positive (1) or negative (0). |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
<div class="bg-gray-50 p-6 rounded-lg"> |
|
|
<div class="text-green-600 mb-4"> |
|
|
<i class="fas fa-code text-3xl"></i> |
|
|
</div> |
|
|
<h3 class="text-xl font-semibold mb-3 text-gray-800">Technical Details</h3> |
|
|
<p class="text-gray-600"> |
|
|
This demo simulates the behavior of TensorFlow/Keras models for MNIST and scikit-learn for NLP. In a real implementation, you would connect to a backend running the actual models. |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<footer class="bg-gray-800 text-white py-8"> |
|
|
<div class="container mx-auto px-4 text-center"> |
|
|
<p class="mb-4"> |
|
|
<i class="fas fa-laptop-code mr-2"></i>AI Model Playground Demo |
|
|
</p> |
|
|
<div class="flex justify-center space-x-6 mb-4"> |
|
|
<a href="#" class="hover:text-blue-300"><i class="fab fa-github text-xl"></i></a> |
|
|
<a href="#" class="hover:text-blue-300"><i class="fab fa-twitter text-xl"></i></a> |
|
|
<a href="#" class="hover:text-blue-300"><i class="fab fa-linkedin text-xl"></i></a> |
|
|
</div> |
|
|
<p class="text-gray-400 text-sm"> |
|
|
© 2023 AI Demo. All rights reserved. |
|
|
</p> |
|
|
</div> |
|
|
</footer> |
|
|
|
|
|
<script> |
|
|
|
|
|
const canvas = document.getElementById('drawingCanvas'); |
|
|
const ctx = canvas.getContext('2d'); |
|
|
const clearBtn = document.getElementById('clearBtn'); |
|
|
const predictBtn = document.getElementById('predictBtn'); |
|
|
const predictionResults = document.getElementById('predictionResults'); |
|
|
|
|
|
|
|
|
ctx.fillStyle = 'white'; |
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height); |
|
|
ctx.strokeStyle = 'black'; |
|
|
ctx.lineWidth = 15; |
|
|
ctx.lineCap = 'round'; |
|
|
|
|
|
let isDrawing = false; |
|
|
let lastX = 0; |
|
|
let lastY = 0; |
|
|
|
|
|
|
|
|
canvas.addEventListener('mousedown', startDrawing); |
|
|
canvas.addEventListener('mousemove', draw); |
|
|
canvas.addEventListener('mouseup', stopDrawing); |
|
|
canvas.addEventListener('mouseout', stopDrawing); |
|
|
|
|
|
|
|
|
canvas.addEventListener('touchstart', handleTouchStart); |
|
|
canvas.addEventListener('touchmove', handleTouchMove); |
|
|
canvas.addEventListener('touchend', handleTouchEnd); |
|
|
|
|
|
function handleTouchStart(e) { |
|
|
e.preventDefault(); |
|
|
const touch = e.touches[0]; |
|
|
const mouseEvent = new MouseEvent('mousedown', { |
|
|
clientX: touch.clientX, |
|
|
clientY: touch.clientY |
|
|
}); |
|
|
canvas.dispatchEvent(mouseEvent); |
|
|
} |
|
|
|
|
|
function handleTouchMove(e) { |
|
|
e.preventDefault(); |
|
|
const touch = e.touches[0]; |
|
|
const mouseEvent = new MouseEvent('mousemove', { |
|
|
clientX: touch.clientX, |
|
|
clientY: touch.clientY |
|
|
}); |
|
|
canvas.dispatchEvent(mouseEvent); |
|
|
} |
|
|
|
|
|
function handleTouchEnd(e) { |
|
|
e.preventDefault(); |
|
|
const mouseEvent = new MouseEvent('mouseup'); |
|
|
canvas.dispatchEvent(mouseEvent); |
|
|
} |
|
|
|
|
|
function startDrawing(e) { |
|
|
isDrawing = true; |
|
|
[lastX, lastY] = [e.offsetX, e.offsetY]; |
|
|
} |
|
|
|
|
|
function draw(e) { |
|
|
if (!isDrawing) return; |
|
|
ctx.beginPath(); |
|
|
ctx.moveTo(lastX, lastY); |
|
|
ctx.lineTo(e.offsetX, e.offsetY); |
|
|
ctx.stroke(); |
|
|
[lastX, lastY] = [e.offsetX, e.offsetY]; |
|
|
} |
|
|
|
|
|
function stopDrawing() { |
|
|
isDrawing = false; |
|
|
} |
|
|
|
|
|
clearBtn.addEventListener('click', () => { |
|
|
ctx.fillStyle = 'white'; |
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height); |
|
|
predictionResults.innerHTML = ` |
|
|
<div class="text-center py-8 text-gray-400"> |
|
|
<i class="fas fa-draw-polygon text-4xl mb-2"></i> |
|
|
<p>Draw a digit to see predictions</p> |
|
|
</div> |
|
|
`; |
|
|
}); |
|
|
|
|
|
predictBtn.addEventListener('click', () => { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); |
|
|
|
|
|
|
|
|
const predictions = Array(10).fill().map(() => Math.random()); |
|
|
const total = predictions.reduce((sum, val) => sum + val, 0); |
|
|
const normalizedPredictions = predictions.map(p => (p / total * 100).toFixed(1)); |
|
|
const predictedDigit = predictions.indexOf(Math.max(...predictions)); |
|
|
|
|
|
|
|
|
let resultsHTML = ` |
|
|
<div class="text-center mb-4"> |
|
|
<span class="text-5xl font-bold text-indigo-600">${predictedDigit}</span> |
|
|
<p class="text-gray-500 mt-1">Predicted Digit</p> |
|
|
</div> |
|
|
`; |
|
|
|
|
|
normalizedPredictions.forEach((confidence, i) => { |
|
|
resultsHTML += ` |
|
|
<div class="mb-2"> |
|
|
<div class="flex justify-between mb-1"> |
|
|
<span class="font-medium">${i}:</span> |
|
|
<span class="text-gray-600">${confidence}%</span> |
|
|
</div> |
|
|
<div class="w-full bg-gray-200 rounded-full h-2.5"> |
|
|
<div class="bg-indigo-600 h-2.5 rounded-full prediction-bar" style="width: ${confidence}%"></div> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
}); |
|
|
|
|
|
predictionResults.innerHTML = resultsHTML; |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
document.querySelectorAll('.prediction-bar').forEach(bar => { |
|
|
bar.style.transition = 'width 0.5s ease'; |
|
|
}); |
|
|
}, 10); |
|
|
}); |
|
|
|
|
|
|
|
|
const textInput = document.getElementById('textInput'); |
|
|
const analyzeBtn = document.getElementById('analyzeBtn'); |
|
|
const sentimentResults = document.getElementById('sentimentResults'); |
|
|
|
|
|
analyzeBtn.addEventListener('click', analyzeSentiment); |
|
|
textInput.addEventListener('keypress', (e) => { |
|
|
if (e.key === 'Enter' && !e.shiftKey) { |
|
|
e.preventDefault(); |
|
|
analyzeSentiment(); |
|
|
} |
|
|
}); |
|
|
|
|
|
function analyzeSentiment() { |
|
|
const text = textInput.value.trim(); |
|
|
if (!text) return; |
|
|
|
|
|
|
|
|
const sentimentScore = Math.random() > 0.3 ? 1 : 0; |
|
|
const confidence = (Math.random() * 30 + 70).toFixed(1); |
|
|
|
|
|
let resultHTML = ` |
|
|
<div class="flex items-center justify-between mb-4"> |
|
|
<h4 class="text-lg font-semibold">Analysis Results</h4> |
|
|
<span class="px-3 py-1 rounded-full text-sm font-medium ${sentimentScore ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}"> |
|
|
${sentimentScore ? 'Positive' : 'Negative'} |
|
|
</span> |
|
|
</div> |
|
|
<div class="mb-4"> |
|
|
<div class="flex justify-between mb-1"> |
|
|
<span class="font-medium">Confidence:</span> |
|
|
<span class="text-gray-600">${confidence}%</span> |
|
|
</div> |
|
|
<div class="w-full bg-gray-200 rounded-full h-2.5"> |
|
|
<div class="${sentimentScore ? 'bg-green-500' : 'bg-red-500'} h-2.5 rounded-full" style="width: ${confidence}%"></div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="bg-white p-4 rounded-lg border border-gray-200"> |
|
|
<h5 class="font-medium mb-2">Processed Text:</h5> |
|
|
<p class="text-gray-700">"${text.toLowerCase()}"</p> |
|
|
</div> |
|
|
`; |
|
|
|
|
|
sentimentResults.innerHTML = resultHTML; |
|
|
} |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
const examples = [ |
|
|
"I love eating pizza!", |
|
|
"This movie was terrible.", |
|
|
"The service at this restaurant is amazing.", |
|
|
"I hate waiting in long lines." |
|
|
]; |
|
|
|
|
|
let currentExample = 0; |
|
|
|
|
|
function cycleExamples() { |
|
|
textInput.placeholder = ""; |
|
|
textInput.setAttribute('placeholder', ''); |
|
|
|
|
|
const placeholderEl = document.createElement('div'); |
|
|
placeholderEl.className = 'typewriter absolute top-3 left-4 text-gray-400 pointer-events-none'; |
|
|
placeholderEl.textContent = examples[currentExample]; |
|
|
|
|
|
const inputContainer = textInput.parentNode; |
|
|
inputContainer.style.position = 'relative'; |
|
|
inputContainer.appendChild(placeholderEl); |
|
|
|
|
|
currentExample = (currentExample + 1) % examples.length; |
|
|
|
|
|
setTimeout(() => { |
|
|
placeholderEl.remove(); |
|
|
setTimeout(cycleExamples, 2000); |
|
|
}, 3500); |
|
|
} |
|
|
|
|
|
setTimeout(cycleExamples, 1000); |
|
|
}, 1500); |
|
|
</script> |
|
|
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Gabz8646/gg" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
|
</html> |