Skip to content

Latest commit

Β 

History

29 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🐱 Michibot

El primer asistente de voz conversacional en espaΓ±ol LATAM que se siente humano

Un robot de escritorio que te escucha, te entiende y te responde en menos de un segundo.

Python FastAPI ESP32-S3 License: MIT Week 1 LATAM

Quick Start Β· Arquitectura Β· Performance Β· Roadmap Β· Contribuir


πŸ’‘ ΒΏDe quΓ© se trata?

La mayorΓ­a de los asistentes de voz DIY son lentos. Entre que terminΓ‘s de hablar y escuchΓ‘s la primera palabra del robot pasan 2 a 4 segundos. Arriba de 1.5 s se siente robot-lento. Arriba de 3 s el usuario abandona.

Michibot tiene un solo objetivo: que la primera palabra del robot sea audible en menos de 900 ms en turnos complejos, y en menos de 200 ms en respuestas conocidas. A esa velocidad la conversaciΓ³n deja de sentirse como hablarle a una mΓ‘quina.

No es magia β€” es la suma de decisiones de arquitectura que la mayorΓ­a de los proyectos DIY no toman: streaming end-to-end desde el primer dΓ­a, wake word on-device, un router de 3 tiers que evita llamar al LLM en el 70 % de los turnos, proveedores cloud especializados por etapa, y pre-warming de todas las conexiones.

Michibot es la fusiΓ³n de ElectronBot (cuerpo + servos + display) y EchoEar (audio ESP32-S3), con un backend en Python que lo hace conversacional.


⚑ Performance

Medido en condiciones reales β€” desktop LATAM contra PoPs US-East, red domΓ©stica:

Tier QuΓ© hace p50 first-audio Costo / turno % de turnos
T1 Β· Canned Respuesta WAV pre-sintetizada desde disco ~15 ms $0.000000 ~40 %
T2 Β· Template Datos locales β†’ Cartesia streaming ~235 ms ~$0.0019 ~30 %
T3 Β· LLM full STT β†’ Groq Llama 70B β†’ Cartesia, con speculative TTS ~586 ms ~$0.0065 ~30 %

Costo promedio ponderado: ~$0.0027 por turno. Con 600 turnos/mes el costo variable es ~$1.60 β€” margen suficiente para una subscripciΓ³n de $9.99/mes.

πŸ”¬ El T2 bajΓ³ de 935 ms β†’ 235 ms (βˆ’700 ms) al hacer la conexiΓ³n WebSocket a Cartesia persistente. Ver adapters/tts_cartesia.py.


✨ Highlights

  • 🎯 Intent Router 3-tier β€” el 70 % de los turnos se responden sin llamar al LLM
  • ⚑ Streaming end-to-end desde el primer dΓ­a (speculative TTS por frase)
  • πŸ›‘ Barge-in nativo β€” interrumpΓ­s al robot hablando encima, se calla al toque
  • πŸ”Œ Adapter pattern puro β€” swapeΓ‘s proveedores editando un YAML, cero if provider ==
  • ☁️ Dual-mode cloud / local β€” misma interfaz, Deepgram/Groq/Cartesia o whisper.cpp/Ollama/Piper
  • πŸ”₯ Pre-warming de WebSockets β€” la primera respuesta no paga el handshake
  • πŸ“Š Cost tracker + mΓ©tricas JSONL β€” p50/p95 y costo por tier con un script
  • 🐱 Wake word "Hola Michi" β€” entrenable, on-device vΓ­a microWakeWord en Week 2
  • πŸ€– Un solo chip β€” ESP32-S3 maneja audio + WiFi + servos + display (Week 2-3)

πŸ—οΈ Arquitectura

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ DEVICE (ESP32-S3 β€” Week 2-3) ───────────────────┐
β”‚                                                                       β”‚
β”‚   mic I2S ──▢ ESP-SR AFE ──▢ microWakeWord("Hola Michi")             β”‚
β”‚                                          β”‚                            β”‚
β”‚                                          β–Ό                            β”‚
β”‚                                  ACK filler <50 ms                    β”‚
β”‚                                          β”‚                            β”‚
β”‚                                          β–Ό                            β”‚
β”‚                               WebSocket client                        β”‚
β”‚   speaker I2S ◀── audio playback ◀── WebSocket client                 β”‚
β”‚   display GC9A01 ◀── face animation ◀── event handler                 β”‚
β”‚   servos (portados del STM32 original)                                β”‚
β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
     β”‚   WebSocket binario (PCM 16 kHz) + JSON control
     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ BACKEND (FastAPI Β· async) ───────────────────────┐
β”‚                                                                        β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚
β”‚   β”‚         VoiceSessionOrchestrator                      β”‚           β”‚
β”‚   β”‚    STT stream ──▢ Intent Router ──▢ response stream   β”‚           β”‚
β”‚   β”‚                     β”‚   β”‚   β”‚                          β”‚           β”‚
β”‚   β”‚                     β–Ό   β–Ό   β–Ό                           β”‚           β”‚
β”‚   β”‚              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”            β”‚           β”‚
β”‚   β”‚              β”‚  T1  Canned     ~15 ms      β”‚  ~40 %    β”‚           β”‚
β”‚   β”‚              β”‚  T2  Template   ~235 ms     β”‚  ~30 %    β”‚           β”‚
β”‚   β”‚              β”‚  T3  LLM full   ~586 ms     β”‚  ~30 %    β”‚           β”‚
β”‚   β”‚              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β”‚           β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚
β”‚                  β–²            β–²            β–²                            β”‚
β”‚                  β”‚            β”‚            β”‚                            β”‚
β”‚              Deepgram      Groq 70B     Cartesia                        β”‚
β”‚              Nova-3        500 tok/s    Sonic                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

El truco estΓ‘ en el router

Cada turno pasa primero por un Intent Router que clasifica en 3 tiers:

Tier CuΓ‘ndo dispara QuΓ© ejecuta Costo
T1 Match regex contra ~18 frases canned (saludos, cortesΓ­as, afirmaciones) Lee un WAV del disco y lo stremea al cliente $0
T2 Match contra handlers de template (ej: "ΒΏquΓ© hora es?") Genera texto con datos locales, manda a TTS streaming Solo TTS
T3 Fallback: cualquier cosa que no matchee T1/T2 Pipeline completo STT β†’ Groq Llama 70B β†’ Cartesia con speculative TTS Los 3

El ~70 % de los turnos de una conversaciΓ³n real caen en T1/T2. Por eso la latencia percibida promedio es muchΓ­simo mΓ‘s baja que el peor caso.


πŸš€ Quick Start

Prerrequisitos

  • Python 3.11+
  • uv β€” gestor de dependencias rΓ‘pido
  • MicrΓ³fono y parlantes funcionando
  • 3 API keys (las 3 tienen free tier):

InstalaciΓ³n

git clone https://github.com/<tu-user>/michibot.git
cd michibot
uv sync
cp env.example.txt .env
# EditΓ‘ .env y pegΓ‘ las 3 API keys

Correr

# Terminal 1 β€” backend
uv run uvicorn electronbot_es.server.app:app --host 127.0.0.1 --port 8000

# Terminal 2 β€” cliente mock con wake word
uv run python -m electronbot_es.mock.mock_esp32 --wake-word

# DecΓ­ "hey jarvis" (placeholder β€” el real "Hola Michi" llega en Week 2)

Ver mΓ©tricas

uv run python scripts/metrics.py --last 20
Ejemplo de salida
=== Michibot metrics β€” 20 turns ===

tier    n     %   first_audio p50   p95   tts_first p50   p95    avg_cost   total
---------------------------------------------------------------------------------
T1      8   40%            15 ms   30 ms          15 ms   30 ms  $0.000000 $0.0000
T2      6   30%           235 ms  280 ms         235 ms  280 ms  $0.001878 $0.0113
T3      6   30%           586 ms  820 ms         586 ms  820 ms  $0.006514 $0.0391
---------------------------------------------------------------------------------
total cost: $0.0504   avg/turn: $0.002520
T3 tokens avg: in=225  out=41
T1+T2 match rate: 70%  (target >60%)

🧱 Estructura del repo

michibot/
β”œβ”€β”€ src/electronbot_es/
β”‚   β”œβ”€β”€ core/
β”‚   β”‚   β”œβ”€β”€ orchestrator.py     # VoiceSessionOrchestrator + speculative TTS
β”‚   β”‚   β”œβ”€β”€ cost.py             # EstimaciΓ³n de costo por turno
β”‚   β”‚   β”œβ”€β”€ obs.py              # Logger JSONL de mΓ©tricas
β”‚   β”‚   β”œβ”€β”€ messages.py         # Schemas pydantic del protocolo WebSocket
β”‚   β”‚   β”œβ”€β”€ protocols.py        # STT / LLM / TTS como Protocol
β”‚   β”‚   β”œβ”€β”€ persona.py          # System prompt LATAM del LLM
β”‚   β”‚   └── config.py
β”‚   β”œβ”€β”€ router/
β”‚   β”‚   β”œβ”€β”€ intent_router.py    # DecisiΓ³n T1 / T2 / T3
β”‚   β”‚   β”œβ”€β”€ canned_responses.yaml
β”‚   β”‚   └── templates/          # Handlers T2 (hora, clima, etc.)
β”‚   β”œβ”€β”€ adapters/
β”‚   β”‚   β”œβ”€β”€ stt_deepgram.py      Β·  stt_whisper.py
β”‚   β”‚   β”œβ”€β”€ llm_groq.py          Β·  llm_claude.py   Β·  llm_ollama.py
β”‚   β”‚   └── tts_cartesia.py      Β·  tts_piper.py
β”‚   β”œβ”€β”€ server/
β”‚   β”‚   └── app.py              # FastAPI + /ws/voice
β”‚   └── mock/
β”‚       β”œβ”€β”€ mock_esp32.py       # Cliente de desarrollo (mic + speaker + WS)
β”‚       └── wake_word.py        # openWakeWord wrapper
β”œβ”€β”€ docs/
β”‚   β”œβ”€β”€ protocol.md             # Contrato WebSocket v1 (inmutable)
β”‚   β”œβ”€β”€ roadmap.md              # Weeks 2-12+
β”‚   β”œβ”€β”€ hardware.md             # Decisiones de hardware
β”‚   β”œβ”€β”€ cloud-providers.md      # Setup Deepgram / Groq / Cartesia
β”‚   └── llm-benchmark.md        # Benchmark espaΓ±ol LATAM
β”œβ”€β”€ assets/canned/              # WAVs pre-sintetizados (T1)
β”œβ”€β”€ scripts/                    # generate_canned, metrics, benchmarks, ...
└── tests/                      # pytest Β· 40+ tests

πŸ› οΈ Stack tΓ©cnico

Backend

  • FastAPI + Uvicorn (async)
  • Pydantic v2 (schemas WS)
  • structlog / JSONL
  • pytest + pytest-asyncio

Cloud providers

  • Deepgram Nova-3 (STT)
  • Groq Llama 3.3 70B (LLM)
  • Cartesia Sonic (TTS)
  • Anthropic Haiku (fallback)

Local / dev

  • whisper.cpp (STT)
  • Ollama Llama 3.2 3B (LLM)
  • Piper es_MX (TTS)
  • openWakeWord (baseline)

Device (Week 2+)

  • ESP32-S3 (β‰₯8 MB PSRAM)
  • ESP-IDF 5.x
  • ESP-SR AFE (AEC + VAD)
  • microWakeWord (TFLM)

Mobile (Week 7+)

  • React Native + Expo
  • Supabase (auth + DB)
  • RevenueCat (subs)

Tooling

  • uv (deps)
  • ruff + mypy
  • GitHub Actions (CI)

πŸ“ˆ Roadmap

Semana Objetivo Estado
W1 Backend + mock + router + observabilidad βœ…
W2 Firmware ESP32-S3 + wake word real "Hola Michi" πŸ”œ
W3 Servos + display GC9A01 + personalidad física ⏳
W4 Integración end-to-end + aceptación MVP ⏳
W5-6 Multi-tenant (Supabase + auth + billing) ⏳
W7-8 App móvil React Native + Expo ⏳
W9 Deploy producción + stores + beta cerrada ⏳
W10-12 Iteración + launch público ⏳

Detalles semana por semana en docs/roadmap.md.


πŸ“š DocumentaciΓ³n


🀝 Contribuir

Michibot es un proyecto en desarrollo activo β€” Week 1 reciΓ©n cerrΓ³. Si querΓ©s aportar:

  1. Issues β€” reportΓ‘ bugs, pedΓ­ features, comentΓ‘ ideas
  2. Benchmarks β€” si tenΓ©s una GPU decente y querΓ©s correr el modo local, mandΓ‘ tus nΓΊmeros
  3. Canned responses LATAM β€” falta ampliar el catΓ‘logo T1 con mΓ‘s variantes regionales (Argentina, MΓ©xico, Colombia, Chile, Perú…)
  4. Voces TTS β€” experimentar con Cartesia Voice Cloning para acentos regionales (la voz actual es neutro LATAM)

πŸ“œ Licencia

MIT. Hecho con cariΓ±o en LATAM.


Si Michibot te parece interesante, tirale una ⭐ β€” ayuda un montΓ³n.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages