trying to create a function to elevenlabs and can't get it right

// Helper function: Convert ArrayBuffer to Base64 (for web environments)
function arrayBufferToBase64(buffer) {
let binary = ‘’;
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}

async function generateVoice() {
const apiKey = ai.config.elevenlabs_api_key;
const voiceId = ai.config.voice_id;
const text = ai.vars.text_to_speak;
const outputVariable = ai.config.outputVariable || ‘voiceAudioUrl’;

if (!apiKey || !voiceId || !text) {
throw new Error(‘Missing required parameters: elevenlabs_api_key, voice_id, or text_to_speak’);
}

// :white_check_mark: move output_format to URL
const url = https://api.elevenlabs.io/v1/text-to-speech/${voiceId}?output_format=mp3_44100_128;
const payload = {
text: text,
model_id: ‘eleven_turbo_v2_5’,
voice_settings: {
stability: 0.5,
similarity_boost: 0.75
}
};

try {
const response = await fetch(url, {
method: ‘POST’,
headers: {
‘xi-api-key’: apiKey,
‘Content-Type’: ‘application/json’,
‘Accept’: ‘audio/mpeg’
},
body: JSON.stringify(payload)
});

if (!response.ok) {
  const errorText = await response.text();
  throw new Error(`ElevenLabs API error: ${response.status} - ${errorText}`);
}

const audioBuffer = await response.arrayBuffer();
const base64Audio = arrayBufferToBase64(audioBuffer);
const audioUrl = `data:audio/mpeg;base64,${base64Audio}`;


ai.vars[outputVariable] = audioUrl;
console.log(`✅ Audio generated and saved to variable: ${outputVariable}`);

} catch (error) {
console.error(‘:cross_mark: Error generating voice:’, error);
throw new Error(Failed to generate voice: ${error.message});
}
}

await generateVoice();

We’re working on integrating ElevenLabs with MindStudio and are trying to replicate the behavior of your built-in textToSpeech block (which generates a cloud-hosted audio link and saves it to {{voiceAudioUrl}}), but using direct API calls instead.

Currently, we successfully generate audio files via ElevenLabs API, including specifying the desired output_format (for example, mp3_44100_128). However, instead of getting a cloud-hosted link (CDN URL) like your block provides, we end up with only a data URL (e.g., data:audio/mpeg;base64,...), which does not play well in the MindStudio interface.

Our request:
We would appreciate guidance or examples on:

  • How to send the result as a Buffer or Binary (instead of Data URL)
    so it can be automatically uploaded and stored via MindStudio’s CDN, just like the native block does.
  • Alternatively, if you have an internal API or service we can call to upload a file and receive a CDN link back, we would love to get documentation or a sample on how to use it.

We specifically need this to work because we are using custom voices we designed in ElevenLabs, which are not accessible through the built-in textToSpeech block.

Thanks a lot for your help and guidance!

I have tried this - but received an error :
Run Started
Jul 15, 2025 1:15:26 AM
1 Action Finished Successfully
Execute Function

1 Action started on CloudRunnerInstance ID: 4ws5x at Jul 15, 2025 1:15:26.447 AM GMT+3
2 Resolving variables
3 4 msResolved function configuration object: JSON
{voice_id: "acCWxmzPBgXdHwA63uzP"text_to_speak: "Hello! This is Sophia, your AI capital advisor"outputVariable: "voiceAudioUrl"elevenlabs_api_key: "sk_bfa6fef283dd81437a83bb2b6e80e691c27a6c4cee37f5a9"}
4 Loading code
5 16 msPreparing JavaScript execution environment (Node v22.15.0 LTS)
6 Executing “ElevenLabs Voice Generator”
7 Console log: “:white_check_mark: Text to speak:” “Hello! This is Sophia, your AI capital advisor”
8 Console log: “:microphone: Sending request to ElevenLabs…”
9 Console log: ":white_check_mark: Base64 audio length:"260608
10 Error: “:cross_mark: uploadFile returned empty url”
11 Execution error: Error: :cross_mark: uploadFile returned empty url

Here is the full code:
async function simpleElevenLabsFetch() {
const apiKey = ai.config.elevenlabs_api_key;
const voiceId = ai.config.voice_id;
const text = ai.config.text_to_speak; // כאן שיניתי ל־ai.config כי זה ב־config, לא ב־vars
const outputVariable = ai.config.outputVariable || ‘voiceAudioUrl’;

function arrayBufferToBase64(buffer) {
let binary = ‘’;
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}

if (!apiKey || !voiceId || !text) {
throw new Error(‘:cross_mark: Missing required parameters: elevenlabs_api_key, voice_id, or text_to_speak’);
}

console.log(‘:white_check_mark: Text to speak:’, text);

const url = https://api.elevenlabs.io/v1/text-to-speech/${voiceId}?output_format=mp3_44100_128;
const payload = {
text: text,
model_id: ‘eleven_turbo_v2_5’
};

try {
console.log(‘:microphone: Sending request to ElevenLabs…’);
const response = await fetch(url, {
method: ‘POST’,
headers: {
‘xi-api-key’: apiKey,
‘Content-Type’: ‘application/json’,
‘Accept’: ‘audio/mpeg’
},
body: JSON.stringify(payload)
});

if (!response.ok) {
  const errorText = await response.text();
  throw new Error(`ElevenLabs API error: ${response.status} - ${errorText}`);
}

const audioBuffer = await response.arrayBuffer();
const base64Audio = arrayBufferToBase64(audioBuffer);

console.log('✅ Base64 audio length:', base64Audio.length);

// ⬇️ 
const uploadResult = await ai.uploadFile(base64Audio, 'audio/mpeg', 'base64');
if (!uploadResult.url) {
  throw new Error('❌ uploadFile returned empty url');
}

ai.vars[outputVariable] = uploadResult.url;
console.log(`✅ Audio URL saved to variable: ${outputVariable}`);

} catch (error) {
console.error(‘:cross_mark: Error fetching audio:’, error);
throw error;
}
}

await simpleElevenLabsFetch();

Hi,
I’m using ElevenLabs API to generate audio (output_format=mp3_44100_128).
When I fetch the audio, I correctly get an arrayBuffer with ID3 header (valid MP3).

However, when I upload it using ai.uploadFile(buffer, 'audio/mpeg', 'binary') or similar (also tried Uint8Array, base64),
the file is saved but becomes corrupted — media players say the file is unsupported or invalid.

In contrast, PDFs and images upload fine.

Could you confirm:
:white_check_mark: Is ai.uploadFile intended to support binary audio files (MP3)?
:white_check_mark: What data format and type should be passed? (ArrayBuffer, TypedArray, base64, Blob, File…)
:white_check_mark: Are there known limitations or MIME-type restrictions?

Thank you!