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

Nuxt3上传音频至Whisper API遇BadRequestError问题求助

问题解决:Nuxt3中Whisper API无法识别WAV音频文件

问题现象

开发Nuxt3项目时,客户端通过FormData上传WAV格式音频到服务器/api/whisper路由,服务器用formidable解析后调用OpenAI Whisper API,返回400错误:Unrecognized file format. Supported formats: ['flac', 'm4a', 'mp3', 'mp4', 'mpeg', 'mpga', 'oga', 'ogg', 'wav', 'webm'],客户端显示Transcript: Internal Server Error。上传的文件确实是Whisper支持的WAV格式。

问题原因

formidable默认会将上传的文件保存为无后缀名的临时文件,而Whisper API是通过文件名后缀识别文件格式的,没有后缀的文件会被判定为不支持的格式。

解决方案

给formidable保存的临时文件添加正确后缀名,或在调用Whisper API时手动指定包含后缀的文件名,以下是两种可行方案:

方案1:修改formidable配置,保留文件后缀

修改parseForm函数,配置formidable的filename选项,让临时文件保留原文件的后缀:

async function parseForm(event: any) {
  return new Promise((resolve, reject) => {
    const form = formidable({
      filename: (name, ext, part, form) => {
        // 保留原文件名的后缀
        return `${Date.now()}${ext}`;
      }
    });
    form.parse(event.req, (err, fields, files) => {
      if (err) reject(err)
      resolve({ fields, files })
    })
  })
}

方案2:调用Whisper API时指定文件名

无需修改formidable配置,给可读流手动添加name属性(包含后缀),OpenAI SDK会读取该属性识别文件格式:

// 替换原转录调用代码
const fileStream = fs.createReadStream(filePath);
// 手动添加带后缀的文件名
Object.defineProperty(fileStream, 'name', { value: audioFile[0].originalFilename });

const transcript = await openAI.audio.transcriptions.create({
  model: "whisper-1", 
  file: fileStream,
  language: "ja"
})

修改后的完整服务器代码(方案2示例)

import OpenAI from "openai";
import formidable from 'formidable';
import fs from 'fs';

const openAI = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
})

export default defineEventHandler(async (event) => {
  try {
    const { fields, files } = await parseForm(event);
    const audioFile = files.audio
    if (!audioFile) throw new Error('Audio file is missing')
    
    const filePath = audioFile[0].filepath
    if (!filePath) {
      console.error('ファイルパスが未定義です。')
      return { status: 400, body: 'File path is undefined' }
    }

    // 创建可读流并添加文件名属性
    const fileStream = fs.createReadStream(filePath);
    Object.defineProperty(fileStream, 'name', { value: audioFile[0].originalFilename });

    const transcript = await openAI.audio.transcriptions.create({
      model: "whisper-1", 
      file: fileStream,
      language: "ja"
    })

    return {
      status: 200,
      body: transcript.text // 转录文本在text属性中,直接返回便于前端处理
    }
  } catch (error) {
    console.error(error)
    return {
      status: 500,
      body: "Internal Server Error"
    }
  }
})

async function parseForm(event: any) {
  return new Promise((resolve, reject) => {
    const form = formidable();
    form.parse(event.req, (err, fields, files) => {
      if (err) reject(err)
      resolve({ fields, files })
    })
  })
}

额外注意点

  • 客户端代码中,transcript.value = res.body需注意:服务器返回的transcript.text才是转录的纯文本内容,原代码返回整个transcript对象可能导致前端显示异常。
  • 可在客户端添加文件格式校验,仅允许选择Whisper支持的格式,减少无效请求。

内容的提问来源于stack exchange,提问作者umi tori

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 11:05:55