PHP调用OpenAI Whisper接口报错,请求排查问题
PHP对接OpenAI Whisper接口报错排查
问题描述
我正在使用PHP对接OpenAI的Whisper接口,但按照文档操作始终报错。文本生成(Completions)和图片生成接口可正常返回结果,仅Whisper接口存在问题。
原代码
<?php define('OPENAI_API_KEY', 'sk-**********'); $type = empty($_GET['type'])? '':$_GET['type']; $prompt = empty($_GET['prompt'])? '':$_GET['prompt']; if(!empty($prompt)||$type=='audio'){ switch($type){ case 'text': $url = 'https://api.openai.com/v1/completions'; $params['prompt'] = $prompt; $params['max_tokens'] = 2048; $params['model'] = 'text-davinci-003'; break; case 'image': $url = 'https://api.openai.com/v1/images/generations'; $params['prompt'] = $prompt; //$params['model'] = 'image-alpha-001'; $params['n'] = 1; $params['size'] = '512x512'; break; case 'audio': $url = 'https://api.openai.com/v1/audio/transcriptions'; // $params['prompt'] = $prompt; // $params['max_tokens'] = 2048; $params['model'] = 'whisper-1'; $params['file'] = curl_file_create(__DIR__ . '/audio/11.m4a');//fopen('./audio/11.wav','r+');//curl_file_create(__DIR__ . '/files/en-marvel-endgame.m4a'); //$params['response_format'] = 'text'; break; default: $url = 'https://api.openai.com/v1/completions'; $params['prompt'] = $prompt; $params['max_tokens'] = 2048; $params['model'] = 'text-davinci-003'; } //var_dump($params['file']);exit; $response = sendPostRequest($params,$url); $response_data = json_decode($response,true); var_dump($response_data);exit; } //echo $response; function sendPostRequest($params,$url) { $curl = curl_init(); //var_dump($params);exit; curl_setopt_array($curl, array( CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => 0, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_POSTFIELDS => json_encode($params), CURLOPT_HTTPHEADER => array( "Content-Type: application/json",//multipart/form-data "Authorization: Bearer " . OPENAI_API_KEY ), )); //var_dump($curl); $response = curl_exec($curl); //var_dump($response);exit; curl_close($curl); return $response; }
报错情况
- 将请求头设置为
multipart/form-data时,返回报错:Could not parse multipart form - 移除Content-Type请求头时,返回报错:you must provide a model parameter
问题根源
Whisper转录接口要求用multipart/form-data格式提交请求,但原代码存在两个核心问题:
- 所有请求统一用
json_encode($params)处理POST数据,而文件上传不能用JSON格式,必须直接传递数组让cURL自动处理multipart编码。 - 请求头的
Content-Type设置错误:上传文件时不需要手动指定multipart/form-data,手动指定会缺少必要的boundary参数,导致接口解析失败;而默认用JSON头时,文件参数无法被接口识别,所以会提示缺少model参数。
修复方案
修改sendPostRequest函数,根据接口类型区分请求格式:
修复后的完整代码
<?php define('OPENAI_API_KEY', 'sk-**********'); $type = empty($_GET['type'])? '':$_GET['type']; $prompt = empty($_GET['prompt'])? '':$_GET['prompt']; if(!empty($prompt)||$type=='audio'){ $isJson = true; switch($type){ case 'text': $url = 'https://api.openai.com/v1/completions'; $params['prompt'] = $prompt; $params['max_tokens'] = 2048; $params['model'] = 'text-davinci-003'; break; case 'image': $url = 'https://api.openai.com/v1/images/generations'; $params['prompt'] = $prompt; $params['n'] = 1; $params['size'] = '512x512'; break; case 'audio': $url = 'https://api.openai.com/v1/audio/transcriptions'; $params['model'] = 'whisper-1'; $params['file'] = curl_file_create(__DIR__ . '/audio/11.m4a'); $isJson = false; break; default: $url = 'https://api.openai.com/v1/completions'; $params['prompt'] = $prompt; $params['max_tokens'] = 2048; $params['model'] = 'text-davinci-003'; } $response = sendPostRequest($params, $url, $isJson); $response_data = json_decode($response, true); var_dump($response_data); exit; } function sendPostRequest($params, $url, $isJson = true) { $curl = curl_init(); $options = [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => 0, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_HTTPHEADER => [ "Authorization: Bearer " . OPENAI_API_KEY ], ]; if ($isJson) { $options[CURLOPT_POSTFIELDS] = json_encode($params); $options[CURLOPT_HTTPHEADER][] = "Content-Type: application/json"; } else { $options[CURLOPT_POSTFIELDS] = $params; // 上传文件时无需手动设置Content-Type,cURL会自动生成带boundary的正确头 } curl_setopt_array($curl, $options); $response = curl_exec($curl); curl_close($curl); return $response; }
关键修改点
- 新增
$isJson标记,区分JSON请求和multipart文件上传请求 - 音频请求时直接传递包含
curl_file_create生成的文件对象的数组,不进行JSON编码 - 仅在文本/图片请求时添加
Content-Type: application/json头,音频请求让cURL自动生成multipart格式的请求头 - 清理了原代码中不必要的注释,让逻辑更清晰
内容的提问来源于stack exchange,提问作者蒋振东
相关产品推荐
相关产品推荐

