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.
Files changed (29) hide show
  1. package/dist/cli.js +48 -17
  2. package/dist/server.js +58 -33
  3. package/dist/web-ui/assets/DashboardView-BTtCBA4g.css +1 -0
  4. package/dist/web-ui/assets/DashboardView-BWPFis7P.js +1 -0
  5. package/dist/web-ui/assets/LayoutView-BkUJgLW2.js +1 -0
  6. package/dist/web-ui/assets/LoginView-C8E6nJw2.js +1 -0
  7. package/dist/web-ui/assets/{LogsView-2h2Y0XE8.js → LogsView-CtRfyOCZ.js} +1 -1
  8. package/dist/web-ui/assets/{ProvidersView-bE1Hv9D-.js → ProvidersView-B6fm2FPQ.js} +1 -1
  9. package/dist/web-ui/assets/SettingsView-BHuXlGS1.js +1 -0
  10. package/dist/web-ui/assets/SetupView-BkBbUyaW.css +1 -0
  11. package/dist/web-ui/assets/SetupView-Oau3EJgh.js +1 -0
  12. package/dist/web-ui/assets/{config-nvSp8hHp.js → config-CHaFDQC7.js} +1 -1
  13. package/dist/web-ui/assets/{index-sPrBBnf5.js → index-BmtcBnoW.js} +18 -18
  14. package/dist/web-ui/assets/{providers-di7L8jy_.js → providers-Aw7T7j0r.js} +1 -1
  15. package/dist/web-ui/assets/useManagerApi-PldAaNYo.js +1 -0
  16. package/dist/web-ui/assets/useToast-C9BTyaBD.js +1 -0
  17. package/dist/web-ui/index.html +1 -1
  18. package/package.json +1 -1
  19. package/dist/web-ui/assets/DashboardView-3c_i_3VF.js +0 -1
  20. package/dist/web-ui/assets/DashboardView-BHG4xIdN.css +0 -1
  21. package/dist/web-ui/assets/LayoutView-BhN1f8wo.js +0 -1
  22. package/dist/web-ui/assets/LoginView-J23vsMu2.js +0 -1
  23. package/dist/web-ui/assets/ProcessView-Bn8Ph7rh.css +0 -1
  24. package/dist/web-ui/assets/ProcessView-Bs2k6aAf.js +0 -1
  25. package/dist/web-ui/assets/SettingsView-BmLmC-_v.js +0 -1
  26. package/dist/web-ui/assets/SetupView-Cgj7ubNz.js +0 -1
  27. package/dist/web-ui/assets/SetupView-kPJXJ7dX.css +0 -1
  28. package/dist/web-ui/assets/useManagerApi-qPjxfB0X.js +0 -1
  29. 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(), AUTOSTART_CMD);
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
- `"${nodePath}" "${target.serverJs}" >nul 2>&1`,
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 itemPath = join6(windowsStartupDir(), AUTOSTART_CMD);
35271
- writeFileSync3(itemPath, windowsBody(nodePath, target), "utf-8");
35272
- return itemPath;
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 itemPath = join6(windowsStartupDir(), AUTOSTART_CMD);
35305
- if (!existsSync2(itemPath)) return false;
35306
- rmSync2(itemPath, { force: true });
35307
- return true;
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
- const content = readFileSync5(itemPath, "utf-8");
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\u76F4\u542F\u6A21\u5F0F: ${itemPath}` : `\u5DF2\u81EA\u52A8\u6CE8\u518C\u5F00\u673A\u81EA\u542F: ${itemPath}`);
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\u76F4\u63A5\u542F\u52A8\u670D\u52A1\uFF09`);
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 \u91CD\u7F6E\u4E3A admin/admin\uFF1B\u6539\u540E\u65E7\u767B\u5F55\u6001\u7ACB\u5373\u5931\u6548\uFF09").option("--reset", "\u91CD\u7F6E\u4E3A\u9ED8\u8BA4\u8D26\u53F7 admin/admin").option("--config <path>", "\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4 ~/.ellm-proxy/ellm.config.json\uFF09").action(
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\u91CD\u7F6E\u4E3A\u9ED8\u8BA4\u8D26\u53F7 admin/admin\uFF08\u65E7\u767B\u5F55 token \u7ACB\u5373\u5931\u6548\uFF09\u3002");
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\u5728\u914D\u7F6E\u6587\u4EF6\u4E2D\u8BBE\u7F6E\u8D26\u53F7\uFF1A\u4F7F\u7528 admin/admin\uFF08\u6216 WEBUI_USERNAME/WEBUI_PASSWORD \u73AF\u5883\u53D8\u91CF\uFF09\u3002");
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("\u8BBE\u7F6E\u65B9\u5F0F\uFF1Aellm-proxy account <username> <password>\uFF0C\u91CD\u7F6E\uFF1Aellm-proxy account --reset");
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
- const envUsername = process.env["WEBUI_USERNAME"] || "admin";
18950
- const envPassword = process.env["WEBUI_PASSWORD"] || "admin";
18951
- return { username: fileUsername ?? envUsername, password: filePassword ?? envPassword };
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(), AUTOSTART_CMD);
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
- `"${nodePath}" "${target.serverJs}" >nul 2>&1`,
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 itemPath = join5(windowsStartupDir(), AUTOSTART_CMD);
20695
- writeFileSync5(itemPath, windowsBody(nodePath, target), "utf-8");
20696
- return itemPath;
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 itemPath = join5(windowsStartupDir(), AUTOSTART_CMD);
20729
- if (!existsSync7(itemPath)) return false;
20730
- rmSync2(itemPath, { force: true });
20731
- return true;
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
- const content = readFileSync6(itemPath, "utf-8");
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, POST /start|stop|restart, GET|POST /autostart, GET /update, POST /update/enabled|check|apply, GET /harness, POST /harness/claude-code|codex|dsh\uFF09`
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,k as m,b as Q,F as P,f as d,i as j,r as y,A,_ as X,p as pe,q as ce,a3 as _e,l as ve}from"./index-sPrBBnf5.js";import{u as me}from"./providers-di7L8jy_.js";import{u as Z}from"./useToast-D76qyWZg.js";import"./config-nvSp8hHp.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(`
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,s as Mt,v as He,x as cr,y as Lt,z as jo,B as Ts,C as ia,D as Os,G as aa,H as Is,I as Kt,J as sa,K as xi,L as Ns,M as Cs,O as As,P as xs,Q as Ps,R as Xr,S as Ds,T as Kr,U as Rs,V as Ms,W as Ls,X as ws,Y 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,q as ko,Z as fo,$ as Vs,k as q,h as ae,i as tt,g as P,a0 as Fs,l as Ht,r as Pe,_ as cn,a1 as Xo,a2 as Rt,p as la,a3 as $s,E as Ao,a4 as Us,a5 as js,a6 as Bs,a7 as ks}from"./index-sPrBBnf5.js";import{u as un}from"./useToast-D76qyWZg.js";import{u as Ko}from"./providers-di7L8jy_.js";import"./config-nvSp8hHp.js";var yr={exports:{}},po={exports:{}},ho={};/**
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{X as p,r as u,l as n,A as i}from"./index-sPrBBnf5.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};
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};