// dt-realtime: mint ephemeral OpenAI Realtime session tokens add_action('rest_api_init', function () { register_rest_route('dt/v1', '/realtime-session', [ 'methods' => 'POST', 'callback' => function (\WP_REST_Request $req) { $model = 'gpt-realtime-mini'; // or 'gpt-realtime' for higher quality $voice = 'alloy'; // built-in voice id (e.g., alloy, verse, breeze) $instructions = << $model, 'voice' => $voice, 'modalities' => ['audio', 'text'], 'instructions' => $instructions, // Optional: steer turn-taking and latency 'input_audio_format' => 'pcm16', 'output_audio_format' => 'pcm16', 'turn_detection' => ['type' => 'server_vad', 'threshold' => 0.5, 'prefix_padding_ms' => 150, 'silence_duration_ms' => 550], ]; $ch = curl_init('https://api.openai.com/v1/realtime/sessions'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . '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', 'Content-Type: application/json' ], CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode($body), CURLOPT_TIMEOUT => 10 ]); $resp = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $err = curl_error($ch); curl_close($ch); if ($err || $code < 200 || $code >= 300) { return new \WP_REST_Response(['error' => 'OpenAI session create failed', 'detail' => $resp ?: $err], 500); } $json = json_decode($resp, true); // This field name comes from OpenAI: client_secret.value (the ephemeral token) $token = $json['client_secret']['value'] ?? null; if (!$token) { return new \WP_REST_Response(['error' => 'No client token in response', 'detail' => $json], 500); } // Pass through model for client convenience return new \WP_REST_Response(['token' => $token, 'model' => $body['model']], 200); }, 'permission_callback' => '__return_true', // If needed, add nonce/cap check ]); });