/** * ════════════════════════════════════════════════════════════════════════ * LinguaVerify AI v5.1 - COMPLETE PRODUCTION JAVASCRIPT * Frontend Logic • Text Visibility FIXED • All Features Working * Author: Your Name | Date: Oct 2025 | Version: 5.1 * ════════════════════════════════════════════════════════════════════════ */ // ════════════════════════════════════════════════════════════════════════ // GLOBAL STATE // ════════════════════════════════════════════════════════════════════════ let currentResult = null; // Language names mapping const LANGUAGE_NAMES = { 'en': 'English', 'es': 'Spanish', 'fr': 'French', 'de': 'German', 'hi': 'Hindi', 'ar': 'Arabic', 'zh': 'Chinese', 'ja': 'Japanese', 'ko': 'Korean', 'ru': 'Russian', 'pt': 'Portuguese', 'it': 'Italian', 'nl': 'Dutch', 'tr': 'Turkish', 'pl': 'Polish', 'th': 'Thai', 'vi': 'Vietnamese', 'id': 'Indonesian', 'ta': 'Tamil', 'te': 'Telugu', 'bn': 'Bengali', 'ur': 'Urdu', 'fa': 'Persian', 'he': 'Hebrew', 'mr': 'Marathi', 'gu': 'Gujarati', 'kn': 'Kannada', 'ml': 'Malayalam', 'pa': 'Punjabi', 'si': 'Sinhala', 'ne': 'Nepali', 'my': 'Burmese', 'km': 'Khmer', 'lo': 'Lao', 'am': 'Amharic', 'sw': 'Swahili', 'unknown': 'Unknown' }; // Example datasets const examples = { 1: { title_a: "Deep Learning for Medical Diagnosis", title_b: "चिकित्सा निदान के लिए डीप लर्निंग", domain: "medicine" }, 2: { title_a: "Climate Change Impact on Agriculture", title_b: "Impacto del Cambio Climático en la Agricultura", domain: "climate_change" }, 3: { title_a: "Artificial Intelligence Research and Development", title_b: "بحث وتطوير الذكاء الاصطناعي", domain: "artificial_intelligence" } }; // ════════════════════════════════════════════════════════════════════════ // INITIALIZATION // ════════════════════════════════════════════════════════════════════════ document.addEventListener('DOMContentLoaded', () => { console.log('%c🧠 LinguaVerify AI v5.1 - PRODUCTION READY', 'color: #a78bfa; font-size: 16px; font-weight: bold; background: #1a1f3a; padding: 10px; border-radius: 5px;'); console.log('%c✨ All Features Active', 'color: #10b981; font-size: 12px;'); initializeApp(); setupEventListeners(); checkSystemHealth(); fixInputVisibility(); console.log('%c⌨️ Keyboard Shortcuts:', 'color: #a78bfa; font-weight: bold;'); console.log(' Ctrl/Cmd + Enter: Verify titles'); console.log(' Esc: Clear results'); }); // ════════════════════════════════════════════════════════════════════════ // TEXT VISIBILITY FIX (CRITICAL) // ════════════════════════════════════════════════════════════════════════ function fixInputVisibility() { const inputs = document.querySelectorAll('.luxury-input, .luxury-select'); inputs.forEach(input => { // Set text color input.style.color = '#ffffff'; input.style.webkitTextFillColor = '#ffffff'; // Fix on input event input.addEventListener('input', function() { this.style.color = '#ffffff'; this.style.webkitTextFillColor = '#ffffff'; }); // Fix on focus input.addEventListener('focus', function() { this.style.color = '#ffffff'; this.style.webkitTextFillColor = '#ffffff'; }); // Fix on blur input.addEventListener('blur', function() { this.style.color = '#ffffff'; this.style.webkitTextFillColor = '#ffffff'; }); }); console.log('✅ Input visibility enforced'); } // ════════════════════════════════════════════════════════════════════════ // APP INITIALIZATION // ════════════════════════════════════════════════════════════════════════ function initializeApp() { const titleA = document.getElementById('title_a'); const titleB = document.getElementById('title_b'); if (titleA) { updateCharCount('title_a', 'char_count_a'); detectLanguageRealtime('title_a', 'detected_lang_a', 'lang_badge_a'); titleA.addEventListener('input', () => { updateCharCount('title_a', 'char_count_a'); detectLanguageRealtime('title_a', 'detected_lang_a', 'lang_badge_a'); }); } if (titleB) { updateCharCount('title_b', 'char_count_b'); detectLanguageRealtime('title_b', 'detected_lang_b', 'lang_badge_b'); titleB.addEventListener('input', () => { updateCharCount('title_b', 'char_count_b'); detectLanguageRealtime('title_b', 'detected_lang_b', 'lang_badge_b'); }); } } // ════════════════════════════════════════════════════════════════════════ // EVENT LISTENERS // ════════════════════════════════════════════════════════════════════════ function setupEventListeners() { // Keyboard shortcuts document.addEventListener('keydown', (e) => { // Ctrl/Cmd + Enter to verify if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { e.preventDefault(); verifyTitles(); } // Escape to clear results if (e.key === 'Escape') { const results = document.getElementById('results'); if (results && results.style.display !== 'none') { hideResults(); showNotification('Results cleared', 'info'); } } }); } // ════════════════════════════════════════════════════════════════════════ // CHARACTER COUNTING // ════════════════════════════════════════════════════════════════════════ function updateCharCount(textareaId, countId) { const textarea = document.getElementById(textareaId); const counter = document.getElementById(countId); if (textarea && counter) { const length = textarea.value.length; counter.textContent = `${length} char${length !== 1 ? 's' : ''}`; // Change color if too long if (length > 500) { counter.style.color = '#f59e0b'; } else { counter.style.color = 'rgba(255, 255, 255, 0.4)'; } } } // ════════════════════════════════════════════════════════════════════════ // REAL-TIME LANGUAGE DETECTION // ════════════════════════════════════════════════════════════════════════ let languageDetectionTimeouts = {}; function detectLanguageRealtime(textareaId, langSpanId, badgeId) { const textarea = document.getElementById(textareaId); const langSpan = document.getElementById(langSpanId); const badge = document.getElementById(badgeId); if (!textarea || !langSpan || !badge) return; const text = textarea.value.trim(); // Handle empty input if (!text) { langSpan.textContent = 'Waiting...'; badge.style.background = 'rgba(139, 92, 246, 0.15)'; badge.style.borderColor = 'rgba(139, 92, 246, 0.25)'; badge.style.color = '#a78bfa'; return; } // Show detecting state langSpan.textContent = 'Detecting...'; badge.style.background = 'rgba(59, 130, 246, 0.15)'; badge.style.borderColor = 'rgba(59, 130, 246, 0.25)'; badge.style.color = '#60a5fa'; // Clear previous timeout if (languageDetectionTimeouts[textareaId]) { clearTimeout(languageDetectionTimeouts[textareaId]); } // Debounce API call languageDetectionTimeouts[textareaId] = setTimeout(() => { fetch('/detect_language', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: text }) }) .then(response => response.json()) .then(data => { const langName = LANGUAGE_NAMES[data.language] || data.language.toUpperCase(); const confidence = Math.round(data.confidence * 100); langSpan.textContent = `${langName} (${confidence}%)`; badge.style.background = 'rgba(16, 185, 129, 0.15)'; badge.style.borderColor = 'rgba(16, 185, 129, 0.25)'; badge.style.color = '#34d399'; }) .catch(error => { console.error('Language detection error:', error); langSpan.textContent = 'Auto-detect'; badge.style.background = 'rgba(239, 68, 68, 0.15)'; badge.style.borderColor = 'rgba(239, 68, 68, 0.25)'; badge.style.color = '#f87171'; }); }, 500); // 500ms debounce } // ════════════════════════════════════════════════════════════════════════ // EXAMPLE LOADING // ════════════════════════════════════════════════════════════════════════ function loadExample(id) { const example = examples[id]; if (!example) { showNotification('Example not found', 'error'); return; } const titleA = document.getElementById('title_a'); const titleB = document.getElementById('title_b'); const domain = document.getElementById('domain'); if (titleA && titleB && domain) { // Set values titleA.value = example.title_a; titleB.value = example.title_b; domain.value = example.domain; // Force text visibility titleA.style.color = '#ffffff'; titleB.style.color = '#ffffff'; titleA.style.webkitTextFillColor = '#ffffff'; titleB.style.webkitTextFillColor = '#ffffff'; // Update UI updateCharCount('title_a', 'char_count_a'); updateCharCount('title_b', 'char_count_b'); detectLanguageRealtime('title_a', 'detected_lang_a', 'lang_badge_a'); detectLanguageRealtime('title_b', 'detected_lang_b', 'lang_badge_b'); // Auto-verify after 1 second setTimeout(() => verifyTitles(), 1000); showNotification('✅ Example loaded successfully', 'success'); } } // ════════════════════════════════════════════════════════════════════════ // MAIN VERIFICATION FUNCTION // ════════════════════════════════════════════════════════════════════════ async function verifyTitles() { const titleA = document.getElementById('title_a')?.value.trim(); const titleB = document.getElementById('title_b')?.value.trim(); const domain = document.getElementById('domain')?.value; const enableTranslation = document.getElementById('enable_translation')?.checked; // Validation if (!titleA || !titleB) { showNotification('⚠️ Please enter both titles', 'warning'); return; } // Set loading state setLoadingState(true); hideResults(); try { const response = await fetch('/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title_a: titleA, title_b: titleB, domain: domain, enable_translation: enableTranslation }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || `HTTP ${response.status}`); } const result = await response.json(); currentResult = result; // Display results with animation delay setTimeout(() => { displayResults(result, domain, enableTranslation); }, 300); showNotification('✅ Analysis complete', 'success'); } catch (error) { console.error('Verification error:', error); showNotification('❌ Error: ' + error.message, 'error'); } finally { setLoadingState(false); } } // ════════════════════════════════════════════════════════════════════════ // LOADING STATE MANAGEMENT // ════════════════════════════════════════════════════════════════════════ function setLoadingState(isLoading) { const btnContent = document.getElementById('btn-content'); const btnLoader = document.getElementById('btn-loader'); const button = document.querySelector('.btn-primary-gradient'); if (btnContent && btnLoader && button) { if (isLoading) { btnContent.style.display = 'none'; btnLoader.style.display = 'flex'; button.disabled = true; button.style.opacity = '0.7'; button.style.cursor = 'not-allowed'; } else { btnContent.style.display = 'flex'; btnLoader.style.display = 'none'; button.disabled = false; button.style.opacity = '1'; button.style.cursor = 'pointer'; } } } // ════════════════════════════════════════════════════════════════════════ // DISPLAY RESULTS // ════════════════════════════════════════════════════════════════════════ function displayResults(result, domain, translationEnabled) { const resultsPanel = document.getElementById('results'); if (!resultsPanel) return; // Show results panel resultsPanel.style.display = 'block'; // Smooth scroll to results setTimeout(() => { resultsPanel.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }, 100); // Update decision badge const badge = document.getElementById('decision-badge'); if (badge) { badge.textContent = result.label.replace('_', ' '); badge.className = 'decision-badge-luxury ' + (result.label === 'EQUIVALENT' ? 'equivalent' : 'not-equivalent'); } // Update translation panel const translationPanel = document.getElementById('translation-panel'); if (translationEnabled && result.translations && translationPanel) { translationPanel.style.display = 'block'; // Translation A const transA = result.translations.title_a; if (transA) { document.getElementById('trans_lang_a').textContent = (transA.src_lang || 'auto').toUpperCase(); document.getElementById('trans_original_a').textContent = transA.original_text; document.getElementById('trans_result_a').textContent = transA.translated_text; } // Translation B const transB = result.translations.title_b; if (transB) { document.getElementById('trans_lang_b').textContent = (transB.src_lang || 'auto').toUpperCase(); document.getElementById('trans_original_b').textContent = transB.original_text; document.getElementById('trans_result_b').textContent = transB.translated_text; } } else if (translationPanel) { translationPanel.style.display = 'none'; } // Animate metrics animateMetric('final-score', result.final_score, 3); animateMetric('embedding-score', result.embedding_score, 3); animateProgressBar('progress-final', result.final_score * 100); animateProgressBar('progress-embed', result.embedding_score * 100); // Translation score (if available) const translationScoreCard = document.getElementById('translation-score-card'); const translationScoreValue = document.getElementById('translation-score'); if (result.translation_score !== null && translationScoreCard && translationScoreValue) { translationScoreCard.style.display = 'block'; animateMetric('translation-score', result.translation_score, 3); animateProgressBar('progress-trans', result.translation_score * 100); } else if (translationScoreCard) { translationScoreCard.style.display = 'none'; } // Update other metrics document.getElementById('confidence').textContent = result.confidence; document.getElementById('processing-time').textContent = result.traces.total_time_ms + 'ms'; document.getElementById('method').textContent = (result.method || 'labse_only').replace(/_/g, ' ').toUpperCase(); // Language detection const langs = result.detected_languages; document.getElementById('lang_detect_a').textContent = LANGUAGE_NAMES[langs.title_a] || langs.title_a.toUpperCase(); document.getElementById('lang_detect_b').textContent = LANGUAGE_NAMES[langs.title_b] || langs.title_b.toUpperCase(); document.getElementById('lang_conf_a').textContent = Math.round(langs.confidence_a * 100) + '%'; document.getElementById('lang_conf_b').textContent = Math.round(langs.confidence_b * 100) + '%'; // Metadata const domainFormatted = domain.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()); document.getElementById('domain-display').textContent = domainFormatted; document.getElementById('threshold').textContent = result.adjusted_threshold.toFixed(3); } // ════════════════════════════════════════════════════════════════════════ // ANIMATED COUNTERS // ════════════════════════════════════════════════════════════════════════ function animateMetric(elementId, targetValue, decimals = 0) { const element = document.getElementById(elementId); if (!element) return; const duration = 1000; // 1 second const startValue = 0; const increment = (targetValue - startValue) / (duration / 16); let currentValue = startValue; const counter = setInterval(() => { currentValue += increment; if (currentValue >= targetValue) { currentValue = targetValue; clearInterval(counter); } element.textContent = currentValue.toFixed(decimals); }, 16); // ~60fps } function animateProgressBar(elementId, targetWidth) { const element = document.getElementById(elementId); if (!element) return; // Start from 0 element.style.width = '0%'; // Animate to target setTimeout(() => { element.style.width = Math.min(targetWidth, 100) + '%'; }, 100); } // ════════════════════════════════════════════════════════════════════════ // UTILITY FUNCTIONS // ════════════════════════════════════════════════════════════════════════ function hideResults() { const resultsPanel = document.getElementById('results'); if (resultsPanel) { resultsPanel.style.display = 'none'; } } function showNotification(message, type = 'info') { const notification = document.createElement('div'); notification.className = `notification notification-${type}`; notification.textContent = message; // Styling Object.assign(notification.style, { position: 'fixed', top: '100px', right: '20px', padding: '1rem 1.5rem', borderRadius: '12px', color: 'white', fontSize: '0.9rem', fontWeight: '500', zIndex: '10000', opacity: '0', transform: 'translateX(400px)', transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3)', backdropFilter: 'blur(10px)' }); // Type-specific colors if (type === 'success') { notification.style.background = 'linear-gradient(135deg, rgba(16, 185, 129, 0.9), rgba(5, 150, 105, 0.9))'; } else if (type === 'error') { notification.style.background = 'linear-gradient(135deg, rgba(239, 68, 68, 0.9), rgba(220, 38, 38, 0.9))'; } else if (type === 'warning') { notification.style.background = 'linear-gradient(135deg, rgba(245, 158, 11, 0.9), rgba(217, 119, 6, 0.9))'; } else { notification.style.background = 'linear-gradient(135deg, rgba(59, 130, 246, 0.9), rgba(37, 99, 235, 0.9))'; } document.body.appendChild(notification); // Slide in setTimeout(() => { notification.style.opacity = '1'; notification.style.transform = 'translateX(0)'; }, 10); // Slide out and remove setTimeout(() => { notification.style.opacity = '0'; notification.style.transform = 'translateX(400px)'; setTimeout(() => notification.remove(), 300); }, 3000); } // ════════════════════════════════════════════════════════════════════════ // SYSTEM HEALTH CHECK // ════════════════════════════════════════════════════════════════════════ async function checkSystemHealth() { try { const response = await fetch('/health'); const data = await response.json(); console.log('%c🟢 System Health:', 'color: #10b981; font-weight: bold;'); console.log(' Status:', data.status); console.log(' Version:', data.version); console.log(' Models:', data.models); console.log(' Cache:', data.cache_size); console.log(' Device:', data.device); } catch (error) { console.warn('%c⚠️ Could not fetch health status:', 'color: #f59e0b;', error); } } // ════════════════════════════════════════════════════════════════════════ // GLOBAL EXPORTS // ════════════════════════════════════════════════════════════════════════ window.verifyTitles = verifyTitles; window.loadExample = loadExample; window.hideResults = hideResults; // ════════════════════════════════════════════════════════════════════════ // CONSOLE BRANDING // ════════════════════════════════════════════════════════════════════════ console.log('%c━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'color: #a78bfa;'); console.log('%c🧠 LinguaVerify AI v5.1 - Production Ready', 'color: #10b981; font-size: 14px; font-weight: bold;'); console.log('%c200+ Languages • Dual-Path AI • Text Visibility Fixed ✅', 'color: #10b981; font-size: 11px;'); console.log('%c━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'color: #a78bfa;'); console.log('%cDeveloped with ❤️ by Your Name', 'color: #60a5fa; font-size: 10px;'); console.log('%c━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'color: #a78bfa;');