Spaces:
Building
Building
Serve Hermes dashboard under app route
Browse files- README.md +1 -1
- health-server.js +48 -6
README.md
CHANGED
|
@@ -128,7 +128,7 @@ http://localhost:7861
|
|
| 128 |
| `/` | HuggingMess dashboard |
|
| 129 |
| `/health` | Health check for HF and UptimeRobot |
|
| 130 |
| `/status` | JSON status |
|
| 131 |
-
| `/
|
| 132 |
| `/v1/models` | Proxied Hermes OpenAI-compatible API server |
|
| 133 |
| `/telegram` | Telegram webhook endpoint |
|
| 134 |
|
|
|
|
| 128 |
| `/` | HuggingMess dashboard |
|
| 129 |
| `/health` | Health check for HF and UptimeRobot |
|
| 130 |
| `/status` | JSON status |
|
| 131 |
+
| `/app/` | Proxied Hermes dashboard/app |
|
| 132 |
| `/v1/models` | Proxied Hermes OpenAI-compatible API server |
|
| 133 |
| `/telegram` | Telegram webhook endpoint |
|
| 134 |
|
health-server.js
CHANGED
|
@@ -11,6 +11,7 @@ const TELEGRAM_WEBHOOK_PORT = Number(process.env.TELEGRAM_WEBHOOK_PORT || 8765);
|
|
| 11 |
const GATEWAY_HOST = "127.0.0.1";
|
| 12 |
const startTime = Date.now();
|
| 13 |
const API_SERVER_KEY = process.env.API_SERVER_KEY || "";
|
|
|
|
| 14 |
|
| 15 |
const SYNC_STATUS_FILE = "/tmp/huggingmess-sync-status.json";
|
| 16 |
const UPTIMEROBOT_STATUS_FILE = "/tmp/huggingmess-uptimerobot-status.json";
|
|
@@ -69,6 +70,11 @@ function proxyRequest(req, res, targetPort, rewritePath = (path) => path) {
|
|
| 69 |
req.pipe(proxy);
|
| 70 |
}
|
| 71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
function formatUptime(ms) {
|
| 73 |
const total = Math.floor(ms / 1000);
|
| 74 |
const days = Math.floor(total / 86400);
|
|
@@ -114,7 +120,7 @@ function badge(label, state) {
|
|
| 114 |
|
| 115 |
function renderDashboard(data) {
|
| 116 |
const syncStatus = String(data.backup?.status || "unknown").toUpperCase();
|
| 117 |
-
const dashboardLink = data.dashboard ? `<a class="button" href="/
|
| 118 |
const apiLink = data.gateway ? `<a class="button secondary" href="/v1/models">API Models</a>` : "";
|
| 119 |
const keepAlive = data.uptimerobot?.configured
|
| 120 |
? `UptimeRobot is monitoring <code>${data.uptimerobot.url}</code>.`
|
|
@@ -178,34 +184,70 @@ const server = http.createServer(async (req, res) => {
|
|
| 178 |
const parsed = new URL(req.url, "http://localhost");
|
| 179 |
const path = parsed.pathname;
|
| 180 |
|
| 181 |
-
if (path === "/health" || path ===
|
| 182 |
const data = await statusPayload();
|
| 183 |
res.writeHead(data.ok ? 200 : 503, { "content-type": "application/json" });
|
| 184 |
res.end(JSON.stringify({ ok: data.ok, gateway: data.gateway, uptime: data.uptime }));
|
| 185 |
return;
|
| 186 |
}
|
| 187 |
|
| 188 |
-
if (path === "/status" || path ===
|
| 189 |
const data = await statusPayload();
|
| 190 |
res.writeHead(200, { "content-type": "application/json" });
|
| 191 |
res.end(JSON.stringify(data, null, 2));
|
| 192 |
return;
|
| 193 |
}
|
| 194 |
|
| 195 |
-
if (path === "/"
|
| 196 |
const data = await statusPayload();
|
| 197 |
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
| 198 |
res.end(renderDashboard(data));
|
| 199 |
return;
|
| 200 |
}
|
| 201 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
if (path === "/telegram" || path.startsWith("/telegram/")) {
|
| 203 |
proxyRequest(req, res, TELEGRAM_WEBHOOK_PORT);
|
| 204 |
return;
|
| 205 |
}
|
| 206 |
|
| 207 |
-
if (path ===
|
| 208 |
-
proxyRequest(req, res, DASHBOARD_PORT, (p) => p.replace(/^\/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
return;
|
| 210 |
}
|
| 211 |
|
|
|
|
| 11 |
const GATEWAY_HOST = "127.0.0.1";
|
| 12 |
const startTime = Date.now();
|
| 13 |
const API_SERVER_KEY = process.env.API_SERVER_KEY || "";
|
| 14 |
+
const APP_BASE = "/app";
|
| 15 |
|
| 16 |
const SYNC_STATUS_FILE = "/tmp/huggingmess-sync-status.json";
|
| 17 |
const UPTIMEROBOT_STATUS_FILE = "/tmp/huggingmess-uptimerobot-status.json";
|
|
|
|
| 70 |
req.pipe(proxy);
|
| 71 |
}
|
| 72 |
|
| 73 |
+
function redirect(res, location, statusCode = 302) {
|
| 74 |
+
res.writeHead(statusCode, { location });
|
| 75 |
+
res.end();
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
function formatUptime(ms) {
|
| 79 |
const total = Math.floor(ms / 1000);
|
| 80 |
const days = Math.floor(total / 86400);
|
|
|
|
| 120 |
|
| 121 |
function renderDashboard(data) {
|
| 122 |
const syncStatus = String(data.backup?.status || "unknown").toUpperCase();
|
| 123 |
+
const dashboardLink = data.dashboard ? `<a class="button" href="${APP_BASE}/">Open Hermes App</a>` : "";
|
| 124 |
const apiLink = data.gateway ? `<a class="button secondary" href="/v1/models">API Models</a>` : "";
|
| 125 |
const keepAlive = data.uptimerobot?.configured
|
| 126 |
? `UptimeRobot is monitoring <code>${data.uptimerobot.url}</code>.`
|
|
|
|
| 184 |
const parsed = new URL(req.url, "http://localhost");
|
| 185 |
const path = parsed.pathname;
|
| 186 |
|
| 187 |
+
if (path === "/health" || path === `${APP_BASE}/health`) {
|
| 188 |
const data = await statusPayload();
|
| 189 |
res.writeHead(data.ok ? 200 : 503, { "content-type": "application/json" });
|
| 190 |
res.end(JSON.stringify({ ok: data.ok, gateway: data.gateway, uptime: data.uptime }));
|
| 191 |
return;
|
| 192 |
}
|
| 193 |
|
| 194 |
+
if (path === "/status" || path === `${APP_BASE}/status`) {
|
| 195 |
const data = await statusPayload();
|
| 196 |
res.writeHead(200, { "content-type": "application/json" });
|
| 197 |
res.end(JSON.stringify(data, null, 2));
|
| 198 |
return;
|
| 199 |
}
|
| 200 |
|
| 201 |
+
if (path === "/") {
|
| 202 |
const data = await statusPayload();
|
| 203 |
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
| 204 |
res.end(renderDashboard(data));
|
| 205 |
return;
|
| 206 |
}
|
| 207 |
|
| 208 |
+
if (path === "/dashboard" || path === "/dashboard/") {
|
| 209 |
+
redirect(res, `${APP_BASE}/${parsed.search}`);
|
| 210 |
+
return;
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
if (path === "/telegram" || path.startsWith("/telegram/")) {
|
| 214 |
proxyRequest(req, res, TELEGRAM_WEBHOOK_PORT);
|
| 215 |
return;
|
| 216 |
}
|
| 217 |
|
| 218 |
+
if (path === APP_BASE || path.startsWith(`${APP_BASE}/`)) {
|
| 219 |
+
proxyRequest(req, res, DASHBOARD_PORT, (p) => p.replace(/^\/app/, "") || "/");
|
| 220 |
+
return;
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
if (
|
| 224 |
+
path === "/favicon.ico" ||
|
| 225 |
+
path.startsWith("/assets/") ||
|
| 226 |
+
path.startsWith("/api/") ||
|
| 227 |
+
path.startsWith("/dashboard-plugins/") ||
|
| 228 |
+
path.startsWith("/ds-assets/")
|
| 229 |
+
) {
|
| 230 |
+
proxyRequest(req, res, DASHBOARD_PORT);
|
| 231 |
+
return;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
if (
|
| 235 |
+
[
|
| 236 |
+
"/analytics",
|
| 237 |
+
"/chat",
|
| 238 |
+
"/config",
|
| 239 |
+
"/cron",
|
| 240 |
+
"/docs",
|
| 241 |
+
"/env",
|
| 242 |
+
"/logs",
|
| 243 |
+
"/models",
|
| 244 |
+
"/plugins",
|
| 245 |
+
"/profiles",
|
| 246 |
+
"/sessions",
|
| 247 |
+
"/skills",
|
| 248 |
+
].some((route) => path === route || path.startsWith(`${route}/`))
|
| 249 |
+
) {
|
| 250 |
+
redirect(res, `${APP_BASE}${path}${parsed.search}`);
|
| 251 |
return;
|
| 252 |
}
|
| 253 |
|