AI音声をボイスチャンネルにストリーミングするdiscord.jsのTTSボット
読み上げボットはDiscordで特に人気のあるボットです。ボイスチャンネルに参加し、マイクを使わないメンバーが書いた内容を読み上げます。自分でつくれば声を選べます。ナレーター、アナウンサー、ゲームやアニメのキャラクター、サーバー独自の声などです。
このガイドでは、discord.jsと@discordjs/voiceでボットをつくります。音声はSuperClonicaの音声合成APIから届き、私たちの計測では約300 msでストリーミングが始まるので、メッセージが届くとほぼすぐに話し始めます。
必要なもの
Node.js 18以降、Message Content intentを有効にしたDiscord Developer Portalのボットアプリ、「接続」と「発言」の権限付きの招待です。次にインストールします:
npm install discord.js @discordjs/voice @discordjs/opus ffmpeg-static
@discordjs/voiceのREADMEによると、@discordjs/opusなどのOpusライブラリと、ffmpeg-staticが提供するFFmpegが必要です。エンドツーエンド暗号化のDAVEライブラリは最初から入っています。音声合成APIのページでSuperClonicaのAPIキーを作成してください。無料でカードも不要です。
ボット
DISCORD_TOKEN、TTS_CHANNEL_ID(読み上げるテキストチャンネル)、SUPERCLONICA_KEY、VOICE_ID(選んだカタログの声のページに表示されるID)を設定し、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);各メッセージは"stream": trueの1リクエストになります。APIはOggストリームを返し、@discordjs/voiceがFFmpegで変換して届いた順に再生します。ボットが話している間に来たメッセージはキューで待ちます。
声とプラン
SuperClonicaカタログのすべての声は、どのプランでも購入なしにIDでAPIから使えます。自分の録音から声を学習させてボットに使わせることもできます。無料キーは1日1分です。月5ドルのスタートは10分ごとの枠で最大3分、上位プランは8分、20分、65分です。枠を使い切るとAPIは429とRetry-Afterを返し、料金はかかりません。
APIをまったく使わないなら、自分のパソコンで無料のSuperClonicaエンジンを動かしてください。オフライン版はPythonのTTSボットのガイドで紹介しています。