Spaces:
Running
Running
Tu Nombre commited on
Commit ·
d1dbb0b
1
Parent(s): fe91d69
Actualización: Cambio a modelo Llama 3.1 8B
Browse files- familiar.html +0 -147
- index.html +0 -130
familiar.html
DELETED
|
@@ -1,147 +0,0 @@
|
|
| 1 |
-
<!DOCTYPE html>
|
| 2 |
-
<html lang="es">
|
| 3 |
-
<head>
|
| 4 |
-
<meta charset="UTF-8">
|
| 5 |
-
<title>Visor Familiar</title>
|
| 6 |
-
<script src="https://unpkg.com/peerjs@1.5.2/dist/peerjs.min.js"></script>
|
| 7 |
-
<style>
|
| 8 |
-
body { background: #000; color: #0ff; font-family: sans-serif; text-align: center; }
|
| 9 |
-
#videoRemoto { width: 100%; max-width: 500px; border: 2px solid #0ff; border-radius: 10px; }
|
| 10 |
-
#alerta-box { display:none; position:fixed; top:0; left:0; width:100%; padding:20px;
|
| 11 |
-
font-size:1.5em; font-weight:bold; z-index:999; animation: parpadeo 0.5s infinite; }
|
| 12 |
-
.CRITICO { background: #f00; color: #fff; }
|
| 13 |
-
.MODERADO { background: #ff0; color: #000; }
|
| 14 |
-
@keyframes parpadeo { 0%,100%{opacity:1} 50%{opacity:0.3} }
|
| 15 |
-
#historial { text-align:left; max-width:500px; margin:10px auto;
|
| 16 |
-
background:#111; border-radius:8px; padding:10px; max-height:200px; overflow-y:auto; }
|
| 17 |
-
#vitales-familiar { display:flex; justify-content:center; gap:20px; margin:10px auto; max-width:500px; }
|
| 18 |
-
.vital-f { background:#1a1a1a; border-radius:8px; padding:8px 16px; font-size:0.9em; color:#fff; }
|
| 19 |
-
.vital-f span { font-size:1.3em; font-weight:bold; display:block; }
|
| 20 |
-
.v-normal { color: #0f0; }
|
| 21 |
-
.v-bajo { color: #ff0; }
|
| 22 |
-
.v-critico { color: #f00; }
|
| 23 |
-
</style>
|
| 24 |
-
</head>
|
| 25 |
-
<body>
|
| 26 |
-
<div id="alerta-box"></div>
|
| 27 |
-
<h1>👁️ Visor Familiar</h1>
|
| 28 |
-
<input type="text" id="familiarNombre" placeholder="Tu nombre (ej: maria)..." style="padding:10px;width:80%;">
|
| 29 |
-
<button onclick="registrar()" style="padding:15px;width:80%;margin-top:10px;">📡 CONECTAR Y VIGILAR</button>
|
| 30 |
-
<div id="status">Esperando...</div>
|
| 31 |
-
<video id="videoRemoto" autoplay playsinline></video>
|
| 32 |
-
|
| 33 |
-
<!-- Vitales en tiempo real -->
|
| 34 |
-
<div id="vitales-familiar">
|
| 35 |
-
<div class="vital-f">
|
| 36 |
-
💧 Oxígeno
|
| 37 |
-
<span id="f-oxigeno" class="v-normal">--</span>
|
| 38 |
-
</div>
|
| 39 |
-
<div class="vital-f">
|
| 40 |
-
❤️ Corazón
|
| 41 |
-
<span id="f-corazon" class="v-normal">--</span>
|
| 42 |
-
</div>
|
| 43 |
-
</div>
|
| 44 |
-
|
| 45 |
-
<div id="historial"><b>📋 Historial Groq:</b><br></div>
|
| 46 |
-
|
| 47 |
-
<script>
|
| 48 |
-
let peer = null;
|
| 49 |
-
let ws = null;
|
| 50 |
-
let audioCtx = null;
|
| 51 |
-
|
| 52 |
-
function registrar() {
|
| 53 |
-
const nombre = document.getElementById('familiarNombre').value.trim().toLowerCase();
|
| 54 |
-
|
| 55 |
-
const wsUrl = (location.protocol === 'https:' ? 'wss' : 'ws') + '://' + location.host + '/ws/familiar';
|
| 56 |
-
ws = new WebSocket(wsUrl);
|
| 57 |
-
ws.onmessage = (e) => {
|
| 58 |
-
const data = JSON.parse(e.data);
|
| 59 |
-
manejarAlerta(data);
|
| 60 |
-
};
|
| 61 |
-
|
| 62 |
-
if (peer) peer.destroy();
|
| 63 |
-
peer = new Peer("fam-" + nombre, {
|
| 64 |
-
host: '0.peerjs.com', port: 443, path: '/', secure: true,
|
| 65 |
-
config: { iceServers: [
|
| 66 |
-
{ urls: 'stun:stun.l.google.com:19302' },
|
| 67 |
-
{ urls: 'stun:stun1.l.google.com:19302' }
|
| 68 |
-
]}
|
| 69 |
-
});
|
| 70 |
-
peer.on('open', (id) => {
|
| 71 |
-
document.getElementById('status').textContent = "🟡 Registrado: " + id + " — Esperando paciente...";
|
| 72 |
-
});
|
| 73 |
-
peer.on('call', (call) => {
|
| 74 |
-
call.answer();
|
| 75 |
-
call.on('stream', (remoteStream) => {
|
| 76 |
-
const video = document.getElementById('videoRemoto');
|
| 77 |
-
video.srcObject = remoteStream;
|
| 78 |
-
video.play().catch(() => video.addEventListener('click', () => video.play(), { once: true }));
|
| 79 |
-
document.getElementById('status').textContent = "🟢 VÍDEO EN VIVO + GROQ VIGILANDO";
|
| 80 |
-
});
|
| 81 |
-
call.on('close', () => {
|
| 82 |
-
document.getElementById('status').textContent = "🔴 Paciente desconectado";
|
| 83 |
-
document.getElementById('videoRemoto').srcObject = null;
|
| 84 |
-
});
|
| 85 |
-
});
|
| 86 |
-
peer.on('error', (err) => {
|
| 87 |
-
document.getElementById('status').textContent = "❌ " + err.message;
|
| 88 |
-
});
|
| 89 |
-
}
|
| 90 |
-
|
| 91 |
-
function manejarAlerta(data) {
|
| 92 |
-
const nivel = data.nivel || 'NORMAL';
|
| 93 |
-
const mensaje = data.mensaje || '';
|
| 94 |
-
const hora = new Date().toLocaleTimeString();
|
| 95 |
-
const iconos = { CRITICO: '🔴', MODERADO: '🟡', NORMAL: '🟢' };
|
| 96 |
-
const mapClase = { NORMAL: 'v-normal', BAJO: 'v-bajo', ALTERADO: 'v-bajo', CRITICO: 'v-critico' };
|
| 97 |
-
const iconO2 = { NORMAL: '🟢', BAJO: '🟡', CRITICO: '🔴' };
|
| 98 |
-
const iconFC = { NORMAL: '🟢', ALTERADO: '🟡', CRITICO: '🔴' };
|
| 99 |
-
|
| 100 |
-
// Actualizar vitales en familiar
|
| 101 |
-
if (data.oxigeno_visual) {
|
| 102 |
-
const el = document.getElementById('f-oxigeno');
|
| 103 |
-
el.textContent = (iconO2[data.oxigeno_visual] || '⚪') + ' ' + data.oxigeno_visual;
|
| 104 |
-
el.className = mapClase[data.oxigeno_visual] || 'v-normal';
|
| 105 |
-
}
|
| 106 |
-
if (data.corazon_visual) {
|
| 107 |
-
const el = document.getElementById('f-corazon');
|
| 108 |
-
el.textContent = (iconFC[data.corazon_visual] || '⚪') + ' ' + data.corazon_visual;
|
| 109 |
-
el.className = mapClase[data.corazon_visual] || 'v-normal';
|
| 110 |
-
}
|
| 111 |
-
|
| 112 |
-
// Historial
|
| 113 |
-
const historial = document.getElementById('historial');
|
| 114 |
-
const entrada = document.createElement('div');
|
| 115 |
-
entrada.textContent = hora + ' — ' + (iconos[nivel] || '⚪') + ' ' + mensaje;
|
| 116 |
-
entrada.style.color = nivel === 'CRITICO' ? '#f88' : nivel === 'MODERADO' ? '#ff0' : '#0f0';
|
| 117 |
-
historial.appendChild(entrada);
|
| 118 |
-
historial.scrollTop = historial.scrollHeight;
|
| 119 |
-
|
| 120 |
-
// Alerta visual + sonido
|
| 121 |
-
const box = document.getElementById('alerta-box');
|
| 122 |
-
if (nivel === 'CRITICO' || nivel === 'MODERADO') {
|
| 123 |
-
box.textContent = (iconos[nivel]) + ' ' + nivel + ': ' + mensaje;
|
| 124 |
-
box.className = 'alerta-box ' + nivel;
|
| 125 |
-
box.style.display = 'block';
|
| 126 |
-
sonarAlarma(nivel);
|
| 127 |
-
setTimeout(() => box.style.display = 'none', 8000);
|
| 128 |
-
}
|
| 129 |
-
}
|
| 130 |
-
|
| 131 |
-
function sonarAlarma(nivel) {
|
| 132 |
-
try {
|
| 133 |
-
if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
| 134 |
-
const osc = audioCtx.createOscillator();
|
| 135 |
-
const gain = audioCtx.createGain();
|
| 136 |
-
osc.connect(gain);
|
| 137 |
-
gain.connect(audioCtx.destination);
|
| 138 |
-
osc.frequency.value = nivel === 'CRITICO' ? 880 : 440;
|
| 139 |
-
osc.type = 'square';
|
| 140 |
-
gain.gain.value = 0.3;
|
| 141 |
-
osc.start();
|
| 142 |
-
osc.stop(audioCtx.currentTime + (nivel === 'CRITICO' ? 2 : 1));
|
| 143 |
-
} catch(e) {}
|
| 144 |
-
}
|
| 145 |
-
</script>
|
| 146 |
-
</body>
|
| 147 |
-
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
index.html
DELETED
|
@@ -1,130 +0,0 @@
|
|
| 1 |
-
<!DOCTYPE html>
|
| 2 |
-
<html lang="es">
|
| 3 |
-
<head>
|
| 4 |
-
<meta charset="UTF-8">
|
| 5 |
-
<title>Paciente</title>
|
| 6 |
-
<script src="https://unpkg.com/peerjs@1.5.2/dist/peerjs.min.js"></script>
|
| 7 |
-
<style>
|
| 8 |
-
body { background: #000; color: #fff; font-family: sans-serif; text-align: center; }
|
| 9 |
-
#video { width: 100%; max-width: 500px; border: 2px solid #0f0; border-radius: 10px; }
|
| 10 |
-
#analisis { margin-top: 10px; padding: 10px; border-radius: 8px; background: #111; max-width: 500px; margin: 10px auto; }
|
| 11 |
-
.CRITICO { color: #f00; font-weight: bold; font-size: 1.2em; }
|
| 12 |
-
.MODERADO { color: #ff0; }
|
| 13 |
-
.NORMAL { color: #0f0; }
|
| 14 |
-
#vitales { display: flex; justify-content: center; gap: 20px; margin-top: 8px; }
|
| 15 |
-
.vital { background: #1a1a1a; border-radius: 8px; padding: 8px 16px; font-size: 0.9em; }
|
| 16 |
-
.vital span { font-size: 1.3em; font-weight: bold; display: block; }
|
| 17 |
-
.v-normal { color: #0f0; }
|
| 18 |
-
.v-bajo { color: #ff0; }
|
| 19 |
-
.v-critico { color: #f00; }
|
| 20 |
-
</style>
|
| 21 |
-
</head>
|
| 22 |
-
<body>
|
| 23 |
-
<h1>🏥 Monitor Paciente</h1>
|
| 24 |
-
<input type="text" id="nombreInput" placeholder="Tu nombre (ej: cristobal)..." style="padding:10px;width:80%;">
|
| 25 |
-
<input type="text" id="familiarInput" placeholder="Nombre del familiar (ej: maria)..." style="padding:10px;width:80%;">
|
| 26 |
-
<button onclick="iniciar()" style="padding:15px;width:80%;margin-top:10px;">▶ INICIAR MONITORIZACIÓN</button>
|
| 27 |
-
<h2 id="status">INACTIVO</h2>
|
| 28 |
-
<video id="video" autoplay muted playsinline></video>
|
| 29 |
-
<canvas id="canvas" style="display:none;"></canvas>
|
| 30 |
-
|
| 31 |
-
<div id="analisis">
|
| 32 |
-
<div id="nivelGroq" class="NORMAL">🟢 Sistema listo</div>
|
| 33 |
-
<div id="mensajeGroq"></div>
|
| 34 |
-
<div id="vitales">
|
| 35 |
-
<div class="vital">
|
| 36 |
-
💧 Oxígeno
|
| 37 |
-
<span id="oxigeno-val" class="v-normal">--</span>
|
| 38 |
-
</div>
|
| 39 |
-
<div class="vital">
|
| 40 |
-
❤️ Corazón
|
| 41 |
-
<span id="corazon-val" class="v-normal">--</span>
|
| 42 |
-
</div>
|
| 43 |
-
</div>
|
| 44 |
-
</div>
|
| 45 |
-
|
| 46 |
-
<script>
|
| 47 |
-
let localStream, peer, ws;
|
| 48 |
-
let intervaloAnalisis = null;
|
| 49 |
-
|
| 50 |
-
async function iniciar() {
|
| 51 |
-
const nombre = document.getElementById('nombreInput').value.trim().toLowerCase();
|
| 52 |
-
const familiar = document.getElementById('familiarInput').value.trim().toLowerCase();
|
| 53 |
-
|
| 54 |
-
try {
|
| 55 |
-
localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
|
| 56 |
-
document.getElementById('video').srcObject = localStream;
|
| 57 |
-
} catch (e) {
|
| 58 |
-
document.getElementById('status').textContent = "❌ Cámara: " + e.message;
|
| 59 |
-
return;
|
| 60 |
-
}
|
| 61 |
-
|
| 62 |
-
const wsUrl = (location.protocol === 'https:' ? 'wss' : 'ws') + '://' + location.host + '/ws/paciente';
|
| 63 |
-
ws = new WebSocket(wsUrl);
|
| 64 |
-
ws.onopen = () => {
|
| 65 |
-
document.getElementById('status').textContent = "🔗 Groq conectado — iniciando análisis...";
|
| 66 |
-
iniciarAnalisis();
|
| 67 |
-
};
|
| 68 |
-
ws.onmessage = (e) => {
|
| 69 |
-
const data = JSON.parse(e.data);
|
| 70 |
-
if (data.analisis) mostrarAnalisis(data.analisis);
|
| 71 |
-
};
|
| 72 |
-
ws.onerror = () => document.getElementById('status').textContent = "❌ Error WebSocket";
|
| 73 |
-
|
| 74 |
-
if (peer) peer.destroy();
|
| 75 |
-
peer = new Peer("pac-" + nombre, {
|
| 76 |
-
host: '0.peerjs.com', port: 443, path: '/', secure: true,
|
| 77 |
-
config: { iceServers: [
|
| 78 |
-
{ urls: 'stun:stun.l.google.com:19302' },
|
| 79 |
-
{ urls: 'stun:stun1.l.google.com:19302' }
|
| 80 |
-
]}
|
| 81 |
-
});
|
| 82 |
-
peer.on('open', () => {
|
| 83 |
-
document.getElementById('status').textContent = "📞 Llamando a familiar...";
|
| 84 |
-
const call = peer.call("fam-" + familiar, localStream);
|
| 85 |
-
call.on('stream', () => document.getElementById('status').textContent = "🟢 FAMILIAR CONECTADO + GROQ ACTIVO");
|
| 86 |
-
call.on('error', (err) => document.getElementById('status').textContent = "❌ " + err.message);
|
| 87 |
-
});
|
| 88 |
-
peer.on('error', (err) => document.getElementById('status').textContent = "❌ PeerJS: " + err.message);
|
| 89 |
-
}
|
| 90 |
-
|
| 91 |
-
function iniciarAnalisis() {
|
| 92 |
-
const video = document.getElementById('video');
|
| 93 |
-
const canvas = document.getElementById('canvas');
|
| 94 |
-
const ctx = canvas.getContext('2d');
|
| 95 |
-
if (intervaloAnalisis) clearInterval(intervaloAnalisis);
|
| 96 |
-
intervaloAnalisis = setInterval(() => {
|
| 97 |
-
if (video.readyState < 2) return;
|
| 98 |
-
canvas.width = 640;
|
| 99 |
-
canvas.height = 480;
|
| 100 |
-
ctx.drawImage(video, 0, 0, 640, 480);
|
| 101 |
-
const frame = canvas.toDataURL('image/jpeg', 0.7).split(',')[1];
|
| 102 |
-
if (ws && ws.readyState === WebSocket.OPEN) {
|
| 103 |
-
ws.send(JSON.stringify({ frame }));
|
| 104 |
-
}
|
| 105 |
-
}, 5000);
|
| 106 |
-
}
|
| 107 |
-
|
| 108 |
-
function mostrarAnalisis(a) {
|
| 109 |
-
const iconos = { CRITICO: '🔴', MODERADO: '🟡', NORMAL: '🟢' };
|
| 110 |
-
const elNivel = document.getElementById('nivelGroq');
|
| 111 |
-
elNivel.className = a.nivel;
|
| 112 |
-
elNivel.textContent = (iconos[a.nivel] || '⚪') + ' ' + a.nivel;
|
| 113 |
-
document.getElementById('mensajeGroq').textContent = a.mensaje;
|
| 114 |
-
|
| 115 |
-
// Vitales visuales
|
| 116 |
-
const mapClase = { NORMAL: 'v-normal', BAJO: 'v-bajo', ALTERADO: 'v-bajo', CRITICO: 'v-critico' };
|
| 117 |
-
const iconO2 = { NORMAL: '🟢', BAJO: '🟡', CRITICO: '🔴' };
|
| 118 |
-
const iconFC = { NORMAL: '🟢', ALTERADO: '🟡', CRITICO: '🔴' };
|
| 119 |
-
|
| 120 |
-
const oxEl = document.getElementById('oxigeno-val');
|
| 121 |
-
oxEl.textContent = (iconO2[a.oxigeno_visual] || '⚪') + ' ' + (a.oxigeno_visual || '--');
|
| 122 |
-
oxEl.className = mapClase[a.oxigeno_visual] || 'v-normal';
|
| 123 |
-
|
| 124 |
-
const fcEl = document.getElementById('corazon-val');
|
| 125 |
-
fcEl.textContent = (iconFC[a.corazon_visual] || '⚪') + ' ' + (a.corazon_visual || '--');
|
| 126 |
-
fcEl.className = mapClase[a.corazon_visual] || 'v-normal';
|
| 127 |
-
}
|
| 128 |
-
</script>
|
| 129 |
-
</body>
|
| 130 |
-
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|