let requirements; let categorizedRequirements; let solutionsCriticizedVersions = []; let isRequirements = false; function downloadTDocs() { document.getElementById("getReqs").setAttribute('disabled', 'true') document.getElementById("downloadZip").setAttribute('disabled', 'true') document.getElementById("progressText").classList.remove('hidden'); document.getElementById("progressText").innerHTML = "Downloading TDocs, please wait, it may take a while ..."; document.getElementById("loadingBar").classList.remove("hidden"); const data = tableToGenBody({ "TDoc": "doc" }); const dataSet = [...new Set(data.map(item => item.doc))]; console.log(dataSet); let body = { "documents": dataSet, "meeting": document.getElementById('meetingSelect').value }; if (document.getElementById('agendaItem').value != "" | document.getElementById('agendaItem').value != "Tous") { body['agenda_item'] = document.getElementById('agendaItem').value; } fetch('/download_tdocs', { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }) .then(resp => resp.blob()) .then(blob => { document.getElementById("getReqs").removeAttribute('disabled') document.getElementById("downloadZip").removeAttribute('disabled') document.getElementById("loadingBar").classList.add("hidden"); document.getElementById("progressText").classList.add("hidden"); const url = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; let dl_name = `${document.getElementById('meetingSelect').value}`; if (document.getElementById('agendaItem').value != "" | document.getElementById('agendaItem') .value != "Tous") { dl_name = dl_name + `_${document.getElementById('agendaItem').value}` }; if (document.getElementById('docStatus').value != "" | document.getElementById('docStatus') .value != "Tous") { dl_name = dl_name + `_${document.getElementById('docStatus').value}` }; if (document.getElementById('docType').value != "" | document.getElementById('docType').value != "Tous") { dl_name = `${document.getElementById('docType').value}_${dl_name}` }; if (isRequirements) { dl_name = `requirements_${dl_name}_${url.split('/').pop()}` } dl_name = dl_name + ".zip"; a.download = dl_name; document.body.appendChild(a); a.click(); a.remove(); window.URL.revokeObjectURL(url); // libération mémoire }) } function getDataFrame() { isRequirements = false; document.getElementById("progressText").classList.remove('hidden'); document.getElementById("progressText").innerHTML = "Getting TDoc list of meeting ..."; document.getElementById("loadingBar").classList.remove("hidden"); document.getElementById("getTDocs").setAttribute('disabled', 'true') const wg = document.getElementById('workingGroupSelect').value; const meeting = document.getElementById('meetingSelect').value; document.getElementById('docType').innerHTML = `` document.getElementById('docStatus').innerHTML = `` document.getElementById('agendaItem').innerHTML = `` const dataFrame = document.getElementById("dataFrame"); fetch("/get_dataframe", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ "working_group": wg, "meeting": meeting }) }) .then(resp => resp.json()) .then(data => { document.getElementById("filters").classList.remove("hidden"); document.getElementById("downloadZip").classList.remove("hidden"); document.getElementById("getReqs").classList.remove("hidden"); document.getElementById("getTDocs").removeAttribute("disabled") document.getElementById("progressText").classList.add('hidden'); document.getElementById("loadingBar").classList.add("hidden"); const dataframeBody = dataFrame.querySelector("tbody"); dataframeBody.innerHTML = ""; const setType = new Set(); const setAgenda = new Set(); const setStatus = new Set(); data.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 = ` ${row["TDoc"]} ${row["Title"]} ${row["Type"]} ${row["TDoc Status"]} ${row["Agenda item description"]} ${row["URL"]} `; dataframeBody.appendChild(tr); setType.add(row["Type"]); setAgenda.add(row["Agenda item description"]); setStatus.add(row["TDoc Status"]); }) setType.forEach(tdoctype => { const option = document.createElement("option"); option.textContent = tdoctype; option.value = tdoctype; document.getElementById('docType').appendChild(option); }) setAgenda.forEach(agenda => { const option = document.createElement("option"); option.textContent = agenda; option.value = agenda; document.getElementById('agendaItem').appendChild(option); }) setStatus.forEach(status => { const option = document.createElement("option"); option.textContent = status; option.value = status; document.getElementById('docStatus').appendChild(option); }) }) } function filterTable() { const type = document.getElementById('docType').value const status = document.getElementById('docStatus').value const agenda = document.getElementById('agendaItem').value document.querySelectorAll('#dataFrame tbody tr').forEach(row => { const showRow = (type === 'Tous' || row.dataset.type === type || type === "") && (status === 'Tous' || row.dataset.status === status || status === "") && (agenda === 'Tous' || row.dataset.agenda === agenda || agenda === "") row.style.display = showRow ? '' : 'none' }) } function getMeetings() { isRequirements = false; const workingGroup = document.getElementById("workingGroupSelect").value; document.getElementById("meetingSelect").setAttribute('disabled', 'true') document.getElementById("meetingSelect").innerHTML = "" document.getElementById("getTDocs").setAttribute('disabled', 'true') fetch("/get_meetings", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ "working_group": workingGroup }) }) .then(resp => resp.json()) .then(data => { document.getElementById("meetingSelect").innerHTML = ""; for (const [key, value] of Object.entries(data.meetings)) { const option = document.createElement("option"); option.textContent = key; option.value = value; document.getElementById('meetingSelect').appendChild(option); } document.getElementById("meetingSelect").removeAttribute("disabled"); document.getElementById("getTDocs").removeAttribute("disabled") }) } function generateRequirements() { isRequirements = false; document.getElementById("getReqs").setAttribute('disabled', 'true') document.getElementById("downloadZip").setAttribute('disabled', 'true') document.getElementById("progressText").classList.remove('hidden'); document.getElementById("progressText").innerHTML = "Generating requirements, please wait, it may take a while ..."; document.getElementById("loadingBar").classList.remove("hidden"); const bodyreq = tableToGenBody({ "TDoc": "document", "URL": "url" }); fetch("/generate_requirements", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ "documents": bodyreq }) }) .then(resp => resp.json()) .then(data => { let req_id = 0; document.getElementById("loadingBar").classList.add("hidden"); document.getElementById("progressText").classList.add("hidden"); document.getElementById("reqStatus").classList.remove("hidden"); document.getElementById("getReqs").classList.add("hidden"); document.getElementById("searchReq").classList.remove("hidden"); document.getElementById("categorizeReq").classList.remove("hidden"); document.getElementById("getReqs").removeAttribute('disabled') document.getElementById("downloadZip").removeAttribute('disabled') requirements = []; data.requirements.forEach(obj => { obj.requirements.forEach(req => { requirements.push({ req_id, "document": obj.document, "context": obj.context, "requirement": req }) req_id++; }) }) }) } function queryRequirements() { fetch("/get_reqs_from_query", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ query: document.getElementById("problemDescription").value, requirements }) }) .then(resp => resp.json()) .then(data => { const dataFrame = document.getElementById("dataFrameDiv"); const dataFrameHead = dataFrame.querySelector("thead"); const dataFrameBody = dataFrame.querySelector("tbody"); document.getElementById("buttons").classList.remove("hidden"); document.getElementById("searchReq").classList.add("hidden"); document.getElementById("categorizeReq").classList.add("hidden"); document.getElementById("getReqs").classList.add("hidden"); document.getElementById("reqStatus").classList.add("hidden"); document.getElementById("downloadZip").classList.remove("hidden"); isRequirements = true; dataFrame.classList.remove("hidden"); dataFrameHead.innerHTML = ` TDoc Context Requirement `; dataFrameBody.innerHTML = ""; data.requirements.forEach(req => { const tr = document.createElement("tr"); tr.innerHTML = ` ${req["document"]} ${req["context"]} ${req["requirement"]} `; dataFrameBody.appendChild(tr); }) }) } function tableToGenBody(columnsMap) { // columnsMap : { "NomHeaderDansTable": "nom_voulu", ... } const dataFrame = document.getElementById("dataFrame"); const headers = Array.from(dataFrame.querySelectorAll('thead th')).map(th => th.innerText.trim()); // Indices des colonnes à extraire const selectedIndices = headers .map((header, idx) => columnsMap[header] ? idx : -1) .filter(idx => idx !== -1); return Array.from(dataFrame.querySelectorAll('tbody tr')) .filter(row => getComputedStyle(row).display !== 'none') .map(row => { const cells = Array.from(row.querySelectorAll('td')); const obj = {}; selectedIndices.forEach(idx => { const originalHeader = headers[idx]; const newKey = columnsMap[originalHeader]; obj[newKey] = cells[idx].innerText.trim(); }); return obj; }); } function createCard(cardTitle, cardSub, cardText) { return `

${cardTitle}

${cardSub}

${cardText}

`; } function createCarousel(carouselTitle, id, cards) { let cardsHTML = cards.join("\n"); return `

${carouselTitle}

${cardsHTML}
`; } function categorizeRequirements(max_categories) { isRequirements = false; document.getElementById('categorizeReq').setAttribute('disabled', 'true'); document.getElementById('downloadZip').setAttribute('disabled', 'true'); document.getElementById('searchReq').setAttribute('disabled', 'true'); document.getElementById('progressText').classList.remove('hidden'); document.getElementById('loadingBar').classList.remove('hidden'); document.getElementById('progressText').textContent = "Grouping requirements by their context ..."; fetch("https://game4all-reqroup.hf.space/reqs/categorize_requirements", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ requirements, "max_n_categories": max_categories }) }) .then(resp => resp.json()) .then(data => { categorizedRequirements = data; document.getElementById('dataFrameForm').classList.add('hidden'); document.getElementById('filters').classList.add('hidden'); document.getElementById('categorizeReqContainer').classList.remove('hidden'); document.getElementById('dataFrameDiv').classList.add('hidden'); document.getElementById('buttons').classList.add('hidden'); document.getElementById('carousels').innerHTML = '

Requirements categories list

' data.categories.forEach(cat => { let reqCards = []; cat.requirements.forEach(reqContent => { // Correction ici reqCards.push(createCard(reqContent.document, reqContent.context, reqContent.requirement)) }); document.getElementById('carousels').innerHTML += createCarousel(cat.title, cat.id, reqCards); }) }) } // Variable globale pour tracker les états d'ouverture par catégorie let accordionStates = {}; function createSolutionAccordion(solutionCriticizedHistory, containerId, versionIndex = 0, categoryIndex = null) { const container = document.getElementById(containerId); if (!container) { console.error(`Container with ID "${containerId}" not found`); return; } // Si categoryIndex est spécifié, ne mettre à jour que cette catégorie if (categoryIndex !== null) { updateSingleAccordion(solutionCriticizedHistory, containerId, versionIndex, categoryIndex); return; } // Vider le container seulement si on recrée tout container.innerHTML = ''; // Récupérer les données de la version actuelle directement const currentVersionData = solutionCriticizedHistory[versionIndex]; // Créer l'accordéon principal const accordion = document.createElement('div'); accordion.className = 'space-y-2'; accordion.id = 'main-accordion'; // Afficher seulement les solutions de la version actuelle currentVersionData.critiques.forEach((item, index) => { createSingleAccordionItem(item, index, versionIndex, solutionCriticizedHistory, accordion); }); // Ajouter l'accordéon au container container.appendChild(accordion); } function createSingleAccordionItem(item, index, versionIndex, solutionCriticizedHistory, accordion) { const solution = item.solution; const criticism = item.criticism; // Récupérer le titre de la catégorie const categoryTitle = document.querySelector(`#category-${solution['Category_Id']} h2`)?.textContent || `Catégorie ${solution['Category_Id'] + 1}`; // Container pour chaque solution const solutionCard = document.createElement('div'); solutionCard.className = 'border border-gray-200 rounded-md shadow-sm'; solutionCard.id = `accordion-item-${index}`; // En-tête de l'accordéon avec navigation 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 = `

${categoryTitle}

Version ${currentVersion}
`; // Contenu de l'accordéon const content = document.createElement('div'); content.className = `accordion-content px-4 py-3 space-y-3`; content.id = `content-${solution['Category_Id']}`; // Vérifier l'état d'ouverture précédent const isOpen = accordionStates[solution['Category_Id']] || false; if (!isOpen) { content.classList.add('hidden'); } else { header.querySelector('.accordion-icon').style.transform = 'rotate(180deg)'; } // Section Problem Description const problemSection = document.createElement('div'); problemSection.className = 'bg-red-50 border-l-2 border-red-400 p-3 rounded-r-md'; problemSection.innerHTML = `

Problem Description

${solution['Problem Description'] || 'Aucune description du problème disponible.'}

`; // Section Solution Description const solutionSection = document.createElement('div'); solutionSection.className = 'bg-green-50 border-l-2 border-green-400 p-3 rounded-r-md'; solutionSection.innerHTML = `

Solution Description

${solution['Solution Description'] || 'Aucune description de solution disponible.'}

`; // Section Critique const critiqueSection = document.createElement('div'); critiqueSection.className = 'bg-yellow-50 border-l-2 border-yellow-400 p-3 rounded-r-md'; let critiqueContent = `

Critique & Analysis

`; // Sous-sections de critique if (criticism.technical_challenges && criticism.technical_challenges.length > 0) { critiqueContent += `
Technical Challenges:
`; } if (criticism.weaknesses && criticism.weaknesses.length > 0) { critiqueContent += `
Weaknesses:
`; } if (criticism.limitations && criticism.limitations.length > 0) { critiqueContent += `
Limitations:
`; } critiqueSection.innerHTML = critiqueContent; // Ajouter les sections au contenu content.appendChild(problemSection); content.appendChild(solutionSection); content.appendChild(critiqueSection); // Événement de clic pour l'accordéon (exclure les boutons de navigation) header.addEventListener('click', (e) => { // Ne pas déclencher l'accordéon si on clique sur les boutons de navigation 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; } }); // Événements de navigation pour cette catégorie spécifique 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); }); // Assembler la carte de solution solutionCard.appendChild(header); solutionCard.appendChild(content); accordion.appendChild(solutionCard); } function updateSingleAccordion(solutionCriticizedHistory, containerId, newVersionIndex, categoryIndex) { // Vérifier les limites de version 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; // Mettre à jour le contenu de cette catégorie spécifique const tempContainer = document.createElement('div'); createSingleAccordionItem(newItem, categoryIndex, newVersionIndex, solutionCriticizedHistory, tempContainer); // Remplacer l'ancien item par le nouveau accordionItem.parentNode.replaceChild(tempContainer.firstChild, accordionItem); } // Fonction d'initialisation simplifiée function initializeSolutionAccordion(solutionCriticizedHistory, containerId, startVersion = 0) { // Réinitialiser les états d'accordéon accordionStates = {}; createSolutionAccordion(solutionCriticizedHistory, containerId, startVersion); document.getElementById("criticizeSoluceContainer").classList.remove('hidden') } async function generateSolutions(){ isRequirements = false; let response = await fetch('https://game4all-reqroup.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){ isRequirements = false; let response = await fetch('https://game4all-reqroup.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){ isRequirements = false; let response = await fetch('https://game4all-reqroup.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; 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) } } initializeSolutionAccordion(solutionsCriticizedVersions, "criticizeSoluceContainer") } // Écouteurs d'événements pour les filtres document.getElementById('docType').addEventListener('change', filterTable) document.getElementById('docStatus').addEventListener('change', filterTable) document.getElementById('agendaItem').addEventListener('change', filterTable) document.getElementById("workingGroupSelect").addEventListener('change', getMeetings) document.getElementById('getTDocs').addEventListener('click', getDataFrame) document.getElementById("getReqs").addEventListener("click", generateRequirements); document.getElementById('categorizeReq').addEventListener('click', () => categorizeRequirements(8)); document.getElementById("downloadZip").addEventListener('click', downloadTDocs) document.getElementById("queryReq").addEventListener("click", queryRequirements) document.getElementById('getSolutionsStepByStep').addEventListener('click', async () => await workflow()) document.getElementById("getSolutions").addEventListener('click', async () => { let steps = document.getElementById('limitInput').value != '' ? document.getElementById('limitInput').value : 10; await workflow(steps) }) document.getElementById('searchReq').addEventListener('click', () => { document.getElementById('dataFrameForm').classList.add('hidden'); document.getElementById('filters').classList.add('hidden'); document.getElementById('queryReqForm').classList.remove('hidden'); document.getElementById('dataFrameDiv').classList.add('hidden'); document.getElementById('buttons').classList.add('hidden'); })