mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-01-27 14:50:20 +08:00
Merge branch 'master' of github.com:comfyanonymous/ComfyUI
This commit is contained in:
commit
519cddcefc
@ -142,10 +142,6 @@ def get_total_memory(dev=None, torch_total_too=False):
|
|||||||
total_vram = get_total_memory(get_torch_device()) / (1024 * 1024)
|
total_vram = get_total_memory(get_torch_device()) / (1024 * 1024)
|
||||||
total_ram = psutil.virtual_memory().total / (1024 * 1024)
|
total_ram = psutil.virtual_memory().total / (1024 * 1024)
|
||||||
logging.info("Total VRAM {:0.0f} MB, total RAM {:0.0f} MB".format(total_vram, total_ram))
|
logging.info("Total VRAM {:0.0f} MB, total RAM {:0.0f} MB".format(total_vram, total_ram))
|
||||||
if not args.normalvram and not args.cpu:
|
|
||||||
if lowvram_available and total_vram <= 4096:
|
|
||||||
logging.warning("Trying to enable lowvram mode because your GPU seems to have 4GB or less. If you don't want this use: --normalvram")
|
|
||||||
set_vram_to = VRAMState.LOW_VRAM
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
OOM_EXCEPTION = torch.cuda.OutOfMemoryError
|
OOM_EXCEPTION = torch.cuda.OutOfMemoryError
|
||||||
@ -484,9 +480,8 @@ def load_models_gpu(models, memory_required=0, force_patch_weights=False):
|
|||||||
model_size = loaded_model.model_memory_required(torch_dev)
|
model_size = loaded_model.model_memory_required(torch_dev)
|
||||||
current_free_mem = get_free_memory(torch_dev)
|
current_free_mem = get_free_memory(torch_dev)
|
||||||
lowvram_model_memory = int(max(64 * (1024 * 1024), (current_free_mem - 1024 * (1024 * 1024)) / 1.3))
|
lowvram_model_memory = int(max(64 * (1024 * 1024), (current_free_mem - 1024 * (1024 * 1024)) / 1.3))
|
||||||
if model_size > (current_free_mem - inference_memory): # only switch to lowvram if really necessary
|
if model_size <= (current_free_mem - inference_memory): # only switch to lowvram if really necessary
|
||||||
vram_set_state = VRAMState.LOW_VRAM
|
|
||||||
else:
|
|
||||||
lowvram_model_memory = 0
|
lowvram_model_memory = 0
|
||||||
|
|
||||||
if vram_set_state == VRAMState.NO_VRAM:
|
if vram_set_state == VRAMState.NO_VRAM:
|
||||||
|
|||||||
126
comfy/web/extensions/core/webcamCapture.js
Normal file
126
comfy/web/extensions/core/webcamCapture.js
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import { app } from "../../scripts/app.js";
|
||||||
|
import { api } from "../../scripts/api.js";
|
||||||
|
|
||||||
|
const WEBCAM_READY = Symbol();
|
||||||
|
|
||||||
|
app.registerExtension({
|
||||||
|
name: "Comfy.WebcamCapture",
|
||||||
|
getCustomWidgets(app) {
|
||||||
|
return {
|
||||||
|
WEBCAM(node, inputName) {
|
||||||
|
let res;
|
||||||
|
node[WEBCAM_READY] = new Promise((resolve) => (res = resolve));
|
||||||
|
|
||||||
|
const container = document.createElement("div");
|
||||||
|
container.style.background = "rgba(0,0,0,0.25)";
|
||||||
|
container.style.textAlign = "center";
|
||||||
|
|
||||||
|
const video = document.createElement("video");
|
||||||
|
video.style.height = video.style.width = "100%";
|
||||||
|
|
||||||
|
const loadVideo = async () => {
|
||||||
|
try {
|
||||||
|
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false });
|
||||||
|
container.replaceChildren(video);
|
||||||
|
|
||||||
|
setTimeout(() => res(video), 500); // Fallback as loadedmetadata doesnt fire sometimes?
|
||||||
|
video.addEventListener("loadedmetadata", () => res(video), false);
|
||||||
|
video.srcObject = stream;
|
||||||
|
video.play();
|
||||||
|
} catch (error) {
|
||||||
|
const label = document.createElement("div");
|
||||||
|
label.style.color = "red";
|
||||||
|
label.style.overflow = "auto";
|
||||||
|
label.style.maxHeight = "100%";
|
||||||
|
label.style.whiteSpace = "pre-wrap";
|
||||||
|
|
||||||
|
if (window.isSecureContext) {
|
||||||
|
label.textContent = "Unable to load webcam, please ensure access is granted:\n" + error.message;
|
||||||
|
} else {
|
||||||
|
label.textContent = "Unable to load webcam. A secure context is required, if you are not accessing ComfyUI on localhost (127.0.0.1) you will have to enable TLS (https)\n\n" + error.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
container.replaceChildren(label);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadVideo();
|
||||||
|
|
||||||
|
return { widget: node.addDOMWidget(inputName, "WEBCAM", container) };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
nodeCreated(node) {
|
||||||
|
if ((node.type, node.constructor.comfyClass !== "WebcamCapture")) return;
|
||||||
|
|
||||||
|
let video;
|
||||||
|
const camera = node.widgets.find((w) => w.name === "image");
|
||||||
|
const w = node.widgets.find((w) => w.name === "width");
|
||||||
|
const h = node.widgets.find((w) => w.name === "height");
|
||||||
|
const captureOnQueue = node.widgets.find((w) => w.name === "capture_on_queue");
|
||||||
|
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
|
||||||
|
const capture = () => {
|
||||||
|
canvas.width = w.value;
|
||||||
|
canvas.height = h.value;
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
ctx.drawImage(video, 0, 0, w.value, h.value);
|
||||||
|
const data = canvas.toDataURL("image/png");
|
||||||
|
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
node.imgs = [img];
|
||||||
|
app.graph.setDirtyCanvas(true);
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
node.setSizeForImage?.();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
img.src = data;
|
||||||
|
};
|
||||||
|
|
||||||
|
const btn = node.addWidget("button", "waiting for camera...", "capture", capture);
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.serializeValue = () => undefined;
|
||||||
|
|
||||||
|
camera.serializeValue = async () => {
|
||||||
|
if (captureOnQueue.value) {
|
||||||
|
capture();
|
||||||
|
} else if (!node.imgs?.length) {
|
||||||
|
const err = `No webcam image captured`;
|
||||||
|
alert(err);
|
||||||
|
throw new Error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload image to temp storage
|
||||||
|
const blob = await new Promise((r) => canvas.toBlob(r));
|
||||||
|
const name = `${+new Date()}.png`;
|
||||||
|
const file = new File([blob], name);
|
||||||
|
const body = new FormData();
|
||||||
|
body.append("image", file);
|
||||||
|
body.append("subfolder", "webcam");
|
||||||
|
body.append("type", "temp");
|
||||||
|
const resp = await api.fetchApi("/upload/image", {
|
||||||
|
method: "POST",
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
if (resp.status !== 200) {
|
||||||
|
const err = `Error uploading camera image: ${resp.status} - ${resp.statusText}`;
|
||||||
|
alert(err);
|
||||||
|
throw new Error(err);
|
||||||
|
}
|
||||||
|
return `webcam/${name} [temp]`;
|
||||||
|
};
|
||||||
|
|
||||||
|
node[WEBCAM_READY].then((v) => {
|
||||||
|
video = v;
|
||||||
|
// If width isnt specified then use video output resolution
|
||||||
|
if (!w.value) {
|
||||||
|
w.value = video.videoWidth || 640;
|
||||||
|
h.value = video.videoHeight || 480;
|
||||||
|
}
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.label = "capture";
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
33
comfy_extras/nodes/nodes_webcam.py
Normal file
33
comfy_extras/nodes/nodes_webcam.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
from comfy.cmd import folder_paths
|
||||||
|
from comfy.nodes.base_nodes import LoadImage
|
||||||
|
from comfy.nodes.common import MAX_RESOLUTION
|
||||||
|
|
||||||
|
|
||||||
|
class WebcamCapture(LoadImage):
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"image": ("WEBCAM", {}),
|
||||||
|
"width": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 1}),
|
||||||
|
"height": ("INT", {"default": 0, "min": 0, "max": MAX_RESOLUTION, "step": 1}),
|
||||||
|
"capture_on_queue": ("BOOLEAN", {"default": True}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("IMAGE",)
|
||||||
|
FUNCTION = "load_capture"
|
||||||
|
|
||||||
|
CATEGORY = "image"
|
||||||
|
|
||||||
|
def load_capture(s, image, **kwargs):
|
||||||
|
return super().load_image(folder_paths.get_annotated_filepath(image))
|
||||||
|
|
||||||
|
|
||||||
|
NODE_CLASS_MAPPINGS = {
|
||||||
|
"WebcamCapture": WebcamCapture,
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
|
"WebcamCapture": "Webcam Capture",
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user