- 新增启动弹窗通知(绿色主题,支持关闭) - 新增 StreamPreview 流式文本预览节点 - 新增 fileUpload、updateNotifier 前端 JS 模块 - 重构多个 client,统一错误处理 - 删除废弃节点 batch_nano_banana_v2、quan_neng_sheng_tu 等 - 将 .config 纳入版本控制(已清空密钥)
123 lines
5.0 KiB
JavaScript
123 lines
5.0 KiB
JavaScript
import { app } from "../../../scripts/app.js";
|
|
import { api } from "../../../scripts/api.js";
|
|
|
|
// 上传单个文件到 ComfyUI input 目录,返回服务端绝对路径
|
|
async function uploadFile(file) {
|
|
const formData = new FormData();
|
|
formData.append("image", file, file.name);
|
|
const resp = await api.fetchApi("/upload/image", { method: "POST", body: formData });
|
|
if (!resp.ok) throw new Error(`上传失败: ${file.name}`);
|
|
const data = await resp.json();
|
|
const inputDir = await getInputDir();
|
|
// 拼成绝对路径(Windows 用反斜杠也可以,用正斜杠 Python 也认)
|
|
return inputDir ? inputDir.replace(/\\/g, "/") + "/" + data.name : data.name;
|
|
}
|
|
|
|
// 获取 ComfyUI input 目录绝对路径(缓存)
|
|
let _inputDir = null;
|
|
async function getInputDir() {
|
|
if (_inputDir !== null) return _inputDir;
|
|
try {
|
|
const resp = await api.fetchApi("/o1key/input_dir");
|
|
if (resp.ok) _inputDir = (await resp.json()).path;
|
|
else _inputDir = "";
|
|
} catch { _inputDir = ""; }
|
|
return _inputDir;
|
|
}
|
|
|
|
// 创建一个"选择文件"按钮,点击后弹出文件选择框
|
|
// onPaths(paths: string[]) 回调拿到上传后的路径列表
|
|
function makeUploadButton(label, accept, multiple, onPaths) {
|
|
const btn = document.createElement("button");
|
|
btn.textContent = label;
|
|
btn.style.cssText =
|
|
"width:100%;padding:4px 8px;cursor:pointer;margin-top:2px;" +
|
|
"background:#3a5a3a;color:#ddd;border:1px solid #666;" +
|
|
"border-radius:4px;font-size:12px;";
|
|
|
|
const fileInput = document.createElement("input");
|
|
fileInput.type = "file";
|
|
fileInput.multiple = multiple;
|
|
fileInput.accept = accept;
|
|
fileInput.style.display = "none";
|
|
document.body.appendChild(fileInput);
|
|
|
|
btn.addEventListener("click", () => fileInput.click());
|
|
|
|
fileInput.addEventListener("change", async () => {
|
|
const files = Array.from(fileInput.files);
|
|
if (!files.length) return;
|
|
btn.textContent = "⏳ 上传中...";
|
|
btn.disabled = true;
|
|
try {
|
|
const paths = [];
|
|
for (const f of files) paths.push(await uploadFile(f));
|
|
onPaths(paths);
|
|
btn.textContent = `✅ 已上传 ${files.length} 个`;
|
|
setTimeout(() => { btn.textContent = label; }, 2000);
|
|
} catch (e) {
|
|
console.error("[o1key fileUpload]", e);
|
|
btn.textContent = "❌ 上传失败";
|
|
setTimeout(() => { btn.textContent = label; }, 2000);
|
|
} finally {
|
|
btn.disabled = false;
|
|
fileInput.value = "";
|
|
}
|
|
});
|
|
|
|
return btn;
|
|
}
|
|
|
|
const ACCEPT = ".pdf,.txt,.md,.csv,.json,.py,.js,.ts,.html,.xml,.docx,.xlsx,.pptx,.zip,.wav,.mp3,.png,.jpg,.jpeg,.webp";
|
|
|
|
app.registerExtension({
|
|
name: "o1key.fileUpload",
|
|
|
|
async beforeRegisterNodeDef(nodeType, nodeData) {
|
|
if (nodeData.name !== "LoadFile") return;
|
|
|
|
const origCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
origCreated?.call(this);
|
|
|
|
const singleWidget = this.widgets?.find(w => w.name === "单文件路径");
|
|
const folderWidget = this.widgets?.find(w => w.name === "文件夹路径");
|
|
|
|
// "单文件路径"下方加按钮(支持多选,追加路径)
|
|
if (singleWidget) {
|
|
const btn = makeUploadButton("📂 选择文件(可多选)", ACCEPT, true, (paths) => {
|
|
const existing = singleWidget.value?.trim();
|
|
singleWidget.value = existing
|
|
? existing + ", " + paths.join(", ")
|
|
: paths.join(", ");
|
|
singleWidget.callback?.(singleWidget.value);
|
|
app.graph.setDirtyCanvas(true);
|
|
});
|
|
this.addDOMWidget("upload_single_btn", "btn", btn, {
|
|
getValue() { return null; },
|
|
setValue() {},
|
|
});
|
|
}
|
|
|
|
// 清空按钮:同时清空单文件路径和文件夹路径
|
|
if (singleWidget || folderWidget) {
|
|
const clearBtn = document.createElement("button");
|
|
clearBtn.textContent = "🗑 清空文件路径";
|
|
clearBtn.style.cssText =
|
|
"width:100%;padding:4px 8px;cursor:pointer;margin-top:2px;" +
|
|
"background:#5a3a3a;color:#ddd;border:1px solid #666;" +
|
|
"border-radius:4px;font-size:12px;";
|
|
clearBtn.addEventListener("click", () => {
|
|
if (singleWidget) { singleWidget.value = ""; singleWidget.callback?.(""); }
|
|
if (folderWidget) { folderWidget.value = ""; folderWidget.callback?.(""); }
|
|
app.graph.setDirtyCanvas(true);
|
|
});
|
|
this.addDOMWidget("clear_paths_btn", "btn", clearBtn, {
|
|
getValue() { return null; },
|
|
setValue() {},
|
|
});
|
|
}
|
|
};
|
|
},
|
|
});
|