nexusnarrative-core / script.js
hts-ai's picture
nous sommes tout les deux des ingenieur d'ia sybersecurité :: mistral (garde fou) ------ LLM. (nvidia -- gpt oss 120 )--mem0. (gemma 3) ---mistral garde fou. Openrouter. Token.
fd64174 verified
Raw
History Blame Contribute Delete
8.76 kB
document.addEventListener('DOMContentLoaded', () => {
// Chat Interface Logic
const chatMessages = document.getElementById('chat-messages');
const chatInput = document.getElementById('chat-input');
const sendBtn = document.getElementById('send-btn');
const modelSelector = document.getElementById('model-selector');
const reasoningToggle = document.getElementById('reasoning-toggle');
const apiKeyInput = document.getElementById('api-key');
const tokenCount = document.getElementById('token-count');
const latencyDisplay = document.getElementById('latency-display');
let conversationHistory = [];
let totalTokens = 0;
// Default API Key (user can override)
const DEFAULT_API_KEY = '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';
function getApiKey() {
return apiKeyInput.value.trim() || DEFAULT_API_KEY;
}
function addMessage(role, content, reasoning = null) {
const messageDiv = document.createElement('div');
messageDiv.className = 'flex gap-3' + (role === 'user' ? ' flex-row-reverse' : '');
const avatar = role === 'user'
? `<div class="w-8 h-8 rounded-full bg-ai-500/20 flex items-center justify-center flex-shrink-0">
<i data-feather="user" class="w-4 h-4 text-ai-400"></i>
</div>`
: `<div class="w-8 h-8 rounded-full bg-cyber-500/20 flex items-center justify-center flex-shrink-0">
<i data-feather="bot" class="w-4 h-4 text-cyber-400"></i>
</div>`;
let contentHtml = `<p class="text-slate-300 text-sm whitespace-pre-wrap">${escapeHtml(content)}</p>`;
if (reasoning) {
contentHtml = `
<details class="mb-2">
<summary class="text-xs text-amber-400 cursor-pointer hover:text-amber-300 flex items-center gap-1">
<i data-feather="zap" class="w-3 h-3"></i> Reasoning Process
</summary>
<div class="mt-2 p-2 bg-slate-900/50 rounded border border-slate-700 text-xs text-slate-400 font-mono whitespace-pre-wrap">${escapeHtml(reasoning)}</div>
</details>
${contentHtml}
`;
}
messageDiv.innerHTML = `
${avatar}
<div class="bg-slate-800/50 border border-slate-700 rounded-lg p-3 max-w-2xl ${role === 'user' ? 'bg-ai-500/10 border-ai-500/30' : ''}">
<div class="text-xs text-slate-500 mb-1 font-mono">${role === 'user' ? 'YOU' : modelSelector.options[modelSelector.selectedIndex].text.split('(')[0].trim()}</div>
${contentHtml}
</div>
`;
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
if (window.feather) {
window.feather.replace();
}
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
async function sendMessage() {
const message = chatInput.value.trim();
if (!message) return;
const model = modelSelector.value;
const useReasoning = reasoningToggle.checked && (
model.includes('nemotron') || model.includes('gpt-oss')
);
const apiKey = getApiKey();
// Add user message
addMessage('user', message);
chatInput.value = '';
// Add to conversation history
conversationHistory.push({ role: 'user', content: message });
// Show loading
const loadingDiv = document.createElement('div');
loadingDiv.className = 'flex gap-3';
loadingDiv.id = 'loading-indicator';
loadingDiv.innerHTML = `
<div class="w-8 h-8 rounded-full bg-cyber-500/20 flex items-center justify-center flex-shrink-0">
<i data-feather="bot" class="w-4 h-4 text-cyber-400 animate-pulse"></i>
</div>
<div class="bg-slate-800/50 border border-slate-700 rounded-lg p-3">
<div class="flex gap-1">
<div class="w-2 h-2 bg-cyber-400 rounded-full animate-bounce"></div>
<div class="w-2 h-2 bg-cyber-400 rounded-full animate-bounce" style="animation-delay: 0.1s"></div>
<div class="w-2 h-2 bg-cyber-400 rounded-full animate-bounce" style="animation-delay: 0.2s"></div>
</div>
</div>
`;
chatMessages.appendChild(loadingDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
const startTime = performance.now();
try {
const requestBody = {
model: model,
messages: conversationHistory
};
if (useReasoning) {
requestBody.extra_body = { reasoning: { enabled: true } };
}
const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`,
'HTTP-Referer': window.location.href,
'X-Title': 'NexusNarrative Core'
},
body: JSON.stringify(requestBody)
});
if (!response.ok) {
throw new Error(`API Error: ${response.status} ${response.statusText}`);
}
const data = await response.json();
const endTime = performance.now();
const latency = Math.round(endTime - startTime);
// Remove loading
document.getElementById('loading-indicator')?.remove();
// Extract response
const assistantMessage = data.choices[0].message;
const reasoningDetails = assistantMessage.reasoning_details || null;
// Update stats
totalTokens += data.usage?.total_tokens || 0;
tokenCount.textContent = `Tokens: ${totalTokens.toLocaleString()}`;
latencyDisplay.textContent = `Latency: ${latency}ms`;
// Add assistant response
addMessage('assistant', assistantMessage.content, reasoningDetails);
// Update conversation history
if (reasoningDetails) {
conversationHistory.push({
role: 'assistant',
content: assistantMessage.content,
reasoning_details: reasoningDetails
});
} else {
conversationHistory.push({
role: 'assistant',
content: assistantMessage.content
});
}
} catch (error) {
document.getElementById('loading-indicator')?.remove();
addMessage('assistant', `Erreur: ${error.message}`);
}
}
// Event listeners
sendBtn.addEventListener('click', sendMessage);
chatInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendMessage();
});
// Simulate live logs in the terminal
const logsContainer = document.getElementById('terminal-logs');
const messages = [
{ type: 'DIRECTOR', text: 'Optimizing task queue...', color: 'text-cyber-400' },
{ type: 'SYSTEM', text: 'Garbage collection cleared 24MB.', color: 'text-slate-500' },
{ type: 'WRITER', text: 'Drafting chapter 4 scene 2...', color: 'text-ai-400' },
{ type: 'LORE', text: 'Updating character vector: "Kael"', color: 'text-amber-400' },
{ type: 'SYSTEM', text: 'Health check passed. Latency: 14ms', color: 'text-slate-500' }
];
let msgIndex = 0;
function addLog() {
if(!logsContainer) return;
const msg = messages[msgIndex % messages.length];
const div = document.createElement('div');
div.className = 'mb-1 opacity-0 transition-opacity duration-500';
div.innerHTML = `<span class="${msg.color}">[${msg.type}]</span> ${msg.text}`;
// Insert before the last prompt line
const lastLine = logsContainer.lastElementChild;
logsContainer.insertBefore(div, lastLine);
// Trigger reflow for animation
setTimeout(() => div.classList.remove('opacity-0'), 50);
// Auto scroll
logsContainer.scrollTop = logsContainer.scrollHeight;
msgIndex++;
// Random interval between 2s and 5s
const nextTime = Math.random() * 3000 + 2000;
setTimeout(addLog, nextTime);
}
// Start simulation after 1s
setTimeout(addLog, 1000);
});