Ptt_Eval_V3 / templates /index.html
YchKhan's picture
Update templates/index.html
4169ea5 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Patentability</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<script>
// Array to store problem history versions
const problemHistory = [];
let currentHistoryIndex = -1;
// Store all refined problem suggestions
let storedRefinedProblems = {};
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.getElementById('loadingIndicator').style.display = 'block';
// 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('loadingIndicator').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('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';
// 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('div');
challengesList.className = 'key-issue-challenges';
issue.challenges.forEach(challenge => {
const challengeTag = document.createElement('div');
challengeTag.className = 'challenge-tag';
challengeTag.textContent = challenge;
// Add click handler to toggle selection
challengeTag.addEventListener('click', function(e) {
e.stopPropagation(); // Prevent triggering parent card click
this.classList.toggle('selected');
// Update selected challenges data
const selectedChallenges = JSON.parse(issueCard.dataset.selectedChallenges || '[]');
const challengeText = this.textContent;
if (this.classList.contains('selected')) {
// Add challenge to selected list if not already there
if (!selectedChallenges.includes(challengeText)) {
selectedChallenges.push(challengeText);
}
} else {
// Remove challenge from selected list
const index = selectedChallenges.indexOf(challengeText);
if (index !== -1) {
selectedChallenges.splice(index, 1);
}
}
// Update dataset
issueCard.dataset.selectedChallenges = JSON.stringify(selectedChallenges);
// Update card selected state based on whether any challenges are selected
if (selectedChallenges.length > 0) {
issueCard.classList.add('selected');
} else {
issueCard.classList.remove('selected');
}
});
challengesList.appendChild(challengeTag);
});
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);
// Show the results container
document.getElementById('resultsContainer').style.display = 'block';
}
// Add a new query field with the given text (or empty if not provided)
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);
}
// Perform search and update the results table
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';
});
}
// Extract insights from document
function extractInsights(paperUrl, row) {
const patentBackground = document.getElementById('userInput').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 = '<div class="loading-spinner"></div><div>Extracting insights...</div>';
} 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 = '<div class="loading-spinner"></div><div>Extracting insights...</div>';
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 = `<div class="error">Error: ${data.error}</div>`;
} 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 = '<div class="error">No insights found</div>';
}
})
.catch(error => {
console.error('Error:', error);
insightsContainer.innerHTML = `<div class="error">Error extracting insights: ${error.message}</div>`;
});
}
// Helper function to update selected insights stored in the row's dataset
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);
}
// Collect all selected insights from all rows
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;
}
// Enhance the problem using the selected insights
function enhanceProblem() {
const problemInput = document.getElementById('userInput');
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}`);
});
}
// Display the refined problem options
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' });
}
// Apply the selected refined problem
function applyRefinedProblem(problemText) {
const problemInput = document.getElementById('userInput');
// 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);
}
// Update the history navigation UI
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';
}
}
// Navigate to previous problem version
function navigateProblemHistory(direction) {
const problemInput = document.getElementById('userInput');
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 analyzePaper(paperUrl, queryItemElement) {
const patentBackground = document.getElementById('userInput').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 = '<div class="loading-spinner"></div>';
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 = '<div class="loading-spinner"></div>';
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';
});
}
// Update the placeholder text numbers after deletions
function updateQueryIndices() {
const queryItems = document.getElementById('queriesContainer').children;
for (let i = 0; i < queryItems.length; i++) {
const queryField = queryItems[i].querySelector('.query-field');
queryField.placeholder = `Search Query ${i + 1}`;
}
}
// Get all queries as an array of strings
function getQueries() {
const queryFields = document.querySelectorAll('.query-field');
return Array.from(queryFields).map(field => field.value.trim());
}
// Analyze all unanalyzed papers in the results
function analyzeAllPapers() {
// Show loading overlay
const loadingOverlay = document.getElementById('globalLoadingOverlay');
if (loadingOverlay) loadingOverlay.style.display = 'flex';
// 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('userInput').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 = '<div class="loading-spinner"></div>';
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 = '<div class="loading-spinner"></div>';
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();
}
}
});
});
}
// Remove rows with failed analyses
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);
}
// Export all tables to Excel
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('userInput').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('userInput').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}`);
}
}
// Check if any insights are selected to enable/disable enhance button
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;
}
}
// Initialize comment area for insights
function initializeCommentArea() {
const container = document.getElementById('insightCommentContainer');
if (!container) return;
const textarea = document.createElement('textarea');
textarea.id = 'insightCommentArea';
textarea.className = 'insight-comment-textarea';
textarea.placeholder = 'Add additional suggestions for enhancing the problem (optional)...';
container.innerHTML = '';
container.appendChild(textarea);
}
// Create a new accordion section for search results
function createAccordionSection(timestamp) {
const accordionSection = document.createElement('div');
accordionSection.className = 'accordion-section';
const accordionHeader = document.createElement('div');
accordionHeader.className = 'accordion-header';
accordionHeader.innerHTML = `
<span>Search Results <span class="query-timestamp">${timestamp}</span></span>
<span class="toggle-icon">▼</span>
`;
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;
}
// Extract insights from all analyzed documents
function extractAllInsights() {
const patentBackground = document.getElementById('userInput').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 = '<div class="loading-spinner"></div><div>Extracting insights...</div>';
} 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 = '<div class="loading-spinner"></div><div>Extracting insights...</div>';
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 = `<div class="error">Error: ${data.error}</div>`;
} 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 = '<div class="error">No insights found</div>';
}
// Process next document
updateProgress();
processNextDocument(index + 1);
})
.catch(error => {
console.error('Error:', error);
insightsContainer.innerHTML = `<div class="error">Error extracting insights: ${error.message}</div>`;
// Continue with next document even if this one failed
updateProgress();
processNextDocument(index + 1);
});
}
// Start processing documents
processNextDocument(0);
}
// Check if any documents have been analyzed to enable/disable Extract All Insights button
function checkAnalyzedDocuments() {
const queryItems = document.querySelectorAll('.query-item');
let hasAnalyzedDocuments = false;
queryItems.forEach(queryItem => {
const rows = queryItem.querySelectorAll('tbody tr:not(.insights-row)');
rows.forEach(row => {
// Check if the row has score and justification cells (has been analyzed)
if (row.cells.length > 4 && row.cells[4].textContent.trim() !== 'Error' &&
row.cells[4].textContent.trim() !== '') {
hasAnalyzedDocuments = true;
}
});
});
const extractAllButton = document.getElementById('extractAllInsightsButton');
if (hasAnalyzedDocuments) {
extractAllButton.classList.remove('disabled');
extractAllButton.disabled = false;
} else {
extractAllButton.classList.add('disabled');
extractAllButton.disabled = true;
}
}
// Group insights by score and display in a consolidated table
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('.card');
card.parentNode.insertBefore(container, card.nextSibling);
}
// Create header
const header = document.createElement('div');
header.className = 'grouped-insights-header';
header.innerHTML = `
<div>Insights Grouped by Score</div>
<div class="grouped-insights-actions">
<button class="ai-select-btn pulse" id="aiSelectButton" onclick="aiSelectInsights()">AI Select Insights</button>
<div class="grouped-insights-close" onclick="closeGroupedInsights()">&times;</div>
</div>
`;
// 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 = `
<div>
<span style="display: inline-block; width: 25px; height: 25px; text-align: center; border-radius: 50%; ${scoreColor} font-weight: bold;">${score}</span>
<span style="margin-left: 8px;">Score ${score} Insights (${insights.length})</span>
</div>
<div class="score-group-actions">
<button class="insights-button select-score-all-btn" onclick="selectAllInScore(${score})">Select All</button>
<button class="insights-button clear-score-all-btn" onclick="clearAllInScore(${score})">Clear All</button>
</div>
`;
// 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}
<a href="${source.url}" target="_blank" class="insight-source" title="${source.title}">${score}</a>
`;
// 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);
}
// Close the grouped insights view
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();
}
// Update the original document rows
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();
}
// Use AI to select the most relevant insights across all score groups
function aiSelectInsights() {
const patentBackground = document.getElementById('userInput').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}`);
});
}
// Check if any documents have been analyzed to enable/disable the Group Insights button
function checkGroupInsightsButton() {
const queryItems = document.querySelectorAll('.query-item');
let hasInsights = false;
queryItems.forEach(queryItem => {
const rows = queryItem.querySelectorAll('tbody tr:not(.insights-row)');
rows.forEach(row => {
if (row.dataset.selectedInsights || row.dataset.unselectedInsights) {
try {
const selected = JSON.parse(row.dataset.selectedInsights || '[]');
const unselected = JSON.parse(row.dataset.unselectedInsights || '[]');
if (selected.length > 0 || unselected.length > 0) {
hasInsights = true;
}
} catch (e) {}
}
});
});
const groupInsightsButton = document.getElementById('groupInsightsByScoreButton');
if (hasInsights) {
groupInsightsButton.classList.remove('disabled');
groupInsightsButton.disabled = false;
} else {
groupInsightsButton.classList.add('disabled');
groupInsightsButton.disabled = true;
}
}
function generateSearchQueries() {
const userInput = document.getElementById('userInput').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.');
});
}
</script>
<script>
document.addEventListener('DOMContentLoaded', () => {
const form = document.querySelector('form');
const userInput = document.getElementById('userInput');
const loadingIndicator = document.getElementById('loadingIndicator');
const keyIssuesContainer = document.getElementById('keyIssuesContainer');
const keyIssuesList = document.getElementById('keyIssuesList');
const insightCommentContainer = document.getElementById('insightCommentContainer');
// Store selected key issues
let selectedKeyIssues = [];
// Handle form submission
form.addEventListener('submit', async (e) => {
e.preventDefault();
const userQuery = userInput.value.trim();
if (!userQuery) {
alert('Please enter a problem description.');
return;
}
// Show loading indicator
loadingIndicator.style.display = 'block';
keyIssuesContainer.style.display = 'none';
keyIssuesList.innerHTML = '';
try {
// Call the generate-key-issues endpoint
const response = await fetch('/generate-key-issues', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query: userQuery }),
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
if (data.error) {
alert(`Error: ${data.error}`);
return;
}
// Display key issues
displayKeyIssues(data.key_issues);
} catch (error) {
console.error('Error generating key issues:', error);
alert(`Error generating key issues: ${error.message}`);
} finally {
// Hide loading indicator
loadingIndicator.style.display = 'none';
}
});
// Function to display key issues
function displayKeyIssues(keyIssues) {
if (!keyIssues || keyIssues.length === 0) {
alert('No key issues found.');
return;
}
// Reset selected issues
selectedKeyIssues = [];
// Clear previous issues
keyIssuesList.innerHTML = '';
// Create and append key issue cards
keyIssues.forEach(issue => {
const issueCard = document.createElement('div');
issueCard.className = 'key-issue-card';
issueCard.dataset.issueId = issue.id;
// Format the content with title, description, challenges and impact
let cardContent = `
<div class="key-issue-title">${issue.title}</div>
<div class="key-issue-description">${issue.description}</div>
<ul class="key-issue-challenges">
`;
// Add each challenge as a list item
issue.challenges.forEach(challenge => {
cardContent += `<li>${challenge}</li>`;
});
cardContent += `
</ul>
<div class="key-issue-impact">Impact: ${issue.potential_impact}</div>
`;
issueCard.innerHTML = cardContent;
// Add click handler to toggle selection
issueCard.addEventListener('click', () => {
issueCard.classList.toggle('selected');
if (issueCard.classList.contains('selected')) {
selectedKeyIssues.push(issue);
} else {
selectedKeyIssues = selectedKeyIssues.filter(item => item.id !== issue.id);
}
// Update the comment area based on selections
updateCommentArea();
});
keyIssuesList.appendChild(issueCard);
});
// Show the key issues container
keyIssuesContainer.style.display = 'block';
}
// Function to update the comment area when key issues are selected
function updateCommentArea() {
if (selectedKeyIssues.length > 0) {
let commentHTML = `
<h4>Selected Key Issues</h4>
<textarea class="insight-comment-textarea" placeholder="Add your thoughts about these key issues..."></textarea>
`;
insightCommentContainer.innerHTML = commentHTML;
} else {
insightCommentContainer.innerHTML = '';
}
}
});
</script>
<script>
// Add event listeners for floating buttons
document.addEventListener('DOMContentLoaded', function() {
// Initialize the comment area
initializeCommentArea();
// Check for selected insights periodically to enable/disable enhance button
setInterval(checkSelectedInsights, 1000);
// Check for analyzed documents to enable/disable Extract All Insights button
setInterval(checkAnalyzedDocuments, 1000);
// Check for insights to enable/disable Group Insights by Score button
setInterval(checkGroupInsightsButton, 1000);
// Check if search has been performed and update button states
setInterval(checkSearchPerformed, 1000);
// Analyze all button
document.getElementById('analyzeAllButton').addEventListener('click', function() {
if(hasSearchResults()) {
analyzeAllPapers();
}
});
// Remove failed button
document.getElementById('removeFailedButton').addEventListener('click', function() {
if(hasSearchResults()) {
removeFailedAnalyses();
}
});
// Export to Excel button
document.getElementById('exportExcelButton').addEventListener('click', function() {
if(hasSearchResults()) {
exportToExcel();
}
});
// Generate Search Queries floating button
document.getElementById('generateQueriesButton').addEventListener('click', function() {
// Call the search queries generation function
generateSearchQueries();
});
// Initialize the collapsible ribbon
initRibbonAccordion();
// Set up ribbon button events
setupRibbonButtons();
// Auto Run All button
document.getElementById('autoRunAllButton').addEventListener('click', function() {
autoRunAllProcess();
});
});
// Function to check if any search has been performed
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 to check if search has been performed and update all button states
function checkSearchPerformed() {
const searchPerformed = hasSearchResults();
// Get all floating buttons
const analyzeAllButton = document.getElementById('analyzeAllButton');
const removeFailedButton = document.getElementById('removeFailedButton');
const extractAllInsightsButton = document.getElementById('extractAllInsightsButton');
const groupInsightsButton = document.getElementById('groupInsightsByScoreButton');
const enhanceProblemButton = document.getElementById('enhanceProblemButton');
const exportExcelButton = document.getElementById('exportExcelButton');
// Set disabled state for buttons that should be disabled when no search is performed
if (!searchPerformed) {
analyzeAllButton.classList.add('disabled');
analyzeAllButton.disabled = true;
removeFailedButton.classList.add('disabled');
removeFailedButton.disabled = true;
exportExcelButton.classList.add('disabled');
exportExcelButton.disabled = true;
// The other buttons (extract, group, enhance) should already be disabled by their respective check functions
} else {
analyzeAllButton.classList.remove('disabled');
analyzeAllButton.disabled = false;
removeFailedButton.classList.remove('disabled');
removeFailedButton.disabled = false;
exportExcelButton.classList.remove('disabled');
exportExcelButton.disabled = false;
// The other buttons will be enabled/disabled by their respective check functions
}
}
// Initialize the ribbon accordion
function initRibbonAccordion() {
const ribbon = document.querySelector('.ribbon-accordion');
const ribbonHeader = ribbon.querySelector('.ribbon-header');
ribbonHeader.addEventListener('click', function() {
ribbon.classList.toggle('collapsed');
});
}
// Set up ribbon button events (mirror the functionality of the floating buttons)
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();
}
});
}
// Auto Run All Process - This automates the entire workflow
async function autoRunAllProcess() {
// Check if there's a problem description
const userInput = document.getElementById('userInput').value.trim();
if (!userInput) {
alert('Please enter a technical problem description first');
return;
}
// Show the ribbon fully
document.querySelector('.ribbon-accordion').classList.remove('collapsed');
// Show progress bar and step indicator
const progressBarContainer = document.querySelector('.progress-bar-container');
const progressBar = document.querySelector('.progress-bar');
const progressStep = document.querySelector('.progress-step');
progressBarContainer.style.display = 'block';
progressStep.style.display = 'block';
progressBar.style.width = '0%';
// Disable the auto run button
const autoRunBtn = document.getElementById('autoRunAllButton');
autoRunBtn.disabled = true;
autoRunBtn.style.opacity = '0.7';
autoRunBtn.textContent = 'Running...';
try {
// Step 1: Generate search queries
progressStep.textContent = '1/7: Generating search queries...';
progressBar.style.width = '10%';
await new Promise(resolve => {
// Call generate queries function
generateSearchQueries();
// Wait for results to appear
const checkInterval = setInterval(() => {
if (document.querySelector('.accordion-section')) {
clearInterval(checkInterval);
resolve();
}
}, 500);
// Timeout after 30 seconds in case of error
setTimeout(() => {
clearInterval(checkInterval);
resolve();
}, 30000);
});
// Step 2: Perform searches for each query
progressStep.textContent = '2/7: Performing searches for each query...';
progressBar.style.width = '25%';
await new Promise(resolve => {
const queryItems = document.querySelectorAll('.query-item');
let totalQueries = 0;
let completedQueries = 0;
if (queryItems.length === 0) {
resolve();
return;
}
queryItems.forEach((queryItem, index) => {
const queryField = queryItem.querySelector('.query-field');
if (queryField && queryField.value.trim()) {
totalQueries++;
// Slight delay between searches to prevent overloading
setTimeout(() => {
const searchBtn = queryItem.querySelector('.search-button');
if (searchBtn) {
searchBtn.click();
// Wait for search to complete
const checkInterval = setInterval(() => {
const loadingElement = queryItem.querySelector('.search-loading');
if (loadingElement && loadingElement.style.display === 'none') {
clearInterval(checkInterval);
completedQueries++;
if (completedQueries >= totalQueries) {
resolve();
}
}
}, 500);
// Timeout after 30 seconds per query
setTimeout(() => {
clearInterval(checkInterval);
completedQueries++;
if (completedQueries >= totalQueries) {
resolve();
}
}, 30000);
}
}, index * 2000); // Stagger searches by 2 seconds
}
});
// If no valid queries found
if (totalQueries === 0) {
resolve();
}
});
// Step 3: Analyze all retrieved documents
progressStep.textContent = '3/7: Analyzing all retrieved documents...';
progressBar.style.width = '40%';
await new Promise(resolve => {
analyzeAllPapers();
// Wait for analyses to complete
const checkInterval = setInterval(() => {
// Check if the global loading overlay is gone
const loadingOverlay = document.getElementById('globalLoadingOverlay');
if (loadingOverlay && loadingOverlay.style.display === 'none') {
clearInterval(checkInterval);
resolve();
}
}, 500);
// Timeout after 2 minutes
setTimeout(() => {
clearInterval(checkInterval);
resolve();
}, 120000);
});
// Step 4: Remove failed analyses
progressStep.textContent = '4/7: Removing failed analyses...';
progressBar.style.width = '50%';
removeFailedAnalyses();
await new Promise(resolve => setTimeout(resolve, 1000));
// Step 5: Extract insights from all documents
progressStep.textContent = '5/7: Extracting insights from all documents...';
progressBar.style.width = '65%';
await new Promise(resolve => {
extractAllInsights();
// Wait for extractions to complete
const checkInterval = setInterval(() => {
const loadingOverlay = document.getElementById('globalLoadingOverlay');
if (loadingOverlay && loadingOverlay.style.display === 'none') {
clearInterval(checkInterval);
resolve();
}
}, 500);
// Timeout after 3 minutes
setTimeout(() => {
clearInterval(checkInterval);
resolve();
}, 180000);
});
// Step 6: Group insights by score
progressStep.textContent = '6/7: Grouping insights by score...';
progressBar.style.width = '80%';
groupInsightsByScore();
await new Promise(resolve => setTimeout(resolve, 1000));
// Step 7: AI suggest insights
progressStep.textContent = '7/7: Using AI to suggest the best insights...';
progressBar.style.width = '90%';
await new Promise(resolve => {
// Find and click the AI Select Insights button
const aiSelectBtn = document.getElementById('aiSelectButton');
if (aiSelectBtn) {
aiSelectBtn.click();
// Wait for AI selection to complete
const checkInterval = setInterval(() => {
const loadingOverlay = document.getElementById('globalLoadingOverlay');
if (loadingOverlay && loadingOverlay.style.display === 'none') {
clearInterval(checkInterval);
resolve();
}
}, 500);
// Timeout after 1 minute
setTimeout(() => {
clearInterval(checkInterval);
resolve();
}, 60000);
} else {
resolve();
}
});
// Step 8: Enhance problem using selected insights
progressStep.textContent = 'Enhancing problem with selected insights...';
progressBar.style.width = '100%';
enhanceProblem();
// Process complete
setTimeout(() => {
progressStep.textContent = 'All processes completed successfully!';
// Re-enable the auto run button
autoRunBtn.disabled = false;
autoRunBtn.style.opacity = '1';
autoRunBtn.textContent = 'Auto Run All Process';
// Hide progress bar after 5 seconds
setTimeout(() => {
if (!autoRunBtn.disabled) { // Only hide if not running again
progressBarContainer.style.display = 'none';
progressStep.style.display = 'none';
}
}, 5000);
}, 1000);
} catch (error) {
console.error('Error in auto run process:', error);
progressStep.textContent = 'Process interrupted due to an error.';
progressBar.style.width = '100%';
progressBar.style.backgroundColor = '#ef4444';
// Re-enable the auto run button
autoRunBtn.disabled = false;
autoRunBtn.style.opacity = '1';
autoRunBtn.textContent = 'Auto Run All Process';
}
}
</script>
</head>
<body>
<div class="container">
<header class="header">
<div class="logo">
<div class="logo-icon">P</div>
<h1>Patentability</h1>
</div>
<p>Enter a detailed description of your technical problem to generate search queries for finding relevant research papers.</p>
</header>
<section class="card">
<form id="queryForm" onsubmit="generateQueries(event)">
<div class="form-group">
<label for="userInput">Technical Problem Description:</label>
<div class="problem-history">
<div id="problemHistoryNav" class="problem-history-nav" style="display: none;">
<div class="history-arrow history-prev disabled" onclick="navigateProblemHistory('prev')"></div>
<div class="history-arrow history-next disabled" onclick="navigateProblemHistory('next')"></div>
<div class="history-status"></div>
</div>
<textarea id="userInput" placeholder="Describe your technical problem in detail..." required></textarea>
</div>
</div>
<button type="submit" class="btn btn-primary">Generate Key Issues</button>
</form>
<div id="loadingIndicator">
<div class="loading-spinner"></div>
<p>Generating key issues... Please wait.</p>
</div>
<div id="keyIssuesContainer" class="key-issues-container" style="display: none;">
<h3>Key Technical Issues</h3>
<div id="keyIssuesList" class="key-issues-list">
<!-- Key issues will be added here dynamically -->
</div>
</div>
<div id="insightCommentContainer" class="insight-comment-area"></div>
<div id="refinedProblemContainer" class="refined-problem-container" style="display: none;">
<div id="refinedProblemTabs" class="refined-problem-tabs"></div>
<div id="refinedProblemContent" class="refined-problem-content"></div>
</div>
</section>
<section class="search-options">
<label>Search Options:</label>
<div class="checkbox-group">
<div class="checkbox-item">
<input type="checkbox" id="pdfOption" name="searchOptions" value="pdf" checked>
<label for="pdfOption">PDF</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="patentOption" name="searchOptions" value="patent">
<label for="patentOption">Patent</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="webOption" name="searchOptions" value="web">
<label for="webOption">Web</label>
</div>
</div>
</section>
<section id="resultsContainer">
<h2>Generated Search Queries</h2>
<div id="queriesContainer">
<!-- Query fields will be added here dynamically -->
</div>
<div class="button-container">
<button type="button" class="btn btn-secondary" onclick="addQueryField()">
<span>Add New Query</span>
</button>
</div>
</section>
</div>
<!-- Global action buttons (floating) -->
<div class="floating-buttons">
<button id="generateQueriesButton" class="btn floating-button" style="background-color: #8e44ad; color: white;" title="Generate Search Queries">
Generate Search Queries
</button>
<button id="analyzeAllButton" class="btn btn-primary floating-button" title="Analyze All Unanalyzed Papers">
Analyze All
</button>
<button id="removeFailedButton" class="btn btn-danger floating-button" title="Remove Papers with Failed Analyses">
Remove Failed
</button>
<button id="extractAllInsightsButton" class="btn btn-info floating-button disabled" title="Extract Insights for All Analyzed Documents" onclick="extractAllInsights()" disabled>
Extract All Insights
</button>
<button id="groupInsightsByScoreButton" class="btn btn-group-insights floating-button disabled" title="Group All Insights by Score" onclick="groupInsightsByScore()" disabled>
Group Insights
</button>
<button id="enhanceProblemButton" class="btn enhance-problem-button floating-button disabled" title="Enhance Problem using Selected Insights" onclick="enhanceProblem()" disabled>
Enhance Problem
</button>
<button id="exportExcelButton" class="btn btn-success floating-button" title="Export All Data to Excel">
Export to Excel
</button>
</div>
<!-- Global loading overlay -->
<div id="globalLoadingOverlay" class="loading-overlay">
<div class="loading-content">
<div class="loading-spinner"></div>
<div class="progress-text">Processing...</div>
</div>
</div>
<!-- Collapsible ribbon accordion -->
<div class="ribbon-accordion collapsed">
<div class="ribbon-header">
<div class="ribbon-title">
<span class="ribbon-icon">🧰</span>
<span>Patentability Tools</span>
</div>
<div class="ribbon-toggle"></div>
</div>
<div class="ribbon-content">
<button id="autoRunAllButton" class="auto-run-btn">Auto Run All Process</button>
<div class="progress-bar-container">
<div class="progress-bar"></div>
</div>
<div class="progress-step">Waiting to start...</div>
<button id="ribbonGenerateQueriesButton" class="btn floating-button" style="background-color: #8e44ad; color: white;" title="Generate Search Queries">
Generate Search Queries
</button>
<button id="ribbonAnalyzeAllButton" class="btn btn-primary floating-button" title="Analyze All Unanalyzed Papers">
Analyze All
</button>
<button id="ribbonRemoveFailedButton" class="btn btn-danger floating-button" title="Remove Papers with Failed Analyses">
Remove Failed
</button>
<button id="ribbonExtractAllInsightsButton" class="btn btn-info floating-button" title="Extract Insights for All Analyzed Documents">
Extract All Insights
</button>
<button id="ribbonGroupInsightsButton" class="btn btn-group-insights floating-button" title="Group All Insights by Score">
Group Insights
</button>
<button id="ribbonEnhanceProblemButton" class="btn enhance-problem-button floating-button" title="Enhance Problem using Selected Insights">
Enhance Problem
</button>
<button id="ribbonExportExcelButton" class="btn btn-success floating-button" title="Export All Data to Excel">
Export to Excel
</button>
</div>
</div>
<script>
// Add event listeners for floating buttons
document.addEventListener('DOMContentLoaded', function() {
// Initialize the comment area
initializeCommentArea();
// Check for selected insights periodically to enable/disable enhance button
setInterval(checkSelectedInsights, 1000);
// Check for analyzed documents to enable/disable Extract All Insights button
setInterval(checkAnalyzedDocuments, 1000);
// Check for insights to enable/disable Group Insights by Score button
setInterval(checkGroupInsightsButton, 1000);
// Check if search has been performed and update button states
setInterval(checkSearchPerformed, 1000);
// Analyze all button
document.getElementById('analyzeAllButton').addEventListener('click', function() {
if(hasSearchResults()) {
analyzeAllPapers();
}
});
// Remove failed button
document.getElementById('removeFailedButton').addEventListener('click', function() {
if(hasSearchResults()) {
removeFailedAnalyses();
}
});
// Export to Excel button
document.getElementById('exportExcelButton').addEventListener('click', function() {
if(hasSearchResults()) {
exportToExcel();
}
});
// Generate Search Queries floating button
document.getElementById('generateQueriesButton').addEventListener('click', function() {
// Call the search queries generation function
generateSearchQueries();
});
});
// Function to check if any search has been performed
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 to check if search has been performed and update all button states
function checkSearchPerformed() {
const searchPerformed = hasSearchResults();
// Get all floating buttons
const analyzeAllButton = document.getElementById('analyzeAllButton');
const removeFailedButton = document.getElementById('removeFailedButton');
const extractAllInsightsButton = document.getElementById('extractAllInsightsButton');
const groupInsightsButton = document.getElementById('groupInsightsByScoreButton');
const enhanceProblemButton = document.getElementById('enhanceProblemButton');
const exportExcelButton = document.getElementById('exportExcelButton');
// Set disabled state for buttons that should be disabled when no search is performed
if (!searchPerformed) {
analyzeAllButton.classList.add('disabled');
analyzeAllButton.disabled = true;
removeFailedButton.classList.add('disabled');
removeFailedButton.disabled = true;
exportExcelButton.classList.add('disabled');
exportExcelButton.disabled = true;
// The other buttons (extract, group, enhance) should already be disabled by their respective check functions
} else {
analyzeAllButton.classList.remove('disabled');
analyzeAllButton.disabled = false;
removeFailedButton.classList.remove('disabled');
removeFailedButton.disabled = false;
exportExcelButton.classList.remove('disabled');
exportExcelButton.disabled = false;
// The other buttons will be enabled/disabled by their respective check functions
}
}
</script>
</body>
</html>