Ordre 20260912T193441Z-7358817909. Steg 1 var ikke transformen, men å rette
roadmapens R13-gate og få den ratifisert. Gaten `grep -rl "Cosmo"
skills/*/references -> 0` var usann på to uavhengige måter:
1. Ordren fanget den første: 451 av forekomstene er Azure Cosmos DB, ekte
produktinnhold. Diskriminatoren er ikke bokstaven «s» — `Cosmos <norsk
substantiv>` er genitiv av personaen (`### Cosmos tonalitet`), mens
`Cosmos DB`/`CosmosClient`/`cosmos_ru` er produkt.
2. Denne økten fant den andre: 132 persona-forekomster ligger i prosa,
tabeller, dialog-replikker og proveniens-linjer. Heading-nøytralisering
kan ikke nå dem, så «0 persona» er uoppnåelig også under den ratifiserte
formen. Operatøren ratifiserte alternativ A: gaten speiler formen, og de
132 bokføres til R13b/R14.
Tre korreksjoner av premisser som sto i ordren og STATE:
«ca 320 produkt» -> 451 (case-sensitivt nett manglet 327 lowercase
TOC-ankre + 99 identifikatorer; sann nevner 1 638)
«169 headinger» -> 401. 169 var `^## For Cosmo`-prefikset (168) og var
internt inkonsistent med sin egen topp-variant (204)
«417 matcher ingen
populasjon» -> 417 er cosmo-headinger utenfor kodefences; briefens
nevner var reell hele tiden
Fence-bevissthet er målt skadelig, ikke nødvendig: begge toggle-regler er
gale på dette korpuset (naiv toggle skjuler en ekte heading i
chain-of-thought-prompting.md, CommonMark-regelen ubalanserer
service-level-documentation-dr.md). Fence-agnostisk deteksjon finner 401
heading-linjer i nøyaktig de samme 40 variantene som fence-bevisst finner
400 i — ingen kodeblokk-linje er byte-identisk til en persona-heading. Derfor
nøkles transformen på 40 enumererte heading-tekster og ignorerer fences. En
ukjent variant kaster; en slug-kollisjon kaster. Ingenting auto-fikses.
TOC-en regenereres ikke, den rettes kirurgisk: alle 327 persona-lenker hadde
lenketekst lik én av de 40 heading-tekstene og anker lik slugify av den
(327/327, 0 avvik), så heading og TOC-entry skrives i samme operasjon og
ingen mellomtilstand etterlater en død lenke.
Ratifisert målform: `For Cosmo`, `For Cosmo Skyberg` og `For arkitekten
(Cosmo)` konvergerer på `For arkitekten`. To filer kolliderte og er adjudisert
ved å lese dem, ikke ved regel.
Verifisering (alle 7 kriterier fra ordren):
G1 persona på heading-linjer 401 -> 0
G2 døde fragmentlenker 1 -> 1 (pre-eksisterende, unntatt)
G3 produkt-forekomster 451 -> 451; `Cosmos DB|Azure Cosmos` 308 = 308
de 3 kun-produkt-filene byte-identiske
nettet validert begge veier injisert persona feller G1; genitiv feller G1;
produkt-heading og de 3 filene passerer
hele diffen 802 heading-linjer + 654 TOC-linjer, ANNET = 0
linjeantall 728 lagt til = 728 slettet
suite 1120/1120 (1097 + 23 nye)
validate-plugin 250 PASS / 0 FAIL
stikkprøve 10 filer, alle 5 skills, inkl. de 3 mest
produkt-tunge (26/20/19) — kun heading+TOC
Utenfor scope, urørt: de 4 SKILL.md, de 23 commands, CLAUDE.md, README.md,
NOTICE.md, docs/ (alt R14).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
415 lines
14 KiB
Markdown
415 lines
14 KiB
Markdown
# Real-Time Audio API for Conversational AI
|
|
|
|
**Last updated:** 2026-02
|
|
**Status:** GA
|
|
**Category:** Multi-Modal AI
|
|
**Type:** reference
|
|
|
|
---
|
|
|
|
## Innhold
|
|
|
|
- [Introduksjon](#introduksjon)
|
|
- [Kjernekomponentar](#kjernekomponentar)
|
|
- [Støtta modellar](#støtta-modellar)
|
|
- [Session Management og State Tracking](#session-management-og-state-tracking)
|
|
- [Audio Codec-val og bandbreiddeoptimalisering](#audio-codec-val-og-bandbreiddeoptimalisering)
|
|
- [Interruption og Turn-Taking](#interruption-og-turn-taking)
|
|
- [Deployment og Scaling Patterns](#deployment-og-scaling-patterns)
|
|
- [Norsk offentleg sektor](#norsk-offentleg-sektor)
|
|
- [Beslutningsrammeverk](#beslutningsrammeverk)
|
|
- [For arkitekten](#for-arkitekten)
|
|
|
|
## Introduksjon
|
|
|
|
Azure OpenAI GPT Realtime API er ein del av GPT-4o-modellfamilien som støttar låg-latency "speech in, speech out" samtaleinteraksjonar. API-et er designa for sanntids bruksscenario som kundeserviceagentar, taleassistentar og sanntidstolkar, der rask respons er kritisk for brukaropplevinga.
|
|
|
|
Realtime API tilbyr tre transportmekanismar: WebRTC for klientside-applikasjonar med minimal latency, WebSocket for server-til-server-scenario, og SIP for integrasjon med telefonisystem. For dei fleste bruksscenario tilrår Microsoft WebRTC, som er designa spesifikt for låg-latency sanntids audiostreaming.
|
|
|
|
For norsk offentleg sektor opnar Realtime API moglegheiter for talebaserte borgartenester, tilgjengelege grensesnitt for personar med funksjonshemmingar, og automatiserte telefontenester. API-et støttar norsk via GPT-4o sin fleirspråklege kapabilitet, noko som gjer det relevant for NAV sin telefoniteneste, kommunale servicesentra og andre offentlege kontaktpunkt.
|
|
|
|
---
|
|
|
|
## Kjernekomponentar
|
|
|
|
| Komponent | Formål | Teknologi |
|
|
|-----------|--------|-----------|
|
|
| **GPT Realtime API** | Låg-latency tale-til-tale interaksjon | Azure OpenAI GPT-4o Realtime |
|
|
| **WebRTC Transport** | Klientside audiostreaming | WebRTC Protocol |
|
|
| **WebSocket Transport** | Server-til-server kommunikasjon | WebSocket Protocol |
|
|
| **SIP Transport** | Telefoniintegrasjon | Session Initiation Protocol |
|
|
| **Voice Activity Detection** | Automatisk taledeteksjon | Innebygd VAD |
|
|
| **Session Management** | Tilstandshandtering per samtale | Realtime API Sessions |
|
|
|
|
---
|
|
|
|
## Støtta modellar
|
|
|
|
| Modell | Versjon | Tilgjengelegheit |
|
|
|--------|---------|-----------------|
|
|
| `gpt-4o-realtime-preview` | 2024-12-17 | Global Deployment |
|
|
| `gpt-4o-mini-realtime-preview` | 2024-12-17 | Global Deployment |
|
|
| `gpt-realtime` | 2025-08-28 | Global Deployment |
|
|
| `gpt-realtime-mini` | 2025-10-06 | Global Deployment |
|
|
| `gpt-realtime-mini-2025-12-15` | 2025-12-15 | Global Deployment |
|
|
|
|
---
|
|
|
|
## Session Management og State Tracking
|
|
|
|
### Sesjonsarkitektur
|
|
|
|
Kvar sesjon har ein aktiv samtale (conversation) som akkumulerer input-signal til ein respons blir trigga — enten via eksplisitt event frå klienten eller automatisk via Voice Activity Detection (VAD).
|
|
|
|
### Samtalesekvens
|
|
|
|
```
|
|
Klient Server
|
|
| |
|
|
| session.create |
|
|
|------------------------------>|
|
|
| session.created |
|
|
|<------------------------------|
|
|
| conversation.created |
|
|
|<------------------------------|
|
|
| |
|
|
| conversation.item.create |
|
|
|------------------------------>|
|
|
| conversation.item.created |
|
|
|<------------------------------|
|
|
| |
|
|
| response.create |
|
|
|------------------------------>|
|
|
| response.audio.delta |
|
|
|<------------------------------|
|
|
| response.audio.delta |
|
|
|<------------------------------|
|
|
| response.done |
|
|
|<------------------------------|
|
|
```
|
|
|
|
### Python WebSocket-implementering
|
|
|
|
```python
|
|
import asyncio
|
|
import json
|
|
import websockets
|
|
from azure.identity import DefaultAzureCredential
|
|
|
|
async def realtime_conversation():
|
|
"""Etabler ein Realtime API-sesjon via WebSocket."""
|
|
|
|
credential = DefaultAzureCredential()
|
|
token = credential.get_token(
|
|
"https://cognitiveservices.azure.com/.default"
|
|
)
|
|
|
|
url = (
|
|
"wss://<resource>.openai.azure.com/openai/realtime"
|
|
"?api-version=2025-04-01-preview"
|
|
"&deployment=gpt-4o-realtime-preview"
|
|
)
|
|
|
|
headers = {
|
|
"Authorization": f"Bearer {token.token}"
|
|
}
|
|
|
|
async with websockets.connect(url, extra_headers=headers) as ws:
|
|
# Konfigurer sesjon
|
|
await ws.send(json.dumps({
|
|
"type": "session.update",
|
|
"session": {
|
|
"modalities": ["text", "audio"],
|
|
"instructions": (
|
|
"Du er ein norsk kundeserviceagent for Direktoratet for digital tjenesteutvikling. "
|
|
"Svar på norsk. Ver høfleg og presis."
|
|
),
|
|
"voice": "alloy",
|
|
"input_audio_format": "pcm16",
|
|
"output_audio_format": "pcm16",
|
|
"turn_detection": {
|
|
"type": "server_vad",
|
|
"threshold": 0.5,
|
|
"prefix_padding_ms": 300,
|
|
"silence_duration_ms": 500
|
|
}
|
|
}
|
|
}))
|
|
|
|
# Lytt etter responsar
|
|
async for message in ws:
|
|
event = json.loads(message)
|
|
|
|
if event["type"] == "response.audio.delta":
|
|
# Spel av audio-chunk
|
|
audio_data = event["delta"]
|
|
await play_audio(audio_data)
|
|
|
|
elif event["type"] == "response.audio_transcript.delta":
|
|
# Vis transkripsjon i sanntid
|
|
print(event["delta"], end="", flush=True)
|
|
|
|
elif event["type"] == "response.done":
|
|
print("\n[Respons ferdig]")
|
|
```
|
|
|
|
### JavaScript WebRTC-implementering
|
|
|
|
```javascript
|
|
import { RTClient } from "rt-client";
|
|
import { DefaultAzureCredential } from "@azure/identity";
|
|
|
|
async function startRealtimeSession() {
|
|
const credential = new DefaultAzureCredential();
|
|
|
|
const client = new RTClient(
|
|
new URL("https://<resource>.openai.azure.com/"),
|
|
credential,
|
|
{ deployment: "gpt-4o-realtime-preview" }
|
|
);
|
|
|
|
// Konfigurer sesjon
|
|
await client.configure({
|
|
modalities: ["text", "audio"],
|
|
instructions: "Du er ein norsk serviceagent. Svar på norsk.",
|
|
voice: "alloy",
|
|
turn_detection: {
|
|
type: "server_vad",
|
|
threshold: 0.5,
|
|
silence_duration_ms: 500
|
|
}
|
|
});
|
|
|
|
// Start mikrofon-streaming
|
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
const audioTrack = stream.getAudioTracks()[0];
|
|
|
|
client.sendAudio(audioTrack);
|
|
|
|
// Handter responsar
|
|
client.on("response.audio.delta", (event) => {
|
|
// Spel av mottatt audio
|
|
audioPlayer.appendBuffer(event.delta);
|
|
});
|
|
|
|
client.on("response.audio_transcript.done", (event) => {
|
|
console.log("Agent sa:", event.transcript);
|
|
});
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Audio Codec-val og bandbreiddeoptimalisering
|
|
|
|
### Støtta audioformat
|
|
|
|
| Format | Retning | Eigenskapar |
|
|
|--------|---------|-------------|
|
|
| **PCM16** | Input/Output | 24kHz, 16-bit, mono. Lågast latency |
|
|
| **G.711 u-law** | Input/Output | 8kHz. Telefonikompatibelt |
|
|
| **G.711 A-law** | Input/Output | 8kHz. Europeisk telefonistandard |
|
|
|
|
### Bandbreiddeestimering
|
|
|
|
| Format | Bitrate | Bruksscenario |
|
|
|--------|---------|---------------|
|
|
| PCM16 24kHz | ~384 kbps | Høgkvalitets samtale |
|
|
| G.711 8kHz | ~64 kbps | Telefoni, låg bandbreidde |
|
|
|
|
### Optimalisering for norske forhold
|
|
|
|
```python
|
|
def select_audio_config(network_conditions):
|
|
"""Vel audioformat basert på nettverkstilhøve."""
|
|
|
|
if network_conditions["bandwidth_kbps"] > 500:
|
|
return {
|
|
"input_audio_format": "pcm16",
|
|
"output_audio_format": "pcm16",
|
|
"sample_rate": 24000,
|
|
"quality": "high"
|
|
}
|
|
elif network_conditions["bandwidth_kbps"] > 100:
|
|
return {
|
|
"input_audio_format": "g711_ulaw",
|
|
"output_audio_format": "g711_ulaw",
|
|
"sample_rate": 8000,
|
|
"quality": "telephony"
|
|
}
|
|
else:
|
|
return {
|
|
"input_audio_format": "g711_alaw",
|
|
"output_audio_format": "g711_alaw",
|
|
"sample_rate": 8000,
|
|
"quality": "low_bandwidth"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Interruption og Turn-Taking
|
|
|
|
### Voice Activity Detection (VAD)
|
|
|
|
Server-side VAD handterer automatisk turskifte i samtalen:
|
|
|
|
```python
|
|
# VAD-konfigurasjon
|
|
vad_config = {
|
|
"type": "server_vad",
|
|
"threshold": 0.5, # Sensitivitet (0.0-1.0)
|
|
"prefix_padding_ms": 300, # Audio før talestart
|
|
"silence_duration_ms": 500 # Pauselengde for turskifte
|
|
}
|
|
```
|
|
|
|
### Avbrytingshandtering
|
|
|
|
Når brukaren avbryt agenten, må systemet:
|
|
|
|
1. **Stoppe pågåande audioavspeling** — Trunkere assistenten sin respons
|
|
2. **Synkronisere samtaletilstand** — Klient og server må vere i sync
|
|
3. **Starte ny respons** — Basert på brukarens avbryting
|
|
|
|
```python
|
|
# Trunkering av pågåande respons
|
|
await ws.send(json.dumps({
|
|
"type": "conversation.item.truncate",
|
|
"item_id": current_response_item_id,
|
|
"content_index": 0,
|
|
"audio_end_ms": current_playback_position_ms
|
|
}))
|
|
|
|
# Vente på server-bekreftelse
|
|
# Server sender conversation.item.truncated
|
|
```
|
|
|
|
### Manuell Turn Management
|
|
|
|
For scenario der automatisk VAD ikkje er tilstrekkeleg:
|
|
|
|
```python
|
|
# Deaktiver VAD for manuell kontroll
|
|
session_config = {
|
|
"turn_detection": None # Manuell turskifte
|
|
}
|
|
|
|
# Klient kontrollerer turskifte eksplisitt
|
|
await ws.send(json.dumps({
|
|
"type": "input_audio_buffer.commit"
|
|
}))
|
|
|
|
# Be om respons eksplisitt
|
|
await ws.send(json.dumps({
|
|
"type": "response.create"
|
|
}))
|
|
```
|
|
|
|
---
|
|
|
|
## Deployment og Scaling Patterns
|
|
|
|
### Arkitekturmønster for produksjon
|
|
|
|
```
|
|
Brukarar
|
|
|
|
|
v
|
|
Azure Front Door (Global Load Balancing)
|
|
|
|
|
v
|
|
Azure API Management (Rate limiting, Auth)
|
|
|
|
|
v
|
|
WebRTC/WebSocket Gateway
|
|
|
|
|
├── GPT-4o Realtime (Region: Norway East)
|
|
├── GPT-4o Realtime (Region: Sweden Central)
|
|
└── GPT-4o Realtime (Region: West Europe)
|
|
```
|
|
|
|
### Scaling-strategi
|
|
|
|
| Dimensjon | Tilnærming |
|
|
|-----------|-----------|
|
|
| **Concurrent sessions** | Global deployment med automatisk lastfordeling |
|
|
| **Geographic distribution** | Multi-region for låg latency |
|
|
| **Session stickiness** | WebSocket connections bound til region |
|
|
| **Failover** | Automatisk rerouting ved regionsfeil |
|
|
|
|
### Kostnadsoversikt
|
|
|
|
```python
|
|
def estimate_realtime_cost(sessions_per_day, avg_duration_minutes):
|
|
"""Estimerer kostnader for Realtime API."""
|
|
|
|
# Prisar per 1M tokens (estimat, sjekk aktuell prisliste)
|
|
input_cost_per_1m = 100 # USD per 1M audio input tokens
|
|
output_cost_per_1m = 200 # USD per 1M audio output tokens
|
|
|
|
# Ca. 1500 tokens per minutt tale
|
|
tokens_per_minute = 1500
|
|
|
|
daily_input_tokens = sessions_per_day * avg_duration_minutes * tokens_per_minute * 0.6
|
|
daily_output_tokens = sessions_per_day * avg_duration_minutes * tokens_per_minute * 0.4
|
|
|
|
daily_cost_usd = (
|
|
(daily_input_tokens / 1_000_000) * input_cost_per_1m +
|
|
(daily_output_tokens / 1_000_000) * output_cost_per_1m
|
|
)
|
|
|
|
return {
|
|
"dagleg_kostnad_usd": daily_cost_usd,
|
|
"dagleg_kostnad_nok": daily_cost_usd * 11, # Ca. valutakurs
|
|
"månadleg_kostnad_nok": daily_cost_usd * 11 * 30
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Norsk offentleg sektor
|
|
|
|
### Bruksscenario
|
|
|
|
- **NAV kontaktsenter**: Automatisert talebasert rettleiing for ytingar og søknader
|
|
- **Kommunale servicesentra**: 24/7 talebasert borgarservice
|
|
- **Helsevesenet**: Triageringssamtalar med automatisk dokumentasjon
|
|
- **Direktoratetet**: Talebasert rettleiing for førarkort og køyretøytenester
|
|
|
|
### Regulatoriske krav
|
|
|
|
| Krav | Tiltak |
|
|
|------|--------|
|
|
| **GDPR artikkel 22** | Informer brukar om automatisert avgjerd |
|
|
| **Forvaltingslova § 11a** | Brukar har rett til å snakke med eit menneske |
|
|
| **Språklova** | Støtt både bokmål og nynorsk |
|
|
| **Samisk språklov** | Vurder samisk støtte for relevante tenester |
|
|
| **Content filtering** | Innhaldsfiltrering er aktivert for tekst, men ikkje for audio |
|
|
|
|
### Viktig avgrensing
|
|
|
|
Innhaldsfiltreringssystemet i Azure OpenAI blir **ikkje** brukt på prompts og completions prosessert av audiomodellar som Whisper og Realtime API. Dette betyr at organisasjonen må implementere eigne innhaldsfilter for audiopipelines.
|
|
|
|
---
|
|
|
|
## Beslutningsrammeverk
|
|
|
|
| Scenario | Anbefaling | Begrunnelse |
|
|
|----------|------------|-------------|
|
|
| Web-app med sanntidstale | WebRTC transport | Lågast latency, klient-optimalisert |
|
|
| Server-til-server integrasjon | WebSocket transport | Full kontroll, server-side logikk |
|
|
| Telefoniintegrasjon | SIP transport | Direkte integrasjon med PBX |
|
|
| Høg-volum kundesenter | gpt-realtime-mini | Lågare kostnad, tilstrekkeleg kvalitet |
|
|
| Komplekse rådgivingssamtalar | gpt-realtime | Betre resonnering og kontekst |
|
|
| Sensitive samtalar (helse) | WebSocket + manuell VAD | Full kontroll over dataflyt |
|
|
|
|
---
|
|
|
|
## For arkitekten
|
|
|
|
- **GPT Realtime API** er designa for låg-latency "speech in, speech out" — bruk WebRTC for klient-applikasjonar (lågast latency) og WebSocket for server-til-server (meir kontroll)
|
|
- **SIP-transport** muliggjer direkte integrasjon med eksisterande telefonisystem — relevant for NAV, kommunale servicesentra og andre offentlege kontaktpunkt med telefonibasert borgarservice
|
|
- **Voice Activity Detection (VAD)** med konfigurerbar sensitivitet handterer turskifte automatisk — juster `silence_duration_ms` (500ms standard) for norsk taleflyt
|
|
- **Innhaldsfiltrering gjeld IKKJE for audio** — implementer eigne filter for sensitive bruksscenario i offentleg sektor, spesielt helse og rettsvesen
|
|
- **gpt-realtime-mini** gir 60-70% lågare kostnad enn full gpt-realtime — evaluer om kvaliteten er tilstrekkeleg for enklare bruksscenario som FAQ og rettleiing
|