Update index.html
Browse files- index.html +176 -10
index.html
CHANGED
|
@@ -2242,6 +2242,68 @@
|
|
| 2242 |
animation: spin 1s linear infinite;
|
| 2243 |
}
|
| 2244 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2245 |
@keyframes bounce {
|
| 2246 |
|
| 2247 |
0%,
|
|
@@ -4674,7 +4736,13 @@
|
|
| 4674 |
</aside>
|
| 4675 |
|
| 4676 |
<!-- Main Area -->
|
| 4677 |
-
<main class="main-area hero-mode">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4678 |
<div class="main-background-lighting">
|
| 4679 |
<div class="ambient-glow glow-1"></div>
|
| 4680 |
<div class="ambient-glow glow-2"></div>
|
|
@@ -5435,7 +5503,18 @@
|
|
| 5435 |
activateFeature('video');
|
| 5436 |
break;
|
| 5437 |
case 'upload':
|
| 5438 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5439 |
return;
|
| 5440 |
case 'voice':
|
| 5441 |
toggleVoiceMode();
|
|
@@ -5881,6 +5960,83 @@
|
|
| 5881 |
});
|
| 5882 |
}
|
| 5883 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5884 |
function setupEventListeners() {
|
| 5885 |
// FIXED: Restructured with early returns to prevent fall-through bugs
|
| 5886 |
document.addEventListener('click', (e) => {
|
|
@@ -6250,11 +6406,11 @@
|
|
| 6250 |
container.appendChild(textContainer);
|
| 6251 |
container.appendChild(cursor);
|
| 6252 |
|
| 6253 |
-
//
|
| 6254 |
-
for (let i = 0; i < words.length; i +=
|
| 6255 |
if (!isTyping) break;
|
| 6256 |
|
| 6257 |
-
const chunk = words.slice(i, i +
|
| 6258 |
const span = document.createElement('span');
|
| 6259 |
span.className = 'streaming-text';
|
| 6260 |
span.innerHTML = (i === 0 ? '' : ' ') + chunk;
|
|
@@ -6264,9 +6420,8 @@
|
|
| 6264 |
|
| 6265 |
smoothScrollToBottom();
|
| 6266 |
|
| 6267 |
-
//
|
| 6268 |
-
|
| 6269 |
-
await new Promise(resolve => setTimeout(resolve, delay));
|
| 6270 |
}
|
| 6271 |
|
| 6272 |
cursor.remove();
|
|
@@ -6311,8 +6466,14 @@
|
|
| 6311 |
];
|
| 6312 |
let statusIdx = 0;
|
| 6313 |
|
|
|
|
|
|
|
| 6314 |
messageContent.innerHTML = `
|
| 6315 |
<div style="display:flex; flex-direction:column; align-items:flex-start; gap:12px; padding: 10px 0;">
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6316 |
<div class="ai-processing-ring">
|
| 6317 |
<div class="blinking-emoji" style="width:24px; height:24px;">
|
| 6318 |
<div class="eye" style="width:3px; height:5px;"></div>
|
|
@@ -6803,10 +6964,13 @@
|
|
| 6803 |
const data = await response.json();
|
| 6804 |
|
| 6805 |
if (data.results && data.results.length > 0) {
|
|
|
|
|
|
|
|
|
|
| 6806 |
messageContent.innerHTML = `
|
| 6807 |
<div class="tool-output-header">
|
| 6808 |
<i data-lucide="search"></i>
|
| 6809 |
-
<span>Sources Discovered</span>
|
| 6810 |
</div>
|
| 6811 |
<div class="search-results">
|
| 6812 |
${data.results.map(res => `
|
|
@@ -6818,7 +6982,7 @@
|
|
| 6818 |
</div>
|
| 6819 |
<div class="compiling-loader" id="compilingLoader">
|
| 6820 |
<i data-lucide="loader-2"></i>
|
| 6821 |
-
<span>
|
| 6822 |
</div>
|
| 6823 |
`;
|
| 6824 |
if (window.lucide) lucide.createIcons();
|
|
@@ -7685,6 +7849,8 @@
|
|
| 7685 |
}
|
| 7686 |
|
| 7687 |
refreshIcons();
|
|
|
|
|
|
|
| 7688 |
}
|
| 7689 |
|
| 7690 |
// --- SPA Routing Logic ---
|
|
|
|
| 2242 |
animation: spin 1s linear infinite;
|
| 2243 |
}
|
| 2244 |
|
| 2245 |
+
/* Drag and Drop Overlay */
|
| 2246 |
+
.drag-drop-overlay {
|
| 2247 |
+
position: absolute;
|
| 2248 |
+
top: 0;
|
| 2249 |
+
left: 0;
|
| 2250 |
+
width: 100%;
|
| 2251 |
+
height: 100%;
|
| 2252 |
+
background: rgba(16, 163, 127, 0.15);
|
| 2253 |
+
backdrop-filter: blur(8px);
|
| 2254 |
+
border: 2px dashed var(--accent-blue);
|
| 2255 |
+
z-index: 500;
|
| 2256 |
+
display: none;
|
| 2257 |
+
align-items: center;
|
| 2258 |
+
justify-content: center;
|
| 2259 |
+
flex-direction: column;
|
| 2260 |
+
gap: 20px;
|
| 2261 |
+
pointer-events: none;
|
| 2262 |
+
transition: all 0.3s ease;
|
| 2263 |
+
}
|
| 2264 |
+
|
| 2265 |
+
.drag-drop-overlay.active {
|
| 2266 |
+
display: flex;
|
| 2267 |
+
animation: fadeIn 0.3s ease;
|
| 2268 |
+
}
|
| 2269 |
+
|
| 2270 |
+
.drag-drop-icon {
|
| 2271 |
+
width: 80px;
|
| 2272 |
+
height: 80px;
|
| 2273 |
+
background: rgba(16, 163, 127, 0.1);
|
| 2274 |
+
border-radius: 50%;
|
| 2275 |
+
display: flex;
|
| 2276 |
+
align-items: center;
|
| 2277 |
+
justify-content: center;
|
| 2278 |
+
color: var(--accent-blue);
|
| 2279 |
+
animation: pulse-glow 2s infinite;
|
| 2280 |
+
}
|
| 2281 |
+
|
| 2282 |
+
@keyframes pulse-glow {
|
| 2283 |
+
0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(16, 163, 127, 0.4); }
|
| 2284 |
+
50% { transform: scale(1.1); box-shadow: 0 0 20px 10px rgba(16, 163, 127, 0); }
|
| 2285 |
+
}
|
| 2286 |
+
|
| 2287 |
+
.drag-drop-text {
|
| 2288 |
+
font-size: 24px;
|
| 2289 |
+
font-weight: 700;
|
| 2290 |
+
color: var(--text-primary);
|
| 2291 |
+
}
|
| 2292 |
+
|
| 2293 |
+
.llm-badge {
|
| 2294 |
+
display: inline-flex;
|
| 2295 |
+
align-items: center;
|
| 2296 |
+
gap: 6px;
|
| 2297 |
+
background: rgba(255, 255, 255, 0.05);
|
| 2298 |
+
border: 1px solid var(--border-color);
|
| 2299 |
+
padding: 4px 10px;
|
| 2300 |
+
border-radius: 8px;
|
| 2301 |
+
font-size: 11px;
|
| 2302 |
+
color: var(--text-secondary);
|
| 2303 |
+
font-weight: 600;
|
| 2304 |
+
margin-bottom: 8px;
|
| 2305 |
+
}
|
| 2306 |
+
|
| 2307 |
@keyframes bounce {
|
| 2308 |
|
| 2309 |
0%,
|
|
|
|
| 4736 |
</aside>
|
| 4737 |
|
| 4738 |
<!-- Main Area -->
|
| 4739 |
+
<main class="main-area hero-mode" id="mainArea">
|
| 4740 |
+
<div class="drag-drop-overlay" id="dragDropOverlay">
|
| 4741 |
+
<div class="drag-drop-icon">
|
| 4742 |
+
<i data-lucide="upload-cloud" style="width: 40px; height: 40px;"></i>
|
| 4743 |
+
</div>
|
| 4744 |
+
<div class="drag-drop-text">Drop files to upload to Nexa AI</div>
|
| 4745 |
+
</div>
|
| 4746 |
<div class="main-background-lighting">
|
| 4747 |
<div class="ambient-glow glow-1"></div>
|
| 4748 |
<div class="ambient-glow glow-2"></div>
|
|
|
|
| 5503 |
activateFeature('video');
|
| 5504 |
break;
|
| 5505 |
case 'upload':
|
| 5506 |
+
// Trigger hidden file input
|
| 5507 |
+
let fileInput = document.getElementById('hiddenFileInput');
|
| 5508 |
+
if (!fileInput) {
|
| 5509 |
+
fileInput = document.createElement('input');
|
| 5510 |
+
fileInput.type = 'file';
|
| 5511 |
+
fileInput.id = 'hiddenFileInput';
|
| 5512 |
+
fileInput.multiple = true;
|
| 5513 |
+
fileInput.style.display = 'none';
|
| 5514 |
+
fileInput.onchange = (e) => handleFiles(e.target.files);
|
| 5515 |
+
document.body.appendChild(fileInput);
|
| 5516 |
+
}
|
| 5517 |
+
fileInput.click();
|
| 5518 |
return;
|
| 5519 |
case 'voice':
|
| 5520 |
toggleVoiceMode();
|
|
|
|
| 5960 |
});
|
| 5961 |
}
|
| 5962 |
|
| 5963 |
+
function setupDragAndDrop() {
|
| 5964 |
+
const mainArea = document.getElementById('mainArea');
|
| 5965 |
+
const overlay = document.getElementById('dragDropOverlay');
|
| 5966 |
+
|
| 5967 |
+
if (!mainArea || !overlay) return;
|
| 5968 |
+
|
| 5969 |
+
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
| 5970 |
+
mainArea.addEventListener(eventName, (e) => {
|
| 5971 |
+
e.preventDefault();
|
| 5972 |
+
e.stopPropagation();
|
| 5973 |
+
}, false);
|
| 5974 |
+
});
|
| 5975 |
+
|
| 5976 |
+
['dragenter', 'dragover'].forEach(eventName => {
|
| 5977 |
+
mainArea.addEventListener(eventName, () => {
|
| 5978 |
+
overlay.classList.add('active');
|
| 5979 |
+
}, false);
|
| 5980 |
+
});
|
| 5981 |
+
|
| 5982 |
+
['dragleave', 'drop'].forEach(eventName => {
|
| 5983 |
+
mainArea.addEventListener(eventName, () => {
|
| 5984 |
+
overlay.classList.remove('active');
|
| 5985 |
+
}, false);
|
| 5986 |
+
});
|
| 5987 |
+
|
| 5988 |
+
mainArea.addEventListener('drop', (e) => {
|
| 5989 |
+
const dt = e.dataTransfer;
|
| 5990 |
+
const files = dt.files;
|
| 5991 |
+
if (files && files.length > 0) {
|
| 5992 |
+
handleFiles(files);
|
| 5993 |
+
}
|
| 5994 |
+
}, false);
|
| 5995 |
+
}
|
| 5996 |
+
|
| 5997 |
+
function handleFiles(files) {
|
| 5998 |
+
const container = document.getElementById('attachmentsContainer');
|
| 5999 |
+
if (!container) return;
|
| 6000 |
+
|
| 6001 |
+
container.style.display = 'flex';
|
| 6002 |
+
|
| 6003 |
+
Array.from(files).forEach(file => {
|
| 6004 |
+
const card = document.createElement('div');
|
| 6005 |
+
card.className = 'file-attachment-card';
|
| 6006 |
+
card.setAttribute('data-filename', file.name);
|
| 6007 |
+
|
| 6008 |
+
const fileExt = file.name.split('.').pop().toUpperCase();
|
| 6009 |
+
let iconColor = '#3182ce'; // Default blue
|
| 6010 |
+
let iconName = 'file-text';
|
| 6011 |
+
|
| 6012 |
+
if (['JPG', 'JPEG', 'PNG', 'GIF', 'WEBP'].includes(fileExt)) {
|
| 6013 |
+
iconColor = '#10a37f';
|
| 6014 |
+
iconName = 'image';
|
| 6015 |
+
} else if (fileExt === 'PDF') {
|
| 6016 |
+
iconColor = '#e53e3e';
|
| 6017 |
+
iconName = 'file-text';
|
| 6018 |
+
}
|
| 6019 |
+
|
| 6020 |
+
card.innerHTML = `
|
| 6021 |
+
<div class="file-attachment-icon" style="background: ${iconColor}">
|
| 6022 |
+
<i data-lucide="${iconName}" style="width: 18px; height: 18px;"></i>
|
| 6023 |
+
</div>
|
| 6024 |
+
<div class="file-attachment-info">
|
| 6025 |
+
<span class="file-attachment-name">${file.name}</span>
|
| 6026 |
+
<span class="file-attachment-type">${fileExt} File</span>
|
| 6027 |
+
</div>
|
| 6028 |
+
<div class="file-attachment-remove" onclick="this.parentElement.remove(); if(document.getElementById('attachmentsContainer').children.length === 0) document.getElementById('attachmentsContainer').style.display='none';">
|
| 6029 |
+
<i data-lucide="x"></i>
|
| 6030 |
+
</div>
|
| 6031 |
+
`;
|
| 6032 |
+
container.appendChild(card);
|
| 6033 |
+
if (window.lucide) lucide.createIcons();
|
| 6034 |
+
|
| 6035 |
+
// Automatically start analysis if backend supports it
|
| 6036 |
+
handleFileAnalysis(file, card);
|
| 6037 |
+
});
|
| 6038 |
+
}
|
| 6039 |
+
|
| 6040 |
function setupEventListeners() {
|
| 6041 |
// FIXED: Restructured with early returns to prevent fall-through bugs
|
| 6042 |
document.addEventListener('click', (e) => {
|
|
|
|
| 6406 |
container.appendChild(textContainer);
|
| 6407 |
container.appendChild(cursor);
|
| 6408 |
|
| 6409 |
+
// Optimized for maximum speed: Process in larger chunks with minimal delay
|
| 6410 |
+
for (let i = 0; i < words.length; i += 8) {
|
| 6411 |
if (!isTyping) break;
|
| 6412 |
|
| 6413 |
+
const chunk = words.slice(i, i + 8).join(' ');
|
| 6414 |
const span = document.createElement('span');
|
| 6415 |
span.className = 'streaming-text';
|
| 6416 |
span.innerHTML = (i === 0 ? '' : ' ') + chunk;
|
|
|
|
| 6420 |
|
| 6421 |
smoothScrollToBottom();
|
| 6422 |
|
| 6423 |
+
// Minimum possible delay for ultra-fast "writing" effect
|
| 6424 |
+
await new Promise(resolve => setTimeout(resolve, 5));
|
|
|
|
| 6425 |
}
|
| 6426 |
|
| 6427 |
cursor.remove();
|
|
|
|
| 6466 |
];
|
| 6467 |
let statusIdx = 0;
|
| 6468 |
|
| 6469 |
+
const modelLabel = currentAiModel || 'Qwen 2.5';
|
| 6470 |
+
|
| 6471 |
messageContent.innerHTML = `
|
| 6472 |
<div style="display:flex; flex-direction:column; align-items:flex-start; gap:12px; padding: 10px 0;">
|
| 6473 |
+
<div class="llm-badge">
|
| 6474 |
+
<i data-lucide="cpu" style="width:12px;"></i>
|
| 6475 |
+
<span>Using ${modelLabel}</span>
|
| 6476 |
+
</div>
|
| 6477 |
<div class="ai-processing-ring">
|
| 6478 |
<div class="blinking-emoji" style="width:24px; height:24px;">
|
| 6479 |
<div class="eye" style="width:3px; height:5px;"></div>
|
|
|
|
| 6964 |
const data = await response.json();
|
| 6965 |
|
| 6966 |
if (data.results && data.results.length > 0) {
|
| 6967 |
+
const count = data.results.length;
|
| 6968 |
+
addMessage(`🔍 I found **${count} search results** related to your question. Let me visit the most relevant sources to gather accurate information.`, 'ai');
|
| 6969 |
+
|
| 6970 |
messageContent.innerHTML = `
|
| 6971 |
<div class="tool-output-header">
|
| 6972 |
<i data-lucide="search"></i>
|
| 6973 |
+
<span>Intelligence Sources Discovered</span>
|
| 6974 |
</div>
|
| 6975 |
<div class="search-results">
|
| 6976 |
${data.results.map(res => `
|
|
|
|
| 6982 |
</div>
|
| 6983 |
<div class="compiling-loader" id="compilingLoader">
|
| 6984 |
<i data-lucide="loader-2"></i>
|
| 6985 |
+
<span>Synthesizing verified research report...</span>
|
| 6986 |
</div>
|
| 6987 |
`;
|
| 6988 |
if (window.lucide) lucide.createIcons();
|
|
|
|
| 7849 |
}
|
| 7850 |
|
| 7851 |
refreshIcons();
|
| 7852 |
+
setupEventListeners();
|
| 7853 |
+
setupDragAndDrop();
|
| 7854 |
}
|
| 7855 |
|
| 7856 |
// --- SPA Routing Logic ---
|