|
|
| <!DOCTYPE html> |
| <html lang="en" class="dark"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>PiPattern VizWhiz 🌀</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <script src="https://unpkg.com/feather-icons"></script> |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script> |
| <script src="https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js"></script> |
| <style> |
| #vanta-bg { |
| position: absolute; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| z-index: -1; |
| opacity: 0.2; |
| } |
| .result-container { |
| transition: all 0.3s ease; |
| } |
| .result-container:hover { |
| transform: translateY(-5px); |
| box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); |
| } |
| .code-block { |
| font-family: 'Fira Code', monospace; |
| background-color: #1e293b; |
| border-radius: 0.375rem; |
| padding: 1rem; |
| overflow-x: auto; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-900 text-gray-100 min-h-screen"> |
| <div id="vanta-bg"></div> |
| |
| <div class="container mx-auto px-4 py-12"> |
| <header class="text-center mb-12"> |
| <h1 class="text-4xl md:text-5xl font-bold mb-4 bg-gradient-to-r from-purple-400 via-pink-500 to-indigo-500 text-transparent bg-clip-text"> |
| PiRepeater Visualizer |
| </h1> |
| <p class="text-xl text-gray-400 max-w-2xl mx-auto"> |
| Enter a 9-digit number and visualize the mathematical patterns in π |
| </p> |
| </header> |
|
|
| <main class="max-w-4xl mx-auto"> |
| <div class="bg-gray-800 rounded-xl shadow-xl p-6 mb-8"> |
| <div class="flex flex-col md:flex-row gap-4"> |
| <input |
| type="text" |
| id="pi-input" |
| placeholder="Enter 9 digits (e.g., 123456789)" |
| class="flex-grow px-4 py-3 bg-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500" |
| maxlength="9" |
| pattern="\d{9}" |
| > |
| <select |
| id="model-select" |
| class="px-4 py-3 bg-gray-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500" |
| > |
| <option value="Shreyas1441AI/Pi_repeater_plot3">Plot 3</option> |
| <option value="Shreyas1441AI/Pi_repeater_plot6">Plot 6</option> |
| <option value="Shreyas1441AI/Pi_repeater_plot8" selected>Plot 8</option> |
| </select> |
| <button |
| id="visualize-btn" |
| class="px-6 py-3 bg-gradient-to-r from-purple-500 to-indigo-600 rounded-lg font-medium hover:from-purple-600 hover:to-indigo-700 transition flex items-center justify-center gap-2" |
| > |
| <i data-feather="eye"></i> |
| Visualize |
| </button> |
| </div> |
| <p class="text-gray-400 text-sm mt-2">Enter exactly 9 digits (0-9) to analyze</p> |
| </div> |
| <div id="loading" class="hidden text-center py-8"> |
| <div class="inline-block animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-purple-500 mb-4"></div> |
| <p class="text-gray-400">Analyzing π patterns...</p> |
| </div> |
| <div id="results" class="hidden space-y-8"> |
| <div class="bg-gray-800 rounded-xl p-6"> |
| <h3 class="text-xl font-bold mb-4 flex items-center gap-2"> |
| <i data-feather="info"></i> |
| Input Analysis |
| </h3> |
| <div class="code-block" id="input-analysis"></div> |
| </div> |
| |
| <div id="model-results" class="grid grid-cols-1 md:grid-cols-3 gap-6"></div> |
| |
| <div id="comparison-view" class="bg-gray-800 rounded-xl p-6"> |
| <h3 class="text-xl font-bold mb-4 flex items-center gap-2"> |
| <i data-feather="compare"></i> |
| Model Comparison |
| </h3> |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4" id="comparison-images"></div> |
| </div> |
| </div> |
| </main> |
| </div> |
|
|
| <script> |
| feather.replace(); |
| |
| // Initialize Vanta.js globe background |
| VANTA.GLOBE({ |
| el: "#vanta-bg", |
| mouseControls: true, |
| touchControls: true, |
| gyroControls: false, |
| minHeight: 200.00, |
| minWidth: 200.00, |
| scale: 1.00, |
| scaleMobile: 1.00, |
| color: 0x7e5bef, |
| backgroundColor: 0x111827, |
| size: 0.8 |
| }); |
| document.getElementById('visualize-btn').addEventListener('click', async function() { |
| const input = document.getElementById('pi-input').value; |
| |
| if (!/^\d{9}$/.test(input)) { |
| alert('Please enter exactly 9 digits (0-9)'); |
| return; |
| } |
| |
| // Show loading, hide results |
| document.getElementById('loading').classList.remove('hidden'); |
| document.getElementById('results').classList.add('hidden'); |
| |
| try { |
| // Process all models |
| const models = [ |
| "Shreyas1441AI/Pi_repeater_plot3", |
| "Shreyas1441AI/Pi_repeater_plot6", |
| "Shreyas1441AI/Pi_repeater_plot8" |
| ]; |
| |
| const results = await Promise.all(models.map(async model => { |
| const client = await Client.connect(model); |
| const result = await client.predict("/predict", { |
| input_digits: input |
| }); |
| return { |
| model, |
| data: result.data |
| }; |
| })); |
| |
| // Display all results |
| displayAllResults(results, input); |
| |
| // Hide loading, show results |
| document.getElementById('loading').classList.add('hidden'); |
| document.getElementById('results').classList.remove('hidden'); |
| |
| } catch (error) { |
| console.error('Error:', error); |
| document.getElementById('loading').classList.add('hidden'); |
| alert('An error occurred while processing your request. Please try again.'); |
| } |
| }); |
| |
| function formatExplanation(text) { |
| // Format explanation with proper line breaks and styling |
| return text |
| .replace(/\n/g, '<br>') |
| .replace(/\s{4,}/g, match => ' '.repeat(match.length)) |
| .replace(/\b(Step \d+:)\b/g, '<span class="text-purple-400 font-semibold">$1</span>') |
| .replace(/\b(\w+ = ".+")\b/g, '<span class="text-green-400">$1</span>') |
| .replace(/\b(\w+ = \d+)\b/g, '<span class="text-blue-400">$1</span>'); |
| } |
| function displayAllResults(results, input) { |
| const modelResultsContainer = document.getElementById('model-results'); |
| const comparisonContainer = document.getElementById('comparison-images'); |
| const inputAnalysisContainer = document.getElementById('input-analysis'); |
| |
| // Clear previous results |
| modelResultsContainer.innerHTML = ''; |
| comparisonContainer.innerHTML = ''; |
| |
| // Show input analysis |
| inputAnalysisContainer.innerHTML = `Analyzing sequence: <span class="text-purple-400">${input}</span>`; |
| |
| // Process each result |
| results.forEach((result, index) => { |
| const [explanation, imageData] = result.data; |
| const modelName = result.model.split('/').pop(); |
| |
| // Create result card |
| const resultCard = document.createElement('div'); |
| resultCard.className = 'bg-gray-800 rounded-xl shadow-lg overflow-hidden result-container'; |
| resultCard.innerHTML = ` |
| <div class="p-6"> |
| <h3 class="text-xl font-bold mb-2 flex items-center gap-2"> |
| <i data-feather="${index === 0 ? 'cpu' : index === 1 ? 'layers' : 'sliders'}"></i> |
| ${modelName} Visualization |
| </h3> |
| <div class="mb-4 flex justify-center"> |
| <img src="${imageData.plot}" alt="${modelName} Visualization" class="max-w-full h-auto rounded-lg"> |
| </div> |
| <div class="code-block overflow-auto max-h-60 p-4">${formatExplanation(explanation)}</div> |
| </div> |
| `; |
| modelResultsContainer.appendChild(resultCard); |
| |
| // Add to comparison |
| const comparisonItem = document.createElement('div'); |
| comparisonItem.className = 'bg-gray-700 rounded-lg overflow-hidden'; |
| comparisonItem.innerHTML = ` |
| <div class="p-4"> |
| <h4 class="text-sm font-medium mb-2">${modelName}</h4> |
| <img src="${imageData.plot}" alt="${modelName}" class="w-full h-auto rounded"> |
| </div> |
| `; |
| comparisonContainer.appendChild(comparisonItem); |
| }); |
| |
| // Refresh feather icons |
| feather.replace(); |
| } |
| function addToComparison(imageSrc, modelName) { |
| const comparisonContainer = document.getElementById('comparison-images'); |
| |
| const comparisonItem = document.createElement('div'); |
| comparisonItem.className = 'bg-gray-700 rounded-lg overflow-hidden'; |
| comparisonItem.innerHTML = ` |
| <div class="p-4"> |
| <h4 class="text-sm font-medium mb-2">${modelName}</h4> |
| <img src="${imageSrc}" alt="${modelName}" class="w-full h-auto rounded"> |
| </div> |
| `; |
| comparisonContainer.appendChild(comparisonItem); |
| } |
| |
| function displayResults(data, modelName) { |
| const resultsContainer = document.getElementById('results'); |
| const [explanation, imageData] = data; |
| |
| // Hide loading |
| document.getElementById('loading').classList.add('hidden'); |
| |
| // Clear previous results |
| resultsContainer.innerHTML = ''; |
| |
| // Add model info |
| const modelInfo = document.createElement('div'); |
| modelInfo.className = 'bg-gray-800 rounded-xl p-6 mb-6'; |
| modelInfo.innerHTML = ` |
| <h3 class="text-xl font-bold mb-2 flex items-center gap-2"> |
| <i data-feather="cpu"></i> |
| Model: ${modelName.split('/').pop()} |
| </h3> |
| <p class="text-gray-400">Input: ${document.getElementById('pi-input').value}</p> |
| `; |
| resultsContainer.appendChild(modelInfo); |
| |
| // Add image |
| const imageContainer = document.createElement('div'); |
| imageContainer.className = 'bg-gray-800 rounded-xl shadow-lg overflow-hidden result-container'; |
| imageContainer.innerHTML = ` |
| <h3 class="text-xl font-bold p-6 pb-0 flex items-center gap-2"> |
| <i data-feather="image"></i> |
| Visualization |
| </h3> |
| <div class="p-6"> |
| <img src="${imageData.plot}" alt="Pi Repeater Visualization" class="w-full h-auto rounded-lg"> |
| </div> |
| `; |
| resultsContainer.appendChild(imageContainer); |
| |
| // Add explanation |
| const explanationContainer = document.createElement('div'); |
| explanationContainer.className = 'bg-gray-800 rounded-xl shadow-lg overflow-hidden result-container'; |
| explanationContainer.innerHTML = ` |
| <h3 class="text-xl font-bold p-6 pb-0 flex items-center gap-2"> |
| <i data-feather="info"></i> |
| Process Explanation |
| </h3> |
| <div class="p-6"> |
| <div class="code-block">${formatExplanation(explanation)}</div> |
| </div> |
| `; |
| resultsContainer.appendChild(explanationContainer); |
| |
| // Show results and refresh icons |
| resultsContainer.classList.remove('hidden'); |
| feather.replace(); |
| } |
| |
| function formatExplanation(text) { |
| // Format the text with line breaks and monospace formatting |
| return text.split('\n').map(line => { |
| if (line.trim() === '') return '<br>'; |
| if (line.includes(' |
| </body> |
| </html> |