Nessun oggetto della modifica
Nessun oggetto della modifica
Riga 132: Riga 132:
   <!-- ============ JS (tutto qui) ============ -->
   <!-- ============ JS (tutto qui) ============ -->
   <script>
   <script>
    // --- utility legacy ---
  // ======== Invio prompt via proxy sicuro ========
    function toggleDashboardBox(id){
// Definizione funzione + binding dei pulsanti/shortcut
      var el=document.getElementById(id); if(!el) return;
      var ai=document.getElementById('mpAI'); if(ai) ai.style.display='none';
      el.style.display=(el.style.display==='none'||!el.style.display)?'block':'none';
    }
    async function clearServerLog(){
      try{
        const r=await fetch('/dashboard/api/log_clear.php',{method:'POST',credentials:'include'});
        const j=await r.json().catch(()=>({ok:false}));
        alert(j && j.ok ? 'Log svuotato.' : 'Impossibile svuotare il log.');
      }catch(e){ alert('Errore rete: '+e.message); }
    }
    function showMpAI(){
      ['api-settings','project-status','chatgpt-plus','test-tools','activity-log'].forEach(id=>{
        var el=document.getElementById(id); if(el) el.style.display='none';
      });
      var ai=document.getElementById('mpAI'); if(ai) ai.style.display='block';
    }


    /* ========= MPAI APP ========= */
async function sendPrompt(){
    (function(){
  const chatEl = document.querySelector('#mpai-chat');
      // Stato
  const ta    = document.querySelector('#mpai-input');
      let currentProject=null, sessionId=null, sessionMeta=null;
  const model  = (document.querySelector('#mpai-model')?.value || 'gpt-4o-2024-05-13').trim();
      let history=[], attachments=[];
  const temp  = parseFloat(document.querySelector('#mpai-temp')?.value || '0.7') || 0.7;
  const sanitizedOnly = !!(document.querySelector('#mpai-sanitized-only')?.checked);


      // Shortcuts
  const content = (ta.value || '').trim();
      const $ = s => document.querySelector(s);
  if (!content){ ta.focus(); return; }
      const chatEl = $('#mpai-chat');
      const fileListEl = $('#mpai-file-list');


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


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


      // Progetti
  // Costruisci prompt preface
      async function loadProjects(){
  const contextName = window.currentProject
        const box=$('#mpai-project-list');
    ? `Progetto: ${window.currentProject}`
        box.innerHTML='<em class="muted">Carico progetti…</em>';
    : `Sessione: ${window.sessionMeta?.title || 'Nuova conversazione'}`;
        try{
          const r=await fetch('/dashboard/api/project_list.php',{cache:'no-store',credentials:'include'});
          const j=await r.json();
          const arr=Array.isArray(j)?j:(Array.isArray(j.projects)?j.projects:[]);
          if(!arr.length){ box.innerHTML='<em class="muted">Nessun progetto</em>'; return; }
          box.innerHTML='';
          arr.forEach(item=>{
            const name=(typeof item==='string')?item:(item.name||item);
            const row=document.createElement('div');
            row.className='row';
            row.innerHTML='<span class="title">'+name+'</span><span><button class="mpai-btn" data-open="'+name+'">Apri</button></span>';
            row.querySelector('[data-open]').onclick=()=>{ currentProject=name; loadLocal(name); };
            box.appendChild(row);
          });
          if(!currentProject){ currentProject=(typeof arr[0]==='string')?arr[0]:(arr[0].name||arr[0]); loadLocal(currentProject); }
        }catch(e){ box.innerHTML='<span class="muted">Errore caricamento: '+e.message+'</span>'; }
      }
      async function createProject(){
        const inp=$('#mpai-project-name');
        const name=(inp.value||'').trim();
        if(!name){ alert('Inserisci un nome progetto'); return; }
        try{
          const r=await fetch('/dashboard/api/project_create.php',{method:'POST',headers:{'Content-Type':'application/json'},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||'')); }
        }catch(e){ alert('Errore rete: '+e.message); }
      }


      // Upload (solo elenco locale)
  const fileNames = (attachments || []).map(a => a.name).join(', ');
      const dz=$('#mpai-dropzone'), fi=$('#mpai-file-input');
  const preface = `${contextName}
      dz.addEventListener('dragover',e=>{ e.preventDefault(); dz.style.opacity=.85; });
File allegati${sanitizedOnly ? ' (sanificati)' : ''}: ${fileNames || 'nessuno'}
      dz.addEventListener('dragleave',()=>{ dz.style.opacity=1; });
      dz.addEventListener('drop',e=>{
        e.preventDefault(); dz.style.opacity=1;
        Array.from(e.dataTransfer.files||[]).forEach(f=>attachments.push({file:f,name:f.name}));
        renderFiles();
      });
      fi.addEventListener('change',()=>{
        Array.from(fi.files||[]).forEach(f=>attachments.push({file:f,name:f.name}));
        fi.value=''; renderFiles();
      });


      // Invio prompt (PROXY)
Istruzioni: rispondi in ITALIANO, struttura chiara (titoli, punti elenco), sii operativo. Temperatura: ${temp}.
      async function sendPrompt(){
---
        const ta=$('#mpai-input');
Utente:
        const model=($('#mpai-model')?.value||'gpt-4o-2024-05-13').trim();
${content}`;
        const temp=parseFloat($('#mpai-temp')?.value||'0.7')||0.7;
        const sanitizedOnly=$('#mpai-sanitized-only')?.checked;


        const content=(ta.value||'').trim();
  // Placeholder “Elaboro…”
        if(!content){ ta.focus(); return; }
  const pending = document.createElement('div');
  pending.className = 'mpai-msg';
  pending.innerHTML = '<em class="muted">Elaboro…</em>';
  chatEl.appendChild(pending);
  chatEl.scrollTop = chatEl.scrollHeight;


        if(!currentProject && !sessionId){ ensureSession(); loadSession(sessionId); }
  try{
    const r = await fetch('/dashboard/api/openai_project_gpt.php', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      cache: 'no-store',
      body: JSON.stringify({ model, prompt: preface })
    });


        history.push({role:'user',content}); appendMsg('user',content); ta.value='';
    const raw = await r.text();


        const contextName = currentProject ? `Progetto: ${currentProject}` : `Sessione: ${sessionMeta?.title||'Nuova conversazione'}`;
    // Se la risposta non è 2xx, mostra l’errore “grezzo”
        const fileNames = attachments.map(a=>a.name).join(', ');
    if (!r.ok){
        const preface = `${contextName}
      pending.remove();
File allegati${sanitizedOnly?' (sanificati)':''}: ${fileNames||'nessuno'}
      appendMsg('error', `HTTP ${r.status} ${r.statusText}\n\n${raw || '(nessun body)'}`);
      return;
    }


Istruzioni: rispondi in ITALIANO, struttura chiara (titoli, punti elenco), sii operativo. Temperatura: ${temp}.
    // Prova a parse-are il JSON
---
    let j;
Utente:
    try{ j = JSON.parse(raw); }
${content}`;
    catch(e){
      pending.remove();
      appendMsg('error', `Risposta non in JSON:\n\n${raw.slice(0,1500)}`);
      return;
    }


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


        try{
    if (j.status === 'ok' && j.result){
          const r=await fetch('/dashboard/api/openai_project_gpt.php',{
      // Rinomina la bozza alla prima risposta
            method:'POST',
      if (!window.currentProject && window.sessionMeta && window.sessionMeta.title === 'Nuova conversazione'){
            headers:{'Content-Type':'application/json'},
        window.sessionMeta.title = (content.slice(0,48) || 'Nuova conversazione');
            credentials:'include',
         saveSession && saveSession();
            cache:'no-store',
            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; }
          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();
          if(j.status==='ok' && j.result){
            if(!currentProject && sessionMeta && sessionMeta.title==='Nuova conversazione'){ sessionMeta.title=(content.slice(0,48)||'Nuova conversazione'); saveSession(); }
            history.push({role:'assistant',content:j.result}); appendMsg('assistant',j.result); saveLocal();
          }else{
            const err=j.error||'Errore sconosciuto';
            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); }
       }
       }
      history.push({role:'assistant', content: j.result});
      appendMsg('assistant', j.result);
      saveLocal && saveLocal();
    } else {
      const err = j.error || 'Errore sconosciuto';
      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}`);
  }
}


      // Bind
// Binding: click su “Invia” e ⌘/Ctrl+Invio nell’area di testo
      document.addEventListener('click',e=>{
document.addEventListener('click', (e)=>{
        if(e.target && e.target.id==='mpai-send') sendPrompt();
  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();
document.addEventListener('keydown', (e)=>{
        if(e.target && e.target.id==='mpai-clear'){
  if ((e.metaKey||e.ctrlKey) && e.key === 'Enter'){
          if(!currentProject && !sessionId){ ensureSession(); loadSession(sessionId); }
    const ta = document.querySelector('#mpai-input');
          if(!confirm('Svuotare la conversazione locale?')) return;
    if (ta && ta === document.activeElement){ e.preventDefault(); sendPrompt(); }
          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(); } }
      });


      // Boot
// opzionale: utile per test da console
      loadProjects();
window.sendPrompt = sendPrompt;
      if(!currentProject){ ensureSession(); loadSession(sessionId); }
    })();
   </script>
   </script>



Versione delle 07:57, 28 set 2025

🔧 Dashboard Operativa – Masticationpedia

Centro di comando per progetti, API, file e backup

🧾 Apri Log Dashboard