Overview
The Discord integration allows AIRI to join voice channels, listen to users, transcribe speech, and respond with both text and voice. It supports slash commands, mentions, and direct messages.
Features
- Voice Channel Support: Join voice channels and participate in conversations
- Speech-to-Text: Automatically transcribe user voice input
- Text-to-Speech: Respond with natural-sounding voice
- Slash Commands: Interactive commands like
/summon and /ping
- Text Chat: Respond to mentions and DMs
- Multi-Guild Support: Work across multiple Discord servers simultaneously
Prerequisites
- Node.js 18 or higher
- A Discord bot token
- OpenAI API key (for LLM and transcription)
- ElevenLabs API key (for TTS)
- AIRI server runtime running
Setup
1. Create Discord Bot
- Go to Discord Developer Portal
- Click New Application
- Go to Bot section and click Add Bot
- Enable these Privileged Gateway Intents:
- Server Members Intent
- Message Content Intent
- Copy your Bot Token
- Copy your Application ID (from General Information)
2. Invite Bot to Server
Use this URL, replacing YOUR_CLIENT_ID with your Application ID:
https://discord.com/api/oauth2/authorize?client_id=YOUR_CLIENT_ID&permissions=36703296&scope=bot%20applications.commands
Required Permissions:
- Read Messages/View Channels
- Send Messages
- Connect to Voice
- Speak in Voice
- Use Voice Activity
Navigate to the Discord bot service:
cd services/discord-bot
cp .env .env.local
Edit .env.local:
# Discord Configuration
DISCORD_TOKEN='your-bot-token-here'
DISCORD_BOT_CLIENT_ID='your-application-id-here'
# AIRI Server Connection
AIRI_URL='ws://localhost:6121/ws'
AIRI_TOKEN='abcd'
# OpenAI Configuration
OPENAI_API_KEY='sk-...'
OPENAI_MODEL='gpt-4o'
OPENAI_API_BASE_URL='https://api.openai.com/v1'
# ElevenLabs Configuration (for TTS)
ELEVENLABS_API_KEY='your-elevenlabs-key'
ELEVENLABS_API_BASE_URL='https://api.elevenlabs.io/v1'
4. Install Dependencies
From the project root:
5. Start the Bot
pnpm run -F @proj-airi/discord-bot start
You should see:
Discord bot ready! User: YourBotName#1234
Usage
Voice Commands
- Join a voice channel
- Use the
/summon command in any text channel
- AIRI will join your voice channel
- Start speaking - AIRI will transcribe and respond
AIRI uses Voice Activity Detection (VAD) to automatically detect when users are speaking.
Text Commands
Slash Commands:
/ping - Check if the bot is responsive
/summon - Invite AIRI to your current voice channel
Mentions:
Mention the bot in any channel:
@AIRI what's the weather like today?
Direct Messages:
Send a DM to the bot - no mention required.
Code Examples
Basic Adapter Setup
From services/discord-bot/src/adapters/airi-adapter.ts:55:
import { Client as AiriClient } from '@proj-airi/server-sdk'
import { Client, GatewayIntentBits } from 'discord.js'
export class DiscordAdapter {
private airiClient: AiriClient
private discordClient: Client
constructor(config: DiscordAdapterConfig) {
// Initialize Discord client
this.discordClient = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.DirectMessages,
],
})
// Initialize AIRI client
this.airiClient = new AiriClient({
name: 'discord',
possibleEvents: [
'input:text',
'input:text:voice',
'input:voice',
'module:configure',
'output:gen-ai:chat:message',
],
token: config.airiToken,
url: config.airiUrl,
})
}
}
From services/discord-bot/src/adapters/airi-adapter.ts:261:
// Handle text messages
this.discordClient.on(Events.MessageCreate, async (message) => {
if (message.author.bot) return
const isMentioned = message.mentions.has(this.discordClient.user)
const isDM = !message.guild
if (isMentioned || isDM) {
const content = message.content
.replace(/<@!?\d+>/g, '')
.trim()
// Send to AIRI
this.airiClient.send({
type: 'input:text',
data: {
text: content,
discord: {
channelId: message.channelId,
guildId: message.guildId,
guildMember: {
id: message.author.id,
displayName: message.member?.displayName,
},
},
},
})
}
})
Receiving Responses from AIRI
From services/discord-bot/src/adapters/airi-adapter.ts:159:
// Handle output from AIRI system
this.airiClient.onEvent('output:gen-ai:chat:message', async (event) => {
const message = event.data.message
const discordContext = event.data['gen-ai:chat'].input.data.discord
if (message?.content && discordContext?.channelId) {
const channel = await this.discordClient.channels.fetch(
discordContext.channelId
)
if (channel?.isTextBased()) {
// Split long messages if needed
if (message.content.length <= 2000) {
await channel.send(message.content)
} else {
// Handle chunking for messages over 2000 chars
// ...
}
}
}
})
Voice Channel Integration
From services/discord-bot/src/bots/discord/commands/summon.ts:157:
import { joinVoiceChannel, createAudioPlayer } from '@discordjs/voice'
async joinChannel(interaction, channel) {
const connection = joinVoiceChannel({
channelId: channel.id,
guildId: channel.guild.id,
adapterCreator: channel.guild.voiceAdapterCreator,
selfDeaf: false,
selfMute: false,
})
// Wait for connection to be ready
await Promise.race([
entersState(connection, VoiceConnectionStatus.Ready, 20_000),
entersState(connection, VoiceConnectionStatus.Signalling, 20_000),
])
// Listen to voice data
connection.receiver.speaking.on('start', (userId) => {
this.monitorMember(userId, channel.id)
})
}
Configuration
Dynamic Reconfiguration
The Discord bot supports runtime configuration updates via the module:configure event:
this.airiClient.onEvent('module:configure', async (event) => {
const { token, enabled } = event.data.config
if (enabled === false) {
await this.discordClient.destroy()
return
}
if (token && this.discordToken !== token) {
this.discordToken = token
await this.discordClient.login(this.discordToken)
}
})
Voice Settings
- Sample Rate: 48000 Hz (Opus)
- Channels: Stereo
- Transcription: OpenAI Whisper
- TTS: ElevenLabs
Troubleshooting
Bot is not responding
- Check the bot is online in Discord
- Verify the bot has permissions in the channel
- Check logs for connection errors
Voice not working
- Ensure you have
ELEVENLABS_API_KEY configured
- Verify the bot has “Connect” and “Speak” permissions
- Check that voice gateway is connected in logs
Commands not showing
- Commands are registered when the bot starts
- Wait a few minutes for Discord to sync
- Try reinviting the bot with the correct scope
Next Steps
Configure Voice Settings
Customize voice and transcription settings
Telegram Integration
Add AIRI to Telegram