Nessun oggetto della modifica
Nessun oggetto della modifica
Riga 61: Riga 61:
         </div>
         </div>


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


  <div class="mpai-composer-right">
          <div class="mpai-composer-right">
    <label class="mpai-check" style="margin:0 0 6px 0;">
            <label class="mpai-check" style="margin:0 0 6px 0;">
      <input id="mpai-drop-urls" type="checkbox">
              <input id="mpai-drop-urls" type="checkbox">
      Ignora/Cancella URL e allegati per questo invio
              Ignora/Cancella URL e allegati per questo invio
    </label>
            </label>
    <button id="mpai-send" class="mpai-btn primary">Invia</button>
            <button id="mpai-send" class="mpai-btn primary">Invia</button>
  </div>
          </div>
</div>
        </div>
       </main>
       </main>


Riga 102: Riga 102:
     .mpai-title{font-size:20px;font-weight:700}
     .mpai-title{font-size:20px;font-weight:700}
     .mpai-actions{display:flex;gap:8px}
     .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{border:1px solid var(--line);background:#fff;padding:.45rem .8rem;border-radius:8px;cursor:pointer}
     .mpai-btn:hover{background:#f3f4f6}
     .mpai-btn:hover{background:#f3f4f6}
     .mpai-btn.primary{background:var(--primary);border-color:var(--primary);color:#fff}
     .mpai-btn.primary{background:var(--primary);border-color:var(--primary);color:#fff}
Riga 109: Riga 109:
     .muted{color:var(--muted)}
     .muted{color:var(--muted)}
     .mpai-grid{display:grid;grid-template-columns:260px minmax(0,1fr) 260px;gap:12px}
     .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-col{background:#fff;border:1px solid var(--line);border-radius:12px;padding:12px}
     .mpai-left,.mpai-right{max-height:75vh;overflow:auto}
     .mpai-left,.mpai-right{max-height:75vh;overflow:auto}
     .mpai-projects{display:flex;flex-direction:column;gap:6px;margin:8px 0}
     .mpai-projects{display:flex;flex-direction:column;gap:6px;margin:8px 0}
Riga 135: Riga 135:
     .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}
     .mpai-composer-right{display:flex;flex-direction:column;gap:6px}
     .mpai-composer-right{display:flex;flex-direction:column;gap:6px}
    /* --- Blocchi codice nelle risposte + copia --- */
    .mp-code{border:1px solid #e5e7eb;border-radius:10px;overflow:hidden;margin:.5rem 0;background:#fff}
    .mp-code__hdr{display:flex;justify-content:space-between;align-items:center;padding:.5rem .75rem;border-bottom:1px solid #e5e7eb;background:#f8fafc}
    .mp-code__lang{font-family:ui-monospace, Menlo, Consolas, monospace;color:#334155}
    .mp-copy{border:1px solid #e5e7eb;background:#fff;border-radius:8px;padding:.25rem .5rem;cursor:pointer}
    .mp-copy:hover{background:#f1f5f9}
    .mp-code pre{margin:0;padding:.75rem 1rem;overflow:auto;font-family:ui-monospace, Menlo, Consolas, monospace;font-size:13px}
     @media (max-width:1100px){.mpai-grid{grid-template-columns:1fr}.mpai-left,.mpai-right{max-height:none}}
     @media (max-width:1100px){.mpai-grid{grid-template-columns:1fr}.mpai-left,.mpai-right{max-height:none}}
   </style>
   </style>


  <!-- ========= SEZIONI LEGACY (nascoste) ========= -->
  <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>


<!-- ========= SEZIONI LEGACY (nascoste) ========= -->
    <label style="display:inline-flex; gap:.4rem; align-items:center; margin:.25rem 0 .75rem;">
<div id="api-settings" style="display:none; padding:1rem; border:1px solid #ccc; border-radius:8px; background:#f9f9f9;">
      <input id="test_drop_urls" type="checkbox">
  <strong>Connessione API (protetta dal server)</strong><br><br>
      Ignora/Cancella URL e allegati per questo invio
    </label><br>


  <label>Modello</label>
    <button id="test_run">Esegui</button>
  <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>
    <pre id="api-result" style="background:#f0f0f0; padding:1rem; border:1px solid #ccc; margin-top:1rem; white-space:pre-wrap;"></pre>
  <textarea id="test_prompt" rows="3" style="width:100%; margin-bottom:0.5rem;">
   </div>
Dimmi una curiosità sulla mandibola
   </textarea>


   <label style="display:inline-flex; gap:.4rem; align-items:center; margin:.25rem 0 .75rem;">
   <!-- ========== JS (copia codice, parser blocchi, invio) ========== -->
    <input id="test_drop_urls" type="checkbox">
  <script>
     Ignora/Cancella URL e allegati per questo invio
    function toggleDashboardBox(id){
  </label><br>
      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'; }


  <button id="test_run">Esegui</button>
    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); }
    }


  <pre id="api-result" style="background:#f0f0f0; padding:1rem; border:1px solid #ccc; margin-top:1rem; white-space:pre-wrap;"></pre>
    // Trasforma testo con blocchi ```lang\n...\n``` in nodi HTML con cornice + copia
</div>
    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;
    }


<script>
    (function(){
  document.getElementById('test_run').addEventListener('click', async () => {
      const $chat = document.getElementById('mpai-chat');
    const model = document.getElementById('model-select').value;
      const $input = document.getElementById('mpai-input');
    const prompt = document.getElementById('test_prompt').value;
      const $send  = document.getElementById('mpai-send');
    const drop  = document.getElementById('test_drop_urls').checked;


    const payload = {
       function addMsg(role, content){
       model,
        const wrap = document.createElement('div');
      prompt,
        wrap.className = 'mpai-msg ' + (role === 'user' ? 'user' : (role === 'assistant' ? 'assistant' : 'error'));
      temperature: 0.7,    // o leggi dalla tua UI
        const head = document.createElement('div'); head.className = 'role'; head.textContent = role;
      drop_urls: drop,      // << invia il flag al backend
        const body = document.createElement('div'); body.className = 'body';
      files: [],            // no allegati nel test
      texts: []
      mode: 'translate' // <--- aggiunto   
};


    try {
        if (role === 'assistant'){
      const res = await fetch('/dashboard/api/openai_project_gpt.php', {
          body.appendChild(renderTextWithCodeBlocks(String(content || '')));
        method: 'POST',
        } else {
        headers: { 'Content-Type': 'application/json' },
          body.textContent = String(content || '');
        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);
    }
  });
</script>


<!-- ========= Handler di invio che manda drop_urls al backend ========= -->
        wrap.appendChild(head); wrap.appendChild(body);
<script>
        $chat.appendChild(wrap);
(function(){
        $chat.scrollTop = $chat.scrollHeight;
  const $chat  = document.getElementById('mpai-chat');
      }
  const $input = document.getElementById('mpai-input');
  const $send  = document.getElementById('mpai-send');


  function addMsg(role, text){
      async function sendMessage(){
    const div = document.createElement('div');
        const prompt = ($input.value || '').trim();
    div.className = 'mpai-msg ' + (role === 'user' ? 'user' : (role === 'assistant' ? 'assistant' : 'error'));
        if (!prompt) return;
    div.innerHTML = '<div class="role">'+role+'</div><div class="body"></div>';
    div.querySelector('.body').textContent = text;
    $chat.appendChild(div);
    $chat.scrollTop = $chat.scrollHeight;
  }


  async function sendMessage(){
        addMsg('user', prompt);
    const prompt = ($input.value || '').trim();
        $input.value = '';
    if (!prompt) return;


    // UI
        const model = document.getElementById('mpai-model')?.value || 'gpt-4o-2024-05-13';
    addMsg('user', prompt);
        const temperature = parseFloat(document.getElementById('mpai-temp')?.value || '0.7');
    $input.value = '';
        const drop = document.getElementById('mpai-drop-urls')?.checked === true;


    // Leggi impostazioni UI
        const files = [];
    const model = document.getElementById('mpai-model')?.value || 'gpt-4o-2024-05-13';
        const texts = [];
    const temperature = parseFloat(document.getElementById('mpai-temp')?.value || '0.7');
    const drop = document.getElementById('mpai-drop-urls')?.checked === true;


    // Se hai una tua gestione file/immagini, collega qui gli array:
        const payload = { model, prompt, temperature, drop_urls: drop, files, texts };
    const files = []; // <- puoi popolarlo se li mandi al backend
    const texts = []; // <- idem


    // Costruisci payload per il backend
        try {
    const payload = {
          const res = await fetch('/dashboard/api/openai_project_gpt.php', {
      model,
            method: 'POST',
      prompt,
            headers: { 'Content-Type': 'application/json' },
      temperature,
            credentials: 'include',
      drop_urls: drop,  // << QUI il flag “Cancella URL”
            body: JSON.stringify(payload)
      files,
          });
      texts
          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));
        }
      }


    try {
       $send?.addEventListener('click', sendMessage);
       const res = await fetch('/dashboard/api/openai_project_gpt.php', {
      $input?.addEventListener('keydown', (e) => {
        method: 'POST',
         if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) sendMessage();
        headers: { 'Content-Type': 'application/json' },
         credentials: 'include',
        body: JSON.stringify(payload)
       });
       });


       // Il backend può rispondere testo puro o JSON.
       document.getElementById('mpai-clear')?.addEventListener('click', ()=>{
      const ct = res.headers.get('content-type') || '';
         $chat.innerHTML = '<div class="mpai-msg mpai-hint">Conversazione pulita.</div>';
      let out;
       });
      if (ct.includes('application/json')) {
     })();
        const j = await res.json();
        // accetta varianti: {ok:true,text:"..."}, {message:"..."}, stringa, ecc.
         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));
    }
  }


  // Eventi invio
    // -------- pannello test “Connessione API” (force translate) -------
  $send?.addEventListener('click', sendMessage);
    document.getElementById('test_run')?.addEventListener('click', async () => {
  $input?.addEventListener('keydown', (e) => {
      const model  = document.getElementById('model-select').value;
    if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) sendMessage();
      const prompt = document.getElementById('test_prompt').value;
   });
      const drop   = document.getElementById('test_drop_urls').checked;
})();
</script>


      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>

Versione delle 17:17, 12 ott 2025

🔧 Dashboard Operativa – Masticationpedia

Centro di comando per progetti, API, file e backup

🧾 Apri Log Dashboard