Aylem Voice Demo Webapp
Lokale Webapp fuer den Sprach-Test des Aylem-Telefon-Assistenten — laeuft im A/B-Modus mit zwei Stacks parallel:
| Pfad | Stack | Use |
|---|---|---|
/ (http://localhost:5050/) | Polly · Lex V2 · Lambda · Bedrock Claude Sonnet 4.5 | Phase-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 2 | Open-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-Profileav-prododer AssumeRole-Profileav-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.pyBrowser oeffnen:
- Polly: http://localhost:5050/
- ElevenLabs: http://localhost:5050/elevenlabs
- Cartesia: http://localhost:5050/cartesia (zusaetzlich Worker laufen lassen, siehe
../livekit-agent/README.md)
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):
| Var | Default |
|---|---|
LEX_BOT_ID | YOOLVJ4JWB |
LEX_ALIAS_ID | S9ZL5VK1T7 (= live) |
LEX_LOCALE | de_DE |
AWS_REGION | eu-central-1 |
PORT | 5050 |
POLLY_VOICE_ID | Vicki |
POLLY_ENGINE | generative |
POLLY_LANGUAGE | de-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)