anycoder-b95e2145 / index.js
Shivam098's picture
Upload index.js with huggingface_hub
c4221c8 verified
import { pipeline, env } from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.8.0';
// ============================================
// CONFIGURATION
// ============================================
const CONFIG = {
model: 'Xenova/Llama-3.2-3B-Instruct', // Quantized version for faster loading
maxTokens: 512,
temperature: 0.7,
topP: 0.9,
doSample: true,
repetitionPenalty: 1.1
};
// ============================================
// DOM ELEMENTS
// ============================================
const elements = {
chatContainer: document.getElementById('chat-container'),
messagesList: document.getElementById('messages-list'),
userInput: document.getElementById('user-input'),
sendBtn: document.getElementById('send-btn'),
loadingIndicator: document.getElementById('loading-indicator'),
loadingMessage: document.getElementById('loading-message'),
progressBar: document.getElementById('progress-bar'),
progressFill: document.getElementById('progress-fill'),
welcomeScreen: document.getElementById('welcome-screen'),
statusDot: document.querySelector('.status-dot'),
statusText: document.querySelector('.status-text'),
exampleBtns: document.querySelectorAll('.example-btn')
};
// ============================================
// APPLICATION STATE
// ============================================
let appState = {
modelLoaded: false,
isGenerating: false,
messages: []
};
// ============================================
// WORKER HANDLERS
// ============================================
let currentResponse = '';
let isWorkerBusy = false;
// Handle worker messages
worker.onmessage = (e) => {
const { type, payload } = e.data;
switch (type) {
case 'loading':
updateModelStatus('loading');
break;
case 'progress':
updateProgress(payload.progress, payload.message);
break;
case 'loaded':
appState.modelLoaded = true;
updateModelStatus('ready');
hideLoading();
hideWelcomeScreen();
break;
case 'result':
handleGenerationComplete(payload.result);
break;
case 'error':
showError(payload.error);
break;
case 'cancelled':
stopGeneration();
break;
}
};
// ============================================
// MODEL INITIALIZATION
// ============================================
async function initializeModel() {
try {
showLoading('Initializing model...');
worker.postMessage({
type: 'load',
payload: { model: CONFIG.model }
});
} catch (error) {
showError(`Failed to initialize model: ${error.message}`);
}
}
// ============================================
// GENERATION FUNCTIONS
// ============================================
async function sendMessage(message) {
if (!appState.modelLoaded || isWorkerBusy) return;
// Add user message to chat
addMessage('user', message);
appState.messages.push({ role: 'user', content: message });
// Clear input
elements.userInput.value = '';
elements.userInput.style.height = 'auto';
updateSendButton();
// Start generation
isWorkerBusy = true;
currentResponse = '';
showLoading('Generating response...');
try {
// Create prompt for the model
const prompt = createPrompt();
worker.postMessage({
type: 'generate',
payload: {
prompt: prompt,
maxTokens: CONFIG.maxTokens,
temperature: CONFIG.temperature,
topP: CONFIG.topP,
doSample: CONFIG.doSample,
repetitionPenalty: CONFIG.repetitionPenalty
}
});
} catch (error) {
showError(`Generation failed: ${error.message}`);
isWorkerBusy = false;
}
}
function createPrompt() {
// Convert messages to chat format
if (appState.messages.length === 0) {
return 'You are a helpful AI assistant. Please answer the user\'s question helpfully and accurately.';
}
return appState.messages
.map(msg => `${msg.role}: ${msg.content}`)
.join('\n\n') + '\n\nassistant:';
}
// ============================================
// MESSAGE HANDLING
// ============================================
function addMessage(role, content) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${role}`;
const avatar = role === 'user' ? '👤' : '🤖';
messageDiv.innerHTML = `
<div class="message-avatar">${avatar}</div>
<div class="message-content">${formatContent(content)}</div>
`;
elements.messagesList.appendChild(messageDiv);
scrollToBottom();
return messageDiv;
}
function handleGenerationComplete(generatedText) {
// Add AI response to chat
const messageDiv = addMessage('ai', '');
// Create content element for streaming
const contentElement = messageDiv.querySelector('.message-content');
contentElement.classList.add('typing-cursor');
// Stream the response
streamText(contentElement, generatedText)
.then(() => {
contentElement.classList.remove('typing-cursor');
appState.messages.push({ role: 'assistant', content: generatedText });
isWorkerBusy = false;
hideLoading();
})
.catch(error => {
showError(`Streaming failed: ${error.message}`);
isWorkerBusy = false;
hideLoading();
});
}
async function streamText(element, text) {
const words = text.split(' ');
let currentText = '';
for (let i = 0; i < words.length; i++) {
currentText += words[i] + ' ';
element.innerHTML = formatContent(currentText);
scrollToBottom();
// Add a small delay for more natural typing effect
await new Promise(resolve => setTimeout(resolve, 10 + Math.random() * 20));
}
}
function formatContent(text) {
// Simple text formatting
// Escape HTML
let formatted = text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
// Format code blocks
formatted = formatted.replace(/```(\w*)\n([\s\S]*?)```/g, (match, lang, code) => {
return `<pre><code class="language-${lang}">${escapeHtml(code.trim())}</code></pre>`;
});
// Format inline code
formatted = formatted.replace(/`([^`]+)`/g, '<code>$1</code>');
// Format bold text
formatted = formatted.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
// Format line breaks
formatted = formatted.replace(/\n/g, '<br>');
return formatted;
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// ============================================
// UI FUNCTIONS
// ============================================
function showLoading(message) {
elements.loadingIndicator.classList.remove('hidden');
elements.loadingMessage.textContent = message;
elements.progressBar.classList.remove('hidden');
elements.progressFill.style.width = '0%';
}
function hideLoading() {
elements.loadingIndicator.classList.add('hidden');
elements.progressBar.classList.add('hidden');
}
function updateProgress(progress, message) {
elements.progressFill.style.width = `${progress}%`;
if (message) {
elements.loadingMessage.textContent = message;
}
}
function updateModelStatus(status) {
elements.statusDot.className = 'status-dot';
if (status === 'loading') {
elements.statusDot.classList.add('loading');
elements.statusText.textContent = 'Loading model...';
} else if (status === 'ready') {
elements.statusDot.classList.add('ready');
elements.statusText.textContent = 'Ready';
}
}
function showError(error) {
console.error('Error:', error);
hideLoading();
// Add error message to chat
const messageDiv = document.createElement('div');
messageDiv.className = `message ai`;
messageDiv.innerHTML = `
<div class="message-avatar">⚠️</div>
<div class="message-content" style="color: var(--error-color);">
<strong>Error:</strong> ${error}
</div>
`;
elements.messagesList.appendChild(messageDiv);
isWorkerBusy = false;
}
function scrollToBottom() {
elements.chatContainer.scrollTop = elements.chatContainer.scrollHeight;
}
function hideWelcomeScreen() {
elements.welcomeScreen.style.display = 'none';
}
// ============================================
// EVENT LISTENERS
// ============================================
function updateSendButton() {
const hasText = elements.userInput.value.trim().length > 0;
elements.sendBtn.disabled = !hasText || isWorkerBusy;
}
async function handleInput() {
updateSendButton();
// Auto-resize textarea
elements.userInput.style.height = 'auto';
elements.userInput.style.height = Math.min(elements.userInput.scrollHeight, 200) + 'px';
}
async function handleSend() {
const message = elements.userInput.value.trim();
if (message && !isWorkerBusy) {
await sendMessage(message);
}
}
// ============================================
// INITIALIZATION
// ============================================
async function init() {
// Configure environment
env.allowLocalModels = false;
env.useBrowserCache = true;
// Initialize model
await initializeModel();
// Setup event listeners
elements.userInput.addEventListener('input', handleInput);
elements.userInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSend();
}
});
elements.sendBtn.addEventListener('click', handleSend);
// Setup example prompts
elements.exampleBtns.forEach(btn => {
btn.addEventListener('click', () => {
elements.userInput.value = btn.dataset.prompt;
handleInput();
elements.userInput.focus();
});
});
// Focus input on load
elements.userInput.focus();
}
// Start the application
init();
</arg_value>=== worker.js ===
// This file is handled as an inline blob in index.html for single-file deployment
// The worker code is provided as a string in the index.html script tag