// 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'); // Add to selected key issues if not already there if (!selectedKeyIssues.some(item => item.id === issue.id)) { selectedKeyIssues.push(issue); } } else { issueCard.classList.remove('selected'); // Remove from selected key issues selectedKeyIssues = selectedKeyIssues.filter(item => item.id !== issue.id); } // Update the comment area based on selections updateCommentArea(); }); 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; // No direct click handler on issue cards - they only get selected through challenge selection // Initialize the dataset.selectedChallenges array issueCard.dataset.selectedChallenges = JSON.stringify([]); // 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); // Create API submit button (floating style) const apiSubmitButton = document.createElement('button'); apiSubmitButton.id = 'generatePriorArtButton'; apiSubmitButton.className = 'btn btn-primary floating-button'; apiSubmitButton.textContent = 'Generate Prior Art'; apiSubmitButton.style.backgroundColor = '#10b981'; // Green color to differentiate apiSubmitButton.style.color = 'white'; apiSubmitButton.addEventListener('click', submitSelectedKeyIssuesToAPI); // Add to floating buttons container document.querySelector('.floating-buttons').appendChild(apiSubmitButton); // Show the results container document.getElementById('resultsContainer').style.display = 'block'; } // Function to submit selected key issues to the API function submitSelectedKeyIssuesToAPI() { const userInput = document.getElementById('userInput').value.trim(); if (!userInput) { alert('Please provide a technical problem description'); return; } // Find all key issue cards with selected challenges const issueCards = document.querySelectorAll('.key-issue-card'); const keyIssuesData = []; issueCards.forEach(card => { const selectedChallenges = JSON.parse(card.dataset.selectedChallenges || '[]'); // Only include issues with at least one selected challenge if (selectedChallenges.length > 0) { const issueDescription = card.querySelector('.key-issue-description').textContent; keyIssuesData.push({ "description": issueDescription, "challenges": selectedChallenges }); } }); // If no key issues with selected challenges, show message if (keyIssuesData.length === 0) { alert('Please select at least one challenge in a key issue'); return; } // Create or update API response container with loading message - using refined problem container style let apiResponseContainer = document.getElementById('apiResponseContainer'); if (!apiResponseContainer) { apiResponseContainer = document.createElement('div'); apiResponseContainer.id = 'apiResponseContainer'; apiResponseContainer.className = 'refined-problem-container'; document.getElementById('resultsContainer').appendChild(apiResponseContainer); } // Set loading message apiResponseContainer.innerHTML = `
Processing

Generating prior art based on selected key issues and challenges. This may take a moment...

`; // Show the container and scroll to it apiResponseContainer.style.display = 'block'; apiResponseContainer.scrollIntoView({ behavior: 'smooth' }); // Prepare the payload const payload = { "keys_issues": keyIssuesData, "technical_topic": userInput }; console.log('Sending data to API:', JSON.stringify(payload, null, 2)); // Send data to API fetch('/generate-prior-art', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(payload) }) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { console.log('API Response:', data); // For testing, we can use a mock response based on the example format // Remove this in production if (!data || (Array.isArray(data) && data.length === 0)) { console.log('Using mock data for testing'); data = [ { "problem_description": "I am working on managing conflicting instructions for network behavior in 5G systems. The core problem is how to ensure that requests coming dynamically from applications serving critical functions are reliably given higher priority and override the static network settings stored in a user's plan. This requires a solution that addresses the security risks associated with allowing applications to dictate network treatment and ensures this rule is enforced uniformly across the central network components.", "problematic": "How can 5G core network functions securely and reliably enforce dynamic network treatment instructions from critical function applications, ensuring they consistently override conflicting static policy configurations derived from user plans, while uniformly mitigating the security risks associated with application-level control over network behavior?", "score": 0.845 }, { "problem_description": "I am working on enhancing security in 5G networks, specifically related to how network segments are configured based on user profiles. My goal is to address the security risks that arise when requests from external applications conflict with the priority settings defined in a user's profile for essential services, ensuring that unauthorized changes to service priority are securely prevented and handled throughout the core network.", "problematic": "How can security risks arising from external application requests conflicting with user profile-defined priority settings for essential services in 5G networks be securely mitigated, ensuring that unauthorized modifications to service priority are effectively prevented and managed throughout the core network segments configured based on these profiles?", "score": 0.624 }, { "problem_description": "I am working on managing conflicting instructions for network behavior in 5G systems. The core problem is how to ensure that requests coming dynamically from applications serving critical functions are reliably given higher priority and override the static network settings stored in a user's plan. This requires a solution that addresses the security risks associated with allowing applications to dictate network treatment and ensures this rule is enforced uniformly across the central network components.", "problematic": "How can 5G core network functions securely and reliably enforce dynamic network treatment instructions from critical function applications, ensuring they consistently override conflicting static policy configurations derived from user plans, while uniformly mitigating the security risks associated with application-level control over network behavior?", "score": 0.312 }, { "problem_description": "I am working on enhancing security in 5G networks, specifically related to how network segments are configured based on user profiles. My goal is to address the security risks that arise when requests from external applications conflict with the priority settings defined in a user's profile for essential services, ensuring that unauthorized changes to service priority are securely prevented and handled throughout the core network.", "problematic": "How can security risks arising from external application requests conflicting with user profile-defined priority settings for essential services in 5G networks be securely mitigated, ensuring that unauthorized modifications to service priority are effectively prevented and managed throughout the core network segments configured based on these profiles?", "score": 0.305 } ]; } // Display the API response displayAPIResponse(data); }) .catch(error => { console.error('Error submitting to API:', error); // Display error message in the API response container apiResponseContainer.innerHTML = `
Error
Error Generating Prior Art

There was an error communicating with the API: ${error.message}

Please try again later or contact support.

`; }); } // Function to display the API response in a tabbed format function displayAPIResponse(data) { // Get or create container for API response let apiResponseContainer = document.getElementById('apiResponseContainer'); if (!apiResponseContainer) { apiResponseContainer = document.createElement('div'); apiResponseContainer.id = 'apiResponseContainer'; apiResponseContainer.className = 'refined-problem-container'; // Use the same style as refined problems document.getElementById('resultsContainer').appendChild(apiResponseContainer); } // Clear previous content apiResponseContainer.innerHTML = ''; // Create tabs and content containers similar to refined problems const tabs = document.createElement('div'); tabs.className = 'refined-problem-tabs'; apiResponseContainer.appendChild(tabs); const content = document.createElement('div'); content.className = 'refined-problem-content'; apiResponseContainer.appendChild(content); try { // Parse the data if it's a string const problems = Array.isArray(data) ? data : (typeof data === 'string' ? JSON.parse(data) : (data.result || data.results || [])); // Sort problems by score in descending order problems.sort((a, b) => (b.score || 0) - (a.score || 0)); // Add tabs and content for each problem problems.forEach((problem, index) => { const key = `problem_${index + 1}`; const isFirst = index === 0; // Create tab const tab = document.createElement('div'); tab.className = `refined-problem-tab ${isFirst ? 'active' : ''}`; tab.dataset.target = key; // Format score as percentage const score = typeof problem.score === 'number' ? Math.round(problem.score * 100) : 'N/A'; tab.textContent = `Option ${index + 1} (${score}%)`; 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; // Problem title (using problematic as title) const title = document.createElement('div'); title.className = 'refined-problem-title'; title.textContent = problem.problematic || 'Alternative Problem Statement'; // Problem description const description = document.createElement('div'); description.className = 'refined-problem-description'; description.textContent = problem.problem_description || problem.description || ''; // Apply button const applyButton = document.createElement('button'); applyButton.className = 'apply-problem-btn'; applyButton.textContent = 'Apply This Problem'; applyButton.onclick = function() { // Use the existing applyRefinedProblem function applyRefinedProblem(problem.problem_description || problem.description || ''); }; // Add all elements to the problem div problemDiv.appendChild(title); problemDiv.appendChild(description); problemDiv.appendChild(applyButton); content.appendChild(problemDiv); }); // If no problems found, display a message if (problems.length === 0) { const noResultsDiv = document.createElement('div'); noResultsDiv.className = 'refined-problem active'; noResultsDiv.textContent = 'No problem alternatives were generated. Please try again.'; content.appendChild(noResultsDiv); } } catch (error) { console.error('Error displaying API response:', error); // Display error message const errorDiv = document.createElement('div'); errorDiv.className = 'refined-problem active'; errorDiv.innerHTML = `
Error
There was an error processing the API response: ${error.message}
`; content.appendChild(errorDiv); } // Show the container apiResponseContainer.style.display = 'block'; // Scroll to the container apiResponseContainer.scrollIntoView({ behavior: 'smooth' }); } // 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 = '
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}
`; }); } // 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 }); // Switch to Patentability Tools tab first switchToPatentabilityTab(); 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 = ''; // Collect problem descriptions for evaluation const problemDescriptions = []; for (const key in result) { if (result.hasOwnProperty(key)) { problemDescriptions.push(result[key].description); } } // 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.dataset.problemIndex = problemDescriptions.indexOf(problem.description); // Create tab content with placeholder for score const tabTextSpan = document.createElement('span'); tabTextSpan.textContent = `Option ${key.split('_')[2]}`; // Create score element that will be updated later const tabScoreSpan = document.createElement('span'); tabScoreSpan.className = 'tab-score-indicator'; tabScoreSpan.innerHTML = `
`; tab.appendChild(tabTextSpan); tab.appendChild(tabScoreSpan); 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 markdown-content'; // Use Marked.js to render Markdown try { // Configure marked options for security marked.setOptions({ sanitize: false, // HTML is allowed but sanitized breaks: true, // Interpret line breaks as
gfm: true, // Use GitHub Flavored Markdown headerIds: true, // Add IDs to headers for linking }); // Render the markdown description.innerHTML = marked.parse(problem.description); } catch (e) { console.error('Error parsing markdown:', e); description.textContent = problem.description; // Fallback to plain text } // Create score display with loading spinner initially const scoreContainer = document.createElement('div'); scoreContainer.className = 'problem-score-container'; scoreContainer.innerHTML = `
Evaluating specificity...
`; scoreContainer.dataset.problemIndex = problemDescriptions.indexOf(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(scoreContainer); problemDiv.appendChild(applyButton); content.appendChild(problemDiv); isFirst = false; } } // Show the container refinedContainer.style.display = 'block'; // Scroll to the container refinedContainer.scrollIntoView({ behavior: 'smooth' }); // If we have problem descriptions, evaluate them if (problemDescriptions.length > 0) { // Call the API to evaluate problem descriptions fetch('/evaluate-problem-descriptions', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ 'problem_descriptions': problemDescriptions }) }) .then(response => response.json()) .then(data => { console.log('Problem evaluation results:', data); // Update the UI with evaluation scores if (Array.isArray(data)) { data.forEach((evaluation, index) => { const scoreContainers = document.querySelectorAll(`.problem-score-container[data-problem-index="${index}"]`); scoreContainers.forEach(container => { const loadingEl = container.querySelector('.problem-score-loading'); const scoreEl = container.querySelector('.problem-score'); if (loadingEl && scoreEl && evaluation.score !== undefined) { // Hide loading spinner loadingEl.style.display = 'none'; // Format the score as a percentage const scoreValue = (evaluation.score * 100).toFixed(1); // Determine color based on score let scoreColor = '#ff4d4d'; // Red for low scores if (evaluation.score >= 0.7) { scoreColor = '#4caf50'; // Green for high scores } else if (evaluation.score >= 0.5) { scoreColor = '#ff9800'; // Orange for medium scores } // Show score with appropriate styling scoreEl.innerHTML = `Specificity Score: ${scoreValue}%`; scoreEl.style.display = 'block'; // Also update the score in the tab const tabWithSameIndex = document.querySelector(`.refined-problem-tab[data-problem-index="${index}"]`); if (tabWithSameIndex) { const tabScoreSpan = tabWithSameIndex.querySelector('.tab-score-indicator'); if (tabScoreSpan) { tabScoreSpan.innerHTML = `${scoreValue}%`; } } } }); }); } else if (data.error) { console.error('Error evaluating problems:', data.error); // Update UI to show error state document.querySelectorAll('.problem-score-loading').forEach(el => { el.innerHTML = 'Evaluation failed'; }); } }) .catch(error => { console.error('Error:', error); // Update UI to show error state document.querySelectorAll('.problem-score-loading').forEach(el => { el.innerHTML = 'Evaluation failed'; }); }); } } // 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 = '
'; 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'; }); } // 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 = '
'; 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(); } } }); }); } // 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 = ` 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; } // 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 = '
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); } // 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 = `
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})
`; // 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); } // 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.'); }); } 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; // Build the complete HTML structure let cardContent = `
${issue.title}
${issue.description}
Challenges:
Impact: ${issue.potential_impact}
`; issueCard.innerHTML = cardContent; // Get the challenges list container that was just created const challengesList = issueCard.querySelector('.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'); // Add to selected key issues if not already there if (!selectedKeyIssues.some(item => item.id === issue.id)) { selectedKeyIssues.push(issue); } } else { issueCard.classList.remove('selected'); // Remove from selected key issues selectedKeyIssues = selectedKeyIssues.filter(item => item.id !== issue.id); } // Update the comment area based on selections updateCommentArea(); }); challengesList.appendChild(challengeTag); }); // The challenges list and impact are already in the HTML structure // We just need to populate the challenges list with individual challenge tags // 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 = `

Selected Key Issues

`; insightCommentContainer.innerHTML = commentHTML; } else { insightCommentContainer.innerHTML = ''; } } }); // 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(); } }); // Generate Prior Art button (if exists) const ribbonGeneratePriorArtButton = document.getElementById('ribbonGeneratePriorArtButton'); if (ribbonGeneratePriorArtButton) { ribbonGeneratePriorArtButton.addEventListener('click', function() { submitSelectedKeyIssuesToAPI(); }); } } // 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'; } }