crm/server.js

111 lines
3.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const http = require("http");
const fs = require("fs");
const path = require("path");
const PORT = process.env.PORT || 3000;
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({}); } });
});
}
async function fetchAlemOrders() {
// Интеграция с Alem CRM - данные подтянутся, когда Alem подключится
if (!process.env.ALEM_BASE_URL || !process.env.ALEM_API_KEY) {
return null;
}
try {
// Создаём сессию
const sessionResp = await fetch(process.env.ALEM_BASE_URL + "/api/v1/open-api/conversation", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + process.env.ALEM_API_KEY
},
body: JSON.stringify({
template_id: process.env.ALEM_TEMPLATE_ID,
title: "CRM Dashboard",
user_id: "crm_b2c_user"
})
});
if (!sessionResp.ok) throw new Error("Alem session " + sessionResp.status);
const sessionBody = await sessionResp.json();
const sessionId = sessionBody?.data?.session_id;
if (!sessionId) throw new Error("No session_id from Alem");
// Запрашиваем топ-10 заказов B2C
const queryResp = await fetch(process.env.ALEM_BASE_URL + "/api/v1/open-api/conversation/" + sessionId + "/send", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + process.env.ALEM_API_KEY
},
body: JSON.stringify({
content: "Покажи топ-10 самых крупных заказов B2C за сегодня в формате JSON с полями: id, client, region, service, status, amount. Только JSON массив.",
user_id: "crm_b2c_user",
model_api_key: process.env.ALEM_API_KEY
})
});
if (!queryResp.ok) throw new Error("Alem query " + queryResp.status);
// SSE-поток
const raw = await queryResp.text();
let answer = null;
for (const line of raw.split("\n")) {
const s = line.trim();
if (!s.startsWith("data:")) continue;
const payload = s.slice(5).trim();
if (!payload || payload === "[DONE]") continue;
try {
const ev = JSON.parse(payload);
if (ev && ev.detail && typeof ev.detail.full_content === "string" && ev.detail.full_content) {
answer = ev.detail.full_content;
}
} catch (e) {}
}
if (!answer) return null;
// Пытаемся извлечь JSON из ответа
const jsonMatch = answer.match(/\[[\s\S]*\]/);
if (jsonMatch) {
return JSON.parse(jsonMatch[0]);
}
return null;
} catch (e) {
console.error("Alem error:", e.message);
return null;
}
}
http.createServer(async (req, res) => {
// API: данные для дашборда
if (req.method === "GET" && req.url.split("?")[0] === "/api/alem-orders") {
const orders = await fetchAlemOrders();
res.writeHead(200, {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
});
res.end(JSON.stringify({ orders: orders || [] }));
return;
}
// Статика: index.html
let file = req.url === "/" ? "/index.html" : req.url.split("?")[0];
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("CRM Dashboard на порту " + PORT));