|
|
| 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> |
|
| |
|