Du behöver

1. 46elks

  1. Skapa ett konto på 46elks.se.
  2. Hyr ett virtuellt telefonnummer på 46elks.se/numbers.
  3. Allokera ett gratis Websocket-nummer på 46elks.se/numbers.

2. OpenAI

  1. Skapa ett konto eller logga in på platform.openai.com.
  2. Gå till platform.openai.com/api-keys.
  3. Klicka "Create new secret key" och följ instruktionerna. Spara nyckeln direkt — den visas bara en gång.

3. Lovable

  1. Skapa ett konto eller logga in på lovable.dev.
  2. Starta ett nytt projekt på lovable.dev/dashboard.
  3. 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.
  1. Lovable kommer att be dig sätta upp "Cloud" — tillåt det.
  2. 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&section=secrets.
  3. 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ältet voice_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.
  4. 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:

Om du fortfarande fastnar, prompta Lovable att felsöka. Nedan finns de vanligaste problemen:

SymptomTrolig 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.