|
|
|
let requirements = []; |
|
let accordionStates = {}; |
|
let formattedRequirements = []; |
|
let categorizedRequirements = []; |
|
let solutionsCriticizedVersions = []; |
|
let isRequirements = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function toggleElementsEnabled(elementIds, enabled = true) { |
|
elementIds.forEach(id => { |
|
const element = document.getElementById(id); |
|
if (element) { |
|
if (enabled) { |
|
element.removeAttribute('disabled'); |
|
} else { |
|
element.setAttribute('disabled', 'true'); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function toggleContainersVisibility(containerIds, visible = true) { |
|
containerIds.forEach(id => { |
|
const container = document.getElementById(id); |
|
if (container) { |
|
if (visible) { |
|
container.classList.remove('hidden'); |
|
} else { |
|
container.classList.add('hidden'); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function showLoadingOverlay(message = 'Chargement en cours...') { |
|
document.getElementById('progress-text').textContent = message; |
|
toggleContainersVisibility(['loading-overlay'], true); |
|
} |
|
|
|
|
|
|
|
|
|
function hideLoadingOverlay() { |
|
toggleContainersVisibility(['loading-overlay'], false); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function populateSelect(selectId, options, defaultText = 'Sélectionner...') { |
|
const select = document.getElementById(selectId); |
|
if (select) { |
|
select.innerHTML = `<option value="">${defaultText}</option>`; |
|
Object.entries(options).forEach(([text, value]) => { |
|
const option = document.createElement('option'); |
|
option.value = value; |
|
option.textContent = text; |
|
select.appendChild(option); |
|
}); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function extractTableData(mapping) { |
|
const tbody = document.querySelector('#data-table tbody'); |
|
const rows = tbody.querySelectorAll('tr'); |
|
const data = []; |
|
|
|
rows.forEach(row => { |
|
const checkboxes = row.querySelectorAll('input[type="checkbox"]:checked'); |
|
if (checkboxes.length > 0) { |
|
const rowData = {}; |
|
Object.entries(mapping).forEach(([columnName, propertyName]) => { |
|
const cell = row.querySelector(`td[data-column="${columnName}"]`); |
|
if (cell) { |
|
if(columnName == "URL") { |
|
rowData[propertyName] = cell.querySelector('a').getAttribute('href'); |
|
} else { |
|
rowData[propertyName] = cell.textContent.trim(); |
|
} |
|
} |
|
}); |
|
data.push(rowData); |
|
} |
|
}); |
|
|
|
return data; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function getMeetings() { |
|
const workingGroup = document.getElementById('working-group-select').value; |
|
if (!workingGroup) return; |
|
|
|
showLoadingOverlay('Récupération des meetings...'); |
|
toggleElementsEnabled(['get-meetings-btn'], false); |
|
|
|
try { |
|
const response = await fetch('/get_meetings', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify({ working_group: workingGroup }) |
|
}); |
|
|
|
const data = await response.json(); |
|
populateSelect('meeting-select', data.meetings, 'Select a meeting'); |
|
toggleContainersVisibility(['meeting-container'], true); |
|
} catch (error) { |
|
console.error('Erreur lors de la récupération des meetings:', error); |
|
alert('Erreur lors de la récupération des meetings'); |
|
} finally { |
|
hideLoadingOverlay(); |
|
toggleElementsEnabled(['get-meetings-btn'], true); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
async function getTDocs() { |
|
const workingGroup = document.getElementById('working-group-select').value; |
|
const meeting = document.getElementById('meeting-select').value; |
|
|
|
if (!workingGroup || !meeting) return; |
|
|
|
showLoadingOverlay('Récupération de la liste des TDocs...'); |
|
toggleElementsEnabled(['get-tdocs-btn'], false); |
|
|
|
try { |
|
const response = await fetch('/get_dataframe', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify({ working_group: workingGroup, meeting: meeting }) |
|
}); |
|
|
|
const data = await response.json(); |
|
populateDataTable(data.data); |
|
setupFilters(data.data); |
|
|
|
toggleContainersVisibility([ |
|
'filters-container', |
|
'action-buttons-container', |
|
'data-table-container' |
|
], true); |
|
|
|
isRequirements = false; |
|
} catch (error) { |
|
console.error('Erreur lors de la récupération des TDocs:', error); |
|
alert('Erreur lors de la récupération des TDocs'); |
|
} finally { |
|
hideLoadingOverlay(); |
|
toggleElementsEnabled(['get-tdocs-btn'], true); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function populateDataTable(data) { |
|
const tbody = document.querySelector('#data-table tbody'); |
|
tbody.innerHTML = ''; |
|
|
|
data.forEach(row => { |
|
const tr = document.createElement('tr'); |
|
tr.setAttribute('data-type', row.Type || ''); |
|
tr.setAttribute('data-status', row['TDoc Status'] || ''); |
|
tr.setAttribute('data-agenda', row['Agenda item description'] || ''); |
|
|
|
tr.innerHTML = ` |
|
<td class="px-4 py-2"> |
|
<input type="checkbox" class="row-checkbox"> |
|
</td> |
|
<td class="px-4 py-2" data-column="TDoc">${row.TDoc || ''}</td> |
|
<td class="px-4 py-2" data-column="Title">${row.Title || ''}</td> |
|
<td class="px-4 py-2" data-column="Type">${row.Type || ''}</td> |
|
<td class="px-4 py-2" data-column="Status">${row['TDoc Status'] || ''}</td> |
|
<td class="px-4 py-2" data-column="Agenda">${row['Agenda item description'] || ''}</td> |
|
<td class="px-4 py-2" data-column="URL"> |
|
<a href="${row.URL || '#'}" target="_blank" class="text-blue-500 hover:underline"> |
|
${row.URL ? 'Lien' : 'N/A'} |
|
</a> |
|
</td> |
|
`; |
|
|
|
tbody.appendChild(tr); |
|
}); |
|
|
|
setupTableEvents(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function setupFilters(data) { |
|
const types = [...new Set(data.map(item => item.Type).filter(Boolean))]; |
|
const statuses = [...new Set(data.map(item => item['TDoc Status']).filter(Boolean))]; |
|
const agendaItems = [...new Set(data.map(item => item['Agenda item description']).filter(Boolean))]; |
|
|
|
populateSelect('doc-type-filter', Object.fromEntries(types.map(t => [t, t])), 'Tous'); |
|
populateSelect('doc-status-filter', Object.fromEntries(statuses.map(s => [s, s])), 'Tous'); |
|
populateSelect('agenda-item-filter', Object.fromEntries(agendaItems.map(a => [a, a])), 'Tous'); |
|
|
|
setupFilterEvents(); |
|
} |
|
|
|
|
|
|
|
|
|
function setupFilterEvents() { |
|
['doc-type-filter', 'doc-status-filter', 'agenda-item-filter'].forEach(filterId => { |
|
document.getElementById(filterId).addEventListener('change', applyFilters); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
function applyFilters() { |
|
const typeFilter = document.getElementById('doc-type-filter').value; |
|
const statusFilter = document.getElementById('doc-status-filter').value; |
|
const agendaFilter = document.getElementById('agenda-item-filter').value; |
|
|
|
const rows = document.querySelectorAll('#data-table tbody tr'); |
|
|
|
rows.forEach(row => { |
|
const type = row.getAttribute('data-type'); |
|
const status = row.getAttribute('data-status'); |
|
const agenda = row.getAttribute('data-agenda'); |
|
|
|
const typeMatch = !typeFilter || type === typeFilter; |
|
const statusMatch = !statusFilter || status === statusFilter; |
|
const agendaMatch = !agendaFilter || agenda === agendaFilter; |
|
|
|
if (typeMatch && statusMatch && agendaMatch) { |
|
row.style.display = ''; |
|
} else { |
|
row.style.display = 'none'; |
|
} |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
function setupTableEvents() { |
|
|
|
document.getElementById('select-all-checkbox').addEventListener('change', function() { |
|
const checkboxes = document.querySelectorAll('.row-checkbox'); |
|
checkboxes.forEach(checkbox => { |
|
if(checkbox.parentElement.parentElement.style.display != "none"){checkbox.checked = this.checked;} |
|
}); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
async function downloadTDocs() { |
|
showLoadingOverlay('Téléchargement des TDocs en cours...'); |
|
toggleElementsEnabled(['download-tdocs-btn', 'extract-requirements-btn'], false); |
|
|
|
try { |
|
|
|
const selectedData = extractTableData({ 'TDoc': 'document', 'URL': 'url' }); |
|
if (selectedData.length === 0) { |
|
alert('Veuillez sélectionner au moins un document'); |
|
return; |
|
} |
|
|
|
|
|
const documents = selectedData.map(obj => obj.document) |
|
|
|
const response = await fetch('/download_tdocs', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify({ documents: documents }) |
|
}); |
|
|
|
const blob = await response.blob(); |
|
downloadBlob(blob, generateDownloadFilename()); |
|
} catch (error) { |
|
console.error('Erreur lors du téléchargement:', error); |
|
alert('Erreur lors du téléchargement des TDocs'); |
|
} finally { |
|
hideLoadingOverlay(); |
|
toggleElementsEnabled(['download-tdocs-btn', 'extract-requirements-btn'], true); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function generateDownloadFilename() { |
|
let filename = document.getElementById('meeting-select').value || 'documents'; |
|
|
|
const agendaItem = document.getElementById('agenda-item-filter').value; |
|
const docStatus = document.getElementById('doc-status-filter').value; |
|
const docType = document.getElementById('doc-type-filter').value; |
|
|
|
if (agendaItem && agendaItem !== 'Tous') { |
|
filename += `_${agendaItem}`; |
|
} |
|
if (docStatus && docStatus !== 'Tous') { |
|
filename += `_${docStatus}`; |
|
} |
|
if (docType && docType !== 'Tous') { |
|
filename = `${docType}_${filename}`; |
|
} |
|
if (isRequirements) { |
|
filename = `requirements_${filename}`; |
|
} |
|
|
|
return `${filename}.zip`; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function downloadBlob(blob, filename) { |
|
const url = window.URL.createObjectURL(blob); |
|
const a = document.createElement('a'); |
|
a.href = url; |
|
a.download = filename; |
|
document.body.appendChild(a); |
|
a.click(); |
|
a.remove(); |
|
window.URL.revokeObjectURL(url); |
|
} |
|
|
|
|
|
|
|
|
|
async function extractRequirements() { |
|
const selectedData = extractTableData({ 'TDoc': 'document', 'URL': 'url' }); |
|
if (selectedData.length === 0) { |
|
alert('Veuillez sélectionner au moins un document'); |
|
return; |
|
} |
|
|
|
showLoadingOverlay('Extraction des requirements en cours...'); |
|
toggleElementsEnabled(['extract-requirements-btn'], false); |
|
|
|
try { |
|
const response = await fetch('/generate_requirements', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify({ documents: selectedData }) |
|
}); |
|
|
|
const data = await response.json(); |
|
requirements = data.requirements; |
|
let req_id = 0; |
|
data.requirements.forEach(obj => { |
|
obj.requirements.forEach(req => { |
|
formattedRequirements.push({ |
|
req_id, |
|
"document": obj.document, |
|
"context": obj.context, |
|
"requirement": req |
|
}) |
|
req_id++; |
|
}) |
|
}) |
|
displayRequirements(requirements); |
|
|
|
toggleContainersVisibility(['requirements-container', 'query-requirements-container'], true); |
|
toggleContainersVisibility(['find-requirements-btn', 'categorize-requirements-btn', 'get-solutions-btn', 'get-solutions-step-btn'], true); |
|
|
|
isRequirements = true; |
|
} catch (error) { |
|
console.error('Erreur lors de l\'extraction des requirements:', error); |
|
alert('Erreur lors de l\'extraction des requirements'); |
|
} finally { |
|
hideLoadingOverlay(); |
|
toggleElementsEnabled(['extract-requirements-btn'], true); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function displayRequirements(requirementsData) { |
|
const container = document.getElementById('requirements-list'); |
|
container.innerHTML = ''; |
|
|
|
requirementsData.forEach((docReq, docIndex) => { |
|
const docDiv = document.createElement('div'); |
|
docDiv.className = 'mb-6 p-4 border border-gray-200 rounded-lg bg-white'; |
|
|
|
docDiv.innerHTML = ` |
|
<h3 class="text-lg font-semibold mb-2">${docReq.document}</h3> |
|
<p class="text-gray-600 mb-3">${docReq.context}</p> |
|
<ul class="list-disc list-inside space-y-1"> |
|
${docReq.requirements.map((req, reqIndex) => |
|
`<li class="text-sm" data-req-id="${docIndex}-${reqIndex}">${req}</li>` |
|
).join('')} |
|
</ul> |
|
`; |
|
|
|
container.appendChild(docDiv); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
async function categorizeRequirements(max_categories) { |
|
if (!formattedRequirements || formattedRequirements.length === 0) { |
|
alert('Aucun requirement à catégoriser'); |
|
return; |
|
} |
|
|
|
showLoadingOverlay('Catégorisation des requirements en cours...'); |
|
toggleElementsEnabled(['categorize-requirements-btn'], false); |
|
|
|
try { |
|
const response = await fetch('https://organizedprogrammers-reqxtract-api.hf.space/reqs/categorize_requirements', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify({ requirements: formattedRequirements, "max_n_categories": max_categories }) |
|
}); |
|
|
|
const data = await response.json(); |
|
categorizedRequirements = data; |
|
displayCategorizedRequirements(categorizedRequirements.categories); |
|
|
|
|
|
toggleContainersVisibility(['query-requirements-container'], false); |
|
toggleContainersVisibility(['categorized-requirements-container', 'solutions-action-buttons-container'], true); |
|
|
|
} catch (error) { |
|
console.error('Erreur lors de la catégorisation des requirements:', error); |
|
alert('Erreur lors de la catégorisation des requirements'); |
|
} finally { |
|
hideLoadingOverlay(); |
|
toggleElementsEnabled(['categorize-requirements-btn'], true); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function displayCategorizedRequirements(categorizedData) { |
|
const container = document.getElementById('categorized-requirements-list'); |
|
container.innerHTML = ''; |
|
|
|
categorizedData.forEach((category, categoryIndex) => { |
|
const categoryDiv = document.createElement('div'); |
|
categoryDiv.className = 'mb-6 p-4 border border-gray-200 rounded-lg bg-white'; |
|
|
|
categoryDiv.innerHTML = ` |
|
<h3 class="text-lg font-semibold mb-2 text-blue-600">${category.title}</h3> |
|
<div class="space-y-2"> |
|
${category.requirements.map((req, reqIndex) => |
|
`<div class="p-2 bg-gray-50 rounded border-l-4 border-blue-400" data-cat-req-id="${categoryIndex}-${reqIndex}"> |
|
<div class="text-sm font-medium text-gray-700">${req.document}</div> |
|
<div class="text-sm text-gray-600">${req.requirement}</div> |
|
</div>` |
|
).join('')} |
|
</div> |
|
`; |
|
|
|
container.appendChild(categoryDiv); |
|
}); |
|
} |
|
|
|
async function searchRequirements() { |
|
const query = document.getElementById('query-input').value.trim(); |
|
if (!query) { |
|
alert('Veuillez entrer une requête de recherche'); |
|
return; |
|
} |
|
|
|
if (!formattedRequirements || formattedRequirements.length === 0) { |
|
alert('Aucun requirement disponible pour la recherche'); |
|
return; |
|
} |
|
|
|
showLoadingOverlay('Recherche en cours...'); |
|
toggleElementsEnabled(['search-requirements-btn'], false); |
|
|
|
try { |
|
|
|
const response = await fetch('/get_reqs_from_query', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify({ |
|
query: query, |
|
requirements: formattedRequirements |
|
}) |
|
}); |
|
|
|
const data = await response.json(); |
|
displaySearchResults(data.requirements); |
|
|
|
} catch (error) { |
|
console.error('Erreur lors de la recherche:', error); |
|
alert('Erreur lors de la recherche des requirements'); |
|
} finally { |
|
hideLoadingOverlay(); |
|
toggleElementsEnabled(['search-requirements-btn'], true); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
function displaySearchResults(results) { |
|
const container = document.getElementById('query-results'); |
|
container.innerHTML = ''; |
|
|
|
if (results.length === 0) { |
|
container.innerHTML = '<p class="text-gray-500">Aucun résultat trouvé pour cette requête.</p>'; |
|
return; |
|
} |
|
|
|
const resultsDiv = document.createElement('div'); |
|
resultsDiv.className = 'space-y-3'; |
|
|
|
results.forEach((result, index) => { |
|
const resultDiv = document.createElement('div'); |
|
resultDiv.className = 'p-3 bg-blue-50 border border-blue-200 rounded-lg'; |
|
|
|
resultDiv.innerHTML = ` |
|
<div class="text-sm font-medium text-blue-800">${result.document}</div> |
|
<div class="text-sm text-gray-600 mb-1">${result.context}</div> |
|
<div class="text-sm">${result.requirement}</div> |
|
`; |
|
|
|
resultsDiv.appendChild(resultDiv); |
|
}); |
|
|
|
container.appendChild(resultsDiv); |
|
} |
|
|
|
function createSolutionAccordion(solutionCriticizedHistory, containerId, versionIndex = 0, categoryIndex = null) { |
|
const container = document.getElementById(containerId); |
|
if (!container) { |
|
console.error(`Container with ID "${containerId}" not found`); |
|
return; |
|
} |
|
|
|
|
|
if (categoryIndex !== null) { |
|
updateSingleAccordion(solutionCriticizedHistory, containerId, versionIndex, categoryIndex); |
|
return; |
|
} |
|
|
|
|
|
container.innerHTML = ''; |
|
|
|
|
|
const currentVersionData = solutionCriticizedHistory[versionIndex]; |
|
|
|
|
|
const accordion = document.createElement('div'); |
|
accordion.className = 'space-y-2'; |
|
accordion.id = 'main-accordion'; |
|
|
|
|
|
currentVersionData.critiques.forEach((item, index) => { |
|
createSingleAccordionItem(item, index, versionIndex, solutionCriticizedHistory, accordion); |
|
}); |
|
|
|
|
|
container.appendChild(accordion); |
|
} |
|
|
|
function createSingleAccordionItem(item, index, versionIndex, solutionCriticizedHistory, accordion) { |
|
const solution = item.solution; |
|
const criticism = item.criticism; |
|
|
|
|
|
const categoryTitle = document.querySelector(`#category-${solution['Category_Id']} h2`)?.textContent || `Catégorie ${solution['Category_Id'] + 1}`; |
|
|
|
|
|
const solutionCard = document.createElement('div'); |
|
solutionCard.className = 'border border-gray-200 rounded-md shadow-sm'; |
|
solutionCard.id = `accordion-item-${index}`; |
|
|
|
|
|
const header = document.createElement('div'); |
|
header.className = 'bg-gray-50 px-4 py-2 cursor-pointer hover:bg-gray-100 transition-colors duration-200'; |
|
|
|
const currentVersion = versionIndex + 1; |
|
const totalVersions = solutionCriticizedHistory.length; |
|
|
|
header.innerHTML = ` |
|
<div class="flex justify-between items-center"> |
|
<div class="flex items-center space-x-3"> |
|
<h3 class="text-sm font-semibold text-gray-800">${categoryTitle}</h3> |
|
<div class="flex items-center space-x-2 bg-white px-3 py-1 rounded-full border"> |
|
<button class="version-btn-left w-6 h-6 flex items-center justify-center rounded-full hover:bg-gray-100 transition-colors ${currentVersion === 1 ? 'opacity-50 cursor-not-allowed' : ''}" |
|
data-solution-index="${solution['Category_Id']}" |
|
${currentVersion === 1 ? 'disabled' : ''}> |
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path> |
|
</svg> |
|
</button> |
|
<span class="text-xs font-medium text-gray-600 min-w-[60px] text-center version-indicator">Version ${currentVersion}</span> |
|
<button class="version-btn-right w-6 h-6 flex items-center justify-center rounded-full hover:bg-gray-100 transition-colors ${currentVersion === totalVersions ? 'opacity-50 cursor-not-allowed' : ''}" |
|
data-solution-index="${solution['Category_Id']}" |
|
${currentVersion === totalVersions ? 'disabled' : ''}> |
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path> |
|
</svg> |
|
</button> |
|
</div> |
|
</div> |
|
<svg class="w-4 h-4 transform transition-transform duration-200 accordion-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path> |
|
</svg> |
|
</div> |
|
`; |
|
|
|
|
|
const content = document.createElement('div'); |
|
content.className = `accordion-content px-4 py-3 space-y-3`; |
|
content.id = `content-${solution['Category_Id']}`; |
|
|
|
|
|
const isOpen = accordionStates[solution['Category_Id']] || false; |
|
if (!isOpen) { |
|
content.classList.add('hidden'); |
|
} else { |
|
header.querySelector('.accordion-icon').style.transform = 'rotate(180deg)'; |
|
} |
|
|
|
|
|
const problemSection = document.createElement('div'); |
|
problemSection.className = 'bg-red-50 border-l-2 border-red-400 p-3 rounded-r-md'; |
|
problemSection.innerHTML = ` |
|
<h4 class="text-sm font-semibold text-red-800 mb-2 flex items-center"> |
|
<svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 20 20"> |
|
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"></path> |
|
</svg> |
|
Problem Description |
|
</h4> |
|
<p class="text-xs text-gray-700 leading-relaxed">${solution['Problem Description'] || 'Aucune description du problème disponible.'}</p> |
|
`; |
|
|
|
|
|
const solutionSection = document.createElement('div'); |
|
solutionSection.className = 'bg-green-50 border-l-2 border-green-400 p-3 rounded-r-md'; |
|
solutionSection.innerHTML = ` |
|
<h4 class="text-sm font-semibold text-green-800 mb-2 flex items-center"> |
|
<svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 20 20"> |
|
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path> |
|
</svg> |
|
Solution Description |
|
</h4> |
|
<p class="text-xs text-gray-700 leading-relaxed">${solution['Solution Description'] || 'Aucune description de solution disponible.'}</p> |
|
`; |
|
|
|
|
|
const critiqueSection = document.createElement('div'); |
|
critiqueSection.className = 'bg-yellow-50 border-l-2 border-yellow-400 p-3 rounded-r-md'; |
|
|
|
let critiqueContent = ` |
|
<h4 class="text-sm font-semibold text-yellow-800 mb-2 flex items-center"> |
|
<svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 20 20"> |
|
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path> |
|
</svg> |
|
Critique & Analysis |
|
</h4> |
|
`; |
|
|
|
|
|
if (criticism.technical_challenges && criticism.technical_challenges.length > 0) { |
|
critiqueContent += ` |
|
<div class="mb-2"> |
|
<h5 class="text-xs font-semibold text-yellow-700 mb-1">Technical Challenges:</h5> |
|
<ul class="list-disc list-inside space-y-0.5 text-xs text-gray-700 ml-3"> |
|
${criticism.technical_challenges.map(challenge => `<li>${challenge}</li>`).join('')} |
|
</ul> |
|
</div> |
|
`; |
|
} |
|
|
|
if (criticism.weaknesses && criticism.weaknesses.length > 0) { |
|
critiqueContent += ` |
|
<div class="mb-2"> |
|
<h5 class="text-xs font-semibold text-yellow-700 mb-1">Weaknesses:</h5> |
|
<ul class="list-disc list-inside space-y-0.5 text-xs text-gray-700 ml-3"> |
|
${criticism.weaknesses.map(weakness => `<li>${weakness}</li>`).join('')} |
|
</ul> |
|
</div> |
|
`; |
|
} |
|
|
|
if (criticism.limitations && criticism.limitations.length > 0) { |
|
critiqueContent += ` |
|
<div class="mb-2"> |
|
<h5 class="text-xs font-semibent text-yellow-700 mb-1">Limitations:</h5> |
|
<ul class="list-disc list-inside space-y-0.5 text-xs text-gray-700 ml-3"> |
|
${criticism.limitations.map(limitation => `<li>${limitation}</li>`).join('')} |
|
</ul> |
|
</div> |
|
`; |
|
} |
|
|
|
critiqueSection.innerHTML = critiqueContent; |
|
|
|
|
|
content.appendChild(problemSection); |
|
content.appendChild(solutionSection); |
|
content.appendChild(critiqueSection); |
|
|
|
|
|
header.addEventListener('click', (e) => { |
|
|
|
if (e.target.closest('.version-btn-left') || e.target.closest('.version-btn-right')) { |
|
return; |
|
} |
|
|
|
const icon = header.querySelector('.accordion-icon'); |
|
const isCurrentlyOpen = !content.classList.contains('hidden'); |
|
|
|
if (isCurrentlyOpen) { |
|
content.classList.add('hidden'); |
|
icon.style.transform = 'rotate(0deg)'; |
|
accordionStates[solution['Category_Id']] = false; |
|
} else { |
|
content.classList.remove('hidden'); |
|
icon.style.transform = 'rotate(180deg)'; |
|
accordionStates[solution['Category_Id']] = true; |
|
} |
|
}); |
|
|
|
|
|
header.querySelector('.version-btn-left')?.addEventListener('click', (e) => { |
|
e.stopPropagation(); |
|
updateSingleAccordion(solutionCriticizedHistory, 'accordion-container', versionIndex - 1, index); |
|
}); |
|
|
|
header.querySelector('.version-btn-right')?.addEventListener('click', (e) => { |
|
e.stopPropagation(); |
|
updateSingleAccordion(solutionCriticizedHistory, 'accordion-container', versionIndex + 1, index); |
|
}); |
|
|
|
|
|
solutionCard.appendChild(header); |
|
solutionCard.appendChild(content); |
|
accordion.appendChild(solutionCard); |
|
} |
|
|
|
function updateSingleAccordion(solutionCriticizedHistory, containerId, newVersionIndex, categoryIndex) { |
|
|
|
if (newVersionIndex < 0 || newVersionIndex >= solutionCriticizedHistory.length) { |
|
return; |
|
} |
|
|
|
const accordionItem = document.getElementById(`accordion-item-${categoryIndex}`); |
|
if (!accordionItem) return; |
|
|
|
const newData = solutionCriticizedHistory[newVersionIndex]; |
|
const newItem = newData.critiques[categoryIndex]; |
|
|
|
if (!newItem) return; |
|
|
|
|
|
const tempContainer = document.createElement('div'); |
|
createSingleAccordionItem(newItem, categoryIndex, newVersionIndex, solutionCriticizedHistory, tempContainer); |
|
|
|
|
|
accordionItem.parentNode.replaceChild(tempContainer.firstChild, accordionItem); |
|
} |
|
|
|
|
|
function initializeSolutionAccordion(solutionCriticizedHistory, containerId, startVersion = 0) { |
|
|
|
accordionStates = {}; |
|
createSolutionAccordion(solutionCriticizedHistory, containerId, startVersion); |
|
document.getElementById(containerId).classList.remove('hidden') |
|
} |
|
|
|
async function generateSolutions(){ |
|
let response = await fetch('https://organizedprogrammers-reqxtract-api.hf.space/solution/search_solutions_gemini', {method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(categorizedRequirements)}) |
|
let responseObj = await response.json() |
|
return responseObj; |
|
} |
|
|
|
async function generateCriticisms(solutions){ |
|
let response = await fetch('https://organizedprogrammers-reqxtract-api.hf.space/solution/criticize_solution', {method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(solutions)}) |
|
let responseObj = await response.json() |
|
solutionsCriticizedVersions.push(responseObj) |
|
} |
|
|
|
async function refineSolutions(critiques){ |
|
let response = await fetch('https://organizedprogrammers-reqxtract-api.hf.space/solution/refine_solution', {method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(critiques)}) |
|
let responseObj = await response.json() |
|
await generateCriticisms(responseObj) |
|
} |
|
|
|
async function workflow(steps = 1){ |
|
let soluce; |
|
showLoadingOverlay('Génération des solutions & critiques ....'); |
|
for(let step = 1; step <= steps; step++){ |
|
if(solutionsCriticizedVersions.length == 0){ |
|
soluce = await generateSolutions(); |
|
await generateCriticisms(soluce) |
|
} else { |
|
let prevSoluce = solutionsCriticizedVersions[solutionsCriticizedVersions.length - 1]; |
|
await refineSolutions(prevSoluce) |
|
} |
|
} |
|
hideLoadingOverlay(); |
|
initializeSolutionAccordion(solutionsCriticizedVersions, "solutions-list") |
|
} |
|
|
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
document.getElementById('get-meetings-btn').addEventListener('click', getMeetings); |
|
document.getElementById('get-tdocs-btn').addEventListener('click', getTDocs); |
|
document.getElementById('download-tdocs-btn').addEventListener('click', downloadTDocs); |
|
document.getElementById('extract-requirements-btn').addEventListener('click', extractRequirements); |
|
document.getElementById('categorize-requirements-btn').addEventListener('click', ()=>{categorizeRequirements(8)}); |
|
|
|
|
|
document.getElementById('find-requirements-btn').addEventListener('click', function() { |
|
|
|
toggleContainersVisibility(['query-requirements-container'], true); |
|
|
|
document.getElementById('query-requirements-container').scrollIntoView({ behavior: 'smooth' }); |
|
}); |
|
|
|
|
|
document.getElementById('search-requirements-btn').addEventListener('click', searchRequirements); |
|
|
|
|
|
document.getElementById('get-solutions-btn').addEventListener('click', () => { |
|
alert('Fonctionnalité à implémenter'); |
|
}); |
|
document.getElementById('get-solutions-step-btn').addEventListener('click', () => { |
|
workflow(); |
|
}); |
|
}); |