dsh-multi-router 0.5.9 → 0.6.0
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/CHANGELOG.md +10 -0
- package/README.md +26 -1
- package/cordis.patch.yml +2 -2
- package/lib/accounts.js +4 -4
- package/lib/api-service.js +11 -0
- package/lib/api-service.js.map +7 -0
- package/lib/chunk-4V52V5GO.js +105 -0
- package/lib/chunk-4V52V5GO.js.map +7 -0
- package/lib/{chunk-S6ZQ45SS.js → chunk-JUOESKAK.js} +3 -3
- package/lib/{chunk-P43AWJ4Q.js → chunk-LLDJVBTQ.js} +3 -3
- package/lib/{chunk-U2MU2M5C.js → chunk-NSKCFVHP.js} +13 -111
- package/lib/chunk-NSKCFVHP.js.map +7 -0
- package/lib/{chunk-I4EW5TI7.js → chunk-OCMOMSB4.js} +46 -14
- package/lib/chunk-OCMOMSB4.js.map +7 -0
- package/lib/{chunk-FTM7RHQV.js → chunk-OK2T2UAZ.js} +4 -4
- package/lib/{chunk-J3XO7RTF.js → chunk-ROZINFTV.js} +3 -2
- package/lib/chunk-ROZINFTV.js.map +7 -0
- package/lib/chunk-SNEZMYNU.js +332 -0
- package/lib/chunk-SNEZMYNU.js.map +7 -0
- package/lib/{chunk-MCHV2R25.js → chunk-WVNY4LSL.js} +3 -1
- package/lib/{chunk-MCHV2R25.js.map → chunk-WVNY4LSL.js.map} +2 -2
- package/lib/cli.js +7 -6
- package/lib/cli.js.map +1 -1
- package/lib/client.js +340 -7
- package/lib/client.js.map +2 -2
- package/lib/clients.js +6 -5
- package/lib/{host-v0.5.9.js → host-v0.6.0.js} +18 -13
- package/lib/host.js +18 -13
- package/lib/index.js +18 -13
- package/lib/index.js.map +2 -2
- package/lib/manager.js +11 -7
- package/lib/router.js +2 -2
- package/lib/shim.js +3 -3
- package/package.json +1 -1
- package/lib/chunk-I4EW5TI7.js.map +0 -7
- package/lib/chunk-J3XO7RTF.js.map +0 -7
- package/lib/chunk-U2MU2M5C.js.map +0 -7
- /package/lib/{chunk-S6ZQ45SS.js.map → chunk-JUOESKAK.js.map} +0 -0
- /package/lib/{chunk-P43AWJ4Q.js.map → chunk-LLDJVBTQ.js.map} +0 -0
- /package/lib/{chunk-FTM7RHQV.js.map → chunk-OK2T2UAZ.js.map} +0 -0
package/lib/client.js
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var client_exports = {};
|
|
22
22
|
__export(client_exports, {
|
|
23
23
|
AccountPool: () => AccountPool,
|
|
24
|
+
ApiServicePanel: () => ApiServicePanel,
|
|
24
25
|
CheckinPanel: () => CheckinPanel,
|
|
25
26
|
InitialSetup: () => InitialSetup,
|
|
26
27
|
ModelsPanel: () => ModelsPanel,
|
|
@@ -28,6 +29,8 @@ __export(client_exports, {
|
|
|
28
29
|
RestartGuidance: () => RestartGuidance,
|
|
29
30
|
RouterPage: () => RouterPage,
|
|
30
31
|
RoutesTable: () => RoutesTable,
|
|
32
|
+
SidebarUsage: () => SidebarUsage,
|
|
33
|
+
SidebarUsageCard: () => SidebarUsageCard,
|
|
31
34
|
UpdateReminder: () => UpdateReminder,
|
|
32
35
|
UsageDetails: () => UsageDetails,
|
|
33
36
|
apply: () => apply,
|
|
@@ -44,7 +47,7 @@ module.exports = __toCommonJS(client_exports);
|
|
|
44
47
|
var import_react = require("react");
|
|
45
48
|
|
|
46
49
|
// package.json
|
|
47
|
-
var version = "0.
|
|
50
|
+
var version = "0.6.0";
|
|
48
51
|
|
|
49
52
|
// src/client.jsx
|
|
50
53
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -127,6 +130,101 @@ function apply(ctx) {
|
|
|
127
130
|
reloadFromHost = () => requestPluginReload(ctx.get?.("remote"));
|
|
128
131
|
ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({ name: "plugins.bundle.config", key: "dsh-multi-router" }, RouterPage));
|
|
129
132
|
ctx.slots.inject("shell.overlay", () => ctx.slots.register({ name: "shell.overlay", id: "dsh-multi-router-updates" }, UpdateReminder));
|
|
133
|
+
ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
|
|
134
|
+
name: "sidebar.footer.action",
|
|
135
|
+
id: "dsh-multi-router-usage",
|
|
136
|
+
order: 10,
|
|
137
|
+
inject: () => ({ open: () => {
|
|
138
|
+
const navigation = ctx.get?.("pluginNavigation");
|
|
139
|
+
if (!navigation?.openBundle) throw Error("\u8BF7\u5728\u63D2\u4EF6\u9875\u6253\u5F00 dsh-multi-router\uFF1B\u5F53\u524D DSH \u672A\u63D0\u4F9B\u8BE6\u60C5\u5BFC\u822A\u3002");
|
|
140
|
+
navigation.openBundle("dsh-multi-router");
|
|
141
|
+
} })
|
|
142
|
+
}, SidebarUsage));
|
|
143
|
+
}
|
|
144
|
+
var SUMMARY_EVENT = "dsh-multi-router-summary";
|
|
145
|
+
var compactTokens = (n) => n >= 1e9 ? `${(n / 1e9).toFixed(1)}B` : n >= 1e6 ? `${(n / 1e6).toFixed(1)}M` : n >= 1e3 ? `${(n / 1e3).toFixed(1)}K` : fmt(n);
|
|
146
|
+
function SidebarUsageCard({ data, wide = true, open, error }) {
|
|
147
|
+
const title = `${data.today}\uFF08\u5317\u4EAC\u65F6\u95F4\uFF09
|
|
148
|
+
\u4ECA\u65E5 ${fmt(data.tokens)} Token \xB7 ${fmt(data.requests)} \u6B21\u8BF7\u6C42
|
|
149
|
+
\u7D2F\u8BA1 ${fmt(data.totalTokens)} Token${data.unmetered ? `
|
|
150
|
+
${fmt(data.unmetered)} \u6B21\u8C03\u7528\u672A\u8FD4\u56DE\u7528\u91CF` : ""}${error ? `
|
|
151
|
+
${error}` : ""}
|
|
152
|
+
\u70B9\u51FB\u6253\u5F00\u8D26\u53F7\u4E0E\u8DEF\u7531`;
|
|
153
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
154
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
|
|
155
|
+
[class*="_footArea"] [class*="_footerActions"]:has(.mr-sidebar-usage){flex-direction:column}
|
|
156
|
+
.mr-sidebar-usage{box-sizing:border-box;display:flex;align-items:center;gap:10px;width:100%;min-width:0;min-height:48px;padding:7px 10px;border:1px solid var(--dsw-alias-border-l2,#444);border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary,#eee);font:inherit;text-align:left;cursor:pointer}
|
|
157
|
+
.mr-sidebar-usage:hover{background:var(--dsw-alias-bg-module-platform,#303036)}.mr-sidebar-usage:focus-visible{outline:2px solid var(--dsw-alias-state-active-primary,#3a71db);outline-offset:2px}
|
|
158
|
+
.mr-sidebar-usage svg{flex-shrink:0}.mr-sidebar-usage span{flex:1;min-width:0}.mr-sidebar-usage small{display:block;color:var(--dsw-alias-label-secondary,#aaa);font-size:10px;line-height:15px;white-space:nowrap}.mr-sidebar-usage strong{display:block;font-size:13px;font-weight:600;line-height:18px;font-variant-numeric:tabular-nums;white-space:nowrap}.mr-sidebar-usage[data-wide=false]{width:36px;min-height:36px;padding:8px;justify-content:center}
|
|
159
|
+
` }),
|
|
160
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { className: "mr-sidebar-usage", "data-wide": wide, title, "aria-label": `Token \u7528\u91CF\u6982\u89C8\uFF0C\u4ECA\u65E5 ${fmt(data.tokens)}\uFF0C\u7D2F\u8BA1 ${fmt(data.totalTokens)}\uFF0C\u6253\u5F00\u63D2\u4EF6\u8BE6\u60C5`, onClick: open, children: [
|
|
161
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.6", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 4v16h17M8 16v-5m5 5V7m5 9v-7" }) }),
|
|
162
|
+
wide && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
163
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
164
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("small", { children: [
|
|
165
|
+
"\u4ECA\u65E5 Token",
|
|
166
|
+
error ? " \xB7 \u672A\u5237\u65B0" : ""
|
|
167
|
+
] }),
|
|
168
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: compactTokens(data.tokens) })
|
|
169
|
+
] }),
|
|
170
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
171
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: "\u7D2F\u8BA1 Token" }),
|
|
172
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: compactTokens(data.totalTokens) })
|
|
173
|
+
] })
|
|
174
|
+
] })
|
|
175
|
+
] })
|
|
176
|
+
] });
|
|
177
|
+
}
|
|
178
|
+
function SidebarUsage({ wide = true, open }) {
|
|
179
|
+
const [data, setData] = (0, import_react.useState)(null), [error, setError] = (0, import_react.useState)("");
|
|
180
|
+
(0, import_react.useEffect)(() => {
|
|
181
|
+
let stopped = false, pending = false, again = false;
|
|
182
|
+
const abort = new AbortController();
|
|
183
|
+
async function poll(event) {
|
|
184
|
+
if (document.hidden) return;
|
|
185
|
+
if (pending) {
|
|
186
|
+
if (event?.type === SUMMARY_EVENT) again = true;
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
pending = true;
|
|
190
|
+
try {
|
|
191
|
+
const next = await readManagementResponse(await fetch(`${ENDPOINT}/summary`, { cache: "no-store", signal: AbortSignal.any([abort.signal, AbortSignal.timeout(8e3)]) }));
|
|
192
|
+
if (!stopped) {
|
|
193
|
+
setData(next);
|
|
194
|
+
setError("");
|
|
195
|
+
}
|
|
196
|
+
} catch {
|
|
197
|
+
if (!stopped) setError("\u6682\u65F6\u65E0\u6CD5\u5237\u65B0\u672C\u673A\u7EDF\u8BA1");
|
|
198
|
+
} finally {
|
|
199
|
+
pending = false;
|
|
200
|
+
if (again && !stopped) {
|
|
201
|
+
again = false;
|
|
202
|
+
void poll();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
void poll();
|
|
207
|
+
const timer = setInterval(() => {
|
|
208
|
+
void poll();
|
|
209
|
+
}, 6e4);
|
|
210
|
+
document.addEventListener("visibilitychange", poll);
|
|
211
|
+
window.addEventListener(SUMMARY_EVENT, poll);
|
|
212
|
+
return () => {
|
|
213
|
+
stopped = true;
|
|
214
|
+
abort.abort();
|
|
215
|
+
clearInterval(timer);
|
|
216
|
+
document.removeEventListener("visibilitychange", poll);
|
|
217
|
+
window.removeEventListener(SUMMARY_EVENT, poll);
|
|
218
|
+
};
|
|
219
|
+
}, []);
|
|
220
|
+
if (!data || data.enabled === false) return null;
|
|
221
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SidebarUsageCard, { data, wide, error, open: () => {
|
|
222
|
+
try {
|
|
223
|
+
open();
|
|
224
|
+
} catch (e) {
|
|
225
|
+
setError(e.message);
|
|
226
|
+
}
|
|
227
|
+
} });
|
|
130
228
|
}
|
|
131
229
|
function Modal({ title, close, children, busy }) {
|
|
132
230
|
const ref = (0, import_react.useRef)(null);
|
|
@@ -318,9 +416,10 @@ function RouterPage({ view = "page" }) {
|
|
|
318
416
|
try {
|
|
319
417
|
const res = await fetch(ENDPOINT, { method: "POST", headers: { "Content-Type": "application/json", "X-Multi-Router-Key": data.key }, body: JSON.stringify({ revision: data.revision, ...action }) });
|
|
320
418
|
const next = await readManagementResponse(res);
|
|
321
|
-
const { exported, workbuddyLogin, loginResult, ...state } = next;
|
|
419
|
+
const { exported, workbuddyLogin, loginResult, apiKey, ...state } = next;
|
|
322
420
|
setData(state);
|
|
323
|
-
|
|
421
|
+
if (action.sidebarUsage !== void 0 || action.action === "config.import") window.dispatchEvent(new Event(SUMMARY_EVENT));
|
|
422
|
+
setNotice(action.action.startsWith("api.") ? next.apiService?.phase === "error" ? "\u914D\u7F6E\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u670D\u52A1\u5C1A\u672A\u542F\u52A8\uFF0C\u8BF7\u67E5\u770B\u4E0B\u65B9\u63D0\u793A\u3002" : action.action === "api.key.reveal" ? "" : "API \u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002" : action.action === "workbuddy.sms" ? "" : action.action === "workbuddy.login" ? loginResult?.warning || "\u767B\u5F55\u51ED\u8BC1\u5DF2\u4FDD\u5B58\uFF0C\u81EA\u52A8\u7B7E\u5230\u5F00\u5173\u4FDD\u6301\u539F\u8BBE\u7F6E\u3002" : action.action === "checkins.verify" ? "\u767B\u5F55\u9A8C\u8BC1\u901A\u8FC7\uFF0C\u65E7\u7684\u4EE4\u724C\u5931\u6548\u63D0\u793A\u5DF2\u89E3\u9664\uFF1B\u672A\u63D0\u4EA4\u7B7E\u5230\u3002" : action.action === "checkins.settings" ? "\u7B7E\u5230\u8BA1\u5212\u5DF2\u4FDD\u5B58\uFF1B\u4ECA\u65E5\u5DF2\u5904\u7406\u8BB0\u5F55\u4FDD\u6301\u4E0D\u53D8\u3002" : action.action.startsWith("checkins.") || action.action.startsWith("plugins.") || action.action === "setup.dismiss" ? "" : action.action === "accounts.discover" || action.action === "monitor.refresh" ? "\u5DF2\u91CD\u65B0\u68C0\u6D4B\u672C\u673A\u767B\u5F55\u5E76\u5237\u65B0\u7528\u91CF\uFF1B\u68C0\u6D4B\u7ED3\u679C\u89C1\u4E0B\u65B9\u3002" : action.action.includes("refresh") ? "\u5DF2\u5237\u65B0\u3002\u65E0\u6CD5\u83B7\u53D6\u7684\u8D26\u53F7\u4F1A\u4FDD\u7559\u4E0A\u6B21\u6570\u636E\u5E76\u6807\u8BB0\u3002" : action.action === "config.import" ? "\u914D\u7F6E\u5DF2\u5BFC\u5165\u5E76\u751F\u6548\uFF0C\u539F\u914D\u7F6E\u5DF2\u5907\u4EFD\uFF1B\u6A21\u578B\u548C\u7528\u91CF\u6B63\u5728\u540E\u53F0\u66F4\u65B0\u3002" : action.action.startsWith("config.") || action.action === "account.export" ? "" : "\u5DF2\u4FDD\u5B58\u5E76\u751F\u6548\u3002");
|
|
324
423
|
return next;
|
|
325
424
|
} catch (e) {
|
|
326
425
|
setError(e.message);
|
|
@@ -368,6 +467,12 @@ function RouterPage({ view = "page" }) {
|
|
|
368
467
|
"v",
|
|
369
468
|
data?.pluginVersion ?? version
|
|
370
469
|
] }),
|
|
470
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check refresh-control", children: [
|
|
471
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", disabled: busy || !data || backendNeedsRestart(data), checked: data?.options?.sidebarUsage !== false, onChange: (e) => {
|
|
472
|
+
void act({ action: "options.save", sidebarUsage: e.target.checked });
|
|
473
|
+
} }),
|
|
474
|
+
"\u4FA7\u680F\u7528\u91CF"
|
|
475
|
+
] }),
|
|
371
476
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "status", children: [
|
|
372
477
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("i", { className: busy || !data ? "warn" : "good", "aria-hidden": "true" }),
|
|
373
478
|
busy ? "\u6B63\u5728\u5904\u7406\u2026" : !data ? "\u6B63\u5728\u8FDE\u63A5\u2026" : "\u672C\u673A\u8FD0\u884C"
|
|
@@ -381,7 +486,7 @@ function RouterPage({ view = "page" }) {
|
|
|
381
486
|
}, children: "\u5237\u65B0\u9762\u677F" })
|
|
382
487
|
] })
|
|
383
488
|
] }),
|
|
384
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", { "aria-label": "\u8DEF\u7531\u63D2\u4EF6\u914D\u7F6E\u9875\u7B7E", children: [["overview", "\u603B\u89C8\u4E0E\u7528\u91CF"], ["usage", "Token \u660E\u7EC6"], ["accounts", "\u8D26\u53F7\u4E0E\u767B\u5F55"], ["checkins", "\u79EF\u5206\u7B7E\u5230"], ["models", "\u6A21\u578B\u7BA1\u7406"], ["routes", "\u8DEF\u7531\u89C4\u5219"], ["plugins", "\u63D2\u4EF6\u66F4\u65B0"], ["migration", "\u914D\u7F6E\u8FC1\u79FB"]].map(([key, label]) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { "aria-pressed": tab === key, onClick: () => {
|
|
489
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("nav", { "aria-label": "\u8DEF\u7531\u63D2\u4EF6\u914D\u7F6E\u9875\u7B7E", children: [["overview", "\u603B\u89C8\u4E0E\u7528\u91CF"], ["usage", "Token \u660E\u7EC6"], ["accounts", "\u8D26\u53F7\u4E0E\u767B\u5F55"], ["checkins", "\u79EF\u5206\u7B7E\u5230"], ["models", "\u6A21\u578B\u7BA1\u7406"], ["routes", "\u8DEF\u7531\u89C4\u5219"], ["api", "API \u670D\u52A1"], ["plugins", "\u63D2\u4EF6\u66F4\u65B0"], ["migration", "\u914D\u7F6E\u8FC1\u79FB"]].map(([key, label]) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { "aria-pressed": tab === key, onClick: () => {
|
|
385
490
|
setTab(key);
|
|
386
491
|
setError("");
|
|
387
492
|
setNotice("");
|
|
@@ -413,6 +518,7 @@ function RouterPage({ view = "page" }) {
|
|
|
413
518
|
] }),
|
|
414
519
|
["overview", "accounts"].includes(tab) && data.setup?.dismissed !== true && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InitialSetup, { data, busy, act, go: (key) => setTab(key) }),
|
|
415
520
|
tab === "overview" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Overview, { data, busy, act, go: (key) => setTab(key) }),
|
|
521
|
+
tab === "api" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ApiServicePanel, { data: data.apiService, busy, act }),
|
|
416
522
|
tab === "plugins" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PluginUpdatesPanel, { data: data.pluginUpdates, busy, act }),
|
|
417
523
|
tab === "checkins" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CheckinPanel, { data, busy, act }),
|
|
418
524
|
tab === "usage" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UsageDetails, { data, busy, act }),
|
|
@@ -494,6 +600,219 @@ function RouterPage({ view = "page" }) {
|
|
|
494
600
|
}, error, notice }) })
|
|
495
601
|
] });
|
|
496
602
|
}
|
|
603
|
+
function ApiServicePanel({ data: a, busy, act }) {
|
|
604
|
+
const [key, setKey] = (0, import_react.useState)(""), [hint, setHint] = (0, import_react.useState)(""), [confirmKey, setConfirmKey] = (0, import_react.useState)(null), [models, setModels] = (0, import_react.useState)(false), [example, setExample] = (0, import_react.useState)("");
|
|
605
|
+
const copyField = (0, import_react.useRef)(null);
|
|
606
|
+
(0, import_react.useEffect)(() => {
|
|
607
|
+
setKey((current) => a?.keyHint && current.endsWith(a.keyHint.slice(-4)) ? current : "");
|
|
608
|
+
}, [a?.keyHint]);
|
|
609
|
+
(0, import_react.useEffect)(() => {
|
|
610
|
+
if (!key) return;
|
|
611
|
+
const timer = setTimeout(() => setKey(""), 6e4);
|
|
612
|
+
return () => clearTimeout(timer);
|
|
613
|
+
}, [key]);
|
|
614
|
+
if (!a) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "steps", children: "\u5F53\u524D\u540E\u53F0\u672A\u63D0\u4F9B API \u670D\u52A1\uFF0C\u8BF7\u66F4\u65B0\u63D2\u4EF6\u3002" });
|
|
615
|
+
const save = (fields) => act({ action: "api.settings", apiRevision: a.revision, ...fields });
|
|
616
|
+
async function keyAction(action) {
|
|
617
|
+
const result = await act({ action, apiRevision: a.revision });
|
|
618
|
+
if (result) {
|
|
619
|
+
setKey(result.apiKey || "");
|
|
620
|
+
setConfirmKey(null);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
async function copy(value, fallback = false) {
|
|
624
|
+
try {
|
|
625
|
+
await navigator.clipboard.writeText(value);
|
|
626
|
+
setHint("\u5DF2\u590D\u5236\u3002");
|
|
627
|
+
} catch {
|
|
628
|
+
setHint("\u5F53\u524D\u73AF\u5883\u65E0\u6CD5\u81EA\u52A8\u590D\u5236\uFF0C\u8BF7\u5728\u6587\u672C\u6846\u4E2D\u5168\u9009\u590D\u5236\u3002");
|
|
629
|
+
if (fallback) copyField.current?.select();
|
|
630
|
+
else setExample(value);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
const model = a.models[0]?.id || "\u4F60\u7684\u8DEF\u7531\u6A21\u578B ID";
|
|
634
|
+
const command = `curl '${a.baseUrl}/chat/completions' \\
|
|
635
|
+
-H 'Authorization: Bearer YOUR_API_KEY' \\
|
|
636
|
+
-H 'Content-Type: application/json' \\
|
|
637
|
+
-d '${JSON.stringify({ model, messages: [{ role: "user", content: "\u4F60\u597D" }], stream: true })}'`;
|
|
638
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "stack", children: [
|
|
639
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
|
|
640
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
|
|
641
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
642
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "API \u670D\u52A1" }),
|
|
643
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u5C06\u8D26\u53F7\u6C60\u4E0E\u7EDF\u4E00\u8DEF\u7531\u63D0\u4F9B\u7ED9\u5176\u4ED6\u5DE5\u5177\u3002\u968F DSH \u8FD0\u884C\uFF0C\u9ED8\u8BA4\u5173\u95ED\u3002" })
|
|
644
|
+
] }),
|
|
645
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "status", role: "status", children: [
|
|
646
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("i", { className: a.phase === "running" ? "good" : a.phase === "error" ? "warn" : "", "aria-hidden": "true" }),
|
|
647
|
+
{ running: "\u8FD0\u884C\u4E2D", stopped: "\u5DF2\u5173\u95ED", starting: "\u542F\u52A8\u4E2D", error: "\u542F\u52A8\u5931\u8D25" }[a.phase] || a.phase
|
|
648
|
+
] })
|
|
649
|
+
] }),
|
|
650
|
+
a.error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "error", role: "alert", children: a.error }),
|
|
651
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
|
|
652
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: a.phase === "running" ? `${a.active} \u4E2A\u5904\u7406\u4E2D\u8BF7\u6C42 \xB7 ${a.allowLan ? "\u672C\u673A\u4E0E\u7F51\u7EDC\u8BBF\u95EE" : "\u4EC5\u672C\u673A\u8BBF\u95EE"}` : "\u5F00\u542F\u540E\u5373\u53EF\u590D\u5236\u63A5\u5165\u5730\u5740\uFF1B\u5173\u95ED\u4F1A\u7EC8\u6B62\u6B63\u5728\u5904\u7406\u7684 API \u8BF7\u6C42\u3002" }),
|
|
653
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check", children: [
|
|
654
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: a.enabled, disabled: busy || !a.hasKey, onChange: (e) => {
|
|
655
|
+
void save({ enabled: e.target.checked });
|
|
656
|
+
} }),
|
|
657
|
+
"\u542F\u7528 API \u670D\u52A1"
|
|
658
|
+
] })
|
|
659
|
+
] }),
|
|
660
|
+
!a.hasKey && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "steps", children: "\u5148\u751F\u6210 API Key\uFF0C\u518D\u542F\u7528\u670D\u52A1\u3002\u8D26\u53F7\u767B\u5F55\u51ED\u8BC1\u4E0D\u4F1A\u901A\u8FC7\u6B64\u670D\u52A1\u63D0\u4F9B\u3002" })
|
|
661
|
+
] }),
|
|
662
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "metrics", children: [
|
|
663
|
+
metric("\u4ECA\u65E5 API \u8C03\u7528", fmt(a.today.calls), `${a.today.attempts} \u6B21\u4E0A\u6E38\u5C1D\u8BD5\uFF0C\u542B\u6545\u969C\u5207\u6362`),
|
|
664
|
+
metric("\u4ECA\u65E5 API Token", fmt(a.today.tokens), "\u5E73\u53F0\u5B9E\u9645\u8FD4\u56DE\u7528\u91CF"),
|
|
665
|
+
metric("\u5DF2\u5F00\u653E\u6A21\u578B", fmt(a.models.length), a.modelIds === null ? "\u8DDF\u968F\u8DEF\u7531\u5C55\u793A\u8BBE\u7F6E" : "\u81EA\u9009\u6A21\u578B"),
|
|
666
|
+
metric("\u5904\u7406\u4E2D", fmt(a.active), "\u6700\u591A 8 \u4E2A\u5E76\u53D1 API \u8BF7\u6C42")
|
|
667
|
+
] }),
|
|
668
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
|
|
669
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar", children: [
|
|
670
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
671
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u63A5\u5165\u4FE1\u606F" }),
|
|
672
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u5BA2\u6237\u7AEF\u9009\u62E9 OpenAI \u517C\u5BB9\u65B9\u5F0F\uFF0C\u586B\u5199\u4E0B\u65B9 Base URL \u4E0E API Key\u3002" })
|
|
673
|
+
] }),
|
|
674
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => setExample(command), children: "\u8C03\u7528\u793A\u4F8B" })
|
|
675
|
+
] }),
|
|
676
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { children: [
|
|
677
|
+
"Base URL",
|
|
678
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
|
|
679
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "mono", style: { flex: 1, minWidth: 180 }, readOnly: true, value: a.baseUrl, onFocus: (e) => e.currentTarget.select() }),
|
|
680
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: () => {
|
|
681
|
+
void copy(a.baseUrl);
|
|
682
|
+
}, children: "\u590D\u5236\u5730\u5740" })
|
|
683
|
+
] })
|
|
684
|
+
] }),
|
|
685
|
+
a.allowLan && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
686
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u5176\u4ED6\u8BBE\u5907\u53EF\u4F7F\u7528\u4EE5\u4E0B\u672C\u673A\u7F51\u5361\u5730\u5740\uFF08\u9700\u8981\u7F51\u7EDC\u53EF\u8FBE\u53CA\u9632\u706B\u5899\u653E\u884C\uFF09\uFF1A" }),
|
|
687
|
+
a.lanUrls.length ? a.lanUrls.map((url) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mono", style: { overflowWrap: "anywhere" }, children: url }, url)) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u6682\u65E0\u53EF\u7528 IPv4 \u7F51\u5361\u5730\u5740\u3002" })
|
|
688
|
+
] }),
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { children: [
|
|
690
|
+
"API Key",
|
|
691
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
|
|
692
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { ref: copyField, className: "mono", style: { flex: 1, minWidth: 180 }, readOnly: true, autoComplete: "off", spellCheck: "false", value: key || a.keyHint || "\u5C1A\u672A\u751F\u6210", onFocus: (e) => e.currentTarget.select() }),
|
|
693
|
+
a.hasKey && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
694
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => {
|
|
695
|
+
if (key) setKey("");
|
|
696
|
+
else void keyAction("api.key.reveal");
|
|
697
|
+
}, children: key ? "\u9690\u85CF" : "\u663E\u793A" }),
|
|
698
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: async () => {
|
|
699
|
+
const result = await act({ action: "api.key.reveal", apiRevision: a.revision });
|
|
700
|
+
if (result?.apiKey) {
|
|
701
|
+
setKey(result.apiKey);
|
|
702
|
+
await copy(result.apiKey, true);
|
|
703
|
+
}
|
|
704
|
+
}, children: "\u590D\u5236 Key" })
|
|
705
|
+
] })
|
|
706
|
+
] })
|
|
707
|
+
] }),
|
|
708
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
|
|
709
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => {
|
|
710
|
+
if (a.hasKey) setConfirmKey("create");
|
|
711
|
+
else void keyAction("api.key.create");
|
|
712
|
+
}, children: a.hasKey ? "\u91CD\u7F6E API Key" : "\u751F\u6210 API Key" }),
|
|
713
|
+
a.hasKey && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => setConfirmKey("revoke"), children: "\u64A4\u9500 Key \u5E76\u5173\u95ED\u670D\u52A1" }),
|
|
714
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "Key \u4EC5\u4FDD\u5B58\u5728\u672C\u673A\u79C1\u6709\u6587\u4EF6\uFF1B\u663E\u793A\u540E 60 \u79D2\u81EA\u52A8\u9690\u85CF\u3002" })
|
|
715
|
+
] }),
|
|
716
|
+
hint && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", role: "status", children: hint })
|
|
717
|
+
] }),
|
|
718
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box stack", children: [
|
|
719
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u670D\u52A1\u8BBE\u7F6E" }),
|
|
720
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: "stack", onSubmit: (e) => {
|
|
721
|
+
e.preventDefault();
|
|
722
|
+
const f = new FormData(e.currentTarget);
|
|
723
|
+
void save({ port: Number(f.get("port")), allowLan: f.has("lan") });
|
|
724
|
+
}, children: [
|
|
725
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
|
|
726
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "filter", children: [
|
|
727
|
+
"\u76D1\u542C\u7AEF\u53E3",
|
|
728
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "number", name: "port", min: "1024", max: "65535", required: true, defaultValue: a.port, disabled: busy })
|
|
729
|
+
] }),
|
|
730
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check", children: [
|
|
731
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", name: "lan", defaultChecked: a.allowLan, disabled: busy }),
|
|
732
|
+
"\u5141\u8BB8\u5C40\u57DF\u7F51\u8BBF\u95EE"
|
|
733
|
+
] }),
|
|
734
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, children: "\u4FDD\u5B58\u8BBE\u7F6E" })
|
|
735
|
+
] }),
|
|
736
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u9ED8\u8BA4\u76D1\u542C 127.0.0.1\u3002\u5F00\u542F\u7F51\u7EDC\u8BBF\u95EE\u540E\u76D1\u542C\u6240\u6709 IPv4 \u7F51\u5361\uFF0C\u4F7F\u7528 HTTP\uFF0C\u8BF7\u4EC5\u7528\u4E8E\u53EF\u4FE1\u7F51\u7EDC\uFF1B\u5982\u9700\u5916\u7F51\u8BBF\u95EE\uFF0C\u8BF7\u81EA\u884C\u914D\u7F6E HTTPS \u4E0E\u8BBF\u95EE\u9650\u5236\u3002\u4FEE\u6539\u7AEF\u53E3\u6216\u8BBF\u95EE\u8303\u56F4\u4F1A\u4E2D\u65AD\u5F53\u524D API \u8BF7\u6C42\u3002" })
|
|
737
|
+
] }, a.revision)
|
|
738
|
+
] }),
|
|
739
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "box table-shell", children: [
|
|
740
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bar table-footer", children: [
|
|
741
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
742
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u5F00\u653E\u6A21\u578B" }),
|
|
743
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: a.modelIds === null ? "\u81EA\u52A8\u8DDF\u968F\u5DF2\u5C55\u793A\u8DEF\u7531\uFF0C\u5305\u542B\u52A8\u6001\u514D\u8D39\u6A21\u578B\u3002" : "\u4EC5\u5F00\u653E\u624B\u52A8\u9009\u62E9\u7684\u8DEF\u7531\u3002" })
|
|
744
|
+
] }),
|
|
745
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => setModels(true), children: "\u9009\u62E9\u5F00\u653E\u6A21\u578B" })
|
|
746
|
+
] }),
|
|
747
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "scroll", role: "region", "aria-label": "API \u5F00\u653E\u6A21\u578B", tabIndex: "0", children: [
|
|
748
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { className: "table", children: [
|
|
749
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
750
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u6A21\u578B\u540D\u79F0" }),
|
|
751
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u8C03\u7528\u6A21\u578B ID" })
|
|
752
|
+
] }) }),
|
|
753
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: a.models.map((m) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
754
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: m.name }),
|
|
755
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "mono", style: { overflowWrap: "anywhere" }, children: m.id })
|
|
756
|
+
] }, m.id)) })
|
|
757
|
+
] }),
|
|
758
|
+
!a.models.length && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "empty", children: "\u6682\u672A\u5F00\u653E\u6A21\u578B\uFF0C\u8BF7\u5C55\u793A\u8DEF\u7531\u6216\u624B\u52A8\u9009\u62E9\u3002" })
|
|
759
|
+
] })
|
|
760
|
+
] }),
|
|
761
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { children: [
|
|
762
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: "\u63A5\u53E3\u4E0E\u7EDF\u8BA1\u8BF4\u660E" }),
|
|
763
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u652F\u6301 GET /v1/models\u3001POST /v1/chat/completions\uFF08\u6D41\u5F0F\u4E0E\u666E\u901A JSON\uFF09\uFF0C\u6CBF\u7528\u8DEF\u7531\u7684\u63A8\u7406\u9ED8\u8BA4\u503C\uFF0C\u53EF\u7528 reasoning_effort \u8986\u76D6\u3002\u5DE5\u5177\u8C03\u7528\u4E0E\u56FE\u7247\u80FD\u529B\u53D6\u51B3\u4E8E\u76EE\u6807\u6A21\u578B\uFF1B\u5916\u90E8\u5DE5\u5177\u81EA\u884C\u6267\u884C\u5DE5\u5177\u5E76\u56DE\u4F20\u7ED3\u679C\u3002\u7528\u91CF\u8BB0\u5F55\u5230 Token \u660E\u7EC6\u7684\u300CAPI \u670D\u52A1\u300D\u6765\u6E90\uFF0C\u4E0D\u4FDD\u5B58\u8BF7\u6C42\u5185\u5BB9\u6216 Key\uFF1B\u4E0A\u4E0B\u6587\u7531\u8C03\u7528\u5BA2\u6237\u7AEF\u4F20\u5165\u3002\u6B64\u7248\u672C\u4E0D\u63D0\u4F9B Responses\u3001Embeddings \u6216\u8DE8\u7AD9\u6D4F\u89C8\u5668 CORS \u63A5\u53E3\u3002\u542F\u7528\u72B6\u6001\u4F1A\u4FDD\u5B58\uFF0CDSH \u4E0B\u6B21\u542F\u52A8\u81EA\u52A8\u6062\u590D\uFF1B\u9000\u51FA DSH \u540E\u505C\u6B62\u3002" })
|
|
764
|
+
] }),
|
|
765
|
+
confirmKey && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Modal, { title: confirmKey === "create" ? "\u91CD\u7F6E API Key" : "\u64A4\u9500 API Key", busy, close: () => setConfirmKey(null), children: [
|
|
766
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "modal-body stack", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: confirmKey === "create" ? "\u65E7 Key \u5C06\u7ACB\u5373\u5931\u6548\uFF0C\u5176\u4ED6\u5BA2\u6237\u7AEF\u9700\u8981\u586B\u5199\u65B0 Key\u3002" : "Key \u5C06\u7ACB\u5373\u5931\u6548\uFF0CAPI \u670D\u52A1\u4F1A\u5173\u95ED\uFF0C\u6B63\u5728\u5904\u7406\u7684 API \u8BF7\u6C42\u5C06\u4E2D\u65AD\u3002" }) }),
|
|
767
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "modal-foot row", children: [
|
|
768
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { disabled: busy, onClick: () => setConfirmKey(null), children: "\u53D6\u6D88" }),
|
|
769
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { className: "primary", disabled: busy, onClick: () => {
|
|
770
|
+
void keyAction(`api.key.${confirmKey}`);
|
|
771
|
+
}, children: [
|
|
772
|
+
"\u786E\u8BA4",
|
|
773
|
+
confirmKey === "create" ? "\u91CD\u7F6E" : "\u64A4\u9500"
|
|
774
|
+
] })
|
|
775
|
+
] })
|
|
776
|
+
] }),
|
|
777
|
+
models && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Modal, { title: "\u9009\u62E9 API \u5F00\u653E\u6A21\u578B", busy, close: () => setModels(false), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ApiModels, { data: a, busy, save: async (modelIds) => {
|
|
778
|
+
if (await save({ modelIds })) setModels(false);
|
|
779
|
+
} }) }),
|
|
780
|
+
example && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Modal, { title: "\u63A5\u5165\u793A\u4F8B / \u624B\u52A8\u590D\u5236", busy: false, close: () => setExample(""), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "modal-body stack", children: [
|
|
781
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u5C06 YOUR_API_KEY \u66FF\u6362\u4E3A\u81EA\u5DF1\u7684\u670D\u52A1 Key\u3002Base URL \u5DF2\u5305\u542B /v1\uFF1B\u6D4B\u8BD5\u8C03\u7528\u4F1A\u6B63\u5E38\u6D88\u8017\u76EE\u6807\u8D26\u53F7\u7684\u7528\u91CF\u3002" }),
|
|
782
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { children: [
|
|
783
|
+
"\u53EF\u590D\u5236\u5185\u5BB9",
|
|
784
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", { className: "mono", readOnly: true, rows: 8, value: example, onFocus: (e) => e.currentTarget.select() })
|
|
785
|
+
] })
|
|
786
|
+
] }) })
|
|
787
|
+
] });
|
|
788
|
+
}
|
|
789
|
+
function ApiModels({ data, busy, save }) {
|
|
790
|
+
const [follow, setFollow] = (0, import_react.useState)(data.modelIds === null), [selected, setSelected] = (0, import_react.useState)(data.modelIds ?? data.models.map((m) => m.id));
|
|
791
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { onSubmit: (e) => {
|
|
792
|
+
e.preventDefault();
|
|
793
|
+
void save(follow ? null : selected);
|
|
794
|
+
}, children: [
|
|
795
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "modal-body stack", children: [
|
|
796
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check", children: [
|
|
797
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: follow, disabled: busy, onChange: (e) => setFollow(e.target.checked) }),
|
|
798
|
+
"\u8DDF\u968F\u8DEF\u7531\u5C55\u793A\uFF08\u65B0\u53D1\u73B0\u7684\u514D\u8D39\u6A21\u578B\u4E5F\u81EA\u52A8\u5F00\u653E\uFF09"
|
|
799
|
+
] }),
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
|
|
801
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", disabled: busy || follow, onClick: () => setSelected(data.choices.map((m) => m.id)), children: "\u5168\u9009" }),
|
|
802
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", disabled: busy || follow, onClick: () => setSelected([]), children: "\u5168\u4E0D\u9009" })
|
|
803
|
+
] }),
|
|
804
|
+
data.choices.map((m) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "check", children: [
|
|
805
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", disabled: busy || follow, checked: follow ? m.visible : selected.includes(m.id), onChange: (e) => setSelected(e.target.checked ? [...selected, m.id] : selected.filter((id) => id !== m.id)) }),
|
|
806
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
807
|
+
m.name,
|
|
808
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "mono muted", style: { overflowWrap: "anywhere" }, children: m.id })
|
|
809
|
+
] })
|
|
810
|
+
] }, m.id)),
|
|
811
|
+
!data.choices.length && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: "\u8BF7\u5148\u6DFB\u52A0\u8DEF\u7531\u3002" })
|
|
812
|
+
] }),
|
|
813
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "modal-foot row", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "primary", disabled: busy, children: "\u4FDD\u5B58\u5F00\u653E\u8303\u56F4" }) })
|
|
814
|
+
] });
|
|
815
|
+
}
|
|
497
816
|
function ModelsPanel({ data, provider, providerSelect, search, setSearch, busy, act }) {
|
|
498
817
|
const [editing, setEditing] = (0, import_react.useState)(null);
|
|
499
818
|
const models = data.providers.find((p) => p.id === provider)?.models ?? [];
|
|
@@ -1054,11 +1373,11 @@ function PerformanceMetrics({ events }) {
|
|
|
1054
1373
|
] });
|
|
1055
1374
|
}
|
|
1056
1375
|
function UsageDetails({ data, busy, act }) {
|
|
1057
|
-
const [account, setAccount] = (0, import_react.useState)(""), [route, setRoute] = (0, import_react.useState)(""), [outcome, setOutcome] = (0, import_react.useState)(""), [page, setPage] = (0, import_react.useState)(0);
|
|
1376
|
+
const [account, setAccount] = (0, import_react.useState)(""), [route, setRoute] = (0, import_react.useState)(""), [outcome, setOutcome] = (0, import_react.useState)(""), [source, setSource] = (0, import_react.useState)(""), [page, setPage] = (0, import_react.useState)(0);
|
|
1058
1377
|
const [period, setPeriod] = (0, import_react.useState)("30"), [start, setStart] = (0, import_react.useState)(() => new Date(Date.now() - 29 * 864e5).toLocaleDateString("en-CA", { timeZone: "Asia/Shanghai" })), [end, setEnd] = (0, import_react.useState)(() => (/* @__PURE__ */ new Date()).toLocaleDateString("en-CA", { timeZone: "Asia/Shanghai" }));
|
|
1059
1378
|
const all = data.telemetry?.events || [], retention = data.options.usageRetentionDays;
|
|
1060
1379
|
const [from, until] = usageDateBounds(period, start, end), invalidRange = !(from < until);
|
|
1061
|
-
const events = all.filter((e) => e.at >= from && e.at < until && (!account || e.account === account) && (!route || e.alias === route) && (!outcome || e.outcome === outcome));
|
|
1380
|
+
const events = all.filter((e) => e.at >= from && e.at < until && (!account || e.account === account) && (!route || e.alias === route) && (!outcome || e.outcome === outcome) && (!source || (e.source || "dsh") === source));
|
|
1062
1381
|
const pages = Math.max(1, Math.ceil(events.length / 50)), current = Math.min(page, pages - 1);
|
|
1063
1382
|
const accountName = (id) => data.accounts.find((a) => a.id === id)?.name || id;
|
|
1064
1383
|
const routeName = (id) => data.routes.find((r) => r.id === id)?.name || id;
|
|
@@ -1145,6 +1464,17 @@ function UsageDetails({ data, busy, act }) {
|
|
|
1145
1464
|
[...new Set(all.map((e) => e.alias))].map((id) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: id, children: routeName(id) }, id))
|
|
1146
1465
|
] })
|
|
1147
1466
|
] }),
|
|
1467
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "filter", children: [
|
|
1468
|
+
"\u6765\u6E90",
|
|
1469
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { value: source, onChange: (e) => {
|
|
1470
|
+
setSource(e.target.value);
|
|
1471
|
+
setPage(0);
|
|
1472
|
+
}, children: [
|
|
1473
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "", children: "\u5168\u90E8\u6765\u6E90" }),
|
|
1474
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "dsh", children: "DSH \u4F1A\u8BDD" }),
|
|
1475
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "api", children: "API \u670D\u52A1" })
|
|
1476
|
+
] })
|
|
1477
|
+
] }),
|
|
1148
1478
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "filter", children: [
|
|
1149
1479
|
"\u7ED3\u679C",
|
|
1150
1480
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { value: outcome, onChange: (e) => {
|
|
@@ -1184,7 +1514,10 @@ function UsageDetails({ data, busy, act }) {
|
|
|
1184
1514
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "\u7ED3\u679C" })
|
|
1185
1515
|
] }) }),
|
|
1186
1516
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: events.slice(current * 50, (current + 1) * 50).map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
1187
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
1517
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", { children: [
|
|
1518
|
+
when(e.at),
|
|
1519
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { className: "muted", children: e.source === "api" ? "API \u670D\u52A1" : "DSH \u4F1A\u8BDD" })
|
|
1520
|
+
] }),
|
|
1188
1521
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", { children: [
|
|
1189
1522
|
data.providers.find((p) => p.id === e.provider)?.name || e.provider,
|
|
1190
1523
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}),
|