Spaces:
Sleeping
Sleeping
Update templates/index.html
Browse files- templates/index.html +637 -15
templates/index.html
CHANGED
@@ -345,6 +345,9 @@
|
|
345 |
row.parentNode.insertBefore(insightsRow, row.nextSibling);
|
346 |
}
|
347 |
|
|
|
|
|
|
|
348 |
// Send request to extract insights
|
349 |
fetch('/post_insights', {
|
350 |
method: 'POST',
|
@@ -371,25 +374,47 @@
|
|
371 |
const insightsActions = document.createElement('div');
|
372 |
insightsActions.className = 'insights-actions';
|
373 |
|
|
|
|
|
|
|
|
|
374 |
const selectAllBtn = document.createElement('button');
|
375 |
-
selectAllBtn.className = 'insights-button';
|
376 |
selectAllBtn.textContent = 'Select All';
|
377 |
-
|
378 |
-
|
|
|
|
|
|
|
|
|
|
|
379 |
tags.forEach(tag => tag.classList.add('selected'));
|
380 |
-
|
381 |
-
|
382 |
-
|
|
|
|
|
|
|
|
|
383 |
|
384 |
const clearAllBtn = document.createElement('button');
|
385 |
-
clearAllBtn.className = 'insights-button';
|
386 |
clearAllBtn.textContent = 'Clear All';
|
387 |
-
|
388 |
-
|
|
|
|
|
|
|
|
|
|
|
389 |
tags.forEach(tag => tag.classList.remove('selected'));
|
390 |
-
|
391 |
-
|
392 |
-
|
|
|
|
|
|
|
|
|
393 |
|
394 |
insightsActions.appendChild(selectAllBtn);
|
395 |
insightsActions.appendChild(clearAllBtn);
|
@@ -415,12 +440,15 @@
|
|
415 |
const tagElement = document.createElement('div');
|
416 |
tagElement.className = 'insight-tag';
|
417 |
tagElement.textContent = insight;
|
418 |
-
tagElement.
|
419 |
-
|
420 |
|
421 |
// Update selected insights
|
422 |
updateSelectedInsights(row, insightsContainer);
|
423 |
-
|
|
|
|
|
|
|
424 |
|
425 |
// Add to selected by default
|
426 |
tagElement.classList.add('selected');
|
@@ -433,6 +461,9 @@
|
|
433 |
row.dataset.selectedInsights = JSON.stringify(selectedInsights);
|
434 |
row.dataset.unselectedInsights = JSON.stringify(unselectedInsights);
|
435 |
|
|
|
|
|
|
|
436 |
} else {
|
437 |
insightsContainer.innerHTML = '<div class="error">No insights found</div>';
|
438 |
}
|
@@ -1202,6 +1233,584 @@
|
|
1202 |
|
1203 |
return accordionSection;
|
1204 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1205 |
</script>
|
1206 |
</head>
|
1207 |
<body>
|
@@ -1282,6 +1891,12 @@
|
|
1282 |
<button id="enhanceProblemButton" class="btn enhance-problem-button floating-button disabled" title="Enhance Problem using Selected Insights" onclick="enhanceProblem()" disabled>
|
1283 |
Enhance Problem
|
1284 |
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
1285 |
<button id="analyzeAllButton" class="btn btn-primary floating-button" title="Analyze All Unanalyzed Papers">
|
1286 |
Analyze All
|
1287 |
</button>
|
@@ -1310,9 +1925,16 @@
|
|
1310 |
// Check for selected insights periodically to enable/disable enhance button
|
1311 |
setInterval(checkSelectedInsights, 1000);
|
1312 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1313 |
// Analyze all button
|
1314 |
document.getElementById('analyzeAllButton').addEventListener('click', function() {
|
1315 |
analyzeAllPapers();
|
|
|
1316 |
});
|
1317 |
|
1318 |
// Remove failed button
|
|
|
345 |
row.parentNode.insertBefore(insightsRow, row.nextSibling);
|
346 |
}
|
347 |
|
348 |
+
// Store the row reference as a data attribute on the container for later access
|
349 |
+
insightsContainer.dataset.parentRow = row.rowIndex;
|
350 |
+
|
351 |
// Send request to extract insights
|
352 |
fetch('/post_insights', {
|
353 |
method: 'POST',
|
|
|
374 |
const insightsActions = document.createElement('div');
|
375 |
insightsActions.className = 'insights-actions';
|
376 |
|
377 |
+
// Store the insights for this specific container
|
378 |
+
const containerInsights = [...data.result.insights];
|
379 |
+
insightsContainer.dataset.allInsights = JSON.stringify(containerInsights);
|
380 |
+
|
381 |
const selectAllBtn = document.createElement('button');
|
382 |
+
selectAllBtn.className = 'insights-button select-all-btn';
|
383 |
selectAllBtn.textContent = 'Select All';
|
384 |
+
// Use a closure to ensure the button has access to the correct container and row
|
385 |
+
selectAllBtn.addEventListener('click', function() {
|
386 |
+
const container = this.closest('.insights-container');
|
387 |
+
const parentRow = row;
|
388 |
+
const allInsights = JSON.parse(container.dataset.allInsights || '[]');
|
389 |
+
|
390 |
+
const tags = container.querySelectorAll('.insight-tag');
|
391 |
tags.forEach(tag => tag.classList.add('selected'));
|
392 |
+
|
393 |
+
parentRow.dataset.selectedInsights = JSON.stringify(allInsights);
|
394 |
+
parentRow.dataset.unselectedInsights = JSON.stringify([]);
|
395 |
+
|
396 |
+
// Trigger check for enabling/disabling enhance button
|
397 |
+
checkSelectedInsights();
|
398 |
+
});
|
399 |
|
400 |
const clearAllBtn = document.createElement('button');
|
401 |
+
clearAllBtn.className = 'insights-button clear-all-btn';
|
402 |
clearAllBtn.textContent = 'Clear All';
|
403 |
+
// Use a closure to ensure the button has access to the correct container and row
|
404 |
+
clearAllBtn.addEventListener('click', function() {
|
405 |
+
const container = this.closest('.insights-container');
|
406 |
+
const parentRow = row;
|
407 |
+
const allInsights = JSON.parse(container.dataset.allInsights || '[]');
|
408 |
+
|
409 |
+
const tags = container.querySelectorAll('.insight-tag');
|
410 |
tags.forEach(tag => tag.classList.remove('selected'));
|
411 |
+
|
412 |
+
parentRow.dataset.selectedInsights = JSON.stringify([]);
|
413 |
+
parentRow.dataset.unselectedInsights = JSON.stringify(allInsights);
|
414 |
+
|
415 |
+
// Trigger check for enabling/disabling enhance button
|
416 |
+
checkSelectedInsights();
|
417 |
+
});
|
418 |
|
419 |
insightsActions.appendChild(selectAllBtn);
|
420 |
insightsActions.appendChild(clearAllBtn);
|
|
|
440 |
const tagElement = document.createElement('div');
|
441 |
tagElement.className = 'insight-tag';
|
442 |
tagElement.textContent = insight;
|
443 |
+
tagElement.addEventListener('click', function() {
|
444 |
+
this.classList.toggle('selected');
|
445 |
|
446 |
// Update selected insights
|
447 |
updateSelectedInsights(row, insightsContainer);
|
448 |
+
|
449 |
+
// Trigger check for enabling/disabling enhance button
|
450 |
+
checkSelectedInsights();
|
451 |
+
});
|
452 |
|
453 |
// Add to selected by default
|
454 |
tagElement.classList.add('selected');
|
|
|
461 |
row.dataset.selectedInsights = JSON.stringify(selectedInsights);
|
462 |
row.dataset.unselectedInsights = JSON.stringify(unselectedInsights);
|
463 |
|
464 |
+
// Trigger check for enabling/disabling enhance button immediately
|
465 |
+
checkSelectedInsights();
|
466 |
+
|
467 |
} else {
|
468 |
insightsContainer.innerHTML = '<div class="error">No insights found</div>';
|
469 |
}
|
|
|
1233 |
|
1234 |
return accordionSection;
|
1235 |
}
|
1236 |
+
|
1237 |
+
// Extract insights from all analyzed documents
|
1238 |
+
function extractAllInsights() {
|
1239 |
+
const patentBackground = document.getElementById('userInput').value.trim();
|
1240 |
+
if (!patentBackground) {
|
1241 |
+
alert('Please provide a patent background in the input field');
|
1242 |
+
return;
|
1243 |
+
}
|
1244 |
+
|
1245 |
+
// Show loading overlay
|
1246 |
+
const loadingOverlay = document.getElementById('globalLoadingOverlay');
|
1247 |
+
if (loadingOverlay) {
|
1248 |
+
loadingOverlay.style.display = 'flex';
|
1249 |
+
loadingOverlay.querySelector('.progress-text').textContent = 'Extracting insights from all documents...';
|
1250 |
+
}
|
1251 |
+
|
1252 |
+
// Get all query items
|
1253 |
+
const queryItems = document.querySelectorAll('.query-item');
|
1254 |
+
let totalDocuments = 0;
|
1255 |
+
let completedDocuments = 0;
|
1256 |
+
|
1257 |
+
// Count total analyzed documents that need insights extraction
|
1258 |
+
const analyzedRows = [];
|
1259 |
+
queryItems.forEach(queryItem => {
|
1260 |
+
const rows = queryItem.querySelectorAll('tbody tr:not(.insights-row)');
|
1261 |
+
rows.forEach(row => {
|
1262 |
+
// Only include rows that have been analyzed (have score and justification cells)
|
1263 |
+
if (row.cells.length > 4 && row.cells[4].textContent.trim() !== 'Error' &&
|
1264 |
+
row.cells[4].textContent.trim() !== 'N/A' && row.cells[4].textContent.trim() !== '') {
|
1265 |
+
analyzedRows.push(row);
|
1266 |
+
totalDocuments++;
|
1267 |
+
}
|
1268 |
+
});
|
1269 |
+
});
|
1270 |
+
|
1271 |
+
if (totalDocuments === 0) {
|
1272 |
+
if (loadingOverlay) loadingOverlay.style.display = 'none';
|
1273 |
+
alert('No analyzed documents found. Please analyze documents first.');
|
1274 |
+
return;
|
1275 |
+
}
|
1276 |
+
|
1277 |
+
// Function to update progress
|
1278 |
+
function updateProgress() {
|
1279 |
+
completedDocuments++;
|
1280 |
+
if (loadingOverlay) {
|
1281 |
+
const progressElement = loadingOverlay.querySelector('.progress-text');
|
1282 |
+
if (progressElement) {
|
1283 |
+
progressElement.textContent = `Extracting insights: ${completedDocuments}/${totalDocuments}`;
|
1284 |
+
}
|
1285 |
+
}
|
1286 |
+
|
1287 |
+
if (completedDocuments >= totalDocuments) {
|
1288 |
+
if (loadingOverlay) loadingOverlay.style.display = 'none';
|
1289 |
+
checkSelectedInsights(); // Update enhance button state based on selected insights
|
1290 |
+
}
|
1291 |
+
}
|
1292 |
+
|
1293 |
+
// Process each analyzed document sequentially to avoid overwhelming the server
|
1294 |
+
function processNextDocument(index) {
|
1295 |
+
if (index >= analyzedRows.length) {
|
1296 |
+
return; // All documents processed
|
1297 |
+
}
|
1298 |
+
|
1299 |
+
const row = analyzedRows[index];
|
1300 |
+
const urlLink = row.querySelector('.url-link');
|
1301 |
+
const documentType = row.cells[0].textContent.toLowerCase();
|
1302 |
+
|
1303 |
+
if (!urlLink || !urlLink.href) {
|
1304 |
+
updateProgress();
|
1305 |
+
processNextDocument(index + 1);
|
1306 |
+
return;
|
1307 |
+
}
|
1308 |
+
|
1309 |
+
// Check if there's already an insights row for this document
|
1310 |
+
let insightsRow = row.nextElementSibling;
|
1311 |
+
if (insightsRow && insightsRow.className === 'insights-row') {
|
1312 |
+
// Insights row already exists, get the container
|
1313 |
+
insightsContainer = insightsRow.querySelector('.insights-container');
|
1314 |
+
insightsContainer.innerHTML = '<div class="loading-spinner"></div><div>Extracting insights...</div>';
|
1315 |
+
} else {
|
1316 |
+
// Create insights row that spans across all columns
|
1317 |
+
insightsRow = document.createElement('tr');
|
1318 |
+
insightsRow.className = 'insights-row';
|
1319 |
+
|
1320 |
+
const insightsTd = document.createElement('td');
|
1321 |
+
insightsTd.colSpan = row.cells.length;
|
1322 |
+
|
1323 |
+
insightsContainer = document.createElement('div');
|
1324 |
+
insightsContainer.className = 'insights-container';
|
1325 |
+
insightsContainer.innerHTML = '<div class="loading-spinner"></div><div>Extracting insights...</div>';
|
1326 |
+
|
1327 |
+
insightsTd.appendChild(insightsContainer);
|
1328 |
+
insightsRow.appendChild(insightsTd);
|
1329 |
+
|
1330 |
+
// Insert after the current row
|
1331 |
+
row.parentNode.insertBefore(insightsRow, row.nextSibling);
|
1332 |
+
}
|
1333 |
+
|
1334 |
+
// Store the row reference as a data attribute on the container for later access
|
1335 |
+
insightsContainer.dataset.parentRow = row.rowIndex;
|
1336 |
+
|
1337 |
+
// Send request to extract insights
|
1338 |
+
fetch('/post_insights', {
|
1339 |
+
method: 'POST',
|
1340 |
+
body: JSON.stringify({
|
1341 |
+
'patent_background': patentBackground,
|
1342 |
+
'pdf_url': urlLink.href,
|
1343 |
+
'data_type': documentType
|
1344 |
+
}),
|
1345 |
+
headers: { 'Content-Type': 'application/json' }
|
1346 |
+
})
|
1347 |
+
.then(response => response.json())
|
1348 |
+
.then(data => {
|
1349 |
+
if (data.error) {
|
1350 |
+
insightsContainer.innerHTML = `<div class="error">Error: ${data.error}</div>`;
|
1351 |
+
} else if (data.result && data.result.insights) {
|
1352 |
+
// Create header with title and actions
|
1353 |
+
const insightsHeader = document.createElement('div');
|
1354 |
+
insightsHeader.className = 'insights-header';
|
1355 |
+
|
1356 |
+
const insightsTitle = document.createElement('div');
|
1357 |
+
insightsTitle.className = 'insights-title';
|
1358 |
+
insightsTitle.textContent = 'Document Insights';
|
1359 |
+
|
1360 |
+
const insightsActions = document.createElement('div');
|
1361 |
+
insightsActions.className = 'insights-actions';
|
1362 |
+
|
1363 |
+
// Store the insights for this specific container
|
1364 |
+
const containerInsights = [...data.result.insights];
|
1365 |
+
insightsContainer.dataset.allInsights = JSON.stringify(containerInsights);
|
1366 |
+
|
1367 |
+
const selectAllBtn = document.createElement('button');
|
1368 |
+
selectAllBtn.className = 'insights-button select-all-btn';
|
1369 |
+
selectAllBtn.textContent = 'Select All';
|
1370 |
+
selectAllBtn.addEventListener('click', function() {
|
1371 |
+
const container = this.closest('.insights-container');
|
1372 |
+
const parentRow = row;
|
1373 |
+
const allInsights = JSON.parse(container.dataset.allInsights || '[]');
|
1374 |
+
|
1375 |
+
const tags = container.querySelectorAll('.insight-tag');
|
1376 |
+
tags.forEach(tag => tag.classList.add('selected'));
|
1377 |
+
|
1378 |
+
parentRow.dataset.selectedInsights = JSON.stringify(allInsights);
|
1379 |
+
parentRow.dataset.unselectedInsights = JSON.stringify([]);
|
1380 |
+
|
1381 |
+
checkSelectedInsights();
|
1382 |
+
});
|
1383 |
+
|
1384 |
+
const clearAllBtn = document.createElement('button');
|
1385 |
+
clearAllBtn.className = 'insights-button clear-all-btn';
|
1386 |
+
clearAllBtn.textContent = 'Clear All';
|
1387 |
+
clearAllBtn.addEventListener('click', function() {
|
1388 |
+
const container = this.closest('.insights-container');
|
1389 |
+
const parentRow = row;
|
1390 |
+
const allInsights = JSON.parse(container.dataset.allInsights || '[]');
|
1391 |
+
|
1392 |
+
const tags = container.querySelectorAll('.insight-tag');
|
1393 |
+
tags.forEach(tag => tag.classList.remove('selected'));
|
1394 |
+
|
1395 |
+
parentRow.dataset.selectedInsights = JSON.stringify([]);
|
1396 |
+
parentRow.dataset.unselectedInsights = JSON.stringify(allInsights);
|
1397 |
+
|
1398 |
+
checkSelectedInsights();
|
1399 |
+
});
|
1400 |
+
|
1401 |
+
insightsActions.appendChild(selectAllBtn);
|
1402 |
+
insightsActions.appendChild(clearAllBtn);
|
1403 |
+
|
1404 |
+
insightsHeader.appendChild(insightsTitle);
|
1405 |
+
insightsHeader.appendChild(insightsActions);
|
1406 |
+
|
1407 |
+
// Create insight tags
|
1408 |
+
const insightsList = document.createElement('div');
|
1409 |
+
insightsList.className = 'insights-list';
|
1410 |
+
|
1411 |
+
// Clear the container and add the new elements
|
1412 |
+
insightsContainer.innerHTML = '';
|
1413 |
+
insightsContainer.appendChild(insightsHeader);
|
1414 |
+
insightsContainer.appendChild(insightsList);
|
1415 |
+
|
1416 |
+
// Initialize selected insights
|
1417 |
+
const selectedInsights = [];
|
1418 |
+
const unselectedInsights = [];
|
1419 |
+
|
1420 |
+
// Add insight tags
|
1421 |
+
data.result.insights.forEach(insight => {
|
1422 |
+
const tagElement = document.createElement('div');
|
1423 |
+
tagElement.className = 'insight-tag';
|
1424 |
+
tagElement.textContent = insight;
|
1425 |
+
tagElement.addEventListener('click', function() {
|
1426 |
+
this.classList.toggle('selected');
|
1427 |
+
updateSelectedInsights(row, insightsContainer);
|
1428 |
+
checkSelectedInsights();
|
1429 |
+
});
|
1430 |
+
|
1431 |
+
// Add to selected by default
|
1432 |
+
tagElement.classList.add('selected');
|
1433 |
+
selectedInsights.push(insight);
|
1434 |
+
|
1435 |
+
insightsList.appendChild(tagElement);
|
1436 |
+
});
|
1437 |
+
|
1438 |
+
// Store initial selections
|
1439 |
+
row.dataset.selectedInsights = JSON.stringify(selectedInsights);
|
1440 |
+
row.dataset.unselectedInsights = JSON.stringify(unselectedInsights);
|
1441 |
+
|
1442 |
+
} else {
|
1443 |
+
insightsContainer.innerHTML = '<div class="error">No insights found</div>';
|
1444 |
+
}
|
1445 |
+
|
1446 |
+
// Process next document
|
1447 |
+
updateProgress();
|
1448 |
+
processNextDocument(index + 1);
|
1449 |
+
})
|
1450 |
+
.catch(error => {
|
1451 |
+
console.error('Error:', error);
|
1452 |
+
insightsContainer.innerHTML = `<div class="error">Error extracting insights: ${error.message}</div>`;
|
1453 |
+
|
1454 |
+
// Continue with next document even if this one failed
|
1455 |
+
updateProgress();
|
1456 |
+
processNextDocument(index + 1);
|
1457 |
+
});
|
1458 |
+
}
|
1459 |
+
|
1460 |
+
// Start processing documents
|
1461 |
+
processNextDocument(0);
|
1462 |
+
}
|
1463 |
+
|
1464 |
+
// Check if any documents have been analyzed to enable/disable Extract All Insights button
|
1465 |
+
function checkAnalyzedDocuments() {
|
1466 |
+
const queryItems = document.querySelectorAll('.query-item');
|
1467 |
+
let hasAnalyzedDocuments = false;
|
1468 |
+
|
1469 |
+
queryItems.forEach(queryItem => {
|
1470 |
+
const rows = queryItem.querySelectorAll('tbody tr:not(.insights-row)');
|
1471 |
+
rows.forEach(row => {
|
1472 |
+
// Check if the row has score and justification cells (has been analyzed)
|
1473 |
+
if (row.cells.length > 4 && row.cells[4].textContent.trim() !== 'Error' &&
|
1474 |
+
row.cells[4].textContent.trim() !== '') {
|
1475 |
+
hasAnalyzedDocuments = true;
|
1476 |
+
}
|
1477 |
+
});
|
1478 |
+
});
|
1479 |
+
|
1480 |
+
const extractAllButton = document.getElementById('extractAllInsightsButton');
|
1481 |
+
if (hasAnalyzedDocuments) {
|
1482 |
+
extractAllButton.classList.remove('disabled');
|
1483 |
+
extractAllButton.disabled = false;
|
1484 |
+
} else {
|
1485 |
+
extractAllButton.classList.add('disabled');
|
1486 |
+
extractAllButton.disabled = true;
|
1487 |
+
}
|
1488 |
+
}
|
1489 |
+
|
1490 |
+
// Group insights by score and display in a consolidated table
|
1491 |
+
function groupInsightsByScore() {
|
1492 |
+
// Get all query items
|
1493 |
+
const queryItems = document.querySelectorAll('.query-item');
|
1494 |
+
let hasInsights = false;
|
1495 |
+
|
1496 |
+
// Create structure to hold insights grouped by score
|
1497 |
+
const insightsByScore = {
|
1498 |
+
5: { insights: [], sources: [] },
|
1499 |
+
4: { insights: [], sources: [] },
|
1500 |
+
3: { insights: [], sources: [] },
|
1501 |
+
2: { insights: [], sources: [] },
|
1502 |
+
1: { insights: [], sources: [] },
|
1503 |
+
0: { insights: [], sources: [] }
|
1504 |
+
};
|
1505 |
+
|
1506 |
+
// Collect all insights from all documents and group by score
|
1507 |
+
queryItems.forEach(queryItem => {
|
1508 |
+
const rows = queryItem.querySelectorAll('tbody tr:not(.insights-row)');
|
1509 |
+
rows.forEach(row => {
|
1510 |
+
// Skip if no score or insights
|
1511 |
+
if (row.cells.length <= 4 || !row.dataset.selectedInsights) {
|
1512 |
+
return;
|
1513 |
+
}
|
1514 |
+
|
1515 |
+
// Get the score
|
1516 |
+
const scoreText = row.cells[4].textContent.trim();
|
1517 |
+
if (scoreText === 'Error' || scoreText === 'N/A' || isNaN(parseFloat(scoreText))) {
|
1518 |
+
return;
|
1519 |
+
}
|
1520 |
+
|
1521 |
+
const score = Math.round(parseFloat(scoreText));
|
1522 |
+
const urlLink = row.querySelector('.url-link');
|
1523 |
+
|
1524 |
+
if (!urlLink) return;
|
1525 |
+
|
1526 |
+
// Get insights from this document
|
1527 |
+
try {
|
1528 |
+
const selectedInsights = JSON.parse(row.dataset.selectedInsights || '[]');
|
1529 |
+
const unselectedInsights = JSON.parse(row.dataset.unselectedInsights || '[]');
|
1530 |
+
const allInsights = [...selectedInsights, ...unselectedInsights];
|
1531 |
+
|
1532 |
+
// Add insights to the appropriate score group
|
1533 |
+
if (score >= 0 && score <= 5 && allInsights.length > 0) {
|
1534 |
+
hasInsights = true;
|
1535 |
+
|
1536 |
+
// For all insights in this document
|
1537 |
+
allInsights.forEach(insight => {
|
1538 |
+
// Check if this insight is already in the group
|
1539 |
+
const existingIndex = insightsByScore[score].insights.findIndex(i => i === insight);
|
1540 |
+
|
1541 |
+
if (existingIndex === -1) {
|
1542 |
+
// New insight
|
1543 |
+
insightsByScore[score].insights.push(insight);
|
1544 |
+
insightsByScore[score].sources.push({
|
1545 |
+
url: urlLink.href,
|
1546 |
+
title: row.cells[1].textContent.trim().substring(0, 30) + '...',
|
1547 |
+
selected: selectedInsights.includes(insight)
|
1548 |
+
});
|
1549 |
+
}
|
1550 |
+
});
|
1551 |
+
}
|
1552 |
+
} catch (e) {
|
1553 |
+
console.error('Error parsing insights:', e);
|
1554 |
+
}
|
1555 |
+
});
|
1556 |
+
});
|
1557 |
+
|
1558 |
+
if (!hasInsights) {
|
1559 |
+
alert('No insights found. Please analyze documents and extract insights first.');
|
1560 |
+
return;
|
1561 |
+
}
|
1562 |
+
|
1563 |
+
// Create or get the grouped insights container
|
1564 |
+
let container = document.getElementById('groupedInsightsContainer');
|
1565 |
+
if (!container) {
|
1566 |
+
container = document.createElement('div');
|
1567 |
+
container.id = 'groupedInsightsContainer';
|
1568 |
+
container.className = 'grouped-insights-container';
|
1569 |
+
|
1570 |
+
// Insert after the problem input card
|
1571 |
+
const card = document.querySelector('.card');
|
1572 |
+
card.parentNode.insertBefore(container, card.nextSibling);
|
1573 |
+
}
|
1574 |
+
|
1575 |
+
// Create header
|
1576 |
+
const header = document.createElement('div');
|
1577 |
+
header.className = 'grouped-insights-header';
|
1578 |
+
header.innerHTML = `
|
1579 |
+
<div>Insights Grouped by Score</div>
|
1580 |
+
<div class="grouped-insights-close" onclick="closeGroupedInsights()">×</div>
|
1581 |
+
`;
|
1582 |
+
|
1583 |
+
// Create content area
|
1584 |
+
const content = document.createElement('div');
|
1585 |
+
content.className = 'grouped-insights-content';
|
1586 |
+
|
1587 |
+
// Create score groups
|
1588 |
+
for (let score = 5; score >= 0; score--) {
|
1589 |
+
const insights = insightsByScore[score].insights;
|
1590 |
+
const sources = insightsByScore[score].sources;
|
1591 |
+
|
1592 |
+
if (insights.length === 0) continue;
|
1593 |
+
|
1594 |
+
const scoreGroup = document.createElement('div');
|
1595 |
+
scoreGroup.className = 'score-group';
|
1596 |
+
scoreGroup.dataset.score = score;
|
1597 |
+
|
1598 |
+
// Create score header
|
1599 |
+
const scoreHeader = document.createElement('div');
|
1600 |
+
scoreHeader.className = 'score-group-header';
|
1601 |
+
|
1602 |
+
let scoreColor = '';
|
1603 |
+
if (score >= 0 && score <= 5) {
|
1604 |
+
const redComponent = Math.floor((score / 5) * 255);
|
1605 |
+
const greenComponent = Math.floor(((5 - score) / 5) * 255);
|
1606 |
+
scoreColor = `background-color: rgb(${redComponent}, ${greenComponent}, 0); color: white;`;
|
1607 |
+
}
|
1608 |
+
|
1609 |
+
scoreHeader.innerHTML = `
|
1610 |
+
<div>
|
1611 |
+
<span style="display: inline-block; width: 25px; height: 25px; text-align: center; border-radius: 50%; ${scoreColor} font-weight: bold;">${score}</span>
|
1612 |
+
<span style="margin-left: 8px;">Score ${score} Insights (${insights.length})</span>
|
1613 |
+
</div>
|
1614 |
+
<div class="score-group-actions">
|
1615 |
+
<button class="insights-button select-score-all-btn" onclick="selectAllInScore(${score})">Select All</button>
|
1616 |
+
<button class="insights-button clear-score-all-btn" onclick="clearAllInScore(${score})">Clear All</button>
|
1617 |
+
</div>
|
1618 |
+
`;
|
1619 |
+
|
1620 |
+
// Create insights list
|
1621 |
+
const insightsList = document.createElement('div');
|
1622 |
+
insightsList.className = 'score-insights-list';
|
1623 |
+
|
1624 |
+
// Add each insight
|
1625 |
+
insights.forEach((insight, index) => {
|
1626 |
+
const source = sources[index];
|
1627 |
+
const tagElement = document.createElement('div');
|
1628 |
+
tagElement.className = `grouped-insight-tag${source.selected ? ' selected' : ''}`;
|
1629 |
+
tagElement.dataset.score = score;
|
1630 |
+
tagElement.dataset.index = index;
|
1631 |
+
tagElement.dataset.source = source.url;
|
1632 |
+
|
1633 |
+
// Create insight text with source link
|
1634 |
+
tagElement.innerHTML = `
|
1635 |
+
${insight}
|
1636 |
+
<a href="${source.url}" target="_blank" class="insight-source" title="${source.title}">${score}</a>
|
1637 |
+
`;
|
1638 |
+
|
1639 |
+
// Add click event to toggle selection
|
1640 |
+
tagElement.addEventListener('click', function(e) {
|
1641 |
+
// Prevent clicking on the source link from toggling selection
|
1642 |
+
if (e.target.classList.contains('insight-source')) return;
|
1643 |
+
|
1644 |
+
this.classList.toggle('selected');
|
1645 |
+
updateGroupedInsightSelections();
|
1646 |
+
});
|
1647 |
+
|
1648 |
+
insightsList.appendChild(tagElement);
|
1649 |
+
});
|
1650 |
+
|
1651 |
+
// Add header and list to score group
|
1652 |
+
scoreGroup.appendChild(scoreHeader);
|
1653 |
+
scoreGroup.appendChild(insightsList);
|
1654 |
+
|
1655 |
+
// Add score group to content
|
1656 |
+
content.appendChild(scoreGroup);
|
1657 |
+
}
|
1658 |
+
|
1659 |
+
// Clear the container and add new content
|
1660 |
+
container.innerHTML = '';
|
1661 |
+
container.appendChild(header);
|
1662 |
+
container.appendChild(content);
|
1663 |
+
|
1664 |
+
// Show the container
|
1665 |
+
container.style.display = 'block';
|
1666 |
+
|
1667 |
+
// Collapse all accordions
|
1668 |
+
const accordions = document.querySelectorAll('.accordion-section');
|
1669 |
+
accordions.forEach(accordion => {
|
1670 |
+
const header = accordion.querySelector('.accordion-header');
|
1671 |
+
const body = accordion.querySelector('.accordion-body');
|
1672 |
+
if (header && body && !header.classList.contains('collapsed')) {
|
1673 |
+
header.classList.add('collapsed');
|
1674 |
+
body.classList.add('collapsed');
|
1675 |
+
|
1676 |
+
// Update the toggle icon
|
1677 |
+
const toggleIcon = header.querySelector('.toggle-icon');
|
1678 |
+
if (toggleIcon) toggleIcon.textContent = '▶';
|
1679 |
+
}
|
1680 |
+
});
|
1681 |
+
|
1682 |
+
// Scroll to the insights container
|
1683 |
+
container.scrollIntoView({ behavior: 'smooth' });
|
1684 |
+
}
|
1685 |
+
|
1686 |
+
// Close the grouped insights view
|
1687 |
+
function closeGroupedInsights() {
|
1688 |
+
const container = document.getElementById('groupedInsightsContainer');
|
1689 |
+
if (container) {
|
1690 |
+
container.style.display = 'none';
|
1691 |
+
}
|
1692 |
+
}
|
1693 |
+
|
1694 |
+
// Select all insights for a specific score
|
1695 |
+
function selectAllInScore(score) {
|
1696 |
+
const container = document.getElementById('groupedInsightsContainer');
|
1697 |
+
const tags = container.querySelectorAll(`.grouped-insight-tag[data-score="${score}"]`);
|
1698 |
+
|
1699 |
+
tags.forEach(tag => {
|
1700 |
+
tag.classList.add('selected');
|
1701 |
+
});
|
1702 |
+
|
1703 |
+
updateGroupedInsightSelections();
|
1704 |
+
}
|
1705 |
+
|
1706 |
+
// Clear all insights for a specific score
|
1707 |
+
function clearAllInScore(score) {
|
1708 |
+
const container = document.getElementById('groupedInsightsContainer');
|
1709 |
+
const tags = container.querySelectorAll(`.grouped-insight-tag[data-score="${score}"]`);
|
1710 |
+
|
1711 |
+
tags.forEach(tag => {
|
1712 |
+
tag.classList.remove('selected');
|
1713 |
+
});
|
1714 |
+
|
1715 |
+
updateGroupedInsightSelections();
|
1716 |
+
}
|
1717 |
+
|
1718 |
+
// Update the selection state of insights in their original document rows
|
1719 |
+
function updateGroupedInsightSelections() {
|
1720 |
+
// Get all selected insights from the grouped view
|
1721 |
+
const container = document.getElementById('groupedInsightsContainer');
|
1722 |
+
const selectedTags = container.querySelectorAll('.grouped-insight-tag.selected');
|
1723 |
+
|
1724 |
+
// Create a mapping of URL to selected insights
|
1725 |
+
const selectionsBySource = {};
|
1726 |
+
|
1727 |
+
// Process each selected tag
|
1728 |
+
selectedTags.forEach(tag => {
|
1729 |
+
const insight = tag.textContent.trim().replace(/\d+$/, '').trim(); // Remove the score number at the end
|
1730 |
+
const sourceUrl = tag.dataset.source;
|
1731 |
+
|
1732 |
+
if (!selectionsBySource[sourceUrl]) {
|
1733 |
+
selectionsBySource[sourceUrl] = [];
|
1734 |
+
}
|
1735 |
+
|
1736 |
+
selectionsBySource[sourceUrl].push(insight);
|
1737 |
+
});
|
1738 |
+
|
1739 |
+
// Now update the original document rows
|
1740 |
+
const queryItems = document.querySelectorAll('.query-item');
|
1741 |
+
queryItems.forEach(queryItem => {
|
1742 |
+
const rows = queryItem.querySelectorAll('tbody tr:not(.insights-row)');
|
1743 |
+
rows.forEach(row => {
|
1744 |
+
const urlLink = row.querySelector('.url-link');
|
1745 |
+
if (!urlLink) return;
|
1746 |
+
|
1747 |
+
const sourceUrl = urlLink.href;
|
1748 |
+
|
1749 |
+
// If we have selections for this source
|
1750 |
+
if (selectionsBySource[sourceUrl]) {
|
1751 |
+
// Get all insights for this row
|
1752 |
+
try {
|
1753 |
+
// Combine selected and unselected to get all insights
|
1754 |
+
const currentSelected = JSON.parse(row.dataset.selectedInsights || '[]');
|
1755 |
+
const currentUnselected = JSON.parse(row.dataset.unselectedInsights || '[]');
|
1756 |
+
const allInsights = [...currentSelected, ...currentUnselected];
|
1757 |
+
|
1758 |
+
// New selected and unselected based on grouped view
|
1759 |
+
const newSelected = [];
|
1760 |
+
const newUnselected = [];
|
1761 |
+
|
1762 |
+
// Process each insight
|
1763 |
+
allInsights.forEach(insight => {
|
1764 |
+
if (selectionsBySource[sourceUrl].includes(insight)) {
|
1765 |
+
newSelected.push(insight);
|
1766 |
+
} else {
|
1767 |
+
newUnselected.push(insight);
|
1768 |
+
}
|
1769 |
+
});
|
1770 |
+
|
1771 |
+
// Update the dataset
|
1772 |
+
row.dataset.selectedInsights = JSON.stringify(newSelected);
|
1773 |
+
row.dataset.unselectedInsights = JSON.stringify(newUnselected);
|
1774 |
+
} catch (e) {
|
1775 |
+
console.error('Error updating insights selections:', e);
|
1776 |
+
}
|
1777 |
+
}
|
1778 |
+
});
|
1779 |
+
});
|
1780 |
+
|
1781 |
+
// Update enhance button state
|
1782 |
+
checkSelectedInsights();
|
1783 |
+
}
|
1784 |
+
|
1785 |
+
// Check if any documents have been analyzed to enable/disable the Group Insights button
|
1786 |
+
function checkGroupInsightsButton() {
|
1787 |
+
const queryItems = document.querySelectorAll('.query-item');
|
1788 |
+
let hasInsights = false;
|
1789 |
+
|
1790 |
+
queryItems.forEach(queryItem => {
|
1791 |
+
const rows = queryItem.querySelectorAll('tbody tr:not(.insights-row)');
|
1792 |
+
rows.forEach(row => {
|
1793 |
+
if (row.dataset.selectedInsights || row.dataset.unselectedInsights) {
|
1794 |
+
try {
|
1795 |
+
const selected = JSON.parse(row.dataset.selectedInsights || '[]');
|
1796 |
+
const unselected = JSON.parse(row.dataset.unselectedInsights || '[]');
|
1797 |
+
if (selected.length > 0 || unselected.length > 0) {
|
1798 |
+
hasInsights = true;
|
1799 |
+
}
|
1800 |
+
} catch (e) {}
|
1801 |
+
}
|
1802 |
+
});
|
1803 |
+
});
|
1804 |
+
|
1805 |
+
const groupInsightsButton = document.getElementById('groupInsightsByScoreButton');
|
1806 |
+
if (hasInsights) {
|
1807 |
+
groupInsightsButton.classList.remove('disabled');
|
1808 |
+
groupInsightsButton.disabled = false;
|
1809 |
+
} else {
|
1810 |
+
groupInsightsButton.classList.add('disabled');
|
1811 |
+
groupInsightsButton.disabled = true;
|
1812 |
+
}
|
1813 |
+
}
|
1814 |
</script>
|
1815 |
</head>
|
1816 |
<body>
|
|
|
1891 |
<button id="enhanceProblemButton" class="btn enhance-problem-button floating-button disabled" title="Enhance Problem using Selected Insights" onclick="enhanceProblem()" disabled>
|
1892 |
Enhance Problem
|
1893 |
</button>
|
1894 |
+
<button id="groupInsightsByScoreButton" class="btn btn-group-insights floating-button disabled" title="Group All Insights by Score" onclick="groupInsightsByScore()" disabled>
|
1895 |
+
Group Insights
|
1896 |
+
</button>
|
1897 |
+
<button id="extractAllInsightsButton" class="btn btn-info floating-button disabled" title="Extract Insights for All Analyzed Documents" onclick="extractAllInsights()" disabled>
|
1898 |
+
Extract All Insights
|
1899 |
+
</button>
|
1900 |
<button id="analyzeAllButton" class="btn btn-primary floating-button" title="Analyze All Unanalyzed Papers">
|
1901 |
Analyze All
|
1902 |
</button>
|
|
|
1925 |
// Check for selected insights periodically to enable/disable enhance button
|
1926 |
setInterval(checkSelectedInsights, 1000);
|
1927 |
|
1928 |
+
// Check for analyzed documents to enable/disable Extract All Insights button
|
1929 |
+
setInterval(checkAnalyzedDocuments, 1000);
|
1930 |
+
|
1931 |
+
// Check for insights to enable/disable Group Insights by Score button
|
1932 |
+
setInterval(checkGroupInsightsButton, 1000);
|
1933 |
+
|
1934 |
// Analyze all button
|
1935 |
document.getElementById('analyzeAllButton').addEventListener('click', function() {
|
1936 |
analyzeAllPapers();
|
1937 |
+
// Button will be enabled when analyses complete and checkAnalyzedDocuments runs
|
1938 |
});
|
1939 |
|
1940 |
// Remove failed button
|