Skip to content

Commit 0875713

Browse files
authored
Merge pull request #9 from myshell-ai/support-input-video
feat: support input audio
2 parents 078b3f5 + bc62e8a commit 0875713

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed

web/shellagent.js

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { app } from "../../scripts/app.js";
22
import { api } from "../../scripts/api.js";
33

4+
var __defProp = Object.defineProperty;
5+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6+
47
app.registerExtension({
58
name: "Shellagent.extension",
69
async setup() {
@@ -173,6 +176,18 @@ app.registerExtension({
173176
}
174177
}
175178

179+
if (nodeData.name === "ShellAgentPluginInputAudio") {
180+
if (
181+
nodeData?.input?.required?.default_value?.[1]?.audio_upload === true
182+
) {
183+
nodeData.input.required.audioUI = ["AUDIO_UI"];
184+
nodeData.input.required.upload = [
185+
"SHELLAGENT_AUDIOUPLOAD",
186+
{ widget: "default_value" },
187+
];
188+
}
189+
}
190+
176191
if (nodeData.name === "ShellAgentPluginInputVideo") {
177192
addUploadWidget(nodeType, nodeData, "default_value");
178193
chainCallback(nodeType.prototype, "onNodeCreated", function () {
@@ -354,23 +369,81 @@ app.registerExtension({
354369

355370
afterConfigureGraph(missingNodeTypes, app) {
356371
function addIn(type, nodeId) {
372+
if(LiteGraph.slot_types_default_in[type] == null) {
373+
LiteGraph.slot_types_default_in[type] = []
374+
}
357375
if (LiteGraph.slot_types_default_in[type].indexOf(nodeId) === -1) {
358376
LiteGraph.slot_types_default_in[type].unshift(nodeId)
359377
}
360378
}
361379

362380
function addOut(type, nodeId) {
381+
if(LiteGraph.slot_types_default_out[type] == null) {
382+
LiteGraph.slot_types_default_out[type] = []
383+
}
363384
if (LiteGraph.slot_types_default_out[type].indexOf(nodeId) === -1) {
364385
LiteGraph.slot_types_default_out[type].unshift(nodeId)
365386
}
366387
}
367388

368389
addIn('IMAGE', 'ShellAgentPluginInputImage')
390+
addIn('AUDIO', 'ShellAgentPluginInputAudio')
369391
addOut('IMAGE', 'ShellAgentPluginSaveImage')
370392
addOut('IMAGE', 'ShellAgentPluginSaveImages')
393+
addOut('AUDIO', 'ShellAgentPluginSaveAudios')
394+
addOut('AUDIO', 'ShellAgentPluginSaveAudio')
371395
addOut('STRING', 'ShellAgentPluginOutputInteger')
372396
addOut('STRING', 'ShellAgentPluginOutputFloat')
373397
addOut('STRING', 'ShellAgentPluginOutputText')
398+
},
399+
getCustomWidgets() {
400+
return {
401+
SHELLAGENT_AUDIOUPLOAD(node, inputName) {
402+
const audioWidget = node.widgets.find(
403+
(w) => w.name === "default_value"
404+
);
405+
const audioUIWidget = node.widgets.find(
406+
(w) => w.name === "audioUI"
407+
);
408+
const onAudioWidgetUpdate = /* @__PURE__ */ __name(() => {
409+
audioUIWidget.element.src = api.apiURL(
410+
getResourceURL(...splitFilePath(audioWidget.value))
411+
);
412+
}, "onAudioWidgetUpdate");
413+
if (audioWidget.value) {
414+
onAudioWidgetUpdate();
415+
}
416+
audioWidget.callback = onAudioWidgetUpdate;
417+
const onGraphConfigured = node.onGraphConfigured;
418+
node.onGraphConfigured = function() {
419+
onGraphConfigured?.apply(this, arguments);
420+
if (audioWidget.value) {
421+
onAudioWidgetUpdate();
422+
}
423+
};
424+
const fileInput = document.createElement("input");
425+
fileInput.type = "file";
426+
fileInput.accept = "audio/*";
427+
fileInput.style.display = "none";
428+
fileInput.onchange = () => {
429+
if (fileInput.files.length) {
430+
uploadFileAudio(audioWidget, audioUIWidget, fileInput.files[0], true);
431+
}
432+
};
433+
const uploadWidget = node.addWidget(
434+
"button",
435+
inputName,
436+
/* value=*/
437+
"",
438+
() => {
439+
fileInput.click();
440+
},
441+
{ serialize: false }
442+
);
443+
uploadWidget.label = "choose file to upload";
444+
return { widget: uploadWidget };
445+
}
446+
};
374447
}
375448
});
376449

@@ -744,4 +817,55 @@ function addLoadVideoCommon(nodeType, nodeData) {
744817
}
745818
});
746819
});
820+
}
821+
822+
function getResourceURL(subfolder, filename, type = "input") {
823+
const params = [
824+
"filename=" + encodeURIComponent(filename),
825+
"type=" + type,
826+
"subfolder=" + subfolder,
827+
app.getRandParam().substring(1)
828+
].join("&");
829+
return `/view?${params}`;
830+
}
831+
832+
function splitFilePath(path) {
833+
const folder_separator = path.lastIndexOf("/");
834+
if (folder_separator === -1) {
835+
return ["", path];
836+
}
837+
return [
838+
path.substring(0, folder_separator),
839+
path.substring(folder_separator + 1)
840+
];
841+
}
842+
843+
async function uploadFileAudio(audioWidget, audioUIWidget, file2, updateNode, pasted = false) {
844+
try {
845+
const body = new FormData();
846+
body.append("image", file2);
847+
if (pasted) body.append("subfolder", "pasted");
848+
const resp = await api.fetchApi("/upload/image", {
849+
method: "POST",
850+
body
851+
});
852+
if (resp.status === 200) {
853+
const data = await resp.json();
854+
let path = data.name;
855+
if (data.subfolder) path = data.subfolder + "/" + path;
856+
if (!audioWidget.options.values.includes(path)) {
857+
audioWidget.options.values.push(path);
858+
}
859+
if (updateNode) {
860+
audioUIWidget.element.src = api.apiURL(
861+
getResourceURL(...splitFilePath(path))
862+
);
863+
audioWidget.value = path;
864+
}
865+
} else {
866+
window.alert(resp.status + " - " + resp.statusText);
867+
}
868+
} catch (error) {
869+
window.alert(error);
870+
}
747871
}

0 commit comments

Comments
 (0)