ii-agent-dlya-zadach-sozday/server.js

113 lines
4.4 KiB
JavaScript

const http = require("http");
const fs = require("fs");
const path = require("path");
const PORT = process.env.PORT || 3000;
const DATA = path.join(__dirname, "data.json");
function readData() {
try { return JSON.parse(fs.readFileSync(DATA, "utf8")); } catch (_) { return { items: [], conversations: [] }; }
}
function writeData(data) {
fs.writeFileSync(DATA, JSON.stringify(data, null, 2));
}
function body(req) {
return new Promise((resolve) => {
let s = "";
req.on("data", (c) => (s += c));
req.on("end", () => { try { resolve(JSON.parse(s || "{}")); } catch (_) { resolve({}); } });
});
}
http.createServer(async (req, res) => {
const url = req.url.split("?")[0];
// API: получить настройки агента
if (req.method === "GET" && url === "/api/agent") {
res.writeHead(200, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ role: "Помощник", behavior: "Вежливый и точный", tools: [] }));
}
// API: сохранить настройки агента
if (req.method === "POST" && url === "/api/agent") {
const settings = await body(req);
res.writeHead(200, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ ok: true }));
}
// API: отправить сообщение и получить ответ ИИ
if (req.method === "POST" && url === "/api/chat") {
const { message } = await body(req);
let answer = "Заглушка: ИИ пока не подключён. Настройка в Фазе 2.";
try {
if (process.env.AI_BASE_URL && process.env.AI_API_KEY) {
const r = await fetch(process.env.AI_BASE_URL + "/chat/completions", {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: "Bearer " + process.env.AI_API_KEY },
body: JSON.stringify({ model: process.env.AI_MODEL || "gpt-4o-mini", messages: [{ role: "user", content: message }] })
});
if (r.ok) {
const j = await r.json();
answer = j.choices?.[0]?.message?.content || "ИИ вернул пустой ответ";
} else {
answer = "ИИ недоступен (код " + r.status + ")";
}
}
} catch (e) {
answer = "Ошибка ИИ: " + e.message;
}
const data = readData();
data.conversations = data.conversations || [];
data.conversations.push({ role: "user", content: message, ts: Date.now() });
data.conversations.push({ role: "assistant", content: answer, ts: Date.now() });
writeData(data);
res.writeHead(200, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ ok: true, answer }));
}
// API: получить историю диалогов
if (req.method === "GET" && url === "/api/history") {
const data = readData();
res.writeHead(200, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ conversations: data.conversations || [] }));
}
// API: очистить историю
if (req.method === "POST" && url === "/api/history/clear") {
const data = readData();
data.conversations = [];
writeData(data);
res.writeHead(200, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ ok: true }));
}
// API: экспортировать результаты
if (req.method === "POST" && url === "/api/export") {
const { format } = await body(req);
const data = readData();
let content = "";
let type = "text/plain";
let ext = "txt";
if (format === "json") {
content = JSON.stringify(data.conversations, null, 2);
type = "application/json";
ext = "json";
} else {
content = (data.conversations || []).map(m => `[${m.role}] ${m.content}`).join("\n\n");
}
res.writeHead(200, { "Content-Type": type, "Content-Disposition": "attachment; filename=export." + ext });
return res.end(content);
}
// Статика
let file = url === "/" ? "/index.html" : url;
const full = path.join(__dirname, file);
if (full.startsWith(__dirname) && fs.existsSync(full) && fs.statSync(full).isFile()) {
const ext = path.extname(full);
const type = ext === ".css" ? "text/css" : ext === ".js" ? "application/javascript" : "text/html";
res.writeHead(200, { "Content-Type": type + "; charset=utf-8" });
return res.end(fs.readFileSync(full));
}
res.writeHead(404); res.end("Not found");
}).listen(PORT, () => console.log("Сервер на порту " + PORT));