Emalawi19's picture
Update server.js
7bd848c verified
Raw
History Blame Contribute Delete
3.34 kB
const express = require("express");
const puppeteer = require("puppeteer-core");
const app = express();
app.use(express.json());
// CORS — allow requests from any frontend
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type");
res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
if (req.method === "OPTIONS") return res.sendStatus(200);
next();
});
const CF_ACCOUNT_ID = process.env.CF_ACCOUNT_ID;
const CF_API_TOKEN = process.env.CF_API_TOKEN;
const CF_MODEL = "@cf/meta/llama-3.1-8b-instruct";
app.get("/health", (req, res) => {
res.json({ status: "ok" });
});
app.get("/debug", async (req, res) => {
const hasAccountId = !!process.env.CF_ACCOUNT_ID;
const hasToken = !!process.env.CF_API_TOKEN;
let networkTest = "not attempted";
try {
const r = await fetch("https://api.cloudflare.com/client/v4/ips");
networkTest = `reached Cloudflare, status ${r.status}`;
} catch (err) {
networkTest = `failed: ${err.message}`;
}
res.json({ hasAccountId, hasToken, networkTest });
});
async function getPlanFromAI(instruction) {
const url = `https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/ai/run/${CF_MODEL}`;
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${CF_API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
messages: [
{
role: "system",
content:
'You convert a user\'s browsing instruction into a single JSON object: {"url": "<the website to visit>"}. ' +
"Only output valid JSON, nothing else. If no clear URL or site is mentioned, guess the most likely official site.",
},
{ role: "user", content: instruction },
],
}),
});
const data = await response.json();
if (!data.success) {
throw new Error("Cloudflare AI error: " + JSON.stringify(data.errors));
}
const raw = data.result.response;
try {
return JSON.parse(raw);
} catch {
throw new Error("AI did not return valid JSON: " + raw);
}
}
app.post("/run-task", async (req, res) => {
const { instruction } = req.body;
if (!instruction) return res.status(400).json({ error: "Missing 'instruction' in request body" });
let plan;
try {
plan = await getPlanFromAI(instruction);
} catch (err) {
return res.status(502).json({ success: false, stage: "ai", error: err.message });
}
if (!plan.url) {
return res.status(502).json({ success: false, error: "AI plan missing 'url'", plan });
}
let browser;
try {
browser = await puppeteer.launch({
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
args: ["--no-sandbox", "--disable-setuid-sandbox"],
headless: true,
});
const page = await browser.newPage();
await page.goto(plan.url, { waitUntil: "domcontentloaded", timeout: 30000 });
const title = await page.title();
res.json({ success: true, instruction, plan, title });
} catch (err) {
res.status(500).json({ success: false, stage: "puppeteer", error: err.message });
} finally {
if (browser) await browser.close();
}
});
const PORT = process.env.PORT || 7860;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));