// Array to store problem history versions
const problemHistory = [];
let currentHistoryIndex = -1;
// Store all refined problem suggestions
let storedRefinedProblems = {};
document.getElementById("tab1").style.display = "block";
function openTab(evt, tabName) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(tabName).style.display = "block";
evt.currentTarget.className += " active";
}
function navigateProblemHistory(direction) {
const problemInput = document.getElementById('userProblemDescription');
console.log("Current history index:", currentHistoryIndex, "Total history:", problemHistory.length);
if (direction === 'prev' && currentHistoryIndex > 0) {
currentHistoryIndex--;
problemInput.value = problemHistory[currentHistoryIndex];
console.log("Moving to previous version:", currentHistoryIndex);
} else if (direction === 'next' && currentHistoryIndex < problemHistory.length - 1) {
currentHistoryIndex++;
problemInput.value = problemHistory[currentHistoryIndex];
console.log("Moving to next version:", currentHistoryIndex);
}
updateHistoryNavigation();
}
function generateQueries(event) {
event.preventDefault();
const userInput = document.getElementById('userInput').value.trim();
if (!userInput) {
alert('Please enter a technical problem description');
return;
}
// Show loading indicator
document.querySelector(".progress-text").innerHTML = "Generating key issues ... Please wait."
document.getElementById('globalLoadingOverlay').style.display = 'flex';
// Send message to Flask backend
fetch('/generate-key-issues', {
method: 'POST',
body: JSON.stringify({ 'query': userInput }),
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
// Hide loading indicator
document.getElementById('globalLoadingOverlay').style.display = 'none';
// Check if we have key issues in the response
if (data.key_issues && data.key_issues.length > 0) {
// Display the key issues
displayKeyIssues(data.key_issues);
} else if (data.error) {
alert('Error: ' + data.error);
} else {
alert('No key issues found. Please try a different query.');
}
})
.catch(error => {
document.getElementById('globalLoadingOverlay').style.display = 'none';
console.error('Error:', error);
alert('There was an error communicating with the server. Please try again.');
});
}
function performSearch(query, queryItemElement) {
if (!query.trim()) {
alert('Please enter a search query');
return;
}
const loadingElement = queryItemElement.querySelector('.search-loading');
const tableElement = queryItemElement.querySelector('.results-table');
const tableBody = tableElement.querySelector('tbody');
// Show loading and hide previous results
loadingElement.style.display = 'block';
tableElement.style.display = 'none';
// Clear previous results
tableBody.innerHTML = '';
// Get checkbox values
const pdfChecked = document.getElementById('pdfOption').checked;
const patentChecked = document.getElementById('patentOption').checked;
const webChecked = document.getElementById('webOption').checked;
// Create form data with query and checkbox values
const formData = new FormData();
formData.append('query', query);
formData.append('pdfOption', pdfChecked);
formData.append('patentOption', patentChecked);
formData.append('webOption', webChecked);
// Send search request to backend
fetch('/search', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
// Hide loading indicator
loadingElement.style.display = 'none';
if (data.results && data.results.length > 0) {
// Populate table with results
data.results.forEach(result => {
const row = document.createElement('tr');
const typeCell = document.createElement('td');
typeCell.textContent = result.type;
const titleCell = document.createElement('td');
titleCell.textContent = result.title;
const bodyCell = document.createElement('td');
bodyCell.textContent = result.body;
const urlCell = document.createElement('td');
const urlLink = document.createElement('a');
urlLink.href = result.url;
urlLink.textContent = result.url;
urlLink.className = 'url-link';
urlLink.target = '_blank';
urlCell.appendChild(urlLink);
// Add "Analyze" button to the URL cell
const analyzeButton = document.createElement('button');
analyzeButton.textContent = 'Analyze';
analyzeButton.className = 'action-button analyze-button';
analyzeButton.onclick = function(e) {
e.preventDefault();
analyzePaper(result.url, queryItemElement);
};
urlCell.appendChild(document.createElement('br'));
urlCell.appendChild(analyzeButton);
row.appendChild(typeCell);
row.appendChild(titleCell);
row.appendChild(bodyCell);
row.appendChild(urlCell);
tableBody.appendChild(row);
});
// Show the table
tableElement.style.display = 'table';
} else {
// No results
const row = document.createElement('tr');
const cell = document.createElement('td');
cell.colSpan = 4; // Updated to 4 since we now have 4 columns with the type column
cell.textContent = 'No results found.';
cell.style.textAlign = 'center';
row.appendChild(cell);
tableBody.appendChild(row);
tableElement.style.display = 'table';
}
})
.catch(error => {
loadingElement.style.display = 'none';
console.error('Error:', error);
// Show error in table
const row = document.createElement('tr');
const cell = document.createElement('td');
cell.colSpan = 4; // Updated to 4 since we now have 4 columns with the type column
cell.textContent = 'Error performing search. Please try again.';
cell.style.textAlign = 'center';
cell.style.color = 'red';
row.appendChild(cell);
tableBody.appendChild(row);
tableElement.style.display = 'table';
});
}
function analyzePaper(paperUrl, queryItemElement) {
const patentBackground = document.getElementById('userProblemDescription').value.trim();
if (!patentBackground) {
alert('Please provide a patent background in the input field');
return;
}
// Find the row containing this URL
const rows = queryItemElement.querySelectorAll('tbody tr');
let targetRow;
let documentType = 'pdf'; // Default type
for (const row of rows) {
const urlLink = row.querySelector('.url-link');
if (urlLink && urlLink.href === paperUrl) {
targetRow = row;
// Get the document type from the first cell of the row
documentType = row.cells[0].textContent.toLowerCase();
break;
}
}
if (!targetRow) {
alert('Could not find the paper in the results table');
return;
}
// Check if we already have analysis columns
let scoreCell, justificationCell;
if (targetRow.cells.length <= 4) {
// We need to create the cells
scoreCell = document.createElement('td');
scoreCell.className = 'score-cell';
scoreCell.innerHTML = '
';
justificationCell = document.createElement('td');
justificationCell.className = 'justification-cell';
justificationCell.innerHTML = 'Analyzing...';
targetRow.appendChild(scoreCell);
targetRow.appendChild(justificationCell);
} else {
// Use existing cells
scoreCell = targetRow.cells[4];
justificationCell = targetRow.cells[5];
scoreCell.innerHTML = '
';
justificationCell.innerHTML = 'Analyzing...';
}
// Send analysis request to backend
fetch('/analyze', {
method: 'POST',
body: JSON.stringify({
'patent_background': patentBackground,
'pdf_url': paperUrl,
'data_type': documentType
}),
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
if (data.error) {
scoreCell.innerHTML = 'Error';
justificationCell.innerHTML = data.error;
} else if (data.result) {
// Get score and justification from the result
const result = data.result;
const score = result.score !== undefined ? result.score : 'N/A';
const justification = result.justification || 'No justification provided';
// Update cells with results
scoreCell.innerHTML = score;
justificationCell.innerHTML = justification;
// Color-code the score
if (score >= 0 && score <= 5) {
const redComponent = Math.floor((score / 5) * 255);
const greenComponent = Math.floor(((5 - score) / 5) * 255);
scoreCell.style.backgroundColor = `rgb(${redComponent}, ${greenComponent}, 0)`;
scoreCell.style.color = 'white';
scoreCell.style.fontWeight = 'bold';
scoreCell.style.textAlign = 'center';
}
// Add "Extract Insights" button to the justify cell
const insightsButton = document.createElement('button');
insightsButton.textContent = 'Extract Insights';
insightsButton.className = 'action-button insights-button';
insightsButton.style.marginTop = '5px';
insightsButton.style.fontSize = '0.8em';
insightsButton.onclick = function(e) {
e.preventDefault();
extractInsights(paperUrl, targetRow);
};
justificationCell.appendChild(document.createElement('br'));
justificationCell.appendChild(insightsButton);
} else {
scoreCell.innerHTML = 'No data';
justificationCell.innerHTML = 'Analysis failed';
}
})
.catch(error => {
console.error('Error:', error);
scoreCell.innerHTML = 'Error';
justificationCell.innerHTML = 'Failed to analyze paper';
});
}
function extractInsights(paperUrl, row) {
const patentBackground = document.getElementById('userProblemDescription').value.trim();
if (!patentBackground) {
alert('Please provide a patent background in the input field');
return;
}
const documentType = row.cells[0].textContent.toLowerCase();
// Check if there's already an insights row for this document
let insightsRow = row.nextElementSibling;
if (insightsRow && insightsRow.className === 'insights-row') {
// Insights row already exists, get the container
insightsContainer = insightsRow.querySelector('.insights-container');
insightsContainer.innerHTML = '
Extracting insights...
';
} else {
// Create insights row that spans across all columns
insightsRow = document.createElement('tr');
insightsRow.className = 'insights-row';
const insightsTd = document.createElement('td');
insightsTd.colSpan = row.cells.length;
insightsContainer = document.createElement('div');
insightsContainer.className = 'insights-container';
insightsContainer.innerHTML = '
Extracting insights...
';
insightsTd.appendChild(insightsContainer);
insightsRow.appendChild(insightsTd);
// Insert after the current row
row.parentNode.insertBefore(insightsRow, row.nextSibling);
}
// Store the row reference as a data attribute on the container for later access
insightsContainer.dataset.parentRow = row.rowIndex;
// Send request to extract insights
fetch('/post_insights', {
method: 'POST',
body: JSON.stringify({
'patent_background': patentBackground,
'pdf_url': paperUrl,
'data_type': documentType
}),
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
if (data.error) {
insightsContainer.innerHTML = `Error: ${data.error}
`;
} else if (data.result && data.result.insights) {
// Create header with title and actions
const insightsHeader = document.createElement('div');
insightsHeader.className = 'insights-header';
const insightsTitle = document.createElement('div');
insightsTitle.className = 'insights-title';
insightsTitle.textContent = 'Document Insights';
const insightsActions = document.createElement('div');
insightsActions.className = 'insights-actions';
// Store the insights for this specific container
const containerInsights = [...data.result.insights];
insightsContainer.dataset.allInsights = JSON.stringify(containerInsights);
const selectAllBtn = document.createElement('button');
selectAllBtn.className = 'insights-button select-all-btn';
selectAllBtn.textContent = 'Select All';
// Use a closure to ensure the button has access to the correct container and row
selectAllBtn.addEventListener('click', function() {
const container = this.closest('.insights-container');
const parentRow = row;
const allInsights = JSON.parse(container.dataset.allInsights || '[]');
const tags = container.querySelectorAll('.insight-tag');
tags.forEach(tag => tag.classList.add('selected'));
parentRow.dataset.selectedInsights = JSON.stringify(allInsights);
parentRow.dataset.unselectedInsights = JSON.stringify([]);
// Trigger check for enabling/disabling enhance button
checkSelectedInsights();
});
const clearAllBtn = document.createElement('button');
clearAllBtn.className = 'insights-button clear-all-btn';
clearAllBtn.textContent = 'Clear All';
// Use a closure to ensure the button has access to the correct container and row
clearAllBtn.addEventListener('click', function() {
const container = this.closest('.insights-container');
const parentRow = row;
const allInsights = JSON.parse(container.dataset.allInsights || '[]');
const tags = container.querySelectorAll('.insight-tag');
tags.forEach(tag => tag.classList.remove('selected'));
parentRow.dataset.selectedInsights = JSON.stringify([]);
parentRow.dataset.unselectedInsights = JSON.stringify(allInsights);
// Trigger check for enabling/disabling enhance button
checkSelectedInsights();
});
insightsActions.appendChild(selectAllBtn);
insightsActions.appendChild(clearAllBtn);
insightsHeader.appendChild(insightsTitle);
insightsHeader.appendChild(insightsActions);
// Create insight tags
const insightsList = document.createElement('div');
insightsList.className = 'insights-list';
// Clear the container and add the new elements
insightsContainer.innerHTML = '';
insightsContainer.appendChild(insightsHeader);
insightsContainer.appendChild(insightsList);
// Initialize selected insights
const selectedInsights = [];
const unselectedInsights = [];
// Add insight tags
data.result.insights.forEach(insight => {
const tagElement = document.createElement('div');
tagElement.className = 'insight-tag';
tagElement.textContent = insight;
tagElement.addEventListener('click', function() {
this.classList.toggle('selected');
// Update selected insights
updateSelectedInsights(row, insightsContainer);
// Trigger check for enabling/disabling enhance button
checkSelectedInsights();
});
// Add to unselected by default
// tagElement.classList.add('selected');
unselectedInsights.push(insight);
insightsList.appendChild(tagElement);
});
// Store initial selections
row.dataset.selectedInsights = JSON.stringify(selectedInsights);
row.dataset.unselectedInsights = JSON.stringify(unselectedInsights);
// Trigger check for enabling/disabling enhance button immediately
checkSelectedInsights();
} else {
insightsContainer.innerHTML = 'No insights found
';
}
})
.catch(error => {
console.error('Error:', error);
insightsContainer.innerHTML = `Error extracting insights: ${error.message}
`;
});
}
function updateSelectedInsights(row, insightsContainer) {
const selectedInsights = [];
const unselectedInsights = [];
const tags = insightsContainer.querySelectorAll('.insight-tag');
tags.forEach(tag => {
if (tag.classList.contains('selected')) {
selectedInsights.push(tag.textContent);
} else {
unselectedInsights.push(tag.textContent);
}
});
row.dataset.selectedInsights = JSON.stringify(selectedInsights);
row.dataset.unselectedInsights = JSON.stringify(unselectedInsights);
}
function checkSelectedInsights() {
const selectedInsights = collectAllSelectedInsights();
const enhanceButton = document.getElementById('enhanceProblemButton');
if (selectedInsights.length > 0) {
enhanceButton.classList.remove('disabled');
enhanceButton.disabled = false;
} else {
enhanceButton.classList.add('disabled');
enhanceButton.disabled = true;
}
}
function collectAllSelectedInsights() {
const allSelectedInsights = [];
const queryItems = document.querySelectorAll('.query-item');
queryItems.forEach(queryItem => {
const rows = queryItem.querySelectorAll('tbody tr:not(.insights-row)');
rows.forEach(row => {
if (row.dataset.selectedInsights) {
try {
const selectedInsights = JSON.parse(row.dataset.selectedInsights);
selectedInsights.forEach(insight => {
if (!allSelectedInsights.includes(insight)) {
allSelectedInsights.push(insight);
}
});
} catch (e) {
console.error('Error parsing selected insights:', e);
}
}
});
});
return allSelectedInsights;
}
function exportToExcel() {
// Show loading overlay
const loadingOverlay = document.getElementById('globalLoadingOverlay');
if (loadingOverlay) {
loadingOverlay.style.display = 'flex';
loadingOverlay.querySelector('.progress-text').textContent = 'Generating Excel file...';
}
try {
// Collect all data from all tables
const allData = [];
const queryItems = document.querySelectorAll('.query-item');
queryItems.forEach(queryItem => {
// Get the search query text for this table
const queryText = queryItem.querySelector('.query-field').value;
// Get all rows in this table
const rows = queryItem.querySelectorAll('tbody tr:not(.insights-row)');
rows.forEach(row => {
// Skip empty rows or error rows
if (row.cells.length === 1 && row.cells[0].colSpan > 1) {
return; // Skip "No results found" rows
}
// Prepare object for this row
const rowData = {
'Topic': queryText,
'Type': row.cells[0].textContent,
'Title': row.cells[1].textContent,
'Description': row.cells[2].textContent,
'URL': row.querySelector('.url-link')?.href || ''
};
// Add score and justification if they exist
if (row.cells.length > 4) {
rowData['Score'] = row.cells[4].textContent;
rowData['Justification'] = row.cells[5].textContent.split('\n')[0]; // Only get the justification text
} else {
rowData['Score'] = '';
rowData['Justification'] = '';
}
// Add selected and unselected insights if they exist
if (row.dataset.selectedInsights) {
try {
const selectedInsights = JSON.parse(row.dataset.selectedInsights);
rowData['Selected Insights'] = selectedInsights.join('; ');
} catch (e) {
rowData['Selected Insights'] = '';
}
} else {
rowData['Selected Insights'] = '';
}
if (row.dataset.unselectedInsights) {
try {
const unselectedInsights = JSON.parse(row.dataset.unselectedInsights);
rowData['Unselected Insights'] = unselectedInsights.join('; ');
} catch (e) {
rowData['Unselected Insights'] = '';
}
} else {
rowData['Unselected Insights'] = '';
}
allData.push(rowData);
});
});
// Check if we have any data
if (allData.length === 0) {
if (loadingOverlay) loadingOverlay.style.display = 'none';
alert('No data to export. Please perform a search first.');
return;
}
// Get all problem versions
const problemVersions = {};
if (problemHistory.length > 0) {
problemHistory.forEach((problem, index) => {
problemVersions[`Problem Version ${index + 1}`] = problem;
});
} else {
// If no history, just use the current problem
const currentProblem = document.getElementById('userProblemDescription').value.trim();
if (currentProblem) {
problemVersions['Problem Version 1'] = currentProblem;
}
}
// Send to server for Excel generation
fetch('/export-excel', {
method: 'POST',
body: JSON.stringify({
'tableData': allData,
'userQuery': document.getElementById('userProblemDescription').value,
'problemVersions': problemVersions
}),
headers: { 'Content-Type': 'application/json' }
})
.then(response => {
if (!response.ok) {
throw new Error(`Server error: ${response.status}`);
}
return response.blob();
})
.then(blob => {
// Hide loading overlay
if (loadingOverlay) loadingOverlay.style.display = 'none';
// Create URL for the blob
const url = window.URL.createObjectURL(new Blob([blob], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
}));
// Create a link and trigger download
const a = document.createElement('a');
a.href = url;
a.download = 'patent_search_results.xlsx';
document.body.appendChild(a);
a.click();
// Clean up
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
})
.catch(error => {
console.error('Error exporting to Excel:', error);
if (loadingOverlay) loadingOverlay.style.display = 'none';
alert(`Error exporting to Excel: ${error.message}`);
});
} catch (error) {
console.error('Error preparing Excel data:', error);
if (loadingOverlay) loadingOverlay.style.display = 'none';
alert(`Error preparing data for export: ${error.message}`);
}
}
function hasSearchResults() {
const resultsContainer = document.getElementById('resultsContainer');
const hasResults = resultsContainer && resultsContainer.style.display !== 'none';
const hasTables = document.querySelectorAll('.results-table[style*="display: table"]').length > 0;
return hasResults && hasTables;
}
function analyzeAllPapers() {
// Show loading overlay
const loadingOverlay = document.getElementById('globalLoadingOverlay');
if (loadingOverlay) loadingOverlay.style.display = 'flex';
if (loadingOverlay) loadingOverlay.querySelector('.progress-text').textContent = 'Analyzing all papers...';
// Get all query items
const queryItems = document.querySelectorAll('.query-item');
let totalToAnalyze = 0;
let completedAnalyses = 0;
// Count total papers that need analysis
queryItems.forEach(queryItem => {
const rows = queryItem.querySelectorAll('tbody tr');
rows.forEach(row => {
if (row.cells.length <= 4 || row.cells[4].textContent.trim() === 'Error' ||
row.cells[4].textContent.trim() === 'N/A' || row.cells[4].textContent.trim() === '') {
totalToAnalyze++;
}
});
});
if (totalToAnalyze === 0) {
alert('No papers need analysis');
if (loadingOverlay) loadingOverlay.style.display = 'none';
return;
}
// Function to update progress
function updateProgress() {
completedAnalyses++;
if (loadingOverlay) {
const progressElement = loadingOverlay.querySelector('.progress-text');
if (progressElement) {
progressElement.textContent = `Analyzing papers: ${completedAnalyses}/${totalToAnalyze}`;
}
}
if (completedAnalyses >= totalToAnalyze) {
if (loadingOverlay) loadingOverlay.style.display = 'none';
}
}
// Analyze each paper that needs it
queryItems.forEach(queryItem => {
const rows = queryItem.querySelectorAll('tbody tr');
rows.forEach(row => {
// Check if this row needs analysis
if (row.cells.length <= 4 || row.cells[4].textContent.trim() === 'Error' ||
row.cells[4].textContent.trim() === 'N/A' || row.cells[4].textContent.trim() === '') {
// Get the URL
const urlLink = row.querySelector('.url-link');
const documentType = row.cells[0].textContent.toLowerCase();
if (urlLink && urlLink.href) {
// Create a promise for this analysis
const promise = new Promise((resolve) => {
// Prepare for analysis
const patentBackground = document.getElementById('userProblemDescription').value.trim();
// Create score and justification cells if needed
let scoreCell, justificationCell;
if (row.cells.length <= 4) {
scoreCell = document.createElement('td');
scoreCell.className = 'score-cell';
scoreCell.innerHTML = '
';
justificationCell = document.createElement('td');
justificationCell.className = 'justification-cell';
justificationCell.innerHTML = 'Analyzing...';
row.appendChild(scoreCell);
row.appendChild(justificationCell);
} else {
scoreCell = row.cells[4];
justificationCell = row.cells[5];
scoreCell.innerHTML = '
';
justificationCell.innerHTML = 'Analyzing...';
}
// Send analysis request
fetch('/analyze', {
method: 'POST',
body: JSON.stringify({
'patent_background': patentBackground,
'pdf_url': urlLink.href,
'data_type': documentType
}),
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
if (data.error) {
scoreCell.innerHTML = 'Error';
justificationCell.innerHTML = data.error;
} else if (data.result) {
// Get score and justification
const result = data.result;
const score = result.score !== undefined ? result.score : 'N/A';
const justification = result.justification || 'No justification provided';
// Update cells
scoreCell.innerHTML = score;
justificationCell.innerHTML = justification;
// Color-code score
if (score >= 0 && score <= 5) {
const redComponent = Math.floor((score / 5) * 255);
const greenComponent = Math.floor(((5 - score) / 5) * 255);
scoreCell.style.backgroundColor = `rgb(${redComponent}, ${greenComponent}, 0)`;
scoreCell.style.color = 'white';
scoreCell.style.fontWeight = 'bold';
scoreCell.style.textAlign = 'center';
}
// Add "Extract Insights" button to the justify cell - for Analyze All function
const insightsButton = document.createElement('button');
insightsButton.textContent = 'Extract Insights';
insightsButton.className = 'action-button insights-button';
insightsButton.style.marginTop = '5px';
insightsButton.style.fontSize = '0.8em';
insightsButton.onclick = function(e) {
e.preventDefault();
extractInsights(urlLink.href, row);
};
justificationCell.appendChild(document.createElement('br'));
justificationCell.appendChild(insightsButton);
} else {
scoreCell.innerHTML = 'No data';
justificationCell.innerHTML = 'Analysis failed';
}
resolve();
})
.catch(error => {
console.error('Error:', error);
scoreCell.innerHTML = 'Error';
justificationCell.innerHTML = 'Failed to analyze paper';
resolve();
});
});
// When this analysis is done, update the progress
promise.then(() => {
updateProgress();
});
} else {
// No URL found, count as completed
updateProgress();
}
}
});
});
}
function removeFailedAnalyses() {
const queryItems = document.querySelectorAll('.query-item');
let removedCount = 0;
queryItems.forEach(queryItem => {
const tbody = queryItem.querySelector('tbody');
const rows = Array.from(tbody.querySelectorAll('tr'));
rows.forEach(row => {
if (row.cells.length > 4) {
const scoreText = row.cells[4].textContent.trim();
if (scoreText === 'Error' || scoreText === 'N/A' || scoreText === 'No data') {
tbody.removeChild(row);
removedCount++;
}
}
});
});
// Create and display a simple notification instead of alert
const notification = document.createElement('div');
notification.className = 'simple-notification';
notification.textContent = `Removed ${removedCount} papers with failed analyses`;
notification.style.position = 'fixed';
notification.style.top = '20px';
notification.style.right = '20px';
notification.style.background = '#4CAF50';
notification.style.color = 'white';
notification.style.padding = '15px';
notification.style.borderRadius = '5px';
notification.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
notification.style.zIndex = '10000';
// Add notification to the body
document.body.appendChild(notification);
// Remove notification after 3 seconds
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 3000);
}
function extractAllInsights() {
const patentBackground = document.getElementById('userProblemDescription').value.trim();
if (!patentBackground) {
alert('Please provide a patent background in the input field');
return;
}
// Show loading overlay
const loadingOverlay = document.getElementById('globalLoadingOverlay');
if (loadingOverlay) {
loadingOverlay.style.display = 'flex';
loadingOverlay.querySelector('.progress-text').textContent = 'Extracting insights from all documents...';
}
// Get all query items
const queryItems = document.querySelectorAll('.query-item');
let totalDocuments = 0;
let completedDocuments = 0;
// Count total analyzed documents that need insights extraction
const analyzedRows = [];
queryItems.forEach(queryItem => {
const rows = queryItem.querySelectorAll('tbody tr:not(.insights-row)');
rows.forEach(row => {
// Only include rows that have been analyzed (have score and justification cells)
if (row.cells.length > 4 && row.cells[4].textContent.trim() !== 'Error' &&
row.cells[4].textContent.trim() !== 'N/A' && row.cells[4].textContent.trim() !== '') {
analyzedRows.push(row);
totalDocuments++;
}
});
});
if (totalDocuments === 0) {
if (loadingOverlay) loadingOverlay.style.display = 'none';
alert('No analyzed documents found. Please analyze documents first.');
return;
}
// Function to update progress
function updateProgress() {
completedDocuments++;
if (loadingOverlay) {
const progressElement = loadingOverlay.querySelector('.progress-text');
if (progressElement) {
progressElement.textContent = `Extracting insights: ${completedDocuments}/${totalDocuments}`;
}
}
if (completedDocuments >= totalDocuments) {
if (loadingOverlay) loadingOverlay.style.display = 'none';
checkSelectedInsights(); // Update enhance button state based on selected insights
}
}
// Process each analyzed document sequentially to avoid overwhelming the server
function processNextDocument(index) {
if (index >= analyzedRows.length) {
return; // All documents processed
}
const row = analyzedRows[index];
const urlLink = row.querySelector('.url-link');
const documentType = row.cells[0].textContent.toLowerCase();
if (!urlLink || !urlLink.href) {
updateProgress();
processNextDocument(index + 1);
return;
}
// Check if there's already an insights row for this document
let insightsRow = row.nextElementSibling;
if (insightsRow && insightsRow.className === 'insights-row') {
// Insights row already exists, get the container
insightsContainer = insightsRow.querySelector('.insights-container');
insightsContainer.innerHTML = '
Extracting insights...
';
} else {
// Create insights row that spans across all columns
insightsRow = document.createElement('tr');
insightsRow.className = 'insights-row';
const insightsTd = document.createElement('td');
insightsTd.colSpan = row.cells.length;
insightsContainer = document.createElement('div');
insightsContainer.className = 'insights-container';
insightsContainer.innerHTML = '
Extracting insights...
';
insightsTd.appendChild(insightsContainer);
insightsRow.appendChild(insightsTd);
// Insert after the current row
row.parentNode.insertBefore(insightsRow, row.nextSibling);
}
// Store the row reference as a data attribute on the container for later access
insightsContainer.dataset.parentRow = row.rowIndex;
// Send request to extract insights
fetch('/post_insights', {
method: 'POST',
body: JSON.stringify({
'patent_background': patentBackground,
'pdf_url': urlLink.href,
'data_type': documentType
}),
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
if (data.error) {
insightsContainer.innerHTML = `Error: ${data.error}
`;
} else if (data.result && data.result.insights) {
// Create header with title and actions
const insightsHeader = document.createElement('div');
insightsHeader.className = 'insights-header';
const insightsTitle = document.createElement('div');
insightsTitle.className = 'insights-title';
insightsTitle.textContent = 'Document Insights';
const insightsActions = document.createElement('div');
insightsActions.className = 'insights-actions';
// Store the insights for this specific container
const containerInsights = [...data.result.insights];
insightsContainer.dataset.allInsights = JSON.stringify(containerInsights);
const selectAllBtn = document.createElement('button');
selectAllBtn.className = 'insights-button select-all-btn';
selectAllBtn.textContent = 'Select All';
selectAllBtn.addEventListener('click', function() {
const container = this.closest('.insights-container');
const parentRow = row;
const allInsights = JSON.parse(container.dataset.allInsights || '[]');
const tags = container.querySelectorAll('.insight-tag');
tags.forEach(tag => tag.classList.add('selected'));
parentRow.dataset.selectedInsights = JSON.stringify(allInsights);
parentRow.dataset.unselectedInsights = JSON.stringify([]);
checkSelectedInsights();
});
const clearAllBtn = document.createElement('button');
clearAllBtn.className = 'insights-button clear-all-btn';
clearAllBtn.textContent = 'Clear All';
clearAllBtn.addEventListener('click', function() {
const container = this.closest('.insights-container');
const parentRow = row;
const allInsights = JSON.parse(container.dataset.allInsights || '[]');
const tags = container.querySelectorAll('.insight-tag');
tags.forEach(tag => tag.classList.remove('selected'));
parentRow.dataset.selectedInsights = JSON.stringify([]);
parentRow.dataset.unselectedInsights = JSON.stringify(allInsights);
checkSelectedInsights();
});
insightsActions.appendChild(selectAllBtn);
insightsActions.appendChild(clearAllBtn);
insightsHeader.appendChild(insightsTitle);
insightsHeader.appendChild(insightsActions);
// Create insight tags
const insightsList = document.createElement('div');
insightsList.className = 'insights-list';
// Clear the container and add the new elements
insightsContainer.innerHTML = '';
insightsContainer.appendChild(insightsHeader);
insightsContainer.appendChild(insightsList);
// Initialize selected insights
const selectedInsights = [];
const unselectedInsights = [];
// Add insight tags
data.result.insights.forEach(insight => {
const tagElement = document.createElement('div');
tagElement.className = 'insight-tag';
tagElement.textContent = insight;
tagElement.addEventListener('click', function() {
this.classList.toggle('selected');
updateSelectedInsights(row, insightsContainer);
checkSelectedInsights();
});
// Add to unselected by default
// tagElement.classList.add('selected');
unselectedInsights.push(insight);
insightsList.appendChild(tagElement);
});
// Store initial selections
row.dataset.selectedInsights = JSON.stringify(selectedInsights);
row.dataset.unselectedInsights = JSON.stringify(unselectedInsights);
} else {
insightsContainer.innerHTML = 'No insights found
';
}
// Process next document
updateProgress();
processNextDocument(index + 1);
})
.catch(error => {
console.error('Error:', error);
insightsContainer.innerHTML = `Error extracting insights: ${error.message}
`;
// Continue with next document even if this one failed
updateProgress();
processNextDocument(index + 1);
});
}
// Start processing documents
processNextDocument(0);
}
function groupInsightsByScore() {
// Get all query items
const queryItems = document.querySelectorAll('.query-item');
let hasInsights = false;
// Create structure to hold insights grouped by score
const insightsByScore = {
5: { insights: [], sources: [] },
4: { insights: [], sources: [] },
3: { insights: [], sources: [] },
2: { insights: [], sources: [] },
1: { insights: [], sources: [] },
0: { insights: [], sources: [] }
};
// Collect all insights from all documents and group by score
queryItems.forEach(queryItem => {
const rows = queryItem.querySelectorAll('tbody tr:not(.insights-row)');
rows.forEach(row => {
// Skip if no score or insights
if (row.cells.length <= 4 || !row.dataset.selectedInsights) {
return;
}
// Get the score
const scoreText = row.cells[4].textContent.trim();
if (scoreText === 'Error' || scoreText === 'N/A' || isNaN(parseFloat(scoreText))) {
return;
}
const score = Math.round(parseFloat(scoreText));
const urlLink = row.querySelector('.url-link');
if (!urlLink) return;
// Get insights from this document
try {
const selectedInsights = JSON.parse(row.dataset.selectedInsights || '[]');
const unselectedInsights = JSON.parse(row.dataset.unselectedInsights || '[]');
const allInsights = [...selectedInsights, ...unselectedInsights];
// Add insights to the appropriate score group
if (score >= 0 && score <= 5 && allInsights.length > 0) {
hasInsights = true;
// For all insights in this document
allInsights.forEach(insight => {
// Check if this insight is already in the group
const existingIndex = insightsByScore[score].insights.findIndex(i => i === insight);
if (existingIndex === -1) {
// New insight
insightsByScore[score].insights.push(insight);
insightsByScore[score].sources.push({
url: urlLink.href,
title: row.cells[1].textContent.trim().substring(0, 30) + '...',
selected: selectedInsights.includes(insight)
});
}
});
}
} catch (e) {
console.error('Error parsing insights:', e);
}
});
});
if (!hasInsights) {
alert('No insights found. Please analyze documents and extract insights first.');
return;
}
// Create or get the grouped insights container
let container = document.getElementById('groupedInsightsContainer');
if (!container) {
container = document.createElement('div');
container.id = 'groupedInsightsContainer';
container.className = 'grouped-insights-container';
// Insert after the problem input card
const card = document.querySelector("#tab2 .card");
card.parentNode.insertBefore(container, card.nextSibling);
}
// Create header
const header = document.createElement('div');
header.className = 'grouped-insights-header';
header.innerHTML = `
Insights Grouped by Score
`;
// Create content area
const content = document.createElement('div');
content.className = 'grouped-insights-content';
// Create score groups
for (let score = 5; score >= 0; score--) {
const insights = insightsByScore[score].insights;
const sources = insightsByScore[score].sources;
if (insights.length === 0) continue;
const scoreGroup = document.createElement('div');
scoreGroup.className = 'score-group';
scoreGroup.dataset.score = score;
// Create score header
const scoreHeader = document.createElement('div');
scoreHeader.className = 'score-group-header';
let scoreColor = '';
if (score >= 0 && score <= 5) {
const redComponent = Math.floor((score / 5) * 255);
const greenComponent = Math.floor(((5 - score) / 5) * 255);
scoreColor = `background-color: rgb(${redComponent}, ${greenComponent}, 0); color: white;`;
}
scoreHeader.innerHTML = `
${score}
Score ${score} Insights (${insights.length})
Select All
Clear All
`;
// Create insights list
const insightsList = document.createElement('div');
insightsList.className = 'score-insights-list';
// Add each insight
insights.forEach((insight, index) => {
const source = sources[index];
const tagElement = document.createElement('div');
tagElement.className = `grouped-insight-tag${source.selected ? ' selected' : ''}`;
tagElement.dataset.score = score;
tagElement.dataset.index = index;
tagElement.dataset.source = source.url;
// Create insight text with source link
tagElement.innerHTML = `
${insight}
${score}
`;
// Add click event to toggle selection
tagElement.addEventListener('click', function(e) {
// Prevent clicking on the source link from toggling selection
if (e.target.classList.contains('insight-source')) return;
this.classList.toggle('selected');
updateGroupedInsightSelections();
});
insightsList.appendChild(tagElement);
});
// Add header and list to score group
scoreGroup.appendChild(scoreHeader);
scoreGroup.appendChild(insightsList);
// Add score group to content
content.appendChild(scoreGroup);
}
// Clear the container and add new content
container.innerHTML = '';
container.appendChild(header);
container.appendChild(content);
// Show the container
container.style.display = 'block';
// Collapse all accordions
const accordions = document.querySelectorAll('.accordion-section');
accordions.forEach(accordion => {
const header = accordion.querySelector('.accordion-header');
const body = accordion.querySelector('.accordion-body');
if (header && body && !header.classList.contains('collapsed')) {
header.classList.add('collapsed');
body.classList.add('collapsed');
// Update the toggle icon
const toggleIcon = header.querySelector('.toggle-icon');
if (toggleIcon) toggleIcon.textContent = '▶';
}
});
// Scroll to the insights container
container.scrollIntoView({ behavior: 'smooth' });
// Remove the pulse animation after a few seconds
setTimeout(() => {
const aiSelectBtn = document.getElementById('aiSelectButton');
if (aiSelectBtn) {
aiSelectBtn.classList.remove('pulse');
}
}, 5000);
}
function enhanceProblem() {
const problemInput = document.getElementById('userProblemDescription');
const originalProblem = problemInput.value.trim();
if (!originalProblem) {
alert('Please provide a technical problem description first');
return;
}
const selectedInsights = collectAllSelectedInsights();
if (selectedInsights.length === 0) {
alert('Please select at least one insight to enhance the problem');
return;
}
// Get user comments if any
const userComments = document.getElementById('insightCommentArea')?.value || '';
// If we have stored refined problems for this exact problem, just show them
const currentProblemKey = JSON.stringify({
problem: originalProblem,
insights: selectedInsights.sort(),
comments: userComments
});
if (storedRefinedProblems[currentProblemKey]) {
showRefinedProblems(storedRefinedProblems[currentProblemKey]);
return;
}
// Show loading overlay
const loadingOverlay = document.getElementById('globalLoadingOverlay');
if (loadingOverlay) {
loadingOverlay.style.display = 'flex';
loadingOverlay.querySelector('.progress-text').textContent = 'Enhancing problem statement...';
}
// Send request to backend to refine the problem
fetch('/refine-problem', {
method: 'POST',
body: JSON.stringify({
'original_problem': originalProblem,
'insights': selectedInsights,
'user_comments': userComments
}),
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
// Hide loading overlay
if (loadingOverlay) loadingOverlay.style.display = 'none';
if (data.error) {
alert(`Error: ${data.error}`);
return;
}
if (data.result) {
// Add current problem to history if not already there
if (currentHistoryIndex === -1) {
problemHistory.push(originalProblem);
currentHistoryIndex = 0;
}
// Store the refined problems for future use
storedRefinedProblems[currentProblemKey] = data.result;
// Show refined problem options
showRefinedProblems(data.result);
}
})
.catch(error => {
console.error('Error:', error);
if (loadingOverlay) loadingOverlay.style.display = 'none';
alert(`Error enhancing problem: ${error.message}`);
});
}
function closeGroupedInsights() {
const container = document.getElementById('groupedInsightsContainer');
if (container) {
container.style.display = 'none';
}
}
// Select all insights for a specific score
function selectAllInScore(score) {
const container = document.getElementById('groupedInsightsContainer');
const tags = container.querySelectorAll(`.grouped-insight-tag[data-score="${score}"]`);
tags.forEach(tag => {
tag.classList.add('selected');
});
updateGroupedInsightSelections();
}
// Clear all insights for a specific score
function clearAllInScore(score) {
const container = document.getElementById('groupedInsightsContainer');
const tags = container.querySelectorAll(`.grouped-insight-tag[data-score="${score}"]`);
tags.forEach(tag => {
tag.classList.remove('selected');
});
updateGroupedInsightSelections();
}
function updateGroupedInsightSelections() {
// Get all selected insights from the grouped view
const container = document.getElementById('groupedInsightsContainer');
const selectedTags = container.querySelectorAll('.grouped-insight-tag.selected');
// Create a mapping of URL to selected insights
const selectionsBySource = {};
// Process each selected tag
selectedTags.forEach(tag => {
const insight = tag.textContent.trim().replace(/\d+$/, '').trim(); // Remove the score number at the end
const sourceUrl = tag.dataset.source;
if (!selectionsBySource[sourceUrl]) {
selectionsBySource[sourceUrl] = [];
}
selectionsBySource[sourceUrl].push(insight);
});
// Now update the original document rows
const queryItems = document.querySelectorAll('.query-item');
queryItems.forEach(queryItem => {
const rows = queryItem.querySelectorAll('tbody tr:not(.insights-row)');
rows.forEach(row => {
const urlLink = row.querySelector('.url-link');
if (!urlLink) return;
const sourceUrl = urlLink.href;
// If we have selections for this source
if (selectionsBySource[sourceUrl]) {
// Get all insights for this row
try {
// Combine selected and unselected to get all insights
const currentSelected = JSON.parse(row.dataset.selectedInsights || '[]');
const currentUnselected = JSON.parse(row.dataset.unselectedInsights || '[]');
const allInsights = [...currentSelected, ...currentUnselected];
// New selected and unselected based on grouped view
const newSelected = [];
const newUnselected = [];
// Process each insight
allInsights.forEach(insight => {
if (selectionsBySource[sourceUrl].includes(insight)) {
newSelected.push(insight);
} else {
newUnselected.push(insight);
}
});
// Update the dataset
row.dataset.selectedInsights = JSON.stringify(newSelected);
row.dataset.unselectedInsights = JSON.stringify(newUnselected);
} catch (e) {
console.error('Error updating insights selections:', e);
}
}
});
});
// Update enhance button state
checkSelectedInsights();
}
function showRefinedProblems(result) {
const refinedContainer = document.getElementById('refinedProblemContainer');
const tabs = document.getElementById('refinedProblemTabs');
const content = document.getElementById('refinedProblemContent');
// Clear previous content
tabs.innerHTML = '';
content.innerHTML = '';
// Add tabs and content for each refined problem
let isFirst = true;
for (const key in result) {
if (result.hasOwnProperty(key)) {
const problem = result[key];
// Create tab
const tab = document.createElement('div');
tab.className = `refined-problem-tab ${isFirst ? 'active' : ''}`;
tab.dataset.target = key;
tab.textContent = `Option ${key.split('_')[1]}`;
tab.onclick = function() {
document.querySelectorAll('.refined-problem-tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.refined-problem').forEach(p => p.classList.remove('active'));
tab.classList.add('active');
document.getElementById(key).classList.add('active');
};
tabs.appendChild(tab);
// Create content
const problemDiv = document.createElement('div');
problemDiv.className = `refined-problem ${isFirst ? 'active' : ''}`;
problemDiv.id = key;
const title = document.createElement('div');
title.className = 'refined-problem-title';
title.textContent = problem.title;
const description = document.createElement('div');
description.className = 'refined-problem-description';
description.textContent = problem.description;
const applyButton = document.createElement('button');
applyButton.className = 'apply-problem-btn';
applyButton.textContent = 'Apply This Problem';
applyButton.onclick = function() {
applyRefinedProblem(problem.description);
};
problemDiv.appendChild(title);
problemDiv.appendChild(description);
problemDiv.appendChild(applyButton);
content.appendChild(problemDiv);
isFirst = false;
}
}
// Show the container
refinedContainer.style.display = 'block';
// Scroll to the container
refinedContainer.scrollIntoView({ behavior: 'smooth' });
}
function applyRefinedProblem(problemText) {
const problemInput = document.getElementById('userProblemDescription');
// Add current problem to history
problemHistory.push(problemInput.value);
currentHistoryIndex = problemHistory.length - 1; // Set to latest version
// Update problem text with the new version
problemInput.value = problemText;
// Now add the new version to history
problemHistory.push(problemText);
currentHistoryIndex = problemHistory.length - 1; // Update index to point to the newly added version
// Update history navigation display
updateHistoryNavigation();
// Display is kept visible, removed: document.getElementById('refinedProblemContainer').style.display = 'none';
// Focus on the problem input
problemInput.focus();
console.log("Problem history after applying:", problemHistory, "Current index:", currentHistoryIndex);
}
function updateHistoryNavigation() {
const historyNav = document.getElementById('problemHistoryNav');
const prevBtn = historyNav.querySelector('.history-prev');
const nextBtn = historyNav.querySelector('.history-next');
const status = historyNav.querySelector('.history-status');
// Update buttons state
prevBtn.classList.toggle('disabled', currentHistoryIndex <= 0);
nextBtn.classList.toggle('disabled', currentHistoryIndex >= problemHistory.length - 1);
// Update status text
if (problemHistory.length > 0) {
status.textContent = `Version ${currentHistoryIndex + 1} of ${problemHistory.length}`;
historyNav.style.display = 'flex';
} else {
historyNav.style.display = 'none';
}
}
function aiSelectInsights() {
const patentBackground = document.getElementById('userProblemDescription').value.trim();
if (!patentBackground) {
alert('Please provide a patent background in the input field');
return;
}
// Change button appearance to show it's working
const aiSelectBtn = document.getElementById('aiSelectButton');
if (aiSelectBtn) {
aiSelectBtn.disabled = true;
aiSelectBtn.textContent = 'AI Selecting...';
aiSelectBtn.style.opacity = '0.7';
}
// Show loading overlay
const loadingOverlay = document.getElementById('globalLoadingOverlay');
if (loadingOverlay) {
loadingOverlay.style.display = 'flex';
loadingOverlay.querySelector('.progress-text').textContent = 'AI selecting the most relevant insights...';
}
// Get all insights from all score groups
const container = document.getElementById('groupedInsightsContainer');
const insightTags = container.querySelectorAll('.grouped-insight-tag');
const insights = Array.from(insightTags).map(tag => {
return tag.textContent.trim().replace(/\d+$/, '').trim(); // Remove the score number
});
if (insights.length === 0) {
if (loadingOverlay) loadingOverlay.style.display = 'none';
alert('No insights found');
return;
}
// Send request to backend to get AI selection
fetch('/ai-select-insights', {
method: 'POST',
body: JSON.stringify({
'patent_background': patentBackground,
'insights': insights
}),
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
// Reset button appearance
if (aiSelectBtn) {
aiSelectBtn.disabled = false;
aiSelectBtn.textContent = 'AI Select Insights';
aiSelectBtn.style.opacity = '1';
}
if (loadingOverlay) loadingOverlay.style.display = 'none';
if (data.error) {
alert(`Error: ${data.error}`);
return;
}
if (data.selected_insights && data.selected_insights.length > 0) {
// First clear all selections
insightTags.forEach(tag => {
tag.classList.remove('selected');
});
// Then select the recommended insights
insightTags.forEach(tag => {
const insightText = tag.textContent.trim().replace(/\d+$/, '').trim();
if (data.selected_insights.includes(insightText)) {
tag.classList.add('selected');
}
});
// Update the original document rows
updateGroupedInsightSelections();
// Remove alert notification - user can see the selected insights visually
// alert(`AI selected ${data.selected_insights.length} insights from ${insights.length} available insights`);
} else {
alert('AI could not identify any relevant insights to select');
}
})
.catch(error => {
console.error('Error:', error);
// Reset button appearance
if (aiSelectBtn) {
aiSelectBtn.disabled = false;
aiSelectBtn.textContent = 'AI Select Insights';
aiSelectBtn.style.opacity = '1';
}
if (loadingOverlay) loadingOverlay.style.display = 'none';
alert(`Error using AI to select insights: ${error.message}`);
});
}
function generateSearchQueries() {
function addQueryField(queryText = '', container = null) {
const queriesContainer = container || document.getElementById('queriesContainer');
// Count existing query items in this container for indexing
const queryItems = container ?
container.querySelectorAll('.query-item') :
document.getElementById('queriesContainer').querySelectorAll('.query-item');
const queryIndex = queryItems.length + 1;
// Create main container for this query item
const queryItem = document.createElement('div');
queryItem.className = 'query-item';
// Create container for query field and buttons
const queryContainer = document.createElement('div');
queryContainer.className = 'query-container';
// Input field
const queryField = document.createElement('input');
queryField.type = 'text';
queryField.className = 'query-field';
queryField.value = queryText;
queryField.placeholder = `Search Query ${queryIndex}`;
// Delete button
const deleteButton = document.createElement('button');
deleteButton.type = 'button';
deleteButton.className = 'action-button delete-button';
deleteButton.textContent = 'Delete';
deleteButton.onclick = function() {
queryItem.parentNode.removeChild(queryItem);
// Update the placeholder numbers for remaining queries within this container
const parent = container || document.getElementById('queriesContainer');
const items = parent.querySelectorAll('.query-item');
items.forEach((item, idx) => {
const field = item.querySelector('.query-field');
if (field) field.placeholder = `Search Query ${idx + 1}`;
});
};
// Search button
const searchButton = document.createElement('button');
searchButton.type = 'button';
searchButton.className = 'action-button search-button';
searchButton.textContent = 'Search';
searchButton.onclick = function() {
performSearch(queryField.value, queryItem);
};
// Add elements to container
queryContainer.appendChild(queryField);
queryContainer.appendChild(searchButton);
queryContainer.appendChild(deleteButton);
// Create loading indicator for this search
const searchLoading = document.createElement('div');
searchLoading.className = 'search-loading';
searchLoading.textContent = 'Searching... Please wait.';
// Create table for results
const resultsTable = document.createElement('table');
resultsTable.className = 'results-table';
// Add table header
const tableHeader = document.createElement('thead');
const headerRow = document.createElement('tr');
const typeHeader = document.createElement('th');
typeHeader.textContent = 'Type';
const titleHeader = document.createElement('th');
titleHeader.textContent = 'Title';
const bodyHeader = document.createElement('th');
bodyHeader.textContent = 'Description';
const urlHeader = document.createElement('th');
urlHeader.textContent = 'URL';
const scoreHeader = document.createElement('th');
scoreHeader.textContent = 'Score';
const justificationHeader = document.createElement('th');
justificationHeader.textContent = 'Justification';
headerRow.appendChild(typeHeader);
headerRow.appendChild(titleHeader);
headerRow.appendChild(bodyHeader);
headerRow.appendChild(urlHeader);
headerRow.appendChild(scoreHeader);
headerRow.appendChild(justificationHeader);
tableHeader.appendChild(headerRow);
// Add table body
const tableBody = document.createElement('tbody');
resultsTable.appendChild(tableHeader);
resultsTable.appendChild(tableBody);
// Add all elements to the query item
queryItem.appendChild(queryContainer);
queryItem.appendChild(searchLoading);
queryItem.appendChild(resultsTable);
// Add container to the queries list
queriesContainer.appendChild(queryItem);
}
function createAccordionSection(timestamp) {
const accordionSection = document.createElement('div');
accordionSection.className = 'accordion-section';
const accordionHeader = document.createElement('div');
accordionHeader.className = 'accordion-header';
accordionHeader.innerHTML = `
Search Results ${timestamp}
▼
`;
accordionHeader.onclick = function() {
this.classList.toggle('collapsed');
const body = this.nextElementSibling;
body.classList.toggle('collapsed');
// Update the toggle icon
const toggleIcon = this.querySelector('.toggle-icon');
if (body.classList.contains('collapsed')) {
toggleIcon.textContent = '▶';
} else {
toggleIcon.textContent = '▼';
}
};
const accordionBody = document.createElement('div');
accordionBody.className = 'accordion-body';
const accordionContent = document.createElement('div');
accordionContent.className = 'accordion-content';
accordionBody.appendChild(accordionContent);
accordionSection.appendChild(accordionHeader);
accordionSection.appendChild(accordionBody);
return accordionSection;
}
const userInput = document.getElementById('userProblemDescription').value.trim();
if (!userInput) {
alert('Please enter a technical problem description');
return;
}
// Show loading indicator
document.getElementById('loadingIndicator').style.display = 'block';
// Collapse all existing query sections
const existingAccordions = document.querySelectorAll('.accordion-section');
existingAccordions.forEach(accordion => {
const header = accordion.querySelector('.accordion-header');
const body = accordion.querySelector('.accordion-body');
if (header && body && !header.classList.contains('collapsed')) {
header.classList.add('collapsed');
body.classList.add('collapsed');
}
});
// Send message to Flask backend
fetch('/chat', {
method: 'POST',
body: new URLSearchParams({ 'message': userInput }),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})
.then(response => response.json())
.then(data => {
// Hide loading indicator
document.getElementById('loadingIndicator').style.display = 'none';
try {
// Parse the JSON string from the LLM response
let jsonData;
// First check if data.reply is already an object
if (typeof data.reply === 'object') {
jsonData = data.reply;
} else {
// Try to extract JSON if it's a string possibly with markdown code blocks
const jsonString = data.reply.replace(/```json|```/g, '').trim();
jsonData = JSON.parse(jsonString);
}
// Create a new accordion section for these search results
const timestamp = new Date().toLocaleString();
const accordionSection = createAccordionSection(timestamp);
// Add each query from the response to this accordion
Object.keys(jsonData).forEach(key => {
addQueryField(jsonData[key], accordionSection.querySelector('.accordion-content'));
});
// Add the accordion to the container
const queriesContainer = document.getElementById('queriesContainer');
queriesContainer.insertBefore(accordionSection, queriesContainer.firstChild);
// Show results container
document.getElementById('resultsContainer').style.display = 'block';
} catch (error) {
console.error('Error parsing JSON:', error);
alert('There was an error processing the response. Please try again.');
}
})
.catch(error => {
document.getElementById('loadingIndicator').style.display = 'none';
console.error('Error:', error);
alert('There was an error communicating with the server. Please try again.');
});
}
function displayKeyIssues(keyIssues) {
// Get or create the key issues container
let keyIssuesContainer = document.getElementById('keyIssuesContainer');
if (!keyIssuesContainer) {
keyIssuesContainer = document.createElement('div');
keyIssuesContainer.id = 'keyIssuesContainer';
keyIssuesContainer.className = 'key-issues-container';
document.getElementById('resultsContainer').appendChild(keyIssuesContainer);
}
// Clear previous content
keyIssuesContainer.innerHTML = '';
// Create header
const header = document.createElement('h3');
header.textContent = 'Key Issues';
keyIssuesContainer.appendChild(header);
// Create issues list
const issuesList = document.createElement('div');
issuesList.className = 'key-issues-list';
const KIsubmitButton = document.createElement('button');
KIsubmitButton.className = "btn btn-primary";
KIsubmitButton.id = "key-issues-submit-btn";
KIsubmitButton.textContent = "Generate problem descriptions";
KIsubmitButton.style.marginTop = "10px";
KIsubmitButton.onclick = generateProblemDescriptions;
const centerButton = document.createElement("center");
centerButton.appendChild(KIsubmitButton);
// Add each key issue
keyIssues.forEach(issue => {
const issueCard = document.createElement('div');
issueCard.className = 'key-issue-card';
issueCard.dataset.id = issue.id;
const issueTitle = document.createElement('div');
issueTitle.className = 'key-issue-title';
issueTitle.textContent = issue.title;
const issueDescription = document.createElement('div');
issueDescription.className = 'key-issue-description';
issueDescription.textContent = issue.description;
const challengesTitle = document.createElement('div');
challengesTitle.style.fontWeight = 'bold';
challengesTitle.style.marginTop = '10px';
challengesTitle.textContent = 'Challenges:';
const challengesList = document.createElement('ul');
challengesList.className = 'key-issue-challenges';
issue.challenges.forEach(challenge => {
const challengeItem = document.createElement('li');
challengeItem.textContent = challenge;
challengesList.appendChild(challengeItem);
});
const impactTitle = document.createElement('div');
impactTitle.style.fontWeight = 'bold';
impactTitle.style.marginTop = '10px';
impactTitle.textContent = 'Potential Impact:';
const issueImpact = document.createElement('div');
issueImpact.className = 'key-issue-impact';
issueImpact.textContent = issue.potential_impact;
// Add click handler to toggle selection
issueCard.addEventListener('click', function() {
this.classList.toggle('selected');
});
// Append all elements
issueCard.appendChild(issueTitle);
issueCard.appendChild(issueDescription);
issueCard.appendChild(challengesTitle);
issueCard.appendChild(challengesList);
issueCard.appendChild(impactTitle);
issueCard.appendChild(issueImpact);
issuesList.appendChild(issueCard);
});
keyIssuesContainer.appendChild(issuesList);
keyIssuesContainer.appendChild(centerButton);
keyIssuesContainer.style.display = "block";
}
function generateProblemDescriptions(){
let result = {
descriptions: {},
challenges: {}
};
const selectedCards = document.querySelectorAll(".key-issue-card.selected");
selectedCards.forEach(card => {
const userInput = document.getElementById('userInput').value.trim();
const id = card.getAttribute("data-id");
const description = card.querySelector('.key-issue-description').textContent.trim();
const challenges = Array.from(card.querySelectorAll(".key-issue-challenges li")).map(challenge => challenge.textContent.trim());
result.descriptions[id] = description;
result.challenges[id] = challenges;
result["technical_topic"] = userInput;
})
document.querySelector('.progress-text').innerHTML = "Generating problem descriptions ... This may take a while."
document.getElementById('globalLoadingOverlay').style.display = 'flex';
// Send message to Flask backend
fetch('/create-several-probdesc', {
method: 'POST',
body: JSON.stringify(result),
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
// Hide loading indicator
document.getElementById('globalLoadingOverlay').style.display = 'none';
// Check if we have key issues in the response
if (data.problem_descriptions && data.problem_descriptions.length > 0) {
// Display the key issues
displayProblemDescriptions(data.problem_descriptions);
} else if (data.error) {
alert('Error: ' + data.error);
} else {
alert('No problem descriptions found/generated. Please try again with another or the same query.');
}
})
.catch(error => {
document.getElementById('globalLoadingOverlay').style.display = 'none';
console.error('Error:', error);
alert('There was an error communicating with the server. Please try again.');
});
}
function displayProblemDescriptions(probDescs) {
// Get or create the key issues container
let probDescCards = document.getElementById("probDescCards");
let probDescContainer = document.getElementById('probDescContainer');
// Clear previous content
probDescContainer.innerHTML = '';
// Create header
const header = document.createElement('h3');
header.textContent = 'Problem Descriptions';
probDescContainer.appendChild(header);
// Create issues list
const descriptionList = document.createElement('div');
descriptionList.className = 'prob-desc-list';
// Add each key issue
probDescs.forEach((desc, index) => {
const descCard = document.createElement('div');
descCard.className = 'prob-desc-card';
descCard.dataset.id = index+1;
const descTitle = document.createElement('div');
descTitle.className = 'prob-desc-title';
descTitle.textContent = `Problem Description n°${index+1}`;
const descDescription = document.createElement('div');
descDescription.className = 'prob-desc-description';
descDescription.textContent = desc;
// Add click handler to toggle selection
descCard.addEventListener('click', function() {
document.getElementById("userProblemDescription").textContent = desc;
document.getElementsByClassName("tablinks")[1].click();
});
// Append all elements
descCard.appendChild(descTitle);
descCard.appendChild(descDescription);
descriptionList.appendChild(descCard);
});
probDescContainer.appendChild(descriptionList);
probDescCards.style.display = "block";
}
function initRibbonAccordion() {
const ribbon = document.querySelector('.ribbon-accordion');
const ribbonHeader = ribbon.querySelector('.ribbon-header');
ribbonHeader.addEventListener('click', function() {
ribbon.classList.toggle('collapsed');
});
}
function setupRibbonButtons() {
// Generate Queries
document.getElementById('ribbonGenerateQueriesButton').addEventListener('click', function() {
generateSearchQueries();
});
// Analyze All
document.getElementById('ribbonAnalyzeAllButton').addEventListener('click', function() {
if(hasSearchResults()) {
analyzeAllPapers();
}
});
// Remove Failed
document.getElementById('ribbonRemoveFailedButton').addEventListener('click', function() {
if(hasSearchResults()) {
removeFailedAnalyses();
}
});
// Extract All Insights
document.getElementById('ribbonExtractAllInsightsButton').addEventListener('click', function() {
extractAllInsights();
});
// Group Insights
document.getElementById('ribbonGroupInsightsButton').addEventListener('click', function() {
groupInsightsByScore();
});
// Enhance Problem
document.getElementById('ribbonEnhanceProblemButton').addEventListener('click', function() {
enhanceProblem();
});
// Export to Excel
document.getElementById('ribbonExportExcelButton').addEventListener('click', function() {
if(hasSearchResults()) {
exportToExcel();
}
});
}
initRibbonAccordion();
setupRibbonButtons();