使用 Expo 在 React Native 中播放来自 OpenAI TTS API 的音频响应

问题描述 投票:0回答:1

我最近开始使用 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 expo mp3 text-to-speech expo-av
1个回答
0
投票

好吧,经过一些认真的尝试试图解决这个问题,这是我的解决方案,我希望它对您和其他人有好处。目前对我有用(我仍在测试功能,因此可能会遇到问题,但祈祷吧)。

此外,我除了播放声音实例以确保其正常工作之外,还没有处理更多的事情,因此可能会期待更多的工作..

客户

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);
© www.soinside.com 2019 - 2024. All rights reserved.