mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-12 23:34:42 +02:00
feat(stt): phase 1-2 — commande, backend vocal, routeur cerveau, HUD MVP
- cli.py : commande `stt` (--setup, --mode, --no-tts) - config.py : défauts embarqués + ~/.config/stt/stt.toml - voice/engine.py : refactor de hermes-voice en classe avec callbacks d'état - brain/router.py : 3 modes (hermes SSH / local LiteLLM / claude API) + auto-détection LAN - server/app.py : HTTP statique (HUD) + websocket (états → HUD) - memory/store.py : tier local SQLite (Qdrant + sync GitHub = phase 4) - hud/index.html : HUD MVP (visualiseur d'état + conversation) Vérifié hors-LAN : py_compile, --help, config, routeur (→ claude), mémoire SQLite. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013FmcxGsyXZXogiAHQLjnZT
This commit is contained in:
parent
8096ba208d
commit
6c680c4f8b
15 changed files with 799 additions and 33 deletions
82
stt/hud/index.html
Normal file
82
stt/hud/index.html
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>STT — Funk</title>
|
||||
<style>
|
||||
:root { --accent:#36d1ff; --bg:#04080f; --dim:#1b2a3a; }
|
||||
* { box-sizing:border-box; }
|
||||
body {
|
||||
margin:0; height:100vh; background:radial-gradient(circle at 50% 40%, #0a1626, var(--bg));
|
||||
color:#cfe9ff; font-family:system-ui, sans-serif; overflow:hidden;
|
||||
display:flex; flex-direction:column; align-items:center; justify-content:center;
|
||||
}
|
||||
#core {
|
||||
width:240px; height:240px; border-radius:50%; position:relative;
|
||||
display:flex; align-items:center; justify-content:center; transition:all .4s;
|
||||
box-shadow:0 0 60px -10px var(--accent);
|
||||
}
|
||||
#core::before, #core::after {
|
||||
content:""; position:absolute; border-radius:50%; border:2px solid var(--accent);
|
||||
inset:0; opacity:.5; animation:pulse 3s ease-in-out infinite;
|
||||
}
|
||||
#core::after { inset:30px; opacity:.25; animation-delay:.6s; }
|
||||
#state { font-size:1.1rem; letter-spacing:.25em; text-transform:uppercase; }
|
||||
.idle #core { box-shadow:0 0 50px -15px var(--accent); filter:saturate(.6); }
|
||||
.listening #core { box-shadow:0 0 80px 0 var(--accent); }
|
||||
.thinking #core { box-shadow:0 0 70px 0 #ffd23f; }
|
||||
.speaking #core { box-shadow:0 0 90px 5px #36ff9e; }
|
||||
@keyframes pulse { 0%,100%{transform:scale(1);opacity:.5} 50%{transform:scale(1.08);opacity:.15} }
|
||||
#log {
|
||||
position:absolute; bottom:0; left:0; right:0; max-height:32vh; overflow:auto;
|
||||
padding:1rem 1.5rem; font-size:.95rem; line-height:1.5; backdrop-filter:blur(4px);
|
||||
}
|
||||
.turn { margin:.3rem 0; }
|
||||
.user { color:#9fd0ff; }
|
||||
.asst { color:#aef5cf; }
|
||||
.err { color:#ff8c8c; }
|
||||
.tag { opacity:.5; font-size:.75rem; margin-left:.5rem; }
|
||||
#conn { position:absolute; top:12px; right:16px; font-size:.75rem; opacity:.6; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="idle">
|
||||
<div id="conn">●</div>
|
||||
<div id="core"></div>
|
||||
<div id="state">veille</div>
|
||||
<div id="log"></div>
|
||||
|
||||
<script>
|
||||
const WS_PORT = 9300; // doit matcher ui.ws_port
|
||||
const LABELS = { idle:"veille", listening:"écoute", thinking:"réflexion", speaking:"réponse" };
|
||||
const body = document.body, stateEl = document.getElementById("state");
|
||||
const logEl = document.getElementById("log"), connEl = document.getElementById("conn");
|
||||
|
||||
function setState(s) {
|
||||
body.className = s;
|
||||
stateEl.textContent = LABELS[s] || s;
|
||||
}
|
||||
function addTurn(cls, text, tag) {
|
||||
const d = document.createElement("div");
|
||||
d.className = "turn " + cls;
|
||||
d.textContent = text;
|
||||
if (tag) { const t = document.createElement("span"); t.className="tag"; t.textContent=tag; d.appendChild(t); }
|
||||
logEl.appendChild(d);
|
||||
logEl.scrollTop = logEl.scrollHeight;
|
||||
}
|
||||
function connect() {
|
||||
const ws = new WebSocket(`ws://${location.hostname}:${WS_PORT}`);
|
||||
ws.onopen = () => connEl.style.color = "#36ff9e";
|
||||
ws.onclose = () => { connEl.style.color = "#ff8c8c"; setTimeout(connect, 1500); };
|
||||
ws.onmessage = (e) => {
|
||||
const ev = JSON.parse(e.data);
|
||||
if (ev.type === "state") setState(ev.state);
|
||||
else if (ev.type === "user") addTurn("user", "🗣️ " + ev.text);
|
||||
else if (ev.type === "assistant") addTurn("asst", "🤖 " + ev.text, ev.mode);
|
||||
else if (ev.type === "error") addTurn("err", "⚠️ " + ev.text);
|
||||
};
|
||||
}
|
||||
connect();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue