Spaces:
Sleeping
Sleeping
// Tab switching functionality | |
document.addEventListener("DOMContentLoaded", () => { | |
// Initialize theme | |
initTheme() | |
// Tab switching | |
const tabButtons = document.querySelectorAll(".tab-button") | |
const tabContents = document.querySelectorAll(".tab-content") | |
tabButtons.forEach((button) => { | |
button.addEventListener("click", () => { | |
// Remove active class from all buttons and hide all contents | |
tabButtons.forEach((btn) => btn.classList.remove("active")) | |
tabContents.forEach((content) => content.classList.add("hidden")) | |
// Add active class to clicked button and show corresponding content | |
button.classList.add("active") | |
const contentId = "content-" + button.id.split("-")[1] | |
document.getElementById(contentId).classList.remove("hidden") | |
// Save active tab to localStorage | |
localStorage.setItem("activeTab", button.id) | |
}) | |
}) | |
// Restore active tab from localStorage | |
const activeTab = localStorage.getItem("activeTab") | |
if (activeTab) { | |
document.getElementById(activeTab)?.click() | |
} | |
// File input handling | |
const fileInput = document.getElementById("fileInput") | |
const fileName = document.getElementById("fileName") | |
fileInput.addEventListener("change", () => { | |
if (fileInput.files.length > 0) { | |
fileName.textContent = fileInput.files[0].name | |
} else { | |
fileName.textContent = "No file chosen" | |
} | |
}) | |
// Copy output button | |
const copyButton = document.getElementById("copyOutput") | |
copyButton.addEventListener("click", () => { | |
const output = document.getElementById("output") | |
navigator.clipboard | |
.writeText(output.textContent) | |
.then(() => { | |
showNotification("Results copied successfully!") | |
}) | |
.catch((err) => { | |
console.error("Failed to copy text: ", err) | |
showNotification("Failed to copy text: " + err.message, "error") | |
}) | |
}) | |
// Translation options toggle | |
const translateBtn = document.getElementById("translateBtn") | |
const translationOptions = document.getElementById("translationOptions") | |
translateBtn.addEventListener("click", () => { | |
// Toggle translation options visibility | |
if (translationOptions.classList.contains("hidden")) { | |
translationOptions.classList.remove("hidden") | |
} else { | |
// If options are already visible, perform translation | |
translateText() | |
} | |
}) | |
// Theme toggle | |
const themeToggle = document.getElementById("theme-toggle") | |
themeToggle.addEventListener("click", toggleTheme) | |
// Add download results button | |
const outputContainer = document.querySelector(".bg-gray-100.dark\\:bg-gray-700.p-4.rounded-xl") | |
const downloadButton = document.createElement("button") | |
downloadButton.id = "downloadOutput" | |
downloadButton.className = | |
"text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 flex items-center ml-4 transition-colors duration-200" | |
downloadButton.innerHTML = ` | |
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" /> | |
</svg> | |
Download | |
` | |
downloadButton.addEventListener("click", downloadResults) | |
// Add the download button next to the copy button | |
const resultHeader = outputContainer.querySelector(".flex.justify-between.items-center.mb-2") | |
resultHeader.appendChild(downloadButton) | |
// Initialize history panel | |
initHistoryPanel() | |
// Make sure theme toggle is properly initialized | |
const themeToggleBtn = document.getElementById("theme-toggle") | |
if (themeToggleBtn) { | |
themeToggleBtn.addEventListener("click", toggleTheme) | |
console.log("Theme toggle button initialized") | |
} else { | |
console.error("Theme toggle button not found") | |
} | |
// Initialize theme immediately | |
initTheme() | |
console.log("Theme initialized:", document.documentElement.classList.contains("dark") ? "dark" : "light") | |
}) | |
// Theme functions | |
function initTheme() { | |
// Check if user preference exists in localStorage | |
const savedTheme = localStorage.getItem("theme") | |
if (savedTheme === "dark" || (!savedTheme && window.matchMedia("(prefers-color-scheme: dark)").matches)) { | |
// Set dark mode | |
document.documentElement.classList.add("dark") | |
document.getElementById("sun-icon")?.classList.remove("hidden") | |
document.getElementById("moon-icon")?.classList.add("hidden") | |
} else { | |
// Set light mode | |
document.documentElement.classList.remove("dark") | |
document.getElementById("sun-icon")?.classList.add("hidden") | |
document.getElementById("moon-icon")?.classList.remove("hidden") | |
} | |
} | |
function toggleTheme() { | |
// Toggle the dark class on the html element | |
document.documentElement.classList.toggle("dark") | |
// Update the icons | |
const sunIcon = document.getElementById("sun-icon") | |
const moonIcon = document.getElementById("moon-icon") | |
if (sunIcon && moonIcon) { | |
if (document.documentElement.classList.contains("dark")) { | |
// Dark mode is active | |
sunIcon.classList.remove("hidden") | |
moonIcon.classList.add("hidden") | |
localStorage.setItem("theme", "dark") | |
showNotification("Dark mode activated") | |
} else { | |
// Light mode is active | |
sunIcon.classList.add("hidden") | |
moonIcon.classList.remove("hidden") | |
localStorage.setItem("theme", "light") | |
showNotification("Light mode activated") | |
} | |
} | |
} | |
// Show notification function | |
function showNotification(message, type = "success") { | |
// Create notification element | |
const notification = document.createElement("div") | |
// Set class based on notification type | |
if (type === "success") { | |
notification.className = | |
"notification fixed top-4 right-4 bg-green-100 border-l-4 border-green-500 text-green-700 p-4 rounded shadow-md dark:bg-green-900 dark:text-green-100 dark:border-green-400" | |
} else if (type === "error") { | |
notification.className = | |
"notification fixed top-4 right-4 bg-red-100 border-l-4 border-red-500 text-red-700 p-4 rounded shadow-md dark:bg-red-900 dark:text-red-100 dark:border-red-400" | |
} else if (type === "warning") { | |
notification.className = | |
"notification fixed top-4 right-4 bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 rounded shadow-md dark:bg-yellow-900 dark:text-yellow-100 dark:border-yellow-400" | |
} else if (type === "info") { | |
notification.className = | |
"notification fixed top-4 right-4 bg-blue-100 border-l-4 border-blue-500 text-blue-700 p-4 rounded shadow-md dark:bg-blue-900 dark:text-blue-100 dark:border-blue-400" | |
} | |
notification.innerHTML = message | |
// Add to document | |
document.body.appendChild(notification) | |
// Remove after 3 seconds | |
setTimeout(() => { | |
notification.style.opacity = "0" | |
notification.style.transform = "translateY(-20px)" | |
notification.style.transition = "opacity 0.5s, transform 0.5s" | |
setTimeout(() => { | |
notification.remove() | |
}, 500) | |
}, 3000) | |
} | |
// Show/hide loader | |
function toggleLoader(show) { | |
const loader = document.getElementById("loader") | |
if (show) { | |
loader.classList.remove("hidden") | |
} else { | |
loader.classList.add("hidden") | |
} | |
} | |
// Download results function | |
function downloadResults() { | |
const output = document.getElementById("output") | |
const content = output.textContent || output.innerText | |
if (!content || content.trim() === "") { | |
showNotification("No content to download", "warning") | |
return | |
} | |
// Create a blob with the content | |
const blob = new Blob([content], { type: "text/plain" }) | |
const url = URL.createObjectURL(blob) | |
// Create a temporary link and trigger download | |
const a = document.createElement("a") | |
a.href = url | |
a.download = "ai-results-" + new Date().toISOString().slice(0, 10) + ".txt" | |
document.body.appendChild(a) | |
a.click() | |
// Clean up | |
setTimeout(() => { | |
document.body.removeChild(a) | |
URL.revokeObjectURL(url) | |
}, 100) | |
showNotification("Results downloaded successfully!") | |
// Add to history | |
addToHistory("Downloaded results", content.substring(0, 50) + (content.length > 50 ? "..." : "")) | |
} | |
// History management | |
function initHistoryPanel() { | |
// Create history panel | |
const historyPanel = document.createElement("div") | |
historyPanel.id = "historyPanel" | |
historyPanel.className = | |
"fixed right-0 top-0 h-full w-80 bg-white dark:bg-gray-800 shadow-lg transform translate-x-full transition-transform duration-300 ease-in-out z-50 overflow-y-auto" | |
// Add history header | |
historyPanel.innerHTML = ` | |
<div class="p-4 bg-purple-600 text-white"> | |
<div class="flex justify-between items-center"> | |
<h3 class="text-lg font-semibold">History</h3> | |
<button id="closeHistory" class="text-white hover:text-purple-200"> | |
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> | |
</svg> | |
</button> | |
</div> | |
</div> | |
<div id="historyItems" class="p-4 space-y-3"></div> | |
` | |
document.body.appendChild(historyPanel) | |
// Add history button to the header | |
const header = document.querySelector(".bg-gradient-to-r.from-purple-600.to-indigo-600.p-6.relative") | |
const historyButton = document.createElement("button") | |
historyButton.id = "historyButton" | |
historyButton.className = "absolute left-6 top-6 p-2 rounded-full bg-white/20 hover:bg-white/30 transition-colors" | |
historyButton.innerHTML = ` | |
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" /> | |
</svg> | |
` | |
header.appendChild(historyButton) | |
// Add event listeners | |
document.getElementById("historyButton").addEventListener("click", toggleHistoryPanel) | |
document.getElementById("closeHistory").addEventListener("click", toggleHistoryPanel) | |
// Load history from localStorage | |
loadHistory() | |
} | |
function toggleHistoryPanel() { | |
const historyPanel = document.getElementById("historyPanel") | |
if (historyPanel.classList.contains("translate-x-full")) { | |
historyPanel.classList.remove("translate-x-full") | |
} else { | |
historyPanel.classList.add("translate-x-full") | |
} | |
} | |
function addToHistory(action, details) { | |
// Get existing history or initialize empty array | |
const history = JSON.parse(localStorage.getItem("aiAppHistory") || "[]") | |
// Add new item | |
history.unshift({ | |
action, | |
details, | |
timestamp: new Date().toISOString(), | |
}) | |
// Keep only the last 20 items | |
if (history.length > 20) { | |
history.pop() | |
} | |
// Save back to localStorage | |
localStorage.setItem("aiAppHistory", JSON.stringify(history)) | |
// Update UI if history panel exists | |
loadHistory() | |
} | |
function loadHistory() { | |
const historyItemsContainer = document.getElementById("historyItems") | |
if (!historyItemsContainer) return | |
// Clear existing items | |
historyItemsContainer.innerHTML = "" | |
// Get history from localStorage | |
const history = JSON.parse(localStorage.getItem("aiAppHistory") || "[]") | |
if (history.length === 0) { | |
historyItemsContainer.innerHTML = `<p class="text-gray-500 dark:text-gray-400 text-center">No history yet</p>` | |
return | |
} | |
// Add each history item | |
history.forEach((item, index) => { | |
const historyItem = document.createElement("div") | |
historyItem.className = "bg-gray-100 dark:bg-gray-700 p-3 rounded-lg" | |
const date = new Date(item.timestamp) | |
const formattedDate = date.toLocaleDateString() + " " + date.toLocaleTimeString() | |
historyItem.innerHTML = ` | |
<div class="flex justify-between items-start"> | |
<h4 class="font-medium text-gray-800 dark:text-gray-200">${item.action}</h4> | |
<span class="text-xs text-gray-500 dark:text-gray-400">${formattedDate}</span> | |
</div> | |
<p class="text-sm text-gray-600 dark:text-gray-300 mt-1">${item.details}</p> | |
` | |
historyItemsContainer.appendChild(historyItem) | |
}) | |
} | |
// Format the output based on the type of result | |
function formatOutput(data, type) { | |
const outputElement = document.getElementById("output") | |
outputElement.innerHTML = "" // Clear previous content | |
// Create a container for formatted output | |
const container = document.createElement("div") | |
container.className = "formatted-output" | |
switch (type) { | |
case "translation": | |
// Get language names | |
const sourceLang = getLanguageName(document.getElementById("sourceLanguage").value) | |
const targetLang = getLanguageName(document.getElementById("targetLanguage").value) | |
// Create translation result elements | |
const header = document.createElement("div") | |
header.className = "result-header" | |
header.innerHTML = `<h3>Translation Result</h3>` | |
const originalBox = document.createElement("div") | |
originalBox.className = "text-box original" | |
originalBox.innerHTML = ` | |
<div class="text-box-header">${sourceLang}</div> | |
<div class="text-content">${document.getElementById("textInput").value}</div> | |
` | |
const translatedBox = document.createElement("div") | |
translatedBox.className = "text-box translated" | |
// Add text-to-speech button for translated text | |
const translatedText = data.translation || data.result || data.text || JSON.stringify(data) | |
translatedBox.innerHTML = ` | |
<div class="text-box-header flex justify-between items-center"> | |
<span>${targetLang}</span> | |
<button class="text-to-speech-btn p-1 rounded hover:bg-gray-200 dark:hover:bg-gray-600" title="Listen to text"> | |
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 12.728M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z" /> | |
</svg> | |
</button> | |
</div> | |
<div class="text-content">${translatedText}</div> | |
` | |
container.appendChild(header) | |
container.appendChild(originalBox) | |
container.appendChild(translatedBox) | |
// Add event listener for text-to-speech | |
setTimeout(() => { | |
const ttsBtn = container.querySelector(".text-to-speech-btn") | |
if (ttsBtn) { | |
ttsBtn.addEventListener("click", () => { | |
speakText(translatedText, document.getElementById("targetLanguage").value) | |
}) | |
} | |
}, 0) | |
// Add to history | |
addToHistory("Translation", `${sourceLang} to ${targetLang}`) | |
break | |
case "summarize": | |
const summaryHeader = document.createElement("div") | |
summaryHeader.className = "result-header" | |
summaryHeader.innerHTML = `<h3>Summary</h3>` | |
const summaryContent = document.createElement("div") | |
summaryContent.className = "text-box summary" | |
summaryContent.innerHTML = ` | |
<div class="text-content">${data.summary || data.result || data.text || JSON.stringify(data)}</div> | |
` | |
container.appendChild(summaryHeader) | |
container.appendChild(summaryContent) | |
// Add to history | |
addToHistory("Summarization", "Text summarized") | |
break | |
case "qa": | |
const qaHeader = document.createElement("div") | |
qaHeader.className = "result-header" | |
qaHeader.innerHTML = `<h3>Answer</h3>` | |
const questionBox = document.createElement("div") | |
questionBox.className = "text-box question" | |
questionBox.innerHTML = ` | |
<div class="text-box-header">Question</div> | |
<div class="text-content">${document.getElementById("questionInput").value}</div> | |
` | |
const answerBox = document.createElement("div") | |
answerBox.className = "text-box answer" | |
answerBox.innerHTML = ` | |
<div class="text-box-header">Answer</div> | |
<div class="text-content">${data.answer || data.result || JSON.stringify(data)}</div> | |
` | |
container.appendChild(qaHeader) | |
container.appendChild(questionBox) | |
container.appendChild(answerBox) | |
// Add to history | |
addToHistory("Question Answered", document.getElementById("questionInput").value) | |
break | |
case "code": | |
const codeHeader = document.createElement("div") | |
codeHeader.className = "result-header" | |
codeHeader.innerHTML = `<h3>Generated Code</h3>` | |
const codeBox = document.createElement("div") | |
codeBox.className = "text-box code" | |
// Format code with syntax highlighting if possible | |
const codeContent = document.createElement("pre") | |
codeContent.className = "code-content" | |
codeContent.textContent = data.code || data.result || JSON.stringify(data, null, 2) | |
codeBox.appendChild(codeContent) | |
container.appendChild(codeHeader) | |
container.appendChild(codeBox) | |
// Add to history | |
addToHistory("Code Generation", document.getElementById("codeInput").value.substring(0, 50) + "...") | |
break | |
case "extract_text": | |
const extractHeader = document.createElement("div") | |
extractHeader.className = "result-header" | |
extractHeader.innerHTML = `<h3>Extracted Text</h3>` | |
const extractBox = document.createElement("div") | |
extractBox.className = "text-box extracted" | |
extractBox.innerHTML = ` | |
<div class="text-content">${data.text || data.result || JSON.stringify(data)}</div> | |
` | |
container.appendChild(extractHeader) | |
container.appendChild(extractBox) | |
// Add to history | |
addToHistory("Text Extraction", "Extracted from file") | |
break | |
case "image_caption": | |
const captionHeader = document.createElement("div") | |
captionHeader.className = "result-header" | |
captionHeader.innerHTML = `<h3>Image Analysis</h3>` | |
const captionBox = document.createElement("div") | |
captionBox.className = "text-box caption" | |
captionBox.innerHTML = ` | |
<div class="text-content">${data.caption || data.result || JSON.stringify(data)}</div> | |
` | |
container.appendChild(captionHeader) | |
container.appendChild(captionBox) | |
// Add to history | |
addToHistory("Image Analysis", "Image analyzed") | |
break | |
default: | |
// Fallback to JSON display for unknown types | |
container.innerHTML = `<pre>${JSON.stringify(data, null, 2)}</pre>` | |
} | |
outputElement.appendChild(container) | |
} | |
// Text-to-speech function | |
function speakText(text, langCode) { | |
if (!text) return | |
// Stop any ongoing speech | |
window.speechSynthesis.cancel() | |
// Create utterance | |
const utterance = new SpeechSynthesisUtterance(text) | |
// Map language codes to BCP 47 language tags | |
const langMap = { | |
ar: "ar-SA", | |
en: "en-US", | |
fr: "fr-FR", | |
es: "es-ES", | |
zh: "zh-CN", | |
} | |
// Set language | |
utterance.lang = langMap[langCode] || "en-US" | |
// Get available voices | |
const voices = window.speechSynthesis.getVoices() | |
// Try to find a voice for the selected language | |
const voice = voices.find((v) => v.lang.startsWith(langMap[langCode]?.split("-")[0] || "en")) | |
if (voice) { | |
utterance.voice = voice | |
} | |
// Speak | |
window.speechSynthesis.speak(utterance) | |
// Show notification | |
showNotification("Playing audio...", "info") | |
} | |
// Helper function to get language name from code | |
function getLanguageName(code) { | |
const languages = { | |
ar: "Arabic", | |
en: "English", | |
fr: "French", | |
es: "Spanish", | |
zh: "Chinese", | |
} | |
return languages[code] || code | |
} | |
// API Functions | |
async function uploadFile(endpoint) { | |
const fileInput = document.getElementById("fileInput") | |
const file = fileInput.files[0] | |
if (!file) { | |
showNotification("Please select a file first.", "warning") | |
return | |
} | |
toggleLoader(true) | |
const formData = new FormData() | |
formData.append("file", file) | |
try { | |
const response = await fetch(`https://soltane777-textgeneration.hf.space/${endpoint}`, { | |
method: "POST", | |
body: formData, | |
}) | |
if (!response.ok) { | |
throw new Error(`Server responded with status: ${response.status}`) | |
} | |
const data = await response.json() | |
formatOutput(data, endpoint) | |
} catch (error) { | |
console.error("Error:", error) | |
document.getElementById("output").innerHTML = | |
`<div class="error-message">Error: ${error.message || "Failed to fetch data"}</div>` | |
showNotification("Error processing file: " + (error.message || "Unknown error"), "error") | |
} finally { | |
toggleLoader(false) | |
} | |
} | |
async function processText(endpoint) { | |
// If endpoint is translate, we now handle it separately | |
if (endpoint === "translate") { | |
// Show translation options if they're hidden | |
if (document.getElementById("translationOptions").classList.contains("hidden")) { | |
document.getElementById("translationOptions").classList.remove("hidden") | |
return | |
} | |
return translateText() | |
} | |
const text = document.getElementById("textInput").value | |
if (!text) { | |
showNotification("Please enter text first.", "warning") | |
return | |
} | |
toggleLoader(true) | |
const formData = new FormData() | |
formData.append("text", text) | |
try { | |
const response = await fetch(`https://soltane777-textgeneration.hf.space/${endpoint}`, { | |
method: "POST", | |
body: formData, | |
}) | |
if (!response.ok) { | |
throw new Error(`Server responded with status: ${response.status}`) | |
} | |
const data = await response.json() | |
formatOutput(data, endpoint) | |
} catch (error) { | |
console.error("Error:", error) | |
document.getElementById("output").innerHTML = | |
`<div class="error-message">Error: ${error.message || "Failed to fetch data"}</div>` | |
showNotification("Error processing text: " + (error.message || "Unknown error"), "error") | |
} finally { | |
toggleLoader(false) | |
} | |
} | |
async function translateText() { | |
const text = document.getElementById("textInput").value | |
const sourceLanguage = document.getElementById("sourceLanguage").value | |
const targetLanguage = document.getElementById("targetLanguage").value | |
if (!text) { | |
showNotification("Please enter text to translate.", "warning") | |
return | |
} | |
toggleLoader(true) | |
const formData = new FormData() | |
formData.append("text", text) | |
formData.append("source_lang", sourceLanguage) | |
formData.append("target_lang", targetLanguage) | |
try { | |
const response = await fetch("https://soltane777-textgeneration.hf.space/translate", { | |
method: "POST", | |
body: formData, | |
}) | |
if (!response.ok) { | |
throw new Error(`Server responded with status: ${response.status}`) | |
} | |
const data = await response.json() | |
formatOutput(data, "translation") | |
} catch (error) { | |
console.error("Error:", error) | |
document.getElementById("output").innerHTML = | |
`<div class="error-message">Error: ${error.message || "Failed to fetch translation data"}</div>` | |
showNotification("Error translating text: " + (error.message || "Unknown error"), "error") | |
} finally { | |
toggleLoader(false) | |
} | |
} | |
async function askQuestion() { | |
const context = document.getElementById("contextInput").value | |
const question = document.getElementById("questionInput").value | |
if (!context || !question) { | |
showNotification("Please enter both reference text and question.", "warning") | |
return | |
} | |
toggleLoader(true) | |
try { | |
const response = await fetch("https://soltane777-textgeneration.hf.space/qa/", { | |
method: "POST", | |
headers: { "Content-Type": "application/json" }, | |
body: JSON.stringify({ context: context, question: question }), | |
}) | |
if (!response.ok) { | |
throw new Error(`Server responded with status: ${response.status}`) | |
} | |
const data = await response.json() | |
formatOutput(data, "qa") | |
} catch (error) { | |
console.error("Error:", error) | |
document.getElementById("output").innerHTML = | |
`<div class="error-message">Error: ${error.message || "Failed to fetch data"}</div>` | |
showNotification("Error getting answer: " + (error.message || "Unknown error"), "error") | |
} finally { | |
toggleLoader(false) | |
} | |
} | |
async function generateCode() { | |
const prompt = document.getElementById("codeInput").value | |
if (!prompt) { | |
showNotification("Please enter a description for the code.", "warning") | |
return | |
} | |
toggleLoader(true) | |
const formData = new FormData() | |
formData.append("prompt", prompt) | |
try { | |
const response = await fetch("https://soltane777-textgeneration.hf.space/generate_code/", { | |
method: "POST", | |
body: formData, | |
}) | |
if (!response.ok) { | |
throw new Error(`Server responded with status: ${response.status}`) | |
} | |
const data = await response.json() | |
formatOutput(data, "code") | |
} catch (error) { | |
console.error("Error:", error) | |
document.getElementById("output").innerHTML = | |
`<div class="error-message">Error: ${error.message || "Failed to fetch data"}</div>` | |
showNotification("Error generating code: " + (error.message || "Unknown error"), "error") | |
} finally { | |
toggleLoader(false) | |
} | |
} | |
// Initialize speech synthesis voices | |
if ("speechSynthesis" in window) { | |
// Load voices | |
speechSynthesis.onvoiceschanged = () => { | |
speechSynthesis.getVoices() | |
} | |
} | |