Fix: Add Hermes introduction and ensure modal dropdown is populated

- Add dynamic Hermes introduction generation when modal opens
- Fetch models directly in modal instead of copying from existing dropdown
- Fix empty dropdown issue by ensuring models are loaded before display
- Add page-specific intro caching and fallback handling
This commit is contained in:
Russell Ballestrini 2025-06-30 21:10:16 -04:00
parent f455f17fa3
commit ebb316fcf1

140
src/ui.js
View file

@ -613,17 +613,14 @@ export async function openHermesModal() {
`;
}
// Copy options from existing model dropdown
const existingDropdown = document.getElementById('model-selection');
if (existingDropdown) {
Array.from(existingDropdown.options).forEach(option => {
const newOption = document.createElement('option');
newOption.value = option.value;
newOption.textContent = option.textContent;
newOption.selected = option.selected;
modelSelect.appendChild(newOption);
});
}
// Populate model dropdown dynamically
const models = await fetchModelsFromEndpoints();
models.forEach(model => {
const option = document.createElement('option');
option.value = model.uniqueId;
option.textContent = `${model.endpointId} | ${model.modelName}`;
modelSelect.appendChild(option);
});
// Restore saved model selection
const savedModel = localStorage.getItem('hermes-selected-model');
@ -719,18 +716,26 @@ export async function openHermesModal() {
localStorage.removeItem('vllmEndpointsHash');
const models = await fetchModelsFromEndpoints();
// Update both dropdowns
[modelSelect, document.getElementById('model-selection')].forEach(dropdown => {
if (dropdown) {
dropdown.innerHTML = '';
models.forEach(model => {
const option = document.createElement('option');
option.value = model.uniqueId;
option.textContent = `${model.endpointId} | ${model.modelName}`;
dropdown.appendChild(option);
});
}
// Update modal dropdown
modelSelect.innerHTML = '';
models.forEach(model => {
const option = document.createElement('option');
option.value = model.uniqueId;
option.textContent = `${model.endpointId} | ${model.modelName}`;
modelSelect.appendChild(option);
});
// Update main page dropdown if it exists
const mainDropdown = document.getElementById('model-selection');
if (mainDropdown) {
mainDropdown.innerHTML = '';
models.forEach(model => {
const option = document.createElement('option');
option.value = model.uniqueId;
option.textContent = `${model.endpointId} | ${model.modelName}`;
mainDropdown.appendChild(option);
});
}
};
const clearBtn = document.createElement('button');
@ -847,6 +852,97 @@ export async function openHermesModal() {
}
restoreConversationHistory();
// Generate dynamic Hermes introduction using LLM
async function addHermesIntroduction() {
const history = loadConversationHistory();
if (history.length === 0) {
const pageContent = extractWebpageContent();
const pageTitle = document.title;
const pageUrl = window.location.href;
// Create cache key based on page content hash (handle Unicode safely)
const contentForHash = pageContent.substring(0, 1000);
let contentHash;
try {
contentHash = btoa(unescape(encodeURIComponent(contentForHash))).replace(/[^a-zA-Z0-9]/g, '').substring(0, 32);
} catch (e) {
// Fallback: use simple string hash if btoa fails
let hash = 0;
for (let i = 0; i < contentForHash.length; i++) {
const char = contentForHash.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
contentHash = Math.abs(hash).toString(36).substring(0, 32);
}
const cacheKey = `hermes-intro-${contentHash}`;
// Check if we have a cached introduction for this page content
const cachedIntro = localStorage.getItem(cacheKey);
if (cachedIntro) {
displayIntroduction(cachedIntro);
// Add cached intro to chat history
chatHistory.push({ role: "assistant", content: cachedIntro });
saveConversationHistory(chatHistory);
return;
}
// Generate new introduction using LLM
const introDiv = document.createElement('div');
introDiv.style.cssText = 'position: relative; margin-bottom: 10px; padding: 10px; border-radius: 5px; background: rgba(0,100,200,0.1); border-left: 4px solid #0066cc;';
introDiv.innerHTML = '<p><strong>🤖 Hermes:</strong> <em>✨ Analyzing this page and crafting a personalized introduction... This may take a moment.</em></p>';
chatBox.appendChild(introDiv);
chatBox.scrollTop = chatBox.scrollHeight;
try {
const prompt = `You are Hermes, a large language model from Nous Research. Write a friendly 3-paragraph introduction for yourself when embedded on this webpage. Be specific about this page's content and identify 2-3 key takeaways. Keep it conversational and helpful.
Page Title: ${pageTitle}
Page URL: ${pageUrl}
Page Content: ${pageContent.substring(0, 2000)}
Format: Start with "Greetings! I'm Hermes..." and make it sound natural and engaging. Write 3 full paragraphs that showcase your capabilities and how you can help with THIS specific page.`;
let generatedIntro = '';
for await (const chunk of sendMessage(prompt)) {
generatedIntro += chunk;
// Update display in real-time
introDiv.innerHTML = `<p><strong>🤖 Hermes:</strong> ${generatedIntro}</p>`;
// Scroll to bottom as content updates
chatBox.scrollTop = chatBox.scrollHeight;
}
// Add to chat history and save
chatHistory.push({ role: "assistant", content: generatedIntro });
saveConversationHistory(chatHistory);
// Cache the generated introduction
localStorage.setItem(cacheKey, generatedIntro);
chatBox.scrollTop = chatBox.scrollHeight;
} catch (error) {
console.error('Error generating introduction:', error);
const fallbackIntro = 'Greetings! I\'m Hermes, a large language model from Nous Research. I\'m here to help you understand this page and assist with any questions, coding, or creative tasks you might have. Feel free to ask me anything!';
introDiv.innerHTML = `<p><strong>🤖 Hermes:</strong> ${fallbackIntro}</p>`;
// Add fallback to chat history too
chatHistory.push({ role: "assistant", content: fallbackIntro });
saveConversationHistory(chatHistory);
}
}
}
function displayIntroduction(introText) {
const introDiv = document.createElement('div');
introDiv.style.cssText = 'position: relative; margin-bottom: 10px; padding: 10px; border-radius: 5px; background: rgba(0,100,200,0.1); border-left: 4px solid #0066cc;';
introDiv.innerHTML = `<p><strong>🤖 Hermes:</strong> ${introText}</p>`;
chatBox.appendChild(introDiv);
chatBox.scrollTop = chatBox.scrollHeight;
}
// Call addHermesIntroduction after restoring history
await addHermesIntroduction();
// Create input area
const inputArea = document.createElement('div');
if (USE_CUSTOM_STYLING) {