anycoder-ca50967c / index.js
akhaliq's picture
akhaliq HF Staff
Upload index.js with huggingface_hub
c2096ea verified
class ChatbotApp {
constructor() {
this.generator = null;
this.messages = [
{ role: "system", content: "You are a helpful assistant. Be concise and friendly." }
];
this.isGenerating = false;
this.init();
}
async init() {
this.setupElements();
this.setupEventListeners();
await this.loadModel();
}
setupElements() {
this.chatMessages = document.getElementById('chatMessages');
this.messageInput = document.getElementById('messageInput');
this.sendButton = document.getElementById('sendButton');
this.status = document.getElementById('status');
this.loadingIndicator = document.getElementById('loadingIndicator');
this.progressFill = document.getElementById('progressFill');
this.progressText = document.getElementById('progressText');
this.charCount = document.getElementById('charCount');
}
setupEventListeners() {
// Send button click
this.sendButton.addEventListener('click', () => this.sendMessage());
// Enter key to send (Shift+Enter for new line)
this.messageInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
this.sendMessage();
}
});
// Character count
this.messageInput.addEventListener('input', () => {
const length = this.messageInput.value.length;
this.charCount.textContent = `${length} / 1000`;
// Auto-resize textarea
this.messageInput.style.height = 'auto';
this.messageInput.style.height = Math.min(this.messageInput.scrollHeight, 120) + 'px';
});
// Initialize worker
this.setupWorker();
}
setupWorker() {
// Create worker from separate file
this.worker = new Worker('worker.js');
this.worker.addEventListener('message', (e) => {
switch(e.data.type) {
case 'progress':
this.updateProgress(e.data.progress);
break;
case 'modelLoaded':
this.onModelLoaded(e.data.generator);
break;
case 'error':
this.onError(e.data.error);
break;
}
});
}
async loadModel() {
this.status.textContent = 'Downloading model...';
this.loadingIndicator.classList.remove('hidden');
this.worker.postMessage({ type: 'loadModel' });
}
updateProgress(progress) {
this.progressFill.style.width = `${progress}%`;
this.progressText.textContent = `${Math.round(progress)}%`;
}
onModelLoaded(generator) {
this.generator = generator;
this.loadingIndicator.classList.add('hidden');
this.status.textContent = 'Ready';
this.messageInput.disabled = false;
this.sendButton.disabled = false;
this.messageInput.focus();
}
onError(error) {
this.loadingIndicator.classList.add('hidden');
this.status.textContent = 'Error loading model';
this.addMessage('system', `Error: ${error}. Please refresh the page to try again.`);
}
async sendMessage() {
const message = this.messageInput.value.trim();
if (!message || this.isGenerating || !this.generator) return;
// Add user message
this.addMessage('user', message);
this.messages.push({ role: "user", content: message });
// Clear input
this.messageInput.value = '';
this.messageInput.style.height = 'auto';
this.charCount.textContent = '0 / 1000';
// Disable input
this.isGenerating = true;
this.messageInput.disabled = true;
this.sendButton.disabled = true;
this.status.textContent = 'Thinking...';
// Add AI message with typing indicator
const aiMessageId = this.addMessage('ai', '', true);
try {
// Generate response with streaming
const streamer = new transformers.TextStreamer(this.generator.tokenizer, {
skip_prompt: true,
skip_special_tokens: true,
callback_function: (text) => {
this.updateMessage(aiMessageId, text);
}
});
const output = await this.generator(this.messages, {
max_new_tokens: 512,
do_sample: false,
streamer: streamer,
});
// Add the AI response to messages
const aiResponse = output[0].generated_text.at(-1).content;
this.messages.push({ role: "assistant", content: aiResponse });
} catch (error) {
this.updateMessage(aiMessageId, 'Sorry, I encountered an error. Please try again.');
console.error('Generation error:', error);
} finally {
// Re-enable input
this.isGenerating = false;
this.messageInput.disabled = false;
this.sendButton.disabled = false;
this.status.textContent = 'Ready';
this.messageInput.focus();
}
}
addMessage(role, content, isTyping = false) {
const messageId = 'msg-' + Date.now();
const messageDiv = document.createElement('div');
messageDiv.className = `message ${role}`;
messageDiv.id = messageId;
const avatar = document.createElement('div');
avatar.className = role === 'user' ? 'user-avatar' : 'ai-avatar';
avatar.innerHTML = role === 'user'
? '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>'
: '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2L2 7v10c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V7l-10-5z" />
<path d="M12 8v4" />
<circle cx="12" cy="16" r="1" />
</svg>';
const messageContent = document.createElement('div');
messageContent.className = 'message-content';
const bubble = document.createElement('div');
bubble.className = 'message-bubble';
if (isTyping) {
bubble.innerHTML = '<div class="typing-indicator">
<div class="typing-dot"></div>
<div class="typing-dot"></div>
<div class="typing-dot"></div>
</div>';
} else {
bubble.textContent = content;
}
const time = document.createElement('div');
time.className = 'message-time';
time.textContent = new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
messageContent.appendChild(bubble);
messageContent.appendChild(time);
messageDiv.appendChild(avatar);
messageDiv.appendChild(messageContent);
this.chatMessages.appendChild(messageDiv);
this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
return messageId;
}
updateMessage(messageId, content) {
const messageElement = document.getElementById(messageId);
if (messageElement) {
const bubble = messageElement.querySelector('.message-bubble');
bubble.textContent = content;
this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
}
}
}
// Initialize the app when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
new ChatbotApp();
});