dsh-audiogen 0.3.5 → 0.4.1

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
@@ -6,8 +6,8 @@ window.__ModuleLoader__.load({
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react_dom_client = require("react-dom/client");
8
8
  let react = require("react");
9
- let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
10
9
  let react_jsx_runtime = require("react/jsx-runtime");
10
+ let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
11
11
  //#region src/protocol.ts
12
12
  /** Same-origin route family (loopback-only, mirroring dsh-imagegen). */
13
13
  const SETTINGS_API = {
@@ -28,10 +28,19 @@ window.__ModuleLoader__.load({
28
28
  clear: "/api/dsh-audiogen/history/clear",
29
29
  audio: "/api/dsh-audiogen/history/audio"
30
30
  };
31
+ /** Host-persisted resource-library routes. */
32
+ const LIBRARY_API = {
33
+ list: "/api/dsh-audiogen/library/list",
34
+ save: "/api/dsh-audiogen/library/save",
35
+ update: "/api/dsh-audiogen/library/update",
36
+ remove: "/api/dsh-audiogen/library/remove",
37
+ audio: "/api/dsh-audiogen/library/audio"
38
+ };
31
39
  //#endregion
32
40
  //#region src/client/api.ts
33
41
  /**
34
- * Browser-side API client for the audio generation and history routes.
42
+ * Browser-side API client for the audio generation, history and
43
+ * resource-library routes.
35
44
  */
36
45
  var AudiogenApi = class {
37
46
  async generate(request) {
@@ -48,6 +57,41 @@ window.__ModuleLoader__.load({
48
57
  async clearHistory() {
49
58
  await fetch(HISTORY_API.clear, { method: "POST" });
50
59
  }
60
+ async libraryList() {
61
+ const body = await (await fetch(LIBRARY_API.list, { method: "POST" })).json();
62
+ return body.ok === true ? body.entries ?? [] : [];
63
+ }
64
+ async librarySave(request) {
65
+ const body = await (await fetch(LIBRARY_API.save, {
66
+ method: "POST",
67
+ headers: { "content-type": "application/json" },
68
+ body: JSON.stringify(request)
69
+ })).json();
70
+ return {
71
+ ok: body.ok === true,
72
+ ...body.entry === void 0 ? {} : { entry: body.entry },
73
+ ...body.message === void 0 ? {} : { message: body.message }
74
+ };
75
+ }
76
+ async libraryUpdate(request) {
77
+ const body = await (await fetch(LIBRARY_API.update, {
78
+ method: "POST",
79
+ headers: { "content-type": "application/json" },
80
+ body: JSON.stringify(request)
81
+ })).json();
82
+ return {
83
+ ok: body.ok === true,
84
+ ...body.entry === void 0 ? {} : { entry: body.entry },
85
+ ...body.message === void 0 ? {} : { message: body.message }
86
+ };
87
+ }
88
+ async libraryRemove(ids) {
89
+ return { ok: (await (await fetch(LIBRARY_API.remove, {
90
+ method: "POST",
91
+ headers: { "content-type": "application/json" },
92
+ body: JSON.stringify({ ids })
93
+ })).json()).ok === true };
94
+ }
51
95
  };
52
96
  //#endregion
53
97
  //#region src/client/controller.ts
@@ -90,6 +134,8 @@ window.__ModuleLoader__.load({
90
134
  "entry.label": "AI 音频",
91
135
  "entry.tooltip": "AI 音频面板(TTS / 音乐 / 音效)",
92
136
  "panel.title": "AI 音频",
137
+ "tab.studio": "生成",
138
+ "tab.library": "资源库",
93
139
  "mode.tts": "文本转语音",
94
140
  "mode.music": "音乐生成",
95
141
  "mode.sfx": "音效生成",
@@ -117,6 +163,7 @@ window.__ModuleLoader__.load({
117
163
  "settings.enabled": "启用插件",
118
164
  "settings.announceToAgent": "向 Agent 播报本插件",
119
165
  "settings.allowAgentAudio": "允许 Agent 调用音频生成",
166
+ "settings.autoSaveLibrary": "生成后自动保存到资源库",
120
167
  "settings.save": "保存",
121
168
  "settings.saving": "保存中…",
122
169
  "settings.discard": "放弃修改",
@@ -188,6 +235,8 @@ window.__ModuleLoader__.load({
188
235
  "entry.label": "AI Audio",
189
236
  "entry.tooltip": "AI audio panel (TTS / music / SFX)",
190
237
  "panel.title": "AI Audio",
238
+ "tab.studio": "Studio",
239
+ "tab.library": "Library",
191
240
  "mode.tts": "Text to speech",
192
241
  "mode.music": "Music",
193
242
  "mode.sfx": "Sound effects",
@@ -215,6 +264,7 @@ window.__ModuleLoader__.load({
215
264
  "settings.enabled": "Enable plugin",
216
265
  "settings.announceToAgent": "Announce this plugin to agents",
217
266
  "settings.allowAgentAudio": "Allow agents to generate audio",
267
+ "settings.autoSaveLibrary": "Auto-save generated audio to the library",
218
268
  "settings.save": "Save",
219
269
  "settings.saving": "Saving…",
220
270
  "settings.discard": "Discard",
@@ -298,6 +348,223 @@ window.__ModuleLoader__.load({
298
348
  return rendered;
299
349
  }
300
350
  //#endregion
351
+ //#region src/client/icons.tsx
352
+ function Svg(props) {
353
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
354
+ width: "1em",
355
+ height: "1em",
356
+ viewBox: props.viewBox ?? "0 0 16 16",
357
+ fill: "none",
358
+ stroke: "currentColor",
359
+ strokeWidth: "1.5",
360
+ strokeLinecap: "round",
361
+ strokeLinejoin: "round",
362
+ "aria-hidden": "true",
363
+ children: props.children
364
+ });
365
+ }
366
+ function PlayIcon() {
367
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Svg, {
368
+ viewBox: "0 0 16 16",
369
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
370
+ d: "M5 3.2v9.6a.6.6 0 0 0 .9.5l7.5-4.8a.6.6 0 0 0 0-1L5.9 2.7a.6.6 0 0 0-.9.5Z",
371
+ fill: "currentColor",
372
+ stroke: "none"
373
+ })
374
+ });
375
+ }
376
+ function PauseIcon() {
377
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
378
+ viewBox: "0 0 16 16",
379
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
380
+ x: "4.2",
381
+ y: "2.8",
382
+ width: "2.6",
383
+ height: "10.4",
384
+ rx: "0.9",
385
+ fill: "currentColor",
386
+ stroke: "none"
387
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
388
+ x: "9.2",
389
+ y: "2.8",
390
+ width: "2.6",
391
+ height: "10.4",
392
+ rx: "0.9",
393
+ fill: "currentColor",
394
+ stroke: "none"
395
+ })]
396
+ });
397
+ }
398
+ function StarIcon(props) {
399
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Svg, {
400
+ viewBox: "0 0 16 16",
401
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
402
+ d: "M8 1.9l1.8 3.7 4.1.6-3 2.9.7 4.1L8 11.2l-3.6 1.9.7-4.1-3-2.9 4.1-.6L8 1.9Z",
403
+ fill: props.filled === true ? "currentColor" : "none"
404
+ })
405
+ });
406
+ }
407
+ function DownloadIcon() {
408
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
409
+ viewBox: "0 0 16 16",
410
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 2.5v7M8 9.5l-2.6-2.6M8 9.5l2.6-2.6" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.8 10.8v1.7a1 1 0 0 0 1 1h8.4a1 1 0 0 0 1-1v-1.7" })]
411
+ });
412
+ }
413
+ function TrashIcon() {
414
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Svg, {
415
+ viewBox: "0 0 16 16",
416
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3 4.4h10M6.2 2.9h3.6M5.2 4.4l.5 8a1 1 0 0 0 1 .9h2.6a1 1 0 0 0 1-.9l.5-8" })
417
+ });
418
+ }
419
+ function SearchIcon() {
420
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
421
+ viewBox: "0 0 16 16",
422
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
423
+ cx: "7",
424
+ cy: "7",
425
+ r: "4.2"
426
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m10.2 10.2 3 3" })]
427
+ });
428
+ }
429
+ function CopyIcon() {
430
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
431
+ viewBox: "0 0 16 16",
432
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
433
+ x: "5.4",
434
+ y: "5.4",
435
+ width: "7.4",
436
+ height: "7.4",
437
+ rx: "1.2"
438
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M10.6 5.4V4a1.2 1.2 0 0 0-1.2-1.2H4A1.2 1.2 0 0 0 2.8 4v5.4A1.2 1.2 0 0 0 4 10.6h1.4" })]
439
+ });
440
+ }
441
+ function CheckIcon() {
442
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Svg, {
443
+ viewBox: "0 0 16 16",
444
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m3.2 8.4 3.1 3.1L12.8 4.9" })
445
+ });
446
+ }
447
+ function VolumeIcon() {
448
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
449
+ viewBox: "0 0 16 16",
450
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
451
+ d: "M2.8 6.2v3.6h2.4l3 2.6V3.6l-3 2.6H2.8Z",
452
+ fill: "currentColor",
453
+ stroke: "none"
454
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M10.4 5.6a3.4 3.4 0 0 1 0 4.8M12 4.2a5.6 5.6 0 0 1 0 7.6" })]
455
+ });
456
+ }
457
+ function MuteIcon() {
458
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
459
+ viewBox: "0 0 16 16",
460
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
461
+ d: "M2.8 6.2v3.6h2.4l3 2.6V3.6l-3 2.6H2.8Z",
462
+ fill: "currentColor",
463
+ stroke: "none"
464
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "m10.4 6.2 3.2 3.6M13.6 6.2l-3.2 3.6" })]
465
+ });
466
+ }
467
+ function MicIcon() {
468
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
469
+ viewBox: "0 0 16 16",
470
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
471
+ x: "5.8",
472
+ y: "2",
473
+ width: "4.4",
474
+ height: "7.2",
475
+ rx: "2.2"
476
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3.2 8a4.8 4.8 0 0 0 9.6 0M8 12.8V14" })]
477
+ });
478
+ }
479
+ function MusicNoteIcon() {
480
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
481
+ viewBox: "0 0 16 16",
482
+ children: [
483
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M6.2 12.6V4l6-1.4v8.6" }),
484
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
485
+ cx: "4.7",
486
+ cy: "12.6",
487
+ r: "1.7"
488
+ }),
489
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
490
+ cx: "10.7",
491
+ cy: "11.2",
492
+ r: "1.7"
493
+ })
494
+ ]
495
+ });
496
+ }
497
+ function WaveIcon() {
498
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Svg, {
499
+ viewBox: "0 0 16 16",
500
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2 6h1M4.5 3.5v9M7.2 2v12M9.9 4v8M12.6 5.5v5M14.5 6.5v3" })
501
+ });
502
+ }
503
+ function GridIcon() {
504
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
505
+ viewBox: "0 0 16 16",
506
+ children: [
507
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
508
+ x: "2.5",
509
+ y: "2.5",
510
+ width: "4.6",
511
+ height: "4.6",
512
+ rx: "1"
513
+ }),
514
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
515
+ x: "8.9",
516
+ y: "2.5",
517
+ width: "4.6",
518
+ height: "4.6",
519
+ rx: "1"
520
+ }),
521
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
522
+ x: "2.5",
523
+ y: "8.9",
524
+ width: "4.6",
525
+ height: "4.6",
526
+ rx: "1"
527
+ }),
528
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
529
+ x: "8.9",
530
+ y: "8.9",
531
+ width: "4.6",
532
+ height: "4.6",
533
+ rx: "1"
534
+ })
535
+ ]
536
+ });
537
+ }
538
+ function ListIcon() {
539
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Svg, {
540
+ viewBox: "0 0 16 16",
541
+ children: [
542
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M5.4 4.2h8.2M5.4 8h8.2M5.4 11.8h8.2" }),
543
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
544
+ cx: "2.8",
545
+ cy: "4.2",
546
+ r: "0.8",
547
+ fill: "currentColor",
548
+ stroke: "none"
549
+ }),
550
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
551
+ cx: "2.8",
552
+ cy: "8",
553
+ r: "0.8",
554
+ fill: "currentColor",
555
+ stroke: "none"
556
+ }),
557
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
558
+ cx: "2.8",
559
+ cy: "11.8",
560
+ r: "0.8",
561
+ fill: "currentColor",
562
+ stroke: "none"
563
+ })
564
+ ]
565
+ });
566
+ }
567
+ //#endregion
301
568
  //#region src/client/settings-scope.ts
302
569
  /**
303
570
  * Browser-side settings scope for the dsh-audiogen namespace, served by the
@@ -532,54 +799,508 @@ window.__ModuleLoader__.load({
532
799
  }
533
800
  //#endregion
534
801
  //#region \0dsh-css:/Users/shimingming/Projects_code/dsh-audiogen/src/client/audio-panel.module.css.mjs
535
- const css$3 = ".Oo1fpq_panel{background:var(--dsw-alias-bg-base,#f7f7f8);height:100%;color:var(--dsw-alias-label-primary,#1f2328);font-family:var(--dsw-font-family,system-ui, sans-serif);flex-direction:column;gap:12px;padding:14px 16px;display:flex;overflow:hidden}.Oo1fpq_header{justify-content:space-between;align-items:center;display:flex}.Oo1fpq_title{margin:0;font-size:16px;font-weight:700}.Oo1fpq_layout{flex:1;gap:14px;min-height:0;display:flex}.Oo1fpq_form{flex-direction:column;flex:none;gap:12px;width:300px;min-width:260px;max-width:340px;display:flex;overflow-y:auto}.Oo1fpq_result{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);border-radius:12px;flex-direction:column;flex:1;min-width:0;padding:14px;display:flex;overflow-y:auto}.Oo1fpq_label{color:var(--dsw-alias-label-secondary,#6b7280);flex-direction:column;gap:5px;font-size:12px;font-weight:600;display:flex}.Oo1fpq_textarea,.Oo1fpq_input,.Oo1fpq_select{border:1px solid var(--dsw-alias-border-l2,#d1d5db);background:var(--dsw-alias-bg-layer-3,#fff);width:100%;min-height:36px;color:var(--dsw-alias-label-primary,#1f2328);font:inherit;border-radius:8px;outline:none;padding:7px 10px;font-size:13px}.Oo1fpq_textarea{resize:vertical;min-height:110px}.Oo1fpq_modeRow{gap:6px;display:flex}.Oo1fpq_modeButton{border:1px solid var(--dsw-alias-border-l2,#d1d5db);font:inherit;cursor:pointer;background:0 0;border-radius:8px;flex:1;padding:7px 8px;font-size:12px}.Oo1fpq_modeButton[data-active=true]{border-color:var(--dsw-alias-brand-primary,#2563eb);color:var(--dsw-alias-brand-primary,#2563eb);font-weight:600}.Oo1fpq_generate{background:var(--dsw-alias-label-primary,#1f2328);color:var(--dsw-alias-bg-layer-3,#fff);font:inherit;cursor:pointer;border:0;border-radius:10px;padding:9px 14px;font-size:13px}.Oo1fpq_generate:disabled{opacity:.5;cursor:default}.Oo1fpq_empty,.Oo1fpq_error,.Oo1fpq_hint{color:var(--dsw-alias-label-secondary,#6b7280);font-size:13px}.Oo1fpq_error{color:#b91c1c}.Oo1fpq_audioList{gap:10px;margin-top:8px;display:grid}.Oo1fpq_audioCard{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:10px;flex-direction:column;gap:6px;padding:10px;display:flex}.Oo1fpq_audio{width:100%;height:36px}.Oo1fpq_download{color:#2563eb;font-size:12px;text-decoration:none}.Oo1fpq_history{border-left:1px solid var(--dsw-alias-border-l1,#e5e7eb);flex:none;width:260px;padding-left:12px;overflow-y:auto}.Oo1fpq_historyTitle{font-size:13px;font-weight:700}.Oo1fpq_historyEmpty{color:var(--dsw-alias-label-tertiary,#9ca3af);font-size:12px}.Oo1fpq_historyItem{border-bottom:1px solid var(--dsw-alias-border-l1,#e5e7eb);padding:8px 0}.Oo1fpq_historyPrompt{text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.Oo1fpq_historyMeta{color:var(--dsw-alias-label-tertiary,#9ca3af);font-size:11px}.Oo1fpq_historyAudio{width:100%;height:30px;margin-top:4px}.Oo1fpq_advanced{border:1px dashed var(--dsw-alias-border-l2,#d1d5db);border-radius:8px;flex-direction:column;gap:8px;padding:8px 10px;display:flex}.Oo1fpq_advanced summary{cursor:pointer;color:var(--dsw-alias-label-secondary,#6b7280);font-size:12px;font-weight:600}.Oo1fpq_row{align-items:flex-end;gap:8px;display:flex}.Oo1fpq_row .Oo1fpq_label{flex:1}.Oo1fpq_checkbox{color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;align-items:center;gap:6px;font-size:12px;font-weight:600;display:flex}";
536
- const tagId$3 = "dsh-audiogen/audio-panel.module.css";
537
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
802
+ const css$4 = ".Oo1fpq_panel{background:var(--dsw-alias-bg-base,#f7f7f8);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary,#1f2328);font-family:var(--dsw-font-family,system-ui, sans-serif);flex-direction:column;gap:12px;padding:14px 16px 16px;display:flex;position:relative}.Oo1fpq_panel,.Oo1fpq_panel *,.Oo1fpq_panel :before,.Oo1fpq_panel :after{box-sizing:border-box}.Oo1fpq_header{flex:none;justify-content:space-between;align-items:center;gap:12px;display:flex}.Oo1fpq_title{color:var(--dsw-alias-label-primary,#1f2328);white-space:nowrap;margin:0;font-size:16px;font-weight:700}.Oo1fpq_tabs{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f3f4f6);border-radius:10px;align-items:center;gap:2px;padding:3px;display:inline-flex}.Oo1fpq_tab{min-height:27px;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border:0;border-radius:8px;align-items:center;gap:6px;padding:0 12px;font-family:inherit;font-size:12.5px;transition:color .12s,background .12s;display:inline-flex}.Oo1fpq_tab:hover{color:var(--dsw-alias-label-primary,#1f2328)}.Oo1fpq_tab[data-active=true]{color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-1,#fff);font-weight:600;box-shadow:0 1px 3px #0000001a}.Oo1fpq_studio{flex:1;gap:14px;min-width:0;min-height:0;display:flex}.Oo1fpq_formCol{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:none;gap:11px;width:300px;min-width:260px;max-width:340px;min-height:0;padding:2px;display:flex;overflow-y:auto}.Oo1fpq_formCol::-webkit-scrollbar{width:8px}.Oo1fpq_formCol::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.Oo1fpq_modeRow{grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;display:grid}.Oo1fpq_modeButton{border:1px solid var(--dsw-alias-border-l2,#d1d5db);background:var(--dsw-alias-bg-layer-1,#fff);min-height:34px;color:var(--dsw-alias-label-secondary,#6b7280);white-space:nowrap;cursor:pointer;border-radius:9px;justify-content:center;align-items:center;padding:6px 4px;font-family:inherit;font-size:11.5px;transition:border-color .12s,color .12s,background .12s;display:flex}.Oo1fpq_modeButton:hover{border-color:var(--dsw-alias-label-dimmed,#9ca3af);color:var(--dsw-alias-label-primary,#1f2328)}.Oo1fpq_modeButton[data-active=true]{border-color:var(--dsw-alias-brand-primary,#2563eb);color:var(--dsw-alias-brand-primary,#2563eb);background:color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 8%, transparent);font-weight:600}.Oo1fpq_label{color:var(--dsw-alias-label-secondary,#6b7280);flex-direction:column;gap:5px;font-size:12px;font-weight:600;display:flex}.Oo1fpq_input,.Oo1fpq_textarea{border:1px solid var(--dsw-alias-border-l2,#d1d5db);background:var(--dsw-alias-bg-layer-2,#fff);width:100%;min-height:36px;color:var(--dsw-alias-label-primary,#1f2328);border-radius:9px;outline:none;padding:7px 10px;font-family:inherit;font-size:13px;transition:border-color .12s,box-shadow .12s}.Oo1fpq_input:focus,.Oo1fpq_textarea:focus{border-color:var(--dsw-alias-brand-primary,#2563eb);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 14%, transparent)}.Oo1fpq_textarea{resize:vertical;min-height:96px}.Oo1fpq_checkbox{color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;align-items:center;gap:7px;font-size:12px;font-weight:600;display:flex}.Oo1fpq_checkbox input{accent-color:var(--dsw-alias-brand-primary,#2563eb);margin:0}.Oo1fpq_hint{color:var(--dsw-alias-label-tertiary,#9ca3af);margin:0;font-size:11.5px;line-height:1.55}.Oo1fpq_row{align-items:flex-end;gap:8px;display:flex}.Oo1fpq_row .Oo1fpq_label{flex:1;min-width:0}.Oo1fpq_advanced{border:1px dashed var(--dsw-alias-border-l2,#d1d5db);background:var(--dsw-alias-bg-layer-1,#fff);border-radius:10px;flex-direction:column;gap:9px;padding:9px 11px;display:flex}.Oo1fpq_advanced summary{cursor:pointer;color:var(--dsw-alias-label-secondary,#6b7280);font-size:12px;font-weight:600}.Oo1fpq_generate{background:var(--dsw-alias-label-primary,#1f2328);color:var(--dsw-alias-bg-layer-3,#fff);cursor:pointer;border:0;border-radius:10px;padding:10px 14px;font-family:inherit;font-size:13px;font-weight:600;transition:opacity .12s,transform 80ms}.Oo1fpq_generate:hover:not(:disabled){opacity:.92}.Oo1fpq_generate:active:not(:disabled){transform:translateY(1px)}.Oo1fpq_generate:disabled{opacity:.5;cursor:default}.Oo1fpq_resultCol{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;border-radius:12px;flex-direction:column;flex:1;gap:10px;min-width:0;padding:14px;display:flex;overflow-y:auto}.Oo1fpq_resultCol::-webkit-scrollbar{width:8px}.Oo1fpq_resultCol::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.Oo1fpq_resultEmpty{text-align:center;color:var(--dsw-alias-label-secondary,#6b7280);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:6px;font-size:13px;display:flex}.Oo1fpq_resultEmptyIcon{background:var(--dsw-alias-bg-layer-2,#f3f4f6);border-radius:50%;justify-content:center;align-items:center;width:52px;height:52px;margin-bottom:4px;font-size:24px;display:inline-flex}.Oo1fpq_resultEmptyHint{color:var(--dsw-alias-label-tertiary,#9ca3af);margin:0;font-size:11.5px}.Oo1fpq_error{border:1px solid var(--dsw-alias-label-error,#b91c1c);background:color-mix(in srgb, var(--dsw-alias-label-error,#b91c1c) 6%, transparent);color:var(--dsw-alias-label-error,#b91c1c);border-radius:9px;flex:none;margin:0;padding:9px 12px;font-size:12.5px;line-height:1.55}.Oo1fpq_resultMeta{color:var(--dsw-alias-label-tertiary,#9ca3af);flex:none;align-items:center;gap:8px;font-size:12px;display:flex}.Oo1fpq_resultModeChip{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f3f4f6);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:999px;padding:2px 9px;font-size:11px}.Oo1fpq_audioList{gap:10px;display:grid}.Oo1fpq_audioCard{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f7f7f8);border-radius:12px;flex-direction:column;gap:8px;padding:12px;transition:border-color .12s;display:flex}.Oo1fpq_audioCard[data-saved=true]{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 42%, var(--dsw-alias-border-l1,#e5e7eb));background:color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 5%, var(--dsw-alias-bg-layer-2,#f7f7f8))}.Oo1fpq_audioCardHead{flex-wrap:wrap;align-items:center;gap:6px;min-width:0;display:flex}.Oo1fpq_voiceIdChip{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);max-width:100%;color:var(--dsw-alias-label-secondary,#6b7280);text-overflow:ellipsis;white-space:nowrap;border-radius:999px;padding:2px 9px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10.5px;overflow:hidden}.Oo1fpq_savedChip{background:color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 12%, transparent);color:var(--dsw-alias-brand-primary,#2563eb);border-radius:999px;align-items:center;gap:5px;padding:2px 9px;font-size:11px;font-weight:600;display:inline-flex}.Oo1fpq_audioCardIndex{color:var(--dsw-alias-label-tertiary,#9ca3af);font-variant-numeric:tabular-nums;margin-left:auto;font-size:11px}.Oo1fpq_audioCardActions{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.Oo1fpq_ghostButton{border:1px solid var(--dsw-alias-border-l2,#d1d5db);min-height:27px;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border-radius:999px;align-items:center;gap:5px;padding:3px 11px;font-family:inherit;font-size:12px;text-decoration:none;transition:color .12s,border-color .12s,background .12s;display:inline-flex}.Oo1fpq_ghostButton:hover{color:var(--dsw-alias-brand-primary,#2563eb);border-color:var(--dsw-alias-brand-primary,#2563eb);background:color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 8%, transparent)}.Oo1fpq_historyCol{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);border-radius:12px;flex-direction:column;flex:none;width:250px;min-width:210px;max-width:290px;min-height:0;display:flex;overflow:hidden}.Oo1fpq_historyHeader{border-bottom:1px solid var(--dsw-alias-border-l1,#e5e7eb);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:10px 12px;display:flex}.Oo1fpq_historyTitle{color:var(--dsw-alias-label-primary,#1f2328);font-size:13px;font-weight:700}.Oo1fpq_historyClear{border:1px solid var(--dsw-alias-border-l2,#d1d5db);color:var(--dsw-alias-label-tertiary,#9ca3af);cursor:pointer;background:0 0;border-radius:999px;padding:2px 9px;font-family:inherit;font-size:11px}.Oo1fpq_historyClear:hover{color:var(--dsw-alias-label-error,#b91c1c);border-color:var(--dsw-alias-label-error,#b91c1c)}.Oo1fpq_historyList{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:8px;min-height:0;padding:9px;display:flex;overflow-y:auto}.Oo1fpq_historyList::-webkit-scrollbar{width:8px}.Oo1fpq_historyList::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.Oo1fpq_historyEmpty{text-align:center;color:var(--dsw-alias-label-tertiary,#9ca3af);flex:1;justify-content:center;align-items:center;padding:18px;font-size:12px;display:flex}.Oo1fpq_historyItem{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f7f7f8);border-radius:10px;flex-direction:column;gap:6px;padding:9px;display:flex}.Oo1fpq_historyPrompt{color:var(--dsw-alias-label-primary,#1f2328);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;line-height:1.45;display:-webkit-box;overflow:hidden}.Oo1fpq_historyMeta{color:var(--dsw-alias-label-tertiary,#9ca3af);white-space:nowrap;text-overflow:ellipsis;font-size:10.5px;overflow:hidden}.Oo1fpq_historyActions{justify-content:flex-end;display:flex}.Oo1fpq_historyAction{border:1px solid var(--dsw-alias-border-l2,#d1d5db);color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border-radius:999px;align-items:center;gap:4px;padding:2px 9px;font-family:inherit;font-size:11px;display:inline-flex}.Oo1fpq_historyAction:hover{color:var(--dsw-alias-brand-primary,#2563eb);border-color:var(--dsw-alias-brand-primary,#2563eb)}.Oo1fpq_player{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);border-radius:10px;align-items:center;gap:9px;padding:8px 10px;display:flex}.Oo1fpq_playerCompact{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);border-radius:9px;align-items:center;gap:8px;padding:6px 8px;display:flex}.Oo1fpq_playButton{background:var(--dsw-alias-label-primary,#1f2328);width:30px;height:30px;color:var(--dsw-alias-bg-layer-3,#fff);cursor:pointer;border:0;border-radius:50%;flex:none;justify-content:center;align-items:center;transition:opacity .12s,transform 80ms;display:inline-flex}.Oo1fpq_playerCompact .Oo1fpq_playButton{width:26px;height:26px}.Oo1fpq_playButton:hover{opacity:.9}.Oo1fpq_playButton:active{transform:scale(.94)}.Oo1fpq_track{background:var(--dsw-alias-border-l2,#d1d5db);cursor:pointer;border-radius:999px;flex:1;min-width:0;height:4px;position:relative}.Oo1fpq_trackFill{background:var(--dsw-alias-brand-primary,#2563eb);border-radius:999px;position:absolute;inset:0 auto 0 0}.Oo1fpq_trackKnob{background:var(--dsw-alias-brand-primary,#2563eb);border-radius:50%;width:11px;height:11px;transition:transform .1s;position:absolute;top:50%;transform:translate(-50%,-50%)}.Oo1fpq_time{font-variant-numeric:tabular-nums;min-width:62px;color:var(--dsw-alias-label-tertiary,#9ca3af);white-space:nowrap;text-align:right;flex:none;font-size:10.5px}.Oo1fpq_playerCompact .Oo1fpq_time{min-width:56px;font-size:10px}.Oo1fpq_muteButton{width:24px;height:24px;color:var(--dsw-alias-label-tertiary,#9ca3af);cursor:pointer;background:0 0;border:0;border-radius:6px;flex:none;justify-content:center;align-items:center;display:inline-flex}.Oo1fpq_muteButton:hover{color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-2,#f3f4f6)}.Oo1fpq_modalMask{z-index:200;backdrop-filter:blur(3px);background:#0006;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.Oo1fpq_modal{border:1px solid var(--dsw-alias-border-l2,#d1d5db);background:var(--dsw-alias-bg-layer-1,#fff);border-radius:14px;flex-direction:column;gap:12px;width:440px;max-width:100%;max-height:calc(100vh - 40px);padding:16px;display:flex;box-shadow:0 18px 50px #00000038}.Oo1fpq_modalHead{color:var(--dsw-alias-label-primary,#1f2328);justify-content:space-between;align-items:center;gap:10px;font-size:14px;display:flex}.Oo1fpq_modalBody{flex-direction:column;gap:11px;min-height:0;display:flex;overflow-y:auto}.Oo1fpq_formRow{grid-template-columns:1fr 1fr;gap:10px;display:grid}.Oo1fpq_modalFoot{justify-content:flex-end;align-items:center;gap:8px;display:flex}.Oo1fpq_primaryButton{background:var(--dsw-alias-label-primary,#1f2328);min-height:32px;color:var(--dsw-alias-bg-layer-3,#fff);cursor:pointer;border:0;border-radius:8px;align-items:center;gap:6px;padding:0 14px;font-family:inherit;font-size:12.5px;font-weight:600;display:inline-flex}.Oo1fpq_primaryButton:disabled{opacity:.5;cursor:default}.Oo1fpq_secondaryButton{border:1px solid var(--dsw-alias-border-l2,#d1d5db);min-height:32px;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;background:0 0;border-radius:8px;padding:0 14px;font-family:inherit;font-size:12.5px}.Oo1fpq_secondaryButton:hover{color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-2,#f3f4f6)}.Oo1fpq_iconButton{width:26px;height:26px;color:var(--dsw-alias-label-tertiary,#9ca3af);cursor:pointer;background:0 0;border:0;border-radius:7px;flex:none;justify-content:center;align-items:center;font-size:16px;line-height:1;display:inline-flex}.Oo1fpq_iconButton:hover{color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-2,#f3f4f6)}.Oo1fpq_toast{z-index:150;border:1px solid var(--dsw-alias-border-l2,#d1d5db);background:var(--dsw-alias-bg-mask-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);backdrop-filter:blur(6px);pointer-events:none;border-radius:999px;align-items:center;gap:7px;padding:7px 16px;font-size:12.5px;animation:.16s ease-out Oo1fpq_audiogenToastIn;display:inline-flex;position:absolute;bottom:18px;left:50%;transform:translate(-50%);box-shadow:0 8px 24px #00000038}@keyframes Oo1fpq_audiogenToastIn{0%{opacity:0;transform:translate(-50%,6px)}to{opacity:1;transform:translate(-50%)}}@media (prefers-reduced-motion:reduce){.Oo1fpq_toast{animation-duration:1ms}}.Oo1fpq_modelCheckList{border:1px solid var(--dsw-alias-border-l2,#d1d5db);background:var(--dsw-alias-bg-layer-3,#fff);border-radius:8px;flex-direction:column;gap:4px;max-height:180px;padding:8px;display:flex;overflow-y:auto}.Oo1fpq_resultGroups{flex-direction:column;gap:16px;display:flex}.Oo1fpq_resultGroup{flex-direction:column;gap:8px;display:flex}.Oo1fpq_resultGroupHead{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.Oo1fpq_resultGroupChip{background:var(--dsw-alias-bg-hover,#f3f4f6);border:1px solid var(--dsw-alias-border-l2,#d1d5db);color:var(--dsw-alias-label-primary,#1f2328);border-radius:999px;padding:3px 10px;font-size:12px;font-weight:600}.Oo1fpq_resultGroupError{color:#dc2626;font-size:12px}.Oo1fpq_resultGroupCount{color:var(--dsw-alias-label-tertiary,#9ca3af);font-size:11px}.Oo1fpq_overrideTable{flex-direction:column;gap:6px;display:flex}.Oo1fpq_overrideRow{align-items:center;gap:6px;display:flex}.Oo1fpq_overrideCell{min-width:0;color:var(--dsw-alias-label-secondary,#6b7280);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:12px;font-weight:500;overflow:hidden}.Oo1fpq_overrideCell .Oo1fpq_input{min-height:30px;padding:5px 8px}.Oo1fpq_overrideCellHead{color:var(--dsw-alias-label-primary,#1f2328);white-space:normal;font-weight:700}";
803
+ const tagId$4 = "dsh-audiogen/audio-panel.module.css";
804
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
538
805
  const tag = document.createElement("style");
539
806
  tag.dataset.plugin = "dsh-audiogen";
540
- tag.dataset.pluginCss = tagId$3;
541
- tag.textContent = css$3;
807
+ tag.dataset.pluginCss = tagId$4;
808
+ tag.textContent = css$4;
542
809
  document.head.appendChild(tag);
543
810
  }
544
811
  var audio_panel_module_css_default = {
545
- "history": "Oo1fpq_history",
546
- "form": "Oo1fpq_form",
547
- "layout": "Oo1fpq_layout",
548
- "textarea": "Oo1fpq_textarea",
549
- "historyMeta": "Oo1fpq_historyMeta",
550
- "audioList": "Oo1fpq_audioList",
551
- "checkbox": "Oo1fpq_checkbox",
552
- "modeRow": "Oo1fpq_modeRow",
553
- "download": "Oo1fpq_download",
812
+ "audioCardHead": "Oo1fpq_audioCardHead",
813
+ "modeButton": "Oo1fpq_modeButton",
814
+ "title": "Oo1fpq_title",
815
+ "formCol": "Oo1fpq_formCol",
816
+ "voiceIdChip": "Oo1fpq_voiceIdChip",
554
817
  "historyItem": "Oo1fpq_historyItem",
555
- "historyAudio": "Oo1fpq_historyAudio",
556
- "row": "Oo1fpq_row",
818
+ "resultGroupChip": "Oo1fpq_resultGroupChip",
819
+ "resultEmpty": "Oo1fpq_resultEmpty",
820
+ "historyHeader": "Oo1fpq_historyHeader",
821
+ "historyActions": "Oo1fpq_historyActions",
822
+ "historyAction": "Oo1fpq_historyAction",
823
+ "resultGroups": "Oo1fpq_resultGroups",
824
+ "resultGroup": "Oo1fpq_resultGroup",
825
+ "panel": "Oo1fpq_panel",
826
+ "modeRow": "Oo1fpq_modeRow",
827
+ "playerCompact": "Oo1fpq_playerCompact",
828
+ "generate": "Oo1fpq_generate",
829
+ "resultEmptyIcon": "Oo1fpq_resultEmptyIcon",
830
+ "formRow": "Oo1fpq_formRow",
831
+ "audioList": "Oo1fpq_audioList",
832
+ "modalFoot": "Oo1fpq_modalFoot",
833
+ "resultGroupCount": "Oo1fpq_resultGroupCount",
834
+ "historyTitle": "Oo1fpq_historyTitle",
835
+ "overrideTable": "Oo1fpq_overrideTable",
836
+ "historyCol": "Oo1fpq_historyCol",
557
837
  "advanced": "Oo1fpq_advanced",
558
- "title": "Oo1fpq_title",
559
- "result": "Oo1fpq_result",
838
+ "overrideCell": "Oo1fpq_overrideCell",
839
+ "header": "Oo1fpq_header",
840
+ "textarea": "Oo1fpq_textarea",
560
841
  "error": "Oo1fpq_error",
842
+ "ghostButton": "Oo1fpq_ghostButton",
843
+ "secondaryButton": "Oo1fpq_secondaryButton",
844
+ "iconButton": "Oo1fpq_iconButton",
845
+ "resultMeta": "Oo1fpq_resultMeta",
846
+ "primaryButton": "Oo1fpq_primaryButton",
561
847
  "historyPrompt": "Oo1fpq_historyPrompt",
562
- "historyEmpty": "Oo1fpq_historyEmpty",
563
- "empty": "Oo1fpq_empty",
564
- "input": "Oo1fpq_input",
565
- "historyTitle": "Oo1fpq_historyTitle",
848
+ "audiogenToastIn": "Oo1fpq_audiogenToastIn",
849
+ "modalBody": "Oo1fpq_modalBody",
850
+ "studio": "Oo1fpq_studio",
851
+ "tab": "Oo1fpq_tab",
852
+ "historyList": "Oo1fpq_historyList",
853
+ "checkbox": "Oo1fpq_checkbox",
854
+ "row": "Oo1fpq_row",
566
855
  "hint": "Oo1fpq_hint",
567
- "select": "Oo1fpq_select",
568
- "panel": "Oo1fpq_panel",
569
- "header": "Oo1fpq_header",
856
+ "modal": "Oo1fpq_modal",
857
+ "toast": "Oo1fpq_toast",
858
+ "audioCardIndex": "Oo1fpq_audioCardIndex",
859
+ "track": "Oo1fpq_track",
860
+ "input": "Oo1fpq_input",
861
+ "tabs": "Oo1fpq_tabs",
862
+ "resultModeChip": "Oo1fpq_resultModeChip",
863
+ "modalHead": "Oo1fpq_modalHead",
864
+ "modelCheckList": "Oo1fpq_modelCheckList",
570
865
  "label": "Oo1fpq_label",
571
- "audio": "Oo1fpq_audio",
866
+ "historyMeta": "Oo1fpq_historyMeta",
867
+ "overrideCellHead": "Oo1fpq_overrideCellHead",
868
+ "savedChip": "Oo1fpq_savedChip",
869
+ "historyClear": "Oo1fpq_historyClear",
870
+ "resultEmptyHint": "Oo1fpq_resultEmptyHint",
871
+ "historyEmpty": "Oo1fpq_historyEmpty",
872
+ "trackFill": "Oo1fpq_trackFill",
873
+ "trackKnob": "Oo1fpq_trackKnob",
874
+ "resultCol": "Oo1fpq_resultCol",
875
+ "time": "Oo1fpq_time",
876
+ "playButton": "Oo1fpq_playButton",
877
+ "audioCardActions": "Oo1fpq_audioCardActions",
878
+ "overrideRow": "Oo1fpq_overrideRow",
879
+ "resultGroupHead": "Oo1fpq_resultGroupHead",
880
+ "muteButton": "Oo1fpq_muteButton",
572
881
  "audioCard": "Oo1fpq_audioCard",
573
- "modeButton": "Oo1fpq_modeButton",
574
- "generate": "Oo1fpq_generate"
882
+ "resultGroupError": "Oo1fpq_resultGroupError",
883
+ "modalMask": "Oo1fpq_modalMask",
884
+ "player": "Oo1fpq_player"
575
885
  };
576
886
  //#endregion
577
- //#region src/client/AudioGenPanel.tsx
887
+ //#region src/client/audio-player.tsx
888
+ /**
889
+ * Custom audio player: play/pause, seekable progress and time readout.
890
+ * Replaces the native `<audio controls>` look with a themed control so the
891
+ * panel matches the DSH design tokens in light and dark modes.
892
+ */
893
+ function format(seconds) {
894
+ if (!Number.isFinite(seconds) || seconds < 0) return "0:00";
895
+ const whole = Math.floor(seconds);
896
+ const minutes = Math.floor(whole / 60);
897
+ const rest = whole % 60;
898
+ return `${minutes}:${rest < 10 ? `0${rest}` : String(rest)}`;
899
+ }
900
+ function AudioPlayer(props) {
901
+ const ref = (0, react.useRef)(null);
902
+ const [playing, setPlaying] = (0, react.useState)(false);
903
+ const [muted, setMuted] = (0, react.useState)(false);
904
+ const [current, setCurrent] = (0, react.useState)(0);
905
+ const [duration, setDuration] = (0, react.useState)(0);
906
+ (0, react.useEffect)(() => {
907
+ setPlaying(false);
908
+ setCurrent(0);
909
+ setDuration(0);
910
+ }, [props.src]);
911
+ const toggle = (0, react.useCallback)(() => {
912
+ const el = ref.current;
913
+ if (el === null) return;
914
+ if (el.paused) el.play().catch(() => {});
915
+ else el.pause();
916
+ }, []);
917
+ const seek = (0, react.useCallback)((event) => {
918
+ const el = ref.current;
919
+ if (el === null || duration <= 0) return;
920
+ const rect = event.currentTarget.getBoundingClientRect();
921
+ el.currentTime = Math.min(1, Math.max(0, (event.clientX - rect.left) / rect.width)) * duration;
922
+ }, [duration]);
923
+ const toggleMute = (0, react.useCallback)(() => {
924
+ const el = ref.current;
925
+ if (el === null) return;
926
+ el.muted = !el.muted;
927
+ setMuted(el.muted);
928
+ }, []);
929
+ const percent = duration > 0 ? Math.min(100, current / duration * 100) : 0;
930
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
931
+ className: props.compact === true ? audio_panel_module_css_default.playerCompact : audio_panel_module_css_default.player,
932
+ "data-playing": playing ? "true" : "false",
933
+ children: [
934
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
935
+ ref,
936
+ src: props.src,
937
+ preload: "metadata",
938
+ onPlay: () => setPlaying(true),
939
+ onPause: () => setPlaying(false),
940
+ onEnded: () => setPlaying(false),
941
+ onTimeUpdate: (event) => setCurrent(event.currentTarget.currentTime),
942
+ onLoadedMetadata: (event) => setDuration(event.currentTarget.duration)
943
+ }),
944
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
945
+ type: "button",
946
+ className: audio_panel_module_css_default.playButton,
947
+ "aria-label": playing ? "暂停" : "播放",
948
+ onClick: toggle,
949
+ children: playing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PauseIcon, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlayIcon, {})
950
+ }),
951
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
952
+ className: audio_panel_module_css_default.track,
953
+ role: "slider",
954
+ "aria-label": "播放进度",
955
+ "aria-valuemin": 0,
956
+ "aria-valuemax": Math.round(duration),
957
+ "aria-valuenow": Math.round(current),
958
+ onClick: seek,
959
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
960
+ className: audio_panel_module_css_default.trackFill,
961
+ style: { width: `${percent}%` }
962
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
963
+ className: audio_panel_module_css_default.trackKnob,
964
+ style: { left: `${percent}%` }
965
+ })]
966
+ }),
967
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
968
+ className: audio_panel_module_css_default.time,
969
+ children: [format(current), duration > 0 ? ` / ${format(duration)}` : ""]
970
+ }),
971
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
972
+ type: "button",
973
+ className: audio_panel_module_css_default.muteButton,
974
+ "aria-label": muted ? "取消静音" : "静音",
975
+ onClick: toggleMute,
976
+ children: muted ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MuteIcon, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(VolumeIcon, {})
977
+ })
978
+ ]
979
+ });
980
+ }
981
+ //#endregion
982
+ //#region src/client/library-save-dialog.tsx
983
+ /**
984
+ * «保存到资源库» dialog: pick type/category, set name/tags/note, then save.
985
+ * Built from either freshly generated audio or a history entry.
986
+ */
987
+ function typeOfMode(mode) {
988
+ if (mode === "voice_design") return "voice";
989
+ return mode;
990
+ }
991
+ const LIBRARY_TYPE_LABELS = {
992
+ voice: "音色",
993
+ music: "音乐",
994
+ sfx: "音效",
995
+ tts: "TTS 语音"
996
+ };
997
+ function parseTags(text) {
998
+ return [...new Set(text.split(/[,,、\n]/).map((tag) => tag.trim()).filter((tag) => tag !== ""))].slice(0, 20);
999
+ }
1000
+ function guessCategory(type, context) {
1001
+ if (type === "voice") {
1002
+ const probe = `${context.voiceId ?? ""} ${context.voice ?? ""}`.toLowerCase();
1003
+ if (/male|男/.test(probe)) return "male";
1004
+ if (/female|女/.test(probe)) return "female";
1005
+ return "custom";
1006
+ }
1007
+ if (type === "tts") return (context.voice ?? context.voiceId ?? "default").replace(/[^a-zA-Z0-9\u4e00-\u9fa5._-]+/g, "_");
1008
+ return "";
1009
+ }
1010
+ function LibrarySaveDialog(props) {
1011
+ const { api, files, context } = props;
1012
+ const [type, setType] = (0, react.useState)(typeOfMode(context.mode));
1013
+ const [category, setCategory] = (0, react.useState)(() => guessCategory(typeOfMode(context.mode), context));
1014
+ const [name, setName] = (0, react.useState)("");
1015
+ const [tags, setTags] = (0, react.useState)("");
1016
+ const [note, setNote] = (0, react.useState)("");
1017
+ const [saving, setSaving] = (0, react.useState)(false);
1018
+ const [error, setError] = (0, react.useState)(null);
1019
+ const isVoice = type === "voice";
1020
+ const isTts = type === "tts";
1021
+ const defaultName = (0, react.useMemo)(() => {
1022
+ const flat = context.prompt.replace(/\s+/g, " ").trim();
1023
+ return flat === "" ? "未命名音频" : flat.length > 40 ? `${flat.slice(0, 40)}…` : flat;
1024
+ }, [context.prompt]);
1025
+ const switchType = (next) => {
1026
+ setType(next);
1027
+ setCategory(guessCategory(next, context));
1028
+ };
1029
+ const save = async () => {
1030
+ setSaving(true);
1031
+ setError(null);
1032
+ try {
1033
+ const result = await api.librarySave({
1034
+ audioFiles: files.map((file) => ({
1035
+ id: file.id,
1036
+ file: file.file,
1037
+ mime: file.mime,
1038
+ ...file.voiceId === void 0 ? {} : { voiceId: file.voiceId },
1039
+ ...file.duration === void 0 ? {} : { duration: file.duration }
1040
+ })),
1041
+ type,
1042
+ ...category.trim() !== "" && (isVoice || isTts) ? { category: category.trim() } : {},
1043
+ ...name.trim() !== "" ? { name: name.trim() } : {},
1044
+ ...parseTags(tags).length > 0 ? { tags: parseTags(tags) } : {},
1045
+ ...note.trim() !== "" ? { note: note.trim() } : {},
1046
+ provenance: {
1047
+ mode: context.mode,
1048
+ prompt: context.prompt,
1049
+ ...context.channel === void 0 ? {} : { channel: context.channel },
1050
+ ...context.channelId === void 0 ? {} : { channelId: context.channelId },
1051
+ ...context.model === void 0 ? {} : { model: context.model },
1052
+ ...context.voice === void 0 ? {} : { voice: context.voice },
1053
+ ...context.voiceId === void 0 ? {} : { voiceId: context.voiceId },
1054
+ ...context.params === void 0 ? {} : { params: context.params }
1055
+ }
1056
+ });
1057
+ if (!result.ok || result.entry === void 0) {
1058
+ setError(result.message ?? "保存失败");
1059
+ return;
1060
+ }
1061
+ props.onSaved(result.entry);
1062
+ } catch (err) {
1063
+ setError(err instanceof Error ? err.message : String(err));
1064
+ } finally {
1065
+ setSaving(false);
1066
+ }
1067
+ };
1068
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1069
+ className: audio_panel_module_css_default.modalMask,
1070
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1071
+ className: audio_panel_module_css_default.modal,
1072
+ role: "dialog",
1073
+ "aria-modal": "true",
1074
+ "aria-label": "保存到资源库",
1075
+ children: [
1076
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1077
+ className: audio_panel_module_css_default.modalHead,
1078
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: files.length > 1 ? `保存 ${files.length} 段音频到资源库` : "保存到资源库" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1079
+ type: "button",
1080
+ className: audio_panel_module_css_default.iconButton,
1081
+ "aria-label": "关闭",
1082
+ onClick: props.onClose,
1083
+ children: "×"
1084
+ })]
1085
+ }),
1086
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1087
+ className: audio_panel_module_css_default.modalBody,
1088
+ children: [
1089
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1090
+ className: audio_panel_module_css_default.formRow,
1091
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1092
+ className: audio_panel_module_css_default.label,
1093
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "资源类型" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
1094
+ className: audio_panel_module_css_default.input,
1095
+ value: type,
1096
+ onChange: (event) => switchType(event.target.value),
1097
+ children: [
1098
+ "voice",
1099
+ "music",
1100
+ "sfx",
1101
+ "tts"
1102
+ ].map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1103
+ value: item,
1104
+ children: LIBRARY_TYPE_LABELS[item]
1105
+ }, item))
1106
+ })]
1107
+ }), isVoice || isTts ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1108
+ className: audio_panel_module_css_default.label,
1109
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: isVoice ? "音色分级(男 / 女)" : "按音色归档(voice 键)" }), isVoice ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1110
+ className: audio_panel_module_css_default.input,
1111
+ value: category,
1112
+ onChange: (event) => setCategory(event.target.value),
1113
+ children: [
1114
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1115
+ value: "male",
1116
+ children: "男声 male"
1117
+ }),
1118
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1119
+ value: "female",
1120
+ children: "女声 female"
1121
+ }),
1122
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1123
+ value: "custom",
1124
+ children: "未分级 custom"
1125
+ })
1126
+ ]
1127
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1128
+ className: audio_panel_module_css_default.input,
1129
+ value: category,
1130
+ onChange: (event) => setCategory(event.target.value),
1131
+ placeholder: context.voice ?? "default"
1132
+ })]
1133
+ }) : null]
1134
+ }),
1135
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1136
+ className: audio_panel_module_css_default.label,
1137
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "名称(留空则使用提示词)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1138
+ className: audio_panel_module_css_default.input,
1139
+ value: name,
1140
+ onChange: (event) => setName(event.target.value),
1141
+ placeholder: defaultName
1142
+ })]
1143
+ }),
1144
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1145
+ className: audio_panel_module_css_default.label,
1146
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "标签(逗号分隔,可多个)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1147
+ className: audio_panel_module_css_default.input,
1148
+ value: tags,
1149
+ onChange: (event) => setTags(event.target.value),
1150
+ placeholder: "温暖, 男声, 复古…"
1151
+ })]
1152
+ }),
1153
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1154
+ className: audio_panel_module_css_default.label,
1155
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "备注(可选)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1156
+ className: audio_panel_module_css_default.textarea,
1157
+ rows: 2,
1158
+ value: note,
1159
+ onChange: (event) => setNote(event.target.value),
1160
+ placeholder: "用途、风格备注…"
1161
+ })]
1162
+ }),
1163
+ error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1164
+ className: audio_panel_module_css_default.error,
1165
+ children: error
1166
+ }) : null
1167
+ ]
1168
+ }),
1169
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1170
+ className: audio_panel_module_css_default.modalFoot,
1171
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1172
+ type: "button",
1173
+ className: audio_panel_module_css_default.secondaryButton,
1174
+ onClick: props.onClose,
1175
+ children: "取消"
1176
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1177
+ type: "button",
1178
+ className: audio_panel_module_css_default.primaryButton,
1179
+ disabled: saving || files.length === 0,
1180
+ onClick: () => void save(),
1181
+ children: saving ? "保存中…" : "保存到资源库"
1182
+ })]
1183
+ })
1184
+ ]
1185
+ })
1186
+ });
1187
+ }
1188
+ //#endregion
1189
+ //#region src/client/studio-view.tsx
578
1190
  /**
579
- * The AI 音频 panel: a compact audio-generation studio.
580
- * TTS / music / SFX / voice design are separated; each mode only lists
581
- * compatible models and shows its own parameters.
1191
+ * Studio view: the generation form (left), result cards (center) and the
1192
+ * compact generation history (right). Owns the «加入资源库» interactions —
1193
+ * a pre-generation checkbox, a per-card save dialog, and a history star.
582
1194
  */
1195
+ /** 每模型可覆盖的参数行(留空 = 自动,沿用上方全局配置)。 */
1196
+ const OVERRIDE_ROWS = [
1197
+ {
1198
+ key: "format",
1199
+ label: "输出格式",
1200
+ type: "select",
1201
+ options: [
1202
+ "mp3",
1203
+ "wav",
1204
+ "pcm",
1205
+ "flac",
1206
+ "ogg"
1207
+ ],
1208
+ placeholder: "自动"
1209
+ },
1210
+ {
1211
+ key: "duration",
1212
+ label: "时长(秒)",
1213
+ type: "number",
1214
+ placeholder: "自动"
1215
+ },
1216
+ {
1217
+ key: "voice",
1218
+ label: "音色",
1219
+ type: "text",
1220
+ placeholder: "自动"
1221
+ },
1222
+ {
1223
+ key: "speed",
1224
+ label: "语速",
1225
+ type: "number",
1226
+ placeholder: "自动"
1227
+ },
1228
+ {
1229
+ key: "emotion",
1230
+ label: "情绪",
1231
+ type: "text",
1232
+ placeholder: "自动"
1233
+ },
1234
+ {
1235
+ key: "sample_rate",
1236
+ label: "采样率",
1237
+ type: "number",
1238
+ placeholder: "自动"
1239
+ },
1240
+ {
1241
+ key: "bitrate",
1242
+ label: "码率",
1243
+ type: "number",
1244
+ placeholder: "自动"
1245
+ },
1246
+ {
1247
+ key: "lyrics",
1248
+ label: "歌词",
1249
+ type: "text",
1250
+ placeholder: "自动"
1251
+ },
1252
+ {
1253
+ key: "seed",
1254
+ label: "seed",
1255
+ type: "number",
1256
+ placeholder: "自动"
1257
+ },
1258
+ {
1259
+ key: "steps",
1260
+ label: "steps",
1261
+ type: "number",
1262
+ placeholder: "自动"
1263
+ },
1264
+ {
1265
+ key: "cfg_scale",
1266
+ label: "cfg_scale",
1267
+ type: "number",
1268
+ placeholder: "自动"
1269
+ }
1270
+ ];
1271
+ /** 每模型覆盖值 → 请求字段的数值/类型转换(空值跳过)。 */
1272
+ function overrideSpread(override) {
1273
+ const out = {};
1274
+ const val = override.format?.trim() ?? "";
1275
+ if (val !== "") out.format = val;
1276
+ const num = (key) => {
1277
+ const raw = (override[key] ?? "").trim();
1278
+ if (raw === "") return void 0;
1279
+ const parsed = Number(raw);
1280
+ return Number.isFinite(parsed) ? parsed : void 0;
1281
+ };
1282
+ const duration = num("duration");
1283
+ if (duration !== void 0) out.duration = duration;
1284
+ const voice = override.voice?.trim() ?? "";
1285
+ if (voice !== "") out.voice = voice;
1286
+ const speed = num("speed");
1287
+ if (speed !== void 0) out.speed = speed;
1288
+ const emotion = override.emotion?.trim() ?? "";
1289
+ if (emotion !== "") out.emotion = emotion;
1290
+ const sampleRate = num("sample_rate");
1291
+ if (sampleRate !== void 0) out.sampleRate = sampleRate;
1292
+ const bitrate = num("bitrate");
1293
+ if (bitrate !== void 0) out.bitrate = bitrate;
1294
+ const lyrics = override.lyrics?.trim() ?? "";
1295
+ if (lyrics !== "") out.lyrics = lyrics;
1296
+ const seed = num("seed");
1297
+ if (seed !== void 0) out.seed = seed;
1298
+ const steps = num("steps");
1299
+ if (steps !== void 0) out.steps = steps;
1300
+ const cfgScale = num("cfg_scale");
1301
+ if (cfgScale !== void 0) out.cfgScale = cfgScale;
1302
+ return out;
1303
+ }
583
1304
  function useConfig(scope) {
584
1305
  const [value, setValue] = (0, react.useState)(scope.getSnapshot().value);
585
1306
  (0, react.useEffect)(() => scope.subscribe(() => {
@@ -610,12 +1331,48 @@ window.__ModuleLoader__.load({
610
1331
  function dataUrlOf(audio) {
611
1332
  return `data:${audio.mime};base64,${audio.b64}`;
612
1333
  }
613
- function AudioGenPanel(props) {
614
- const { api, scope } = props;
615
- const config = useConfig(scope);
616
- const enabled = config?.enabled ?? true;
617
- const modelOptions = audioModelOptions(config);
618
- const channels = config?.channels ?? [];
1334
+ function fileNameOf(url) {
1335
+ try {
1336
+ return decodeURIComponent(new URL(url, "http://localhost").pathname.split("/").pop() ?? "");
1337
+ } catch {
1338
+ return "";
1339
+ }
1340
+ }
1341
+ /** Turn a history entry's audio refs into GeneratedAudio-shaped inputs. */
1342
+ function audioRefsOfEntry(entry) {
1343
+ return entry.audio.map((audio) => {
1344
+ const file = fileNameOf(audio.url);
1345
+ return {
1346
+ id: file.replace(/\.[a-z0-9]+$/i, ""),
1347
+ file,
1348
+ url: audio.url,
1349
+ mime: audio.mime,
1350
+ bytes: 0,
1351
+ b64: "",
1352
+ ...audio.duration === void 0 ? {} : { duration: audio.duration },
1353
+ ...audio.voiceId === void 0 ? {} : { voiceId: audio.voiceId }
1354
+ };
1355
+ });
1356
+ }
1357
+ function contextOfEntry(entry) {
1358
+ return {
1359
+ mode: entry.mode,
1360
+ prompt: entry.prompt,
1361
+ ...entry.voice === void 0 ? {} : { voice: entry.voice },
1362
+ ...entry.voiceId === void 0 ? {} : { voiceId: entry.voiceId },
1363
+ ...entry.model === void 0 ? {} : { model: entry.model },
1364
+ ...entry.channel === void 0 ? {} : { channel: entry.channel },
1365
+ ...entry.channelId === void 0 ? {} : { channelId: entry.channelId },
1366
+ ...entry.params === void 0 ? {} : { params: entry.params }
1367
+ };
1368
+ }
1369
+ function StudioView(props) {
1370
+ const { api, scope, config, reuse } = props;
1371
+ const effectiveConfig = useConfig(scope);
1372
+ const cfg = config ?? effectiveConfig;
1373
+ const enabled = cfg?.enabled ?? true;
1374
+ const modelOptions = audioModelOptions(cfg);
1375
+ const channels = cfg?.channels ?? [];
619
1376
  const connected = enabled && channels.some((channel) => {
620
1377
  const keyHeld = scope.getSecretSetSnapshot(`channelSecrets.${channel.id}`);
621
1378
  return channel.apiUrl.trim() !== "" && keyHeld && (channel.models.length > 0 || channel.preset === "minimax");
@@ -624,6 +1381,8 @@ window.__ModuleLoader__.load({
624
1381
  const [prompt, setPrompt] = (0, react.useState)("");
625
1382
  const [previewText, setPreviewText] = (0, react.useState)("");
626
1383
  const [model, setModel] = (0, react.useState)("");
1384
+ const [selectedModels, setSelectedModels] = (0, react.useState)([]);
1385
+ const [overrides, setOverrides] = (0, react.useState)({});
627
1386
  const [voice, setVoice] = (0, react.useState)("");
628
1387
  const [speed, setSpeed] = (0, react.useState)("");
629
1388
  const [duration, setDuration] = (0, react.useState)("");
@@ -641,8 +1400,12 @@ window.__ModuleLoader__.load({
641
1400
  const [audioChannel, setAudioChannel] = (0, react.useState)("");
642
1401
  const [subtitle, setSubtitle] = (0, react.useState)(false);
643
1402
  const [loading, setLoading] = (0, react.useState)(false);
1403
+ const [progress, setProgress] = (0, react.useState)("");
644
1404
  const [error, setError] = (0, react.useState)(null);
645
- const [outputs, setOutputs] = (0, react.useState)([]);
1405
+ const [results, setResults] = (0, react.useState)([]);
1406
+ const [saveToLibrary, setSaveToLibrary] = (0, react.useState)(cfg?.autoSaveToLibrary === true);
1407
+ const [savedIds, setSavedIds] = (0, react.useState)(/* @__PURE__ */ new Set());
1408
+ const [saveDialog, setSaveDialog] = (0, react.useState)(null);
646
1409
  const { entries, reload, clear } = useHistory();
647
1410
  const [designChannelId, setDesignChannelId] = (0, react.useState)("");
648
1411
  const isMiniMaxChannel = (0, react.useMemo)(() => {
@@ -661,52 +1424,138 @@ window.__ModuleLoader__.load({
661
1424
  if (mode === "voice_design") return [];
662
1425
  return modelOptions.models.filter((entry) => entry.category === void 0 || entry.category === "tts" && mode === "tts" || entry.category === mode).map((entry) => entry.alias);
663
1426
  }, [modelOptions.models, mode]);
1427
+ (0, react.useEffect)(() => {
1428
+ if (visibleModels.length === 0) return;
1429
+ setSelectedModels((current) => {
1430
+ const valid = current.filter((item) => visibleModels.includes(item));
1431
+ if (valid.length > 0) return valid;
1432
+ return [visibleModels[0]];
1433
+ });
1434
+ }, [visibleModels]);
1435
+ (0, react.useEffect)(() => {
1436
+ setOverrides((current) => {
1437
+ const next = {};
1438
+ for (const alias of selectedModels) if (current[alias] !== void 0) next[alias] = current[alias];
1439
+ return next;
1440
+ });
1441
+ }, [selectedModels]);
1442
+ const setOverrideValue = (model, key, value) => {
1443
+ setOverrides((current) => ({
1444
+ ...current,
1445
+ [model]: {
1446
+ ...current[model] ?? {},
1447
+ [key]: value
1448
+ }
1449
+ }));
1450
+ };
664
1451
  (0, react.useEffect)(() => {
665
1452
  if (visibleModels.length > 0 && !visibleModels.includes(model)) setModel(visibleModels[0]);
666
1453
  }, [visibleModels, model]);
1454
+ (0, react.useEffect)(() => {
1455
+ if (reuse === void 0 || reuse === null) return;
1456
+ setMode(reuse.mode);
1457
+ if (reuse.voiceId !== void 0 || reuse.voice !== void 0) setVoice(reuse.voiceId ?? reuse.voice ?? "");
1458
+ if (reuse.model !== void 0 && reuse.model !== "") {
1459
+ setModel(reuse.model);
1460
+ setSelectedModels([reuse.model]);
1461
+ }
1462
+ }, [reuse?.nonce]);
667
1463
  const submit = async () => {
668
1464
  if (prompt.trim() === "") {
669
1465
  setError(tt("prompt.required"));
670
1466
  return;
671
1467
  }
1468
+ const targets = mode === "voice_design" ? [""] : selectedModels.length > 0 ? selectedModels : model !== "" ? [model] : visibleModels.length > 0 ? [visibleModels[0]] : [];
1469
+ if (targets.length === 0) {
1470
+ setError("当前模式暂无可用模型");
1471
+ return;
1472
+ }
672
1473
  setLoading(true);
673
1474
  setError(null);
1475
+ setProgress("");
1476
+ const gathered = [];
1477
+ let anySaved = false;
674
1478
  try {
675
- const response = await api.generate({
676
- mode,
677
- model: mode === "voice_design" ? "" : (model || visibleModels[0]) ?? "",
678
- prompt: prompt.trim(),
679
- ...mode === "voice_design" && designChannelId !== "" ? { channelId: designChannelId } : {},
680
- ...previewText.trim() !== "" ? { previewText: previewText.trim() } : {},
681
- ...voice.trim() !== "" ? { voice: voice.trim() } : {},
682
- ...speed.trim() !== "" ? { speed: Number(speed) } : {},
683
- ...duration.trim() !== "" ? { duration: Number(duration) } : {},
684
- ...lyrics.trim() !== "" ? { lyrics: lyrics.trim() } : {},
685
- ...instrumental ? { isInstrumental: true } : {},
686
- ...loop ? { loop: true } : {},
687
- ...promptInfluence.trim() !== "" ? { promptInfluence: Number(promptInfluence) } : {},
688
- ...format.trim() !== "" ? { format: format.trim() } : {},
689
- ...emotion.trim() !== "" ? { emotion: emotion.trim() } : {},
690
- ...vol.trim() !== "" ? { vol: Number(vol) } : {},
691
- ...pitch.trim() !== "" ? { pitch: Number(pitch) } : {},
692
- ...toneText.trim() !== "" ? { pronunciationTone: toneText.split("\n").map((item) => item.trim()).filter((item) => item !== "") } : {},
693
- ...sampleRate.trim() !== "" ? { sampleRate: Number(sampleRate) } : {},
694
- ...bitrate.trim() !== "" ? { bitrate: Number(bitrate) } : {},
695
- ...audioChannel.trim() !== "" ? { audioChannel: Number(audioChannel) } : {},
696
- ...subtitle ? { subtitleEnable: true } : {}
697
- });
698
- if (!response.ok) {
699
- setError(response.message ?? "生成失败");
700
- return;
1479
+ for (const [index, target] of targets.entries()) {
1480
+ setProgress(`生成中 ${index + 1}/${targets.length}(${target || "音色设计"})…`);
1481
+ let response;
1482
+ try {
1483
+ response = await api.generate({
1484
+ mode,
1485
+ model: target,
1486
+ prompt: prompt.trim(),
1487
+ saveToLibrary,
1488
+ ...mode === "voice_design" && designChannelId !== "" ? { channelId: designChannelId } : {},
1489
+ ...previewText.trim() !== "" ? { previewText: previewText.trim() } : {},
1490
+ ...voice.trim() !== "" ? { voice: voice.trim() } : {},
1491
+ ...speed.trim() !== "" ? { speed: Number(speed) } : {},
1492
+ ...duration.trim() !== "" ? { duration: Number(duration) } : {},
1493
+ ...lyrics.trim() !== "" ? { lyrics: lyrics.trim() } : {},
1494
+ ...instrumental ? { isInstrumental: true } : {},
1495
+ ...loop ? { loop: true } : {},
1496
+ ...promptInfluence.trim() !== "" ? { promptInfluence: Number(promptInfluence) } : {},
1497
+ ...format.trim() !== "" ? { format: format.trim() } : {},
1498
+ ...emotion.trim() !== "" ? { emotion: emotion.trim() } : {},
1499
+ ...vol.trim() !== "" ? { vol: Number(vol) } : {},
1500
+ ...pitch.trim() !== "" ? { pitch: Number(pitch) } : {},
1501
+ ...toneText.trim() !== "" ? { pronunciationTone: toneText.split("\n").map((item) => item.trim()).filter((item) => item !== "") } : {},
1502
+ ...sampleRate.trim() !== "" ? { sampleRate: Number(sampleRate) } : {},
1503
+ ...bitrate.trim() !== "" ? { bitrate: Number(bitrate) } : {},
1504
+ ...audioChannel.trim() !== "" ? { audioChannel: Number(audioChannel) } : {},
1505
+ ...subtitle ? { subtitleEnable: true } : {},
1506
+ ...target === "" ? {} : overrideSpread(overrides[target] ?? {})
1507
+ });
1508
+ } catch (err) {
1509
+ gathered.push({
1510
+ model: target,
1511
+ outputs: [],
1512
+ error: err instanceof Error ? err.message : String(err)
1513
+ });
1514
+ continue;
1515
+ }
1516
+ if (!response.ok) {
1517
+ gathered.push({
1518
+ model: target,
1519
+ outputs: [],
1520
+ error: response.message ?? "生成失败"
1521
+ });
1522
+ continue;
1523
+ }
1524
+ const generated = response.outputs ?? [];
1525
+ gathered.push({
1526
+ model: target,
1527
+ outputs: generated
1528
+ });
1529
+ if ((response.resources?.length ?? 0) > 0 && saveToLibrary) anySaved = true;
701
1530
  }
702
- setOutputs(response.outputs ?? []);
1531
+ setResults(gathered);
1532
+ if (anySaved) {
1533
+ setSavedIds((current) => /* @__PURE__ */ new Set([...current, ...gathered.flatMap((group) => group.outputs.map((item) => item.id))]));
1534
+ props.showToast("已保存到资源库");
1535
+ props.onLibraryChanged();
1536
+ }
1537
+ const failed = gathered.filter((group) => group.error !== void 0 && group.outputs.length === 0);
1538
+ if (failed.length > 0 && failed.length === gathered.length) setError(failed.map((group) => `「${group.model || "音色设计"}」${group.error}`).join(";"));
703
1539
  reload();
704
1540
  } catch (err) {
705
1541
  setError(err instanceof Error ? err.message : String(err));
706
1542
  } finally {
707
1543
  setLoading(false);
1544
+ setProgress("");
708
1545
  }
709
1546
  };
1547
+ const openSaveDialog = (files, context) => {
1548
+ setSaveDialog({
1549
+ files,
1550
+ context
1551
+ });
1552
+ };
1553
+ const onDialogSaved = (entry) => {
1554
+ if (saveDialog !== null) setSavedIds((current) => /* @__PURE__ */ new Set([...current, ...saveDialog.files.map((file) => file.id)]));
1555
+ setSaveDialog(null);
1556
+ props.showToast(`已保存「${entry.name}」`);
1557
+ props.onLibraryChanged();
1558
+ };
710
1559
  const modeLabel = (0, react.useMemo)(() => {
711
1560
  if (mode === "tts") return tt("mode.tts");
712
1561
  if (mode === "music") return tt("mode.music");
@@ -715,445 +1564,571 @@ window.__ModuleLoader__.load({
715
1564
  }, [mode]);
716
1565
  const needModel = mode !== "voice_design";
717
1566
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
718
- className: audio_panel_module_css_default.panel,
719
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
720
- className: audio_panel_module_css_default.header,
721
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
722
- className: audio_panel_module_css_default.title,
723
- children: tt("panel.title")
724
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
725
- className: audio_panel_module_css_default.hint,
726
- children: modeLabel
727
- })]
728
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
729
- className: audio_panel_module_css_default.layout,
730
- children: [
731
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
732
- className: audio_panel_module_css_default.form,
733
- children: [
734
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
735
- className: audio_panel_module_css_default.modeRow,
736
- children: [
737
- "tts",
738
- "music",
739
- "sfx",
740
- "voice_design"
741
- ].map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
742
- type: "button",
743
- className: audio_panel_module_css_default.modeButton,
744
- "data-active": mode === item ? "true" : "false",
745
- onClick: () => setMode(item),
746
- children: item === "tts" ? tt("mode.tts") : item === "music" ? tt("mode.music") : item === "sfx" ? tt("mode.sfx") : tt("mode.voiceDesign")
747
- }, item))
748
- }),
1567
+ className: audio_panel_module_css_default.studio,
1568
+ children: [
1569
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1570
+ className: audio_panel_module_css_default.formCol,
1571
+ children: [
1572
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1573
+ className: audio_panel_module_css_default.modeRow,
1574
+ children: [
1575
+ "tts",
1576
+ "music",
1577
+ "sfx",
1578
+ "voice_design"
1579
+ ].map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1580
+ type: "button",
1581
+ className: audio_panel_module_css_default.modeButton,
1582
+ "data-active": mode === item ? "true" : "false",
1583
+ onClick: () => setMode(item),
1584
+ children: item === "tts" ? tt("mode.tts") : item === "music" ? tt("mode.music") : item === "sfx" ? tt("mode.sfx") : tt("mode.voiceDesign")
1585
+ }, item))
1586
+ }),
1587
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1588
+ className: audio_panel_module_css_default.label,
1589
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: mode === "voice_design" ? "音色描述" : mode === "tts" ? "文本" : "提示词" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1590
+ className: audio_panel_module_css_default.textarea,
1591
+ value: prompt,
1592
+ onChange: (event) => setPrompt(event.target.value),
1593
+ placeholder: tt("prompt.placeholder")
1594
+ })]
1595
+ }),
1596
+ mode === "voice_design" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
749
1597
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
750
1598
  className: audio_panel_module_css_default.label,
751
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: mode === "voice_design" ? "音色描述" : mode === "tts" ? "文本" : "提示词" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
752
- className: audio_panel_module_css_default.textarea,
753
- value: prompt,
754
- onChange: (event) => setPrompt(event.target.value),
755
- placeholder: tt("prompt.placeholder")
1599
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "厂商 / 渠道" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1600
+ className: audio_panel_module_css_default.input,
1601
+ value: designChannelId,
1602
+ onChange: (event) => setDesignChannelId(event.target.value),
1603
+ children: [channels.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1604
+ value: "",
1605
+ children: "(尚未配置渠道)"
1606
+ }) : null, channels.map((candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
1607
+ value: candidate.id,
1608
+ children: [
1609
+ candidate.name,
1610
+ "(",
1611
+ candidate.preset === "minimax" ? "MiniMax" : candidate.preset === "elevenlabs" ? "ElevenLabs" : candidate.preset || "自定义",
1612
+ ")"
1613
+ ]
1614
+ }, candidate.id))]
756
1615
  })]
757
1616
  }),
758
- mode === "voice_design" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
759
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
760
- className: audio_panel_module_css_default.label,
761
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "厂商 / 渠道" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
762
- className: audio_panel_module_css_default.select,
763
- value: designChannelId,
764
- onChange: (event) => setDesignChannelId(event.target.value),
765
- children: [channels.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
766
- value: "",
767
- children: "(尚未配置渠道)"
768
- }) : null, channels.map((candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
769
- value: candidate.id,
770
- children: [
771
- candidate.name,
772
- "(",
773
- candidate.preset === "minimax" ? "MiniMax" : candidate.preset === "elevenlabs" ? "ElevenLabs" : candidate.preset || "自定义",
774
- ")"
775
- ]
776
- }, candidate.id))]
777
- })]
778
- }),
779
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
780
- className: audio_panel_module_css_default.hint,
781
- children: "MiniMax:/v1/voice_design;ElevenLabs:/v1/text-to-voice/design(试听文本 100-1000 字符,过短将自动生成)"
782
- }),
783
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
784
- className: audio_panel_module_css_default.label,
785
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "试听文本" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
786
- className: audio_panel_module_css_default.input,
787
- value: previewText,
788
- onChange: (event) => setPreviewText(event.target.value),
789
- placeholder: "你好,这是新设计的音色试听。"
790
- })]
791
- })
792
- ] }) : null,
793
- needModel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
794
- className: audio_panel_module_css_default.label,
795
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("model.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
796
- className: audio_panel_module_css_default.select,
797
- value: model,
798
- onChange: (event) => setModel(event.target.value),
799
- children: [visibleModels.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
800
- value: "",
801
- children: "(当前模式暂无可用模型)"
802
- }) : null, visibleModels.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
803
- value: item,
804
- children: item
805
- }, item))]
806
- })]
807
- }) : null,
808
- mode === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
809
- className: audio_panel_module_css_default.label,
810
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("voice.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
811
- className: audio_panel_module_css_default.input,
812
- value: voice,
813
- onChange: (event) => setVoice(event.target.value),
814
- placeholder: isMiniMaxChannel ? "male-qn-qingse / female-shaonv" : "alloy / 自定义音色"
815
- })]
816
- }) : null,
817
- mode === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1617
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1618
+ className: audio_panel_module_css_default.hint,
1619
+ children: "MiniMax:/v1/voice_design;ElevenLabs:/v1/text-to-voice/design(试听文本 100-1000 字符,过短将自动生成)"
1620
+ }),
1621
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
818
1622
  className: audio_panel_module_css_default.label,
819
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("speed.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1623
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "试听文本" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
820
1624
  className: audio_panel_module_css_default.input,
821
- type: "number",
822
- step: "0.1",
823
- min: "0.5",
824
- max: "2",
825
- value: speed,
826
- onChange: (event) => setSpeed(event.target.value),
827
- placeholder: "1.0"
1625
+ value: previewText,
1626
+ onChange: (event) => setPreviewText(event.target.value),
1627
+ placeholder: "你好,这是新设计的音色试听。"
828
1628
  })]
829
- }) : null,
830
- mode === "tts" && isMiniMaxChannel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
831
- className: audio_panel_module_css_default.advanced,
832
- children: [
833
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "MiniMax 高级参数" }),
834
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1629
+ })
1630
+ ] }) : null,
1631
+ needModel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1632
+ className: audio_panel_module_css_default.label,
1633
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [tt("model.label"), "(可多选,同一提示词逐个生成以对比)"] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1634
+ className: audio_panel_module_css_default.modelCheckList,
1635
+ children: [visibleModels.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1636
+ className: audio_panel_module_css_default.hint,
1637
+ children: "(当前模式暂无可用模型)"
1638
+ }) : null, visibleModels.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1639
+ className: audio_panel_module_css_default.checkbox,
1640
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1641
+ type: "checkbox",
1642
+ checked: selectedModels.includes(item),
1643
+ onChange: (event) => {
1644
+ const checked = event.target.checked;
1645
+ setSelectedModels((current) => checked ? [.../* @__PURE__ */ new Set([...current, item])] : current.filter((alias) => alias !== item));
1646
+ if (checked && (model === "" || !visibleModels.includes(model))) setModel(item);
1647
+ }
1648
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1649
+ title: "点击生成对比",
1650
+ children: item
1651
+ })]
1652
+ }, item))]
1653
+ })]
1654
+ }) : null,
1655
+ needModel && selectedModels.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
1656
+ className: audio_panel_module_css_default.advanced,
1657
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "每模型参数覆盖(默认自动:沿用上方相同配置,如输出格式均为 mp3)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1658
+ className: audio_panel_module_css_default.overrideTable,
1659
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1660
+ className: audio_panel_module_css_default.overrideRow,
1661
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: `${audio_panel_module_css_default.overrideCell} ${audio_panel_module_css_default.overrideCellHead}` }), selectedModels.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1662
+ className: `${audio_panel_module_css_default.overrideCell} ${audio_panel_module_css_default.overrideCellHead}`,
1663
+ children: item
1664
+ }, item))]
1665
+ }), OVERRIDE_ROWS.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1666
+ className: audio_panel_module_css_default.overrideRow,
1667
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1668
+ className: audio_panel_module_css_default.overrideCell,
1669
+ title: row.label,
1670
+ children: row.label
1671
+ }), selectedModels.map((item) => {
1672
+ const value = overrides[item]?.[row.key] ?? "";
1673
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1674
+ className: audio_panel_module_css_default.overrideCell,
1675
+ children: row.type === "select" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1676
+ className: audio_panel_module_css_default.input,
1677
+ value,
1678
+ onChange: (event) => setOverrideValue(item, row.key, event.target.value),
1679
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1680
+ value: "",
1681
+ children: "自动"
1682
+ }), row.options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1683
+ value: option,
1684
+ children: option
1685
+ }, option))]
1686
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1687
+ className: audio_panel_module_css_default.input,
1688
+ type: row.type === "number" ? "number" : "text",
1689
+ value,
1690
+ placeholder: row.placeholder ?? "自动",
1691
+ onChange: (event) => setOverrideValue(item, row.key, event.target.value)
1692
+ })
1693
+ }, item);
1694
+ })]
1695
+ }, row.key))]
1696
+ })]
1697
+ }) : null,
1698
+ mode === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1699
+ className: audio_panel_module_css_default.label,
1700
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("voice.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1701
+ className: audio_panel_module_css_default.input,
1702
+ value: voice,
1703
+ onChange: (event) => setVoice(event.target.value),
1704
+ placeholder: isMiniMaxChannel ? "male-qn-qingse / female-shaonv" : "alloy / 自定义音色"
1705
+ })]
1706
+ }) : null,
1707
+ mode === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1708
+ className: audio_panel_module_css_default.label,
1709
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("speed.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1710
+ className: audio_panel_module_css_default.input,
1711
+ type: "number",
1712
+ step: "0.1",
1713
+ min: "0.5",
1714
+ max: "2",
1715
+ value: speed,
1716
+ onChange: (event) => setSpeed(event.target.value),
1717
+ placeholder: "1.0"
1718
+ })]
1719
+ }) : null,
1720
+ mode === "tts" && isMiniMaxChannel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
1721
+ className: audio_panel_module_css_default.advanced,
1722
+ children: [
1723
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "MiniMax 高级参数" }),
1724
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1725
+ className: audio_panel_module_css_default.label,
1726
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "情绪 emotion" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1727
+ className: audio_panel_module_css_default.input,
1728
+ value: emotion,
1729
+ onChange: (event) => setEmotion(event.target.value),
1730
+ placeholder: "happy / sad / angry / nervous…"
1731
+ })]
1732
+ }),
1733
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1734
+ className: audio_panel_module_css_default.row,
1735
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
835
1736
  className: audio_panel_module_css_default.label,
836
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "情绪 emotion" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1737
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "音量 vol (0-10)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
837
1738
  className: audio_panel_module_css_default.input,
838
- value: emotion,
839
- onChange: (event) => setEmotion(event.target.value),
840
- placeholder: "happy / sad / angry / nervous…"
1739
+ type: "number",
1740
+ min: "0",
1741
+ max: "10",
1742
+ step: "0.5",
1743
+ value: vol,
1744
+ onChange: (event) => setVol(event.target.value),
1745
+ placeholder: "1"
841
1746
  })]
842
- }),
843
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
844
- className: audio_panel_module_css_default.row,
845
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1747
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1748
+ className: audio_panel_module_css_default.label,
1749
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "音调 pitch (-12~12)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1750
+ className: audio_panel_module_css_default.input,
1751
+ type: "number",
1752
+ min: "-12",
1753
+ max: "12",
1754
+ value: pitch,
1755
+ onChange: (event) => setPitch(event.target.value),
1756
+ placeholder: "0"
1757
+ })]
1758
+ })]
1759
+ }),
1760
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1761
+ className: audio_panel_module_css_default.row,
1762
+ children: [
1763
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
846
1764
  className: audio_panel_module_css_default.label,
847
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "音量 vol (0-10)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1765
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "采样率" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
848
1766
  className: audio_panel_module_css_default.input,
849
1767
  type: "number",
850
- min: "0",
851
- max: "10",
852
- step: "0.5",
853
- value: vol,
854
- onChange: (event) => setVol(event.target.value),
855
- placeholder: "1"
1768
+ min: "16000",
1769
+ max: "48000",
1770
+ step: "8000",
1771
+ value: sampleRate,
1772
+ onChange: (event) => setSampleRate(event.target.value),
1773
+ placeholder: "32000"
856
1774
  })]
857
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1775
+ }),
1776
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
858
1777
  className: audio_panel_module_css_default.label,
859
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "音调 pitch (-12~12)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1778
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "码率 bps" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
860
1779
  className: audio_panel_module_css_default.input,
861
1780
  type: "number",
862
- min: "-12",
863
- max: "12",
864
- value: pitch,
865
- onChange: (event) => setPitch(event.target.value),
866
- placeholder: "0"
1781
+ min: "64000",
1782
+ max: "320000",
1783
+ step: "8000",
1784
+ value: bitrate,
1785
+ onChange: (event) => setBitrate(event.target.value),
1786
+ placeholder: "128000"
867
1787
  })]
868
- })]
869
- }),
870
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
871
- className: audio_panel_module_css_default.row,
872
- children: [
873
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
874
- className: audio_panel_module_css_default.label,
875
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "采样率" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
876
- className: audio_panel_module_css_default.input,
877
- type: "number",
878
- min: "16000",
879
- max: "48000",
880
- step: "8000",
881
- value: sampleRate,
882
- onChange: (event) => setSampleRate(event.target.value),
883
- placeholder: "32000"
884
- })]
885
- }),
886
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
887
- className: audio_panel_module_css_default.label,
888
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "码率 bps" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
889
- className: audio_panel_module_css_default.input,
890
- type: "number",
891
- min: "64000",
892
- max: "320000",
893
- step: "8000",
894
- value: bitrate,
895
- onChange: (event) => setBitrate(event.target.value),
896
- placeholder: "128000"
897
- })]
898
- }),
899
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
900
- className: audio_panel_module_css_default.label,
901
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "声道" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
902
- className: audio_panel_module_css_default.select,
903
- value: audioChannel,
904
- onChange: (event) => setAudioChannel(event.target.value),
905
- children: [
906
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
907
- value: "",
908
- children: "默认(1)"
909
- }),
910
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
911
- value: "1",
912
- children: "1"
913
- }),
914
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
915
- value: "2",
916
- children: "2"
917
- })
918
- ]
919
- })]
920
- })
921
- ]
922
- }),
923
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
924
- className: audio_panel_module_css_default.label,
925
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "发音词典(每行一条:\"文字/读音\")" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
926
- className: audio_panel_module_css_default.textarea,
927
- value: toneText,
928
- onChange: (event) => setToneText(event.target.value),
929
- placeholder: "处理/(chu3)(li3)\n危险/dangerous"
930
- })]
931
- }),
932
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
933
- className: audio_panel_module_css_default.checkbox,
934
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
935
- type: "checkbox",
936
- checked: subtitle,
937
- onChange: (event) => setSubtitle(event.target.checked)
938
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "生成字幕 subtitle_enable" })]
939
- })
940
- ]
941
- }) : null,
942
- mode === "music" || mode === "sfx" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
943
- className: audio_panel_module_css_default.label,
944
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("duration.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
945
- className: audio_panel_module_css_default.input,
946
- type: "number",
947
- step: "1",
948
- min: "1",
949
- max: "120",
950
- value: duration,
951
- onChange: (event) => setDuration(event.target.value),
952
- placeholder: "30"
953
- })]
954
- }) : null,
955
- mode === "sfx" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
956
- className: audio_panel_module_css_default.checkbox,
957
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
958
- type: "checkbox",
959
- checked: loop,
960
- onChange: (event) => setLoop(event.target.checked)
961
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "循环音效 loop(无缝循环,需 eleven_text_to_sound_v2)" })]
962
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
963
- className: audio_panel_module_css_default.label,
964
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "提示词影响度 prompt_influence (0-1)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
965
- className: audio_panel_module_css_default.input,
966
- type: "number",
967
- step: "0.1",
968
- min: "0",
969
- max: "1",
970
- value: promptInfluence,
971
- onChange: (event) => setPromptInfluence(event.target.value),
972
- placeholder: "0.3"
973
- })]
974
- })] }) : null,
975
- mode === "music" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1788
+ }),
1789
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1790
+ className: audio_panel_module_css_default.label,
1791
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "声道" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1792
+ className: audio_panel_module_css_default.input,
1793
+ value: audioChannel,
1794
+ onChange: (event) => setAudioChannel(event.target.value),
1795
+ children: [
1796
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1797
+ value: "",
1798
+ children: "默认(1)"
1799
+ }),
1800
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1801
+ value: "1",
1802
+ children: "1"
1803
+ }),
1804
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1805
+ value: "2",
1806
+ children: "2"
1807
+ })
1808
+ ]
1809
+ })]
1810
+ })
1811
+ ]
1812
+ }),
976
1813
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
977
1814
  className: audio_panel_module_css_default.label,
978
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "歌词(纯音乐模式可留空;多段用空行分隔)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1815
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "发音词典(每行一条:\"文字/读音\")" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
979
1816
  className: audio_panel_module_css_default.textarea,
980
- value: lyrics,
981
- onChange: (event) => setLyrics(event.target.value),
982
- placeholder: "第一段歌词…\n\n第二段歌词…"
1817
+ value: toneText,
1818
+ onChange: (event) => setToneText(event.target.value),
1819
+ placeholder: "处理/(chu3)(li3)\n危险/dangerous"
983
1820
  })]
984
1821
  }),
985
1822
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
986
1823
  className: audio_panel_module_css_default.checkbox,
987
1824
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
988
1825
  type: "checkbox",
989
- checked: instrumental,
990
- onChange: (event) => setInstrumental(event.target.checked)
991
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "纯音乐(无歌词/人声)is_instrumental" })]
992
- }),
993
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
994
- className: audio_panel_module_css_default.row,
995
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
996
- className: audio_panel_module_css_default.label,
997
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "采样率" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
998
- className: audio_panel_module_css_default.select,
999
- value: sampleRate,
1000
- onChange: (event) => setSampleRate(event.target.value),
1001
- children: [
1002
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1003
- value: "",
1004
- children: "默认(44100)"
1005
- }),
1006
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1007
- value: "16000",
1008
- children: "16000"
1009
- }),
1010
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1011
- value: "24000",
1012
- children: "24000"
1013
- }),
1014
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1015
- value: "32000",
1016
- children: "32000"
1017
- }),
1018
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1019
- value: "44100",
1020
- children: "44100"
1021
- })
1022
- ]
1023
- })]
1024
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1025
- className: audio_panel_module_css_default.label,
1026
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "码率 bps" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1027
- className: audio_panel_module_css_default.select,
1028
- value: bitrate,
1029
- onChange: (event) => setBitrate(event.target.value),
1030
- children: [
1031
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1032
- value: "",
1033
- children: "默认(256000)"
1034
- }),
1035
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1036
- value: "32000",
1037
- children: "32000"
1038
- }),
1039
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1040
- value: "64000",
1041
- children: "64000"
1042
- }),
1043
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1044
- value: "128000",
1045
- children: "128000"
1046
- }),
1047
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1048
- value: "256000",
1049
- children: "256000"
1050
- })
1051
- ]
1052
- })]
1053
- })]
1826
+ checked: subtitle,
1827
+ onChange: (event) => setSubtitle(event.target.checked)
1828
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "生成字幕 subtitle_enable" })]
1054
1829
  })
1055
- ] }) : null,
1056
- needModel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1830
+ ]
1831
+ }) : null,
1832
+ mode === "music" || mode === "sfx" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1833
+ className: audio_panel_module_css_default.label,
1834
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("duration.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1835
+ className: audio_panel_module_css_default.input,
1836
+ type: "number",
1837
+ step: "1",
1838
+ min: "1",
1839
+ max: "120",
1840
+ value: duration,
1841
+ onChange: (event) => setDuration(event.target.value),
1842
+ placeholder: "30"
1843
+ })]
1844
+ }) : null,
1845
+ mode === "sfx" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1846
+ className: audio_panel_module_css_default.checkbox,
1847
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1848
+ type: "checkbox",
1849
+ checked: loop,
1850
+ onChange: (event) => setLoop(event.target.checked)
1851
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "循环音效 loop(无缝循环,需 eleven_text_to_sound_v2)" })]
1852
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1853
+ className: audio_panel_module_css_default.label,
1854
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "提示词影响度 prompt_influence (0-1)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1855
+ className: audio_panel_module_css_default.input,
1856
+ type: "number",
1857
+ step: "0.1",
1858
+ min: "0",
1859
+ max: "1",
1860
+ value: promptInfluence,
1861
+ onChange: (event) => setPromptInfluence(event.target.value),
1862
+ placeholder: "0.3"
1863
+ })]
1864
+ })] }) : null,
1865
+ mode === "music" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1866
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1057
1867
  className: audio_panel_module_css_default.label,
1058
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("format.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1059
- className: audio_panel_module_css_default.select,
1060
- value: format,
1061
- onChange: (event) => setFormat(event.target.value),
1062
- children: [
1063
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1064
- value: "mp3",
1065
- children: "mp3"
1066
- }),
1067
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1068
- value: "wav",
1069
- children: "wav"
1070
- }),
1071
- mode === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1072
- value: "flac",
1073
- children: "flac"
1074
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1075
- value: "ogg",
1076
- children: "ogg"
1077
- })] }) : null,
1078
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1079
- value: "pcm",
1080
- children: "pcm"
1081
- })
1082
- ]
1868
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "歌词(纯音乐模式可留空;多段用空行分隔)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1869
+ className: audio_panel_module_css_default.textarea,
1870
+ value: lyrics,
1871
+ onChange: (event) => setLyrics(event.target.value),
1872
+ placeholder: "第一段歌词…\n\n第二段歌词…"
1083
1873
  })]
1084
- }) : null,
1085
- !connected && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1086
- className: audio_panel_module_css_default.hint,
1087
- children: tt("config.missing")
1088
1874
  }),
1089
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1090
- type: "button",
1091
- className: audio_panel_module_css_default.generate,
1092
- disabled: loading || !connected || needModel && visibleModels.length === 0,
1093
- onClick: () => void submit(),
1094
- children: loading ? tt("generating") : tt("generate")
1875
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1876
+ className: audio_panel_module_css_default.checkbox,
1877
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1878
+ type: "checkbox",
1879
+ checked: instrumental,
1880
+ onChange: (event) => setInstrumental(event.target.checked)
1881
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "纯音乐(无歌词/人声)is_instrumental" })]
1882
+ }),
1883
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1884
+ className: audio_panel_module_css_default.row,
1885
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1886
+ className: audio_panel_module_css_default.label,
1887
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "采样率" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1888
+ className: audio_panel_module_css_default.input,
1889
+ value: sampleRate,
1890
+ onChange: (event) => setSampleRate(event.target.value),
1891
+ children: [
1892
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1893
+ value: "",
1894
+ children: "默认(44100)"
1895
+ }),
1896
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1897
+ value: "16000",
1898
+ children: "16000"
1899
+ }),
1900
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1901
+ value: "24000",
1902
+ children: "24000"
1903
+ }),
1904
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1905
+ value: "32000",
1906
+ children: "32000"
1907
+ }),
1908
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1909
+ value: "44100",
1910
+ children: "44100"
1911
+ })
1912
+ ]
1913
+ })]
1914
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1915
+ className: audio_panel_module_css_default.label,
1916
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "码率 bps" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1917
+ className: audio_panel_module_css_default.input,
1918
+ value: bitrate,
1919
+ onChange: (event) => setBitrate(event.target.value),
1920
+ children: [
1921
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1922
+ value: "",
1923
+ children: "默认(256000)"
1924
+ }),
1925
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1926
+ value: "32000",
1927
+ children: "32000"
1928
+ }),
1929
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1930
+ value: "64000",
1931
+ children: "64000"
1932
+ }),
1933
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1934
+ value: "128000",
1935
+ children: "128000"
1936
+ }),
1937
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1938
+ value: "256000",
1939
+ children: "256000"
1940
+ })
1941
+ ]
1942
+ })]
1943
+ })]
1095
1944
  })
1096
- ]
1097
- }),
1098
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1099
- className: audio_panel_module_css_default.result,
1100
- children: [error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1101
- className: audio_panel_module_css_default.error,
1102
- children: error
1103
- }) : null, outputs.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1104
- className: audio_panel_module_css_default.empty,
1105
- children: tt("result.empty")
1106
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1107
- className: audio_panel_module_css_default.hint,
1108
- children: tt("result.done", { count: outputs.length })
1109
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1110
- className: audio_panel_module_css_default.audioList,
1111
- children: outputs.map((audio, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1112
- className: audio_panel_module_css_default.audioCard,
1945
+ ] }) : null,
1946
+ needModel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1947
+ className: audio_panel_module_css_default.label,
1948
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("format.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1949
+ className: audio_panel_module_css_default.input,
1950
+ value: format,
1951
+ onChange: (event) => setFormat(event.target.value),
1113
1952
  children: [
1114
- audio.voiceId !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1115
- className: audio_panel_module_css_default.hint,
1116
- children: ["新音色 ID:", audio.voiceId]
1117
- }) : null,
1118
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
1119
- className: audio_panel_module_css_default.audio,
1120
- controls: true,
1121
- preload: "metadata",
1122
- src: dataUrlOf(audio)
1953
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1954
+ value: "mp3",
1955
+ children: "mp3"
1123
1956
  }),
1124
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
1125
- className: audio_panel_module_css_default.download,
1126
- href: dataUrlOf(audio),
1127
- download: `generated-${index + 1}.${audio.mime.split("/")[1]?.replace("mpeg", "mp3") ?? "mp3"}`,
1128
- children: "下载"
1957
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1958
+ value: "wav",
1959
+ children: "wav"
1960
+ }),
1961
+ mode === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1962
+ value: "flac",
1963
+ children: "flac"
1964
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1965
+ value: "ogg",
1966
+ children: "ogg"
1967
+ })] }) : null,
1968
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1969
+ value: "pcm",
1970
+ children: "pcm"
1129
1971
  })
1130
1972
  ]
1131
- }, audio.id))
1132
- })] })]
1133
- }),
1134
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
1135
- className: audio_panel_module_css_default.history,
1136
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1137
- className: audio_panel_module_css_default.historyHeader,
1138
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
1139
- className: audio_panel_module_css_default.historyTitle,
1140
- children: tt("history.title")
1141
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1142
- type: "button",
1143
- onClick: clear,
1144
- style: {
1145
- border: 0,
1146
- background: "none",
1147
- cursor: "pointer",
1148
- color: "inherit",
1149
- fontSize: 12
1150
- },
1151
- children: "清空"
1152
1973
  })]
1153
- }), entries.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1154
- className: audio_panel_module_css_default.historyEmpty,
1155
- children: tt("history.empty")
1156
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: entries.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1974
+ }) : null,
1975
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1976
+ className: audio_panel_module_css_default.checkbox,
1977
+ title: "生成完成后自动保存到资源库;也可在设置中开启全部自动保存",
1978
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1979
+ type: "checkbox",
1980
+ checked: saveToLibrary,
1981
+ onChange: (event) => setSaveToLibrary(event.target.checked)
1982
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "生成后保存到资源库" })]
1983
+ }),
1984
+ !connected && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1985
+ className: audio_panel_module_css_default.hint,
1986
+ children: tt("config.missing")
1987
+ }),
1988
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1989
+ type: "button",
1990
+ className: audio_panel_module_css_default.generate,
1991
+ disabled: loading || !connected || needModel && visibleModels.length === 0,
1992
+ onClick: () => void submit(),
1993
+ children: loading ? progress !== "" ? progress : tt("generating") : tt("generate")
1994
+ })
1995
+ ]
1996
+ }),
1997
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1998
+ className: audio_panel_module_css_default.resultCol,
1999
+ children: [error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2000
+ className: audio_panel_module_css_default.error,
2001
+ children: error
2002
+ }) : null, results.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2003
+ className: audio_panel_module_css_default.resultEmpty,
2004
+ children: [
2005
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2006
+ className: audio_panel_module_css_default.resultEmptyIcon,
2007
+ children: "🎵"
2008
+ }),
2009
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: tt("result.empty") }),
2010
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2011
+ className: audio_panel_module_css_default.resultEmptyHint,
2012
+ children: "生成结果将在这里播放、下载,并可一键加入资源库"
2013
+ })
2014
+ ]
2015
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2016
+ className: audio_panel_module_css_default.resultMeta,
2017
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("result.done", { count: results.reduce((sum, group) => sum + group.outputs.length, 0) }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2018
+ className: audio_panel_module_css_default.resultModeChip,
2019
+ children: modeLabel
2020
+ })]
2021
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2022
+ className: audio_panel_module_css_default.resultGroups,
2023
+ children: results.map((group, groupIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2024
+ className: audio_panel_module_css_default.resultGroup,
2025
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2026
+ className: audio_panel_module_css_default.resultGroupHead,
2027
+ children: [
2028
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2029
+ className: audio_panel_module_css_default.resultGroupChip,
2030
+ children: group.model || "音色设计"
2031
+ }),
2032
+ group.error !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2033
+ className: audio_panel_module_css_default.resultGroupError,
2034
+ children: ["生成失败:", group.error]
2035
+ }) : null,
2036
+ group.outputs.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2037
+ className: audio_panel_module_css_default.resultGroupCount,
2038
+ children: [group.outputs.length, " 段"]
2039
+ }) : null
2040
+ ]
2041
+ }), group.outputs.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2042
+ className: audio_panel_module_css_default.audioList,
2043
+ children: group.outputs.map((audio, index) => {
2044
+ const saved = savedIds.has(audio.id);
2045
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2046
+ className: audio_panel_module_css_default.audioCard,
2047
+ "data-saved": saved ? "true" : "false",
2048
+ children: [
2049
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2050
+ className: audio_panel_module_css_default.audioCardHead,
2051
+ children: [
2052
+ audio.voiceId !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2053
+ className: audio_panel_module_css_default.voiceIdChip,
2054
+ title: "新音色 ID",
2055
+ children: ["新音色 ", audio.voiceId]
2056
+ }) : null,
2057
+ saved ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2058
+ className: audio_panel_module_css_default.savedChip,
2059
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}), " 已入库"]
2060
+ }) : null,
2061
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2062
+ className: audio_panel_module_css_default.audioCardIndex,
2063
+ children: ["#", index + 1]
2064
+ })
2065
+ ]
2066
+ }),
2067
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPlayer, {
2068
+ src: dataUrlOf(audio),
2069
+ itemKey: audio.id
2070
+ }),
2071
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2072
+ className: audio_panel_module_css_default.audioCardActions,
2073
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
2074
+ className: audio_panel_module_css_default.ghostButton,
2075
+ href: dataUrlOf(audio),
2076
+ download: `generated-${groupIndex + 1}-${index + 1}.${audio.mime.split("/")[1]?.replace("mpeg", "mp3") ?? "mp3"}`,
2077
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DownloadIcon, {}), " 下载"]
2078
+ }), saved ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2079
+ type: "button",
2080
+ className: audio_panel_module_css_default.ghostButton,
2081
+ onClick: () => props.showToast("该音频已加入资源库"),
2082
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}), " 已入库"]
2083
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2084
+ type: "button",
2085
+ className: audio_panel_module_css_default.ghostButton,
2086
+ onClick: () => openSaveDialog([audio], {
2087
+ mode,
2088
+ prompt: prompt.trim(),
2089
+ ...voice.trim() !== "" ? { voice: voice.trim() } : {},
2090
+ ...audio.voiceId === void 0 ? {} : { voiceId: audio.voiceId },
2091
+ ...group.model !== "" ? { model: group.model } : {},
2092
+ ...channels.length > 0 ? { channel: channels.find((candidate) => candidate.id === (mode === "voice_design" ? designChannelId : modelOptions.defaultChannelId))?.name ?? channels[0]?.name ?? "" } : {},
2093
+ params: {
2094
+ mode,
2095
+ model: mode === "voice_design" ? "" : group.model,
2096
+ prompt: prompt.trim(),
2097
+ ...voice.trim() !== "" ? { voice: voice.trim() } : {},
2098
+ ...speed.trim() !== "" ? { speed: Number(speed) } : {},
2099
+ ...duration.trim() !== "" ? { duration: Number(duration) } : {},
2100
+ ...format.trim() !== "" ? { format: format.trim() } : {}
2101
+ }
2102
+ }),
2103
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StarIcon, {}), " 加入资源库"]
2104
+ })]
2105
+ })
2106
+ ]
2107
+ }, audio.id);
2108
+ })
2109
+ }) : null]
2110
+ }, `${group.model}-${groupIndex}`))
2111
+ })] })]
2112
+ }),
2113
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
2114
+ className: audio_panel_module_css_default.historyCol,
2115
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2116
+ className: audio_panel_module_css_default.historyHeader,
2117
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
2118
+ className: audio_panel_module_css_default.historyTitle,
2119
+ children: tt("history.title")
2120
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2121
+ type: "button",
2122
+ className: audio_panel_module_css_default.historyClear,
2123
+ onClick: clear,
2124
+ children: "清空"
2125
+ })]
2126
+ }), entries.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2127
+ className: audio_panel_module_css_default.historyEmpty,
2128
+ children: tt("history.empty")
2129
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2130
+ className: audio_panel_module_css_default.historyList,
2131
+ children: entries.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1157
2132
  className: audio_panel_module_css_default.historyItem,
1158
2133
  children: [
1159
2134
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -1169,192 +2144,1135 @@ window.__ModuleLoader__.load({
1169
2144
  entry.channel ? ` · ${entry.channel}` : ""
1170
2145
  ]
1171
2146
  }),
1172
- entry.audio.map((audio, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
1173
- className: audio_panel_module_css_default.historyAudio,
1174
- controls: true,
1175
- preload: "none",
1176
- src: audio.url
1177
- }, index))
2147
+ entry.audio.map((audio, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPlayer, {
2148
+ src: audio.url,
2149
+ compact: true,
2150
+ itemKey: `${entry.id}-${index}`
2151
+ }, index)),
2152
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2153
+ className: audio_panel_module_css_default.historyActions,
2154
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2155
+ type: "button",
2156
+ className: audio_panel_module_css_default.historyAction,
2157
+ onClick: () => openSaveDialog(audioRefsOfEntry(entry), contextOfEntry(entry)),
2158
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StarIcon, {}), " 入库"]
2159
+ })
2160
+ })
1178
2161
  ]
1179
- }, entry.id)) })]
1180
- })
1181
- ]
1182
- })]
2162
+ }, entry.id))
2163
+ })]
2164
+ }),
2165
+ saveDialog !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LibrarySaveDialog, {
2166
+ api,
2167
+ files: saveDialog.files,
2168
+ context: saveDialog.context,
2169
+ onClose: () => setSaveDialog(null),
2170
+ onSaved: onDialogSaved
2171
+ }) : null
2172
+ ]
1183
2173
  });
1184
2174
  }
1185
2175
  //#endregion
1186
- //#region \0dsh-css:/Users/shimingming/Projects_code/dsh-audiogen/src/client/panel.module.css.mjs
1187
- const css$2 = "[data-pane=conversation],[class*=centerCol]{position:relative}[data-dsh-audiogen-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0}html[data-dsh-audiogen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-dsh-audiogen-view]{display:block}html[data-dsh-audiogen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-pane=conversation]>:not([data-dsh-audiogen-view]),html[data-dsh-audiogen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [class*=centerCol]>:not([data-dsh-audiogen-view]){display:none!important}.rwa6qG_entry{width:100%;height:32px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:8px;padding:0 12px;font-size:13px;display:flex}.rwa6qG_entry:hover{background:var(--dsw-specific-sidebar-nav-item-hover);color:var(--dsw-alias-label-primary)}.rwa6qG_entry[data-active]{background:var(--dsw-specific-sidebar-nav-item-active);color:var(--dsw-alias-label-primary);font-weight:600}.rwa6qG_entryIcon{flex:none;justify-content:center;align-items:center;display:inline-flex}.rwa6qG_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] .rwa6qG_entry{justify-content:center;width:100%;padding:0}[data-dsh-frame][data-sidebar-collapsed] .rwa6qG_entryLabel{display:none}.rwa6qG_view{overflow:hidden}.rwa6qG_panel,.rwa6qG_panel *,.rwa6qG_panel :before,.rwa6qG_panel :after{box-sizing:border-box}.rwa6qG_panel{background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:10px;padding:14px 16px 16px;display:flex;position:relative;overflow:hidden}.rwa6qG_panelHeader{flex:none;justify-content:space-between;align-items:center;gap:12px;display:flex}.rwa6qG_panelHeading{align-items:baseline;gap:10px;min-width:0;display:flex}.rwa6qG_panelTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:16px;font-weight:700}.rwa6qG_githubLink{width:22px;height:22px;color:var(--dsw-alias-label-secondary);border-radius:6px;flex:none;justify-content:center;align-items:center;text-decoration:none;transition:color .12s,background .12s;display:inline-flex}.rwa6qG_githubLink:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.rwa6qG_connectionStatus{border:1px solid var(--dsw-alias-label-error);height:28px;color:var(--dsw-alias-label-error);font:inherit;white-space:nowrap;background:0 0;border-radius:8px;flex:none;align-items:center;gap:6px;padding:0 10px;font-size:12px;line-height:1;display:inline-flex}.rwa6qG_connectionStatus[data-connected=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.rwa6qG_connectionDot{background:currentColor;border-radius:50%;width:6px;height:6px}.rwa6qG_updateBanner{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-primary);overflow-wrap:anywhere;border-radius:10px;flex:none;justify-content:space-between;align-items:center;gap:12px;padding:7px 10px 7px 12px;font-size:12px;line-height:1.5;display:flex}.rwa6qG_updateBanner[data-kind=ok]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.rwa6qG_updateText{min-width:0}.rwa6qG_updateActions{flex:none;align-items:center;gap:10px;display:inline-flex}.rwa6qG_updateRelease{color:inherit;text-underline-offset:2px;white-space:nowrap;text-decoration:underline}@media (width<=700px){.rwa6qG_panelHeader{align-items:flex-start}.rwa6qG_panelHeading{flex-direction:column;align-items:flex-start;gap:2px}.rwa6qG_updateBanner{flex-direction:column;align-items:flex-start}.rwa6qG_updateActions{justify-content:space-between;width:100%}}.rwa6qG_studio{flex:1;gap:14px;min-width:0;min-height:0;display:flex}.rwa6qG_config{flex-direction:column;flex:none;gap:12px;width:300px;min-width:260px;max-width:340px;height:100%;min-height:0;display:flex;overflow:hidden}.rwa6qG_configScroll{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:12px;min-height:0;padding-right:2px;display:flex;overflow-y:auto}.rwa6qG_configScroll::-webkit-scrollbar{width:8px}.rwa6qG_configScroll::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.rwa6qG_canvas{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:12px;flex-direction:column;flex:1;min-width:0;min-height:0;display:flex;position:relative;overflow:hidden}.rwa6qG_taskTray{z-index:6;border:1px solid var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-bg-layer-1) 92%, transparent);backdrop-filter:blur(10px);border-radius:9px;flex-direction:column;width:min(360px,100% - 24px);max-height:calc(100% - 24px);display:flex;position:absolute;top:12px;right:12px;overflow:hidden;box-shadow:0 8px 24px #0000001f}.rwa6qG_taskTray[data-open=false]{width:auto;max-width:calc(100% - 24px)}.rwa6qG_taskTrayHeader{min-height:34px;color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);align-items:stretch;font-size:12px;font-weight:600;display:flex}.rwa6qG_taskTray[data-open=false] .rwa6qG_taskTrayHeader{border-bottom:0}.rwa6qG_taskTrayToggle{min-width:0;color:inherit;cursor:pointer;font:inherit;font-size:inherit;font-weight:inherit;text-align:left;background:0 0;border:0;flex:1;align-items:center;gap:8px;padding:8px 10px;display:flex}.rwa6qG_taskTrayToggle:hover{background:var(--dsw-alias-bg-layer-2)}.rwa6qG_taskTrayCount{min-width:18px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);text-align:center;border-radius:999px;padding:1px 5px;font-size:11px;font-weight:500}.rwa6qG_taskTrayChevron{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:12px;font-weight:400}.rwa6qG_taskTrayClose{border:0;border-left:1px solid var(--dsw-alias-border-l1);width:32px;color:var(--dsw-alias-label-tertiary);cursor:pointer;font:inherit;background:0 0;font-size:17px}.rwa6qG_taskTrayClose:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.rwa6qG_taskTray[data-open=false] .rwa6qG_taskTrayToggle{min-height:34px}.rwa6qG_taskRows{min-height:0;overflow-y:auto}.rwa6qG_taskTray[data-open=false] .rwa6qG_taskRows{display:none}.rwa6qG_taskRow{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:7px;padding:7px 10px;display:grid}.rwa6qG_taskRow:first-of-type{border-top:0}.rwa6qG_taskStatus{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:11px}.rwa6qG_taskRow[data-status=running] .rwa6qG_taskStatus{color:var(--dsw-alias-brand-primary)}.rwa6qG_taskRow[data-status=failed] .rwa6qG_taskStatus{color:var(--dsw-alias-label-error)}.rwa6qG_taskPrompt{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.rwa6qG_taskRow button{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);cursor:pointer;font:inherit;border:0;border-radius:5px;padding:2px 7px;font-size:11px}.rwa6qG_taskRow button:hover{color:var(--dsw-alias-brand-primary)}.rwa6qG_configGuide{z-index:1100;background:#00000059;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.rwa6qG_configGuideBody{border:1px solid var(--dsw-alias-border-l2);width:min(360px,100%);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border-radius:10px;flex-direction:column;gap:12px;padding:18px;display:flex;box-shadow:0 14px 40px #0003}.rwa6qG_configGuideBody span{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.55}.rwa6qG_configGuideBody button{min-height:30px;color:var(--dsw-alias-bg-layer-1);background:var(--dsw-alias-brand-primary);cursor:pointer;font:inherit;border:0;border-radius:7px;align-self:flex-end;padding:0 12px;font-size:12px}.rwa6qG_history{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:12px;flex-direction:column;flex:none;width:240px;min-width:200px;max-width:280px;min-height:0;display:flex;overflow:hidden}.rwa6qG_historyHeader{border-bottom:1px solid var(--dsw-alias-border-l1);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:10px 12px;display:flex}.rwa6qG_historyFilters{border-bottom:1px solid var(--dsw-alias-border-l1);grid-template-columns:1fr 1fr;gap:6px;padding:8px 10px;display:grid}.rwa6qG_historySearch,.rwa6qG_historyFilters select,.rwa6qG_gallerySearch{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);min-width:0;min-height:29px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;border-radius:7px;padding:0 8px;font-size:11px}.rwa6qG_historySearch{grid-column:1/-1}.rwa6qG_gallerySearch{width:156px}.rwa6qG_galleryTagInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);width:130px;min-height:29px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;border-radius:7px;padding:0 8px;font-size:11px}.rwa6qG_galleryBulkButton{border:1px solid var(--dsw-alias-border-l2);min-height:29px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);cursor:pointer;font:inherit;border-radius:7px;padding:0 8px;font-size:11px}.rwa6qG_galleryBulkButton:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.rwa6qG_galleryBulkButton:disabled{opacity:.45;cursor:default}.rwa6qG_historyTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.rwa6qG_historyClear{font:inherit;color:var(--dsw-alias-label-tertiary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:999px;padding:2px 8px;font-size:11.5px}.rwa6qG_historyClear:hover{color:var(--dsw-alias-label-error);border-color:var(--dsw-alias-label-error)}.rwa6qG_historyList{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:8px;min-height:0;padding:10px;display:flex;overflow-y:auto}.rwa6qG_historyList::-webkit-scrollbar{width:8px}.rwa6qG_historyList::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.rwa6qG_historyEmpty{text-align:center;color:var(--dsw-alias-label-tertiary);flex:1;justify-content:center;align-items:center;padding:20px;font-size:12px;line-height:1.6;display:flex}.rwa6qG_historyItem{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);border-radius:10px;flex-direction:column;flex:none;gap:6px;padding:8px;display:flex}.rwa6qG_historyItem:hover{border-color:var(--dsw-alias-border-l2)}.rwa6qG_historyItem[data-active]{border-color:var(--dsw-alias-brand-primary)}.rwa6qG_historyMain{font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:flex-start;gap:8px;min-width:0;padding:0;display:flex}.rwa6qG_historyThumb{object-fit:cover;background:var(--dsw-alias-bg-base);border-radius:8px;flex:none;width:52px;height:52px}.rwa6qG_historyThumbPlaceholder{background:var(--dsw-alias-bg-layer-3);border-radius:8px;flex:none;width:52px;height:52px}.rwa6qG_historyInfo{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.rwa6qG_historyPrompt{color:var(--dsw-alias-label-primary);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;line-height:1.4;display:-webkit-box;overflow:hidden}.rwa6qG_historyMeta{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.rwa6qG_historyActions{justify-content:flex-end;gap:6px;display:flex}.rwa6qG_historyAction{font:inherit;color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:999px;padding:2px 8px;font-size:11.5px}.rwa6qG_historyAction:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.rwa6qG_historyAction[data-danger]:hover{color:var(--dsw-alias-label-error);border-color:var(--dsw-alias-label-error)}.rwa6qG_card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;flex:none;gap:10px;padding:12px;display:flex}.rwa6qG_modeRow{align-items:center;gap:8px;display:flex}.rwa6qG_modePill{flex:1;justify-content:center;height:28px;font-size:13px}.rwa6qG_uploadBox{min-height:128px;color:var(--dsw-alias-label-secondary);border:1.5px dashed var(--dsw-alias-border-l2);cursor:pointer;font:inherit;text-align:center;background:0 0;border-radius:12px;flex-direction:column;justify-content:center;align-items:center;gap:6px;padding:16px;font-size:12.5px;display:flex}.rwa6qG_uploadBox:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-interactive-bg-hover)}.rwa6qG_uploadBox:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.rwa6qG_uploadIcon{color:var(--dsw-alias-label-tertiary);display:inline-flex}.rwa6qG_uploadHint{color:var(--dsw-alias-label-tertiary);font-size:11px}.rwa6qG_reference{flex-direction:column;gap:8px;display:flex}.rwa6qG_referenceImage{object-fit:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;width:100%;max-height:176px}.rwa6qG_referenceActions{gap:8px;display:flex}.rwa6qG_hiddenFile{display:none}.rwa6qG_prompt{width:100%;min-height:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);resize:vertical;box-sizing:border-box;border-radius:10px;outline:none;padding:10px 12px;font-family:inherit;font-size:13px;line-height:1.6}.rwa6qG_prompt:focus-visible{border-color:var(--dsw-alias-brand-primary)}.rwa6qG_prompt::placeholder{color:var(--dsw-alias-label-tertiary)}.rwa6qG_promptFooter{justify-content:space-between;align-items:center;gap:8px;margin-top:-6px;display:flex}.rwa6qG_templatesButton{border:1px solid var(--dsw-alias-brand-primary);background:linear-gradient(135deg, color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), color-mix(in srgb, var(--dsw-alias-brand-primary) 5%, transparent));height:26px;color:var(--dsw-alias-brand-primary);cursor:pointer;box-shadow:0 1px 0 color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent);border-radius:999px;align-items:center;gap:6px;padding:0 12px;font-family:inherit;font-size:12px;font-weight:600;transition:transform .12s,box-shadow .12s,background .12s;display:inline-flex}.rwa6qG_templatesButton svg{flex:none}.rwa6qG_templatesButton:hover{background:linear-gradient(135deg, color-mix(in srgb, var(--dsw-alias-brand-primary) 24%, transparent), color-mix(in srgb, var(--dsw-alias-brand-primary) 8%, transparent));color:var(--dsw-alias-brand-primary);box-shadow:0 2px 6px color-mix(in srgb, var(--dsw-alias-brand-primary) 30%, transparent);transform:translateY(-1px)}.rwa6qG_templatesButton:active{transform:translateY(0)}.rwa6qG_enhanceButton{border:1px solid var(--dsw-alias-border-l2);height:26px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:999px;margin-left:auto;padding:0 11px;font-size:12px}.rwa6qG_enhanceButton:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.rwa6qG_enhanceButton:disabled{opacity:.5;cursor:default}.rwa6qG_promptCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px}.rwa6qG_paramGroup{flex-direction:column;gap:8px;display:flex}.rwa6qG_paramLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.rwa6qG_optionRow{flex-wrap:wrap;gap:6px;display:flex}.rwa6qG_optionGrid{grid-template-columns:repeat(3,1fr);gap:6px;display:grid}.rwa6qG_optionPill{justify-content:center}.rwa6qG_paramHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.45}.rwa6qG_footer{border-top:1px solid var(--dsw-alias-border-l1);flex-direction:column;flex:none;align-items:stretch;gap:8px;padding:10px 2px 0 0;display:flex}.rwa6qG_modelWrap{flex-direction:column;gap:5px;min-width:0;display:flex}.rwa6qG_modelLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.rwa6qG_modelSelect{width:100%;height:36px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;text-align:left;border-radius:18px;outline:none;justify-content:space-between;align-items:center;gap:8px;padding:0 12px;font-family:inherit;font-size:13px;display:flex}.rwa6qG_modelSelect:focus-visible{border-color:var(--dsw-alias-brand-primary)}.rwa6qG_modelSelect:disabled{opacity:.55;cursor:default}.rwa6qG_modelMenu{min-width:0;display:block;position:relative}.rwa6qG_modelMenuList{z-index:40;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;flex-direction:column;padding:4px;display:flex;position:absolute;bottom:calc(100% + 6px);left:0;right:0;overflow:hidden;box-shadow:0 -8px 24px #0000002e}.rwa6qG_modelMenuItem{width:100%;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;white-space:nowrap;text-overflow:ellipsis;background:0 0;border:none;border-radius:8px;padding:7px 10px;font-size:13px;display:block;overflow:hidden}.rwa6qG_modelMenuItem:hover{background:var(--dsw-alias-bg-hover)}.rwa6qG_modelMenuItem[data-selected]{color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-1);font-weight:600}.rwa6qG_generateButton{width:100%}.rwa6qG_generateInner{align-items:center;gap:7px;display:inline-flex}.rwa6qG_canvasState{text-align:center;color:var(--dsw-alias-label-tertiary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:24px;display:flex}.rwa6qG_canvasStateTitle{color:var(--dsw-alias-label-secondary);font-size:14px;font-weight:600}.rwa6qG_canvasStateHint{max-width:380px;font-size:12px;line-height:1.6}.rwa6qG_canvasEmptyIcon{color:var(--dsw-alias-label-tertiary);margin-bottom:4px;display:inline-flex}.rwa6qG_canvasError{color:var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-label-error);overflow-wrap:anywhere;border-radius:10px;flex:none;margin:14px;padding:10px 14px;font-size:12.5px;line-height:1.6}.rwa6qG_canvasBody{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:10px;min-height:0;padding:14px;display:flex;overflow-y:auto}.rwa6qG_canvasBody::-webkit-scrollbar{width:8px}.rwa6qG_canvasBody::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.rwa6qG_canvasMeta{color:var(--dsw-alias-label-tertiary);flex:none;align-items:center;gap:8px;font-size:12px;display:flex}.rwa6qG_canvasHistoryTag{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);white-space:nowrap;border-radius:999px;padding:1px 8px;font-size:11px}.rwa6qG_grid{flex:1;grid-template-rows:repeat(2,minmax(0,1fr));grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;min-height:0;display:grid}.rwa6qG_grid[data-count=\"1\"] .rwa6qG_imageCard{grid-area:1/1/3/3}.rwa6qG_imageCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);cursor:zoom-in;border-radius:12px;flex-direction:column;min-height:0;margin:0;display:flex;position:relative;overflow:hidden}.rwa6qG_imageCard:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.rwa6qG_image{object-fit:cover;background:var(--dsw-alias-bg-base);flex:1;width:100%;min-height:0;display:block}.rwa6qG_imageCaption{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-overflow:ellipsis;border-top:1px solid var(--dsw-alias-border-l1);padding:7px 10px;font-size:11px;line-height:1.5;overflow:hidden}.rwa6qG_download{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);opacity:0;backdrop-filter:blur(4px);border-radius:999px;padding:2px 10px;font-size:12px;font-weight:500;line-height:20px;text-decoration:none;transition:opacity .12s;position:absolute;top:8px;right:8px}.rwa6qG_imageCard:hover .rwa6qG_download{opacity:1}.rwa6qG_download:hover{background:var(--dsw-alias-bg-base)}.rwa6qG_galleryAdd{font:inherit;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;opacity:0;backdrop-filter:blur(4px);border-radius:999px;align-items:center;gap:5px;padding:2px 10px;font-size:12px;font-weight:500;line-height:20px;transition:opacity .12s;display:inline-flex;position:absolute;top:8px;left:8px}.rwa6qG_imageCard:hover .rwa6qG_galleryAdd{opacity:1}.rwa6qG_galleryAdd:hover{background:var(--dsw-alias-bg-base)}.rwa6qG_galleryAdd:disabled{opacity:.4;cursor:default}.rwa6qG_zoomHint{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);opacity:0;backdrop-filter:blur(4px);pointer-events:none;border-radius:999px;align-items:center;gap:5px;padding:2px 10px;font-size:12px;font-weight:500;line-height:20px;transition:opacity .12s;display:inline-flex;position:absolute;bottom:8px;left:8px}.rwa6qG_imageCard:hover .rwa6qG_zoomHint{opacity:1}.rwa6qG_spinner,.rwa6qG_bigSpinner{border:2px solid;border-top-color:#0000;border-radius:50%;flex:none;animation:.8s linear infinite rwa6qG_dshImageGenSpin;display:inline-block}.rwa6qG_spinner{width:11px;height:11px}.rwa6qG_bigSpinner{width:30px;height:30px;color:var(--dsw-alias-state-business-primary);border-width:3px;margin-bottom:6px}.rwa6qG_lightbox{z-index:1000;backdrop-filter:blur(6px);background:#000000b8;justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}.rwa6qG_lightboxClose{color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;border-radius:50%;justify-content:center;align-items:center;width:38px;height:38px;display:inline-flex;position:absolute;top:16px;right:16px}.rwa6qG_lightboxClose:hover{background:#ffffff42}.rwa6qG_lightboxNav{color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;border-radius:50%;justify-content:center;align-items:center;width:42px;height:42px;display:inline-flex;position:absolute;top:50%;transform:translateY(-50%)}.rwa6qG_lightboxNav:hover{background:#ffffff42}.rwa6qG_lightboxNav[data-dir=prev]{left:max(20px,50% - 640px)}.rwa6qG_lightboxNav[data-dir=next]{right:max(20px,50% - 640px)}.rwa6qG_lightboxFigure{flex-direction:column;gap:10px;width:min(1100px,100vw - 160px);max-width:min(1100px,100vw - 160px);height:min(820px,100vh - 48px);min-height:0;margin:0;display:flex}.rwa6qG_lightboxStage{background:#ffffff0a;border-radius:10px;flex:1;min-height:0;position:relative;overflow:auto}.rwa6qG_lightboxScaleFrame{justify-content:center;align-items:center;min-width:100%;min-height:100%;display:flex}.rwa6qG_lightboxImage{object-fit:contain;border-radius:10px;max-width:100%;max-height:100%;display:block;box-shadow:0 24px 80px #00000080}.rwa6qG_lightboxTools{justify-content:center;align-items:center;gap:6px;display:flex}.rwa6qG_lightboxTool,.rwa6qG_lightboxZoomLevel,.rwa6qG_lightboxCopy{color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;justify-content:center;align-items:center;display:inline-flex}.rwa6qG_lightboxTool,.rwa6qG_lightboxZoomLevel{height:32px}.rwa6qG_lightboxTool{border-radius:50%;width:32px}.rwa6qG_lightboxZoomLevel{min-width:58px;font:inherit;font-variant-numeric:tabular-nums;border-radius:999px;padding:0 9px;font-size:12px}.rwa6qG_lightboxTool:hover,.rwa6qG_lightboxZoomLevel:hover,.rwa6qG_lightboxCopy:hover{background:#ffffff42}.rwa6qG_lightboxCaptionRow{align-items:flex-start;gap:8px;min-width:0;display:flex}.rwa6qG_lightboxCaption{color:#ffffffe6;-webkit-line-clamp:3;-webkit-box-orient:vertical;flex:1;min-width:0;font-size:12px;line-height:1.6;display:-webkit-box;overflow:hidden}.rwa6qG_lightboxCopy{min-height:28px;font:inherit;white-space:nowrap;border-radius:999px;flex:none;gap:5px;padding:4px 9px;font-size:12px}.rwa6qG_lightboxMeta{justify-content:space-between;align-items:center;gap:12px;display:flex}.rwa6qG_lightboxIndex{color:#fffc;font-variant-numeric:tabular-nums;font-size:12px}.rwa6qG_lightboxActions{align-items:center;gap:8px;display:inline-flex}.rwa6qG_lightboxDownload,.rwa6qG_lightboxEdit{font:inherit;color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;border-radius:999px;padding:4px 14px;font-size:12.5px;font-weight:500;text-decoration:none}.rwa6qG_lightboxDownload:hover,.rwa6qG_lightboxEdit:hover{background:#ffffff42}.rwa6qG_lightboxEdit{color:#fff;background:#ffffff24;border:1px solid #ffffff47;border-radius:999px}@media (width<=720px){.rwa6qG_lightbox{padding:16px}.rwa6qG_lightboxFigure{width:calc(100vw - 32px);max-width:none}.rwa6qG_lightboxNav[data-dir=prev]{left:20px}.rwa6qG_lightboxNav[data-dir=next]{right:20px}.rwa6qG_lightboxCaptionRow,.rwa6qG_lightboxMeta{flex-direction:column;align-items:stretch}.rwa6qG_lightboxCopy,.rwa6qG_lightboxActions{align-self:flex-end}}@keyframes rwa6qG_dshImageGenSpin{to{transform:rotate(360deg)}}.rwa6qG_galleryToast{z-index:30;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);backdrop-filter:blur(6px);pointer-events:none;border-radius:999px;align-items:center;gap:7px;padding:6px 16px;font-size:13px;font-weight:500;animation:.16s ease-out rwa6qG_dshImageGenToastIn;display:inline-flex;position:absolute;bottom:24px;left:50%;transform:translate(-50%);box-shadow:0 8px 24px #00000038}@keyframes rwa6qG_dshImageGenToastIn{0%{opacity:0;transform:translate(-50%,6px)}to{opacity:1;transform:translate(-50%)}}@media (prefers-reduced-motion:reduce){.rwa6qG_download,.rwa6qG_spinner,.rwa6qG_bigSpinner{transition:none;animation-duration:1.5s}}.rwa6qG_config[data-gallery=true] .rwa6qG_configScroll>:not(:first-child),.rwa6qG_config[data-gallery=true] .rwa6qG_footer,.rwa6qG_canvas[data-gallery=true]>.rwa6qG_canvasState,.rwa6qG_canvas[data-gallery=true]>.rwa6qG_canvasError,.rwa6qG_canvas[data-gallery=true]>.rwa6qG_canvasBody,.rwa6qG_studio:has(.rwa6qG_config[data-gallery=true])>.rwa6qG_history{display:none}.rwa6qG_config[data-gallery=true] .rwa6qG_configScroll{flex:none;order:1;display:flex;overflow:visible}.rwa6qG_config[data-gallery=true] .rwa6qG_galleryFilters{flex:1;order:2;min-height:0}.rwa6qG_galleryFilters{padding:18px 14px;overflow:hidden auto}.rwa6qG_galleryFilterHeading{color:var(--dsw-alias-label-tertiary);margin:0 4px 10px;font-size:12px;font-weight:600}.rwa6qG_galleryFilter{width:100%;min-height:34px;color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left;background:0 0;border:0;border-radius:9px;justify-content:space-between;align-items:center;padding:0 10px;display:flex}.rwa6qG_galleryFilter:hover,.rwa6qG_galleryFilter[data-active]{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent)}.rwa6qG_galleryFilterCount{min-width:20px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2);text-align:center;border-radius:999px;padding:1px 6px;font-size:11px}.rwa6qG_galleryFilterDivider{background:var(--dsw-alias-border-l1);height:1px;margin:18px 4px}.rwa6qG_galleryRatioList{flex-wrap:wrap;gap:6px;display:flex}.rwa6qG_galleryRatio{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);cursor:pointer;border:0;border-radius:999px;padding:6px 10px;font-size:12px}.rwa6qG_galleryRatio[data-active]{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 13%, transparent)}.rwa6qG_galleryTagFilterList{flex-wrap:wrap;gap:6px;display:flex}.rwa6qG_galleryTagFilter{border:1px solid var(--dsw-alias-border-l1);min-width:0;max-width:100%;min-height:27px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);cursor:pointer;font:inherit;border-radius:6px;align-items:center;gap:5px;padding:0 8px;font-size:11px;display:inline-flex}.rwa6qG_galleryTagFilter span:first-child{text-overflow:ellipsis;white-space:nowrap;max-width:112px;overflow:hidden}.rwa6qG_galleryTagFilter span:last-child{color:var(--dsw-alias-label-tertiary);font-size:10px}.rwa6qG_galleryTagFilter:hover,.rwa6qG_galleryTagFilter[data-active]{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent)}.rwa6qG_galleryFilterNote{color:var(--dsw-alias-label-quaternary);margin:20px 4px 0;font-size:11px;line-height:1.5}.rwa6qG_galleryWorkspace{box-sizing:border-box;flex-direction:column;width:100%;min-width:0;height:100%;min-height:0;padding:22px 24px 26px;display:flex;position:absolute;inset:0;overflow:hidden}.rwa6qG_galleryToolbar{flex:none;justify-content:space-between;align-items:center;gap:16px;min-width:0;margin-bottom:18px;display:flex}.rwa6qG_galleryHeading{color:var(--dsw-alias-label-primary);margin:0;font-size:20px;font-weight:700;display:inline}.rwa6qG_galleryCount{color:var(--dsw-alias-label-tertiary);margin-left:8px;font-size:13px}.rwa6qG_galleryToolbarActions{flex-wrap:wrap;align-items:center;gap:10px;min-width:0;display:flex}.rwa6qG_gallerySelectMode,.rwa6qG_galleryBulkButton,.rwa6qG_gallerySelectionClear{border:1px solid var(--dsw-alias-border-l1);min-height:30px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);cursor:pointer;font:inherit;border-radius:7px;padding:0 10px;font-size:12px}.rwa6qG_gallerySelectMode:hover,.rwa6qG_gallerySelectMode[data-active],.rwa6qG_galleryBulkButton:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:color-mix(in srgb, var(--dsw-alias-brand-primary) 38%, var(--dsw-alias-border-l1));background:color-mix(in srgb, var(--dsw-alias-brand-primary) 11%, transparent)}.rwa6qG_galleryBulkButton:disabled{cursor:not-allowed;opacity:.45}.rwa6qG_gallerySelectionBar{border:1px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 35%, var(--dsw-alias-border-l1));background:color-mix(in srgb, var(--dsw-alias-brand-primary) 7%, var(--dsw-alias-bg-layer-1));border-radius:9px;flex:none;align-items:center;gap:10px;min-width:0;margin:-4px 0 16px;padding:10px 12px;display:flex}.rwa6qG_gallerySelectionBar strong{color:var(--dsw-alias-brand-primary);flex:none;font-size:12px}.rwa6qG_gallerySelectionClear{margin-left:auto}.rwa6qG_gallerySelectionClear:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.rwa6qG_galleryTagInput,.rwa6qG_gallerySearch{border:1px solid var(--dsw-alias-border-l1);min-width:0;height:30px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);font:inherit;border-radius:7px;outline:none;padding:0 10px;font-size:12px}.rwa6qG_galleryTagInput{flex:190px}.rwa6qG_galleryTagInput:focus,.rwa6qG_gallerySearch:focus{border-color:var(--dsw-alias-brand-primary)}.rwa6qG_galleryViewToggle{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:9px;padding:3px;display:flex}.rwa6qG_galleryViewToggle button,.rwa6qG_gallerySort,.rwa6qG_galleryClear{min-height:30px;color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border:0;border-radius:7px;padding:0 10px;font-size:12px}.rwa6qG_galleryViewToggle button[data-active],.rwa6qG_galleryViewToggle button:hover,.rwa6qG_gallerySort:hover,.rwa6qG_galleryClear:hover{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 11%, transparent)}.rwa6qG_gallerySort{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1)}.rwa6qG_galleryClear{border:1px solid var(--dsw-alias-border-l1)}.rwa6qG_compareControl{flex-direction:column;gap:6px;margin:0 0 10px;display:flex}.rwa6qG_compareToggle,.rwa6qG_compareModelChoices label{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;font-size:12px;display:flex}.rwa6qG_compareToggle input,.rwa6qG_compareModelChoices input{accent-color:var(--dsw-alias-brand-primary)}.rwa6qG_compareModelChoices{flex-wrap:wrap;gap:6px;display:flex}.rwa6qG_compareModelChoices label{border:1px solid var(--dsw-alias-border-l1);border-radius:5px;padding:4px 6px;font-size:10px}.rwa6qG_comparisonBoard{z-index:4;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;flex-direction:column;display:flex;position:absolute;inset:14px;overflow:hidden;box-shadow:0 8px 24px #0000001f}.rwa6qG_comparisonBoard>header{border-bottom:1px solid var(--dsw-alias-border-l1);justify-content:space-between;align-items:center;padding:10px 12px;display:flex}.rwa6qG_comparisonBoard>header div{align-items:baseline;gap:7px;display:flex}.rwa6qG_comparisonBoard>header strong{color:var(--dsw-alias-label-primary);font-size:13px}.rwa6qG_comparisonBoard>header span{color:var(--dsw-alias-label-tertiary);font-size:11px}.rwa6qG_comparisonBoard>header button{border:1px solid var(--dsw-alias-border-l1);min-height:28px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);cursor:pointer;font:inherit;border-radius:5px;padding:0 9px;font-size:11px}.rwa6qG_comparisonGrid{flex:1;grid-template-rows:minmax(0,1fr);grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;min-height:0;padding:12px;display:grid;overflow:auto}.rwa6qG_comparisonGrid article{flex-direction:column;gap:7px;min-width:0;height:100%;min-height:0;display:flex}.rwa6qG_comparisonGrid article>strong{color:var(--dsw-alias-label-primary);font-size:12px}.rwa6qG_comparisonImageButton{cursor:zoom-in;background:var(--dsw-alias-bg-base);border:0;flex:1;width:100%;min-height:0;padding:0;display:flex;overflow:hidden}.rwa6qG_comparisonImageButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.rwa6qG_comparisonGrid article>span{min-height:0;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2);flex:1;place-items:center;font-size:12px;display:grid}.rwa6qG_comparisonGrid img{object-fit:contain;background:var(--dsw-alias-bg-base);flex:1;width:100%;height:100%;min-height:0;max-height:none;display:block}.rwa6qG_comparisonFullscreen{z-index:1200;background:#000000eb;padding:54px 24px 24px;position:fixed;inset:0;overflow:auto}.rwa6qG_comparisonFullscreenGrid{grid-template-columns:repeat(auto-fit,minmax(300px,1fr));align-items:start;gap:18px;min-height:100%;display:grid}.rwa6qG_comparisonFullscreen figure{min-width:0;margin:0}.rwa6qG_comparisonFullscreen figcaption{color:#fff;margin-bottom:8px;font-size:13px;font-weight:600}.rwa6qG_comparisonFullscreen img{background:#111;width:100%;margin-bottom:10px;display:block}.rwa6qG_historyItem[data-comparison]{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary) 55%, var(--dsw-alias-border-l1))}.rwa6qG_galleryMasonry{box-sizing:border-box;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex:auto;grid-template-columns:repeat(3,minmax(0,1fr));grid-auto-rows:max-content;align-content:start;gap:16px;width:100%;min-width:0;max-width:100%;height:0;min-height:0;padding:2px 8px 16px 2px;display:grid;overflow:hidden scroll}.rwa6qG_galleryMasonry::-webkit-scrollbar{width:8px}.rwa6qG_galleryMasonry::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.rwa6qG_galleryCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:14px;width:100%;margin:0;display:block;position:relative;overflow:hidden;box-shadow:0 5px 18px #18203612}.rwa6qG_galleryCard[data-selected]{border-color:var(--dsw-alias-brand-primary);box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-brand-primary) 26%, transparent), 0 5px 18px #18203612}.rwa6qG_gallerySelect{z-index:2;cursor:pointer;background:#00000094;border:1px solid #ffffffbf;border-radius:7px;place-items:center;width:26px;height:26px;display:grid;position:absolute;top:9px;right:9px}.rwa6qG_gallerySelect input{width:16px;height:16px;accent-color:var(--dsw-alias-brand-primary);cursor:pointer;margin:0}.rwa6qG_galleryImageButton{background:var(--dsw-alias-bg-base);cursor:zoom-in;border:0;width:100%;padding:0;display:block;position:relative}.rwa6qG_galleryImageButton[data-selecting]{cursor:pointer}.rwa6qG_galleryImage{aspect-ratio:4/3;object-fit:cover;width:100%;display:block}.rwa6qG_galleryMasonry[data-view=masonry] .rwa6qG_galleryCard:nth-child(3n+1) .rwa6qG_galleryImage{aspect-ratio:4/5}.rwa6qG_galleryMasonry[data-view=masonry] .rwa6qG_galleryCard:nth-child(3n+2) .rwa6qG_galleryImage{aspect-ratio:4/3}.rwa6qG_galleryMasonry[data-view=masonry] .rwa6qG_galleryCard:nth-child(3n) .rwa6qG_galleryImage{aspect-ratio:3/4}.rwa6qG_galleryBadge{color:#fff;backdrop-filter:blur(4px);background:#121724c2;border-radius:999px;padding:4px 9px;font-size:11px;position:absolute;top:10px;left:10px}.rwa6qG_galleryCardFooter{align-items:center;gap:9px;min-width:0;padding:10px 12px;display:flex}.rwa6qG_galleryAvatar{color:#fff;background:var(--dsw-alias-brand-primary);border-radius:50%;flex:none;place-items:center;width:27px;height:27px;font-size:12px;font-weight:700;display:grid}.rwa6qG_galleryCardInfo{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.rwa6qG_galleryCardInfo strong,.rwa6qG_galleryCardInfo small{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.rwa6qG_galleryCardInfo strong{color:var(--dsw-alias-label-primary);font-size:12px}.rwa6qG_galleryCardInfo small{color:var(--dsw-alias-label-tertiary);font-size:10px}.rwa6qG_galleryTags{flex-wrap:wrap;gap:4px;margin-top:4px;display:flex}.rwa6qG_galleryTags button{max-width:96px;min-height:19px;color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent);cursor:pointer;font:inherit;text-overflow:ellipsis;white-space:nowrap;border:0;border-radius:4px;padding:1px 6px;font-size:10px;line-height:1.35;overflow:hidden}.rwa6qG_galleryTags button:hover{background:color-mix(in srgb, var(--dsw-alias-brand-primary) 17%, transparent)}.rwa6qG_galleryTags .rwa6qG_galleryTagEdit{color:var(--dsw-alias-label-tertiary);background:0 0;flex:none}.rwa6qG_galleryTagEditor{align-items:center;gap:6px;padding:0 12px 10px 48px;display:flex}.rwa6qG_galleryTagEditor input{border:1px solid var(--dsw-alias-border-l2);min-width:0;height:27px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;border-radius:6px;outline:none;flex:1;padding:0 8px;font-size:11px}.rwa6qG_galleryTagEditor input:focus{border-color:var(--dsw-alias-brand-primary)}.rwa6qG_galleryTagEditor button{border:1px solid var(--dsw-alias-border-l2);height:27px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);cursor:pointer;font:inherit;border-radius:6px;padding:0 8px;font-size:11px}.rwa6qG_galleryTagEditor button[type=submit]{color:var(--dsw-alias-brand-primary)}.rwa6qG_galleryRemove{width:24px;height:24px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:50%;flex:none;padding:0;font-size:18px}.rwa6qG_galleryRemove:hover{color:var(--dsw-alias-state-error);background:var(--dsw-alias-bg-layer-2)}@media (width<=1100px){.rwa6qG_galleryMasonry{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width<=760px){.rwa6qG_studio{flex-direction:column;overflow:auto}.rwa6qG_config{width:auto;max-width:none;height:auto;min-height:0}.rwa6qG_config[data-gallery=true]{flex:none}.rwa6qG_canvas{min-height:560px}.rwa6qG_galleryToolbar{flex-direction:column;align-items:flex-start}.rwa6qG_galleryToolbarActions{flex-wrap:wrap;width:100%}.rwa6qG_galleryMasonry{grid-template-columns:1fr}}";
1188
- const tagId$2 = "dsh-audiogen/panel.module.css";
1189
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
2176
+ //#region \0dsh-css:/Users/shimingming/Projects_code/dsh-audiogen/src/client/library.module.css.mjs
2177
+ const css$3 = ".vzUV2a_library{flex-direction:column;flex:1;gap:10px;min-width:0;min-height:0;display:flex}.vzUV2a_toolbar{flex-wrap:wrap;flex:none;align-items:center;gap:12px;display:flex}.vzUV2a_searchBox{border:1px solid var(--dsw-alias-border-l2,#d1d5db);background:var(--dsw-alias-bg-layer-1,#fff);min-width:170px;height:33px;color:var(--dsw-alias-label-tertiary,#9ca3af);border-radius:999px;flex:220px;align-items:center;gap:7px;padding:0 11px;display:inline-flex}.vzUV2a_searchBox:focus-within{border-color:var(--dsw-alias-brand-primary,#2563eb);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 14%, transparent)}.vzUV2a_searchInput{min-width:0;height:100%;color:var(--dsw-alias-label-primary,#1f2328);background:0 0;border:0;outline:none;flex:1;font-family:inherit;font-size:12.5px}.vzUV2a_searchInput::placeholder{color:var(--dsw-alias-label-tertiary,#9ca3af)}.vzUV2a_typeChips{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f3f4f6);border-radius:10px;align-items:center;gap:5px;padding:3px;display:inline-flex}.vzUV2a_chip{min-height:27px;color:var(--dsw-alias-label-secondary,#6b7280);white-space:nowrap;cursor:pointer;background:0 0;border:0;border-radius:8px;align-items:center;gap:5px;padding:0 11px;font-family:inherit;font-size:12px;transition:color .12s,background .12s;display:inline-flex}.vzUV2a_chip:hover{color:var(--dsw-alias-label-primary,#1f2328)}.vzUV2a_chip[data-active=true]{color:var(--dsw-alias-brand-primary,#2563eb);background:var(--dsw-alias-bg-layer-1,#fff);font-weight:600;box-shadow:0 1px 3px #0000001a}.vzUV2a_chipCount{background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-tertiary,#9ca3af);font-variant-numeric:tabular-nums;border-radius:999px;padding:1px 6px;font-size:10.5px}.vzUV2a_chip[data-active=true] .vzUV2a_chipCount{background:color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 10%, transparent);color:var(--dsw-alias-brand-primary,#2563eb)}.vzUV2a_filterRow{flex-wrap:wrap;flex:none;align-items:center;gap:6px;display:flex}.vzUV2a_filterLabel{color:var(--dsw-alias-label-tertiary,#9ca3af);font-size:11px;font-weight:600}.vzUV2a_smallChip{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f3f4f6);min-height:24px;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;border-radius:999px;align-items:center;gap:4px;padding:0 10px;font-family:inherit;font-size:11.5px;display:inline-flex}.vzUV2a_smallChip:hover{color:var(--dsw-alias-label-primary,#1f2328);border-color:var(--dsw-alias-label-dimmed,#9ca3af)}.vzUV2a_smallChip[data-active=true]{color:var(--dsw-alias-brand-primary,#2563eb);border-color:var(--dsw-alias-brand-primary,#2563eb);background:color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 9%, transparent);font-weight:600}.vzUV2a_listHead{border-bottom:1px solid var(--dsw-alias-border-l1,#e5e7eb);flex:none;justify-content:space-between;align-items:center;gap:10px;padding-bottom:2px;display:flex}.vzUV2a_listCount{color:var(--dsw-alias-label-tertiary,#9ca3af);font-size:12px}.vzUV2a_listActions{flex-wrap:wrap;align-items:center;gap:6px;display:inline-flex}.vzUV2a_selCount{color:var(--dsw-alias-brand-primary,#2563eb);font-size:11.5px;font-weight:600}.vzUV2a_smallSelect{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);height:27px;color:var(--dsw-alias-label-primary,#1f2328);border-radius:7px;outline:none;padding:0 8px;font-family:inherit;font-size:11.5px}.vzUV2a_ghostBtn{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);min-height:27px;color:var(--dsw-alias-label-secondary,#6b7280);cursor:pointer;border-radius:999px;align-items:center;gap:5px;padding:0 11px;font-family:inherit;font-size:11.5px;display:inline-flex}.vzUV2a_ghostBtn:hover:not(:disabled){color:var(--dsw-alias-brand-primary,#2563eb);border-color:var(--dsw-alias-brand-primary,#2563eb)}.vzUV2a_dangerBtn{border:1px solid var(--dsw-alias-label-error,#b91c1c);min-height:27px;color:var(--dsw-alias-label-error,#b91c1c);cursor:pointer;background:0 0;border-radius:999px;align-items:center;gap:5px;padding:0 11px;font-family:inherit;font-size:11.5px;display:inline-flex}.vzUV2a_dangerBtn:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-label-error,#b91c1c) 8%, transparent)}.vzUV2a_ghostBtn:disabled,.vzUV2a_dangerBtn:disabled{opacity:.45;cursor:default}.vzUV2a_stateNote{color:var(--dsw-alias-label-tertiary,#9ca3af);margin:0;padding:8px 4px;font-size:12px}.vzUV2a_stateNote[data-error]{color:var(--dsw-alias-label-error,#b91c1c)}.vzUV2a_empty{text-align:center;color:var(--dsw-alias-label-secondary,#6b7280);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:6px;font-size:13px;display:flex}.vzUV2a_emptyIcon{background:var(--dsw-alias-bg-layer-2,#f3f4f6);border-radius:50%;justify-content:center;align-items:center;width:56px;height:56px;margin-bottom:4px;font-size:26px;display:inline-flex}.vzUV2a_emptyHint{color:var(--dsw-alias-label-tertiary,#9ca3af);margin:0;font-size:11.5px}.vzUV2a_grid{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex:1;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));align-content:start;gap:12px;min-height:0;padding:2px 2px 6px;display:grid;overflow-y:auto}.vzUV2a_grid::-webkit-scrollbar{width:8px}.vzUV2a_grid::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.vzUV2a_card{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-1,#fff);cursor:pointer;border-radius:12px;flex-direction:column;gap:7px;padding:11px;transition:border-color .12s,box-shadow .12s,transform .12s;display:flex;position:relative}.vzUV2a_card:hover{border-color:var(--dsw-alias-label-dimmed,#9ca3af);transform:translateY(-1px);box-shadow:0 4px 14px #18203614}.vzUV2a_card[data-selected=true]{border-color:var(--dsw-alias-brand-primary,#2563eb);box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 24%, transparent)}.vzUV2a_cardCheck{z-index:2;position:absolute;top:9px;right:9px}.vzUV2a_cardCheck input{width:16px;height:16px;accent-color:var(--dsw-alias-brand-primary,#2563eb);cursor:pointer}.vzUV2a_cardHead{justify-content:space-between;align-items:center;gap:8px;display:flex}.vzUV2a_typeBadge{background:var(--dsw-alias-bg-layer-2,#f3f4f6);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:999px;align-items:center;gap:5px;padding:2px 9px;font-size:10.5px;font-weight:600;display:inline-flex}.vzUV2a_typeBadge[data-type=voice]{color:#8b5cf6;background:#8b5cf61f}.vzUV2a_typeBadge[data-type=music]{color:#059669;background:#10b9811f}.vzUV2a_typeBadge[data-type=sfx]{color:#b45309;background:#f59e0b24}.vzUV2a_typeBadge[data-type=tts]{color:#2563eb;background:#3b82f61f}.vzUV2a_cardTime{color:var(--dsw-alias-label-tertiary,#9ca3af);white-space:nowrap;font-size:10.5px}.vzUV2a_cardName{color:var(--dsw-alias-label-primary,#1f2328);-webkit-line-clamp:2;-webkit-box-orient:vertical;min-height:34px;font-size:12.5px;line-height:1.4;display:-webkit-box;overflow:hidden}.vzUV2a_cardFoot{flex-wrap:wrap;align-items:center;gap:5px;display:flex}.vzUV2a_metaChip{background:var(--dsw-alias-bg-layer-2,#f3f4f6);max-width:140px;color:var(--dsw-alias-label-tertiary,#9ca3af);text-overflow:ellipsis;white-space:nowrap;border-radius:999px;padding:1px 8px;font-size:10.5px;overflow:hidden}.vzUV2a_metaChip[data-tag]{color:var(--dsw-alias-brand-primary,#2563eb);background:color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 10%, transparent)}.vzUV2a_drawerMask{z-index:120;backdrop-filter:blur(2px);background:#0000004d;justify-content:flex-end;display:flex;position:absolute;inset:0}.vzUV2a_drawer{background:var(--dsw-alias-bg-layer-1,#fff);border-left:1px solid var(--dsw-alias-border-l2,#d1d5db);flex-direction:column;width:min(430px,100% - 24px);height:100%;animation:.18s ease-out vzUV2a_audiogenDrawerIn;display:flex;box-shadow:-12px 0 36px #0000002e}@keyframes vzUV2a_audiogenDrawerIn{0%{opacity:0;transform:translate(20px)}to{opacity:1;transform:translate(0)}}.vzUV2a_drawerHead{border-bottom:1px solid var(--dsw-alias-border-l1,#e5e7eb);flex:none;justify-content:space-between;align-items:center;gap:10px;padding:13px 14px;display:flex}.vzUV2a_drawerTitle{color:var(--dsw-alias-label-primary,#1f2328);text-overflow:ellipsis;white-space:nowrap;font-size:13.5px;font-weight:700;overflow:hidden}.vzUV2a_iconBtn{width:26px;height:26px;color:var(--dsw-alias-label-tertiary,#9ca3af);cursor:pointer;background:0 0;border:0;border-radius:7px;flex:none;justify-content:center;align-items:center;font-size:16px;line-height:1;display:inline-flex}.vzUV2a_iconBtn:hover{color:var(--dsw-alias-label-primary,#1f2328);background:var(--dsw-alias-bg-layer-2,#f3f4f6)}.vzUV2a_drawerBody{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:14px;min-height:0;padding:14px;display:flex;overflow-y:auto}.vzUV2a_drawerBody::-webkit-scrollbar{width:8px}.vzUV2a_drawerBody::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.vzUV2a_drawerSection{flex-direction:column;gap:9px;display:flex}.vzUV2a_drawerLabel{letter-spacing:.04em;color:var(--dsw-alias-label-tertiary,#9ca3af);text-transform:uppercase;font-size:11px;font-weight:700}.vzUV2a_drawerPlayerList{flex-direction:column;gap:8px;display:flex}.vzUV2a_drawerPlayer{flex-direction:column;gap:4px;display:flex}.vzUV2a_drawerPlayerName{color:var(--dsw-alias-label-tertiary,#9ca3af);text-overflow:ellipsis;white-space:nowrap;padding-left:4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;overflow:hidden}.vzUV2a_drawerField{color:var(--dsw-alias-label-secondary,#6b7280);flex-direction:column;gap:4px;font-size:11.5px;font-weight:600;display:flex}.vzUV2a_drawerSplit{grid-template-columns:1fr 1fr;gap:9px;display:grid}.vzUV2a_input,.vzUV2a_textarea{border:1px solid var(--dsw-alias-border-l2,#d1d5db);background:var(--dsw-alias-bg-layer-2,#f7f7f8);width:100%;min-height:32px;color:var(--dsw-alias-label-primary,#1f2328);border-radius:8px;outline:none;padding:6px 9px;font-family:inherit;font-size:12.5px}.vzUV2a_input:focus,.vzUV2a_textarea:focus{border-color:var(--dsw-alias-brand-primary,#2563eb);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 12%, transparent)}.vzUV2a_textarea{resize:vertical}.vzUV2a_provenance{border:1px solid var(--dsw-alias-border-l1,#e5e7eb);background:var(--dsw-alias-bg-layer-2,#f7f7f8);border-radius:10px;flex-direction:column;gap:7px;padding:10px 11px;display:flex}.vzUV2a_provRow{gap:8px;min-width:0;display:flex}.vzUV2a_provKey{width:64px;color:var(--dsw-alias-label-tertiary,#9ca3af);flex:none;padding-top:1px;font-size:11px;font-weight:600}.vzUV2a_provValue{min-width:0;color:var(--dsw-alias-label-primary,#1f2328);overflow-wrap:anywhere;flex-wrap:wrap;align-items:flex-start;gap:6px;font-size:12px;line-height:1.5;display:flex}.vzUV2a_mono{color:var(--dsw-alias-label-secondary,#6b7280);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10.5px}.vzUV2a_promptText{color:var(--dsw-alias-label-secondary,#6b7280)}.vzUV2a_code{background:var(--dsw-alias-bg-layer-3,#eceef1);overflow-wrap:anywhere;border-radius:5px;padding:2px 6px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10.5px}.vzUV2a_paramsDetails summary{cursor:pointer;color:var(--dsw-alias-brand-primary,#2563eb);user-select:none;font-size:11px}.vzUV2a_paramsDetails pre{background:var(--dsw-alias-bg-layer-3,#eceef1);width:100%;max-height:200px;color:var(--dsw-alias-label-secondary,#6b7280);border-radius:7px;margin:5px 0 0;padding:8px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;line-height:1.5;overflow:auto}.vzUV2a_drawerActions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.vzUV2a_primaryBtn{background:var(--dsw-alias-label-primary,#1f2328);min-height:30px;color:var(--dsw-alias-bg-layer-3,#fff);cursor:pointer;border:0;border-radius:8px;align-items:center;gap:6px;padding:0 13px;font-family:inherit;font-size:12px;font-weight:600;display:inline-flex}.vzUV2a_primaryBtn:disabled{opacity:.5;cursor:default}@media (prefers-reduced-motion:reduce){.vzUV2a_drawer{animation-duration:1ms}}";
2178
+ const tagId$3 = "dsh-audiogen/library.module.css";
2179
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
1190
2180
  const tag = document.createElement("style");
1191
2181
  tag.dataset.plugin = "dsh-audiogen";
1192
- tag.dataset.pluginCss = tagId$2;
1193
- tag.textContent = css$2;
2182
+ tag.dataset.pluginCss = tagId$3;
2183
+ tag.textContent = css$3;
1194
2184
  document.head.appendChild(tag);
1195
2185
  }
1196
- var panel_module_css_default = {
1197
- "lightboxTools": "rwa6qG_lightboxTools",
1198
- "prompt": "rwa6qG_prompt",
1199
- "galleryTagInput": "rwa6qG_galleryTagInput",
1200
- "historyAction": "rwa6qG_historyAction",
1201
- "lightboxFigure": "rwa6qG_lightboxFigure",
1202
- "galleryWorkspace": "rwa6qG_galleryWorkspace",
1203
- "gallerySort": "rwa6qG_gallerySort",
1204
- "galleryMasonry": "rwa6qG_galleryMasonry",
1205
- "image": "rwa6qG_image",
1206
- "modelWrap": "rwa6qG_modelWrap",
1207
- "lightboxActions": "rwa6qG_lightboxActions",
1208
- "card": "rwa6qG_card",
1209
- "lightbox": "rwa6qG_lightbox",
1210
- "historyFilters": "rwa6qG_historyFilters",
1211
- "canvasHistoryTag": "rwa6qG_canvasHistoryTag",
1212
- "uploadHint": "rwa6qG_uploadHint",
1213
- "uploadIcon": "rwa6qG_uploadIcon",
1214
- "modelMenuList": "rwa6qG_modelMenuList",
1215
- "galleryToolbar": "rwa6qG_galleryToolbar",
1216
- "galleryFilterHeading": "rwa6qG_galleryFilterHeading",
1217
- "lightboxStage": "rwa6qG_lightboxStage",
1218
- "updateText": "rwa6qG_updateText",
1219
- "historyActions": "rwa6qG_historyActions",
1220
- "lightboxScaleFrame": "rwa6qG_lightboxScaleFrame",
1221
- "lightboxIndex": "rwa6qG_lightboxIndex",
1222
- "galleryHeading": "rwa6qG_galleryHeading",
1223
- "comparisonFullscreen": "rwa6qG_comparisonFullscreen",
1224
- "lightboxCaption": "rwa6qG_lightboxCaption",
1225
- "compareControl": "rwa6qG_compareControl",
1226
- "galleryFilter": "rwa6qG_galleryFilter",
1227
- "optionPill": "rwa6qG_optionPill",
1228
- "comparisonFullscreenGrid": "rwa6qG_comparisonFullscreenGrid",
1229
- "paramHint": "rwa6qG_paramHint",
1230
- "compareToggle": "rwa6qG_compareToggle",
1231
- "galleryImageButton": "rwa6qG_galleryImageButton",
1232
- "canvas": "rwa6qG_canvas",
1233
- "lightboxClose": "rwa6qG_lightboxClose",
1234
- "galleryRemove": "rwa6qG_galleryRemove",
1235
- "canvasEmptyIcon": "rwa6qG_canvasEmptyIcon",
1236
- "historyList": "rwa6qG_historyList",
1237
- "historyThumb": "rwa6qG_historyThumb",
1238
- "paramLabel": "rwa6qG_paramLabel",
1239
- "config": "rwa6qG_config",
1240
- "taskPrompt": "rwa6qG_taskPrompt",
1241
- "history": "rwa6qG_history",
1242
- "configScroll": "rwa6qG_configScroll",
1243
- "generateInner": "rwa6qG_generateInner",
1244
- "canvasBody": "rwa6qG_canvasBody",
1245
- "dshImageGenSpin": "rwa6qG_dshImageGenSpin",
1246
- "galleryFilters": "rwa6qG_galleryFilters",
2186
+ var library_module_css_default = {
2187
+ "provRow": "vzUV2a_provRow",
2188
+ "textarea": "vzUV2a_textarea",
2189
+ "drawerActions": "vzUV2a_drawerActions",
2190
+ "chipCount": "vzUV2a_chipCount",
2191
+ "listActions": "vzUV2a_listActions",
2192
+ "cardCheck": "vzUV2a_cardCheck",
2193
+ "typeBadge": "vzUV2a_typeBadge",
2194
+ "mono": "vzUV2a_mono",
2195
+ "primaryBtn": "vzUV2a_primaryBtn",
2196
+ "grid": "vzUV2a_grid",
2197
+ "card": "vzUV2a_card",
2198
+ "filterRow": "vzUV2a_filterRow",
2199
+ "drawer": "vzUV2a_drawer",
2200
+ "drawerHead": "vzUV2a_drawerHead",
2201
+ "drawerBody": "vzUV2a_drawerBody",
2202
+ "listHead": "vzUV2a_listHead",
2203
+ "typeChips": "vzUV2a_typeChips",
2204
+ "cardTime": "vzUV2a_cardTime",
2205
+ "cardName": "vzUV2a_cardName",
2206
+ "empty": "vzUV2a_empty",
2207
+ "drawerPlayerName": "vzUV2a_drawerPlayerName",
2208
+ "provenance": "vzUV2a_provenance",
2209
+ "toolbar": "vzUV2a_toolbar",
2210
+ "drawerMask": "vzUV2a_drawerMask",
2211
+ "drawerPlayer": "vzUV2a_drawerPlayer",
2212
+ "paramsDetails": "vzUV2a_paramsDetails",
2213
+ "filterLabel": "vzUV2a_filterLabel",
2214
+ "stateNote": "vzUV2a_stateNote",
2215
+ "promptText": "vzUV2a_promptText",
2216
+ "smallSelect": "vzUV2a_smallSelect",
2217
+ "selCount": "vzUV2a_selCount",
2218
+ "chip": "vzUV2a_chip",
2219
+ "provKey": "vzUV2a_provKey",
2220
+ "provValue": "vzUV2a_provValue",
2221
+ "ghostBtn": "vzUV2a_ghostBtn",
2222
+ "dangerBtn": "vzUV2a_dangerBtn",
2223
+ "drawerLabel": "vzUV2a_drawerLabel",
2224
+ "emptyIcon": "vzUV2a_emptyIcon",
2225
+ "searchBox": "vzUV2a_searchBox",
2226
+ "code": "vzUV2a_code",
2227
+ "smallChip": "vzUV2a_smallChip",
2228
+ "cardHead": "vzUV2a_cardHead",
2229
+ "drawerPlayerList": "vzUV2a_drawerPlayerList",
2230
+ "listCount": "vzUV2a_listCount",
2231
+ "emptyHint": "vzUV2a_emptyHint",
2232
+ "cardFoot": "vzUV2a_cardFoot",
2233
+ "iconBtn": "vzUV2a_iconBtn",
2234
+ "drawerTitle": "vzUV2a_drawerTitle",
2235
+ "drawerSection": "vzUV2a_drawerSection",
2236
+ "library": "vzUV2a_library",
2237
+ "searchInput": "vzUV2a_searchInput",
2238
+ "drawerSplit": "vzUV2a_drawerSplit",
2239
+ "metaChip": "vzUV2a_metaChip",
2240
+ "drawerField": "vzUV2a_drawerField",
2241
+ "input": "vzUV2a_input",
2242
+ "audiogenDrawerIn": "vzUV2a_audiogenDrawerIn"
2243
+ };
2244
+ //#endregion
2245
+ //#region src/client/library-view.tsx
2246
+ /**
2247
+ * Library view: curated audio assets, organized by type (voice / music / sfx /
2248
+ * tts) with categories (voice: male/female/custom; tts: the speaking voice).
2249
+ * Search + chips + card grid + detail drawer (full provenance) + batch mode.
2250
+ */
2251
+ const TYPE_ORDER = [
2252
+ "voice",
2253
+ "music",
2254
+ "sfx",
2255
+ "tts"
2256
+ ];
2257
+ const VOICE_CATEGORIES = [
2258
+ "male",
2259
+ "female",
2260
+ "custom"
2261
+ ];
2262
+ function timeAgo(ts) {
2263
+ const diff = Date.now() - ts;
2264
+ const minute = 6e4;
2265
+ const hour = 60 * minute;
2266
+ const day = 24 * hour;
2267
+ if (diff < minute) return "刚刚";
2268
+ if (diff < hour) return `${Math.floor(diff / minute)} 分钟前`;
2269
+ if (diff < day) return `${Math.floor(diff / hour)} 小时前`;
2270
+ if (diff < 7 * day) return `${Math.floor(diff / day)} 天前`;
2271
+ const date = new Date(ts);
2272
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
2273
+ }
2274
+ function typeIcon(type) {
2275
+ if (type === "voice") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MicIcon, {});
2276
+ if (type === "music") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MusicNoteIcon, {});
2277
+ if (type === "sfx") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WaveIcon, {});
2278
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ListIcon, {});
2279
+ }
2280
+ function LibraryView(props) {
2281
+ const { api, revision } = props;
2282
+ const [entries, setEntries] = (0, react.useState)([]);
2283
+ const [loading, setLoading] = (0, react.useState)(true);
2284
+ const [error, setError] = (0, react.useState)(null);
2285
+ const [keyword, setKeyword] = (0, react.useState)("");
2286
+ const [typeFilter, setTypeFilter] = (0, react.useState)("all");
2287
+ const [categoryFilter, setCategoryFilter] = (0, react.useState)("all");
2288
+ const [tagFilter, setTagFilter] = (0, react.useState)(null);
2289
+ const [detailId, setDetailId] = (0, react.useState)(null);
2290
+ const [batchMode, setBatchMode] = (0, react.useState)(false);
2291
+ const [selected, setSelected] = (0, react.useState)(/* @__PURE__ */ new Set());
2292
+ const [confirmDelete, setConfirmDelete] = (0, react.useState)(null);
2293
+ const [busy, setBusy] = (0, react.useState)(false);
2294
+ const [copied, setCopied] = (0, react.useState)(null);
2295
+ const load = () => {
2296
+ setLoading(true);
2297
+ setError(null);
2298
+ api.libraryList().then(setEntries).catch((err) => setError(err instanceof Error ? err.message : String(err))).finally(() => setLoading(false));
2299
+ };
2300
+ (0, react.useEffect)(() => {
2301
+ load();
2302
+ }, [revision]);
2303
+ (0, react.useEffect)(() => {
2304
+ setCategoryFilter("all");
2305
+ }, [typeFilter]);
2306
+ const categoriesOf = (0, react.useMemo)(() => {
2307
+ const map = /* @__PURE__ */ new Map();
2308
+ for (const entry of entries) {
2309
+ if (entry.category === void 0 || entry.category === "") continue;
2310
+ const list = map.get(entry.type) ?? [];
2311
+ if (!list.includes(entry.category)) list.push(entry.category);
2312
+ map.set(entry.type, list);
2313
+ }
2314
+ return map;
2315
+ }, [entries]);
2316
+ const tags = (0, react.useMemo)(() => {
2317
+ const counts = /* @__PURE__ */ new Map();
2318
+ for (const entry of entries) for (const tag of entry.tags) counts.set(tag, (counts.get(tag) ?? 0) + 1);
2319
+ return [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 14);
2320
+ }, [entries]);
2321
+ const filtered = (0, react.useMemo)(() => {
2322
+ const needle = keyword.trim().toLowerCase();
2323
+ return entries.filter((entry) => {
2324
+ if (typeFilter !== "all" && entry.type !== typeFilter) return false;
2325
+ if (categoryFilter !== "all" && (entry.category ?? "") !== categoryFilter) return false;
2326
+ if (tagFilter !== null && !entry.tags.includes(tagFilter)) return false;
2327
+ if (needle !== "") {
2328
+ if (![
2329
+ entry.name,
2330
+ ...entry.tags,
2331
+ entry.provenance.prompt,
2332
+ entry.provenance.model ?? "",
2333
+ entry.provenance.channel ?? ""
2334
+ ].join(" ").toLowerCase().includes(needle)) return false;
2335
+ }
2336
+ return true;
2337
+ });
2338
+ }, [
2339
+ entries,
2340
+ keyword,
2341
+ typeFilter,
2342
+ categoryFilter,
2343
+ tagFilter
2344
+ ]);
2345
+ const typeCounts = (0, react.useMemo)(() => {
2346
+ const counts = {
2347
+ all: entries.length,
2348
+ voice: 0,
2349
+ music: 0,
2350
+ sfx: 0,
2351
+ tts: 0
2352
+ };
2353
+ for (const entry of entries) counts[entry.type] += 1;
2354
+ return counts;
2355
+ }, [entries]);
2356
+ const detail = entries.find((entry) => entry.id === detailId) ?? null;
2357
+ const currentCategoryOptions = (0, react.useMemo)(() => {
2358
+ if (typeFilter === "all") return [];
2359
+ return [.../* @__PURE__ */ new Set([...categoriesOf.get(typeFilter) ?? [], ...typeFilter === "voice" ? VOICE_CATEGORIES : []])];
2360
+ }, [typeFilter, categoriesOf]);
2361
+ const toggleSelect = (id) => {
2362
+ setSelected((current) => {
2363
+ const next = new Set(current);
2364
+ if (!next.delete(id)) next.add(id);
2365
+ return next;
2366
+ });
2367
+ };
2368
+ const doDelete = async (ids) => {
2369
+ setBusy(true);
2370
+ try {
2371
+ await api.libraryRemove(ids);
2372
+ setEntries((current) => current.filter((entry) => !ids.includes(entry.id)));
2373
+ setSelected((current) => {
2374
+ const next = new Set(current);
2375
+ for (const id of ids) next.delete(id);
2376
+ return next;
2377
+ });
2378
+ if (detailId !== null && ids.includes(detailId)) setDetailId(null);
2379
+ props.showToast(`已删除 ${ids.length} 个资源`);
2380
+ } catch (err) {
2381
+ props.showToast(err instanceof Error ? err.message : "删除失败");
2382
+ } finally {
2383
+ setBusy(false);
2384
+ setConfirmDelete(null);
2385
+ }
2386
+ };
2387
+ const copyText = async (text, key) => {
2388
+ try {
2389
+ await navigator.clipboard.writeText(text);
2390
+ setCopied(key);
2391
+ window.setTimeout(() => setCopied(null), 1400);
2392
+ } catch {
2393
+ props.showToast("复制失败");
2394
+ }
2395
+ };
2396
+ const [draft, setDraft] = (0, react.useState)(null);
2397
+ (0, react.useEffect)(() => {
2398
+ if (detail !== null) setDraft({
2399
+ name: detail.name,
2400
+ tags: detail.tags.join(", "),
2401
+ note: detail.note ?? "",
2402
+ type: detail.type,
2403
+ category: detail.category ?? ""
2404
+ });
2405
+ }, [detailId]);
2406
+ const saveDraft = async () => {
2407
+ if (detail === null || draft === null) return;
2408
+ setBusy(true);
2409
+ try {
2410
+ const result = await api.libraryUpdate({
2411
+ id: detail.id,
2412
+ name: draft.name,
2413
+ tags: draft.tags.split(/[,,、\n]/).map((tag) => tag.trim()).filter((tag) => tag !== ""),
2414
+ note: draft.note,
2415
+ type: draft.type,
2416
+ ...(draft.type === "voice" || draft.type === "tts") && draft.category.trim() !== "" ? { category: draft.category.trim() } : {}
2417
+ });
2418
+ if (!result.ok || result.entry === void 0) {
2419
+ props.showToast(result.message ?? "保存失败");
2420
+ return;
2421
+ }
2422
+ setEntries((current) => current.map((entry) => entry.id === result.entry.id ? result.entry : entry));
2423
+ props.showToast("资源已更新");
2424
+ } catch (err) {
2425
+ props.showToast(err instanceof Error ? err.message : "保存失败");
2426
+ } finally {
2427
+ setBusy(false);
2428
+ }
2429
+ };
2430
+ const batchMoveCategory = async (category, type) => {
2431
+ if (selected.size === 0) return;
2432
+ setBusy(true);
2433
+ try {
2434
+ for (const id of selected) await api.libraryUpdate({
2435
+ id,
2436
+ type,
2437
+ ...category !== "" ? { category } : {}
2438
+ });
2439
+ await load();
2440
+ setSelected(/* @__PURE__ */ new Set());
2441
+ props.showToast(`已移动 ${selected.size} 个资源`);
2442
+ } catch (err) {
2443
+ props.showToast(err instanceof Error ? err.message : "移动失败");
2444
+ } finally {
2445
+ setBusy(false);
2446
+ }
2447
+ };
2448
+ const [batchTypeSelect, setBatchTypeSelect] = (0, react.useState)("voice");
2449
+ const [batchCategorySelect, setBatchCategorySelect] = (0, react.useState)("");
2450
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2451
+ className: library_module_css_default.library,
2452
+ children: [
2453
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2454
+ className: library_module_css_default.toolbar,
2455
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2456
+ className: library_module_css_default.searchBox,
2457
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SearchIcon, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2458
+ className: library_module_css_default.searchInput,
2459
+ value: keyword,
2460
+ onChange: (event) => setKeyword(event.target.value),
2461
+ placeholder: "搜索名称、标签、提示词、模型…"
2462
+ })]
2463
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2464
+ className: library_module_css_default.typeChips,
2465
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2466
+ type: "button",
2467
+ className: library_module_css_default.chip,
2468
+ "data-active": typeFilter === "all" ? "true" : "false",
2469
+ onClick: () => setTypeFilter("all"),
2470
+ children: ["全部 ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2471
+ className: library_module_css_default.chipCount,
2472
+ children: typeCounts.all
2473
+ })]
2474
+ }), TYPE_ORDER.map((type) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2475
+ type: "button",
2476
+ className: library_module_css_default.chip,
2477
+ "data-active": typeFilter === type ? "true" : "false",
2478
+ onClick: () => setTypeFilter(type),
2479
+ children: [
2480
+ typeIcon(type),
2481
+ " ",
2482
+ LIBRARY_TYPE_LABELS[type],
2483
+ " ",
2484
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2485
+ className: library_module_css_default.chipCount,
2486
+ children: typeCounts[type]
2487
+ })
2488
+ ]
2489
+ }, type))]
2490
+ })]
2491
+ }),
2492
+ typeFilter !== "all" && currentCategoryOptions.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2493
+ className: library_module_css_default.filterRow,
2494
+ children: [
2495
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2496
+ className: library_module_css_default.filterLabel,
2497
+ children: "分类"
2498
+ }),
2499
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2500
+ type: "button",
2501
+ className: library_module_css_default.smallChip,
2502
+ "data-active": categoryFilter === "all" ? "true" : "false",
2503
+ onClick: () => setCategoryFilter("all"),
2504
+ children: "全部"
2505
+ }),
2506
+ currentCategoryOptions.map((category) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2507
+ type: "button",
2508
+ className: library_module_css_default.smallChip,
2509
+ "data-active": categoryFilter === category ? "true" : "false",
2510
+ onClick: () => setCategoryFilter(category),
2511
+ children: typeFilter === "voice" ? {
2512
+ male: "男声",
2513
+ female: "女声",
2514
+ custom: "未分级"
2515
+ }[category] ?? category : category
2516
+ }, category))
2517
+ ]
2518
+ }) : null,
2519
+ tags.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2520
+ className: library_module_css_default.filterRow,
2521
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2522
+ className: library_module_css_default.filterLabel,
2523
+ children: "标签"
2524
+ }), tags.map(([tag, count]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2525
+ type: "button",
2526
+ className: library_module_css_default.smallChip,
2527
+ "data-active": tagFilter === tag ? "true" : "false",
2528
+ onClick: () => setTagFilter(tagFilter === tag ? null : tag),
2529
+ children: [
2530
+ tag,
2531
+ " ",
2532
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2533
+ className: library_module_css_default.chipCount,
2534
+ children: count
2535
+ })
2536
+ ]
2537
+ }, tag))]
2538
+ }) : null,
2539
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2540
+ className: library_module_css_default.listHead,
2541
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2542
+ className: library_module_css_default.listCount,
2543
+ children: [filtered.length, " 个资源"]
2544
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2545
+ className: library_module_css_default.listActions,
2546
+ children: batchMode ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2547
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2548
+ className: library_module_css_default.selCount,
2549
+ children: ["已选 ", selected.size]
2550
+ }),
2551
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
2552
+ className: library_module_css_default.smallSelect,
2553
+ value: batchTypeSelect,
2554
+ onChange: (event) => {
2555
+ setBatchTypeSelect(event.target.value);
2556
+ setBatchCategorySelect("");
2557
+ },
2558
+ children: TYPE_ORDER.map((type) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2559
+ value: type,
2560
+ children: LIBRARY_TYPE_LABELS[type]
2561
+ }, type))
2562
+ }),
2563
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2564
+ className: library_module_css_default.smallSelect,
2565
+ list: "library-category-options",
2566
+ placeholder: "分类(可选)",
2567
+ value: batchCategorySelect,
2568
+ onChange: (event) => setBatchCategorySelect(event.target.value)
2569
+ }),
2570
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("datalist", {
2571
+ id: "library-category-options",
2572
+ children: (categoriesOf.get(batchTypeSelect) ?? []).map((category) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", { value: category }, category))
2573
+ }),
2574
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2575
+ type: "button",
2576
+ className: library_module_css_default.ghostBtn,
2577
+ disabled: busy || selected.size === 0,
2578
+ onClick: () => void batchMoveCategory(batchCategorySelect, batchTypeSelect),
2579
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}), " 移动"]
2580
+ }),
2581
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2582
+ type: "button",
2583
+ className: library_module_css_default.dangerBtn,
2584
+ disabled: busy || selected.size === 0,
2585
+ onClick: () => {
2586
+ if (confirmDelete === "batch") doDelete([...selected]);
2587
+ else setConfirmDelete("batch");
2588
+ },
2589
+ children: [
2590
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {}),
2591
+ " ",
2592
+ confirmDelete === "batch" ? "确认删除" : "批量删除"
2593
+ ]
2594
+ }),
2595
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2596
+ type: "button",
2597
+ className: library_module_css_default.ghostBtn,
2598
+ onClick: () => {
2599
+ setBatchMode(false);
2600
+ setSelected(/* @__PURE__ */ new Set());
2601
+ setConfirmDelete(null);
2602
+ },
2603
+ children: "退出"
2604
+ })
2605
+ ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2606
+ type: "button",
2607
+ className: library_module_css_default.ghostBtn,
2608
+ onClick: () => setBatchMode(true),
2609
+ children: "多选管理"
2610
+ })
2611
+ })]
2612
+ }),
2613
+ loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2614
+ className: library_module_css_default.stateNote,
2615
+ children: "加载中…"
2616
+ }) : null,
2617
+ error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2618
+ className: library_module_css_default.stateNote,
2619
+ "data-error": true,
2620
+ children: error
2621
+ }) : null,
2622
+ !loading && error === null && filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2623
+ className: library_module_css_default.empty,
2624
+ children: [
2625
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2626
+ className: library_module_css_default.emptyIcon,
2627
+ children: "🎧"
2628
+ }),
2629
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: "资源库还是空的" }),
2630
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2631
+ className: library_module_css_default.emptyHint,
2632
+ children: "在生成页点击「加入资源库」,把满意的音频沉淀为可管理的资源"
2633
+ })
2634
+ ]
2635
+ }) : null,
2636
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2637
+ className: library_module_css_default.grid,
2638
+ children: filtered.map((entry) => {
2639
+ const fileCount = entry.files.length;
2640
+ const first = entry.files[0];
2641
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
2642
+ className: library_module_css_default.card,
2643
+ "data-selected": selected.has(entry.id) ? "true" : "false",
2644
+ onClick: () => {
2645
+ if (batchMode) toggleSelect(entry.id);
2646
+ else setDetailId(entry.id);
2647
+ },
2648
+ role: "button",
2649
+ tabIndex: 0,
2650
+ onKeyDown: (event) => {
2651
+ if (event.key === "Enter" || event.key === " ") {
2652
+ event.preventDefault();
2653
+ if (batchMode) toggleSelect(entry.id);
2654
+ else setDetailId(entry.id);
2655
+ }
2656
+ },
2657
+ children: [
2658
+ batchMode ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2659
+ className: library_module_css_default.cardCheck,
2660
+ onClick: (event) => event.stopPropagation(),
2661
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2662
+ type: "checkbox",
2663
+ checked: selected.has(entry.id),
2664
+ onChange: () => toggleSelect(entry.id)
2665
+ })
2666
+ }) : null,
2667
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2668
+ className: library_module_css_default.cardHead,
2669
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2670
+ className: library_module_css_default.typeBadge,
2671
+ "data-type": entry.type,
2672
+ children: [typeIcon(entry.type), LIBRARY_TYPE_LABELS[entry.type]]
2673
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2674
+ className: library_module_css_default.cardTime,
2675
+ children: timeAgo(entry.createdAt)
2676
+ })]
2677
+ }),
2678
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
2679
+ className: library_module_css_default.cardName,
2680
+ title: entry.name,
2681
+ children: entry.name
2682
+ }),
2683
+ first !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2684
+ onClick: (event) => event.stopPropagation(),
2685
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPlayer, {
2686
+ src: first.url,
2687
+ compact: true,
2688
+ itemKey: entry.id
2689
+ })
2690
+ }) : null,
2691
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2692
+ className: library_module_css_default.cardFoot,
2693
+ children: [
2694
+ entry.category !== void 0 && entry.category !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2695
+ className: library_module_css_default.metaChip,
2696
+ children: entry.type === "voice" ? {
2697
+ male: "男声",
2698
+ female: "女声",
2699
+ custom: "未分级"
2700
+ }[entry.category] ?? entry.category : entry.category
2701
+ }) : null,
2702
+ entry.provenance.model !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2703
+ className: library_module_css_default.metaChip,
2704
+ title: `模型:${entry.provenance.model}`,
2705
+ children: entry.provenance.model
2706
+ }) : null,
2707
+ fileCount > 1 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2708
+ className: library_module_css_default.metaChip,
2709
+ children: ["×", fileCount]
2710
+ }) : null,
2711
+ entry.tags.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2712
+ className: library_module_css_default.metaChip,
2713
+ "data-tag": true,
2714
+ children: [entry.tags[0], entry.tags.length > 1 ? ` +${entry.tags.length - 1}` : ""]
2715
+ }) : null
2716
+ ]
2717
+ })
2718
+ ]
2719
+ }, entry.id);
2720
+ })
2721
+ }),
2722
+ detail !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2723
+ className: library_module_css_default.drawerMask,
2724
+ onClick: () => setDetailId(null),
2725
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
2726
+ className: library_module_css_default.drawer,
2727
+ onClick: (event) => event.stopPropagation(),
2728
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
2729
+ className: library_module_css_default.drawerHead,
2730
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
2731
+ className: library_module_css_default.drawerTitle,
2732
+ children: detail.name
2733
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2734
+ type: "button",
2735
+ className: library_module_css_default.iconBtn,
2736
+ "aria-label": "关闭",
2737
+ onClick: () => setDetailId(null),
2738
+ children: "×"
2739
+ })]
2740
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2741
+ className: library_module_css_default.drawerBody,
2742
+ children: [
2743
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2744
+ className: library_module_css_default.drawerSection,
2745
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2746
+ className: library_module_css_default.drawerPlayerList,
2747
+ children: detail.files.map((file) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2748
+ className: library_module_css_default.drawerPlayer,
2749
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2750
+ className: library_module_css_default.drawerPlayerName,
2751
+ children: file.rel.split("/").pop()
2752
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPlayer, {
2753
+ src: file.url,
2754
+ itemKey: `${file.rel}-${detail.createdAt}`
2755
+ })]
2756
+ }, file.rel))
2757
+ })
2758
+ }),
2759
+ draft !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2760
+ className: library_module_css_default.drawerSection,
2761
+ children: [
2762
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2763
+ className: library_module_css_default.drawerLabel,
2764
+ children: "编辑"
2765
+ }),
2766
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2767
+ className: library_module_css_default.drawerField,
2768
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "名称" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2769
+ className: library_module_css_default.input,
2770
+ value: draft.name,
2771
+ onChange: (event) => setDraft({
2772
+ ...draft,
2773
+ name: event.target.value
2774
+ })
2775
+ })]
2776
+ }),
2777
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2778
+ className: library_module_css_default.drawerField,
2779
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "标签(逗号分隔)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2780
+ className: library_module_css_default.input,
2781
+ value: draft.tags,
2782
+ onChange: (event) => setDraft({
2783
+ ...draft,
2784
+ tags: event.target.value
2785
+ })
2786
+ })]
2787
+ }),
2788
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2789
+ className: library_module_css_default.drawerField,
2790
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "备注" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
2791
+ className: library_module_css_default.textarea,
2792
+ rows: 2,
2793
+ value: draft.note,
2794
+ onChange: (event) => setDraft({
2795
+ ...draft,
2796
+ note: event.target.value
2797
+ })
2798
+ })]
2799
+ }),
2800
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2801
+ className: library_module_css_default.drawerSplit,
2802
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2803
+ className: library_module_css_default.drawerField,
2804
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "类型" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
2805
+ className: library_module_css_default.input,
2806
+ value: draft.type,
2807
+ onChange: (event) => setDraft({
2808
+ ...draft,
2809
+ type: event.target.value,
2810
+ category: ""
2811
+ }),
2812
+ children: TYPE_ORDER.map((type) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2813
+ value: type,
2814
+ children: LIBRARY_TYPE_LABELS[type]
2815
+ }, type))
2816
+ })]
2817
+ }), draft.type === "voice" || draft.type === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2818
+ className: library_module_css_default.drawerField,
2819
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: draft.type === "voice" ? "分级(男/女)" : "音色键" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2820
+ className: library_module_css_default.input,
2821
+ list: "library-category-options",
2822
+ value: draft.category,
2823
+ onChange: (event) => setDraft({
2824
+ ...draft,
2825
+ category: event.target.value
2826
+ }),
2827
+ placeholder: draft.type === "voice" ? "male / female / custom" : "voice 键"
2828
+ })]
2829
+ }) : null]
2830
+ }),
2831
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2832
+ type: "button",
2833
+ className: library_module_css_default.primaryBtn,
2834
+ disabled: busy,
2835
+ onClick: () => void saveDraft(),
2836
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}), " 保存修改"]
2837
+ })
2838
+ ]
2839
+ }) : null,
2840
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2841
+ className: library_module_css_default.drawerSection,
2842
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2843
+ className: library_module_css_default.drawerLabel,
2844
+ children: "来源(可追溯)"
2845
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2846
+ className: library_module_css_default.provenance,
2847
+ children: [
2848
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2849
+ className: library_module_css_default.provRow,
2850
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2851
+ className: library_module_css_default.provKey,
2852
+ children: "类型"
2853
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2854
+ className: library_module_css_default.provValue,
2855
+ children: [
2856
+ LIBRARY_TYPE_LABELS[detail.type],
2857
+ " · ",
2858
+ detail.provenance.mode
2859
+ ]
2860
+ })]
2861
+ }),
2862
+ detail.provenance.channel !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2863
+ className: library_module_css_default.provRow,
2864
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2865
+ className: library_module_css_default.provKey,
2866
+ children: "渠道"
2867
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2868
+ className: library_module_css_default.provValue,
2869
+ children: detail.provenance.channel
2870
+ })]
2871
+ }) : null,
2872
+ detail.provenance.apiUrl !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2873
+ className: library_module_css_default.provRow,
2874
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2875
+ className: library_module_css_default.provKey,
2876
+ children: "API 地址"
2877
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2878
+ className: `${library_module_css_default.provValue} ${library_module_css_default.mono}`,
2879
+ children: detail.provenance.apiUrl
2880
+ })]
2881
+ }) : null,
2882
+ detail.provenance.model !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2883
+ className: library_module_css_default.provRow,
2884
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2885
+ className: library_module_css_default.provKey,
2886
+ children: "模型"
2887
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2888
+ className: library_module_css_default.provValue,
2889
+ children: [detail.provenance.model, detail.provenance.upstream !== void 0 && detail.provenance.upstream !== detail.provenance.model ? ` → ${detail.provenance.upstream}` : ""]
2890
+ })]
2891
+ }) : null,
2892
+ detail.provenance.voice !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2893
+ className: library_module_css_default.provRow,
2894
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2895
+ className: library_module_css_default.provKey,
2896
+ children: "音色"
2897
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2898
+ className: library_module_css_default.provValue,
2899
+ children: detail.provenance.voice
2900
+ })]
2901
+ }) : null,
2902
+ detail.provenance.voiceId !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2903
+ className: library_module_css_default.provRow,
2904
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2905
+ className: library_module_css_default.provKey,
2906
+ children: "Voice ID"
2907
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2908
+ className: library_module_css_default.provValue,
2909
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
2910
+ className: library_module_css_default.code,
2911
+ children: detail.provenance.voiceId
2912
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2913
+ type: "button",
2914
+ className: library_module_css_default.iconBtn,
2915
+ title: "复制 Voice ID",
2916
+ onClick: () => void copyText(detail.provenance.voiceId, `vid-${detail.id}`),
2917
+ children: copied === `vid-${detail.id}` ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyIcon, {})
2918
+ })]
2919
+ })]
2920
+ }) : null,
2921
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2922
+ className: library_module_css_default.provRow,
2923
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2924
+ className: library_module_css_default.provKey,
2925
+ children: "提示词"
2926
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2927
+ className: `${library_module_css_default.provValue} ${library_module_css_default.promptText}`,
2928
+ children: detail.provenance.prompt || "—"
2929
+ })]
2930
+ }),
2931
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2932
+ className: library_module_css_default.provRow,
2933
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2934
+ className: library_module_css_default.provKey,
2935
+ children: "创建时间"
2936
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2937
+ className: library_module_css_default.provValue,
2938
+ children: new Date(detail.createdAt).toLocaleString("zh-CN", { hour12: false })
2939
+ })]
2940
+ }),
2941
+ detail.provenance.params !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2942
+ className: library_module_css_default.provRow,
2943
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2944
+ className: library_module_css_default.provKey,
2945
+ children: "生成参数"
2946
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2947
+ className: library_module_css_default.provValue,
2948
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
2949
+ className: library_module_css_default.paramsDetails,
2950
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "查看参数快照" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
2951
+ className: library_module_css_default.code,
2952
+ children: JSON.stringify(detail.provenance.params, null, 2)
2953
+ })]
2954
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2955
+ type: "button",
2956
+ className: library_module_css_default.iconBtn,
2957
+ title: "复制参数 JSON",
2958
+ onClick: () => void copyText(JSON.stringify(detail.provenance.params, null, 2), `params-${detail.id}`),
2959
+ children: copied === `params-${detail.id}` ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyIcon, {})
2960
+ })]
2961
+ })]
2962
+ }) : null,
2963
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2964
+ className: library_module_css_default.provRow,
2965
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2966
+ className: library_module_css_default.provKey,
2967
+ children: "文件"
2968
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2969
+ className: `${library_module_css_default.provValue} ${library_module_css_default.mono}`,
2970
+ children: [
2971
+ detail.files.length,
2972
+ " 段 · ",
2973
+ detail.files.map((file) => file.rel).join(",")
2974
+ ]
2975
+ })]
2976
+ })
2977
+ ]
2978
+ })]
2979
+ }),
2980
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2981
+ className: library_module_css_default.drawerActions,
2982
+ children: [detail.provenance.voiceId !== void 0 || detail.provenance.voice !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2983
+ type: "button",
2984
+ className: library_module_css_default.primaryBtn,
2985
+ onClick: () => {
2986
+ props.onReuseVoice({
2987
+ mode: "tts",
2988
+ ...detail.provenance.voiceId !== void 0 ? { voiceId: detail.provenance.voiceId } : {},
2989
+ ...detail.provenance.voice !== void 0 ? { voice: detail.provenance.voice } : {},
2990
+ ...detail.provenance.model !== void 0 ? { model: detail.provenance.model } : {}
2991
+ });
2992
+ setDetailId(null);
2993
+ },
2994
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MicIcon, {}), " 用此音色去 TTS"]
2995
+ }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2996
+ type: "button",
2997
+ className: library_module_css_default.dangerBtn,
2998
+ onClick: () => {
2999
+ if (confirmDelete === detail.id) doDelete([detail.id]);
3000
+ else setConfirmDelete(detail.id);
3001
+ },
3002
+ disabled: busy,
3003
+ children: [
3004
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {}),
3005
+ " ",
3006
+ confirmDelete === detail.id ? "确认删除" : "删除资源"
3007
+ ]
3008
+ })]
3009
+ })
3010
+ ]
3011
+ })]
3012
+ })
3013
+ }) : null
3014
+ ]
3015
+ });
3016
+ }
3017
+ //#endregion
3018
+ //#region src/client/AudioGenPanel.tsx
3019
+ /**
3020
+ * The AI 音频 panel shell: header with 生成 / 资源库 tabs, toast host, and
3021
+ * cross-tab hooks (library refresh after saves, «use this voice» reuse).
3022
+ */
3023
+ function AudioGenPanel(props) {
3024
+ const { api, scope } = props;
3025
+ const [tab, setTab] = (0, react.useState)("studio");
3026
+ const [libraryRev, setLibraryRev] = (0, react.useState)(0);
3027
+ const [reuse, setReuse] = (0, react.useState)(null);
3028
+ const [toast, setToast] = (0, react.useState)(null);
3029
+ const toastTimer = (0, react.useRef)(void 0);
3030
+ const showToast = (text) => {
3031
+ setToast(text);
3032
+ if (toastTimer.current !== void 0) window.clearTimeout(toastTimer.current);
3033
+ toastTimer.current = window.setTimeout(() => setToast(null), 2400);
3034
+ };
3035
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3036
+ className: audio_panel_module_css_default.panel,
3037
+ children: [
3038
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
3039
+ className: audio_panel_module_css_default.header,
3040
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
3041
+ className: audio_panel_module_css_default.title,
3042
+ children: tt("panel.title")
3043
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3044
+ className: audio_panel_module_css_default.tabs,
3045
+ role: "tablist",
3046
+ "aria-label": "AI 音频",
3047
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3048
+ type: "button",
3049
+ role: "tab",
3050
+ "aria-selected": tab === "studio",
3051
+ className: audio_panel_module_css_default.tab,
3052
+ "data-active": tab === "studio" ? "true" : "false",
3053
+ onClick: () => setTab("studio"),
3054
+ children: [
3055
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GridIcon, {}),
3056
+ " ",
3057
+ tt("tab.studio")
3058
+ ]
3059
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3060
+ type: "button",
3061
+ role: "tab",
3062
+ "aria-selected": tab === "library",
3063
+ className: audio_panel_module_css_default.tab,
3064
+ "data-active": tab === "library" ? "true" : "false",
3065
+ onClick: () => setTab("library"),
3066
+ children: [
3067
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ListIcon, {}),
3068
+ " ",
3069
+ tt("tab.library")
3070
+ ]
3071
+ })]
3072
+ })]
3073
+ }),
3074
+ tab === "studio" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StudioView, {
3075
+ api,
3076
+ scope,
3077
+ reuse,
3078
+ onLibraryChanged: () => setLibraryRev((revision) => revision + 1),
3079
+ showToast
3080
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LibraryView, {
3081
+ api,
3082
+ revision: libraryRev,
3083
+ showToast,
3084
+ onReuseVoice: (payload) => {
3085
+ setReuse({
3086
+ nonce: Date.now(),
3087
+ mode: payload.mode,
3088
+ ...payload.voice === void 0 ? {} : { voice: payload.voice },
3089
+ ...payload.voiceId === void 0 ? {} : { voiceId: payload.voiceId },
3090
+ ...payload.model === void 0 ? {} : { model: payload.model }
3091
+ });
3092
+ setTab("studio");
3093
+ }
3094
+ }),
3095
+ toast !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3096
+ className: audio_panel_module_css_default.toast,
3097
+ role: "status",
3098
+ children: toast
3099
+ }) : null
3100
+ ]
3101
+ });
3102
+ }
3103
+ //#endregion
3104
+ //#region \0dsh-css:/Users/shimingming/Projects_code/dsh-audiogen/src/client/panel.module.css.mjs
3105
+ const css$2 = "[data-pane=conversation],[class*=centerCol]{position:relative}[data-dsh-audiogen-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0}html[data-dsh-audiogen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-dsh-audiogen-view]{display:block}html[data-dsh-audiogen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-pane=conversation]>:not([data-dsh-audiogen-view]),html[data-dsh-audiogen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [class*=centerCol]>:not([data-dsh-audiogen-view]){display:none!important}.rwa6qG_entry{width:100%;height:32px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:8px;padding:0 12px;font-size:13px;display:flex}.rwa6qG_entry:hover{background:var(--dsw-specific-sidebar-nav-item-hover);color:var(--dsw-alias-label-primary)}.rwa6qG_entry[data-active]{background:var(--dsw-specific-sidebar-nav-item-active);color:var(--dsw-alias-label-primary);font-weight:600}.rwa6qG_entryIcon{flex:none;justify-content:center;align-items:center;display:inline-flex}.rwa6qG_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] .rwa6qG_entry{justify-content:center;width:100%;padding:0}[data-dsh-frame][data-sidebar-collapsed] .rwa6qG_entryLabel{display:none}.rwa6qG_view{overflow:hidden}.rwa6qG_panel,.rwa6qG_panel *,.rwa6qG_panel :before,.rwa6qG_panel :after{box-sizing:border-box}.rwa6qG_panel{background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:10px;padding:14px 16px 16px;display:flex;position:relative;overflow:hidden}.rwa6qG_panelHeader{flex:none;justify-content:space-between;align-items:center;gap:12px;display:flex}.rwa6qG_panelHeading{align-items:baseline;gap:10px;min-width:0;display:flex}.rwa6qG_panelTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:16px;font-weight:700}.rwa6qG_githubLink{width:22px;height:22px;color:var(--dsw-alias-label-secondary);border-radius:6px;flex:none;justify-content:center;align-items:center;text-decoration:none;transition:color .12s,background .12s;display:inline-flex}.rwa6qG_githubLink:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.rwa6qG_connectionStatus{border:1px solid var(--dsw-alias-label-error);height:28px;color:var(--dsw-alias-label-error);font:inherit;white-space:nowrap;background:0 0;border-radius:8px;flex:none;align-items:center;gap:6px;padding:0 10px;font-size:12px;line-height:1;display:inline-flex}.rwa6qG_connectionStatus[data-connected=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.rwa6qG_connectionDot{background:currentColor;border-radius:50%;width:6px;height:6px}.rwa6qG_updateBanner{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-primary);overflow-wrap:anywhere;border-radius:10px;flex:none;justify-content:space-between;align-items:center;gap:12px;padding:7px 10px 7px 12px;font-size:12px;line-height:1.5;display:flex}.rwa6qG_updateBanner[data-kind=ok]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.rwa6qG_updateText{min-width:0}.rwa6qG_updateActions{flex:none;align-items:center;gap:10px;display:inline-flex}.rwa6qG_updateRelease{color:inherit;text-underline-offset:2px;white-space:nowrap;text-decoration:underline}@media (width<=700px){.rwa6qG_panelHeader{align-items:flex-start}.rwa6qG_panelHeading{flex-direction:column;align-items:flex-start;gap:2px}.rwa6qG_updateBanner{flex-direction:column;align-items:flex-start}.rwa6qG_updateActions{justify-content:space-between;width:100%}}.rwa6qG_studio{flex:1;gap:14px;min-width:0;min-height:0;display:flex}.rwa6qG_config{flex-direction:column;flex:none;gap:12px;width:300px;min-width:260px;max-width:340px;height:100%;min-height:0;display:flex;overflow:hidden}.rwa6qG_configScroll{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:12px;min-height:0;padding-right:2px;display:flex;overflow-y:auto}.rwa6qG_configScroll::-webkit-scrollbar{width:8px}.rwa6qG_configScroll::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.rwa6qG_canvas{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:12px;flex-direction:column;flex:1;min-width:0;min-height:0;display:flex;position:relative;overflow:hidden}.rwa6qG_taskTray{z-index:6;border:1px solid var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-bg-layer-1) 92%, transparent);backdrop-filter:blur(10px);border-radius:9px;flex-direction:column;width:min(360px,100% - 24px);max-height:calc(100% - 24px);display:flex;position:absolute;top:12px;right:12px;overflow:hidden;box-shadow:0 8px 24px #0000001f}.rwa6qG_taskTray[data-open=false]{width:auto;max-width:calc(100% - 24px)}.rwa6qG_taskTrayHeader{min-height:34px;color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);align-items:stretch;font-size:12px;font-weight:600;display:flex}.rwa6qG_taskTray[data-open=false] .rwa6qG_taskTrayHeader{border-bottom:0}.rwa6qG_taskTrayToggle{min-width:0;color:inherit;cursor:pointer;font:inherit;font-size:inherit;font-weight:inherit;text-align:left;background:0 0;border:0;flex:1;align-items:center;gap:8px;padding:8px 10px;display:flex}.rwa6qG_taskTrayToggle:hover{background:var(--dsw-alias-bg-layer-2)}.rwa6qG_taskTrayCount{min-width:18px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);text-align:center;border-radius:999px;padding:1px 5px;font-size:11px;font-weight:500}.rwa6qG_taskTrayChevron{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:12px;font-weight:400}.rwa6qG_taskTrayClose{border:0;border-left:1px solid var(--dsw-alias-border-l1);width:32px;color:var(--dsw-alias-label-tertiary);cursor:pointer;font:inherit;background:0 0;font-size:17px}.rwa6qG_taskTrayClose:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.rwa6qG_taskTray[data-open=false] .rwa6qG_taskTrayToggle{min-height:34px}.rwa6qG_taskRows{min-height:0;overflow-y:auto}.rwa6qG_taskTray[data-open=false] .rwa6qG_taskRows{display:none}.rwa6qG_taskRow{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:7px;padding:7px 10px;display:grid}.rwa6qG_taskRow:first-of-type{border-top:0}.rwa6qG_taskStatus{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:11px}.rwa6qG_taskRow[data-status=running] .rwa6qG_taskStatus{color:var(--dsw-alias-brand-primary)}.rwa6qG_taskRow[data-status=failed] .rwa6qG_taskStatus{color:var(--dsw-alias-label-error)}.rwa6qG_taskPrompt{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.rwa6qG_taskRow button{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);cursor:pointer;font:inherit;border:0;border-radius:5px;padding:2px 7px;font-size:11px}.rwa6qG_taskRow button:hover{color:var(--dsw-alias-brand-primary)}.rwa6qG_configGuide{z-index:1100;background:#00000059;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.rwa6qG_configGuideBody{border:1px solid var(--dsw-alias-border-l2);width:min(360px,100%);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border-radius:10px;flex-direction:column;gap:12px;padding:18px;display:flex;box-shadow:0 14px 40px #0003}.rwa6qG_configGuideBody span{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.55}.rwa6qG_configGuideBody button{min-height:30px;color:var(--dsw-alias-bg-layer-1);background:var(--dsw-alias-brand-primary);cursor:pointer;font:inherit;border:0;border-radius:7px;align-self:flex-end;padding:0 12px;font-size:12px}.rwa6qG_history{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:12px;flex-direction:column;flex:none;width:240px;min-width:200px;max-width:280px;min-height:0;display:flex;overflow:hidden}.rwa6qG_historyHeader{border-bottom:1px solid var(--dsw-alias-border-l1);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:10px 12px;display:flex}.rwa6qG_historyFilters{border-bottom:1px solid var(--dsw-alias-border-l1);grid-template-columns:1fr 1fr;gap:6px;padding:8px 10px;display:grid}.rwa6qG_historySearch,.rwa6qG_historyFilters select,.rwa6qG_gallerySearch{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);min-width:0;min-height:29px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;border-radius:7px;padding:0 8px;font-size:11px}.rwa6qG_historySearch{grid-column:1/-1}.rwa6qG_gallerySearch{width:156px}.rwa6qG_galleryTagInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);width:130px;min-height:29px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;border-radius:7px;padding:0 8px;font-size:11px}.rwa6qG_galleryBulkButton{border:1px solid var(--dsw-alias-border-l2);min-height:29px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);cursor:pointer;font:inherit;border-radius:7px;padding:0 8px;font-size:11px}.rwa6qG_galleryBulkButton:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.rwa6qG_galleryBulkButton:disabled{opacity:.45;cursor:default}.rwa6qG_historyTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.rwa6qG_historyClear{font:inherit;color:var(--dsw-alias-label-tertiary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:999px;padding:2px 8px;font-size:11.5px}.rwa6qG_historyClear:hover{color:var(--dsw-alias-label-error);border-color:var(--dsw-alias-label-error)}.rwa6qG_historyList{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:8px;min-height:0;padding:10px;display:flex;overflow-y:auto}.rwa6qG_historyList::-webkit-scrollbar{width:8px}.rwa6qG_historyList::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.rwa6qG_historyEmpty{text-align:center;color:var(--dsw-alias-label-tertiary);flex:1;justify-content:center;align-items:center;padding:20px;font-size:12px;line-height:1.6;display:flex}.rwa6qG_historyItem{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);border-radius:10px;flex-direction:column;flex:none;gap:6px;padding:8px;display:flex}.rwa6qG_historyItem:hover{border-color:var(--dsw-alias-border-l2)}.rwa6qG_historyItem[data-active]{border-color:var(--dsw-alias-brand-primary)}.rwa6qG_historyMain{font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:flex-start;gap:8px;min-width:0;padding:0;display:flex}.rwa6qG_historyThumb{object-fit:cover;background:var(--dsw-alias-bg-base);border-radius:8px;flex:none;width:52px;height:52px}.rwa6qG_historyThumbPlaceholder{background:var(--dsw-alias-bg-layer-3);border-radius:8px;flex:none;width:52px;height:52px}.rwa6qG_historyInfo{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.rwa6qG_historyPrompt{color:var(--dsw-alias-label-primary);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;line-height:1.4;display:-webkit-box;overflow:hidden}.rwa6qG_historyMeta{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.rwa6qG_historyActions{justify-content:flex-end;gap:6px;display:flex}.rwa6qG_historyAction{font:inherit;color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:999px;padding:2px 8px;font-size:11.5px}.rwa6qG_historyAction:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.rwa6qG_historyAction[data-danger]:hover{color:var(--dsw-alias-label-error);border-color:var(--dsw-alias-label-error)}.rwa6qG_card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;flex:none;gap:10px;padding:12px;display:flex}.rwa6qG_modeRow{align-items:center;gap:8px;display:flex}.rwa6qG_modePill{flex:1;justify-content:center;height:28px;font-size:13px}.rwa6qG_uploadBox{min-height:128px;color:var(--dsw-alias-label-secondary);border:1.5px dashed var(--dsw-alias-border-l2);cursor:pointer;font:inherit;text-align:center;background:0 0;border-radius:12px;flex-direction:column;justify-content:center;align-items:center;gap:6px;padding:16px;font-size:12.5px;display:flex}.rwa6qG_uploadBox:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-interactive-bg-hover)}.rwa6qG_uploadBox:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.rwa6qG_uploadIcon{color:var(--dsw-alias-label-tertiary);display:inline-flex}.rwa6qG_uploadHint{color:var(--dsw-alias-label-tertiary);font-size:11px}.rwa6qG_reference{flex-direction:column;gap:8px;display:flex}.rwa6qG_referenceImage{object-fit:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;width:100%;max-height:176px}.rwa6qG_referenceActions{gap:8px;display:flex}.rwa6qG_hiddenFile{display:none}.rwa6qG_prompt{width:100%;min-height:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);resize:vertical;box-sizing:border-box;border-radius:10px;outline:none;padding:10px 12px;font-family:inherit;font-size:13px;line-height:1.6}.rwa6qG_prompt:focus-visible{border-color:var(--dsw-alias-brand-primary)}.rwa6qG_prompt::placeholder{color:var(--dsw-alias-label-tertiary)}.rwa6qG_promptFooter{justify-content:space-between;align-items:center;gap:8px;margin-top:-6px;display:flex}.rwa6qG_templatesButton{border:1px solid var(--dsw-alias-brand-primary);background:linear-gradient(135deg, color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), color-mix(in srgb, var(--dsw-alias-brand-primary) 5%, transparent));height:26px;color:var(--dsw-alias-brand-primary);cursor:pointer;box-shadow:0 1px 0 color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent);border-radius:999px;align-items:center;gap:6px;padding:0 12px;font-family:inherit;font-size:12px;font-weight:600;transition:transform .12s,box-shadow .12s,background .12s;display:inline-flex}.rwa6qG_templatesButton svg{flex:none}.rwa6qG_templatesButton:hover{background:linear-gradient(135deg, color-mix(in srgb, var(--dsw-alias-brand-primary) 24%, transparent), color-mix(in srgb, var(--dsw-alias-brand-primary) 8%, transparent));color:var(--dsw-alias-brand-primary);box-shadow:0 2px 6px color-mix(in srgb, var(--dsw-alias-brand-primary) 30%, transparent);transform:translateY(-1px)}.rwa6qG_templatesButton:active{transform:translateY(0)}.rwa6qG_enhanceButton{border:1px solid var(--dsw-alias-border-l2);height:26px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:999px;margin-left:auto;padding:0 11px;font-size:12px}.rwa6qG_enhanceButton:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.rwa6qG_enhanceButton:disabled{opacity:.5;cursor:default}.rwa6qG_promptCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px}.rwa6qG_paramGroup{flex-direction:column;gap:8px;display:flex}.rwa6qG_paramLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.rwa6qG_optionRow{flex-wrap:wrap;gap:6px;display:flex}.rwa6qG_optionGrid{grid-template-columns:repeat(3,1fr);gap:6px;display:grid}.rwa6qG_optionPill{justify-content:center}.rwa6qG_paramHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.45}.rwa6qG_footer{border-top:1px solid var(--dsw-alias-border-l1);flex-direction:column;flex:none;align-items:stretch;gap:8px;padding:10px 2px 0 0;display:flex}.rwa6qG_modelWrap{flex-direction:column;gap:5px;min-width:0;display:flex}.rwa6qG_modelLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.rwa6qG_modelSelect{width:100%;height:36px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;text-align:left;border-radius:18px;outline:none;justify-content:space-between;align-items:center;gap:8px;padding:0 12px;font-family:inherit;font-size:13px;display:flex}.rwa6qG_modelSelect:focus-visible{border-color:var(--dsw-alias-brand-primary)}.rwa6qG_modelSelect:disabled{opacity:.55;cursor:default}.rwa6qG_modelMenu{min-width:0;display:block;position:relative}.rwa6qG_modelMenuList{z-index:40;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;flex-direction:column;padding:4px;display:flex;position:absolute;bottom:calc(100% + 6px);left:0;right:0;overflow:hidden;box-shadow:0 -8px 24px #0000002e}.rwa6qG_modelMenuItem{width:100%;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;white-space:nowrap;text-overflow:ellipsis;background:0 0;border:none;border-radius:8px;padding:7px 10px;font-size:13px;display:block;overflow:hidden}.rwa6qG_modelMenuItem:hover{background:var(--dsw-alias-bg-hover)}.rwa6qG_modelMenuItem[data-selected]{color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-1);font-weight:600}.rwa6qG_generateButton{width:100%}.rwa6qG_generateInner{align-items:center;gap:7px;display:inline-flex}.rwa6qG_canvasState{text-align:center;color:var(--dsw-alias-label-tertiary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:24px;display:flex}.rwa6qG_canvasStateTitle{color:var(--dsw-alias-label-secondary);font-size:14px;font-weight:600}.rwa6qG_canvasStateHint{max-width:380px;font-size:12px;line-height:1.6}.rwa6qG_canvasEmptyIcon{color:var(--dsw-alias-label-tertiary);margin-bottom:4px;display:inline-flex}.rwa6qG_canvasError{color:var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-label-error);overflow-wrap:anywhere;border-radius:10px;flex:none;margin:14px;padding:10px 14px;font-size:12.5px;line-height:1.6}.rwa6qG_canvasBody{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:10px;min-height:0;padding:14px;display:flex;overflow-y:auto}.rwa6qG_canvasBody::-webkit-scrollbar{width:8px}.rwa6qG_canvasBody::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.rwa6qG_canvasMeta{color:var(--dsw-alias-label-tertiary);flex:none;align-items:center;gap:8px;font-size:12px;display:flex}.rwa6qG_canvasHistoryTag{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);white-space:nowrap;border-radius:999px;padding:1px 8px;font-size:11px}.rwa6qG_grid{flex:1;grid-template-rows:repeat(2,minmax(0,1fr));grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;min-height:0;display:grid}.rwa6qG_grid[data-count=\"1\"] .rwa6qG_imageCard{grid-area:1/1/3/3}.rwa6qG_imageCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);cursor:zoom-in;border-radius:12px;flex-direction:column;min-height:0;margin:0;display:flex;position:relative;overflow:hidden}.rwa6qG_imageCard:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.rwa6qG_image{object-fit:cover;background:var(--dsw-alias-bg-base);flex:1;width:100%;min-height:0;display:block}.rwa6qG_imageCaption{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-overflow:ellipsis;border-top:1px solid var(--dsw-alias-border-l1);padding:7px 10px;font-size:11px;line-height:1.5;overflow:hidden}.rwa6qG_download{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);opacity:0;backdrop-filter:blur(4px);border-radius:999px;padding:2px 10px;font-size:12px;font-weight:500;line-height:20px;text-decoration:none;transition:opacity .12s;position:absolute;top:8px;right:8px}.rwa6qG_imageCard:hover .rwa6qG_download{opacity:1}.rwa6qG_download:hover{background:var(--dsw-alias-bg-base)}.rwa6qG_galleryAdd{font:inherit;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;opacity:0;backdrop-filter:blur(4px);border-radius:999px;align-items:center;gap:5px;padding:2px 10px;font-size:12px;font-weight:500;line-height:20px;transition:opacity .12s;display:inline-flex;position:absolute;top:8px;left:8px}.rwa6qG_imageCard:hover .rwa6qG_galleryAdd{opacity:1}.rwa6qG_galleryAdd:hover{background:var(--dsw-alias-bg-base)}.rwa6qG_galleryAdd:disabled{opacity:.4;cursor:default}.rwa6qG_zoomHint{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);opacity:0;backdrop-filter:blur(4px);pointer-events:none;border-radius:999px;align-items:center;gap:5px;padding:2px 10px;font-size:12px;font-weight:500;line-height:20px;transition:opacity .12s;display:inline-flex;position:absolute;bottom:8px;left:8px}.rwa6qG_imageCard:hover .rwa6qG_zoomHint{opacity:1}.rwa6qG_spinner,.rwa6qG_bigSpinner{border:2px solid;border-top-color:#0000;border-radius:50%;flex:none;animation:.8s linear infinite rwa6qG_dshImageGenSpin;display:inline-block}.rwa6qG_spinner{width:11px;height:11px}.rwa6qG_bigSpinner{width:30px;height:30px;color:var(--dsw-alias-state-business-primary);border-width:3px;margin-bottom:6px}.rwa6qG_lightbox{z-index:1000;backdrop-filter:blur(6px);background:#000000b8;justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}.rwa6qG_lightboxClose{color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;border-radius:50%;justify-content:center;align-items:center;width:38px;height:38px;display:inline-flex;position:absolute;top:16px;right:16px}.rwa6qG_lightboxClose:hover{background:#ffffff42}.rwa6qG_lightboxNav{color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;border-radius:50%;justify-content:center;align-items:center;width:42px;height:42px;display:inline-flex;position:absolute;top:50%;transform:translateY(-50%)}.rwa6qG_lightboxNav:hover{background:#ffffff42}.rwa6qG_lightboxNav[data-dir=prev]{left:max(20px,50% - 640px)}.rwa6qG_lightboxNav[data-dir=next]{right:max(20px,50% - 640px)}.rwa6qG_lightboxFigure{flex-direction:column;gap:10px;width:min(1100px,100vw - 160px);max-width:min(1100px,100vw - 160px);height:min(820px,100vh - 48px);min-height:0;margin:0;display:flex}.rwa6qG_lightboxStage{background:#ffffff0a;border-radius:10px;flex:1;min-height:0;position:relative;overflow:auto}.rwa6qG_lightboxScaleFrame{justify-content:center;align-items:center;min-width:100%;min-height:100%;display:flex}.rwa6qG_lightboxImage{object-fit:contain;border-radius:10px;max-width:100%;max-height:100%;display:block;box-shadow:0 24px 80px #00000080}.rwa6qG_lightboxTools{justify-content:center;align-items:center;gap:6px;display:flex}.rwa6qG_lightboxTool,.rwa6qG_lightboxZoomLevel,.rwa6qG_lightboxCopy{color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;justify-content:center;align-items:center;display:inline-flex}.rwa6qG_lightboxTool,.rwa6qG_lightboxZoomLevel{height:32px}.rwa6qG_lightboxTool{border-radius:50%;width:32px}.rwa6qG_lightboxZoomLevel{min-width:58px;font:inherit;font-variant-numeric:tabular-nums;border-radius:999px;padding:0 9px;font-size:12px}.rwa6qG_lightboxTool:hover,.rwa6qG_lightboxZoomLevel:hover,.rwa6qG_lightboxCopy:hover{background:#ffffff42}.rwa6qG_lightboxCaptionRow{align-items:flex-start;gap:8px;min-width:0;display:flex}.rwa6qG_lightboxCaption{color:#ffffffe6;-webkit-line-clamp:3;-webkit-box-orient:vertical;flex:1;min-width:0;font-size:12px;line-height:1.6;display:-webkit-box;overflow:hidden}.rwa6qG_lightboxCopy{min-height:28px;font:inherit;white-space:nowrap;border-radius:999px;flex:none;gap:5px;padding:4px 9px;font-size:12px}.rwa6qG_lightboxMeta{justify-content:space-between;align-items:center;gap:12px;display:flex}.rwa6qG_lightboxIndex{color:#fffc;font-variant-numeric:tabular-nums;font-size:12px}.rwa6qG_lightboxActions{align-items:center;gap:8px;display:inline-flex}.rwa6qG_lightboxDownload,.rwa6qG_lightboxEdit{font:inherit;color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;border-radius:999px;padding:4px 14px;font-size:12.5px;font-weight:500;text-decoration:none}.rwa6qG_lightboxDownload:hover,.rwa6qG_lightboxEdit:hover{background:#ffffff42}.rwa6qG_lightboxEdit{color:#fff;background:#ffffff24;border:1px solid #ffffff47;border-radius:999px}@media (width<=720px){.rwa6qG_lightbox{padding:16px}.rwa6qG_lightboxFigure{width:calc(100vw - 32px);max-width:none}.rwa6qG_lightboxNav[data-dir=prev]{left:20px}.rwa6qG_lightboxNav[data-dir=next]{right:20px}.rwa6qG_lightboxCaptionRow,.rwa6qG_lightboxMeta{flex-direction:column;align-items:stretch}.rwa6qG_lightboxCopy,.rwa6qG_lightboxActions{align-self:flex-end}}@keyframes rwa6qG_dshImageGenSpin{to{transform:rotate(360deg)}}.rwa6qG_galleryToast{z-index:30;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);backdrop-filter:blur(6px);pointer-events:none;border-radius:999px;align-items:center;gap:7px;padding:6px 16px;font-size:13px;font-weight:500;animation:.16s ease-out rwa6qG_dshImageGenToastIn;display:inline-flex;position:absolute;bottom:24px;left:50%;transform:translate(-50%);box-shadow:0 8px 24px #00000038}@keyframes rwa6qG_dshImageGenToastIn{0%{opacity:0;transform:translate(-50%,6px)}to{opacity:1;transform:translate(-50%)}}@media (prefers-reduced-motion:reduce){.rwa6qG_download,.rwa6qG_spinner,.rwa6qG_bigSpinner{transition:none;animation-duration:1.5s}}.rwa6qG_config[data-gallery=true] .rwa6qG_configScroll>:not(:first-child),.rwa6qG_config[data-gallery=true] .rwa6qG_footer,.rwa6qG_canvas[data-gallery=true]>.rwa6qG_canvasState,.rwa6qG_canvas[data-gallery=true]>.rwa6qG_canvasError,.rwa6qG_canvas[data-gallery=true]>.rwa6qG_canvasBody,.rwa6qG_studio:has(.rwa6qG_config[data-gallery=true])>.rwa6qG_history{display:none}.rwa6qG_config[data-gallery=true] .rwa6qG_configScroll{flex:none;order:1;display:flex;overflow:visible}.rwa6qG_config[data-gallery=true] .rwa6qG_galleryFilters{flex:1;order:2;min-height:0}.rwa6qG_galleryFilters{padding:18px 14px;overflow:hidden auto}.rwa6qG_galleryFilterHeading{color:var(--dsw-alias-label-tertiary);margin:0 4px 10px;font-size:12px;font-weight:600}.rwa6qG_galleryFilter{width:100%;min-height:34px;color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left;background:0 0;border:0;border-radius:9px;justify-content:space-between;align-items:center;padding:0 10px;display:flex}.rwa6qG_galleryFilter:hover,.rwa6qG_galleryFilter[data-active]{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent)}.rwa6qG_galleryFilterCount{min-width:20px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2);text-align:center;border-radius:999px;padding:1px 6px;font-size:11px}.rwa6qG_galleryFilterDivider{background:var(--dsw-alias-border-l1);height:1px;margin:18px 4px}.rwa6qG_galleryRatioList{flex-wrap:wrap;gap:6px;display:flex}.rwa6qG_galleryRatio{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);cursor:pointer;border:0;border-radius:999px;padding:6px 10px;font-size:12px}.rwa6qG_galleryRatio[data-active]{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 13%, transparent)}.rwa6qG_galleryTagFilterList{flex-wrap:wrap;gap:6px;display:flex}.rwa6qG_galleryTagFilter{border:1px solid var(--dsw-alias-border-l1);min-width:0;max-width:100%;min-height:27px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);cursor:pointer;font:inherit;border-radius:6px;align-items:center;gap:5px;padding:0 8px;font-size:11px;display:inline-flex}.rwa6qG_galleryTagFilter span:first-child{text-overflow:ellipsis;white-space:nowrap;max-width:112px;overflow:hidden}.rwa6qG_galleryTagFilter span:last-child{color:var(--dsw-alias-label-tertiary);font-size:10px}.rwa6qG_galleryTagFilter:hover,.rwa6qG_galleryTagFilter[data-active]{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent)}.rwa6qG_galleryFilterNote{color:var(--dsw-alias-label-quaternary);margin:20px 4px 0;font-size:11px;line-height:1.5}.rwa6qG_galleryWorkspace{box-sizing:border-box;flex-direction:column;width:100%;min-width:0;height:100%;min-height:0;padding:22px 24px 26px;display:flex;position:absolute;inset:0;overflow:hidden}.rwa6qG_galleryToolbar{flex:none;justify-content:space-between;align-items:center;gap:16px;min-width:0;margin-bottom:18px;display:flex}.rwa6qG_galleryHeading{color:var(--dsw-alias-label-primary);margin:0;font-size:20px;font-weight:700;display:inline}.rwa6qG_galleryCount{color:var(--dsw-alias-label-tertiary);margin-left:8px;font-size:13px}.rwa6qG_galleryToolbarActions{flex-wrap:wrap;align-items:center;gap:10px;min-width:0;display:flex}.rwa6qG_gallerySelectMode,.rwa6qG_galleryBulkButton,.rwa6qG_gallerySelectionClear{border:1px solid var(--dsw-alias-border-l1);min-height:30px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);cursor:pointer;font:inherit;border-radius:7px;padding:0 10px;font-size:12px}.rwa6qG_gallerySelectMode:hover,.rwa6qG_gallerySelectMode[data-active],.rwa6qG_galleryBulkButton:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:color-mix(in srgb, var(--dsw-alias-brand-primary) 38%, var(--dsw-alias-border-l1));background:color-mix(in srgb, var(--dsw-alias-brand-primary) 11%, transparent)}.rwa6qG_galleryBulkButton:disabled{cursor:not-allowed;opacity:.45}.rwa6qG_gallerySelectionBar{border:1px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 35%, var(--dsw-alias-border-l1));background:color-mix(in srgb, var(--dsw-alias-brand-primary) 7%, var(--dsw-alias-bg-layer-1));border-radius:9px;flex:none;align-items:center;gap:10px;min-width:0;margin:-4px 0 16px;padding:10px 12px;display:flex}.rwa6qG_gallerySelectionBar strong{color:var(--dsw-alias-brand-primary);flex:none;font-size:12px}.rwa6qG_gallerySelectionClear{margin-left:auto}.rwa6qG_gallerySelectionClear:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.rwa6qG_galleryTagInput,.rwa6qG_gallerySearch{border:1px solid var(--dsw-alias-border-l1);min-width:0;height:30px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);font:inherit;border-radius:7px;outline:none;padding:0 10px;font-size:12px}.rwa6qG_galleryTagInput{flex:190px}.rwa6qG_galleryTagInput:focus,.rwa6qG_gallerySearch:focus{border-color:var(--dsw-alias-brand-primary)}.rwa6qG_galleryViewToggle{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:9px;padding:3px;display:flex}.rwa6qG_galleryViewToggle button,.rwa6qG_gallerySort,.rwa6qG_galleryClear{min-height:30px;color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border:0;border-radius:7px;padding:0 10px;font-size:12px}.rwa6qG_galleryViewToggle button[data-active],.rwa6qG_galleryViewToggle button:hover,.rwa6qG_gallerySort:hover,.rwa6qG_galleryClear:hover{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 11%, transparent)}.rwa6qG_gallerySort{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1)}.rwa6qG_galleryClear{border:1px solid var(--dsw-alias-border-l1)}.rwa6qG_compareControl{flex-direction:column;gap:6px;margin:0 0 10px;display:flex}.rwa6qG_compareToggle,.rwa6qG_compareModelChoices label{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;font-size:12px;display:flex}.rwa6qG_compareToggle input,.rwa6qG_compareModelChoices input{accent-color:var(--dsw-alias-brand-primary)}.rwa6qG_compareModelChoices{flex-wrap:wrap;gap:6px;display:flex}.rwa6qG_compareModelChoices label{border:1px solid var(--dsw-alias-border-l1);border-radius:5px;padding:4px 6px;font-size:10px}.rwa6qG_comparisonBoard{z-index:4;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;flex-direction:column;display:flex;position:absolute;inset:14px;overflow:hidden;box-shadow:0 8px 24px #0000001f}.rwa6qG_comparisonBoard>header{border-bottom:1px solid var(--dsw-alias-border-l1);justify-content:space-between;align-items:center;padding:10px 12px;display:flex}.rwa6qG_comparisonBoard>header div{align-items:baseline;gap:7px;display:flex}.rwa6qG_comparisonBoard>header strong{color:var(--dsw-alias-label-primary);font-size:13px}.rwa6qG_comparisonBoard>header span{color:var(--dsw-alias-label-tertiary);font-size:11px}.rwa6qG_comparisonBoard>header button{border:1px solid var(--dsw-alias-border-l1);min-height:28px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);cursor:pointer;font:inherit;border-radius:5px;padding:0 9px;font-size:11px}.rwa6qG_comparisonGrid{flex:1;grid-template-rows:minmax(0,1fr);grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;min-height:0;padding:12px;display:grid;overflow:auto}.rwa6qG_comparisonGrid article{flex-direction:column;gap:7px;min-width:0;height:100%;min-height:0;display:flex}.rwa6qG_comparisonGrid article>strong{color:var(--dsw-alias-label-primary);font-size:12px}.rwa6qG_comparisonImageButton{cursor:zoom-in;background:var(--dsw-alias-bg-base);border:0;flex:1;width:100%;min-height:0;padding:0;display:flex;overflow:hidden}.rwa6qG_comparisonImageButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.rwa6qG_comparisonGrid article>span{min-height:0;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2);flex:1;place-items:center;font-size:12px;display:grid}.rwa6qG_comparisonGrid img{object-fit:contain;background:var(--dsw-alias-bg-base);flex:1;width:100%;height:100%;min-height:0;max-height:none;display:block}.rwa6qG_comparisonFullscreen{z-index:1200;background:#000000eb;padding:54px 24px 24px;position:fixed;inset:0;overflow:auto}.rwa6qG_comparisonFullscreenGrid{grid-template-columns:repeat(auto-fit,minmax(300px,1fr));align-items:start;gap:18px;min-height:100%;display:grid}.rwa6qG_comparisonFullscreen figure{min-width:0;margin:0}.rwa6qG_comparisonFullscreen figcaption{color:#fff;margin-bottom:8px;font-size:13px;font-weight:600}.rwa6qG_comparisonFullscreen img{background:#111;width:100%;margin-bottom:10px;display:block}.rwa6qG_historyItem[data-comparison]{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary) 55%, var(--dsw-alias-border-l1))}.rwa6qG_galleryMasonry{box-sizing:border-box;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex:auto;grid-template-columns:repeat(3,minmax(0,1fr));grid-auto-rows:max-content;align-content:start;gap:16px;width:100%;min-width:0;max-width:100%;height:0;min-height:0;padding:2px 8px 16px 2px;display:grid;overflow:hidden scroll}.rwa6qG_galleryMasonry::-webkit-scrollbar{width:8px}.rwa6qG_galleryMasonry::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.rwa6qG_galleryCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:14px;width:100%;margin:0;display:block;position:relative;overflow:hidden;box-shadow:0 5px 18px #18203612}.rwa6qG_galleryCard[data-selected]{border-color:var(--dsw-alias-brand-primary);box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-brand-primary) 26%, transparent), 0 5px 18px #18203612}.rwa6qG_gallerySelect{z-index:2;cursor:pointer;background:#00000094;border:1px solid #ffffffbf;border-radius:7px;place-items:center;width:26px;height:26px;display:grid;position:absolute;top:9px;right:9px}.rwa6qG_gallerySelect input{width:16px;height:16px;accent-color:var(--dsw-alias-brand-primary);cursor:pointer;margin:0}.rwa6qG_galleryImageButton{background:var(--dsw-alias-bg-base);cursor:zoom-in;border:0;width:100%;padding:0;display:block;position:relative}.rwa6qG_galleryImageButton[data-selecting]{cursor:pointer}.rwa6qG_galleryImage{aspect-ratio:4/3;object-fit:cover;width:100%;display:block}.rwa6qG_galleryMasonry[data-view=masonry] .rwa6qG_galleryCard:nth-child(3n+1) .rwa6qG_galleryImage{aspect-ratio:4/5}.rwa6qG_galleryMasonry[data-view=masonry] .rwa6qG_galleryCard:nth-child(3n+2) .rwa6qG_galleryImage{aspect-ratio:4/3}.rwa6qG_galleryMasonry[data-view=masonry] .rwa6qG_galleryCard:nth-child(3n) .rwa6qG_galleryImage{aspect-ratio:3/4}.rwa6qG_galleryBadge{color:#fff;backdrop-filter:blur(4px);background:#121724c2;border-radius:999px;padding:4px 9px;font-size:11px;position:absolute;top:10px;left:10px}.rwa6qG_galleryCardFooter{align-items:center;gap:9px;min-width:0;padding:10px 12px;display:flex}.rwa6qG_galleryAvatar{color:#fff;background:var(--dsw-alias-brand-primary);border-radius:50%;flex:none;place-items:center;width:27px;height:27px;font-size:12px;font-weight:700;display:grid}.rwa6qG_galleryCardInfo{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.rwa6qG_galleryCardInfo strong,.rwa6qG_galleryCardInfo small{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.rwa6qG_galleryCardInfo strong{color:var(--dsw-alias-label-primary);font-size:12px}.rwa6qG_galleryCardInfo small{color:var(--dsw-alias-label-tertiary);font-size:10px}.rwa6qG_galleryTags{flex-wrap:wrap;gap:4px;margin-top:4px;display:flex}.rwa6qG_galleryTags button{max-width:96px;min-height:19px;color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent);cursor:pointer;font:inherit;text-overflow:ellipsis;white-space:nowrap;border:0;border-radius:4px;padding:1px 6px;font-size:10px;line-height:1.35;overflow:hidden}.rwa6qG_galleryTags button:hover{background:color-mix(in srgb, var(--dsw-alias-brand-primary) 17%, transparent)}.rwa6qG_galleryTags .rwa6qG_galleryTagEdit{color:var(--dsw-alias-label-tertiary);background:0 0;flex:none}.rwa6qG_galleryTagEditor{align-items:center;gap:6px;padding:0 12px 10px 48px;display:flex}.rwa6qG_galleryTagEditor input{border:1px solid var(--dsw-alias-border-l2);min-width:0;height:27px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;border-radius:6px;outline:none;flex:1;padding:0 8px;font-size:11px}.rwa6qG_galleryTagEditor input:focus{border-color:var(--dsw-alias-brand-primary)}.rwa6qG_galleryTagEditor button{border:1px solid var(--dsw-alias-border-l2);height:27px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);cursor:pointer;font:inherit;border-radius:6px;padding:0 8px;font-size:11px}.rwa6qG_galleryTagEditor button[type=submit]{color:var(--dsw-alias-brand-primary)}.rwa6qG_galleryRemove{width:24px;height:24px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:50%;flex:none;padding:0;font-size:18px}.rwa6qG_galleryRemove:hover{color:var(--dsw-alias-state-error);background:var(--dsw-alias-bg-layer-2)}@media (width<=1100px){.rwa6qG_galleryMasonry{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width<=760px){.rwa6qG_studio{flex-direction:column;overflow:auto}.rwa6qG_config{width:auto;max-width:none;height:auto;min-height:0}.rwa6qG_config[data-gallery=true]{flex:none}.rwa6qG_canvas{min-height:560px}.rwa6qG_galleryToolbar{flex-direction:column;align-items:flex-start}.rwa6qG_galleryToolbarActions{flex-wrap:wrap;width:100%}.rwa6qG_galleryMasonry{grid-template-columns:1fr}}";
3106
+ const tagId$2 = "dsh-audiogen/panel.module.css";
3107
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
3108
+ const tag = document.createElement("style");
3109
+ tag.dataset.plugin = "dsh-audiogen";
3110
+ tag.dataset.pluginCss = tagId$2;
3111
+ tag.textContent = css$2;
3112
+ document.head.appendChild(tag);
3113
+ }
3114
+ var panel_module_css_default = {
3115
+ "lightboxDownload": "rwa6qG_lightboxDownload",
3116
+ "galleryHeading": "rwa6qG_galleryHeading",
3117
+ "panelTitle": "rwa6qG_panelTitle",
3118
+ "canvasStateHint": "rwa6qG_canvasStateHint",
3119
+ "compareToggle": "rwa6qG_compareToggle",
3120
+ "generateInner": "rwa6qG_generateInner",
3121
+ "config": "rwa6qG_config",
3122
+ "galleryViewToggle": "rwa6qG_galleryViewToggle",
1247
3123
  "galleryRatio": "rwa6qG_galleryRatio",
1248
- "generateButton": "rwa6qG_generateButton",
1249
- "galleryCardFooter": "rwa6qG_galleryCardFooter",
1250
- "historyMain": "rwa6qG_historyMain",
1251
- "gallerySelectionClear": "rwa6qG_gallerySelectionClear",
1252
- "templatesButton": "rwa6qG_templatesButton",
1253
- "comparisonImageButton": "rwa6qG_comparisonImageButton",
1254
- "galleryAvatar": "rwa6qG_galleryAvatar",
1255
- "panelHeader": "rwa6qG_panelHeader",
3124
+ "canvasError": "rwa6qG_canvasError",
3125
+ "galleryMasonry": "rwa6qG_galleryMasonry",
3126
+ "galleryFilterDivider": "rwa6qG_galleryFilterDivider",
3127
+ "lightboxZoomLevel": "rwa6qG_lightboxZoomLevel",
3128
+ "reference": "rwa6qG_reference",
3129
+ "lightboxEdit": "rwa6qG_lightboxEdit",
3130
+ "lightboxTool": "rwa6qG_lightboxTool",
1256
3131
  "githubLink": "rwa6qG_githubLink",
1257
- "lightboxCaptionRow": "rwa6qG_lightboxCaptionRow",
1258
- "comparisonBoard": "rwa6qG_comparisonBoard",
1259
- "galleryTagEdit": "rwa6qG_galleryTagEdit",
1260
- "uploadBox": "rwa6qG_uploadBox",
1261
- "lightboxImage": "rwa6qG_lightboxImage",
1262
- "galleryCard": "rwa6qG_galleryCard",
1263
- "taskTrayChevron": "rwa6qG_taskTrayChevron",
1264
- "entry": "rwa6qG_entry",
1265
- "historyThumbPlaceholder": "rwa6qG_historyThumbPlaceholder",
1266
- "taskTrayToggle": "rwa6qG_taskTrayToggle",
1267
- "galleryTagFilterList": "rwa6qG_galleryTagFilterList",
1268
- "taskTrayHeader": "rwa6qG_taskTrayHeader",
1269
- "modelMenuItem": "rwa6qG_modelMenuItem",
1270
- "galleryCardInfo": "rwa6qG_galleryCardInfo",
1271
- "canvasStateHint": "rwa6qG_canvasStateHint",
1272
- "taskRow": "rwa6qG_taskRow",
3132
+ "galleryAdd": "rwa6qG_galleryAdd",
3133
+ "lightboxCaption": "rwa6qG_lightboxCaption",
3134
+ "panelHeader": "rwa6qG_panelHeader",
3135
+ "lightboxScaleFrame": "rwa6qG_lightboxScaleFrame",
3136
+ "configGuide": "rwa6qG_configGuide",
3137
+ "canvasBody": "rwa6qG_canvasBody",
3138
+ "galleryBadge": "rwa6qG_galleryBadge",
3139
+ "historyEmpty": "rwa6qG_historyEmpty",
3140
+ "connectionDot": "rwa6qG_connectionDot",
3141
+ "paramLabel": "rwa6qG_paramLabel",
3142
+ "configScroll": "rwa6qG_configScroll",
3143
+ "galleryToast": "rwa6qG_galleryToast",
3144
+ "lightbox": "rwa6qG_lightbox",
3145
+ "updateRelease": "rwa6qG_updateRelease",
3146
+ "canvasState": "rwa6qG_canvasState",
3147
+ "lightboxIndex": "rwa6qG_lightboxIndex",
3148
+ "optionRow": "rwa6qG_optionRow",
1273
3149
  "modePill": "rwa6qG_modePill",
1274
- "grid": "rwa6qG_grid",
1275
- "paramGroup": "rwa6qG_paramGroup",
3150
+ "lightboxImage": "rwa6qG_lightboxImage",
3151
+ "updateBanner": "rwa6qG_updateBanner",
1276
3152
  "hiddenFile": "rwa6qG_hiddenFile",
1277
- "galleryFilterCount": "rwa6qG_galleryFilterCount",
3153
+ "modelWrap": "rwa6qG_modelWrap",
3154
+ "galleryAvatar": "rwa6qG_galleryAvatar",
3155
+ "canvasMeta": "rwa6qG_canvasMeta",
3156
+ "galleryCardFooter": "rwa6qG_galleryCardFooter",
3157
+ "comparisonImageButton": "rwa6qG_comparisonImageButton",
3158
+ "historyTitle": "rwa6qG_historyTitle",
3159
+ "galleryTagEditor": "rwa6qG_galleryTagEditor",
3160
+ "generateButton": "rwa6qG_generateButton",
3161
+ "historyAction": "rwa6qG_historyAction",
1278
3162
  "connectionStatus": "rwa6qG_connectionStatus",
1279
- "historyPrompt": "rwa6qG_historyPrompt",
1280
- "gallerySelectionBar": "rwa6qG_gallerySelectionBar",
1281
- "galleryViewToggle": "rwa6qG_galleryViewToggle",
1282
- "updateRelease": "rwa6qG_updateRelease",
1283
- "configGuideBody": "rwa6qG_configGuideBody",
1284
- "historyEmpty": "rwa6qG_historyEmpty",
1285
- "galleryFilterDivider": "rwa6qG_galleryFilterDivider",
3163
+ "taskTrayChevron": "rwa6qG_taskTrayChevron",
3164
+ "galleryBulkButton": "rwa6qG_galleryBulkButton",
3165
+ "referenceActions": "rwa6qG_referenceActions",
3166
+ "historyThumb": "rwa6qG_historyThumb",
3167
+ "panel": "rwa6qG_panel",
3168
+ "paramGroup": "rwa6qG_paramGroup",
1286
3169
  "galleryTagFilter": "rwa6qG_galleryTagFilter",
1287
- "galleryBadge": "rwa6qG_galleryBadge",
3170
+ "comparisonBoard": "rwa6qG_comparisonBoard",
3171
+ "paramHint": "rwa6qG_paramHint",
3172
+ "modelSelect": "rwa6qG_modelSelect",
3173
+ "historyMeta": "rwa6qG_historyMeta",
3174
+ "galleryTags": "rwa6qG_galleryTags",
3175
+ "uploadBox": "rwa6qG_uploadBox",
1288
3176
  "modelLabel": "rwa6qG_modelLabel",
1289
- "taskTray": "rwa6qG_taskTray",
1290
- "taskTrayCount": "rwa6qG_taskTrayCount",
1291
- "historyHeader": "rwa6qG_historyHeader",
1292
- "taskStatus": "rwa6qG_taskStatus",
3177
+ "gallerySelectionClear": "rwa6qG_gallerySelectionClear",
3178
+ "modeRow": "rwa6qG_modeRow",
3179
+ "spinner": "rwa6qG_spinner",
3180
+ "historyPrompt": "rwa6qG_historyPrompt",
3181
+ "modelMenuList": "rwa6qG_modelMenuList",
3182
+ "optionGrid": "rwa6qG_optionGrid",
3183
+ "image": "rwa6qG_image",
3184
+ "lightboxStage": "rwa6qG_lightboxStage",
3185
+ "lightboxCopy": "rwa6qG_lightboxCopy",
3186
+ "lightboxFigure": "rwa6qG_lightboxFigure",
3187
+ "panelHeading": "rwa6qG_panelHeading",
3188
+ "galleryFilters": "rwa6qG_galleryFilters",
3189
+ "lightboxMeta": "rwa6qG_lightboxMeta",
3190
+ "galleryRatioList": "rwa6qG_galleryRatioList",
3191
+ "configGuideBody": "rwa6qG_configGuideBody",
3192
+ "canvasStateTitle": "rwa6qG_canvasStateTitle",
3193
+ "entryIcon": "rwa6qG_entryIcon",
3194
+ "updateText": "rwa6qG_updateText",
3195
+ "galleryToolbar": "rwa6qG_galleryToolbar",
3196
+ "gallerySelectionBar": "rwa6qG_gallerySelectionBar",
3197
+ "galleryImageButton": "rwa6qG_galleryImageButton",
3198
+ "galleryCardInfo": "rwa6qG_galleryCardInfo",
3199
+ "taskPrompt": "rwa6qG_taskPrompt",
3200
+ "imageCard": "rwa6qG_imageCard",
3201
+ "canvasEmptyIcon": "rwa6qG_canvasEmptyIcon",
3202
+ "modelMenu": "rwa6qG_modelMenu",
3203
+ "galleryClear": "rwa6qG_galleryClear",
3204
+ "compareControl": "rwa6qG_compareControl",
3205
+ "view": "rwa6qG_view",
3206
+ "taskTrayHeader": "rwa6qG_taskTrayHeader",
3207
+ "bigSpinner": "rwa6qG_bigSpinner",
1293
3208
  "promptFooter": "rwa6qG_promptFooter",
1294
- "enhanceButton": "rwa6qG_enhanceButton",
1295
- "historyItem": "rwa6qG_historyItem",
1296
- "lightboxNav": "rwa6qG_lightboxNav",
3209
+ "taskTray": "rwa6qG_taskTray",
3210
+ "historyInfo": "rwa6qG_historyInfo",
3211
+ "gallerySort": "rwa6qG_gallerySort",
1297
3212
  "galleryCount": "rwa6qG_galleryCount",
1298
- "promptCount": "rwa6qG_promptCount",
1299
- "optionGrid": "rwa6qG_optionGrid",
1300
- "historySearch": "rwa6qG_historySearch",
1301
- "panel": "rwa6qG_panel",
1302
- "modelMenu": "rwa6qG_modelMenu",
1303
- "lightboxZoomLevel": "rwa6qG_lightboxZoomLevel",
1304
- "lightboxDownload": "rwa6qG_lightboxDownload",
1305
- "canvasError": "rwa6qG_canvasError",
1306
- "footer": "rwa6qG_footer",
1307
- "historyTitle": "rwa6qG_historyTitle",
1308
- "canvasState": "rwa6qG_canvasState",
3213
+ "studio": "rwa6qG_studio",
3214
+ "historyHeader": "rwa6qG_historyHeader",
3215
+ "grid": "rwa6qG_grid",
3216
+ "lightboxNav": "rwa6qG_lightboxNav",
3217
+ "taskTrayCount": "rwa6qG_taskTrayCount",
3218
+ "updateActions": "rwa6qG_updateActions",
1309
3219
  "imageCaption": "rwa6qG_imageCaption",
3220
+ "historyItem": "rwa6qG_historyItem",
3221
+ "optionPill": "rwa6qG_optionPill",
3222
+ "modelMenuItem": "rwa6qG_modelMenuItem",
3223
+ "lightboxCaptionRow": "rwa6qG_lightboxCaptionRow",
3224
+ "comparisonGrid": "rwa6qG_comparisonGrid",
3225
+ "galleryTagFilterList": "rwa6qG_galleryTagFilterList",
3226
+ "galleryImage": "rwa6qG_galleryImage",
3227
+ "enhanceButton": "rwa6qG_enhanceButton",
1310
3228
  "dshImageGenToastIn": "rwa6qG_dshImageGenToastIn",
1311
- "galleryClear": "rwa6qG_galleryClear",
1312
- "compareModelChoices": "rwa6qG_compareModelChoices",
1313
- "galleryTags": "rwa6qG_galleryTags",
1314
- "galleryBulkButton": "rwa6qG_galleryBulkButton",
1315
- "referenceActions": "rwa6qG_referenceActions",
3229
+ "historyThumbPlaceholder": "rwa6qG_historyThumbPlaceholder",
3230
+ "entry": "rwa6qG_entry",
3231
+ "prompt": "rwa6qG_prompt",
3232
+ "gallerySearch": "rwa6qG_gallerySearch",
3233
+ "galleryFilterCount": "rwa6qG_galleryFilterCount",
3234
+ "historySearch": "rwa6qG_historySearch",
3235
+ "galleryToolbarActions": "rwa6qG_galleryToolbarActions",
3236
+ "comparisonFullscreen": "rwa6qG_comparisonFullscreen",
3237
+ "templatesButton": "rwa6qG_templatesButton",
3238
+ "footer": "rwa6qG_footer",
3239
+ "lightboxTools": "rwa6qG_lightboxTools",
3240
+ "referenceImage": "rwa6qG_referenceImage",
3241
+ "uploadHint": "rwa6qG_uploadHint",
3242
+ "galleryTagEdit": "rwa6qG_galleryTagEdit",
3243
+ "canvasHistoryTag": "rwa6qG_canvasHistoryTag",
3244
+ "galleryFilter": "rwa6qG_galleryFilter",
3245
+ "taskTrayToggle": "rwa6qG_taskTrayToggle",
3246
+ "canvas": "rwa6qG_canvas",
3247
+ "historyMain": "rwa6qG_historyMain",
3248
+ "promptCount": "rwa6qG_promptCount",
3249
+ "historyActions": "rwa6qG_historyActions",
3250
+ "lightboxActions": "rwa6qG_lightboxActions",
3251
+ "galleryWorkspace": "rwa6qG_galleryWorkspace",
1316
3252
  "galleryFilterNote": "rwa6qG_galleryFilterNote",
1317
- "spinner": "rwa6qG_spinner",
1318
- "configGuide": "rwa6qG_configGuide",
1319
- "galleryImage": "rwa6qG_galleryImage",
1320
- "gallerySelect": "rwa6qG_gallerySelect",
3253
+ "historyFilters": "rwa6qG_historyFilters",
3254
+ "compareModelChoices": "rwa6qG_compareModelChoices",
3255
+ "comparisonFullscreenGrid": "rwa6qG_comparisonFullscreenGrid",
3256
+ "taskRow": "rwa6qG_taskRow",
1321
3257
  "historyClear": "rwa6qG_historyClear",
3258
+ "zoomHint": "rwa6qG_zoomHint",
3259
+ "galleryRemove": "rwa6qG_galleryRemove",
3260
+ "gallerySelectMode": "rwa6qG_gallerySelectMode",
3261
+ "lightboxClose": "rwa6qG_lightboxClose",
1322
3262
  "entryLabel": "rwa6qG_entryLabel",
1323
- "galleryToolbarActions": "rwa6qG_galleryToolbarActions",
1324
- "comparisonGrid": "rwa6qG_comparisonGrid",
1325
- "galleryTagEditor": "rwa6qG_galleryTagEditor",
1326
- "galleryAdd": "rwa6qG_galleryAdd",
1327
- "lightboxMeta": "rwa6qG_lightboxMeta",
3263
+ "uploadIcon": "rwa6qG_uploadIcon",
3264
+ "galleryFilterHeading": "rwa6qG_galleryFilterHeading",
3265
+ "gallerySelect": "rwa6qG_gallerySelect",
3266
+ "taskTrayClose": "rwa6qG_taskTrayClose",
1328
3267
  "download": "rwa6qG_download",
1329
- "updateActions": "rwa6qG_updateActions",
1330
- "studio": "rwa6qG_studio",
3268
+ "card": "rwa6qG_card",
3269
+ "dshImageGenSpin": "rwa6qG_dshImageGenSpin",
3270
+ "historyList": "rwa6qG_historyList",
3271
+ "history": "rwa6qG_history",
3272
+ "galleryCard": "rwa6qG_galleryCard",
3273
+ "taskStatus": "rwa6qG_taskStatus",
1331
3274
  "taskRows": "rwa6qG_taskRows",
1332
- "galleryRatioList": "rwa6qG_galleryRatioList",
1333
- "bigSpinner": "rwa6qG_bigSpinner",
1334
- "historyMeta": "rwa6qG_historyMeta",
1335
- "gallerySelectMode": "rwa6qG_gallerySelectMode",
1336
- "connectionDot": "rwa6qG_connectionDot",
1337
- "modelSelect": "rwa6qG_modelSelect",
1338
- "imageCard": "rwa6qG_imageCard",
1339
- "lightboxEdit": "rwa6qG_lightboxEdit",
1340
- "panelHeading": "rwa6qG_panelHeading",
1341
- "referenceImage": "rwa6qG_referenceImage",
1342
- "reference": "rwa6qG_reference",
1343
- "canvasStateTitle": "rwa6qG_canvasStateTitle",
1344
- "modeRow": "rwa6qG_modeRow",
1345
- "historyInfo": "rwa6qG_historyInfo",
1346
- "taskTrayClose": "rwa6qG_taskTrayClose",
1347
- "zoomHint": "rwa6qG_zoomHint",
1348
- "optionRow": "rwa6qG_optionRow",
1349
- "updateBanner": "rwa6qG_updateBanner",
1350
- "entryIcon": "rwa6qG_entryIcon",
1351
- "view": "rwa6qG_view",
1352
- "galleryToast": "rwa6qG_galleryToast",
1353
- "panelTitle": "rwa6qG_panelTitle",
1354
- "gallerySearch": "rwa6qG_gallerySearch",
1355
- "canvasMeta": "rwa6qG_canvasMeta",
1356
- "lightboxCopy": "rwa6qG_lightboxCopy",
1357
- "lightboxTool": "rwa6qG_lightboxTool"
3275
+ "galleryTagInput": "rwa6qG_galleryTagInput"
1358
3276
  };
1359
3277
  //#endregion
1360
3278
  //#region src/client/mount.tsx
@@ -2011,79 +3929,79 @@ window.__ModuleLoader__.load({
2011
3929
  document.head.appendChild(tag);
2012
3930
  }
2013
3931
  var settings_card_module_css_default = {
2014
- "modelCatalogTools": "zmjoSq_modelCatalogTools",
2015
- "candidateList": "zmjoSq_candidateList",
2016
- "modelCatalogTitle": "zmjoSq_modelCatalogTitle",
2017
- "headText": "zmjoSq_headText",
2018
- "editorTitle": "zmjoSq_editorTitle",
2019
- "customSettingsBody": "zmjoSq_customSettingsBody",
2020
- "modelCatalogMeta": "zmjoSq_modelCatalogMeta",
2021
- "description": "zmjoSq_description",
2022
- "channelRow": "zmjoSq_channelRow",
2023
- "channelDanger": "zmjoSq_channelDanger",
2024
- "editorTag": "zmjoSq_editorTag",
2025
- "input": "zmjoSq_input",
2026
- "modelCatalogHead": "zmjoSq_modelCatalogHead",
2027
- "pending": "zmjoSq_pending",
2028
- "modelArrow": "zmjoSq_modelArrow",
2029
- "save": "zmjoSq_save",
2030
- "channelSection": "zmjoSq_channelSection",
2031
- "modelCatalog": "zmjoSq_modelCatalog",
2032
- "channelHost": "zmjoSq_channelHost",
2033
- "editorHeader": "zmjoSq_editorHeader",
2034
- "modelCategorySelect": "zmjoSq_modelCategorySelect",
2035
- "modelInput": "zmjoSq_modelInput",
2036
- "channelAdd": "zmjoSq_channelAdd",
2037
- "modelRow": "zmjoSq_modelRow",
2038
- "field": "zmjoSq_field",
2039
- "candidateHead": "zmjoSq_candidateHead",
2040
- "channelEditor": "zmjoSq_channelEditor",
2041
- "modelBadge": "zmjoSq_modelBadge",
2042
- "candidateTitle": "zmjoSq_candidateTitle",
2043
- "channelEmpty": "zmjoSq_channelEmpty",
2044
- "footer": "zmjoSq_footer",
2045
- "channelName": "zmjoSq_channelName",
2046
- "candidatePanel": "zmjoSq_candidatePanel",
2047
- "discard": "zmjoSq_discard",
2048
- "label": "zmjoSq_label",
2049
- "channelAddRow": "zmjoSq_channelAddRow",
3932
+ "candidateLabel": "zmjoSq_candidateLabel",
2050
3933
  "chevronOpen": "zmjoSq_chevronOpen",
2051
- "sectionTitle": "zmjoSq_sectionTitle",
2052
- "failed": "zmjoSq_failed",
2053
- "reset": "zmjoSq_reset",
2054
- "editorWrap": "zmjoSq_editorWrap",
2055
- "customSettingsSummary": "zmjoSq_customSettingsSummary",
2056
- "card": "zmjoSq_card",
2057
- "candidateId": "zmjoSq_candidateId",
2058
3934
  "channelMeta": "zmjoSq_channelMeta",
3935
+ "modelBadge": "zmjoSq_modelBadge",
3936
+ "candidatePanel": "zmjoSq_candidatePanel",
3937
+ "channelEditor": "zmjoSq_channelEditor",
3938
+ "channelList": "zmjoSq_channelList",
2059
3939
  "sectionHint": "zmjoSq_sectionHint",
3940
+ "channelAction": "zmjoSq_channelAction",
3941
+ "card": "zmjoSq_card",
3942
+ "link": "zmjoSq_link",
3943
+ "channelDotWarn": "zmjoSq_channelDotWarn",
3944
+ "headText": "zmjoSq_headText",
3945
+ "modelCatalog": "zmjoSq_modelCatalog",
3946
+ "modelEmpty": "zmjoSq_modelEmpty",
3947
+ "candidateList": "zmjoSq_candidateList",
3948
+ "label": "zmjoSq_label",
2060
3949
  "body": "zmjoSq_body",
3950
+ "reset": "zmjoSq_reset",
3951
+ "channelAddRow": "zmjoSq_channelAddRow",
3952
+ "customSettings": "zmjoSq_customSettings",
3953
+ "channelRow": "zmjoSq_channelRow",
3954
+ "modelRows": "zmjoSq_modelRows",
3955
+ "candidateTitle": "zmjoSq_candidateTitle",
3956
+ "description": "zmjoSq_description",
2061
3957
  "candidateActions": "zmjoSq_candidateActions",
2062
- "name": "zmjoSq_name",
3958
+ "modelCatalogTools": "zmjoSq_modelCatalogTools",
2063
3959
  "head": "zmjoSq_head",
2064
- "modelEmpty": "zmjoSq_modelEmpty",
3960
+ "input": "zmjoSq_input",
3961
+ "channelSection": "zmjoSq_channelSection",
3962
+ "select": "zmjoSq_select",
3963
+ "modelCatalogMeta": "zmjoSq_modelCatalogMeta",
3964
+ "candidateId": "zmjoSq_candidateId",
3965
+ "modelCatalogTitle": "zmjoSq_modelCatalogTitle",
3966
+ "deleteConfirmText": "zmjoSq_deleteConfirmText",
3967
+ "readOnly": "zmjoSq_readOnly",
2065
3968
  "sectionHeader": "zmjoSq_sectionHeader",
2066
- "channelDotReady": "zmjoSq_channelDotReady",
2067
- "channelList": "zmjoSq_channelList",
2068
- "channelMain": "zmjoSq_channelMain",
2069
- "header": "zmjoSq_header",
3969
+ "failed": "zmjoSq_failed",
2070
3970
  "modelRowRemove": "zmjoSq_modelRowRemove",
3971
+ "editorTag": "zmjoSq_editorTag",
3972
+ "footer": "zmjoSq_footer",
3973
+ "header": "zmjoSq_header",
2071
3974
  "addModel": "zmjoSq_addModel",
3975
+ "editorWrap": "zmjoSq_editorWrap",
3976
+ "channelName": "zmjoSq_channelName",
2072
3977
  "candidate": "zmjoSq_candidate",
2073
- "candidateLabel": "zmjoSq_candidateLabel",
2074
- "readOnly": "zmjoSq_readOnly",
2075
- "link": "zmjoSq_link",
2076
- "deleteConfirmText": "zmjoSq_deleteConfirmText",
2077
- "channelDotWarn": "zmjoSq_channelDotWarn",
2078
- "channelAction": "zmjoSq_channelAction",
2079
- "editorFooter": "zmjoSq_editorFooter",
2080
- "chevron": "zmjoSq_chevron",
2081
- "linkButton": "zmjoSq_linkButton",
2082
- "modelRows": "zmjoSq_modelRows",
3978
+ "modelCatalogHead": "zmjoSq_modelCatalogHead",
3979
+ "modelInput": "zmjoSq_modelInput",
2083
3980
  "channelBadge": "zmjoSq_channelBadge",
2084
- "select": "zmjoSq_select",
2085
- "customSettings": "zmjoSq_customSettings",
2086
- "detectOk": "zmjoSq_detectOk"
3981
+ "modelArrow": "zmjoSq_modelArrow",
3982
+ "channelDanger": "zmjoSq_channelDanger",
3983
+ "channelDotReady": "zmjoSq_channelDotReady",
3984
+ "editorTitle": "zmjoSq_editorTitle",
3985
+ "modelRow": "zmjoSq_modelRow",
3986
+ "modelCategorySelect": "zmjoSq_modelCategorySelect",
3987
+ "discard": "zmjoSq_discard",
3988
+ "linkButton": "zmjoSq_linkButton",
3989
+ "chevron": "zmjoSq_chevron",
3990
+ "channelMain": "zmjoSq_channelMain",
3991
+ "detectOk": "zmjoSq_detectOk",
3992
+ "field": "zmjoSq_field",
3993
+ "editorHeader": "zmjoSq_editorHeader",
3994
+ "pending": "zmjoSq_pending",
3995
+ "save": "zmjoSq_save",
3996
+ "channelHost": "zmjoSq_channelHost",
3997
+ "editorFooter": "zmjoSq_editorFooter",
3998
+ "sectionTitle": "zmjoSq_sectionTitle",
3999
+ "candidateHead": "zmjoSq_candidateHead",
4000
+ "name": "zmjoSq_name",
4001
+ "channelAdd": "zmjoSq_channelAdd",
4002
+ "customSettingsSummary": "zmjoSq_customSettingsSummary",
4003
+ "customSettingsBody": "zmjoSq_customSettingsBody",
4004
+ "channelEmpty": "zmjoSq_channelEmpty"
2087
4005
  };
2088
4006
  //#endregion
2089
4007
  //#region src/client/SettingsCard.tsx
@@ -2110,7 +4028,8 @@ window.__ModuleLoader__.load({
2110
4028
  booleanField("enabled"),
2111
4029
  booleanField("announceToAgent"),
2112
4030
  booleanField("allowAgentAudioGeneration"),
2113
- textField("defaultModel")
4031
+ textField("defaultModel"),
4032
+ booleanField("autoSaveToLibrary")
2114
4033
  ]);
2115
4034
  this.channelsForm = new ChannelsForm(scope);
2116
4035
  }
@@ -2123,7 +4042,8 @@ window.__ModuleLoader__.load({
2123
4042
  enabled: this.form.field("enabled"),
2124
4043
  announceToAgent: this.form.field("announceToAgent"),
2125
4044
  allowAgentAudioGeneration: this.form.field("allowAgentAudioGeneration"),
2126
- defaultModel: this.form.field("defaultModel")
4045
+ defaultModel: this.form.field("defaultModel"),
4046
+ autoSaveToLibrary: this.form.field("autoSaveToLibrary")
2127
4047
  };
2128
4048
  }
2129
4049
  inject() {
@@ -2946,6 +4866,22 @@ window.__ModuleLoader__.load({
2946
4866
  ]
2947
4867
  })
2948
4868
  }),
4869
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4870
+ className: settings_card_module_css_default.field,
4871
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
4872
+ className: settings_card_module_css_default.label,
4873
+ children: [
4874
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4875
+ type: "checkbox",
4876
+ checked: state.autoSaveToLibrary.text === "true",
4877
+ disabled: !state.writable,
4878
+ onChange: (event) => props.edit("autoSaveToLibrary", String(event.target.checked))
4879
+ }),
4880
+ " ",
4881
+ t("settings.autoSaveLibrary")
4882
+ ]
4883
+ })
4884
+ }),
2949
4885
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2950
4886
  className: settings_card_module_css_default.footer,
2951
4887
  children: [
@@ -2988,17 +4924,17 @@ window.__ModuleLoader__.load({
2988
4924
  document.head.appendChild(tag);
2989
4925
  }
2990
4926
  var audio_toolview_module_css_default = {
4927
+ "header": "_7K1QKa_header",
4928
+ "audios": "_7K1QKa_audios",
4929
+ "empty": "_7K1QKa_empty",
2991
4930
  "message": "_7K1QKa_message",
2992
- "root": "_7K1QKa_root",
2993
- "error": "_7K1QKa_error",
2994
4931
  "audio": "_7K1QKa_audio",
2995
- "empty": "_7K1QKa_empty",
2996
- "status": "_7K1QKa_status",
2997
- "audioRow": "_7K1QKa_audioRow",
4932
+ "root": "_7K1QKa_root",
2998
4933
  "download": "_7K1QKa_download",
2999
4934
  "icon": "_7K1QKa_icon",
3000
- "audios": "_7K1QKa_audios",
3001
- "header": "_7K1QKa_header"
4935
+ "status": "_7K1QKa_status",
4936
+ "audioRow": "_7K1QKa_audioRow",
4937
+ "error": "_7K1QKa_error"
3002
4938
  };
3003
4939
  //#endregion
3004
4940
  //#region src/client/audio-toolview.tsx