dsh-audiogen 0.4.0 → 0.4.2

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
@@ -16,6 +16,8 @@ window.__ModuleLoader__.load({
16
16
  };
17
17
  /** The audio-generation proxy route. */
18
18
  const GENERATE_API = "/api/dsh-audiogen/generate";
19
+ /** Loopback-only task cancellation route (aborts the host-side upstream call). */
20
+ const TASK_API = { cancel: "/api/dsh-audiogen/task/cancel" };
19
21
  /** Host-mediated built-in provider catalog (channels the user can instantiate). */
20
22
  const PRESETS_API = "/api/dsh-audiogen/presets";
21
23
  /** Host-mediated model/voice discovery endpoint. */
@@ -42,31 +44,39 @@ window.__ModuleLoader__.load({
42
44
  * Browser-side API client for the audio generation, history and
43
45
  * resource-library routes.
44
46
  */
47
+ /** POST helper: the host API requires the JSON content type on every POST. */
48
+ function postJson(path, body, signal) {
49
+ return fetch(path, {
50
+ method: "POST",
51
+ headers: { "content-type": "application/json" },
52
+ body: JSON.stringify(body),
53
+ ...signal === void 0 ? {} : { signal }
54
+ });
55
+ }
45
56
  var AudiogenApi = class {
46
- async generate(request) {
47
- return await (await fetch(GENERATE_API, {
48
- method: "POST",
49
- headers: { "content-type": "application/json" },
50
- body: JSON.stringify(request)
51
- })).json();
57
+ async generate(request, signal) {
58
+ return await (await postJson(GENERATE_API, {
59
+ ...request,
60
+ taskId: request.taskId
61
+ }, signal)).json();
62
+ }
63
+ /** 取消进行中的任务:宿主侧中断全部在途上游调用,剩余模型跳过。 */
64
+ async cancelTask(taskId) {
65
+ await postJson(TASK_API.cancel, { taskId }).catch(() => {});
52
66
  }
53
67
  async history() {
54
- const body = await (await fetch(HISTORY_API.list, { method: "POST" })).json();
68
+ const body = await (await postJson(HISTORY_API.list, {})).json();
55
69
  return body.ok === true ? body.history ?? [] : [];
56
70
  }
57
71
  async clearHistory() {
58
- await fetch(HISTORY_API.clear, { method: "POST" });
72
+ await postJson(HISTORY_API.clear, {});
59
73
  }
60
74
  async libraryList() {
61
- const body = await (await fetch(LIBRARY_API.list, { method: "POST" })).json();
75
+ const body = await (await postJson(LIBRARY_API.list, {})).json();
62
76
  return body.ok === true ? body.entries ?? [] : [];
63
77
  }
64
78
  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();
79
+ const body = await (await postJson(LIBRARY_API.save, request)).json();
70
80
  return {
71
81
  ok: body.ok === true,
72
82
  ...body.entry === void 0 ? {} : { entry: body.entry },
@@ -74,11 +84,7 @@ window.__ModuleLoader__.load({
74
84
  };
75
85
  }
76
86
  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();
87
+ const body = await (await postJson(LIBRARY_API.update, request)).json();
82
88
  return {
83
89
  ok: body.ok === true,
84
90
  ...body.entry === void 0 ? {} : { entry: body.entry },
@@ -86,11 +92,7 @@ window.__ModuleLoader__.load({
86
92
  };
87
93
  }
88
94
  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 };
95
+ return { ok: (await (await postJson(LIBRARY_API.remove, { ids })).json()).ok === true };
94
96
  }
95
97
  };
96
98
  //#endregion
@@ -164,6 +166,7 @@ window.__ModuleLoader__.load({
164
166
  "settings.announceToAgent": "向 Agent 播报本插件",
165
167
  "settings.allowAgentAudio": "允许 Agent 调用音频生成",
166
168
  "settings.autoSaveLibrary": "生成后自动保存到资源库",
169
+ "settings.maxConcurrent": "最大并发生成数(同时打到上游的请求数,默认 5)",
167
170
  "settings.save": "保存",
168
171
  "settings.saving": "保存中…",
169
172
  "settings.discard": "放弃修改",
@@ -265,6 +268,7 @@ window.__ModuleLoader__.load({
265
268
  "settings.announceToAgent": "Announce this plugin to agents",
266
269
  "settings.allowAgentAudio": "Allow agents to generate audio",
267
270
  "settings.autoSaveLibrary": "Auto-save generated audio to the library",
271
+ "settings.maxConcurrent": "Max concurrent generations (in-flight upstream calls, default 5)",
268
272
  "settings.save": "Save",
269
273
  "settings.saving": "Saving…",
270
274
  "settings.discard": "Discard",
@@ -765,12 +769,6 @@ window.__ModuleLoader__.load({
765
769
  controller.load();
766
770
  return controller;
767
771
  }
768
- /**
769
- * Flatten the configured channels into the model options the panel lists
770
- * (aliases; the default channel's models first) plus the default channel id.
771
- * Falls back to the legacy flat allow-list while no channels exist (upgrade
772
- * path). Pure projection — no host calls.
773
- */
774
772
  function audioModelOptions(config) {
775
773
  const channels = config?.channels ?? [];
776
774
  if (channels.length === 0) return { models: [] };
@@ -785,7 +783,10 @@ window.__ModuleLoader__.load({
785
783
  seen.add(model.alias);
786
784
  models.push({
787
785
  alias: model.alias,
788
- ...model.category === void 0 ? {} : { category: model.category }
786
+ ...model.category === void 0 ? {} : { category: model.category },
787
+ channelId: channel.id,
788
+ channelName: channel.name,
789
+ preset: channel.preset
789
790
  });
790
791
  }
791
792
  }
@@ -798,8 +799,346 @@ window.__ModuleLoader__.load({
798
799
  };
799
800
  }
800
801
  //#endregion
802
+ //#region src/client/field-specs.ts
803
+ const PRESET_MINIMAX = "minimax";
804
+ const PRESET_ELEVENLABS = "elevenlabs";
805
+ const PRESET_STABILITY = "stability-audio";
806
+ /** 各 preset 支持的音乐输出格式(交集用于全局字段)。 */
807
+ const MUSIC_FORMATS = {
808
+ [PRESET_MINIMAX]: [
809
+ "mp3",
810
+ "wav",
811
+ "pcm"
812
+ ],
813
+ [PRESET_ELEVENLABS]: ["mp3", "wav"],
814
+ [PRESET_STABILITY]: ["mp3", "wav"]
815
+ };
816
+ const MUSIC_KEYS = [
817
+ "duration",
818
+ "format",
819
+ "lyrics",
820
+ "instrumental",
821
+ "sampleRate",
822
+ "bitrate"
823
+ ];
824
+ const TTS_KEYS = [
825
+ "voice",
826
+ "speed",
827
+ "format",
828
+ "emotion",
829
+ "vol",
830
+ "pitch",
831
+ "toneText",
832
+ "sampleRate",
833
+ "bitrate",
834
+ "audioChannel",
835
+ "subtitle"
836
+ ];
837
+ const SFX_KEYS = [
838
+ "duration",
839
+ "format",
840
+ "loop",
841
+ "promptInfluence",
842
+ "seed",
843
+ "steps",
844
+ "cfgScale"
845
+ ];
846
+ function presetSupports(preset, key, mode) {
847
+ const p = preset.toLowerCase();
848
+ if (!(MUSIC_KEYS.includes(key) ? MUSIC_KEYS : TTS_KEYS.includes(key) ? TTS_KEYS : SFX_KEYS).includes(key)) return true;
849
+ switch (key) {
850
+ case "lyrics":
851
+ case "instrumental": return p === PRESET_MINIMAX || p === PRESET_ELEVENLABS;
852
+ case "sampleRate":
853
+ case "bitrate":
854
+ case "audioChannel": return p === PRESET_MINIMAX;
855
+ case "emotion":
856
+ case "vol":
857
+ case "pitch":
858
+ case "toneText":
859
+ case "subtitle": return p === PRESET_MINIMAX;
860
+ case "loop":
861
+ case "promptInfluence": return p === PRESET_ELEVENLABS;
862
+ case "seed":
863
+ case "steps":
864
+ case "cfgScale": return p === PRESET_STABILITY;
865
+ default: return true;
866
+ }
867
+ }
868
+ const SPECS = {
869
+ duration: {
870
+ label: "时长(秒)",
871
+ type: "number",
872
+ min: 1,
873
+ max: 120,
874
+ placeholder: "30",
875
+ hint: "duration;MiniMax 音乐 ≤190、ElevenLabs 音乐 3-600(转 ms)、Stability 按模型 190/380"
876
+ },
877
+ format: {
878
+ label: "输出格式",
879
+ type: "select",
880
+ options: [
881
+ "mp3",
882
+ "wav",
883
+ "pcm",
884
+ "flac",
885
+ "ogg"
886
+ ],
887
+ hint: "format / output_format / response_format"
888
+ },
889
+ lyrics: {
890
+ label: "歌词(纯音乐模式可留空;多段用空行分隔)",
891
+ type: "text",
892
+ placeholder: "第一段歌词…\n\n第二段歌词…",
893
+ hint: "MiniMax lyrics / ElevenLabs lyrics_text"
894
+ },
895
+ instrumental: {
896
+ label: "纯音乐(无歌词/人声)",
897
+ type: "checkbox",
898
+ hint: "MiniMax is_instrumental / ElevenLabs force_instrumental"
899
+ },
900
+ sampleRate: {
901
+ label: "采样率",
902
+ type: "select",
903
+ options: [
904
+ "16000",
905
+ "24000",
906
+ "32000",
907
+ "44100"
908
+ ],
909
+ placeholder: "默认(44100)",
910
+ hint: "audio_setting.sample_rate:16000-44100"
911
+ },
912
+ bitrate: {
913
+ label: "码率 bps",
914
+ type: "select",
915
+ options: [
916
+ "32000",
917
+ "64000",
918
+ "128000",
919
+ "256000"
920
+ ],
921
+ placeholder: "默认(256000)",
922
+ hint: "audio_setting.bitrate:32000-256000"
923
+ },
924
+ audioChannel: {
925
+ label: "声道",
926
+ type: "select",
927
+ options: ["1", "2"],
928
+ placeholder: "默认(1)",
929
+ hint: "audio_setting.channel(TTS)"
930
+ },
931
+ voice: {
932
+ label: "音色",
933
+ type: "text",
934
+ placeholder: "自定义音色",
935
+ hint: "voice_id(MiniMax 必填)/ voice(ElevenLabs)"
936
+ },
937
+ speed: {
938
+ label: "语速",
939
+ type: "number",
940
+ min: .5,
941
+ max: 2,
942
+ step: .1,
943
+ placeholder: "1.0",
944
+ hint: "speed(MiniMax 0.5-2)"
945
+ },
946
+ emotion: {
947
+ label: "情绪 emotion",
948
+ type: "text",
949
+ placeholder: "happy / sad / angry / nervous…",
950
+ hint: "voice_setting.emotion",
951
+ advanced: true
952
+ },
953
+ vol: {
954
+ label: "音量 vol (0-10)",
955
+ type: "number",
956
+ min: 0,
957
+ max: 10,
958
+ step: .5,
959
+ placeholder: "1",
960
+ hint: "voice_setting.vol",
961
+ advanced: true
962
+ },
963
+ pitch: {
964
+ label: "音调 pitch (-12~12)",
965
+ type: "number",
966
+ min: -12,
967
+ max: 12,
968
+ placeholder: "0",
969
+ hint: "voice_setting.pitch",
970
+ advanced: true
971
+ },
972
+ toneText: {
973
+ label: "发音词典(每行一条:\"文字/读音\")",
974
+ type: "text",
975
+ placeholder: "处理/(chu3)(li3)\n危险/dangerous",
976
+ hint: "pronunciation_dict.tone",
977
+ advanced: true
978
+ },
979
+ subtitle: {
980
+ label: "生成字幕 subtitle_enable",
981
+ type: "checkbox",
982
+ hint: "subtitle_enable",
983
+ advanced: true
984
+ },
985
+ loop: {
986
+ label: "循环音效 loop(无缝循环)",
987
+ type: "checkbox",
988
+ hint: "ElevenLabs loop(仅 eleven_text_to_sound_v2)"
989
+ },
990
+ promptInfluence: {
991
+ label: "提示词影响度 prompt_influence (0-1)",
992
+ type: "number",
993
+ min: 0,
994
+ max: 1,
995
+ step: .1,
996
+ placeholder: "0.3",
997
+ hint: "prompt_influence:越高越贴提示词"
998
+ },
999
+ seed: {
1000
+ label: "seed",
1001
+ type: "number",
1002
+ min: 0,
1003
+ max: 4294967294,
1004
+ placeholder: "默认(随机)",
1005
+ hint: "Stable Audio seed(同参数可复现)"
1006
+ },
1007
+ steps: {
1008
+ label: "steps",
1009
+ type: "number",
1010
+ min: 4,
1011
+ max: 100,
1012
+ placeholder: "默认",
1013
+ hint: "Stable Audio 采样步数(2: 30-100;2.5/3: 4-8)"
1014
+ },
1015
+ cfgScale: {
1016
+ label: "cfg_scale",
1017
+ type: "number",
1018
+ min: 1,
1019
+ max: 25,
1020
+ placeholder: "默认",
1021
+ hint: "Stable Audio 提示词遵循度(2 默认 7,2.5/3 默认 1)"
1022
+ }
1023
+ };
1024
+ function specOf(key, presets) {
1025
+ return {
1026
+ key,
1027
+ ...SPECS[key],
1028
+ ...presets === void 0 ? {} : { presets }
1029
+ };
1030
+ }
1031
+ /** 当前模式 + 所选模型集合(渠道集合)对应的「全局字段」清单。 */
1032
+ function globalFieldSpecs(mode, presets) {
1033
+ const list = [];
1034
+ const all = (key, keys) => keys.includes(key) && presets.every((preset) => presetSupports(preset, key, mode));
1035
+ if (mode === "tts") {
1036
+ list.push(specOf("voice"), specOf("speed"));
1037
+ list.push({
1038
+ ...specOf("format"),
1039
+ options: [
1040
+ "mp3",
1041
+ "wav",
1042
+ "flac",
1043
+ "ogg",
1044
+ "pcm"
1045
+ ]
1046
+ });
1047
+ const advanced = [
1048
+ "emotion",
1049
+ "vol",
1050
+ "pitch",
1051
+ "toneText",
1052
+ "sampleRate",
1053
+ "bitrate",
1054
+ "audioChannel",
1055
+ "subtitle"
1056
+ ].filter((key) => all(key, TTS_KEYS) && presets.length > 0);
1057
+ for (const key of advanced) list.push(specOf(key));
1058
+ } else if (mode === "music") {
1059
+ list.push(specOf("duration"));
1060
+ const supported = presets.length === 0 ? [[
1061
+ "mp3",
1062
+ "wav",
1063
+ "pcm"
1064
+ ]] : presets.map((preset) => MUSIC_FORMATS[preset.toLowerCase()] ?? ["mp3", "wav"]);
1065
+ const intersect = supported.reduce((acc, cur) => acc.filter((item) => cur.includes(item)), supported[0] ?? ["mp3", "wav"]);
1066
+ list.push({
1067
+ ...specOf("format"),
1068
+ options: intersect.length > 0 ? intersect : ["mp3", "wav"]
1069
+ });
1070
+ if (all("lyrics", MUSIC_KEYS) && presets.length > 0) list.push(specOf("lyrics"));
1071
+ if (all("instrumental", MUSIC_KEYS) && presets.length > 0) list.push(specOf("instrumental"));
1072
+ if (all("sampleRate", MUSIC_KEYS) && presets.length > 0) list.push(specOf("sampleRate"));
1073
+ if (all("bitrate", MUSIC_KEYS) && presets.length > 0) list.push(specOf("bitrate"));
1074
+ } else if (mode === "sfx") {
1075
+ list.push(specOf("duration"));
1076
+ list.push({
1077
+ ...specOf("format"),
1078
+ options: [
1079
+ "mp3",
1080
+ "wav",
1081
+ "pcm"
1082
+ ]
1083
+ });
1084
+ if (all("loop", SFX_KEYS) && presets.length > 0) list.push(specOf("loop"));
1085
+ if (all("promptInfluence", SFX_KEYS) && presets.length > 0) list.push(specOf("promptInfluence"));
1086
+ if (all("seed", SFX_KEYS) && presets.length > 0) list.push(specOf("seed"), specOf("steps"), specOf("cfgScale"));
1087
+ }
1088
+ return list;
1089
+ }
1090
+ /** 「每模型参数覆盖」矩阵的字段全集(含适用渠道标注)。 */
1091
+ function overrideRowSpecs(mode) {
1092
+ const rows = [];
1093
+ const presets = [
1094
+ ["format", [
1095
+ PRESET_MINIMAX,
1096
+ PRESET_ELEVENLABS,
1097
+ PRESET_STABILITY
1098
+ ]],
1099
+ ["duration", [
1100
+ PRESET_MINIMAX,
1101
+ PRESET_ELEVENLABS,
1102
+ PRESET_STABILITY
1103
+ ]],
1104
+ ["voice", [PRESET_MINIMAX, PRESET_ELEVENLABS]],
1105
+ ["speed", [PRESET_MINIMAX, PRESET_ELEVENLABS]],
1106
+ ["lyrics", [PRESET_MINIMAX, PRESET_ELEVENLABS]],
1107
+ ["instrumental", [PRESET_MINIMAX, PRESET_ELEVENLABS]],
1108
+ ["sampleRate", [PRESET_MINIMAX]],
1109
+ ["bitrate", [PRESET_MINIMAX]],
1110
+ ["audioChannel", [PRESET_MINIMAX]],
1111
+ ["emotion", [PRESET_MINIMAX]],
1112
+ ["vol", [PRESET_MINIMAX]],
1113
+ ["pitch", [PRESET_MINIMAX]],
1114
+ ["toneText", [PRESET_MINIMAX]],
1115
+ ["subtitle", [PRESET_MINIMAX]],
1116
+ ["loop", [PRESET_ELEVENLABS]],
1117
+ ["promptInfluence", [PRESET_ELEVENLABS]],
1118
+ ["seed", [PRESET_STABILITY]],
1119
+ ["steps", [PRESET_STABILITY]],
1120
+ ["cfgScale", [PRESET_STABILITY]]
1121
+ ];
1122
+ for (const [key, applicable] of presets) {
1123
+ const spec = specOf(key, applicable);
1124
+ rows.push({
1125
+ ...spec,
1126
+ presets: applicable
1127
+ });
1128
+ }
1129
+ return rows;
1130
+ }
1131
+ /** 渠道 preset 的展示名。 */
1132
+ function presetLabel(preset) {
1133
+ if (preset === PRESET_MINIMAX) return "MiniMax";
1134
+ if (preset === PRESET_ELEVENLABS) return "ElevenLabs";
1135
+ if (preset === PRESET_STABILITY) return "Stability";
1136
+ if (preset === "openai-tts") return "OpenAI";
1137
+ return "自定义";
1138
+ }
1139
+ //#endregion
801
1140
  //#region \0dsh-css:/Users/shimingming/Projects_code/dsh-audiogen/src/client/audio-panel.module.css.mjs
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}}";
1141
+ 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_compareBox{border:1px dashed var(--dsw-alias-brand-primary,#2563eb);background:color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 4%, var(--dsw-alias-bg-layer-1,#fff));border-radius:10px;flex-direction:column;gap:7px;padding:9px 11px;display:flex}.Oo1fpq_compareChips{flex-wrap:wrap;gap:6px;display:flex}.Oo1fpq_compareChip{border:1px solid var(--dsw-alias-border-l2,#d1d5db);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;padding:0 11px;font-family:inherit;font-size:12px;transition:color .12s,border-color .12s,background .12s;display:inline-flex}.Oo1fpq_compareChip:hover{color:var(--dsw-alias-label-primary,#1f2328);border-color:var(--dsw-alias-label-dimmed,#9ca3af)}.Oo1fpq_compareChip[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}.Oo1fpq_compareBoard{flex-direction:column;gap:12px;display:flex}.Oo1fpq_compareGroup{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:11px;display:flex}.Oo1fpq_compareGroup[data-state=running]{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary,#2563eb) 45%, var(--dsw-alias-border-l1,#e5e7eb))}.Oo1fpq_compareGroup[data-state=done]{border-color:color-mix(in srgb, #10b981 45%, var(--dsw-alias-border-l1,#e5e7eb))}.Oo1fpq_compareGroup[data-state=error]{border-color:color-mix(in srgb, var(--dsw-alias-label-error,#b91c1c) 45%, var(--dsw-alias-border-l1,#e5e7eb))}.Oo1fpq_compareGroupHead{justify-content:space-between;align-items:center;gap:10px;display:flex}.Oo1fpq_compareModelName{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l1,#e5e7eb);color:var(--dsw-alias-label-primary,#1f2328);text-overflow:ellipsis;white-space:nowrap;border-radius:999px;padding:3px 10px;font-size:12px;font-weight:600;overflow:hidden}.Oo1fpq_compareState{color:var(--dsw-alias-label-tertiary,#9ca3af);white-space:nowrap;align-items:center;gap:5px;font-size:11px;display:inline-flex}.Oo1fpq_compareGroup[data-state=running] .Oo1fpq_compareState{color:var(--dsw-alias-brand-primary,#2563eb)}.Oo1fpq_compareGroup[data-state=done] .Oo1fpq_compareState{color:#059669}.Oo1fpq_compareGroup[data-state=error] .Oo1fpq_compareState,.Oo1fpq_hint[data-error]{color:var(--dsw-alias-label-error,#b91c1c)}.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}.Oo1fpq_taskList{flex-direction:column;gap:14px;display:flex}.Oo1fpq_taskCard{border:1px solid var(--dsw-alias-border-l2,#d1d5db);background:var(--dsw-alias-bg-layer-2,#fafafa);border-radius:10px;flex-direction:column;gap:8px;padding:10px 12px;display:flex}.Oo1fpq_taskCard[data-state=failed]{border-color:#dc2626}.Oo1fpq_taskCard[data-state=cancelled]{opacity:.75}.Oo1fpq_taskHead{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.Oo1fpq_taskLabel{color:var(--dsw-alias-label-primary,#1f2328);text-overflow:ellipsis;white-space:nowrap;max-width:200px;font-size:13px;font-weight:600;overflow:hidden}.Oo1fpq_taskStatus{color:var(--dsw-alias-label-secondary,#6b7280);font-size:12px}.Oo1fpq_taskStatus[data-state=done]{color:#16a34a}.Oo1fpq_taskStatus[data-state=failed]{color:#dc2626}.Oo1fpq_taskActions{gap:6px;margin-left:auto;display:flex}.Oo1fpq_historyTabs{flex-wrap:wrap;gap:6px;margin-bottom:10px;display:flex}.Oo1fpq_historyTab{border:1px solid var(--dsw-alias-border-l2,#d1d5db);cursor:pointer;background:var(--dsw-alias-bg-layer-3,#fff);color:var(--dsw-alias-label-secondary,#6b7280);border-radius:999px;padding:3px 10px;font-size:12px}.Oo1fpq_historyTab[data-active=true]{background:var(--dsw-alias-bg-hover,#f3f4f6);color:var(--dsw-alias-label-primary,#1f2328);font-weight:600}.Oo1fpq_historyTabCount{color:var(--dsw-alias-label-tertiary,#9ca3af);margin-left:4px;font-size:11px}.Oo1fpq_historyCompareSummary{cursor:pointer;flex-wrap:wrap;align-items:center;gap:8px;display:flex}.Oo1fpq_historyCompareBadge{color:#7c3aed;white-space:nowrap;background:#f5f3ff;border:1px solid #ddd6fe;border-radius:999px;padding:1px 8px;font-size:11px;font-weight:600}.Oo1fpq_historyModelRow{border-top:1px dashed var(--dsw-alias-border-l1,#e5e7eb);flex-direction:column;gap:4px;margin-top:8px;padding-top:8px;display:flex}.Oo1fpq_overrideOnly{color:var(--dsw-alias-label-tertiary,#9ca3af);font-size:10px;font-weight:500}.Oo1fpq_overrideDash{color:var(--dsw-alias-label-tertiary,#9ca3af);padding:0 6px}";
803
1142
  const tagId$4 = "dsh-audiogen/audio-panel.module.css";
804
1143
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
805
1144
  const tag = document.createElement("style");
@@ -809,68 +1148,101 @@ window.__ModuleLoader__.load({
809
1148
  document.head.appendChild(tag);
810
1149
  }
811
1150
  var audio_panel_module_css_default = {
812
- "playButton": "Oo1fpq_playButton",
813
- "secondaryButton": "Oo1fpq_secondaryButton",
814
- "iconButton": "Oo1fpq_iconButton",
1151
+ "checkbox": "Oo1fpq_checkbox",
1152
+ "historyList": "Oo1fpq_historyList",
1153
+ "compareChips": "Oo1fpq_compareChips",
1154
+ "historyCompareBadge": "Oo1fpq_historyCompareBadge",
815
1155
  "title": "Oo1fpq_title",
816
- "historyCol": "Oo1fpq_historyCol",
817
- "audioList": "Oo1fpq_audioList",
818
- "savedChip": "Oo1fpq_savedChip",
819
- "ghostButton": "Oo1fpq_ghostButton",
820
- "resultCol": "Oo1fpq_resultCol",
821
- "modalFoot": "Oo1fpq_modalFoot",
822
- "hint": "Oo1fpq_hint",
823
1156
  "modeRow": "Oo1fpq_modeRow",
824
- "modeButton": "Oo1fpq_modeButton",
825
- "historyItem": "Oo1fpq_historyItem",
826
- "resultEmpty": "Oo1fpq_resultEmpty",
827
- "advanced": "Oo1fpq_advanced",
1157
+ "compareBox": "Oo1fpq_compareBox",
1158
+ "historyEmpty": "Oo1fpq_historyEmpty",
1159
+ "resultGroup": "Oo1fpq_resultGroup",
1160
+ "taskStatus": "Oo1fpq_taskStatus",
1161
+ "compareBoard": "Oo1fpq_compareBoard",
1162
+ "overrideCell": "Oo1fpq_overrideCell",
1163
+ "taskActions": "Oo1fpq_taskActions",
1164
+ "historyTabCount": "Oo1fpq_historyTabCount",
1165
+ "modalFoot": "Oo1fpq_modalFoot",
1166
+ "historyModelRow": "Oo1fpq_historyModelRow",
828
1167
  "resultMeta": "Oo1fpq_resultMeta",
829
- "historyClear": "Oo1fpq_historyClear",
1168
+ "textarea": "Oo1fpq_textarea",
1169
+ "taskCard": "Oo1fpq_taskCard",
1170
+ "overrideOnly": "Oo1fpq_overrideOnly",
1171
+ "resultCol": "Oo1fpq_resultCol",
1172
+ "tab": "Oo1fpq_tab",
1173
+ "audioList": "Oo1fpq_audioList",
1174
+ "playerCompact": "Oo1fpq_playerCompact",
1175
+ "historyActions": "Oo1fpq_historyActions",
1176
+ "resultGroups": "Oo1fpq_resultGroups",
1177
+ "resultGroupCount": "Oo1fpq_resultGroupCount",
1178
+ "compareGroupHead": "Oo1fpq_compareGroupHead",
1179
+ "historyTabs": "Oo1fpq_historyTabs",
1180
+ "formRow": "Oo1fpq_formRow",
1181
+ "modal": "Oo1fpq_modal",
1182
+ "iconButton": "Oo1fpq_iconButton",
830
1183
  "historyTitle": "Oo1fpq_historyTitle",
831
- "resultModeChip": "Oo1fpq_resultModeChip",
832
- "checkbox": "Oo1fpq_checkbox",
1184
+ "overrideRow": "Oo1fpq_overrideRow",
833
1185
  "track": "Oo1fpq_track",
1186
+ "historyMeta": "Oo1fpq_historyMeta",
1187
+ "trackKnob": "Oo1fpq_trackKnob",
1188
+ "modalMask": "Oo1fpq_modalMask",
1189
+ "secondaryButton": "Oo1fpq_secondaryButton",
1190
+ "hint": "Oo1fpq_hint",
1191
+ "muteButton": "Oo1fpq_muteButton",
1192
+ "historyPrompt": "Oo1fpq_historyPrompt",
1193
+ "audioCardIndex": "Oo1fpq_audioCardIndex",
1194
+ "time": "Oo1fpq_time",
1195
+ "resultGroupError": "Oo1fpq_resultGroupError",
1196
+ "overrideCellHead": "Oo1fpq_overrideCellHead",
1197
+ "modeButton": "Oo1fpq_modeButton",
1198
+ "historyAction": "Oo1fpq_historyAction",
1199
+ "audioCardActions": "Oo1fpq_audioCardActions",
1200
+ "generate": "Oo1fpq_generate",
834
1201
  "panel": "Oo1fpq_panel",
835
- "modal": "Oo1fpq_modal",
836
- "historyActions": "Oo1fpq_historyActions",
1202
+ "compareState": "Oo1fpq_compareState",
1203
+ "compareGroup": "Oo1fpq_compareGroup",
1204
+ "row": "Oo1fpq_row",
1205
+ "taskList": "Oo1fpq_taskList",
1206
+ "resultEmptyHint": "Oo1fpq_resultEmptyHint",
1207
+ "modalHead": "Oo1fpq_modalHead",
1208
+ "taskHead": "Oo1fpq_taskHead",
1209
+ "taskLabel": "Oo1fpq_taskLabel",
1210
+ "historyCompareSummary": "Oo1fpq_historyCompareSummary",
1211
+ "historyClear": "Oo1fpq_historyClear",
837
1212
  "primaryButton": "Oo1fpq_primaryButton",
838
- "playerCompact": "Oo1fpq_playerCompact",
1213
+ "savedChip": "Oo1fpq_savedChip",
1214
+ "overrideDash": "Oo1fpq_overrideDash",
839
1215
  "modalBody": "Oo1fpq_modalBody",
840
- "modalHead": "Oo1fpq_modalHead",
841
- "historyEmpty": "Oo1fpq_historyEmpty",
842
- "historyPrompt": "Oo1fpq_historyPrompt",
843
- "historyAction": "Oo1fpq_historyAction",
844
- "header": "Oo1fpq_header",
1216
+ "historyTab": "Oo1fpq_historyTab",
845
1217
  "audioCardHead": "Oo1fpq_audioCardHead",
846
- "tab": "Oo1fpq_tab",
847
- "row": "Oo1fpq_row",
848
- "formCol": "Oo1fpq_formCol",
849
- "input": "Oo1fpq_input",
850
- "historyList": "Oo1fpq_historyList",
851
- "formRow": "Oo1fpq_formRow",
852
- "historyMeta": "Oo1fpq_historyMeta",
853
- "trackKnob": "Oo1fpq_trackKnob",
854
- "audioCardIndex": "Oo1fpq_audioCardIndex",
855
1218
  "historyHeader": "Oo1fpq_historyHeader",
856
- "modalMask": "Oo1fpq_modalMask",
857
- "audiogenToastIn": "Oo1fpq_audiogenToastIn",
858
- "voiceIdChip": "Oo1fpq_voiceIdChip",
1219
+ "resultGroupHead": "Oo1fpq_resultGroupHead",
1220
+ "audioCard": "Oo1fpq_audioCard",
1221
+ "compareChip": "Oo1fpq_compareChip",
1222
+ "overrideTable": "Oo1fpq_overrideTable",
859
1223
  "label": "Oo1fpq_label",
860
1224
  "error": "Oo1fpq_error",
861
- "generate": "Oo1fpq_generate",
862
- "audioCardActions": "Oo1fpq_audioCardActions",
863
- "time": "Oo1fpq_time",
1225
+ "header": "Oo1fpq_header",
1226
+ "advanced": "Oo1fpq_advanced",
864
1227
  "tabs": "Oo1fpq_tabs",
865
- "resultEmptyHint": "Oo1fpq_resultEmptyHint",
866
- "studio": "Oo1fpq_studio",
867
1228
  "resultEmptyIcon": "Oo1fpq_resultEmptyIcon",
868
- "audioCard": "Oo1fpq_audioCard",
869
1229
  "player": "Oo1fpq_player",
870
- "toast": "Oo1fpq_toast",
1230
+ "studio": "Oo1fpq_studio",
1231
+ "playButton": "Oo1fpq_playButton",
1232
+ "formCol": "Oo1fpq_formCol",
1233
+ "input": "Oo1fpq_input",
871
1234
  "trackFill": "Oo1fpq_trackFill",
872
- "muteButton": "Oo1fpq_muteButton",
873
- "textarea": "Oo1fpq_textarea"
1235
+ "toast": "Oo1fpq_toast",
1236
+ "resultModeChip": "Oo1fpq_resultModeChip",
1237
+ "compareModelName": "Oo1fpq_compareModelName",
1238
+ "historyItem": "Oo1fpq_historyItem",
1239
+ "audiogenToastIn": "Oo1fpq_audiogenToastIn",
1240
+ "resultGroupChip": "Oo1fpq_resultGroupChip",
1241
+ "voiceIdChip": "Oo1fpq_voiceIdChip",
1242
+ "resultEmpty": "Oo1fpq_resultEmpty",
1243
+ "ghostButton": "Oo1fpq_ghostButton",
1244
+ "historyCol": "Oo1fpq_historyCol",
1245
+ "modelCheckList": "Oo1fpq_modelCheckList"
874
1246
  };
875
1247
  //#endregion
876
1248
  //#region src/client/audio-player.tsx
@@ -1179,8 +1551,53 @@ window.__ModuleLoader__.load({
1179
1551
  /**
1180
1552
  * Studio view: the generation form (left), result cards (center) and the
1181
1553
  * compact generation history (right). Owns the «加入资源库» interactions —
1182
- * a pre-generation checkbox, a per-card save dialog, and a history star.
1554
+ * a pre-generation checkbox, a per-card save dialog, and a history star
1555
+ * plus a model-comparison mode that runs the same prompt across several
1556
+ * models and shows one result group per model.
1183
1557
  */
1558
+ /** 每模型覆盖值 → 请求字段的数值/类型转换(空值跳过)。 */
1559
+ function overrideSpread(override) {
1560
+ const out = {};
1561
+ const val = (override.format ?? "").trim();
1562
+ if (val !== "") out.format = val;
1563
+ const num = (key) => {
1564
+ const raw = (override[key] ?? "").trim();
1565
+ if (raw === "") return void 0;
1566
+ const parsed = Number(raw);
1567
+ return Number.isFinite(parsed) ? parsed : void 0;
1568
+ };
1569
+ const duration = num("duration");
1570
+ if (duration !== void 0) out.duration = duration;
1571
+ const voice = (override.voice ?? "").trim();
1572
+ if (voice !== "") out.voice = voice;
1573
+ const speed = num("speed");
1574
+ if (speed !== void 0) out.speed = speed;
1575
+ const emotion = (override.emotion ?? "").trim();
1576
+ if (emotion !== "") out.emotion = emotion;
1577
+ const sampleRate = num("sample_rate");
1578
+ if (sampleRate !== void 0) out.sampleRate = sampleRate;
1579
+ const bitrate = num("bitrate");
1580
+ if (bitrate !== void 0) out.bitrate = bitrate;
1581
+ const lyrics = (override.lyrics ?? "").trim();
1582
+ if (lyrics !== "") out.lyrics = lyrics;
1583
+ const seed = num("seed");
1584
+ if (seed !== void 0) out.seed = seed;
1585
+ const steps = num("steps");
1586
+ if (steps !== void 0) out.steps = steps;
1587
+ const cfgScale = num("cfg_scale");
1588
+ if (cfgScale !== void 0) out.cfgScale = cfgScale;
1589
+ return out;
1590
+ }
1591
+ function taskIdOf(entry) {
1592
+ const params = entry.params;
1593
+ return typeof params?.taskId === "string" && params.taskId !== "" ? params.taskId : "";
1594
+ }
1595
+ function modeLabelOf(mode) {
1596
+ if (mode === "tts") return tt("mode.tts");
1597
+ if (mode === "music") return tt("mode.music");
1598
+ if (mode === "sfx") return tt("mode.sfx");
1599
+ return tt("mode.voiceDesign");
1600
+ }
1184
1601
  function useConfig(scope) {
1185
1602
  const [value, setValue] = (0, react.useState)(scope.getSnapshot().value);
1186
1603
  (0, react.useEffect)(() => scope.subscribe(() => {
@@ -1191,7 +1608,11 @@ window.__ModuleLoader__.load({
1191
1608
  function useHistory() {
1192
1609
  const [entries, setEntries] = (0, react.useState)([]);
1193
1610
  const reload = () => {
1194
- fetch(HISTORY_API.list, { method: "POST" }).then(async (response) => {
1611
+ fetch(HISTORY_API.list, {
1612
+ method: "POST",
1613
+ headers: { "content-type": "application/json" },
1614
+ body: "{}"
1615
+ }).then(async (response) => {
1195
1616
  const body = await response.json();
1196
1617
  if (body.ok === true) setEntries(body.history ?? []);
1197
1618
  }).catch(() => {});
@@ -1200,7 +1621,11 @@ window.__ModuleLoader__.load({
1200
1621
  reload();
1201
1622
  }, []);
1202
1623
  const clear = () => {
1203
- fetch(HISTORY_API.clear, { method: "POST" }).then(() => reload()).catch(() => {});
1624
+ fetch(HISTORY_API.clear, {
1625
+ method: "POST",
1626
+ headers: { "content-type": "application/json" },
1627
+ body: "{}"
1628
+ }).then(() => reload()).catch(() => {});
1204
1629
  };
1205
1630
  return {
1206
1631
  entries,
@@ -1277,15 +1702,26 @@ window.__ModuleLoader__.load({
1277
1702
  const [bitrate, setBitrate] = (0, react.useState)("");
1278
1703
  const [audioChannel, setAudioChannel] = (0, react.useState)("");
1279
1704
  const [subtitle, setSubtitle] = (0, react.useState)(false);
1280
- const [loading, setLoading] = (0, react.useState)(false);
1705
+ const [seed, setSeed] = (0, react.useState)("");
1706
+ const [steps, setSteps] = (0, react.useState)("");
1707
+ const [cfgScale, setCfgScale] = (0, react.useState)("");
1281
1708
  const [error, setError] = (0, react.useState)(null);
1282
- const [outputs, setOutputs] = (0, react.useState)([]);
1709
+ const [tasks, setTasks] = (0, react.useState)([]);
1710
+ const tasksRef = (0, react.useRef)([]);
1711
+ (0, react.useEffect)(() => {
1712
+ tasksRef.current = tasks;
1713
+ }, [tasks]);
1714
+ const taskControllers = (0, react.useRef)(/* @__PURE__ */ new Map());
1283
1715
  const [saveToLibrary, setSaveToLibrary] = (0, react.useState)(cfg?.autoSaveToLibrary === true);
1284
1716
  const [savedIds, setSavedIds] = (0, react.useState)(/* @__PURE__ */ new Set());
1285
1717
  const [saveDialog, setSaveDialog] = (0, react.useState)(null);
1718
+ const [historyTab, setHistoryTab] = (0, react.useState)("all");
1719
+ const [compareMode, setCompareMode] = (0, react.useState)(false);
1720
+ const [compareModels, setCompareModels] = (0, react.useState)([]);
1721
+ const [overrides, setOverrides] = (0, react.useState)({});
1286
1722
  const { entries, reload, clear } = useHistory();
1287
1723
  const [designChannelId, setDesignChannelId] = (0, react.useState)("");
1288
- const isMiniMaxChannel = (0, react.useMemo)(() => {
1724
+ (0, react.useMemo)(() => {
1289
1725
  const target = channels.find((candidate) => candidate.id === modelOptions.defaultChannelId) ?? channels[0];
1290
1726
  return target !== void 0 && (target.preset === "minimax" || /minimax/i.test(target.apiUrl));
1291
1727
  }, [channels, modelOptions.defaultChannelId]);
@@ -1301,64 +1737,282 @@ window.__ModuleLoader__.load({
1301
1737
  if (mode === "voice_design") return [];
1302
1738
  return modelOptions.models.filter((entry) => entry.category === void 0 || entry.category === "tts" && mode === "tts" || entry.category === mode).map((entry) => entry.alias);
1303
1739
  }, [modelOptions.models, mode]);
1740
+ const currentPreset = (0, react.useMemo)(() => {
1741
+ if (mode === "voice_design") return channels.find((candidate) => candidate.id === designChannelId)?.preset ?? "";
1742
+ return (modelOptions.models.find((entry) => entry.alias === model) ?? modelOptions.models.find((entry) => entry.alias === (visibleModels[0] ?? "")))?.preset ?? "";
1743
+ }, [
1744
+ mode,
1745
+ model,
1746
+ visibleModels,
1747
+ modelOptions.models,
1748
+ channels,
1749
+ designChannelId
1750
+ ]);
1751
+ const fieldPresets = (0, react.useMemo)(() => {
1752
+ if (mode === "voice_design") return [];
1753
+ if (compareMode) {
1754
+ const presets = [];
1755
+ for (const alias of compareModels) {
1756
+ const entry = modelOptions.models.find((candidate) => candidate.alias === alias);
1757
+ if (entry !== void 0 && !presets.includes(entry.preset)) presets.push(entry.preset);
1758
+ }
1759
+ if (presets.length === 0) return [currentPreset].filter((value) => value !== "");
1760
+ return presets;
1761
+ }
1762
+ return [currentPreset].filter((value) => value !== "");
1763
+ }, [
1764
+ mode,
1765
+ compareMode,
1766
+ compareModels,
1767
+ modelOptions.models,
1768
+ currentPreset
1769
+ ]);
1770
+ const globalSpecs = (0, react.useMemo)(() => globalFieldSpecs(mode, fieldPresets), [mode, fieldPresets]);
1771
+ const groupedModels = (0, react.useMemo)(() => {
1772
+ const groups = [];
1773
+ for (const entry of modelOptions.models) {
1774
+ let group = groups.find((candidate) => candidate.channelId === entry.channelId);
1775
+ if (group === void 0) {
1776
+ group = {
1777
+ channelId: entry.channelId,
1778
+ channelName: entry.channelName,
1779
+ models: []
1780
+ };
1781
+ groups.push(group);
1782
+ }
1783
+ group.models.push({ alias: entry.alias });
1784
+ }
1785
+ return groups.map((group) => ({
1786
+ ...group,
1787
+ models: group.models.filter((entry) => visibleModels.includes(entry.alias))
1788
+ })).filter((group) => group.models.length > 0);
1789
+ }, [modelOptions.models, visibleModels]);
1304
1790
  (0, react.useEffect)(() => {
1305
1791
  if (visibleModels.length > 0 && !visibleModels.includes(model)) setModel(visibleModels[0]);
1306
1792
  }, [visibleModels, model]);
1793
+ (0, react.useEffect)(() => {
1794
+ setCompareModels((current) => current.filter((item) => visibleModels.includes(item)));
1795
+ }, [mode, visibleModels]);
1796
+ (0, react.useEffect)(() => {
1797
+ if (!compareMode) return;
1798
+ setCompareModels((current) => {
1799
+ const valid = current.filter((item) => visibleModels.includes(item));
1800
+ const rest = visibleModels.filter((item) => !valid.includes(item));
1801
+ while (valid.length < 2 && rest.length > 0) valid.push(rest.shift());
1802
+ return valid;
1803
+ });
1804
+ }, [compareMode, visibleModels]);
1307
1805
  (0, react.useEffect)(() => {
1308
1806
  if (reuse === void 0 || reuse === null) return;
1309
1807
  setMode(reuse.mode);
1310
1808
  if (reuse.voiceId !== void 0 || reuse.voice !== void 0) setVoice(reuse.voiceId ?? reuse.voice ?? "");
1311
1809
  if (reuse.model !== void 0 && reuse.model !== "") setModel(reuse.model);
1312
1810
  }, [reuse?.nonce]);
1313
- const submit = async () => {
1811
+ /** Build the shared generation request for one model. */
1812
+ const requestOf = (modelName) => ({
1813
+ mode,
1814
+ model: modelName,
1815
+ prompt: prompt.trim(),
1816
+ saveToLibrary,
1817
+ ...mode === "voice_design" && designChannelId !== "" ? { channelId: designChannelId } : {},
1818
+ ...previewText.trim() !== "" ? { previewText: previewText.trim() } : {},
1819
+ ...voice.trim() !== "" ? { voice: voice.trim() } : {},
1820
+ ...speed.trim() !== "" ? { speed: Number(speed) } : {},
1821
+ ...duration.trim() !== "" ? { duration: Number(duration) } : {},
1822
+ ...lyrics.trim() !== "" ? { lyrics: lyrics.trim() } : {},
1823
+ ...instrumental ? { isInstrumental: true } : {},
1824
+ ...loop ? { loop: true } : {},
1825
+ ...promptInfluence.trim() !== "" ? { promptInfluence: Number(promptInfluence) } : {},
1826
+ ...format.trim() !== "" ? { format: format.trim() } : {},
1827
+ ...emotion.trim() !== "" ? { emotion: emotion.trim() } : {},
1828
+ ...vol.trim() !== "" ? { vol: Number(vol) } : {},
1829
+ ...pitch.trim() !== "" ? { pitch: Number(pitch) } : {},
1830
+ ...toneText.trim() !== "" ? { pronunciationTone: toneText.split("\n").map((item) => item.trim()).filter((item) => item !== "") } : {},
1831
+ ...sampleRate.trim() !== "" ? { sampleRate: Number(sampleRate) } : {},
1832
+ ...bitrate.trim() !== "" ? { bitrate: Number(bitrate) } : {},
1833
+ ...audioChannel.trim() !== "" ? { audioChannel: Number(audioChannel) } : {},
1834
+ ...subtitle ? { subtitleEnable: true } : {},
1835
+ ...seed.trim() !== "" ? { seed: Number(seed) } : {},
1836
+ ...steps.trim() !== "" ? { steps: Number(steps) } : {},
1837
+ ...cfgScale.trim() !== "" ? { cfgScale: Number(cfgScale) } : {}
1838
+ });
1839
+ const applyResponse = (response) => {
1840
+ const generated = response.outputs ?? [];
1841
+ if ((response.resources?.length ?? 0) > 0 && saveToLibrary) {
1842
+ setSavedIds((current) => /* @__PURE__ */ new Set([...current, ...generated.map((item) => item.id)]));
1843
+ props.showToast("已保存到资源库");
1844
+ props.onLibraryChanged();
1845
+ }
1846
+ reload();
1847
+ return generated;
1848
+ };
1849
+ const patchTask = (taskId, fn) => {
1850
+ setTasks((current) => current.map((task) => task.id === taskId ? fn(task) : task));
1851
+ };
1852
+ /** 提交即建任务:非阻塞,可继续发起其他生成;并发由宿主「最大并发生成数」闸门控制。 */
1853
+ const submit = () => {
1314
1854
  if (prompt.trim() === "") {
1315
1855
  setError(tt("prompt.required"));
1316
1856
  return;
1317
1857
  }
1318
- setLoading(true);
1858
+ const isCompare = compareMode && needModel;
1859
+ const models = isCompare ? compareModels.length >= 2 ? compareModels : visibleModels.slice(0, 2) : [];
1860
+ if (isCompare && models.length < 2) {
1861
+ setError("请至少选择 2 个模型进行对比");
1862
+ return;
1863
+ }
1864
+ const singleModel = isCompare ? "" : model || visibleModels[0] || "";
1865
+ if (!isCompare && singleModel === "") {
1866
+ setError("当前模式暂无可用模型");
1867
+ return;
1868
+ }
1319
1869
  setError(null);
1320
- try {
1321
- const response = await api.generate({
1322
- mode,
1323
- model: mode === "voice_design" ? "" : (model || visibleModels[0]) ?? "",
1324
- prompt: prompt.trim(),
1325
- saveToLibrary,
1326
- ...mode === "voice_design" && designChannelId !== "" ? { channelId: designChannelId } : {},
1327
- ...previewText.trim() !== "" ? { previewText: previewText.trim() } : {},
1328
- ...voice.trim() !== "" ? { voice: voice.trim() } : {},
1329
- ...speed.trim() !== "" ? { speed: Number(speed) } : {},
1330
- ...duration.trim() !== "" ? { duration: Number(duration) } : {},
1331
- ...lyrics.trim() !== "" ? { lyrics: lyrics.trim() } : {},
1332
- ...instrumental ? { isInstrumental: true } : {},
1333
- ...loop ? { loop: true } : {},
1334
- ...promptInfluence.trim() !== "" ? { promptInfluence: Number(promptInfluence) } : {},
1335
- ...format.trim() !== "" ? { format: format.trim() } : {},
1336
- ...emotion.trim() !== "" ? { emotion: emotion.trim() } : {},
1337
- ...vol.trim() !== "" ? { vol: Number(vol) } : {},
1338
- ...pitch.trim() !== "" ? { pitch: Number(pitch) } : {},
1339
- ...toneText.trim() !== "" ? { pronunciationTone: toneText.split("\n").map((item) => item.trim()).filter((item) => item !== "") } : {},
1340
- ...sampleRate.trim() !== "" ? { sampleRate: Number(sampleRate) } : {},
1341
- ...bitrate.trim() !== "" ? { bitrate: Number(bitrate) } : {},
1342
- ...audioChannel.trim() !== "" ? { audioChannel: Number(audioChannel) } : {},
1343
- ...subtitle ? { subtitleEnable: true } : {}
1344
- });
1345
- if (!response.ok) {
1346
- setError(response.message ?? "生成失败");
1347
- return;
1870
+ const taskId = `t-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
1871
+ const planModels = isCompare ? models : [singleModel];
1872
+ const plan = planModels.map((modelName) => ({
1873
+ model: modelName,
1874
+ request: {
1875
+ ...requestOf(modelName),
1876
+ taskId,
1877
+ ...overrideSpread(overrides[modelName] ?? {})
1348
1878
  }
1349
- const generated = response.outputs ?? [];
1350
- setOutputs(generated);
1351
- if ((response.resources?.length ?? 0) > 0 && saveToLibrary) {
1352
- setSavedIds(new Set(generated.map((item) => item.id)));
1353
- props.showToast("已保存到资源库");
1354
- props.onLibraryChanged();
1879
+ }));
1880
+ const task = {
1881
+ id: taskId,
1882
+ mode,
1883
+ prompt: prompt.trim(),
1884
+ kind: isCompare ? "compare" : "single",
1885
+ label: isCompare ? `对比 ${models.join(" / ")}` : singleModel,
1886
+ status: "running",
1887
+ progress: {
1888
+ done: 0,
1889
+ total: plan.length,
1890
+ current: ""
1891
+ },
1892
+ startedAt: Date.now(),
1893
+ groups: planModels.map((modelName) => ({
1894
+ model: modelName,
1895
+ state: "waiting",
1896
+ outputs: []
1897
+ }))
1898
+ };
1899
+ setTasks((current) => [task, ...current]);
1900
+ runTask(taskId, plan);
1901
+ };
1902
+ /** 执行一个任务:并行发起(宿主闸门限流),进度回写;支持取消。 */
1903
+ const runTask = async (taskId, plan) => {
1904
+ const controllers = [];
1905
+ taskControllers.current.set(taskId, controllers);
1906
+ const taskIsFinished = () => {
1907
+ const task = tasksRef.current.find((candidate) => candidate.id === taskId);
1908
+ if (task === void 0) return "pending";
1909
+ if (task.status === "cancelled") return "cancelled";
1910
+ return "running";
1911
+ };
1912
+ await Promise.allSettled(plan.map(async (step) => {
1913
+ const controller = new AbortController();
1914
+ controllers.push(controller);
1915
+ patchTask(taskId, (task) => ({
1916
+ ...task,
1917
+ progress: {
1918
+ ...task.progress,
1919
+ current: step.model
1920
+ },
1921
+ groups: task.groups.map((group) => group.model === step.model ? {
1922
+ ...group,
1923
+ state: "running",
1924
+ error: void 0
1925
+ } : group)
1926
+ }));
1927
+ try {
1928
+ const response = await api.generate(step.request, controller.signal);
1929
+ if (!response.ok) throw new Error(response.message ?? "生成失败");
1930
+ const generated = applyResponse(response);
1931
+ patchTask(taskId, (task) => ({
1932
+ ...task,
1933
+ groups: task.groups.map((group) => group.model === step.model ? {
1934
+ ...group,
1935
+ state: "done",
1936
+ outputs: generated
1937
+ } : group)
1938
+ }));
1939
+ } catch (err) {
1940
+ if (controller.signal.aborted === true || taskIsFinished() === "cancelled") patchTask(taskId, (task) => ({
1941
+ ...task,
1942
+ groups: task.groups.map((group) => group.model === step.model ? {
1943
+ ...group,
1944
+ state: "cancelled",
1945
+ error: void 0
1946
+ } : group)
1947
+ }));
1948
+ else patchTask(taskId, (task) => ({
1949
+ ...task,
1950
+ groups: task.groups.map((group) => group.model === step.model ? {
1951
+ ...group,
1952
+ state: "error",
1953
+ error: err instanceof Error ? err.message : String(err)
1954
+ } : group)
1955
+ }));
1956
+ } finally {
1957
+ patchTask(taskId, (task) => ({
1958
+ ...task,
1959
+ progress: {
1960
+ ...task.progress,
1961
+ done: task.progress.done + 1,
1962
+ current: ""
1963
+ }
1964
+ }));
1355
1965
  }
1356
- reload();
1357
- } catch (err) {
1358
- setError(err instanceof Error ? err.message : String(err));
1359
- } finally {
1360
- setLoading(false);
1361
- }
1966
+ }));
1967
+ taskControllers.current.delete(taskId);
1968
+ setTasks((current) => current.map((task) => {
1969
+ if (task.id !== taskId) return task;
1970
+ if (task.status === "cancelled") return {
1971
+ ...task,
1972
+ finishedAt: task.finishedAt ?? Date.now()
1973
+ };
1974
+ const done = task.groups.filter((group) => group.state === "done").length;
1975
+ const failed = task.groups.filter((group) => group.state === "error").length;
1976
+ const cancelled = task.groups.filter((group) => group.state === "cancelled").length;
1977
+ if (done > 0) return {
1978
+ ...task,
1979
+ status: "done",
1980
+ finishedAt: Date.now()
1981
+ };
1982
+ if (cancelled === task.groups.length) return {
1983
+ ...task,
1984
+ status: "cancelled",
1985
+ finishedAt: Date.now()
1986
+ };
1987
+ return {
1988
+ ...task,
1989
+ status: "failed",
1990
+ finishedAt: Date.now(),
1991
+ error: failed > 0 ? task.groups.filter((group) => group.state === "error").map((group) => `「${group.model}」${group.error ?? ""}`).join(";") : "生成失败"
1992
+ };
1993
+ }));
1994
+ };
1995
+ /** 取消任务:本地中止在途 fetch + 宿主中断上游请求,剩余模型跳过。 */
1996
+ const cancelTask = (taskId) => {
1997
+ for (const controller of taskControllers.current.get(taskId) ?? []) controller.abort();
1998
+ api.cancelTask(taskId);
1999
+ patchTask(taskId, (task) => ({
2000
+ ...task,
2001
+ status: "cancelled",
2002
+ finishedAt: Date.now(),
2003
+ progress: {
2004
+ ...task.progress,
2005
+ current: ""
2006
+ },
2007
+ groups: task.groups.map((group) => group.state === "waiting" || group.state === "running" ? {
2008
+ ...group,
2009
+ state: "cancelled",
2010
+ error: void 0
2011
+ } : group)
2012
+ }));
2013
+ };
2014
+ const removeTask = (taskId) => {
2015
+ setTasks((current) => current.filter((task) => task.id !== taskId));
1362
2016
  };
1363
2017
  const openSaveDialog = (files, context) => {
1364
2018
  setSaveDialog({
@@ -1366,19 +2020,373 @@ window.__ModuleLoader__.load({
1366
2020
  context
1367
2021
  });
1368
2022
  };
2023
+ /** 按字段规格渲染一个表单控件(渠道/模式感知:字段集由 globalSpecs 决定)。 */
2024
+ const renderField = (spec) => {
2025
+ const common = {
2026
+ className: audio_panel_module_css_default.input,
2027
+ disabled: false
2028
+ };
2029
+ switch (spec.key) {
2030
+ case "voice": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2031
+ className: audio_panel_module_css_default.label,
2032
+ title: spec.hint,
2033
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2034
+ className: audio_panel_module_css_default.input,
2035
+ value: voice,
2036
+ onChange: (event) => setVoice(event.target.value),
2037
+ placeholder: currentPreset === "minimax" ? "male-qn-qingse / female-shaonv" : "alloy / 自定义音色"
2038
+ })]
2039
+ }, spec.key);
2040
+ case "speed": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2041
+ className: audio_panel_module_css_default.label,
2042
+ title: spec.hint,
2043
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2044
+ className: audio_panel_module_css_default.input,
2045
+ type: "number",
2046
+ step: spec.step ?? .1,
2047
+ min: spec.min,
2048
+ max: spec.max,
2049
+ value: speed,
2050
+ onChange: (event) => setSpeed(event.target.value),
2051
+ placeholder: spec.placeholder
2052
+ })]
2053
+ }, spec.key);
2054
+ case "duration": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2055
+ className: audio_panel_module_css_default.label,
2056
+ title: spec.hint,
2057
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2058
+ className: audio_panel_module_css_default.input,
2059
+ type: "number",
2060
+ step: spec.step ?? 1,
2061
+ min: spec.min,
2062
+ max: spec.max,
2063
+ value: duration,
2064
+ onChange: (event) => setDuration(event.target.value),
2065
+ placeholder: spec.placeholder
2066
+ })]
2067
+ }, spec.key);
2068
+ case "format": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2069
+ className: audio_panel_module_css_default.label,
2070
+ title: spec.hint,
2071
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
2072
+ className: audio_panel_module_css_default.input,
2073
+ value: format,
2074
+ onChange: (event) => setFormat(event.target.value),
2075
+ children: (spec.options ?? [
2076
+ "mp3",
2077
+ "wav",
2078
+ "pcm"
2079
+ ]).map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2080
+ value: option,
2081
+ children: option
2082
+ }, option))
2083
+ })]
2084
+ }, spec.key);
2085
+ case "lyrics": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2086
+ className: audio_panel_module_css_default.label,
2087
+ title: spec.hint,
2088
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
2089
+ className: audio_panel_module_css_default.textarea,
2090
+ value: lyrics,
2091
+ onChange: (event) => setLyrics(event.target.value),
2092
+ placeholder: "第一段歌词…\n\n第二段歌词…"
2093
+ })]
2094
+ }, spec.key);
2095
+ case "instrumental": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2096
+ className: audio_panel_module_css_default.checkbox,
2097
+ title: spec.hint,
2098
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2099
+ type: "checkbox",
2100
+ checked: instrumental,
2101
+ onChange: (event) => setInstrumental(event.target.checked)
2102
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
2103
+ spec.label,
2104
+ "(是:",
2105
+ currentPreset === "elevenlabs" ? "force_instrumental" : "is_instrumental",
2106
+ ")"
2107
+ ] })]
2108
+ }, spec.key);
2109
+ case "sampleRate": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2110
+ className: audio_panel_module_css_default.label,
2111
+ title: spec.hint,
2112
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
2113
+ className: audio_panel_module_css_default.input,
2114
+ value: sampleRate,
2115
+ onChange: (event) => setSampleRate(event.target.value),
2116
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2117
+ value: "",
2118
+ children: "默认(44100)"
2119
+ }), (spec.options ?? []).map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2120
+ value: option,
2121
+ children: option
2122
+ }, option))]
2123
+ })]
2124
+ }, spec.key);
2125
+ case "bitrate": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2126
+ className: audio_panel_module_css_default.label,
2127
+ title: spec.hint,
2128
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
2129
+ className: audio_panel_module_css_default.input,
2130
+ value: bitrate,
2131
+ onChange: (event) => setBitrate(event.target.value),
2132
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2133
+ value: "",
2134
+ children: "默认(256000)"
2135
+ }), (spec.options ?? []).map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2136
+ value: option,
2137
+ children: option
2138
+ }, option))]
2139
+ })]
2140
+ }, spec.key);
2141
+ case "audioChannel": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2142
+ className: audio_panel_module_css_default.label,
2143
+ title: spec.hint,
2144
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
2145
+ className: audio_panel_module_css_default.input,
2146
+ value: audioChannel,
2147
+ onChange: (event) => setAudioChannel(event.target.value),
2148
+ children: [
2149
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2150
+ value: "",
2151
+ children: "默认(1)"
2152
+ }),
2153
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2154
+ value: "1",
2155
+ children: "1"
2156
+ }),
2157
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2158
+ value: "2",
2159
+ children: "2"
2160
+ })
2161
+ ]
2162
+ })]
2163
+ }, spec.key);
2164
+ case "emotion": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2165
+ className: audio_panel_module_css_default.label,
2166
+ title: spec.hint,
2167
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2168
+ className: audio_panel_module_css_default.input,
2169
+ value: emotion,
2170
+ onChange: (event) => setEmotion(event.target.value),
2171
+ placeholder: spec.placeholder
2172
+ })]
2173
+ }, spec.key);
2174
+ case "vol": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2175
+ className: audio_panel_module_css_default.label,
2176
+ title: spec.hint,
2177
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2178
+ className: audio_panel_module_css_default.input,
2179
+ type: "number",
2180
+ min: spec.min,
2181
+ max: spec.max,
2182
+ step: spec.step ?? .5,
2183
+ value: vol,
2184
+ onChange: (event) => setVol(event.target.value),
2185
+ placeholder: spec.placeholder
2186
+ })]
2187
+ }, spec.key);
2188
+ case "pitch": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2189
+ className: audio_panel_module_css_default.label,
2190
+ title: spec.hint,
2191
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2192
+ className: audio_panel_module_css_default.input,
2193
+ type: "number",
2194
+ min: spec.min,
2195
+ max: spec.max,
2196
+ value: pitch,
2197
+ onChange: (event) => setPitch(event.target.value),
2198
+ placeholder: spec.placeholder
2199
+ })]
2200
+ }, spec.key);
2201
+ case "toneText": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2202
+ className: audio_panel_module_css_default.label,
2203
+ title: spec.hint,
2204
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
2205
+ className: audio_panel_module_css_default.textarea,
2206
+ value: toneText,
2207
+ onChange: (event) => setToneText(event.target.value),
2208
+ placeholder: spec.placeholder
2209
+ })]
2210
+ }, spec.key);
2211
+ case "subtitle": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2212
+ className: audio_panel_module_css_default.checkbox,
2213
+ title: spec.hint,
2214
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2215
+ type: "checkbox",
2216
+ checked: subtitle,
2217
+ onChange: (event) => setSubtitle(event.target.checked)
2218
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label })]
2219
+ }, spec.key);
2220
+ case "loop": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2221
+ className: audio_panel_module_css_default.checkbox,
2222
+ title: spec.hint,
2223
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2224
+ type: "checkbox",
2225
+ checked: loop,
2226
+ onChange: (event) => setLoop(event.target.checked)
2227
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label })]
2228
+ }, spec.key);
2229
+ case "promptInfluence": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2230
+ className: audio_panel_module_css_default.label,
2231
+ title: spec.hint,
2232
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2233
+ className: audio_panel_module_css_default.input,
2234
+ type: "number",
2235
+ step: spec.step ?? .1,
2236
+ min: spec.min,
2237
+ max: spec.max,
2238
+ value: promptInfluence,
2239
+ onChange: (event) => setPromptInfluence(event.target.value),
2240
+ placeholder: spec.placeholder
2241
+ })]
2242
+ }, spec.key);
2243
+ case "seed":
2244
+ case "steps":
2245
+ case "cfgScale": {
2246
+ const value = spec.key === "seed" ? seed : spec.key === "steps" ? steps : cfgScale;
2247
+ const setter = spec.key === "seed" ? setSeed : spec.key === "steps" ? setSteps : setCfgScale;
2248
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2249
+ className: audio_panel_module_css_default.label,
2250
+ title: spec.hint,
2251
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2252
+ ...common,
2253
+ type: "number",
2254
+ step: spec.step ?? 1,
2255
+ min: spec.min,
2256
+ max: spec.max,
2257
+ value: String(value),
2258
+ placeholder: spec.placeholder,
2259
+ onChange: (event) => setter(event.target.value)
2260
+ })]
2261
+ }, spec.key);
2262
+ }
2263
+ default: return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: spec.label }, spec.key);
2264
+ }
2265
+ };
1369
2266
  const onDialogSaved = (entry) => {
1370
2267
  if (saveDialog !== null) setSavedIds((current) => /* @__PURE__ */ new Set([...current, ...saveDialog.files.map((file) => file.id)]));
1371
2268
  setSaveDialog(null);
1372
2269
  props.showToast(`已保存「${entry.name}」`);
1373
2270
  props.onLibraryChanged();
1374
2271
  };
1375
- const modeLabel = (0, react.useMemo)(() => {
2272
+ /** One result card (single mode shares it with the compare groups). */
2273
+ const renderAudioCard = (audio, index, label, contextModel) => {
2274
+ const saved = savedIds.has(audio.id);
2275
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2276
+ className: audio_panel_module_css_default.audioCard,
2277
+ "data-saved": saved ? "true" : "false",
2278
+ children: [
2279
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2280
+ className: audio_panel_module_css_default.audioCardHead,
2281
+ children: [
2282
+ audio.voiceId !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2283
+ className: audio_panel_module_css_default.voiceIdChip,
2284
+ title: "新音色 ID",
2285
+ children: ["新音色 ", audio.voiceId]
2286
+ }) : null,
2287
+ saved ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2288
+ className: audio_panel_module_css_default.savedChip,
2289
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}), " 已入库"]
2290
+ }) : null,
2291
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2292
+ className: audio_panel_module_css_default.audioCardIndex,
2293
+ children: ["#", index + 1]
2294
+ })
2295
+ ]
2296
+ }),
2297
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPlayer, {
2298
+ src: dataUrlOf(audio),
2299
+ itemKey: `${label}-${audio.id}`
2300
+ }),
2301
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2302
+ className: audio_panel_module_css_default.audioCardActions,
2303
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
2304
+ className: audio_panel_module_css_default.ghostButton,
2305
+ href: dataUrlOf(audio),
2306
+ download: `generated-${index + 1}.${audio.mime.split("/")[1]?.replace("mpeg", "mp3") ?? "mp3"}`,
2307
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DownloadIcon, {}), " 下载"]
2308
+ }), saved ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2309
+ type: "button",
2310
+ className: audio_panel_module_css_default.ghostButton,
2311
+ onClick: () => props.showToast("该音频已加入资源库"),
2312
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}), " 已入库"]
2313
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2314
+ type: "button",
2315
+ className: audio_panel_module_css_default.ghostButton,
2316
+ onClick: () => openSaveDialog([audio], {
2317
+ mode,
2318
+ prompt: prompt.trim(),
2319
+ ...voice.trim() !== "" ? { voice: voice.trim() } : {},
2320
+ ...audio.voiceId === void 0 ? {} : { voiceId: audio.voiceId },
2321
+ ...contextModel !== "" ? { model: contextModel } : {},
2322
+ ...channels.length > 0 ? { channel: channels.find((candidate) => candidate.id === (mode === "voice_design" ? designChannelId : modelOptions.defaultChannelId))?.name ?? channels[0]?.name ?? "" } : {},
2323
+ params: requestOf(contextModel)
2324
+ }),
2325
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StarIcon, {}), " 加入资源库"]
2326
+ })]
2327
+ })
2328
+ ]
2329
+ }, `${label}-${audio.id}`);
2330
+ };
2331
+ (0, react.useMemo)(() => {
1376
2332
  if (mode === "tts") return tt("mode.tts");
1377
2333
  if (mode === "music") return tt("mode.music");
1378
2334
  if (mode === "sfx") return tt("mode.sfx");
1379
2335
  return tt("mode.voiceDesign");
1380
2336
  }, [mode]);
2337
+ /** 历史记录:按 taskId 聚合出「单条 / 对比任务卡」两种条目。 */
2338
+ const historyItems = (0, react.useMemo)(() => {
2339
+ const taskCounts = /* @__PURE__ */ new Map();
2340
+ for (const entry of entries) {
2341
+ const taskId = taskIdOf(entry);
2342
+ if (taskId !== "") taskCounts.set(taskId, (taskCounts.get(taskId) ?? 0) + 1);
2343
+ }
2344
+ const merged = [];
2345
+ const byTask = /* @__PURE__ */ new Map();
2346
+ for (const entry of entries) {
2347
+ const taskId = taskIdOf(entry);
2348
+ if (taskId !== "" && (taskCounts.get(taskId) ?? 0) > 1) {
2349
+ const existing = byTask.get(taskId);
2350
+ if (existing !== void 0) {
2351
+ existing.models.push({
2352
+ model: entry.model,
2353
+ ...entry.channel === void 0 ? {} : { channel: entry.channel },
2354
+ entry
2355
+ });
2356
+ if (entry.createdAt > existing.createdAt) existing.createdAt = entry.createdAt;
2357
+ continue;
2358
+ }
2359
+ const item = {
2360
+ key: taskId,
2361
+ kind: "compare",
2362
+ mode: entry.mode,
2363
+ prompt: entry.prompt,
2364
+ createdAt: entry.createdAt,
2365
+ entry,
2366
+ models: [{
2367
+ model: entry.model,
2368
+ ...entry.channel === void 0 ? {} : { channel: entry.channel },
2369
+ entry
2370
+ }]
2371
+ };
2372
+ byTask.set(taskId, item);
2373
+ merged.push(item);
2374
+ continue;
2375
+ }
2376
+ merged.push({
2377
+ key: entry.id,
2378
+ kind: "single",
2379
+ mode: entry.mode,
2380
+ prompt: entry.prompt,
2381
+ createdAt: entry.createdAt,
2382
+ entry,
2383
+ models: []
2384
+ });
2385
+ }
2386
+ return merged.sort((left, right) => right.createdAt - left.createdAt);
2387
+ }, [entries]);
1381
2388
  const needModel = mode !== "voice_design";
2389
+ const runningCount = tasks.filter((task) => task.status === "running").length;
1382
2390
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1383
2391
  className: audio_panel_module_css_default.studio,
1384
2392
  children: [
@@ -1445,6 +2453,106 @@ window.__ModuleLoader__.load({
1445
2453
  })
1446
2454
  ] }) : null,
1447
2455
  needModel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2456
+ className: audio_panel_module_css_default.checkbox,
2457
+ title: "选择多个模型,用相同参数逐个生成,便于对比效果",
2458
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2459
+ type: "checkbox",
2460
+ checked: compareMode,
2461
+ onChange: (event) => setCompareMode(event.target.checked)
2462
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "模型对比(多模型同参数生成)" })]
2463
+ }) : null,
2464
+ needModel ? compareMode ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2465
+ className: audio_panel_module_css_default.compareBox,
2466
+ children: [
2467
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2468
+ className: audio_panel_module_css_default.label,
2469
+ children: "对比模型(至少 2 个,最多 4 个)"
2470
+ }),
2471
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2472
+ className: audio_panel_module_css_default.compareChips,
2473
+ children: [visibleModels.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2474
+ type: "button",
2475
+ className: audio_panel_module_css_default.compareChip,
2476
+ "data-active": compareModels.includes(item) ? "true" : "false",
2477
+ onClick: () => setCompareModels((current) => current.includes(item) ? current.filter((candidate) => candidate !== item) : current.length < 4 ? [...current, item] : current),
2478
+ children: item
2479
+ }, item)), visibleModels.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2480
+ className: audio_panel_module_css_default.hint,
2481
+ children: "当前模式暂无可用模型"
2482
+ }) : null]
2483
+ }),
2484
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
2485
+ className: audio_panel_module_css_default.advanced,
2486
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "每模型参数覆盖(默认自动:沿用上方相同配置)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2487
+ className: audio_panel_module_css_default.overrideTable,
2488
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2489
+ className: audio_panel_module_css_default.overrideRow,
2490
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: `${audio_panel_module_css_default.overrideCell} ${audio_panel_module_css_default.overrideCellHead}` }), compareModels.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2491
+ className: `${audio_panel_module_css_default.overrideCell} ${audio_panel_module_css_default.overrideCellHead}`,
2492
+ children: item
2493
+ }, item))]
2494
+ }), overrideRowSpecs(mode).map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2495
+ className: audio_panel_module_css_default.overrideRow,
2496
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2497
+ className: audio_panel_module_css_default.overrideCell,
2498
+ title: `${row.hint ?? ""}${row.presets.length < 3 ? `(适用:${row.presets.map(presetLabel).join("/")})` : ""}`,
2499
+ children: [row.label, row.presets.length < 3 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2500
+ className: audio_panel_module_css_default.overrideOnly,
2501
+ children: [" 仅", row.presets.map(presetLabel).join("/")]
2502
+ }) : null]
2503
+ }), compareModels.map((item) => {
2504
+ const entry = modelOptions.models.find((candidate) => candidate.alias === item);
2505
+ if (!(entry !== void 0 && row.presets.includes(entry.preset))) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2506
+ className: audio_panel_module_css_default.overrideCell,
2507
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2508
+ className: audio_panel_module_css_default.overrideDash,
2509
+ children: "—"
2510
+ })
2511
+ }, item);
2512
+ const value = overrides[item]?.[row.key] ?? "";
2513
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2514
+ className: audio_panel_module_css_default.overrideCell,
2515
+ children: row.type === "select" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
2516
+ className: audio_panel_module_css_default.input,
2517
+ value,
2518
+ onChange: (event) => {
2519
+ setOverrides((current) => ({
2520
+ ...current,
2521
+ [item]: {
2522
+ ...current[item] ?? {},
2523
+ [row.key]: event.target.value
2524
+ }
2525
+ }));
2526
+ },
2527
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2528
+ value: "",
2529
+ children: "自动"
2530
+ }), row.options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2531
+ value: option,
2532
+ children: option
2533
+ }, option))]
2534
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2535
+ className: audio_panel_module_css_default.input,
2536
+ type: row.type === "number" ? "number" : "text",
2537
+ value,
2538
+ placeholder: row.placeholder ?? "自动",
2539
+ onChange: (event) => {
2540
+ setOverrides((current) => ({
2541
+ ...current,
2542
+ [item]: {
2543
+ ...current[item] ?? {},
2544
+ [row.key]: event.target.value
2545
+ }
2546
+ }));
2547
+ }
2548
+ })
2549
+ }, item);
2550
+ })]
2551
+ }, row.key))]
2552
+ })]
2553
+ })
2554
+ ]
2555
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1448
2556
  className: audio_panel_module_css_default.label,
1449
2557
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("model.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1450
2558
  className: audio_panel_module_css_default.input,
@@ -1453,288 +2561,19 @@ window.__ModuleLoader__.load({
1453
2561
  children: [visibleModels.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1454
2562
  value: "",
1455
2563
  children: "(当前模式暂无可用模型)"
1456
- }) : null, visibleModels.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1457
- value: item,
1458
- children: item
1459
- }, item))]
2564
+ }) : null, groupedModels.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("optgroup", {
2565
+ label: group.channelName,
2566
+ children: group.models.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2567
+ value: item.alias,
2568
+ children: item.alias
2569
+ }, item.alias))
2570
+ }, group.channelId))]
1460
2571
  })]
1461
2572
  }) : null,
1462
- mode === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1463
- className: audio_panel_module_css_default.label,
1464
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("voice.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1465
- className: audio_panel_module_css_default.input,
1466
- value: voice,
1467
- onChange: (event) => setVoice(event.target.value),
1468
- placeholder: isMiniMaxChannel ? "male-qn-qingse / female-shaonv" : "alloy / 自定义音色"
1469
- })]
1470
- }) : null,
1471
- mode === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1472
- className: audio_panel_module_css_default.label,
1473
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("speed.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1474
- className: audio_panel_module_css_default.input,
1475
- type: "number",
1476
- step: "0.1",
1477
- min: "0.5",
1478
- max: "2",
1479
- value: speed,
1480
- onChange: (event) => setSpeed(event.target.value),
1481
- placeholder: "1.0"
1482
- })]
1483
- }) : null,
1484
- mode === "tts" && isMiniMaxChannel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
2573
+ globalSpecs.filter((spec) => spec.advanced !== true).map((spec) => renderField(spec)),
2574
+ mode === "tts" && globalSpecs.some((spec) => spec.advanced === true) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
1485
2575
  className: audio_panel_module_css_default.advanced,
1486
- children: [
1487
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "MiniMax 高级参数" }),
1488
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1489
- className: audio_panel_module_css_default.label,
1490
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "情绪 emotion" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1491
- className: audio_panel_module_css_default.input,
1492
- value: emotion,
1493
- onChange: (event) => setEmotion(event.target.value),
1494
- placeholder: "happy / sad / angry / nervous…"
1495
- })]
1496
- }),
1497
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1498
- className: audio_panel_module_css_default.row,
1499
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1500
- className: audio_panel_module_css_default.label,
1501
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "音量 vol (0-10)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1502
- className: audio_panel_module_css_default.input,
1503
- type: "number",
1504
- min: "0",
1505
- max: "10",
1506
- step: "0.5",
1507
- value: vol,
1508
- onChange: (event) => setVol(event.target.value),
1509
- placeholder: "1"
1510
- })]
1511
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1512
- className: audio_panel_module_css_default.label,
1513
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "音调 pitch (-12~12)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1514
- className: audio_panel_module_css_default.input,
1515
- type: "number",
1516
- min: "-12",
1517
- max: "12",
1518
- value: pitch,
1519
- onChange: (event) => setPitch(event.target.value),
1520
- placeholder: "0"
1521
- })]
1522
- })]
1523
- }),
1524
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1525
- className: audio_panel_module_css_default.row,
1526
- children: [
1527
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1528
- className: audio_panel_module_css_default.label,
1529
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "采样率" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1530
- className: audio_panel_module_css_default.input,
1531
- type: "number",
1532
- min: "16000",
1533
- max: "48000",
1534
- step: "8000",
1535
- value: sampleRate,
1536
- onChange: (event) => setSampleRate(event.target.value),
1537
- placeholder: "32000"
1538
- })]
1539
- }),
1540
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1541
- className: audio_panel_module_css_default.label,
1542
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "码率 bps" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1543
- className: audio_panel_module_css_default.input,
1544
- type: "number",
1545
- min: "64000",
1546
- max: "320000",
1547
- step: "8000",
1548
- value: bitrate,
1549
- onChange: (event) => setBitrate(event.target.value),
1550
- placeholder: "128000"
1551
- })]
1552
- }),
1553
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1554
- className: audio_panel_module_css_default.label,
1555
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "声道" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1556
- className: audio_panel_module_css_default.input,
1557
- value: audioChannel,
1558
- onChange: (event) => setAudioChannel(event.target.value),
1559
- children: [
1560
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1561
- value: "",
1562
- children: "默认(1)"
1563
- }),
1564
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1565
- value: "1",
1566
- children: "1"
1567
- }),
1568
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1569
- value: "2",
1570
- children: "2"
1571
- })
1572
- ]
1573
- })]
1574
- })
1575
- ]
1576
- }),
1577
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1578
- className: audio_panel_module_css_default.label,
1579
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "发音词典(每行一条:\"文字/读音\")" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1580
- className: audio_panel_module_css_default.textarea,
1581
- value: toneText,
1582
- onChange: (event) => setToneText(event.target.value),
1583
- placeholder: "处理/(chu3)(li3)\n危险/dangerous"
1584
- })]
1585
- }),
1586
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1587
- className: audio_panel_module_css_default.checkbox,
1588
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1589
- type: "checkbox",
1590
- checked: subtitle,
1591
- onChange: (event) => setSubtitle(event.target.checked)
1592
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "生成字幕 subtitle_enable" })]
1593
- })
1594
- ]
1595
- }) : null,
1596
- mode === "music" || mode === "sfx" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1597
- className: audio_panel_module_css_default.label,
1598
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("duration.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1599
- className: audio_panel_module_css_default.input,
1600
- type: "number",
1601
- step: "1",
1602
- min: "1",
1603
- max: "120",
1604
- value: duration,
1605
- onChange: (event) => setDuration(event.target.value),
1606
- placeholder: "30"
1607
- })]
1608
- }) : null,
1609
- mode === "sfx" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1610
- className: audio_panel_module_css_default.checkbox,
1611
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1612
- type: "checkbox",
1613
- checked: loop,
1614
- onChange: (event) => setLoop(event.target.checked)
1615
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "循环音效 loop(无缝循环,需 eleven_text_to_sound_v2)" })]
1616
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1617
- className: audio_panel_module_css_default.label,
1618
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "提示词影响度 prompt_influence (0-1)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1619
- className: audio_panel_module_css_default.input,
1620
- type: "number",
1621
- step: "0.1",
1622
- min: "0",
1623
- max: "1",
1624
- value: promptInfluence,
1625
- onChange: (event) => setPromptInfluence(event.target.value),
1626
- placeholder: "0.3"
1627
- })]
1628
- })] }) : null,
1629
- mode === "music" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1630
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1631
- className: audio_panel_module_css_default.label,
1632
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "歌词(纯音乐模式可留空;多段用空行分隔)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1633
- className: audio_panel_module_css_default.textarea,
1634
- value: lyrics,
1635
- onChange: (event) => setLyrics(event.target.value),
1636
- placeholder: "第一段歌词…\n\n第二段歌词…"
1637
- })]
1638
- }),
1639
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1640
- className: audio_panel_module_css_default.checkbox,
1641
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1642
- type: "checkbox",
1643
- checked: instrumental,
1644
- onChange: (event) => setInstrumental(event.target.checked)
1645
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "纯音乐(无歌词/人声)is_instrumental" })]
1646
- }),
1647
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1648
- className: audio_panel_module_css_default.row,
1649
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1650
- className: audio_panel_module_css_default.label,
1651
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "采样率" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1652
- className: audio_panel_module_css_default.input,
1653
- value: sampleRate,
1654
- onChange: (event) => setSampleRate(event.target.value),
1655
- children: [
1656
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1657
- value: "",
1658
- children: "默认(44100)"
1659
- }),
1660
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1661
- value: "16000",
1662
- children: "16000"
1663
- }),
1664
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1665
- value: "24000",
1666
- children: "24000"
1667
- }),
1668
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1669
- value: "32000",
1670
- children: "32000"
1671
- }),
1672
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1673
- value: "44100",
1674
- children: "44100"
1675
- })
1676
- ]
1677
- })]
1678
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1679
- className: audio_panel_module_css_default.label,
1680
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "码率 bps" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1681
- className: audio_panel_module_css_default.input,
1682
- value: bitrate,
1683
- onChange: (event) => setBitrate(event.target.value),
1684
- children: [
1685
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1686
- value: "",
1687
- children: "默认(256000)"
1688
- }),
1689
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1690
- value: "32000",
1691
- children: "32000"
1692
- }),
1693
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1694
- value: "64000",
1695
- children: "64000"
1696
- }),
1697
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1698
- value: "128000",
1699
- children: "128000"
1700
- }),
1701
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1702
- value: "256000",
1703
- children: "256000"
1704
- })
1705
- ]
1706
- })]
1707
- })]
1708
- })
1709
- ] }) : null,
1710
- needModel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1711
- className: audio_panel_module_css_default.label,
1712
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("format.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1713
- className: audio_panel_module_css_default.input,
1714
- value: format,
1715
- onChange: (event) => setFormat(event.target.value),
1716
- children: [
1717
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1718
- value: "mp3",
1719
- children: "mp3"
1720
- }),
1721
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1722
- value: "wav",
1723
- children: "wav"
1724
- }),
1725
- mode === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1726
- value: "flac",
1727
- children: "flac"
1728
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1729
- value: "ogg",
1730
- children: "ogg"
1731
- })] }) : null,
1732
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1733
- value: "pcm",
1734
- children: "pcm"
1735
- })
1736
- ]
1737
- })]
2576
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "MiniMax 高级参数" }), globalSpecs.filter((spec) => spec.advanced === true).map((spec) => renderField(spec))]
1738
2577
  }) : null,
1739
2578
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1740
2579
  className: audio_panel_module_css_default.checkbox,
@@ -1752,10 +2591,18 @@ window.__ModuleLoader__.load({
1752
2591
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1753
2592
  type: "button",
1754
2593
  className: audio_panel_module_css_default.generate,
1755
- disabled: loading || !connected || needModel && visibleModels.length === 0,
1756
- onClick: () => void submit(),
1757
- children: loading ? tt("generating") : tt("generate")
1758
- })
2594
+ disabled: !connected || (compareMode && needModel ? compareModels.length < 2 : needModel && visibleModels.length === 0),
2595
+ onClick: submit,
2596
+ children: compareMode && needModel ? "对比生成" : tt("generate")
2597
+ }),
2598
+ runningCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
2599
+ className: audio_panel_module_css_default.hint,
2600
+ children: [
2601
+ "进行中任务:",
2602
+ runningCount,
2603
+ " 个(并发上限在「设置 → 插件 → AI 音频」调整)"
2604
+ ]
2605
+ }) : null
1759
2606
  ]
1760
2607
  }),
1761
2608
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -1763,7 +2610,7 @@ window.__ModuleLoader__.load({
1763
2610
  children: [error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1764
2611
  className: audio_panel_module_css_default.error,
1765
2612
  children: error
1766
- }) : null, outputs.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2613
+ }) : null, tasks.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1767
2614
  className: audio_panel_module_css_default.resultEmpty,
1768
2615
  children: [
1769
2616
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -1773,84 +2620,88 @@ window.__ModuleLoader__.load({
1773
2620
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: tt("result.empty") }),
1774
2621
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1775
2622
  className: audio_panel_module_css_default.resultEmptyHint,
1776
- children: "生成结果将在这里播放、下载,并可一键加入资源库"
2623
+ children: "点击「开始生成」即创建一个任务,可同时进行多个;勾选「模型对比」用多个模型同参数生成对比"
1777
2624
  })
1778
2625
  ]
1779
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1780
- className: audio_panel_module_css_default.resultMeta,
1781
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("result.done", { count: outputs.length }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1782
- className: audio_panel_module_css_default.resultModeChip,
1783
- children: modeLabel
1784
- })]
1785
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1786
- className: audio_panel_module_css_default.audioList,
1787
- children: outputs.map((audio, index) => {
1788
- const saved = savedIds.has(audio.id);
2626
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2627
+ className: audio_panel_module_css_default.taskList,
2628
+ children: tasks.map((task) => {
2629
+ const elapsed = task.finishedAt !== void 0 ? Math.round((task.finishedAt - task.startedAt) / 1e3) : Math.round((Date.now() - task.startedAt) / 1e3);
2630
+ const statusText = task.status === "running" ? `生成中 ${task.progress.done}/${task.progress.total}${task.progress.current !== "" ? ` · ${task.progress.current}` : ""} · ${elapsed}s` : task.status === "done" ? `完成 · ${task.groups.reduce((sum, group) => sum + group.outputs.length, 0)} 段 · ${elapsed}s` : task.status === "cancelled" ? "已取消" : "失败";
1789
2631
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1790
- className: audio_panel_module_css_default.audioCard,
1791
- "data-saved": saved ? "true" : "false",
2632
+ className: audio_panel_module_css_default.taskCard,
2633
+ "data-state": task.status,
1792
2634
  children: [
1793
2635
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1794
- className: audio_panel_module_css_default.audioCardHead,
2636
+ className: audio_panel_module_css_default.taskHead,
1795
2637
  children: [
1796
- audio.voiceId !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1797
- className: audio_panel_module_css_default.voiceIdChip,
1798
- title: "新音色 ID",
1799
- children: ["新音色 ", audio.voiceId]
1800
- }) : null,
1801
- saved ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1802
- className: audio_panel_module_css_default.savedChip,
1803
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}), " 已入库"]
1804
- }) : null,
2638
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2639
+ className: audio_panel_module_css_default.resultModeChip,
2640
+ children: task.mode
2641
+ }),
2642
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2643
+ className: audio_panel_module_css_default.taskLabel,
2644
+ title: task.prompt,
2645
+ children: task.label
2646
+ }),
2647
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2648
+ className: audio_panel_module_css_default.taskStatus,
2649
+ "data-state": task.status,
2650
+ children: statusText
2651
+ }),
1805
2652
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1806
- className: audio_panel_module_css_default.audioCardIndex,
1807
- children: ["#", index + 1]
2653
+ className: audio_panel_module_css_default.taskActions,
2654
+ children: [task.status === "running" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2655
+ type: "button",
2656
+ className: audio_panel_module_css_default.ghostButton,
2657
+ onClick: () => cancelTask(task.id),
2658
+ children: "取消"
2659
+ }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2660
+ type: "button",
2661
+ className: audio_panel_module_css_default.ghostButton,
2662
+ onClick: () => removeTask(task.id),
2663
+ children: "移除"
2664
+ })]
1808
2665
  })
1809
2666
  ]
1810
2667
  }),
1811
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPlayer, {
1812
- src: dataUrlOf(audio),
1813
- itemKey: audio.id
1814
- }),
1815
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1816
- className: audio_panel_module_css_default.audioCardActions,
1817
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
1818
- className: audio_panel_module_css_default.ghostButton,
1819
- href: dataUrlOf(audio),
1820
- download: `generated-${index + 1}.${audio.mime.split("/")[1]?.replace("mpeg", "mp3") ?? "mp3"}`,
1821
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DownloadIcon, {}), " 下载"]
1822
- }), saved ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1823
- type: "button",
1824
- className: audio_panel_module_css_default.ghostButton,
1825
- onClick: () => props.showToast("该音频已加入资源库"),
1826
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}), " 已入库"]
1827
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1828
- type: "button",
1829
- className: audio_panel_module_css_default.ghostButton,
1830
- onClick: () => openSaveDialog([audio], {
1831
- mode,
1832
- prompt: prompt.trim(),
1833
- ...voice.trim() !== "" ? { voice: voice.trim() } : {},
1834
- ...audio.voiceId === void 0 ? {} : { voiceId: audio.voiceId },
1835
- ...model !== "" ? { model } : {},
1836
- ...channels.length > 0 ? { channel: channels.find((candidate) => candidate.id === (mode === "voice_design" ? designChannelId : modelOptions.defaultChannelId))?.name ?? channels[0]?.name ?? "" } : {},
1837
- params: {
1838
- mode,
1839
- model: mode === "voice_design" ? "" : (model || visibleModels[0]) ?? "",
1840
- prompt: prompt.trim(),
1841
- ...voice.trim() !== "" ? { voice: voice.trim() } : {},
1842
- ...speed.trim() !== "" ? { speed: Number(speed) } : {},
1843
- ...duration.trim() !== "" ? { duration: Number(duration) } : {},
1844
- ...format.trim() !== "" ? { format: format.trim() } : {}
1845
- }
1846
- }),
1847
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StarIcon, {}), " 加入资源库"]
1848
- })]
2668
+ task.error !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2669
+ className: audio_panel_module_css_default.hint,
2670
+ "data-error": true,
2671
+ children: task.error
2672
+ }) : null,
2673
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2674
+ className: audio_panel_module_css_default.compareBoard,
2675
+ children: task.groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2676
+ className: audio_panel_module_css_default.compareGroup,
2677
+ "data-state": group.state,
2678
+ children: [
2679
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2680
+ className: audio_panel_module_css_default.compareGroupHead,
2681
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2682
+ className: audio_panel_module_css_default.compareModelName,
2683
+ children: group.model
2684
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2685
+ className: audio_panel_module_css_default.compareState,
2686
+ children: group.state === "waiting" ? "等待中…" : group.state === "running" ? "生成中…" : group.state === "done" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}), " 完成"] }) : group.state === "cancelled" ? "已取消" : "失败"
2687
+ })]
2688
+ }),
2689
+ group.state === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2690
+ className: audio_panel_module_css_default.hint,
2691
+ "data-error": true,
2692
+ children: group.error
2693
+ }) : null,
2694
+ group.outputs.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2695
+ className: audio_panel_module_css_default.audioList,
2696
+ children: group.outputs.map((audio, index) => renderAudioCard(audio, index, group.model, group.model))
2697
+ }) : null
2698
+ ]
2699
+ }, group.model))
1849
2700
  })
1850
2701
  ]
1851
- }, audio.id);
2702
+ }, task.id);
1852
2703
  })
1853
- })] })]
2704
+ })]
1854
2705
  }),
1855
2706
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
1856
2707
  className: audio_panel_module_css_default.historyCol,
@@ -1868,41 +2719,113 @@ window.__ModuleLoader__.load({
1868
2719
  }), entries.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1869
2720
  className: audio_panel_module_css_default.historyEmpty,
1870
2721
  children: tt("history.empty")
1871
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2722
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2723
+ className: audio_panel_module_css_default.historyTabs,
2724
+ children: [
2725
+ "all",
2726
+ "tts",
2727
+ "music",
2728
+ "sfx",
2729
+ "voice_design"
2730
+ ].map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2731
+ type: "button",
2732
+ className: audio_panel_module_css_default.historyTab,
2733
+ "data-active": historyTab === tab ? "true" : "false",
2734
+ onClick: () => setHistoryTab(tab),
2735
+ children: [tab === "all" ? "全部" : modeLabelOf(tab), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2736
+ className: audio_panel_module_css_default.historyTabCount,
2737
+ children: tab === "all" ? entries.length : historyItems.filter((item) => item.mode === tab).length
2738
+ })]
2739
+ }, tab))
2740
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1872
2741
  className: audio_panel_module_css_default.historyList,
1873
- children: entries.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1874
- className: audio_panel_module_css_default.historyItem,
1875
- children: [
1876
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1877
- className: audio_panel_module_css_default.historyPrompt,
1878
- children: entry.prompt
1879
- }),
1880
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1881
- className: audio_panel_module_css_default.historyMeta,
1882
- children: [
1883
- entry.mode,
1884
- " · ",
1885
- entry.model,
1886
- entry.channel ? ` · ${entry.channel}` : ""
1887
- ]
1888
- }),
1889
- entry.audio.map((audio, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPlayer, {
1890
- src: audio.url,
1891
- compact: true,
1892
- itemKey: `${entry.id}-${index}`
1893
- }, index)),
1894
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1895
- className: audio_panel_module_css_default.historyActions,
1896
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1897
- type: "button",
1898
- className: audio_panel_module_css_default.historyAction,
1899
- onClick: () => openSaveDialog(audioRefsOfEntry(entry), contextOfEntry(entry)),
1900
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StarIcon, {}), " 入库"]
2742
+ children: (historyTab === "all" ? historyItems : historyItems.filter((item) => item.mode === historyTab)).map((item) => {
2743
+ if (item.kind === "compare") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
2744
+ className: audio_panel_module_css_default.historyItem,
2745
+ open: true,
2746
+ children: [
2747
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
2748
+ className: audio_panel_module_css_default.historyCompareSummary,
2749
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2750
+ className: audio_panel_module_css_default.historyPrompt,
2751
+ children: item.prompt
2752
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2753
+ className: audio_panel_module_css_default.historyCompareBadge,
2754
+ children: [
2755
+ "对比 · ",
2756
+ item.models.length,
2757
+ " 个模型"
2758
+ ]
2759
+ })]
2760
+ }),
2761
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2762
+ className: audio_panel_module_css_default.historyMeta,
2763
+ children: [
2764
+ modeLabelOf(item.mode),
2765
+ " · ",
2766
+ item.models.map((model) => model.model).join(" / ")
2767
+ ]
2768
+ }),
2769
+ item.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2770
+ className: audio_panel_module_css_default.historyModelRow,
2771
+ children: [
2772
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2773
+ className: audio_panel_module_css_default.historyMeta,
2774
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: model.model }), model.channel !== void 0 ? ` · ${model.channel}` : ""]
2775
+ }),
2776
+ model.entry.audio.map((audio, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPlayer, {
2777
+ src: audio.url,
2778
+ compact: true,
2779
+ itemKey: `${item.key}-${model.entry.id}-${index}`
2780
+ }, index)),
2781
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2782
+ className: audio_panel_module_css_default.historyActions,
2783
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2784
+ type: "button",
2785
+ className: audio_panel_module_css_default.historyAction,
2786
+ onClick: () => openSaveDialog(audioRefsOfEntry(model.entry), contextOfEntry(model.entry)),
2787
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StarIcon, {}), " 入库"]
2788
+ })
2789
+ })
2790
+ ]
2791
+ }, model.entry.id))
2792
+ ]
2793
+ }, item.key);
2794
+ const entry = item.entry;
2795
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2796
+ className: audio_panel_module_css_default.historyItem,
2797
+ children: [
2798
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2799
+ className: audio_panel_module_css_default.historyPrompt,
2800
+ children: entry.prompt
2801
+ }),
2802
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2803
+ className: audio_panel_module_css_default.historyMeta,
2804
+ children: [
2805
+ modeLabelOf(entry.mode),
2806
+ " · ",
2807
+ entry.model,
2808
+ entry.channel ? ` · ${entry.channel}` : ""
2809
+ ]
2810
+ }),
2811
+ entry.audio.map((audio, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPlayer, {
2812
+ src: audio.url,
2813
+ compact: true,
2814
+ itemKey: `${entry.id}-${index}`
2815
+ }, index)),
2816
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2817
+ className: audio_panel_module_css_default.historyActions,
2818
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2819
+ type: "button",
2820
+ className: audio_panel_module_css_default.historyAction,
2821
+ onClick: () => openSaveDialog(audioRefsOfEntry(entry), contextOfEntry(entry)),
2822
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StarIcon, {}), " 入库"]
2823
+ })
1901
2824
  })
1902
- })
1903
- ]
1904
- }, entry.id))
1905
- })]
2825
+ ]
2826
+ }, item.key);
2827
+ })
2828
+ })] })]
1906
2829
  }),
1907
2830
  saveDialog !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LibrarySaveDialog, {
1908
2831
  api,
@@ -1926,62 +2849,62 @@ window.__ModuleLoader__.load({
1926
2849
  document.head.appendChild(tag);
1927
2850
  }
1928
2851
  var library_module_css_default = {
1929
- "toolbar": "vzUV2a_toolbar",
1930
- "primaryBtn": "vzUV2a_primaryBtn",
2852
+ "drawerMask": "vzUV2a_drawerMask",
1931
2853
  "audiogenDrawerIn": "vzUV2a_audiogenDrawerIn",
1932
2854
  "drawerLabel": "vzUV2a_drawerLabel",
1933
- "emptyHint": "vzUV2a_emptyHint",
1934
- "emptyIcon": "vzUV2a_emptyIcon",
1935
- "chipCount": "vzUV2a_chipCount",
2855
+ "searchBox": "vzUV2a_searchBox",
2856
+ "listHead": "vzUV2a_listHead",
2857
+ "card": "vzUV2a_card",
1936
2858
  "filterRow": "vzUV2a_filterRow",
1937
- "cardFoot": "vzUV2a_cardFoot",
1938
- "listCount": "vzUV2a_listCount",
1939
- "chip": "vzUV2a_chip",
1940
- "metaChip": "vzUV2a_metaChip",
1941
- "drawerHead": "vzUV2a_drawerHead",
1942
- "typeBadge": "vzUV2a_typeBadge",
1943
- "drawerSection": "vzUV2a_drawerSection",
1944
- "textarea": "vzUV2a_textarea",
1945
2859
  "smallChip": "vzUV2a_smallChip",
1946
- "dangerBtn": "vzUV2a_dangerBtn",
1947
- "cardTime": "vzUV2a_cardTime",
1948
- "listActions": "vzUV2a_listActions",
1949
- "drawer": "vzUV2a_drawer",
1950
- "cardName": "vzUV2a_cardName",
2860
+ "emptyIcon": "vzUV2a_emptyIcon",
1951
2861
  "iconBtn": "vzUV2a_iconBtn",
1952
- "drawerPlayerList": "vzUV2a_drawerPlayerList",
1953
- "drawerPlayerName": "vzUV2a_drawerPlayerName",
2862
+ "drawerBody": "vzUV2a_drawerBody",
1954
2863
  "drawerField": "vzUV2a_drawerField",
2864
+ "listActions": "vzUV2a_listActions",
1955
2865
  "input": "vzUV2a_input",
1956
- "filterLabel": "vzUV2a_filterLabel",
2866
+ "metaChip": "vzUV2a_metaChip",
2867
+ "mono": "vzUV2a_mono",
2868
+ "cardCheck": "vzUV2a_cardCheck",
2869
+ "drawerSection": "vzUV2a_drawerSection",
2870
+ "drawerTitle": "vzUV2a_drawerTitle",
1957
2871
  "provenance": "vzUV2a_provenance",
1958
- "searchBox": "vzUV2a_searchBox",
2872
+ "stateNote": "vzUV2a_stateNote",
2873
+ "textarea": "vzUV2a_textarea",
2874
+ "code": "vzUV2a_code",
2875
+ "paramsDetails": "vzUV2a_paramsDetails",
2876
+ "drawerPlayer": "vzUV2a_drawerPlayer",
2877
+ "drawerActions": "vzUV2a_drawerActions",
2878
+ "drawerPlayerName": "vzUV2a_drawerPlayerName",
2879
+ "primaryBtn": "vzUV2a_primaryBtn",
2880
+ "typeBadge": "vzUV2a_typeBadge",
2881
+ "cardFoot": "vzUV2a_cardFoot",
2882
+ "selCount": "vzUV2a_selCount",
2883
+ "grid": "vzUV2a_grid",
2884
+ "drawer": "vzUV2a_drawer",
2885
+ "searchInput": "vzUV2a_searchInput",
2886
+ "drawerPlayerList": "vzUV2a_drawerPlayerList",
1959
2887
  "provKey": "vzUV2a_provKey",
1960
- "cardCheck": "vzUV2a_cardCheck",
2888
+ "drawerHead": "vzUV2a_drawerHead",
2889
+ "dangerBtn": "vzUV2a_dangerBtn",
2890
+ "toolbar": "vzUV2a_toolbar",
2891
+ "provRow": "vzUV2a_provRow",
1961
2892
  "provValue": "vzUV2a_provValue",
1962
- "mono": "vzUV2a_mono",
1963
2893
  "ghostBtn": "vzUV2a_ghostBtn",
1964
- "code": "vzUV2a_code",
1965
- "stateNote": "vzUV2a_stateNote",
2894
+ "chipCount": "vzUV2a_chipCount",
1966
2895
  "typeChips": "vzUV2a_typeChips",
1967
- "drawerPlayer": "vzUV2a_drawerPlayer",
1968
- "paramsDetails": "vzUV2a_paramsDetails",
1969
- "listHead": "vzUV2a_listHead",
1970
- "cardHead": "vzUV2a_cardHead",
2896
+ "smallSelect": "vzUV2a_smallSelect",
1971
2897
  "drawerSplit": "vzUV2a_drawerSplit",
1972
- "selCount": "vzUV2a_selCount",
1973
- "drawerTitle": "vzUV2a_drawerTitle",
1974
- "provRow": "vzUV2a_provRow",
1975
- "empty": "vzUV2a_empty",
1976
- "promptText": "vzUV2a_promptText",
1977
- "searchInput": "vzUV2a_searchInput",
1978
- "drawerActions": "vzUV2a_drawerActions",
1979
- "drawerMask": "vzUV2a_drawerMask",
1980
- "grid": "vzUV2a_grid",
1981
- "card": "vzUV2a_card",
1982
2898
  "library": "vzUV2a_library",
1983
- "smallSelect": "vzUV2a_smallSelect",
1984
- "drawerBody": "vzUV2a_drawerBody"
2899
+ "emptyHint": "vzUV2a_emptyHint",
2900
+ "cardHead": "vzUV2a_cardHead",
2901
+ "cardTime": "vzUV2a_cardTime",
2902
+ "promptText": "vzUV2a_promptText",
2903
+ "empty": "vzUV2a_empty",
2904
+ "cardName": "vzUV2a_cardName",
2905
+ "filterLabel": "vzUV2a_filterLabel",
2906
+ "listCount": "vzUV2a_listCount",
2907
+ "chip": "vzUV2a_chip"
1985
2908
  };
1986
2909
  //#endregion
1987
2910
  //#region src/client/library-view.tsx
@@ -2356,10 +3279,10 @@ window.__ModuleLoader__.load({
2356
3279
  className: library_module_css_default.stateNote,
2357
3280
  children: "加载中…"
2358
3281
  }) : null,
2359
- error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3282
+ error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2360
3283
  className: library_module_css_default.stateNote,
2361
3284
  "data-error": true,
2362
- children: error
3285
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: error }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: "若提示 not found / 404:插件宿主尚未加载新代码,请重启 `dsh web` 后在浏览器强制刷新(Cmd+Shift+R)。" })]
2363
3286
  }) : null,
2364
3287
  !loading && error === null && filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2365
3288
  className: library_module_css_default.empty,
@@ -2854,167 +3777,167 @@ window.__ModuleLoader__.load({
2854
3777
  document.head.appendChild(tag);
2855
3778
  }
2856
3779
  var panel_module_css_default = {
2857
- "modelWrap": "rwa6qG_modelWrap",
2858
- "modeRow": "rwa6qG_modeRow",
2859
- "taskStatus": "rwa6qG_taskStatus",
2860
- "panelHeader": "rwa6qG_panelHeader",
2861
- "taskPrompt": "rwa6qG_taskPrompt",
2862
- "compareControl": "rwa6qG_compareControl",
2863
- "download": "rwa6qG_download",
2864
- "canvasMeta": "rwa6qG_canvasMeta",
2865
- "galleryTagFilter": "rwa6qG_galleryTagFilter",
2866
- "galleryClear": "rwa6qG_galleryClear",
2867
- "historyThumbPlaceholder": "rwa6qG_historyThumbPlaceholder",
2868
- "panelTitle": "rwa6qG_panelTitle",
2869
- "lightboxTools": "rwa6qG_lightboxTools",
2870
- "galleryTags": "rwa6qG_galleryTags",
2871
- "githubLink": "rwa6qG_githubLink",
2872
- "imageCard": "rwa6qG_imageCard",
2873
- "galleryCardFooter": "rwa6qG_galleryCardFooter",
2874
- "lightboxCaption": "rwa6qG_lightboxCaption",
2875
3780
  "view": "rwa6qG_view",
2876
- "panel": "rwa6qG_panel",
2877
- "canvasError": "rwa6qG_canvasError",
2878
- "canvasBody": "rwa6qG_canvasBody",
2879
- "lightboxMeta": "rwa6qG_lightboxMeta",
2880
- "galleryTagEditor": "rwa6qG_galleryTagEditor",
2881
- "galleryToolbar": "rwa6qG_galleryToolbar",
2882
- "uploadBox": "rwa6qG_uploadBox",
2883
- "galleryTagFilterList": "rwa6qG_galleryTagFilterList",
2884
- "history": "rwa6qG_history",
2885
- "historySearch": "rwa6qG_historySearch",
2886
- "historyFilters": "rwa6qG_historyFilters",
2887
- "modePill": "rwa6qG_modePill",
2888
- "prompt": "rwa6qG_prompt",
2889
- "lightboxStage": "rwa6qG_lightboxStage",
2890
- "comparisonBoard": "rwa6qG_comparisonBoard",
2891
- "spinner": "rwa6qG_spinner",
2892
- "galleryImage": "rwa6qG_galleryImage",
2893
- "dshImageGenToastIn": "rwa6qG_dshImageGenToastIn",
2894
- "hiddenFile": "rwa6qG_hiddenFile",
2895
- "taskTrayCount": "rwa6qG_taskTrayCount",
2896
- "compareModelChoices": "rwa6qG_compareModelChoices",
2897
- "taskTray": "rwa6qG_taskTray",
2898
- "canvasEmptyIcon": "rwa6qG_canvasEmptyIcon",
2899
- "gallerySort": "rwa6qG_gallerySort",
3781
+ "lightboxClose": "rwa6qG_lightboxClose",
3782
+ "galleryWorkspace": "rwa6qG_galleryWorkspace",
2900
3783
  "galleryRemove": "rwa6qG_galleryRemove",
2901
- "bigSpinner": "rwa6qG_bigSpinner",
2902
- "historyClear": "rwa6qG_historyClear",
2903
- "templatesButton": "rwa6qG_templatesButton",
2904
- "promptCount": "rwa6qG_promptCount",
2905
- "generateButton": "rwa6qG_generateButton",
2906
- "taskRow": "rwa6qG_taskRow",
2907
- "modelSelect": "rwa6qG_modelSelect",
2908
- "compareToggle": "rwa6qG_compareToggle",
2909
- "taskTrayToggle": "rwa6qG_taskTrayToggle",
2910
- "taskTrayChevron": "rwa6qG_taskTrayChevron",
2911
- "galleryImageButton": "rwa6qG_galleryImageButton",
2912
- "lightboxTool": "rwa6qG_lightboxTool",
2913
- "comparisonImageButton": "rwa6qG_comparisonImageButton",
2914
- "galleryCount": "rwa6qG_galleryCount",
3784
+ "lightboxMeta": "rwa6qG_lightboxMeta",
3785
+ "canvasState": "rwa6qG_canvasState",
3786
+ "taskTrayHeader": "rwa6qG_taskTrayHeader",
2915
3787
  "galleryFilterHeading": "rwa6qG_galleryFilterHeading",
2916
- "entryLabel": "rwa6qG_entryLabel",
3788
+ "galleryFilterDivider": "rwa6qG_galleryFilterDivider",
3789
+ "galleryViewToggle": "rwa6qG_galleryViewToggle",
3790
+ "galleryClear": "rwa6qG_galleryClear",
2917
3791
  "galleryHeading": "rwa6qG_galleryHeading",
2918
- "galleryRatioList": "rwa6qG_galleryRatioList",
2919
- "lightboxCaptionRow": "rwa6qG_lightboxCaptionRow",
2920
- "updateActions": "rwa6qG_updateActions",
2921
- "configGuideBody": "rwa6qG_configGuideBody",
2922
- "uploadIcon": "rwa6qG_uploadIcon",
2923
- "optionGrid": "rwa6qG_optionGrid",
3792
+ "connectionDot": "rwa6qG_connectionDot",
3793
+ "uploadHint": "rwa6qG_uploadHint",
3794
+ "compareModelChoices": "rwa6qG_compareModelChoices",
3795
+ "canvasError": "rwa6qG_canvasError",
3796
+ "galleryFilterNote": "rwa6qG_galleryFilterNote",
3797
+ "hiddenFile": "rwa6qG_hiddenFile",
3798
+ "historyThumbPlaceholder": "rwa6qG_historyThumbPlaceholder",
3799
+ "configGuide": "rwa6qG_configGuide",
3800
+ "galleryTagFilter": "rwa6qG_galleryTagFilter",
3801
+ "updateBanner": "rwa6qG_updateBanner",
3802
+ "lightboxTool": "rwa6qG_lightboxTool",
3803
+ "historyTitle": "rwa6qG_historyTitle",
2924
3804
  "dshImageGenSpin": "rwa6qG_dshImageGenSpin",
2925
- "footer": "rwa6qG_footer",
2926
- "reference": "rwa6qG_reference",
2927
3805
  "lightbox": "rwa6qG_lightbox",
2928
- "lightboxEdit": "rwa6qG_lightboxEdit",
3806
+ "referenceActions": "rwa6qG_referenceActions",
3807
+ "lightboxFigure": "rwa6qG_lightboxFigure",
3808
+ "taskTrayClose": "rwa6qG_taskTrayClose",
2929
3809
  "referenceImage": "rwa6qG_referenceImage",
2930
- "enhanceButton": "rwa6qG_enhanceButton",
2931
- "galleryRatio": "rwa6qG_galleryRatio",
2932
- "galleryToolbarActions": "rwa6qG_galleryToolbarActions",
2933
- "paramHint": "rwa6qG_paramHint",
2934
- "card": "rwa6qG_card",
2935
- "comparisonFullscreenGrid": "rwa6qG_comparisonFullscreenGrid",
2936
- "connectionDot": "rwa6qG_connectionDot",
2937
- "historyMain": "rwa6qG_historyMain",
2938
- "connectionStatus": "rwa6qG_connectionStatus",
2939
- "galleryTagInput": "rwa6qG_galleryTagInput",
2940
3810
  "lightboxDownload": "rwa6qG_lightboxDownload",
3811
+ "lightboxActions": "rwa6qG_lightboxActions",
3812
+ "download": "rwa6qG_download",
3813
+ "comparisonBoard": "rwa6qG_comparisonBoard",
3814
+ "galleryImageButton": "rwa6qG_galleryImageButton",
3815
+ "optionRow": "rwa6qG_optionRow",
3816
+ "entryLabel": "rwa6qG_entryLabel",
3817
+ "galleryAdd": "rwa6qG_galleryAdd",
3818
+ "canvasMeta": "rwa6qG_canvasMeta",
3819
+ "historyList": "rwa6qG_historyList",
3820
+ "reference": "rwa6qG_reference",
3821
+ "footer": "rwa6qG_footer",
3822
+ "lightboxCopy": "rwa6qG_lightboxCopy",
3823
+ "galleryImage": "rwa6qG_galleryImage",
3824
+ "galleryBadge": "rwa6qG_galleryBadge",
3825
+ "historyInfo": "rwa6qG_historyInfo",
3826
+ "gallerySearch": "rwa6qG_gallerySearch",
3827
+ "lightboxIndex": "rwa6qG_lightboxIndex",
3828
+ "lightboxImage": "rwa6qG_lightboxImage",
2941
3829
  "lightboxScaleFrame": "rwa6qG_lightboxScaleFrame",
2942
- "galleryFilterDivider": "rwa6qG_galleryFilterDivider",
2943
- "config": "rwa6qG_config",
2944
- "updateRelease": "rwa6qG_updateRelease",
2945
- "galleryFilter": "rwa6qG_galleryFilter",
2946
- "galleryTagEdit": "rwa6qG_galleryTagEdit",
2947
- "configGuide": "rwa6qG_configGuide",
3830
+ "galleryBulkButton": "rwa6qG_galleryBulkButton",
3831
+ "paramHint": "rwa6qG_paramHint",
3832
+ "updateActions": "rwa6qG_updateActions",
3833
+ "modelWrap": "rwa6qG_modelWrap",
3834
+ "lightboxTools": "rwa6qG_lightboxTools",
3835
+ "galleryCardFooter": "rwa6qG_galleryCardFooter",
3836
+ "zoomHint": "rwa6qG_zoomHint",
2948
3837
  "panelHeading": "rwa6qG_panelHeading",
2949
- "entryIcon": "rwa6qG_entryIcon",
2950
- "gallerySelectionClear": "rwa6qG_gallerySelectionClear",
2951
- "galleryFilterCount": "rwa6qG_galleryFilterCount",
3838
+ "panelTitle": "rwa6qG_panelTitle",
3839
+ "taskTrayToggle": "rwa6qG_taskTrayToggle",
3840
+ "modelSelect": "rwa6qG_modelSelect",
3841
+ "generateButton": "rwa6qG_generateButton",
3842
+ "compareControl": "rwa6qG_compareControl",
3843
+ "historySearch": "rwa6qG_historySearch",
3844
+ "optionPill": "rwa6qG_optionPill",
3845
+ "historyPrompt": "rwa6qG_historyPrompt",
3846
+ "uploadBox": "rwa6qG_uploadBox",
3847
+ "gallerySelect": "rwa6qG_gallerySelect",
3848
+ "grid": "rwa6qG_grid",
3849
+ "galleryCount": "rwa6qG_galleryCount",
3850
+ "bigSpinner": "rwa6qG_bigSpinner",
3851
+ "canvas": "rwa6qG_canvas",
3852
+ "taskTrayCount": "rwa6qG_taskTrayCount",
2952
3853
  "historyHeader": "rwa6qG_historyHeader",
2953
- "paramGroup": "rwa6qG_paramGroup",
2954
- "lightboxActions": "rwa6qG_lightboxActions",
3854
+ "comparisonGrid": "rwa6qG_comparisonGrid",
3855
+ "galleryFilter": "rwa6qG_galleryFilter",
3856
+ "lightboxCaption": "rwa6qG_lightboxCaption",
2955
3857
  "galleryToast": "rwa6qG_galleryToast",
2956
- "paramLabel": "rwa6qG_paramLabel",
2957
- "taskRows": "rwa6qG_taskRows",
2958
- "modelLabel": "rwa6qG_modelLabel",
2959
- "generateInner": "rwa6qG_generateInner",
2960
- "updateBanner": "rwa6qG_updateBanner",
2961
- "lightboxImage": "rwa6qG_lightboxImage",
2962
- "comparisonFullscreen": "rwa6qG_comparisonFullscreen",
2963
- "historyInfo": "rwa6qG_historyInfo",
2964
3858
  "promptFooter": "rwa6qG_promptFooter",
2965
- "image": "rwa6qG_image",
2966
- "optionRow": "rwa6qG_optionRow",
2967
- "modelMenuList": "rwa6qG_modelMenuList",
3859
+ "githubLink": "rwa6qG_githubLink",
3860
+ "canvasEmptyIcon": "rwa6qG_canvasEmptyIcon",
3861
+ "dshImageGenToastIn": "rwa6qG_dshImageGenToastIn",
3862
+ "galleryMasonry": "rwa6qG_galleryMasonry",
3863
+ "galleryAvatar": "rwa6qG_galleryAvatar",
3864
+ "panelHeader": "rwa6qG_panelHeader",
3865
+ "connectionStatus": "rwa6qG_connectionStatus",
3866
+ "galleryTagInput": "rwa6qG_galleryTagInput",
3867
+ "galleryToolbarActions": "rwa6qG_galleryToolbarActions",
2968
3868
  "imageCaption": "rwa6qG_imageCaption",
2969
- "galleryCard": "rwa6qG_galleryCard",
2970
- "canvasStateHint": "rwa6qG_canvasStateHint",
2971
- "galleryWorkspace": "rwa6qG_galleryWorkspace",
3869
+ "templatesButton": "rwa6qG_templatesButton",
3870
+ "updateRelease": "rwa6qG_updateRelease",
3871
+ "card": "rwa6qG_card",
3872
+ "galleryRatio": "rwa6qG_galleryRatio",
3873
+ "compareToggle": "rwa6qG_compareToggle",
3874
+ "galleryTags": "rwa6qG_galleryTags",
3875
+ "comparisonImageButton": "rwa6qG_comparisonImageButton",
3876
+ "galleryRatioList": "rwa6qG_galleryRatioList",
2972
3877
  "historyEmpty": "rwa6qG_historyEmpty",
2973
- "galleryAvatar": "rwa6qG_galleryAvatar",
2974
- "studio": "rwa6qG_studio",
2975
- "historyTitle": "rwa6qG_historyTitle",
2976
- "canvasHistoryTag": "rwa6qG_canvasHistoryTag",
2977
- "historyThumb": "rwa6qG_historyThumb",
2978
- "historyMeta": "rwa6qG_historyMeta",
2979
- "historyActions": "rwa6qG_historyActions",
2980
- "uploadHint": "rwa6qG_uploadHint",
2981
- "galleryMasonry": "rwa6qG_galleryMasonry",
3878
+ "modePill": "rwa6qG_modePill",
3879
+ "paramGroup": "rwa6qG_paramGroup",
3880
+ "galleryFilterCount": "rwa6qG_galleryFilterCount",
3881
+ "comparisonFullscreenGrid": "rwa6qG_comparisonFullscreenGrid",
2982
3882
  "modelMenuItem": "rwa6qG_modelMenuItem",
2983
- "configScroll": "rwa6qG_configScroll",
2984
- "zoomHint": "rwa6qG_zoomHint",
2985
- "galleryFilterNote": "rwa6qG_galleryFilterNote",
2986
- "entry": "rwa6qG_entry",
2987
- "taskTrayClose": "rwa6qG_taskTrayClose",
2988
- "referenceActions": "rwa6qG_referenceActions",
3883
+ "config": "rwa6qG_config",
2989
3884
  "modelMenu": "rwa6qG_modelMenu",
2990
- "canvasStateTitle": "rwa6qG_canvasStateTitle",
2991
- "historyPrompt": "rwa6qG_historyPrompt",
3885
+ "galleryTagEditor": "rwa6qG_galleryTagEditor",
3886
+ "imageCard": "rwa6qG_imageCard",
3887
+ "lightboxCaptionRow": "rwa6qG_lightboxCaptionRow",
3888
+ "historyFilters": "rwa6qG_historyFilters",
3889
+ "gallerySelectionBar": "rwa6qG_gallerySelectionBar",
3890
+ "taskPrompt": "rwa6qG_taskPrompt",
3891
+ "historyThumb": "rwa6qG_historyThumb",
3892
+ "canvasBody": "rwa6qG_canvasBody",
3893
+ "taskRows": "rwa6qG_taskRows",
3894
+ "optionGrid": "rwa6qG_optionGrid",
3895
+ "modelLabel": "rwa6qG_modelLabel",
3896
+ "entryIcon": "rwa6qG_entryIcon",
3897
+ "galleryCard": "rwa6qG_galleryCard",
2992
3898
  "historyItem": "rwa6qG_historyItem",
3899
+ "lightboxStage": "rwa6qG_lightboxStage",
3900
+ "taskStatus": "rwa6qG_taskStatus",
3901
+ "uploadIcon": "rwa6qG_uploadIcon",
3902
+ "paramLabel": "rwa6qG_paramLabel",
3903
+ "galleryCardInfo": "rwa6qG_galleryCardInfo",
3904
+ "taskTray": "rwa6qG_taskTray",
2993
3905
  "lightboxZoomLevel": "rwa6qG_lightboxZoomLevel",
2994
- "lightboxCopy": "rwa6qG_lightboxCopy",
2995
- "lightboxIndex": "rwa6qG_lightboxIndex",
2996
- "gallerySelectionBar": "rwa6qG_gallerySelectionBar",
2997
- "galleryBadge": "rwa6qG_galleryBadge",
3906
+ "modelMenuList": "rwa6qG_modelMenuList",
3907
+ "historyMain": "rwa6qG_historyMain",
3908
+ "galleryTagEdit": "rwa6qG_galleryTagEdit",
3909
+ "canvasStateTitle": "rwa6qG_canvasStateTitle",
3910
+ "history": "rwa6qG_history",
3911
+ "historyClear": "rwa6qG_historyClear",
3912
+ "comparisonFullscreen": "rwa6qG_comparisonFullscreen",
3913
+ "enhanceButton": "rwa6qG_enhanceButton",
3914
+ "historyAction": "rwa6qG_historyAction",
2998
3915
  "updateText": "rwa6qG_updateText",
2999
- "historyList": "rwa6qG_historyList",
3000
- "taskTrayHeader": "rwa6qG_taskTrayHeader",
3916
+ "historyActions": "rwa6qG_historyActions",
3917
+ "galleryToolbar": "rwa6qG_galleryToolbar",
3918
+ "configGuideBody": "rwa6qG_configGuideBody",
3919
+ "taskTrayChevron": "rwa6qG_taskTrayChevron",
3920
+ "configScroll": "rwa6qG_configScroll",
3001
3921
  "lightboxNav": "rwa6qG_lightboxNav",
3002
- "canvasState": "rwa6qG_canvasState",
3003
- "gallerySearch": "rwa6qG_gallerySearch",
3004
- "canvas": "rwa6qG_canvas",
3005
- "galleryAdd": "rwa6qG_galleryAdd",
3006
- "lightboxFigure": "rwa6qG_lightboxFigure",
3007
- "historyAction": "rwa6qG_historyAction",
3008
- "galleryBulkButton": "rwa6qG_galleryBulkButton",
3009
- "galleryFilters": "rwa6qG_galleryFilters",
3922
+ "gallerySelectionClear": "rwa6qG_gallerySelectionClear",
3923
+ "gallerySort": "rwa6qG_gallerySort",
3924
+ "modeRow": "rwa6qG_modeRow",
3925
+ "taskRow": "rwa6qG_taskRow",
3926
+ "historyMeta": "rwa6qG_historyMeta",
3927
+ "spinner": "rwa6qG_spinner",
3928
+ "studio": "rwa6qG_studio",
3929
+ "entry": "rwa6qG_entry",
3930
+ "canvasHistoryTag": "rwa6qG_canvasHistoryTag",
3931
+ "lightboxEdit": "rwa6qG_lightboxEdit",
3932
+ "promptCount": "rwa6qG_promptCount",
3933
+ "panel": "rwa6qG_panel",
3934
+ "image": "rwa6qG_image",
3935
+ "prompt": "rwa6qG_prompt",
3936
+ "galleryTagFilterList": "rwa6qG_galleryTagFilterList",
3010
3937
  "gallerySelectMode": "rwa6qG_gallerySelectMode",
3011
- "galleryViewToggle": "rwa6qG_galleryViewToggle",
3012
- "galleryCardInfo": "rwa6qG_galleryCardInfo",
3013
- "gallerySelect": "rwa6qG_gallerySelect",
3014
- "comparisonGrid": "rwa6qG_comparisonGrid",
3015
- "lightboxClose": "rwa6qG_lightboxClose",
3016
- "optionPill": "rwa6qG_optionPill",
3017
- "grid": "rwa6qG_grid"
3938
+ "canvasStateHint": "rwa6qG_canvasStateHint",
3939
+ "generateInner": "rwa6qG_generateInner",
3940
+ "galleryFilters": "rwa6qG_galleryFilters"
3018
3941
  };
3019
3942
  //#endregion
3020
3943
  //#region src/client/mount.tsx
@@ -3671,79 +4594,79 @@ window.__ModuleLoader__.load({
3671
4594
  document.head.appendChild(tag);
3672
4595
  }
3673
4596
  var settings_card_module_css_default = {
3674
- "channelAddRow": "zmjoSq_channelAddRow",
3675
- "channelRow": "zmjoSq_channelRow",
3676
- "channelMeta": "zmjoSq_channelMeta",
3677
- "editorTitle": "zmjoSq_editorTitle",
3678
- "editorHeader": "zmjoSq_editorHeader",
3679
- "linkButton": "zmjoSq_linkButton",
3680
- "sectionHeader": "zmjoSq_sectionHeader",
3681
- "customSettings": "zmjoSq_customSettings",
4597
+ "input": "zmjoSq_input",
4598
+ "modelCatalogHead": "zmjoSq_modelCatalogHead",
4599
+ "modelArrow": "zmjoSq_modelArrow",
4600
+ "save": "zmjoSq_save",
3682
4601
  "modelCatalog": "zmjoSq_modelCatalog",
3683
- "field": "zmjoSq_field",
3684
- "candidate": "zmjoSq_candidate",
3685
- "pending": "zmjoSq_pending",
3686
- "candidateLabel": "zmjoSq_candidateLabel",
3687
- "head": "zmjoSq_head",
3688
- "channelAction": "zmjoSq_channelAction",
3689
- "failed": "zmjoSq_failed",
4602
+ "customSettingsSummary": "zmjoSq_customSettingsSummary",
4603
+ "modelInput": "zmjoSq_modelInput",
4604
+ "select": "zmjoSq_select",
4605
+ "channelAdd": "zmjoSq_channelAdd",
4606
+ "editorTitle": "zmjoSq_editorTitle",
4607
+ "modelCatalogTools": "zmjoSq_modelCatalogTools",
4608
+ "candidateList": "zmjoSq_candidateList",
4609
+ "label": "zmjoSq_label",
4610
+ "channelList": "zmjoSq_channelList",
4611
+ "footer": "zmjoSq_footer",
4612
+ "customSettingsBody": "zmjoSq_customSettingsBody",
4613
+ "body": "zmjoSq_body",
3690
4614
  "sectionHint": "zmjoSq_sectionHint",
3691
- "editorTag": "zmjoSq_editorTag",
3692
- "channelName": "zmjoSq_channelName",
3693
- "modelRowRemove": "zmjoSq_modelRowRemove",
4615
+ "channelDanger": "zmjoSq_channelDanger",
4616
+ "editorWrap": "zmjoSq_editorWrap",
3694
4617
  "link": "zmjoSq_link",
3695
- "name": "zmjoSq_name",
3696
- "modelArrow": "zmjoSq_modelArrow",
3697
- "modelRows": "zmjoSq_modelRows",
3698
- "footer": "zmjoSq_footer",
3699
- "addModel": "zmjoSq_addModel",
4618
+ "linkButton": "zmjoSq_linkButton",
4619
+ "head": "zmjoSq_head",
4620
+ "candidateLabel": "zmjoSq_candidateLabel",
4621
+ "candidateTitle": "zmjoSq_candidateTitle",
4622
+ "customSettings": "zmjoSq_customSettings",
4623
+ "channelEmpty": "zmjoSq_channelEmpty",
3700
4624
  "channelMain": "zmjoSq_channelMain",
3701
- "customSettingsSummary": "zmjoSq_customSettingsSummary",
3702
- "modelInput": "zmjoSq_modelInput",
3703
- "save": "zmjoSq_save",
4625
+ "candidate": "zmjoSq_candidate",
4626
+ "chevronOpen": "zmjoSq_chevronOpen",
4627
+ "discard": "zmjoSq_discard",
3704
4628
  "header": "zmjoSq_header",
3705
- "modelCategorySelect": "zmjoSq_modelCategorySelect",
4629
+ "channelName": "zmjoSq_channelName",
3706
4630
  "card": "zmjoSq_card",
3707
- "channelEmpty": "zmjoSq_channelEmpty",
3708
- "candidateActions": "zmjoSq_candidateActions",
3709
- "channelList": "zmjoSq_channelList",
3710
- "channelDanger": "zmjoSq_channelDanger",
3711
- "input": "zmjoSq_input",
4631
+ "channelSection": "zmjoSq_channelSection",
4632
+ "editorHeader": "zmjoSq_editorHeader",
4633
+ "chevron": "zmjoSq_chevron",
4634
+ "channelDotWarn": "zmjoSq_channelDotWarn",
3712
4635
  "candidateId": "zmjoSq_candidateId",
3713
- "candidateList": "zmjoSq_candidateList",
3714
- "editorFooter": "zmjoSq_editorFooter",
3715
4636
  "modelCatalogMeta": "zmjoSq_modelCatalogMeta",
4637
+ "modelCategorySelect": "zmjoSq_modelCategorySelect",
4638
+ "channelBadge": "zmjoSq_channelBadge",
4639
+ "channelRow": "zmjoSq_channelRow",
4640
+ "deleteConfirmText": "zmjoSq_deleteConfirmText",
4641
+ "modelEmpty": "zmjoSq_modelEmpty",
4642
+ "addModel": "zmjoSq_addModel",
4643
+ "detectOk": "zmjoSq_detectOk",
4644
+ "channelEditor": "zmjoSq_channelEditor",
4645
+ "sectionHeader": "zmjoSq_sectionHeader",
3716
4646
  "reset": "zmjoSq_reset",
4647
+ "failed": "zmjoSq_failed",
3717
4648
  "sectionTitle": "zmjoSq_sectionTitle",
3718
- "discard": "zmjoSq_discard",
3719
- "modelCatalogHead": "zmjoSq_modelCatalogHead",
3720
- "channelSection": "zmjoSq_channelSection",
3721
- "headText": "zmjoSq_headText",
3722
- "chevron": "zmjoSq_chevron",
3723
- "channelAdd": "zmjoSq_channelAdd",
3724
- "modelCatalogTools": "zmjoSq_modelCatalogTools",
3725
4649
  "candidatePanel": "zmjoSq_candidatePanel",
3726
- "channelBadge": "zmjoSq_channelBadge",
3727
- "candidateHead": "zmjoSq_candidateHead",
4650
+ "channelHost": "zmjoSq_channelHost",
3728
4651
  "readOnly": "zmjoSq_readOnly",
3729
- "label": "zmjoSq_label",
3730
- "channelDotWarn": "zmjoSq_channelDotWarn",
3731
- "body": "zmjoSq_body",
3732
- "channelEditor": "zmjoSq_channelEditor",
3733
- "modelEmpty": "zmjoSq_modelEmpty",
3734
- "select": "zmjoSq_select",
3735
- "deleteConfirmText": "zmjoSq_deleteConfirmText",
3736
4652
  "channelDotReady": "zmjoSq_channelDotReady",
3737
- "channelHost": "zmjoSq_channelHost",
3738
- "modelCatalogTitle": "zmjoSq_modelCatalogTitle",
3739
- "chevronOpen": "zmjoSq_chevronOpen",
4653
+ "channelAddRow": "zmjoSq_channelAddRow",
4654
+ "editorTag": "zmjoSq_editorTag",
4655
+ "modelRows": "zmjoSq_modelRows",
3740
4656
  "modelRow": "zmjoSq_modelRow",
4657
+ "candidateHead": "zmjoSq_candidateHead",
4658
+ "candidateActions": "zmjoSq_candidateActions",
4659
+ "name": "zmjoSq_name",
4660
+ "channelMeta": "zmjoSq_channelMeta",
3741
4661
  "modelBadge": "zmjoSq_modelBadge",
3742
- "detectOk": "zmjoSq_detectOk",
3743
- "candidateTitle": "zmjoSq_candidateTitle",
3744
- "description": "zmjoSq_description",
3745
- "editorWrap": "zmjoSq_editorWrap",
3746
- "customSettingsBody": "zmjoSq_customSettingsBody"
4662
+ "editorFooter": "zmjoSq_editorFooter",
4663
+ "pending": "zmjoSq_pending",
4664
+ "field": "zmjoSq_field",
4665
+ "headText": "zmjoSq_headText",
4666
+ "channelAction": "zmjoSq_channelAction",
4667
+ "modelRowRemove": "zmjoSq_modelRowRemove",
4668
+ "modelCatalogTitle": "zmjoSq_modelCatalogTitle",
4669
+ "description": "zmjoSq_description"
3747
4670
  };
3748
4671
  //#endregion
3749
4672
  //#region src/client/SettingsCard.tsx
@@ -3771,7 +4694,8 @@ window.__ModuleLoader__.load({
3771
4694
  booleanField("announceToAgent"),
3772
4695
  booleanField("allowAgentAudioGeneration"),
3773
4696
  textField("defaultModel"),
3774
- booleanField("autoSaveToLibrary")
4697
+ booleanField("autoSaveToLibrary"),
4698
+ textField("maxConcurrentGenerations")
3775
4699
  ]);
3776
4700
  this.channelsForm = new ChannelsForm(scope);
3777
4701
  }
@@ -3785,7 +4709,8 @@ window.__ModuleLoader__.load({
3785
4709
  announceToAgent: this.form.field("announceToAgent"),
3786
4710
  allowAgentAudioGeneration: this.form.field("allowAgentAudioGeneration"),
3787
4711
  defaultModel: this.form.field("defaultModel"),
3788
- autoSaveToLibrary: this.form.field("autoSaveToLibrary")
4712
+ autoSaveToLibrary: this.form.field("autoSaveToLibrary"),
4713
+ maxConcurrentGenerations: this.form.field("maxConcurrentGenerations")
3789
4714
  };
3790
4715
  }
3791
4716
  inject() {
@@ -4624,6 +5549,21 @@ window.__ModuleLoader__.load({
4624
5549
  ]
4625
5550
  })
4626
5551
  }),
5552
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5553
+ className: settings_card_module_css_default.field,
5554
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
5555
+ className: settings_card_module_css_default.label,
5556
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("settings.maxConcurrent") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5557
+ type: "number",
5558
+ min: "1",
5559
+ max: "20",
5560
+ className: settings_card_module_css_default.input,
5561
+ value: state.maxConcurrentGenerations.text,
5562
+ disabled: !state.writable,
5563
+ onChange: (event) => props.edit("maxConcurrentGenerations", event.target.value)
5564
+ })]
5565
+ })
5566
+ }),
4627
5567
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4628
5568
  className: settings_card_module_css_default.footer,
4629
5569
  children: [
@@ -4666,17 +5606,17 @@ window.__ModuleLoader__.load({
4666
5606
  document.head.appendChild(tag);
4667
5607
  }
4668
5608
  var audio_toolview_module_css_default = {
4669
- "header": "_7K1QKa_header",
4670
- "download": "_7K1QKa_download",
4671
- "message": "_7K1QKa_message",
5609
+ "status": "_7K1QKa_status",
5610
+ "empty": "_7K1QKa_empty",
4672
5611
  "audioRow": "_7K1QKa_audioRow",
4673
- "icon": "_7K1QKa_icon",
4674
5612
  "audio": "_7K1QKa_audio",
4675
5613
  "error": "_7K1QKa_error",
4676
- "status": "_7K1QKa_status",
4677
- "empty": "_7K1QKa_empty",
4678
- "root": "_7K1QKa_root",
4679
- "audios": "_7K1QKa_audios"
5614
+ "audios": "_7K1QKa_audios",
5615
+ "download": "_7K1QKa_download",
5616
+ "header": "_7K1QKa_header",
5617
+ "icon": "_7K1QKa_icon",
5618
+ "message": "_7K1QKa_message",
5619
+ "root": "_7K1QKa_root"
4680
5620
  };
4681
5621
  //#endregion
4682
5622
  //#region src/client/audio-toolview.tsx