dsh-audiogen 0.4.1 → 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}}.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}";
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,79 +1148,101 @@ window.__ModuleLoader__.load({
809
1148
  document.head.appendChild(tag);
810
1149
  }
811
1150
  var audio_panel_module_css_default = {
812
- "audioCardHead": "Oo1fpq_audioCardHead",
813
- "modeButton": "Oo1fpq_modeButton",
1151
+ "checkbox": "Oo1fpq_checkbox",
1152
+ "historyList": "Oo1fpq_historyList",
1153
+ "compareChips": "Oo1fpq_compareChips",
1154
+ "historyCompareBadge": "Oo1fpq_historyCompareBadge",
814
1155
  "title": "Oo1fpq_title",
815
- "formCol": "Oo1fpq_formCol",
816
- "voiceIdChip": "Oo1fpq_voiceIdChip",
817
- "historyItem": "Oo1fpq_historyItem",
818
- "resultGroupChip": "Oo1fpq_resultGroupChip",
819
- "resultEmpty": "Oo1fpq_resultEmpty",
820
- "historyHeader": "Oo1fpq_historyHeader",
821
- "historyActions": "Oo1fpq_historyActions",
822
- "historyAction": "Oo1fpq_historyAction",
823
- "resultGroups": "Oo1fpq_resultGroups",
824
- "resultGroup": "Oo1fpq_resultGroup",
825
- "panel": "Oo1fpq_panel",
826
1156
  "modeRow": "Oo1fpq_modeRow",
827
- "playerCompact": "Oo1fpq_playerCompact",
828
- "generate": "Oo1fpq_generate",
829
- "resultEmptyIcon": "Oo1fpq_resultEmptyIcon",
830
- "formRow": "Oo1fpq_formRow",
831
- "audioList": "Oo1fpq_audioList",
832
- "modalFoot": "Oo1fpq_modalFoot",
833
- "resultGroupCount": "Oo1fpq_resultGroupCount",
834
- "historyTitle": "Oo1fpq_historyTitle",
835
- "overrideTable": "Oo1fpq_overrideTable",
836
- "historyCol": "Oo1fpq_historyCol",
837
- "advanced": "Oo1fpq_advanced",
1157
+ "compareBox": "Oo1fpq_compareBox",
1158
+ "historyEmpty": "Oo1fpq_historyEmpty",
1159
+ "resultGroup": "Oo1fpq_resultGroup",
1160
+ "taskStatus": "Oo1fpq_taskStatus",
1161
+ "compareBoard": "Oo1fpq_compareBoard",
838
1162
  "overrideCell": "Oo1fpq_overrideCell",
839
- "header": "Oo1fpq_header",
840
- "textarea": "Oo1fpq_textarea",
841
- "error": "Oo1fpq_error",
842
- "ghostButton": "Oo1fpq_ghostButton",
843
- "secondaryButton": "Oo1fpq_secondaryButton",
844
- "iconButton": "Oo1fpq_iconButton",
1163
+ "taskActions": "Oo1fpq_taskActions",
1164
+ "historyTabCount": "Oo1fpq_historyTabCount",
1165
+ "modalFoot": "Oo1fpq_modalFoot",
1166
+ "historyModelRow": "Oo1fpq_historyModelRow",
845
1167
  "resultMeta": "Oo1fpq_resultMeta",
846
- "primaryButton": "Oo1fpq_primaryButton",
847
- "historyPrompt": "Oo1fpq_historyPrompt",
848
- "audiogenToastIn": "Oo1fpq_audiogenToastIn",
849
- "modalBody": "Oo1fpq_modalBody",
850
- "studio": "Oo1fpq_studio",
1168
+ "textarea": "Oo1fpq_textarea",
1169
+ "taskCard": "Oo1fpq_taskCard",
1170
+ "overrideOnly": "Oo1fpq_overrideOnly",
1171
+ "resultCol": "Oo1fpq_resultCol",
851
1172
  "tab": "Oo1fpq_tab",
852
- "historyList": "Oo1fpq_historyList",
853
- "checkbox": "Oo1fpq_checkbox",
854
- "row": "Oo1fpq_row",
855
- "hint": "Oo1fpq_hint",
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",
856
1181
  "modal": "Oo1fpq_modal",
857
- "toast": "Oo1fpq_toast",
858
- "audioCardIndex": "Oo1fpq_audioCardIndex",
1182
+ "iconButton": "Oo1fpq_iconButton",
1183
+ "historyTitle": "Oo1fpq_historyTitle",
1184
+ "overrideRow": "Oo1fpq_overrideRow",
859
1185
  "track": "Oo1fpq_track",
860
- "input": "Oo1fpq_input",
861
- "tabs": "Oo1fpq_tabs",
862
- "resultModeChip": "Oo1fpq_resultModeChip",
863
- "modalHead": "Oo1fpq_modalHead",
864
- "modelCheckList": "Oo1fpq_modelCheckList",
865
- "label": "Oo1fpq_label",
866
1186
  "historyMeta": "Oo1fpq_historyMeta",
867
- "overrideCellHead": "Oo1fpq_overrideCellHead",
868
- "savedChip": "Oo1fpq_savedChip",
869
- "historyClear": "Oo1fpq_historyClear",
870
- "resultEmptyHint": "Oo1fpq_resultEmptyHint",
871
- "historyEmpty": "Oo1fpq_historyEmpty",
872
- "trackFill": "Oo1fpq_trackFill",
873
1187
  "trackKnob": "Oo1fpq_trackKnob",
874
- "resultCol": "Oo1fpq_resultCol",
1188
+ "modalMask": "Oo1fpq_modalMask",
1189
+ "secondaryButton": "Oo1fpq_secondaryButton",
1190
+ "hint": "Oo1fpq_hint",
1191
+ "muteButton": "Oo1fpq_muteButton",
1192
+ "historyPrompt": "Oo1fpq_historyPrompt",
1193
+ "audioCardIndex": "Oo1fpq_audioCardIndex",
875
1194
  "time": "Oo1fpq_time",
876
- "playButton": "Oo1fpq_playButton",
1195
+ "resultGroupError": "Oo1fpq_resultGroupError",
1196
+ "overrideCellHead": "Oo1fpq_overrideCellHead",
1197
+ "modeButton": "Oo1fpq_modeButton",
1198
+ "historyAction": "Oo1fpq_historyAction",
877
1199
  "audioCardActions": "Oo1fpq_audioCardActions",
878
- "overrideRow": "Oo1fpq_overrideRow",
1200
+ "generate": "Oo1fpq_generate",
1201
+ "panel": "Oo1fpq_panel",
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",
1212
+ "primaryButton": "Oo1fpq_primaryButton",
1213
+ "savedChip": "Oo1fpq_savedChip",
1214
+ "overrideDash": "Oo1fpq_overrideDash",
1215
+ "modalBody": "Oo1fpq_modalBody",
1216
+ "historyTab": "Oo1fpq_historyTab",
1217
+ "audioCardHead": "Oo1fpq_audioCardHead",
1218
+ "historyHeader": "Oo1fpq_historyHeader",
879
1219
  "resultGroupHead": "Oo1fpq_resultGroupHead",
880
- "muteButton": "Oo1fpq_muteButton",
881
1220
  "audioCard": "Oo1fpq_audioCard",
882
- "resultGroupError": "Oo1fpq_resultGroupError",
883
- "modalMask": "Oo1fpq_modalMask",
884
- "player": "Oo1fpq_player"
1221
+ "compareChip": "Oo1fpq_compareChip",
1222
+ "overrideTable": "Oo1fpq_overrideTable",
1223
+ "label": "Oo1fpq_label",
1224
+ "error": "Oo1fpq_error",
1225
+ "header": "Oo1fpq_header",
1226
+ "advanced": "Oo1fpq_advanced",
1227
+ "tabs": "Oo1fpq_tabs",
1228
+ "resultEmptyIcon": "Oo1fpq_resultEmptyIcon",
1229
+ "player": "Oo1fpq_player",
1230
+ "studio": "Oo1fpq_studio",
1231
+ "playButton": "Oo1fpq_playButton",
1232
+ "formCol": "Oo1fpq_formCol",
1233
+ "input": "Oo1fpq_input",
1234
+ "trackFill": "Oo1fpq_trackFill",
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"
885
1246
  };
886
1247
  //#endregion
887
1248
  //#region src/client/audio-player.tsx
@@ -1190,88 +1551,14 @@ window.__ModuleLoader__.load({
1190
1551
  /**
1191
1552
  * Studio view: the generation form (left), result cards (center) and the
1192
1553
  * compact generation history (right). Owns the «加入资源库» interactions —
1193
- * 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.
1194
1557
  */
1195
- /** 每模型可覆盖的参数行(留空 = 自动,沿用上方全局配置)。 */
1196
- const OVERRIDE_ROWS = [
1197
- {
1198
- key: "format",
1199
- label: "输出格式",
1200
- type: "select",
1201
- options: [
1202
- "mp3",
1203
- "wav",
1204
- "pcm",
1205
- "flac",
1206
- "ogg"
1207
- ],
1208
- placeholder: "自动"
1209
- },
1210
- {
1211
- key: "duration",
1212
- label: "时长(秒)",
1213
- type: "number",
1214
- placeholder: "自动"
1215
- },
1216
- {
1217
- key: "voice",
1218
- label: "音色",
1219
- type: "text",
1220
- placeholder: "自动"
1221
- },
1222
- {
1223
- key: "speed",
1224
- label: "语速",
1225
- type: "number",
1226
- placeholder: "自动"
1227
- },
1228
- {
1229
- key: "emotion",
1230
- label: "情绪",
1231
- type: "text",
1232
- placeholder: "自动"
1233
- },
1234
- {
1235
- key: "sample_rate",
1236
- label: "采样率",
1237
- type: "number",
1238
- placeholder: "自动"
1239
- },
1240
- {
1241
- key: "bitrate",
1242
- label: "码率",
1243
- type: "number",
1244
- placeholder: "自动"
1245
- },
1246
- {
1247
- key: "lyrics",
1248
- label: "歌词",
1249
- type: "text",
1250
- placeholder: "自动"
1251
- },
1252
- {
1253
- key: "seed",
1254
- label: "seed",
1255
- type: "number",
1256
- placeholder: "自动"
1257
- },
1258
- {
1259
- key: "steps",
1260
- label: "steps",
1261
- type: "number",
1262
- placeholder: "自动"
1263
- },
1264
- {
1265
- key: "cfg_scale",
1266
- label: "cfg_scale",
1267
- type: "number",
1268
- placeholder: "自动"
1269
- }
1270
- ];
1271
1558
  /** 每模型覆盖值 → 请求字段的数值/类型转换(空值跳过)。 */
1272
1559
  function overrideSpread(override) {
1273
1560
  const out = {};
1274
- const val = override.format?.trim() ?? "";
1561
+ const val = (override.format ?? "").trim();
1275
1562
  if (val !== "") out.format = val;
1276
1563
  const num = (key) => {
1277
1564
  const raw = (override[key] ?? "").trim();
@@ -1281,17 +1568,17 @@ window.__ModuleLoader__.load({
1281
1568
  };
1282
1569
  const duration = num("duration");
1283
1570
  if (duration !== void 0) out.duration = duration;
1284
- const voice = override.voice?.trim() ?? "";
1571
+ const voice = (override.voice ?? "").trim();
1285
1572
  if (voice !== "") out.voice = voice;
1286
1573
  const speed = num("speed");
1287
1574
  if (speed !== void 0) out.speed = speed;
1288
- const emotion = override.emotion?.trim() ?? "";
1575
+ const emotion = (override.emotion ?? "").trim();
1289
1576
  if (emotion !== "") out.emotion = emotion;
1290
1577
  const sampleRate = num("sample_rate");
1291
1578
  if (sampleRate !== void 0) out.sampleRate = sampleRate;
1292
1579
  const bitrate = num("bitrate");
1293
1580
  if (bitrate !== void 0) out.bitrate = bitrate;
1294
- const lyrics = override.lyrics?.trim() ?? "";
1581
+ const lyrics = (override.lyrics ?? "").trim();
1295
1582
  if (lyrics !== "") out.lyrics = lyrics;
1296
1583
  const seed = num("seed");
1297
1584
  if (seed !== void 0) out.seed = seed;
@@ -1301,6 +1588,16 @@ window.__ModuleLoader__.load({
1301
1588
  if (cfgScale !== void 0) out.cfgScale = cfgScale;
1302
1589
  return out;
1303
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
+ }
1304
1601
  function useConfig(scope) {
1305
1602
  const [value, setValue] = (0, react.useState)(scope.getSnapshot().value);
1306
1603
  (0, react.useEffect)(() => scope.subscribe(() => {
@@ -1311,7 +1608,11 @@ window.__ModuleLoader__.load({
1311
1608
  function useHistory() {
1312
1609
  const [entries, setEntries] = (0, react.useState)([]);
1313
1610
  const reload = () => {
1314
- 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) => {
1315
1616
  const body = await response.json();
1316
1617
  if (body.ok === true) setEntries(body.history ?? []);
1317
1618
  }).catch(() => {});
@@ -1320,7 +1621,11 @@ window.__ModuleLoader__.load({
1320
1621
  reload();
1321
1622
  }, []);
1322
1623
  const clear = () => {
1323
- 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(() => {});
1324
1629
  };
1325
1630
  return {
1326
1631
  entries,
@@ -1381,8 +1686,6 @@ window.__ModuleLoader__.load({
1381
1686
  const [prompt, setPrompt] = (0, react.useState)("");
1382
1687
  const [previewText, setPreviewText] = (0, react.useState)("");
1383
1688
  const [model, setModel] = (0, react.useState)("");
1384
- const [selectedModels, setSelectedModels] = (0, react.useState)([]);
1385
- const [overrides, setOverrides] = (0, react.useState)({});
1386
1689
  const [voice, setVoice] = (0, react.useState)("");
1387
1690
  const [speed, setSpeed] = (0, react.useState)("");
1388
1691
  const [duration, setDuration] = (0, react.useState)("");
@@ -1399,16 +1702,26 @@ window.__ModuleLoader__.load({
1399
1702
  const [bitrate, setBitrate] = (0, react.useState)("");
1400
1703
  const [audioChannel, setAudioChannel] = (0, react.useState)("");
1401
1704
  const [subtitle, setSubtitle] = (0, react.useState)(false);
1402
- const [loading, setLoading] = (0, react.useState)(false);
1403
- const [progress, setProgress] = (0, react.useState)("");
1705
+ const [seed, setSeed] = (0, react.useState)("");
1706
+ const [steps, setSteps] = (0, react.useState)("");
1707
+ const [cfgScale, setCfgScale] = (0, react.useState)("");
1404
1708
  const [error, setError] = (0, react.useState)(null);
1405
- const [results, setResults] = (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());
1406
1715
  const [saveToLibrary, setSaveToLibrary] = (0, react.useState)(cfg?.autoSaveToLibrary === true);
1407
1716
  const [savedIds, setSavedIds] = (0, react.useState)(/* @__PURE__ */ new Set());
1408
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)({});
1409
1722
  const { entries, reload, clear } = useHistory();
1410
1723
  const [designChannelId, setDesignChannelId] = (0, react.useState)("");
1411
- const isMiniMaxChannel = (0, react.useMemo)(() => {
1724
+ (0, react.useMemo)(() => {
1412
1725
  const target = channels.find((candidate) => candidate.id === modelOptions.defaultChannelId) ?? channels[0];
1413
1726
  return target !== void 0 && (target.preset === "minimax" || /minimax/i.test(target.apiUrl));
1414
1727
  }, [channels, modelOptions.defaultChannelId]);
@@ -1424,125 +1737,282 @@ window.__ModuleLoader__.load({
1424
1737
  if (mode === "voice_design") return [];
1425
1738
  return modelOptions.models.filter((entry) => entry.category === void 0 || entry.category === "tts" && mode === "tts" || entry.category === mode).map((entry) => entry.alias);
1426
1739
  }, [modelOptions.models, mode]);
1427
- (0, react.useEffect)(() => {
1428
- if (visibleModels.length === 0) return;
1429
- setSelectedModels((current) => {
1430
- const valid = current.filter((item) => visibleModels.includes(item));
1431
- if (valid.length > 0) return valid;
1432
- return [visibleModels[0]];
1433
- });
1434
- }, [visibleModels]);
1435
- (0, react.useEffect)(() => {
1436
- setOverrides((current) => {
1437
- const next = {};
1438
- for (const alias of selectedModels) if (current[alias] !== void 0) next[alias] = current[alias];
1439
- return next;
1440
- });
1441
- }, [selectedModels]);
1442
- const setOverrideValue = (model, key, value) => {
1443
- setOverrides((current) => ({
1444
- ...current,
1445
- [model]: {
1446
- ...current[model] ?? {},
1447
- [key]: value
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);
1448
1758
  }
1449
- }));
1450
- };
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]);
1451
1790
  (0, react.useEffect)(() => {
1452
1791
  if (visibleModels.length > 0 && !visibleModels.includes(model)) setModel(visibleModels[0]);
1453
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]);
1454
1805
  (0, react.useEffect)(() => {
1455
1806
  if (reuse === void 0 || reuse === null) return;
1456
1807
  setMode(reuse.mode);
1457
1808
  if (reuse.voiceId !== void 0 || reuse.voice !== void 0) setVoice(reuse.voiceId ?? reuse.voice ?? "");
1458
- if (reuse.model !== void 0 && reuse.model !== "") {
1459
- setModel(reuse.model);
1460
- setSelectedModels([reuse.model]);
1461
- }
1809
+ if (reuse.model !== void 0 && reuse.model !== "") setModel(reuse.model);
1462
1810
  }, [reuse?.nonce]);
1463
- 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 = () => {
1464
1854
  if (prompt.trim() === "") {
1465
1855
  setError(tt("prompt.required"));
1466
1856
  return;
1467
1857
  }
1468
- const targets = mode === "voice_design" ? [""] : selectedModels.length > 0 ? selectedModels : model !== "" ? [model] : visibleModels.length > 0 ? [visibleModels[0]] : [];
1469
- if (targets.length === 0) {
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 === "") {
1470
1866
  setError("当前模式暂无可用模型");
1471
1867
  return;
1472
1868
  }
1473
- setLoading(true);
1474
1869
  setError(null);
1475
- setProgress("");
1476
- const gathered = [];
1477
- let anySaved = false;
1478
- try {
1479
- for (const [index, target] of targets.entries()) {
1480
- setProgress(`生成中 ${index + 1}/${targets.length}(${target || "音色设计"})…`);
1481
- let response;
1482
- try {
1483
- response = await api.generate({
1484
- mode,
1485
- model: target,
1486
- prompt: prompt.trim(),
1487
- saveToLibrary,
1488
- ...mode === "voice_design" && designChannelId !== "" ? { channelId: designChannelId } : {},
1489
- ...previewText.trim() !== "" ? { previewText: previewText.trim() } : {},
1490
- ...voice.trim() !== "" ? { voice: voice.trim() } : {},
1491
- ...speed.trim() !== "" ? { speed: Number(speed) } : {},
1492
- ...duration.trim() !== "" ? { duration: Number(duration) } : {},
1493
- ...lyrics.trim() !== "" ? { lyrics: lyrics.trim() } : {},
1494
- ...instrumental ? { isInstrumental: true } : {},
1495
- ...loop ? { loop: true } : {},
1496
- ...promptInfluence.trim() !== "" ? { promptInfluence: Number(promptInfluence) } : {},
1497
- ...format.trim() !== "" ? { format: format.trim() } : {},
1498
- ...emotion.trim() !== "" ? { emotion: emotion.trim() } : {},
1499
- ...vol.trim() !== "" ? { vol: Number(vol) } : {},
1500
- ...pitch.trim() !== "" ? { pitch: Number(pitch) } : {},
1501
- ...toneText.trim() !== "" ? { pronunciationTone: toneText.split("\n").map((item) => item.trim()).filter((item) => item !== "") } : {},
1502
- ...sampleRate.trim() !== "" ? { sampleRate: Number(sampleRate) } : {},
1503
- ...bitrate.trim() !== "" ? { bitrate: Number(bitrate) } : {},
1504
- ...audioChannel.trim() !== "" ? { audioChannel: Number(audioChannel) } : {},
1505
- ...subtitle ? { subtitleEnable: true } : {},
1506
- ...target === "" ? {} : overrideSpread(overrides[target] ?? {})
1507
- });
1508
- } catch (err) {
1509
- gathered.push({
1510
- model: target,
1511
- outputs: [],
1512
- error: err instanceof Error ? err.message : String(err)
1513
- });
1514
- continue;
1515
- }
1516
- if (!response.ok) {
1517
- gathered.push({
1518
- model: target,
1519
- outputs: [],
1520
- error: response.message ?? "生成失败"
1521
- });
1522
- continue;
1523
- }
1524
- const generated = response.outputs ?? [];
1525
- gathered.push({
1526
- model: target,
1527
- outputs: generated
1528
- });
1529
- if ((response.resources?.length ?? 0) > 0 && saveToLibrary) anySaved = true;
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] ?? {})
1530
1878
  }
1531
- setResults(gathered);
1532
- if (anySaved) {
1533
- setSavedIds((current) => /* @__PURE__ */ new Set([...current, ...gathered.flatMap((group) => group.outputs.map((item) => item.id))]));
1534
- props.showToast("已保存到资源库");
1535
- props.onLibraryChanged();
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
+ }));
1536
1965
  }
1537
- const failed = gathered.filter((group) => group.error !== void 0 && group.outputs.length === 0);
1538
- if (failed.length > 0 && failed.length === gathered.length) setError(failed.map((group) => `「${group.model || "音色设计"}」${group.error}`).join(";"));
1539
- reload();
1540
- } catch (err) {
1541
- setError(err instanceof Error ? err.message : String(err));
1542
- } finally {
1543
- setLoading(false);
1544
- setProgress("");
1545
- }
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));
1546
2016
  };
1547
2017
  const openSaveDialog = (files, context) => {
1548
2018
  setSaveDialog({
@@ -1550,19 +2020,373 @@ window.__ModuleLoader__.load({
1550
2020
  context
1551
2021
  });
1552
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
+ };
1553
2266
  const onDialogSaved = (entry) => {
1554
2267
  if (saveDialog !== null) setSavedIds((current) => /* @__PURE__ */ new Set([...current, ...saveDialog.files.map((file) => file.id)]));
1555
2268
  setSaveDialog(null);
1556
2269
  props.showToast(`已保存「${entry.name}」`);
1557
2270
  props.onLibraryChanged();
1558
2271
  };
1559
- 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)(() => {
1560
2332
  if (mode === "tts") return tt("mode.tts");
1561
2333
  if (mode === "music") return tt("mode.music");
1562
2334
  if (mode === "sfx") return tt("mode.sfx");
1563
2335
  return tt("mode.voiceDesign");
1564
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]);
1565
2388
  const needModel = mode !== "voice_design";
2389
+ const runningCount = tasks.filter((task) => task.status === "running").length;
1566
2390
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1567
2391
  className: audio_panel_module_css_default.studio,
1568
2392
  children: [
@@ -1629,348 +2453,127 @@ window.__ModuleLoader__.load({
1629
2453
  })
1630
2454
  ] }) : null,
1631
2455
  needModel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1632
- className: audio_panel_module_css_default.label,
1633
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [tt("model.label"), "(可多选,同一提示词逐个生成以对比)"] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1634
- className: audio_panel_module_css_default.modelCheckList,
1635
- children: [visibleModels.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1636
- className: audio_panel_module_css_default.hint,
1637
- children: "(当前模式暂无可用模型)"
1638
- }) : null, visibleModels.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1639
- className: audio_panel_module_css_default.checkbox,
1640
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1641
- type: "checkbox",
1642
- checked: selectedModels.includes(item),
1643
- onChange: (event) => {
1644
- const checked = event.target.checked;
1645
- setSelectedModels((current) => checked ? [.../* @__PURE__ */ new Set([...current, item])] : current.filter((alias) => alias !== item));
1646
- if (checked && (model === "" || !visibleModels.includes(model))) setModel(item);
1647
- }
1648
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1649
- title: "点击生成对比",
1650
- children: item
1651
- })]
1652
- }, item))]
1653
- })]
1654
- }) : null,
1655
- needModel && selectedModels.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
1656
- className: audio_panel_module_css_default.advanced,
1657
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "每模型参数覆盖(默认自动:沿用上方相同配置,如输出格式均为 mp3)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1658
- className: audio_panel_module_css_default.overrideTable,
1659
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1660
- className: audio_panel_module_css_default.overrideRow,
1661
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: `${audio_panel_module_css_default.overrideCell} ${audio_panel_module_css_default.overrideCellHead}` }), selectedModels.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1662
- className: `${audio_panel_module_css_default.overrideCell} ${audio_panel_module_css_default.overrideCellHead}`,
1663
- children: item
1664
- }, item))]
1665
- }), OVERRIDE_ROWS.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1666
- className: audio_panel_module_css_default.overrideRow,
1667
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1668
- className: audio_panel_module_css_default.overrideCell,
1669
- title: row.label,
1670
- children: row.label
1671
- }), selectedModels.map((item) => {
1672
- const value = overrides[item]?.[row.key] ?? "";
1673
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1674
- className: audio_panel_module_css_default.overrideCell,
1675
- children: row.type === "select" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1676
- className: audio_panel_module_css_default.input,
1677
- value,
1678
- onChange: (event) => setOverrideValue(item, row.key, event.target.value),
1679
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1680
- value: "",
1681
- children: "自动"
1682
- }), row.options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1683
- value: option,
1684
- children: option
1685
- }, option))]
1686
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1687
- className: audio_panel_module_css_default.input,
1688
- type: row.type === "number" ? "number" : "text",
1689
- value,
1690
- placeholder: row.placeholder ?? "自动",
1691
- onChange: (event) => setOverrideValue(item, row.key, event.target.value)
1692
- })
1693
- }, item);
1694
- })]
1695
- }, row.key))]
1696
- })]
1697
- }) : null,
1698
- mode === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1699
- className: audio_panel_module_css_default.label,
1700
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("voice.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1701
- className: audio_panel_module_css_default.input,
1702
- value: voice,
1703
- onChange: (event) => setVoice(event.target.value),
1704
- placeholder: isMiniMaxChannel ? "male-qn-qingse / female-shaonv" : "alloy / 自定义音色"
1705
- })]
1706
- }) : null,
1707
- mode === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1708
- className: audio_panel_module_css_default.label,
1709
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("speed.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1710
- className: audio_panel_module_css_default.input,
1711
- type: "number",
1712
- step: "0.1",
1713
- min: "0.5",
1714
- max: "2",
1715
- value: speed,
1716
- onChange: (event) => setSpeed(event.target.value),
1717
- placeholder: "1.0"
1718
- })]
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: "模型对比(多模型同参数生成)" })]
1719
2463
  }) : null,
1720
- mode === "tts" && isMiniMaxChannel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
1721
- className: audio_panel_module_css_default.advanced,
2464
+ needModel ? compareMode ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2465
+ className: audio_panel_module_css_default.compareBox,
1722
2466
  children: [
1723
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "MiniMax 高级参数" }),
1724
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2467
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1725
2468
  className: audio_panel_module_css_default.label,
1726
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "情绪 emotion" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1727
- className: audio_panel_module_css_default.input,
1728
- value: emotion,
1729
- onChange: (event) => setEmotion(event.target.value),
1730
- placeholder: "happy / sad / angry / nervous…"
1731
- })]
2469
+ children: "对比模型(至少 2 个,最多 4 个)"
1732
2470
  }),
1733
2471
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1734
- className: audio_panel_module_css_default.row,
1735
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1736
- className: audio_panel_module_css_default.label,
1737
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "音量 vol (0-10)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1738
- className: audio_panel_module_css_default.input,
1739
- type: "number",
1740
- min: "0",
1741
- max: "10",
1742
- step: "0.5",
1743
- value: vol,
1744
- onChange: (event) => setVol(event.target.value),
1745
- placeholder: "1"
1746
- })]
1747
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1748
- className: audio_panel_module_css_default.label,
1749
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "音调 pitch (-12~12)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1750
- className: audio_panel_module_css_default.input,
1751
- type: "number",
1752
- min: "-12",
1753
- max: "12",
1754
- value: pitch,
1755
- onChange: (event) => setPitch(event.target.value),
1756
- placeholder: "0"
1757
- })]
1758
- })]
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]
1759
2483
  }),
1760
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1761
- className: audio_panel_module_css_default.row,
1762
- children: [
1763
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1764
- className: audio_panel_module_css_default.label,
1765
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "采样率" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1766
- className: audio_panel_module_css_default.input,
1767
- type: "number",
1768
- min: "16000",
1769
- max: "48000",
1770
- step: "8000",
1771
- value: sampleRate,
1772
- onChange: (event) => setSampleRate(event.target.value),
1773
- placeholder: "32000"
1774
- })]
1775
- }),
1776
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1777
- className: audio_panel_module_css_default.label,
1778
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "码率 bps" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1779
- className: audio_panel_module_css_default.input,
1780
- type: "number",
1781
- min: "64000",
1782
- max: "320000",
1783
- step: "8000",
1784
- value: bitrate,
1785
- onChange: (event) => setBitrate(event.target.value),
1786
- placeholder: "128000"
1787
- })]
1788
- }),
1789
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1790
- className: audio_panel_module_css_default.label,
1791
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "声道" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1792
- className: audio_panel_module_css_default.input,
1793
- value: audioChannel,
1794
- onChange: (event) => setAudioChannel(event.target.value),
1795
- children: [
1796
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1797
- value: "",
1798
- children: "默认(1)"
1799
- }),
1800
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1801
- value: "1",
1802
- children: "1"
1803
- }),
1804
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1805
- value: "2",
1806
- children: "2"
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: "—"
1807
2510
  })
1808
- ]
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);
1809
2550
  })]
1810
- })
1811
- ]
1812
- }),
1813
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1814
- className: audio_panel_module_css_default.label,
1815
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "发音词典(每行一条:\"文字/读音\")" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1816
- className: audio_panel_module_css_default.textarea,
1817
- value: toneText,
1818
- onChange: (event) => setToneText(event.target.value),
1819
- placeholder: "处理/(chu3)(li3)\n危险/dangerous"
2551
+ }, row.key))]
1820
2552
  })]
1821
- }),
1822
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1823
- className: audio_panel_module_css_default.checkbox,
1824
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1825
- type: "checkbox",
1826
- checked: subtitle,
1827
- onChange: (event) => setSubtitle(event.target.checked)
1828
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "生成字幕 subtitle_enable" })]
1829
2553
  })
1830
2554
  ]
1831
- }) : null,
1832
- mode === "music" || mode === "sfx" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2555
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1833
2556
  className: audio_panel_module_css_default.label,
1834
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("duration.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2557
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("model.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1835
2558
  className: audio_panel_module_css_default.input,
1836
- type: "number",
1837
- step: "1",
1838
- min: "1",
1839
- max: "120",
1840
- value: duration,
1841
- onChange: (event) => setDuration(event.target.value),
1842
- placeholder: "30"
2559
+ value: model,
2560
+ onChange: (event) => setModel(event.target.value),
2561
+ children: [visibleModels.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2562
+ value: "",
2563
+ children: "(当前模式暂无可用模型)"
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))]
1843
2571
  })]
1844
2572
  }) : null,
1845
- mode === "sfx" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1846
- className: audio_panel_module_css_default.checkbox,
1847
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1848
- type: "checkbox",
1849
- checked: loop,
1850
- onChange: (event) => setLoop(event.target.checked)
1851
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "循环音效 loop(无缝循环,需 eleven_text_to_sound_v2)" })]
1852
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1853
- className: audio_panel_module_css_default.label,
1854
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "提示词影响度 prompt_influence (0-1)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1855
- className: audio_panel_module_css_default.input,
1856
- type: "number",
1857
- step: "0.1",
1858
- min: "0",
1859
- max: "1",
1860
- value: promptInfluence,
1861
- onChange: (event) => setPromptInfluence(event.target.value),
1862
- placeholder: "0.3"
1863
- })]
1864
- })] }) : null,
1865
- mode === "music" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1866
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1867
- className: audio_panel_module_css_default.label,
1868
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "歌词(纯音乐模式可留空;多段用空行分隔)" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1869
- className: audio_panel_module_css_default.textarea,
1870
- value: lyrics,
1871
- onChange: (event) => setLyrics(event.target.value),
1872
- placeholder: "第一段歌词…\n\n第二段歌词…"
1873
- })]
1874
- }),
1875
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1876
- className: audio_panel_module_css_default.checkbox,
1877
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1878
- type: "checkbox",
1879
- checked: instrumental,
1880
- onChange: (event) => setInstrumental(event.target.checked)
1881
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "纯音乐(无歌词/人声)is_instrumental" })]
1882
- }),
1883
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1884
- className: audio_panel_module_css_default.row,
1885
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1886
- className: audio_panel_module_css_default.label,
1887
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "采样率" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1888
- className: audio_panel_module_css_default.input,
1889
- value: sampleRate,
1890
- onChange: (event) => setSampleRate(event.target.value),
1891
- children: [
1892
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1893
- value: "",
1894
- children: "默认(44100)"
1895
- }),
1896
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1897
- value: "16000",
1898
- children: "16000"
1899
- }),
1900
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1901
- value: "24000",
1902
- children: "24000"
1903
- }),
1904
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1905
- value: "32000",
1906
- children: "32000"
1907
- }),
1908
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1909
- value: "44100",
1910
- children: "44100"
1911
- })
1912
- ]
1913
- })]
1914
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1915
- className: audio_panel_module_css_default.label,
1916
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "码率 bps" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1917
- className: audio_panel_module_css_default.input,
1918
- value: bitrate,
1919
- onChange: (event) => setBitrate(event.target.value),
1920
- children: [
1921
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1922
- value: "",
1923
- children: "默认(256000)"
1924
- }),
1925
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1926
- value: "32000",
1927
- children: "32000"
1928
- }),
1929
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1930
- value: "64000",
1931
- children: "64000"
1932
- }),
1933
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1934
- value: "128000",
1935
- children: "128000"
1936
- }),
1937
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1938
- value: "256000",
1939
- children: "256000"
1940
- })
1941
- ]
1942
- })]
1943
- })]
1944
- })
1945
- ] }) : null,
1946
- needModel ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1947
- className: audio_panel_module_css_default.label,
1948
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("format.label") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1949
- className: audio_panel_module_css_default.input,
1950
- value: format,
1951
- onChange: (event) => setFormat(event.target.value),
1952
- children: [
1953
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1954
- value: "mp3",
1955
- children: "mp3"
1956
- }),
1957
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1958
- value: "wav",
1959
- children: "wav"
1960
- }),
1961
- mode === "tts" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1962
- value: "flac",
1963
- children: "flac"
1964
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1965
- value: "ogg",
1966
- children: "ogg"
1967
- })] }) : null,
1968
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1969
- value: "pcm",
1970
- children: "pcm"
1971
- })
1972
- ]
1973
- })]
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", {
2575
+ className: audio_panel_module_css_default.advanced,
2576
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "MiniMax 高级参数" }), globalSpecs.filter((spec) => spec.advanced === true).map((spec) => renderField(spec))]
1974
2577
  }) : null,
1975
2578
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1976
2579
  className: audio_panel_module_css_default.checkbox,
@@ -1988,10 +2591,18 @@ window.__ModuleLoader__.load({
1988
2591
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1989
2592
  type: "button",
1990
2593
  className: audio_panel_module_css_default.generate,
1991
- disabled: loading || !connected || needModel && visibleModels.length === 0,
1992
- onClick: () => void submit(),
1993
- children: loading ? progress !== "" ? progress : tt("generating") : tt("generate")
1994
- })
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
1995
2606
  ]
1996
2607
  }),
1997
2608
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -1999,7 +2610,7 @@ window.__ModuleLoader__.load({
1999
2610
  children: [error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2000
2611
  className: audio_panel_module_css_default.error,
2001
2612
  children: error
2002
- }) : null, results.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2613
+ }) : null, tasks.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2003
2614
  className: audio_panel_module_css_default.resultEmpty,
2004
2615
  children: [
2005
2616
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -2009,106 +2620,88 @@ window.__ModuleLoader__.load({
2009
2620
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: tt("result.empty") }),
2010
2621
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2011
2622
  className: audio_panel_module_css_default.resultEmptyHint,
2012
- children: "生成结果将在这里播放、下载,并可一键加入资源库"
2623
+ children: "点击「开始生成」即创建一个任务,可同时进行多个;勾选「模型对比」用多个模型同参数生成对比"
2013
2624
  })
2014
2625
  ]
2015
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2016
- className: audio_panel_module_css_default.resultMeta,
2017
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("result.done", { count: results.reduce((sum, group) => sum + group.outputs.length, 0) }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2018
- className: audio_panel_module_css_default.resultModeChip,
2019
- children: modeLabel
2020
- })]
2021
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2022
- className: audio_panel_module_css_default.resultGroups,
2023
- children: results.map((group, groupIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2024
- className: audio_panel_module_css_default.resultGroup,
2025
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2026
- className: audio_panel_module_css_default.resultGroupHead,
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" ? "已取消" : "失败";
2631
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2632
+ className: audio_panel_module_css_default.taskCard,
2633
+ "data-state": task.status,
2027
2634
  children: [
2028
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2029
- className: audio_panel_module_css_default.resultGroupChip,
2030
- children: group.model || "音色设计"
2031
- }),
2032
- group.error !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2033
- className: audio_panel_module_css_default.resultGroupError,
2034
- children: ["生成失败:", group.error]
2035
- }) : null,
2036
- group.outputs.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2037
- className: audio_panel_module_css_default.resultGroupCount,
2038
- children: [group.outputs.length, " 段"]
2039
- }) : null
2040
- ]
2041
- }), group.outputs.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2042
- className: audio_panel_module_css_default.audioList,
2043
- children: group.outputs.map((audio, index) => {
2044
- const saved = savedIds.has(audio.id);
2045
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2046
- className: audio_panel_module_css_default.audioCard,
2047
- "data-saved": saved ? "true" : "false",
2635
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2636
+ className: audio_panel_module_css_default.taskHead,
2048
2637
  children: [
2049
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2050
- className: audio_panel_module_css_default.audioCardHead,
2051
- children: [
2052
- audio.voiceId !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2053
- className: audio_panel_module_css_default.voiceIdChip,
2054
- title: "新音色 ID",
2055
- children: ["新音色 ", audio.voiceId]
2056
- }) : null,
2057
- saved ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2058
- className: audio_panel_module_css_default.savedChip,
2059
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}), " 已入库"]
2060
- }) : null,
2061
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2062
- className: audio_panel_module_css_default.audioCardIndex,
2063
- children: ["#", index + 1]
2064
- })
2065
- ]
2638
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2639
+ className: audio_panel_module_css_default.resultModeChip,
2640
+ children: task.mode
2066
2641
  }),
2067
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPlayer, {
2068
- src: dataUrlOf(audio),
2069
- itemKey: audio.id
2642
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2643
+ className: audio_panel_module_css_default.taskLabel,
2644
+ title: task.prompt,
2645
+ children: task.label
2070
2646
  }),
2071
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2072
- className: audio_panel_module_css_default.audioCardActions,
2073
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
2074
- className: audio_panel_module_css_default.ghostButton,
2075
- href: dataUrlOf(audio),
2076
- download: `generated-${groupIndex + 1}-${index + 1}.${audio.mime.split("/")[1]?.replace("mpeg", "mp3") ?? "mp3"}`,
2077
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DownloadIcon, {}), " 下载"]
2078
- }), saved ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
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
+ }),
2652
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2653
+ className: audio_panel_module_css_default.taskActions,
2654
+ children: [task.status === "running" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2079
2655
  type: "button",
2080
2656
  className: audio_panel_module_css_default.ghostButton,
2081
- onClick: () => props.showToast("该音频已加入资源库"),
2082
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}), " 已入库"]
2083
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2657
+ onClick: () => cancelTask(task.id),
2658
+ children: "取消"
2659
+ }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2084
2660
  type: "button",
2085
2661
  className: audio_panel_module_css_default.ghostButton,
2086
- onClick: () => openSaveDialog([audio], {
2087
- mode,
2088
- prompt: prompt.trim(),
2089
- ...voice.trim() !== "" ? { voice: voice.trim() } : {},
2090
- ...audio.voiceId === void 0 ? {} : { voiceId: audio.voiceId },
2091
- ...group.model !== "" ? { model: group.model } : {},
2092
- ...channels.length > 0 ? { channel: channels.find((candidate) => candidate.id === (mode === "voice_design" ? designChannelId : modelOptions.defaultChannelId))?.name ?? channels[0]?.name ?? "" } : {},
2093
- params: {
2094
- mode,
2095
- model: mode === "voice_design" ? "" : group.model,
2096
- prompt: prompt.trim(),
2097
- ...voice.trim() !== "" ? { voice: voice.trim() } : {},
2098
- ...speed.trim() !== "" ? { speed: Number(speed) } : {},
2099
- ...duration.trim() !== "" ? { duration: Number(duration) } : {},
2100
- ...format.trim() !== "" ? { format: format.trim() } : {}
2101
- }
2102
- }),
2103
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StarIcon, {}), " 加入资源库"]
2662
+ onClick: () => removeTask(task.id),
2663
+ children: "移除"
2104
2664
  })]
2105
2665
  })
2106
2666
  ]
2107
- }, audio.id);
2108
- })
2109
- }) : null]
2110
- }, `${group.model}-${groupIndex}`))
2111
- })] })]
2667
+ }),
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))
2700
+ })
2701
+ ]
2702
+ }, task.id);
2703
+ })
2704
+ })]
2112
2705
  }),
2113
2706
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
2114
2707
  className: audio_panel_module_css_default.historyCol,
@@ -2126,41 +2719,113 @@ window.__ModuleLoader__.load({
2126
2719
  }), entries.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2127
2720
  className: audio_panel_module_css_default.historyEmpty,
2128
2721
  children: tt("history.empty")
2129
- }) : /* @__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", {
2130
2741
  className: audio_panel_module_css_default.historyList,
2131
- children: entries.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2132
- className: audio_panel_module_css_default.historyItem,
2133
- children: [
2134
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2135
- className: audio_panel_module_css_default.historyPrompt,
2136
- children: entry.prompt
2137
- }),
2138
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2139
- className: audio_panel_module_css_default.historyMeta,
2140
- children: [
2141
- entry.mode,
2142
- " · ",
2143
- entry.model,
2144
- entry.channel ? ` · ${entry.channel}` : ""
2145
- ]
2146
- }),
2147
- entry.audio.map((audio, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AudioPlayer, {
2148
- src: audio.url,
2149
- compact: true,
2150
- itemKey: `${entry.id}-${index}`
2151
- }, index)),
2152
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2153
- className: audio_panel_module_css_default.historyActions,
2154
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2155
- type: "button",
2156
- className: audio_panel_module_css_default.historyAction,
2157
- onClick: () => openSaveDialog(audioRefsOfEntry(entry), contextOfEntry(entry)),
2158
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StarIcon, {}), " 入库"]
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
+ })
2159
2824
  })
2160
- })
2161
- ]
2162
- }, entry.id))
2163
- })]
2825
+ ]
2826
+ }, item.key);
2827
+ })
2828
+ })] })]
2164
2829
  }),
2165
2830
  saveDialog !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LibrarySaveDialog, {
2166
2831
  api,
@@ -2184,62 +2849,62 @@ window.__ModuleLoader__.load({
2184
2849
  document.head.appendChild(tag);
2185
2850
  }
2186
2851
  var library_module_css_default = {
2187
- "provRow": "vzUV2a_provRow",
2188
- "textarea": "vzUV2a_textarea",
2189
- "drawerActions": "vzUV2a_drawerActions",
2190
- "chipCount": "vzUV2a_chipCount",
2191
- "listActions": "vzUV2a_listActions",
2192
- "cardCheck": "vzUV2a_cardCheck",
2193
- "typeBadge": "vzUV2a_typeBadge",
2194
- "mono": "vzUV2a_mono",
2195
- "primaryBtn": "vzUV2a_primaryBtn",
2196
- "grid": "vzUV2a_grid",
2852
+ "drawerMask": "vzUV2a_drawerMask",
2853
+ "audiogenDrawerIn": "vzUV2a_audiogenDrawerIn",
2854
+ "drawerLabel": "vzUV2a_drawerLabel",
2855
+ "searchBox": "vzUV2a_searchBox",
2856
+ "listHead": "vzUV2a_listHead",
2197
2857
  "card": "vzUV2a_card",
2198
2858
  "filterRow": "vzUV2a_filterRow",
2199
- "drawer": "vzUV2a_drawer",
2200
- "drawerHead": "vzUV2a_drawerHead",
2859
+ "smallChip": "vzUV2a_smallChip",
2860
+ "emptyIcon": "vzUV2a_emptyIcon",
2861
+ "iconBtn": "vzUV2a_iconBtn",
2201
2862
  "drawerBody": "vzUV2a_drawerBody",
2202
- "listHead": "vzUV2a_listHead",
2203
- "typeChips": "vzUV2a_typeChips",
2204
- "cardTime": "vzUV2a_cardTime",
2205
- "cardName": "vzUV2a_cardName",
2206
- "empty": "vzUV2a_empty",
2207
- "drawerPlayerName": "vzUV2a_drawerPlayerName",
2863
+ "drawerField": "vzUV2a_drawerField",
2864
+ "listActions": "vzUV2a_listActions",
2865
+ "input": "vzUV2a_input",
2866
+ "metaChip": "vzUV2a_metaChip",
2867
+ "mono": "vzUV2a_mono",
2868
+ "cardCheck": "vzUV2a_cardCheck",
2869
+ "drawerSection": "vzUV2a_drawerSection",
2870
+ "drawerTitle": "vzUV2a_drawerTitle",
2208
2871
  "provenance": "vzUV2a_provenance",
2209
- "toolbar": "vzUV2a_toolbar",
2210
- "drawerMask": "vzUV2a_drawerMask",
2211
- "drawerPlayer": "vzUV2a_drawerPlayer",
2212
- "paramsDetails": "vzUV2a_paramsDetails",
2213
- "filterLabel": "vzUV2a_filterLabel",
2214
2872
  "stateNote": "vzUV2a_stateNote",
2215
- "promptText": "vzUV2a_promptText",
2216
- "smallSelect": "vzUV2a_smallSelect",
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",
2217
2882
  "selCount": "vzUV2a_selCount",
2218
- "chip": "vzUV2a_chip",
2883
+ "grid": "vzUV2a_grid",
2884
+ "drawer": "vzUV2a_drawer",
2885
+ "searchInput": "vzUV2a_searchInput",
2886
+ "drawerPlayerList": "vzUV2a_drawerPlayerList",
2219
2887
  "provKey": "vzUV2a_provKey",
2888
+ "drawerHead": "vzUV2a_drawerHead",
2889
+ "dangerBtn": "vzUV2a_dangerBtn",
2890
+ "toolbar": "vzUV2a_toolbar",
2891
+ "provRow": "vzUV2a_provRow",
2220
2892
  "provValue": "vzUV2a_provValue",
2221
2893
  "ghostBtn": "vzUV2a_ghostBtn",
2222
- "dangerBtn": "vzUV2a_dangerBtn",
2223
- "drawerLabel": "vzUV2a_drawerLabel",
2224
- "emptyIcon": "vzUV2a_emptyIcon",
2225
- "searchBox": "vzUV2a_searchBox",
2226
- "code": "vzUV2a_code",
2227
- "smallChip": "vzUV2a_smallChip",
2894
+ "chipCount": "vzUV2a_chipCount",
2895
+ "typeChips": "vzUV2a_typeChips",
2896
+ "smallSelect": "vzUV2a_smallSelect",
2897
+ "drawerSplit": "vzUV2a_drawerSplit",
2898
+ "library": "vzUV2a_library",
2899
+ "emptyHint": "vzUV2a_emptyHint",
2228
2900
  "cardHead": "vzUV2a_cardHead",
2229
- "drawerPlayerList": "vzUV2a_drawerPlayerList",
2901
+ "cardTime": "vzUV2a_cardTime",
2902
+ "promptText": "vzUV2a_promptText",
2903
+ "empty": "vzUV2a_empty",
2904
+ "cardName": "vzUV2a_cardName",
2905
+ "filterLabel": "vzUV2a_filterLabel",
2230
2906
  "listCount": "vzUV2a_listCount",
2231
- "emptyHint": "vzUV2a_emptyHint",
2232
- "cardFoot": "vzUV2a_cardFoot",
2233
- "iconBtn": "vzUV2a_iconBtn",
2234
- "drawerTitle": "vzUV2a_drawerTitle",
2235
- "drawerSection": "vzUV2a_drawerSection",
2236
- "library": "vzUV2a_library",
2237
- "searchInput": "vzUV2a_searchInput",
2238
- "drawerSplit": "vzUV2a_drawerSplit",
2239
- "metaChip": "vzUV2a_metaChip",
2240
- "drawerField": "vzUV2a_drawerField",
2241
- "input": "vzUV2a_input",
2242
- "audiogenDrawerIn": "vzUV2a_audiogenDrawerIn"
2907
+ "chip": "vzUV2a_chip"
2243
2908
  };
2244
2909
  //#endregion
2245
2910
  //#region src/client/library-view.tsx
@@ -2614,10 +3279,10 @@ window.__ModuleLoader__.load({
2614
3279
  className: library_module_css_default.stateNote,
2615
3280
  children: "加载中…"
2616
3281
  }) : null,
2617
- error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3282
+ error !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2618
3283
  className: library_module_css_default.stateNote,
2619
3284
  "data-error": true,
2620
- 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)。" })]
2621
3286
  }) : null,
2622
3287
  !loading && error === null && filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2623
3288
  className: library_module_css_default.empty,
@@ -3112,167 +3777,167 @@ window.__ModuleLoader__.load({
3112
3777
  document.head.appendChild(tag);
3113
3778
  }
3114
3779
  var panel_module_css_default = {
3115
- "lightboxDownload": "rwa6qG_lightboxDownload",
3116
- "galleryHeading": "rwa6qG_galleryHeading",
3117
- "panelTitle": "rwa6qG_panelTitle",
3118
- "canvasStateHint": "rwa6qG_canvasStateHint",
3119
- "compareToggle": "rwa6qG_compareToggle",
3120
- "generateInner": "rwa6qG_generateInner",
3121
- "config": "rwa6qG_config",
3780
+ "view": "rwa6qG_view",
3781
+ "lightboxClose": "rwa6qG_lightboxClose",
3782
+ "galleryWorkspace": "rwa6qG_galleryWorkspace",
3783
+ "galleryRemove": "rwa6qG_galleryRemove",
3784
+ "lightboxMeta": "rwa6qG_lightboxMeta",
3785
+ "canvasState": "rwa6qG_canvasState",
3786
+ "taskTrayHeader": "rwa6qG_taskTrayHeader",
3787
+ "galleryFilterHeading": "rwa6qG_galleryFilterHeading",
3788
+ "galleryFilterDivider": "rwa6qG_galleryFilterDivider",
3122
3789
  "galleryViewToggle": "rwa6qG_galleryViewToggle",
3123
- "galleryRatio": "rwa6qG_galleryRatio",
3790
+ "galleryClear": "rwa6qG_galleryClear",
3791
+ "galleryHeading": "rwa6qG_galleryHeading",
3792
+ "connectionDot": "rwa6qG_connectionDot",
3793
+ "uploadHint": "rwa6qG_uploadHint",
3794
+ "compareModelChoices": "rwa6qG_compareModelChoices",
3124
3795
  "canvasError": "rwa6qG_canvasError",
3125
- "galleryMasonry": "rwa6qG_galleryMasonry",
3126
- "galleryFilterDivider": "rwa6qG_galleryFilterDivider",
3127
- "lightboxZoomLevel": "rwa6qG_lightboxZoomLevel",
3128
- "reference": "rwa6qG_reference",
3129
- "lightboxEdit": "rwa6qG_lightboxEdit",
3796
+ "galleryFilterNote": "rwa6qG_galleryFilterNote",
3797
+ "hiddenFile": "rwa6qG_hiddenFile",
3798
+ "historyThumbPlaceholder": "rwa6qG_historyThumbPlaceholder",
3799
+ "configGuide": "rwa6qG_configGuide",
3800
+ "galleryTagFilter": "rwa6qG_galleryTagFilter",
3801
+ "updateBanner": "rwa6qG_updateBanner",
3130
3802
  "lightboxTool": "rwa6qG_lightboxTool",
3131
- "githubLink": "rwa6qG_githubLink",
3803
+ "historyTitle": "rwa6qG_historyTitle",
3804
+ "dshImageGenSpin": "rwa6qG_dshImageGenSpin",
3805
+ "lightbox": "rwa6qG_lightbox",
3806
+ "referenceActions": "rwa6qG_referenceActions",
3807
+ "lightboxFigure": "rwa6qG_lightboxFigure",
3808
+ "taskTrayClose": "rwa6qG_taskTrayClose",
3809
+ "referenceImage": "rwa6qG_referenceImage",
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",
3132
3817
  "galleryAdd": "rwa6qG_galleryAdd",
3133
- "lightboxCaption": "rwa6qG_lightboxCaption",
3134
- "panelHeader": "rwa6qG_panelHeader",
3135
- "lightboxScaleFrame": "rwa6qG_lightboxScaleFrame",
3136
- "configGuide": "rwa6qG_configGuide",
3137
- "canvasBody": "rwa6qG_canvasBody",
3818
+ "canvasMeta": "rwa6qG_canvasMeta",
3819
+ "historyList": "rwa6qG_historyList",
3820
+ "reference": "rwa6qG_reference",
3821
+ "footer": "rwa6qG_footer",
3822
+ "lightboxCopy": "rwa6qG_lightboxCopy",
3823
+ "galleryImage": "rwa6qG_galleryImage",
3138
3824
  "galleryBadge": "rwa6qG_galleryBadge",
3139
- "historyEmpty": "rwa6qG_historyEmpty",
3140
- "connectionDot": "rwa6qG_connectionDot",
3141
- "paramLabel": "rwa6qG_paramLabel",
3142
- "configScroll": "rwa6qG_configScroll",
3143
- "galleryToast": "rwa6qG_galleryToast",
3144
- "lightbox": "rwa6qG_lightbox",
3145
- "updateRelease": "rwa6qG_updateRelease",
3146
- "canvasState": "rwa6qG_canvasState",
3825
+ "historyInfo": "rwa6qG_historyInfo",
3826
+ "gallerySearch": "rwa6qG_gallerySearch",
3147
3827
  "lightboxIndex": "rwa6qG_lightboxIndex",
3148
- "optionRow": "rwa6qG_optionRow",
3149
- "modePill": "rwa6qG_modePill",
3150
3828
  "lightboxImage": "rwa6qG_lightboxImage",
3151
- "updateBanner": "rwa6qG_updateBanner",
3152
- "hiddenFile": "rwa6qG_hiddenFile",
3829
+ "lightboxScaleFrame": "rwa6qG_lightboxScaleFrame",
3830
+ "galleryBulkButton": "rwa6qG_galleryBulkButton",
3831
+ "paramHint": "rwa6qG_paramHint",
3832
+ "updateActions": "rwa6qG_updateActions",
3153
3833
  "modelWrap": "rwa6qG_modelWrap",
3154
- "galleryAvatar": "rwa6qG_galleryAvatar",
3155
- "canvasMeta": "rwa6qG_canvasMeta",
3834
+ "lightboxTools": "rwa6qG_lightboxTools",
3156
3835
  "galleryCardFooter": "rwa6qG_galleryCardFooter",
3157
- "comparisonImageButton": "rwa6qG_comparisonImageButton",
3158
- "historyTitle": "rwa6qG_historyTitle",
3159
- "galleryTagEditor": "rwa6qG_galleryTagEditor",
3836
+ "zoomHint": "rwa6qG_zoomHint",
3837
+ "panelHeading": "rwa6qG_panelHeading",
3838
+ "panelTitle": "rwa6qG_panelTitle",
3839
+ "taskTrayToggle": "rwa6qG_taskTrayToggle",
3840
+ "modelSelect": "rwa6qG_modelSelect",
3160
3841
  "generateButton": "rwa6qG_generateButton",
3161
- "historyAction": "rwa6qG_historyAction",
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",
3853
+ "historyHeader": "rwa6qG_historyHeader",
3854
+ "comparisonGrid": "rwa6qG_comparisonGrid",
3855
+ "galleryFilter": "rwa6qG_galleryFilter",
3856
+ "lightboxCaption": "rwa6qG_lightboxCaption",
3857
+ "galleryToast": "rwa6qG_galleryToast",
3858
+ "promptFooter": "rwa6qG_promptFooter",
3859
+ "githubLink": "rwa6qG_githubLink",
3860
+ "canvasEmptyIcon": "rwa6qG_canvasEmptyIcon",
3861
+ "dshImageGenToastIn": "rwa6qG_dshImageGenToastIn",
3862
+ "galleryMasonry": "rwa6qG_galleryMasonry",
3863
+ "galleryAvatar": "rwa6qG_galleryAvatar",
3864
+ "panelHeader": "rwa6qG_panelHeader",
3162
3865
  "connectionStatus": "rwa6qG_connectionStatus",
3163
- "taskTrayChevron": "rwa6qG_taskTrayChevron",
3164
- "galleryBulkButton": "rwa6qG_galleryBulkButton",
3165
- "referenceActions": "rwa6qG_referenceActions",
3166
- "historyThumb": "rwa6qG_historyThumb",
3167
- "panel": "rwa6qG_panel",
3168
- "paramGroup": "rwa6qG_paramGroup",
3169
- "galleryTagFilter": "rwa6qG_galleryTagFilter",
3170
- "comparisonBoard": "rwa6qG_comparisonBoard",
3171
- "paramHint": "rwa6qG_paramHint",
3172
- "modelSelect": "rwa6qG_modelSelect",
3173
- "historyMeta": "rwa6qG_historyMeta",
3866
+ "galleryTagInput": "rwa6qG_galleryTagInput",
3867
+ "galleryToolbarActions": "rwa6qG_galleryToolbarActions",
3868
+ "imageCaption": "rwa6qG_imageCaption",
3869
+ "templatesButton": "rwa6qG_templatesButton",
3870
+ "updateRelease": "rwa6qG_updateRelease",
3871
+ "card": "rwa6qG_card",
3872
+ "galleryRatio": "rwa6qG_galleryRatio",
3873
+ "compareToggle": "rwa6qG_compareToggle",
3174
3874
  "galleryTags": "rwa6qG_galleryTags",
3175
- "uploadBox": "rwa6qG_uploadBox",
3176
- "modelLabel": "rwa6qG_modelLabel",
3177
- "gallerySelectionClear": "rwa6qG_gallerySelectionClear",
3178
- "modeRow": "rwa6qG_modeRow",
3179
- "spinner": "rwa6qG_spinner",
3180
- "historyPrompt": "rwa6qG_historyPrompt",
3181
- "modelMenuList": "rwa6qG_modelMenuList",
3875
+ "comparisonImageButton": "rwa6qG_comparisonImageButton",
3876
+ "galleryRatioList": "rwa6qG_galleryRatioList",
3877
+ "historyEmpty": "rwa6qG_historyEmpty",
3878
+ "modePill": "rwa6qG_modePill",
3879
+ "paramGroup": "rwa6qG_paramGroup",
3880
+ "galleryFilterCount": "rwa6qG_galleryFilterCount",
3881
+ "comparisonFullscreenGrid": "rwa6qG_comparisonFullscreenGrid",
3882
+ "modelMenuItem": "rwa6qG_modelMenuItem",
3883
+ "config": "rwa6qG_config",
3884
+ "modelMenu": "rwa6qG_modelMenu",
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",
3182
3894
  "optionGrid": "rwa6qG_optionGrid",
3183
- "image": "rwa6qG_image",
3895
+ "modelLabel": "rwa6qG_modelLabel",
3896
+ "entryIcon": "rwa6qG_entryIcon",
3897
+ "galleryCard": "rwa6qG_galleryCard",
3898
+ "historyItem": "rwa6qG_historyItem",
3184
3899
  "lightboxStage": "rwa6qG_lightboxStage",
3185
- "lightboxCopy": "rwa6qG_lightboxCopy",
3186
- "lightboxFigure": "rwa6qG_lightboxFigure",
3187
- "panelHeading": "rwa6qG_panelHeading",
3188
- "galleryFilters": "rwa6qG_galleryFilters",
3189
- "lightboxMeta": "rwa6qG_lightboxMeta",
3190
- "galleryRatioList": "rwa6qG_galleryRatioList",
3191
- "configGuideBody": "rwa6qG_configGuideBody",
3900
+ "taskStatus": "rwa6qG_taskStatus",
3901
+ "uploadIcon": "rwa6qG_uploadIcon",
3902
+ "paramLabel": "rwa6qG_paramLabel",
3903
+ "galleryCardInfo": "rwa6qG_galleryCardInfo",
3904
+ "taskTray": "rwa6qG_taskTray",
3905
+ "lightboxZoomLevel": "rwa6qG_lightboxZoomLevel",
3906
+ "modelMenuList": "rwa6qG_modelMenuList",
3907
+ "historyMain": "rwa6qG_historyMain",
3908
+ "galleryTagEdit": "rwa6qG_galleryTagEdit",
3192
3909
  "canvasStateTitle": "rwa6qG_canvasStateTitle",
3193
- "entryIcon": "rwa6qG_entryIcon",
3910
+ "history": "rwa6qG_history",
3911
+ "historyClear": "rwa6qG_historyClear",
3912
+ "comparisonFullscreen": "rwa6qG_comparisonFullscreen",
3913
+ "enhanceButton": "rwa6qG_enhanceButton",
3914
+ "historyAction": "rwa6qG_historyAction",
3194
3915
  "updateText": "rwa6qG_updateText",
3916
+ "historyActions": "rwa6qG_historyActions",
3195
3917
  "galleryToolbar": "rwa6qG_galleryToolbar",
3196
- "gallerySelectionBar": "rwa6qG_gallerySelectionBar",
3197
- "galleryImageButton": "rwa6qG_galleryImageButton",
3198
- "galleryCardInfo": "rwa6qG_galleryCardInfo",
3199
- "taskPrompt": "rwa6qG_taskPrompt",
3200
- "imageCard": "rwa6qG_imageCard",
3201
- "canvasEmptyIcon": "rwa6qG_canvasEmptyIcon",
3202
- "modelMenu": "rwa6qG_modelMenu",
3203
- "galleryClear": "rwa6qG_galleryClear",
3204
- "compareControl": "rwa6qG_compareControl",
3205
- "view": "rwa6qG_view",
3206
- "taskTrayHeader": "rwa6qG_taskTrayHeader",
3207
- "bigSpinner": "rwa6qG_bigSpinner",
3208
- "promptFooter": "rwa6qG_promptFooter",
3209
- "taskTray": "rwa6qG_taskTray",
3210
- "historyInfo": "rwa6qG_historyInfo",
3918
+ "configGuideBody": "rwa6qG_configGuideBody",
3919
+ "taskTrayChevron": "rwa6qG_taskTrayChevron",
3920
+ "configScroll": "rwa6qG_configScroll",
3921
+ "lightboxNav": "rwa6qG_lightboxNav",
3922
+ "gallerySelectionClear": "rwa6qG_gallerySelectionClear",
3211
3923
  "gallerySort": "rwa6qG_gallerySort",
3212
- "galleryCount": "rwa6qG_galleryCount",
3924
+ "modeRow": "rwa6qG_modeRow",
3925
+ "taskRow": "rwa6qG_taskRow",
3926
+ "historyMeta": "rwa6qG_historyMeta",
3927
+ "spinner": "rwa6qG_spinner",
3213
3928
  "studio": "rwa6qG_studio",
3214
- "historyHeader": "rwa6qG_historyHeader",
3215
- "grid": "rwa6qG_grid",
3216
- "lightboxNav": "rwa6qG_lightboxNav",
3217
- "taskTrayCount": "rwa6qG_taskTrayCount",
3218
- "updateActions": "rwa6qG_updateActions",
3219
- "imageCaption": "rwa6qG_imageCaption",
3220
- "historyItem": "rwa6qG_historyItem",
3221
- "optionPill": "rwa6qG_optionPill",
3222
- "modelMenuItem": "rwa6qG_modelMenuItem",
3223
- "lightboxCaptionRow": "rwa6qG_lightboxCaptionRow",
3224
- "comparisonGrid": "rwa6qG_comparisonGrid",
3225
- "galleryTagFilterList": "rwa6qG_galleryTagFilterList",
3226
- "galleryImage": "rwa6qG_galleryImage",
3227
- "enhanceButton": "rwa6qG_enhanceButton",
3228
- "dshImageGenToastIn": "rwa6qG_dshImageGenToastIn",
3229
- "historyThumbPlaceholder": "rwa6qG_historyThumbPlaceholder",
3230
3929
  "entry": "rwa6qG_entry",
3231
- "prompt": "rwa6qG_prompt",
3232
- "gallerySearch": "rwa6qG_gallerySearch",
3233
- "galleryFilterCount": "rwa6qG_galleryFilterCount",
3234
- "historySearch": "rwa6qG_historySearch",
3235
- "galleryToolbarActions": "rwa6qG_galleryToolbarActions",
3236
- "comparisonFullscreen": "rwa6qG_comparisonFullscreen",
3237
- "templatesButton": "rwa6qG_templatesButton",
3238
- "footer": "rwa6qG_footer",
3239
- "lightboxTools": "rwa6qG_lightboxTools",
3240
- "referenceImage": "rwa6qG_referenceImage",
3241
- "uploadHint": "rwa6qG_uploadHint",
3242
- "galleryTagEdit": "rwa6qG_galleryTagEdit",
3243
3930
  "canvasHistoryTag": "rwa6qG_canvasHistoryTag",
3244
- "galleryFilter": "rwa6qG_galleryFilter",
3245
- "taskTrayToggle": "rwa6qG_taskTrayToggle",
3246
- "canvas": "rwa6qG_canvas",
3247
- "historyMain": "rwa6qG_historyMain",
3931
+ "lightboxEdit": "rwa6qG_lightboxEdit",
3248
3932
  "promptCount": "rwa6qG_promptCount",
3249
- "historyActions": "rwa6qG_historyActions",
3250
- "lightboxActions": "rwa6qG_lightboxActions",
3251
- "galleryWorkspace": "rwa6qG_galleryWorkspace",
3252
- "galleryFilterNote": "rwa6qG_galleryFilterNote",
3253
- "historyFilters": "rwa6qG_historyFilters",
3254
- "compareModelChoices": "rwa6qG_compareModelChoices",
3255
- "comparisonFullscreenGrid": "rwa6qG_comparisonFullscreenGrid",
3256
- "taskRow": "rwa6qG_taskRow",
3257
- "historyClear": "rwa6qG_historyClear",
3258
- "zoomHint": "rwa6qG_zoomHint",
3259
- "galleryRemove": "rwa6qG_galleryRemove",
3933
+ "panel": "rwa6qG_panel",
3934
+ "image": "rwa6qG_image",
3935
+ "prompt": "rwa6qG_prompt",
3936
+ "galleryTagFilterList": "rwa6qG_galleryTagFilterList",
3260
3937
  "gallerySelectMode": "rwa6qG_gallerySelectMode",
3261
- "lightboxClose": "rwa6qG_lightboxClose",
3262
- "entryLabel": "rwa6qG_entryLabel",
3263
- "uploadIcon": "rwa6qG_uploadIcon",
3264
- "galleryFilterHeading": "rwa6qG_galleryFilterHeading",
3265
- "gallerySelect": "rwa6qG_gallerySelect",
3266
- "taskTrayClose": "rwa6qG_taskTrayClose",
3267
- "download": "rwa6qG_download",
3268
- "card": "rwa6qG_card",
3269
- "dshImageGenSpin": "rwa6qG_dshImageGenSpin",
3270
- "historyList": "rwa6qG_historyList",
3271
- "history": "rwa6qG_history",
3272
- "galleryCard": "rwa6qG_galleryCard",
3273
- "taskStatus": "rwa6qG_taskStatus",
3274
- "taskRows": "rwa6qG_taskRows",
3275
- "galleryTagInput": "rwa6qG_galleryTagInput"
3938
+ "canvasStateHint": "rwa6qG_canvasStateHint",
3939
+ "generateInner": "rwa6qG_generateInner",
3940
+ "galleryFilters": "rwa6qG_galleryFilters"
3276
3941
  };
3277
3942
  //#endregion
3278
3943
  //#region src/client/mount.tsx
@@ -3929,79 +4594,79 @@ window.__ModuleLoader__.load({
3929
4594
  document.head.appendChild(tag);
3930
4595
  }
3931
4596
  var settings_card_module_css_default = {
3932
- "candidateLabel": "zmjoSq_candidateLabel",
3933
- "chevronOpen": "zmjoSq_chevronOpen",
3934
- "channelMeta": "zmjoSq_channelMeta",
3935
- "modelBadge": "zmjoSq_modelBadge",
3936
- "candidatePanel": "zmjoSq_candidatePanel",
3937
- "channelEditor": "zmjoSq_channelEditor",
3938
- "channelList": "zmjoSq_channelList",
3939
- "sectionHint": "zmjoSq_sectionHint",
3940
- "channelAction": "zmjoSq_channelAction",
3941
- "card": "zmjoSq_card",
3942
- "link": "zmjoSq_link",
3943
- "channelDotWarn": "zmjoSq_channelDotWarn",
3944
- "headText": "zmjoSq_headText",
4597
+ "input": "zmjoSq_input",
4598
+ "modelCatalogHead": "zmjoSq_modelCatalogHead",
4599
+ "modelArrow": "zmjoSq_modelArrow",
4600
+ "save": "zmjoSq_save",
3945
4601
  "modelCatalog": "zmjoSq_modelCatalog",
3946
- "modelEmpty": "zmjoSq_modelEmpty",
4602
+ "customSettingsSummary": "zmjoSq_customSettingsSummary",
4603
+ "modelInput": "zmjoSq_modelInput",
4604
+ "select": "zmjoSq_select",
4605
+ "channelAdd": "zmjoSq_channelAdd",
4606
+ "editorTitle": "zmjoSq_editorTitle",
4607
+ "modelCatalogTools": "zmjoSq_modelCatalogTools",
3947
4608
  "candidateList": "zmjoSq_candidateList",
3948
4609
  "label": "zmjoSq_label",
4610
+ "channelList": "zmjoSq_channelList",
4611
+ "footer": "zmjoSq_footer",
4612
+ "customSettingsBody": "zmjoSq_customSettingsBody",
3949
4613
  "body": "zmjoSq_body",
3950
- "reset": "zmjoSq_reset",
3951
- "channelAddRow": "zmjoSq_channelAddRow",
3952
- "customSettings": "zmjoSq_customSettings",
3953
- "channelRow": "zmjoSq_channelRow",
3954
- "modelRows": "zmjoSq_modelRows",
3955
- "candidateTitle": "zmjoSq_candidateTitle",
3956
- "description": "zmjoSq_description",
3957
- "candidateActions": "zmjoSq_candidateActions",
3958
- "modelCatalogTools": "zmjoSq_modelCatalogTools",
4614
+ "sectionHint": "zmjoSq_sectionHint",
4615
+ "channelDanger": "zmjoSq_channelDanger",
4616
+ "editorWrap": "zmjoSq_editorWrap",
4617
+ "link": "zmjoSq_link",
4618
+ "linkButton": "zmjoSq_linkButton",
3959
4619
  "head": "zmjoSq_head",
3960
- "input": "zmjoSq_input",
4620
+ "candidateLabel": "zmjoSq_candidateLabel",
4621
+ "candidateTitle": "zmjoSq_candidateTitle",
4622
+ "customSettings": "zmjoSq_customSettings",
4623
+ "channelEmpty": "zmjoSq_channelEmpty",
4624
+ "channelMain": "zmjoSq_channelMain",
4625
+ "candidate": "zmjoSq_candidate",
4626
+ "chevronOpen": "zmjoSq_chevronOpen",
4627
+ "discard": "zmjoSq_discard",
4628
+ "header": "zmjoSq_header",
4629
+ "channelName": "zmjoSq_channelName",
4630
+ "card": "zmjoSq_card",
3961
4631
  "channelSection": "zmjoSq_channelSection",
3962
- "select": "zmjoSq_select",
3963
- "modelCatalogMeta": "zmjoSq_modelCatalogMeta",
4632
+ "editorHeader": "zmjoSq_editorHeader",
4633
+ "chevron": "zmjoSq_chevron",
4634
+ "channelDotWarn": "zmjoSq_channelDotWarn",
3964
4635
  "candidateId": "zmjoSq_candidateId",
3965
- "modelCatalogTitle": "zmjoSq_modelCatalogTitle",
4636
+ "modelCatalogMeta": "zmjoSq_modelCatalogMeta",
4637
+ "modelCategorySelect": "zmjoSq_modelCategorySelect",
4638
+ "channelBadge": "zmjoSq_channelBadge",
4639
+ "channelRow": "zmjoSq_channelRow",
3966
4640
  "deleteConfirmText": "zmjoSq_deleteConfirmText",
3967
- "readOnly": "zmjoSq_readOnly",
4641
+ "modelEmpty": "zmjoSq_modelEmpty",
4642
+ "addModel": "zmjoSq_addModel",
4643
+ "detectOk": "zmjoSq_detectOk",
4644
+ "channelEditor": "zmjoSq_channelEditor",
3968
4645
  "sectionHeader": "zmjoSq_sectionHeader",
4646
+ "reset": "zmjoSq_reset",
3969
4647
  "failed": "zmjoSq_failed",
3970
- "modelRowRemove": "zmjoSq_modelRowRemove",
3971
- "editorTag": "zmjoSq_editorTag",
3972
- "footer": "zmjoSq_footer",
3973
- "header": "zmjoSq_header",
3974
- "addModel": "zmjoSq_addModel",
3975
- "editorWrap": "zmjoSq_editorWrap",
3976
- "channelName": "zmjoSq_channelName",
3977
- "candidate": "zmjoSq_candidate",
3978
- "modelCatalogHead": "zmjoSq_modelCatalogHead",
3979
- "modelInput": "zmjoSq_modelInput",
3980
- "channelBadge": "zmjoSq_channelBadge",
3981
- "modelArrow": "zmjoSq_modelArrow",
3982
- "channelDanger": "zmjoSq_channelDanger",
4648
+ "sectionTitle": "zmjoSq_sectionTitle",
4649
+ "candidatePanel": "zmjoSq_candidatePanel",
4650
+ "channelHost": "zmjoSq_channelHost",
4651
+ "readOnly": "zmjoSq_readOnly",
3983
4652
  "channelDotReady": "zmjoSq_channelDotReady",
3984
- "editorTitle": "zmjoSq_editorTitle",
4653
+ "channelAddRow": "zmjoSq_channelAddRow",
4654
+ "editorTag": "zmjoSq_editorTag",
4655
+ "modelRows": "zmjoSq_modelRows",
3985
4656
  "modelRow": "zmjoSq_modelRow",
3986
- "modelCategorySelect": "zmjoSq_modelCategorySelect",
3987
- "discard": "zmjoSq_discard",
3988
- "linkButton": "zmjoSq_linkButton",
3989
- "chevron": "zmjoSq_chevron",
3990
- "channelMain": "zmjoSq_channelMain",
3991
- "detectOk": "zmjoSq_detectOk",
3992
- "field": "zmjoSq_field",
3993
- "editorHeader": "zmjoSq_editorHeader",
3994
- "pending": "zmjoSq_pending",
3995
- "save": "zmjoSq_save",
3996
- "channelHost": "zmjoSq_channelHost",
3997
- "editorFooter": "zmjoSq_editorFooter",
3998
- "sectionTitle": "zmjoSq_sectionTitle",
3999
4657
  "candidateHead": "zmjoSq_candidateHead",
4658
+ "candidateActions": "zmjoSq_candidateActions",
4000
4659
  "name": "zmjoSq_name",
4001
- "channelAdd": "zmjoSq_channelAdd",
4002
- "customSettingsSummary": "zmjoSq_customSettingsSummary",
4003
- "customSettingsBody": "zmjoSq_customSettingsBody",
4004
- "channelEmpty": "zmjoSq_channelEmpty"
4660
+ "channelMeta": "zmjoSq_channelMeta",
4661
+ "modelBadge": "zmjoSq_modelBadge",
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"
4005
4670
  };
4006
4671
  //#endregion
4007
4672
  //#region src/client/SettingsCard.tsx
@@ -4029,7 +4694,8 @@ window.__ModuleLoader__.load({
4029
4694
  booleanField("announceToAgent"),
4030
4695
  booleanField("allowAgentAudioGeneration"),
4031
4696
  textField("defaultModel"),
4032
- booleanField("autoSaveToLibrary")
4697
+ booleanField("autoSaveToLibrary"),
4698
+ textField("maxConcurrentGenerations")
4033
4699
  ]);
4034
4700
  this.channelsForm = new ChannelsForm(scope);
4035
4701
  }
@@ -4043,7 +4709,8 @@ window.__ModuleLoader__.load({
4043
4709
  announceToAgent: this.form.field("announceToAgent"),
4044
4710
  allowAgentAudioGeneration: this.form.field("allowAgentAudioGeneration"),
4045
4711
  defaultModel: this.form.field("defaultModel"),
4046
- autoSaveToLibrary: this.form.field("autoSaveToLibrary")
4712
+ autoSaveToLibrary: this.form.field("autoSaveToLibrary"),
4713
+ maxConcurrentGenerations: this.form.field("maxConcurrentGenerations")
4047
4714
  };
4048
4715
  }
4049
4716
  inject() {
@@ -4882,6 +5549,21 @@ window.__ModuleLoader__.load({
4882
5549
  ]
4883
5550
  })
4884
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
+ }),
4885
5567
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4886
5568
  className: settings_card_module_css_default.footer,
4887
5569
  children: [
@@ -4924,17 +5606,17 @@ window.__ModuleLoader__.load({
4924
5606
  document.head.appendChild(tag);
4925
5607
  }
4926
5608
  var audio_toolview_module_css_default = {
4927
- "header": "_7K1QKa_header",
4928
- "audios": "_7K1QKa_audios",
5609
+ "status": "_7K1QKa_status",
4929
5610
  "empty": "_7K1QKa_empty",
4930
- "message": "_7K1QKa_message",
5611
+ "audioRow": "_7K1QKa_audioRow",
4931
5612
  "audio": "_7K1QKa_audio",
4932
- "root": "_7K1QKa_root",
5613
+ "error": "_7K1QKa_error",
5614
+ "audios": "_7K1QKa_audios",
4933
5615
  "download": "_7K1QKa_download",
5616
+ "header": "_7K1QKa_header",
4934
5617
  "icon": "_7K1QKa_icon",
4935
- "status": "_7K1QKa_status",
4936
- "audioRow": "_7K1QKa_audioRow",
4937
- "error": "_7K1QKa_error"
5618
+ "message": "_7K1QKa_message",
5619
+ "root": "_7K1QKa_root"
4938
5620
  };
4939
5621
  //#endregion
4940
5622
  //#region src/client/audio-toolview.tsx