← back to Dear Bubbe Nextjs
app/api/social-post/route.ts
174 lines
import { NextRequest, NextResponse } from 'next/server'
import { exec } from 'child_process'
import { promisify } from 'util'
import fs from 'fs/promises'
import path from 'path'
const execAsync = promisify(exec)
// Rate limiting: max 1 post per 5 minutes
const lastPostTime = new Map<string, number>()
const RATE_LIMIT_MS = 5 * 60 * 1000 // 5 minutes
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const { userMessage, bubbeResponse, messageId, timestamp } = body
if (!userMessage || !bubbeResponse) {
return NextResponse.json(
{ error: 'Missing required fields' },
{ status: 400 }
)
}
// Rate limiting check
const now = Date.now()
const lastPost = lastPostTime.get('global') || 0
if (now - lastPost < RATE_LIMIT_MS) {
const waitTime = Math.ceil((RATE_LIMIT_MS - (now - lastPost)) / 1000)
console.log(`[SOCIAL-POST] Rate limited, wait ${waitTime} seconds`)
return NextResponse.json({
success: false,
rateLimited: true,
waitSeconds: waitTime
})
}
console.log('[SOCIAL-POST] Triggering immediate post for:', messageId)
console.log('[SOCIAL-POST] User message:', userMessage.substring(0, 50))
console.log('[SOCIAL-POST] Bubbe response:', bubbeResponse.substring(0, 50))
// Save to chat history for the auto-poster to process.
// Use cwd (not a hardcoded absolute path) so it works on any host, and
// ensure the logs/ dir exists — writeFile can't create parent dirs (was ENOENT).
const chatHistoryPath = path.join(process.cwd(), 'logs', 'chat-history.json')
await fs.mkdir(path.dirname(chatHistoryPath), { recursive: true })
let chats = []
try {
const existing = await fs.readFile(chatHistoryPath, 'utf8')
chats = JSON.parse(existing)
} catch (e) {
// File doesn't exist yet
}
// Add new chat with timestamp
chats.push({
id: messageId,
userMessage,
bubbeResponse,
timestamp: timestamp || new Date().toISOString(),
postedAt: new Date().toISOString()
})
// Keep only last 100 chats
if (chats.length > 100) {
chats = chats.slice(-100)
}
await fs.writeFile(chatHistoryPath, JSON.stringify(chats, null, 2))
// Update rate limit
lastPostTime.set('global', now)
// Trigger the social poster script asynchronously
execAsync('node /root/Projects/dear-bubbe-nextjs/lib/social-autoposter.js')
.then(result => {
console.log('[SOCIAL-POST] Social posting completed:', result.stdout)
})
.catch(err => {
console.error('[SOCIAL-POST] Social posting error:', err.message)
})
// Log the post attempt
const logPath = '/root/Projects/dear-bubbe-nextjs/logs/realtime-posts.log'
const logEntry = {
timestamp: new Date().toISOString(),
messageId,
userSnippet: userMessage.substring(0, 50),
bubbeSnippet: bubbeResponse.substring(0, 50),
triggered: true
}
try {
let logs = []
try {
const existingLogs = await fs.readFile(logPath, 'utf8')
logs = JSON.parse(existingLogs)
} catch (e) {
// File doesn't exist
}
logs.push(logEntry)
// Keep only last 50 entries
if (logs.length > 50) {
logs = logs.slice(-50)
}
await fs.writeFile(logPath, JSON.stringify(logs, null, 2))
} catch (e) {
console.error('[SOCIAL-POST] Failed to write log:', e)
}
return NextResponse.json({
success: true,
messageId,
message: 'Social posting triggered'
})
} catch (error) {
console.error('[SOCIAL-POST] Error:', error)
return NextResponse.json(
{ error: 'Failed to trigger social post' },
{ status: 500 }
)
}
}
export async function GET(request: NextRequest) {
// Return status of recent posts
try {
const logPath = '/root/Projects/dear-bubbe-nextjs/logs/realtime-posts.log'
const socialLogPath = '/root/Projects/dear-bubbe-nextjs/logs/social-posts.log'
let realtimeLogs = []
let socialLogs = []
try {
const realtimeData = await fs.readFile(logPath, 'utf8')
realtimeLogs = JSON.parse(realtimeData)
} catch (e) {
// File doesn't exist
}
try {
const socialData = await fs.readFile(socialLogPath, 'utf8')
socialLogs = JSON.parse(socialData)
} catch (e) {
// File doesn't exist
}
// Get last 10 of each
const recent = {
realtime: realtimeLogs.slice(-10),
posted: socialLogs.slice(-10),
rateLimitActive: false
}
// Check if rate limit is active
const now = Date.now()
const lastPost = lastPostTime.get('global') || 0
if (now - lastPost < RATE_LIMIT_MS) {
recent.rateLimitActive = true
}
return NextResponse.json(recent)
} catch (error) {
return NextResponse.json(
{ error: 'Failed to get status' },
{ status: 500 }
)
}
}