betty2 / example.js
sdgsdggds's picture
Upload folder using huggingface_hub
e7c953d verified
// Enhanced example of using the DubAPI library with AI integration
const DubAPI = require('./index.js');
const AIHandler = require('./ai-handler.js');
const MemoryHandler = require('./memory-handler.js');
console.log('Starting DubAPI example...');
// Replace with your queup.net credentials
const username = 'Jiwon';
const password = 'cookTV12';
// Replace with the room you want to connect to
const roomName = 'classical-music_171599336015945';
// Bot configuration
const config = {
commandPrefix: '!', // Prefix for commands
autoReconnect: true, // Automatically reconnect on disconnection
reconnectInterval: 15000, // Time in ms to wait before reconnecting
greetUsers: true, // Whether to greet users when they join
autoUpvote: true, // Whether to automatically upvote songs
botName: 'Jiwon', // Bot's name for mention detection
respondToMentions: true, // Whether to respond when mentioned
useAI: true, // Whether to use AI responses
geminiAPIKeys: [ // Multiple Gemini API keys that will be used in rotation
'AIzaSyAQAw_EZv1kX_l24ViMGnPYGC3ExbIZFCU', 'AIzaSyCXBuz5GCChcPiff9MFtfb6tCspytAKukQ', 'AIzaSyDtntYvtVZ1huXt65sEE-Pj1UDxLFZom2w' // First API key
// Add more API keys here, separated by commas
]
};
console.log('Attempting to create DubAPI instance with username:', username);
console.log('Connecting to room:', roomName);
// Initialize memory handler
let memoryHandler = new MemoryHandler({
maxMessagesPerUser: 10, // Remember last 10 messages per user
maxMemoryAge: 30 * 60 * 1000 // Remember messages for 30 minutes
});
// Initialize AI handler if enabled
let aiHandler = null;
if (config.useAI && config.geminiAPIKeys && config.geminiAPIKeys.length > 0) {
aiHandler = new AIHandler(config.geminiAPIKeys, memoryHandler);
console.log('AI handler initialized with Gemini API and conversation memory');
}
new DubAPI({username: username, password: password}, function(err, bot) {
if (err) return console.error('Error connecting:', err);
console.log('Running DubAPI v' + bot.version);
// ========== Utility Functions ==========
// Format time in seconds to mm:ss
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs < 10 ? '0' + secs : secs}`;
}
// Check if user has staff permissions
function isStaff(user) {
return user && bot.isStaff(user);
}
// ========== Command Handler ==========
// Handle chat commands
function handleCommand(data) {
// Ignore if not a command
if (!data.message.startsWith(config.commandPrefix)) return;
// Parse command and arguments
const args = data.message.slice(config.commandPrefix.length).trim().split(/\s+/);
const command = args.shift().toLowerCase();
// Get user who sent the command
const user = bot.getUser(data.user.id);
switch (command) {
case 'ping':
bot.sendChat('Pong! 🏓');
break;
case 'memory':
if (memoryHandler) {
const stats = memoryHandler.getStats();
const now = Date.now();
const oldestTime = stats.oldestMessage ? new Date(stats.oldestMessage).toISOString().substring(11, 19) : 'none';
bot.sendChat(`Memory stats: ${stats.userCount} users, ${stats.totalMessages} messages, oldest from ${oldestTime}`);
if (args[0] === 'clear' && isStaff(user)) {
// Only staff can clear memory
memoryHandler.memories.clear();
bot.sendChat('Memory cleared by ' + user.username);
}
} else {
bot.sendChat('Memory system is not active.');
}
break;
case 'info':
const currentMedia = bot.getMedia();
if (currentMedia) {
bot.sendChat(`Current track: ${currentMedia.name} by ${currentMedia.artist || 'Unknown'}`);
} else {
bot.sendChat('No track is currently playing.');
}
break;
case 'time':
const remaining = bot.getTimeRemaining();
const elapsed = bot.getTimeElapsed();
if (remaining >= 0) {
bot.sendChat(`Time remaining: ${formatTime(remaining)} | Elapsed: ${formatTime(elapsed)}`);
} else {
bot.sendChat('No track is currently playing.');
}
break;
case 'skip':
if (isStaff(user) && bot.hasPermission(user, 'skip')) {
bot.moderateSkip(function(err) {
if (err) return console.error('Error skipping track:', err);
bot.sendChat('Track skipped by ' + user.username);
});
} else {
bot.sendChat('You need to be staff with skip permission to use this command.');
}
break;
case 'users':
const users = bot.getUsers();
bot.sendChat(`There are ${users.length} users in the room.`);
break;
case 'staff':
const staff = bot.getStaff();
bot.sendChat(`There are ${staff.length} staff members in the room.`);
break;
case 'help':
bot.sendChat('Available commands: !ping, !info, !time, !users, !staff, !help');
break;
default:
// Unknown command
break;
}
}
// ========== Connection Functions ==========
function connect() {
console.log('Attempting to connect to room:', roomName);
bot.connect(roomName);
}
// ========== Event Listeners ==========
bot.on('connected', function(name) {
console.log('Connected to ' + name);
console.log('Bot is ready to respond to commands. Use ' + config.commandPrefix + 'help for available commands');
});
bot.on('disconnected', function(name) {
console.log('Disconnected from ' + name);
if (config.autoReconnect) {
console.log(`Attempting to reconnect in ${config.reconnectInterval / 1000} seconds...`);
setTimeout(connect, config.reconnectInterval);
}
});
bot.on('error', function(err) {
console.error('Error:', err);
});
// Chat message handler
bot.on(bot.events.chatMessage, function(data) {
console.log(data.user.username + ': ' + data.message);
// Store all messages in memory for context (except bot's own messages)
if (data.user.username !== config.botName && memoryHandler) {
memoryHandler.addMessage(data.user.username, data.message, false);
}
// Handle commands
handleCommand(data);
// Handle mentions (when bot is called by name)
if (config.respondToMentions && data.user.username !== config.botName) {
// Use simple string methods instead of regex for more reliable detection
const message = data.message;
const lowerMessage = message.toLowerCase();
const botName = config.botName.toLowerCase();
// Check for mentions in several ways
const isMentioned =
lowerMessage.includes('@' + botName) || // @kuber
lowerMessage.startsWith(botName) || // starts with kuber
lowerMessage.includes(' ' + botName + ' ') || // kuber with spaces around
lowerMessage.endsWith(' ' + botName); // ends with kuber
console.log('Checking for mentions in message:', message, 'Mentioned:', isMentioned);
// Check if bot is mentioned
if (isMentioned) {
console.log(`Bot was mentioned by ${data.user.username}`);
// Get the user message without the bot's name for cleaner AI input
let userMessage = data.message;
const botNamePattern = new RegExp(`@?${config.botName}`, 'gi');
userMessage = userMessage.replace(botNamePattern, '').trim();
// Special case handling for specific commands
if (userMessage.toLowerCase().includes('what') &&
(userMessage.toLowerCase().includes('song') ||
userMessage.toLowerCase().includes('track') ||
userMessage.toLowerCase().includes('playing'))) {
// Get current song info directly
const currentMedia = bot.getMedia();
if (currentMedia) {
const response = `@${data.user.username}, we're listening to ${currentMedia.name} by ${currentMedia.artist || 'Unknown'}.`;
return bot.sendChat(response);
}
}
if (userMessage.toLowerCase() === 'help' || userMessage.toLowerCase() === '?') {
const response = `@${data.user.username}, try using ${config.commandPrefix}help to see my commands.`;
return bot.sendChat(response);
}
// Handle response based on whether AI is enabled
if (config.useAI && aiHandler) {
// Call AI for response with username for context
console.log(`Sending to AI: ${userMessage} (from: ${data.user.username})`);
aiHandler.getAIResponse(userMessage, data.user.username)
.then(aiResponse => {
// Log the full response for debugging
console.log(`===== FULL AI RESPONSE (${aiResponse.length} chars) ====`);
console.log(aiResponse);
console.log(`===== END OF FULL AI RESPONSE ====`);
// Split the message into larger chunks for output
const maxLength = 250; // Increased from 160 to 250 characters per chunk
const chunks = [];
// Mention the user in the first chunk only
let firstChunk = `@${data.user.username}, `;
// Simplified chunking algorithm that focuses on reliability
// Just split the text into chunks of maxLength characters, trying to split on word boundaries
// First chunk gets the user mention
let remaining = aiResponse;
let isFirst = true;
while (remaining.length > 0) {
// Calculate how much we can fit in this chunk
const limit = isFirst ? (maxLength - firstChunk.length) : maxLength;
let splitAt = Math.min(remaining.length, limit);
// If we need to split, try to do it at a word boundary
if (remaining.length > limit) {
// Look for the last space within our limit
const lastSpace = remaining.substring(0, limit).lastIndexOf(' ');
if (lastSpace > limit / 2) { // Only use space if it's reasonably positioned
splitAt = lastSpace + 1; // Include the space
}
}
// Extract this chunk of text
const part = remaining.substring(0, splitAt).trim();
// Add to chunks array with user mention if it's the first chunk
if (part.length > 0) {
chunks.push(isFirst ? (firstChunk + part) : part);
}
// Move to next section of text
remaining = remaining.substring(splitAt).trim();
isFirst = false;
}
// Send all chunks with a delay between them
console.log(`Sending response in ${chunks.length} chunks`);
let sentCount = 0;
function sendNextChunk() {
if (sentCount < chunks.length) {
const chunk = chunks[sentCount];
console.log(`Sending chunk ${sentCount + 1}/${chunks.length}: ${chunk.length} chars`);
bot.sendChat(chunk);
sentCount++;
if (sentCount < chunks.length) {
// Schedule next chunk with a delay
setTimeout(sendNextChunk, 800);
} else {
// All chunks sent, store in memory
if (memoryHandler) {
memoryHandler.addMessage(data.user.username, aiResponse, true);
}
console.log('All chunks sent successfully');
}
}
}
// Start sending chunks
sendNextChunk();
})
.catch(err => {
console.error('AI Response Error:', err);
bot.sendChat(`@${data.user.username}, sorry, my AI brain is having trouble right now. Try again later?`);
});
} else {
// Fallback to pre-defined responses when AI is disabled
const responses = [
`Yes, @${data.user.username}? How can I help you?`,
`I'm here, @${data.user.username}! Need something?`,
`Hey @${data.user.username}, what's up?`,
`@${data.user.username}, at your service! Try ${config.commandPrefix}help for commands.`
];
const response = responses[Math.floor(Math.random() * responses.length)];
// Send the response with a small delay to seem more natural
setTimeout(() => {
bot.sendChat(response);
}, 1000 + Math.random() * 1000); // Random delay between 1-2 seconds
}
}
}
});
// User join handler
bot.on(bot.events.userJoin, function(data) {
console.log(`${data.user.username} joined the room`);
});
// User leave handler
bot.on(bot.events.userLeave, function(data) {
console.log(`${data.user.username} left the room`);
});
// Song change handler
bot.on(bot.events.roomPlaylistUpdate, function(data) {
if (!data.media) return;
console.log(`Now playing: ${data.media.name} by ${data.media.artist || 'Unknown'}`);
// Auto upvote songs if enabled
if (config.autoUpvote) {
setTimeout(() => {
bot.downdub(function(err) {
if (err) console.error('Error upvoting:', err);
else console.log('Auto-upvoted current song');
});
}, 5000); // Wait 5 seconds before upvoting
}
});
// Connect to the room
connect();
});