Add Grok and VEO video workflow support
This commit is contained in:
+10
-4
@@ -4,10 +4,16 @@ app.registerExtension({
|
||||
name: "o1key.hideSidebarItems",
|
||||
async setup() {
|
||||
const hide = () => {
|
||||
// 隐藏侧边栏的"说明"、"应用"、"模型"、"节点"按钮
|
||||
const hiddenLabels = ["说明", "帮助", "Help", "应用", "Apps", "模型", "Models", "节点", "Nodes"];
|
||||
// 隐藏侧边栏的"说明"、"应用"、"模型"、"节点"、"模板"按钮
|
||||
const hiddenLabels = ["说明", "帮助", "help", "应用", "apps", "模型", "models", "节点", "nodes", "模板", "templates", "template"];
|
||||
document.querySelectorAll(".side-bar-button, [class*='sidebar'] button, .p-togglebutton").forEach(btn => {
|
||||
const label = btn.getAttribute("aria-label") || btn.textContent || "";
|
||||
const label = [
|
||||
btn.getAttribute("aria-label"),
|
||||
btn.getAttribute("title"),
|
||||
btn.getAttribute("data-title"),
|
||||
btn.getAttribute("data-label"),
|
||||
btn.textContent,
|
||||
].filter(Boolean).join(" ").toLowerCase();
|
||||
if (hiddenLabels.some(k => label.includes(k))) {
|
||||
btn.style.display = "none";
|
||||
}
|
||||
@@ -212,4 +218,4 @@ app.registerExtension({
|
||||
setTimeout(hide, 1000);
|
||||
setTimeout(hide, 3000);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
+78
-12
@@ -1,7 +1,9 @@
|
||||
import { app } from "../../../scripts/app.js";
|
||||
import { api } from "../../../scripts/api.js";
|
||||
|
||||
const STORAGE_KEY = "o1key-notes";
|
||||
const SEEDED_KEY = "o1key-notes-seeded-v2";
|
||||
const NOTES_API = "/o1key/notes";
|
||||
const STYLE_ID = "o1key-notes-styles";
|
||||
|
||||
let notes = [];
|
||||
@@ -207,27 +209,91 @@ function injectStyles() {
|
||||
document.head.appendChild(el);
|
||||
}
|
||||
|
||||
function loadNotes() {
|
||||
function readCachedNotes() {
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
notes = raw ? JSON.parse(raw).map(makeNote) : [];
|
||||
if (raw === null) return { found: false, notes: [] };
|
||||
const parsed = JSON.parse(raw);
|
||||
return { found: true, notes: Array.isArray(parsed) ? parsed.map(makeNote) : [] };
|
||||
} catch {
|
||||
notes = [];
|
||||
return { found: false, notes: [] };
|
||||
}
|
||||
}
|
||||
|
||||
function writeCachedNotes() {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(notes));
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function hasSeededNotes() {
|
||||
try {
|
||||
return !!localStorage.getItem(SEEDED_KEY);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function markSeededNotes() {
|
||||
try {
|
||||
localStorage.setItem(SEEDED_KEY, "1");
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function createSeedNotes() {
|
||||
return SAMPLE_NOTES.map(makeNote);
|
||||
}
|
||||
|
||||
async function loadNotes() {
|
||||
const cached = readCachedNotes();
|
||||
|
||||
try {
|
||||
const resp = await api.fetchApi(NOTES_API);
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
||||
const data = await resp.json();
|
||||
|
||||
if (data.exists) {
|
||||
notes = Array.isArray(data.notes) ? data.notes.map(makeNote) : [];
|
||||
writeCachedNotes();
|
||||
return;
|
||||
}
|
||||
|
||||
notes = cached.found ? cached.notes : createSeedNotes();
|
||||
markSeededNotes();
|
||||
writeCachedNotes();
|
||||
await persistNotesToFile();
|
||||
return;
|
||||
} catch (e) {
|
||||
console.warn("[o1key notes] file storage unavailable, using localStorage", e);
|
||||
}
|
||||
|
||||
if (!localStorage.getItem(SEEDED_KEY)) {
|
||||
const existingTitles = new Set(notes.map(n => n.title));
|
||||
const samples = SAMPLE_NOTES.map(makeNote).filter(n => !existingTitles.has(n.title));
|
||||
notes = [...samples, ...notes];
|
||||
localStorage.setItem(SEEDED_KEY, "1");
|
||||
saveNotes();
|
||||
notes = cached.found ? cached.notes : [];
|
||||
if (!cached.found && !hasSeededNotes()) {
|
||||
notes = createSeedNotes();
|
||||
markSeededNotes();
|
||||
writeCachedNotes();
|
||||
}
|
||||
}
|
||||
|
||||
function saveNotes() {
|
||||
writeCachedNotes();
|
||||
void persistNotesToFile();
|
||||
}
|
||||
|
||||
async function persistNotesToFile() {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(notes));
|
||||
} catch {}
|
||||
const resp = await api.fetchApi(NOTES_API, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ notes }),
|
||||
});
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.warn("[o1key notes] failed to save notes file", e);
|
||||
setPanelStatus("笔记文件保存失败,已保存在浏览器缓存");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function allTags() {
|
||||
@@ -250,7 +316,7 @@ function filteredNotes() {
|
||||
app.registerExtension({
|
||||
name: "o1key.notePanel",
|
||||
async setup() {
|
||||
loadNotes();
|
||||
await loadNotes();
|
||||
app.extensionManager.registerSidebarTab({
|
||||
id: "o1key-notes",
|
||||
title: "笔记",
|
||||
|
||||
+60
-5
@@ -43,6 +43,7 @@ app.registerExtension({
|
||||
if (!confirm("确定要重启 ComfyUI 吗?")) return;
|
||||
btn.style.opacity = "0.5";
|
||||
btn.style.pointerEvents = "none";
|
||||
await disableExperimentalAssetApi();
|
||||
try { await fetch("/o1key/restart", { method: "POST" }); } catch {}
|
||||
pollUntilReady();
|
||||
});
|
||||
@@ -51,16 +52,70 @@ app.registerExtension({
|
||||
injected = true;
|
||||
}
|
||||
|
||||
async function disableExperimentalAssetApi() {
|
||||
if (!(await shouldDisableExperimentalAssetApi())) return;
|
||||
try {
|
||||
await fetch("/api/settings/Comfy.Assets.UseAssetAPI", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(false),
|
||||
signal: AbortSignal.timeout(2000),
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function shouldDisableExperimentalAssetApi() {
|
||||
try {
|
||||
const r = await fetch("/api/settings/Comfy.Assets.UseAssetAPI", {
|
||||
cache: "no-store",
|
||||
signal: AbortSignal.timeout(2000),
|
||||
});
|
||||
if (!r.ok || !(await r.json())) return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
return !(await fetchOk("/api/assets/seed/status", 2000));
|
||||
}
|
||||
|
||||
async function fetchOk(url, timeout = 2500) {
|
||||
try {
|
||||
const r = await fetch(url, {
|
||||
cache: "no-store",
|
||||
signal: AbortSignal.timeout(timeout),
|
||||
});
|
||||
return r.ok;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function comfyReady() {
|
||||
const [statsOk, modelFoldersOk] = await Promise.all([
|
||||
fetchOk("/api/system_stats"),
|
||||
fetchOk("/api/experiment/models"),
|
||||
]);
|
||||
return statsOk && modelFoldersOk;
|
||||
}
|
||||
|
||||
function pollUntilReady() {
|
||||
let attempts = 0;
|
||||
const maxAttempts = 40;
|
||||
const maxAttempts = 80;
|
||||
const minRestartWaitMs = 5000;
|
||||
const startedAt = Date.now();
|
||||
let sawUnavailable = false;
|
||||
const interval = setInterval(async () => {
|
||||
attempts++;
|
||||
if (attempts > maxAttempts) { clearInterval(interval); forceReload(); return; }
|
||||
try {
|
||||
const r = await fetch("/api/system_stats", { signal: AbortSignal.timeout(2000) });
|
||||
if (r.ok) { clearInterval(interval); forceReload(); }
|
||||
} catch {}
|
||||
const ready = await comfyReady();
|
||||
if (!ready) {
|
||||
sawUnavailable = true;
|
||||
return;
|
||||
}
|
||||
if (!sawUnavailable && Date.now() - startedAt < minRestartWaitMs) return;
|
||||
|
||||
clearInterval(interval);
|
||||
await disableExperimentalAssetApi();
|
||||
setTimeout(forceReload, 800);
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user