Spaces:
Running
Running
File size: 5,868 Bytes
5dbb619 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
// 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.</br></br>
For more details, read the <a href="https://github.com/gpuweb/gpuweb/wiki/Implementation-Status" target="_blank" style="f; color: #286aac">WebGPU Implementation Status</a>.
`;
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();
|