Nessun oggetto della modifica
Etichetta: Ripristino manuale
Nessun oggetto della modifica
Riga 6: Riga 6:
   <button onclick="clearServerLog()">🧹 Svuota Log</button>
   <button onclick="clearServerLog()">🧹 Svuota Log</button>


  <!-- 🔘 Pulsanti -->
   <div style="margin: 2rem 0; display: flex; flex-wrap: wrap; gap: 1rem;">
   <div style="margin: 2rem 0; display: flex; flex-wrap: wrap; gap: 1rem;">
     <button class="dashboard-toggle" onclick="toggleDashboardBox('api-settings')">⚙️ Connessione API</button>
     <button class="dashboard-toggle" onclick="toggleDashboardBox('api-settings')">⚙️ Connessione API</button>
 
 
  <button class="dashboard-toggle"
  onclick="(window.showMpAI ? showMpAI() : (function(){var el=document.getElementById('mpAI'); if(el){ el.style.display='block'; el.scrollIntoView({behavior:'smooth'});} else { alert('#mpAI non trovato'); } })())">
  🤖 Masticationpedia AI
</button>
<script>
  // Definito presto, prima di altri script
  function showMpAI(){
    // nascondi eventuali box legacy
    ['api-settings','project-status','chatgpt-plus','test-tools','activity-log']
      .forEach(function(id){ var el=document.getElementById(id); if(el) el.style.display='none'; });
    // mostra la UI AI
    var ai = document.getElementById('mpAI');
    if (ai){ ai.style.display='block'; ai.scrollIntoView({behavior:'smooth'}); }
    else { alert('Elemento #mpAI non trovato'); }
  }
</script>


    <button class="dashboard-toggle"
      onclick="(window.showMpAI ? showMpAI() : (function(){var el=document.getElementById('mpAI'); if(el){ el.style.display='block'; el.scrollIntoView({behavior:'smooth'});} else { alert('#mpAI non trovato'); } })())">
      🤖 Masticationpedia AI
    </button>
   </div>
   </div>


   <!-- ============== MASTICATIONPEDIA AI (schermata unica) ============== -->
   <!-- ============== MASTICATIONPEDIA AI ============== -->
   <div id="mpAI" class="mpai-root" style="display:none">
   <div id="mpAI" class="mpai-root" style="display:none">
    <!-- Header -->
     <div class="mpai-header">
     <div class="mpai-header">
       <div class="mpai-title">🤖 Masticationpedia <b>AI</b></div>
       <div class="mpai-title">🤖 Masticationpedia <b>AI</b></div>
Riga 44: Riga 27:


     <div class="mpai-grid">
     <div class="mpai-grid">
      <!-- Sidebar sinistra: Progetti -->
       <aside class="mpai-col mpai-left">
       <aside class="mpai-col mpai-left">
         <h4>📂 Progetti</h4>
         <h4>📂 Progetti</h4>
Riga 59: Riga 41:
       </aside>
       </aside>


      <!-- Chat centrale -->
       <main class="mpai-col mpai-center">
       <main class="mpai-col mpai-center">
        <!-- Allegati (solo elenco locale per ora) -->
         <div id="mpai-uploads" class="mpai-uploads" data-state="idle">
         <div id="mpai-uploads" class="mpai-uploads" data-state="idle">
           <div class="mpai-dropzone" id="mpai-dropzone">
           <div class="mpai-dropzone" id="mpai-dropzone">
Riga 75: Riga 55:
         </div>
         </div>


        <!-- Messaggi -->
         <div id="mpai-chat" class="mpai-chat">
         <div id="mpai-chat" class="mpai-chat">
           <div class="mpai-msg mpai-hint">
           <div class="mpai-msg mpai-hint">
Riga 82: Riga 61:
         </div>
         </div>


        <!-- Prompt -->
         <div class="mpai-composer">
         <div class="mpai-composer">
           <textarea id="mpai-input" rows="3" placeholder="Scrivi qui la tua domanda..."></textarea>
           <textarea id="mpai-input" rows="3" placeholder="Scrivi qui la tua domanda..."></textarea>
Riga 89: Riga 67:
       </main>
       </main>


      <!-- Sidebar destra: Impostazioni -->
       <aside class="mpai-col mpai-right">
       <aside class="mpai-col mpai-right">
         <h4>⚙️ Impostazioni</h4>
         <h4>⚙️ Impostazioni</h4>
Riga 114: Riga 91:
   <!-- ============ STILI (CSS) ============ -->
   <!-- ============ STILI (CSS) ============ -->
   <style>
   <style>
     .mpai-root{--bg:#f7f8fa;--card:#fff;--muted:#6b7280;--line:#e5e7eb;--text:#111827;
     .mpai-root{--bg:#f7f8fa;--card:#fff;--muted:#6b7280;--line:#e5e7eb;--text:#111827;--primary:#0a7cff;--danger:#e74c3c;--accent:#eef2ff;font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;color:var(--text)}
      --primary:#0a7cff;--danger:#e74c3c;--accent:#eef2ff;
      font-family: system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif; color:var(--text);}
     .mpai-header{display:flex;align-items:center;justify-content:space-between;margin:8px 0 12px}
     .mpai-header{display:flex;align-items:center;justify-content:space-between;margin:8px 0 12px}
     .mpai-title{font-size:20px;font-weight:700}
     .mpai-title{font-size:20px;font-weight:700}
Riga 152: Riga 127:
     .mpai-composer{display:flex;gap:8px;align-items:flex-end}
     .mpai-composer{display:flex;gap:8px;align-items:flex-end}
     .mpai-composer textarea{flex:1 1 auto;min-height:90px;border:1px solid var(--line);border-radius:12px;padding:10px}
     .mpai-composer textarea{flex:1 1 auto;min-height:90px;border:1px solid var(--line);border-radius:12px;padding:10px}
     @media (max-width: 1100px){
     @media (max-width:1100px){.mpai-grid{grid-template-columns:1fr}.mpai-left,.mpai-right{max-height:none}}
      .mpai-grid{grid-template-columns:1fr}
      .mpai-left,.mpai-right{max-height:none}
    }
   </style>
   </style>


   <!-- ============ JS (tutto qui) ============ -->
   <!-- ============ JS (tutto qui) ============ -->
   <script>
   <script>
     // ---- Funzioni base / legacy ----
     // --- utility legacy ---
     function toggleDashboardBox(id){
     function toggleDashboardBox(id){
       var el = document.getElementById(id);
       var el=document.getElementById(id); if(!el) return;
      if (!el) return;
       var ai=document.getElementById('mpAI'); if(ai) ai.style.display='none';
       var ai = document.getElementById('mpAI'); if (ai) ai.style.display='none';
       el.style.display=(el.style.display==='none'||!el.style.display)?'block':'none';
       el.style.display = (el.style.display === 'none' || !el.style.display) ? 'block' : 'none';
     }
     }
     async function clearServerLog(){
     async function clearServerLog(){
       try{
       try{
         const r = await fetch('/dashboard/api/log_clear.php',{method:'POST',credentials:'include'});
         const r=await fetch('/dashboard/api/log_clear.php',{method:'POST',credentials:'include'});
         const j = await r.json().catch(()=>({ok:false}));
         const j=await r.json().catch(()=>({ok:false}));
         alert(j && j.ok ? 'Log svuotato.' : 'Impossibile svuotare il log.');
         alert(j && j.ok ? 'Log svuotato.' : 'Impossibile svuotare il log.');
       }catch(e){ alert('Errore rete: '+e.message); }
       }catch(e){ alert('Errore rete: '+e.message); }
     }
     }
    function uploadToOpenAI(){ alert('Prossimo step: upload verso OpenAI.'); }
     function showMpAI(){
     function showMpAI(){
       ['api-settings','project-status','chatgpt-plus','test-tools','activity-log']
       ['api-settings','project-status','chatgpt-plus','test-tools','activity-log'].forEach(id=>{
        .forEach(id => { var el = document.getElementById(id); if (el) el.style.display='none'; });
        var el=document.getElementById(id); if(el) el.style.display='none';
       var ai = document.getElementById('mpAI');
      });
      if (ai) ai.style.display = 'block';
       var ai=document.getElementById('mpAI'); if(ai) ai.style.display='block';
     }
     }


Riga 185: Riga 155:
     (function(){
     (function(){
       // Stato
       // Stato
       let currentProject = null;    // progetto “reale” (server) o null
       let currentProject=null, sessionId=null, sessionMeta=null;
      let sessionId = null;          // id bozza locale se non c'è progetto
       let history=[], attachments=[];
      let sessionMeta = null;       // {title, updated}
       let history = [];
      let attachments = [];


       // Shortcuts
       // Shortcuts
Riga 196: Riga 163:
       const fileListEl = $('#mpai-file-list');
       const fileListEl = $('#mpai-file-list');


       // UI helpers
       // UI
       function appendMsg(role, content){
       function appendMsg(role, content){
         const div = document.createElement('div');
         const div=document.createElement('div');
         div.className = 'mpai-msg ' + (role === 'user' ? 'user' : (role === 'assistant' ? 'assistant' : 'error'));
         div.className='mpai-msg '+(role==='user'?'user':role==='assistant'?'assistant':'error');
         div.innerHTML = '<div class="role">'+(role==='user'?'Tu':role==='assistant'?'GPT':'Errore')+'</div>'
         div.innerHTML='<div class="role">'+(role==='user'?'Tu':role==='assistant'?'GPT':'Errore')+'</div>'
                      + '<div class="content" style="white-space:pre-wrap">'+content+'</div>';
                    + '<div class="content" style="white-space:pre-wrap">'+content+'</div>';
         chatEl.appendChild(div);
         chatEl.appendChild(div); chatEl.scrollTop=chatEl.scrollHeight;
        chatEl.scrollTop = chatEl.scrollHeight;
      }
      function saveLocal(){
        if (!currentProject) return;
        localStorage.setItem('mpai.hist.'+currentProject, JSON.stringify(history.slice(-200)));
       }
       }
      function saveLocal(){ if(!currentProject) return; localStorage.setItem('mpai.hist.'+currentProject, JSON.stringify(history.slice(-200))); }
       function loadLocal(project){
       function loadLocal(project){
         const raw = localStorage.getItem('mpai.hist.'+project);
         const raw=localStorage.getItem('mpai.hist.'+project);
         history = raw ? JSON.parse(raw) : [];
         history = raw?JSON.parse(raw):[];
         chatEl.innerHTML = '';
         chatEl.innerHTML='';
         if (!history.length){
         if(!history.length){ appendMsg('assistant','Pronto! Dimmi cosa vuoi fare su "'+project+'". Allegami anche file sanificati se servono.'); }
          appendMsg('assistant', 'Pronto! Dimmi cosa vuoi fare su "'+project+'". Allegami anche file sanificati se servono.');
         else { history.forEach(m=>appendMsg(m.role,m.content)); }
         } else {
          history.forEach(m => appendMsg(m.role, m.content));
        }
       }
       }
       function renderFiles(){
       function renderFiles(){
         fileListEl.innerHTML = '';
         fileListEl.innerHTML='';
         attachments.forEach((a,i)=>{
         attachments.forEach((a,i)=>{
           const pill = document.createElement('span');
           const pill=document.createElement('span');
           pill.className = 'mpai-filepill';
           pill.className='mpai-filepill';
           pill.innerHTML = '<span title="Allegato">'+a.name+'</span><button title="Rimuovi">✕</button>';
           pill.innerHTML='<span title="Allegato">'+a.name+'</span><button title="Rimuovi">✕</button>';
           pill.querySelector('button').onclick = ()=>{ attachments.splice(i,1); renderFiles(); };
           pill.querySelector('button').onclick=()=>{ attachments.splice(i,1); renderFiles(); };
           fileListEl.appendChild(pill);
           fileListEl.appendChild(pill);
         });
         });
       }
       }


       // ======== Sessioni locali (bozze senza progetto) ========
       // Sessioni locali
       function ensureSession(){
       function ensureSession(){
         if (!sessionId){
         if(!sessionId){
           sessionId = 'sess-' + Date.now();
           sessionId='sess-'+Date.now();
           sessionMeta = { title: 'Nuova conversazione', updated: Date.now() };
           sessionMeta={title:'Nuova conversazione',updated:Date.now()};
           localStorage.setItem('mpai.session.meta.'+sessionId, JSON.stringify(sessionMeta));
           localStorage.setItem('mpai.session.meta.'+sessionId, JSON.stringify(sessionMeta));
         }
         }
       }
       }
       function saveSession(){
       function saveSession(){
         if (!sessionId) return;
         if(!sessionId) return;
         const key = 'mpai.session.hist.' + sessionId;
         localStorage.setItem('mpai.session.hist.'+sessionId, JSON.stringify(history.slice(-200)));
        localStorage.setItem(key, JSON.stringify(history.slice(-200)));
         sessionMeta.updated=Date.now();
         sessionMeta.updated = Date.now();
         localStorage.setItem('mpai.session.meta.'+sessionId, JSON.stringify(sessionMeta));
         localStorage.setItem('mpai.session.meta.'+sessionId, JSON.stringify(sessionMeta));
       }
       }
       function loadSession(id){
       function loadSession(id){
         sessionId = id;
         sessionId=id;
         const key = 'mpai.session.hist.' + id;
         const raw=localStorage.getItem('mpai.session.hist.'+id);
        const raw = localStorage.getItem(key);
         history=raw?JSON.parse(raw):[];
         history = raw ? JSON.parse(raw) : [];
         const metaRaw=localStorage.getItem('mpai.session.meta.'+id);
         const metaRaw = localStorage.getItem('mpai.session.meta.'+id);
         sessionMeta=metaRaw?JSON.parse(metaRaw):{title:'Nuova conversazione',updated:Date.now()};
         sessionMeta = metaRaw ? JSON.parse(metaRaw) : {title:'Nuova conversazione', updated:Date.now()};
         chatEl.innerHTML='';
         chatEl.innerHTML = '';
         if(!history.length){ appendMsg('assistant','Pronto! Dimmi cosa vuoi fare. Puoi allegare file sanificati.'); }
         if (!history.length){
         else { history.forEach(m=>appendMsg(m.role,m.content)); }
          appendMsg('assistant', 'Pronto! Dimmi cosa vuoi fare. Puoi allegare file sanificati.');
         } else {
          history.forEach(m => appendMsg(m.role, m.content));
        }
       }
       }
       function resetToNewChat(){
       function resetToNewChat(){
         history = [];
         history=[]; attachments=[]; renderFiles(); chatEl.innerHTML='';
        attachments = [];
         if(currentProject){ appendMsg('assistant','Nuova chat per "'+currentProject+'".'); saveLocal(); }
        renderFiles();
         else { sessionId=null; sessionMeta=null; ensureSession(); appendMsg('assistant','Nuova conversazione.'); saveSession(); }
        chatEl.innerHTML = '';
         if (currentProject){
          appendMsg('assistant','Nuova chat per "'+currentProject+'".');
          saveLocal();
         } else {
          sessionId = null; sessionMeta = null;
          ensureSession();
          appendMsg('assistant','Nuova conversazione.');
          saveSession();
        }
       }
       }


       // ======== Progetti (sinistra) ========
       // Progetti
       async function loadProjects(){
       async function loadProjects(){
         const box = $('#mpai-project-list');
         const box=$('#mpai-project-list');
         box.innerHTML = '<em class="muted">Carico progetti…</em>';
         box.innerHTML='<em class="muted">Carico progetti…</em>';
         try{
         try{
           const r = await fetch('/dashboard/api/project_list.php', {cache:'no-store', credentials:'include'});
           const r=await fetch('/dashboard/api/project_list.php',{cache:'no-store',credentials:'include'});
           const j = await r.json();
           const j=await r.json();
           const arr = Array.isArray(j) ? j : (Array.isArray(j.projects) ? j.projects : []);
           const arr=Array.isArray(j)?j:(Array.isArray(j.projects)?j.projects:[]);
           if (!arr.length){ box.innerHTML='<em class="muted">Nessun progetto</em>'; return; }
           if(!arr.length){ box.innerHTML='<em class="muted">Nessun progetto</em>'; return; }
           box.innerHTML='';
           box.innerHTML='';
           arr.forEach(item=>{
           arr.forEach(item=>{
             const name = (typeof item === 'string') ? item : (item.name || item);
             const name=(typeof item==='string')?item:(item.name||item);
             const row = document.createElement('div');
             const row=document.createElement('div');
             row.className = 'row';
             row.className='row';
             row.innerHTML = '<span class="title">'+name+'</span>'
             row.innerHTML='<span class="title">'+name+'</span><span><button class="mpai-btn" data-open="'+name+'">Apri</button></span>';
                          + '<span><button class="mpai-btn" data-open="'+name+'">Apri</button></span>';
             row.querySelector('[data-open]').onclick=()=>{ currentProject=name; loadLocal(name); };
             row.querySelector('[data-open]').onclick = ()=>{ currentProject=name; loadLocal(name); };
             box.appendChild(row);
             box.appendChild(row);
           });
           });
           if (!currentProject){
           if(!currentProject){ currentProject=(typeof arr[0]==='string')?arr[0]:(arr[0].name||arr[0]); loadLocal(currentProject); }
            const first = (typeof arr[0]==='string')?arr[0]:(arr[0].name||arr[0]);
         }catch(e){ box.innerHTML='<span class="muted">Errore caricamento: '+e.message+'</span>'; }
            currentProject = first;
            loadLocal(first);
          }
         }catch(e){
          box.innerHTML = '<span class="muted">Errore caricamento: '+e.message+'</span>';
        }
       }
       }
       async function createProject(){
       async function createProject(){
         const inp = $('#mpai-project-name');
         const inp=$('#mpai-project-name');
         const name = (inp.value||'').trim();
         const name=(inp.value||'').trim();
         if (!name){ alert('Inserisci un nome progetto'); return; }
         if(!name){ alert('Inserisci un nome progetto'); return; }
         try{
         try{
           const r = await fetch('/dashboard/api/project_create.php', {
           const r=await fetch('/dashboard/api/project_create.php',{method:'POST',headers:{'Content-Type':'application/json'},credentials:'include',body:JSON.stringify({name})});
            method:'POST',
           const txt=await r.text(); let j; try{ j=JSON.parse(txt); }catch{ j={ok:false,raw:txt}; }
            headers:{'Content-Type':'application/json'},
           if(j.ok!==false){ await loadProjects(); currentProject=name; history=[]; loadLocal(name); inp.value=''; }
            credentials:'include',
            body: JSON.stringify({name})
          });
           const txt = await r.text(); let j; try{ j=JSON.parse(txt) }catch{ j={ok:false,raw:txt}; }
           if (j.ok!==false){ await loadProjects(); currentProject=name; history=[]; loadLocal(name); inp.value=''; }
           else { alert('Errore creazione: '+(j.error||'')); }
           else { alert('Errore creazione: '+(j.error||'')); }
         }catch(e){ alert('Errore rete: '+e.message); }
         }catch(e){ alert('Errore rete: '+e.message); }
       }
       }


       // ======== Upload locale (solo elenco) ========
       // Upload (solo elenco locale)
       const dz = $('#mpai-dropzone');
       const dz=$('#mpai-dropzone'), fi=$('#mpai-file-input');
      const fi = $('#mpai-file-input');
       dz.addEventListener('dragover',e=>{ e.preventDefault(); dz.style.opacity=.85; });
       dz.addEventListener('dragover', e => { e.preventDefault(); dz.style.opacity = .85; });
       dz.addEventListener('dragleave',()=>{ dz.style.opacity=1; });
       dz.addEventListener('dragleave', () => { dz.style.opacity = 1; });
       dz.addEventListener('drop',e=>{
       dz.addEventListener('drop', e => {
         e.preventDefault(); dz.style.opacity=1;
         e.preventDefault(); dz.style.opacity = 1;
         Array.from(e.dataTransfer.files||[]).forEach(f=>attachments.push({file:f,name:f.name}));
         Array.from(e.dataTransfer.files||[]).forEach(f=> attachments.push({file:f,name:f.name}));
         renderFiles();
         renderFiles();
       });
       });
       fi.addEventListener('change', () => {
       fi.addEventListener('change',()=>{
         Array.from(fi.files||[]).forEach(f=> attachments.push({file:f,name:f.name}));
         Array.from(fi.files||[]).forEach(f=>attachments.push({file:f,name:f.name}));
         fi.value=''; renderFiles();
         fi.value=''; renderFiles();
       });
       });


       // ======== Invio prompt via proxy sicuro ========
       // Invio prompt (PROXY)
       <script>
       async function sendPrompt(){
// --- PATCH: sendPrompt con errori visibili ---
        const ta=$('#mpai-input');
async function sendPrompt(){
        const model=($('#mpai-model')?.value||'gpt-4o-2024-05-13').trim();
  const ta = document.querySelector('#mpai-input');
        const temp=parseFloat($('#mpai-temp')?.value||'0.7')||0.7;
  const model = (document.querySelector('#mpai-model')?.value || 'gpt-4o-2024-05-13').trim();
        const sanitizedOnly=$('#mpai-sanitized-only')?.checked;
  const temp = parseFloat(document.querySelector('#mpai-temp')?.value || '0.7') || 0.7;
  const sanitizedOnly = !!(document.querySelector('#mpai-sanitized-only')?.checked);


  const content = (ta.value || '').trim();
        const content=(ta.value||'').trim();
  if (!content){ ta.focus(); return; }
        if(!content){ ta.focus(); return; }


  // Se non c'è un progetto, usa la bozza locale
        if(!currentProject && !sessionId){ ensureSession(); loadSession(sessionId); }
  if (!window.currentProject && !window.sessionId){  
    ensureSession();
    loadSession(sessionId);
  }


  // Messaggio utente
        history.push({role:'user',content}); appendMsg('user',content); ta.value='';
  history.push({role:'user', content});
  appendMsg('user', content);
  ta.value = '';


  // Contesto
        const contextName = currentProject ? `Progetto: ${currentProject}` : `Sessione: ${sessionMeta?.title||'Nuova conversazione'}`;
  const contextName = (window.currentProject)
        const fileNames = attachments.map(a=>a.name).join(', ');
    ? `Progetto: ${window.currentProject}`
        const preface = `${contextName}
    : `Sessione: ${window.sessionMeta?.title || 'Nuova conversazione'}`;
File allegati${sanitizedOnly?' (sanificati)':''}: ${fileNames||'nessuno'}
 
  const fileNames = attachments.map(a => a.name).join(', ');
  const preface = `${contextName}
File allegati${sanitizedOnly ? ' (sanificati)' : ''}: ${fileNames || 'nessuno'}


Istruzioni: rispondi in ITALIANO, struttura chiara (titoli, punti elenco), sii operativo. Temperatura: ${temp}.
Istruzioni: rispondi in ITALIANO, struttura chiara (titoli, punti elenco), sii operativo. Temperatura: ${temp}.
Riga 372: Riga 291:
${content}`;
${content}`;


  // Placeholder
        const pending=document.createElement('div');
  const pending = document.createElement('div');
        pending.className='mpai-msg';
  pending.className = 'mpai-msg';
        pending.innerHTML='<em class="muted">Elaboro…</em>';
  pending.innerHTML = '<em class="muted">Elaboro…</em>';
        chatEl.appendChild(pending); chatEl.scrollTop=chatEl.scrollHeight;
  document.querySelector('#mpai-chat').appendChild(pending);


  try{
        try{
    const r = await fetch('/dashboard/api/openai_project_gpt.php', {
          const r=await fetch('/dashboard/api/openai_project_gpt.php',{
      method: 'POST',
            method:'POST',
      headers: { 'Content-Type': 'application/json' },
            headers:{'Content-Type':'application/json'},
      credentials: 'include',     // manda i cookie/credenziali per Basic Auth
            credentials:'include',
      mode: 'same-origin',
            cache:'no-store',
      cache: 'no-store',
            body:JSON.stringify({model,prompt:preface})
      body: JSON.stringify({ model, prompt: preface })
          });
    });
          const raw=await r.text();
 
          if(!r.ok){ pending.remove(); appendMsg('error',`HTTP ${r.status} ${r.statusText}\n\n${raw||'(nessun body)'}`); return; }
    const raw = await r.text();
          let j; try{ j=JSON.parse(raw); }catch(e){ pending.remove(); appendMsg('error','Risposta non in JSON:\n\n'+raw.slice(0,1500)); return; }
 
          pending.remove();
    // se non è 2xx, mostra status + body grezzo
          if(j.status==='ok' && j.result){
    if (!r.ok){
            if(!currentProject && sessionMeta && sessionMeta.title==='Nuova conversazione'){ sessionMeta.title=(content.slice(0,48)||'Nuova conversazione'); saveSession(); }
      pending.remove();
            history.push({role:'assistant',content:j.result}); appendMsg('assistant',j.result); saveLocal();
      console.error('GPT proxy error', r.status, r.statusText, raw);
          }else{
      appendMsg('error', `HTTP ${r.status} ${r.statusText}\n\n${raw || '(nessun body)'}`);
            const err=j.error||'Errore sconosciuto';
      return;
            appendMsg('error',`API error: ${err}\n\nRAW:\n${(j.raw||'').slice(0,1500)}`);
    }
          }
 
         }catch(e){ pending.remove(); appendMsg('error','Errore di rete/JS: '+e.message); }
    // prova a parse-are il JSON
    let j;
    try { j = JSON.parse(raw); }
    catch(parseErr){
      pending.remove();
      console.error('JSON parse error', parseErr, raw);
      appendMsg('error', `Risposta non in JSON:\n\n${raw.slice(0,1500)}`);
      return;
    }
 
    pending.remove();
 
    if (j.status === 'ok' && j.result){
      // aggiorna titolo bozza alla prima risposta
      if (!window.currentProject && window.sessionMeta && window.sessionMeta.title === 'Nuova conversazione'){
        window.sessionMeta.title = (content.slice(0,48) || 'Nuova conversazione');
         saveSession && saveSession();
       }
       }
      history.push({role:'assistant', content: j.result});
      appendMsg('assistant', j.result);
      saveLocal && saveLocal();
    } else {
      console.error('API said error', j);
      const err = j.error || 'Errore sconosciuto';
      appendMsg('error', `API error: ${err}\n\nRAW:\n${(j.raw||'').slice(0,1500)}`);
    }
  } catch(e){
    pending.remove();
    console.error('Network/JS error', e);
    appendMsg('error', `Errore di rete/JS: ${e.message}`);
  }
}
</script>


      // Bind
      document.addEventListener('click',e=>{
        if(e.target && e.target.id==='mpai-send') sendPrompt();
        if(e.target && e.target.id==='mpai-project-create') createProject();
        if(e.target && e.target.id==='mpai-new-chat') resetToNewChat();
        if(e.target && e.target.id==='mpai-clear'){
          if(!currentProject && !sessionId){ ensureSession(); loadSession(sessionId); }
          if(!confirm('Svuotare la conversazione locale?')) return;
          resetToNewChat();
        }
      });
      document.addEventListener('keydown',e=>{
        if((e.metaKey||e.ctrlKey) && e.key==='Enter'){ const ta=$('#mpai-input'); if(ta && ta===document.activeElement){ e.preventDefault(); sendPrompt(); } }
      });


  <!-- ========== SEZIONI LEGACY (nascoste di default) ========== -->
      // Boot
      loadProjects();
      if(!currentProject){ ensureSession(); loadSession(sessionId); }
    })();
  </script>


   <!-- 📦 Connessione API -->
   <!-- ========== SEZIONI LEGACY (nascoste) ========== -->
   <div id="api-settings" style="display:none; padding:1rem; border:1px solid #ccc; border-radius:8px; background:#f9f9f9;">
   <div id="api-settings" style="display:none; padding:1rem; border:1px solid #ccc; border-radius:8px; background:#f9f9f9;">
     <strong>Connessione API (protetta dal server)</strong><br><br>
     <strong>Connessione API (protetta dal server)</strong><br><br>
Riga 447: Riga 351:
     <button onclick="(async()=>{try{const r=await fetch('/dashboard/api/openai_project_gpt.php',{method:'POST',headers:{'Content-Type':'application/json'},credentials:'include',body:JSON.stringify({model:document.getElementById('model-select').value,prompt:document.getElementById('test-prompt').value})}); const j=await r.json(); document.getElementById('api-result').textContent=JSON.stringify(j,null,2);}catch(e){document.getElementById('api-result').textContent=e.message;}})()">▶️ Esegui</button>
     <button onclick="(async()=>{try{const r=await fetch('/dashboard/api/openai_project_gpt.php',{method:'POST',headers:{'Content-Type':'application/json'},credentials:'include',body:JSON.stringify({model:document.getElementById('model-select').value,prompt:document.getElementById('test-prompt').value})}); const j=await r.json(); document.getElementById('api-result').textContent=JSON.stringify(j,null,2);}catch(e){document.getElementById('api-result').textContent=e.message;}})()">▶️ Esegui</button>
     <pre id="api-result" style="background:#f0f0f0; padding:1rem; border:1px solid #ccc; margin-top:1rem; white-space:pre-wrap;"></pre>
     <pre id="api-result" style="background:#f0f0f0; padding:1rem; border:1px solid #ccc; margin-top:1rem; white-space:pre-wrap;"></pre>
  </div>
  <!-- 📊 Stato Progetti (demo) -->
  <div id="project-status" style="display:none; padding:1rem; border:1px solid #ccc; border-radius:8px; background:#f9f9f9;">
    <strong>📊 Stato Progetti</strong><br><br>
    <div id="gptResponse" class="gpt-card" style="margin-top:8px; background:#fff; border:1px solid #e6e6e6; border-radius:10px; padding:16px; font: 16px/1.6 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; color:#1f2328; box-shadow: 0 1px 2px rgba(0,0,0,.04);">
      <em style="opacity:.7">Qui apparirà la risposta generata da GPT sull’analisi del progetto…</em>
    </div>
  </div>
  <!-- 📘 Registro Attività -->
  <div id="activity-log" style="display:none; padding:1rem; border:1px solid #ccc; border-radius:8px; background:#fdfdfd;">
    <strong>📘 Registro attività:</strong>
    <button onclick="(function(){const box=document.getElementById('activityLogContent'); if(box) box.textContent=''; })()" style="float:right; background:#e74c3c; color:white; border:none; padding:0.4rem 1rem; border-radius:6px; font-weight:bold;">🧹 Svuota</button>
    <div id="activityLogContent" style="margin-top:1rem; max-height:250px; overflow-y:auto; background:#f0f0f0; padding:1rem; border:1px solid #ccc; border-radius:6px; font-family:monospace; font-size:0.85rem;">
      <em><span style="color:#888;">Registro avviato...</span></em>
    </div>
   </div>
   </div>
</html>
</html>

Versione delle 07:50, 28 set 2025

🔧 Dashboard Operativa – Masticationpedia

Centro di comando per progetti, API, file e backup

🧾 Apri Log Dashboard