anycoder-9ba2995f / index.js
akhaliq's picture
akhaliq HF Staff
Upload index.js with huggingface_hub
7d29472 verified
import { pipeline } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.8.0';
class Chatbot {
constructor() {
this.generator = null;
this.isGenerating = false;
this.conversationHistory = [];
this.maxHistoryLength = 10;
this.currentModel = 'Xenova/distilgpt2';
this.currentDevice = 'wasm';
this.initializeElements();
this.attachEventListeners();
this.loadModel();
}
initializeElements() {
this.messagesContainer = document.getElementById('messages');
this.messageInput = document.getElementById('message-input');
this.sendButton = document.getElementById('send-button');
this.clearButton = document.getElementById('clear-chat');
this.modelSelect = document.getElementById('model-select');
this.deviceSelect = document.getElementById('device-select');
this.typingIndicator = document.getElementById('typing-indicator');
this.loadingOverlay = document.getElementById('loading-overlay');
this.errorToast = document.getElementById('error-toast');
this.errorMessage = document.getElementById('error-message');
this.charCount = document.getElementById('char-count');
this.dismissErrorBtn = document.getElementById('dismiss-error');
}
attachEventListeners() {
this.sendButton.addEventListener('click', () => this.sendMessage());
this.clearButton.addEventListener('click', () => this.clearChat());
this.modelSelect.addEventListener('change', (e) => this.changeModel(e.target.value));
this.deviceSelect.addEventListener('change', (e) => this.changeDevice(e.target.value));
this.messageInput.addEventListener('input', () => {
this.updateCharCount();
this.autoResizeTextarea();
this.sendButton.disabled = !this.messageInput.value.trim() || this.isGenerating;
});
this.messageInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
this.sendMessage();
}
});
this.dismissErrorBtn.addEventListener('click', () => this.hideError());
// Check for WebGPU support
this.checkWebGPUSupport();
}
async checkWebGPUSupport() {
if (!navigator.gpu) {
this.deviceSelect.querySelector('option[value="webgpu"]').disabled = true;
this.deviceSelect.value = 'wasm';
this.currentDevice = 'wasm';
}
}
async loadModel() {
this.showLoading();
try {
const config = {
device: this.currentDevice,
dtype: this.currentDevice === 'webgpu' ? 'fp16' : 'q4'
};
this.generator = await pipeline('text-generation', this.currentModel, config);
this.hideLoading();
this.sendButton.disabled = !this.messageInput.value.trim();
} catch (error) {
console.error('Error loading model:', error);
this.hideLoading();
this.showError('Failed to load model. Please try again or select a different model.');
this.sendButton.disabled = true;
}
}
async changeModel(modelName) {
if (modelName === this.currentModel) return;
this.currentModel = modelName;
await this.loadModel();
}
async changeDevice(device) {
if (device === this.currentDevice) return;
this.currentDevice = device;
await this.loadModel();
}
async sendMessage() {
const message = this.messageInput.value.trim();
if (!message || this.isGenerating) return;
this.addMessage(message, 'user');
this.messageInput.value = '';
this.updateCharCount();
this.autoResizeTextarea();
this.sendButton.disabled = true;
this.isGenerating = true;
this.showTypingIndicator();
try {
const prompt = this.buildPrompt(message);
const response = await this.generateResponse(prompt);
this.addMessage(response, 'bot');
} catch (error) {
console.error('Error generating response:', error);
this.showError('Failed to generate response. Please try again.');
} finally {
this.isGenerating = false;
this.hideTypingIndicator();
this.sendButton.disabled = !this.messageInput.value.trim();
}
}
buildPrompt(userMessage) {
let prompt = "You are a helpful AI assistant. Respond in a friendly and informative way.\n\n";
// Include recent conversation history
if (this.conversationHistory.length > 0) {
const recentHistory = this.conversationHistory.slice(-4);
recentHistory.forEach(msg => {
if (msg.role === 'user') {
prompt += `User: ${msg.content}\n`;
} else {
prompt += `Assistant: ${msg.content}\n`;
}
});
}
prompt += `User: ${userMessage}\nAssistant:`;
return prompt;
}
async generateResponse(prompt) {
const maxNewTokens = 100;
const temperature = 0.7;
const result = await this.generator(prompt, {
max_new_tokens: maxNewTokens,
temperature: temperature,
do_sample: true,
pad_token_id: 50256,
return_full_text: false
});
let response = result[0].generated_text.trim();
// Clean up the response
response = response.replace(/^(Assistant:|AI:|Bot:)/i, '').trim();
response = response.split('\n')[0]; // Take only the first line
if (!response) {
response = "I'm not sure how to respond to that. Could you try rephrasing?";
}
return response;
}
addMessage(content, role) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${role}-message`;
const messageContent = document.createElement('div');
messageContent.className = 'message-content';
messageContent.innerHTML = `<p>${this.escapeHtml(content)}</p>`;
const messageTime = document.createElement('div');
messageTime.className = 'message-time';
messageTime.textContent = role === 'user' ? 'You' : 'Bot';
messageDiv.appendChild(messageContent);
messageDiv.appendChild(messageTime);
this.messagesContainer.appendChild(messageDiv);
this.scrollToBottom();
// Update conversation history
this.conversationHistory.push({ role, content });
if (this.conversationHistory.length > this.maxHistoryLength) {
this.conversationHistory.shift();
}
}
clearChat() {
this.messagesContainer.innerHTML = `
<div class="message bot-message">
<div class="message-content">
<p>Hello! I'm your AI assistant. How can I help you today?</p>
</div>
<div class="message-time">Bot</div>
</div>
`;
this.conversationHistory = [];
this.scrollToBottom();
}
updateCharCount() {
const length = this.messageInput.value.length;
this.charCount.textContent = `${length} / 500`;
}
autoResizeTextarea() {
this.messageInput.style.height = 'auto';
this.messageInput.style.height = Math.min(this.messageInput.scrollHeight, 120) + 'px';
}
showTypingIndicator() {
this.typingIndicator.classList.remove('hidden');
this.scrollToBottom();
}
hideTypingIndicator() {
this.typingIndicator.classList.add('hidden');
}
showLoading() {
this.loadingOverlay.classList.remove('hidden');
}
hideLoading() {
this.loadingOverlay.classList.add('hidden');
}
showError(message) {
this.errorMessage.textContent = message;
this.errorToast.classList.remove('hidden');
setTimeout(() => this.hideError(), 5000);
}
hideError() {
this.errorToast.classList.add('hidden');
}
scrollToBottom() {
this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
}
// Initialize the chatbot when the page loads
document.addEventListener('DOMContentLoaded', () => {
new Chatbot();
});