v3
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
/* Espace enfant : dialogue texte uniquement. Aucun WebSocket/audio/MCP. */
|
||||
(() => {
|
||||
'use strict';
|
||||
const $ = id => document.getElementById(id);
|
||||
const session = JSON.parse($('dona-child-session').textContent);
|
||||
const messages = $('child-messages');
|
||||
const form = $('child-form');
|
||||
const input = $('child-input');
|
||||
const send = $('child-send');
|
||||
let busy = false;
|
||||
function bubble(text, role, loading=false) {
|
||||
const article=document.createElement('article');article.className='chat-turn '+role+(loading?' loading':'');
|
||||
if (role==='scratch') {
|
||||
const pic=document.createElement('img');pic.src='/static/img/scratch-cat-user.png';pic.alt='Le chat Scratch';pic.className='chat-avatar scratch-avatar';article.append(pic);
|
||||
} else {
|
||||
const avatar=document.createElement('div');avatar.className='user-avatar';avatar.textContent='🙂';avatar.setAttribute('aria-hidden','true');article.append(avatar);
|
||||
}
|
||||
const copy=document.createElement('div');copy.className='turn-copy';
|
||||
const speaker=document.createElement('span');speaker.className='speaker';speaker.textContent=role==='scratch'?'Scratch':'Moi';
|
||||
const textBox=document.createElement('div');textBox.className='chat-bubble';textBox.textContent=text;
|
||||
copy.append(speaker,textBox);article.append(copy);messages.append(article);
|
||||
messages.scrollTop=messages.scrollHeight;
|
||||
return article;
|
||||
}
|
||||
async function post(url,data) {
|
||||
const r=await fetch(url,{method:'POST',credentials:'same-origin',headers:{
|
||||
'Content-Type':'application/json','X-Dona-Enfant':'1'
|
||||
},body:JSON.stringify(data)});
|
||||
let payload={};try{payload=await r.json();}catch(_){}
|
||||
if(!r.ok)throw new Error(payload.error||'Connexion impossible');
|
||||
return payload;
|
||||
}
|
||||
form.addEventListener('submit',async event=>{
|
||||
event.preventDefault();
|
||||
if(busy)return;
|
||||
const text=input.value.trim();if(!text)return;
|
||||
busy=true;send.disabled=true;input.disabled=true;
|
||||
input.value='';bubble(text,'you');
|
||||
const pending=bubble('Scratch réfléchit…','scratch',true);
|
||||
try {
|
||||
const result=await post('/api/enfant/message',{session,message:text});
|
||||
pending.querySelector('.chat-bubble').textContent=result.reply||'Je n’ai pas compris, on réessaie ?';
|
||||
pending.classList.remove('loading');
|
||||
} catch(err) {
|
||||
pending.querySelector('.chat-bubble').textContent=err.message;
|
||||
pending.classList.remove('loading');
|
||||
} finally {
|
||||
busy=false;send.disabled=false;input.disabled=false;input.focus();
|
||||
messages.scrollTop=messages.scrollHeight;
|
||||
}
|
||||
});
|
||||
input.addEventListener('keydown',event=>{
|
||||
if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();form.requestSubmit();}
|
||||
});
|
||||
$('child-clear').addEventListener('click',async()=>{
|
||||
if(busy)return;
|
||||
try {
|
||||
await post('/api/enfant/clear',{session});
|
||||
messages.replaceChildren();
|
||||
bubble('Coucou ! 😺 On commence une nouvelle histoire ?','scratch');
|
||||
} catch(err){bubble(err.message,'scratch');}
|
||||
input.focus();
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user