server.js•4.21 kB
// server1.js - Clean Express backend for Replicate API proxy 
import express from 'express';
import fetch from 'node-fetch';
import path from 'path';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
dotenv.config();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const app = express();
const PORT = process.env.PORT || 8080;
const REPLICATE_API_TOKEN = process.env.REPLICATE_API_TOKEN;
// ===== CORS Middleware =====
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
  
  if (req.method === 'OPTIONS') {
    res.sendStatus(200);
  } else {
    next();
  }
});
// ===== API Key Validation =====
if (!REPLICATE_API_TOKEN) {
  console.error('Error: REPLICATE_API_TOKEN environment variable not set.');
  process.exit(1);
}
app.use(express.json());
app.use(express.static(path.join(__dirname, '../../'), {
  setHeaders: (res, path) => {
    res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
    res.setHeader('Pragma', 'no-cache');
    res.setHeader('Expires', '0');
  }
}));
app.post('/api/replicate', async (req, res) => {
  
  try {
    const url = 'https://api.replicate.com/v1/models/meta/llama-4-maverick-instruct/predictions';
    
    
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': `Bearer ${REPLICATE_API_TOKEN}`,
        'User-Agent': 'MARM-Systems/1.4'
      },
      body: JSON.stringify({
        input: {
          prompt: req.body.prompt,
          temperature: req.body.temperature || 0.7,
          max_tokens: req.body.max_tokens || 8192,
          top_p: req.body.top_p || 0.9
        }
      })
    });
    
    
    const text = await response.text();
    
    let data;
    try {
      data = JSON.parse(text);
      
      if (data.status === 'starting' || data.status === 'processing') {
        
        const pollStart = Date.now();
        const maxPollTime = 30000; 
        
        while ((Date.now() - pollStart) < maxPollTime) {
          await new Promise(resolve => setTimeout(resolve, 2000)); 
          
          const pollResponse = await fetch(`https://api.replicate.com/v1/predictions/${data.id}`, {
            method: 'GET',
            headers: {
              'Authorization': `Bearer ${REPLICATE_API_TOKEN}`,
              'Content-Type': 'application/json'
            }
          });
          
          if (pollResponse.ok) {
            const pollData = await pollResponse.json();
            
            if (pollData.status === 'succeeded' && pollData.output) {
              res.status(200).json(pollData);
              return;
            } else if (pollData.status === 'failed' || pollData.status === 'canceled') {
              res.status(500).json({ error: 'Prediction failed', details: pollData.error });
              return;
            }
          } else {
            console.error('[MARM DEBUG] Failed to poll prediction:', pollResponse.status);
            break;
          }
        }
        
        res.status(408).json({ error: 'Prediction timeout', id: data.id });
        return;
      }
      
      res.status(response.status).json(data);
    } catch (e) {
      console.error('[MARM DEBUG] Failed to parse Replicate API response as JSON:', e.message);
      res.status(502).json({ error: 'Invalid JSON from Replicate API', raw: text });
    }
  } catch (error) {
    console.error('[MARM DEBUG] Replicate proxy error:', error.name, error.message);
    res.status(500).json({ error: 'Internal server error', details: error.message });
  }
});
// ===== Error Handling Middleware =====
app.use((err, req, res, next) => {
  console.error('Unhandled error:', err);
  res.status(500).json({ error: 'Unhandled server error', details: err.message });
});
// ===== Server Startup =====
app.listen(PORT, '0.0.0.0', () => {
  console.log(`MARM Webchat server running on port ${PORT}`);
});