You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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格式提交请求,但原代码存在两个核心问题:

  1. 所有请求统一用json_encode($params)处理POST数据,而文件上传不能用JSON格式,必须直接传递数组让cURL自动处理multipart编码。
  2. 请求头的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,提问作者蒋振东

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 04:04:57