AccademIA

"Il primo passo verso la tua laurea inizia qui."

Lettura obbligatoria prima dell’accesso

⚖ Condizioni d’uso e Avvertenze Legali

Versione 1.0 — Marzo 2025 — RobPac Publishing

Inserisci la chiave e poi conferma le tre caselle.

Art. 1 — Natura del Servizio

AccademIA è uno strumento di supporto per organizzare, sviluppare e revisionare materiali utili al percorso di tesi. Non sostituisce il giudizio del relatore, non sostituisce la valutazione dell’ateneo e non garantisce approvazione, punteggio, laurea, conformità regolamentare o assenza di contestazioni.

Art. 2 — Responsabilità finale del contenuto

Ogni indice, abstract, capitolo, revisione, citazione, riferimento bibliografico, dato o formulazione generati tramite il Servizio devono essere controllati, verificati, adattati e validati prima di qualsiasi utilizzo. La responsabilità finale dell’elaborato consegnato resta integralmente in capo a chi utilizza il Servizio.

Art. 3 — Fonti, citazioni e rischio di errori

I sistemi di intelligenza artificiale possono produrre errori, omissioni, inesattezze, riferimenti incompleti o fonti non verificabili. AccademIA non garantisce l’esistenza effettiva, la correttezza o la pertinenza di ogni riferimento restituito. È obbligatorio verificare in autonomia fonti, citazioni, note, bibliografia, dati, traduzioni e formulazioni prima dell’uso.

Art. 4 — Copyright, diritti di terzi e uso lecito

È vietato caricare, usare o rielaborare tramite il Servizio materiali protetti da diritto d’autore o da altri diritti di terzi senza avere i necessari permessi, licenze o basi giuridiche. AccademIA non garantisce che ogni output sia privo di profili di similarità, contestazioni di copyright o violazioni di regolamenti accademici. Chi utilizza il Servizio si assume ogni responsabilità per i materiali caricati e per l’uso finale dei contenuti generati.

Art. 5 — Regole accademiche e integrità

Il Servizio non deve essere utilizzato per eludere regolamenti universitari, procedure antiplagio, regole di integrità accademica o istruzioni del relatore. AccademIA va usata come supporto operativo al lavoro personale, non come esonero dalla responsabilità di studio, verifica e rielaborazione critica.

Art. 6 — Dati, strumenti tecnici e continuità del servizio

Per funzionare, il Servizio utilizza account, salvataggio cloud e strumenti tecnici di terze parti. Pur adottando misure ragionevoli, non viene garantita continuità assoluta del servizio, assenza di interruzioni, recupero perpetuo dei dati o disponibilità ininterrotta di provider esterni, API o infrastrutture.

Art. 7 — Documenti completi

I testi completi di Termini di Servizio e Privacy & Cookie sono consultabili qui: Termini · Privacy.

✦ Powered by Claude AI + Web Search accademico

La tua laurea,
con I.A.

Genera passo dopo passo indice, abstract e capitoli con fonti accademiche reali ricercate in tempo reale.

📖 Come funziona AccademIA — Guida rapida
1
Inserisci i dati del tuo progettoTipo di laurea, facoltà, corso, approccio metodologico e solo dopo argomento. Se il tuo relatore ti ha già fornito un indice, seleziona "Ho già un indice" e incollalo.
2
Genera e approva l’IndiceAccademIA propone una struttura capitolare ottimale per la tua disciplina. Puoi richiedere modifiche liberamente fino ad approvazione — le revisioni di indice e abstract non consumano il tuo budget di revisioni.
3
Genera e approva l’AbstractProdotto automaticamente in base all’indice approvato, con struttura accademica e parole chiave. Modificabile liberamente.
4
Genera i Capitoli uno alla voltaOgni capitolo viene scritto con ricerca web in tempo reale per trovare fonti reali. Approva ogni capitolo prima di passare al successivo. Hai 3 revisioni disponibili per capitolo e un budget base fisso di 10 revisioni totali incluse, indipendentemente dal numero di capitoli.
5
Scarica il DOCXA tesi completata, scarichi un documento Word formattato con indice, abstract e tutti i capitoli, pronto per la revisione del relatore.
⚠ Pacchetti aggiuntivi: Se esaurisci le revisioni disponibili, puoi attivare un Pacchetto Revisioni aggiuntive (+3 revisioni su un capitolo) oppure un Upgrade di piano coerente con il piano attivo. Dopo il pagamento ricevi una nuova chiave che attiva il piano superiore mantenendo lo stato della tesi.

Licenza standard: una licenza resta associata a una sola tesi. La cancellazione dei contenuti non libera la licenza per una tesi diversa.

🔍 Fonti: AccademIA usa web search per trovare fonti reali, ma verifica sempre ogni citazione prima della consegna. Alcune fonti potrebbero richiedere accesso istituzionale (JSTOR, Scopus, ecc.).
1
Dati
2
Indice
3
Abstract
4
Capitoli
5
Download
Stato lavorazione
Step attuale
Account
Non collegato
Sync
Non attiva
Revisioni
Dettagli del tuo progetto
Teorico-bibliografica
Storico-critica
Analisi testuale / ermeneutica
Revisione della letteratura
Comparativa
Giuridico-normativa
Documentale
Caso studio documentale su fonti fornite
Scegli l’approccio più vicino alla tesi reale. Nel menu compaiono solo tipologie gestibili dal piano standard: teorico-bibliografiche, storico-critiche, ermeneutiche/testuali, revisioni della letteratura, comparative, giuridico-normative, documentali e casi studio fondati su fonti fornite. Non sono previste tesi con raccolta dati originale, cliniche, sperimentali, statistiche proprietarie o progettuali tecniche specialistiche.
✦ AI decide la struttura ottimale
🧩 Export progressivo del lavoro sviluppato fino al momento
`; } function safeDocName(label){ return `${label}_${(thesis.argomento||'tesi').substring(0,40).replace(/[^a-zA-Z0-9]+/g,'_')}.doc`; } function safeTxtName(label){ return `${label}_${(thesis.argomento||'tesi').substring(0,40).replace(/[^a-zA-Z0-9]+/g,'_')}.txt`; } function downloadTextFile(filename, text){ downloadBlob(filename, text, 'text/plain;charset=utf-8'); } function chapterContentHasInlineHeading(chapterContent){ const normalized=String(chapterContent||'').replace(/^\uFEFF/,'').trimStart(); if(!normalized)return false; const lines=normalized.split('\n').map(line=>line.trim()).filter(Boolean).slice(0,4); const cleaned=lines.map(line=>line.replace(/^#{1,6}\s*/,'').replace(/^\*\*(.+)\*\*$/,'$1').trim()); const hasInlineFullHeading=cleaned.some(line=>/^capitolo\s+\d+\s*[—-]\s*\S+/i.test(line)||/^capitolo\s+\d+\s*:\s*\S+/i.test(line)); if(hasInlineFullHeading)return true; if(cleaned.length>=2&&/^capitolo\s+\d+\b/i.test(cleaned[0])&&!/^\d+(?:\.\d+)+\b/.test(cleaned[1]))return true; return false; } function exportChapterStatusLabel(idx){ const state=getChapterGenerationState(idx); if(state==='approved') return 'approvato'; if(state==='complete') return 'completato'; if(state==='partial' || state==='error') return 'bozza'; return 'non ancora disponibile'; } function buildWorkInProgressPlainText(){ const chunks=[]; const title=String(thesis.argomento||'').trim(); chunks.push(`Titolo tesi\n${title||'non ancora disponibile'}`); const details=[]; if(String(thesis.tipo||'').trim()) details.push(`Tipo laurea: ${tipoLaureaLabel(thesis.tipo)}`); if(String(thesis.facolta||'').trim()) details.push(`Facoltà: ${thesis.facolta}`); if(String(thesis.corso||'').trim()) details.push(`Corso: ${thesis.corso}`); if(String(thesis.metodologia||'').trim()) details.push(`Metodologia: ${thesis.metodologia}`); chunks.push(`Dati principali\n${details.length?details.join('\n'):'non ancora disponibili'}`); const hasApprovedIndex=isIndexApprovedState(); const indexText=String(thesis.indice||'').trim(); chunks.push(`Indice${hasApprovedIndex?' (approvato)':''}\n${indexText||'non ancora disponibile'}`); const hasApprovedAbstract=isAbstractApprovedState(); const abstractText=String(thesis.abstract||'').trim(); chunks.push(`Abstract${hasApprovedAbstract?' (approvato)':''}\n${abstractText||'non ancora disponibile'}`); const titles=Array.isArray(thesis.chapterTitles)?thesis.chapterTitles:[]; const total=Math.max(titles.length, Array.isArray(thesis.chapters)?thesis.chapters.length:0); const chaptersOut=[]; for(let i=0;i{ const chapterContent=getCanonicalChapterContentLocal(i,{persist:true}) || ''; const hasChapterHeading=chapterContentHasInlineHeading(chapterContent); out += hasChapterHeading ? `\n\n${chapterContent}\n` : `\n\nCAPITOLO ${i+1}: ${(thesis.chapterTitles?.[i]||ch.title||'').trim()}\n\n${chapterContent}\n`; }); return out.trim()+"\n"; } function downloadIndiceDoc(){ if(!thesis.indice){showToast('Indice non disponibile',true);return;} downloadBlob(safeDocName('Indice'), buildSingleDoc('Indice della tesi', `
${escHtml(thesis.indice)}
`)); } function downloadIndiceTxt(){ if(!thesis.indice){showToast('Indice non disponibile',true);return;} downloadTextFile(safeTxtName('Indice'), thesis.indice); } function downloadAbstractDoc(){ if(!thesis.abstract){showToast('Abstract non disponibile',true);return;} downloadBlob(safeDocName('Abstract'), buildSingleDoc('Abstract', `

${escHtml(thesis.abstract).replace(/\n/g,'
')}

`)); } function downloadAbstractTxt(){ if(!thesis.abstract){showToast('Abstract non disponibile',true);return;} downloadTextFile(safeTxtName('Abstract'), thesis.abstract); } function downloadChapterDoc(idx){ const ch=thesis.chapters?.[idx]; if(!ch){showToast('Capitolo non disponibile',true);return;} const chapterContent=getCanonicalChapterContentLocal(idx,{persist:true}) || ''; const hasChapterHeading=chapterContentHasInlineHeading(chapterContent); const title=hasChapterHeading ? (thesis.chapterTitles?.[idx]||ch.title||`Capitolo ${idx+1}`) : `Capitolo ${idx+1}: ${thesis.chapterTitles?.[idx]||ch.title||''}`; downloadBlob(safeDocName(`Capitolo_${idx+1}`), buildSingleDoc(title, `
${formatChapterHtml(chapterContent)}
`)); } function downloadChapterTxt(idx){ const ch=thesis.chapters?.[idx]; if(!ch){showToast('Capitolo non disponibile',true);return;} const chapterContent=getCanonicalChapterContentLocal(idx,{persist:true}) || ''; const hasChapterHeading=chapterContentHasInlineHeading(chapterContent); const title=`Capitolo ${idx+1}: ${thesis.chapterTitles?.[idx]||ch.title||''}`; downloadTextFile(safeTxtName(`Capitolo_${idx+1}`), hasChapterHeading ? chapterContent : `${title}\n\n${chapterContent}`); } function downloadDocx(){ if(!requirePlanFeature('fullExport')) return; const html=buildWordHTML(); const blob=new Blob([html],{type:'application/vnd.ms-word;charset=utf-8'}); const url=URL.createObjectURL(blob); const a=document.createElement('a');a.href=url; a.download=`AccademIA_${thesis.argomento.substring(0,30).replace(/[^a-zA-Z0-9]/g,'_')}.doc`; a.click();URL.revokeObjectURL(url);showToast('Download avviato ✓'); } function downloadFullTxt(){ if(!requirePlanFeature('fullExport')) return; downloadTextFile(safeTxtName('Tesi_completa'), buildFullPlainText()); showToast('Download testo completo avviato ✓'); } function copyWorkInProgress(){ if(!requirePlanFeature('progressiveExport')) return; copyTextValue('Lavoro completo finora', buildWorkInProgressPlainText()); } function downloadWorkInProgressTxt(){ if(!requirePlanFeature('progressiveExport')) return; downloadTextFile(safeTxtName('Lavoro_completo_finora'), buildWorkInProgressPlainText()); showToast('Download lavoro completo finora avviato ✓'); } function buildFormattedThesisDocHtml(){ const title=String(thesis.argomento||'Tesi').trim() || 'Tesi'; const pageBreakHtml='
 
'; const pageBreakSectionStyle='page-break-before: always; break-before: page; mso-page-break-before: always;'; const buildSection=(heading,content,needsPageBreak=false)=>` ${needsPageBreak ? pageBreakHtml : ''}
${heading} ${content}
`; const chapterBlocks=[]; (thesis.chapters||[]).forEach((ch,idx)=>{ const chapterContent=String(getCanonicalChapterContentLocal(idx,{persist:true}) || '').trim(); if(!chapterContent)return; const chapterTitle=String(thesis.chapterTitles?.[idx]||ch?.title||'').trim(); const heading=`

Capitolo ${idx+1}${chapterTitle?` — ${escHtml(chapterTitle)}`:''}

`; chapterBlocks.push(buildSection(heading, `
${formatChapterHtml(chapterContent)}
`, true)); }); const rawIndex=String(thesis.indice||'').trim(); const indexHtml=rawIndex ? `
${escHtml(rawIndex)}
` : `

`; const rawAbstract=String(thesis.abstract||'').trim(); const abstractHtml=rawAbstract ? `

${escHtml(rawAbstract).replace(/\n/g,'
')}

` : `

`; return ` ${buildSection('', `
${escHtml(title)}
`, false)} ${buildSection('

Indice

', indexHtml, true)} ${buildSection('

Abstract

', abstractHtml, true)} ${chapterBlocks.join('\n')} `; } function downloadFormattedThesisDoc(){ if(!requirePlanFeature('fullExport')) return; const hasContent=String(thesis.indice||'').trim() || String(thesis.abstract||'').trim() || (thesis.chapters||[]).some((_,idx)=>String(getCanonicalChapterContentLocal(idx,{persist:true}) || '').trim()); if(!hasContent){ showToast('Nessun contenuto disponibile per la bozza formattata', true); return; } downloadBlob(safeDocName('Bozza_tesi_formattata'), buildFormattedThesisDocHtml()); showToast('Download bozza tesi formattata avviato ✓'); } (function(){ const FINAL_SECTION_DEFS=[ {key:'conclusions',label:'Conclusioni',aliases:['conclusioni','conclusione']}, {key:'bibliography',label:'Bibliografia',aliases:['bibliografia','riferimenti bibliografici','bibliografia essenziale','riferimenti']}, {key:'legalReferences',label:'Riferimenti normativi',aliases:['riferimenti normativi','fonti normative','normativa','riferimenti giuridici']}, {key:'sitography',label:'Sitografia',aliases:['sitografia','webgrafia','risorse online','fonti online']} ]; function ensureFinalWorkflowState(){ if(typeof thesis==='undefined' || !thesis) return null; if(!thesis.finalSections || typeof thesis.finalSections!=='object') thesis.finalSections={}; FINAL_SECTION_DEFS.forEach(def=>{ if(typeof thesis.finalSections[def.key]!=='string') thesis.finalSections[def.key]=''; }); if(typeof thesis.finalSupervisorMaterials!=='string') thesis.finalSupervisorMaterials=''; if(!thesis.finalWorkflowState){ if(thesis.finalWorkflowState!=='generating') thesis.finalWorkflowState=hasAnyFinalSection()?'complete':'pending'; } return thesis.finalSections; } function hasAnyFinalSection(){ const fs=thesis?.finalSections||{}; return FINAL_SECTION_DEFS.some(def=>String(fs[def.key]||'').trim()); } function getChapterTextForFinal(idx){ if(typeof getCanonicalChapterContentLocal==='function'){ return String(getCanonicalChapterContentLocal(idx,{persist:true})||'').trim(); } const ch=(thesis?.chapters||[])[idx]||{}; return String(ch.content||ch.text||'').trim(); } function isChapterReadyForFinal(ch,idx){ const text=getChapterTextForFinal(idx); if(!text) return false; if(ch?.approved===true || ch?.approvedAt) return true; if(ch?.generationState==='complete' || ch?.state==='complete' || ch?.done===true) return true; return text.split(/\s+/).filter(Boolean).length>500; } function getExpectedChapterCount(){ const fromIndex=String(thesis?.indice||'').trim()?extractChapterTitles(thesis.indice):[]; if(fromIndex.length) return fromIndex.length; if(Array.isArray(thesis?.chapterTitles) && thesis.chapterTitles.length) return thesis.chapterTitles.length; if(Array.isArray(thesis?.chapters) && thesis.chapters.length) return thesis.chapters.length; const candidates=[Number(thesis?.chapterCount),Number(thesis?.numChapters),Number(thesis?.capitoli)].filter(n=>Number.isFinite(n)&&n>0); return candidates.length?candidates[0]:0; } function areChaptersReadyForFinal(){ if(typeof thesis==='undefined' || !thesis) return false; const total=getExpectedChapterCount(); if(!total) return false; const chapters=Array.isArray(thesis.chapters)?thesis.chapters:[]; for(let i=0;inormalized===alias || normalized.startsWith(alias+' ') || normalized.startsWith(alias+' —') || normalized.startsWith(alias+' -'))) return def.key; } return ''; } function splitFinalSectionsFromText(text){ const output={conclusions:'',bibliography:'',legalReferences:'',sitography:''}; const lines=String(text||'').replace(/\r/g,'').split('\n'); let current=''; for(const line of lines){ const key=detectFinalSectionKey(line); if(key){current=key;continue;} if(!current){ if(line.trim()) output.conclusions += `${line}\n`; continue; } output[current] += `${line}\n`; } Object.keys(output).forEach(k=>{output[k]=String(output[k]||'').trim();}); if(!Object.values(output).some(Boolean) && String(text||'').trim()) output.conclusions=String(text||'').trim(); return output; } function stripFinalSectionHeading(text,def){ const lines=String(text||'').replace(/\r/g,'').split('\n'); while(lines.length && !String(lines[0]||'').trim()) lines.shift(); if(lines.length && detectFinalSectionKey(lines[0])===def.key) lines.shift(); return lines.join('\n').trim(); } function normalizeSingleFinalSectionOutput(raw,def){ const parsed=splitFinalSectionsFromText(raw); const direct=String(parsed?.[def.key]||'').trim(); if(direct) return direct; return stripFinalSectionHeading(raw,def); } function looksLikeTruncatedFinalText(text){ const t=String(text||'').trim(); if(!t) return true; if(/[,:;—-]\s*$/.test(t)) return true; if(/\b(?:di|del|della|dell|che|e|o|un|una|il|la|lo|nel|nella|per|con|da|a)$/i.test(t)) return true; return false; } function validateSingleFinalSection(def,value){ const text=String(value||'').trim(); const words=countWords(text); if(!text) return {ok:false,message:`${def.label} vuota`}; if(looksLikeTruncatedFinalText(text)) return {ok:false,message:`${def.label} probabilmente troncata`}; if(def.key==='conclusions' && words<280) return {ok:false,message:'Conclusioni troppo brevi'}; if(def.key==='bibliography' && words<18) return {ok:false,message:'Bibliografia assente o troppo breve'}; if((def.key==='legalReferences' || def.key==='sitography') && words<4) return {ok:false,message:`${def.label} troppo breve`}; return {ok:true,message:''}; } function validateGeneratedFinalSections(sections){ const issues=[]; FINAL_SECTION_DEFS.forEach(def=>{ const result=validateSingleFinalSection(def,String(sections?.[def.key]||'')); if(!result.ok) issues.push(result.message); }); return {ok:issues.length===0,message:issues.join('; ')}; } function buildSingleFinalSectionPrompt(def){ const materials=String(thesis.finalSupervisorMaterials||'').trim(); const chapters=collectChaptersForFinalPrompt(); const common=[ 'TASK: thesis_final_sections', `Genera SOLO la sezione finale: # ${String(def.label||'').toUpperCase()}.`, 'Non generare altri capitoli. Non generare altre sezioni finali.', 'Usa il titolo richiesto come prima riga e poi il testo della sezione.', 'Non chiudere con frasi sospese. Non inventare fonti o dati non verificabili.', '', `TITOLO TESI: ${String(thesis.argomento||'').trim()}`, `TIPO LAUREA: ${String(typeof tipoLaureaLabel==='function'?tipoLaureaLabel(thesis.tipo):thesis.tipo||'').trim()}`, `FACOLTÀ: ${String(thesis.facolta||'').trim()}`, `CORSO: ${String(thesis.corso||'').trim()}`, `METODOLOGIA: ${String(thesis.metodologia||'').trim()}`, '', 'INDICE APPROVATO', String(thesis.indice||'').trim(), '', 'ABSTRACT APPROVATO', String(thesis.abstract||'').trim(), '', 'MATERIALI E FONTI INDICATE DAL RELATORE', materials || 'Nessun materiale aggiuntivo indicato dal relatore.', '', 'CAPITOLI GIÀ SVILUPPATI', chapters ]; const specific={ conclusions:[ 'ISTRUZIONI SPECIFICHE CONCLUSIONI', 'Scrivi conclusioni complete, argomentative e non riassuntive, tra 450 e 700 parole.', 'Valorizza risultati, limiti teorici e possibile sviluppo della ricerca.' ], bibliography:[ 'ISTRUZIONI SPECIFICHE BIBLIOGRAFIA', 'Elenca solo fonti indicate o chiaramente ricavabili: Locke, Bergson, Ricoeur, Parfit, Taylor se pertinenti al materiale.', 'Non inventare editore, anno, DOI, URL o pagine se non presenti.', 'Formato essenziale accademico, una fonte per riga.' ], legalReferences:[ 'ISTRUZIONI SPECIFICHE RIFERIMENTI NORMATIVI', 'Se la tesi non richiede riferimenti normativi, scrivi esattamente: Non pertinente per questa tesi teorico-filosofica.', 'Non inventare leggi, sentenze o articoli normativi.' ], sitography:[ 'ISTRUZIONI SPECIFICHE SITOGRAFIA', 'Se non sono state usate fonti web, scrivi esattamente: Non necessaria: le fonti usate sono bibliografiche e non sitografiche.', 'Non inventare URL.' ] }[def.key]||[]; return [...common,'',...specific].join('\n'); } function buildFinalSectionInput(def){ return { prompt:buildSingleFinalSectionPrompt(def), finalSectionKey:def.key, finalSectionLabel:def.label, thesisTitle:String(thesis.argomento||''), degreeType:thesis.tipo||'', faculty:thesis.facolta||'', course:thesis.corso||'', methodology:thesis.metodologia||'', approvedOutline:String(thesis.indice||''), approvedAbstract:String(thesis.abstract||''), chapterTitles:Array.isArray(thesis.chapterTitles)?thesis.chapterTitles:[], previousChapters:collectChaptersForFinalPrompt(), supervisorMaterials:String(thesis.finalSupervisorMaterials||''), constraints:thesis.constraints||{} }; } function finalSectionsAsPlainText(){ if(typeof thesis==='undefined' || !thesis) return ''; ensureFinalWorkflowState(); const blocks=[]; FINAL_SECTION_DEFS.forEach(def=>{ const value=String(thesis.finalSections?.[def.key]||'').trim(); if(value) blocks.push(`${def.label}\\n\\n${value}`); }); return blocks.join('\\n\\n'); } function cleanFinalSectionForExport(def,value){ let text=String(value||'').replace(/\\r/g,'').replace(/\\n/g,'\n').trim(); const lines=text.split('\n'); while(lines.length && !String(lines[0]||'').trim()) lines.shift(); while(lines.length){ const first=String(lines[0]||'').trim(); const normalized=normalizeHeadingLabel(first); const label=String(def?.label||'').trim().toLowerCase(); if(first.startsWith('#') || normalized===label || detectFinalSectionKey(first)===def.key){ lines.shift(); continue; } break; } text=lines.join('\n').replace(/\*/g,'').trim(); return text; } function paragraphizeFinalSectionHtml(def,value){ const cleaned=cleanFinalSectionForExport(def,value); if(!cleaned) return ''; const safe=typeof escHtml==='function' ? escHtml(cleaned) : cleaned.replace(/[&<>]/g,c=>({'&':'&','<':'<','>':'>'}[c])); if(def.key==='bibliography'){ const entries=safe .split(/\n+/) .map(x=>x.trim()) .filter(Boolean); return entries.map(entry=>`

${entry}

`).join(''); } return safe .split(/\n{2,}/) .map(par=>par.trim()) .filter(Boolean) .map(par=>`

${par.replace(/\n/g,'
')}

`) .join(''); } function shouldOmitFinalSectionInFormattedExport(def,value){ const cleaned=cleanFinalSectionForExport(def,value).toLowerCase().replace(/\s+/g,' ').trim(); if(!cleaned) return true; if(def.key==='legalReferences' && (cleaned.startsWith('non pertinente') || cleaned.includes('non pertinente per questa tesi'))) return true; if(def.key==='sitography' && (cleaned.startsWith('non necessaria') || cleaned.startsWith('non necessario') || cleaned.includes('fonti usate sono bibliografiche'))) return true; return false; } function finalSectionsAsHtml(){ const text=finalSectionsAsPlainText(); if(!text) return ''; const pageBreakHtml='
 
'; const blocks=[]; FINAL_SECTION_DEFS.forEach(def=>{ const value=String(thesis.finalSections?.[def.key]||'').trim(); if(shouldOmitFinalSectionInFormattedExport(def,value)) return; const bodyHtml=paragraphizeFinalSectionHtml(def,value); if(!bodyHtml) return; blocks.push(`${pageBreakHtml}

${def.label}

${bodyHtml}
`); }); return blocks.join('\n'); } function saveFinalEditorValues(){ if(typeof thesis==='undefined' || !thesis) return; ensureFinalWorkflowState(); const materials=document.getElementById('finalSupervisorMaterials'); if(materials) thesis.finalSupervisorMaterials=materials.value; FINAL_SECTION_DEFS.forEach(def=>{ const el=document.getElementById(`finalSection_${def.key}`); if(el) thesis.finalSections[def.key]=el.value; }); thesis.finalWorkflowState=hasAnyFinalSection()?'complete':'pending'; if(typeof saveProgress==='function') saveProgress(); } function countWords(text){return String(text||'').trim().split(/\s+/).filter(Boolean).length;} window.renderFinalSectionsPanel=function renderFinalSectionsPanel(){ if(typeof thesis==='undefined' || !thesis) return; ensureFinalWorkflowState(); let card=document.getElementById('finalWorkflowCard'); if(!card){ card=document.createElement('div'); card.id='finalWorkflowCard'; card.className='final-workflow-card'; const exportBar=document.querySelector('.download-bar.progressive'); const container=document.querySelector('.container'); if(exportBar?.parentNode) exportBar.parentNode.insertBefore(card, exportBar); else if(container) container.appendChild(card); else document.body.appendChild(card); } if(!planAllows('finalWorkflow')){ card.innerHTML=`
Fase finale della tesi
Conclusioni, bibliografia e riferimenti finali sono inclusi nel piano Completa o Avanzata.
Upgrade richiesto
Il lavoro già salvato resta disponibile: l'upgrade cambia solo il piano attivo.
`; return; } const ready=areChaptersReadyForFinal(); const generated=hasAnyFinalSection(); const isGenerating=thesis.finalWorkflowState==='generating'; const isError=thesis.finalWorkflowState==='error'; const status=isGenerating?'Generazione fase finale in corso':(isError?'Errore fase finale':(generated?'Fase finale generata':(ready?'Pronta per la fase finale':'In attesa dei capitoli'))); const finalError=String(thesis.finalWorkflowError||'').trim(); const finalStep=String(thesis.finalWorkflowStep||'').trim(); const progressHtml=isGenerating&&finalStep?`
⏳ ${typeof escHtml==='function'?escHtml(finalStep):finalStep}
`:''; const errorHtml=finalError?`
Errore fase finale
${typeof escHtml==='function'?escHtml(finalError):finalError}
`:''; const sectionsHtml=FINAL_SECTION_DEFS.map(def=>{ const value=String(thesis.finalSections?.[def.key]||''); const words=countWords(value); return `
`; }).join(''); card.innerHTML=`
Fase finale della tesi
Conclusioni, Bibliografia, Riferimenti normativi e Sitografia restano separati dai capitoli, come apparato finale dell’elaborato.
${status}
${ready?'I capitoli risultano sufficientemente pronti per generare la fase finale.':'La fase finale va generata dopo il completamento dei capitoli. Il campo materiali può essere compilato anche prima.'}
${progressHtml} ${errorHtml}
${sectionsHtml}
`; }; window.saveFinalEditorValues=saveFinalEditorValues; window.saveFinalSectionsManual=function saveFinalSectionsManual(){ if(!requirePlanFeature('finalWorkflow')) return; saveFinalEditorValues(); if(typeof showToast==='function') showToast('Fase finale salvata ✓'); renderFinalSectionsPanel(); }; window.clearFinalWorkflowError=function clearFinalWorkflowError(){ if(typeof thesis==='undefined' || !thesis) return; thesis.finalWorkflowError=''; if(thesis.finalWorkflowState==='error') thesis.finalWorkflowState=hasAnyFinalSection()?'complete':'pending'; if(typeof saveProgress==='function') saveProgress(); renderFinalSectionsPanel(); }; window.generateFinalSections=async function generateFinalSections(){ if(typeof thesis==='undefined' || !thesis) return; if(!requirePlanFeature('finalWorkflow')) return; ensureFinalWorkflowState(); saveFinalEditorValues(); thesis.finalWorkflowState='generating'; thesis.finalWorkflowError=''; thesis.finalWorkflowStep='Preparazione fase finale'; thesis.finalSections={conclusions:'',bibliography:'',legalReferences:'',sitography:''}; if(typeof saveProgress==='function') saveProgress(); renderFinalSectionsPanel(); try{ for(const def of FINAL_SECTION_DEFS){ thesis.finalWorkflowStep=`Generazione ${def.label}`; if(typeof saveProgress==='function') saveProgress(); renderFinalSectionsPanel(); const input=buildFinalSectionInput(def); const resp=await fetch('/api/task',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({task:'thesis_final_sections',input})}); const data=await resp.json().catch(()=>({})); if(!resp.ok) throw new Error(data?.details||data?.error||`HTTP ${resp.status}`); const raw=String(data?.text||'').trim(); if(!raw) throw new Error(`${def.label}: il provider non ha restituito testo.`); const value=normalizeSingleFinalSectionOutput(raw,def); const validation=validateSingleFinalSection(def,value); if(!validation.ok) throw new Error(validation.message); thesis.finalSections[def.key]=value; if(typeof saveProgress==='function') saveProgress(); renderFinalSectionsPanel(); } const finalValidation=validateGeneratedFinalSections(thesis.finalSections); if(!finalValidation.ok) throw new Error(`Fase finale incompleta: ${finalValidation.message}.`); thesis.finalWorkflowState='complete'; thesis.finalWorkflowStep=''; thesis.finalWorkflowError=''; thesis.finalGeneratedAt=new Date().toISOString(); if(typeof saveProgress==='function') saveProgress(); renderFinalSectionsPanel(); if(typeof showToast==='function') showToast('Fase finale generata ✓'); document.getElementById('finalWorkflowCard')?.scrollIntoView({behavior:'smooth',block:'start'}); }catch(err){ thesis.finalWorkflowState='error'; thesis.finalWorkflowStep=''; thesis.finalWorkflowError=String(err?.message||err||'Errore sconosciuto durante la fase finale.'); if(typeof saveProgress==='function') saveProgress(); renderFinalSectionsPanel(); } }; function appendFinalPlainText(base){ const finalText=finalSectionsAsPlainText(); if(!finalText) return base; return `${String(base||'').trim()}\\n\\n${finalText}`.trim(); } if(typeof buildFullPlainText==='function'){ const originalBuildFullPlainText=buildFullPlainText; buildFullPlainText=function(){return appendFinalPlainText(originalBuildFullPlainText());}; } if(typeof buildFormattedThesisDocHtml==='function'){ const originalBuildFormattedThesisDocHtml=buildFormattedThesisDocHtml; buildFormattedThesisDocHtml=function(){ const html=originalBuildFormattedThesisDocHtml(); const finalHtml=finalSectionsAsHtml(); if(!finalHtml) return html; return String(html||'').replace(' ',`${finalHtml}\\n `); }; } if(typeof buildWordHTML==='function'){ const originalBuildWordHTML=buildWordHTML; buildWordHTML=function(){ const html=originalBuildWordHTML(); const finalText=finalSectionsAsPlainText(); if(!finalText) return html; const safe=typeof escHtml==='function'?escHtml(finalText):finalText.replace(/[&<>]/g,c=>({'&':'&','<':'<','>':'>'}[c])); return `${html}
${safe}
`; }; } if(typeof renderNextChapterLauncher==='function'){ const originalRenderNextChapterLauncher=renderNextChapterLauncher; renderNextChapterLauncher=function(){ const result=originalRenderNextChapterLauncher.apply(this,arguments); try{renderFinalSectionsPanel();}catch(_){ } return result; }; } if(document.readyState==='loading'){ document.addEventListener('DOMContentLoaded',()=>setTimeout(()=>{try{renderFinalSectionsPanel();}catch(_){ }},250)); }else{ setTimeout(()=>{try{renderFinalSectionsPanel();}catch(_){ }},250); } })(); function buildWordHTML(){ const tl=tipoLaureaLabel(thesis.tipo); let b=`

${escHtml(thesis.argomento)}

${escHtml(thesis.facolta)} — ${escHtml(thesis.corso)}

${tl}




INDICE

${escHtml(thesis.indice||'')}



ABSTRACT

${escHtml(thesis.abstract||'').replace(/\n/g,'
')}


`; (thesis.chapters||[]).forEach((ch,i)=>{ const chapterContent=getCanonicalChapterContentLocal(i,{persist:true}) || ''; const hasChapterHeading=chapterContentHasInlineHeading(chapterContent); const chapterHeading=hasChapterHeading ? '' : `

CAPITOLO ${i+1}: ${escHtml(ch.title||thesis.chapterTitles?.[i]||'')}

`; b+=`
${chapterHeading}
${formatChapterHtml(chapterContent)}

`; }); return `${b} `; } function formatChapterHtml(text){ return text.split('\n').map(line=>{ line=escHtml(line); if(/^\*\*(.+)\*\*$/.test(line))return`

${line.replace(/\*\*/g,'')}

`; if(line.trim()==='')return'
'; return`

${line}

`; }).join(''); } // ══════════════════════════════════════════════ // API TASK — no search // ══════════════════════════════════════════════ function summarizePreviousChaptersForPayload(){ return (thesis.chapters||[]).map((ch,idx)=>{ const safeCh=(ch&&typeof ch==='object')?ch:{}; return { index:idx+1, title:thesis.chapterTitles?.[idx]||safeCh.title||`Capitolo ${idx+1}`, approved:!!((thesis.approvedChapters||[])[idx]), summary:String(safeCh.content||'').replace(/\s+/g,' ').trim().slice(0,900) }; }).filter(x=>x.summary); } function buildStructuredTaskInput(taskName,userPrompt,extra={}){ const argomento=(document.getElementById('argomento')?.value||thesis.argomento||'').trim(); const facolta=(document.getElementById('facolta')?.value||thesis.facolta||'').trim(); const corso=(document.getElementById('corso')?.value||thesis.corso||'').trim(); const tipo=(document.getElementById('tipoLaurea')?.value||thesis.tipo||'').trim(); const chapterTitles=Array.isArray(thesis.chapterTitles)?thesis.chapterTitles:[]; return { prompt:[userPrompt,facultyPromptGuidance(facolta,corso,metodologia||thesis.metodologia||'')].filter(Boolean).join('\n\n'), taskName, theme:argomento, faculty:facolta, degreeCourse:corso, degreeType:tipo, methodology:metodologia||thesis.metodologia||'', requestedChapters:Number(document.getElementById('numChapters')?.value||chapterTitles.length||0)||0, approvedOutline:thesis.indice||'', approvedAbstract:thesis.abstract||'', chapterTitles, approvedChapters:(thesis.chapters||[]).map((ch,i)=>((thesis.approvedChapters||[])[i]&&ch)?{title:ch.title||'',content:ch.content||''}:null).filter(Boolean), previousChapters:summarizePreviousChaptersForPayload(), currentChapterIndex:Number.isFinite(Number(extra.currentChapterIndex))?Number(extra.currentChapterIndex):(typeof thesis.currentChapterIdx==='number'?thesis.currentChapterIdx:0), currentChapterTitle:String(extra.currentChapterTitle||chapterTitles[Number.isFinite(Number(extra.currentChapterIndex))?Number(extra.currentChapterIndex):thesis.currentChapterIdx]||''), constraints:{ noInventedSources:true, noArtificialTransitions:true, preserveAcademicTone:true, preferSobriety:true, includeFootnotes: notesApparatusEnabled() }, facultyCompatibility:getFacultyCompatibility(facolta), facultyGuidance:facultyPromptGuidance(facolta,corso,metodologia||thesis.metodologia||''), syncKey: getSyncKey(), sessionToken: getAccountSessionToken(), adminKey: getAdminDashKey(), thesisGuard, licenseProfile: buildThesisProfile('thesis'), extra }; } function normalizeTitleBase(topic){ return (topic||'').replace(/\s+/g,' ').trim().replace(/[\.;:!?]+$/,''); } function methodologyLabel(v){ return ({ teorica:'teorico-critica', teorico_bibliografica:'teorico-bibliografica', caso_studio:'basata su studio di caso', revisione_sistematica:'di revisione sistematica della letteratura', comparativa:'comparativa' })[v]||''; } function methodologyFrame(v){ return ({ teorica:{study:'lettura teorico-critica', question:'quadri teorici, nodi concettuali e implicazioni interpretative'}, teorico_bibliografica:{study:'analisi teorico-bibliografica', question:'concetti, autori e implicazioni teoriche'}, caso_studio:{study:'studio di caso', question:'analisi del caso, risultati e trasferibilità delle evidenze'}, revisione_sistematica:{study:'revisione sistematica della letteratura', question:'stato dell’arte, convergenze e lacune della ricerca'}, comparativa:{study:'analisi comparativa', question:'confronto tra modelli, contesti e risultati'} })[v]||{study:'analisi accademica', question:'quadro teorico e sviluppi di ricerca'}; } function facultyTitleProfile(facolta){ const name=(facolta||'').toLowerCase(); if(name.includes('psicologia')) return {adj:'psicologici', a:'determinanti psicologiche e psicosociali', b:'ricadute su benessere, comportamento e adattamento', c:'processi cognitivi ed emotivi', d:'fattori di rischio e protezione', app:'prospettive di intervento e ricerca'}; if(name.includes('giurisprudenza')) return {adj:'giuridici', a:'profili normativi e costituzionali', b:'orientamenti giurisprudenziali e dottrinali', c:'criticità interpretative', d:'bilanciamento degli interessi coinvolti', app:'implicazioni applicative e sistematiche'}; if(name.includes('economia')) return {adj:'economico-manageriali', a:'determinanti economiche e assetti organizzativi', b:'ricadute strategiche e manageriali', c:'governance e processi decisionali', d:'performance, sostenibilità e controllo', app:'prospettive operative e manageriali'}; if(name.includes('ingegneria') || name.includes('informatica')) return {adj:'tecnico-progettuali', a:'modelli architetturali', b:'ricadute operative', c:'ottimizzazione dei processi', d:'scalabilità e affidabilità', app:'sviluppi progettuali'}; if(name.includes('medicina') || name.includes('farmacia') || name.includes('biologia') || name.includes('biotecnologie') || name.includes('veterinaria')) return {adj:'clinico-scientifici', a:'evidenze scientifiche', b:'implicazioni cliniche o assistenziali', c:'prevenzione', d:'gestione del rischio', app:'ricadute professionali'}; if(name.includes('educazione') || name.includes('formazione')) return {adj:'pedagogico-formativi', a:'processi educativi e dispositivi formativi', b:'ricadute didattiche e formative', c:'strategie pedagogiche', d:'contesti di apprendimento e inclusione', app:'prospettive educative'}; if(name.includes('comunicazione')) return {adj:'comunicativo-mediatici', a:'dinamiche comunicative e dispositivi mediali', b:'implicazioni mediatiche, sociali e strategiche', c:'narrazioni digitali e framing', d:'processi persuasivi e discorso pubblico', app:'sviluppi applicativi'}; if(name.includes('scienze politiche') || name.includes('relazioni internazionali') || name.includes('sociali') || name.includes('sociologia')) return {adj:'socio-politici', a:'dinamiche sociali, istituzionali e di policy', b:'implicazioni di governance e regolazione', c:'trasformazioni culturali e politiche', d:'politiche pubbliche, attori e conflitti', app:'sviluppi di policy e letture comparate'}; if(name.includes('lettere') || name.includes('lingue') || name.includes('filosofia') || name.includes('storia')) return {adj:'storico-critici', a:'quadri teorici e contesti storico-culturali', b:'linee interpretative e dibattito critico', c:'genealogie concettuali e testuali', d:'letture critiche e problemi storiografici', app:'prospettive ermeneutiche'}; if(name.includes('architettura') || name.includes('design') || name.includes('beni culturali') || name.includes('turismo')) return {adj:'storico-progettuali', a:'criteri progettuali e valorizzazione', b:'ricadute fruitive, culturali e operative', c:'lettura del contesto e fruizione', d:'sostenibilità e gestione', app:'sviluppi operativi'}; if(name.includes('teologia')) return {adj:'teologico-pastorali', a:'fondamenti teologici e tradizione', b:'ricadute ecclesiali e pastorali', c:'ermeneutica biblica e sistematica', d:'prassi pastorale e discernimento', app:'prospettive pastorali'}; return {adj:'disciplinari', a:'fondamenti teorici', b:'implicazioni applicative', c:'quadri interpretativi', d:'questioni aperte', app:'sviluppi di ricerca'}; } function degreeFrame(tipo){ return ({ triennale:{x:'quadro teorico, nodi principali e implicazioni applicative', y:'fondamenti teorici e sviluppi operativi'}, magistrale_2:{x:'questioni critiche, modelli interpretativi e sviluppi di ricerca', y:'evidenze, nodi problematici e prospettive di approfondimento'}, magistrale_5:{x:'assetto teorico, implicazioni professionali e profili operativi', y:'evidenze, criticità e applicazioni professionali'} })[tipo]||{x:'quadro teorico e sviluppi di ricerca', y:'implicazioni teoriche e applicative'}; } function getTitleSuggestionContext(){ const topic=(document.getElementById('argomento')?.value||'').trim(); const tipo=(document.getElementById('tipoLaurea')?.value||'').trim(); const facolta=(document.getElementById('facolta')?.value||'').trim(); const corso=(document.getElementById('corso')?.value||'').trim(); const approccio=(metodologia||'').trim(); const missing=[]; if(!tipo) missing.push('tipo di laurea'); if(!facolta) missing.push('facoltà'); if(!corso) missing.push('corso di laurea'); if(!approccio) missing.push('approccio metodologico'); if(!topic || normalizeTitleBase(topic).length<12) missing.push('argomento'); return {topic,tipo,facolta,corso,approccio,missing,ready:missing.length===0}; } function normalizeCreativeTopic(topic){ let value=normalizeTitleBase(topic) .replace(/^(indagare|analizzare|studiare|esaminare|approfondire|valutare|comprendere|osservare|esplorare)\s+/i,'') .replace(/^(su|sul|sulla|sullo|sui|sugli|sulle)\s+/i,'') .replace(/^il\s+tema\s+di\s+/i,'') .replace(/^la\s+questione\s+di\s+/i,'') .replace(/^il\s+ruolo\s+di\s+/i,'') .replace(/^l['’]analisi\s+di\s+/i,'') .trim(); value=value.replace(/\bgenerazione z\b/ig,'Generazione Z'); return value ? value.charAt(0).toUpperCase()+value.slice(1) : ''; } function normalizeCreativeComparison(value){ return normalizeTitleBase(value) .toLowerCase() .normalize('NFD').replace(/[̀-ͯ]/g,'') .replace(/[^a-z0-9\s]/gi,' ') .replace(/\s+/g,' ') .trim(); } function buildConceptualTopicVariants(base){ const variants=new Set(); const clean=normalizeCreativeTopic(base); if(!clean) return []; variants.add(clean); const replacementSets=[ [[/\bstereotipi\b/ig,'processi stereotipici'],[/\bgenerazione z\b/ig,'Generazione Z']], [[/\bstereotipi\b/ig,'rappresentazioni sociali'],[/\bgenerazione z\b/ig,'immagine della Generazione Z']], [[/\bautostima\b/ig,'percezione di sé'],[/\bsocial media\b/ig,'ambienti digitali']], [[/\bimpatto\b/ig,'ricadute'],[/\bsocial media\b/ig,'piattaforme sociali']], [[/\bintelligenza artificiale\b/ig,'IA generativa'],[/\bmercato del lavoro\b/ig,'trasformazioni del lavoro']], [[/\bprocrastinazione\b/ig,'rinvio intenzionale'],[/\bansia\b/ig,'attivazione ansiosa']] ]; replacementSets.forEach(set=>{ let candidate=clean; set.forEach(([rx,repl])=>{ candidate=candidate.replace(rx,repl); }); candidate=normalizeTitleBase(candidate); if(candidate && candidate.toLowerCase()!==clean.toLowerCase()) variants.add(candidate); }); if(/\bstereotipi\b/i.test(clean) && /\bGenerazione Z\b/i.test(clean)){ variants.add('La costruzione dell’immagine della Generazione Z'); variants.add('La Generazione Z come oggetto di rappresentazione sociale'); } return Array.from(variants).slice(0,6); } function disciplineAngles(context){ const source=`${context.facolta} ${context.corso}`.toLowerCase(); if(source.includes('psicolog')) return ['categorizzazione sociale','dinamiche identitarie','processi di attribuzione','benessere psicosociale']; if(source.includes('sociolog') || source.includes('scienze sociali')) return ['rappresentazioni collettive','dinamiche generazionali','costruzione sociale','mutamenti culturali']; if(source.includes('comunicaz')) return ['narrazioni mediatiche','immaginario collettivo','discorso pubblico','processi di framing']; if(source.includes('econom')) return ['assetti organizzativi','comportamenti di consumo','dinamiche decisionali','ricadute manageriali']; if(source.includes('giurisprud') || source.includes('diritto')) return ['qualificazione giuridica','bilanciamento degli interessi','profili applicativi','cornice normativa']; if(source.includes('educaz') || source.includes('formaz')) return ['contesti di apprendimento','processi educativi','strategie formative','ricadute pedagogiche']; if(source.includes('beni culturali') || source.includes('turismo')) return ['valorizzazione del patrimonio','fruizione culturale','sostenibilità','governance territoriale']; if(source.includes('lettere') || source.includes('lingue')) return ['analisi testuale','contesto storico-culturale','tradizione critica','problemi interpretativi']; if(source.includes('filosof')) return ['nodi concettuali','confronto tra autori','argomentazione teorica','problemi epistemologici']; if(source.includes('storia')) return ['contesto storico','problemi storiografici','periodizzazione','nessi causali']; if(source.includes('teolog')) return ['fondamenti teologici','ermeneutica','tradizione ecclesiale','ricadute pastorali']; return ['cornici teoriche','snodi concettuali','dinamiche interpretative','ricadute applicative']; } function upperFirstTitleChar(title){ if(!title) return ''; const trimmed=String(title).trim(); if(!trimmed) return ''; return trimmed.charAt(0).toUpperCase()+trimmed.slice(1); } function uniqueTitlePush(bucket,title,baseNorm){ const clean=upperFirstTitleChar(normalizeTitleBase(title)); const norm=normalizeCreativeComparison(clean); if(!clean || clean.length<18) return; if(norm===baseNorm) return; if(bucket.some(existing=>normalizeCreativeComparison(existing)===norm)) return; if(bucket.some(existing=>titleStructureFingerprint(existing)===titleStructureFingerprint(clean))) return; if(bucket.some(existing=>titleOpeningToken(existing)===titleOpeningToken(clean))) return; if(titleWordCount(clean)>16) return; bucket.push(clean); } function titleWordCount(value){ return String(value||'').trim().split(/\s+/).filter(Boolean).length; } function titleOpeningToken(value){ return normalizeCreativeComparison(String(value||'').split(/\s+/)[0]||''); } function titleStructureFingerprint(value){ return normalizeCreativeComparison(value) .replace(/\b(di|del|della|delle|dei|degli|e|tra|nel|nella|nelle|per|con|una|uno|un)\b/g,' ') .replace(/\s+/g,' ') .trim(); } function createTitleSuggestions(context){ if(!context || !context.ready) return []; const base=normalizeCreativeTopic(context.topic); if(!base || base.length<12) return []; const faculty=facultyTitleProfile(context.facolta); const course=context.corso; const angles=disciplineAngles(context); const concepts=buildConceptualTopicVariants(base); const baseNorm=normalizeCreativeComparison(base); const titles=[]; const primary=concepts[0]||base; const secondary=concepts[1]||primary; const tertiary=concepts[2]||secondary; const families=[ `Quadri teorici per ${primary}: ${angles[0]} e ${angles[1]}`, `${secondary} nelle scienze ${faculty.adj}: prospettive e modelli interpretativi`, `Limiti critici di ${tertiary}: assunti, controversie e nodi metodologici`, `${tertiary} in ${course}: evidenze empiriche e implicazioni operative`, `Governance di ${secondary}: politiche pubbliche, istituzioni e responsabilità` ]; families.forEach(title=>uniqueTitlePush(titles,title,baseNorm)); return titles.slice(0,5); } function renderTitleSuggestions(){ const wrap=document.getElementById('titleSuggestWrap'); const list=document.getElementById('titleSuggestList'); if(!wrap || !list) return; const context=getTitleSuggestionContext(); const suggestions=createTitleSuggestions(context); if(!suggestions.length){ wrap.style.display='none'; list.innerHTML=''; return; } wrap.style.display='block'; list.innerHTML=suggestions.map(title=>``).join(''); } function applySuggestedTitle(btn){ const el=document.getElementById('argomento'); if(!el || !btn) return; el.value=btn.textContent.trim(); handleArgomentoInput(); } function handleProjectStructureChange(){ if(!window.__restoringState && !isMasterOwnerLocal() && thesisGuard.stage==='locked'){ restoreLockedProfileUi(true); return; } renderTitleSuggestions(); renderCompatibilityNotice(); saveProgress(); } function handleArgomentoInput(){ if(!window.__restoringState && !isMasterOwnerLocal() && thesisGuard.stage==='locked'){ restoreLockedProfileUi(true); return; } renderTitleSuggestions(); saveProgress(); } function getAdminDashKey(){ return (sessionStorage.getItem(ADMIN_DASH_KEY_STORAGE)||'').trim(); } function setAdminDashMessage(message,isError=false){ const el=document.getElementById('adminStatsMsg'); if(!el) return; el.textContent=message||''; el.style.color=isError?'#ffb3b3':'var(--text3)'; } function renderAdminEvents(events){ const wrap=document.getElementById('adminEvents'); if(!wrap) return; if(!Array.isArray(events) || !events.length){ wrap.innerHTML='
Nessun evento recente.
'; return; } wrap.innerHTML=events.map(item=>{ const when=item?.at ? new Date(item.at).toLocaleString('it-IT') : ''; const payload=item?.payload && typeof item.payload==='object' ? Object.entries(item.payload).filter(([_,v])=>v!==undefined&&v!==null&&v!=='').map(([k,v])=>`${k}: ${String(v)}`).join(' · ') : ''; return `
${escHtml(item?.kind||'evento')}${escHtml(when)}
${escHtml(payload||'—')}
`; }).join(''); } function renderAdminStats(data){ const stats=data?.stats||{}; const counts=stats?.counts||{}; const wrap=document.getElementById('adminStatsWrap'); if(wrap) wrap.style.display='block'; const set=(id,val)=>{ const el=document.getElementById(id); if(el) el.textContent=String(val||0); }; set('adminVisitsToday', counts.visit_ping || 0); set('adminProviderOkToday', counts.provider_success || 0); set('adminTimeoutToday', counts.provider_timeout || 0); set('adminAccountToday', counts.account_verify_ok || 0); const meta=document.getElementById('adminStatsMeta'); if(meta){ const updated=stats?.updatedAt ? new Date(stats.updatedAt).toLocaleString('it-IT') : '—'; meta.textContent=`Data: ${stats?.date||'—'} · Aggiornato: ${updated}`; } renderAdminEvents(data?.events||[]); } async function refreshAdminStats(){ const key=getAdminDashKey(); if(!key){ setAdminDashMessage('Inserisci la chiave per leggere i dati interni.', true); return; } setAdminDashMessage('Caricamento dashboard interna...'); try{ const data=await apiTask('__admin_stats',{adminKey:key}); renderAdminStats(data||{}); setAdminDashMessage('Dashboard aggiornata ✓'); }catch(e){ document.getElementById('adminStatsWrap').style.display='none'; setAdminDashMessage(e?.message || 'Dashboard non disponibile', true); } } function saveAdminDashKeyAndLoad(){ const input=document.getElementById('adminDashKeyInput'); const value=(input?.value||'').trim(); if(!value){ setAdminDashMessage('Chiave dashboard mancante', true); return; } sessionStorage.setItem(ADMIN_DASH_KEY_STORAGE,value); refreshAdminStats(); } function clearAdminDashKey(){ sessionStorage.removeItem(ADMIN_DASH_KEY_STORAGE); const input=document.getElementById('adminDashKeyInput'); if(input) input.value=''; document.getElementById('adminStatsWrap').style.display='none'; setAdminDashMessage('Chiave dashboard rimossa.'); } function openAdminStats(){ const input=document.getElementById('adminDashKeyInput'); if(input && getAdminDashKey() && !input.value) input.value=getAdminDashKey(); openModal('adminStatsModal'); if(getAdminDashKey()) refreshAdminStats(); } function buildTaskErrorMessage(payload,status){ const code=(payload&&payload.code)||''; const details=(payload&& (payload.details||payload.error||payload.message)) || ''; if(code==='chapter_already_running' || status===409) return 'Generazione capitolo già in corso per questa tesi/capitolo. Attendi la chiusura corrente.'; if(code==='provider_timeout' || status===504 || /timeout/i.test(details)) return 'Timeout provider. Nessuna modifica applicata: riprova.'; return details || `HTTP ${status}`; } function getTaskTimeoutMs(taskName='outline_draft'){ const task=String(taskName||'').trim(); if(task==='outline_draft' || task==='outline_review') return 75000; if(task==='abstract_draft' || task==='abstract_review') return 90000; if(task==='chapter_draft' || task==='chapter_resume' || task==='chapter_review' || task==='revisione_capitolo') return 300000; if(task==='tutor_revision' || task==='revisione_relatore') return 210000; return 120000; } async function postTask(taskName, userPrompt, extra={}){ const controller=new AbortController(); const timeoutMs=getTaskTimeoutMs(taskName); const timer=setTimeout(()=>controller.abort(), timeoutMs); try{ const r=await fetch('/api/task',{ method:'POST', headers:{'Content-Type':'application/json'}, signal:controller.signal, body:JSON.stringify({task:taskName,input:buildStructuredTaskInput(taskName,userPrompt,extra)}) }); const d=await r.json().catch(()=>({})); if(!r.ok){throw new Error(buildTaskErrorMessage(d,r.status));} return d; }catch(err){ if(err && err.name==='AbortError') throw new Error('Timeout provider. Nessuna modifica applicata: riprova.'); throw err; }finally{ clearTimeout(timer); } } async function callClaude(userPrompt, taskName='outline_draft'){ const d=await postTask(taskName,userPrompt); return d.text||''; } // ══════════════════════════════════════════════ // API TASK — unified chapter call // ══════════════════════════════════════════════ async function callClaudeWithSearch(userPrompt, taskName='chapter_draft', extra={}){ const d=await postTask(taskName,userPrompt,extra); return { text:d.text||'', sources:[], partial:!!d.partial, partialReason:String(d.partialReason||''), sections:(d.sections && typeof d.sections==='object')?d.sections:null, generatedSectionCode:String(d.generatedSectionCode||'') }; } // ══════════════════════════════════════════════ // HELPERS // ══════════════════════════════════════════════ function tipoLaureaLabel(t){return t==='magistrale_2'?'Magistrale (2 anni post-triennale)':t==='magistrale_5'?'Magistrale a ciclo unico (5 anni)':t==='triennale'?'Triennale (3 anni)':'';} function extractChapterTitles(indice){ const lines=String(indice||'').split('\n'); const titles=[]; for(const raw of lines){ const line=String(raw||'').trim().replace(/\*\*/g,''); if(!line) continue; if(/^\d+\.\d+\b/.test(line)) continue; let m=line.match(/^Capitolo\s+(\d+)\s*[—\-:.]?\s*(.*)$/i); if(m){ const title=String(m[2]||'').trim(); titles.push(title || `Capitolo ${m[1]}`); continue; } m=line.match(/^(\d+)\s*[.)]\s+(.+)$/); if(m){ titles.push(String(m[2]||'').trim() || `Capitolo ${m[1]}`); } } return titles.length>0?titles:['Capitolo 1','Capitolo 2','Capitolo 3']; } function streamText(elId,text,onDone){ const el=document.getElementById(elId); if(!el){if(onDone) onDone();return;} const safeText=String(text||''); if(el._streamTimer){clearInterval(el._streamTimer);el._streamTimer=null;} el.textContent=''; if(!safeText){if(onDone) onDone();return;} let i=0; const step=Math.max(1,Math.floor(safeText.length/280)); const iv=setInterval(()=>{ i=Math.min(i+step,safeText.length); el.textContent=safeText.substring(0,i); if(i>=safeText.length){ clearInterval(iv); el._streamTimer=null; if(onDone) onDone(); } },8); el._streamTimer=iv; } function resetIndiceUiAfterFailure(message='Generazione indice interrotta. Riprova.') { const output=document.getElementById('indiceOutput'); const chip=document.getElementById('indiceChip'); const approval=document.getElementById('indiceApproval'); const textEl=document.getElementById('indiceText'); if(output) output.classList.remove('typing'); if(chip){chip.className='status-chip error';chip.innerHTML='✕ Interrotta';} if(approval) approval.style.display='none'; if(textEl && !String(textEl.textContent||'').trim()) textEl.textContent=message; syncPrimaryOutputButtons(); setPhaseButtonBusy('btnStep1',false); updateStep1ButtonState(); } function resetAbstractUiAfterFailure(message='Generazione abstract interrotta. Riprova.'){ const output=document.getElementById('abstractOutput'); const chip=document.getElementById('abstractChip'); const approval=document.getElementById('abstractApproval'); const textEl=document.getElementById('abstractText'); if(output) output.classList.remove('typing'); if(chip){chip.className='status-chip error';chip.innerHTML='✕ Interrotto';} if(approval) approval.style.display='none'; if(textEl && !String(textEl.textContent||'').trim()) textEl.textContent=message; const next=document.getElementById('nextAbstract'); if(next && isIndexApprovedState()) next.classList.add('visible'); syncPrimaryOutputButtons(); setPhaseButtonBusy('btnAbstractAction',false); updateAbstractButtonState(); } function updateWordCount(){const t=[thesis.indice,thesis.abstract,...(thesis.chapters||[]).map(c=>((c&&typeof c==='object')?c.content:'')||'')].join(' ').split(/\s+/).filter(Boolean).length;document.getElementById('wordCount').textContent=t.toLocaleString('it-IT');} function now(){return new Date().toLocaleTimeString('it-IT',{hour:'2-digit',minute:'2-digit'});} function escHtml(t){return(t||'').replace(/&/g,'&').replace(//g,'>');} function showToast(msg,error=false){const t=document.getElementById('toast');t.textContent=msg;t.className='toast show'+(error?' error':'');clearTimeout(t._timer);t._timer=setTimeout(()=>t.className='toast',14000);} function openModal(id){document.getElementById(id).classList.add('open');} function closeModal(id){document.getElementById(id).classList.remove('open');} document.addEventListener('keydown',e=>{ if(e.ctrlKey && e.shiftKey && (e.key==='A' || e.key==='a')){ e.preventDefault(); openAdminStats(); } }); document.querySelectorAll('.modal-overlay').forEach(o=>o.addEventListener('click',e=>{if(e.target===o)o.classList.remove('open');})); (function(){ if(window.__accademiaExportCleanupPatch) return; window.__accademiaExportCleanupPatch=true; function exportEsc(text){ return typeof escHtml==='function' ? escHtml(text) : String(text||'').replace(/[&<>]/g,c=>({'&':'&','<':'<','>':'>'}[c])); } function getIndexChapterTitleForExport(idx){ try{ const titles=typeof extractChapterTitles==='function' ? extractChapterTitles(String(thesis?.indice||'')) : []; const title=String(titles?.[idx]||'').trim(); if(!title) return ''; if(new RegExp('^capitolo\\s+'+(idx+1)+'$','i').test(title)) return ''; return title; }catch(_){ return ''; } } if(typeof buildFormattedThesisDocHtml==='function'){ const previousBuildFormattedThesisDocHtml=buildFormattedThesisDocHtml; buildFormattedThesisDocHtml=function(){ let html=String(previousBuildFormattedThesisDocHtml.apply(this,arguments)||''); const total=Math.max( Array.isArray(thesis?.chapterTitles)?thesis.chapterTitles.length:0, Array.isArray(thesis?.chapters)?thesis.chapters.length:0, 1 ); for(let i=0;iCapitolo ${n}\\s*[—-]\\s*Capitolo ${n}`,'g'),`

Capitolo ${n} — ${safeTitle}

`); html=html.replace(new RegExp(`

Capitolo ${n}\\s*[—-]\\s*Capitolo ${n}


`,'g'),''); html=html.replace(new RegExp(`]*>Capitolo ${n}\\s*[—-]\\s*Capitolo ${n}


`,'g'),''); } } html=html.replace(/\\n/g,''); return html; }; } })(); (function(){ if(window.__accademiaRemoveDuplicateChapterLeadPatch) return; window.__accademiaRemoveDuplicateChapterLeadPatch=true; function escapeRegexText(text){ return String(text||'').replace(/[.*+?^${}()|[\]\\]/g,'\\$&'); } function htmlTextToPattern(text){ const escaped=escapeRegexText(String(text||'').trim()); return escaped.replace(/\s+/g,'\\s+'); } function getExportChapterTitleFromIndex(idx){ try{ const titles=typeof extractChapterTitles==='function' ? extractChapterTitles(String(thesis?.indice||'')) : []; return String(titles?.[idx]||'').trim(); }catch(_){ return ''; } } if(typeof buildFormattedThesisDocHtml==='function'){ const previousBuildFormattedThesisDocHtmlForDuplicateLead=buildFormattedThesisDocHtml; buildFormattedThesisDocHtml=function(){ let html=String(previousBuildFormattedThesisDocHtmlForDuplicateLead.apply(this,arguments)||''); const chapters=Array.isArray(thesis?.chapters)?thesis.chapters:[]; chapters.forEach((_,idx)=>{ const n=idx+1; const title=getExportChapterTitleFromIndex(idx); if(!title) return; const fullTitle=`Capitolo ${n} — ${title}`; const titlePattern=htmlTextToPattern(fullTitle); const duplicateParagraph=new RegExp(`]*>\\s*${titlePattern}\\s*

\\s*(?:)?`,'i'); html=html.replace(duplicateParagraph,''); }); return html; }; } })();