Files
apiAi/server.js
2025-04-14 00:16:20 -04:00

180 lines
4.9 KiB
JavaScript

require("dotenv").config(); // Load environment variables from .env file
const express = require("express");
const axios = require("axios");
const bodyParser = require("body-parser");
const app = express();
const port = 3000; // Backend server will run on this port
// Middleware to parse JSON request bodies
app.use(bodyParser.json());
// API Key validation middleware
const validateApiKey = (req, res, next) => {
const trustedIps = [
"2600:1702:6f0a:3c00:d065:e1b4:ac3b:d889", // Cloudflare real IP
"2600:1702:6f0a:3c00:6525:1a53:cca3:cdcf"
"192.168.1.149",
"144.160.240.69", // another ip
"::1", // localhost IPv6
"127.0.0.1", // localhost IPv4
];
const cfIp = req.headers["cf-connecting-ip"];
const forwardedIp = req.headers["x-forwarded-for"];
const userAgent = req.headers["user-agent"];
const clientIp = cfIp || forwardedIp || req.ip;
console.log("🔐 Incoming IP:", clientIp);
console.log("🧭 User-Agent:", userAgent);
if (trustedIps.includes(clientIp)) {
return next(); // Skip API key check for trusted IPs
}
const apiKey = req.headers["api-key"];
const authHeader = req.headers["authorization"];
// Try to extract token from Authorization: Bearer <token>
let token = null;
if (authHeader && authHeader.startsWith("Bearer ")) {
token = authHeader.split(" ")[1];
}
const providedKey = apiKey || token;
if (!providedKey) {
return res.status(400).json({ error: "API key is missing" });
}
if (providedKey !== process.env.API_KEY) {
return res.status(403).json({ error: "Invalid API key" });
}
next(); // Proceed if the API key is valid
};
app.get("/", (req, res) => {
res.send("Hello from the backend server!");
})
// Forward request to localhost:11434 (ollama)
app.post("/api/generate/api/chat", validateApiKey, async (req, res) => {
try {
const { model, messages, system } = req.body;
console.log(req.headers);
const prompt = messages
.map(
(msg) =>
`${msg.role === "system" ? "" : msg.role + ": "}${msg.content}`,
)
.join("\n");
console.log("🧠 Prompt for Ollama:\n", prompt);
const response = await axios.post(
"http://localhost:11434/api/generate",
{
model: model || "deepseek-r1:latest",
prompt,
stream: true,
},
{ responseType: "stream" },
);
res.setHeader("Content-Type", "application/json");
res.setHeader("Transfer-Encoding", "chunked");
let insideThink = false;
response.data.on("data", (chunk) => {
const lines = chunk.toString("utf8").split("\n").filter(Boolean);
for (const line of lines) {
try {
const json = JSON.parse(line);
const text = json.response;
if (text?.includes("<think>")) {
insideThink = true;
continue;
}
if (text?.includes("</think>")) {
insideThink = false;
continue;
}
if (!insideThink && text) {
const responseLine = JSON.stringify({
message: {
role: "assistant",
content: text,
},
done: false,
});
res.write(responseLine + "\n");
}
} catch (err) {
console.warn("Chunk parse failed:", err);
}
}
});
response.data.on("end", () => {
res.write(JSON.stringify({ done: true }) + "\n");
res.end();
});
response.data.on("error", (err) => {
console.error("Ollama stream error:", err);
res.write(
JSON.stringify({ error: "Stream error", message: err.message }) + "\n",
);
res.end();
});
} catch (error) {
console.error(
"❌ Error communicating with Ollama:",
error.response?.data || error.message,
);
res
.status(500)
.json({ error: "Internal Server Error", message: error.message });
}
});
// Forward request to localhost:11434 (ollama)
app.post("/api/generate", validateApiKey, async (req, res) => {
try {
// Forwarding the request to localhost:11434 with the prompt
const authHeader = req.headers["authorization"];
console.log("Authorization header:", authHeader);
console.log("checking api", apiKey !== process.env.API_KEY);
console.log("Body: ", req.body);
const response = await axios.post(
"http://localhost:11434/api/generate",
req.body,
);
// Send the response from localhost:11434 back to the client
res.status(response.status).json(response.data);
} catch (error) {
// Enhanced error logging
console.error(
"Error forwarding request to localhost:11434:",
error.response ? error.response.data : error.message,
);
res
.status(500)
.json({ error: "Internal Server Error", message: error.message });
}
});
// Start the server
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
});