// Elementi DOM const inputText = document.getElementById('inputText'); const outputText = document.getElementById('outputText'); const translateBtn = document.getElementById('translateBtn'); const detectedLang = document.getElementById('detectedLang'); const clearBtn = document.getElementById('clearBtn'); const copyBtn = document.getElementById('copyBtn'); const charCount = document.getElementById('charCount'); const statusIndicator = document.getElementById('statusIndicator'); const settingsBtn = document.getElementById('settingsBtn'); const settingsModal = document.getElementById('settingsModal'); const closeModal = document.getElementById('closeModal'); const baseUrlInput = document.getElementById('baseUrl'); const modelSelect = document.getElementById('modelSelect'); const refreshModels = document.getElementById('refreshModels'); const saveSettings = document.getElementById('saveSettings'); const toast = document.getElementById('toast'); // Stato applicazione let isTranslating = false; let currentDetectedLang = null; // Carica impostazioni salvate function loadSettings() { const savedBaseUrl = localStorage.getItem('ollamaBaseUrl') || 'http://localhost:11434'; const savedModel = localStorage.getItem('ollamaModel') || ''; baseUrlInput.value = savedBaseUrl; if (savedModel) { const existingOption = Array.from(modelSelect.options).find(opt => opt.value === savedModel); if (!existingOption) { const option = document.createElement('option'); option.value = savedModel; option.textContent = savedModel; modelSelect.appendChild(option); } modelSelect.value = savedModel; } } // Salva impostazioni function saveSettingsData() { const baseUrl = baseUrlInput.value.trim() || 'http://localhost:11434'; const model = modelSelect.value; localStorage.setItem('ollamaBaseUrl', baseUrl); localStorage.setItem('ollamaModel', model); closeSettingsModal(); showToast('Impostazioni salvate!'); } // Carica modelli disponibili async function loadAvailableModels() { const baseUrl = baseUrlInput.value.trim() || 'http://localhost:11434'; console.log('DEBUG - Tentativo di caricare modelli da:', baseUrl); console.log('DEBUG - electronAPI disponibile?', !!window.electronAPI); console.log('DEBUG - getModels funzione?', typeof window.electronAPI?.getModels); refreshModels.disabled = true; refreshModels.innerHTML = ` Caricamento... `; try { const cleanBaseUrl = baseUrl.trim(); console.log('Tentativo connessione a:', cleanBaseUrl); const result = await window.electronAPI.getModels(cleanBaseUrl); if (result.success) { modelSelect.innerHTML = ''; result.models.forEach(model => { const option = document.createElement('option'); option.value = model.name; option.textContent = model.name; modelSelect.appendChild(option); }); const savedModel = localStorage.getItem('ollamaModel'); if (savedModel && result.models.find(m => m.name === savedModel)) { modelSelect.value = savedModel; } showToast(`${result.models.length} modelli trovati!`); } else { showToast('Errore: ' + result.error, 'error'); } } catch (error) { console.error('Errore completo:', error); showToast('Errore di connessione: ' + (error.message || 'Verifica che Ollama sia in esecuzione'), 'error'); } finally { refreshModels.disabled = false; refreshModels.innerHTML = ` Aggiorna `; } } // Rileva la lingua del testo function detectLanguage(text) { if (!text.trim()) { currentDetectedLang = null; detectedLang.textContent = 'Rilevamento automatico...'; detectedLang.className = ''; return null; } // Caratteri italiani comuni const italianChars = /[àèéìòùÀÈÉÌÒÙ]/; const italianWords = /\b(ciao|grazie|buongiorno|come|sono|per|con|su|tra|fra|nel|del|degli|della)\b/gi; // Caratteri inglesi comuni (rari in italiano) const englishChars = /[wkyjWQX]/; const englishWords = /\b(the|and|for|are|with|you|that|have|this|from|they|we|say|her|she|or|an|will|my|one|all|would|there|their|what|so|up|out|if|about|who|get|which|go|me|when|make|can|like|time|no|just|him|know|take|people|into|year|your|good|some|could|them|see|other|than|then|now|look|only|come|its|over|think|also|back|after|use|two|how|our|work|first|well|way|even|new|want|because|any|these|give|day|most|us)\b/gi; const hasItalianChars = italianChars.test(text); const hasItalianWords = (text.match(italianWords) || []).length; const hasEnglishChars = englishChars.test(text); const hasEnglishWords = (text.match(englishWords) || []).length; // Logica di rilevamento let detected = null; if (hasItalianChars) { detected = 'it'; } else if (hasEnglishChars && !hasItalianWords) { detected = 'en'; } else if (hasItalianWords > hasEnglishWords) { detected = 'it'; } else if (hasEnglishWords > italianWords) { detected = 'en'; } else { // Fallback: verifica la distribuzione delle vocali const vowels = text.toLowerCase().match(/[aeiou]/g) || []; const yCount = (text.match(/y/gi) || []).length; if (yCount > 0) { detected = 'en'; } else { detected = 'it'; // default } } currentDetectedLang = detected; updateLanguageIndicator(); return detected; } // Aggiorna l'indicatore di lingua function updateLanguageIndicator() { if (currentDetectedLang === 'it') { detectedLang.innerHTML = '🇮🇹 Italiano → 🇬🇧 Inglese'; detectedLang.className = 'detected-it'; } else if (currentDetectedLang === 'en') { detectedLang.innerHTML = '🇬🇧 Inglese → 🇮🇹 Italiano'; detectedLang.className = 'detected-en'; } else { detectedLang.textContent = 'Rilevamento automatico...'; detectedLang.className = ''; } } // Traduci testo async function translateText() { const text = inputText.value.trim(); if (!text) { showToast('Inserisci del testo da tradurre', 'warning'); return; } const baseUrl = localStorage.getItem('ollamaBaseUrl') || 'http://localhost:11434'; const model = localStorage.getItem('ollamaModel'); if (!model) { showToast('Configura un modello nelle impostazioni', 'warning'); openSettingsModal(); return; } // Rileva la lingua se non già rilevata const detected = currentDetectedLang || detectLanguage(text); if (!detected) { showToast('Impossibile rilevare la lingua', 'warning'); return; } const direction = detected === 'en' ? 'en-it' : 'it-en'; isTranslating = true; translateBtn.disabled = true; translateBtn.innerHTML = ` Traduzione... `; statusIndicator.className = 'status-indicator translating'; try { const result = await window.electronAPI.translateText({ text, direction, model, baseUrl }); if (result.success) { outputText.value = result.translation.trim(); statusIndicator.className = 'status-indicator success'; showToast('Traduzione completata!', 'success'); } else { outputText.value = ''; statusIndicator.className = 'status-indicator error'; showToast('Errore: ' + result.error, 'error'); } } catch (error) { outputText.value = ''; statusIndicator.className = 'status-indicator error'; showToast('Errore: ' + error.message, 'error'); } finally { isTranslating = false; translateBtn.disabled = false; translateBtn.innerHTML = ` Traduci `; } } // Aggiorna conteggio caratteri function updateCharCount() { const count = inputText.value.length; charCount.textContent = `${count} caratter${count === 1 ? 'e' : 'i'}`; } // Copia negli appunti async function copyToClipboard() { const text = outputText.value; if (!text) return; try { await navigator.clipboard.writeText(text); showToast('Testo copiato!', 'success'); } catch (err) { outputText.select(); document.execCommand('copy'); showToast('Testo copiato!', 'success'); } } // Pulisci input function clearInput() { inputText.value = ''; outputText.value = ''; updateCharCount(); statusIndicator.className = 'status-indicator'; currentDetectedLang = null; detectedLang.textContent = 'Rilevamento automatico...'; detectedLang.className = ''; inputText.focus(); } // Mostra toast function showToast(message, type = 'info') { toast.textContent = message; toast.className = `toast show ${type}`; setTimeout(() => { toast.classList.remove('show'); }, 3000); } // Gestione modale function openSettingsModal() { settingsModal.classList.add('show'); loadAvailableModels(); } function closeSettingsModal() { settingsModal.classList.remove('show'); } // Event Listeners translateBtn.addEventListener('click', translateText); inputText.addEventListener('input', () => { updateCharCount(); detectLanguage(inputText.value); }); clearBtn.addEventListener('click', clearInput); copyBtn.addEventListener('click', copyToClipboard); settingsBtn.addEventListener('click', openSettingsModal); closeModal.addEventListener('click', closeSettingsModal); refreshModels.addEventListener('click', loadAvailableModels); saveSettings.addEventListener('click', saveSettingsData); // Chiudi modale con ESC settingsModal.addEventListener('click', (e) => { if (e.target === settingsModal) { closeSettingsModal(); } }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { closeSettingsModal(); } if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { translateText(); } }); // Ascolta richiesta apertura impostazioni dal menu window.electronAPI.onOpenSettings((event) => { openSettingsModal(); }); // Inizializzazione document.addEventListener('DOMContentLoaded', () => { loadSettings(); updateCharCount(); });