@ai-sdk/openai
Version:
The **[OpenAI provider](https://ai-sdk.dev/providers/ai-sdk-providers/openai)** for the [AI SDK](https://ai-sdk.dev/docs) contains language model support for the OpenAI chat and completion APIs and embedding model support for the OpenAI embeddings API.
112 lines (97 loc) • 3.48 kB
text/typescript
import type {
Experimental_RealtimeModelV4 as RealtimeModelV4,
Experimental_RealtimeModelV4ClientEvent as RealtimeModelV4ClientEvent,
Experimental_RealtimeModelV4ClientSecretOptions as RealtimeModelV4ClientSecretOptions,
Experimental_RealtimeModelV4ClientSecretResult as RealtimeModelV4ClientSecretResult,
Experimental_RealtimeModelV4ServerEvent as RealtimeModelV4ServerEvent,
Experimental_RealtimeModelV4SessionConfig as RealtimeModelV4SessionConfig,
} from '@ai-sdk/provider';
import type { FetchFunction } from '@ai-sdk/provider-utils';
import {
buildOpenAISessionConfig,
parseOpenAIRealtimeServerEvent,
serializeOpenAIRealtimeClientEvent,
} from './openai-realtime-event-mapper';
export type OpenAIRealtimeModelConfig = {
provider: string;
baseURL: string;
headers: () => Record<string, string | undefined>;
fetch?: FetchFunction;
};
export class OpenAIRealtimeModel implements RealtimeModelV4 {
readonly specificationVersion = 'v4' as const;
readonly provider: string;
readonly modelId: string;
private readonly config: OpenAIRealtimeModelConfig;
constructor(modelId: string, config: OpenAIRealtimeModelConfig) {
this.modelId = modelId;
this.provider = config.provider;
this.config = config;
}
async doCreateClientSecret(
options: RealtimeModelV4ClientSecretOptions,
): Promise<RealtimeModelV4ClientSecretResult> {
const fetchFn = this.config.fetch ?? fetch;
const url = `${this.config.baseURL}/realtime/client_secrets`;
const session =
options.sessionConfig != null
? buildOpenAISessionConfig(options.sessionConfig, this.modelId)
: { type: 'realtime', model: this.modelId };
const response = await fetchFn(url, {
method: 'POST',
headers: {
...this.config.headers(),
'Content-Type': 'application/json',
},
body: JSON.stringify({
session,
...(options.expiresAfterSeconds != null
? {
// `anchor` is required by the client secrets endpoint; without it
// the request fails with "Missing required parameter:
// 'expires_after.anchor'".
expires_after: {
anchor: 'created_at',
seconds: options.expiresAfterSeconds,
},
}
: {}),
}),
});
if (!response.ok) {
const text = await response.text();
throw new Error(
`OpenAI realtime client secret request failed: ${response.status} ${text}`,
);
}
const data = (await response.json()) as {
value: string;
expires_at?: number;
};
return {
token: data.value,
url: `wss://${new URL(this.config.baseURL).host}/v1/realtime?model=${encodeURIComponent(this.modelId)}`,
expiresAt: data.expires_at,
};
}
getWebSocketConfig(options: { token: string; url: string }): {
url: string;
protocols?: string[];
} {
return {
url: options.url,
protocols: ['realtime', `openai-insecure-api-key.${options.token}`],
};
}
parseServerEvent(raw: unknown): RealtimeModelV4ServerEvent {
return parseOpenAIRealtimeServerEvent(raw);
}
serializeClientEvent(event: RealtimeModelV4ClientEvent): unknown {
return serializeOpenAIRealtimeClientEvent(event, this.modelId);
}
buildSessionConfig(
config: RealtimeModelV4SessionConfig,
): Record<string, unknown> {
return buildOpenAISessionConfig(config, this.modelId);
}
}