feat: 新增文件
This commit is contained in:
92
server/index.js
Normal file
92
server/index.js
Normal file
@@ -0,0 +1,92 @@
|
||||
import express from "express";
|
||||
import { spawn } from "node:child_process";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const repoRoot = path.resolve(__dirname, "..");
|
||||
|
||||
const app = express();
|
||||
app.use(express.static(path.join(__dirname, "public")));
|
||||
|
||||
function sseHeaders(res) {
|
||||
res.setHeader("Content-Type", "text/event-stream; charset=utf-8");
|
||||
res.setHeader("Cache-Control", "no-cache, no-transform");
|
||||
res.setHeader("Connection", "keep-alive");
|
||||
// Nginx proxies may buffer unless disabled; harmless in dev.
|
||||
res.setHeader("X-Accel-Buffering", "no");
|
||||
}
|
||||
|
||||
function sseSend(res, event, data) {
|
||||
if (event) res.write(`event: ${event}\n`);
|
||||
const lines = String(data).split(/\r?\n/);
|
||||
for (const line of lines) res.write(`data: ${line}\n`);
|
||||
res.write("\n");
|
||||
}
|
||||
|
||||
app.get("/api/run", (req, res) => {
|
||||
const prompt = String(req.query.prompt || "").trim();
|
||||
const mock = String(req.query.mock || "1") === "1";
|
||||
const configPath = String(req.query.config || "./configs/config.yaml");
|
||||
|
||||
if (!prompt) {
|
||||
res.status(400).json({ error: "missing prompt" });
|
||||
return;
|
||||
}
|
||||
|
||||
sseHeaders(res);
|
||||
sseSend(res, "status", "starting");
|
||||
|
||||
// Unified in-container execution: Node spawns python directly.
|
||||
const py = process.env.PYTHON_BIN || "python";
|
||||
const args = [
|
||||
path.join(repoRoot, "main.py"),
|
||||
"--prompt",
|
||||
prompt,
|
||||
"--config",
|
||||
configPath,
|
||||
"--script-only",
|
||||
];
|
||||
if (mock) args.push("--mock");
|
||||
|
||||
const child = spawn(py, args, {
|
||||
cwd: repoRoot,
|
||||
env: process.env,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
let buf = "";
|
||||
child.stdout.setEncoding("utf8");
|
||||
child.stdout.on("data", (chunk) => {
|
||||
buf += chunk;
|
||||
const parts = buf.split(/\r?\n/);
|
||||
buf = parts.pop() || "";
|
||||
for (const line of parts) {
|
||||
if (!line) continue;
|
||||
// Forward raw lines. Frontend will parse SCENE_JSON.
|
||||
sseSend(res, "line", line);
|
||||
}
|
||||
});
|
||||
|
||||
child.stderr.setEncoding("utf8");
|
||||
child.stderr.on("data", (chunk) => {
|
||||
sseSend(res, "stderr", chunk);
|
||||
});
|
||||
|
||||
req.on("close", () => {
|
||||
child.kill("SIGTERM");
|
||||
});
|
||||
|
||||
child.on("exit", (code) => {
|
||||
if (buf.trim()) sseSend(res, "line", buf.trim());
|
||||
sseSend(res, "done", String(code ?? 0));
|
||||
res.end();
|
||||
});
|
||||
});
|
||||
|
||||
const port = Number(process.env.PORT || 3000);
|
||||
app.listen(port, () => {
|
||||
console.log(`[server] http://127.0.0.1:${port}`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user