DEV Community

VoiceDeveloper
VoiceDeveloper

Posted on

Build an Audiobook Generator Using ElevenLabs API

Why an Audiobook Generator?

If you’ve ever wanted to turn a pile of markdown files, PDFs, or plain‑text stories into a polished audiobook, you’re not alone. Traditional TTS engines either sound robotic or require a costly subscription. Enter ElevenLabs, a modern voice‑AI platform that delivers natural‑sounding speech and even lets you clone a voice with just a few minutes of audio. In this walkthrough we’ll build a simple, extensible audiobook generator using the ElevenLabs API. By the end you’ll have a script that can:

  • Accept any length of text (chapter by chapter or whole book)
  • Choose a high‑quality voice from ElevenLabs
  • Split the output into manageable MP3 files and stitch them together
  • Optionally clone a custom voice for a truly unique listening experience

All of this can be done with just a few lines of Python (or a curl command if you prefer the command line).


Prerequisites

Before we dive into code, make sure you have:

Item Reason
Python 3.8+ For the example scripts
requests library (pip install requests) Simple HTTP client
pydub (pip install pydub) Audio concatenation
ffmpeg installed on your system Backend for pydub
An ElevenLabs API key Needed to call the TTS endpoint

If you don’t have an API key yet, head over to the ElevenLabs sign‑up page and grab one. The affiliate link below works for anyone signing up for the first time:

👉 Get started with ElevenLabs here 👈


Getting an API Key

  1. Visit the ElevenLabs dashboard.
  2. Click API Keys → Create new key.
  3. Copy the key; you’ll store it in an environment variable called ELEVENLABS_API_KEY.
export ELEVENLABS_API_KEY="your-secret-key-here"
Enter fullscreen mode Exit fullscreen mode

Keeping the key out of source control is a best practice, especially if you plan to share the repo.


Making a Quick Test Call with curl

If you just want to see the magic in action, fire off a single request with curl. Replace YOUR_VOICE_ID with the voice you’d like to use (the default “Rachel” works fine for demos).

curl -X POST "https://api.elevenlabs.io/v1/text-to-speech/YOUR_VOICE_ID" \
  -H "xi-api-key: $ELEVENLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "text": "Hello, world! This is a quick test of the ElevenLabs text‑to‑speech API.",
        "voice_settings": {
          "stability": 0.75,
          "similarity_boost": 0.85
        }
      }' \
  --output test_output.mp3
Enter fullscreen mode Exit fullscreen mode

Open test_output.mp3 in your favourite player – you should hear a surprisingly human voice reading the sentence.


Python Boilerplate

Below is a minimal Python wrapper that handles authentication, sends the request, and writes the MP3 to disk.

import os
import requests

API_URL = "https://api.elevenlabs.io/v1/text-to-speech"
API_KEY = os.getenv("ELEVENLABS_API_KEY")
VOICE_ID = "YOUR_VOICE_ID"          # e.g., "EXAVITQu4vr4xnSDxMaL"

def synthesize(text: str, out_path: str):
    headers = {
        "xi-api-key": API_KEY,
        "Content-Type": "application/json"
    }
    payload = {
        "text": text,
        "voice_settings": {
            "stability": 0.75,
            "similarity_boost": 0.85
        }
    }
    response = requests.post(f"{API_URL}/{VOICE_ID}", json=payload, headers=headers)

    if response.status_code != 200:
        raise Exception(f"API error {response.status_code}: {response.text}")

    with open(out_path, "wb") as f:
        f.write(response.content)

if __name__ == "__main__":
    sample = "It was the best of times, it was the worst of times..."
    synthesize(sample, "chapter1.mp3")
Enter fullscreen mode Exit fullscreen mode

Run the script and you’ll get chapter1.mp3. Swap out the sample variable with any text you like.


Handling Long Texts

Audiobook chapters often exceed the 2 KB limit imposed by the API per request. The recommended approach is to:

  1. Split the chapter into sentences or paragraphs (keep each chunk under ~500 characters).
  2. Send each chunk sequentially.
  3. Concatenate the resulting MP3s.

Here’s a helper that does the heavy lifting:

import textwrap
from pydub import AudioSegment

def split_text(text, max_chars=500):
    # Simple split on newline, then wrap long paragraphs
    paragraphs = text.split("\n")
    chunks = []
    for para in paragraphs:
        if not para.strip():
            continue
        wrapped = textwrap.wrap(para, width=max_chars)
        chunks.extend(wrapped)
    return chunks

def generate_chapter(text, out_file):
    chunks = split_text(text)
    temp_files = []

    for i, chunk in enumerate(chunks):
        tmp = f"tmp_{i}.mp3"
        synthesize(chunk, tmp)
        temp_files.append(tmp)

    # Concatenate all temporary MP3s
    combined = AudioSegment.empty()
    for tmp in temp_files:
        combined += AudioSegment.from_mp3(tmp)

    combined.export(out_file, format="mp3")

    # Clean up temporary files
    for tmp in temp_files:
        os.remove(tmp)

# Example usage:
if __name__ == "__main__":
    with open("my_book_chapter.txt", "r", encoding="utf-8") as f:
        chapter_text = f.read()
    generate_chapter(chapter_text, "chapter1_full.mp3")
Enter fullscreen mode Exit fullscreen mode

The split_text function respects natural paragraph breaks, which helps preserve intonation cues for the model.


Optional: Voice Cloning

ElevenLabs also offers a voice cloning endpoint that lets you upload a few minutes of a speaker’s audio and generate a custom voice ID. The flow is:

  1. POST the audio file to /v1/voices/add (requires a “beta” access token – request it in the dashboard).
  2. Wait for the model to finish training (usually a few minutes).
  3. Use the returned voice_id in the TTS calls above.

Because cloning can be a whole tutorial on its own, we’ll just point you to the official docs and encourage you to experiment once you’re comfortable with the basics.


Deploying as a Small Service

If you want to expose the generator as a tiny web service (e.g., for a personal website), Flask or FastAPI make it painless:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

class TTSRequest(BaseModel):
    text: str
    voice_id: str = "YOUR_DEFAULT_VOICE_ID"

@app.post("/tts")
def tts(req: TTSRequest):
    try:
        out_path = "output.mp3"
        synthesize(req.text, out_path)
        return {"audio_url": f"/static/{out_path}"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
Enter fullscreen mode Exit fullscreen mode

Run uvicorn myservice:app --reload and you have a REST endpoint that any front‑end can hit. Remember to serve the static/ folder so the MP3 files are reachable.


Wrapping Up

You now have a working pipeline:

  1. Grab an API key from ElevenLabs.
  2. Split your manuscript into bite‑sized chunks.
  3. Send each chunk to the TTS endpoint.
  4. Stitch the resulting MP3s together.
  5. (Optional) Clone a custom voice for that extra personal touch.

From here you can add features like chapter metadata, cover art embedding (via ID3 tags), or even a simple CLI that reads a folder of .txt files and spits out a full audiobook package.


Try It Yourself!

The ElevenLabs API makes high‑quality, natural‑sounding narration accessible to any developer. Whether you’re building a personal project, a SaaS product, or just having fun with voice AI, the platform’s generous free tier and straightforward REST interface are perfect for rapid prototyping.

👉 Ready to give it a spin? Grab your ElevenLabs API key now: https://try.elevenlabs.io/kr07zfuqn1bp

Happy coding, and enjoy listening to the stories you bring to life!

Top comments (0)