我刚刚开始制作一个小演示,用于将前端捕获的音频(格式为audio/webm)通过JS转换,然后发送到Laravel应用的后端。我猜有JS库可以处理这种转换,但我更倾向于使用服务器端的FFMPEG解决方案,我现在就是这么做的。
后端代码如下。经过一番尝试后,我使用的PHP Composer包似乎可以工作,而另一个适用于Laravel的包也存在。我更愿意使用这个包,因为我还有其他非Laravel的PHP应用。
问题:
-
使用FFMpeg库,是否有办法将转换后的.mp3文件捕获到脚本中的PHP变量中,而不是先保存到文件系统然后再读取回来?
-
对于OpenAI的调用,我也想捕获那里的异常。现在我只是暂时放了一个占位符。
protected function whisper(Request $request) { $yourApiKey = getenv('OPENAI_API_KEY'); $client = OpenAI::client($yourApiKey); $file = $request->file('file'); $mimeType = $request->file('file')->getMimeType(); $audioContents = $file->getContent(); try { FFMpeg::open($file) ->export() ->toDisk('public') ->inFormat(new \FFMpeg\Format\Audio\Mp3) ->save('song_converted.mp3'); } catch (EncodingException $exception) { $command = $exception->getCommand(); $errorLog = $exception->getErrorOutput(); } $mp3 = Storage::disk('public')->path('song_converted.mp3'); try { $response = $client->audio()->transcribe([ 'model' => 'whisper-1', 'file' => fopen($mp3, 'r'), 'response_format' => 'verbose_json', ]); } catch (EncodingException $exception) { $command = $exception->getCommand(); $errorLog = $exception->getErrorOutput(); } echo json_encode($response);}
回答:
我认为你无法直接将Whisper API的流输出获取到变量中。但我想你想要的是:
- 将Whisper的流响应存储在内存中;或者
- 存储在不需要你管理的文件中。
幸运的是,OpenAI客户端库似乎接受指针资源(即fopen返回的变量)。最接近的解决方案是使用php://temp读写流。PHP会检查其大小是否超过2MB(可配置),如果超过,它会创建一个临时文件进行存储。
这样做的好处是:
- 如果流较小,PHP会全部在内存中处理。
- 如果流较大,你不需要自己管理生成的临时文件。PHP会在使用后删除临时文件。
$mp3 = fopen('php://temp');$response = $client->audio()->transcribe([ 'model' => 'whisper-1', 'file' => fopen($mp3, 'w+'), 'response_format' => 'verbose_json',]);
然后你可以rewind $mp3
流并读取/流出。例如:
// 将指针移回临时存储的开始位置。rewind($mp3);// 直接将流以块的方式复制到// 输出缓冲区/输出流$output = fopen('php://output', 'w');stream_copy_to_stream($mp3, $output, 1024);
在Laravel中,你可能需要这样做:
rewind($mp3);return response()->stream(fn() => echo stream_get_contents($mp3));