Beställ pizza
Ring vår AI och beställ en pizza. Den tar din order, ställer frågor om topping och bekräftar leverans.
Få en ljudström via WebSocket från vilket samtal som helst — inkommande eller utgående — och koppla den till OpenAI, Claude, ElevenLabs, eller din egen modell.
Skaffa ett nummer hos oss
Vi löser allt tekniska för att få ut samtalet som en WebSocket-ström
Du tar emot ljudströmmen och bestämmer själv vad du vill göra med den
Välj vilken AI du vill. Bygg egna verktyg och använd dem i samtalet.
Prova ett av våra demos och se vad som är möjligt med AI i riktiga telefonsamtal.
Ring vår AI och beställ en pizza. Den tar din order, ställer frågor om topping och bekräftar leverans.
Ställ frågor om 46elks API direkt i telefon. Vår assistent har stenkoll.
Ingen black box. Du får ljudströmmen och skickar tillbaka ljud. Däremellan gör du exakt vad du vill — transkribera, analysera, generera svar, anropa dina verktyg.
OpenAI Realtime, Claude, ElevenLabs, Whisper, en egen modell — spelar ingen roll. Det enda som krävs är att din app tar emot och skickar ljud.
En komplett AI-röstassistent i ~60 rader Python. Ingen SIP. Ingen Asterisk. Bara en WebSocket.
async def openai_bridge(elks_ws, openai_ws): # Get the call metadata from the hello message hello = json.loads(await elks_ws.recv()) print(f"Received {hello['to']} <- {hello['from']} ({hello['callid']})") # Tell the API the format we want to receive audio in await elks_ws.send(json.dumps({ "t": "listening", "format": "pcm_24000" })) # Tell the API the format we'll be sending audio in await elks_ws.send(json.dumps({ "t": "sending", "format": "pcm_24000" }))
async def openai_bridge(elks_ws, openai_ws): # Get the call metadata from the hello message hello = json.loads(await elks_ws.recv()) print(f"Received {hello['to']} <- {hello['from']} ({hello['callid']})") # Tell the API the format we want to receive audio in await elks_ws.send(json.dumps({ "t": "listening", "format": "pcm_24000" })) # Tell the API the format we'll be sending audio in await elks_ws.send(json.dumps({ "t": "sending", "format": "pcm_24000" }))
ngrok skapar en säker tunnel från internet till din lokala dator. Det gör att 46elks kan nå din WebSocket-server utan att du behöver deploya.
ngrok http 8000Ladda ner ngrok
Klistra in prompten nedan i Lovable för att generera en fungerande AI-telefonassistent med konfigurerbar systemprompt och välkomstmeddelande.
Bygg en AI-telefonassistent som tar emot röstsamtal via 46elks och svarar i realtid med OpenAI Realtime API. Systemet ska bestå av en Edge Function (WebSocket-brygga), en databas för samtalslogg, och en dashboard-frontend.
---
### 1. Databas
Skapa två tabeller:
**Tabell `calls`:**
- `id` (uuid, primary key, default gen_random_uuid())
- `call_id` (text, unique, not null) — 46elks samtals-ID
- `from_number` (text, not null)
- `to_number` (text, not null)
- `status` (text, default 'active')
- `started_at` (timestamptz, default now())
- `ended_at` (timestamptz, nullable)
- `duration_seconds` (integer, nullable)
**Tabell `call_messages`:**
- `id` (uuid, primary key, default gen_random_uuid())
- `call_id` (text, not null, foreign key → calls.call_id)
- `role` (text, not null) — 'user' eller 'assistant'
- `content` (text, not null)
- `created_at` (timestamptz, default now())
Aktivera Realtime på båda tabellerna. Inaktivera RLS (tabellerna används bara av edge function med service role key, och frontend läser publikt).
---
### 2. Edge Function: `voice-stream`
Skapa en Edge Function med namnet `voice-stream`. Stäng av JWT-verifiering (verify_jwt = false) så att 46elks kan ansluta direkt.
Funktionen är en WebSocket-brygga mellan 46elks och OpenAI Realtime API.
#### ⚠️ KRITISKT: 46elks WebSocket-protokoll
Detta är den viktigaste delen. 46elks använder ett JSON-baserat protokoll över WebSocket. Om du inte följer detta exakt kommer inget ljud att skickas eller tas emot — samtalet blir tyst åt båda håll utan felmeddelanden.
**Handskakningssekvens:**
1. **46elks skickar** `{"t": "hello", ...}` när anslutningen öppnas
2. **Du MÅSTE svara** `{"t": "listening", "format": "pcm_24000"}` — detta aktiverar ljudströmmen från uppringaren till dig
3. **Innan du skickar det första ljudpaketet tillbaka**, MÅSTE du skicka `{"t": "sending", "format": "pcm_24000"}` — detta öppnar skrivbufferten så uppringaren kan höra dig
4. **Ljuddata** skickas som `{"t": "audio", "data": ""}` i båda riktningarna
5. **Avslutning** kommer som `{"t": "bye", "reason": "..."}` — stäng OpenAI-sessionen och uppdatera databasen
**Ljudformat:** PCM 16-bit, 24000 Hz (`pcm_24000` för 46elks, `pcm16` för OpenAI)
#### OpenAI Realtime API-anslutning
Anslut till `wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-12-17` med subprotokollen:
```
["realtime", "openai-insecure-api-key.", "openai-beta.realtime-v1"]
```
**Session-konfiguration** (skicka som `session.update` direkt efter att OpenAI-socketen öppnats):
```json
{
"type": "session.update",
"session": {
"modalities": ["text", "audio"],
"instructions": "Du är en hjälpsam AI-assistent som svarar på svenska.",
"voice": "alloy",
"input_audio_format": "pcm16",
"output_audio_format": "pcm16",
"input_audio_transcription": {
"model": "gpt-4o-mini-transcribe"
},
"turn_detection": {
"type": "server_vad",
"threshold": 0.5,
"prefix_padding_ms": 300,
"silence_duration_ms": 500
}
}
}
```
#### ⚠️ KRITISKT: Timing för hälsningsfras
Skicka INTE `response.create` för hälsningsfrasen direkt. Vänta på:
1. OpenAI skickar `session.updated` (bekräftar att sessionen är konfigurerad)
2. Sedan en `setTimeout` på 500ms (låter ljudpipelinen stabiliseras)
3. Först DÅ skickar du:
```json
{
"type": "response.create",
"response": {
"modalities": ["text", "audio"],
"instructions": "Börja med att hälsa användaren välkommen. Tala på svenska."
}
}
```
#### Ljudflöde
**Inkommande (uppringare → AI):**
- 46elks skickar `{"t": "audio", "data": ""}`
- Vidarebefordra till OpenAI som `{"type": "input_audio_buffer.append", "audio": ""}`
**Utgående (AI → uppringare):**
- OpenAI skickar `response.audio.delta` med `delta` (base64 PCM)
- Första gången: skicka `{"t": "sending", "format": "pcm_24000"}` till 46elks
- Sedan skicka `{"t": "audio", "data": ""}` till 46elks
#### Transkription och databas
- `response.audio_transcript.delta` — samla ihop assistentens text
- `response.audio_transcript.done` — spara till `call_messages` med role='assistant'
- `conversation.item.input_audio_transcription.completed` — spara till `call_messages` med role='user'
#### Samtalsavslutning
Vid `{"t": "bye"}` från 46elks, eller `onclose` på elks-socketen:
- Stäng OpenAI-socketen
- Uppdatera `calls`-tabellen: status='completed', ended_at, duration_seconds
#### Komplett flödesöversikt
```
46elks Edge Function OpenAI Realtime
| | |
|--- WebSocket connect ---->| |
| |--- WebSocket connect ------->|
| |<-- session.created ----------|
|<-- {"t":"hello"} --------| |
|--- {"t":"listening"} --->|--- session.update ---------->|
| |<-- session.updated ----------|
| | (wait 500ms) |
| |--- response.create --------->|
| |<-- response.audio.delta -----|
|<-- {"t":"sending"} ------| |
|<-- {"t":"audio"} --------| |
| | |
|--- {"t":"audio"} ------->|--- input_audio_buffer ------>|
| |<-- response.audio.delta -----|
|<-- {"t":"audio"} --------| |
| | |
|--- {"t":"bye"} --------->|--- close ------------------->|
```
---
### 3. Frontend
Skapa ett mörkt dashboard med:
**Header:** "AI Telefonassistent" med en telefonikon.
**Setup Guide:** En steg-för-steg-guide med 4 steg:
1. Skaffa ett 46elks-konto och telefonnummer (länk till 46elks.se)
2. Lägg till din OpenAI API-nyckel som en secret i Lovable Cloud
3. Peka ditt 46elks-nummer till WebSocket-URL:en (visa URL:en med kopieringsknapp)
4. Testa genom att ringa numret
WebSocket-URL:en ska konstrueras dynamiskt: `wss:///functions/v1/voice-stream`
**Samtalslogg:** En tabell som visar alla samtal med:
- Tid, från-nummer, till-nummer, längd, status (active/completed)
- Klickbar rad som expanderar och visar transkriptet (användar- och AI-meddelanden)
- Realtidsuppdatering via Supabase Realtime (prenumerera på `calls` och `call_messages`)
- Aktiva samtal ska ha en pulserande grön prick
**Design:** Mörkt tema med gröna accenter (terminal-känsla). Använd JetBrains Mono för kodsnuttar och monospace-text.
---
### 4. 46elks-konfiguration
Användaren behöver konfigurera sitt 46elks-nummer i deras dashboard:
- Sätt `voice_start` till WebSocket-URL:en från steg 3 ovan
- 46elks kommer automatiskt att öppna en WebSocket-anslutning vid varje inkommande samtal och skicka `callid`, `from` och `to` som query-parametrar
---
### 5. Secrets
Följande secret behöver konfigureras i Lovable Cloud:
- `OPENAI_API_KEY` — OpenAI API-nyckel med åtkomst till Realtime API
Det här är en fungerande AI-röstassistent. ~60 rader. Byt ut OpenAI mot vilken modell du vill.
En AI som svarar i telefon, pratar naturligt och utför handlingar — bokar tider, kollar ordrar, svarar på frågor. Med tool-calling blir den en agent, inte bara en röst.
Din app initierar ett samtal och kopplar in en AI-agent. Outbound sales, påminnelser, uppföljningar.
Transkribera live. Flagga nyckelord. Kör sentimentanalys medan samtalet pågår. Plocka fram relevant information i realtid.
CRM-uppdateringar, ärendehantering, loggning — automatiskt, i realtid. Telefonen blir ett gränssnitt till dina system.
WebSocket (wss://) med full duplex.
PCM 8/16/24 kHz, G.711, G.722, Opus, MP3, WAV.
Inkommande och utgående samtal.
Separata streams för caller och agent, individuellt kontrollerbara.
bye avslutar samtalet graciöst. interrupt rensar bufferten direkt.
JSON-meddelanden, base64-kodat ljud.
Realtime Voice ingår i 46elks virtuella nummer
Frågor om hur du kan använda 46elks?
Vi hjälper dig gärna på traven.