← 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 }
    )
  }
}