Riga 168:
Riga 168:
<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>
</div>
<script>
// JS minimo temporaneo per sbloccare la pagina
// (serve solo a NON avere errori di sintassi)
</script>
<!-- ========== JS (copia codice, parser blocchi, invio) ========== -->
<script>
function toggleDashboardBox(id){
const el = document.getElementById(id);
if (!el) return;
el.style.display = (el.style.display === 'none' || !el.style.display) ? 'block' : 'none';
if (el.style.display === 'block') el.scrollIntoView({behavior:'smooth'});
}
function showMpAI(){ document.getElementById('mpAI').style.display='block'; }
function mpCopy(btn){
try{
const box = btn.closest('.mp-code');
const pre = box.querySelector('pre');
const txt = pre ? pre.innerText : '';
if (!txt) throw new Error('Codice non trovato');
navigator.clipboard.writeText(txt).then(()=>{
const old = btn.textContent;
btn.textContent = '✅ Copiato';
setTimeout(()=>btn.textContent = old, 1200);
});
}catch(e){ alert('Copia non riuscita: '+e.message); }
}
// Trasforma testo con blocchi ```lang\n...\n``` in nodi HTML con cornice + copia
function renderTextWithCodeBlocks(text){
const frag = document.createDocumentFragment();
const re = /```(\w+)?\n([\s\S]*?)```/g;
let lastIndex = 0, m;
while ((m = re.exec(text)) !== null){
const before = text.slice(lastIndex, m.index).trim();
if (before){
const p = document.createElement('div');
p.textContent = before;
frag.appendChild(p);
}
const lang = (m[1] || 'code').toLowerCase();
const code = m[2].replace(/\n+$/,'');
const box = document.createElement('div'); box.className = 'mp-code';
const hdr = document.createElement('div'); hdr.className = 'mp-code__hdr';
hdr.innerHTML = `<span class="mp-code__lang">${lang}</span>`;
const btn = document.createElement('button'); btn.className='mp-copy'; btn.textContent='📋 Copia'; btn.onclick=()=>mpCopy(btn);
hdr.appendChild(btn);
const pre = document.createElement('pre'); pre.textContent = code;
box.appendChild(hdr); box.appendChild(pre);
frag.appendChild(box);
lastIndex = re.lastIndex;
}
const tail = text.slice(lastIndex).trim();
if (tail){
const p = document.createElement('div'); p.textContent = tail;
frag.appendChild(p);
}
return frag;
}
(function(){
const $chat = document.getElementById('mpai-chat');
const $input = document.getElementById('mpai-input');
const $send = document.getElementById('mpai-send');
function addMsg(role, content){
const wrap = document.createElement('div');
wrap.className = 'mpai-msg ' + (role === 'user' ? 'user' : (role === 'assistant' ? 'assistant' : 'error'));
const head = document.createElement('div'); head.className = 'role'; head.textContent = role;
const body = document.createElement('div'); body.className = 'body';
if (role === 'assistant'){
body.appendChild(renderTextWithCodeBlocks(String(content || '')));
} else {
body.textContent = String(content || '');
}
wrap.appendChild(head); wrap.appendChild(body);
$chat.appendChild(wrap);
$chat.scrollTop = $chat.scrollHeight;
}
async function sendMessage(){
const prompt = ($input.value || '').trim();
if (!prompt) return;
addMsg('user', prompt);
$input.value = '';
const model = document.getElementById('mpai-model')?.value || 'gpt-4o-2024-05-13';
const temperature = parseFloat(document.getElementById('mpai-temp')?.value || '0.7');
const drop = document.getElementById('mpai-drop-urls')?.checked === true;
const files = [];
const texts = [];
const payload = { model, prompt, temperature, drop_urls: drop, files, texts };
try {
const res = await fetch('/dashboard/api/openai_project_gpt.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(payload)
});
const ct = res.headers.get('content-type') || '';
let out;
if (ct.includes('application/json')){
const j = await res.json();
out = j?.text ?? j?.message ?? (typeof j === 'string' ? j : JSON.stringify(j, null, 2));
} else {
out = await res.text();
}
addMsg('assistant', out || '(vuoto)');
} catch (e) {
addMsg('error', String(e));
}
}
$send?.addEventListener('click', sendMessage);
$input?.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) sendMessage();
});
document.getElementById('mpai-clear')?.addEventListener('click', ()=>{
$chat.innerHTML = '<div class="mpai-msg mpai-hint">Conversazione pulita.</div>';
});
})();
// -------- pannello test “Connessione API” (force translate) -------
document.getElementById('test_run')?.addEventListener('click', async () => {
const model = document.getElementById('model-select').value;
const prompt = document.getElementById('test_prompt').value;
const drop = document.getElementById('test_drop_urls').checked;
const payload = {
model,
prompt,
temperature: 0.7,
drop_urls: drop,
files: [],
texts: [],
mode: 'translate' // forza ramo traduzione per il test
};
try {
const res = await fetch('/dashboard/api/openai_project_gpt.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(payload)
});
const j = await res.json();
document.getElementById('api-result').textContent = JSON.stringify(j, null, 2);
} catch (e) {
document.getElementById('api-result').textContent = String(e);
}
});
// Utility: svuota log lato server (se l’hai implementato)
function clearServerLog(){
fetch('/dashboard/api/log_clear.php', {method:'POST', credentials:'include'}).then(()=>alert('Log svuotato'));
}
</script>
</html>
</html>
🔧 Dashboard Operativa – Masticationpedia
Centro di comando per progetti, API, file e backup
🧾 Apri Log Dashboard
🧹 Svuota Log
⚙️ Connessione API
🤖 Masticationpedia AI
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.