如何構建 Podcast 開場生成器
How to Build a Podcast Intro Generator
Podcast 開場生成器可用 Python 與 Jinja2 根據 JSON 設定檔生成口播文案,並接入 ElevenLabs 的 TTS,將文字合成音訊;亦可選用語音複製功能建立自訂聲音。流程還可用 ffmpeg 或 pydub 加入背景音樂及淡入淡出效果,並把音訊上載至 S3 或儲存在本機。
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:
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)
config.json could look like:
{
"show_name": "TechTalk",
"host_name": "Alex",
"topics": "the latest in AI, cloud, and devops"
}
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)
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')
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
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')
7. Automating the Workflow
Let’s stitch everything together in a single script that:
- Loads config
- Generates prompt
- Synthesizes TTS
- Adds music
- 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()
Important: Replace
background.mp3with 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:
Happy podcasting!
來源:DEV Community · dev.to