|
import { marked } from 'https://cdnjs.cloudflare.com/ajax/libs/marked/16.1.1/lib/marked.esm.js'; |
|
|
|
import { assessSolution, getModelList, refineSolution, runFTOAnalysis } from "./gen.js" |
|
import { clearConfig, loadConfig, saveConfig } from "./persistence.js"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export 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'); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
export 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'); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
export function showLoadingOverlay(message = 'Chargement en cours...') { |
|
document.getElementById('progress-text').textContent = message; |
|
toggleContainersVisibility(['loading-overlay'], true); |
|
} |
|
|
|
|
|
|
|
|
|
export function hideLoadingOverlay() { |
|
toggleContainersVisibility(['loading-overlay'], false); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export 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); |
|
}); |
|
} |
|
} |
|
|
|
export function populateCheckboxDropdown(optionsContainerId, options, filterType, labelId, selectionSet, onSelect) { |
|
const container = document.getElementById(optionsContainerId); |
|
container.innerHTML = ''; |
|
selectionSet.clear(); |
|
|
|
|
|
options.forEach(option => { |
|
const safeId = `${filterType}-${encodeURIComponent(option).replace(/[%\s]/g, '_')}`; |
|
const label = document.createElement('label'); |
|
label.className = "flex items-center gap-2 cursor-pointer py-1"; |
|
label.innerHTML = ` |
|
<input type="checkbox" class="${filterType}-checkbox option-checkbox" id="${safeId}" value="${option}"> |
|
<span>${option}</span> |
|
`; |
|
label.querySelector('input').addEventListener('change', function () { |
|
if (this.checked) { |
|
selectionSet.add(this.value); |
|
} else { |
|
selectionSet.delete(this.value); |
|
} |
|
|
|
|
|
updateCheckboxDropdownLabel(filterType, labelId, selectionSet, options.length); |
|
|
|
const allBox = document.querySelector(`.${filterType}-checkbox[value="all"]`); |
|
if (allBox && allBox.checked) allBox.checked = false; |
|
|
|
if (selectionSet.size === 0 && allBox) allBox.checked = true; |
|
onSelect?.(); |
|
}); |
|
container.appendChild(label); |
|
}); |
|
|
|
|
|
updateCheckboxDropdownLabel(filterType, labelId, selectionSet, options.length); |
|
|
|
|
|
const allBox = document.querySelector(`.${filterType}-checkbox[value="all"]`); |
|
if (allBox) { |
|
allBox.addEventListener('change', function () { |
|
if (this.checked) { |
|
|
|
selectionSet.clear(); |
|
container.querySelectorAll('input[type="checkbox"]').forEach(cb => cb.checked = false); |
|
this.checked = true; |
|
updateCheckboxDropdownLabel(filterType, labelId, selectionSet, options.length); |
|
applyFilters(); |
|
} |
|
}); |
|
} |
|
} |
|
|
|
export function updateCheckboxDropdownLabel(type, labelId, set, totalCount) { |
|
const label = document.getElementById(labelId); |
|
if (!set.size) { |
|
label.textContent = type.charAt(0).toUpperCase() + type.slice(1) + " (Tous)"; |
|
} else if (set.size === 1) { |
|
label.textContent = [...set][0]; |
|
} else { |
|
label.textContent = `${type.charAt(0).toUpperCase() + type.slice(1)} (${set.size}/${totalCount})`; |
|
} |
|
} |
|
|
|
export function updateSelectedFilters(filterType, value, isChecked) { |
|
if (isChecked) { |
|
selectedFilters[filterType].add(value); |
|
} else { |
|
selectedFilters[filterType].delete(value); |
|
} |
|
} |
|
|
|
export function populateDaisyDropdown(menuId, options, labelId, onSelect) { |
|
const menu = document.getElementById(menuId); |
|
menu.innerHTML = ''; |
|
|
|
const liAll = document.createElement('li'); |
|
liAll.innerHTML = `<a data-value="">Tous</a>`; |
|
liAll.querySelector('a').onclick = e => { |
|
e.preventDefault(); |
|
document.getElementById(labelId).textContent = "Type"; |
|
onSelect(""); |
|
}; |
|
menu.appendChild(liAll); |
|
|
|
|
|
options.forEach(opt => { |
|
const li = document.createElement('li'); |
|
li.innerHTML = `<a data-value="${opt}">${opt}</a>`; |
|
li.querySelector('a').onclick = e => { |
|
e.preventDefault(); |
|
document.getElementById(labelId).textContent = opt; |
|
onSelect(opt); |
|
}; |
|
menu.appendChild(li); |
|
}); |
|
} |
|
|
|
export function updateFilterLabel(filterType) { |
|
const selectedCount = selectedFilters[filterType].size; |
|
const labelElement = document.getElementById(`${filterType}-filter-label`); |
|
|
|
if (selectedCount === 0) { |
|
labelElement.textContent = `${filterType} (Tous)`; |
|
} else { |
|
labelElement.textContent = `${filterType} (${selectedCount} sélectionné${selectedCount > 1 ? 's' : ''})`; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
export 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; |
|
} |
|
|
|
|
|
|
|
|
|
export function buildSolutionSubCategories(solution) { |
|
|
|
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 reqsSection = document.createElement('div'); |
|
reqsSection.className = "bg-gray-50 border-l-2 border-red-400 p-3 rounded-r-md"; |
|
const reqItemsUl = solution["requirements"].map(req => `<li>${req}</li>`).join(''); |
|
reqsSection.innerHTML = ` |
|
<h4 class="text-sm font-semibold text-gray-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> |
|
Addressed 3GPP requirements |
|
</h4> |
|
<ul class="list-disc pl-5 space-y-1 text-gray-700 text-xs"> |
|
${reqItemsUl} |
|
</ul> |
|
` |
|
|
|
|
|
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> |
|
`; |
|
|
|
|
|
const solContents = document.createElement('div'); |
|
solContents.className = "text-xs text-gray-700 leading-relaxed"; |
|
solutionSection.appendChild(solContents); |
|
|
|
try { |
|
solContents.innerHTML = marked.parse(solution['solution_description']); |
|
} |
|
catch (e) { |
|
console.error(e); |
|
solContents.innerHTML = `<p class="text-xs text-gray-700 leading-relaxed">${solution['solution_description'] || 'No available solution description'}</p>`; |
|
} |
|
|
|
return [problemSection, reqsSection, solutionSection] |
|
} |
|
|
|
|
|
const TABS = { |
|
'doc-table-tab': 'doc-table-tab-contents', |
|
'requirements-tab': 'requirements-tab-contents', |
|
'solutions-tab': 'solutions-tab-contents', |
|
'query-tab': 'query-tab-contents', |
|
'draft-tab': 'draft-tab-contents' |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
export function switchTab(newTab) { |
|
|
|
Object.keys(TABS).forEach(tabId => { |
|
const tabElement = document.getElementById(tabId); |
|
if (tabElement) { |
|
tabElement.classList.remove("tab-active"); |
|
} |
|
}); |
|
|
|
|
|
Object.values(TABS).forEach(contentId => { |
|
const contentElement = document.getElementById(contentId); |
|
if (contentElement) { |
|
contentElement.classList.add("hidden"); |
|
} |
|
}); |
|
|
|
|
|
if (newTab in TABS) { |
|
const newTabElement = document.getElementById(newTab); |
|
const newContentElement = document.getElementById(TABS[newTab]); |
|
|
|
if (newTabElement) newTabElement.classList.add("tab-active"); |
|
if (newContentElement) newContentElement.classList.remove("hidden"); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
export function bindTabs() { |
|
Object.keys(TABS).forEach(tabId => { |
|
const tabElement = document.getElementById(tabId); |
|
tabElement.addEventListener('click', _ => switchTab(tabId)); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
export function enableTabSwitching() { |
|
Object.keys(TABS).forEach(tabId => { |
|
const tab = document.getElementById(tabId); |
|
if (tab) |
|
tab.classList.remove("tab-disabled"); |
|
}) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
export function debounceAutoCategoryCount(state) { |
|
document.getElementById('category-count').disabled = state; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function getConfigFields() { |
|
const providerUrl = document.getElementById('settings-provider-url').value; |
|
const providerToken = document.getElementById('settings-provider-token').value; |
|
const providerModel = document.getElementById('settings-provider-model').value; |
|
const assessmentRules = document.getElementById('settings-assessment-rules').value; |
|
const businessPortfolio = document.getElementById('settings-portfolio').value; |
|
const ftoTopicCount = document.getElementById('settings-fto-topic-count').value; |
|
|
|
return { providerUrl, providerToken, providerModel, assessmentRules, businessPortfolio, ftoTopicCount }; |
|
} |
|
|
|
|
|
|
|
|
|
export function checkPrivateLLMInfoAvailable() { |
|
const { providerUrl, providerToken, providerModel, assessmentRules, businessPortfolio } = getConfigFields(); |
|
const isEmpty = (str) => (!str?.length); |
|
return !isEmpty(providerUrl) && !isEmpty(providerToken) && !isEmpty(assessmentRules) && !isEmpty(businessPortfolio) && !isEmpty(providerModel); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function populateLLMModelSelect(selectElementId, providerUrl, apiKey) { |
|
const selectElement = document.getElementById(selectElementId); |
|
if (!selectElement) { |
|
console.error(`Select element with ID "${selectElementId}" not found.`); |
|
return; |
|
} |
|
|
|
|
|
selectElement.innerHTML = ''; |
|
|
|
try { |
|
const models = await getModelList(providerUrl, apiKey); |
|
|
|
if (models.length === 0) { |
|
const option = document.createElement('option'); |
|
option.value = ""; |
|
option.textContent = "No models found"; |
|
selectElement.appendChild(option); |
|
selectElement.disabled = true; |
|
return; |
|
} |
|
|
|
|
|
const defaultOption = document.createElement('option'); |
|
defaultOption.value = ""; |
|
defaultOption.textContent = "Select a model"; |
|
defaultOption.disabled = true; |
|
defaultOption.selected = true; |
|
selectElement.appendChild(defaultOption); |
|
|
|
|
|
models.forEach(modelName => { |
|
const option = document.createElement('option'); |
|
option.value = modelName; |
|
option.textContent = modelName; |
|
selectElement.appendChild(option); |
|
}); |
|
} catch (error) { |
|
throw error; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
export function handleLoadConfigFields() { |
|
const configuration = loadConfig(); |
|
if (configuration === null) |
|
return; |
|
|
|
const providerUrl = document.getElementById('settings-provider-url'); |
|
const providerToken = document.getElementById('settings-provider-token'); |
|
const providerModel = document.getElementById('settings-provider-model'); |
|
const assessmentRules = document.getElementById('settings-assessment-rules'); |
|
const businessPortfolio = document.getElementById('settings-portfolio'); |
|
const ftoTopicCount = document.getElementById('settings-fto-topic-count'); |
|
|
|
providerUrl.value = configuration.providerUrl; |
|
providerToken.value = configuration.providerToken; |
|
assessmentRules.value = configuration.assessmentRules; |
|
businessPortfolio.value = configuration.businessPortfolio; |
|
ftoTopicCount.value = configuration.ftoTopicCount; |
|
|
|
|
|
populateLLMModelSelect('settings-provider-model', configuration.providerUrl, configuration.providerToken).then(() => { |
|
providerModel.value = configuration.providerModel; |
|
}).catch(e => { |
|
alert("Failed to set LLM model in model selector. Model may not be available anymore, check model in LLM settings."); |
|
}) |
|
} |
|
|
|
|
|
|
|
|
|
export function handleSaveConfigFields() { |
|
saveConfig(getConfigFields()); |
|
alert("Configuration saved locally."); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
export function handleClearConfig() { |
|
clearConfig(); |
|
alert("Saved configuration has been cleared. Configuration set in the fields won't be saved."); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let draftHistory = []; |
|
|
|
|
|
|
|
let draftCurrentIndex = -1; |
|
|
|
|
|
|
|
|
|
|
|
export function moveSolutionToDrafts(solution) { |
|
const draft_tab_item = document.getElementById('draft-tab'); |
|
if (draft_tab_item.classList.contains("hidden")) |
|
draft_tab_item.classList.remove("hidden"); |
|
|
|
switchTab('draft-tab'); |
|
|
|
const { providerUrl, providerToken, providerModel, assessmentRules, businessPortfolio } = getConfigFields(); |
|
|
|
showLoadingOverlay("Assessing solution ...."); |
|
assessSolution(providerUrl, providerModel, providerToken, solution, assessmentRules, businessPortfolio).then(response => { |
|
|
|
draftHistory = []; |
|
draftCurrentIndex = -1; |
|
|
|
|
|
const insights = response.extracted_info.insights.map((e, idx, __) => ({ id: idx, text: e, checked: false })); |
|
|
|
|
|
draftHistory.push({ |
|
type: "draft", |
|
solution: solution, |
|
insights: insights, |
|
assessment_full: response.assessment_full, |
|
final_verdict: response.extracted_info.final_verdict, |
|
assessment_summary: response.extracted_info.summary, |
|
}); |
|
|
|
draftCurrentIndex++; |
|
|
|
renderDraftUI(); |
|
}).catch(e => { |
|
alert(e); |
|
}).finally(() => { |
|
hideLoadingOverlay(); |
|
}) |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
function renderDraftTimeline(timelineContainer, currentIndex, drafts) { |
|
timelineContainer.innerHTML = ''; |
|
drafts.forEach((state, idx) => { |
|
const li = document.createElement('li'); |
|
li.className = `step ${idx <= currentIndex ? 'step-primary' : ''}`; |
|
li.innerHTML = `<span class="step-icon">${state.type == "draft" ? "📝" : `🔎`}</span>${state.type == "draft" ? `Draft #${idx + 1}` : "FTO analysis "}` |
|
|
|
|
|
li.onclick = () => jumpToDraft(idx); |
|
timelineContainer.appendChild(li); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
export function renderDraftUI() { |
|
const solutionDisplay = document.getElementById('solution-draft-display'); |
|
const insightsContainer = document.getElementById('insights-container'); |
|
const timelineContainer = document.getElementById('timeline-container'); |
|
|
|
if (draftCurrentIndex < 0) { |
|
solutionDisplay.innerHTML = `<p>No drafted solutions for now</p>` |
|
insightsContainer.innerHTML = ''; |
|
timelineContainer.innerHTML = ''; |
|
return; |
|
} |
|
|
|
const currentState = draftHistory[draftCurrentIndex]; |
|
|
|
const solutionSections = buildSolutionSubCategories(currentState.solution); |
|
solutionDisplay.innerHTML = ''; |
|
|
|
|
|
for (let child of solutionSections) |
|
solutionDisplay.appendChild(child); |
|
|
|
|
|
|
|
|
|
const finalVerdictTextEl = document.getElementById('assessment-recommendation-status'); |
|
|
|
|
|
const verdict_colors = { |
|
NO_GO: "text-red-600", |
|
CONDITIONAL_GO: "text-orange-600", |
|
IMMEDIATE_GO: "text-green-600" |
|
}; |
|
|
|
|
|
Object.values(verdict_colors).forEach(v => { |
|
finalVerdictTextEl.classList.remove(v); |
|
}); |
|
|
|
finalVerdictTextEl.innerText = currentState.final_verdict; |
|
finalVerdictTextEl.classList.add(verdict_colors[currentState.final_verdict.replace("-", "_")]); |
|
|
|
document.getElementById('assessment-recommendation-summary').innerText = currentState.assessment_summary; |
|
|
|
|
|
insightsContainer.innerHTML = ''; |
|
currentState.insights.forEach(insight => { |
|
const isChecked = insight.checked ? 'checked' : ''; |
|
const insightEl = document.createElement('label'); |
|
insightEl.className = 'label cursor-pointer justify-start gap-4'; |
|
insightEl.innerHTML = ` |
|
<input type="checkbox" id="${insight.id}" ${isChecked} class="checkbox checkbox-primary" /> |
|
<span class="label-text">${insight.text}</span> |
|
`; |
|
|
|
insightEl.querySelector('input').addEventListener('change', (e) => { |
|
insight.checked = e.target.checked; |
|
}); |
|
insightsContainer.appendChild(insightEl); |
|
}); |
|
|
|
|
|
|
|
renderDraftTimeline(timelineContainer, draftCurrentIndex, draftHistory); |
|
|
|
console.log(draftHistory); |
|
console.log(draftCurrentIndex); |
|
} |
|
|
|
|
|
|
|
|
|
export function handleDraftRefine() { |
|
|
|
const refineBtn = document.getElementById('refine-btn'); |
|
const userInsightsText = document.getElementById('user-insight-text').value; |
|
|
|
const currentState = draftHistory[draftCurrentIndex]; |
|
|
|
|
|
const selectedInsights = currentState.insights |
|
.filter(i => i.checked) |
|
.map(i => i.text); |
|
|
|
if (selectedInsights.length === 0 && (userInsightsText === null || userInsightsText === "")) { |
|
alert('Please select at least one insight to refine the solution or provide a manual user insight.'); |
|
return; |
|
} |
|
|
|
|
|
if (draftCurrentIndex < draftHistory.length - 1) { |
|
draftHistory = draftHistory.slice(0, draftCurrentIndex + 1); |
|
} |
|
|
|
|
|
const { providerUrl, providerToken, providerModel, assessmentRules, businessPortfolio } = getConfigFields(); |
|
|
|
showLoadingOverlay('Refining and assessing ....') |
|
|
|
refineSolution(providerUrl, providerModel, providerToken, currentState.solution, selectedInsights, userInsightsText, assessmentRules, businessPortfolio) |
|
.then(newSolution => { |
|
const refinedSolution = newSolution; |
|
return assessSolution(providerUrl, providerModel, providerToken, newSolution, assessmentRules, businessPortfolio) |
|
.then(assessedResult => { |
|
return { refinedSolution, assessedResult }; |
|
}); |
|
}) |
|
.then(result => { |
|
|
|
const newInsights = result.assessedResult.extracted_info.insights.map((e, idx, __) => ({ id: idx, text: e, checked: false })); |
|
|
|
draftHistory.push({ |
|
type: "draft", |
|
solution: result.refinedSolution, |
|
insights: newInsights, |
|
assessment_full: result.assessedResult.assessment_full, |
|
final_verdict: result.assessedResult.extracted_info.final_verdict, |
|
assessment_summary: result.assessedResult.extracted_info.summary, |
|
}); |
|
|
|
draftCurrentIndex++; |
|
renderDraftUI(); |
|
}) |
|
.catch(error => { |
|
|
|
alert("An error occurred while refining a draft:" + error); |
|
}).finally(() => { |
|
hideLoadingOverlay(); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
function jumpToDraft(index) { |
|
if (index >= 0 && index < draftHistory.length) { |
|
draftCurrentIndex = index; |
|
renderDraftUI(); |
|
} |
|
} |
|
|
|
export function handleFTOAnalysis() { |
|
const { providerUrl, providerToken, providerModel, businessPortfolio, ftoTopicCount } = getConfigFields(); |
|
const currentState = draftHistory[draftCurrentIndex]; |
|
|
|
console.log("Launching FTO analysis"); |
|
|
|
showLoadingOverlay("Running FTO analysis... This may take a while"); |
|
|
|
runFTOAnalysis(providerUrl, providerModel, providerToken, currentState.solution, businessPortfolio, ftoTopicCount) |
|
.then(result => { |
|
|
|
const newInsights = result.extracted_info.insights.map((e, idx, __) => ({ id: idx, text: e, checked: false })); |
|
|
|
|
|
const full_assessment_content = `${result.assessment_full}\n\n---\n---\n\n# FTO report contents\n\n${result.fto_report}`; |
|
|
|
draftHistory.push({ |
|
type: "fto", |
|
solution: currentState.solution, |
|
insights: newInsights, |
|
assessment_full: full_assessment_content, |
|
final_verdict: result.extracted_info.final_verdict, |
|
assessment_summary: result.extracted_info.summary, |
|
}); |
|
|
|
draftCurrentIndex++; |
|
renderDraftUI(); |
|
}) |
|
.catch(e => alert(e)) |
|
.finally(() => hideLoadingOverlay()); |
|
} |
|
|
|
|
|
|
|
|
|
export function displayFullAssessment() { |
|
const full_assessment_content = document.getElementById('read-assessment-content'); |
|
const modal = document.getElementById('read-assessment-modal'); |
|
|
|
if (draftCurrentIndex < 0) |
|
return; |
|
|
|
const lastDraft = draftHistory[draftCurrentIndex]; |
|
try { |
|
full_assessment_content.innerHTML = marked.parse(lastDraft.assessment_full); |
|
} |
|
catch (e) { |
|
full_assessment_content.innerHTML = lastDraft.assessment_full; |
|
} |
|
|
|
modal.showModal(); |
|
} |
|
|
|
|
|
|
|
|
|
export async function handleExportDrafts() { |
|
if (draftHistory.length === 0) { |
|
alert("No drafts to export!"); |
|
return; |
|
} |
|
|
|
console.log("Starting ZIP export..."); |
|
|
|
const zip = new JSZip(); |
|
|
|
const separator = '-----------------------------------------'; |
|
|
|
|
|
draftHistory.forEach((draft, index) => { |
|
const fileContent = `## Problem Description\n\n${draft.solution.problem_description}\n\n## Solution\n\n${draft.solution.solution_description}\n\n${separator}\n\n## Assessment \n\n${draft.assessment_full}`; |
|
|
|
const fileName = `${draft.type}_${index + 1}.txt`; |
|
zip.file(fileName, fileContent); |
|
}); |
|
|
|
|
|
|
|
try { |
|
const content = await zip.generateAsync({ type: "blob" }); |
|
|
|
|
|
|
|
const link = document.createElement('a'); |
|
link.href = URL.createObjectURL(content); |
|
link.download = "drafts_export.zip"; |
|
|
|
|
|
document.body.appendChild(link); |
|
link.click(); |
|
document.body.removeChild(link); |
|
|
|
console.log("ZIP file generated and download triggered."); |
|
|
|
} catch (error) { |
|
console.error("Error exporting drafts to zip file:", error); |
|
} |
|
} |