Dashboard Masticationpedia: differenze tra le versioni
Nessun oggetto della modifica |
Nessun oggetto della modifica |
||
| Riga 1: | Riga 1: | ||
<html> | <html> | ||
<h2>🔧 Dashboard Operativa – Masticationpedia</h2> | <h2>🔧 Dashboard Operativa – Masticationpedia</h2> | ||
<p><em>Centro di comando per progetti, API, file e backup</em></p> | <p><em>Centro di comando per progetti, API, file e backup</em></p> | ||
<a href="/dashboard/api/log_view.php" target="_blank">🧾 Apri Log Dashboard</a> | <a href="/dashboard/api/log_view.php" target="_blank">🧾 Apri Log Dashboard</a> | ||
<button onclick="clearServerLog()">🧹 Svuota Log</button> | <button onclick="clearServerLog()">🧹 Svuota Log</button> | ||
<!-- 🔘 Pulsanti --> | <!-- 🔘 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('project-status')">📊 Stato Progetti</button> | |||
<button class="dashboard-toggle" onclick="toggleDashboardBox('chatgpt-plus')">🤖 ChatGPT plus</button> | |||
<button class="dashboard-toggle" onclick="toggleDashboardBox('test-tools')">🧪 Strumenti di Test</button> | |||
<button class="dashboard-toggle" onclick="toggleDashboardBox('activity-log')">📘 Registro Attività</button> | |||
<button class="dashboard-toggle" onclick="showMpAI()">🤖 Masticationpedia AI</button> | |||
</div> | |||
<button class=" | <!-- ============== MASTICATIONPEDIA AI (schermata unica) ============== --> | ||
<div id="mpAI" class="mpai-root" style="display:none"> | |||
<!-- Header --> | |||
<div class="mpai-header"> | |||
</div> | <div class="mpai-title">🤖 Masticationpedia <b>AI</b></div> | ||
<div class="mpai-actions"> | |||
<button id="mpai-new-chat" class="mpai-btn ghost">Nuova chat</button> | |||
<button id="mpai-clear" class="mpai-btn danger">Pulisci conversazione</button> | |||
<button id="mpai-save-as-project" class="mpai-btn">💾 Salva come progetto</button> | |||
</div> | |||
</div> | |||
<div class="mpai-grid"> | |||
<!-- Sidebar sinistra: Progetti --> | |||
<aside class="mpai-col mpai-left"> | |||
<h4>📂 Progetti</h4> | |||
<div id="mpai-project-list" class="mpai-projects"> | |||
<em class="muted">Carico progetti…</em> | |||
</div> | |||
<div class="mpai-new-project"> | |||
<input id="mpai-project-name" type="text" placeholder="Nuovo progetto (A-Z 0-9 _ -)" /> | |||
<button id="mpai-project-create" class="mpai-btn">Crea</button> | |||
</div> | |||
<div class="mpai-help muted"> | |||
Ogni progetto mantiene la sua cronologia locale (browser). | |||
</div> | |||
</aside> | |||
< | <!-- Chat centrale --> | ||
<main class="mpai-col mpai-center"> | |||
<!-- Allegati (solo elenco locale per ora) --> | |||
<div id="mpai-uploads" class="mpai-uploads" data-state="idle"> | |||
<div class="mpai-dropzone" id="mpai-dropzone"> | |||
<div> | |||
<div class="muted" style="margin-bottom:6px;">Trascina qui file <b>sanificati</b> oppure</div> | |||
<label class="mpai-file-label"> | |||
<input id="mpai-file-input" type="file" multiple style="display:none;"> | |||
<span class="mpai-btn">📂 Aggiungi file</span> | |||
</label> | |||
</div> | |||
</div> | |||
<div id="mpai-file-list" class="mpai-filelist"></div> | |||
</div> | |||
<!-- Messaggi --> | |||
<div id="mpai-chat" class="mpai-chat"> | |||
<div class="mpai-msg mpai-hint"> | |||
Benvenuto. Seleziona un progetto a sinistra, oppure scrivi subito: se non c’è un progetto creo una conversazione locale. Le risposte appariranno qui sotto in ordine, come in ChatGPT. | |||
</div> | |||
</div> | |||
<!-- Prompt --> | |||
<div class="mpai-composer"> | |||
<textarea id="mpai-input" rows="3" placeholder="Scrivi qui la tua domanda..."></textarea> | |||
<button id="mpai-send" class="mpai-btn primary">Invia</button> | |||
</div> | |||
</main> | |||
<!-- Sidebar destra: Impostazioni --> | |||
<aside class="mpai-col mpai-right"> | |||
<h4>⚙️ Impostazioni</h4> | |||
<label class="mpai-field">Modello | |||
<select id="mpai-model"> | |||
<option value="gpt-4o-2024-05-13" selected>gpt-4o-2024-05-13</option> | |||
<option value="gpt-4-turbo-2024-04-09">gpt-4-turbo-2024-04-09</option> | |||
</select> | |||
</label> | |||
<label class="mpai-field">Temperatura | |||
<input id="mpai-temp" type="number" min="0" max="1" step="0.1" value="0.7"> | |||
</label> | |||
<label class="mpai-check"> | |||
<input id="mpai-sanitized-only" type="checkbox" checked> | |||
Usa solo file <b>sanificati</b> come contesto | |||
</label> | |||
<div class="mpai-help muted"> | |||
Le API key restano lato server (file sicuro). Il browser non vede mai le chiavi. | |||
</div> | |||
</aside> | |||
</div> | |||
</div> | |||
<!-- ============ STILI (CSS) ============ --> | |||
<style> | |||
.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);} | |||
.mpai-header{display:flex;align-items:center;justify-content:space-between;margin:8px 0 12px} | |||
.mpai-title{font-size:20px;font-weight:700} | |||
.mpai-actions{display:flex;gap:8px} | |||
.mpai-btn{border:1px solid var(--line);background:var(--card);padding:.45rem .8rem;border-radius:8px;cursor:pointer} | |||
.mpai-btn:hover{background:#f3f4f6} | |||
.mpai-btn.primary{background:var(--primary);border-color:var(--primary);color:#fff} | |||
.mpai-btn.danger{background:var(--danger);border-color:var(--danger);color:#fff} | |||
.mpai-btn.ghost{background:transparent} | |||
.muted{color:var(--muted)} | |||
.mpai-grid{display:grid;grid-template-columns:260px minmax(0,1fr) 260px;gap:12px} | |||
.mpai-col{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:12px} | |||
.mpai-left,.mpai-right{max-height:75vh;overflow:auto} | |||
.mpai-projects{display:flex;flex-direction:column;gap:6px;margin:8px 0} | |||
.mpai-projects .row{display:flex;align-items:center;gap:6px;justify-content:space-between;border:1px solid var(--line);border-radius:8px;padding:6px 8px} | |||
.mpai-projects .row .title{font-family:monospace;font-size:12px} | |||
.mpai-new-project{display:flex;gap:6px;margin-top:8px} | |||
.mpai-new-project input{flex:1 1 auto;padding:.45rem .6rem;border:1px solid var(--line);border-radius:8px} | |||
.mpai-field{display:flex;flex-direction:column;gap:4px;margin:8px 0} | |||
.mpai-field input,.mpai-field select{padding:.45rem .6rem;border:1px solid var(--line);border-radius:8px} | |||
.mpai-check{display:flex;align-items:center;gap:8px;margin:8px 0} | |||
.mpai-center{display:flex;flex-direction:column;gap:10px} | |||
.mpai-uploads{border:1px dashed var(--line);border-radius:12px;padding:10px;background:#fafafa} | |||
.mpai-dropzone{display:flex;align-items:center;justify-content:center;border-radius:10px;padding:12px;background:var(--accent);text-align:center} | |||
.mpai-filelist{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px} | |||
.mpai-filepill{display:flex;align-items:center;gap:6px;border:1px solid var(--line);border-radius:999px;padding:4px 8px;background:#fff;font-size:12px} | |||
.mpai-filepill button{border:none;background:transparent;cursor:pointer;color:#c00} | |||
.mpai-chat{display:flex;flex-direction:column;gap:10px;max-height:50vh;overflow:auto;border:1px solid var(--line);border-radius:12px;padding:10px;background:#fff} | |||
.mpai-msg{border:1px solid var(--line);border-radius:12px;padding:10px;background:#fff} | |||
.mpai-msg.user{border-color:#bee3f8;background:#eff6ff} | |||
.mpai-msg.assistant{border-color:#d1fae5;background:#f0fdf4} | |||
.mpai-msg.error{border-color:#fecaca;background:#fff1f2} | |||
.mpai-msg .role{font-weight:600;margin-bottom:4px} | |||
.mpai-hint{border-style:dashed;color:var(--muted)} | |||
.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} | |||
@media (max-width: 1100px){ | |||
.mpai-grid{grid-template-columns:1fr} | |||
.mpai-left,.mpai-right{max-height:none} | |||
} | } | ||
</style> | |||
<!-- ============ JS (tutto qui) ============ --> | |||
<script> | |||
// ---- Funzioni base / legacy ---- | |||
function toggleDashboardBox(id){ | |||
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 uploadToOpenAI(){ alert('Prossimo step: upload verso OpenAI.'); } | |||
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 ========= */ | |||
(function(){ | |||
const | // Stato | ||
let currentProject = null; // progetto “reale” (server) o null | |||
let sessionId = null; // id bozza locale se non c'è progetto | |||
let sessionMeta = null; // {title, updated} | |||
let history = []; | |||
let attachments = []; | |||
// Shortcuts | |||
const $ = s => document.querySelector(s); | |||
const chatEl = $('#mpai-chat'); | |||
const fileListEl = $('#mpai-file-list'); | |||
// UI helpers | |||
function appendMsg(role, content){ | |||
const div = document.createElement('div'); | |||
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 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 (bozze senza progetto) ======== | |||
function ensureSession(){ | |||
if (!sessionId){ | |||
sessionId = 'sess-' + Date.now(); | |||
sessionMeta = { title: 'Nuova conversazione', updated: Date.now() }; | |||
localStorage.setItem('mpai.session.meta.'+sessionId, JSON.stringify(sessionMeta)); | |||
} | |||
} | |||
function saveSession(){ | |||
if (!sessionId) return; | |||
const key = 'mpai.session.hist.' + sessionId; | |||
localStorage.setItem(key, JSON.stringify(history.slice(-200))); | |||
sessionMeta.updated = Date.now(); | |||
localStorage.setItem('mpai.session.meta.'+sessionId, JSON.stringify(sessionMeta)); | |||
} | |||
function loadSession(id){ | |||
sessionId = id; | |||
const key = 'mpai.session.hist.' + id; | |||
const raw = localStorage.getItem(key); | |||
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 (sinistra) ======== | |||
async function loadProjects(){ | |||
const box = $('#mpai-project-list'); | |||
box.innerHTML = '<em class="muted">Carico progetti…</em>'; | |||
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){ | |||
const first = (typeof arr[0]==='string')?arr[0]:(arr[0].name||arr[0]); | |||
currentProject = first; | |||
loadLocal(first); | |||
} | |||
}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 locale (solo elenco) ======== | |||
const dz = $('#mpai-dropzone'); | |||
const fi = $('#mpai-file-input'); | |||
dz.addEventListener('dragover', e => { e.preventDefault(); dz.style.opacity = .85; }); | |||
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 via proxy sicuro ======== | |||
async function sendPrompt(){ | |||
const ta = $('#mpai-input'); | |||
const model = ($('#mpai-model')?.value || 'gpt-4o-2024-05-13').trim(); | |||
const temp = parseFloat($('#mpai-temp')?.value || '0.7') || 0.7; | |||
const sanitizedOnly = !!($('#mpai-sanitized-only')?.checked); | |||
const content = (ta.value || '').trim(); | |||
if (!content){ ta.focus(); return; } | |||
// abilita bozza locale se nessun progetto | |||
if (!currentProject && !sessionId){ | |||
ensureSession(); | |||
loadSession(sessionId); | |||
} | |||
// mostra subito il messaggio dell’utente | |||
history.push({role:'user', content}); | |||
appendMsg('user', content); | |||
ta.value = ''; | |||
// contesto: progetto o sessione locale | |||
const contextName = currentProject | |||
? ('Progetto: ' + currentProject) | |||
: ('Sessione: ' + (sessionMeta && sessionMeta.title ? sessionMeta.title : 'Nuova conversazione')); | |||
const fileNames = attachments.map(a => a.name).join(', '); | |||
const preface = `${contextName} | |||
File allegati${sanitizedOnly ? ' (sanificati)' : ''}: ${fileNames || 'nessuno'} | File allegati${sanitizedOnly ? ' (sanificati)' : ''}: ${fileNames || 'nessuno'} | ||
| Riga 235: | Riga 356: | ||
${content}`; | ${content}`; | ||
// placeholder “Elaboro…” | |||
const pending = document.createElement('div'); | |||
pending.className = 'mpai-msg'; | |||
pending.innerHTML = '<em class="muted">Elaboro…</em>'; | |||
chatEl.appendChild(pending); | |||
chatEl.scrollTop = chatEl.scrollHeight; | |||
try{ | |||
const r = await fetch('/dashboard/api/openai_project_gpt.php', { | |||
method: 'POST', | |||
headers: { 'Content-Type': 'application/json' }, | |||
credentials: 'include', | |||
body: JSON.stringify({ model, prompt: preface }) | |||
}); | |||
// gestione 401 (Basic Auth) | |||
if (r.status === 401){ | |||
pending.remove(); | |||
appendMsg('error','Autenticazione richiesta (401). Riprova: comparirà il popup credenziali.'); | |||
return; | |||
} | |||
const txt = await r.text(); | |||
let j; try{ j = JSON.parse(txt); } catch { j = { status:'error', raw: txt }; } | |||
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'; | |||
history.push({role:'error', content: err}); | |||
appendMsg('error', err + (j.raw ? '\n\nRAW:\n' + j.raw : '')); | |||
saveLocal(); | |||
} | |||
} catch(e){ | |||
pending.remove(); | |||
history.push({role:'error', content: e.message}); | |||
appendMsg('error', e.message); | |||
saveLocal(); | |||
} | } | ||
} | } | ||
// ======== 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 (!confirm('Svuotare la conversazione locale?')) return; | |||
resetToNewChat(); | |||
} | |||
if (e.target && e.target.id==='mpai-save-as-project'){ | |||
const name = prompt('Nome progetto da creare e salvare questa chat:'); | |||
if (!name) return; | |||
$('#mpai-project-name').value = name; | |||
createProject(); | |||
} | |||
}); | |||
document.addEventListener('keydown', (e)=>{ | |||
const ta = $('#mpai-input'); | |||
if ((e.metaKey||e.ctrlKey) && e.key==='Enter' && document.activeElement===ta){ | |||
e.preventDefault(); sendPrompt(); | |||
} | |||
}); | |||
// ======== Boot ======== | |||
}); / | loadProjects(); | ||
if (!currentProject){ ensureSession(); loadSession(sessionId); } | |||
})(); | |||
</script> | |||
< | <!-- ========== SEZIONI LEGACY (nascoste di default) ========== --> | ||
<!-- | <!-- 📦 Connessione API --> | ||
<div id=" | <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> | |||
<label>Modello</label> | |||
<select id="model-select" style="width:100%; margin-bottom:0.5rem;"> | |||
< | <option value="gpt-4o-2024-05-13" selected>gpt-4o-2024-05-13</option> | ||
<option value="gpt-4-turbo-2024-04-09">gpt-4-turbo-2024-04-09</option> | |||
</select> | |||
<label>Prompt di test</label> | |||
<textarea id="test-prompt" rows="3" style="width:100%; margin-bottom:0.5rem;">Dimmi una curiosità sulla mandibola</textarea><br> | |||
<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> | |||
</div> | </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="project-status" style="display:none; padding:1rem; border:1px solid #ccc; border-radius:8px; background:#f9f9f9;"> | |||
<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);"> | <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> | <em style="opacity:.7">Qui apparirà la risposta generata da GPT sull’analisi del progetto…</em> | ||
</div> | </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> | </div> | ||
</html> | </html> | ||
Versione delle 16:17, 27 set 2025
🔧 Dashboard Operativa – Masticationpedia
Centro di comando per progetti, API, file e backup