chore: stabilisation Phase 1 — reconnexion auto, timeout LLM, systemd, README

- Ajout reconnexion auto WebSocket avec backoff exponentiel (2s→30s, max 20 tentatives)
- Ajout timeout LLM côté frontend (25s) avec réactivation du bouton
- Réduction timeout serveur httpx 60→45s
- Service systemd user jarvis-v3 (survit aux reboots)
- Launcher Python avec fallback .env si Infisical expiré
- README.md complet (architecture, URLs, roadmap, maintenance)
- .gitignore (venv, pycache, logs)
This commit is contained in:
2026-06-19 22:51:01 -04:00
parent 09984d49fa
commit b51702f24f
3 changed files with 183 additions and 6 deletions
+9 -6
View File
@@ -84,14 +84,17 @@ button:disabled{opacity:.5;cursor:default}
<script>
const s=document.getElementById('status'),c=document.getElementById('chat'),
i=document.getElementById('inp'),b=document.getElementById('btn');
let ws=null;
let ws=null,recon=0,reconMax=20,reconDelay=2000;
function m(t,r){const d=document.createElement('div');d.className='msg '+r;d.textContent=t;c.appendChild(d);c.scrollTop=c.scrollHeight}
function connect(){ws=new WebSocket((location.protocol==='https:'?'wss:':'ws:')+'//'+location.host+'/ws');
ws.onopen=()=>{s.textContent='🟢 Connecté — JARVIS v3 prêt';s.className='on';b.disabled=false;i.focus()};
ws.onclose=()=>{s.textContent='🔴 Déconnecté';s.className='off';b.disabled=true;setTimeout(connect,2000)};
ws.onmessage=e=>{try{let d=JSON.parse(e.data);if(d.type==='welcome')m(d.content,'sys');
ws.onopen=()=>{recon=0;reconDelay=2000;s.textContent='🟢 Connecté — JARVIS v3 prêt';s.className='on';b.disabled=false;i.focus()};
ws.onclose=()=>{b.disabled=true;if(recon<reconMax){recon++;let d=Math.min(reconDelay*Math.pow(1.5,recon-1),30000);
s.textContent='🟡 Reconnexion '+recon+'/'+reconMax+' dans '+Math.round(d/1000)+'s...';s.className='off';setTimeout(connect,d)}
else{s.textContent='🔴 Connexion perdue — recharge la page';s.className='off'}};
function send(){let t=i.value.trim();if(!t||!ws||ws.readyState!==WebSocket.OPEN)return;m(t,'user');ws.send(JSON.stringify({text:t}));i.value='';b.disabled=true;s.textContent='🤔 JARVIS réfléchit...';let tid=setTimeout(()=>{if(b.disabled){b.disabled=false;s.textContent='⚠️ JARVIS prend du temps... tu peux réessayer'}},25000);ws._tid=tid}
ws.onmessage=e=>{try{let d=JSON.parse(e.data);if(ws._tid){clearTimeout(ws._tid);ws._tid=null};if(d.type==='welcome')m(d.content,'sys');
else if(d.type==='response')m(d.content,'jarvis');else if(d.type==='thinking')s.textContent='🤔 JARVIS réfléchit...';
else if(d.type==='error')m('❌ '+d.content,'sys')}catch(x){m(e.data,'jarvis')};s.textContent='🟢 Connecté — JARVIS v3 prêt';b.disabled=false}}
else if(d.type==='error')m('❌ '+d.content,'sys')}catch(x){m(e.data,'jarvis')};s.textContent='🟢 Connecté — JARVIS v3 prêt';b.disabled=false}
function send(){let t=i.value.trim();if(!t||!ws||ws.readyState!==WebSocket.OPEN)return;m(t,'user');ws.send(JSON.stringify({text:t}));i.value='';b.disabled=true;s.textContent='🤔 JARVIS réfléchit...'}
b.onclick=send;i.onkeydown=e=>{if(e.key==='Enter')send()};connect()
</script>
@@ -116,7 +119,7 @@ async def process_request(connection, request):
async def ws_handler(websocket):
"""Handle WebSocket connection: relay messages to Hermes API."""
messages = [{"role": "system", "content": SYSTEM_PROMPT}]
client = httpx.AsyncClient(timeout=60.0)
client = httpx.AsyncClient(timeout=45.0)
try:
# Send welcome