{"slug": "adding-ai-voice-to-discord-bots", "title": "Adding AI Voice to Discord Bots", "summary": "A developer published a step-by-step guide for adding AI text-to-speech to Discord bots using ElevenLabs' REST API and Python's discord.py library. The tutorial wraps ElevenLabs' text-to-speech endpoint in an async aiohttp call, pipes the returned MP3 bytes through FFmpeg into Opus format, and plays the audio in a voice channel via discord.FFmpegPCMAudio, enabling bots to speak messages or announcements in pre-built or cloned voices.", "body_md": "Discord has become the go‑to place for communities, gaming squads, study groups, and even professional meet‑ups. Most bots you’ll find on the platform are text‑only, but adding a voice component can dramatically boost engagement:\n\nIn the past, developers had to host their own TTS engines or rely on Discord’s built‑in “Speak” feature, which is limited to raw audio streams. Today, services like **ElevenLabs** make high‑quality text‑to‑speech (TTS) and voice cloning a breeze, and they expose simple HTTP APIs that you can call from any language.\n\nBelow you’ll find a step‑by‑step guide to hooking up ElevenLabs to a Discord bot using Python and the `discord.py` library. By the end you’ll have a bot that can read messages, announce events, or even speak in a cloned voice that matches your brand.\n\n`pip install -U discord.py`.\n`apt-get install ffmpeg`, `brew install ffmpeg`).\nElevenLabs provides a straightforward REST endpoint. We’ll create a tiny wrapper that sends plain text and receives an MP3 file.\n\n``` python\nimport aiohttp\nimport os\n\nELEVEN_API_KEY = os.getenv(\"ELEVEN_API_KEY\")\nELEVEN_TTS_URL = \"https://api.elevenlabs.io/v1/text-to-speech\"\n\nasync def synthesize(text: str, voice_id: str = \"EXAVITQu4vr4xnSDxMaL\") -> bytes:\n    \"\"\"\n    Convert `text` to speech using ElevenLabs.\n    Returns raw MP3 bytes.\n    \"\"\"\n    headers = {\n        \"xi-api-key\": ELEVEN_API_KEY,\n        \"Content-Type\": \"application/json\",\n    }\n    payload = {\n        \"text\": text,\n        \"voice_settings\": {\"stability\": 0.75, \"similarity_boost\": 0.85},\n    }\n    async with aiohttp.ClientSession() as session:\n        async with session.post(\n            f\"{ELEVEN_TTS_URL}/{voice_id}\",\n            json=payload,\n            headers=headers,\n        ) as resp:\n            resp.raise_for_status()\n            return await resp.read()\n```\n\n*The `voice_id` can be any of ElevenLabs’ pre‑built voices or a custom clone you created in the dashboard.* \n\nDiscord expects audio in Opus format inside an `AudioSource`. The easiest way is to pipe the MP3 through FFmpeg and let `discord.py` handle the streaming.\n\n``` php\nimport discord\nimport io\nimport subprocess\n\ndef mp3_to_opus(mp3_bytes: bytes) -> discord.FFmpegPCMAudio:\n    \"\"\"\n    Takes raw MP3 bytes, writes them to a pipe, and returns an FFmpegPCMAudio source.\n    \"\"\"\n    # Use a BytesIO object as a temporary file\n    mp3_buffer = io.BytesIO(mp3_bytes)\n\n    # FFmpeg command – reads from stdin (-i pipe:0) and outputs opus to stdout\n    ffmpeg_options = {\n        \"before_options\": \"-nostdin\",\n        \"options\": \"-f s16le -ar 48000 -ac 2 pipe:1\",\n    }\n\n    return discord.FFmpegPCMAudio(mp3_buffer, **ffmpeg_options)\n```\n\nBelow is a minimal bot that joins a voice channel when you type `!join`, then reads any subsequent message that starts with `!say`.\n\n``` python\nimport discord\nfrom discord.ext import commands\n\nintents = discord.Intents.default()\nintents.message_content = True   # Needed for reading message text\n\nbot = commands.Bot(command_prefix=\"!\", intents=intents)\n\n@bot.event\nasync def on_ready():\n    print(f\"🤖 {bot.user} is ready!\")\n\n@bot.command()\nasync def join(ctx):\n    \"\"\"Bot joins the author's voice channel.\"\"\"\n    if ctx.author.voice:\n        channel = ctx.author.voice.channel\n        await channel.connect()\n        await ctx.send(f\"Joined {channel.name} 🎤\")\n    else:\n        await ctx.send(\"You need to be in a voice channel first!\")\n\n@bot.command()\nasync def say(ctx, *, message: str):\n    \"\"\"Bot speaks the supplied text using ElevenLabs.\"\"\"\n    if not ctx.voice_client:\n        await ctx.send(\"I'm not in a voice channel. Use `!join` first.\")\n        return\n\n    # 1️⃣ Synthesize speech\n    try:\n        mp3_data = await synthesize(message)\n    except Exception as e:\n        await ctx.send(f\"❗ TTS error: {e}\")\n        return\n\n    # 2️⃣ Convert to Opus and play\n    audio_source = mp3_to_opus(mp3_data)\n    ctx.voice_client.play(audio_source, after=lambda e: print(\"Finished playing\", e))\n\n    await ctx.send(f\"🗣 Speaking: *{message}*\")\n\n@bot.command()\nasync def leave(ctx):\n    \"\"\"Disconnects the bot from voice.\"\"\"\n    if ctx.voice_client:\n        await ctx.voice_client.disconnect()\n        await ctx.send(\"Goodbye! 👋\")\n    else:\n        await ctx.send(\"I'm not connected to any voice channel.\")\n\nbot.run(os.getenv(\"DISCORD_TOKEN\"))\n```\n\n`!join``!say <text>``<text>` to ElevenLabs, gets back an MP3, pipes it through FFmpeg, and streams the resulting Opus audio into the channel.\n`!leave`\nYou can expand this skeleton in many ways:\n\n`on_member_join`, `on_message_delete`, etc., and let the bot broadcast them.\n`voice_id`, and use it for a truly unique bot personality.\nElevenLabs lets you create a custom voice from as little as 30 seconds of audio. Once you’ve uploaded your sample, you’ll receive a new `voice_id`. Replace the default ID in the `synthesize` function and your bot will speak with *your* voice (or that of a fictional character).\n\n```\nCUSTOM_VOICE_ID = \"your_custom_voice_id_here\"\nmp3_data = await synthesize(\"Welcome to the server!\", voice_id=CUSTOM_VOICE_ID)\n```\n\nThe `voice_settings` payload supports `stability`, `similarity_boost`, `style`, and more. Play around with these values to make the bot sound calm, excited, or even robotic.\n\n```\n\"voice_settings\": {\n    \"stability\": 0.65,\n    \"similarity_boost\": 0.92,\n    \"style\": 0.5,\n    \"use_speaker_boost\": true\n}\n```\n\n| Symptom | Likely Cause | Fix | \n|---|---|---|\n| Bot joins but no audio plays | FFmpeg not in `$PATH` or wrong options | Verify `ffmpeg -version` works and use the`ffmpeg_options` shown above | \n| “TTS error: 401 Unauthorized” | Invalid or missing ElevenLabs API key | Set `ELEVEN_API_KEY` env var correctly | \n| Audio is garbled or too fast | MP3 not being piped correctly | Ensure you’re using `discord.FFmpegPCMAudio` with the proper`before_options` (`-nostdin` ) | \n| Bot disconnects after a few seconds | Rate limit hit on ElevenLabs | Implement a simple in‑memory cooldown (e.g., 1 request per 2 seconds) | \n\nIf you plan to keep the bot running 24/7, consider:\n\n`python:3.11-slim` image with FFmpeg installed (`apt-get update && apt-get install -y ffmpeg`).\n`pm2`, `systemd`, or a cloud function that keeps the process alive.\n`DISCORD_TOKEN` and `ELEVEN_API_KEY` in environment variables or a secret manager rather than hard‑coding them.\nAdding AI voice to a Discord bot is no longer a research‑paper exercise. With a few lines of Python, a free ElevenLabs account, and a dash of creativity, you can turn a silent bot into a conversational companion that reads announcements, narrates games, or simply greets newcomers in a custom‑cloned voice.\n\nGive it a try, experiment with different voice styles, and watch your community react to the new level of immersion.\n\n**Ready to give your bot a voice?** Sign up through this link and start generating high‑quality speech instantly: [https://try.elevenlabs.io/kr07zfuqn1bp](https://try.elevenlabs.io/kr07zfuqn1bp) \n\nHappy coding, and may your bots always be heard!", "url": "https://wpnews.pro/news/adding-ai-voice-to-discord-bots", "canonical_source": "https://dev.to/voice_developer/adding-ai-voice-to-discord-bots-pof", "published_at": "2026-10-01 01:06:32+00:00", "updated_at": "2026-10-01 01:16:43.370182+00:00", "lang": "en", "topics": ["ai-tools", "generative-ai", "developer-tools", "natural-language-processing"], "entities": ["Discord", "ElevenLabs", "Python", "discord.py", "FFmpeg", "aiohttp"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/adding-ai-voice-to-discord-bots", "markdown": "https://wpnews.pro/news/adding-ai-voice-to-discord-bots.md", "text": "https://wpnews.pro/news/adding-ai-voice-to-discord-bots.txt", "jsonld": "https://wpnews.pro/news/adding-ai-voice-to-discord-bots.jsonld"}}