kimhyunwoo's picture
Update index.html
32922f8 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gemma Chatbot</title>
<style>
/* (Same good CSS as before) */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
margin: 0;
background-color: #f4f7f6;
}
h1 {
color: #333;
margin-bottom: 0.5em;
}
#chat-container {
width: 90%;
max-width: 700px;
border: none;
padding: 25px;
border-radius: 15px;
background-color: #fff;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
#chat-messages {
height: 400px;
overflow-y: auto;
margin-bottom: 15px;
padding: 15px;
border: 1px solid #e0e0e0;
border-radius: 10px;
background-color: #fafafa;
}
.message {
margin-bottom: 10px;
padding: 12px;
border-radius: 20px;
max-width: 70%;
word-wrap: break-word;
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
.user-message {
background-color: #d4e5ff;
color: #000;
text-align: right;
align-self: flex-end;
margin-left: auto;
margin-right: 10px;
}
.bot-message {
background-color: #e5e5ea;
color: #000;
text-align: left;
align-self: flex-start;
margin-right: auto;
margin-left: 10px;
}
#input-container {
display: flex;
gap: 10px;
padding-top: 15px;
border-top: 1px solid #e0e0e0;
}
#user-input {
flex-grow: 1;
padding: 12px;
border: 1px solid #ccc;
border-radius: 20px;
font-size: 16px;
outline: none;
transition: border-color 0.2s ease-in-out;
}
#user-input:focus {
border-color: #007bff;
}
#send-button {
padding: 12px 25px;
background-color: #007bff;
color: white;
border: none;
border-radius: 20px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.2s ease-in-out;
}
#send-button:hover {
background-color: #0056b3;
}
#send-button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
#loading-indicator {
display: none;
margin-top: 15px;
text-align: center;
color: #888;
font-style: italic;
}
.system-message {
display: none;
}
</style>
</head>
<body>
<h1>Gemma 3 Chatbot</h1>
<div id="chat-container">
<div id="chat-messages">
<!-- Messages will appear here -->
</div>
<div id="input-container">
<input type="text" id="user-input" placeholder="Type your message..." aria-label="Your message">
<button id="send-button" aria-label="Send message">Send</button>
</div>
<div id="loading-indicator">Loading...</div>
</div>
<script type="module">
import { pipeline, env } from "https://cdn.jsdelivr.net/npm/@huggingface/[email protected]/dist/transformers.js";
// Allow remote models and set a cache directory.
env.allowRemoteModels = true;
env.cacheDir = './cache';
const chatMessagesDiv = document.getElementById('chat-messages');
const userInput = document.getElementById('user-input');
const sendButton = document.getElementById('send-button');
const loadingIndicator = document.getElementById('loading-indicator');
let chatHistory = [
{ role: "system", content: "You are a helpful assistant." },
];
let generator;
async function initializePipeline() {
loadingIndicator.style.display = 'block';
try {
// Correct Gemma 3 model name and text-generation pipeline
generator = await pipeline(
"text-generation",
"onnx-community/gemma-3-1b-it-ONNX",
{
dtype: "q4", // Quantization
progress_callback: (progress) => {
if (progress.status === 'progress') {
loadingIndicator.textContent = `Loading... ${progress.file} - ${Math.round(progress.loaded / 1000000)}MB/${Math.round(progress.total / 1000000)}MB`;
}
if (progress.status === 'loaded') {
loadingIndicator.textContent = 'Model Loaded!';
// Optional: Hide after a short delay, so the user sees it.
setTimeout(() => {
loadingIndicator.style.display = 'none';
}, 1500); // 1.5 seconds
}
},
}
);
} catch (error) {
console.error("Error loading model:", error);
loadingIndicator.textContent = "Error loading model. Check console, ensure a modern browser, and internet connection.";
loadingIndicator.style.color = "red";
sendButton.disabled = true;
return;
}
// Don't hide it here anymore: let the progress_callback and timeout handle it.
addMessage("bot", "Hello! I'm ready to chat. Ask me anything!");
}
initializePipeline();
function addMessage(role, content) {
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', `${role}-message`);
messageDiv.textContent = content;
chatMessagesDiv.appendChild(messageDiv);
chatMessagesDiv.scrollTop = chatMessagesDiv.scrollHeight; // Scroll to bottom
if (role === 'user' || role === 'assistant') {
chatHistory.push({ role: role, content: content });
}
}
async function sendMessage() {
const message = userInput.value.trim();
if (!message || !generator) return;
addMessage('user', message);
userInput.value = '';
loadingIndicator.style.display = 'block';
loadingIndicator.textContent = 'Generating response...'; // Indicate response generation
sendButton.disabled = true;
try {
const output = await generator(chatHistory, {
max_new_tokens: 512,
do_sample: false // Try setting to `true` for varied responses.
});
const botResponse = output[0].generated_text.at(-1).content; // Correctly access generated text
addMessage('assistant', botResponse);
} catch (error) {
console.error("Error generating response:", error);
addMessage('bot', "Sorry, I encountered an error. Please try again.");
} finally {
loadingIndicator.style.display = 'none';
sendButton.disabled = false;
}
}
sendButton.addEventListener('click', sendMessage);
userInput.addEventListener('keypress', (event) => {
if (event.key === 'Enter') {
sendMessage();
}
});
</script>
</body>
</html>