Du behöver
-
46elks-konto med:
- Ett virtuellt telefonnummer.
- Ett websocket-nummer (se steg 1 nedan).
- OpenAI-konto med credits.
- Lovable-konto.
1. 46elks
- Skapa ett konto på 46elks.se.
- Hyr ett virtuellt telefonnummer på 46elks.se/numbers.
- Allokera ett gratis Websocket-nummer på 46elks.se/numbers.
2. OpenAI
- Skapa ett konto eller logga in på platform.openai.com.
- Gå till platform.openai.com/api-keys.
- Klicka "Create new secret key" och följ instruktionerna. Spara nyckeln direkt — den visas bara en gång.
3. Lovable
- Skapa ett konto eller logga in på lovable.dev.
- Starta ett nytt projekt på lovable.dev/dashboard.
- Klistra in prompten nedan i projektet:
Lovable-prompt — klicka för att expandera
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):
{
"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:
{
"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.
- Lovable kommer att be dig sätta upp "Cloud" — tillåt det.
- Du får en fråga om att klistra in din OpenAI API-nyckel. Klistra in din API-key som du fick av OpenAI. Den sparas i ditt projekts cloud-inställningar på
lovable.dev/projects/DITT-PROJEKT-ID?view=cloud§ion=secrets. -
Gå till 46elks.se/numbers och koppla ihop ditt virtuella nummer med AI-agenten:
- Klicka "Edit" på ditt virtuella nummer och sätt
{"connect":"DITT-WEBSOCKET-NUMMER"}i fältetvoice_start. - Klicka sedan "Edit" på ditt websocket-nummer och klistra in den WebSocket-URL du fick av Lovable — den ser ut ungefär så här:
wss://SUPABASEID.supabase.co/functions/v1/voice-stream.
- Klicka "Edit" på ditt virtuella nummer och sätt
- Ring ditt virtuella nummer från din telefon. Om du får prata med en AI-agent har du lyckats!
Felsökning
Om du inte kommer fram, börja med att kontrollera dessa två ställen:
- platform.openai.com/usage — ser du aktivitet här vet du att samtalet når OpenAI.
- 46elks.se/logs — här syns om samtal skapas och kopplas till ditt websocket-nummer.
Om du fortfarande fastnar, prompta Lovable att felsöka. Nedan finns de vanligaste problemen:
| Symptom | Trolig orsak | Åtgärd |
|---|---|---|
| Upptagetsignal direkt | Servern är ej nåbar | Kontrollera att URL:en i 46elks-dashboarden stämmer och att edge function är driftsatt. |
| Inget ljud åt något håll | Fel ljudformat eller handskakningssekvens | Se till att listening och sending skickas i rätt ordning med format pcm_24000. |
| Samtalet kopplas ned | Ogiltig API-nyckel | Verifiera att OPENAI_API_KEY är korrekt sparad i Lovable Cloud och har tillgång till Realtime API. |
| Eko (AI hör sig själv) | Dubbel ljudinput | Blockera inkommande ljud från uppringaren medan AI:n genererar svar. |
Om du fastnar är du välkommen att höra av dig till 46elks support på help@46elks.com eller +46 766 861 004.