← back to Dear Bubbe Nextjs
archived/social-posters/bubbe-twitter-smart.js
185 lines
#!/usr/bin/env node
const fs = require('fs').promises;
const path = require('path');
const axios = require('axios');
const { postTweet } = require('./twitter-v2-official');
// Configuration
const CONFIG = {
MAX_DAILY_POSTS: 100,
MIN_INTERVAL_SECONDS: 180, // 3 minutes
STATS_FILE: '/root/Projects/dear-bubbe-admin/logs/twitter-stats.json',
LAST_POST_FILE: '/root/Projects/dear-bubbe-admin/logs/last-twitter-post.json'
};
// Viral hashtags that work
const HASHTAGS = {
always: ['#BubbeAI', '#Bubbe'],
viral: ['#JewishTwitter', '#Dating', '#Relationships', '#MondayMotivation', '#Funny', '#Comedy', '#NoFilter', '#Truth', '#Savage', '#Life'],
day: {
0: '#SundayFunday',
1: '#MondayMotivation',
2: '#TuesdayThoughts',
3: '#WednesdayWisdom',
4: '#ThursdayThoughts',
5: '#FridayFeeling',
6: '#SaturdayVibes'
}
};
// Content templates
const CONTENT = [
"My boyfriend only texts once a day",
"Should I quit my job without another lined up?",
"My mother-in-law criticized my cooking",
"I spent $500 on shoes",
"Is 35 too old to start dating?",
"My husband forgot our anniversary",
"Should I text my ex?",
"I haven't been to temple in years",
"My kids never call me",
"My boss is micromanaging me"
];
// Get Bubbe response
async function getBubbeResponse(message) {
try {
const response = await axios.post('http://45.61.58.125:3011/api/chat', {
message: message,
mode: 'bubbe',
userId: 'twitter-bot-' + Date.now()
});
return response.data.response;
} catch (error) {
console.error('Failed to get Bubbe response:', error.message);
return null;
}
}
// Format tweet
function formatTweet(response) {
const day = new Date().getDay();
const dayHashtag = HASHTAGS.day[day];
const viralHashtag = HASHTAGS.viral[Math.floor(Math.random() * HASHTAGS.viral.length)];
// Trim response to fit
let trimmed = response;
const maxLength = 280 - 50; // Leave room for hashtags
if (trimmed.length > maxLength) {
trimmed = trimmed.substring(0, maxLength - 3) + '...';
}
return `${trimmed} ${HASHTAGS.always.join(' ')} ${dayHashtag} ${viralHashtag}`;
}
// Check if can post
async function canPost() {
try {
// Check daily limit
const stats = JSON.parse(await fs.readFile(CONFIG.STATS_FILE, 'utf8').catch(() => '{}'));
const today = new Date().toDateString();
if (stats.date !== today) {
stats.date = today;
stats.count = 0;
}
if (stats.count >= CONFIG.MAX_DAILY_POSTS) {
console.log(`Daily limit reached: ${stats.count}/${CONFIG.MAX_DAILY_POSTS}`);
return false;
}
// Check time since last post
const lastPost = JSON.parse(await fs.readFile(CONFIG.LAST_POST_FILE, 'utf8').catch(() => '{}'));
if (lastPost.time) {
const elapsed = (Date.now() - lastPost.time) / 1000;
if (elapsed < CONFIG.MIN_INTERVAL_SECONDS) {
console.log(`Rate limit: wait ${Math.ceil(CONFIG.MIN_INTERVAL_SECONDS - elapsed)}s`);
return false;
}
}
return true;
} catch (error) {
console.error('Error checking limits:', error);
return false;
}
}
// Update stats
async function updateStats() {
try {
const stats = JSON.parse(await fs.readFile(CONFIG.STATS_FILE, 'utf8').catch(() => '{}'));
const today = new Date().toDateString();
if (stats.date !== today) {
stats.date = today;
stats.count = 0;
}
stats.count++;
stats.total = (stats.total || 0) + 1;
await fs.writeFile(CONFIG.STATS_FILE, JSON.stringify(stats, null, 2));
await fs.writeFile(CONFIG.LAST_POST_FILE, JSON.stringify({ time: Date.now() }, null, 2));
return stats;
} catch (error) {
console.error('Error updating stats:', error);
}
}
// Post one tweet
async function postOne() {
if (!await canPost()) {
return false;
}
// Get random content
const topic = CONTENT[Math.floor(Math.random() * CONTENT.length)];
console.log('Topic:', topic);
// Get Bubbe response
const response = await getBubbeResponse(topic);
if (!response) {
console.log('No response from Bubbe');
return false;
}
// Format and post
const tweet = formatTweet(response);
console.log('Tweet:', tweet.substring(0, 100) + '...');
console.log('Length:', tweet.length);
const result = await postTweet(tweet);
if (result.success) {
const stats = await updateStats();
console.log(`✅ Posted! (${stats.count}/${CONFIG.MAX_DAILY_POSTS} today, ${stats.total} total)`);
console.log(`URL: https://x.com/DearBubbe/status/${result.tweetId}`);
return true;
} else {
console.log('❌ Failed:', result.error);
return false;
}
}
// Run continuously
async function run() {
console.log('🚀 Bubbe Twitter Bot Started');
console.log(`Posts per day: ${CONFIG.MAX_DAILY_POSTS}`);
console.log(`Min interval: ${CONFIG.MIN_INTERVAL_SECONDS}s`);
while (true) {
await postOne();
// Wait before next attempt
await new Promise(r => setTimeout(r, CONFIG.MIN_INTERVAL_SECONDS * 1000));
}
}
// Start
if (require.main === module) {
run().catch(console.error);
}