|
<!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> |
|
|
|
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"> |
|
|
|
</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"; |
|
|
|
|
|
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 { |
|
|
|
generator = await pipeline( |
|
"text-generation", |
|
"onnx-community/gemma-3-1b-it-ONNX", |
|
{ |
|
dtype: "q4", |
|
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!'; |
|
|
|
setTimeout(() => { |
|
loadingIndicator.style.display = 'none'; |
|
}, 1500); |
|
} |
|
}, |
|
} |
|
); |
|
|
|
} 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; |
|
} |
|
|
|
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; |
|
|
|
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...'; |
|
sendButton.disabled = true; |
|
|
|
try { |
|
const output = await generator(chatHistory, { |
|
max_new_tokens: 512, |
|
do_sample: false |
|
}); |
|
|
|
const botResponse = output[0].generated_text.at(-1).content; |
|
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> |