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