Boton cerrar y cerrar la pestaña apaga JARVIS
Cerrar el panel dejaba el proceso vivo (whisper agarrando la grafica, el microfono escuchando). Ahora hay un boton "cerrar" (dos clics) y cerrar la ultima pestaña apaga JARVIS del todo: para la voz, suelta whisper y cierra el proceso, via SIGINT (la misma limpieza que Ctrl+C).
This commit is contained in:
parent
3a2a1bb111
commit
fde0fc1c72
6 changed files with 95 additions and 10 deletions
|
|
@ -758,6 +758,13 @@
|
|||
} else if (tipo === "medidas") {
|
||||
ponMedidas(datos);
|
||||
|
||||
} else if (tipo === "cerrando") {
|
||||
// JARVIS se esta apagando: cerrar la ventana del panel. En chromium
|
||||
// --app window.close() cierra la ventana de la aplicacion.
|
||||
document.body.classList.add("parado");
|
||||
ponEstado("parado");
|
||||
setTimeout(() => { try { window.close(); } catch (e) {} }, 300);
|
||||
|
||||
} else if (tipo === "telemetria") {
|
||||
if (datos.nucleos) ponNucleos(datos.nucleos);
|
||||
ponConstantes(datos);
|
||||
|
|
@ -851,6 +858,35 @@
|
|||
}
|
||||
});
|
||||
|
||||
// Cerrar JARVIS del todo. Dos clics para no apagarlo por un roce: el primero
|
||||
// arma ("pulsa otra vez"), el segundo lo manda. Si no se confirma en 3 s,
|
||||
// vuelve a como estaba. Al confirmar, Python contesta "cerrando" y la ventana
|
||||
// se cierra sola.
|
||||
(function () {
|
||||
const b = document.getElementById("cerrar");
|
||||
if (!b) return;
|
||||
const rotulo = b.querySelector(".rotulo");
|
||||
let armado = false, reloj = null;
|
||||
b.addEventListener("click", () => {
|
||||
if (!armado) {
|
||||
armado = true;
|
||||
b.classList.add("armado");
|
||||
rotulo.textContent = "¿seguro?";
|
||||
reloj = setTimeout(() => {
|
||||
armado = false;
|
||||
b.classList.remove("armado");
|
||||
rotulo.textContent = "cerrar";
|
||||
}, 3000);
|
||||
return;
|
||||
}
|
||||
clearTimeout(reloj);
|
||||
rotulo.textContent = "cerrando";
|
||||
try {
|
||||
window.webkit.messageHandlers.accion.postMessage("cerrar");
|
||||
} catch (e) { /* suelto en el navegador: no hay Python que apagar */ }
|
||||
});
|
||||
})();
|
||||
|
||||
// Lanza la tanda de prueba. No cambia nada en el boton: lo que hay que mirar
|
||||
// son las tarjetas, que es justo lo que se quiere comprobar.
|
||||
document.getElementById("prueba").addEventListener("click", (ev) => {
|
||||
|
|
@ -944,14 +980,5 @@
|
|||
{ pid: 1201, nombre: "pipewire", cpu: 2.0, mem: 0.3 },
|
||||
],
|
||||
}});
|
||||
|
||||
window.jarvis.recibe({ tipo: "medidas", datos: {
|
||||
n: 240,
|
||||
lat_p50: 2.1, lat_p95: 4.8, lat_max: 7.2,
|
||||
lat_cerebro: 2.7, lat_catalogo: 0.2,
|
||||
pct_cerebro: 44, pct_catalogo: 53, pct_ruido: 3,
|
||||
vol24: 87, porhora: [2, 0, 1, 4, 6, 3, 5, 8, 4, 2, 1, 3],
|
||||
rag: { hit5: 95, hit1: 82 },
|
||||
}});
|
||||
}
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -159,6 +159,13 @@
|
|||
<button id="prueba" class="secundario" title="Lanza varias tareas reales a la vez para verlas trabajar">
|
||||
<span class="rotulo">prueba</span>
|
||||
</button>
|
||||
|
||||
<!-- Apaga JARVIS del todo: para la voz, suelta el microfono y la grafica, y
|
||||
cierra el proceso. Dos clics para no apagarlo por un roce. -->
|
||||
<button id="cerrar" class="secundario cerrar"
|
||||
title="Apagar JARVIS: cierra el panel, para la voz y suelta la gráfica">
|
||||
<span class="rotulo">cerrar</span>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<!-- candado: tapa todo hasta que se teclea la contraseña -->
|
||||
|
|
|
|||
|
|
@ -659,6 +659,13 @@ h2.separado { margin-top: 26px; }
|
|||
border-color: color-mix(in srgb, var(--mal) 60%, transparent);
|
||||
}
|
||||
|
||||
/* El boton de cerrar, armado tras el primer clic: rojo, para que se vea que el
|
||||
segundo clic apaga de verdad. */
|
||||
.controles button#cerrar.armado {
|
||||
color: var(--mal, #ff7a6b);
|
||||
border-color: var(--mal, #ff7a6b);
|
||||
}
|
||||
|
||||
.controles button:hover {
|
||||
color: var(--brillo);
|
||||
border-color: var(--acento);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ mirando: sin panel abierto son quince mensajes por segundo a nadie.
|
|||
"""
|
||||
import os
|
||||
import shutil
|
||||
import signal
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
|
|
@ -360,6 +361,20 @@ class Panel:
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
def cerrar(self):
|
||||
"""Apaga JARVIS entero: la escucha, la voz, whisper-server y el proceso.
|
||||
|
||||
Cerrar la pestaña o pulsar «cerrar» tiene que soltar de verdad el
|
||||
microfono y la grafica, no dejar el proceso escuchando en segundo plano.
|
||||
Se manda SIGINT al propio proceso: eso dispara el mismo apagado que
|
||||
Ctrl+C —el finally del bucle de escucha para whisper, y atexit lo remata—
|
||||
asi que se reutiliza la limpieza que ya estaba probada, sin duplicarla.
|
||||
Corre desde un hilo del servidor; la señal la atiende el hilo principal.
|
||||
"""
|
||||
self.parado = True # que la escucha no atienda nada mas ya
|
||||
self.para() # corta los hilos y las tareas del panel
|
||||
os.kill(os.getpid(), signal.SIGINT)
|
||||
|
||||
# --------------------------------------------------------------- pulsar
|
||||
|
||||
def pulsado(self, canal: str, dato: str):
|
||||
|
|
@ -417,6 +432,13 @@ class Panel:
|
|||
self.manda_controles()
|
||||
self.estado("escuchando" if not self.centinela.activo else "dormido")
|
||||
|
||||
elif dato == "cerrar":
|
||||
# Apagar JARVIS del todo. Se responde primero al HUD para que la
|
||||
# ventana sepa cerrarse, y luego se mata el proceso.
|
||||
self.cara.manda("cerrando", True)
|
||||
self.cerrar()
|
||||
return
|
||||
|
||||
elif dato.startswith("parar"):
|
||||
# El boton alterna PAUSA. No es solo "cortar lo de ahora": el titulo
|
||||
# promete "cierra el microfono y corta la voz; pulsa otra vez para
|
||||
|
|
|
|||
|
|
@ -42,10 +42,17 @@ FICHEROS = {
|
|||
class Cara:
|
||||
"""El panel: se le empujan eventos y devuelve lo que se pulsa."""
|
||||
|
||||
def __init__(self, al_pulsar=None, puerto=PUERTO):
|
||||
# Segundos que se espera tras cerrarse la ultima pestaña antes de apagar.
|
||||
# Da margen a una RECARGA (que cierra el socket y lo reabre enseguida) para
|
||||
# no confundirla con cerrar la ventana de verdad.
|
||||
GRACIA = 4
|
||||
|
||||
def __init__(self, al_pulsar=None, al_cerrar=None, puerto=PUERTO):
|
||||
self.al_pulsar = al_pulsar # (canal, dato) -> None
|
||||
self.al_cerrar = al_cerrar # se cerro la ultima pestaña -> apagar
|
||||
self.puerto = puerto
|
||||
self._clientes = set()
|
||||
self._hubo_cliente = False # para no apagar antes de abrir el panel
|
||||
self._bucle = None
|
||||
self._hilo = None
|
||||
self._ultimo = {} # el estado, para el que llegue tarde
|
||||
|
|
@ -124,6 +131,7 @@ class Cara:
|
|||
|
||||
async def _cliente(self, ws):
|
||||
self._clientes.add(ws)
|
||||
self._hubo_cliente = True
|
||||
try:
|
||||
# Al conectar se le manda el estado que ya habia. Sin esto, abrir el
|
||||
# panel a media sesion enseña un HUD vacio hasta que algo cambie.
|
||||
|
|
@ -146,6 +154,19 @@ class Cara:
|
|||
pass
|
||||
finally:
|
||||
self._clientes.discard(ws)
|
||||
# Se cerro una pestaña. Si no queda ninguna, se espera un poco (por
|
||||
# si es una recarga) y, si sigue sin haber panel abierto, se apaga
|
||||
# JARVIS: cerrar la ventana suelta el microfono y la grafica.
|
||||
if self._hubo_cliente and not self._clientes and self.al_cerrar:
|
||||
try:
|
||||
asyncio.get_running_loop().call_later(
|
||||
self.GRACIA, self._quiza_cerrar)
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
def _quiza_cerrar(self):
|
||||
if not self._clientes and self.al_cerrar:
|
||||
threading.Thread(target=self.al_cerrar, daemon=True).start()
|
||||
|
||||
# --------------------------------------------------------------- empujar
|
||||
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ def panel(boca: Boca, cerebro=None, escuchando=False, modelo="small",
|
|||
p = Panel(cara, boca, manos, cerebro, candado=not sin_candado,
|
||||
centinela=centinela)
|
||||
cara.al_pulsar = p.pulsado
|
||||
cara.al_cerrar = p.cerrar # cerrar la ultima pestaña apaga JARVIS
|
||||
url = cara.arranca()
|
||||
if not url:
|
||||
return 1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue