Spaces:
Running
Running
| document.addEventListener('DOMContentLoaded', async function() { | |
| // Initialize cloud data | |
| const cloudData = [ | |
| { text: "Happiness", percentage: 0 }, | |
| { text: "Adventure", percentage: 0 }, | |
| { text: "Creativity", percentage: 0 }, | |
| { text: "Friendship", percentage: 0 }, | |
| { text: "Success", percentage: 0 }, | |
| { text: "Love", percentage: 0 }, | |
| { text: "Freedom", percentage: 0 }, | |
| { text: "Peace", percentage: 0 }, | |
| { text: "Growth", percentage: 0 }, | |
| { text: "Discovery", percentage: 0 } | |
| ]; | |
| const cloudContainer = document.getElementById('cloud-container'); | |
| const textInput = document.getElementById('text-input'); | |
| const analyzeBtn = document.getElementById('analyze-btn'); | |
| const resultsSection = document.getElementById('results'); | |
| const similarityResults = document.getElementById('similarity-results'); | |
| // Load the Universal Sentence Encoder | |
| let model; | |
| try { | |
| model = await use.load(); | |
| console.log('Model loaded successfully'); | |
| } catch (err) { | |
| console.error('Failed to load model:', err); | |
| return; | |
| } | |
| // Create initial clouds | |
| createClouds(); | |
| // Add event listeners | |
| analyzeBtn.addEventListener('click', () => { | |
| analyzeBtn.disabled = true; | |
| analyzeBtn.innerHTML = '<i data-feather="loader" class="animate-spin"></i>'; | |
| feather.replace(); | |
| analyzeText().finally(() => { | |
| analyzeBtn.disabled = false; | |
| analyzeBtn.innerHTML = '<i data-feather="search"></i>'; | |
| feather.replace(); | |
| }); | |
| }); | |
| textInput.addEventListener('keypress', function(e) { | |
| if (e.key === 'Enter') { | |
| analyzeBtn.click(); | |
| } | |
| }); | |
| function createClouds() { | |
| cloudContainer.innerHTML = ''; | |
| const containerWidth = cloudContainer.offsetWidth; | |
| const containerHeight = cloudContainer.offsetHeight; | |
| // Create a circular layout for initial clouds | |
| const centerX = containerWidth / 2; | |
| const centerY = containerHeight / 2; | |
| const radius = Math.min(containerWidth, containerHeight) * 0.35; | |
| cloudData.forEach((cloud, i) => { | |
| const angle = (i / cloudData.length) * Math.PI * 2; | |
| const x = centerX + Math.cos(angle) * radius; | |
| const y = centerY + Math.sin(angle) * radius; | |
| // Create cloud with base size | |
| createCloud(cloud, x, y, 40); | |
| }); | |
| } | |
| function createCloud(data, x, y, baseSize) { | |
| const cloud = document.createElement('custom-cloud'); | |
| cloud.setAttribute('text', data.text); | |
| cloud.setAttribute('percentage', data.percentage); | |
| // Position the cloud | |
| cloud.style.left = `${x}px`; | |
| cloud.style.top = `${y}px`; | |
| cloudContainer.appendChild(cloud); | |
| return cloud; | |
| } | |
| async function analyzeText() { | |
| const inputText = textInput.value.trim(); | |
| if (!inputText) { | |
| alert('Please enter some text to analyze'); | |
| return; | |
| } | |
| try { | |
| // Generate embeddings for input text and cloud texts | |
| const inputEmbedding = await model.embed([inputText]); | |
| const cloudTexts = cloudData.map(c => c.text); | |
| const cloudEmbeddings = await model.embed(cloudTexts); | |
| // Calculate cosine similarity between input and each cloud text | |
| const inputArray = await inputEmbedding.array(); | |
| const cloudArrays = await cloudEmbeddings.array(); | |
| const similarities = []; | |
| for (let i = 0; i < cloudData.length; i++) { | |
| const similarity = cosineSimilarity(inputArray[0], cloudArrays[i]); | |
| const percentage = Math.round(similarity * 100); | |
| cloudData[i].percentage = percentage; | |
| similarities.push({ text: cloudData[i].text, percentage }); | |
| } | |
| // Sort by percentage descending | |
| similarities.sort((a, b) => b.percentage - a.percentage); | |
| // Update UI with results | |
| updateClouds(); | |
| showResults(inputText, similarities); | |
| } catch (err) { | |
| console.error('Error analyzing text:', err); | |
| resultsSection.classList.add('hidden'); | |
| alert('An error occurred while analyzing your text. Please try again.'); | |
| throw err; // Re-throw to ensure button state is reset | |
| } | |
| } | |
| function updateClouds() { | |
| cloudContainer.innerHTML = ''; | |
| const containerWidth = cloudContainer.offsetWidth; | |
| const containerHeight = cloudContainer.offsetHeight; | |
| // Sort clouds by percentage (highest first) | |
| const sortedClouds = [...cloudData].sort((a, b) => b.percentage - a.percentage); | |
| // Position clouds in a circular layout | |
| const centerX = containerWidth / 2; | |
| const centerY = containerHeight / 2; | |
| const radius = Math.min(containerWidth, containerHeight) * 0.35; | |
| sortedClouds.forEach((cloud, i) => { | |
| // Calculate angle for positioning | |
| const angle = (i / sortedClouds.length) * Math.PI * 2; | |
| // Calculate position with some randomness for a natural look | |
| const randomOffset = 30; | |
| const x = centerX + Math.cos(angle) * (radius + (Math.random() * randomOffset - randomOffset/2)); | |
| const y = centerY + Math.sin(angle) * (radius + (Math.random() * randomOffset - randomOffset/2)); | |
| // Create cloud with size based on percentage | |
| const baseSize = 40 + (cloud.percentage * 0.8); | |
| createCloud(cloud, x, y, baseSize); | |
| }); | |
| } | |
| function showResults(inputText, similarities) { | |
| resultsSection.classList.remove('hidden'); | |
| similarityResults.innerHTML = ''; | |
| const heading = document.createElement('h3'); | |
| heading.className = 'font-medium text-lg mb-2'; | |
| heading.textContent = `How "${inputText}" relates to our concepts:`; | |
| similarityResults.appendChild(heading); | |
| similarities.forEach(item => { | |
| const resultItem = document.createElement('div'); | |
| resultItem.className = 'flex items-center justify-between'; | |
| const textSpan = document.createElement('span'); | |
| textSpan.className = 'text-gray-700'; | |
| textSpan.textContent = item.text; | |
| const percentageBar = document.createElement('div'); | |
| percentageBar.className = 'flex items-center w-1/2'; | |
| const barContainer = document.createElement('div'); | |
| barContainer.className = 'flex-1 bg-gray-200 rounded-full h-4 mx-2'; | |
| const bar = document.createElement('div'); | |
| bar.className = 'bg-blue-500 h-4 rounded-full'; | |
| bar.style.width = `${item.percentage}%`; | |
| const percentageText = document.createElement('span'); | |
| percentageText.className = 'text-gray-600 w-12 text-right'; | |
| percentageText.textContent = `${item.percentage}%`; | |
| barContainer.appendChild(bar); | |
| percentageBar.appendChild(barContainer); | |
| percentageBar.appendChild(percentageText); | |
| resultItem.appendChild(textSpan); | |
| resultItem.appendChild(percentageBar); | |
| similarityResults.appendChild(resultItem); | |
| }); | |
| } | |
| // Helper function to calculate cosine similarity | |
| function cosineSimilarity(vecA, vecB) { | |
| let dotProduct = 0; | |
| let normA = 0; | |
| let normB = 0; | |
| for (let i = 0; i < vecA.length; i++) { | |
| dotProduct += vecA[i] * vecB[i]; | |
| normA += vecA[i] * vecA[i]; | |
| normB += vecB[i] * vecB[i]; | |
| } | |
| normA = Math.sqrt(normA); | |
| normB = Math.sqrt(normB); | |
| return dotProduct / (normA * normB); | |
| } | |
| // Handle window resize | |
| window.addEventListener('resize', () => { | |
| if (cloudData.some(c => c.percentage > 0)) { | |
| updateClouds(); | |
| } else { | |
| createClouds(); | |
| } | |
| }); | |
| }); | |