Soltane777's picture
Update frontend/script.js
68694e8 verified
// 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()
}
}