// Set up DOM references const generateBtn = document.getElementById("generate-btn"); const promptInput = document.getElementById("prompt-input"); const responseOutput = document.getElementById("response-output"); const statusMessageContainer = document.getElementById("status-message"); const workerPath = './worker.js'; let worker; let modelReady = false; // Handle the click-to-copy event for an emoji translation result function handleEmojiButtonClick(result) { navigator.clipboard.writeText(result); statusMessageContainer.textContent = `Copied to clipboard: ${result}`; console.log(`[UI] Copied "${result}" to clipboard.`); } // Create and append a button for an emoji translation result function createEmojiButton(result) { const button = document.createElement("button"); button.textContent = result; button.onclick = () => handleEmojiButtonClick(result); responseOutput.appendChild(button); } // Check for WebGPU availability and displays an error message if it's not available function checkWebGPU() { if (!navigator.gpu) { statusMessageContainer.innerHTML = ` This application requires WebGPU to run the model in your browser. Please update your browser to enable WebGPU support, try a different browser (like Chrome or Edge, version 113+), or ensure your GPU drivers are up to date.

For more details, read the WebGPU Implementation Status. `; generateBtn.disabled = true; return false; } return true; } // Main function to run worker async function initializeModelInWorker() { console.log("[UI] Initializing application..."); // Create a simulated progress loader that clears once the model loads if (!checkWebGPU()) { return; } let loadingInterval; let progress = 0; statusMessageContainer.textContent = "Loading model (0%)"; loadingInterval = setInterval(() => { if (progress < 99) { progress++; } statusMessageContainer.textContent = `Loading model (${progress}%)`; }, 70); // Create a new worker to run the model in a separate thread worker = new Worker(workerPath); console.log("[UI] Worker created."); // Listen for messages from the worker worker.onmessage = (event) => { const { type, data } = event.data; console.log("[UI] Received message from worker:", { type, data }); switch (type) { case "loaded": clearInterval(loadingInterval); // Stop the fake loader statusMessageContainer.textContent = `Loading model (100%)`; // Show 100% briefly modelReady = true; generateBtn.disabled = false; // Enable the generation button upon model load setTimeout(() => { statusMessageContainer.innerHTML = ``; // Then empty status message }, 500); break; case "result": const line = data.trim(); if (line) { createEmojiButton(line); } break; case "complete": responseComplete(); break; case "error": clearInterval(loadingInterval); console.error("Worker error:", data); if (modelReady) { // Error during generation generateBtn.classList.remove('generating'); statusMessageContainer.textContent = "Failed to generate response. Check the console for errors."; generateBtn.disabled = false; // Re-enable button } else { // Error during model loading statusMessageContainer.textContent = "Failed to load model. Please refresh the page."; } break; } }; // Start loading the model in the worker console.log('[UI] Sending "load" message to worker.'); worker.postMessage({ type: "load" }); } function responseComplete() { generateBtn.classList.remove('generating'); generateBtn.disabled = false; if (responseOutput.childElementCount === 0) { statusMessageContainer.textContent = "No results"; } else { // Clear the status message if we have results statusMessageContainer.textContent = "Click to copy emojis"; // For accessibility, move focus to the first result so keyboard users can navigate them. responseOutput.firstChild.focus(); } } function resetUI() { console.log("[UI] Resetting UI state."); generateBtn.classList.add('generating'); generateBtn.disabled = true; responseOutput.innerHTML = ""; // Clear previous buttons statusMessageContainer.textContent = "Generating..."; // Set generating status } async function generateResponse() { const prompt = promptInput.value.trim(); if (!prompt) { statusMessageContainer.textContent = "Please enter a prompt."; return; } if (!worker || !modelReady) { statusMessageContainer.textContent = "Model is not ready yet. Please wait."; return; } resetUI(); // Send prompt to worker to start generation console.log( `[UI] Sending "generate" message to worker with prompt: "${prompt}"` ); worker.postMessage({ type: "generate", data: { prompt } }); } // After the script is loaded, initialize the text generator. async function initializeAndAttachListeners() { console.log("[UI] Starting initialization and attaching listeners."); await initializeModelInWorker(); generateBtn.addEventListener("click", generateResponse); // Add event listener for "Enter" key press in the prompt input field promptInput.addEventListener("keydown", function (event) { if (event.key === "Enter" && !event.shiftKey && !generateBtn.disabled) { console.log('[UI] "Enter" key pressed, triggering generation.'); event.preventDefault(); // Prevents the default action (form submission/new line) generateResponse(); } }); } initializeAndAttachListeners();