DEV Community

VoiceDeveloper
VoiceDeveloper

Posted on

How to Build a Podcast Intro Generator

The Problem: A Repetitive Podcast Intro

Every podcast starts with the same thing: a brief hook, a name, and a tagline.

If you’re running a weekly show, you’re recording the same intro dozens of times a month.

That’s tedious, it’s a drain on your time, and it can feel robotic when you’re listening back.

What if you could generate a fresh, high‑quality intro on demand—just by changing a few words—without ever touching a microphone again?

That’s what a Podcast Intro Generator does. In this post we’ll walk through how to build one from scratch, using modern voice‑AI tools, and we’ll show you how to plug in ElevenLabs for the TTS and voice‑cloning magic.


1. The Core Pieces

Component Why it matters Typical tech stack
Prompt Engine Generates the text that will be spoken (e.g., “Welcome to TechTalk with your host, Alex.”) Python, Jinja2 templates
Voice Model Provides a realistic, expressive voice that matches your brand. ElevenLabs Voice Cloning API
Text‑to‑Speech (TTS) Turns the prompt into audio. ElevenLabs TTS endpoint
Post‑Processing Adds background music, fades, and trims silence. ffmpeg, pydub
Delivery Stores the clip and makes it easy to embed in your podcast. AWS S3, local filesystem, or your hosting platform’s media library

2. Get Your ElevenLabs API Key

ElevenLabs offers a powerful, developer‑friendly TTS service with a simple REST API. Sign up at the affiliate link below to get a free tier and a 30‑day trial:

👉 https://try.elevenlabs.io/kr07zfuqn1bp

Once you’re registered, grab your API key from the dashboard. We’ll use it in the code snippets that follow.


3. Building the Prompt Engine

Let’s start with a small Python script that pulls data from a JSON config and renders a template.

import json
from jinja2 import Template

# Load config
with open('config.json') as f:
    cfg = json.load(f)

prompt_template = """
Welcome to *{{ show_name }}*, the podcast where {{ host_name }} talks about {{ topics }}.
Tune in, hit subscribe, and enjoy the show!
"""

template = Template(prompt_template)
prompt = template.render(**cfg)
print(prompt)
Enter fullscreen mode Exit fullscreen mode

config.json could look like:

{
  "show_name": "TechTalk",
  "host_name": "Alex",
  "topics": "the latest in AI, cloud, and devops"
}
Enter fullscreen mode Exit fullscreen mode

Feel free to expand this to pull from a database, CMS, or even an Airtable base.


4. Voice Cloning (Optional but Powerful)

If you want the intro to sound like you (or a brand‑specific voice), ElevenLabs’ Voice Cloning lets you upload a few minutes of audio and generate a custom voice model.

import requests

API_KEY = 'YOUR_ELEVENLABS_API_KEY'
headers = {'xi-api-key': API_KEY}

# Step 1: Create a new voice
voice_payload = {
    "name": "Alex Voice",
    "description": "Alex’s warm, conversational tone"
}
voice_resp = requests.post(
    'https://api.elevenlabs.io/v1/voices',
    json=voice_payload,
    headers=headers
)
voice_id = voice_resp.json()['voice_id']
print("Created voice:", voice_id)
Enter fullscreen mode Exit fullscreen mode

Once the voice is ready, you can reference it by voice_id in the TTS call. If you’re happy with one of ElevenLabs’ pre‑built voices, skip this step and just use the voice_id of the built‑in model.


5. Text‑to‑Speech Call

Now we’ll synthesize the prompt into an MP3 file.

import os
import time

def synthesize(prompt, voice_id=None, output_file='intro.mp3'):
    # Build request payload
    payload = {
        "text": prompt,
        "voice_settings": {
            "stability": 0.5,
            "similarity_boost": 0.75
        }
    }

    if voice_id:
        payload["voice_id"] = voice_id

    # Make the request
    url = 'https://api.elevenlabs.io/v1/text-to-speech/' + (voice_id or 'eleven_monolingual_v1')
    resp = requests.post(url, json=payload, headers=headers, stream=True)

    # Write the streamed MP3
    with open(output_file, 'wb') as f:
        for chunk in resp.iter_content(chunk_size=8192):
            f.write(chunk)

    print(f"Saved intro to {output_file}")

# Example usage
synthesize(prompt, voice_id=voice_id, output_file='intro.mp3')
Enter fullscreen mode Exit fullscreen mode

Tip: If you’re calling the API repeatedly (e.g., for a daily episode), keep an eye on request limits and cache the voice model ID to avoid unnecessary re‑uploads.


6. Post‑Processing: Adding Music & Fades

A polished intro usually has a short music cue and fade‑ins/outs. ffmpeg is perfect for this.

# Install ffmpeg if you haven’t already
brew install ffmpeg   # macOS
sudo apt-get install ffmpeg   # Ubuntu

# Assume intro.mp3 is the TTS output
# background.mp3 is a royalty‑free intro jingle
ffmpeg -i intro.mp3 -i background.mp3 \
  -filter_complex "[0:a][1:a]amix=inputs=2:duration=first:dropout_transition=3" \
  -ac 2 -ar 48000 -y intro_with_music.mp3
Enter fullscreen mode Exit fullscreen mode

You can also use pydub in Python for a more programmatic approach:

from pydub import AudioSegment

tts = AudioSegment.from_mp3('intro.mp3')
bg = AudioSegment.from_mp3('background.mp3').fade_in(2000).fade_out(2000)

combined = tts.overlay(bg, position=0)
combined.export('intro_with_music.mp3', format='mp3')
Enter fullscreen mode Exit fullscreen mode

7. Automating the Workflow

Let’s stitch everything together in a single script that:

  1. Loads config
  2. Generates prompt
  3. Synthesizes TTS
  4. Adds music
  5. Uploads to S3 (or prints the path for local use)
import json, os, requests, boto3
from jinja2 import Template
from pydub import AudioSegment

API_KEY = os.getenv('ELEVENLABS_KEY')
S3_BUCKET = 'my-podcast-assets'
s3 = boto3.client('s3')

def generate_intro(cfg_path='config.json'):
    # 1. Prompt
    with open(cfg_path) as f:
        cfg = json.load(f)
    template = Template("""
    Welcome to *{{ show_name }}*, the podcast where {{ host_name }} talks about {{ topics }}.
    Tune in, hit subscribe, and enjoy the show!
    """)
    prompt = template.render(**cfg)

    # 2. TTS
    headers = {'xi-api-key': API_KEY}
    url = f"https://api.elevenlabs.io/v1/text-to-speech/{cfg.get('voice_id', 'eleven_monolingual_v1')}"
    resp = requests.post(url, json={"text": prompt, "voice_settings": {"stability": 0.5}}, headers=headers, stream=True)
    tts_path = 'tts.mp3'
    with open(tts_path, 'wb') as f:
        for chunk in resp.iter_content(8192):
            f.write(chunk)

    # 3. Music overlay
    bg = AudioSegment.from_mp3('background.mp3').fade_in(1500).fade_out(1500)
    tts = AudioSegment.from_mp3(tts_path)
    final = tts.overlay(bg, position=0)
    final_path = 'final_intro.mp3'
    final.export(final_path, format='mp3')

    # 4. Upload
    s3.upload_file(final_path, S3_BUCKET, f"intro_{cfg['show_name']}.mp3")
    print(f"Uploaded {final_path} to s3://{S3_BUCKET}/intro_{cfg['show_name']}.mp3")

if __name__ == "__main__":
    generate_intro()
Enter fullscreen mode Exit fullscreen mode

Important: Replace background.mp3 with your own royalty‑free track. Adjust fade times to match the length of your intro.


8. Scaling & Deployment

  • CI/CD: Add this script to a GitHub Action that runs nightly, generating a new intro for each episode.
  • Serverless: Deploy the Python code as an AWS Lambda function triggered by an event (e.g., a new episode in your CMS).
  • Docker: Wrap everything in a container for easy portability.

9. Common Pitfalls & Debug Tips

Problem Fix
“Stability too high, voice sounds robotic” Lower stability in voice settings to ~0.4.
“Audio cuts off mid‑sentence” Ensure ffmpeg or pydub writes the full file; check for streaming errors.
“API rate limit exceeded” Cache the voice ID, batch requests, or upgrade to a higher plan.

10. Next Steps

  • Personalize further: Add episode‑specific hooks or guest intros by extending the Jinja template.
  • Dynamic music: Use a small library of jingles and select one at random for each episode.
  • Analytics: Store the generated file’s URL in your episode metadata for tracking usage.

Call to Action

Ready to say goodbye to manual intros?

Give ElevenLabs a try—whether you’re just experimenting or building production‑grade pipelines, their API makes voice generation a breeze. Sign up with this link, get a free tier, and start crafting intros that sound like you (or your brand) in minutes:

👉 https://try.elevenlabs.io/kr07zfuqn1bp

Happy podcasting!

Top comments (0)