我最近开始使用 Expo 开发一个 React Native 应用程序,几天前我遇到了一个问题,现在开始让我发疯。
我想将文本字符串发送到 OpenAI TTS API 并立即在我的应用程序中播放音频响应。我不想将文件保存在本地。 API 链接:https://platform.openai.com/docs/guides/text-to-speech
到目前为止,我已经成功发出了 HTTP 请求,并且看起来我从 API 得到了正确的响应。当我输出
response.blob()
时,我得到:
{"_data": {"__collector": {}, "blobId": "5C362F63-71CB-45EC-913E-9A808AF2194F", "name": "speech.mp3", "offset": 0, "size": 143520, "type": "audio/mpeg"}}
问题似乎是用 expo-av 播放声音。我已经用谷歌搜索好几天了,无论我尝试哪种解决方案,在尝试播放声音时都会遇到一些错误。当前代码的当前错误是:
错误:AVPlayerItem 实例失败,错误代码为 -1002,域为“NSURLErrorDomain”。
如果有人可以帮助我,我将非常感激(请编写代码示例)。
我还读过这篇文章,其中的解决方案是切换到 Google 的 TTS API,但这不是我想要的解决方案: https://www.reddit.com/r/reactnative/comments/13pa9wx/playing_blob_audio_using_expo_audio_react_native/
这是我的代码:
const convertTextToSpeech = async (textToConvert) => {
const apiKey = 'myKey';
const url = 'https://api.openai.com/v1/audio/speech';
const requestOptions = {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'tts-1',
input: textToConvert,
voice: 'alloy',
language: 'da',
})
};
await fetch(url, requestOptions)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.blob();
})
.then(blob => {
playSound(blob);
})
.catch(error => {
console.error('There was a problem with the request:', error);
});
};
async function playSound(blob) {
const url = URL.createObjectURL(blob);
const { sound } = await Audio.Sound.createAsync({ uri: url });
await sound.playAsync();
}
好吧,经过一些认真的尝试试图解决这个问题,这是我的解决方案,我希望它对您和其他人有好处。目前对我有用(我仍在测试功能,因此可能会遇到问题,但祈祷吧)。
react-native-buffer
。此外,我除了播放声音实例以确保其正常工作之外,还没有处理更多的事情,因此可能会期待更多的工作..
客户
const toBuffer = async (blob) => {
const uri = await toDataURI(blob);
const base64 = uri.replace(/^.*,/g, "");
return Buffer.from(base64, "base64");
};
const toDataURI = (blob) =>
new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => {
const uri = reader.result?.toString();
resolve(uri);
};
});
const constructTempFilePath = async (buffer) => {
const tempFilePath = FileSystem.cacheDirectory + "speech.mp3";
await FileSystem.writeAsStringAsync(
tempFilePath,
buffer.toString("base64"),
{
encoding: FileSystem.EncodingType.Base64,
}
);
return tempFilePath;
};
和
const blob = await response.blob();
const buffer = await toBuffer(blob);
const tempFilePath = await constructTempFilePath(buffer);
const { sound } = await Audio.Sound.createAsync({ uri: tempFilePath });
await sound.playAsync();
服务器
const mp3 = await openai.audio.speech.create({
model: "tts-1",
voice: "alloy",
input: "Hello World",
});
const mp3Stream = new PassThrough();
mp3Stream.end(Buffer.from(await mp3.arrayBuffer()));
res.setHeader("Content-Type", "audio/mpeg");
res.setHeader("Content-Disposition", 'attachment; filename="audio.mp3"');
mp3Stream.pipe(res);