| Server IP : 54.37.205.81 / Your IP : 216.73.216.76 Web Server : nginx/1.22.1 System : Linux vps-249481fa 6.1.0-50-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.176-1 (2026-07-02) x86_64 User : debian ( 1000) PHP Version : 8.2.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /proc/self/root/opt/lampovert-tutor-server/ |
Upload File : |
import http from "http";
function readJson(req) {
return new Promise((resolve, reject) => {
let data = "";
req.on("data", (c) => (data += c));
req.on("end", () => {
try {
resolve(data ? JSON.parse(data) : {});
} catch (e) {
reject(e);
}
});
});
}
function send(res, status, obj) {
const body = JSON.stringify(obj);
res.writeHead(status, {
"Content-Type": "application/json; charset=utf-8",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type",
"Access-Control-Allow-Methods": "POST, OPTIONS",
});
res.end(body);
}
async function callOpenAIText(messages) {
const apiKey = process.env.OPENAI_API_KEY;
const model = process.env.OPENAI_MODEL || "gpt-4.1";
if (!apiKey) throw new Error("Missing OPENAI_API_KEY on server");
const payload = {
model,
input: messages.map((m) => ({ role: m.role, content: m.content })),
};
const r = await fetch("https://api.openai.com/v1/responses", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const text = await r.text();
if (!r.ok) throw new Error(`OpenAI error ${r.status}: ${text}`);
const json = JSON.parse(text);
const out = [];
const output = json.output || [];
for (const item of output) {
const content = item.content || [];
for (const c of content) {
if (c.type === "output_text" && typeof c.text === "string") out.push(c.text);
}
}
return out.join("\n").trim();
}
// Vision: accetta {image:"data:image/...base64,...", prompt:"..."}
async function callOpenAIVision(imageDataUrl, prompt) {
const apiKey = process.env.OPENAI_API_KEY;
const model = process.env.OPENAI_VISION_MODEL || "gpt-4o";
if (!apiKey) throw new Error("Missing OPENAI_API_KEY on server");
if (!imageDataUrl || typeof imageDataUrl !== "string") throw new Error("Missing image");
const payload = {
model,
input: [
{
role: "user",
content: [
{ type: "input_text", text: String(prompt || "Trascrivi e risolvi l'esercizio.") },
{ type: "input_image", image_url: imageDataUrl },
],
},
],
};
const r = await fetch("https://api.openai.com/v1/responses", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const text = await r.text();
if (!r.ok) throw new Error(`OpenAI error ${r.status}: ${text}`);
const json = JSON.parse(text);
const out = [];
const output = json.output || [];
for (const item of output) {
const content = item.content || [];
for (const c of content) {
if (c.type === "output_text" && typeof c.text === "string") out.push(c.text);
}
}
return out.join("\n").trim();
}
// TTS: restituisce audio/mpeg
async function callOpenAITTS(text) {
const apiKey = process.env.OPENAI_API_KEY;
const model = process.env.OPENAI_TTS_MODEL || "gpt-4o-audio-preview";
if (!apiKey) throw new Error("Missing OPENAI_API_KEY on server");
const payload = {
model,
input: String(text || ""),
voice: process.env.OPENAI_TTS_VOICE || "alloy",
format: "mp3",
};
const r = await fetch("https://api.openai.com/v1/audio/speech", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
if (!r.ok) {
const err = await r.text().catch(() => "");
throw new Error(`OpenAI TTS error ${r.status}: ${err || r.statusText}`);
}
const buf = Buffer.from(await r.arrayBuffer());
return buf;
}
const server = http.createServer(async (req, res) => {
if (req.method === "OPTIONS") return send(res, 200, { ok: true });
try {
if (req.url === "/tutor" && req.method === "POST") {
const body = await readJson(req);
const messages = body.messages;
if (!Array.isArray(messages)) return send(res, 400, { error: "messages must be an array" });
const answer = await callOpenAIText(messages);
return send(res, 200, { answer });
}
if (req.url === "/vision" && req.method === "POST") {
const body = await readJson(req);
const answer = await callOpenAIVision(body.image, body.prompt);
return send(res, 200, { answer });
}
if (req.url === "/tts" && req.method === "POST") {
const body = await readJson(req);
const audio = await callOpenAITTS(body.text);
res.writeHead(200, {
"Content-Type": "audio/mpeg",
"Access-Control-Allow-Origin": "*",
});
return res.end(audio);
}
return send(res, 404, { error: "not_found" });
} catch (e) {
return send(res, 500, { error: String(e.message || e) });
}
});
const port = Number(process.env.PORT || 5070);
server.listen(port, "127.0.0.1", () => {
console.log(`Tutor API listening on http://127.0.0.1:${port}`);
});