Captain3000's picture
i dont want to input my api key when i load the page.
a59bde4 verified
Raw History Blame Contribute Delete
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();
}
});