I am creating an Expo app for mobile that allows users to clone voices by uploading audio clips. I am trying to communicate with the Elevenlabs API by allowing the user to upload audio clips using the Expo DocumentPicker, then sending a POST request to the API with the required information. The API reference can be found here: https://elevenlabs.io/docs/api-reference/add-voice. When I call the API, I get a response saying that the format is incorrect, and I believe it is relating to how the audio files are being sent.
I have these 2 functions:
This function in the screen that I am calling the file picker from:
const handlePickAudio = async () => {
const result = await DocumentPicker.getDocumentAsync({
type: 'audio/*',
copyToCacheDirectory: true,
});
if (result.assets && result.assets.length > 0) {
// setIsUploading(true);
const voiceID = await ElevenLabs.createVoice("Demo Voice", [result.assets[0]]);
console.log("Resulting Voice ID:", voiceID);
if (voiceID) {
// router.push({
// pathname: "/onboarding/onboarding10",
// params: { voiceID: voiceID },
// });
}
else {
Alert.alert('Error', 'Failed to create voice');
}
setIsUploading(false);
}
}
and this function in my elevenlabs functions file:
export const createVoice = async (name: string, audioClips: DocumentPicker.DocumentPickerAsset[]) => {
// set data/options to send to API
const formData = new FormData();
formData.append('name', name);
formData.append('remove_background_noise', 'true');
// append each file individually
for (const clip of audioClips) {
const response = await fetch(clip.uri);
const blob = await response.blob();
formData.append('files', blob, clip.name);
}
const options = {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
'xi-api-key': 'apikey',
},
body: formData
};
let voiceID = '';
// send data to API
const response = await fetch('https://api.elevenlabs.io/v1/voices/add', options);
const json = await response.json();
voiceID = json.voice_id;
return voiceID;
}
When I call the API, I am getting the response:
response {"detail":[{"loc":["body","files",0],"msg":"Expected UploadFile, received: <class 'str'>","type":"value_error"}]}
I have tried converting the files to blobs and sending them that way, and that did not seem to work either. I also got a successful response from using this curl request on my desktop terminal:
curl --request POST \
--url https://api.elevenlabs.io/v1/voices/add \
--header 'Content-Type: multipart/form-data' \
--header 'xi-api-key: apikey' \
--form files=@/Users/myname/Desktop/sampleaudioclip.mp3 \
--form name=Samplename \
--form remove_background_noise=true
It worked on my desktop, but when I try it in the mobile app in Expo, it seems to be giving the files in a different format that the API call does not accept. Please let me know if you would like any more information.
For anyone that is wondering, the issue is likely with React Native's handling of File types differing from HTML/javascript web file handling. The issue was not able to be easily resolved after days of trying, so I made a Python Flask API endpoint and sent the picked file there and used Python to send it to elevenlabs, and returned the voice ID back to my RN app. This approach is not ideal, but works in my application for now.