dsh-her 0.1.0-beta.1 → 0.2.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/lib/client.js CHANGED
@@ -33,7 +33,7 @@ __export(index_exports, {
33
33
  module.exports = __toCommonJS(index_exports);
34
34
 
35
35
  // src/client/Page.tsx
36
- var import_react3 = require("react");
36
+ var import_react5 = require("react");
37
37
 
38
38
  // src/client/api.ts
39
39
  async function post(path, body = {}) {
@@ -57,6 +57,14 @@ var herApi = {
57
57
  expandPersona: (input) => post("/persona/expand", input),
58
58
  tryPersona: (input) => post("/persona/try", input),
59
59
  previewVoice: (voice, speed, text) => post("/voice/preview", { voice, speed, ...text === void 0 ? {} : { text } }),
60
+ mingInstall: () => post("/voice/ming/install"),
61
+ mingUninstall: () => post("/voice/ming/uninstall"),
62
+ mingRestart: () => post("/voice/ming/restart"),
63
+ mingSettings: (patch) => post("/voice/ming/settings", patch),
64
+ mingDesign: (description) => post("/voice/ming/design", { description }),
65
+ mingClone: (audio, name) => post("/voice/ming/clone", { audio, name }),
66
+ mingKeep: (draft, name, change = {}) => post("/voice/ming/keep", { draft, name, ...change }),
67
+ mingRemove: (id) => post("/voice/ming/remove", { id }),
60
68
  startBody: () => post("/body/start"),
61
69
  installBody: () => post("/body/install"),
62
70
  restartBody: () => post("/body/restart"),
@@ -120,18 +128,31 @@ var VOICES = [
120
128
  { id: "longwan_v3", name: "\u9F99\u5A49", desc: "\u7EC6\u817B\uFF0C\u67D4\u58F0", service: "cosyvoice" },
121
129
  { id: "longyingling_v3", name: "\u9F99\u5E94\u8046", desc: "\u6E29\u548C\uFF0C\u4F1A\u5171\u60C5", service: "cosyvoice" },
122
130
  { id: "longanwen_v3", name: "\u9F99\u5B89\u6E29", desc: "\u4F18\u96C5\uFF0C\u77E5\u6027", service: "cosyvoice" },
123
- { id: "longxiaochun_v3", name: "\u9F99\u5C0F\u6DF3", desc: "\u77E5\u6027\uFF0C\u79EF\u6781", service: "cosyvoice" }
131
+ { id: "longxiaochun_v3", name: "\u9F99\u5C0F\u6DF3", desc: "\u77E5\u6027\uFF0C\u79EF\u6781", service: "cosyvoice" },
132
+ // Ming's built-in voices that suit her: grown-up women, warm or sweet (the catalog's "girlfriend" voices).
133
+ { id: "ming:\u7075\u98CE\u4FE1", name: "\u7075\u98CE\u4FE1", desc: "\u4F53\u8D34\uFF0C\u6E29\u6696\u5B89\u5FC3\uFF0C\u5E26\u60C5\u7EEA", service: "ming", moods: ["\u4E2D\u6027", "\u9AD8\u5174", "\u60B2\u4F24", "\u751F\u6C14", "\u538C\u6076"] },
134
+ { id: "ming:\u7075\u96E8\u6C50", name: "\u7075\u96E8\u6C50", desc: "\u8F6F\u7CEF\uFF0C\u6709\u6C14\u58F0\uFF0C\u5E26\u60C5\u7EEA", service: "ming", moods: ["\u4E2D\u6027", "\u9AD8\u5174", "\u60B2\u4F24", "\u60CA\u8BB6", "\u6050\u60E7"] },
135
+ { id: "ming:\u7075\u68A6", name: "\u7075\u68A6", desc: "\u5F88\u751C\uFF0C\u7231\u6492\u5A07", service: "ming" },
136
+ { id: "ming:\u7075\u606C", name: "\u7075\u606C", desc: "\u751C\u871C\uFF0C\u6E29\u67D4", service: "ming" },
137
+ { id: "ming:\u7075\u5C0F\u6C50", name: "\u7075\u5C0F\u6C50", desc: "\u6E05\u751C\uFF0C\u81EA\u7136", service: "ming" },
138
+ { id: "ming:\u7075\u5C0F\u82B8", name: "\u7075\u5C0F\u82B8", desc: "\u6E29\u548C\uFF0C\u50CF\u77E5\u5FC3\u670B\u53CB", service: "ming" }
124
139
  ];
125
140
  function voiceName(id) {
126
141
  return VOICES.find((v2) => v2.id === id)?.name ?? id;
127
142
  }
143
+ function serviceOf(id) {
144
+ if (id.startsWith("ming:") || id.startsWith(OWN_PREFIX)) return "ming";
145
+ return VOICES.find((v2) => v2.id === id)?.service ?? (/Neural$/.test(id) ? "edge" : "cosyvoice");
146
+ }
147
+ var OWN_PREFIX = "ming-own:";
128
148
  var SERVICE_NAMES = {
129
149
  edge: "\u5FAE\u8F6F Edge\uFF08\u514D\u8D39\uFF0C\u8981\u8054\u7F51\uFF09",
130
- cosyvoice: "\u963F\u91CC\u4E91\u767E\u70BC CosyVoice\uFF08\u8981 key\uFF0C\u6309\u5B57\u6570\u4ED8\u8D39\uFF09"
150
+ cosyvoice: "\u963F\u91CC\u4E91\u767E\u70BC CosyVoice\uFF08\u8981 key\uFF0C\u6309\u5B57\u6570\u4ED8\u8D39\uFF09",
151
+ ming: "\u672C\u673A Ming\uFF08\u79BB\u7EBF\u3001\u514D\u8D39\u3001\u80FD\u8868\u8FBE\u60C5\u7EEA\uFF1BApple \u82AF\u7247\uFF0C\u4E0B\u8F7D\u7EA6 2 GB\uFF09"
131
152
  };
132
153
 
133
154
  // src/client/Workshop.tsx
134
- var import_react = require("react");
155
+ var import_react2 = require("react");
135
156
 
136
157
  // src/core/workshop.ts
137
158
  var DESK_DIR = "\u684C\u5BA0";
@@ -182,6 +203,33 @@ function screenColor(card) {
182
203
  return /绿/.test(`${card.outfit}${card.extra}${card.sentence}`) ? { name: "\u7EAF\u7070\u8272", hex: "#808080" } : { name: "\u7EAF\u7EFF\u8272", hex: "#00B140" };
183
204
  }
184
205
  var POSE_WORDS = { stand: "\u7AD9\u7740", sit: "\u5750\u7740", lie: "\u8EBA\u7740" };
206
+ var WEB_HOW = '\u4E00\u6BB5\u6BB5\u751F\u6210\uFF1A\u4E0A\u4F20\u9996\u5E27\uFF0C\u7C98\u8D34\u63D0\u793A\u8BCD\uFF08\u6709"\u8D1F\u9762\u63D0\u793A\u8BCD"\u6846\u5C31\u628A\u8D1F\u9762\u63D0\u793A\u8BCD\u4E5F\u7C98\u8FDB\u53BB\uFF0C\u6709"\u5C3E\u5E27"\u5C31\u4E5F\u653E\u9996\u5E27\u90A3\u5F20\u56FE\uFF09\uFF0C\u4E0B\u8F7D\u540E\u6309\u6587\u4EF6\u540D\u5B58\u8FDB\u5BF9\u5E94\u7684\u6587\u4EF6\u5939\u3002\u300C\u751F\u6210\u6E05\u5355.md\u300D\u91CC\u6BCF\u6BB5\u90FD\u5217\u597D\u4E86\u3002';
207
+ var GENERATORS = {
208
+ minimax: {
209
+ name: "MiniMax Code",
210
+ label: "MiniMax Code\uFF08\u7ED9\u5B83\u4EFB\u52A1\u6587\u4EF6\uFF0C\u81EA\u52A8\u751F\u6210\u4E0B\u8F7D\uFF09",
211
+ settings: "MiniMax-Hailuo-2.3 \u56FE\u751F\u89C6\u9891\uFF0C1080P\uFF0C6 \u79D2\u3002",
212
+ how: '\u5728 MiniMax Code \u91CC\u8BF4\uFF1A"\u6309 <\u9879\u76EE\u6587\u4EF6\u5939>/MiniMax\u751F\u6210\u4EFB\u52A1.md \u751F\u6210"\uFF0C\u5B83\u4F1A\u4E00\u6BB5\u6BB5\u751F\u6210\u3001\u4E0B\u8F7D\u3001\u5B58\u597D\u3002'
213
+ },
214
+ comfyui: {
215
+ name: "ComfyUI",
216
+ label: "ComfyUI\uFF08\u672C\u5730\uFF0CWan 2.2 \u7B49\u56FE\u751F\u89C6\u9891\u5DE5\u4F5C\u6D41\uFF09",
217
+ settings: "\u56FE\u751F\u89C6\u9891\u5DE5\u4F5C\u6D41\uFF08\u6BD4\u5982 Wan 2.2 I2V\uFF09\uFF0C\u5C3A\u5BF8\u548C\u9996\u5E27\u540C\u6BD4\u4F8B\u3001\u77ED\u8FB9 720 \u4EE5\u4E0A\uFF0C\u7EA6 5 \u79D2\uFF0816 fps \u65F6 81 \u5E27\uFF09\uFF0C\u8D1F\u9762\u63D0\u793A\u8BCD\u653E\u8FDB\u8D1F\u9762\u8282\u70B9\uFF0C\u6BCF\u6BB5\u7528\u540C\u4E00\u5957\u53C2\u6570\u3002",
218
+ how: "\u7528\u4F60\u7684\u56FE\u751F\u89C6\u9891\u5DE5\u4F5C\u6D41\u4E00\u6BB5\u6BB5\u8DD1\uFF0C\u6216\u8005\u7528\u811A\u672C\u8BFB\u300CComfyUI\u751F\u6210\u6E05\u5355.json\u300D\uFF08\u6BCF\u6BB5\u7684\u9996\u5E27\u3001\u63D0\u793A\u8BCD\u3001\u8D1F\u9762\u63D0\u793A\u8BCD\u3001\u4FDD\u5B58\u8DEF\u5F84\uFF09\u6279\u91CF\u8DD1\u3002\u8F93\u51FA\u5B58\u6210\u6E05\u5355\u91CC\u7684\u6587\u4EF6\u540D\u3002"
219
+ },
220
+ jimeng: { name: "\u5373\u68A6", label: "\u5373\u68A6\uFF08\u7F51\u9875 / App\uFF09", settings: "\u56FE\u751F\u89C6\u9891\uFF0C1080P\uFF0C5 \u79D2\u3002", how: `\u5728\u5373\u68A6\u91CC${WEB_HOW}` },
221
+ kling: { name: "\u53EF\u7075", label: "\u53EF\u7075\uFF08\u7F51\u9875 / App\uFF09", settings: "\u56FE\u751F\u89C6\u9891\uFF0C1080P\uFF0C5 \u79D2\u3002", how: `\u5728\u53EF\u7075\u91CC${WEB_HOW}` },
222
+ hailuo: { name: "\u6D77\u87BA AI", label: "\u6D77\u87BA AI\uFF08MiniMax \u7684\u7F51\u9875\u7248\uFF09", settings: "\u56FE\u751F\u89C6\u9891\uFF0C1080P\uFF0C6 \u79D2\u3002", how: `\u5728\u6D77\u87BA AI \u91CC${WEB_HOW}` },
223
+ wanx: { name: "\u901A\u4E49\u4E07\u76F8", label: "\u901A\u4E49\u4E07\u76F8\uFF08\u7F51\u9875 / \u963F\u91CC\u4E91\u767E\u70BC\uFF09", settings: "\u56FE\u751F\u89C6\u9891\uFF0C1080P\uFF0C5 \u79D2\u3002", how: `\u5728\u901A\u4E49\u4E07\u76F8\u91CC${WEB_HOW}` },
224
+ vidu: { name: "Vidu", label: "Vidu\uFF08\u7F51\u9875\uFF09", settings: "\u56FE\u751F\u89C6\u9891\uFF0C1080P\uFF0C4\u20135 \u79D2\u3002", how: `\u5728 Vidu \u91CC${WEB_HOW}` }
225
+ };
226
+ var MANUAL_LABEL = "\u624B\u5DE5\u586B\u5199\uFF08\u522B\u7684\u5DE5\u5177\uFF0C\u81EA\u5DF1\u5199\u540D\u5B57\u548C\u8BBE\u7F6E\uFF09";
227
+ function generatorInfo(project) {
228
+ if (project.generator !== "manual" && project.generator in GENERATORS) return GENERATORS[project.generator];
229
+ const name = project.custom?.name.trim() || "\u4F60\u7528\u7684\u5DE5\u5177";
230
+ const settings = project.custom?.settings.trim() || "\u56FE\u751F\u89C6\u9891\uFF0C\u548C\u9996\u5E27\u540C\u6BD4\u4F8B\uFF0C1080P\uFF0C5\u20136 \u79D2\uFF0C\u6BCF\u6BB5\u7528\u540C\u4E00\u5957\u8BBE\u7F6E\u3002";
231
+ return { name, label: MANUAL_LABEL, settings, how: `\u5728${name}\u91CC${WEB_HOW}` };
232
+ }
185
233
  var PRESETS = [
186
234
  { role: "idle", n: 1, required: true, action: "\u5B89\u9759\u5730{pose}\uFF0C\u81EA\u7136\u547C\u5438\uFF0C\u5076\u5C14\u7728\u773C\uFF0C\u5934\u6781\u8F7B\u5FAE\u5730\u6643\u52A8\uFF0C\u5634\u5DF4\u95ED\u5408\uFF0C\u6D45\u6D45\u5730\u7B11" },
187
235
  { role: "talk", n: 1, required: true, action: "\u770B\u7740\u955C\u5934\u6E29\u67D4\u5730\u8BF4\u8BDD\uFF0C\u5634\u5DF4\u81EA\u7136\u6301\u7EED\u5F00\u5408\uFF0C\u8F7B\u8F7B\u70B9\u5934\uFF0C\u624B\u6709\u5F88\u5C0F\u7684\u52A8\u4F5C\u3002\u6700\u540E\u4E00\u79D2\u95ED\u5634\u56DE\u5230\u539F\u59FF\u52BF" },
@@ -235,7 +283,8 @@ function rules(project, kind, scene) {
235
283
  ].join("\u3002") + "\u3002";
236
284
  }
237
285
  function clipPrompt(project, kind, clip, scene) {
238
- return `${rules(project, kind, scene)}\u5979\u662F\uFF1A${describe(project.card)}\u3002${clip.action}\u3002`;
286
+ const prefix = project.generator === "manual" ? project.custom?.prefix.trim() ?? "" : "";
287
+ return `${prefix === "" ? "" : `${prefix.replace(/[,。,.\s]+$/, "")}\u3002`}${rules(project, kind, scene)}\u5979\u662F\uFF1A${describe(project.card)}\u3002${clip.action}\u3002`;
239
288
  }
240
289
  function referencePrompt(project) {
241
290
  const color = screenColor(project.card);
@@ -271,22 +320,58 @@ var EXAMPLE_SLOTS = {
271
320
  };
272
321
  var EXAMPLE_FILES = new Set(Object.values(EXAMPLE_SLOTS).flatMap((slots) => slots.map((s) => s.file)));
273
322
 
274
- // src/client/Workshop.tsx
323
+ // src/client/fold.tsx
324
+ var import_react = require("react");
275
325
  var import_jsx_runtime = require("react/jsx-runtime");
326
+ function Fold({ id, title, summary, tone, summaryClass, open, onToggle, children }) {
327
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `her-card her-foldcard${open ? " open" : ""}`, ...id === void 0 ? {} : { id }, children: [
328
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { className: "her-fold", onClick: onToggle, "aria-expanded": open, children: [
329
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `her-fold-arrow${open ? " open" : ""}`, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 16 16", width: "14", height: "14", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 3.5 10.5 8 6 12.5", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
330
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: title }),
331
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: `her-fold-sum ${summaryClass ?? "her-muted"}`, children: [
332
+ tone !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `her-dot ${tone}` }),
333
+ summary
334
+ ] }),
335
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-fold-toggle", children: open ? "\u6536\u8D77" : "\u5C55\u5F00" })
336
+ ] }),
337
+ open && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "her-fold-body", children })
338
+ ] });
339
+ }
340
+ function useFolds(key, initial) {
341
+ const [folds, setFolds] = (0, import_react.useState)(() => {
342
+ try {
343
+ return { ...initial, ...JSON.parse(localStorage.getItem(key) ?? "{}") };
344
+ } catch {
345
+ return initial;
346
+ }
347
+ });
348
+ const toggle = (0, import_react.useCallback)((card, open) => setFolds((current) => {
349
+ const next = { ...current, [card]: open ?? !current[card] };
350
+ try {
351
+ localStorage.setItem(key, JSON.stringify(next));
352
+ } catch {
353
+ }
354
+ return next;
355
+ }), [key]);
356
+ return [folds, toggle];
357
+ }
358
+
359
+ // src/client/Workshop.tsx
360
+ var import_jsx_runtime2 = require("react/jsx-runtime");
276
361
  var OWN = "__own__";
277
362
  var copy = (text) => void navigator.clipboard?.writeText(text);
278
363
  function Workshop({ state, apply: apply2 }) {
279
- const [items, setItems] = (0, import_react.useState)([]);
280
- const [open, setOpen] = (0, import_react.useState)();
281
- const [draft, setDraft] = (0, import_react.useState)();
282
- const [dirty, setDirty] = (0, import_react.useState)(false);
283
- const [newName, setNewName] = (0, import_react.useState)("");
284
- const [note, setNote] = (0, import_react.useState)();
285
- const reload = (0, import_react.useCallback)(async () => {
364
+ const [items, setItems] = (0, import_react2.useState)([]);
365
+ const [open, setOpen] = (0, import_react2.useState)();
366
+ const [draft, setDraft] = (0, import_react2.useState)();
367
+ const [dirty, setDirty] = (0, import_react2.useState)(false);
368
+ const [newName, setNewName] = (0, import_react2.useState)("");
369
+ const [note, setNote] = (0, import_react2.useState)();
370
+ const reload = (0, import_react2.useCallback)(async () => {
286
371
  const result = await herApi.workshopList();
287
372
  if (result.ok) setItems(result.projects);
288
373
  }, []);
289
- (0, import_react.useEffect)(() => {
374
+ (0, import_react2.useEffect)(() => {
290
375
  void reload();
291
376
  const timer = setInterval(() => void reload(), 4e3);
292
377
  return () => clearInterval(timer);
@@ -335,29 +420,21 @@ function Workshop({ state, apply: apply2 }) {
335
420
  if (dirty && !await save()) return;
336
421
  if (await apply2(herApi.workshopImport(draft.id))) setNote({ kind: "ok", text: "\u5F00\u59CB\u5BFC\u5165\uFF0C\u8FDB\u5EA6\u5728\u4E0B\u9762" });
337
422
  };
338
- const [unfolded, setUnfolded] = (0, import_react.useState)(() => loadFolds());
339
- const toggle = (card, on = !unfolded[card]) => setUnfolded((current) => {
340
- const next = { ...current, [card]: on };
341
- storeFolds(next);
342
- return next;
343
- });
423
+ const [unfolded, toggle] = useFolds(FOLDS_KEY, Object.fromEntries(CARDS.map((c) => [c, true])));
344
424
  const saveStep = async (card) => {
345
425
  if (dirty && !await save()) return;
346
426
  const at = CARDS.indexOf(card);
347
- setUnfolded((current) => {
348
- const next = { ...current, [card]: false, ...at + 1 < CARDS.length ? { [CARDS[at + 1]]: true } : {} };
349
- storeFolds(next);
350
- return next;
351
- });
427
+ toggle(card, false);
428
+ if (at + 1 < CARDS.length) toggle(CARDS[at + 1], true);
352
429
  if (!dirty) setNote({ kind: "ok", text: "\u8FD9\u4E00\u6B65\u5DF2\u7ECF\u4FDD\u5B58\u8FC7\u4E86" });
353
430
  };
354
- const [examples, setExamples] = (0, import_react.useState)([]);
355
- (0, import_react.useEffect)(() => {
431
+ const [examples, setExamples] = (0, import_react2.useState)([]);
432
+ (0, import_react2.useEffect)(() => {
356
433
  void herApi.workshopExamples().then((r) => {
357
434
  if (r.ok) setExamples(r.examples);
358
435
  });
359
436
  }, []);
360
- const [withMedia, setWithMedia] = (0, import_react.useState)(false);
437
+ const [withMedia, setWithMedia] = (0, import_react2.useState)(false);
361
438
  const exportProject = async () => {
362
439
  if (dirty && !await save()) return;
363
440
  setNote({ kind: "ok", text: "\u5728\u684C\u9762\u4E0A\u5F39\u51FA\u7684\u7A97\u53E3\u91CC\u9009\u4E00\u4E2A\u6587\u4EF6\u5939\u2026" });
@@ -380,86 +457,111 @@ function Workshop({ state, apply: apply2 }) {
380
457
  const screen = state.body.screens?.[0];
381
458
  const screenPx = screen === void 0 ? void 0 : { width: Math.round(screen.w * screen.scale), height: Math.round(screen.h * screen.scale) };
382
459
  const desk = status?.parts.find((p) => p.folder === DESK_DIR);
383
- const fold = (card, title, summary, done, body, saveLabel = "\u4FDD\u5B58\u8FD9\u4E00\u6B65") => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Fold, { card, title, summary, done, open: unfolded[card], onToggle: () => toggle(card), children: [
460
+ const fold = (card, title, summary, done, body, saveLabel = "\u4FDD\u5B58\u8FD9\u4E00\u6B65") => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Fold, { title, summary, summaryClass: done ? "her-ok" : "her-muted", open: unfolded[card], onToggle: () => toggle(card), children: [
384
461
  body,
385
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ExampleStrip, { examples: examples.filter((e) => e.card === card) }),
386
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-row", children: [
387
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "her-btn primary", onClick: () => void saveStep(card), children: saveLabel }),
388
- dirty && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-warn", children: "\u6709\u6539\u52A8\u8FD8\u6CA1\u4FDD\u5B58" })
462
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ExampleStrip, { examples: examples.filter((e) => e.card === card) }),
463
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
464
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn primary", onClick: () => void saveStep(card), children: saveLabel }),
465
+ dirty && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-warn", children: "\u6709\u6539\u52A8\u8FD8\u6CA1\u4FDD\u5B58" })
389
466
  ] })
390
467
  ] });
391
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
392
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-card", children: [
393
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: "\u5F62\u8C61\u5DE5\u574A" }),
394
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "her-muted", children: "\u505A\u4E00\u4E2A\u4F60\u81EA\u5DF1\u7684\u5979\uFF1A\u9009\u597D\u5979\u7684\u6837\u5B50\u3001\u5979\u4F4F\u5728\u54EA\u4E9B\u573A\u666F\u91CC\uFF0C\u8FD9\u91CC\u4F1A\u628A\u6BCF\u4E00\u5F20\u56FE\u3001\u6BCF\u4E00\u6BB5\u89C6\u9891\u7684\u63D0\u793A\u8BCD\u90FD\u5199\u597D\uFF0C\u653E\u8FDB\u300C\u6587\u7A3F / dsh-her \u7D20\u6750\u300D\u91CC\u7684\u4E00\u4E2A\u6587\u4EF6\u5939\u3002\u4F60\u7528\u8C46\u5305\u3001\u5373\u68A6\u3001MiniMax \u8FD9\u4E9B\u5DE5\u5177\u751F\u6210\uFF0C\u653E\u56DE\u6587\u4EF6\u5939\uFF0C\u518D\u4E00\u952E\u5BFC\u5165\u3002" }),
395
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "her-grid", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { className: `her-choice ${item.project.id === open ? "on" : ""}`, onClick: () => choose(item), children: [
468
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
469
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-card", children: [
470
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { children: "\u5F62\u8C61\u5DE5\u574A" }),
471
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: "\u505A\u4E00\u4E2A\u4F60\u81EA\u5DF1\u7684\u5979\uFF1A\u9009\u597D\u5979\u7684\u6837\u5B50\u3001\u5979\u4F4F\u5728\u54EA\u4E9B\u573A\u666F\u91CC\uFF0C\u8FD9\u91CC\u4F1A\u628A\u6BCF\u4E00\u5F20\u56FE\u3001\u6BCF\u4E00\u6BB5\u89C6\u9891\u7684\u63D0\u793A\u8BCD\u90FD\u5199\u597D\uFF0C\u653E\u8FDB\u300C\u6587\u7A3F / dsh-her \u7D20\u6750\u300D\u91CC\u7684\u4E00\u4E2A\u6587\u4EF6\u5939\u3002\u4F60\u7528\u5373\u68A6\u3001\u53EF\u7075\u3001MiniMax\u3001ComfyUI \u8FD9\u4E9B\u5DE5\u5177\u751F\u6210\uFF0C\u653E\u56DE\u6587\u4EF6\u5939\uFF0C\u518D\u4E00\u952E\u5BFC\u5165\u3002" }),
472
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "her-grid", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { className: `her-choice ${item.project.id === open ? "on" : ""}`, onClick: () => choose(item), children: [
396
473
  item.project.name,
397
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("small", { children: progressText(item.status) })
474
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("small", { children: progressText(item.status) })
398
475
  ] }, item.project.id)) }),
399
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-row", children: [
400
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "her-input", style: { flex: 1, minWidth: 160 }, value: newName, placeholder: "\u65B0\u5F62\u8C61\u7684\u540D\u5B57\uFF0C\u6BD4\u5982\uFF1A\u5C45\u5BB6\u773C\u955C", onChange: (e) => setNewName(e.target.value) }),
401
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "her-btn", disabled: newName.trim() === "", onClick: () => void create(), children: "\u65B0\u5EFA" }),
402
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "her-btn", onClick: () => void importProject(), children: "\u5BFC\u5165\u5DF2\u6709\u9879\u76EE\u2026" })
476
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
477
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", style: { flex: 1, minWidth: 160 }, value: newName, placeholder: "\u65B0\u5F62\u8C61\u7684\u540D\u5B57\uFF0C\u6BD4\u5982\uFF1A\u5C45\u5BB6\u773C\u955C", onChange: (e) => setNewName(e.target.value) }),
478
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", disabled: newName.trim() === "", onClick: () => void create(), children: "\u65B0\u5EFA" }),
479
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", onClick: () => void importProject(), children: "\u5BFC\u5165\u5DF2\u6709\u9879\u76EE\u2026" })
403
480
  ] }),
404
- draft !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-row", children: [
405
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { className: "her-btn", onClick: () => void exportProject(), children: [
481
+ draft !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
482
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { className: "her-btn", onClick: () => void exportProject(), children: [
406
483
  "\u628A\u300C",
407
484
  draft.name,
408
485
  "\u300D\u5BFC\u51FA\u5230\u6587\u4EF6\u5939\u2026"
409
486
  ] }),
410
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { children: [
411
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: withMedia, onChange: (e) => setWithMedia(e.target.checked) }),
487
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
488
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "checkbox", checked: withMedia, onChange: (e) => setWithMedia(e.target.checked) }),
412
489
  " \u8FDE\u540C\u56FE\u7247\u548C\u89C6\u9891"
413
490
  ] }),
414
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-muted", children: '\u4E0D\u52FE\u53EA\u5BFC\u51FA\u8BBE\u7F6E\uFF08\u5F62\u8C61.json \u548C\u6240\u6709\u63D0\u793A\u8BCD\uFF09\uFF0C\u5F88\u5C0F\uFF1B\u5BFC\u51FA\u7684\u6587\u4EF6\u5939\u5728\u522B\u7684\u7535\u8111\u4E0A\u7528"\u5BFC\u5165\u5DF2\u6709\u9879\u76EE"\u6253\u5F00\u3002' })
491
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-muted", children: '\u4E0D\u52FE\u53EA\u5BFC\u51FA\u8BBE\u7F6E\uFF08\u5F62\u8C61.json \u548C\u6240\u6709\u63D0\u793A\u8BCD\uFF09\uFF0C\u5F88\u5C0F\uFF1B\u5BFC\u51FA\u7684\u6587\u4EF6\u5939\u5728\u522B\u7684\u7535\u8111\u4E0A\u7528"\u5BFC\u5165\u5DF2\u6709\u9879\u76EE"\u6253\u5F00\u3002' })
415
492
  ] }),
416
- draft === void 0 && note !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: note.kind === "error" ? "her-danger" : "her-ok", children: note.text })
493
+ draft === void 0 && note !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: note.kind === "error" ? "her-danger" : "her-ok", children: note.text })
417
494
  ] }),
418
- draft !== void 0 && status !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
419
- fold("look", "1. \u5979\u957F\u4EC0\u4E48\u6837", describe(draft.card), true, /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
420
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-row", children: [
421
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1, minWidth: 160 }, children: [
422
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "her-label", children: "\u5F62\u8C61\u540D\u5B57" }),
423
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "her-input", value: draft.name, onChange: (e) => edit((p) => {
495
+ draft !== void 0 && status !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
496
+ fold("look", "1. \u5979\u957F\u4EC0\u4E48\u6837", describe(draft.card), true, /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
497
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
498
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { flex: 1, minWidth: 160 }, children: [
499
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u5F62\u8C61\u540D\u5B57" }),
500
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", value: draft.name, onChange: (e) => edit((p) => {
424
501
  p.name = e.target.value;
425
502
  }) })
426
503
  ] }),
427
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { flex: 1, minWidth: 160 }, children: [
428
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "her-label", children: "\u7528\u4EC0\u4E48\u751F\u6210\u89C6\u9891" }),
429
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { className: "her-select", value: draft.generator, onChange: (e) => edit((p) => {
504
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { flex: 1, minWidth: 160 }, children: [
505
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u7528\u4EC0\u4E48\u751F\u6210\u89C6\u9891" }),
506
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { className: "her-select", value: draft.generator, onChange: (e) => edit((p) => {
430
507
  p.generator = e.target.value;
508
+ if (p.generator === "manual") p.custom ??= { name: "", settings: "", prefix: "" };
431
509
  }), children: [
432
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "minimax", children: "MiniMax Code\uFF08\u7ED9\u5B83\u4EFB\u52A1\u6587\u4EF6\uFF0C\u81EA\u52A8\u751F\u6210\u4E0B\u8F7D\uFF09" }),
433
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "manual", children: "\u5373\u68A6\u3001\u53EF\u7075\u7B49\uFF08\u81EA\u5DF1\u4E00\u6BB5\u6BB5\u590D\u5236\u63D0\u793A\u8BCD\uFF09" })
510
+ Object.keys(GENERATORS).map((id) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: id, children: GENERATORS[id].label }, id)),
511
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "manual", children: MANUAL_LABEL })
434
512
  ] })
435
513
  ] })
436
514
  ] }),
437
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CardEditor, { card: draft.card, onChange: (card) => edit((p) => {
515
+ draft.generator === "manual" && draft.custom !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
516
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { flex: 1, minWidth: 140 }, children: [
517
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u5DE5\u5177\u540D\u5B57" }),
518
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", value: draft.custom.name, placeholder: "\u6BD4\u5982 Runway\u3001PixVerse\u3001\u81EA\u5DF1\u7684\u5DE5\u4F5C\u6D41", onChange: (e) => edit((p) => {
519
+ p.custom.name = e.target.value;
520
+ }) })
521
+ ] }),
522
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { flex: 2, minWidth: 220 }, children: [
523
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u7EDF\u4E00\u8BBE\u7F6E\uFF08\u5199\u8FDB\u6BCF\u4E2A\u63D0\u793A\u8BCD\u6587\u4EF6\u7684\u5F00\u5934\uFF09" }),
524
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", value: draft.custom.settings, placeholder: generatorInfo({ generator: "manual" }).settings, onChange: (e) => edit((p) => {
525
+ p.custom.settings = e.target.value;
526
+ }) })
527
+ ] }),
528
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { flex: "1 1 100%" }, children: [
529
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u6BCF\u6BB5\u63D0\u793A\u8BCD\u524D\u9762\u52A0\uFF08\u53EF\u4EE5\u4E0D\u586B\uFF1B\u6BD4\u5982 LoRA \u89E6\u53D1\u8BCD\u3001\u753B\u98CE\u8BCD\uFF09" }),
530
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", value: draft.custom.prefix, onChange: (e) => edit((p) => {
531
+ p.custom.prefix = e.target.value;
532
+ }) })
533
+ ] })
534
+ ] }),
535
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "her-muted", children: [
536
+ "\u7EDF\u4E00\u8BBE\u7F6E\uFF1A",
537
+ generatorInfo(draft).settings
538
+ ] }),
539
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CardEditor, { card: draft.card, onChange: (card) => edit((p) => {
438
540
  p.card = card;
439
541
  }) }),
440
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "her-label", children: "\u89D2\u8272\u63CF\u8FF0\uFF08\u6BCF\u5F20\u56FE\u3001\u6BCF\u6BB5\u89C6\u9891\u90FD\u7528\u8FD9\u4E00\u53E5\uFF0C\u5979\u624D\u662F\u540C\u4E00\u4E2A\u4EBA\uFF1B\u53EF\u4EE5\u76F4\u63A5\u6539\uFF09" }),
441
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", { className: "her-textarea", style: { minHeight: 60 }, value: draft.card.sentence, placeholder: describe({ ...draft.card, sentence: "" }), onChange: (e) => edit((p) => {
542
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u89D2\u8272\u63CF\u8FF0\uFF08\u6BCF\u5F20\u56FE\u3001\u6BCF\u6BB5\u89C6\u9891\u90FD\u7528\u8FD9\u4E00\u53E5\uFF0C\u5979\u624D\u662F\u540C\u4E00\u4E2A\u4EBA\uFF1B\u53EF\u4EE5\u76F4\u63A5\u6539\uFF09" }),
543
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("textarea", { className: "her-textarea", style: { minHeight: 60 }, value: draft.card.sentence, placeholder: describe({ ...draft.card, sentence: "" }), onChange: (e) => edit((p) => {
442
544
  p.card.sentence = e.target.value;
443
545
  }) })
444
546
  ] })),
445
- fold("reference", '2. \u53C2\u8003\u56FE\uFF08\u5979\u7684"\u8EAB\u4EFD\u8BC1"\uFF09', status.reference ? "\u2713 \u5DF2\u6709 \u53C2\u8003\u56FE.png" : "\u8FD8\u6CA1\u6709 \u53C2\u8003\u56FE.png", status.reference, /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
446
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { children: [
447
- status.reference ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-ok", children: "\u2713 \u5DF2\u6709 \u53C2\u8003\u56FE.png" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-warn", children: "\u8FD8\u6CA1\u6709 \u53C2\u8003\u56FE.png" }),
547
+ fold("reference", '2. \u53C2\u8003\u56FE\uFF08\u5979\u7684"\u8EAB\u4EFD\u8BC1"\uFF09', status.reference ? "\u2713 \u5DF2\u6709 \u53C2\u8003\u56FE.png" : "\u8FD8\u6CA1\u6709 \u53C2\u8003\u56FE.png", status.reference, /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
548
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
549
+ status.reference ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-ok", children: "\u2713 \u5DF2\u6709 \u53C2\u8003\u56FE.png" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-warn", children: "\u8FD8\u6CA1\u6709 \u53C2\u8003\u56FE.png" }),
448
550
  "\uFF1A\u7EAF\u8272\u80CC\u666F\u3001\u5168\u8EAB\u3001\u6B63\u9762\u7AD9\u7ACB\u3002\u7528\u6587\u751F\u56FE\u5DE5\u5177\u6309\u4E0B\u9762\u7684\u63D0\u793A\u8BCD\u751F\u6210\uFF0C\u5B58\u6210\u300C\u53C2\u8003\u56FE.png\u300D\u653E\u8FDB\u9879\u76EE\u6587\u4EF6\u5939\u3002\u4E4B\u540E\u6BCF\u4E2A\u573A\u666F\u7684\u7167\u7247\u90FD\u8981\u7528\u5B83\u5F53\u53C2\u8003\u56FE\u3002"
449
551
  ] }),
450
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PromptBox, { text: referencePrompt(draft) })
552
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PromptBox, { text: referencePrompt(draft) })
451
553
  ] })),
452
- fold("desk", "3. \u684C\u5BA0\uFF08\u6D6E\u5728\u6700\u4E0A\u5C42\u65F6\u7684\u5979\uFF09", !draft.desk.on ? "\u4E0D\u8981\u684C\u5BA0" : desk === void 0 ? "\u8FD8\u6CA1\u4FDD\u5B58" : `${desk.made}/${desk.planned} \u6BB5${desk.enough ? "\uFF0C\u591F\u7528\u4E86" : ""}`, !draft.desk.on || desk?.enough === true, /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
453
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { children: [
454
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: draft.desk.on, onChange: (e) => edit((p) => {
554
+ fold("desk", "3. \u684C\u5BA0\uFF08\u6D6E\u5728\u6700\u4E0A\u5C42\u65F6\u7684\u5979\uFF09", !draft.desk.on ? "\u4E0D\u8981\u684C\u5BA0" : desk === void 0 ? "\u8FD8\u6CA1\u4FDD\u5B58" : `${desk.made}/${desk.planned} \u6BB5${desk.enough ? "\uFF0C\u591F\u7528\u4E86" : ""}`, !draft.desk.on || desk?.enough === true, /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
555
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
556
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "checkbox", checked: draft.desk.on, onChange: (e) => edit((p) => {
455
557
  p.desk.on = e.target.checked;
456
558
  }) }),
457
559
  " \u8981\u684C\u5BA0\uFF1A\u7EFF\u5E55\u5168\u8EAB\u89C6\u9891\uFF0C\u5BFC\u5165\u65F6\u62A0\u6389\u80CC\u666F\uFF0C\u5979\u6D6E\u5728\u6240\u6709\u7A97\u53E3\u4E0A\u9762"
458
560
  ] }),
459
- draft.desk.on && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
460
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PartStatusLine, { status: desk }),
461
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "her-muted", children: "\u9996\u5E27\u7528\u300C\u53C2\u8003\u56FE.png\u300D\uFF0C\u751F\u6210\u7AD6\u7248 9:16\u30011080P\u30015\u20136 \u79D2\u3002" }),
462
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ClipList, { project: draft, kind: "desk", clips: draft.desk.clips, pose: "stand", onChange: (clips) => edit((p) => {
561
+ draft.desk.on && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
562
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PartStatusLine, { status: desk }),
563
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: "\u9996\u5E27\u7528\u300C\u53C2\u8003\u56FE.png\u300D\uFF0C\u751F\u6210\u7AD6\u7248 9:16\u30011080P\u30015\u20136 \u79D2\u3002" }),
564
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipList, { project: draft, kind: "desk", clips: draft.desk.clips, pose: "stand", onChange: (clips) => edit((p) => {
463
565
  p.desk.clips = clips;
464
566
  }) })
465
567
  ] })
@@ -470,12 +572,12 @@ function Workshop({ state, apply: apply2 }) {
470
572
  }).join(" \xB7 "), draft.scenes.length > 0 && draft.scenes.every((sc) => {
471
573
  const part = status.parts.find((p) => p.folder === sceneDir(sc));
472
574
  return part?.enough === true && part.framed === true;
473
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
474
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "her-muted", children: [
575
+ }), /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
576
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "her-muted", children: [
475
577
  '\u6BCF\u4E2A\u573A\u666F\u662F\u4E00\u5F20\u5168\u5C4F\u7167\u7247\uFF0C\u5979\u5728\u7167\u7247\u91CC\u7684\u4E00\u5757\u5730\u65B9\u52A8\u3002\u81EA\u52A8\u6362\u573A\u666F\u6309\u4E0B\u9762\u7684\u65F6\u95F4\u548C"\u4F60\u5728\u4E0D\u5728"\u6765\u9009\u3002',
476
578
  screenPx === void 0 ? "" : `\u4F60\u7684\u5C4F\u5E55\u662F ${screenPx.width}\xD7${screenPx.height}\uFF0C\u7167\u7247\u5C31\u505A\u8FD9\u4E48\u5927\u3002`
477
579
  ] }),
478
- draft.scenes.map((scene, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
580
+ draft.scenes.map((scene, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
479
581
  SceneEditor,
480
582
  {
481
583
  project: draft,
@@ -496,71 +598,47 @@ function Workshop({ state, apply: apply2 }) {
496
598
  },
497
599
  scene.id
498
600
  )),
499
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "her-btn", onClick: () => edit((p) => {
601
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", onClick: () => edit((p) => {
500
602
  p.scenes.push(newScene(`s${Date.now().toString(36)}`, `\u573A\u666F${p.scenes.length + 1}`));
501
603
  }), children: "\u52A0\u4E00\u4E2A\u573A\u666F" })
502
604
  ] })),
503
- fold("import", "5. \u751F\u6210\u3001\u5BFC\u5165", status.importable ? "\u53EF\u4EE5\u5BFC\u5165\u4E86" : "\u7247\u6BB5\u8FD8\u4E0D\u591F", false, /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
504
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("ol", { className: "her-muted", style: { margin: "4px 0", paddingLeft: 18 }, children: [
505
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
506
- '\u6BCF\u4E00\u6B65\u586B\u5B8C\u70B9"\u4FDD\u5B58\u8FD9\u4E00\u6B65"\uFF1A\u63D0\u793A\u8BCD\u5199\u8FDB\u9879\u76EE\u6587\u4EF6\u5939',
507
- draft.generator === "minimax" ? "\uFF0C\u8FD8\u6709\u7ED9 MiniMax Code \u7684\u300CMiniMax\u751F\u6210\u4EFB\u52A1.md\u300D" : "",
605
+ fold("import", "5. \u751F\u6210\u3001\u5BFC\u5165", status.importable ? "\u53EF\u4EE5\u5BFC\u5165\u4E86" : "\u7247\u6BB5\u8FD8\u4E0D\u591F", false, /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
606
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("ol", { className: "her-muted", style: { margin: "4px 0", paddingLeft: 18 }, children: [
607
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { children: [
608
+ '\u6BCF\u4E00\u6B65\u586B\u5B8C\u70B9"\u4FDD\u5B58\u8FD9\u4E00\u6B65"\uFF1A\u63D0\u793A\u8BCD\u5199\u8FDB\u9879\u76EE\u6587\u4EF6\u5939\uFF0C\u6240\u6709\u7247\u6BB5\u5217\u5728\u300C\u751F\u6210\u6E05\u5355.md\u300D',
609
+ draft.generator === "minimax" ? "\uFF0C\u8FD8\u6709\u7ED9 MiniMax Code \u7684\u300CMiniMax\u751F\u6210\u4EFB\u52A1.md\u300D" : draft.generator === "comfyui" ? "\uFF0C\u8FD8\u6709\u7ED9\u811A\u672C\u7528\u7684\u300CComfyUI\u751F\u6210\u6E05\u5355.json\u300D" : "",
508
610
  "\u3002"
509
611
  ] }),
510
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: draft.generator === "minimax" ? '\u5728 MiniMax Code \u91CC\u8BF4\uFF1A"\u6309 <\u9879\u76EE\u6587\u4EF6\u5939>/MiniMax\u751F\u6210\u4EFB\u52A1.md \u751F\u6210"\u3002' : "\u5728\u5373\u68A6\u3001\u53EF\u7075\u91CC\u4E00\u6BB5\u6BB5\u751F\u6210\uFF0C\u6309\u63D0\u793A\u8BCD\u91CC\u7684\u6587\u4EF6\u540D\u5B58\u8FDB\u5BF9\u5E94\u7684\u6587\u4EF6\u5939\u3002" }),
511
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: '\u573A\u666F\u7684\u7167\u7247\u653E\u597D\u540E\u70B9"\u6846\u4EBA\u7269\u533A"\uFF1B\u7247\u6BB5\u9F50\u4E86\u5C31"\u5BFC\u5165\u8FD9\u4E2A\u5F62\u8C61"\u3002\u6BCF\u90E8\u5206\u81F3\u5C11\u8981 3 \u6BB5\uFF08\u5F85\u673A\u3001\u8BF4\u8BDD \xD72\uFF09\uFF0C\u5176\u4ED6\u7684\u4EE5\u540E\u8865\uFF0C\u518D\u5BFC\u5165\u4E00\u6B21\u5C31\u4F1A\u66F4\u65B0\u3002' })
612
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { children: generatorInfo(draft).how }),
613
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { children: '\u573A\u666F\u7684\u7167\u7247\u653E\u597D\u540E\u70B9"\u6846\u4EBA\u7269\u533A"\uFF1B\u7247\u6BB5\u9F50\u4E86\u5C31"\u5BFC\u5165\u8FD9\u4E2A\u5F62\u8C61"\u3002\u6BCF\u90E8\u5206\u81F3\u5C11\u8981 3 \u6BB5\uFF08\u5F85\u673A\u3001\u8BF4\u8BDD \xD72\uFF09\uFF0C\u5176\u4ED6\u7684\u4EE5\u540E\u8865\uFF0C\u518D\u5BFC\u5165\u4E00\u6B21\u5C31\u4F1A\u66F4\u65B0\u3002' })
512
614
  ] }),
513
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-row", children: [
514
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "her-btn", onClick: () => void herApi.workshopOpen(draft.id).then((r) => report(r, "\u5DF2\u6253\u5F00\u6587\u4EF6\u5939")), children: "\u6253\u5F00\u6587\u4EF6\u5939" }),
515
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "her-btn", disabled: !status.importable || state.import.state === "running", onClick: () => void importLook(), children: "\u5BFC\u5165\u8FD9\u4E2A\u5F62\u8C61" })
615
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
616
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", onClick: () => void herApi.workshopOpen(draft.id).then((r) => report(r, "\u5DF2\u6253\u5F00\u6587\u4EF6\u5939")), children: "\u6253\u5F00\u6587\u4EF6\u5939" }),
617
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", disabled: !status.importable || state.import.state === "running", onClick: () => void importLook(), children: "\u5BFC\u5165\u8FD9\u4E2A\u5F62\u8C61" })
516
618
  ] }),
517
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImportProgress, { state })
619
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ImportProgress, { state })
518
620
  ] }), "\u4FDD\u5B58"),
519
- note !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: note.kind === "error" ? "her-danger" : "her-ok", children: note.text })
621
+ note !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: note.kind === "error" ? "her-danger" : "her-ok", children: note.text })
520
622
  ] })
521
623
  ] });
522
624
  }
523
625
  var CARDS = ["look", "reference", "desk", "scene", "import"];
524
626
  var FOLDS_KEY = "dsh-her.workshop.open";
525
- function loadFolds() {
526
- const all = Object.fromEntries(CARDS.map((c) => [c, true]));
527
- try {
528
- return { ...all, ...JSON.parse(localStorage.getItem(FOLDS_KEY) ?? "{}") };
529
- } catch {
530
- return all;
531
- }
532
- }
533
- function storeFolds(folds) {
534
- try {
535
- localStorage.setItem(FOLDS_KEY, JSON.stringify(folds));
536
- } catch {
537
- }
538
- }
539
- function Fold({ title, summary, done, open, onToggle, children }) {
540
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-card", children: [
541
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { className: "her-fold", onClick: onToggle, "aria-expanded": open, children: [
542
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-fold-arrow", children: open ? "\u25BE" : "\u25B8" }),
543
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: title }),
544
- !open && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `her-fold-sum ${done ? "her-ok" : "her-muted"}`, children: summary })
545
- ] }),
546
- open && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children })
547
- ] });
548
- }
549
627
  function ExampleStrip({ examples }) {
550
628
  if (examples.length === 0) return null;
551
629
  const src = (file) => new URL(`/api/dsh-her/example?f=${encodeURIComponent(file)}`, document.baseURI).href;
552
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-examples", children: [
553
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-label", children: "\u793A\u4F8B" }),
554
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "her-example-row", children: examples.map((e) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("figure", { className: "her-example", children: [
555
- !e.ready ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-example-empty", children: [
630
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-examples", children: [
631
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-label", children: "\u793A\u4F8B" }),
632
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "her-example-row", children: examples.map((e) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("figure", { className: "her-example", children: [
633
+ !e.ready ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-example-empty", children: [
556
634
  "\u793A\u4F8B\u5F85\u653E",
557
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}),
558
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("code", { children: [
635
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("br", {}),
636
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("code", { children: [
559
637
  "examples/workshop/",
560
638
  e.file
561
639
  ] })
562
- ] }) : e.file.endsWith(".mp4") ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("video", { src: src(e.file), muted: true, loop: true, playsInline: true, onMouseEnter: (ev) => void ev.currentTarget.play(), onMouseLeave: (ev) => ev.currentTarget.pause() }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: src(e.file), alt: e.label }),
563
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("figcaption", { children: e.label })
640
+ ] }) : e.file.endsWith(".mp4") ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("video", { src: src(e.file), muted: true, loop: true, playsInline: true, onMouseEnter: (ev) => void ev.currentTarget.play(), onMouseLeave: (ev) => ev.currentTarget.pause() }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { src: src(e.file), alt: e.label }),
641
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("figcaption", { children: e.label })
564
642
  ] }, e.file)) })
565
643
  ] });
566
644
  }
@@ -569,120 +647,120 @@ function progressText(status) {
569
647
  return status.parts.map((p) => `${p.name} ${p.made}/${p.planned}${p.framed === false ? p.photo === true ? "\xB7\u672A\u6846" : "\xB7\u7F3A\u7167\u7247" : ""}`).join(" \xB7 ");
570
648
  }
571
649
  function PartStatusLine({ status }) {
572
- if (status === void 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "her-muted", children: "\u4FDD\u5B58\u540E\u4F1A\u5EFA\u597D\u8FD9\u90E8\u5206\u7684\u6587\u4EF6\u5939\u3002" });
573
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { children: [
650
+ if (status === void 0) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: "\u4FDD\u5B58\u540E\u4F1A\u5EFA\u597D\u8FD9\u90E8\u5206\u7684\u6587\u4EF6\u5939\u3002" });
651
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
574
652
  "\u5DF2\u6709 ",
575
653
  status.made,
576
654
  "/",
577
655
  status.planned,
578
656
  " \u6BB5",
579
- status.enough ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-ok", children: "\uFF0C\u591F\u7528\u4E86" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-warn", children: "\uFF0C\u6700\u5C11\u8981\u5F85\u673A\u3001\u8BF4\u8BDD \xD72 \u8FD9 3 \u6BB5" }),
580
- status.photo === false && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-warn", children: "\uFF1B\u8FD8\u6CA1\u6709\u7167\u7247 plate.png" }),
581
- status.photo === true && status.framed === false && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-warn", children: "\uFF1B\u7167\u7247\u6709\u4E86\uFF0C\u8FD8\u6CA1\u6846\u4EBA\u7269\u533A" }),
582
- status.framed === true && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-ok", children: "\uFF1B\u4EBA\u7269\u533A\u5DF2\u6846\u597D" })
657
+ status.enough ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-ok", children: "\uFF0C\u591F\u7528\u4E86" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-warn", children: "\uFF0C\u6700\u5C11\u8981\u5F85\u673A\u3001\u8BF4\u8BDD \xD72 \u8FD9 3 \u6BB5" }),
658
+ status.photo === false && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-warn", children: "\uFF1B\u8FD8\u6CA1\u6709\u7167\u7247 plate.png" }),
659
+ status.photo === true && status.framed === false && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-warn", children: "\uFF1B\u7167\u7247\u6709\u4E86\uFF0C\u8FD8\u6CA1\u6846\u4EBA\u7269\u533A" }),
660
+ status.framed === true && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-ok", children: "\uFF1B\u4EBA\u7269\u533A\u5DF2\u6846\u597D" })
583
661
  ] });
584
662
  }
585
663
  function PromptBox({ text }) {
586
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-row", style: { alignItems: "flex-start" }, children: [
587
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "her-chat", style: { flex: 1, margin: 0, whiteSpace: "pre-wrap" }, children: text }),
588
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "her-btn small", onClick: () => copy(text), children: "\u590D\u5236" })
664
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", style: { alignItems: "flex-start" }, children: [
665
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "her-chat", style: { flex: 1, margin: 0, whiteSpace: "pre-wrap" }, children: text }),
666
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn small", onClick: () => copy(text), children: "\u590D\u5236" })
589
667
  ] });
590
668
  }
591
669
  function CardEditor({ card, onChange }) {
592
670
  const fields = Object.keys(CARD_CHOICES);
593
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-grid", children: [
671
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-grid", children: [
594
672
  fields.map((field) => {
595
673
  const choices = CARD_CHOICES[field];
596
674
  const own = !choices.includes(card[field]);
597
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
598
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "her-label", children: CARD_LABELS[field] }),
599
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { className: "her-select", value: own ? OWN : card[field], onChange: (e) => onChange({ ...card, [field]: e.target.value === OWN ? "" : e.target.value }), children: [
600
- choices.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: c, children: c }, c)),
601
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: OWN, children: "\u81EA\u5DF1\u5199\u2026" })
675
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
676
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: CARD_LABELS[field] }),
677
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { className: "her-select", value: own ? OWN : card[field], onChange: (e) => onChange({ ...card, [field]: e.target.value === OWN ? "" : e.target.value }), children: [
678
+ choices.map((c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: c, children: c }, c)),
679
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: OWN, children: "\u81EA\u5DF1\u5199\u2026" })
602
680
  ] }),
603
- own && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "her-input", style: { marginTop: 4 }, value: card[field], placeholder: field === "age" ? "\u8981\u5199\u6210\u5E74\u7684\uFF0C\u6BD4\u5982 26 \u5C81" : "\u5199\u4F60\u60F3\u8981\u7684", onChange: (e) => onChange({ ...card, [field]: e.target.value }) })
681
+ own && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", style: { marginTop: 4 }, value: card[field], placeholder: field === "age" ? "\u8981\u5199\u6210\u5E74\u7684\uFF0C\u6BD4\u5982 26 \u5C81" : "\u5199\u4F60\u60F3\u8981\u7684", onChange: (e) => onChange({ ...card, [field]: e.target.value }) })
604
682
  ] }, field);
605
683
  }),
606
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { gridColumn: "1 / -1" }, children: [
607
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "her-label", children: [
684
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { gridColumn: "1 / -1" }, children: [
685
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "her-label", children: [
608
686
  CARD_LABELS.extra,
609
687
  "\uFF08\u53EF\u4E0D\u586B\uFF09"
610
688
  ] }),
611
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "her-input", value: card.extra, placeholder: "\u6BD4\u5982\uFF1A\u5DE6\u773C\u4E0B\u6709\u9897\u5C0F\u75E3\uFF0C\u7B11\u8D77\u6765\u6709\u9152\u7A9D", onChange: (e) => onChange({ ...card, extra: e.target.value }) })
689
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", value: card.extra, placeholder: "\u6BD4\u5982\uFF1A\u5DE6\u773C\u4E0B\u6709\u9897\u5C0F\u75E3\uFF0C\u7B11\u8D77\u6765\u6709\u9152\u7A9D", onChange: (e) => onChange({ ...card, extra: e.target.value }) })
612
690
  ] })
613
691
  ] });
614
692
  }
615
693
  function SceneEditor({ project, scene, isDefault, status, screen, onChange, onDefault, onRemove, onFrame }) {
616
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-scenes", children: [
617
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-row", children: [
618
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "her-input", style: { width: 140 }, value: scene.name, onChange: (e) => onChange((s) => {
694
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-scenes", children: [
695
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
696
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", style: { width: 140 }, value: scene.name, onChange: (e) => onChange((s) => {
619
697
  s.name = e.target.value;
620
698
  }) }),
621
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", { className: "her-select", style: { width: 90 }, value: scene.pose, onChange: (e) => onChange((s) => {
699
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("select", { className: "her-select", style: { width: 90 }, value: scene.pose, onChange: (e) => onChange((s) => {
622
700
  const pose = e.target.value;
623
701
  s.clips = s.clips.map((c) => ({ ...c, file: c.file.replace(/^(stand|sit|lie)_/, `${pose}_`), action: c.action.replace(POSE_WORDS[s.pose], POSE_WORDS[pose]) }));
624
702
  s.pose = pose;
625
- }), children: Object.keys(POSE_WORDS).map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: p, children: POSE_WORDS[p] }, p)) }),
626
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { children: [
627
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "radio", checked: isDefault, onChange: onDefault }),
703
+ }), children: Object.keys(POSE_WORDS).map((p) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: p, children: POSE_WORDS[p] }, p)) }),
704
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
705
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "radio", checked: isDefault, onChange: onDefault }),
628
706
  " \u9ED8\u8BA4\u573A\u666F"
629
707
  ] }),
630
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "her-btn small", onClick: onRemove, children: "\u5220\u6389\u8FD9\u4E2A\u573A\u666F" })
708
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn small", onClick: onRemove, children: "\u5220\u6389\u8FD9\u4E2A\u573A\u666F" })
631
709
  ] }),
632
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "her-label", children: "\u8FD9\u4E2A\u5730\u65B9\u4EC0\u4E48\u6837\uFF08\u5199\u8FDB\u7167\u7247\u7684\u63D0\u793A\u8BCD\uFF09" }),
633
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "her-input", value: scene.place, placeholder: "\u6BD4\u5982\uFF1A\u6E29\u99A8\u7684\u5367\u5BA4\uFF0C\u6728\u8D28\u5E8A\u5934\u67DC\u548C\u53F0\u706F\uFF0C\u6696\u8272\u706F\u5149\uFF0C\u7A97\u5E18\u534A\u62C9", onChange: (e) => onChange((s) => {
710
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u8FD9\u4E2A\u5730\u65B9\u4EC0\u4E48\u6837\uFF08\u5199\u8FDB\u7167\u7247\u7684\u63D0\u793A\u8BCD\uFF09" }),
711
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", value: scene.place, placeholder: "\u6BD4\u5982\uFF1A\u6E29\u99A8\u7684\u5367\u5BA4\uFF0C\u6728\u8D28\u5E8A\u5934\u67DC\u548C\u53F0\u706F\uFF0C\u6696\u8272\u706F\u5149\uFF0C\u7A97\u5E18\u534A\u62C9", onChange: (e) => onChange((s) => {
634
712
  s.place = e.target.value;
635
713
  }) }),
636
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-row", children: [
637
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-muted", children: "\u4EC0\u4E48\u65F6\u5019\u5728\u8FD9\uFF1A" }),
638
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "her-input", style: { width: 90 }, value: scene.hours ?? "", placeholder: "21-24", onChange: (e) => onChange((s) => {
714
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
715
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-muted", children: "\u4EC0\u4E48\u65F6\u5019\u5728\u8FD9\uFF1A" }),
716
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", style: { width: 90 }, value: scene.hours ?? "", placeholder: "21-24", onChange: (e) => onChange((s) => {
639
717
  if (e.target.value.trim() === "") delete s.hours;
640
718
  else s.hours = e.target.value.trim();
641
719
  }) }),
642
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-muted", children: "\u70B9\uFF0C" }),
643
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { className: "her-select", style: { width: 150 }, value: scene.user ?? "", onChange: (e) => onChange((s) => {
720
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-muted", children: "\u70B9\uFF0C" }),
721
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { className: "her-select", style: { width: 150 }, value: scene.user ?? "", onChange: (e) => onChange((s) => {
644
722
  if (e.target.value === "") delete s.user;
645
723
  else s.user = e.target.value;
646
724
  }), children: [
647
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "", children: "\u4E0D\u7BA1\u4F60\u5728\u4E0D\u5728" }),
648
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "active", children: "\u4F60\u5728\u7528\u7535\u8111\u65F6" }),
649
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "idle", children: "\u4F60\u5F88\u4E45\u6CA1\u52A8\u65F6" })
725
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: "\u4E0D\u7BA1\u4F60\u5728\u4E0D\u5728" }),
726
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "active", children: "\u4F60\u5728\u7528\u7535\u8111\u65F6" }),
727
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "idle", children: "\u4F60\u5F88\u4E45\u6CA1\u52A8\u65F6" })
650
728
  ] })
651
729
  ] }),
652
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "her-muted", children: [
730
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "her-muted", children: [
653
731
  "\u7167\u7247\uFF1A\u7528\u53C2\u8003\u56FE\u751F\u6210\uFF08",
654
732
  screen === void 0 ? "\u6A2A\u7248\uFF0C\u548C\u5C4F\u5E55\u4E00\u6837\u7684\u6BD4\u4F8B" : `${screen.width}\xD7${screen.height}`,
655
733
  "\uFF09\uFF0C\u5B58\u6210 plate.png \u653E\u8FDB\u300C",
656
734
  sceneDir(scene),
657
735
  "\u300D\u6587\u4EF6\u5939\u3002"
658
736
  ] }),
659
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PromptBox, { text: scenePhotoPrompt(project, scene, screen) }),
660
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PartStatusLine, { status }),
661
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-row", children: [
662
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "her-btn", disabled: status?.photo !== true, onClick: onFrame, children: "\u6846\u4EBA\u7269\u533A" }),
663
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "her-muted", children: '\u5728\u684C\u9762\u4E0A\u6253\u5F00"\u505A\u573A\u666F"\uFF0C\u6846\u51FA\u5979\u6D3B\u52A8\u7684\u90A3\u4E00\u5757\uFF1B\u4E4B\u540E\u7528 crop.png \u5F53\u9996\u5E27\u751F\u6210\u89C6\u9891\u3002' })
737
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PromptBox, { text: scenePhotoPrompt(project, scene, screen) }),
738
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PartStatusLine, { status }),
739
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
740
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", disabled: status?.photo !== true, onClick: onFrame, children: "\u6846\u4EBA\u7269\u533A" }),
741
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-muted", children: '\u5728\u684C\u9762\u4E0A\u6253\u5F00"\u505A\u573A\u666F"\uFF0C\u6846\u51FA\u5979\u6D3B\u52A8\u7684\u90A3\u4E00\u5757\uFF1B\u4E4B\u540E\u7528 crop.png \u5F53\u9996\u5E27\u751F\u6210\u89C6\u9891\u3002' })
664
742
  ] }),
665
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ClipList, { project, kind: "scene", scene, clips: scene.clips, pose: scene.pose, onChange: (clips) => onChange((s) => {
743
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipList, { project, kind: "scene", scene, clips: scene.clips, pose: scene.pose, onChange: (clips) => onChange((s) => {
666
744
  s.clips = clips;
667
745
  }) })
668
746
  ] });
669
747
  }
670
748
  function ClipList({ project, kind, scene, clips, pose, onChange }) {
671
- const [own, setOwn] = (0, import_react.useState)("");
749
+ const [own, setOwn] = (0, import_react2.useState)("");
672
750
  const set = (i, change) => onChange(clips.map((c, j) => j === i ? { ...c, ...change } : c));
673
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
674
- clips.map((clip, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-row", style: { margin: "3px 0" }, children: [
675
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: { width: 150 }, children: [
676
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: clip.off !== true, disabled: clip.required === true, onChange: (e) => set(i, { off: !e.target.checked }) }),
751
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
752
+ clips.map((clip, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", style: { margin: "3px 0" }, children: [
753
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: { width: 150 }, children: [
754
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "checkbox", checked: clip.off !== true, disabled: clip.required === true, onChange: (e) => set(i, { off: !e.target.checked }) }),
677
755
  " ",
678
756
  clip.file
679
757
  ] }),
680
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "her-input", style: { flex: 1, minWidth: 200 }, value: clip.action, disabled: clip.off === true, onChange: (e) => set(i, { action: e.target.value }) }),
681
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "her-btn small", disabled: clip.off === true, onClick: () => copy(clipPrompt(project, kind, clip, scene)), children: "\u590D\u5236\u63D0\u793A\u8BCD" })
758
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", style: { flex: 1, minWidth: 200 }, value: clip.action, disabled: clip.off === true, onChange: (e) => set(i, { action: e.target.value }) }),
759
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn small", disabled: clip.off === true, onClick: () => copy(clipPrompt(project, kind, clip, scene)), children: "\u590D\u5236\u63D0\u793A\u8BCD" })
682
760
  ] }, clip.file)),
683
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "her-row", children: [
684
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { className: "her-input", style: { flex: 1 }, value: own, placeholder: "\u52A0\u4E00\u6BB5\u81EA\u5DF1\u7684\u52A8\u4F5C\uFF0C\u6BD4\u5982\uFF1A\u7AEF\u8D77\u5496\u5561\u559D\u4E00\u53E3\uFF0C\u518D\u653E\u4E0B", onChange: (e) => setOwn(e.target.value) }),
685
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { className: "her-btn small", disabled: own.trim() === "", onClick: () => {
761
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
762
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", style: { flex: 1 }, value: own, placeholder: "\u52A0\u4E00\u6BB5\u81EA\u5DF1\u7684\u52A8\u4F5C\uFF0C\u6BD4\u5982\uFF1A\u7AEF\u8D77\u5496\u5561\u559D\u4E00\u53E3\uFF0C\u518D\u653E\u4E0B", onChange: (e) => setOwn(e.target.value) }),
763
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn small", disabled: own.trim() === "", onClick: () => {
686
764
  onChange([...clips, customClip(pose, clips, own)]);
687
765
  setOwn("");
688
766
  }, children: "\u52A0\u4E0A" })
@@ -692,32 +770,252 @@ function ClipList({ project, kind, scene, clips, pose, onChange }) {
692
770
  function ImportProgress({ state }) {
693
771
  const imp = state.import;
694
772
  if (imp.state === "running") {
695
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
696
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "her-progress", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { width: `${imp.total === 0 ? 0 : Math.round(imp.done / imp.total * 100)}%` } }) }),
697
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "her-muted", children: imp.step })
773
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
774
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "her-progress", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { width: `${imp.total === 0 ? 0 : Math.round(imp.done / imp.total * 100)}%` } }) }),
775
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: imp.step })
698
776
  ] });
699
777
  }
700
778
  if (imp.state !== "done" && imp.state !== "failed") return null;
701
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "her-report", children: imp.lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: line.level === "error" ? "her-danger" : line.level === "warn" ? "her-warn" : "", children: [
779
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { className: "her-report", children: imp.lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: line.level === "error" ? "her-danger" : line.level === "warn" ? "her-warn" : "", children: [
702
780
  line.level === "ok" ? "\u2705" : line.level === "warn" ? "\u26A0\uFE0F" : "\u274C",
703
781
  " ",
704
782
  line.text
705
783
  ] }, i)) });
706
784
  }
707
785
 
786
+ // src/client/choice.tsx
787
+ var import_jsx_runtime3 = require("react/jsx-runtime");
788
+ function choiceClass(id, inUse, trying) {
789
+ return `her-choice${id === inUse ? " on" : ""}${trying !== void 0 && id === trying && id !== inUse ? " trying" : ""}`;
790
+ }
791
+ function choiceNote(id, inUse, text, busy) {
792
+ if (busy !== void 0 && busy === id) return "\u6B63\u5728\u5408\u6210\u2026";
793
+ return id === inUse ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
794
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "her-badge", children: "\u2713 \u6B63\u5728\u7528" }),
795
+ text
796
+ ] }) : text;
797
+ }
798
+ function voiceLabel(state, id) {
799
+ if (id.startsWith(OWN_PREFIX)) return state.voice.ming.own.find((v2) => `${OWN_PREFIX}${v2.id}` === id)?.name ?? "\u5DF2\u5220\u9664\u7684\u58F0\u97F3";
800
+ return voiceName(id);
801
+ }
802
+ var SERVICE_SHORT = { edge: "\u5FAE\u8F6F Edge", cosyvoice: "\u963F\u91CC\u4E91\u767E\u70BC", ming: "\u672C\u673A Ming" };
803
+
708
804
  // src/client/parts.tsx
709
- var import_react2 = require("react");
710
- var import_jsx_runtime2 = require("react/jsx-runtime");
805
+ var import_react4 = require("react");
806
+
807
+ // src/client/MingVoice.tsx
808
+ var import_react3 = require("react");
809
+ var import_jsx_runtime4 = require("react/jsx-runtime");
810
+ var DESIGN_EXAMPLE = "\u4E8C\u5341\u591A\u5C81\u7684\u5E74\u8F7B\u5973\u6027\uFF0C\u58F0\u97F3\u6E29\u67D4\u751C\u7F8E\u3001\u7565\u5E26\u6175\u61D2\uFF0C\u8BED\u901F\u9002\u4E2D\uFF0C\u50CF\u5728\u6DF1\u591C\u8F7B\u58F0\u548C\u604B\u4EBA\u804A\u5929\u3002";
811
+ function MingSection({ state, apply: apply2, inUse, trying, playing, onListen }) {
812
+ const ming = state.voice.ming;
813
+ const [make, setMake] = (0, import_react3.useState)();
814
+ if (ming.state === "unsupported") {
815
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
816
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { className: "her-label", children: SERVICE_NAMES.ming }),
817
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "her-faint", children: ming.error })
818
+ ] });
819
+ }
820
+ if (!ming.installed) {
821
+ const busy = ming.state === "installing";
822
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
823
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { className: "her-label", children: SERVICE_NAMES.ming }),
824
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "her-muted", children: "\u5B8C\u5168\u5728\u4F60\u7684\u7535\u8111\u4E0A\u8FD0\u884C\uFF0C\u4E0D\u8054\u7F51\u3001\u4E0D\u82B1\u94B1\uFF0C\u80FD\u8DDF\u7740\u5979\u7684\u60C5\u7EEA\u53D8\u58F0\uFF0C\u8FD8\u80FD\u8BBE\u8BA1\u6216\u514B\u9686\u5979\u81EA\u5DF1\u7684\u58F0\u97F3\u3002\u8981\u4E0B\u8F7D\u7EA6 2 GB\uFF0C\u8BF4\u8BDD\u65F6\u5360\u7EA6 2 GB \u5185\u5B58\u3002" }),
825
+ busy && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
826
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "her-muted", children: [
827
+ ming.step,
828
+ ming.total ? `\uFF1A${Math.round((ming.done ?? 0) / ming.total * 100)}%` : "\u2026"
829
+ ] }),
830
+ ming.total !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "her-progress", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { width: `${Math.round((ming.done ?? 0) / ming.total * 100)}%` } }) })
831
+ ] }),
832
+ ming.state === "failed" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "her-warn", children: ming.error }),
833
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "her-row", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "her-btn", disabled: busy, onClick: () => void apply2(herApi.mingInstall()), children: busy ? "\u6B63\u5728\u5B89\u88C5\u2026" : ming.state === "failed" ? "\u518D\u8BD5\u4E00\u6B21" : "\u5B89\u88C5\u672C\u673A\u58F0\u97F3" }) })
834
+ ] });
835
+ }
836
+ const settings = ming.settings;
837
+ const remove = (id, name) => {
838
+ if (window.confirm(`\u5220\u6389\u300C${name}\u300D\u8FD9\u4E2A\u58F0\u97F3\uFF1F`)) void apply2(herApi.mingRemove(id));
839
+ };
840
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
841
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { className: "her-label", children: SERVICE_NAMES.ming }),
842
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "her-muted", children: [
843
+ mingStateText(ming.state),
844
+ ming.state === "failed" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
845
+ " ",
846
+ ming.error,
847
+ " ",
848
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "her-btn small", onClick: () => void apply2(herApi.mingRestart()), children: "\u91CD\u542F" })
849
+ ] })
850
+ ] }),
851
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "her-grid", children: [
852
+ VOICES.filter((v2) => v2.service === "ming").map((v2) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { className: choiceClass(v2.id, inUse, trying), onClick: () => onListen(v2.id), children: [
853
+ v2.name,
854
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("small", { children: choiceNote(v2.id, inUse, `${v2.desc}${v2.id === inUse ? "" : " \xB7 \u70B9\u4E00\u4E0B\u8BD5\u542C"}`, playing) })
855
+ ] }, v2.id)),
856
+ ming.own.map((v2) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: choiceClass(`${OWN_PREFIX}${v2.id}`, inUse, trying), role: "button", tabIndex: 0, onClick: () => onListen(`${OWN_PREFIX}${v2.id}`), children: [
857
+ v2.name,
858
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("small", { children: choiceNote(`${OWN_PREFIX}${v2.id}`, inUse, `${v2.kind === "design" ? "\u6211\u8BBE\u8BA1\u7684" : "\u6211\u514B\u9686\u7684"}${`${OWN_PREFIX}${v2.id}` === inUse ? "" : " \xB7 \u70B9\u4E00\u4E0B\u8BD5\u542C"}`, playing) }),
859
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "her-btn link", onClick: (e) => {
860
+ e.stopPropagation();
861
+ remove(v2.id, v2.name);
862
+ }, children: "\u5220\u6389" })
863
+ ] }, v2.id))
864
+ ] }),
865
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "her-row", children: [
866
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: `her-btn ${make === "design" ? "primary" : ""}`, onClick: () => setMake(make === "design" ? void 0 : "design"), children: "\u8BBE\u8BA1\u4E00\u4E2A\u58F0\u97F3" }),
867
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: `her-btn ${make === "clone" ? "primary" : ""}`, onClick: () => setMake(make === "clone" ? void 0 : "clone"), children: "\u514B\u9686\u4E00\u4E2A\u58F0\u97F3" })
868
+ ] }),
869
+ make === "design" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DesignVoice, { apply: apply2, onDone: () => setMake(void 0) }),
870
+ make === "clone" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CloneVoice, { apply: apply2, onDone: () => setMake(void 0) }),
871
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "her-row", children: [
872
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("select", { className: "her-select", style: { width: "auto" }, value: settings.quality, onChange: (e) => void apply2(herApi.mingSettings({ quality: e.target.value })), children: [
873
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "quality", children: "\u97F3\u8D28\u4F18\u5148\uFF08\u4E00\u53E5\u8BDD\u7EA6 2\u20133 \u79D2\uFF09" }),
874
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "speed", children: "\u901F\u5EA6\u4F18\u5148\uFF08\u7EA6\u5FEB\u4E00\u500D\uFF0C\u97F3\u8D28\u7565\u5DEE\uFF09" })
875
+ ] }),
876
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
877
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "checkbox", checked: settings.moods, onChange: (e) => void apply2(herApi.mingSettings({ moods: e.target.checked })) }),
878
+ " \u8DDF\u7740\u5979\u7684\u60C5\u7EEA\u53D8\u58F0"
879
+ ] }),
880
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("select", { className: "her-select", style: { width: "auto" }, value: settings.idleMinutes ?? "", onChange: (e) => void apply2(herApi.mingSettings({ idleMinutes: e.target.value === "" ? -1 : Number(e.target.value) })), children: [
881
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "", children: "\u4E0D\u8BF4\u8BDD\u65F6\u81EA\u52A8\u7701\u5185\u5B58\uFF08\u6309\u5185\u5B58\u5927\u5C0F\uFF09" }),
882
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "10", children: "\u4E0D\u8BF4\u8BDD 10 \u5206\u949F\u540E\u7701\u5185\u5B58" }),
883
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "30", children: "\u4E0D\u8BF4\u8BDD 30 \u5206\u949F\u540E\u7701\u5185\u5B58" }),
884
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "0", children: "\u4E00\u76F4\u5F00\u7740\uFF08\u5360\u7EA6 2 GB \u5185\u5B58\uFF09" })
885
+ ] })
886
+ ] }),
887
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: "her-faint", children: [
888
+ "\u7701\u5185\u5B58\u65F6\u4F1A\u505C\u6389\u58F0\u97F3\u7A0B\u5E8F\uFF0C\u4F60\u4E00\u5F00\u53E3\u5C31\u91CD\u65B0\u542F\u52A8\uFF08\u7EA6 8 \u79D2\uFF09\u3002\u4E0D\u7528\u4E86\u53EF\u4EE5",
889
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "her-btn link", onClick: () => {
890
+ if (window.confirm("\u5378\u8F7D\u672C\u673A\u58F0\u97F3\uFF1F\u4F1A\u5220\u6389\u7EA6 2 GB \u7684\u7A0B\u5E8F\u548C\u6A21\u578B\uFF1B\u4F60\u81EA\u5DF1\u7684\u58F0\u97F3\u4F1A\u4FDD\u7559\u3002")) void apply2(herApi.mingUninstall());
891
+ }, children: "\u5378\u8F7D\u672C\u673A\u58F0\u97F3" }),
892
+ "\u3002"
893
+ ] })
894
+ ] });
895
+ }
896
+ function mingStateText(state) {
897
+ switch (state) {
898
+ case "ready":
899
+ return "\u5DF2\u5C31\u7EEA";
900
+ case "loading":
901
+ return "\u6B63\u5728\u52A0\u8F7D\u58F0\u97F3\u6A21\u578B\u2026";
902
+ case "stopped":
903
+ return "\u5DF2\u5B89\u88C5\uFF08\u4E3A\u4E86\u7701\u5185\u5B58\u73B0\u5728\u6CA1\u5728\u8FD0\u884C\uFF0C\u8BF4\u8BDD\u65F6\u4F1A\u81EA\u52A8\u542F\u52A8\uFF09";
904
+ case "failed":
905
+ return "\u51FA\u9519\u4E86\uFF1A";
906
+ default:
907
+ return "";
908
+ }
909
+ }
910
+ function DesignVoice({ apply: apply2, onDone }) {
911
+ const [description, setDescription] = (0, import_react3.useState)(DESIGN_EXAMPLE);
912
+ const [drafts, setDrafts] = (0, import_react3.useState)();
913
+ const [chosen, setChosen] = (0, import_react3.useState)();
914
+ const [name, setName] = (0, import_react3.useState)("");
915
+ const [busy, setBusy] = (0, import_react3.useState)(false);
916
+ const [error, setError] = (0, import_react3.useState)();
917
+ const generate = async () => {
918
+ setBusy(true);
919
+ setError(void 0);
920
+ setDrafts(void 0);
921
+ const result = await herApi.mingDesign(description);
922
+ setBusy(false);
923
+ if (!result.ok) return setError(result.message);
924
+ setDrafts(result.drafts);
925
+ setChosen(result.drafts[0]?.id);
926
+ };
927
+ const keep = async () => {
928
+ if (chosen === void 0) return;
929
+ const result = await herApi.mingKeep(chosen, name);
930
+ if (!result.ok) return setError(result.message);
931
+ if (await apply2(herApi.saveCharacter({ voice: `${OWN_PREFIX}${result.voice.id}` }))) onDone();
932
+ };
933
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "her-card", style: { background: "none", padding: "4px 0" }, children: [
934
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { className: "her-label", children: "\u7528\u4E00\u53E5\u8BDD\u63CF\u8FF0\u5979\u7684\u58F0\u97F3\uFF1A\u5E74\u9F84\u3001\u97F3\u8272\u3001\u8BED\u6C14\u3001\u8BED\u901F\uFF0C\u50CF\u4EC0\u4E48\u573A\u5408\u8BF4\u8BDD" }),
935
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("textarea", { className: "her-textarea", style: { minHeight: 60 }, value: description, onChange: (e) => setDescription(e.target.value) }),
936
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "her-row", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "her-btn", disabled: busy, onClick: () => void generate(), children: busy ? "\u6B63\u5728\u751F\u6210 3 \u4E2A\uFF08\u7EA6 10 \u79D2\uFF09\u2026" : "\u751F\u6210 3 \u4E2A\u8BD5\u542C" }) }),
937
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "her-faint", children: "\u540C\u4E00\u53E5\u63CF\u8FF0\uFF0C\u6BCF\u6B21\u751F\u6210\u7684\u58F0\u97F3\u90FD\u4F1A\u6709\u70B9\u4E0D\u540C\u3002\u6311\u4E00\u4E2A\u6700\u559C\u6B22\u7684\u7559\u4E0B\u6765\uFF0C\u5979\u4EE5\u540E\u5C31\u4E00\u76F4\u7528\u8FD9\u4E00\u4E2A\u3002" }),
938
+ drafts !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
939
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "her-row", children: drafts.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { className: `her-btn ${chosen === d.id ? "primary" : ""}`, onClick: () => {
940
+ setChosen(d.id);
941
+ playAudio(d.audio, "wav");
942
+ }, children: [
943
+ "\u25B6 \u7B2C ",
944
+ i + 1,
945
+ " \u4E2A"
946
+ ] }, d.id)) }),
947
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "her-row", children: [
948
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { className: "her-input", style: { flex: 1 }, placeholder: "\u7ED9\u8FD9\u4E2A\u58F0\u97F3\u8D77\u4E2A\u540D\u5B57", value: name, onChange: (e) => setName(e.target.value) }),
949
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "her-btn primary", disabled: chosen === void 0 || name.trim() === "", onClick: () => void keep(), children: "\u7559\u4E0B\u9009\u4E2D\u7684\uFF0C\u8BA9\u5979\u7528\u8FD9\u4E2A\u58F0\u97F3" })
950
+ ] })
951
+ ] }),
952
+ error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "her-danger", children: error })
953
+ ] });
954
+ }
955
+ function CloneVoice({ apply: apply2, onDone }) {
956
+ const [draft, setDraft] = (0, import_react3.useState)();
957
+ const [text, setText] = (0, import_react3.useState)("");
958
+ const [name, setName] = (0, import_react3.useState)("");
959
+ const [consent, setConsent] = (0, import_react3.useState)(false);
960
+ const [busy, setBusy] = (0, import_react3.useState)(false);
961
+ const [error, setError] = (0, import_react3.useState)();
962
+ const upload = async (file) => {
963
+ if (file === void 0) return;
964
+ setBusy(true);
965
+ setError(void 0);
966
+ setDraft(void 0);
967
+ const bytes = new Uint8Array(await file.arrayBuffer());
968
+ let binary = "";
969
+ for (let i = 0; i < bytes.length; i += 32768) binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
970
+ const result = await herApi.mingClone(btoa(binary), file.name);
971
+ setBusy(false);
972
+ if (!result.ok) return setError(result.message);
973
+ setDraft(result.draft);
974
+ setText(result.draft.text);
975
+ };
976
+ const keep = async () => {
977
+ if (draft === void 0) return;
978
+ const result = await herApi.mingKeep(draft.id, name, { text, consent });
979
+ if (!result.ok) return setError(result.message);
980
+ if (await apply2(herApi.saveCharacter({ voice: `${OWN_PREFIX}${result.voice.id}` }))) onDone();
981
+ };
982
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "her-card", style: { background: "none", padding: "4px 0" }, children: [
983
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "her-muted", children: '\u9009\u4E00\u6BB5 5\u201315 \u79D2\u7684\u5F55\u97F3\uFF1A\u4E00\u4E2A\u4EBA\u6E05\u695A\u5730\u8BF4\u8BDD\uFF0C\u6CA1\u6709\u80CC\u666F\u97F3\u4E50\u548C\u6742\u97F3\uFF08\u624B\u673A"\u8BED\u97F3\u5907\u5FD8\u5F55"\u5F55\u7684 m4a \u5C31\u884C\uFF0C\u4E5F\u53EF\u4EE5\u662F wav\u3001mp3\uFF09\u3002\u8D85\u8FC7 15 \u79D2\u53EA\u7528\u524D 15 \u79D2\u3002\u5F55\u97F3\u53EA\u7559\u5728\u4F60\u7684\u7535\u8111\u4E0A\u3002' }),
984
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "file", accept: "audio/*,.m4a,.wav,.mp3,.aiff,.caf", disabled: busy, onChange: (e) => void upload(e.target.files?.[0]) }),
985
+ busy && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "her-muted", children: "\u6B63\u5728\u5904\u7406\u5F55\u97F3\u3001\u542C\u5B83\u8BF4\u4E86\u4EC0\u4E48\u2026" }),
986
+ draft !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
987
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "her-row", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { className: "her-btn", onClick: () => playAudio(draft.audio, "wav"), children: [
988
+ "\u25B6 \u542C\u4E00\u4E0B\uFF08",
989
+ (draft.durationMs / 1e3).toFixed(1),
990
+ " \u79D2\uFF09"
991
+ ] }) }),
992
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { className: "her-label", children: "\u5F55\u97F3\u91CC\u8BF4\u7684\u8BDD\uFF08\u81EA\u52A8\u542C\u51FA\u6765\u7684\uFF0C\u6709\u9519\u5B57\u8981\u6539\u5BF9\uFF1A\u514B\u9686\u8981\u7528\u5230\u5B83\uFF09" }),
993
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("textarea", { className: "her-textarea", style: { minHeight: 50 }, value: text, onChange: (e) => setText(e.target.value) }),
994
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { children: [
995
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "checkbox", checked: consent, onChange: (e) => setConsent(e.target.checked) }),
996
+ " \u8FD9\u662F\u6211\u672C\u4EBA\u7684\u58F0\u97F3\uFF0C\u6216\u8005\u6211\u5F97\u5230\u4E86\u58F0\u97F3\u4E3B\u4EBA\u7684\u540C\u610F\uFF08\u4E0D\u80FD\u7528\u660E\u661F\u6216\u5176\u4ED6\u4EBA\u672A\u7ECF\u540C\u610F\u7684\u58F0\u97F3\uFF09"
997
+ ] }),
998
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "her-row", children: [
999
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { className: "her-input", style: { flex: 1 }, placeholder: "\u7ED9\u8FD9\u4E2A\u58F0\u97F3\u8D77\u4E2A\u540D\u5B57", value: name, onChange: (e) => setName(e.target.value) }),
1000
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "her-btn primary", disabled: !consent || name.trim() === "" || text.trim() === "", onClick: () => void keep(), children: "\u4FDD\u5B58\uFF0C\u8BA9\u5979\u7528\u8FD9\u4E2A\u58F0\u97F3" })
1001
+ ] })
1002
+ ] }),
1003
+ error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "her-danger", children: error })
1004
+ ] });
1005
+ }
1006
+
1007
+ // src/client/parts.tsx
1008
+ var import_jsx_runtime5 = require("react/jsx-runtime");
711
1009
  var MODE_TEXT = {
712
1010
  overlay: { title: "\u6D6E\u5728\u6700\u4E0A\u5C42", desc: "\u50CF\u684C\u5BA0\u4E00\u6837\u5728\u6240\u6709\u7A97\u53E3\u4E0A\u9762\uFF0C\u53EF\u4EE5\u62D6\u52A8\u3001\u70B9\u5979" },
713
1011
  wallpaper: { title: "\u4F4F\u5728\u58C1\u7EB8\u91CC", desc: "\u5728\u684C\u9762\u56FE\u6807\u548C\u6240\u6709\u7A97\u53E3\u4E0B\u9762\uFF0C\u53EA\u770B\u4E0D\u70B9\uFF1B\u6309\u5FEB\u6377\u952E\u53EB\u5979\u51FA\u6765" },
714
1012
  window: { title: "\u666E\u901A\u7A97\u53E3", desc: "\u4E00\u4E2A\u53EF\u4EE5\u5173\u6389\u7684\u7A97\u53E3" }
715
1013
  };
716
1014
  function Dot({ tone }) {
717
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `her-dot ${tone === "off" ? "" : tone}` });
1015
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: `her-dot ${tone === "off" ? "" : tone}` });
718
1016
  }
719
1017
  function BodyStatus({ state, apply: apply2 }) {
720
- const [message, setMessage] = (0, import_react2.useState)();
1018
+ const [message, setMessage] = (0, import_react4.useState)();
721
1019
  const body = state.body;
722
1020
  const install = body.install;
723
1021
  const start = async () => {
@@ -726,84 +1024,78 @@ function BodyStatus({ state, apply: apply2 }) {
726
1024
  await apply2(Promise.resolve(result));
727
1025
  };
728
1026
  const busy = install.state === "checking" || install.state === "downloading" || install.state === "installing";
729
- const progress = busy && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
730
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "her-progress", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { width: `${install.total ? Math.round((install.done ?? 0) / install.total * 100) : 0}%` } }) }),
731
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: install.state === "checking" ? "\u6B63\u5728\u770B\u6709\u6CA1\u6709\u65B0\u7248\u672C\u2026" : install.state === "installing" ? "\u6B63\u5728\u5B89\u88C5\u2026" : `\u6B63\u5728\u4E0B\u8F7D\u8EAB\u4F53\u7A0B\u5E8F ${install.latest ?? ""}\uFF08${mb(install.done)} / ${mb(install.total)} MB\uFF09` })
1027
+ const progress = busy && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1028
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "her-progress", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { width: `${install.total ? Math.round((install.done ?? 0) / install.total * 100) : 0}%` } }) }),
1029
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-muted", children: install.state === "checking" ? "\u6B63\u5728\u770B\u6709\u6CA1\u6709\u65B0\u7248\u672C\u2026" : install.state === "installing" ? "\u6B63\u5728\u5B89\u88C5\u2026" : `\u6B63\u5728\u4E0B\u8F7D\u8EAB\u4F53\u7A0B\u5E8F ${install.latest ?? ""}\uFF08${mb(install.done)} / ${mb(install.total)} MB\uFF09` })
732
1030
  ] });
733
- const failed = install.state === "failed" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "her-danger", children: [
1031
+ const failed = install.state === "failed" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "her-danger", children: [
734
1032
  "\u4E0B\u8F7D\u5B89\u88C5\u6CA1\u6210\u529F\uFF1A",
735
1033
  install.error
736
1034
  ] });
737
1035
  if (body.connected) {
738
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
739
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
740
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Dot, { tone: "ok" }),
1036
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1037
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { children: [
1038
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Dot, { tone: "ok" }),
741
1039
  "\u8EAB\u4F53\u5DF2\u8FDE\u4E0A\uFF08",
742
1040
  body.info?.os,
743
1041
  "\uFF0C\u7248\u672C ",
744
1042
  body.info?.version,
745
1043
  "\uFF09",
746
1044
  body.pack === void 0 ? "" : `\uFF0C\u5916\u5F62\uFF1A${body.pack.name}`,
747
- !install.dev && !busy && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn link", onClick: () => void apply2(herApi.installBody()), children: "\u68C0\u67E5\u66F4\u65B0" }),
748
- !install.dev && !busy && install.latest !== void 0 && install.restart !== true && install.state === "idle" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "her-muted", children: [
1045
+ !install.dev && !busy && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn link", onClick: () => void apply2(herApi.installBody()), children: "\u68C0\u67E5\u66F4\u65B0" }),
1046
+ !install.dev && !busy && install.latest !== void 0 && install.restart !== true && install.state === "idle" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "her-muted", children: [
749
1047
  "\uFF08\u5DF2\u662F\u6700\u65B0\uFF1A",
750
1048
  install.latest,
751
1049
  "\uFF09"
752
1050
  ] })
753
1051
  ] }),
754
- install.restart === true && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
755
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
1052
+ install.restart === true && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-row", children: [
1053
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
756
1054
  "\u65B0\u7248\u672C ",
757
1055
  install.installed,
758
1056
  " \u5DF2\u7ECF\u88C5\u597D\uFF0C\u91CD\u542F\u4E00\u4E0B\u8EAB\u4F53\u5C31\u7528\u4E0A\u4E86\u3002"
759
1057
  ] }),
760
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn primary", onClick: () => void apply2(herApi.restartBody()), children: "\u91CD\u542F\u8EAB\u4F53" })
1058
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn primary", onClick: () => void apply2(herApi.restartBody()), children: "\u91CD\u542F\u8EAB\u4F53" })
761
1059
  ] }),
762
1060
  progress,
763
1061
  failed
764
1062
  ] });
765
1063
  }
766
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
767
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
768
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Dot, { tone: body.running ? "warn" : "bad" }),
1064
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1065
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { children: [
1066
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Dot, { tone: body.running ? "warn" : "bad" }),
769
1067
  body.running ? "\u8EAB\u4F53\u5728\u8FD0\u884C\uFF0C\u6B63\u5728\u8FDE\u63A5\u2026" : "\u8EAB\u4F53\u8FD8\u6CA1\u8FD0\u884C"
770
1068
  ] }),
771
- !body.running && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "her-row", children: body.canStart ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn primary", onClick: () => void start(), children: "\u542F\u52A8\u8EAB\u4F53" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
772
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn primary", disabled: busy, onClick: () => void apply2(herApi.installBody()), children: "\u4E0B\u8F7D\u5B89\u88C5\u8EAB\u4F53" }),
773
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-muted", children: "\u5979\u5728\u684C\u9762\u4E0A\u7684\u6837\u5B50\u662F\u4E00\u4E2A\u5355\u72EC\u7684\u5C0F\u7A0B\u5E8F\uFF08\u7EA6 150 MB\uFF09\uFF0C\u88C5\u5728 dsh-her \u81EA\u5DF1\u7684\u6587\u4EF6\u5939\u91CC\uFF0C\u88C5\u597D\u5C31\u81EA\u52A8\u542F\u52A8\u3002" })
1069
+ !body.running && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "her-row", children: body.canStart ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn primary", onClick: () => void start(), children: "\u542F\u52A8\u8EAB\u4F53" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1070
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn primary", disabled: busy, onClick: () => void apply2(herApi.installBody()), children: "\u4E0B\u8F7D\u5B89\u88C5\u8EAB\u4F53" }),
1071
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-muted", children: "\u5979\u5728\u684C\u9762\u4E0A\u7684\u6837\u5B50\u662F\u4E00\u4E2A\u5355\u72EC\u7684\u5C0F\u7A0B\u5E8F\uFF08\u7EA6 150 MB\uFF09\uFF0C\u88C5\u5728 dsh-her \u81EA\u5DF1\u7684\u6587\u4EF6\u5939\u91CC\uFF0C\u88C5\u597D\u5C31\u81EA\u52A8\u542F\u52A8\u3002" })
774
1072
  ] }) }),
775
1073
  progress,
776
1074
  failed,
777
- message !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: message })
1075
+ message !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-muted", children: message })
778
1076
  ] });
779
1077
  }
780
1078
  var mb = (bytes) => ((bytes ?? 0) / 1e6).toFixed(0);
781
1079
  function PackPicker({ state, apply: apply2 }) {
782
1080
  const body = state.body;
783
1081
  const imp = state.import;
784
- if (!body.connected) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: "\u8EAB\u4F53\u8FDE\u4E0A\u4E4B\u540E\u624D\u80FD\u9009\u5916\u5F62\u3002" });
785
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
786
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-grid", children: [
787
- body.packs.map((pack) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { className: `her-choice ${pack.packId === body.activePack ? "on" : ""}`, onClick: () => void apply2(herApi.usePack(pack.packId)), children: [
1082
+ if (!body.connected) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-muted", children: "\u8EAB\u4F53\u8FDE\u4E0A\u4E4B\u540E\u624D\u80FD\u9009\u5916\u5F62\u3002" });
1083
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1084
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-grid", children: [
1085
+ body.packs.map((pack) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { className: `her-choice ${pack.packId === body.activePack ? "on" : ""}`, onClick: () => void apply2(herApi.usePack(pack.packId)), children: [
788
1086
  pack.name,
789
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("small", { children: [
790
- pack.packId.startsWith("look:") ? "\u591A\u573A\u666F\u5F62\u8C61" : pack.layer === "scene" ? "\u58C1\u7EB8\u573A\u666F" : "\u684C\u5BA0",
791
- " \xB7 ",
792
- pack.actions.filter((a) => !a.id.startsWith("scene_")).length,
793
- " \u4E2A\u52A8\u4F5C",
794
- pack.emotions.length > 0 ? ` \xB7 ${pack.emotions.length} \u79CD\u60C5\u7EEA` : ""
795
- ] })
1087
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { children: choiceNote(pack.packId, body.activePack ?? "", `${pack.packId.startsWith("look:") ? "\u591A\u573A\u666F\u5F62\u8C61" : pack.layer === "scene" ? "\u58C1\u7EB8\u573A\u666F" : "\u684C\u5BA0"} \xB7 ${pack.actions.filter((a) => !a.id.startsWith("scene_")).length} \u4E2A\u52A8\u4F5C${pack.emotions.length > 0 ? ` \xB7 ${pack.emotions.length} \u79CD\u60C5\u7EEA` : ""}`) })
796
1088
  ] }, pack.packId)),
797
- body.packs.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: "\u8FD8\u6CA1\u6709\u5BFC\u5165\u8FC7\u5916\u5F62\u5305\u3002" })
1089
+ body.packs.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-muted", children: "\u8FD8\u6CA1\u6709\u5BFC\u5165\u8FC7\u5916\u5F62\u5305\u3002" })
798
1090
  ] }),
799
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
800
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", disabled: imp.state === "picking" || imp.state === "running", onClick: () => void apply2(herApi.pickPack()), children: "\u5BFC\u5165\u6211\u7684\u7D20\u6750\u2026" }),
801
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-muted", children: "\u4F1A\u5728\u8EAB\u4F53\u90A3\u53F0\u7535\u8111\u4E0A\u5F39\u51FA\u9009\u62E9\u6587\u4EF6\u5939\u7684\u7A97\u53E3\u3002\u7D20\u6750\u600E\u4E48\u505A\u3001\u600E\u4E48\u547D\u540D\uFF0C\u89C1 docs/\u7D20\u6750\u751F\u6210\u63D0\u793A\u8BCD.md\u3002" })
1091
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-row", children: [
1092
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn", disabled: imp.state === "picking" || imp.state === "running", onClick: () => void apply2(herApi.pickPack()), children: "\u5BFC\u5165\u6211\u7684\u7D20\u6750\u2026" }),
1093
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-muted", children: "\u4F1A\u5728\u8EAB\u4F53\u90A3\u53F0\u7535\u8111\u4E0A\u5F39\u51FA\u9009\u62E9\u6587\u4EF6\u5939\u7684\u7A97\u53E3\u3002\u7D20\u6750\u600E\u4E48\u505A\u3001\u600E\u4E48\u547D\u540D\uFF0C\u89C1 docs/\u7D20\u6750\u751F\u6210\u63D0\u793A\u8BCD.md\u3002" })
802
1094
  ] }),
803
- imp.state === "picking" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: "\u8BF7\u5728\u684C\u9762\u4E0A\u5F39\u51FA\u7684\u7A97\u53E3\u91CC\u9009\u62E9\u7D20\u6750\u6587\u4EF6\u5939\u2026" }),
804
- imp.state === "running" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
805
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "her-progress", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { width: `${imp.total === 0 ? 0 : Math.round(imp.done / imp.total * 100)}%` } }) }),
806
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "her-muted", children: [
1095
+ imp.state === "picking" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-muted", children: "\u8BF7\u5728\u684C\u9762\u4E0A\u5F39\u51FA\u7684\u7A97\u53E3\u91CC\u9009\u62E9\u7D20\u6750\u6587\u4EF6\u5939\u2026" }),
1096
+ imp.state === "running" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1097
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "her-progress", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { width: `${imp.total === 0 ? 0 : Math.round(imp.done / imp.total * 100)}%` } }) }),
1098
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "her-muted", children: [
807
1099
  imp.step,
808
1100
  "\uFF08",
809
1101
  imp.done,
@@ -812,7 +1104,7 @@ function PackPicker({ state, apply: apply2 }) {
812
1104
  "\uFF09"
813
1105
  ] })
814
1106
  ] }),
815
- (imp.state === "done" || imp.state === "failed") && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { className: "her-report", children: imp.lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: line.level === "error" ? "her-danger" : line.level === "warn" ? "her-warn" : "", children: [
1107
+ (imp.state === "done" || imp.state === "failed") && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "her-report", children: imp.lines.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { className: line.level === "error" ? "her-danger" : line.level === "warn" ? "her-warn" : "", children: [
816
1108
  line.level === "ok" ? "\u2705" : line.level === "warn" ? "\u26A0\uFE0F" : "\u274C",
817
1109
  " ",
818
1110
  line.text
@@ -821,15 +1113,16 @@ function PackPicker({ state, apply: apply2 }) {
821
1113
  }
822
1114
  function PersonaEditor({ state, apply: apply2, onSaved, saveLabel = "\u4FDD\u5B58" }) {
823
1115
  const c = state.character;
824
- const [name, setName] = (0, import_react2.useState)(c.name);
825
- const [callYou, setCallYou] = (0, import_react2.useState)(c.callYou);
826
- const [pronoun, setPronoun] = (0, import_react2.useState)(c.pronoun);
827
- const [persona, setPersona] = (0, import_react2.useState)(c.persona);
828
- const [idea, setIdea] = (0, import_react2.useState)("");
829
- const [busy, setBusy] = (0, import_react2.useState)();
830
- const [error, setError] = (0, import_react2.useState)();
831
- const [chat, setChat] = (0, import_react2.useState)([]);
832
- const [line, setLine] = (0, import_react2.useState)("");
1116
+ const [name, setName] = (0, import_react4.useState)(c.name);
1117
+ const [callYou, setCallYou] = (0, import_react4.useState)(c.callYou);
1118
+ const [pronoun, setPronoun] = (0, import_react4.useState)(c.pronoun);
1119
+ const [persona, setPersona] = (0, import_react4.useState)(c.persona);
1120
+ const [idea, setIdea] = (0, import_react4.useState)("");
1121
+ const [busy, setBusy] = (0, import_react4.useState)();
1122
+ const [error, setError] = (0, import_react4.useState)();
1123
+ const [chat, setChat] = (0, import_react4.useState)([]);
1124
+ const [line, setLine] = (0, import_react4.useState)("");
1125
+ const dirty = name !== c.name || callYou !== c.callYou || pronoun !== c.pronoun || persona !== c.persona;
833
1126
  const expand = async () => {
834
1127
  setBusy("expand");
835
1128
  setError(void 0);
@@ -856,77 +1149,82 @@ function PersonaEditor({ state, apply: apply2, onSaved, saveLabel = "\u4FDD\u5B5
856
1149
  setBusy(void 0);
857
1150
  if (ok) onSaved?.();
858
1151
  };
859
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
860
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
861
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { flex: 1, minWidth: 140 }, children: [
862
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u5979\u7684\u540D\u5B57" }),
863
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", value: name, onChange: (e) => setName(e.target.value) })
1152
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1153
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-row", children: [
1154
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { flex: 1, minWidth: 140 }, children: [
1155
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "her-label", children: "\u5979\u7684\u540D\u5B57" }),
1156
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { className: "her-input", value: name, onChange: (e) => setName(e.target.value) })
864
1157
  ] }),
865
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { flex: 1, minWidth: 140 }, children: [
866
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u5979\u600E\u4E48\u79F0\u547C\u4F60" }),
867
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", value: callYou, placeholder: "\u6BD4\u5982\uFF1A\u963F\u6587", onChange: (e) => setCallYou(e.target.value) })
1158
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { flex: 1, minWidth: 140 }, children: [
1159
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "her-label", children: "\u5979\u600E\u4E48\u79F0\u547C\u4F60" }),
1160
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { className: "her-input", value: callYou, placeholder: "\u6BD4\u5982\uFF1A\u963F\u6587", onChange: (e) => setCallYou(e.target.value) })
868
1161
  ] }),
869
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { width: 120 }, children: [
870
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u63D0\u5230\u4F60\u65F6\u7528" }),
871
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { className: "her-select", value: pronoun, onChange: (e) => setPronoun(e.target.value), children: [
872
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "\u4ED6", children: "\u4ED6" }),
873
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "\u5979", children: "\u5979" }),
874
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "TA", children: "TA" })
1162
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { width: 120 }, children: [
1163
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "her-label", children: "\u63D0\u5230\u4F60\u65F6\u7528" }),
1164
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { className: "her-select", value: pronoun, onChange: (e) => setPronoun(e.target.value), children: [
1165
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "\u4ED6", children: "\u4ED6" }),
1166
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "\u5979", children: "\u5979" }),
1167
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "TA", children: "TA" })
875
1168
  ] })
876
1169
  ] })
877
1170
  ] }),
878
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u4E00\u53E5\u8BDD\u63CF\u8FF0\u5979\uFF08\u53EF\u9009\uFF09\uFF0C\u8BA9\u6A21\u578B\u5E2E\u4F60\u5199\u6210\u5B8C\u6574\u4EBA\u8BBE" }),
879
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
880
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", style: { flex: 1 }, value: idea, placeholder: "\u6BD4\u5982\uFF1A\u4E8C\u5341\u4E94\u5C81\u7684\u7F16\u5267\uFF0C\u7231\u5410\u69FD\uFF0C\u559C\u6B22\u732B\u548C\u706B\u9505", onChange: (e) => setIdea(e.target.value) }),
881
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", disabled: busy !== void 0 || idea.trim() === "", onClick: () => void expand(), children: busy === "expand" ? "\u6B63\u5728\u5199\u2026" : "\u5E2E\u6211\u5199" })
1171
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "her-label", children: "\u4E00\u53E5\u8BDD\u63CF\u8FF0\u5979\uFF08\u53EF\u9009\uFF09\uFF0C\u8BA9\u6A21\u578B\u5E2E\u4F60\u5199\u6210\u5B8C\u6574\u4EBA\u8BBE" }),
1172
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-row", children: [
1173
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { className: "her-input", style: { flex: 1 }, value: idea, placeholder: "\u6BD4\u5982\uFF1A\u4E8C\u5341\u4E94\u5C81\u7684\u7F16\u5267\uFF0C\u7231\u5410\u69FD\uFF0C\u559C\u6B22\u732B\u548C\u706B\u9505", onChange: (e) => setIdea(e.target.value) }),
1174
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn", disabled: busy !== void 0 || idea.trim() === "", onClick: () => void expand(), children: busy === "expand" ? "\u6B63\u5728\u5199\u2026" : "\u5E2E\u6211\u5199" })
882
1175
  ] }),
883
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u4EBA\u8BBE\uFF08\u53EF\u4EE5\u76F4\u63A5\u6539\uFF09" }),
884
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("textarea", { className: "her-textarea", value: persona, onChange: (e) => setPersona(e.target.value) }),
885
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: "\u5148\u8BD5\u804A\u51E0\u53E5\uFF08\u4E0D\u4F1A\u8FDB\u5979\u7684\u8BB0\u5FC6\uFF09" }),
886
- chat.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "her-chat", children: chat.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: m.who, children: [
1176
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "her-label", children: "\u4EBA\u8BBE\uFF08\u53EF\u4EE5\u76F4\u63A5\u6539\uFF09" }),
1177
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("textarea", { className: "her-textarea", value: persona, onChange: (e) => setPersona(e.target.value) }),
1178
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "her-label", children: "\u5148\u8BD5\u804A\u51E0\u53E5\uFF08\u4E0D\u4F1A\u8FDB\u5979\u7684\u8BB0\u5FC6\uFF09" }),
1179
+ chat.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "her-chat", children: chat.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: m.who, children: [
887
1180
  m.who === "you" ? "\u4F60\uFF1A" : `${name}\uFF1A`,
888
1181
  m.text
889
1182
  ] }, i)) }),
890
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
891
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "her-input", style: { flex: 1 }, value: line, placeholder: "\u8BF4\u4E00\u53E5\u8BD5\u8BD5", onChange: (e) => setLine(e.target.value), onKeyDown: (e) => {
1183
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-row", children: [
1184
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { className: "her-input", style: { flex: 1 }, value: line, placeholder: "\u8BF4\u4E00\u53E5\u8BD5\u8BD5", onChange: (e) => setLine(e.target.value), onKeyDown: (e) => {
892
1185
  if (e.key === "Enter") void tryOne();
893
1186
  } }),
894
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", disabled: busy !== void 0 || persona.trim() === "", onClick: () => void tryOne(), children: busy === "try" ? "\u2026" : "\u53D1\u9001" })
1187
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn", disabled: busy !== void 0 || persona.trim() === "", onClick: () => void tryOne(), children: busy === "try" ? "\u2026" : "\u53D1\u9001" })
895
1188
  ] }),
896
- error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-error", children: error }),
897
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "her-row", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn primary", disabled: busy !== void 0, onClick: () => void save(), children: saveLabel }) })
1189
+ error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-error", children: error }),
1190
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-row", children: [
1191
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn primary", disabled: busy !== void 0 || !dirty && onSaved === void 0, onClick: () => void save(), children: saveLabel }),
1192
+ dirty ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-warn", children: "\u6709\u6539\u52A8\u8FD8\u6CA1\u4FDD\u5B58" }) : onSaved === void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-muted", children: "\u2713 \u5DF2\u4FDD\u5B58\uFF0C\u5979\u6B63\u5728\u7528\u8FD9\u4EFD\u4EBA\u8BBE" })
1193
+ ] })
898
1194
  ] });
899
1195
  }
900
1196
  function KeyHelp({ state }) {
901
1197
  if (state.voice.speaking.status === "no-quota") {
902
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-warn", children: [
903
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: "\u767E\u70BC\u8D26\u53F7\u7684\u989D\u5EA6\u7528\u5B8C\u4E86\uFF0C\u5979\u73B0\u5728\u53EA\u7528\u6587\u5B57\u56DE\u7B54\u3002" }),
904
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: '\u5230\u963F\u91CC\u4E91\u767E\u70BC\u63A7\u5236\u53F0\u5F00\u901A\u6309\u91CF\u4ED8\u8D39\uFF1B\u5982\u679C\u5DF2\u7ECF\u5F00\u901A\uFF0C\u628A"\u4EC5\u4F7F\u7528\u514D\u8D39\u989D\u5EA6"\u5173\u6389\u3002\u5F04\u597D\u540E\u6700\u591A\u534A\u5206\u949F\u5979\u5C31\u80FD\u8BF4\u8BDD\uFF0C\u4E0D\u7528\u91CD\u542F\u3002' }),
905
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-faint", children: state.voice.speaking.error })
1198
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-warn", children: [
1199
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: "\u767E\u70BC\u8D26\u53F7\u7684\u989D\u5EA6\u7528\u5B8C\u4E86\uFF0C\u5979\u73B0\u5728\u53EA\u7528\u6587\u5B57\u56DE\u7B54\u3002" }),
1200
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: '\u5230\u963F\u91CC\u4E91\u767E\u70BC\u63A7\u5236\u53F0\u5F00\u901A\u6309\u91CF\u4ED8\u8D39\uFF1B\u5982\u679C\u5DF2\u7ECF\u5F00\u901A\uFF0C\u628A"\u4EC5\u4F7F\u7528\u514D\u8D39\u989D\u5EA6"\u5173\u6389\u3002\u5F04\u597D\u540E\u6700\u591A\u534A\u5206\u949F\u5979\u5C31\u80FD\u8BF4\u8BDD\uFF0C\u4E0D\u7528\u91CD\u542F\u3002' }),
1201
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-faint", children: state.voice.speaking.error })
906
1202
  ] });
907
1203
  }
908
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-warn", children: [
909
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: "\u5979\u7684\u58F0\u97F3\u7528\u963F\u91CC\u4E91\u767E\u70BC\uFF08CosyVoice\uFF09\uFF0C\u8FD8\u6CA1\u6709\u627E\u5230 API key\uFF0C\u73B0\u5728\u53EA\u7528\u6587\u5B57\u56DE\u7B54\u3002" }),
910
- state.platform === "darwin" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
1204
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-warn", children: [
1205
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: "\u5979\u7684\u58F0\u97F3\u7528\u963F\u91CC\u4E91\u767E\u70BC\uFF08CosyVoice\uFF09\uFF0C\u8FD8\u6CA1\u6709\u627E\u5230 API key\uFF0C\u73B0\u5728\u53EA\u7528\u6587\u5B57\u56DE\u7B54\u3002" }),
1206
+ state.platform === "darwin" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { children: [
911
1207
  "\u5728\u7EC8\u7AEF\u8FD0\u884C\u4E0B\u9762\u8FD9\u6761\u547D\u4EE4\uFF0C\u6309\u63D0\u793A\u7C98\u8D34 key\uFF08\u4E24\u6B21\uFF0C\u5C4F\u5E55\u4E0A\u4E0D\u663E\u793A\uFF09\uFF0C\u4E0D\u7528\u91CD\u542F\uFF1A",
912
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("br", {}),
913
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: "security add-generic-password -a dsh-her -s dsh-her-dashscope -w" })
914
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
1208
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("br", {}),
1209
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { children: "security add-generic-password -a dsh-her -s dsh-her-dashscope -w" })
1210
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { children: [
915
1211
  "\u628A key \u8BBE\u6210\u73AF\u5883\u53D8\u91CF ",
916
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: "DASHSCOPE_API_KEY" }),
1212
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("code", { children: "DASHSCOPE_API_KEY" }),
917
1213
  "\uFF0C\u7136\u540E\u91CD\u542F dsh\u3002"
918
1214
  ] }),
919
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-faint", children: "key \u4E0D\u4F1A\u5B58\u8FDB\u4EFB\u4F55\u6587\u4EF6\uFF0C\u4E5F\u4E0D\u8981\u8D34\u5230\u804A\u5929\u91CC\u3002" })
1215
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-faint", children: "key \u4E0D\u4F1A\u5B58\u8FDB\u4EFB\u4F55\u6587\u4EF6\uFF0C\u4E5F\u4E0D\u8981\u8D34\u5230\u804A\u5929\u91CC\u3002" })
920
1216
  ] });
921
1217
  }
922
1218
  function VoicePicker({ state, apply: apply2, onSaved, saveLabel = "\u7528\u8FD9\u4E2A\u58F0\u97F3" }) {
923
- const [voice, setVoice] = (0, import_react2.useState)(state.character.voice.id);
924
- const [speed, setSpeed] = (0, import_react2.useState)(state.character.voice.speed);
925
- const [error, setError] = (0, import_react2.useState)();
926
- const [playing, setPlaying] = (0, import_react2.useState)();
1219
+ const inUse = state.character.voice;
1220
+ const [trying, setTrying] = (0, import_react4.useState)(inUse.id);
1221
+ const [speed, setSpeed] = (0, import_react4.useState)(inUse.speed);
1222
+ const [error, setError] = (0, import_react4.useState)();
1223
+ const [playing, setPlaying] = (0, import_react4.useState)();
1224
+ const [service, setService] = (0, import_react4.useState)(serviceOf(inUse.id));
927
1225
  const { status: speaking, error: speakingError } = state.voice.speaking;
928
1226
  const listen = async (which) => {
929
- setVoice(which);
1227
+ setTrying(which);
930
1228
  setPlaying(which);
931
1229
  setError(void 0);
932
1230
  const result = await herApi.previewVoice(which, speed, `\u4F60\u597D\u5440\uFF0C\u6211\u662F${state.character.name}\uFF0C\u6211\u5728\u4F60\u684C\u9762\u4E0A\u7B49\u4F60\u597D\u4E45\u5566\u3002\u4ECA\u5929\u8FC7\u5F97\u600E\u4E48\u6837\uFF1F`);
@@ -935,46 +1233,100 @@ function VoicePicker({ state, apply: apply2, onSaved, saveLabel = "\u7528\u8FD9\
935
1233
  else setError(result.message);
936
1234
  };
937
1235
  const save = async () => {
938
- if (await apply2(herApi.saveCharacter({ voice, speed }))) onSaved?.();
1236
+ if (await apply2(herApi.saveCharacter({ voice: trying, speed }))) onSaved?.();
939
1237
  };
940
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
941
- (speaking === "no-key" || speaking === "no-quota") && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(KeyHelp, { state }),
942
- speaking === "off" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-warn", children: "\u5979\u7684\u58F0\u97F3\u5DF2\u5173\u95ED\uFF08\u63D2\u4EF6\u8BBE\u7F6E\u91CC voice.enabled \u662F false\uFF09\uFF0C\u53EA\u7528\u6587\u5B57\u56DE\u7B54\u3002" }),
943
- speaking === "installing" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: "\u7B2C\u4E00\u6B21\u7528\uFF0C\u6B63\u5728\u51C6\u5907 Edge \u8BED\u97F3\u7EC4\u4EF6\uFF08\u4E00\u4E24\u5206\u949F\uFF09\u2026" }),
944
- speaking === "failed" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "her-warn", children: [
945
- "\u5979\u7684\u58F0\u97F3\u521A\u624D\u51FA\u9519\u4E86\uFF1A",
1238
+ const changed = trying !== inUse.id || speed !== inUse.speed;
1239
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1240
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "her-now", children: [
1241
+ "\u6B63\u5728\u7528\uFF1A",
1242
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("b", { children: voiceLabel(state, inUse.id) }),
1243
+ "\uFF08",
1244
+ SERVICE_SHORT[serviceOf(inUse.id)],
1245
+ "\uFF0C\u8BED\u901F ",
1246
+ inUse.speed.toFixed(1),
1247
+ "\uFF09",
1248
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Dot, { tone: speakingTone(speaking) }),
1249
+ speakingShort(speaking)
1250
+ ] }),
1251
+ (speaking === "no-key" || speaking === "no-quota") && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(KeyHelp, { state }),
1252
+ speaking === "off" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-warn", children: "\u5979\u7684\u58F0\u97F3\u5DF2\u5173\u95ED\uFF08\u63D2\u4EF6\u8BBE\u7F6E\u91CC voice.enabled \u662F false\uFF09\uFF0C\u53EA\u7528\u6587\u5B57\u56DE\u7B54\u3002" }),
1253
+ speaking === "installing" && state.voice.speaking.service === "edge" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-muted", children: "\u7B2C\u4E00\u6B21\u7528\uFF0C\u6B63\u5728\u51C6\u5907 Edge \u8BED\u97F3\u7EC4\u4EF6\uFF08\u4E00\u4E24\u5206\u949F\uFF09\u2026" }),
1254
+ speaking === "failed" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "her-warn", children: [
1255
+ "\u5979\u7684\u58F0\u97F3\u51FA\u9519\u4E86\uFF1A",
946
1256
  speakingError ?? "\u672A\u77E5\u539F\u56E0",
947
- "\u3002\u4F1A\u81EA\u52A8\u91CD\u8BD5\u3002"
1257
+ "\u3002",
1258
+ state.voice.speaking.service === "ming" ? "" : "\u4F1A\u81EA\u52A8\u91CD\u8BD5\u3002"
948
1259
  ] }),
949
- ["edge", "cosyvoice"].map((service) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
950
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "her-label", children: SERVICE_NAMES[service] }),
951
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "her-grid", children: VOICES.filter((v2) => v2.service === service).map((v2) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { className: `her-choice ${v2.id === voice ? "on" : ""}`, disabled: speaking === "off", onClick: () => void listen(v2.id), children: [
1260
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "her-tabs her-subtabs", children: ["edge", "cosyvoice", "ming"].map((id) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { className: `her-tab ${service === id ? "on" : ""}`, onClick: () => setService(id), children: [
1261
+ SERVICE_SHORT[id],
1262
+ serviceOf(inUse.id) === id && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-badge her-badge-inline", children: "\u5728\u7528" })
1263
+ ] }, id)) }),
1264
+ service === "ming" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MingSection, { state, apply: apply2, inUse: inUse.id, trying, ...playing === void 0 ? {} : { playing }, onListen: (id) => void listen(id) }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1265
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "her-label", children: SERVICE_NAMES[service] }),
1266
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "her-grid", children: VOICES.filter((v2) => v2.service === service).map((v2) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { className: choiceClass(v2.id, inUse.id, trying), disabled: speaking === "off", onClick: () => void listen(v2.id), children: [
952
1267
  v2.name,
953
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("small", { children: playing === v2.id ? "\u6B63\u5728\u5408\u6210\u2026" : `${v2.desc} \xB7 \u70B9\u4E00\u4E0B\u8BD5\u542C` })
1268
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { children: choiceNote(v2.id, inUse.id, `${v2.desc}${v2.id === inUse.id ? "" : " \xB7 \u70B9\u4E00\u4E0B\u8BD5\u542C"}`, playing) })
954
1269
  ] }, v2.id)) })
955
- ] }, service)),
956
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
957
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "her-muted", children: [
1270
+ ] }),
1271
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-row", children: [
1272
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "her-muted", children: [
958
1273
  "\u8BED\u901F ",
959
1274
  speed.toFixed(1)
960
1275
  ] }),
961
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "range", min: 0.7, max: 1.4, step: 0.1, value: speed, onChange: (e) => setSpeed(Number(e.target.value)) }),
962
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", disabled: speaking === "off", onClick: () => void listen(voice), children: "\u7528\u8FD9\u4E2A\u8BED\u901F\u8BD5\u542C" })
1276
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "range", min: 0.7, max: 1.4, step: 0.1, value: speed, onChange: (e) => setSpeed(Number(e.target.value)) }),
1277
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn", disabled: speaking === "off", onClick: () => void listen(trying), children: "\u7528\u8FD9\u4E2A\u8BED\u901F\u8BD5\u542C" })
963
1278
  ] }),
964
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-faint", children: "Edge \u7684\u58F0\u97F3\u514D\u8D39\uFF0C\u4F46\u4E0D\u662F\u5FAE\u8F6F\u516C\u5F00\u7684\u6B63\u5F0F\u63A5\u53E3\uFF0C\u53EF\u80FD\u54EA\u5929\u5931\u6548\uFF1B\u767E\u70BC\u7684\u58F0\u97F3\u66F4\u7A33\uFF0C\u8981 key \u548C\u4ED8\u8D39\u989D\u5EA6\u3002\u7528\u4F60\u81EA\u5DF1\u5F55\u7684\u58F0\u97F3\u514B\u9686\uFF0C\u4E4B\u540E\u4F1A\u52A0\u5728\u8FD9\u91CC\u3002" }),
965
- error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-error", children: error }),
966
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "her-row", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn primary", onClick: () => void save(), children: saveLabel }) })
1279
+ changed && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-pending", children: [
1280
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
1281
+ "\u4F60\u5728\u8BD5\u300C",
1282
+ voiceLabel(state, trying),
1283
+ "\u300D",
1284
+ speed !== inUse.speed ? `\uFF0C\u8BED\u901F ${speed.toFixed(1)}` : "",
1285
+ "\uFF0C\u8FD8\u6CA1\u6362\u4E0A\u3002"
1286
+ ] }),
1287
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn primary", onClick: () => void save(), children: onSaved === void 0 ? `\u6362\u6210\u300C${voiceLabel(state, trying)}\u300D` : saveLabel }),
1288
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn", onClick: () => {
1289
+ setTrying(inUse.id);
1290
+ setSpeed(inUse.speed);
1291
+ }, children: "\u4E0D\u6362\u4E86" })
1292
+ ] }),
1293
+ !changed && onSaved !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "her-row", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn primary", onClick: () => onSaved(), children: saveLabel }) }),
1294
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-faint", children: "Edge \u7684\u58F0\u97F3\u514D\u8D39\uFF0C\u4F46\u4E0D\u662F\u5FAE\u8F6F\u516C\u5F00\u7684\u6B63\u5F0F\u63A5\u53E3\uFF0C\u53EF\u80FD\u54EA\u5929\u5931\u6548\uFF1B\u767E\u70BC\u7684\u58F0\u97F3\u66F4\u7A33\uFF0C\u8981 key \u548C\u4ED8\u8D39\u989D\u5EA6\uFF1B\u672C\u673A Ming \u4E0D\u8054\u7F51\u3001\u514D\u8D39\u3001\u80FD\u8868\u8FBE\u60C5\u7EEA\uFF0C\u8FD8\u80FD\u8BBE\u8BA1\u6216\u514B\u9686\u5979\u81EA\u5DF1\u7684\u58F0\u97F3\uFF0C\u4F46\u8981\u5148\u88C5\uFF08\u7EA6 2 GB\uFF09\u3002" }),
1295
+ error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-error", children: error })
967
1296
  ] });
968
1297
  }
1298
+ function speakingTone(status) {
1299
+ if (status === "ready") return "ok";
1300
+ if (status === "off") return "off";
1301
+ return status === "checking" || status === "installing" ? "warn" : "bad";
1302
+ }
1303
+ function speakingShort(status) {
1304
+ switch (status) {
1305
+ case "ready":
1306
+ return "\u6B63\u5E38";
1307
+ case "checking":
1308
+ return "\u6B63\u5728\u51C6\u5907";
1309
+ case "installing":
1310
+ return "\u6B63\u5728\u5B89\u88C5";
1311
+ case "no-key":
1312
+ return "\u7F3A key";
1313
+ case "no-quota":
1314
+ return "\u989D\u5EA6\u7528\u5B8C";
1315
+ case "off":
1316
+ return "\u5DF2\u5173\u95ED";
1317
+ default:
1318
+ return "\u51FA\u9519\u4E86";
1319
+ }
1320
+ }
969
1321
  var DEFAULT_CHOICE = "";
970
1322
  function ModelPicker({ state, apply: apply2 }) {
971
1323
  const chosen = state.character.model;
972
- const [groups, setGroups] = (0, import_react2.useState)();
973
- const [loadError, setLoadError] = (0, import_react2.useState)();
974
- const [choice, setChoice] = (0, import_react2.useState)(chosen === void 0 ? DEFAULT_CHOICE : `${chosen.provider}/${chosen.model}`);
975
- const [effort, setEffort] = (0, import_react2.useState)(chosen?.effort ?? "");
976
- const [saved, setSaved] = (0, import_react2.useState)(false);
977
- (0, import_react2.useEffect)(() => {
1324
+ const [groups, setGroups] = (0, import_react4.useState)();
1325
+ const [loadError, setLoadError] = (0, import_react4.useState)();
1326
+ const [choice, setChoice] = (0, import_react4.useState)(chosen === void 0 ? DEFAULT_CHOICE : `${chosen.provider}/${chosen.model}`);
1327
+ const [effort, setEffort] = (0, import_react4.useState)(chosen?.effort ?? "");
1328
+ const [saved, setSaved] = (0, import_react4.useState)(false);
1329
+ (0, import_react4.useEffect)(() => {
978
1330
  void modelCatalog().then((result) => {
979
1331
  if (result.ok) setGroups(result.groups);
980
1332
  else setLoadError(result.message);
@@ -991,97 +1343,109 @@ function ModelPicker({ state, apply: apply2 }) {
991
1343
  const value = provider === void 0 ? null : { provider, model, ...effort === "" ? {} : { effort } };
992
1344
  if (await apply2(herApi.saveCharacter({ model: value }))) setSaved(true);
993
1345
  };
994
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
995
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "her-muted", children: [
996
- "\u73B0\u5728\u7528\u7684\uFF1A",
997
- state.model === null ? "\u6CA1\u6709\u53EF\u7528\u7684\u6A21\u578B" : `${nameOf(state.model.provider, state.model.model)}${state.model.effort ? `\uFF08\u601D\u8003\uFF1A${state.model.effort}\uFF09` : ""}`,
998
- state.model !== null && !state.model.chosen && "\uFF08dsh \u7684\u9ED8\u8BA4\u6A21\u578B\uFF09"
1346
+ const changed = choice !== (chosen === void 0 ? DEFAULT_CHOICE : `${chosen.provider}/${chosen.model}`) || effort !== (chosen?.effort ?? "");
1347
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1348
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "her-now", children: [
1349
+ "\u6B63\u5728\u7528\uFF1A",
1350
+ state.model === null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("b", { children: "\u6CA1\u6709\u53EF\u7528\u7684\u6A21\u578B" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("b", { children: nameOf(state.model.provider, state.model.model) }),
1351
+ state.model?.effort ? `\uFF08\u601D\u8003\uFF1A${state.model.effort}\uFF09` : "",
1352
+ state.model !== null && !state.model.chosen && "\uFF08\u8DDF\u968F dsh \u7684\u9ED8\u8BA4\u6A21\u578B\uFF09",
1353
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Dot, { tone: state.model === null || state.problem !== void 0 ? "bad" : "ok" }),
1354
+ state.model === null ? "\u5979\u6CA1\u6CD5\u8BF4\u8BDD" : state.problem !== void 0 ? "\u4E0A\u4E00\u6B21\u56DE\u7B54\u5931\u8D25\u4E86" : "\u6B63\u5E38"
999
1355
  ] }),
1000
- loadError !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "her-error", children: [
1356
+ state.problem !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-alert", children: state.problem.text }),
1357
+ loadError !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "her-error", children: [
1001
1358
  "\u62FF\u4E0D\u5230 dsh \u7684\u6A21\u578B\u5217\u8868\uFF1A",
1002
1359
  loadError
1003
1360
  ] }),
1004
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
1005
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { className: "her-select", style: { flex: 1, minWidth: 220 }, value: choice, disabled: groups === void 0, onChange: (e) => {
1361
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-row", children: [
1362
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { className: "her-select", style: { flex: 1, minWidth: 220 }, value: choice, disabled: groups === void 0, onChange: (e) => {
1006
1363
  setChoice(e.target.value);
1007
1364
  setEffort("");
1008
1365
  }, children: [
1009
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: DEFAULT_CHOICE, children: "\u8DDF\u968F dsh \u7684\u9ED8\u8BA4\u6A21\u578B" }),
1010
- groups?.map((g) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("optgroup", { label: g.name, children: g.models.map((m) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: `${g.id}/${m.id}`, children: m.name }, m.id)) }, g.id))
1366
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: DEFAULT_CHOICE, children: "\u8DDF\u968F dsh \u7684\u9ED8\u8BA4\u6A21\u578B" }),
1367
+ chosen !== void 0 && groups !== void 0 && !groups.some((g) => g.id === chosen.provider && g.models.some((m) => m.id === chosen.model)) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("option", { value: `${chosen.provider}/${chosen.model}`, children: [
1368
+ chosen.provider,
1369
+ " / ",
1370
+ chosen.model,
1371
+ "\uFF08\u4E0D\u5728 dsh \u7684\u6A21\u578B\u5217\u8868\u91CC\uFF09"
1372
+ ] }),
1373
+ groups?.map((g) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("optgroup", { label: g.name, children: g.models.map((m) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: `${g.id}/${m.id}`, children: m.name }, m.id)) }, g.id))
1011
1374
  ] }),
1012
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { className: "her-select", style: { width: 150 }, value: effort, disabled: efforts.length === 0, onChange: (e) => setEffort(e.target.value), children: [
1013
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: "\u601D\u8003\uFF1A\u9ED8\u8BA4" }),
1014
- efforts.map((x) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("option", { value: x.id, children: [
1375
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { className: "her-select", style: { width: 150 }, value: effort, disabled: efforts.length === 0, onChange: (e) => setEffort(e.target.value), children: [
1376
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "", children: "\u601D\u8003\uFF1A\u9ED8\u8BA4" }),
1377
+ efforts.map((x) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("option", { value: x.id, children: [
1015
1378
  "\u601D\u8003\uFF1A",
1016
1379
  x.name
1017
1380
  ] }, x.id))
1018
1381
  ] }),
1019
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn primary", disabled: groups === void 0, onClick: () => void save(), children: "\u7528\u8FD9\u4E2A\u6A21\u578B" })
1382
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn primary", disabled: groups === void 0 || !changed, onClick: () => void save(), children: changed ? "\u6362\u6210\u8FD9\u4E2A\u6A21\u578B" : "\u6B63\u5728\u7528\u8FD9\u4E2A" })
1020
1383
  ] }),
1021
- saved && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-ok", children: "\u5DF2\u6362\u597D\uFF0C\u4ECE\u5979\u7684\u4E0B\u4E00\u53E5\u8BDD\u5F00\u59CB\u751F\u6548\uFF1B\u4E4B\u524D\u804A\u8FC7\u7684\u90FD\u8FD8\u5728\u3002" }),
1022
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-faint", children: "\u804A\u5929\u8981\u7684\u662F\u5FEB\uFF1A\u9009 Flash \u4E00\u7C7B\u7684\u5FEB\u6A21\u578B\u3001\u601D\u8003\u9009 Low\uFF08\u6216 Off\uFF09\uFF0C\u5979\u5F00\u53E3\u4F1A\u5FEB\u5F88\u591A\u3002\u6A21\u578B\u7684\u8D26\u53F7\u548C\u4EF7\u683C\u5728 dsh \u7684\u8BBE\u7F6E\u91CC\u7BA1\u3002" })
1384
+ changed && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-warn", children: '\u9009\u4E86\u65B0\u7684\u6A21\u578B\uFF0C\u8FD8\u6CA1\u6362\u4E0A\uFF1A\u70B9"\u6362\u6210\u8FD9\u4E2A\u6A21\u578B"\u3002' }),
1385
+ saved && !changed && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-ok", children: "\u5DF2\u6362\u597D\uFF0C\u4ECE\u5979\u7684\u4E0B\u4E00\u53E5\u8BDD\u5F00\u59CB\u751F\u6548\uFF1B\u4E4B\u524D\u804A\u8FC7\u7684\u90FD\u8FD8\u5728\u3002" }),
1386
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-faint", children: "\u804A\u5929\u8981\u7684\u662F\u5FEB\uFF1A\u9009 Flash \u4E00\u7C7B\u7684\u5FEB\u6A21\u578B\u3001\u601D\u8003\u9009 Low\uFF08\u6216 Off\uFF09\uFF0C\u5979\u5F00\u53E3\u4F1A\u5FEB\u5F88\u591A\u3002\u6A21\u578B\u7684\u8D26\u53F7\u548C\u4EF7\u683C\u5728 dsh \u7684\u8BBE\u7F6E\u91CC\u7BA1\u3002" })
1023
1387
  ] });
1024
1388
  }
1025
1389
  function MicCheck({ state }) {
1026
1390
  const shortcut = state.platform === "darwin" ? "\u2303\u2325\u7A7A\u683C" : "Ctrl+Alt+\u7A7A\u683C";
1027
1391
  const fresh = state.heard !== void 0 && Date.now() - state.heard.at < 12e4;
1028
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1029
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
1392
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1393
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { children: [
1030
1394
  "\u6309 ",
1031
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("b", { children: shortcut }),
1395
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("b", { children: shortcut }),
1032
1396
  '\uFF0C\u5BF9\u7740\u9EA6\u514B\u98CE\u8BF4\u4E00\u53E5\u8BDD\uFF08\u6BD4\u5982"\u4F60\u597D\u5440"\uFF09\u3002\u7B2C\u4E00\u6B21\u4F1A\u5F39\u51FA\u9EA6\u514B\u98CE\u6743\u9650\u8BF7\u6C42\uFF0C\u8BF7\u5141\u8BB8\u3002'
1033
1397
  ] }),
1034
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: "\u5979\u811A\u4E0B\u7684\u5C0F\u5706\u70B9\u4EAE\u8D77\u8868\u793A\u5728\u542C\uFF0C\u53D8\u7EFF\u8868\u793A\u542C\u5230\u4E86\u58F0\u97F3\u3002" }),
1035
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: fresh ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1036
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Dot, { tone: "ok" }),
1398
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: "\u5979\u811A\u4E0B\u7684\u5C0F\u5706\u70B9\u4EAE\u8D77\u8868\u793A\u5728\u542C\uFF0C\u53D8\u7EFF\u8868\u793A\u542C\u5230\u4E86\u58F0\u97F3\u3002" }),
1399
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: fresh ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1400
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Dot, { tone: "ok" }),
1037
1401
  "\u6211\u542C\u5230\u4E86\uFF1A\u300C",
1038
1402
  state.heard.text,
1039
1403
  "\u300D"
1040
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-muted", children: "\u8FD8\u6CA1\u542C\u5230\u2026\u2026" }) }),
1041
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-faint", children: "\u542C\u4E0D\u6E05\u65F6\uFF1A\u6362\u4E2A\u5B89\u9759\u7684\u5730\u65B9\uFF0C\u6216\u8005\u68C0\u67E5\u7CFB\u7EDF\u8BBE\u7F6E\u91CC\u9009\u7684\u9EA6\u514B\u98CE\u3002\u5916\u653E\u65F6\u5979\u7684\u58F0\u97F3\u53EF\u80FD\u88AB\u5F53\u6210\u4F60\u5728\u8BF4\u8BDD\uFF0C\u6234\u8033\u673A\u6548\u679C\u6700\u597D\u3002" })
1404
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-muted", children: "\u8FD8\u6CA1\u542C\u5230\u2026\u2026" }) }),
1405
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-faint", children: "\u542C\u4E0D\u6E05\u65F6\uFF1A\u6362\u4E2A\u5B89\u9759\u7684\u5730\u65B9\uFF0C\u6216\u8005\u68C0\u67E5\u7CFB\u7EDF\u8BBE\u7F6E\u91CC\u9009\u7684\u9EA6\u514B\u98CE\u3002\u5916\u653E\u65F6\u5979\u7684\u58F0\u97F3\u53EF\u80FD\u88AB\u5F53\u6210\u4F60\u5728\u8BF4\u8BDD\uFF0C\u6234\u8033\u673A\u6548\u679C\u6700\u597D\u3002" })
1042
1406
  ] });
1043
1407
  }
1044
1408
  function ScenePicker({ state, apply: apply2 }) {
1045
1409
  const look = state.body.look;
1046
1410
  if (look === void 0) return null;
1047
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-scenes", children: [
1048
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
1049
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("b", { children: look.name }),
1411
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-scenes", children: [
1412
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { children: [
1413
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("b", { children: look.name }),
1050
1414
  " \u7684\u573A\u666F",
1051
1415
  look.desk ? '\uFF08"\u6D6E\u5728\u6700\u4E0A\u5C42"\u65F6\u663E\u793A\u684C\u5BA0\uFF0C\u6362\u573A\u666F\u5728\u5176\u4ED6\u4E24\u79CD\u6A21\u5F0F\u4E0B\u770B\u5F97\u5230\uFF09' : ""
1052
1416
  ] }),
1053
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
1054
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
1055
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "checkbox", checked: look.auto, onChange: (e) => void apply2(herApi.setLook({ auto: e.target.checked })) }),
1417
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-row", children: [
1418
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { children: [
1419
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "checkbox", checked: look.auto, onChange: (e) => void apply2(herApi.setLook({ auto: e.target.checked })) }),
1056
1420
  " \u81EA\u52A8\u6362\u573A\u666F"
1057
1421
  ] }),
1058
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
1059
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "checkbox", checked: look.locked, onChange: (e) => void apply2(herApi.setLook({ locked: e.target.checked })) }),
1422
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { children: [
1423
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "checkbox", checked: look.locked, onChange: (e) => void apply2(herApi.setLook({ locked: e.target.checked })) }),
1060
1424
  " \u5F85\u5728\u73B0\u5728\u8FD9\u91CC\u4E0D\u52A8"
1061
1425
  ] })
1062
1426
  ] }),
1063
- look.scenes.map((scene) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row her-scene", children: [
1064
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { children: [
1065
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "checkbox", checked: scene.on, disabled: scene.id === look.current, onChange: (e) => void apply2(herApi.setLook({ on: { [scene.id]: e.target.checked } })) }),
1427
+ look.scenes.map((scene) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-row her-scene", children: [
1428
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { children: [
1429
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "checkbox", checked: scene.on, disabled: scene.id === look.current, onChange: (e) => void apply2(herApi.setLook({ on: { [scene.id]: e.target.checked } })) }),
1066
1430
  " ",
1067
1431
  scene.name
1068
1432
  ] }),
1069
- scene.id === look.current && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-tag ok", children: "\u73B0\u5728\u5728\u8FD9" }),
1070
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-muted", children: scene.when }),
1071
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", disabled: scene.id === look.current || !scene.on, onClick: () => void apply2(herApi.setLook({ go: scene.id })), children: "\u73B0\u5728\u53BB\u8FD9\u91CC" })
1433
+ scene.id === look.current && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-tag ok", children: "\u73B0\u5728\u5728\u8FD9" }),
1434
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-muted", children: scene.when }),
1435
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn", disabled: scene.id === look.current || !scene.on, onClick: () => void apply2(herApi.setLook({ go: scene.id })), children: "\u73B0\u5728\u53BB\u8FD9\u91CC" })
1072
1436
  ] }, scene.id)),
1073
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: '\u81EA\u52A8\u6362\u573A\u666F\u65F6\uFF0C\u6BCF\u4E2A\u573A\u666F\u81F3\u5C11\u5F85 20 \u5206\u949F\uFF0C\u4F60\u4EEC\u8BF4\u8BDD\u7684\u65F6\u5019\u4E0D\u6362\u3002\u8DDF\u5979\u8BF4"\u53BB\u5367\u5BA4\u5427""\u5C31\u5F85\u5728\u8FD9"\u4E5F\u884C\u3002' })
1437
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-muted", children: '\u81EA\u52A8\u6362\u573A\u666F\u65F6\uFF0C\u6BCF\u4E2A\u573A\u666F\u81F3\u5C11\u5F85 20 \u5206\u949F\uFF0C\u4F60\u4EEC\u8BF4\u8BDD\u7684\u65F6\u5019\u4E0D\u6362\u3002\u8DDF\u5979\u8BF4"\u53BB\u5367\u5BA4\u5427""\u5C31\u5F85\u5728\u8FD9"\u4E5F\u884C\u3002' })
1074
1438
  ] });
1075
1439
  }
1076
1440
  function ModePicker({ state, apply: apply2 }) {
1077
1441
  const current = state.body.mode;
1078
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "her-grid", children: ["overlay", "wallpaper", "window"].map((mode) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { className: `her-choice ${current === mode ? "on" : ""}`, disabled: !state.body.connected, onClick: () => void apply2(herApi.setMode(mode)), children: [
1442
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "her-grid", children: ["overlay", "wallpaper", "window"].map((mode) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { className: `her-choice ${current === mode ? "on" : ""}`, disabled: !state.body.connected, onClick: () => void apply2(herApi.setMode(mode)), children: [
1079
1443
  MODE_TEXT[mode].title,
1080
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("small", { children: MODE_TEXT[mode].desc })
1444
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { children: choiceNote(mode, current ?? "", MODE_TEXT[mode].desc) })
1081
1445
  ] }, mode)) });
1082
1446
  }
1083
1447
  function MemoryView({ state, apply: apply2 }) {
1084
- const [report, setReport] = (0, import_react2.useState)();
1448
+ const [report, setReport] = (0, import_react4.useState)();
1085
1449
  const { diary, lastDigestDay } = state.memory;
1086
1450
  const facts = [...state.memory.facts].reverse();
1087
1451
  const episodes = [...state.memory.episodes].reverse();
@@ -1107,84 +1471,84 @@ function MemoryView({ state, apply: apply2 }) {
1107
1471
 
1108
1472
  ${text}`)) void apply2(herApi.memoryRemove([id]));
1109
1473
  };
1110
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1111
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-card", children: [
1112
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("h2", { children: [
1474
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
1475
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-card", children: [
1476
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h2", { children: [
1113
1477
  "\u5173\u4E8E\u4F60\uFF08",
1114
1478
  facts.length,
1115
1479
  "\uFF09"
1116
1480
  ] }),
1117
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: '\u5979\u804A\u5929\u65F6\u81EA\u5DF1\u8BB0\u4E0B\u7684\u76F4\u63A5\u751F\u6548\uFF1B\u804A\u5B8C\u4E00\u5206\u949F\u540E\u5979\u4F1A\u628A\u521A\u624D\u7684\u8BDD\u8FC7\u4E00\u904D\uFF0C\u6311\u51FA\u6765\u7684\u5148"\u5F85\u786E\u8BA4"\uFF0C7 \u5929\u540E\u81EA\u52A8\u786E\u8BA4\uFF0C\u654F\u611F\u7684\u8981\u4F60\u70B9\u786E\u8BA4\u3002' }),
1118
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("ul", { className: "her-list", children: [
1119
- facts.map((f) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { children: [
1120
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "grow", children: f.text }),
1121
- isNew(f.createdAt) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-tag ok", children: "\u4ECA\u5929" }),
1122
- f.status === "candidate" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-tag warn", children: "\u5F85\u786E\u8BA4" }),
1123
- f.sensitive && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-tag bad", children: "\u654F\u611F" }),
1124
- f.status === "candidate" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn small", onClick: () => void apply2(herApi.memoryConfirm([f.id])), children: "\u786E\u8BA4" }),
1125
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn small", onClick: () => forget(f.id, f.text), children: "\u5FD8\u6389" })
1481
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-muted", children: '\u5979\u804A\u5929\u65F6\u81EA\u5DF1\u8BB0\u4E0B\u7684\u76F4\u63A5\u751F\u6548\uFF1B\u804A\u5B8C\u4E00\u5206\u949F\u540E\u5979\u4F1A\u628A\u521A\u624D\u7684\u8BDD\u8FC7\u4E00\u904D\uFF0C\u6311\u51FA\u6765\u7684\u5148"\u5F85\u786E\u8BA4"\uFF0C7 \u5929\u540E\u81EA\u52A8\u786E\u8BA4\uFF0C\u654F\u611F\u7684\u8981\u4F60\u70B9\u786E\u8BA4\u3002' }),
1482
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("ul", { className: "her-list", children: [
1483
+ facts.map((f) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { children: [
1484
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "grow", children: f.text }),
1485
+ isNew(f.createdAt) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-tag ok", children: "\u4ECA\u5929" }),
1486
+ f.status === "candidate" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-tag warn", children: "\u5F85\u786E\u8BA4" }),
1487
+ f.sensitive && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-tag bad", children: "\u654F\u611F" }),
1488
+ f.status === "candidate" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn small", onClick: () => void apply2(herApi.memoryConfirm([f.id])), children: "\u786E\u8BA4" }),
1489
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn small", onClick: () => forget(f.id, f.text), children: "\u5FD8\u6389" })
1126
1490
  ] }, f.id)),
1127
- facts.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { className: "her-muted", children: "\u8FD8\u6CA1\u6709" })
1491
+ facts.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { className: "her-muted", children: "\u8FD8\u6CA1\u6709" })
1128
1492
  ] })
1129
1493
  ] }),
1130
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-card", children: [
1131
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("h2", { children: [
1494
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-card", children: [
1495
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h2", { children: [
1132
1496
  "\u4E8B\u4EF6\uFF08",
1133
1497
  episodes.length,
1134
1498
  "\uFF09"
1135
1499
  ] }),
1136
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: "\u6709\u65E5\u671F\u7684\u4E8B\uFF0C\u5728\u5F53\u5929\u548C\u524D\u4E00\u5929\u5979\u4F1A\u81EA\u7136\u5730\u63D0\u8D77\u3002" }),
1137
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("ul", { className: "her-list", children: [
1138
- episodes.map((e) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { children: [
1139
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-faint", children: e.at.slice(0, 10) }),
1140
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "grow", children: e.text }),
1141
- isNew(e.at) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-tag ok", children: "\u4ECA\u5929" }),
1142
- e.due !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-tag", children: e.due }),
1143
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn small", onClick: () => forget(e.id, e.text), children: "\u5FD8\u6389" })
1500
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-muted", children: "\u6709\u65E5\u671F\u7684\u4E8B\uFF0C\u5728\u5F53\u5929\u548C\u524D\u4E00\u5929\u5979\u4F1A\u81EA\u7136\u5730\u63D0\u8D77\u3002" }),
1501
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("ul", { className: "her-list", children: [
1502
+ episodes.map((e) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { children: [
1503
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-faint", children: e.at.slice(0, 10) }),
1504
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "grow", children: e.text }),
1505
+ isNew(e.at) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-tag ok", children: "\u4ECA\u5929" }),
1506
+ e.due !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-tag", children: e.due }),
1507
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn small", onClick: () => forget(e.id, e.text), children: "\u5FD8\u6389" })
1144
1508
  ] }, e.id)),
1145
- episodes.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { className: "her-muted", children: "\u8FD8\u6CA1\u6709" })
1509
+ episodes.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { className: "her-muted", children: "\u8FD8\u6CA1\u6709" })
1146
1510
  ] })
1147
1511
  ] }),
1148
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-card", children: [
1149
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("h2", { children: [
1512
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-card", children: [
1513
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h2", { children: [
1150
1514
  "\u5979\u7684\u65E5\u8BB0\uFF08",
1151
1515
  diary.length,
1152
1516
  " \u5929\uFF09"
1153
1517
  ] }),
1154
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "her-muted", children: [
1518
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { className: "her-muted", children: [
1155
1519
  "\u65E5\u8BB0\u6BCF\u5929\u5199\u4E00\u7BC7\uFF1A\u4F60\u6700\u540E\u4E00\u6B21\u548C\u5979\u8BF4\u8BDD 30 \u5206\u949F\u540E\uFF08\u6216 23:30 \u4EE5\u540E\uFF09\u3002\u4E0A\u6B21\u5199\u5230\uFF1A",
1156
1520
  lastDigestDay ?? "\u8FD8\u6CA1\u6709"
1157
1521
  ] }),
1158
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: diary.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "her-muted", children: "\u8FD8\u6CA1\u6709" }) : diary.join("\u3001") }),
1159
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "her-row", children: [
1160
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", onClick: () => void digest(), children: "\u73B0\u5728\u6574\u7406\u4ECA\u5929" }),
1161
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "her-btn", onClick: () => void download(), children: "\u5BFC\u51FA\u5168\u90E8\uFF08Markdown\uFF09" })
1522
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: diary.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "her-muted", children: "\u8FD8\u6CA1\u6709" }) : diary.join("\u3001") }),
1523
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "her-row", children: [
1524
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn", onClick: () => void digest(), children: "\u73B0\u5728\u6574\u7406\u4ECA\u5929" }),
1525
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "her-btn", onClick: () => void download(), children: "\u5BFC\u51FA\u5168\u90E8\uFF08Markdown\uFF09" })
1162
1526
  ] }),
1163
- report !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "her-muted", children: report })
1527
+ report !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "her-muted", children: report })
1164
1528
  ] })
1165
1529
  ] });
1166
1530
  }
1167
1531
 
1168
1532
  // src/client/Page.tsx
1169
- var import_jsx_runtime3 = require("react/jsx-runtime");
1533
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1170
1534
  var POLL_MS = 2e3;
1171
1535
  function HerPage() {
1172
- const [state, setState] = (0, import_react3.useState)();
1173
- const [error, setError] = (0, import_react3.useState)();
1174
- const [wizard, setWizard] = (0, import_react3.useState)();
1175
- const refresh = (0, import_react3.useCallback)(async () => {
1536
+ const [state, setState] = (0, import_react5.useState)();
1537
+ const [error, setError] = (0, import_react5.useState)();
1538
+ const [wizard, setWizard] = (0, import_react5.useState)();
1539
+ const refresh = (0, import_react5.useCallback)(async () => {
1176
1540
  const result = await herApi.state();
1177
1541
  if (result.ok) {
1178
1542
  setState(result.state);
1179
1543
  setError(void 0);
1180
1544
  } else setError(result.message);
1181
1545
  }, []);
1182
- (0, import_react3.useEffect)(() => {
1546
+ (0, import_react5.useEffect)(() => {
1183
1547
  void refresh();
1184
1548
  const timer = setInterval(() => void refresh(), POLL_MS);
1185
1549
  return () => clearInterval(timer);
1186
1550
  }, [refresh]);
1187
- const apply2 = (0, import_react3.useCallback)(async (call) => {
1551
+ const apply2 = (0, import_react5.useCallback)(async (call) => {
1188
1552
  const result = await call;
1189
1553
  if (result.ok) {
1190
1554
  setState(result.state);
@@ -1195,148 +1559,159 @@ function HerPage() {
1195
1559
  return false;
1196
1560
  }, []);
1197
1561
  if (state === void 0) {
1198
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "her-page", children: error === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "her-muted", children: "\u6B63\u5728\u8FDE\u63A5\u5979\u7684\u5927\u8111\u2026" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "her-error", children: [
1562
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "her-page", children: error === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "her-muted", children: "\u6B63\u5728\u8FDE\u63A5\u5979\u7684\u5927\u8111\u2026" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "her-error", children: [
1199
1563
  "\u8FDE\u4E0D\u4E0A\uFF1A",
1200
1564
  error
1201
1565
  ] }) });
1202
1566
  }
1203
1567
  const showWizard = wizard ?? !state.character.onboarded;
1204
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-page", children: [
1205
- showWizard ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wizard, { state, apply: apply2, onDone: () => setWizard(false) }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Manage, { state, apply: apply2, onWizard: () => setWizard(true) }),
1206
- error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "her-error", children: error })
1568
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-page", children: [
1569
+ showWizard ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Wizard, { state, apply: apply2, onDone: () => setWizard(false) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Manage, { state, apply: apply2, onWizard: () => setWizard(true) }),
1570
+ error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "her-error", children: error })
1207
1571
  ] });
1208
1572
  }
1209
1573
  var STEPS = ["\u68C0\u67E5", "\u8EAB\u4F53", "\u5916\u5F62", "\u4EBA\u8BBE", "\u58F0\u97F3", "\u9EA6\u514B\u98CE", "\u653E\u5230\u684C\u9762"];
1210
1574
  function Wizard({ state, apply: apply2, onDone }) {
1211
- const [step, setStep] = (0, import_react3.useState)(0);
1575
+ const [step, setStep] = (0, import_react5.useState)(0);
1212
1576
  const next = () => setStep((s) => Math.min(s + 1, STEPS.length - 1));
1213
1577
  const finish = async () => {
1214
1578
  if (await apply2(herApi.saveCharacter({ onboarded: true }))) onDone();
1215
1579
  };
1216
1580
  const body = state.body;
1217
- const nav = (canNext, hint) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-row", children: [
1218
- step > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "her-btn", onClick: () => setStep(step - 1), children: "\u4E0A\u4E00\u6B65" }),
1219
- step < STEPS.length - 1 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "her-btn primary", disabled: !canNext, onClick: next, children: "\u4E0B\u4E00\u6B65" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "her-btn primary", onClick: () => void finish(), children: "\u5B8C\u6210" }),
1220
- hint !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "her-muted", children: hint })
1581
+ const nav = (canNext, hint) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-row", children: [
1582
+ step > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "her-btn", onClick: () => setStep(step - 1), children: "\u4E0A\u4E00\u6B65" }),
1583
+ step < STEPS.length - 1 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "her-btn primary", disabled: !canNext, onClick: next, children: "\u4E0B\u4E00\u6B65" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "her-btn primary", onClick: () => void finish(), children: "\u5B8C\u6210" }),
1584
+ hint !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "her-muted", children: hint })
1221
1585
  ] });
1222
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1223
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-head", children: [
1224
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h1", { children: "\u8BA9\u5979\u4F4F\u5230\u4F60\u7684\u684C\u9762\u4E0A" }),
1225
- state.character.onboarded && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "her-btn link", onClick: onDone, children: "\u56DE\u5230\u7BA1\u7406\u9875" })
1586
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1587
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-head", children: [
1588
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { children: "\u8BA9\u5979\u4F4F\u5230\u4F60\u7684\u684C\u9762\u4E0A" }),
1589
+ state.character.onboarded && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "her-btn link", onClick: onDone, children: "\u56DE\u5230\u7BA1\u7406\u9875" })
1226
1590
  ] }),
1227
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "her-steps", children: STEPS.map((name, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { className: `her-step ${i === step ? "on" : i < step ? "done" : ""}`, onClick: () => setStep(i), children: [
1591
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "her-steps", children: STEPS.map((name, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("button", { className: `her-step ${i === step ? "on" : i < step ? "done" : ""}`, onClick: () => setStep(i), children: [
1228
1592
  i + 1,
1229
1593
  ". ",
1230
1594
  name
1231
1595
  ] }, name)) }),
1232
- step === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", children: [
1233
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u5148\u770B\u770B\u51C6\u5907\u597D\u4E86\u6CA1\u6709" }),
1234
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: state.model === null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1235
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Dot, { tone: "bad" }),
1596
+ step === 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-card", children: [
1597
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u5148\u770B\u770B\u51C6\u5907\u597D\u4E86\u6CA1\u6709" }),
1598
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: state.model === null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1599
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Dot, { tone: "bad" }),
1236
1600
  "dsh \u8FD8\u6CA1\u6709\u53EF\u7528\u7684\u6A21\u578B\u3002\u8BF7\u5148\u5728 dsh \u8BBE\u7F6E\u91CC\u914D\u597D\u4E00\u4E2A\u6A21\u578B\uFF08\u6BD4\u5982 DeepSeek\uFF09\uFF0C\u518D\u56DE\u6765\u3002"
1237
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1238
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Dot, { tone: "ok" }),
1601
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1602
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Dot, { tone: "ok" }),
1239
1603
  "\u5927\u8111\u7528\u7684\u6A21\u578B\uFF1A",
1240
1604
  state.model.provider,
1241
1605
  " / ",
1242
1606
  state.model.model
1243
1607
  ] }) }),
1244
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { children: [
1245
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Dot, { tone: toneOf(state.voice.speaking.status) }),
1608
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { children: [
1609
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Dot, { tone: toneOf(state.voice.speaking.status) }),
1246
1610
  "\u5979\u7684\u58F0\u97F3\uFF1A",
1247
1611
  speakingText(state.voice.speaking.status, state.voice.speaking.service)
1248
1612
  ] }),
1249
- (state.voice.speaking.status === "no-key" || state.voice.speaking.status === "no-quota") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(KeyHelp, { state }),
1250
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { children: [
1251
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Dot, { tone: toneOf(state.voice.status) }),
1613
+ (state.voice.speaking.status === "no-key" || state.voice.speaking.status === "no-quota") && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(KeyHelp, { state }),
1614
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { children: [
1615
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Dot, { tone: toneOf(state.voice.status) }),
1252
1616
  "\u542C\u4F60\u8BF4\u8BDD\uFF1A",
1253
1617
  listeningText(state.voice.status)
1254
1618
  ] }),
1255
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { children: [
1256
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Dot, { tone: "ok" }),
1619
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { children: [
1620
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Dot, { tone: "ok" }),
1257
1621
  "\u7CFB\u7EDF\uFF1A",
1258
1622
  platformText(state.platform)
1259
1623
  ] }),
1260
1624
  nav(state.model !== null, state.model === null ? "\u6CA1\u6709\u6A21\u578B\u5979\u6CA1\u6CD5\u8BF4\u8BDD" : void 0)
1261
1625
  ] }),
1262
- step === 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", children: [
1263
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u5979\u7684\u8EAB\u4F53" }),
1264
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "her-muted", children: '\u5979\u7684\u6837\u5B50\u548C\u58F0\u97F3\u5728\u4E00\u4E2A\u5355\u72EC\u7684\u684C\u9762\u7A0B\u5E8F\u91CC\uFF08"\u8EAB\u4F53"\uFF09\uFF0C\u8FD9\u91CC\u7684 dsh \u662F\u5979\u7684\u5927\u8111\u3002\u4E24\u8FB9\u8FDE\u4E0A\u5979\u624D\u80FD\u51FA\u73B0\u5728\u684C\u9762\u4E0A\u3002' }),
1265
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BodyStatus, { state, apply: apply2 }),
1626
+ step === 1 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-card", children: [
1627
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u5979\u7684\u8EAB\u4F53" }),
1628
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "her-muted", children: '\u5979\u7684\u6837\u5B50\u548C\u58F0\u97F3\u5728\u4E00\u4E2A\u5355\u72EC\u7684\u684C\u9762\u7A0B\u5E8F\u91CC\uFF08"\u8EAB\u4F53"\uFF09\uFF0C\u8FD9\u91CC\u7684 dsh \u662F\u5979\u7684\u5927\u8111\u3002\u4E24\u8FB9\u8FDE\u4E0A\u5979\u624D\u80FD\u51FA\u73B0\u5728\u684C\u9762\u4E0A\u3002' }),
1629
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BodyStatus, { state, apply: apply2 }),
1266
1630
  nav(body.connected, body.connected ? void 0 : "\u4E5F\u53EF\u4EE5\u5148\u8DF3\u8FC7\uFF0C\u4E4B\u540E\u5728\u7BA1\u7406\u9875\u518D\u8FDE"),
1267
- !body.connected && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "her-row", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "her-btn link", onClick: next, children: "\u5148\u8DF3\u8FC7" }) })
1631
+ !body.connected && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "her-row", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "her-btn link", onClick: next, children: "\u5148\u8DF3\u8FC7" }) })
1268
1632
  ] }),
1269
- step === 2 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", children: [
1270
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u9009\u4E00\u4E2A\u5916\u5F62" }),
1271
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "her-muted", children: "\u5916\u5F62\u5305\u662F\u4E00\u7EC4\u77ED\u89C6\u9891\uFF1A\u5F85\u673A\u3001\u8BF4\u8BDD\u3001\u51E0\u4E2A\u52A8\u4F5C\u3002\u70B9\u4E00\u4E0B\u5C31\u6362\u4E0A\uFF1B\u4E5F\u53EF\u4EE5\u5BFC\u5165\u4F60\u81EA\u5DF1\u751F\u6210\u7684\u7D20\u6750\u3002" }),
1272
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PackPicker, { state, apply: apply2 }),
1633
+ step === 2 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-card", children: [
1634
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u9009\u4E00\u4E2A\u5916\u5F62" }),
1635
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "her-muted", children: "\u5916\u5F62\u5305\u662F\u4E00\u7EC4\u77ED\u89C6\u9891\uFF1A\u5F85\u673A\u3001\u8BF4\u8BDD\u3001\u51E0\u4E2A\u52A8\u4F5C\u3002\u70B9\u4E00\u4E0B\u5C31\u6362\u4E0A\uFF1B\u4E5F\u53EF\u4EE5\u5BFC\u5165\u4F60\u81EA\u5DF1\u751F\u6210\u7684\u7D20\u6750\u3002" }),
1636
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PackPicker, { state, apply: apply2 }),
1273
1637
  nav(true)
1274
1638
  ] }),
1275
- step === 3 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", children: [
1276
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u5979\u662F\u8C01" }),
1277
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PersonaEditor, { state, apply: apply2, onSaved: next, saveLabel: "\u4FDD\u5B58\uFF0C\u4E0B\u4E00\u6B65" }),
1639
+ step === 3 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-card", children: [
1640
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u5979\u662F\u8C01" }),
1641
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PersonaEditor, { state, apply: apply2, onSaved: next, saveLabel: "\u4FDD\u5B58\uFF0C\u4E0B\u4E00\u6B65" }),
1278
1642
  nav(true)
1279
1643
  ] }),
1280
- step === 4 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", children: [
1281
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u5979\u7684\u58F0\u97F3" }),
1282
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(VoicePicker, { state, apply: apply2, onSaved: next, saveLabel: "\u7528\u8FD9\u4E2A\u58F0\u97F3\uFF0C\u4E0B\u4E00\u6B65" }),
1644
+ step === 4 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-card", children: [
1645
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u5979\u7684\u58F0\u97F3" }),
1646
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(VoicePicker, { state, apply: apply2, onSaved: next, saveLabel: "\u7528\u8FD9\u4E2A\u58F0\u97F3\uFF0C\u4E0B\u4E00\u6B65" }),
1283
1647
  nav(true)
1284
1648
  ] }),
1285
- step === 5 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", children: [
1286
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u8BD5\u8BD5\u548C\u5979\u8BF4\u8BDD" }),
1287
- body.connected ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MicCheck, { state }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "her-muted", children: "\u8EAB\u4F53\u8FDE\u4E0A\u4E4B\u540E\u624D\u80FD\u7528\u9EA6\u514B\u98CE\u3002" }),
1649
+ step === 5 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-card", children: [
1650
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u8BD5\u8BD5\u548C\u5979\u8BF4\u8BDD" }),
1651
+ body.connected ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MicCheck, { state }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "her-muted", children: "\u8EAB\u4F53\u8FDE\u4E0A\u4E4B\u540E\u624D\u80FD\u7528\u9EA6\u514B\u98CE\u3002" }),
1288
1652
  nav(true)
1289
1653
  ] }),
1290
- step === 6 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", children: [
1291
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u628A\u5979\u653E\u5230\u684C\u9762\u4E0A" }),
1292
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "her-muted", children: "\u968F\u65F6\u53EF\u4EE5\u5728\u7BA1\u7406\u9875\u6539\u3002" }),
1293
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModePicker, { state, apply: apply2 }),
1294
- !body.connected && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "her-muted", children: "\u8EAB\u4F53\u8FDE\u4E0A\u4E4B\u540E\u624D\u80FD\u5207\u6362\u3002" }),
1654
+ step === 6 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-card", children: [
1655
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u628A\u5979\u653E\u5230\u684C\u9762\u4E0A" }),
1656
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "her-muted", children: "\u968F\u65F6\u53EF\u4EE5\u5728\u7BA1\u7406\u9875\u6539\u3002" }),
1657
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ModePicker, { state, apply: apply2 }),
1658
+ !body.connected && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "her-muted", children: "\u8EAB\u4F53\u8FDE\u4E0A\u4E4B\u540E\u624D\u80FD\u5207\u6362\u3002" }),
1295
1659
  nav(true)
1296
1660
  ] })
1297
1661
  ] });
1298
1662
  }
1299
1663
  var TABS = [["overview", "\u6982\u51B5"], ["settings", "\u8BBE\u7F6E"], ["memory", "\u5979\u8BB0\u5F97\u7684\u4E8B"], ["workshop", "\u5F62\u8C61\u5DE5\u574A"]];
1300
1664
  function Manage({ state, apply: apply2, onWizard }) {
1301
- const [tab, setTab] = (0, import_react3.useState)("overview");
1302
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1303
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-head", children: [
1304
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h1", { children: state.character.name }),
1305
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "her-btn link", onClick: onWizard, children: "\u91CD\u65B0\u8D70\u4E00\u904D\u5411\u5BFC" })
1665
+ const [tab, setTab] = (0, import_react5.useState)("overview");
1666
+ const [jump, setJump] = (0, import_react5.useState)();
1667
+ const goSettings = (section) => {
1668
+ setTab("settings");
1669
+ setJump(section);
1670
+ };
1671
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1672
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-head", children: [
1673
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { children: state.character.name }),
1674
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "her-btn link", onClick: onWizard, children: "\u91CD\u65B0\u8D70\u4E00\u904D\u5411\u5BFC" })
1306
1675
  ] }),
1307
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "her-tabs", children: TABS.map(([id, label]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: `her-tab ${tab === id ? "on" : ""}`, onClick: () => setTab(id), children: label }, id)) }),
1308
- tab === "overview" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1309
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", children: [
1310
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u8EAB\u4F53" }),
1311
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BodyStatus, { state, apply: apply2 })
1676
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "her-tabs", children: TABS.map(([id, label]) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: `her-tab ${tab === id ? "on" : ""}`, onClick: () => setTab(id), children: label }, id)) }),
1677
+ tab === "overview" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1678
+ state.problem !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-card her-alert", children: [
1679
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u5979\u521A\u624D\u6CA1\u80FD\u56DE\u7B54" }),
1680
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: state.problem.text }),
1681
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "her-row", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { className: "her-btn primary", onClick: () => goSettings("model"), children: "\u53BB\u6362\u6A21\u578B" }) })
1682
+ ] }),
1683
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-card", children: [
1684
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u8EAB\u4F53" }),
1685
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BodyStatus, { state, apply: apply2 })
1312
1686
  ] }),
1313
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", children: [
1314
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u5927\u8111" }),
1315
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: state.model === null ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1316
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Dot, { tone: "bad" }),
1687
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "her-card", children: [
1688
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { children: "\u5927\u8111" }),
1689
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: state.model === null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1690
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Dot, { tone: "bad" }),
1317
1691
  "\u6CA1\u6709\u53EF\u7528\u7684\u6A21\u578B"
1318
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1319
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Dot, { tone: "ok" }),
1692
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1693
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Dot, { tone: state.problem === void 0 ? "ok" : "bad" }),
1320
1694
  state.model.provider,
1321
1695
  " / ",
1322
1696
  state.model.model,
1323
- state.model.chosen ? "" : "\uFF08dsh \u9ED8\u8BA4\uFF09"
1697
+ state.model.chosen ? "" : "\uFF08dsh \u9ED8\u8BA4\uFF09",
1698
+ state.problem === void 0 ? "" : "\uFF1A\u4E0A\u4E00\u6B21\u56DE\u7B54\u5931\u8D25\u4E86"
1324
1699
  ] }) }),
1325
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { children: [
1326
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Dot, { tone: toneOf(state.voice.speaking.status) }),
1700
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { children: [
1701
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Dot, { tone: toneOf(state.voice.speaking.status) }),
1327
1702
  "\u5979\u7684\u58F0\u97F3\uFF1A",
1328
1703
  speakingText(state.voice.speaking.status, state.voice.speaking.service),
1329
1704
  "\uFF08",
1330
- voiceName(state.character.voice.id),
1705
+ voiceLabel(state, state.character.voice.id),
1331
1706
  "\uFF09"
1332
1707
  ] }),
1333
- (state.voice.speaking.status === "no-key" || state.voice.speaking.status === "no-quota") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(KeyHelp, { state }),
1334
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { children: [
1335
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Dot, { tone: toneOf(state.voice.status) }),
1708
+ (state.voice.speaking.status === "no-key" || state.voice.speaking.status === "no-quota") && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(KeyHelp, { state }),
1709
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { children: [
1710
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Dot, { tone: toneOf(state.voice.status) }),
1336
1711
  "\u542C\u4F60\u8BF4\u8BDD\uFF1A",
1337
1712
  listeningText(state.voice.status)
1338
1713
  ] }),
1339
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "her-muted", children: [
1714
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "her-muted", children: [
1340
1715
  "\u8BB0\u5F97 ",
1341
1716
  state.memory.facts.length,
1342
1717
  " \u4EF6\u5173\u4E8E\u4F60\u7684\u4E8B\u3001",
@@ -1345,45 +1720,60 @@ function Manage({ state, apply: apply2, onWizard }) {
1345
1720
  state.memory.diary.length,
1346
1721
  " \u5929\u65E5\u8BB0\u3002"
1347
1722
  ] }),
1348
- state.heard !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "her-faint", children: [
1723
+ state.heard !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "her-faint", children: [
1349
1724
  "\u6700\u8FD1\u542C\u5230\uFF1A\u300C",
1350
1725
  state.heard.text,
1351
1726
  "\u300D"
1352
1727
  ] })
1353
1728
  ] }),
1354
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "her-muted", children: '\u6539\u4EBA\u8BBE\u3001\u6362\u58F0\u97F3\u3001\u5916\u5F62\u3001\u6A21\u578B\uFF0C\u90FD\u5728"\u8BBE\u7F6E"\u91CC\uFF1B\u5979\u8BB0\u4F4F\u4E86\u4EC0\u4E48\uFF0C\u5728"\u5979\u8BB0\u5F97\u7684\u4E8B"\u91CC\u3002' })
1729
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "her-muted", children: '\u6539\u4EBA\u8BBE\u3001\u6362\u58F0\u97F3\u3001\u5916\u5F62\u3001\u6A21\u578B\uFF0C\u90FD\u5728"\u8BBE\u7F6E"\u91CC\uFF1B\u5979\u8BB0\u4F4F\u4E86\u4EC0\u4E48\uFF0C\u5728"\u5979\u8BB0\u5F97\u7684\u4E8B"\u91CC\u3002' })
1355
1730
  ] }),
1356
- tab === "settings" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Settings, { state, apply: apply2 }),
1357
- tab === "memory" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MemoryView, { state, apply: apply2 }),
1358
- tab === "workshop" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Workshop, { state, apply: apply2 })
1731
+ tab === "settings" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Settings, { state, apply: apply2, jump, onJumped: () => setJump(void 0) }),
1732
+ tab === "memory" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MemoryView, { state, apply: apply2 }),
1733
+ tab === "workshop" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Workshop, { state, apply: apply2 })
1359
1734
  ] });
1360
1735
  }
1361
- var SECTIONS = [["persona", "\u4EBA\u8BBE"], ["voice", "\u58F0\u97F3"], ["look", "\u5916\u5F62"], ["model", "\u6A21\u578B"], ["place", "\u653E\u5728\u54EA\u91CC"]];
1362
- function Settings({ state, apply: apply2 }) {
1363
- const jump = (id) => document.getElementById(`her-set-${id}`)?.scrollIntoView({ behavior: "smooth", block: "start" });
1364
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1365
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "her-steps", children: SECTIONS.map(([id, label]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "her-step", onClick: () => jump(id), children: label }, id)) }),
1366
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", id: "her-set-persona", children: [
1367
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u4EBA\u8BBE" }),
1368
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PersonaEditor, { state, apply: apply2 })
1369
- ] }),
1370
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", id: "her-set-voice", children: [
1371
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u58F0\u97F3" }),
1372
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(VoicePicker, { state, apply: apply2, saveLabel: "\u7528\u8FD9\u4E2A\u58F0\u97F3" })
1373
- ] }),
1374
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", id: "her-set-look", children: [
1375
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u5916\u5F62" }),
1376
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PackPicker, { state, apply: apply2 }),
1377
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ScenePicker, { state, apply: apply2 })
1378
- ] }),
1379
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", id: "her-set-model", children: [
1380
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u6A21\u578B" }),
1381
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModelPicker, { state, apply: apply2 })
1382
- ] }),
1383
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "her-card", id: "her-set-place", children: [
1384
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: "\u653E\u5728\u54EA\u91CC" }),
1385
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModePicker, { state, apply: apply2 })
1386
- ] })
1736
+ var SETTINGS_FOLDS = { persona: false, voice: false, look: false, model: false, place: false };
1737
+ function Settings({ state, apply: apply2, jump, onJumped }) {
1738
+ const [open, toggle] = useFolds("dsh-her.settings.open", SETTINGS_FOLDS);
1739
+ (0, import_react5.useEffect)(() => {
1740
+ if (jump === void 0) return;
1741
+ toggle(jump, true);
1742
+ setTimeout(() => document.getElementById(`her-set-${jump}`)?.scrollIntoView({ behavior: "smooth", block: "start" }), 50);
1743
+ onJumped();
1744
+ }, [jump, onJumped, toggle]);
1745
+ const c = state.character;
1746
+ const body = state.body;
1747
+ const speaking = state.voice.speaking.status;
1748
+ const pack = body.packs.find((p) => p.packId === body.activePack);
1749
+ const card = (id, title, summary, tone, children) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Fold, { id: `her-set-${id}`, title, summary, tone, open: open[id], onToggle: () => toggle(id), children });
1750
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1751
+ card("persona", "\u4EBA\u8BBE", `${c.name}\uFF0C\u53EB\u4F60\u300C${c.callYou || "\uFF08\u6CA1\u8BBE\uFF09"}\u300D`, "ok", /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PersonaEditor, { state, apply: apply2 })),
1752
+ card(
1753
+ "voice",
1754
+ "\u58F0\u97F3",
1755
+ `${voiceLabel(state, c.voice.id)} \xB7 ${SERVICE_SHORT[serviceOf(c.voice.id)]} \xB7 ${speakingText(speaking, state.voice.speaking.service)}`,
1756
+ toneOf(speaking),
1757
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(VoicePicker, { state, apply: apply2, saveLabel: "\u7528\u8FD9\u4E2A\u58F0\u97F3" })
1758
+ ),
1759
+ card(
1760
+ "look",
1761
+ "\u5916\u5F62",
1762
+ body.connected ? `${pack?.name ?? "\u8FD8\u6CA1\u6709\u5916\u5F62"}${body.look === void 0 ? "" : ` \xB7 ${body.look.scenes.length} \u4E2A\u573A\u666F`}` : "\u8EAB\u4F53\u6CA1\u8FDE\u4E0A",
1763
+ body.connected ? pack === void 0 ? "warn" : "ok" : "off",
1764
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1765
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PackPicker, { state, apply: apply2 }),
1766
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ScenePicker, { state, apply: apply2 })
1767
+ ] })
1768
+ ),
1769
+ card(
1770
+ "model",
1771
+ "\u6A21\u578B",
1772
+ state.model === null ? "\u6CA1\u6709\u53EF\u7528\u7684\u6A21\u578B" : `${state.model.provider} / ${state.model.model}${state.model.chosen ? "" : "\uFF08dsh \u9ED8\u8BA4\uFF09"}${state.problem === void 0 ? "" : " \xB7 \u4E0A\u4E00\u6B21\u56DE\u7B54\u5931\u8D25\u4E86"}`,
1773
+ state.model === null || state.problem !== void 0 ? "bad" : "ok",
1774
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ModelPicker, { state, apply: apply2 })
1775
+ ),
1776
+ card("place", "\u653E\u5728\u54EA\u91CC", body.connected ? body.mode === void 0 ? "\u2014" : MODE_TEXT[body.mode]?.title ?? body.mode : "\u8EAB\u4F53\u6CA1\u8FDE\u4E0A", body.connected ? "ok" : "off", /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ModePicker, { state, apply: apply2 }))
1387
1777
  ] });
1388
1778
  }
1389
1779
  function toneOf(status) {
@@ -1393,20 +1783,20 @@ function toneOf(status) {
1393
1783
  return "warn";
1394
1784
  }
1395
1785
  function speakingText(status, service) {
1396
- const name = service === "edge" ? "\u5FAE\u8F6F Edge" : "\u963F\u91CC\u4E91\u767E\u70BC";
1786
+ const name = service === "edge" ? "\u5FAE\u8F6F Edge" : service === "ming" ? "\u672C\u673A Ming" : "\u963F\u91CC\u4E91\u767E\u70BC";
1397
1787
  switch (status) {
1398
1788
  case "ready":
1399
1789
  return `\u5DF2\u5C31\u7EEA\uFF08${name}\uFF09`;
1400
1790
  case "checking":
1401
- return `\u6B63\u5728\u8FDE\u63A5${name}`;
1791
+ return service === "ming" ? "\u6B63\u5728\u52A0\u8F7D\u672C\u673A Ming\uFF08\u7EA6 8 \u79D2\uFF09" : `\u6B63\u5728\u8FDE\u63A5${name}`;
1402
1792
  case "installing":
1403
- return "\u6B63\u5728\u51C6\u5907 Edge \u8BED\u97F3\u7EC4\u4EF6\uFF08\u7B2C\u4E00\u6B21\u7528\uFF0C\u4E00\u4E24\u5206\u949F\uFF09";
1793
+ return service === "ming" ? "\u6B63\u5728\u5B89\u88C5\u672C\u673A Ming\uFF08\u5728 \u8BBE\u7F6E \u2192 \u58F0\u97F3 \u91CC\u770B\u8FDB\u5EA6\uFF09" : "\u6B63\u5728\u51C6\u5907 Edge \u8BED\u97F3\u7EC4\u4EF6\uFF08\u7B2C\u4E00\u6B21\u7528\uFF0C\u4E00\u4E24\u5206\u949F\uFF09";
1404
1794
  case "no-key":
1405
1795
  return "\u8FD8\u6CA1\u6709\u767E\u70BC\u7684 API key\uFF0C\u73B0\u5728\u53EA\u7528\u6587\u5B57\u56DE\u7B54";
1406
1796
  case "no-quota":
1407
1797
  return "\u767E\u70BC\u7684\u989D\u5EA6\u7528\u5B8C\u4E86\uFF0C\u73B0\u5728\u53EA\u7528\u6587\u5B57\u56DE\u7B54";
1408
1798
  case "failed":
1409
- return `${name}\u7684\u8BED\u97F3\u51FA\u9519\u4E86\uFF0C\u6682\u65F6\u53EA\u7528\u6587\u5B57\uFF08\u4F1A\u81EA\u52A8\u91CD\u8BD5\uFF09`;
1799
+ return service === "ming" ? "\u672C\u673A Ming \u7528\u4E0D\u4E86\uFF0C\u6682\u65F6\u53EA\u7528\u6587\u5B57\uFF08\u5728 \u8BBE\u7F6E \u2192 \u58F0\u97F3 \u91CC\u770B\u539F\u56E0\u3001\u91CD\u542F\uFF09" : `${name}\u7684\u8BED\u97F3\u51FA\u9519\u4E86\uFF0C\u6682\u65F6\u53EA\u7528\u6587\u5B57\uFF08\u4F1A\u81EA\u52A8\u91CD\u8BD5\uFF09`;
1410
1800
  case "off":
1411
1801
  return "\u5DF2\u5173\u95ED\uFF0C\u53EA\u7528\u6587\u5B57";
1412
1802
  default:
@@ -1458,10 +1848,18 @@ var STYLES = `
1458
1848
  .her-card h2{font-size:15px;font-weight:600;margin:0 0 6px}
1459
1849
  .her-card p{margin:4px 0}
1460
1850
  .her-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:8px 0}
1461
- .her-fold{display:flex;align-items:baseline;gap:8px;width:100%;border:none;background:none;padding:0;color:${TEXT};font:inherit;cursor:pointer;text-align:left}
1462
- .her-fold h2{margin:0}
1463
- .her-fold-arrow{color:${MUTED};width:14px;font-size:15px;line-height:1}
1851
+ .her-fold{display:flex;align-items:center;gap:10px;width:100%;border:none;background:none;padding:2px 0;color:${TEXT};font:inherit;cursor:pointer;text-align:left}
1852
+ .her-fold h2{margin:0;flex:none}
1853
+ .her-fold-arrow{flex:none;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:50%;background:${ACCENT};color:${ON_ACCENT};transition:transform .15s,opacity .15s}
1854
+ .her-fold-arrow.open{transform:rotate(90deg)}
1855
+ .her-fold:hover .her-fold-arrow{opacity:.85}
1856
+ .her-fold:focus-visible{outline:2px solid ${ACCENT};outline-offset:4px;border-radius:6px}
1464
1857
  .her-fold-sum{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}
1858
+ .her-fold-toggle{flex:none;font-size:12px;padding:3px 12px;border-radius:999px;border:1px solid ${LINE};background:${LAYER2};color:${TEXT}}
1859
+ .her-fold:hover .her-fold-toggle{background:${HOVER}}
1860
+ .her-foldcard.open .her-fold{margin-bottom:10px;padding-bottom:10px;border-bottom:1px solid ${LINE}}
1861
+ .her-subtabs{margin:4px 0 6px}
1862
+ .her-badge-inline{margin:0 0 0 6px;font-size:10px;padding:0 5px}
1465
1863
  .her-examples{margin-top:12px}
1466
1864
  .her-example-row{display:flex;gap:10px;flex-wrap:wrap}
1467
1865
  .her-example{margin:0;width:150px}
@@ -1489,6 +1887,20 @@ var STYLES = `
1489
1887
  .her-step{font-size:12px;padding:3px 10px;border-radius:999px;background:${LAYER1};color:${MUTED};border:none;cursor:pointer;font-family:inherit}
1490
1888
  .her-step.on{background:${ACCENT};color:${ON_ACCENT}}
1491
1889
  .her-step.done{color:${OK}}
1890
+ .her-badge{display:inline-block;font-size:11px;line-height:16px;padding:0 6px;margin-right:6px;border-radius:999px;background:${ACCENT};color:${ON_ACCENT};font-weight:600}
1891
+ .her-choice.trying{border-style:dashed;border-color:${ACCENT}}
1892
+ .her-now{margin:2px 0 8px}
1893
+ .her-now b{font-weight:600}
1894
+ .her-now .her-dot{margin-left:10px}
1895
+ .her-pending{position:sticky;bottom:8px;z-index:2;display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:10px 0;padding:8px 12px;border-radius:10px;border:1px dashed ${ACCENT};background:${v("bg-layer-1-solid", "Canvas")};box-shadow:0 4px 16px rgba(0,0,0,.25)}
1896
+ .her-pending span{flex:1;min-width:200px}
1897
+ .her-alert{border:1px solid ${DANGER};border-radius:10px;padding:8px 12px;color:${TEXT}}
1898
+ .her-card.her-alert{padding:14px 16px}
1899
+ .her-card.her-alert h2{color:${DANGER}}
1900
+ .her-summary{display:grid;grid-template-columns:auto 1fr auto auto;gap:6px 12px;align-items:center}
1901
+ .her-summary-row{display:contents}
1902
+ .her-summary-row b{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
1903
+ .her-summary-note{font-size:12px;color:${MUTED};white-space:nowrap}
1492
1904
  .her-tabs{display:flex;gap:4px;margin-bottom:12px;flex-wrap:wrap}
1493
1905
  .her-tab{border:none;background:none;color:${MUTED};padding:6px 10px;border-radius:8px;cursor:pointer;font:inherit}
1494
1906
  .her-tab.on{background:${LAYER2};color:${TEXT};font-weight:600}
@@ -1511,13 +1923,13 @@ var STYLES = `
1511
1923
  `;
1512
1924
 
1513
1925
  // src/client/index.tsx
1514
- var import_jsx_runtime4 = require("react/jsx-runtime");
1926
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1515
1927
  var PACKAGE_NAME = "dsh-her";
1516
1928
  var inject = ["slots", "locale"];
1517
1929
  var PANEL_ID = "dsh-her";
1518
1930
  var NS = "dsh-her";
1519
1931
  function HerIcon({ size }) {
1520
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 20s-7-4.4-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 10c0 5.6-7 10-7 10z" }) });
1932
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M12 20s-7-4.4-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 10c0 5.6-7 10-7 10z" }) });
1521
1933
  }
1522
1934
  function apply(ctx) {
1523
1935
  ctx.effect(() => ctx.locale.register(NS, { zh: { panel: "\u5979" }, en: { panel: "Her" } }), "dsh-her: dictionaries");