ElevenLabs Custom Node

Hi,

I have been trying to create a custom node to generate a speech based on a text using a custom voice.

However, I don’t know how to save the output to Google Drive. So far it saves something that has 0 bytes (I think it’s just the file name).

I know the rest of the flow is correct because it runs successfully and I can see the audio file in the ElevenLabs’s interface.

I mainly used Gummie and now I’m stuck :slight_smile:

Below is the custom node code I have.

Could you have please have a look?

Thank you,
Kevin

def main(text, file_name, params):
import requests
import os
import time
import json

# Get parameters
api_key = params.get("api_key")
voice_id = params.get("voice_id")

if not api_key:
    raise ValueError("ElevenLabs API key not provided")

if not voice_id:
    raise ValueError("Voice ID not provided")

# Generate a unique filename with timestamp
timestamp = int(time.time())
if not file_name or file_name.strip() == "":
    file_name = f"audio_{timestamp}"

# Ensure the file has .mp3 extension
if not file_name.endswith(".mp3"):
    file_name = f"{file_name}.mp3"

# Step 1: Generate audio with ElevenLabs
tts_url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"

# Request headers
headers = {
    "Accept": "application/json",  # Changed to JSON to get history item ID
    "Content-Type": "application/json", 
    "xi-api-key": api_key
}

# Request body
data = {
    "text": text,
    "model_id": "eleven_multilingual_v2",
    "voice_settings": {
        "speed": 1.10,
        "stability": 0.5,
        "similarity_boost": 0.5
    }
}

# Step 2: First get the history item ID
print("Generating audio with ElevenLabs API...")
response = requests.post(tts_url, json=data, headers=headers)

if response.status_code != 200:
    raise Exception(f"API request failed with status code {response.status_code}: {response.text}")

# Step 3: Get the latest history item
history_url = "https://api.elevenlabs.io/v1/history"
history_headers = {
    "Accept": "application/json",
    "xi-api-key": api_key
}

history_response = requests.get(history_url, headers=history_headers)

if history_response.status_code != 200:
    raise Exception(f"History API request failed with status code {history_response.status_code}: {history_response.text}")

history_data = history_response.json()

if not history_data.get("history"):
    raise Exception("No history items found")

# Get the most recent history item
latest_item = history_data["history"][0]
history_item_id = latest_item["history_item_id"]

# Step 4: Download the audio file from the history
download_url = f"https://api.elevenlabs.io/v1/history/{history_item_id}/audio"
download_headers = {
    "Accept": "audio/mpeg",
    "xi-api-key": api_key
}

print(f"Downloading audio from history item: {history_item_id}")
download_response = requests.get(download_url, headers=download_headers)

if download_response.status_code != 200:
    raise Exception(f"Download failed with status code {download_response.status_code}: {download_response.text}")

# Save the audio file locally
file_path = f"/tmp/{file_name}"
with open(file_path, "wb") as f:
    f.write(download_response.content)

# Debug information
file_size = os.path.getsize(file_path) if os.path.exists(file_path) else 0
print(f"\nDebug: File size is {file_size} bytes\n")
print(f"\n{file_path}\n")

# Return the file path
audio_url = file_path

return audio_url

Hey @kevinlg! If you’re reporting an issue with a flow or an error in a run, please include the run link and make sure it’s shareable so we can take a look.

  1. Find your run link on the history page. Format: https://www.gumloop.com/pipeline?run_id={your_run_id}&workbook_id={workbook_id}

  2. Make it shareable by clicking “Share” → ‘Anyone with the link can view’ in the top-left corner of the flow screen.
    GIF guide

  3. Provide details about the issue—more context helps us troubleshoot faster.

You can find your run history here: https://www.gumloop.com/history

I am not sure if you can pass around urls specially the ones you have created locally. You might have to use the Gumloop api to upload the file and then use the filename to save it in google drive. Another option is to use links but you have to upload the file somewhere like s3 or other filestorage and use it

Hey @kevinlg – To upload the file, the file must exist on the Gumloop working directory or you can output the file URL and then toggle Use Link on the Drive File Writer node. The custom node or run code nodes can’t actually output the file object but you can upload it to the working directory and then reference it via file name.

Hi @Wasay-Gumloop, you mentioned that custom nodes can’t output file objects but can upload to the working directory. My ElevenLabs custom node outputs a file path (‘/tmp/Puma Deviate Nitro 3.mp3’).

How exactly do I reference this file in Google Drive File Writer?

Currently I get this error:

e[31m Google Drive File Writer Failed!
Error with node input or parameter “File URL”. The received value was ‘/tmp/Puma Deviate Nitro 3.mp3’

Invalid URL format. A proper URL must include a scheme (e.g., ‘http’ or ‘https’) as well as a network location (e.g., ‘www.google.com’). Example of a valid URL: ‘https://www.google.com’.
Please double check your node inputs or parameterse[0m

Here’s the link to my flow: https://www.gumloop.com/pipeline?workbook_id=rfcCgDaEPNFRKGjc3tJP6T

Thanks,
Kevin

Hey @kevinlg – So you’ll have to upload the file itself to the working directory, instructions here: https://docs.gumloop.com/api-reference/file-operations/upload-file

You can look into the ElevenLab’s documentation on how to output the file object instead of the file path which can be sent to https://api.gumloop.com/api/v1/upload_file"

Once you’ve successfully uploaded the file using the method above you can output the file_name which would the API response from the endpoint above and connect that directly to the Drive File Writer node.

Let me know if that makes sense.

You can paste in the Gumloop’s doc for the upload file endpoint as well ElevenLab’s doc in the AI prompt and have it generate the code for this.

Hi @Wasay-Gumloop,

Thank you for your help! I have been trying to implement the solution using Gummie but I’m stuck. There’s a file that goes to Google Drive but it’s empty.

Here’s what I have as Run Code node:

def function(audio_url, file_name):
import requests
import base64
import os

print(f"Input audio_url: {audio_url}")
print(f"Input file_name: {file_name}")

# Define file_path variable
file_path = audio_url

# Check if the file exists
if os.path.exists(audio_url):
    file_size = os.path.getsize(audio_url)
    print(f"File exists at {audio_url}, size: {file_size} bytes")
    
    # Read the file content
    with open(audio_url, "rb") as f:
        audio_content = f.read()
    
    # Encode file content to base64
    base64_audio = base64.b64encode(audio_content).decode('utf-8')
    
    # Upload to Gumloop
    gumloop_api_token = "[GUMLOOP_API_KEY]"
    
    upload_url = "https://api.gumloop.com/api/v1/upload_file"
    
    payload = {
        "file_name": f"{file_name}.mp3",
        "file_content": base64_audio,
        "project_id": "xhUbtN61dz4LNDPMDs59hh"
    }

    headers = {
        "Authorization": f"Bearer {gumloop_api_token}",
        "Content-Type": "application/json"
    }
    
    response = requests.post(upload_url, json=payload, headers=headers)
    
    print(f"Upload response status: {response.status_code}")
    
    if response.status_code != 200:
        print(f"Failed to upload to Gumloop: {response.text}")

return file_path

Thanks,
Kevin

Hey @kevinlg – At the moment, we don’t have the capacity to assist with code since it’s highly personalized. That said, I don’t see any reference to ElevenLabs in the code. It looks like it might be generating a random file path rather than the actual file object you need.

Hey @Wasay-Gumloop, thanks. Unfortunately, I can’t solve it with Gummie, even with your inputs. I’ll put in a feature request for custom voices in ElevenLabs (only reason for me trying to do this custom node).

Thank you,
Kevin

Sounds good – will add to the roadmap.

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.