Aylem Voice Demo Webapp

Lokale Webapp fuer den Sprach-Test des Aylem-Telefon-Assistenten — laeuft im A/B-Modus mit zwei Stacks parallel:

PfadStackUse
/ (http://localhost:5050/)Polly · Lex V2 · Lambda · Bedrock Claude Sonnet 4.5Phase-0-Setup mit AWS-only Pipeline
/elevenlabs (http://localhost:5050/elevenlabs)ElevenLabs Conversational AI (Voice Johanna · gpt-4o-mini)ElevenLabs-Pivot, Widget komplett client-side
/cartesia (http://localhost:5050/cartesia)LiveKit + Deepgram + OpenAI + Cartesia Sonic 2Open-Source-Pipeline mit emotion-adaptiver Stimme — braucht laufenden Python-Worker (siehe ../livekit-agent/)

Der Header jeder Seite hat oben rechts einen Switch zur jeweils anderen Variante — so kann man im selben Browser ohne Reload-Tricks vergleichen.

Architektur

/ — Polly-Pfad (AWS-Pipeline)

Browser (Chrome, Web Speech API)
   ↓ erkannter Text via fetch POST
Flask /api/talk @ localhost:5050
   ↓ recognize-text
Lex V2 Bot YOOLVJ4JWB · Alias live (S9ZL5VK1T7) · Locale de_DE
   ↓ Fulfillment
Lambda av-voice-bot-handler
   ↓ Converse
Bedrock EU Anthropic Claude Sonnet 4.5
   ↓ Antwort-Text
Flask /api/tts → Polly Generative Vicki → MP3-Stream → Browser <audio>

Browser uebernimmt ASR (Spracherkennung). TTS laeuft serverseitig ueber Polly Generative Vicki — Browser bekommt das fertige MP3.

/cartesia — LiveKit + Cartesia (pluggable Pipeline + Emotion-Adaption)

Browser /cartesia (LiveKit Web SDK)
   ↓ Token vom Flask /api/cartesia-token, dann WebRTC
LiveKit Cloud Room (kostenloser Dev-Tier)
   ↑↓ Audio
Python Worker — separater Prozess in ../livekit-agent/
   ├─ silero VAD
   ├─ Deepgram nova-2-general (de) — STT
   ├─ OpenAI gpt-4o-mini, T 0.4 — LLM
   │    ↳ jede Antwort startet mit [emotion:tag]
   ├─ tts_node-Override: parst Tag, mappt auf Cartesia controls
   └─ Cartesia Sonic 2 (de Voice) — TTS

Flask reicht hier zwei Sachen aus: die statische cartesia.html und einen /api/cartesia-token-Endpoint, der ein kurzlebiges JWT fuer LiveKit ausstellt. Den Voice-Agent selbst macht der separate Python-Worker (../livekit-agent/agent.py) — der muss parallel zu Flask laufen.

Setup + Run-Anleitung: ../livekit-agent/README.md.

/elevenlabs — ElevenLabs-Pfad (komplett client-side)

Browser
  ├─ <elevenlabs-convai agent-id="agent_4201kr530ct7es7rpm6k9ejtdbpc">
  └─ /script @ unpkg.com/@elevenlabs/convai-widget-embed
       ↓ WebRTC direkt zu ElevenLabs ConvAI
ElevenLabs Conversational AI Agent
  ├─ Voice: Johanna (DACH Customer Care, voice_id coPfQIqaxowKv5u2s2bV)
  ├─ Modell: eleven_flash_v2_5
  ├─ LLM: gpt-4o-mini, T 0.4, max 200 tokens
  └─ Tools: book_reservation, take_order
       ↓ webhook
[Placeholder] https://placeholder.example.com/tools  ← noch zu hosten

Flask reicht hier nur die statische HTML aus. Das Widget verbindet sich per WebRTC direkt zur ElevenLabs-API. Auth ist enable_auth: false am Agent — sprich der Agent ist public, jeder mit der Agent-ID kann ihn ansprechen. Fuer Produktivbetrieb spaeter auf signed-URL-Modus umstellen.

Voraussetzungen

  • Python 3.11+
  • AWS-Credentials mit Lex-Runtime + Polly-Access auf av-production (z.B. via SSO-Profile av-prod oder AssumeRole-Profile av-production) — nur fuer den Polly-Pfad noetig
  • Chrome (Firefox/Safari haben Web Speech API teils nicht oder schlecht)
  • Fuer /elevenlabs: keine AWS-Credentials noetig, nur Internet-Zugang
  • Fuer /cartesia: LiveKit+Deepgram+Cartesia+OpenAI Keys in ../livekit-agent/.env.local (siehe ../livekit-agent/.env.example) — Flask liest die env-Datei automatisch mit. Plus: separater Worker-Prozess muss laufen (cd ../livekit-agent && python agent.py dev).

Start

cd ~/source/agentic-ventures/intern/projekte/telefon-assistent-aws/webapp
 
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
 
export AWS_PROFILE=av-production    # nur fuer Polly-Pfad noetig
python server.py

Browser oeffnen:

Bedienung

Polly-Pfad (/)

  • Mikrofon-Button druecken und gedrueckt halten waehrend du sprichst. Loslassen = Spracherkennung sendet Text an Backend.
  • Leertaste macht das gleiche (sofern der Cursor nicht im Text-Feld ist).
  • Text-Feld als Fallback — tippen + Enter.
  • Neue Session oben rechts loescht den Chat und holt eine neue Session-ID (Conversation-History reset).

ElevenLabs-Pfad (/elevenlabs)

  • Widget unten rechts in der Ecke (klein) oeffnet sich auf Klick.
  • Browser fragt einmalig nach Mikrofon-Zugriff.
  • Sobald verbunden: einfach reden, der Agent antwortet in Echtzeit.
  • Tool-Calls (book_reservation, take_order) gehen aktuell an einen Placeholder-Webhook und liefern keine echten Daten zurueck — der Agent faellt dann nach Timeout auf eine generische Antwort zurueck. Fuer echtes Verhalten muss der Webhook gehostet werden (ngrok / Lambda / AWS API Gateway).

Cartesia-Pfad (/cartesia)

  • Grosser Verbinden-Button mittig auf der Seite.
  • Klick → Token-Holen → WebRTC-Connect zu LiveKit-Cloud → Worker joined denselben Room.
  • Mikrofon-Zugriff wird einmalig erfragt.
  • Status-Anzeige direkt unter dem Button: „Hoert dir zu …” / „Bot spricht …“.
  • Tool-Calls werden im Worker per Python-Funktion verarbeitet — Logging in der Worker-Konsole. Aktuell geben die Tool-Funktionen nur Bestaetigungs-Strings zurueck (kein externer Webhook), Erweiterung ist trivial.
  • Probier die Test-Zeilen die auf der Seite gelistet sind — der Wow-Effekt ist nicht der Inhalt der Antwort, sondern wie sich die Stimmung der Stimme dem Anliegen anpasst.

Konfiguration

Per Environment-Variable umstellbar (nur Polly-Pfad):

VarDefault
LEX_BOT_IDYOOLVJ4JWB
LEX_ALIAS_IDS9ZL5VK1T7 (= live)
LEX_LOCALEde_DE
AWS_REGIONeu-central-1
PORT5050
POLLY_VOICE_IDVicki
POLLY_ENGINEgenerative
POLLY_LANGUAGEde-DE

Der ElevenLabs-Agent wird in der HTML hardcoded referenziert — fuer einen Wechsel der Agent-ID einfach static/elevenlabs.html editieren oder den Agent in ElevenLabs neu konfigurieren.

Limitierungen

Polly-Pfad

  • Voice ist Browser-Default, optional Polly Generative Vicki via /api/tts
  • Browser-ASR ist Chrome-spezifisch
  • Kein TLS, lokal only
  • Keine Persistenz — Chat-Verlauf existiert nur im Lex-Session-State

ElevenLabs-Pfad

  • Tool-Webhooks zeigen auf Placeholder-URL → Aufrufe schlagen fehl
  • Agent ist enable_auth: false (public) — nicht oeffentlich exponieren
  • Free-Tier-Limit von ElevenLabs greift (ConvAI ist paid feature, fuer laengere Sessions Subscription noetig)