Dev.to AI 🤖 Ai 👁 0 📖 6 min read

Adding AI Voice to Discord Bots

Why Add AI Voice to Your Discord Bot? Discord bots have come a long way from simple text commands to immersive experiences that involve music, games, and even real‑time speech. Adding AI‑generated voice lets you: Cr

Why Add AI Voice to Your Discord Bot?

Discord bots have come a long way from simple text commands to immersive experiences that involve music, games, and even real‑time speech. Adding AI‑generated voice lets you:

  • Create dynamic NPCs for role‑playing servers.
  • Read out announcements or news headlines automatically.
  • Provide accessibility by converting text replies into natural‑sounding speech.

With modern text‑to‑speech (TTS) services, you can get lifelike voices in seconds. In this guide we’ll walk through wiring up a Discord bot to the ElevenLabs API—a powerful TTS platform that offers high‑quality voice cloning and a generous free tier. By the end you’ll have a bot that can speak any string you send it, and you’ll know how to swap in a custom voice model if you want.

👉 Quick link: Sign up for ElevenLabs and grab your API key here → https://try.elevenlabs.io/kr07zfuqn1bp

What You’ll Need

Item Reason
Python 3.9+ Most Discord libraries are Python‑centric; the examples use discord.py.
discord.py (2.x) Handles the connection to Discord and the voice subsystem.
FFmpeg Discord requires audio in Opus format; FFmpeg does the conversion.
ElevenLabs API key Needed to request TTS audio.
A Discord server To test the bot (you’ll need the Manage Server permission to add it).

Install the Python dependencies with:

pip install -U discord.py[voice] aiohttp

Make sure FFmpeg is in your system PATH. On macOS you can use brew install ffmpeg, on Windows grab the binaries from the official site, and on Linux apt-get install ffmpeg works.

Setting Up a Basic Discord Bot

If you already have a bot, skip to the next section. Otherwise, create a new application in the Discord Developer Portal, add a bot user, and copy the token.

# bot.py
import os
import discord
from discord.ext import commands

intents = discord.Intents.default()
bot = commands.Bot(command_prefix='!', intents=intents)

@bot.event
async def on_ready():
    print(f'🤖 Logged in as {bot.user}!')

bot.run(os.getenv('DISCORD_TOKEN'))

Save the file, set the DISCORD_TOKEN environment variable, and run python bot.py. You should see the ready message in your console and the bot appear online.

Getting Speech from ElevenLabs

ElevenLabs exposes a simple REST endpoint. Here’s a minimal curl request that returns an MP3 file:

curl -X POST "https://api.elevenlabs.io/v1/text-to-speech/voice-id" \
  -H "xi-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "text": "Hello Discord! I am your AI voice bot.",
        "model_id": "eleven_monolingual_v1",
        "voice_settings": {"stability": 0.75, "similarity_boost": 0.85}
      }' --output speech.mp3

Replace voice-id with the ID of the voice you want to use (the default “Rachel” voice works fine for testing). The response is an MP3 that you can feed straight into FFmpeg.

Using Python’s aiohttp to Call the API

Below is a reusable async function that fetches the audio bytes and writes them to a temporary file:

import aiohttp
import tempfile

ELEVENLABS_API_KEY = "YOUR_ELEVENLABS_API_KEY"
ELEVENLABS_VOICE_ID = "YOUR_VOICE_ID"   # e.g., "Rachel"

async def synthesize_speech(text: str) -> str:
    """
    Sends `text` to ElevenLabs and returns the path to a temporary MP3 file.
    """
    url = f"https://api.elevenlabs.io/v1/text-to-speech/{ELEVENLABS_VOICE_ID}"
    payload = {
        "text": text,
        "model_id": "eleven_monolingual_v1",
        "voice_settings": {"stability": 0.75, "similarity_boost": 0.85}
    }

    headers = {
        "xi-api-key": ELEVENLABS_API_KEY,
        "Content-Type": "application/json"
    }

    async with aiohttp.ClientSession() as session:
        async with session.post(url, json=payload, headers=headers) as resp:
            resp.raise_for_status()
            data = await resp.read()

    # Write to a temporary file so discord.py can read it
    tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
    tmp.write(data)
    tmp.close()
    return tmp.name

Pro tip: If you want to clone a custom voice, head over to ElevenLabs’ dashboard, upload a few minutes of clean audio, and use the new voice ID in the code above. The same endpoint works for both stock and cloned voices.

Making the Bot Speak

Discord expects audio in Opus format, so we’ll let FFmpeg do the conversion on the fly. discord.FFmpegPCMAudio can read directly from an MP3 file.

from discord import FFmpegPCMAudio, PCMVolumeTransformer

FFMPEG_OPTIONS = {
    "options": "-vn",  # no video
    "before_options": "-loglevel panic"  # silence ffmpeg output
}

@bot.command(name='say')
async def say(ctx, *, message: str):
    """Bot joins your voice channel and reads the provided text."""
    if not ctx.author.voice:
        await ctx.send("🔇 You need to be in a voice channel first!")
        return

    # Connect to the voice channel
    voice_channel = ctx.author.voice.channel
    vc = ctx.voice_client

    if vc is None:
        vc = await voice_channel.connect()
    elif vc.channel != voice_channel:
        await vc.move_to(voice_channel)

    # Get TTS audio from ElevenLabs
    try:
        audio_path = await synthesize_speech(message)
    except Exception as e:
        await ctx.send(f"❗️ TTS failed: {e}")
        return

    # Play the audio
    source = FFmpegPCMAudio(audio_path, **FFMPEG_OPTIONS)
    vc.play(PCMVolumeTransformer(source, volume=0.8))

    # Wait for the audio to finish
    while vc.is_playing():
        await asyncio.sleep(0.5)

    # Clean up
    os.remove(audio_path)

What’s Happening?

  1. Voice check – The command only works if the user is already in a voice channel.
  2. Connection logic – Re‑uses an existing voice client or creates a new one.
  3. TTS request – Calls synthesize_speech (the ElevenLabs wrapper we wrote earlier).
  4. Audio playback – FFmpeg streams the MP3 as Opus to Discord.
  5. Cleanup – Deletes the temporary file once playback ends.

Now, typing !say Hello, world! in any text channel will make the bot speak the phrase in the selected ElevenLabs voice.

Going Further: Voice Cloning & Dynamic Settings

ElevenLabs shines when you give the bot a personalized voice. After uploading a few samples of your own voice (or a character’s), you receive a new voice_id. Swap that ID in ELEVENLABS_VOICE_ID and your bot will sound like you.

You can also expose the stability and similarity settings to users:

@bot.command(name='saycustom')
async def saycustom(ctx, stability: float = 0.75, similarity: float = 0.85, *, message: str):
    """Speak with custom voice settings."""
    # ... same connection logic ...

    # Override settings in the payload
    payload = {
        "text": message,
        "model_id": "eleven_monolingual_v1",
        "voice_settings": {"stability": stability, "similarity_boost": similarity}
    }
    # Use a slightly modified synthesize_speech that accepts payload
    # (omitted for brevity)

Now users can tweak how “steady” or “expressive” the voice sounds, opening up fun experimentation for role‑play servers.

Handling Errors Gracefully

Network hiccups or API rate limits can break the flow. Wrap the request in a try/except block (as shown earlier) and inform the user:

except aiohttp.ClientResponseError as e:
    if e.status == 429:
        await ctx.send("⚠️ Rate limited! Try again in a few seconds.")
    else:
        await ctx.send(f"❗️ ElevenLabs error: {e.message}")

Also, always check that the bot has the Speak permission in the voice channel, otherwise Discord will reject the audio stream.

Deploying Your Bot

For a production‑ready bot, consider:

  • Environment variables for DISCORD_TOKEN, ELEVENLABS_API_KEY, and ELEVENLABS_VOICE_ID.
  • Docker: A small container with Python and FFmpeg keeps the runtime consistent.
  • Process managers like pm2 (for Node) or systemd to auto‑restart on crashes.
  • Logging: Capture stdout and stderr from FFmpeg for debugging audio glitches.

A minimal Dockerfile could look like:

FROM python:3.12-slim
RUN apt-get update && apt-get install -y ffmpeg && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "bot.py"]

Push the image to your favorite registry and run it on a VPS, Railway, or Render.

Wrap‑Up

Adding AI‑generated voice to a Discord bot is surprisingly straightforward:

  1. Spin up a Discord bot with discord.py.
  2. Call ElevenLabs to turn text into high‑quality speech.
  3. Stream the audio using FFmpeg and Discord’s voice client.

You now have a foundation you can extend into:

  • Narrated story bots that read chapters aloud.
  • Real‑time translation pipelines (translate → TTS → Discord).
  • Personal assistants that respond with a custom cloned voice.

🎤 Ready to give your bot a voice? Sign up for ElevenLabs, grab your API key, and start building: https://try.elevenlabs.io/kr07zfuqn1bp

Happy coding, and may your bots be ever chatty!

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.