Um bot TTS com discord.js que transmite vozes de IA para um canal de voz
Um bot de texto para fala é um dos bots de Discord mais populares: ele entra no canal de voz e lê o que os membros sem microfone escrevem. Com o seu, você escolhe a voz: um narrador, um locutor, um personagem de jogo ou anime ou a voz própria do seu servidor.
Este guia monta um com discord.js e @discordjs/voice. O áudio vem da API de voz da SuperClonica, que pelas nossas medições transmite fala a partir de uns 300 ms, então o bot fala quase assim que a mensagem chega.
O que você precisa
Node.js 18 ou mais novo, uma aplicação de bot no Discord Developer Portal com o intent Message Content ativado e um convite com as permissões Conectar e Falar. Depois instale:
npm install discord.js @discordjs/voice @discordjs/opus ffmpeg-static
Segundo o README do @discordjs/voice, ele precisa de uma biblioteca Opus como @discordjs/opus e do FFmpeg, que o ffmpeg-static fornece; a biblioteca de criptografia de ponta a ponta DAVE já vem instalada. Crie uma chave de API da SuperClonica na página da API de voz; é grátis e não pede cartão.
O bot
Defina DISCORD_TOKEN, TTS_CHANNEL_ID (o canal de texto que será lido), SUPERCLONICA_KEY e VOICE_ID, o ID que aparece na página da voz do catálogo escolhida, e rode o arquivo com node:
import { Client, GatewayIntentBits } from "discord.js";
import { joinVoiceChannel, createAudioPlayer, createAudioResource, AudioPlayerStatus, getVoiceConnection } from "@discordjs/voice";
import { Readable } from "node:stream";
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent, GatewayIntentBits.GuildVoiceStates] });
const player = createAudioPlayer();
const queue = [];
async function speak(text) {
const answer = await fetch("https://superclonica.com/api/v1/speech", {
method: "POST",
headers: { Authorization: "Bearer " + process.env.SUPERCLONICA_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ text, voice: process.env.VOICE_ID, language: "en", stream: true }),
});
if (!answer.ok) throw new Error(await answer.text());
return createAudioResource(Readable.fromWeb(answer.body));
}
player.on(AudioPlayerStatus.Idle, async () => {
const next = queue.shift();
if (next) player.play(await next());
});
client.on("messageCreate", async (message) => {
if (message.author.bot || message.channelId !== process.env.TTS_CHANNEL_ID) return;
const channel = message.member?.voice.channel;
if (!channel) return;
const connection = getVoiceConnection(message.guildId) ?? joinVoiceChannel({
channelId: channel.id, guildId: message.guildId, adapterCreator: message.guild.voiceAdapterCreator });
connection.subscribe(player);
const job = () => speak(message.member.displayName + " says: " + message.cleanContent.slice(0, 300));
if (player.state.status === AudioPlayerStatus.Idle && queue.length === 0) player.play(await job());
else queue.push(job);
});
client.login(process.env.DISCORD_TOKEN);Cada mensagem vira uma requisição com "stream": true. A API responde com um fluxo Ogg que o @discordjs/voice converte pelo FFmpeg e toca conforme chega; mensagens que chegam enquanto o bot fala esperam numa fila.
Vozes e planos
Toda voz do catálogo da SuperClonica funciona pela API com seu ID, em qualquer plano e sem comprar; você também pode treinar uma voz com a sua gravação e entregá-la ao bot. A chave gratuita dá um minuto de áudio por dia. O Inicial, US$ 5 por mês, dá até 3 minutos de fala em cada janela de 10 minutos, e os planos maiores 8, 20 ou 65 minutos. Quando a janela acaba, a API responde 429 com Retry-After e nada é cobrado.
Para não usar API nenhuma, use o motor gratuito da SuperClonica no seu computador; o guia do bot TTS em Python mostra a versão offline.