Spaces:
Running
Running
File size: 5,291 Bytes
e9d3310 dd1b723 e9d3310 dd1b723 e9d3310 dd1b723 e9d3310 dd1b723 e9d3310 dd1b723 e9d3310 dd1b723 e9d3310 dd1b723 e9d3310 dd1b723 e9d3310 |
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 |
import { pipeline, TextStreamer } from 'https://cdn.jsdelivr.net/npm/@huggingface/[email protected]';
class GemmaChatbot {
constructor() {
this.generator = null;
this.messages = [
{ role: "system", content: "You are a helpful, friendly AI assistant. Keep your responses concise and helpful." }
];
this.isGenerating = false;
this.initializeElements();
this.initializeModel();
}
initializeElements() {
this.chatMessages = document.getElementById('chatMessages');
this.userInput = document.getElementById('userInput');
this.sendButton = document.getElementById('sendButton');
this.loadingIndicator = document.getElementById('loadingIndicator');
this.sendButton.addEventListener('click', () => this.sendMessage());
this.userInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
this.sendMessage();
}
});
}
async initializeModel() {
try {
console.log('Initializing Gemma model...');
this.generator = await pipeline(
'text-generation',
'onnx-community/gemma-3-270m-it-ONNX',
{ dtype: 'fp32' }
);
console.log('Model loaded successfully');
this.enableChat();
} catch (error) {
console.error('Failed to initialize model:', error);
this.showError('Failed to load AI model. Please refresh the page to try again.');
}
}
enableChat() {
this.loadingIndicator.style.display = 'none';
this.userInput.disabled = false;
this.sendButton.disabled = false;
this.userInput.focus();
}
addMessage(content, isUser = false) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${isUser ? 'user' : 'assistant'}`;
const contentDiv = document.createElement('div');
contentDiv.className = 'message-content';
contentDiv.textContent = content;
messageDiv.appendChild(contentDiv);
this.chatMessages.appendChild(messageDiv);
this.scrollToBottom();
return contentDiv;
}
scrollToBottom() {
this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
}
async sendMessage() {
const message = this.userInput.value.trim();
if (!message || this.isGenerating || !this.generator) return;
this.isGenerating = true;
this.userInput.value = '';
this.userInput.disabled = true;
this.sendButton.disabled = true;
// Add user message
this.addMessage(message, true);
this.messages.push({ role: "user", content: message });
// Add assistant message placeholder
const assistantMessageDiv = document.createElement('div');
assistantMessageDiv.className = 'message assistant';
const contentDiv = document.createElement('div');
contentDiv.className = 'message-content';
const typingIndicator = document.createElement('span');
typingIndicator.className = 'typing-indicator';
typingIndicator.innerHTML = '<span></span><span></span><span></span>';
contentDiv.appendChild(typingIndicator);
assistantMessageDiv.appendChild(contentDiv);
this.chatMessages.appendChild(assistantMessageDiv);
this.scrollToBottom();
try {
let fullResponse = '';
// Create custom streamer
const streamer = new TextStreamer(this.generator.tokenizer, {
skip_prompt: true,
skip_special_tokens: true,
callback_function: (text) => {
fullResponse += text;
contentDiv.textContent = fullResponse;
this.scrollToBottom();
}
});
// Generate response
const output = await this.generator(this.messages, {
max_new_tokens: 256,
do_sample: true,
temperature: 0.7,
top_p: 0.9,
streamer: streamer
});
const generatedContent = output[0].generated_text.at(-1).content;
this.messages.push({ role: "assistant", content: generatedContent });
// Ensure final content is displayed
contentDiv.textContent = generatedContent;
} catch (error) {
console.error('Generation error:', error);
contentDiv.textContent = 'Sorry, I encountered an error. Please try again.';
} finally {
this.isGenerating = false;
this.userInput.disabled = false;
this.sendButton.disabled = false;
this.userInput.focus();
}
}
showError(message) {
this.loadingIndicator.innerHTML = `
<div class="error-message">
<p>⚠️ ${message}</p>
</div>
`;
}
}
// Initialize chatbot when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
new GemmaChatbot();
}); |