Merge pull request #69 from crystian/dev
some fixes: utf-8 from nvidia driver is supported comfyui files added read metadata from webp
This commit is contained in:
@@ -38,3 +38,23 @@ print(f"> File2 {file2}")
|
||||
with open(file2, "w") as f2:
|
||||
f2.writelines([f"version = \"{version}\"\n"])
|
||||
|
||||
|
||||
# modify pyproject.toml file with @version
|
||||
file3 = os.path.join(os.path.dirname(__file__), "../pyproject.toml")
|
||||
print(f"> File3: {file3}")
|
||||
|
||||
file3VersionFound = False
|
||||
# lines = None
|
||||
with open(file3, "r") as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
|
||||
if "version = " in line:
|
||||
file3VersionFound = True
|
||||
lines[lines.index(line)] = f"version = \"{version}\"\n"
|
||||
|
||||
if not file3VersionFound:
|
||||
raise RuntimeError(f"Version label not found in file: {file3}")
|
||||
|
||||
with open(file3, "w") as f3:
|
||||
f3.writelines(lines)
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
@author: Crystian
|
||||
@title: Crystools
|
||||
@nickname: Crystools
|
||||
@version: 1.12.0
|
||||
@version: 1.13.0
|
||||
@project: "https://github.com/crystian/ComfyUI-Crystools",
|
||||
@description: Plugins for multiples uses, mainly for debugging, you need them! IG: https://www.instagram.com/crystian.ia
|
||||
"""
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
version = "1.12.0"
|
||||
version = "1.13.0"
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
+150
-143
@@ -1,162 +1,169 @@
|
||||
import torch
|
||||
import pynvml
|
||||
import comfy.model_management
|
||||
|
||||
from ..core import logger
|
||||
|
||||
|
||||
class CGPUInfo:
|
||||
"""
|
||||
This class is responsible for getting information from GPU (ONLY).
|
||||
"""
|
||||
cuda = False
|
||||
pynvmlLoaded = False
|
||||
cudaAvailable = False
|
||||
torchDevice = 'cpu'
|
||||
cudaDevice = 'cpu'
|
||||
cudaDevicesFound = 0
|
||||
switchGPU = True
|
||||
switchVRAM = True
|
||||
switchTemperature = True
|
||||
gpus = []
|
||||
gpusUtilization = []
|
||||
gpusVRAM = []
|
||||
gpusTemperature = []
|
||||
|
||||
def __init__(self):
|
||||
try:
|
||||
pynvml.nvmlInit()
|
||||
self.pynvmlLoaded = True
|
||||
except Exception as e:
|
||||
self.pynvmlLoaded = False
|
||||
logger.error('Could not init pynvml.' + str(e))
|
||||
|
||||
if self.pynvmlLoaded and pynvml.nvmlDeviceGetCount() > 0:
|
||||
self.cudaDevicesFound = pynvml.nvmlDeviceGetCount()
|
||||
|
||||
logger.info(f"GPU/s:")
|
||||
|
||||
# for simulate multiple GPUs (for testing) interchange these comments:
|
||||
# for deviceIndex in range(3):
|
||||
# deviceHandle = pynvml.nvmlDeviceGetHandleByIndex(0)
|
||||
for deviceIndex in range(self.cudaDevicesFound):
|
||||
deviceHandle = pynvml.nvmlDeviceGetHandleByIndex(deviceIndex)
|
||||
|
||||
gpuName = pynvml.nvmlDeviceGetName(deviceHandle)
|
||||
|
||||
logger.info(f"{deviceIndex}) {gpuName}")
|
||||
|
||||
self.gpus.append({
|
||||
'index': deviceIndex,
|
||||
'name': gpuName,
|
||||
})
|
||||
|
||||
# same index as gpus, with default values
|
||||
self.gpusUtilization.append(True)
|
||||
self.gpusVRAM.append(True)
|
||||
self.gpusTemperature.append(True)
|
||||
|
||||
self.cuda = True
|
||||
logger.info(f'NVIDIA Driver: {pynvml.nvmlSystemGetDriverVersion()}')
|
||||
else:
|
||||
logger.warn('No GPU with CUDA detected.')
|
||||
|
||||
try:
|
||||
self.torchDevice = comfy.model_management.get_torch_device_name(comfy.model_management.get_torch_device())
|
||||
except Exception as e:
|
||||
logger.error('Could not pick default device.' + str(e))
|
||||
|
||||
self.cudaDevice = 'cpu' if self.torchDevice == 'cpu' else 'cuda'
|
||||
self.cudaAvailable = torch.cuda.is_available()
|
||||
|
||||
if self.cuda and self.cudaAvailable and self.torchDevice == 'cpu':
|
||||
logger.warn('CUDA is available, but torch is using CPU.')
|
||||
|
||||
def getInfo(self):
|
||||
logger.debug('Getting GPUs info...')
|
||||
return self.gpus
|
||||
|
||||
def getStatus(self):
|
||||
# logger.debug('CGPUInfo getStatus')
|
||||
gpuUtilization = -1
|
||||
gpuTemperature = -1
|
||||
vramUsed = -1
|
||||
vramTotal = -1
|
||||
vramPercent = -1
|
||||
|
||||
gpuType = ''
|
||||
"""
|
||||
This class is responsible for getting information from GPU (ONLY).
|
||||
"""
|
||||
cuda = False
|
||||
pynvmlLoaded = False
|
||||
cudaAvailable = False
|
||||
torchDevice = 'cpu'
|
||||
cudaDevice = 'cpu'
|
||||
cudaDevicesFound = 0
|
||||
switchGPU = True
|
||||
switchVRAM = True
|
||||
switchTemperature = True
|
||||
gpus = []
|
||||
gpusUtilization = []
|
||||
gpusVRAM = []
|
||||
gpusTemperature = []
|
||||
|
||||
if self.cudaDevice == 'cpu':
|
||||
gpuType = 'cpu'
|
||||
gpus.append({
|
||||
'gpu_utilization': 0,
|
||||
'gpu_temperature': 0,
|
||||
'vram_total': 0,
|
||||
'vram_used': 0,
|
||||
'vram_used_percent': 0,
|
||||
})
|
||||
else:
|
||||
gpuType = self.cudaDevice
|
||||
def __init__(self):
|
||||
try:
|
||||
pynvml.nvmlInit()
|
||||
self.pynvmlLoaded = True
|
||||
except Exception as e:
|
||||
self.pynvmlLoaded = False
|
||||
logger.error('Could not init pynvml.' + str(e))
|
||||
|
||||
if self.pynvmlLoaded and self.cuda and self.cudaAvailable:
|
||||
if self.pynvmlLoaded and pynvml.nvmlDeviceGetCount() > 0:
|
||||
self.cudaDevicesFound = pynvml.nvmlDeviceGetCount()
|
||||
|
||||
# for simulate multiple GPUs (for testing) interchange these comments:
|
||||
# for deviceIndex in range(3):
|
||||
# deviceHandle = pynvml.nvmlDeviceGetHandleByIndex(0)
|
||||
for deviceIndex in range(self.cudaDevicesFound):
|
||||
deviceHandle = pynvml.nvmlDeviceGetHandleByIndex(deviceIndex)
|
||||
logger.info(f"GPU/s:")
|
||||
|
||||
gpuUtilization = 0
|
||||
vramPercent = 0
|
||||
vramUsed = 0
|
||||
vramTotal = 0
|
||||
gpuTemperature = 0
|
||||
# for simulate multiple GPUs (for testing) interchange these comments:
|
||||
# for deviceIndex in range(3):
|
||||
# deviceHandle = pynvml.nvmlDeviceGetHandleByIndex(0)
|
||||
for deviceIndex in range(self.cudaDevicesFound):
|
||||
deviceHandle = pynvml.nvmlDeviceGetHandleByIndex(deviceIndex)
|
||||
gpuName = 'Unknown GPU'
|
||||
|
||||
# GPU Utilization
|
||||
if self.switchGPU and self.gpusUtilization[deviceIndex]:
|
||||
try:
|
||||
utilization = pynvml.nvmlDeviceGetUtilizationRates(deviceHandle)
|
||||
gpuUtilization = utilization.gpu
|
||||
except Exception as e:
|
||||
if str(e) == "Unknown Error":
|
||||
logger.error('For some reason, pynvml is not working in a laptop with only battery, try to connect and turn on the monitor')
|
||||
else:
|
||||
logger.error('Could not get GPU utilization.' + str(e))
|
||||
try:
|
||||
gpuName = pynvml.nvmlDeviceGetName(deviceHandle)
|
||||
try:
|
||||
gpuName = gpuName.decode('utf-8', errors='ignore')
|
||||
except AttributeError as e:
|
||||
pass
|
||||
|
||||
logger.error('Monitor of GPU is turning off (not on UI!)')
|
||||
self.switchGPU = False
|
||||
except UnicodeDecodeError as e:
|
||||
gpuName = 'Unknown GPU (decoding error)'
|
||||
print(f"UnicodeDecodeError: {e}")
|
||||
|
||||
# VRAM
|
||||
if self.switchVRAM and self.gpusVRAM[deviceIndex]:
|
||||
# Torch or pynvml?, pynvml is more accurate with the system, torch is more accurate with comfyUI
|
||||
memory = pynvml.nvmlDeviceGetMemoryInfo(deviceHandle)
|
||||
vramUsed = memory.used
|
||||
vramTotal = memory.total
|
||||
logger.info(f"{deviceIndex}) {gpuName}")
|
||||
|
||||
# device = torch.device(gpuType)
|
||||
# vramUsed = torch.cuda.memory_allocated(device)
|
||||
# vramTotal = torch.cuda.get_device_properties(device).total_memory
|
||||
self.gpus.append({
|
||||
'index': deviceIndex,
|
||||
'name': gpuName,
|
||||
})
|
||||
|
||||
vramPercent = vramUsed / vramTotal * 100
|
||||
# same index as gpus, with default values
|
||||
self.gpusUtilization.append(True)
|
||||
self.gpusVRAM.append(True)
|
||||
self.gpusTemperature.append(True)
|
||||
|
||||
# Temperature
|
||||
if self.switchTemperature and self.gpusTemperature[deviceIndex]:
|
||||
try:
|
||||
gpuTemperature = pynvml.nvmlDeviceGetTemperature(deviceHandle, 0)
|
||||
except Exception as e:
|
||||
logger.error('Could not get GPU temperature. Turning off this feature. ' + str(e))
|
||||
self.switchTemperature = False
|
||||
self.cuda = True
|
||||
logger.info(f'NVIDIA Driver: {pynvml.nvmlSystemGetDriverVersion()}')
|
||||
else:
|
||||
logger.warn('No GPU with CUDA detected.')
|
||||
|
||||
gpus.append({
|
||||
'gpu_utilization': gpuUtilization,
|
||||
'gpu_temperature': gpuTemperature,
|
||||
'vram_total': vramTotal,
|
||||
'vram_used': vramUsed,
|
||||
'vram_used_percent': vramPercent,
|
||||
})
|
||||
try:
|
||||
self.torchDevice = comfy.model_management.get_torch_device_name(comfy.model_management.get_torch_device())
|
||||
except Exception as e:
|
||||
logger.error('Could not pick default device.' + str(e))
|
||||
|
||||
return {
|
||||
'device_type': gpuType,
|
||||
'gpus': gpus,
|
||||
}
|
||||
self.cudaDevice = 'cpu' if self.torchDevice == 'cpu' else 'cuda'
|
||||
self.cudaAvailable = torch.cuda.is_available()
|
||||
|
||||
if self.cuda and self.cudaAvailable and self.torchDevice == 'cpu':
|
||||
logger.warn('CUDA is available, but torch is using CPU.')
|
||||
|
||||
def getInfo(self):
|
||||
logger.debug('Getting GPUs info...')
|
||||
return self.gpus
|
||||
|
||||
def getStatus(self):
|
||||
# logger.debug('CGPUInfo getStatus')
|
||||
gpuUtilization = -1
|
||||
gpuTemperature = -1
|
||||
vramUsed = -1
|
||||
vramTotal = -1
|
||||
vramPercent = -1
|
||||
|
||||
gpuType = ''
|
||||
gpus = []
|
||||
|
||||
if self.cudaDevice == 'cpu':
|
||||
gpuType = 'cpu'
|
||||
gpus.append({
|
||||
'gpu_utilization': 0,
|
||||
'gpu_temperature': 0,
|
||||
'vram_total': 0,
|
||||
'vram_used': 0,
|
||||
'vram_used_percent': 0,
|
||||
})
|
||||
else:
|
||||
gpuType = self.cudaDevice
|
||||
|
||||
if self.pynvmlLoaded and self.cuda and self.cudaAvailable:
|
||||
# for simulate multiple GPUs (for testing) interchange these comments:
|
||||
# for deviceIndex in range(3):
|
||||
# deviceHandle = pynvml.nvmlDeviceGetHandleByIndex(0)
|
||||
for deviceIndex in range(self.cudaDevicesFound):
|
||||
deviceHandle = pynvml.nvmlDeviceGetHandleByIndex(deviceIndex)
|
||||
|
||||
gpuUtilization = 0
|
||||
vramPercent = 0
|
||||
vramUsed = 0
|
||||
vramTotal = 0
|
||||
gpuTemperature = 0
|
||||
|
||||
# GPU Utilization
|
||||
if self.switchGPU and self.gpusUtilization[deviceIndex]:
|
||||
try:
|
||||
utilization = pynvml.nvmlDeviceGetUtilizationRates(deviceHandle)
|
||||
gpuUtilization = utilization.gpu
|
||||
except Exception as e:
|
||||
if str(e) == "Unknown Error":
|
||||
logger.error('For some reason, pynvml is not working in a laptop with only battery, try to connect and turn on the monitor')
|
||||
else:
|
||||
logger.error('Could not get GPU utilization.' + str(e))
|
||||
|
||||
logger.error('Monitor of GPU is turning off (not on UI!)')
|
||||
self.switchGPU = False
|
||||
|
||||
# VRAM
|
||||
if self.switchVRAM and self.gpusVRAM[deviceIndex]:
|
||||
# Torch or pynvml?, pynvml is more accurate with the system, torch is more accurate with comfyUI
|
||||
memory = pynvml.nvmlDeviceGetMemoryInfo(deviceHandle)
|
||||
vramUsed = memory.used
|
||||
vramTotal = memory.total
|
||||
|
||||
# device = torch.device(gpuType)
|
||||
# vramUsed = torch.cuda.memory_allocated(device)
|
||||
# vramTotal = torch.cuda.get_device_properties(device).total_memory
|
||||
|
||||
vramPercent = vramUsed / vramTotal * 100
|
||||
|
||||
# Temperature
|
||||
if self.switchTemperature and self.gpusTemperature[deviceIndex]:
|
||||
try:
|
||||
gpuTemperature = pynvml.nvmlDeviceGetTemperature(deviceHandle, 0)
|
||||
except Exception as e:
|
||||
logger.error('Could not get GPU temperature. Turning off this feature. ' + str(e))
|
||||
self.switchTemperature = False
|
||||
|
||||
gpus.append({
|
||||
'gpu_utilization': gpuUtilization,
|
||||
'gpu_temperature': gpuTemperature,
|
||||
'vram_total': vramTotal,
|
||||
'vram_used': vramUsed,
|
||||
'vram_used_percent': vramPercent,
|
||||
})
|
||||
|
||||
return {
|
||||
'device_type': gpuType,
|
||||
'gpus': gpus,
|
||||
}
|
||||
|
||||
+39
-1
@@ -2,6 +2,7 @@ import os
|
||||
import random
|
||||
import sys
|
||||
import json
|
||||
import piexif
|
||||
import hashlib
|
||||
from datetime import datetime
|
||||
import torch
|
||||
@@ -262,7 +263,15 @@ class CImageLoadWithMetadata:
|
||||
def execute(self, image):
|
||||
image_path = folder_paths.get_annotated_filepath(image)
|
||||
|
||||
imgF = Image.open(image_path)
|
||||
img, prompt, metadata = buildMetadata(image_path)
|
||||
if imgF.format == 'WEBP':
|
||||
# Use piexif to extract EXIF data from WebP image
|
||||
try:
|
||||
exif_data = piexif.load(image_path)
|
||||
prompt, metadata = self.process_exif_data(exif_data)
|
||||
except ValueError:
|
||||
prompt = {}
|
||||
|
||||
img = ImageOps.exif_transpose(img)
|
||||
image = img.convert("RGB")
|
||||
@@ -276,6 +285,34 @@ class CImageLoadWithMetadata:
|
||||
|
||||
return image, mask.unsqueeze(0), prompt, metadata
|
||||
|
||||
def process_exif_data(self, exif_data):
|
||||
metadata = {}
|
||||
# 检查 '0th' 键下的 271 值,提取 Prompt 信息
|
||||
if '0th' in exif_data and 271 in exif_data['0th']:
|
||||
prompt_data = exif_data['0th'][271].decode('utf-8')
|
||||
# 移除可能的前缀 'Prompt:'
|
||||
prompt_data = prompt_data.replace('Prompt:', '', 1)
|
||||
# 假设 prompt_data 是一个字符串,尝试将其转换为 JSON 对象
|
||||
try:
|
||||
metadata['prompt'] = json.loads(prompt_data)
|
||||
except json.JSONDecodeError:
|
||||
metadata['prompt'] = prompt_data
|
||||
|
||||
# 检查 '0th' 键下的 270 值,提取 Workflow 信息
|
||||
if '0th' in exif_data and 270 in exif_data['0th']:
|
||||
workflow_data = exif_data['0th'][270].decode('utf-8')
|
||||
# 移除可能的前缀 'Workflow:'
|
||||
workflow_data = workflow_data.replace('Workflow:', '', 1)
|
||||
try:
|
||||
# 尝试将字节字符串转换为 JSON 对象
|
||||
metadata['workflow'] = json.loads(workflow_data)
|
||||
except json.JSONDecodeError:
|
||||
# 如果转换失败,则将原始字符串存储在 metadata 中
|
||||
metadata['workflow'] = workflow_data
|
||||
|
||||
metadata.update(exif_data)
|
||||
return metadata
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(cls, image):
|
||||
image_path = folder_paths.get_annotated_filepath(image)
|
||||
@@ -354,7 +391,8 @@ class CImageSaveWithExtraMetadata(SaveImage):
|
||||
|
||||
if metadata_extra is not None and metadata_extra != 'undefined':
|
||||
try:
|
||||
metadata_extra = json.loads(f"{{{metadata_extra}}}")
|
||||
# metadata_extra = json.loads(f"{{{metadata_extra}}}") // a fix?
|
||||
metadata_extra = json.loads(metadata_extra)
|
||||
except Exception as e:
|
||||
logger.error(f"Error parsing metadata_extra (it will send as string), error: {e}")
|
||||
metadata_extra = {"extra": str(metadata_extra)}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
[project]
|
||||
name = "comfyui-crystools"
|
||||
description = "With this suit, you can see the resources monitor, progress bar & time elapsed, metadata and compare between two images, compare between two JSONs, show any value to console/display, pipes, and more!\nThis provides better nodes to load/save images, previews, etc, and see \"hidden\" data without loading a new workflow."
|
||||
version = "1.13.0"
|
||||
license = "LICENSE"
|
||||
dependencies = ["deepdiff", "torch", "numpy", "Pillow>=9.5.0", "pynvml", "py-cpuinfo"]
|
||||
|
||||
[project.urls]
|
||||
Repository = "https://github.com/crystian/ComfyUI-Crystools"
|
||||
|
||||
[tool.comfy]
|
||||
PublisherId = "crystian"
|
||||
DisplayName = "ComfyUI-Crystools"
|
||||
Icon = "https://raw.githubusercontent.com/crystian/ComfyUI-Crystools/main/docs/screwdriver.png"
|
||||
@@ -4,3 +4,4 @@ numpy
|
||||
Pillow>=9.5.0
|
||||
pynvml
|
||||
py-cpuinfo
|
||||
piexif
|
||||
|
||||
Reference in New Issue
Block a user