Add Grok and VEO video workflow support

This commit is contained in:
o1key
2026-06-04 16:06:23 +08:00
parent 5d9aff9ca7
commit 30e9603f77
24 changed files with 3752 additions and 528 deletions
+10 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}