--- title: HF Realtime Voice emoji: 🎙️ colorFrom: indigo colorTo: purple sdk: docker app_port: 7860 pinned: false short_description: Voice chat over WebSocket against a HF speech-to-speech hf_oauth: true --- # Realtime Voice Demo (WebSocket transport) Browser voice-chat UI for the backend. The browser streams mic audio over a WebSocket using the OpenAI Realtime **GA** protocol and plays back the assistant's audio as it arrives. --- ## 🆕 Novedades / Actualizaciones (Azurian Vocero realtime ver.Beta 2.1) > Versión del navegador que debes ver cargada en consola: **`2026-09-04 11:20`**. > Si no aparece, haz **borrado de datos del sitio + recarga dura (Ctrl+Shift+R)** o abre una pestaña en modo incógnito. ### 🎨 Rediseño visual completo (tema aurora + glassmorphism) - **Tema de fondo aurora**: gradiente radial violeta/rosa/cian sobre lienzo oscuro con malla sutil + animación `auroraShift` lenta. - **Cromado uniforme glass**: todos los elementos flotantes (tarjeta brand, panel user profile, botones icono, botón enviar chat, panel informes sidebar) usan *glass blur + saturate + borde gradiente brand 1px* (técnica mask `padding-box / border-box` doble linear-gradient). - **Tokens de marca 3 colores brand** (violeta `#8b5cf6`, rosa `#ec4899`, cian `#22d3ee`) mezclados con `color-mix(in srgb, brand X%, neutral)` → ningún color hardcodeado deriva; todo el UI sigue estos tres tonos. ### 🧭 Estructura (orden vertical de arriba → abajo) 1. **`header.topbar`** brand "Vocero" → avatar circular iniciales nombre usuario. - 🟦 **Avatar user**: círculo 40×40px con gradiente brand, initials mayúsculas bold 800, hover lift/glow + foco teclado. Al hacer clic → diálogo modal perfil usuario (rejilla 2 columnas email/teléfono/username/rol/empresa/userid/país/fecha creación/último login; links `mailto:`/`tel:`; chips mono para códigos; mobile ≤480px apilado 1 col). - 🟦 **Botón toggle chat (icono speech bubble) → ELIMINADO PERMANENTEMENTE**. La chat ahora siempre está visible inline; el botón toggle ya no existe en el DOM. 2. **`main.stage`** (arriba del todo, flexible): orbe/globode voz animado (3 anillos: core, ring, conic spin 3 velocidades + highlight specular + glows breathe `breatheOrb`) + caption `TAP OR SAY "HOLA VOCERO"` micro-bob uppercase gradient. - ✅ Antes había una zona vacía sobre el orbe → eliminada, ahora el stage empieza en la parte superior (`justify-content: flex-start`). 3. **`
` SIEMPRE VISIBLE, 100% ancho, SOTTO stage, SOPRA footer sticky** (rellena la zona vacía inferior). - ✅ Antes: overlay lateral derecho. **Ahora: bloque inline dentro de `#app` como hijo flex-col**. - 🟦 Sin marco / sin riquadro (fondo aurora seamless, 0 borde, 0 shadow, 0 backdrop blur). - Cabecera `CONVERSACIÓN` h3 uppercase 13px gradiente. - `#chat-history` scroll interno. Burbujas de mensaje glass con **código de colores por rol**: usuario (tint 10% voice-user cyan + borde 44% cyan + glow) / assistant (tint 10% voice-assistant violet/pink + borde 42% + glow). - Distancias seguras anti-borde: `.hist-msg.user margin-left:6px auto dx` / `.hist-msg.assistant margin-right:22px auto sx` → **nunca las burbujas tocan el borde del viewport** (fix confirmado). - Formulario input texto `#chat-form` (arriba del botón enviar ✈️) **actualmente oculto (`hidden`)** para modo voz-puro; elimina ese atributo para reactivarlo. El handler submit que envía `client.sendUserText(text)` al websocket ya está conectado. 4. **Footer sticky `position: sticky; bottom:0; z:3; backdrop-blur`** "Azurian Vocero realtime ver.Beta 2.1" siempre dentro del viewport, incluso cuando el documento crece y haces scroll (no requiere scroll hacia abajo para verlo). Separador superior línea gradiente brand. ### 📜 Sidebar de informes a la IZQUIERDA (antes topbar inline) - Desktop **≥ 1024px**: sidebar fija left 320px siempre visible; `#app padding-left 320px` reserva sitio. - Tablet/Mobile **< 1024**: offcanvas `translateX(-105%)` slide-in con backdrop blur; toggle mediante botón icono reportes `#reports-sidebar-toggle` en topbar con badge contador. - `#reports-hint` siempre visible; `.reports-suggestions` y `.topbar-right` con puerta triple de visibilidad (atributo HTML hidden + CSS rule `[data-debug-only]:not([data-debug-enabled]) !important display:none` + JS `applyDebugOnlyVisibilityGate()` ejecutado 6 veces por lifecycle) → solo aparecen cuando el query param `?debug=true` está presente en la URL. ### ⬇️ Auto-scroll chat SIEMPRE hacia la última respuesta del asistente Arquitectura anti-clipping definitiva (versión 11:20 fix): 1. **CSS sobrante intencional** (`96 → 160px chat-history padding-bottom`, `40→160px chat-panel clamp`, `56→120px #app padding-bottom + safe-area-inset-bottom`) → el último párrafo siempre está por ENCIMA de la línea del footer glass flotante. 2. **Unidades móviles seguras `svh / svw`** (smallest viewport): evita oscilaciones layout cuando aparece/desaparece la barra URL del móvil. 3. **JS cancel-and-reschedule** cada vez que `_scrollToBottom()` se llama: si llegan 100 tokens streaming en 1 frame, el último cancela todas las cadenas pendientes y se ejecuta desde cero → **no hay coalescing flag SKIP** (esta era la causa original del scroll insuficiente). 4. **5 reintentos escalonados `0 / +30 / +70 / +150 / +250ms`**: - 0 ms (inmediato): 90% de los casos. - 30 ms: tras 1 layout-pass. - 70 ms: **corrige el wrapping de la última palabra en una línea nueva** (bug más común). - 150 ms: después de reflow Chrome scroll-anchor. - 250 ms: después de expandir filas tool / imágenes grandes. 5. **Snap con `Number.MAX_SAFE_INTEGER`**: el navegador clampa automáticamente al máximo real (`scrollHeight - clientHeight`); no hay race de leer scrollHeight demasiado pronto. 6. `overflow-anchor: none; scroll-behavior: auto !important;` → sin smooth, sin Chrome scroll-anchor-luchando contra nosotros. 7. Llamadas scroll explicitas extra en: `onResponseFinished` (fin de respuesta assistant, crítico), `onToolCall`, `onToolResult`. ### 🛡️ Protecciones anti-error de refs eliminadas - En el refactor de chat eliminamos 4 nodos DOM (`#chat-btn`, `#chat-badge`, `#chat-panel-backdrop`, `#chat-panel-close`). - **Antes**: el constructor de `ChatView` usaba `$("#...")` strict → lanzaba `Error("Missing element: #chat-btn")` al arrancar. - **Ahora**: esas 4 refs opcionales usan `document.querySelector("#...")` → devuelve `null` cuando no existen, sin throw; todos los listeners guarded `if (el)`. Los 3 IDs obligatorios (`#chat-panel`, `#chat-history`, `#bubble-stack`) siguen con strict para fallar fuerte si alguien los borra por error. ### 🔄 Actualizaciones de versión / cache bust Para evitar caché HTTP agresiva en navegadores móviles (ESM sin bundler + service worker = nunca refrescan URLs iguales), todas las referencias a recursos estáticos usan query param `?v=YYYYMMDDHHMM` sincronizado en **6 puntos**: 1. `index.html ` 2. `index.html