Un bot TTS de Discord en Python que lee el chat en voz alta en un canal de voz
El /tts integrado de Discord lee un mensaje en el dispositivo de cada oyente con su voz del sistema y nunca habla en un canal de voz. Para que los amigos sin micrófono escriban y todos en la llamada los oigan, necesitas un bot que entre al canal de voz y reproduzca allí los mensajes.
Esta guía crea uno en Python con discord.py. Lee un canal de texto elegido con cualquier voz de SuperClonica: con el motor gratuito en tu equipo, sin conexión y sin límites, o mediante la API de voz de SuperClonica si prefieres no ejecutar el modelo tú.
Qué necesitas
Crea una aplicación en el Discord Developer Portal, añade un bot, activa el intent de Message Content en la página Bot e invita al bot con los permisos Conectar y Hablar. Instala FFmpeg de modo que esté en el PATH y después las bibliotecas:
python -m pip install "discord.py[voice]" superclonica-cpu
El extra voice de discord.py 2.7 trae las bibliotecas de cifrado que necesita la voz de Discord. El motor SuperClonica descarga el modelo Supertonic 3, unos 400 MB, en el primer arranque y luego funciona sin conexión en una CPU normal.
El bot con el motor gratuito
Define DISCORD_TOKEN y TTS_CHANNEL_ID, el ID del canal de texto que se leerá, y ejecuta el archivo. Cuando alguien que está en un canal de voz escribe en ese canal de texto, el bot entra a su canal de voz y lee el mensaje con la voz elegida; las frases esperan en una cola y nunca se pisan.
import asyncio, os, re, tempfile
import discord
from superclonica import Superclonica
TOKEN = os.environ["DISCORD_TOKEN"]
TEXT_CHANNEL = int(os.environ["TTS_CHANNEL_ID"]) # the text channel the bot reads
VOICE = "announcer.json" # a voice file from the catalog, or M1..M5, F1..F5
LINK = re.compile(r"https?://\S+")
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)
tts = Superclonica()
queue = asyncio.Queue()
def voice_line(text):
audio, _ = tts.synthesize(text, voice=VOICE, lang="en")
path = tempfile.NamedTemporaryFile(suffix=".wav", delete=False).name
tts.save(path, audio)
return path
async def speaker():
while True:
voice_client, text = await queue.get()
path = await asyncio.to_thread(voice_line, text)
done = asyncio.Event()
voice_client.play(discord.FFmpegPCMAudio(path), after=lambda error: client.loop.call_soon_threadsafe(done.set))
await done.wait()
os.remove(path)
@client.event
async def on_ready():
client.loop.create_task(speaker())
@client.event
async def on_message(message):
if message.author.bot or message.channel.id != TEXT_CHANNEL or not message.author.voice:
return
voice_client = message.guild.voice_client or await message.author.voice.channel.connect()
text = LINK.sub("link", message.clean_content)[:300]
await queue.put((voice_client, f"{message.author.display_name} says: {text}"))
client.run(TOKEN)VOICE puede ser una de las voces integradas M1 a M5 y F1 a F5 o un archivo de voz del catálogo de SuperClonica: las voces gratuitas se descargan sin cuenta y las de pago tras comprarlas. La síntesis va en un hilo aparte, así que el bot sigue respondiendo mientras se genera una frase.
El mismo bot por la API
Si el bot vive en un servidor pequeño sin sitio para el modelo, genera las frases con la API de voz de SuperClonica: sustituye voice_line por esta función y define SUPERCLONICA_KEY. Cualquier voz del catálogo funciona con el ID de su página, sin comprarla.
import os, tempfile
import requests
API = "https://superclonica.com/api/v1/speech"
KEY = os.environ["SUPERCLONICA_KEY"]
VOICE_ID = "49cd4d119695528694fac0a1b9fb58a8" # any catalog voice: the ID on its page
def voice_line(text):
answer = requests.post(API, headers={"Authorization": "Bearer " + KEY}, timeout=120,
json={"text": text, "voice": VOICE_ID, "language": "en", "format": "mp3"})
answer.raise_for_status()
path = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False).name
with open(path, "wb") as file:
file.write(answer.content)
return pathUna clave gratuita da un minuto de audio al día, suficiente para probar; Inicio, 5 $ al mes, da hasta 3 minutos de voz en cada ventana de 10 minutos, de sobra para un servidor animado.
Para que sea agradable
Lee un solo canal, recorta los mensajes largos, di «enlace» en lugar de una dirección web y deja que los moderadores muevan o expulsen al bot. El motor lee como palabras la jerga de chat habitual en español, como pq o tmb, y en otros idiomas. Las voces de personajes del catálogo las hacen fans y no están respaldadas por los titulares de los derechos: úsalas para divertirte en tu servidor, nunca para hacerte pasar por nadie.