ellm-proxy 0.0.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +48 -17
- package/dist/server.js +58 -33
- package/dist/web-ui/assets/DashboardView-BTtCBA4g.css +1 -0
- package/dist/web-ui/assets/DashboardView-BWPFis7P.js +1 -0
- package/dist/web-ui/assets/LayoutView-BkUJgLW2.js +1 -0
- package/dist/web-ui/assets/LoginView-C8E6nJw2.js +1 -0
- package/dist/web-ui/assets/{LogsView-2h2Y0XE8.js → LogsView-CtRfyOCZ.js} +1 -1
- package/dist/web-ui/assets/{ProvidersView-bE1Hv9D-.js → ProvidersView-B6fm2FPQ.js} +1 -1
- package/dist/web-ui/assets/SettingsView-BHuXlGS1.js +1 -0
- package/dist/web-ui/assets/SetupView-BkBbUyaW.css +1 -0
- package/dist/web-ui/assets/SetupView-Oau3EJgh.js +1 -0
- package/dist/web-ui/assets/{config-nvSp8hHp.js → config-CHaFDQC7.js} +1 -1
- package/dist/web-ui/assets/{index-sPrBBnf5.js → index-BmtcBnoW.js} +18 -18
- package/dist/web-ui/assets/{providers-di7L8jy_.js → providers-Aw7T7j0r.js} +1 -1
- package/dist/web-ui/assets/useManagerApi-PldAaNYo.js +1 -0
- package/dist/web-ui/assets/useToast-C9BTyaBD.js +1 -0
- package/dist/web-ui/index.html +1 -1
- package/package.json +1 -1
- package/dist/web-ui/assets/DashboardView-3c_i_3VF.js +0 -1
- package/dist/web-ui/assets/DashboardView-BHG4xIdN.css +0 -1
- package/dist/web-ui/assets/LayoutView-BhN1f8wo.js +0 -1
- package/dist/web-ui/assets/LoginView-J23vsMu2.js +0 -1
- package/dist/web-ui/assets/ProcessView-Bn8Ph7rh.css +0 -1
- package/dist/web-ui/assets/ProcessView-Bs2k6aAf.js +0 -1
- package/dist/web-ui/assets/SettingsView-BmLmC-_v.js +0 -1
- package/dist/web-ui/assets/SetupView-Cgj7ubNz.js +0 -1
- package/dist/web-ui/assets/SetupView-kPJXJ7dX.css +0 -1
- package/dist/web-ui/assets/useManagerApi-qPjxfB0X.js +0 -1
- package/dist/web-ui/assets/useToast-D76qyWZg.js +0 -1
package/dist/cli.js
CHANGED
|
@@ -35167,6 +35167,7 @@ import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as rea
|
|
|
35167
35167
|
import { spawn as spawn3 } from "node:child_process";
|
|
35168
35168
|
import { homedir as homedir2, platform as platform8 } from "node:os";
|
|
35169
35169
|
import { join as join6 } from "node:path";
|
|
35170
|
+
var AUTOSTART_VBS = "ellm-proxy-autostart.vbs";
|
|
35170
35171
|
var AUTOSTART_CMD = "ellm-proxy-autostart.cmd";
|
|
35171
35172
|
var PLIST_LABEL = "com.ellm-proxy.autostart";
|
|
35172
35173
|
var LINUX_UNIT = "ellm-proxy.service";
|
|
@@ -35200,7 +35201,7 @@ function runExit(cmd, args) {
|
|
|
35200
35201
|
function platformItemPath() {
|
|
35201
35202
|
switch (platform8()) {
|
|
35202
35203
|
case "win32":
|
|
35203
|
-
return join6(windowsStartupDir(),
|
|
35204
|
+
return join6(windowsStartupDir(), AUTOSTART_VBS);
|
|
35204
35205
|
case "darwin":
|
|
35205
35206
|
return join6(homedir2(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
35206
35207
|
case "linux":
|
|
@@ -35210,15 +35211,24 @@ function platformItemPath() {
|
|
|
35210
35211
|
}
|
|
35211
35212
|
}
|
|
35212
35213
|
function windowsBody(nodePath, target) {
|
|
35214
|
+
const logPath = join6(target.appDir, "logs", "autostart.log");
|
|
35213
35215
|
const lines = [
|
|
35214
35216
|
"@echo off",
|
|
35215
35217
|
`rem Auto-generated by "ellm-proxy autostart on" (${MARKER}). Disable with "ellm-proxy autostart off".`,
|
|
35216
35218
|
...Object.entries(target.env).map(([k, v]) => `set "${k}=${v}"`),
|
|
35217
|
-
|
|
35219
|
+
`>> "${logPath}" echo [%date% %time%] autostart launching.`,
|
|
35220
|
+
`"${nodePath}" "${target.serverJs}" >> "${logPath}" 2>&1`,
|
|
35218
35221
|
""
|
|
35219
35222
|
];
|
|
35220
35223
|
return lines.join("\r\n");
|
|
35221
35224
|
}
|
|
35225
|
+
function windowsVbsBody(cmdPath) {
|
|
35226
|
+
return [
|
|
35227
|
+
`' Auto-generated by "ellm-proxy autostart on" (${MARKER}). Disable with "ellm-proxy autostart off".`,
|
|
35228
|
+
`CreateObject("WScript.Shell").Run """${cmdPath}""", 0, False`,
|
|
35229
|
+
""
|
|
35230
|
+
].join("\r\n");
|
|
35231
|
+
}
|
|
35222
35232
|
function darwinBody(nodePath, target) {
|
|
35223
35233
|
const logPath = join6(target.appDir, "logs", "autostart.log");
|
|
35224
35234
|
const envEntries = Object.entries(target.env).map(([k, v]) => ` <string>${k}</string>
|
|
@@ -35267,9 +35277,13 @@ function linuxBody(nodePath, target) {
|
|
|
35267
35277
|
].join("\n");
|
|
35268
35278
|
}
|
|
35269
35279
|
async function windowsOn(nodePath, target) {
|
|
35270
|
-
const
|
|
35271
|
-
|
|
35272
|
-
|
|
35280
|
+
const startupDir = windowsStartupDir();
|
|
35281
|
+
mkdirSync3(join6(target.appDir, "logs"), { recursive: true });
|
|
35282
|
+
const cmdPath = join6(target.appDir, AUTOSTART_CMD);
|
|
35283
|
+
writeFileSync3(cmdPath, windowsBody(nodePath, target), "utf-8");
|
|
35284
|
+
writeFileSync3(join6(startupDir, AUTOSTART_VBS), `\uFEFF${windowsVbsBody(cmdPath)}`, "utf16le");
|
|
35285
|
+
rmSync2(join6(startupDir, AUTOSTART_CMD), { force: true });
|
|
35286
|
+
return join6(startupDir, AUTOSTART_VBS);
|
|
35273
35287
|
}
|
|
35274
35288
|
async function darwinOn(nodePath, target) {
|
|
35275
35289
|
const itemPath = join6(homedir2(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
@@ -35301,10 +35315,13 @@ async function linuxOn(nodePath, target) {
|
|
|
35301
35315
|
return itemPath;
|
|
35302
35316
|
}
|
|
35303
35317
|
async function windowsOff() {
|
|
35304
|
-
const
|
|
35305
|
-
|
|
35306
|
-
|
|
35307
|
-
|
|
35318
|
+
const startupDir = windowsStartupDir();
|
|
35319
|
+
const vbsPath = join6(startupDir, AUTOSTART_VBS);
|
|
35320
|
+
const legacyCmd = join6(startupDir, AUTOSTART_CMD);
|
|
35321
|
+
const existed = existsSync2(vbsPath) || existsSync2(legacyCmd);
|
|
35322
|
+
rmSync2(vbsPath, { force: true });
|
|
35323
|
+
rmSync2(legacyCmd, { force: true });
|
|
35324
|
+
return existed;
|
|
35308
35325
|
}
|
|
35309
35326
|
async function darwinOff() {
|
|
35310
35327
|
const itemPath = join6(homedir2(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
@@ -35321,18 +35338,31 @@ async function linuxOff() {
|
|
|
35321
35338
|
await runExit("systemctl", ["--user", "daemon-reload"]);
|
|
35322
35339
|
return true;
|
|
35323
35340
|
}
|
|
35341
|
+
function readTextDetectingBom(path7) {
|
|
35342
|
+
const buf = readFileSync5(path7);
|
|
35343
|
+
if (buf.length >= 2 && buf[0] === 255 && buf[1] === 254) return buf.toString("utf16le").slice(1);
|
|
35344
|
+
return buf.toString("utf-8");
|
|
35345
|
+
}
|
|
35324
35346
|
function autostartStatus(appDir) {
|
|
35325
35347
|
const itemPath = platformItemPath();
|
|
35326
35348
|
let enabled = false;
|
|
35327
35349
|
let outdated = false;
|
|
35328
35350
|
if (itemPath && existsSync2(itemPath)) {
|
|
35329
35351
|
try {
|
|
35330
|
-
|
|
35331
|
-
if (content.includes(MARKER)) enabled = true;
|
|
35352
|
+
if (readTextDetectingBom(itemPath).includes(MARKER)) enabled = true;
|
|
35332
35353
|
else outdated = true;
|
|
35333
35354
|
} catch {
|
|
35334
35355
|
}
|
|
35335
35356
|
}
|
|
35357
|
+
if (platform8() === "win32" && !enabled) {
|
|
35358
|
+
const legacyCmd = join6(windowsStartupDir(), AUTOSTART_CMD);
|
|
35359
|
+
if (existsSync2(legacyCmd)) {
|
|
35360
|
+
try {
|
|
35361
|
+
if (readTextDetectingBom(legacyCmd).includes(MARKER)) outdated = true;
|
|
35362
|
+
} catch {
|
|
35363
|
+
}
|
|
35364
|
+
}
|
|
35365
|
+
}
|
|
35336
35366
|
return {
|
|
35337
35367
|
platform: platform8(),
|
|
35338
35368
|
enabled,
|
|
@@ -35370,7 +35400,7 @@ async function ensureAutostartOnStart(target) {
|
|
|
35370
35400
|
if (status.enabled) return;
|
|
35371
35401
|
if (status.optOut) return;
|
|
35372
35402
|
const { itemPath } = await enableAutostart(target);
|
|
35373
|
-
console.log(status.outdated ? `\u5DF2\u5C06\u5F00\u673A\u81EA\u542F\u9879\u8FC1\u79FB\u4E3A\
|
|
35403
|
+
console.log(status.outdated ? `\u5DF2\u5C06\u5F00\u673A\u81EA\u542F\u9879\u8FC1\u79FB\u4E3A\u65E0\u7A97\u53E3\u6A21\u5F0F: ${itemPath}` : `\u5DF2\u81EA\u52A8\u6CE8\u518C\u5F00\u673A\u81EA\u542F: ${itemPath}`);
|
|
35374
35404
|
console.log("\u7981\u7528\u65B9\u5F0F: ellm-proxy autostart off \u6216\u7BA1\u7406\u53F0\u8BBE\u7F6E\u9875\u3002");
|
|
35375
35405
|
} catch (err) {
|
|
35376
35406
|
console.warn(`\u5F00\u673A\u81EA\u542F\u6CE8\u518C\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u672C\u6B21\u542F\u52A8\uFF09: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -35678,7 +35708,7 @@ cli.command(
|
|
|
35678
35708
|
nodePath: await resolveInterpreter()
|
|
35679
35709
|
});
|
|
35680
35710
|
console.log("\u5F00\u673A\u81EA\u542F\u5DF2\u5F00\u542F\uFF08\u767B\u5F55\u65F6\u89E6\u53D1\uFF09\uFF1A");
|
|
35681
|
-
console.log(` \u81EA\u542F\u9879 : ${itemPath}\uFF08\
|
|
35711
|
+
console.log(` \u81EA\u542F\u9879 : ${itemPath}\uFF08\u767B\u5F55\u65F6\u65E0\u7A97\u53E3\u540E\u53F0\u542F\u52A8\uFF09`);
|
|
35682
35712
|
console.log(" \u7981\u7528\u65B9\u5F0F : ellm-proxy autostart off");
|
|
35683
35713
|
} else {
|
|
35684
35714
|
const { removed } = await disableAutostart({ appDir });
|
|
@@ -35728,7 +35758,7 @@ ${generated}
|
|
|
35728
35758
|
console.log(`\u914D\u7F6E\u6587\u4EF6: ${path7}\uFF08\u540E\u7AEF\u52A8\u6001\u8BFB\u53D6\uFF0C\u65E0\u9700\u91CD\u542F\u5373\u65F6\u751F\u6548\uFF09`);
|
|
35729
35759
|
})
|
|
35730
35760
|
);
|
|
35731
|
-
cli.command("account [username] [password]", "\u67E5\u770B/\u8BBE\u7F6E\u7BA1\u7406\u53F0\u767B\u5F55\u8D26\u53F7\uFF08--reset \
|
|
35761
|
+
cli.command("account [username] [password]", "\u67E5\u770B/\u8BBE\u7F6E\u7BA1\u7406\u53F0\u767B\u5F55\u8D26\u53F7\uFF08--reset \u6E05\u9664\u8D26\u53F7\u8F6C\u4E3A\u514D\u767B\u5F55\uFF1B\u6539\u540E\u65E7\u767B\u5F55\u6001\u7ACB\u5373\u5931\u6548\uFF09").option("--reset", "\u6E05\u9664\u8D26\u53F7\uFF1A\u7BA1\u7406\u53F0\u514D\u767B\u5F55\u8BBF\u95EE\uFF08\u5982\u9700\u91CD\u65B0\u542F\u7528\u767B\u5F55\uFF0C\u518D\u6267\u884C account <\u7528\u6237\u540D> <\u5BC6\u7801>\uFF09").option("--config <path>", "\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4 ~/.ellm-proxy/ellm.config.json\uFF09").action(
|
|
35732
35762
|
(username, password, opts) => run(() => {
|
|
35733
35763
|
ensureConfig(opts.config);
|
|
35734
35764
|
const path7 = configPath(opts.config);
|
|
@@ -35737,7 +35767,7 @@ cli.command("account [username] [password]", "\u67E5\u770B/\u8BBE\u7F6E\u7BA1\u7
|
|
|
35737
35767
|
const webUi = typeof config["web-ui"] === "object" && config["web-ui"] !== null ? config["web-ui"] : {};
|
|
35738
35768
|
if (opts.reset) {
|
|
35739
35769
|
saveConfig({ ...config, "web-ui": { ...webUi, "login-account": {} } });
|
|
35740
|
-
console.log("\u5DF2\
|
|
35770
|
+
console.log("\u5DF2\u6E05\u9664\u8D26\u53F7\uFF1A\u7BA1\u7406\u53F0\u514D\u767B\u5F55\u8BBF\u95EE\uFF08\u65E7\u767B\u5F55 token \u7ACB\u5373\u5931\u6548\uFF09\u3002");
|
|
35741
35771
|
} else if (username && password) {
|
|
35742
35772
|
const name = String(username).trim();
|
|
35743
35773
|
const pass = String(password);
|
|
@@ -35749,12 +35779,13 @@ cli.command("account [username] [password]", "\u67E5\u770B/\u8BBE\u7F6E\u7BA1\u7
|
|
|
35749
35779
|
const account = webUi["login-account"] ?? {};
|
|
35750
35780
|
const name = typeof account.username === "string" && account.username.trim() !== "" ? account.username.trim() : "";
|
|
35751
35781
|
if (name === "") {
|
|
35752
|
-
console.log("\u5F53\u524D\u672A\
|
|
35782
|
+
console.log("\u5F53\u524D\u672A\u8BBE\u7F6E\u8D26\u53F7\uFF1A\u7BA1\u7406\u53F0\u514D\u767B\u5F55\u8BBF\u95EE\uFF08\u7EAF\u672C\u673A\u4F7F\u7528\uFF09\u3002");
|
|
35783
|
+
console.log("\u542F\u7528\u767B\u5F55\uFF1Aellm-proxy account <username> <password>\uFF0C\u6216\u8BBE\u7F6E WEBUI_USERNAME/WEBUI_PASSWORD \u73AF\u5883\u53D8\u91CF\u3002");
|
|
35753
35784
|
} else {
|
|
35754
35785
|
console.log(`\u5F53\u524D\u8D26\u53F7: ${name}`);
|
|
35755
35786
|
console.log(`\u5F53\u524D\u5BC6\u7801: ${String(account.password)}`);
|
|
35756
35787
|
}
|
|
35757
|
-
console.log("\
|
|
35788
|
+
console.log("\u6E05\u9664\u8D26\u53F7\uFF08\u8F6C\u514D\u767B\u5F55\uFF09\uFF1Aellm-proxy account --reset");
|
|
35758
35789
|
}
|
|
35759
35790
|
console.log(`\u914D\u7F6E\u6587\u4EF6: ${path7}\uFF08\u540E\u7AEF\u52A8\u6001\u8BFB\u53D6\uFF0C\u65E0\u9700\u91CD\u542F\u5373\u65F6\u751F\u6548\uFF09`);
|
|
35760
35791
|
})
|
package/dist/server.js
CHANGED
|
@@ -18946,9 +18946,15 @@ function resolveLoginAccount() {
|
|
|
18946
18946
|
}
|
|
18947
18947
|
const fileUsername = typeof account?.username === "string" && account.username.trim() !== "" ? account.username.trim() : void 0;
|
|
18948
18948
|
const filePassword = typeof account?.password === "string" && account.password !== "" ? account.password : void 0;
|
|
18949
|
-
|
|
18950
|
-
|
|
18951
|
-
|
|
18949
|
+
if (fileUsername !== void 0 && filePassword !== void 0) {
|
|
18950
|
+
return { required: true, username: fileUsername, password: filePassword };
|
|
18951
|
+
}
|
|
18952
|
+
const envUsername = process.env["WEBUI_USERNAME"];
|
|
18953
|
+
const envPassword = process.env["WEBUI_PASSWORD"];
|
|
18954
|
+
if (envUsername && envPassword) {
|
|
18955
|
+
return { required: true, username: envUsername, password: envPassword };
|
|
18956
|
+
}
|
|
18957
|
+
return { required: false, username: "", password: "" };
|
|
18952
18958
|
}
|
|
18953
18959
|
function resolveSetupState() {
|
|
18954
18960
|
let setup;
|
|
@@ -19734,8 +19740,11 @@ function tokenOf(account) {
|
|
|
19734
19740
|
return Buffer.from(`${account.username}:${account.password}`).toString("base64");
|
|
19735
19741
|
}
|
|
19736
19742
|
app.post("/login", async (c) => {
|
|
19737
|
-
const { username, password } = await c.req.json();
|
|
19738
19743
|
const account = resolveLoginAccount();
|
|
19744
|
+
if (!account.required) {
|
|
19745
|
+
return c.json({ error: "\u5F53\u524D\u672A\u8BBE\u7F6E\u767B\u5F55\u8D26\u53F7\uFF0C\u7BA1\u7406\u53F0\u514D\u767B\u5F55\u8BBF\u95EE\uFF08\u5982\u9700\u542F\u7528\u8BF7\u5148\u8BBE\u7F6E\u8D26\u53F7\uFF09" }, 400);
|
|
19746
|
+
}
|
|
19747
|
+
const { username, password } = await c.req.json();
|
|
19739
19748
|
if ((username ?? "").trim() !== account.username || password !== account.password) {
|
|
19740
19749
|
return c.json({ error: "\u7528\u6237\u540D\u6216\u5BC6\u7801\u9519\u8BEF" }, 401);
|
|
19741
19750
|
}
|
|
@@ -19743,6 +19752,7 @@ app.post("/login", async (c) => {
|
|
|
19743
19752
|
});
|
|
19744
19753
|
async function authMiddleware(c, next) {
|
|
19745
19754
|
if (c.req.path === "/api/auth/login") return await next();
|
|
19755
|
+
if (!resolveLoginAccount().required) return await next();
|
|
19746
19756
|
const authHeader = c.req.header("Authorization");
|
|
19747
19757
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
19748
19758
|
return c.json({ error: "\u672A\u767B\u5F55" }, 401);
|
|
@@ -19765,7 +19775,8 @@ function createSetupApp() {
|
|
|
19765
19775
|
return c.json({
|
|
19766
19776
|
initialized: state.completed,
|
|
19767
19777
|
deployment: state.deployment,
|
|
19768
|
-
masterKeySet: resolveMasterKey() !== ""
|
|
19778
|
+
masterKeySet: resolveMasterKey() !== "",
|
|
19779
|
+
authRequired: resolveLoginAccount().required
|
|
19769
19780
|
});
|
|
19770
19781
|
});
|
|
19771
19782
|
app3.post("/master-key", async (c) => {
|
|
@@ -20563,22 +20574,6 @@ function createServiceRoutes(ctx) {
|
|
|
20563
20574
|
]
|
|
20564
20575
|
});
|
|
20565
20576
|
});
|
|
20566
|
-
app3.post(
|
|
20567
|
-
"/start",
|
|
20568
|
-
authMiddleware,
|
|
20569
|
-
(c) => c.json({ ok: true, action: "start", note: "\u670D\u52A1\u5DF2\u5728\u8FD0\u884C\uFF08\u80FD\u6536\u5230\u672C\u8BF7\u6C42\u5373\u5DF2\u542F\u52A8\uFF09" })
|
|
20570
|
-
);
|
|
20571
|
-
app3.post("/stop", authMiddleware, (c) => {
|
|
20572
|
-
setTimeout(() => {
|
|
20573
|
-
clearRunInfo(ctx.appDir);
|
|
20574
|
-
process.exit(0);
|
|
20575
|
-
}, 300);
|
|
20576
|
-
return c.json({ ok: true, action: "stop", note: "\u670D\u52A1\u5373\u5C06\u505C\u6B62\uFF08\u91CD\u542F\u8BF7\u7528\u91CD\u542F\u6309\u94AE\u6216 ellm-proxy start\uFF09" });
|
|
20577
|
-
});
|
|
20578
|
-
app3.post("/restart", authMiddleware, (c) => {
|
|
20579
|
-
setTimeout(() => selfRespawn({ serverJs: ctx.serverJs, appDir: ctx.appDir }), 300);
|
|
20580
|
-
return c.json({ ok: true, action: "restart", note: "\u91CD\u542F\u4E2D\uFF0C\u754C\u9762\u5C06\u5728\u6570\u79D2\u540E\u6062\u590D" });
|
|
20581
|
-
});
|
|
20582
20577
|
app3.get("/runinfo", authMiddleware, (c) => {
|
|
20583
20578
|
const info = readRunInfo(ctx.appDir);
|
|
20584
20579
|
return c.json({ ok: true, runInfo: info });
|
|
@@ -20591,6 +20586,7 @@ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as rea
|
|
|
20591
20586
|
import { spawn as spawn2 } from "node:child_process";
|
|
20592
20587
|
import { homedir, platform } from "node:os";
|
|
20593
20588
|
import { join as join5 } from "node:path";
|
|
20589
|
+
var AUTOSTART_VBS = "ellm-proxy-autostart.vbs";
|
|
20594
20590
|
var AUTOSTART_CMD = "ellm-proxy-autostart.cmd";
|
|
20595
20591
|
var PLIST_LABEL = "com.ellm-proxy.autostart";
|
|
20596
20592
|
var LINUX_UNIT = "ellm-proxy.service";
|
|
@@ -20624,7 +20620,7 @@ function runExit(cmd, args) {
|
|
|
20624
20620
|
function platformItemPath() {
|
|
20625
20621
|
switch (platform()) {
|
|
20626
20622
|
case "win32":
|
|
20627
|
-
return join5(windowsStartupDir(),
|
|
20623
|
+
return join5(windowsStartupDir(), AUTOSTART_VBS);
|
|
20628
20624
|
case "darwin":
|
|
20629
20625
|
return join5(homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
20630
20626
|
case "linux":
|
|
@@ -20634,15 +20630,24 @@ function platformItemPath() {
|
|
|
20634
20630
|
}
|
|
20635
20631
|
}
|
|
20636
20632
|
function windowsBody(nodePath, target) {
|
|
20633
|
+
const logPath = join5(target.appDir, "logs", "autostart.log");
|
|
20637
20634
|
const lines = [
|
|
20638
20635
|
"@echo off",
|
|
20639
20636
|
`rem Auto-generated by "ellm-proxy autostart on" (${MARKER}). Disable with "ellm-proxy autostart off".`,
|
|
20640
20637
|
...Object.entries(target.env).map(([k, v]) => `set "${k}=${v}"`),
|
|
20641
|
-
|
|
20638
|
+
`>> "${logPath}" echo [%date% %time%] autostart launching.`,
|
|
20639
|
+
`"${nodePath}" "${target.serverJs}" >> "${logPath}" 2>&1`,
|
|
20642
20640
|
""
|
|
20643
20641
|
];
|
|
20644
20642
|
return lines.join("\r\n");
|
|
20645
20643
|
}
|
|
20644
|
+
function windowsVbsBody(cmdPath) {
|
|
20645
|
+
return [
|
|
20646
|
+
`' Auto-generated by "ellm-proxy autostart on" (${MARKER}). Disable with "ellm-proxy autostart off".`,
|
|
20647
|
+
`CreateObject("WScript.Shell").Run """${cmdPath}""", 0, False`,
|
|
20648
|
+
""
|
|
20649
|
+
].join("\r\n");
|
|
20650
|
+
}
|
|
20646
20651
|
function darwinBody(nodePath, target) {
|
|
20647
20652
|
const logPath = join5(target.appDir, "logs", "autostart.log");
|
|
20648
20653
|
const envEntries = Object.entries(target.env).map(([k, v]) => ` <string>${k}</string>
|
|
@@ -20691,9 +20696,13 @@ function linuxBody(nodePath, target) {
|
|
|
20691
20696
|
].join("\n");
|
|
20692
20697
|
}
|
|
20693
20698
|
async function windowsOn(nodePath, target) {
|
|
20694
|
-
const
|
|
20695
|
-
|
|
20696
|
-
|
|
20699
|
+
const startupDir = windowsStartupDir();
|
|
20700
|
+
mkdirSync4(join5(target.appDir, "logs"), { recursive: true });
|
|
20701
|
+
const cmdPath = join5(target.appDir, AUTOSTART_CMD);
|
|
20702
|
+
writeFileSync5(cmdPath, windowsBody(nodePath, target), "utf-8");
|
|
20703
|
+
writeFileSync5(join5(startupDir, AUTOSTART_VBS), `\uFEFF${windowsVbsBody(cmdPath)}`, "utf16le");
|
|
20704
|
+
rmSync2(join5(startupDir, AUTOSTART_CMD), { force: true });
|
|
20705
|
+
return join5(startupDir, AUTOSTART_VBS);
|
|
20697
20706
|
}
|
|
20698
20707
|
async function darwinOn(nodePath, target) {
|
|
20699
20708
|
const itemPath = join5(homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
@@ -20725,10 +20734,13 @@ async function linuxOn(nodePath, target) {
|
|
|
20725
20734
|
return itemPath;
|
|
20726
20735
|
}
|
|
20727
20736
|
async function windowsOff() {
|
|
20728
|
-
const
|
|
20729
|
-
|
|
20730
|
-
|
|
20731
|
-
|
|
20737
|
+
const startupDir = windowsStartupDir();
|
|
20738
|
+
const vbsPath = join5(startupDir, AUTOSTART_VBS);
|
|
20739
|
+
const legacyCmd = join5(startupDir, AUTOSTART_CMD);
|
|
20740
|
+
const existed = existsSync7(vbsPath) || existsSync7(legacyCmd);
|
|
20741
|
+
rmSync2(vbsPath, { force: true });
|
|
20742
|
+
rmSync2(legacyCmd, { force: true });
|
|
20743
|
+
return existed;
|
|
20732
20744
|
}
|
|
20733
20745
|
async function darwinOff() {
|
|
20734
20746
|
const itemPath = join5(homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
@@ -20745,18 +20757,31 @@ async function linuxOff() {
|
|
|
20745
20757
|
await runExit("systemctl", ["--user", "daemon-reload"]);
|
|
20746
20758
|
return true;
|
|
20747
20759
|
}
|
|
20760
|
+
function readTextDetectingBom(path) {
|
|
20761
|
+
const buf = readFileSync6(path);
|
|
20762
|
+
if (buf.length >= 2 && buf[0] === 255 && buf[1] === 254) return buf.toString("utf16le").slice(1);
|
|
20763
|
+
return buf.toString("utf-8");
|
|
20764
|
+
}
|
|
20748
20765
|
function autostartStatus(appDir) {
|
|
20749
20766
|
const itemPath = platformItemPath();
|
|
20750
20767
|
let enabled = false;
|
|
20751
20768
|
let outdated = false;
|
|
20752
20769
|
if (itemPath && existsSync7(itemPath)) {
|
|
20753
20770
|
try {
|
|
20754
|
-
|
|
20755
|
-
if (content.includes(MARKER)) enabled = true;
|
|
20771
|
+
if (readTextDetectingBom(itemPath).includes(MARKER)) enabled = true;
|
|
20756
20772
|
else outdated = true;
|
|
20757
20773
|
} catch {
|
|
20758
20774
|
}
|
|
20759
20775
|
}
|
|
20776
|
+
if (platform() === "win32" && !enabled) {
|
|
20777
|
+
const legacyCmd = join5(windowsStartupDir(), AUTOSTART_CMD);
|
|
20778
|
+
if (existsSync7(legacyCmd)) {
|
|
20779
|
+
try {
|
|
20780
|
+
if (readTextDetectingBom(legacyCmd).includes(MARKER)) outdated = true;
|
|
20781
|
+
} catch {
|
|
20782
|
+
}
|
|
20783
|
+
}
|
|
20784
|
+
}
|
|
20760
20785
|
return {
|
|
20761
20786
|
platform: platform(),
|
|
20762
20787
|
enabled,
|
|
@@ -22403,7 +22428,7 @@ function createApp(runtime2, admin) {
|
|
|
22403
22428
|
(c) => c.json(
|
|
22404
22429
|
{
|
|
22405
22430
|
ok: false,
|
|
22406
|
-
error: `\u672A\u77E5\u63A5\u53E3: ${c.req.method} ${c.req.path}\uFF08\u53EF\u7528: GET /\uFF08\u7BA1\u7406\u754C\u9762\uFF09, /v1/*\uFF08\u7F51\u5173\uFF09, /api/*\uFF08\u7BA1\u7406\u53F0\uFF09, GET /status, GET /processes,
|
|
22431
|
+
error: `\u672A\u77E5\u63A5\u53E3: ${c.req.method} ${c.req.path}\uFF08\u53EF\u7528: GET /\uFF08\u7BA1\u7406\u754C\u9762\uFF09, /v1/*\uFF08\u7F51\u5173\uFF09, /api/*\uFF08\u7BA1\u7406\u53F0\uFF09, GET /status, GET /processes, GET|POST /autostart, GET /update, POST /update/enabled|check|apply, GET /harness, POST /harness/claude-code|codex|dsh\uFF09`
|
|
22407
22432
|
},
|
|
22408
22433
|
404
|
|
22409
22434
|
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.copy-text[data-v-ff795a0a]{color:#409eff;cursor:pointer}.copy-text[data-v-ff795a0a]:hover{text-decoration:underline}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{d as te,k as ae,q as le,e as w,g as o,w as s,c as S,i as U,r as p,A as V,a as m,j as oe,o as c,b as se,t as r,f as l,h as _,F as ne,v as ue,m as $,_ as re}from"./index-BmtcBnoW.js";import{m as de}from"./useManagerApi-PldAaNYo.js";import{u as ie}from"./providers-Aw7T7j0r.js";import{u as ce}from"./useToast-C9BTyaBD.js";import"./config-CHaFDQC7.js";const ve={class:"flex-col-gap"},pe=["onClick"],me={key:1},_e={class:"flex-between"},ge={class:"flex-gap-8"},fe={class:"usage-grid"},he={class:"usage-cell"},ye={class:"usage-num orange"},we={class:"usage-cell"},be={class:"usage-num blue"},ke={class:"usage-cell"},De={class:"usage-num green"},xe={class:"usage-cell"},Ce={class:"usage-num purple"},Me={class:"usage-cell"},Se={class:"usage-num purple"},Ve={key:0,class:"usage-cell"},Pe={class:"usage-num gray"},$e={key:0},Te=["onClick"],Ae=te({__name:"DashboardView",setup(Be){const D=ie(),{toast:P}=ce(),d=p(null),b=p(!0),x=p(""),v=p(null),k=p("today"),C=t=>{const e=t.getFullYear(),a=String(t.getMonth()+1).padStart(2,"0"),i=String(t.getDate()).padStart(2,"0");return`${e}-${a}-${i}`},R=t=>{const e=new Date;let a,i=e;if(t==="today")a=e;else if(t==="yesterday")a=new Date(e),a.setDate(e.getDate()-1),i=a;else if(t==="beforeYesterday")a=new Date(e),a.setDate(e.getDate()-2),i=a;else if(t==="last3days")a=new Date(e),a.setDate(e.getDate()-2);else if(t==="week"){a=new Date(e);const f=(e.getDay()+6)%7;a.setDate(e.getDate()-f)}else if(t==="month")a=new Date(e.getFullYear(),e.getMonth(),1);else return;k.value=t,v.value=[C(a),C(i)],y()},K=t=>{t?R(t):(k.value="",v.value=null,y())},L=()=>{k.value="",y()},j=$(()=>{var e;const t=new Set;for(const a of D.suppliers)for(const i of a.models)t.add(i.modelName);if((e=d.value)!=null&&e.models)for(const a of d.value.models)t.add(a.model);return[...t].sort()}),y=async()=>{var t;b.value=!0;try{const e=new URLSearchParams;x.value&&e.set("model",x.value),((t=v.value)==null?void 0:t.length)===2&&(e.set("startDate",v.value[0]),e.set("endDate",v.value[1]));const a=e.toString();d.value=await V.get(`/api/usage${a?`?${a}`:""}`)}catch(e){console.error(e)}finally{b.value=!1}},q=async()=>{var t;try{const[e]=await Promise.all([V.get("/api/usage"),D.loadProviders(),V.get("/api/status").then(a=>M.value=a.listenPort).catch(()=>M.value)]);if(d.value=e,!((t=v.value)!=null&&t.length)){const a=new Date;v.value=[C(a),C(a)],await y()}}catch(e){console.error(e)}finally{b.value=!1}},E=window.location.hostname,M=p(Number(window.location.port)||null),O=$(()=>`http://${E}${M.value?`:${M.value}`:""}`),T=p(null),A=p(null),B=p(Date.now()),I=async()=>{try{const[t,e]=await Promise.all([de.processes(),V.get("/api/config").catch(()=>null)]);T.value=t[0]??null,A.value=(e==null?void 0:e.masterKey)??"",B.value=Date.now()}catch{}},z=t=>{if(!t.startedAt)return"-";let e=Math.max(0,Math.floor((B.value-t.startedAt)/1e3));const a=Math.floor(e/86400);e-=a*86400;const i=Math.floor(e/3600);e-=i*3600;const f=Math.floor(e/60);return e-=f*60,[a?`${a}天`:"",i?`${i}时`:"",f?`${f}分`:"",`${e}秒`].filter(Boolean).join(" ")},G=t=>t?t>=1024**3?(t/1024**3).toFixed(1)+"G":t>=1024**2?(t/1024**2).toFixed(1)+"M":Math.round(t/1024)+"K":"-",H=$(()=>{const t=[{key:"API 地址",value:O.value},{key:"API 密钥",value:A.value||"未设置(/v1 免鉴权)"},{key:"供应商数量",value:String(D.providerCount)},{key:"模型总数",value:String(D.totalModelCount)}],e=T.value;return e&&t.push({key:"运行状态",value:e.status==="online"?"运行中":e.status==="errored"?"异常":"已停止"},{key:"PID",value:String(e.pid??"-")},{key:"运行时长",value:z(e)},{key:"内存占用",value:G(e.memory)}),t});let Y;const g=t=>t.toLocaleString(),J=t=>t==null||t<=0?"-":t>=1e3?(t/1e3).toFixed(2)+"s":Math.round(t)+"ms",F=async t=>{try{await navigator.clipboard.writeText(t),P("已复制到剪贴板","success")}catch{const e=document.createElement("textarea");e.value=t,e.style.position="fixed",e.style.opacity="0",document.body.appendChild(e),e.select();try{document.execCommand("copy"),P("已复制到剪贴板","success")}catch{P("复制失败","error")}document.body.removeChild(e)}};return ae(()=>{q(),I(),Y=window.setInterval(I,1e4)}),le(()=>window.clearInterval(Y)),(t,e)=>{const a=m("el-table-column"),i=m("el-table"),f=m("el-card"),h=m("el-option"),N=m("el-select"),Q=m("el-date-picker"),W=m("el-button"),X=m("el-tag"),Z=m("el-empty"),ee=oe("loading");return c(),w("div",ve,[o(f,{shadow:"never"},{header:s(()=>[...e[3]||(e[3]=[l("span",{class:"fw-600"},"服务信息",-1)])]),default:s(()=>[se((c(),S(i,{border:"",data:H.value,"show-header":!1,class:"full-width"},{default:s(()=>[o(a,{prop:"key",width:"160"}),o(a,null,{default:s(({row:n})=>[n.key==="API 地址"||n.key==="API 密钥"?(c(),w("span",{key:0,class:"copy-text",onClick:u=>F(n.value)},r(n.value),9,pe)):(c(),w("span",me,r(n.value),1))]),_:1})]),_:1},8,["data"])),[[ee,b.value]])]),_:1}),d.value?(c(),S(f,{key:0,shadow:"never"},{header:s(()=>[l("div",_e,[e[5]||(e[5]=l("span",{class:"fw-600"},"用量统计",-1)),l("div",ge,[o(N,{modelValue:x.value,"onUpdate:modelValue":e[0]||(e[0]=n=>x.value=n),placeholder:"全部模型",clearable:"",filterable:"",style:{width:"220px"},onChange:y},{default:s(()=>[(c(!0),w(ne,null,ue(j.value,n=>(c(),S(h,{key:n,label:n,value:n},null,8,["label","value"]))),128))]),_:1},8,["modelValue"]),o(N,{modelValue:k.value,"onUpdate:modelValue":e[1]||(e[1]=n=>k.value=n),placeholder:"时间范围",clearable:"",style:{width:"130px"},onChange:K},{default:s(()=>[o(h,{label:"今天",value:"today"}),o(h,{label:"昨天",value:"yesterday"}),o(h,{label:"前天",value:"beforeYesterday"}),o(h,{label:"近三天",value:"last3days"}),o(h,{label:"本周",value:"week"}),o(h,{label:"本月",value:"month"})]),_:1},8,["modelValue"]),o(Q,{modelValue:v.value,"onUpdate:modelValue":e[2]||(e[2]=n=>v.value=n),type:"daterange","range-separator":"至","start-placeholder":"开始日期","end-placeholder":"结束日期","value-format":"YYYY-MM-DD",style:{width:"260px"},onChange:L},null,8,["modelValue"]),o(W,{loading:b.value,onClick:y},{default:s(()=>[...e[4]||(e[4]=[_("刷新",-1)])]),_:1},8,["loading"])]),o(X,{type:"info"},{default:s(()=>[_(r(d.value.total.calls)+" 次调用",1)]),_:1})])]),default:s(()=>{var n;return[l("div",fe,[l("div",he,[l("div",ye,r(g(d.value.total.total_tokens)),1),e[6]||(e[6]=l("div",{class:"usage-label"},"总 Token",-1))]),l("div",we,[l("div",be,r(g(d.value.total.input_tokens)),1),e[7]||(e[7]=l("div",{class:"usage-label"},"输入 Token",-1))]),l("div",ke,[l("div",De,r(g(d.value.total.output_tokens)),1),e[8]||(e[8]=l("div",{class:"usage-label"},"输出 Token",-1))]),l("div",xe,[l("div",Ce,r(g(d.value.total.cache_read_tokens)),1),e[9]||(e[9]=l("div",{class:"usage-label"},"缓存读取",-1))]),l("div",Me,[l("div",Se,r(d.value.total.cache_rate!=null?d.value.total.cache_rate+"%":"-"),1),e[10]||(e[10]=l("div",{class:"usage-label"},"缓存命中率",-1))]),d.value.logStorageMB!=null?(c(),w("div",Ve,[l("div",Pe,r(d.value.logStorageMB),1),e[11]||(e[11]=l("div",{class:"usage-label"},"日志占用 (MB)",-1))])):U("",!0)]),(n=d.value.models)!=null&&n.length?(c(),w("div",$e,[e[12]||(e[12]=l("div",{class:"section-title"},"模型用量",-1)),o(i,{data:d.value.models,border:"",stripe:"",class:"full-width"},{default:s(()=>[o(a,{prop:"model",label:"模型","min-width":"200"},{default:s(({row:u})=>[l("span",{class:"copy-text",onClick:Ie=>F(u.model)},r(u.model),9,Te)]),_:1}),o(a,{label:"调用次数",width:"90",align:"center"},{default:s(({row:u})=>[_(r(u.calls),1)]),_:1}),o(a,{label:"平均耗时",width:"110",align:"center"},{default:s(({row:u})=>[_(r(J(u.avg_duration)),1)]),_:1}),o(a,{label:"总 Token",width:"140",align:"center"},{default:s(({row:u})=>[_(r(g(u.total_tokens)),1)]),_:1}),o(a,{label:"输入 Token",width:"140",align:"center"},{default:s(({row:u})=>[_(r(g(u.input_tokens)),1)]),_:1}),o(a,{label:"输出 Token",width:"140",align:"center"},{default:s(({row:u})=>[_(r(g(u.output_tokens)),1)]),_:1}),o(a,{label:"缓存读取",width:"130",align:"center"},{default:s(({row:u})=>[_(r(g(u.cache_read_tokens)),1)]),_:1}),o(a,{label:"缓存命中率",width:"110",align:"center"},{default:s(({row:u})=>[_(r(u.cache_rate!=null?u.cache_rate+"%":"-"),1)]),_:1})]),_:1},8,["data"])])):(c(),S(Z,{key:1,description:"暂无调用记录","image-size":60}))]}),_:1})):U("",!0)])}}}),Ke=re(Ae,[["__scopeId","data-v-ff795a0a"]]);export{Ke as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{d as T,u as R,c as k,w as o,r as g,a as r,o as v,b as z,e as B,F,f as c,g as l,h as u,t as $,i as x,E as I,j as L,_ as W,k as q,l as j,m as A,n as O,p as G,s as H}from"./index-BmtcBnoW.js";import{m as D,w as J}from"./useManagerApi-PldAaNYo.js";import{u as K}from"./useToast-C9BTyaBD.js";const P={class:"check-body"},Q={class:"version-row"},X={class:"version-row"},Y=T({__name:"UpdateCheckDialog",props:{modelValue:{type:Boolean,default:!1},modelModifiers:{}},emits:["update:modelValue"],setup(S){const{toast:w}=K(),y=R(S,"modelValue"),p=g(!1),m=g(!1),a=g(null),f=g(null),i=g(null),h=async()=>{a.value=null,f.value=null,i.value=null,p.value=!0;try{a.value=await D.checkUpdate()}catch(e){f.value=e.message||"检查更新失败"}finally{p.value=!1}},n=async()=>{var e;if(a.value){try{await I.confirm(`确定更新到 ${a.value.latestVersion}?服务将自动重启并在启动时安装新版本(期间界面请求会短暂失败,属正常现象)。`,"更新确认",{confirmButtonText:"立即更新",cancelButtonText:"取消",type:"warning"})}catch{return}m.value=!0;try{const t=await D.update(),d=await D.applyUpdate();if(!d.updated){i.value=`已是最新版本 ${d.toVersion}`,a.value={hasUpdate:!1,currentVersion:d.toVersion,latestVersion:d.toVersion,checkedAt:Date.now()};return}i.value=`正在重启服务并安装 ${d.toVersion},请稍候(预计 1~3 分钟)...`;const s=await J({targetVersion:d.toVersion,sinceAppliedAt:((e=t.lastApply)==null?void 0:e.appliedAt)??null});s&&!s.error?(w(`已更新到 ${s.toVersion}`,"success"),i.value=`已更新 ${s.fromVersion} → ${s.toVersion}`,a.value={hasUpdate:!1,currentVersion:s.toVersion,latestVersion:s.toVersion,checkedAt:Date.now()}):s!=null&&s.error?(w(`更新失败:${s.error}`,"error"),i.value=`更新失败:${s.error}(服务已恢复旧版本)`):i.value="更新耗时较长,请稍后刷新页面查看结果"}catch(t){w(t.message||"更新失败","error")}finally{m.value=!1}}};return(e,t)=>{const d=r("el-tag"),s=r("el-alert"),V=r("el-button"),U=r("el-empty"),b=r("el-dialog"),C=L("loading");return v(),k(b,{modelValue:y.value,"onUpdate:modelValue":t[2]||(t[2]=_=>y.value=_),title:"检查更新",width:"420px","close-on-click-modal":!m.value,onOpen:h},{footer:o(()=>{var _;return[(_=a.value)!=null&&_.hasUpdate?(v(),k(V,{key:0,type:"primary",loading:m.value,onClick:n},{default:o(()=>[u($(m.value?"更新中...":"立即更新"),1)]),_:1},8,["loading"])):x("",!0),l(V,{onClick:t[1]||(t[1]=M=>y.value=!1)},{default:o(()=>[...t[6]||(t[6]=[u("关闭",-1)])]),_:1})]}),default:o(()=>[z((v(),B("div",P,[a.value?(v(),B(F,{key:0},[c("div",Q,[t[3]||(t[3]=c("span",{class:"version-label"},"当前版本",-1)),l(d,{size:"small"},{default:o(()=>[u($(a.value.currentVersion),1)]),_:1})]),c("div",X,[t[4]||(t[4]=c("span",{class:"version-label"},"最新版本",-1)),l(d,{type:a.value.hasUpdate?"warning":"success",size:"small","disable-transitions":""},{default:o(()=>[u($(a.value.latestVersion),1)]),_:1},8,["type"])]),l(s,{title:a.value.hasUpdate?`发现新版本 ${a.value.latestVersion}`:"已是最新版本",type:a.value.hasUpdate?"warning":"success","show-icon":"",closable:!1,class:"mt-12"},null,8,["title","type"])],64)):!p.value&&f.value?(v(),k(U,{key:1,description:f.value},{default:o(()=>[l(V,{type:"primary",onClick:h},{default:o(()=>[...t[5]||(t[5]=[u("重试",-1)])]),_:1})]),_:1},8,["description"])):x("",!0)])),[[C,p.value]]),i.value?(v(),k(s,{key:0,title:i.value,type:"info","show-icon":"",class:"mt-12",onClose:t[0]||(t[0]=_=>i.value=null)},null,8,["title"])):x("",!0)]),_:1},8,["modelValue","close-on-click-modal"])}}}),Z=W(Y,[["__scopeId","data-v-eaed444e"]]),ee={class:"layout"},te={class:"header-nav"},oe={class:"header-actions"},le={class:"main"},se={class:"page"},ue=T({__name:"LayoutView",setup(S){const w=G(),y=O(),p=g(!1);q(()=>{j()});const m=A(()=>{var n;return((n=H.value)==null?void 0:n.authRequired)!==!1}),a=A(()=>{if(!m.value)return"免登录";const n=localStorage.getItem("webui_token")||"";try{return atob(n).split(":")[0]||"用户"}catch{return"用户"}}),f=A(()=>{const n=w.path;return n==="/"?"/":n.startsWith("/providers")?"/providers":n.startsWith("/settings")?"/settings":n.startsWith("/logs")?"/logs":"/"}),i=()=>{localStorage.removeItem("webui_token"),y.push("/login")},h=n=>{n==="logout"&&i(),n==="check-update"&&(p.value=!0)};return(n,e)=>{const t=r("el-menu-item"),d=r("el-menu"),s=r("ArrowDown"),V=r("el-icon"),U=r("el-button"),b=r("el-dropdown-item"),C=r("el-dropdown-menu"),_=r("el-dropdown"),M=r("el-header"),E=r("router-view");return v(),B("div",ee,[l(M,{class:"header"},{default:o(()=>[e[7]||(e[7]=c("h1",null,[c("span",null,"E"),u("LLM")],-1)),c("nav",te,[l(d,{mode:"horizontal","default-active":f.value,ellipsis:!1,router:"",class:"header-menu"},{default:o(()=>[l(t,{index:"/"},{default:o(()=>[...e[1]||(e[1]=[u("首页",-1)])]),_:1}),l(t,{index:"/providers"},{default:o(()=>[...e[2]||(e[2]=[u("供应商管理",-1)])]),_:1}),l(t,{index:"/logs"},{default:o(()=>[...e[3]||(e[3]=[u("日志",-1)])]),_:1}),l(t,{index:"/settings"},{default:o(()=>[...e[4]||(e[4]=[u("设置",-1)])]),_:1})]),_:1},8,["default-active"])]),c("div",oe,[l(_,{trigger:"click",onCommand:h,class:"ml-12"},{dropdown:o(()=>[l(C,null,{default:o(()=>[l(b,{command:"check-update"},{default:o(()=>[...e[5]||(e[5]=[u("检查更新",-1)])]),_:1}),m.value?(v(),k(b,{key:0,command:"logout",divided:""},{default:o(()=>[...e[6]||(e[6]=[u("退出",-1)])]),_:1})):x("",!0)]),_:1})]),default:o(()=>[l(U,null,{default:o(()=>[u($(a.value)+" ",1),l(V,{class:"el-icon--right"},{default:o(()=>[l(s)]),_:1})]),_:1})]),_:1})])]),_:1}),c("main",le,[c("div",se,[l(E)])]),l(Z,{modelValue:p.value,"onUpdate:modelValue":e[0]||(e[0]=N=>p.value=N)},null,8,["modelValue"])])}}});export{ue as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{d as h,e as b,g as o,w as l,a,o as _,f as k,a0 as x,a6 as f,c as C,i as L,h as B,r as i,A as N,n as I,_ as K}from"./index-BmtcBnoW.js";const A={class:"login-wrap"},E=h({__name:"LoginView",setup(M){const v=I(),n=i(""),s=i(""),t=i(""),d=i(!1);async function r(){if(!n.value){t.value="请输入用户名";return}if(!s.value){t.value="请输入密码";return}d.value=!0,t.value="";try{const u=await N.post("/api/auth/login",{username:n.value.trim(),password:s.value});localStorage.setItem("webui_token",u.token),v.push("/")}catch(u){t.value=u.message||"登录失败"}finally{d.value=!1}}return(u,e)=>{const p=a("el-input"),m=a("el-form-item"),w=a("el-alert"),g=a("el-button"),V=a("el-form"),y=a("el-card");return _(),b("div",A,[o(y,{shadow:"hover",class:"login-card"},{default:l(()=>[e[3]||(e[3]=k("h2",{class:"login-title"},"ELLM",-1)),o(V,{"label-position":"top",onSubmit:x(r,["prevent"])},{default:l(()=>[o(m,{label:"用户名"},{default:l(()=>[o(p,{modelValue:n.value,"onUpdate:modelValue":e[0]||(e[0]=c=>n.value=c),placeholder:"请输入用户名",onKeyup:f(r,["enter"])},null,8,["modelValue"])]),_:1}),o(m,{label:"密码"},{default:l(()=>[o(p,{modelValue:s.value,"onUpdate:modelValue":e[1]||(e[1]=c=>s.value=c),type:"password",placeholder:"请输入密码","show-password":"",onKeyup:f(r,["enter"])},null,8,["modelValue"])]),_:1}),t.value?(_(),C(w,{key:0,title:t.value,type:"error","show-icon":"",class:"mb-16"},null,8,["title"])):L("",!0),o(g,{type:"primary",class:"full-width",loading:d.value,onClick:r},{default:l(()=>[...e[2]||(e[2]=[B(" 登录 ",-1)])]),_:1},8,["loading"])]),_:1})]),_:1})])}}}),U=K(E,[["__scopeId","data-v-c944978e"]]);export{U as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{d as G,a as b,j as H,o as _,c as q,w as a,e as g,g as e,h as i,t as u,
|
|
1
|
+
import{d as G,a as b,j as H,o as _,c as q,w as a,e as g,g as e,h as i,t as u,a2 as m,b as Q,F as P,f as d,i as j,r as y,A,_ as X,k as pe,v as ce,a6 as _e,m as ve}from"./index-BmtcBnoW.js";import{u as me}from"./providers-Aw7T7j0r.js";import{u as Z}from"./useToast-C9BTyaBD.js";import"./config-CHaFDQC7.js";async function ee(p){try{if(navigator.clipboard&&window.isSecureContext)return await navigator.clipboard.writeText(p),!0}catch{}try{const f=document.createElement("textarea");f.value=p,f.style.position="fixed",f.style.opacity="0",document.body.appendChild(f),f.select();const k=document.execCommand("copy");return document.body.removeChild(f),k}catch{return!1}}const te=p=>{if(!p)return"-";const f=new Date(p),k=w=>String(w).padStart(2,"0");return`${f.getFullYear()}-${k(f.getMonth()+1)}-${k(f.getDate())} ${k(f.getHours())}:${k(f.getMinutes())}:${k(f.getSeconds())}`},V=p=>p?typeof p=="string"?p:JSON.stringify(p,null,2):"-",fe=p=>{if(!p)return"-";try{return JSON.stringify(JSON.parse(p),null,2)}catch{return p}},T=p=>p.toLocaleString(),le=p=>p==null||p<=0?"-":p>=1e3?(p/1e3).toFixed(2)+"s":Math.round(p)+"ms",ae=p=>{const f=p.input_tokens||0,k=p.cache_read_tokens||0;return f<=0?"-":(k/f*100).toFixed(1)+"%"},be={key:0,class:"detail-content"},ge={key:0,class:"ip-link"},ye={class:"ip-pop"},ke={class:"ip-pop-row"},he={key:0,class:"ip-pop-row"},xe={key:1,class:"ip-pop-error"},we={key:2},De=["href"],Ce={key:1},$e={key:1},Ve={class:"error-text"},Se={class:"pane-bar"},Ie={class:"json-block"},qe={class:"pane-bar"},ze={class:"json-block"},Re={class:"pane-bar"},Ue={class:"json-block"},je={class:"pane-bar"},Te={class:"json-block"},Ne={class:"pane-bar"},Le={class:"json-block"},Me={class:"pane-bar"},Ye={class:"json-block"},Ee={class:"pane-bar"},Pe={class:"json-block"},Fe={class:"pane-bar"},Be={class:"json-block"},Je=G({__name:"LogDetailDialog",setup(p,{expose:f}){const{toast:k}=Z(),w=y(!1),t=y(null),S=y("info"),I=y(!1);f({open:async v=>{w.value=!0,t.value=null,S.value="info";try{const l=v.id?`?id=${v.id}`:`?_file=${encodeURIComponent(v._file)}`,c=await A.get("/api/logs/detail"+l);c&&c.detail?t.value={...c.detail,...c.meta}:t.value=c}catch(l){console.error(l)}}});const h=async v=>{await ee(v)?k("已复制到剪贴板","success"):k("复制失败","error")},N=async v=>{if(!(v._ipInfo||v._ipInfoError)){I.value=!0;try{const l=await A.get(`/api/logs/ipinfo?ip=${encodeURIComponent(v.ip)}`);l.error?v._ipInfoError=l.error:v._ipInfo=l}catch{v._ipInfoError="查询失败"}finally{I.value=!1}}},M=v=>[v.country,v.region,v.city].filter(Boolean).join(" · ")||"-";return(v,l)=>{const c=b("el-descriptions-item"),Y=b("el-tag"),F=b("el-divider"),B=b("el-popover"),J=b("el-descriptions"),E=b("el-alert"),x=b("el-tab-pane"),D=b("el-button"),K=b("el-tabs"),L=b("el-dialog"),C=H("loading");return _(),q(L,{modelValue:w.value,"onUpdate:modelValue":l[11]||(l[11]=z=>w.value=z),title:"日志详情",width:"80%",top:"5vh","destroy-on-close":""},{default:a(()=>[t.value?(_(),g("div",be,[e(K,{modelValue:S.value,"onUpdate:modelValue":l[10]||(l[10]=z=>S.value=z)},{default:a(()=>{var z,r,s;return[e(x,{label:"基本信息",name:"info"},{default:a(()=>{var n;return[e(J,{column:2,border:""},{default:a(()=>[e(c,{label:"时间"},{default:a(()=>[i(u(m(te)(t.value.time)),1)]),_:1}),e(c,{label:"模型"},{default:a(()=>[i(u(t.value.model),1)]),_:1}),e(c,{label:"方法"},{default:a(()=>[i(u(t.value.method),1)]),_:1}),e(c,{label:"路径"},{default:a(()=>[i(u(t.value.path),1)]),_:1}),e(c,{label:"状态码"},{default:a(()=>[i(u(t.value.status),1)]),_:1}),e(c,{label:"流式"},{default:a(()=>[e(Y,{type:t.value.stream?"warning":"info"},{default:a(()=>[i(u(t.value.stream?"是":"否"),1)]),_:1},8,["type"])]),_:1}),e(c,{label:"IP"},{default:a(()=>[t.value.ip?(_(),g("span",ge,[e(B,{placement:"right",width:"240",trigger:"click",onShow:l[0]||(l[0]=R=>N(t.value))},{reference:a(()=>[d("span",null,u(t.value.ip),1)]),default:a(()=>[Q((_(),g("div",ye,[t.value._ipInfo?(_(),g(P,{key:0},[d("div",ke,[l[12]||(l[12]=d("span",{class:"ip-pop-label"},"归属地",-1)),d("span",null,u(M(t.value._ipInfo)),1)]),t.value._ipInfo.isp?(_(),g("div",he,[l[13]||(l[13]=d("span",{class:"ip-pop-label"},"运营商",-1)),d("span",null,u(t.value._ipInfo.isp),1)])):j("",!0)],64)):t.value._ipInfoError?(_(),g("div",xe,u(t.value._ipInfoError),1)):(_(),g("span",we,"查询中...")),e(F,{style:{margin:"8px 0"}}),d("a",{class:"ip-pop-link",href:`https://m.ip138.com/iplookup.php?ip=${encodeURIComponent(t.value.ip)}`,target:"_blank"},"在 ip138 查看",8,De)])),[[C,I.value]])]),_:1})])):(_(),g("span",Ce,"-"))]),_:1}),e(c,{label:"Session"},{default:a(()=>[i(u(t.value.session_id||"-"),1)]),_:1}),e(c,{label:"Request ID"},{default:a(()=>[t.value.request_id?(_(),g("span",{key:0,class:"request-id",title:"点击复制(可用于关联控制台日志与检索)",onClick:l[1]||(l[1]=R=>h(t.value.request_id))},u(t.value.request_id),1)):(_(),g("span",$e,"-"))]),_:1}),e(c,{label:"输入 Token(含缓存读取)"},{default:a(()=>[i(u(m(T)(t.value.input_tokens??0)),1)]),_:1}),e(c,{label:"输出 Token"},{default:a(()=>[i(u(m(T)(t.value.output_tokens??0)),1)]),_:1}),e(c,{label:"缓存读取"},{default:a(()=>[i(u(m(T)(t.value.cache_read_tokens??0)),1)]),_:1}),e(c,{label:"请求耗时"},{default:a(()=>[i(u(m(le)(t.value.duration)),1)]),_:1}),e(c,{label:"缓存命中率"},{default:a(()=>[i(u(m(ae)(t.value)),1)]),_:1}),t.value.error?(_(),q(c,{key:0,label:"错误",span:2},{default:a(()=>[d("span",Ve,u(t.value.error),1)]),_:1})):j("",!0)]),_:1}),(n=t.value.response)!=null&&n.truncated?(_(),q(E,{key:0,class:"mt-16",type:"warning",closable:!1,title:"内容超过单请求捕获上限,已截断"})):j("",!0)]}),_:1}),(z=t.value.response)!=null&&z._capture?(_(),g(P,{key:0},[e(x,{label:"客户端请求",name:"inbound"},{default:a(()=>[d("div",Se,[e(D,{size:"small",class:"copy-btn",onClick:l[2]||(l[2]=n=>h(m(V)(t.value.response.inbound_request)))},{default:a(()=>[...l[14]||(l[14]=[i(" 复制 ",-1)])]),_:1})]),d("pre",Ie,u(m(V)(t.value.response.inbound_request)),1)]),_:1}),e(x,{label:"转发上游的请求",name:"upstreamReq"},{default:a(()=>[d("div",qe,[e(D,{size:"small",class:"copy-btn",onClick:l[3]||(l[3]=n=>h(m(V)(t.value.response.upstream_request)))},{default:a(()=>[...l[15]||(l[15]=[i(" 复制 ",-1)])]),_:1})]),d("pre",ze,u(m(V)(t.value.response.upstream_request)),1)]),_:1}),t.value.response.upstream_response_text?(_(),q(x,{key:0,label:"上游响应(原始)",name:"upstreamRes"},{default:a(()=>[d("div",Re,[e(D,{size:"small",class:"copy-btn",onClick:l[4]||(l[4]=n=>h(t.value.response.upstream_response_text))},{default:a(()=>[...l[16]||(l[16]=[i(" 复制 ",-1)])]),_:1})]),d("pre",Ue,u(m(fe)(t.value.response.upstream_response_text)),1)]),_:1})):(r=t.value.response.upstream_stream_frames)!=null&&r.length?(_(),q(x,{key:1,label:`上游响应(原始流,${t.value.response.upstream_stream_frames.length} 帧)`,name:"upstreamStream"},{default:a(()=>[d("div",je,[e(D,{size:"small",class:"copy-btn",onClick:l[5]||(l[5]=n=>h(t.value.response.upstream_stream_frames.join(`
|
|
2
2
|
|
|
3
3
|
`)))},{default:a(()=>[...l[17]||(l[17]=[i(" 复制 ",-1)])]),_:1})]),d("pre",Te,u(t.value.response.upstream_stream_frames.join(`
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{N as Kn,
|
|
1
|
+
import{N as Kn,x as Mt,y as He,z as cr,B as Lt,C as jo,D as Ts,G as ia,H as Os,I as aa,J as Is,K as Kt,L as sa,M as xi,O as Ns,P as Cs,Q as As,R as xs,S as Ps,T as Xr,U as Ds,V as Kr,W as Rs,X as Ms,Y as Ls,Z as ws,$ as gn,A as Yt,d as Jt,a as J,o as te,c as Me,w as M,f as K,t as Te,e as Be,F as Bo,v as ko,a0 as fo,a1 as Vs,a2 as q,h as ae,i as tt,g as P,a3 as Fs,m as Ht,r as Pe,_ as cn,a4 as Xo,a5 as Rt,k as la,a6 as $s,E as Ao,a7 as Us,a8 as js,a9 as Bs,aa as ks}from"./index-BmtcBnoW.js";import{u as un}from"./useToast-C9BTyaBD.js";import{u as Ko}from"./providers-Aw7T7j0r.js";import"./config-CHaFDQC7.js";var yr={exports:{}},po={exports:{}},ho={};/**
|
|
2
2
|
* @vue/compiler-core v3.5.42
|
|
3
3
|
* (c) 2018-present Yuxi (Evan) You and Vue contributors
|
|
4
4
|
* @license MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{u as Y}from"./useToast-C9BTyaBD.js";import{d as X,k as q,b as G,o as m,c as E,w as n,e as x,f as s,t as h,i as I,h as i,g as o,F as M,r,E as W,a as v,j as J,_ as Z,m as j,A as ee}from"./index-BmtcBnoW.js";import{u as te}from"./config-CHaFDQC7.js";import{m as S,w as le}from"./useManagerApi-PldAaNYo.js";const se={class:"flex-between"},ae={class:"muted-sm mb-8"},oe={class:"switch-row"},ne={class:"switch-info"},ie={class:"switch-title"},ue={class:"switch-row"},de={class:"switch-info"},re={class:"switch-title"},ce={class:"switch-row"},ve={class:"switch-info"},pe={class:"switch-title"},me=X({__name:"HarnessSwitches",setup(Q){const{toast:g}=Y(),$=r(!0),T=r(!1),p=r(null),V=r(null),u=r(null),P=r(null),w=r("success"),b=async _=>{_||(p.value?T.value=!0:$.value=!0);try{p.value=await S.harness(),V.value=null}catch(a){_||(V.value=a.message)}finally{_||($.value=!1,T.value=!1)}};q(()=>b(!1));const U={claudeCode:{label:"Claude Code",file:"~/.claude/settings.json",toggle:S.setClaudeCode},codex:{label:"Codex CLI",file:"~/.codex/config.toml",toggle:S.setCodex},dsh:{label:"DeepSeek Harness",file:"~/.dsh/settings.yaml",toggle:S.setDsh}},y=async(_,a)=>{if(!p.value||u.value)return;const C=U[_],D=a?`确定开启 ${C.label} 代理?将改写 ${C.file}(开启前自动备份,关闭时从备份还原)。`:`确定关闭 ${C.label} 代理?将从备份还原 ${C.file}(无备份时移除代理相关配置)。`;try{await W.confirm(D,a?"开启确认":"关闭确认",{confirmButtonText:a?"开启":"关闭",cancelButtonText:"取消",type:"warning"})}catch{return}u.value=_;try{const c=await C.toggle(a);P.value=c.note??null,w.value=a?"success":"info",g(a?"已开启代理":"已关闭代理","success")}catch(c){g(c.message||"操作失败","error")}finally{u.value=null,await b(!0)}};return(_,a)=>{const C=v("el-button"),D=v("el-alert"),c=v("el-tag"),t=v("el-switch"),z=v("el-divider"),R=v("el-empty"),L=v("el-card"),B=J("loading");return G((m(),E(L,{shadow:"never"},{header:n(()=>[s("div",se,[a[7]||(a[7]=s("span",{class:"fw-600"},"代理开关",-1)),o(C,{loading:T.value,onClick:a[0]||(a[0]=A=>b(!1))},{default:n(()=>[...a[6]||(a[6]=[i("刷新",-1)])]),_:1},8,["loading"])])]),default:n(()=>[p.value?(m(),x(M,{key:0},[s("div",ae," 将本机 CLI 工具的流量一键指向 ellm-proxy 网关("+h(p.value.gatewayBase)+")。 开启前自动备份原配置为 *.ellm-bak(保留最早的原始备份),关闭时从备份还原。 ",1),P.value?(m(),E(D,{key:0,title:P.value,type:w.value,"show-icon":"",class:"mb-8",onClose:a[1]||(a[1]=A=>P.value=null)},null,8,["title","type"])):I("",!0),s("div",oe,[s("div",ne,[s("div",ie,[a[8]||(a[8]=i(" Claude Code ",-1)),o(c,{type:p.value.claudeCode?"success":"info",size:"small","disable-transitions":""},{default:n(()=>[i(h(p.value.claudeCode?"已开启":"未开启"),1)]),_:1},8,["type"])]),a[9]||(a[9]=s("div",{class:"switch-desc"},[i(" 写入 "),s("code",null,"~/.claude/settings.json"),i(" 的 env.ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN, 鉴权取网关配置的 masterKey(未设置将开启失败);其余字段原样保留,重启 Claude Code 会话后生效。 ")],-1))]),o(t,{"model-value":p.value.claudeCode,loading:u.value==="claudeCode",onChange:a[2]||(a[2]=A=>y("claudeCode",!!A))},null,8,["model-value","loading"])]),o(z,{class:"switch-divider"}),s("div",ue,[s("div",de,[s("div",re,[a[10]||(a[10]=i(" Codex CLI ",-1)),o(c,{type:p.value.codex?"success":"info",size:"small","disable-transitions":""},{default:n(()=>[i(h(p.value.codex?"已开启":"未开启"),1)]),_:1},8,["type"])]),a[11]||(a[11]=s("div",{class:"switch-desc"},[i(" 写入 "),s("code",null,"~/.codex/config.toml"),i(" 的 model_provider 与 [model_providers.ellm-proxy] 段 (保留用户注释与排版);开启后需按提示设置环境变量 ELLM_PROXY_API_KEY 供 Codex 鉴权。 ")],-1))]),o(t,{"model-value":p.value.codex,loading:u.value==="codex",onChange:a[3]||(a[3]=A=>y("codex",!!A))},null,8,["model-value","loading"])]),o(z,{class:"switch-divider"}),s("div",ce,[s("div",ve,[s("div",pe,[a[12]||(a[12]=i(" DeepSeek Harness ",-1)),o(c,{type:p.value.dsh?"success":"info",size:"small","disable-transitions":""},{default:n(()=>[i(h(p.value.dsh?"已开启":"未开启"),1)]),_:1},8,["type"])]),a[13]||(a[13]=s("div",{class:"switch-desc"},[i(" 写入 "),s("code",null,"~/.dsh/settings.yaml"),i(" 的 llm-deepseek.baseURL 与 "),s("code",null,"~/.dsh/.credentials.yaml"),i(" 的 DEEPSEEK_API_KEY(取网关 masterKey,未设置则写占位值);模型请在 dsh 内选择与网关部署名一致的模型。 dsh 为 developer preview,配置格式可能随版本变化。 ")],-1))]),o(t,{"model-value":p.value.dsh,loading:u.value==="dsh",onChange:a[4]||(a[4]=A=>y("dsh",!!A))},null,8,["model-value","loading"])])],64)):(m(),E(R,{key:1,description:V.value||"暂无开关状态"},{default:n(()=>[o(C,{type:"primary",onClick:a[5]||(a[5]=A=>b(!1))},{default:n(()=>[...a[14]||(a[14]=[i("重试",-1)])]),_:1})]),_:1},8,["description"]))]),_:1})),[[B,$.value]])}}}),fe=Z(me,[["__scopeId","data-v-65e65156"]]),_e={class:"service-settings"},ge={class:"flex-between"},ye={key:0,class:"switch-row"},we={class:"switch-info"},be={class:"switch-title"},Ce={key:0,class:"switch-row"},ke={class:"switch-info"},$e={class:"switch-title"},he={class:"switch-desc"},xe={key:0,class:"version-block"},Ve={class:"version-row"},Ae={class:"muted-sm"},Te={key:0,class:"muted-sm"},Ue={class:"version-actions"},Ee=X({__name:"ServiceUpdateSettings",setup(Q){const{toast:g}=Y(),$=r(!0),T=r(!1),p=r(null),V=r(null),u=r(null),P=r(null),w=r(null),b=r(!1),U=r(!1),y=r(null),_=async l=>{var e,d;if(!l){if(T.value)return;T.value=!0}try{const[f,K]=await Promise.allSettled([S.autostart(),S.update()]);p.value=f.status==="fulfilled"?f.value:null,V.value=f.status==="rejected"?(e=f.reason)==null?void 0:e.message:null,u.value=K.status==="fulfilled"?K.value:null,P.value=K.status==="rejected"?(d=K.reason)==null?void 0:d.message:null}finally{$.value=!1,T.value=!1}};q(()=>_(!1));const a=j(()=>{var l,e;return((e=(l=u.value)==null?void 0:l.lastCheck)==null?void 0:e.currentVersion)??null}),C=j(()=>{var l,e;return((e=(l=u.value)==null?void 0:l.lastCheck)==null?void 0:e.latestVersion)??null}),D=j(()=>{var l,e;return((e=(l=u.value)==null?void 0:l.lastCheck)==null?void 0:e.hasUpdate)===!0}),c=j(()=>{var e,d;const l=(d=(e=u.value)==null?void 0:e.lastCheck)==null?void 0:d.checkedAt;return l?new Date(l).toLocaleString():null}),t=j(()=>{var d;const l=(d=u.value)==null?void 0:d.lastApply;if(!l)return null;const e=l.appliedAt?new Date(l.appliedAt).toLocaleString():"";return`${l.fromVersion} → ${l.toVersion}${e?`(${e})`:""}`}),z=l=>l?new Date(l).toLocaleString():"",R=async l=>{if(!p.value||w.value)return;const e=l?"确定开启开机自启?将注册登录触发的自启项(登录时自动恢复服务)。":"确定关闭开机自启?将移除自启项,且此后首次启动不再自动注册。";try{await W.confirm(e,l?"开启确认":"关闭确认",{confirmButtonText:l?"开启":"关闭",cancelButtonText:"取消",type:"warning"})}catch{return}w.value="autostart";try{const d=await S.setAutostart(l);d.note?g(d.note,"success"):g(l?"开机自启已开启":"开机自启已关闭","success")}catch(d){g(d.message||"操作失败","error")}finally{w.value=null,await _(!0)}},L=async l=>{if(!u.value||w.value)return;const e=l?"确定开启自动更新?将每小时检查私有源,发现新版本自动安装并重启服务。":"确定关闭自动更新?不再自动检查(手动检查更新不受影响)。";try{await W.confirm(e,l?"开启确认":"关闭确认",{confirmButtonText:l?"开启":"关闭",cancelButtonText:"取消",type:"warning"})}catch{return}w.value="updateEnabled";try{const d=await S.setUpdateEnabled(l);d.note&&g(d.note,"success")}catch(d){g(d.message||"操作失败","error")}finally{w.value=null,await _(!0)}},B=async()=>{b.value=!0;try{const l=await S.checkUpdate();y.value=l.hasUpdate?`发现新版本 ${l.latestVersion}(当前 ${l.currentVersion}),可点击「立即更新」安装`:`已是最新版本 ${l.currentVersion}(检查于 ${z(l.checkedAt)})`,await _(!0)}catch(l){g(l.message||"检查更新失败","error")}finally{b.value=!1}},A=async()=>{var l;try{await W.confirm(`确定更新到 ${C.value}?服务将自动重启并在启动时安装新版本(期间界面请求会短暂失败,属正常现象)。`,"更新确认",{confirmButtonText:"立即更新",cancelButtonText:"取消",type:"warning"})}catch{return}U.value=!0;try{const e=await S.update(),d=await S.applyUpdate();if(!d.updated){y.value=`已是最新版本 ${d.toVersion}`;return}y.value=`正在重启服务并安装 ${d.toVersion},请稍候(预计 1~3 分钟)...`;const f=await le({targetVersion:d.toVersion,sinceAppliedAt:((l=e.lastApply)==null?void 0:l.appliedAt)??null});f&&!f.error?(g(`已更新到 ${f.toVersion}`,"success"),y.value=`已更新 ${f.fromVersion} → ${f.toVersion}`):f!=null&&f.error?(g(`更新失败:${f.error}`,"error"),y.value=`更新失败:${f.error}(服务已恢复旧版本)`):y.value="更新耗时较长,请稍后刷新页面查看结果"}catch(e){g(e.message||"更新失败","error")}finally{U.value=!1,await _(!0)}};return(l,e)=>{const d=v("el-button"),f=v("el-tag"),K=v("el-switch"),N=v("el-empty"),O=v("el-card"),F=v("el-alert"),k=J("loading");return G((m(),x("div",_e,[o(O,{shadow:"never",class:"mb-16"},{header:n(()=>[s("div",ge,[e[7]||(e[7]=s("span",{class:"fw-600"},"开机自启",-1)),o(d,{loading:T.value,onClick:e[0]||(e[0]=H=>_(!1))},{default:n(()=>[...e[6]||(e[6]=[i("刷新",-1)])]),_:1},8,["loading"])])]),default:n(()=>[p.value?(m(),x("div",ye,[s("div",we,[s("div",be,[e[8]||(e[8]=i(" 登录时自动启动服务 ",-1)),o(f,{type:p.value.enabled?"success":"info",size:"small","disable-transitions":""},{default:n(()=>[i(h(p.value.enabled?"已开启":"未开启"),1)]),_:1},8,["type"])]),e[9]||(e[9]=s("div",{class:"switch-desc"},[i(" 登录操作系统时自动启动服务(无需管理员权限)。 关闭后首次启动 "),s("code",null,"ellm-proxy"),i(" 也不会再自动注册,重新开启即可解除。 ")],-1))]),o(K,{"model-value":p.value.enabled,loading:w.value==="autostart",onChange:e[1]||(e[1]=H=>R(!!H))},null,8,["model-value","loading"])])):(m(),E(N,{key:1,description:V.value||"暂无自启状态"},{default:n(()=>[o(d,{type:"primary",onClick:e[2]||(e[2]=H=>_(!1))},{default:n(()=>[...e[10]||(e[10]=[i("重试",-1)])]),_:1})]),_:1},8,["description"]))]),_:1}),o(O,{shadow:"never",class:"mb-16"},{header:n(()=>[...e[11]||(e[11]=[s("div",{class:"flex-between"},[s("span",{class:"fw-600"},"自动更新")],-1)])]),default:n(()=>[u.value?(m(),x("div",Ce,[s("div",ke,[s("div",$e,[e[12]||(e[12]=i(" 自动检查并安装新版本 ",-1)),o(f,{type:u.value.enabled?"success":"info",size:"small","disable-transitions":""},{default:n(()=>[i(h(u.value.enabled?"已开启":"未开启"),1)]),_:1},8,["type"])]),s("div",he,[u.value.supported?(m(),x(M,{key:1},[i(" 每小时检查 npm 源,发现新版本自动重启服务并在启动时安装(更新期间服务短暂中断); 关闭后仍可在下方手动检查与更新。 ")],64)):(m(),x(M,{key:0},[i(" 当前为源码运行模式,更新功能不可用(仅 npm 全局安装的包支持自动更新)。 ")],64))])]),u.value.supported?(m(),E(K,{key:0,"model-value":u.value.enabled,loading:w.value==="updateEnabled",onChange:e[3]||(e[3]=H=>L(!!H))},null,8,["model-value","loading"])):I("",!0)])):(m(),E(N,{key:1,description:P.value||"暂无更新状态"},{default:n(()=>[o(d,{type:"primary",onClick:e[4]||(e[4]=H=>_(!1))},{default:n(()=>[...e[13]||(e[13]=[i("重试",-1)])]),_:1})]),_:1},8,["description"]))]),_:1}),o(O,{shadow:"never"},{header:n(()=>[...e[14]||(e[14]=[s("div",{class:"flex-between"},[s("span",{class:"fw-600"},"版本信息")],-1)])]),default:n(()=>[u.value?(m(),x("div",xe,[s("div",Ve,[e[17]||(e[17]=s("span",{class:"version-label"},"当前版本",-1)),o(f,{size:"small"},{default:n(()=>[i(h(a.value||"未知"),1)]),_:1}),C.value?(m(),x(M,{key:0},[e[16]||(e[16]=s("span",{class:"version-label"},"最新版本",-1)),o(f,{type:D.value?"warning":"success",size:"small","disable-transitions":""},{default:n(()=>[i(h(C.value),1)]),_:1},8,["type"]),D.value?(m(),E(f,{key:0,type:"warning",size:"small","disable-transitions":""},{default:n(()=>[...e[15]||(e[15]=[i("发现新版本",-1)])]),_:1})):I("",!0)],64)):I("",!0)]),s("div",Ae,[i(" 上次检查:"+h(c.value||"尚未检查")+" ",1),u.value.updating?(m(),x(M,{key:0},[i(" · 更新执行中...")],64)):I("",!0)]),t.value?(m(),x("div",Te,"上次更新:"+h(t.value),1)):I("",!0),s("div",Ue,[o(d,{loading:b.value,disabled:u.value.updating,onClick:B},{default:n(()=>[i(h(b.value?"检查中...":"检查更新"),1)]),_:1},8,["loading","disabled"]),D.value?(m(),E(d,{key:0,type:"primary",loading:U.value,disabled:u.value.updating,onClick:A},{default:n(()=>[i(h(U.value?"更新中...":`立即更新到 ${C.value}`),1)]),_:1},8,["loading","disabled"])):I("",!0)]),y.value?(m(),E(F,{key:1,title:y.value,type:"info","show-icon":"",class:"mt-8",onClose:e[5]||(e[5]=H=>y.value=null)},null,8,["title"])):I("",!0)])):(m(),E(N,{key:1,description:"更新状态不可用"}))]),_:1})])),[[k,$.value]])}}}),Se=Z(Ee,[["__scopeId","data-v-9366cd99"]]),Be={class:"flex-col-gap"},Ie={class:"flex-between"},Pe={class:"muted-sm"},De={key:0},Ke={class:"flex-end"},Re=X({__name:"SettingsView",setup(Q){const{toast:g}=Y(),$=te(),T=r("basic"),p=r(!0),V=r(!1),u=r(""),P=async()=>{if(u.value)try{await navigator.clipboard.writeText(u.value),g("已复制到剪贴板","success")}catch{g("复制失败","error")}},w=r(29770),b=r(null),U=r("passthrough"),y=r(!1),_=r(""),a=r(""),C=async()=>{var c;try{await $.load(),u.value=$.config.masterKey||"",w.value=$.config.port??29770,U.value=$.config.compression==="plain"?"plain":"passthrough",y.value=$.config.logContent===!0;const t=(c=$.config["web-ui"])==null?void 0:c["login-account"];_.value=(t==null?void 0:t.username)||"",a.value=(t==null?void 0:t.password)||"";try{b.value=await ee.get("/api/status").then(z=>z.listenPort)}catch{b.value=null}}catch(t){g(t.message,"error")}finally{p.value=!1}},D=async()=>{V.value=!0;try{await $.update(c=>{var t;c.masterKey=u.value.trim(),c.port=w.value,c.compression=U.value,c.logContent=y.value,c["web-ui"]??(c["web-ui"]={}),(t=c["web-ui"])["login-account"]??(t["login-account"]={}),c["web-ui"]["login-account"].username=_.value.trim(),c["web-ui"]["login-account"].password=a.value}),g("设置已保存并生效","success")}catch(c){g(c.message,"error")}finally{V.value=!1}};return q(C),(c,t)=>{const z=v("el-tag"),R=v("el-button"),L=v("el-input"),B=v("el-form-item"),A=v("el-input-number"),l=v("el-option"),e=v("el-select"),d=v("el-switch"),f=v("el-form"),K=v("el-card"),N=v("el-tab-pane"),O=v("el-tabs"),F=J("loading");return m(),E(O,{modelValue:T.value,"onUpdate:modelValue":t[6]||(t[6]=k=>T.value=k),class:"settings-tabs"},{default:n(()=>[o(N,{label:"基本设置",name:"basic"},{default:n(()=>[G((m(),x("div",Be,[o(K,{shadow:"never"},{header:n(()=>[s("div",Ie,[t[8]||(t[8]=s("span",{class:"fw-600"},"基本设置",-1)),o(z,{type:"success"},{default:n(()=>[...t[7]||(t[7]=[i("运行中",-1)])]),_:1})])]),default:n(()=>[o(f,{"label-position":"top"},{default:n(()=>[o(B,{label:"API 密钥 (masterKey)"},{default:n(()=>[o(L,{modelValue:u.value,"onUpdate:modelValue":t[0]||(t[0]=k=>u.value=k),placeholder:"sk-1234",clearable:""},{append:n(()=>[o(R,{onClick:P},{default:n(()=>[...t[9]||(t[9]=[i("复制",-1)])]),_:1})]),_:1},8,["modelValue"]),t[10]||(t[10]=s("div",{class:"muted-sm"}," 网关 API 认证密钥(/v1/* 请求需携带 Bearer <masterKey>;留空 = 本地放行) ",-1))]),_:1}),o(B,{label:"监听端口 (port)"},{default:n(()=>[o(A,{modelValue:w.value,"onUpdate:modelValue":t[1]||(t[1]=k=>w.value=k),min:1,max:65535,step:1,class:"full-width"},null,8,["modelValue"]),s("div",Pe,[t[12]||(t[12]=i(" 网关与管理台 API 的监听端口,保存后下次重启生效 ",-1)),b.value!==null?(m(),x(M,{key:0},[t[11]||(t[11]=i(" ;当前实际监听 ",-1)),s("b",null,h(b.value),1),b.value!==w.value?(m(),x("span",De,"(由 PORT 环境变量覆盖,此配置值不生效)")):I("",!0)],64)):I("",!0)])]),_:1}),o(B,{label:"压缩语义 (compression)"},{default:n(()=>[o(e,{modelValue:U.value,"onUpdate:modelValue":t[2]||(t[2]=k=>U.value=k),class:"full-width"},{default:n(()=>[o(l,{label:"透传 (passthrough)",value:"passthrough"}),o(l,{label:"明文 (plain)",value:"plain"})]),_:1},8,["modelValue"]),t[13]||(t[13]=s("div",{class:"muted-sm"},"上游响应压缩处理方式,保存后热更新生效",-1))]),_:1}),o(B,{label:"日志内容捕获 (logContent)"},{default:n(()=>[o(d,{modelValue:y.value,"onUpdate:modelValue":t[3]||(t[3]=k=>y.value=k)},null,8,["modelValue"]),t[14]||(t[14]=s("div",{class:"muted-sm"}," 记录完整请求/响应(含上游原始与转换后内容)进日志详情,用于排查定位问题;开启后有少量内存与存储开销,保存后热更新生效 ",-1))]),_:1}),o(B,{label:"管理台用户名 (web-ui.login-account.username)"},{default:n(()=>[o(L,{modelValue:_.value,"onUpdate:modelValue":t[4]||(t[4]=k=>_.value=k),placeholder:"请输入用户名"},null,8,["modelValue"]),t[15]||(t[15]=s("div",{class:"muted-sm"}," 管理台登录用户名,留空回退 WEBUI_USERNAME/WEBUI_PASSWORD 环境变量(两者都设置才生效) ",-1))]),_:1}),o(B,{label:"管理台密码 (web-ui.login-account.password)"},{default:n(()=>[o(L,{modelValue:a.value,"onUpdate:modelValue":t[5]||(t[5]=k=>a.value=k),type:"password",placeholder:"请输入密码(至少 6 位)","show-password":""},null,8,["modelValue"]),t[16]||(t[16]=s("div",{class:"muted-sm"}," 用户名与密码需同时填写才启用登录;都未提供 = 管理台免登录直接访问(纯本机使用)。修改保存后立即生效,需用新账号重新登录 ",-1))]),_:1})]),_:1})]),_:1}),s("div",Ke,[o(R,{type:"primary",loading:V.value,disabled:V.value,onClick:D},{default:n(()=>[i(h(V.value?"保存中...":"保存设置"),1)]),_:1},8,["loading","disabled"])])])),[[F,p.value]])]),_:1}),o(N,{label:"代理开关",name:"harness",lazy:""},{default:n(()=>[o(fe)]),_:1}),o(N,{label:"服务与更新",name:"service",lazy:""},{default:n(()=>[o(Se)]),_:1})]),_:1},8,["modelValue"])}}});export{Re as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.setup-wrap[data-v-631b405c]{min-height:100vh;display:flex;align-items:center;justify-content:center;background:#f5f7fa}.setup-card[data-v-631b405c]{width:520px;max-width:92vw}.setup-title[data-v-631b405c]{text-align:center;margin-bottom:20px;color:#3b82f6}.account-row[data-v-631b405c]{display:flex;gap:12px;width:100%}.label-hint[data-v-631b405c]{display:block;font-size:12px;font-weight:400;color:#909399;line-height:1.4}.full-width[data-v-631b405c]{width:100%}.mb-16[data-v-631b405c]{margin-bottom:16px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{d as M,k as N,l as E,e as I,g as l,w as t,r as d,a as u,o as y,f,h as m,c as x,i as C,a0 as T,ac as w,A as h,ad as L,n as P,_ as R}from"./index-BmtcBnoW.js";const $={class:"setup-wrap"},j={class:"account-row"},q=M({__name:"SetupView",setup(z){const S=P(),r=d(!1),i=d(""),c=d(""),p=d(""),_=d(!1),o=d("");N(async()=>{(await E()).masterKeySet||(i.value=A())});function A(){const s=new Uint8Array(32);crypto.getRandomValues(s);let e="";for(const a of s)e+=String.fromCharCode(a);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function B(){try{await navigator.clipboard.writeText(i.value),w.success("已复制到剪贴板")}catch{w.error("复制失败,请手动选择复制")}}async function V(){o.value="";const s=r.value?"server":"local",e=i.value.trim(),a=c.value.trim()!==""||p.value!=="";if(r.value&&e===""){o.value="服务器部署必须设置主密钥,防止 /v1 网关被他人盗用";return}if(r.value&&!a){o.value="服务器部署必须设置登录账号密码,防止管理台被陌生人登录";return}if(a){if(c.value.trim()===""||p.value===""){o.value="用户名和密码需同时填写";return}if(p.value.length<6){o.value="密码至少 6 位";return}}_.value=!0;try{e!==""&&await h.post("/api/setup/master-key",{mode:"custom",masterKey:e}),await h.post("/api/setup/finish",{deployment:s,...a?{username:c.value.trim(),password:p.value}:{}}),L(s,a),w.success(a?"初始化完成,请使用新账号登录":"初始化完成,免登录进入管理台"),await S.push(a?"/login":"/")}catch(v){o.value=v.message||"保存失败"}finally{_.value=!1}}return(s,e)=>{const a=u("el-checkbox"),v=u("el-alert"),g=u("el-button"),b=u("el-input"),k=u("el-form-item"),K=u("el-form"),U=u("el-card");return y(),I("div",$,[l(U,{shadow:"hover",class:"setup-card"},{default:t(()=>[e[9]||(e[9]=f("h2",{class:"setup-title"},"初始化 ELLM",-1)),l(a,{modelValue:r.value,"onUpdate:modelValue":e[0]||(e[0]=n=>r.value=n),class:"mb-16"},{default:t(()=>[...e[4]||(e[4]=[m(" 允许其他设备访问本服务(局域网 / 公网部署) ",-1)])]),_:1},8,["modelValue"]),r.value?(y(),x(v,{key:0,type:"warning","show-icon":"",closable:!1,title:"服务将对网络中的其他设备可见,请务必保留主密钥并修改默认账号",class:"mb-16"})):C("",!0),l(K,{"label-position":"top",onSubmit:T(V,["prevent"])},{default:t(()=>[l(k,null,{label:t(()=>[...e[5]||(e[5]=[m(" API 主密钥 ",-1),f("span",{class:"label-hint"},"调用 /v1/* 时的 Bearer Token;清空则不启用鉴权(仅建议纯本机使用)",-1)])]),default:t(()=>[l(b,{modelValue:i.value,"onUpdate:modelValue":e[1]||(e[1]=n=>i.value=n),placeholder:"已设置主密钥,留空保持不变",clearable:""},{append:t(()=>[l(g,{disabled:!i.value,onClick:B},{default:t(()=>[...e[6]||(e[6]=[m("复制",-1)])]),_:1},8,["disabled"])]),_:1},8,["modelValue"])]),_:1}),l(k,null,{label:t(()=>[...e[7]||(e[7]=[m(" 管理台登录(可选) ",-1),f("span",{class:"label-hint"},"不填 = 免登录直接进管理台(纯本机使用);勾选上方后必须填写",-1)])]),default:t(()=>[f("div",j,[l(b,{modelValue:c.value,"onUpdate:modelValue":e[2]||(e[2]=n=>c.value=n),placeholder:"用户名",clearable:""},null,8,["modelValue"]),l(b,{modelValue:p.value,"onUpdate:modelValue":e[3]||(e[3]=n=>p.value=n),type:"password","show-password":"",placeholder:"密码(至少 6 位)"},null,8,["modelValue"])])]),_:1}),o.value?(y(),x(v,{key:0,title:o.value,type:"error","show-icon":"",closable:!1,class:"mb-16"},null,8,["title"])):C("",!0),l(g,{type:"primary",class:"full-width",loading:_.value,onClick:V},{default:t(()=>[...e[8]||(e[8]=[m(" 完成初始化 ",-1)])]),_:1},8,["loading"])]),_:1})]),_:1})])}}}),F=R(q,[["__scopeId","data-v-631b405c"]]);export{F as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{Z as p,r as u,m as n,A as i}from"./index-BmtcBnoW.js";const y=p("config",()=>{const e=u({}),o=u(!1),t=n(()=>Array.isArray(e.value.providers)?e.value.providers:[]),l=n(()=>t.value.length),c=n(()=>t.value.reduce((a,d)=>{var s;return a+(((s=d.models)==null?void 0:s.length)??0)},0));async function f(){o.value=!0;try{e.value=await i.get("/api/config")}finally{o.value=!1}}async function r(){return await i.put("/api/config",e.value)}async function v(a){return a(e.value),await r()}return{config:e,loading:o,providers:t,providerCount:l,totalModelCount:c,load:f,save:r,update:v}});export{y as u};
|