Download script.js from Captain3000/mindmeld-chatbot-wizard: direct link, hf CLI and curl.
- Browser
- Download file 11.2 kB
-
https://huggingface.co/spaces/Captain3000/mindmeld-chatbot-wizard/resolve/main/script.js
- Command line
-
hf download hf://spaces/Captain3000/mindmeld-chatbot-wizard/script.js
-
curl -L -o script.js https://huggingface.co/spaces/Captain3000/mindmeld-chatbot-wizard/resolve/main/script.js
11.2 kB
| document.addEventListener('DOMContentLoaded', () => { | |
| // DOM Elements | |
| const apiKeyInput = document.getElementById('api-key'); | |
| const toggleKeyBtn = document.getElementById('toggle-key'); | |
| const modelSelect = document.getElementById('model-select'); | |
| const temperatureSlider = document.getElementById('temperature'); | |
| const tempValue = document.getElementById('temp-value'); | |
| const startChatBtn = document.getElementById('start-chat'); | |
| const modelInfo = document.getElementById('model-info'); | |
| const chatContainer = document.getElementById('chat-container'); | |
| const userInput = document.getElementById('user-input'); | |
| const sendBtn = document.getElementById('send-btn'); | |
| const clearChatBtn = document.getElementById('clear-chat'); | |
| const themeToggle = document.getElementById('theme-toggle'); | |
| const themeIcon = document.getElementById('theme-icon'); | |
| // State | |
| let chatActive = false; | |
| let conversationHistory = []; | |
| let models = []; | |
| let selectedModel = null; | |
| let embeddedDocument = null; | |
| let embedApiKey = ''; | |
| let embedModel = null; | |
| // Initialize | |
| fetchModels(); | |
| setupEventListeners(); | |
| setupEmbedListeners(); | |
| // Functions | |
| function setupEventListeners() { | |
| // Toggle API key visibility | |
| toggleKeyBtn.addEventListener('click', () => { | |
| const type = apiKeyInput.getAttribute('type') === 'password' ? 'text' : 'password'; | |
| apiKeyInput.setAttribute('type', type); | |
| feather.replace(); | |
| }); | |
| // Temperature slider | |
| temperatureSlider.addEventListener('input', () => { | |
| tempValue.textContent = temperatureSlider.value; | |
| }); | |
| // Model selection | |
| modelSelect.addEventListener('change', () => { | |
| const modelId = modelSelect.value; | |
| selectedModel = models.find(m => m.id === modelId); | |
| updateModelInfo(); | |
| }); | |
| // Start chat button | |
| startChatBtn.addEventListener('click', startChat); | |
| // Send message | |
| sendBtn.addEventListener('click', sendMessage); | |
| userInput.addEventListener('keydown', (e) => { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| sendMessage(); | |
| } | |
| }); | |
| // Clear chat | |
| clearChatBtn.addEventListener('click', clearChat); | |
| // Theme toggle | |
| themeToggle.addEventListener('click', toggleTheme); | |
| } | |
| async function fetchModels() { | |
| try { | |
| const response = await fetch('https://openrouter.ai/api/v1/models'); | |
| const data = await response.json(); | |
| models = data.data || []; | |
| populateModelSelect(); | |
| } catch (error) { | |
| console.error('Error fetching models:', error); | |
| addSystemMessage('Failed to load models. Please try again later.'); | |
| } | |
| } | |
| function populateModelSelect() { | |
| modelSelect.innerHTML = '<option value="">Select a model...</option>'; | |
| models.forEach(model => { | |
| const option = document.createElement('option'); | |
| option.value = model.id; | |
| option.textContent = `${model.name} (${model.id})`; | |
| modelSelect.appendChild(option); | |
| }); | |
| } | |
| function updateModelInfo() { | |
| if (!selectedModel) { | |
| modelInfo.innerHTML = 'Select a model to see details'; | |
| return; | |
| } | |
| modelInfo.innerHTML = ` | |
| <div class="flex items-start justify-between"> | |
| <div> | |
| <p class="font-medium text-gray-200">${selectedModel.name}</p> | |
| <p class="text-sm text-gray-400">${selectedModel.id}</p> | |
| </div> | |
| ${selectedModel.pricing ? ` | |
| <div class="text-right"> | |
| <p class="text-xs font-medium text-yellow-300">${(selectedModel.pricing.completion * 1000).toFixed(4)} / 1K tokens</p> | |
| <p class="text-xs text-gray-400">${(selectedModel.pricing.prompt * 1000).toFixed(4)} prompt</p> | |
| </div> | |
| ` : ''} | |
| </div> | |
| <p class="mt-2 text-sm">${selectedModel.description || 'No description available'}</p> | |
| <div class="mt-3 grid grid-cols-2 gap-2 text-xs"> | |
| <div class="bg-gray-700 p-2 rounded"> | |
| <span class="text-gray-400 block">Provider</span> | |
| <span class="font-medium">${selectedModel.provider || 'Unknown'}</span> | |
| </div> | |
| <div class="bg-gray-700 p-2 rounded"> | |
| <span class="text-gray-400 block">Context</span> | |
| <span class="font-medium">${selectedModel.context_length ? selectedModel.context_length.toLocaleString() : 'Unknown'} tokens</span> | |
| </div> | |
| ${selectedModel.top_provider ? ` | |
| <div class="bg-gray-700 p-2 rounded"> | |
| <span class="text-gray-400 block">Top Provider</span> | |
| <span class="font-medium">${selectedModel.top_provider.name}</span> | |
| </div> | |
| ` : ''} | |
| ${selectedModel.features ? ` | |
| <div class="bg-gray-700 p-2 rounded"> | |
| <span class="text-gray-400 block">Features</span> | |
| <span class="font-medium">${Object.keys(selectedModel.features).filter(k => selectedModel.features[k]).join(', ')}</span> | |
| </div> | |
| ` : ''} | |
| </div> | |
| ${selectedModel.pricing ? ` | |
| <div class="mt-3 bg-gray-700 p-3 rounded-lg"> | |
| <h4 class="text-xs font-medium text-gray-300 mb-1">Pricing Details</h4> | |
| <div class="text-xs"> | |
| <p>Prompt: ${(selectedModel.pricing.prompt * 1000).toFixed(4)} / 1K tokens</p> | |
| <p>Completion: ${(selectedModel.pricing.completion * 1000).toFixed(4)} / 1K tokens</p> | |
| ${selectedModel.pricing.request ? `<p>Request: ${selectedModel.pricing.request} / call</p>` : ''} | |
| </div> | |
| </div> | |
| ` : ''} | |
| `; | |
| } | |
| function startChat() { | |
| const apiKey = apiKeyInput.value.trim(); | |
| const modelId = modelSelect.value; | |
| if (!apiKey) { | |
| addSystemMessage('Please enter your OpenRouter API key'); | |
| return; | |
| } | |
| if (!modelId) { | |
| addSystemMessage('Please select a model'); | |
| return; | |
| } | |
| chatActive = true; | |
| conversationHistory = []; | |
| userInput.disabled = false; | |
| sendBtn.disabled = false; | |
| startChatBtn.disabled = true; | |
| startChatBtn.classList.add('opacity-50', 'cursor-not-allowed'); | |
| addSystemMessage(`Chat started with ${selectedModel.name}. Ready to chat!`); | |
| } | |
| async function sendMessage() { | |
| const message = userInput.value.trim(); | |
| if (!message || !chatActive) return; | |
| // Add user message to chat | |
| addMessageToChat('user', message); | |
| userInput.value = ''; | |
| // Show loading indicator | |
| const loadingId = addLoadingIndicator(); | |
| try { | |
| const response = await fetch('https://openrouter.ai/api/v1/chat/completions', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'Authorization': `Bearer ${apiKeyInput.value.trim()}` | |
| }, | |
| body: JSON.stringify({ | |
| model: selectedModel.id, | |
| messages: [ | |
| ...conversationHistory, | |
| { role: 'user', content: message } | |
| ], | |
| temperature: parseFloat(temperatureSlider.value) | |
| }) | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`API error: ${response.status}`); | |
| } | |
| const data = await response.json(); | |
| const aiResponse = data.choices[0].message.content; | |
| // Remove loading indicator and add AI response | |
| removeLoadingIndicator(loadingId); | |
| addMessageToChat('assistant', aiResponse); | |
| // Update conversation history | |
| conversationHistory.push( | |
| { role: 'user', content: message }, | |
| { role: 'assistant', content: aiResponse } | |
| ); | |
| } catch (error) { | |
| console.error('Error:', error); | |
| removeLoadingIndicator(loadingId); | |
| addSystemMessage(`Error: ${error.message}`); | |
| } | |
| } | |
| function addMessageToChat(role, content) { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `chat-bubble ${role === 'user' ? 'user-bubble' : 'ai-bubble'} fade-in`; | |
| messageDiv.textContent = content; | |
| chatContainer.appendChild(messageDiv); | |
| chatContainer.scrollTop = chatContainer.scrollHeight; | |
| } | |
| function addSystemMessage(content) { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = 'text-center text-gray-400 text-sm py-2 fade-in'; | |
| messageDiv.textContent = content; | |
| chatContainer.appendChild(messageDiv); | |
| chatContainer.scrollTop = chatContainer.scrollHeight; | |
| } | |
| function addLoadingIndicator() { | |
| const id = `loading-${Date.now()}`; | |
| const loadingDiv = document.createElement('div'); | |
| loadingDiv.id = id; | |
| loadingDiv.className = 'chat-bubble ai-bubble fade-in'; | |
| const dots = document.createElement('div'); | |
| dots.className = 'loading-dots'; | |
| dots.innerHTML = '<span></span><span></span><span></span>'; | |
| loadingDiv.appendChild(dots); | |
| chatContainer.appendChild(loadingDiv); | |
| chatContainer.scrollTop = chatContainer.scrollHeight; | |
| return id; | |
| } | |
| function removeLoadingIndicator(id) { | |
| const element = document.getElementById(id); | |
| if (element) { | |
| element.remove(); | |
| } | |
| } | |
| function clearChat() { | |
| if (!chatActive) return; | |
| conversationHistory = []; | |
| chatContainer.innerHTML = ''; | |
| addSystemMessage('Chat cleared. Ready for new messages.'); | |
| } | |
| function setupEmbedListeners() { | |
| document.addEventListener('process-document', (e) => { | |
| embeddedDocument = e.detail.content; | |
| // Here you would typically call your embedding API | |
| // For demo purposes, we'll just store the content | |
| addSystemMessage('Document ready for processing! Use commands like:'); | |
| addSystemMessage('"Summarize chapter 3" or "Rewrite paragraph 5 to be more formal"'); | |
| }); | |
| } | |
| function toggleTheme() { | |
| const html = document.documentElement; | |
| html.classList.toggle('dark'); | |
| if (html.classList.contains('dark')) { | |
| themeIcon.setAttribute('data-feather', 'moon'); | |
| } else { | |
| themeIcon.setAttribute('data-feather', 'sun'); | |
| } | |
| feather.replace(); | |
| } | |
| }); |