Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5b210d142 | ||
|
|
6bbf06d9e9 | ||
|
|
0b614b40cf | ||
|
|
27673561bd | ||
|
|
6e2070410d | ||
|
|
7ccf21f74f |
+8
-6
@@ -323,8 +323,8 @@ from .nodes.Vae import VAELoader,VAEDecode
|
||||
from .nodes.ScreenShareNode import ScreenShareNode,FloatingVideo
|
||||
from .nodes.Clipseg import CLIPSeg,CombineMasks
|
||||
from .nodes.ChatGPT import ChatGPTNode,ShowTextForGPT,CharacterInText
|
||||
from .nodes.Audio import SpeechRecognition,SpeechSynthesis
|
||||
from .nodes.Utils import ColorInput,FontInput
|
||||
from .nodes.Audio import GamePal,SpeechRecognition,SpeechSynthesis
|
||||
from .nodes.Utils import ColorInput,FontInput,TextToNumber
|
||||
|
||||
|
||||
# 要导出的所有节点及其名称的字典
|
||||
@@ -337,8 +337,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"TextImage":TextImage,
|
||||
"EnhanceImage":EnhanceImage,
|
||||
"SvgImage":SvgImage,
|
||||
"3DImage":Image3D,
|
||||
# "EmptyLayer":EmptyLayer,
|
||||
"3DImage":Image3D,
|
||||
"ShowLayer":ShowLayer,
|
||||
"NewLayer":NewLayer,
|
||||
"MergeLayers":MergeLayers,
|
||||
@@ -360,7 +359,9 @@ NODE_CLASS_MAPPINGS = {
|
||||
"SpeechRecognition":SpeechRecognition,
|
||||
"SpeechSynthesis":SpeechSynthesis,
|
||||
"Color":ColorInput,
|
||||
"Font":FontInput
|
||||
"Font":FontInput,
|
||||
"TextToNumber":TextToNumber
|
||||
# "GamePal":GamePal
|
||||
}
|
||||
|
||||
# 一个包含节点友好/可读的标题的字典
|
||||
@@ -377,7 +378,8 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"MergeLayers":"MergeLayers ♾️Mixlab",
|
||||
"SpeechSynthesis":"SpeechSynthesis ♾️Mixlab",
|
||||
"SpeechRecognition":"SpeechRecognition ♾️Mixlab",
|
||||
"3DImage":"3DImage ♾️Mixlab"
|
||||
"3DImage":"3DImage ♾️Mixlab",
|
||||
# "GamePal":"GamePal ♾️Mixlab"
|
||||
}
|
||||
|
||||
# web ui的节点功能
|
||||
|
||||
+56
-2
@@ -7,6 +7,16 @@ class SpeechRecognition:
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"upload":("AUDIOINPUTMIX",), },
|
||||
"optional":{
|
||||
"start_by":("INT", {
|
||||
"default": 0,
|
||||
"min": 0, #Minimum value
|
||||
"max": 2048, #Maximum value
|
||||
"step": 1, #Slider's step
|
||||
"display": "number" # Cosmetic only: display as "number" or "slider"
|
||||
}),
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
@@ -19,8 +29,8 @@ class SpeechRecognition:
|
||||
INPUT_IS_LIST = False
|
||||
OUTPUT_IS_LIST = (False,)
|
||||
|
||||
def run(self,upload):
|
||||
return (upload,)
|
||||
def run(self,upload,start_by):
|
||||
return {"ui": {"start_by": [start_by]}, "result": (upload,)}
|
||||
|
||||
|
||||
class SpeechSynthesis:
|
||||
@@ -44,3 +54,47 @@ class SpeechSynthesis:
|
||||
# print(session_history)
|
||||
return {"ui": {"text": text}, "result": (text,)}
|
||||
|
||||
|
||||
#
|
||||
class GamePal:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"input_text": ("STRING",{"multiline": True,"default": ""}),
|
||||
},
|
||||
"optional": {
|
||||
|
||||
"input_num": ("INT",{
|
||||
"default":100,
|
||||
"min": -1, #Minimum value
|
||||
"max": 0xffffffffffffffff, #Maximum value
|
||||
"step": 1, #Slider's step
|
||||
"display": "slider" # Cosmetic only: display as "number" or "slider"
|
||||
}),
|
||||
"python_code": ("STRING",{"multiline": True,"default": "result= 1 if 'Mixlab' in input_text else 0"}),
|
||||
}
|
||||
}
|
||||
|
||||
INPUT_IS_LIST = False
|
||||
RETURN_TYPES = ("INT",)
|
||||
FUNCTION = "run"
|
||||
OUTPUT_NODE = True
|
||||
OUTPUT_IS_LIST = (False,)
|
||||
|
||||
CATEGORY = "♾️Mixlab/audio"
|
||||
|
||||
def run(self, input_text,input_num,python_code):
|
||||
exec(python_code)
|
||||
res=None
|
||||
try:
|
||||
# 可能会引发异常的代码
|
||||
res=result
|
||||
except:
|
||||
# 处理异常的代码
|
||||
print('')
|
||||
|
||||
print(res)
|
||||
|
||||
# print(session_history)
|
||||
return {"ui": {"text": [input_text],"num":[input_num]}, "result": (res,)}
|
||||
+88
-23
@@ -396,33 +396,99 @@ def resize_image(layer_image,scale_option,width,height):
|
||||
return layer_image
|
||||
|
||||
|
||||
def generate_text_image(text_list, font_path, font_size, text_color, vertical=True, spacing=0):
|
||||
# Load Chinese font
|
||||
font = ImageFont.truetype(font_path, font_size)
|
||||
# def generate_text_image(text_list, font_path, font_size, text_color, vertical=True, spacing=0):
|
||||
# # Load Chinese font
|
||||
# font = ImageFont.truetype(font_path, font_size)
|
||||
|
||||
# Calculate image size based on the number of characters and orientation
|
||||
# # Calculate image size based on the number of characters and orientation
|
||||
# if vertical:
|
||||
# width = font_size + 100
|
||||
# height = font_size * len(text_list) + (len(text_list) - 1) * spacing + 100
|
||||
# else:
|
||||
# width = font_size * len(text_list) + (len(text_list) - 1) * spacing + 100
|
||||
# height = font_size + 100
|
||||
|
||||
# # Create a blank image
|
||||
# image = Image.new('RGBA', (width, height), (255, 255, 255,0))
|
||||
# draw = ImageDraw.Draw(image)
|
||||
|
||||
# # Draw text
|
||||
# if vertical:
|
||||
# for i, char in enumerate(text_list):
|
||||
# char_position = (50, 50 + i * font_size)
|
||||
# draw.text(char_position, char, font=font, fill=text_color)
|
||||
# else:
|
||||
# for i, char in enumerate(text_list):
|
||||
# char_position = (50 + i * (font_size + spacing), 50)
|
||||
# draw.text(char_position, char, font=font, fill=text_color)
|
||||
|
||||
# # Save the image
|
||||
# # image.save(output_image_path)
|
||||
|
||||
# # 分离alpha通道
|
||||
# alpha_channel = image.split()[3]
|
||||
|
||||
# # 创建一个只有alpha通道的新图像
|
||||
# alpha_image = Image.new('L', image.size)
|
||||
# alpha_image.putdata(alpha_channel.getdata())
|
||||
|
||||
# image=image.convert('RGB')
|
||||
|
||||
# return (image,alpha_image)
|
||||
|
||||
def generate_text_image(text, font_path, font_size, text_color, vertical=True, spacing=0):
|
||||
# Split text into lines based on line breaks
|
||||
lines = text.split("\n")
|
||||
|
||||
# 1. Determine layout direction
|
||||
if vertical:
|
||||
width = font_size + 100
|
||||
height = font_size * len(text_list) + (len(text_list) - 1) * spacing + 100
|
||||
layout = "vertical"
|
||||
else:
|
||||
width = font_size * len(text_list) + (len(text_list) - 1) * spacing + 100
|
||||
height = font_size + 100
|
||||
layout = "horizontal"
|
||||
|
||||
# Create a blank image
|
||||
# 2. Calculate absolute coordinates for each character
|
||||
char_coordinates = []
|
||||
if layout == "vertical":
|
||||
x = 0
|
||||
y = 0
|
||||
for i in range(len(lines)):
|
||||
line=lines[i]
|
||||
for char in line:
|
||||
char_coordinates.append((x, y))
|
||||
y += font_size + spacing
|
||||
x += font_size + spacing
|
||||
y = 0
|
||||
print(char_coordinates)
|
||||
else:
|
||||
x = 0
|
||||
y = 0
|
||||
for line in lines:
|
||||
for char in line:
|
||||
char_coordinates.append((x, y))
|
||||
x += font_size + spacing
|
||||
y += font_size + spacing
|
||||
x = 0
|
||||
|
||||
# 3. Calculate image width and height
|
||||
if layout == "vertical":
|
||||
width = (len(lines) * (font_size + spacing)) - spacing
|
||||
height = (len(max(lines, key=len)) * (font_size + spacing)) - spacing
|
||||
else:
|
||||
width = (len(max(lines, key=len)) * (font_size + spacing)) - spacing
|
||||
height = (len(lines) * (font_size + spacing)) - spacing
|
||||
|
||||
# 4. Draw each character on the image
|
||||
image = Image.new('RGBA', (width, height), (255, 255, 255,0))
|
||||
draw = ImageDraw.Draw(image)
|
||||
font = ImageFont.truetype(font_path, font_size)
|
||||
|
||||
index=0
|
||||
for i, line in enumerate(lines):
|
||||
for j, char in enumerate(line):
|
||||
x, y = char_coordinates[index]
|
||||
draw.text((x, y), char, font=font, fill=text_color)
|
||||
index+=1
|
||||
|
||||
# Draw text
|
||||
if vertical:
|
||||
for i, char in enumerate(text_list):
|
||||
char_position = (50, 50 + i * font_size)
|
||||
draw.text(char_position, char, font=font, fill=text_color)
|
||||
else:
|
||||
for i, char in enumerate(text_list):
|
||||
char_position = (50 + i * (font_size + spacing), 50)
|
||||
draw.text(char_position, char, font=font, fill=text_color)
|
||||
|
||||
# Save the image
|
||||
# image.save(output_image_path)
|
||||
|
||||
# 分离alpha通道
|
||||
@@ -436,7 +502,6 @@ def generate_text_image(text_list, font_path, font_size, text_color, vertical=Tr
|
||||
|
||||
return (image,alpha_image)
|
||||
|
||||
|
||||
def base64_to_image(base64_string):
|
||||
# 去除前缀
|
||||
prefix, base64_data = base64_string.split(",", 1)
|
||||
@@ -874,7 +939,7 @@ class TextImage:
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
|
||||
"text": ("STRING",{"multiline": False,"default": "龍馬精神迎新歲"}),
|
||||
"text": ("STRING",{"multiline": True,"default": "龍馬精神迎新歲"}),
|
||||
"font_path": ("STRING",{"multiline": False,"default": FONT_PATH}),
|
||||
"font_size": ("INT",{
|
||||
"default":100,
|
||||
@@ -909,7 +974,7 @@ class TextImage:
|
||||
|
||||
text_list=list(text)
|
||||
|
||||
img,mask=generate_text_image(text_list,font_path,font_size,text_color,vertical,spacing)
|
||||
img,mask=generate_text_image(text,font_path,font_size,text_color,vertical,spacing)
|
||||
|
||||
img=pil2tensor(img)
|
||||
mask=pil2tensor(mask)
|
||||
|
||||
@@ -79,11 +79,13 @@ class ScreenShareNode:
|
||||
def INPUT_TYPES(s):
|
||||
return { "required":{
|
||||
"image_base64": ("CHEESE",),
|
||||
"refresh_rate": ("INT", {"default": 500, "min": 0,"step": 50, "max": 0xffffffffffffffff}),
|
||||
},
|
||||
"optional":{
|
||||
"prompt": ("PROMPT",),
|
||||
"slide": ("SLIDE",),
|
||||
"seed": ("SEED",),
|
||||
|
||||
# "seed": ("INT", {"default": 1, "min": 0, "max": 0xffffffffffffffff}),
|
||||
} }
|
||||
|
||||
@@ -97,11 +99,11 @@ class ScreenShareNode:
|
||||
OUTPUT_IS_LIST = (False,False,False,False)
|
||||
|
||||
# 运行的函数
|
||||
def run(self,image_base64,prompt,slide,seed):
|
||||
def run(self,image_base64,refresh_rate ,prompt,slide,seed):
|
||||
im,mask=base64_save(image_base64)
|
||||
# print('##########prompt',prompt)
|
||||
return (im,prompt,slide,seed)
|
||||
|
||||
return {"ui":{"refresh_rate": [refresh_rate]},"result": (im,prompt,slide,seed,)}
|
||||
|
||||
|
||||
class FloatingVideo:
|
||||
@classmethod
|
||||
|
||||
+40
-2
@@ -1,5 +1,5 @@
|
||||
import os
|
||||
|
||||
import re,random
|
||||
# FONT_PATH= os.path.abspath(os.path.join(os.path.dirname(__file__),'../assets/王汉宗颜楷体繁.ttf'))
|
||||
|
||||
import matplotlib.font_manager as fm
|
||||
@@ -80,4 +80,42 @@ class FontInput:
|
||||
|
||||
def run(self,font):
|
||||
|
||||
return (font_files[font],)
|
||||
return (font_files[font],)
|
||||
|
||||
class TextToNumber:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"text": ("STRING",{"multiline": False,"default": "1"}),
|
||||
"random_number": (["enable", "disable"],),
|
||||
"number":("INT", {
|
||||
"default": 0,
|
||||
"min": 0, #Minimum value
|
||||
"max": 10000000000, #Maximum value
|
||||
"step": 1, #Slider's step
|
||||
"display": "number" # Cosmetic only: display as "number" or "slider"
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("INT",)
|
||||
# RETURN_NAMES = ("WIDTH","HEIGHT","X","Y",)
|
||||
|
||||
FUNCTION = "run"
|
||||
|
||||
CATEGORY = "♾️Mixlab/utils"
|
||||
|
||||
INPUT_IS_LIST = False
|
||||
OUTPUT_IS_LIST = (False,)
|
||||
|
||||
def run(self,text,random_number,number):
|
||||
|
||||
numbers = re.findall(r'\d+', text)
|
||||
result=0
|
||||
for n in numbers:
|
||||
result = int(n)
|
||||
print(result)
|
||||
|
||||
if random_number=='enable' and result>0:
|
||||
result= random.randint(1, 10000000000)
|
||||
return {"ui": {"text": [text],"num":[result]}, "result": (result,)}
|
||||
@@ -69,8 +69,7 @@ function speakText (text) {
|
||||
// #MixCopilot
|
||||
|
||||
const start = (element, id, startBtn) => {
|
||||
|
||||
startBtn.className='loading_mixlab'
|
||||
startBtn.className = 'loading_mixlab'
|
||||
|
||||
window.recognition = new webkitSpeechRecognition()
|
||||
|
||||
@@ -95,17 +94,16 @@ const start = (element, id, startBtn) => {
|
||||
localStorage.setItem('_mixlab_speech_recognition', JSON.stringify(data))
|
||||
|
||||
if (timeoutId) clearTimeout(timeoutId)
|
||||
|
||||
|
||||
if (!window.recognition) return
|
||||
|
||||
timeoutId = setTimeout(function () {
|
||||
console.log('结果传递::', result)
|
||||
app.queuePrompt(0, 1)
|
||||
window.recognition?.stop()
|
||||
window.recognition = null;
|
||||
startBtn.className=''
|
||||
window.recognition = null
|
||||
startBtn.className = ''
|
||||
startBtn.innerText = 'START'
|
||||
|
||||
|
||||
timeoutId = null
|
||||
|
||||
@@ -202,6 +200,7 @@ app.registerExtension({
|
||||
margin: 0px 8px 6px;`
|
||||
|
||||
startBtn.style = `
|
||||
margin-top:48px;
|
||||
background-color: var(--comfy-input-bg);
|
||||
border-radius: 8px;
|
||||
border-color: var(--border-color);
|
||||
@@ -219,7 +218,7 @@ app.registerExtension({
|
||||
window.recognition.stop()
|
||||
window.recognition = null
|
||||
startBtn.innerText = 'START'
|
||||
startBtn.className=''
|
||||
startBtn.className = ''
|
||||
} else {
|
||||
start(textArea, this.id, startBtn)
|
||||
startBtn.innerText = 'STOP'
|
||||
@@ -243,16 +242,70 @@ app.registerExtension({
|
||||
|
||||
this.serialize_widgets = true //需要保存参数
|
||||
}
|
||||
|
||||
|
||||
|
||||
// const onGraphConfigured=nodeType.prototype.onGraphConfigured;
|
||||
// nodeType.prototype.onGraphConfigured = function (message) {
|
||||
// onGraphConfigured?.apply(this, arguments)
|
||||
// console.log('###SpeechRecognition onGraphConfigured',this,message)
|
||||
// }
|
||||
|
||||
const onExecuted = nodeType.prototype.onExecuted
|
||||
nodeType.prototype.onExecuted = function (message) {
|
||||
onExecuted?.apply(this, arguments)
|
||||
|
||||
try {
|
||||
let open = message.start_by[0] > 0
|
||||
if (open) {
|
||||
const div = this.widgets.filter(w => w.name == 'chatgptdiv')[0].div
|
||||
const startBtn = div.querySelector('button')
|
||||
let textArea= div.querySelector('textarea')
|
||||
if (open && !window.recognition) {
|
||||
start(textArea, this.id, startBtn)
|
||||
startBtn.innerText = 'STOP'
|
||||
} else if (!open && window.recognition) {
|
||||
window.recognition.stop()
|
||||
window.recognition = null
|
||||
startBtn.innerText = 'START'
|
||||
startBtn.className = ''
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('###SpeechRecognition', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async loadedGraphNode (node, app) {
|
||||
if (node.type === 'SpeechRecognition') {
|
||||
let data = getLocalData('_mixlab_speech_recognition')
|
||||
// console.log('_mixlab_speech_recognition', node.widgets)
|
||||
// console.log('_mixlab_speech_recognition', node )
|
||||
let div = node.widgets.filter(f => f.type === 'div')[0]
|
||||
if (div && data[node.id]) {
|
||||
div.div.querySelector('textarea').value = data[node.id]
|
||||
};
|
||||
|
||||
try {
|
||||
let open = node.widgets_values[1] > 0
|
||||
if (open) {
|
||||
const div = node.widgets.filter(w => w.name == 'chatgptdiv')[0].div
|
||||
const startBtn = div.querySelector('button')
|
||||
let textArea= div.querySelector('textarea')
|
||||
if (open && !window.recognition) {
|
||||
start(textArea, node.id, startBtn)
|
||||
startBtn.innerText = 'STOP'
|
||||
} else if (!open && window.recognition) {
|
||||
window.recognition.stop()
|
||||
window.recognition = null
|
||||
startBtn.innerText = 'START'
|
||||
startBtn.className = ''
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('###SpeechRecognition', error)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -461,7 +461,7 @@ async function requestCamera () {
|
||||
/*
|
||||
A method that returns the required style for the html
|
||||
*/
|
||||
function get_position_style (ctx, widget_width, y, node_height) {
|
||||
function get_position_style (ctx, widget_width, y, node_height, top) {
|
||||
const MARGIN = 4 // the margin around the html element
|
||||
|
||||
/* Create a transform that deals with all the scrolling and zooming */
|
||||
@@ -478,7 +478,7 @@ function get_position_style (ctx, widget_width, y, node_height) {
|
||||
transformOrigin: '0 0',
|
||||
transform: transform,
|
||||
left: `0`,
|
||||
top: `0`,
|
||||
top: `${top}px`,
|
||||
cursor: 'pointer',
|
||||
position: 'absolute',
|
||||
maxWidth: `${widget_width - MARGIN * 2}px`,
|
||||
@@ -585,9 +585,6 @@ app.registerExtension({
|
||||
},
|
||||
async beforeRegisterNodeDef (nodeType, nodeData, app) {
|
||||
if (nodeType.comfyClass == 'ScreenShare') {
|
||||
/*
|
||||
Hijack the onNodeCreated call to add our widget
|
||||
*/
|
||||
const orig_nodeCreated = nodeType.prototype.onNodeCreated
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
orig_nodeCreated?.apply(this, arguments)
|
||||
@@ -603,7 +600,8 @@ app.registerExtension({
|
||||
ctx,
|
||||
widget_width,
|
||||
widget_height * 5,
|
||||
node.size[1]
|
||||
node.size[1],
|
||||
40
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -693,22 +691,22 @@ app.registerExtension({
|
||||
}
|
||||
})
|
||||
|
||||
widget.refreshInput = $el('input', {
|
||||
placeholder: ' Refresh rate:200 ms',
|
||||
type: 'number',
|
||||
min: 100,
|
||||
step: 100,
|
||||
style: {
|
||||
cursor: 'pointer',
|
||||
padding: '8px 24px',
|
||||
fontWeight: '300',
|
||||
margin: '2px',
|
||||
color: 'var(--descrip-text)',
|
||||
backgroundColor: 'var(--comfy-input-bg)'
|
||||
}
|
||||
});
|
||||
widget.refreshInput.className='comfy-multiline-input'
|
||||
|
||||
// widget.refreshInput = $el('input', {
|
||||
// placeholder: ' Refresh rate:200 ms',
|
||||
// type: 'number',
|
||||
// min: 100,
|
||||
// step: 100,
|
||||
// style: {
|
||||
// cursor: 'pointer',
|
||||
// padding: '8px 24px',
|
||||
// fontWeight: '300',
|
||||
// margin: '2px',
|
||||
// color: 'var(--descrip-text)',
|
||||
// backgroundColor: 'var(--comfy-input-bg)'
|
||||
// }
|
||||
// });
|
||||
// widget.refreshInput.className='comfy-multiline-input'
|
||||
|
||||
widget.liveBtn = $el('button', {
|
||||
innerText: 'Live Run',
|
||||
style: {
|
||||
@@ -734,7 +732,7 @@ app.registerExtension({
|
||||
widget.shareDiv.appendChild(widget.shareBtn)
|
||||
widget.shareDiv.appendChild(widget.shareOfWebCamBtn)
|
||||
widget.card.appendChild(widget.openFloatingWinBtn)
|
||||
widget.card.appendChild(widget.refreshInput)
|
||||
// widget.card.appendChild(widget.refreshInput)
|
||||
widget.card.appendChild(widget.liveBtn)
|
||||
|
||||
const toggleShare = async (isCamera = false) => {
|
||||
@@ -894,11 +892,11 @@ app.registerExtension({
|
||||
toggleShare()
|
||||
})
|
||||
|
||||
widget.refreshInput.addEventListener('change', async () => {
|
||||
window._mixlab_screen_refresh_rate = Math.round(
|
||||
widget.refreshInput.value
|
||||
)
|
||||
})
|
||||
// widget.refreshInput.addEventListener('change', async () => {
|
||||
// window._mixlab_screen_refresh_rate = Math.round(
|
||||
// widget.refreshInput.value
|
||||
// )
|
||||
// })
|
||||
|
||||
widget.liveBtn.addEventListener('click', async () => {
|
||||
if (window._mixlab_stopLive) {
|
||||
@@ -939,12 +937,21 @@ app.registerExtension({
|
||||
widget.shareBtn.remove()
|
||||
widget.liveBtn.remove()
|
||||
widget.card.remove()
|
||||
widget.refreshInput.remove()
|
||||
// widget.refreshInput.remove()
|
||||
widget.previewArea.remove()
|
||||
widget.previewCard.remove()
|
||||
}
|
||||
this.serialize_widgets = true
|
||||
}
|
||||
|
||||
const onExecuted = nodeType.prototype.onExecuted
|
||||
nodeType.prototype.onExecuted = function (message) {
|
||||
onExecuted?.apply(this, arguments)
|
||||
// console.log('###ScreenShare', this, message.refresh_rate)
|
||||
window._mixlab_screen_refresh_rate = Math.round(
|
||||
message.refresh_rate[0] || 500
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -1214,7 +1221,7 @@ app.registerExtension({
|
||||
draw (ctx, node, widget_width, y, widget_height) {
|
||||
Object.assign(
|
||||
this.card.style,
|
||||
get_position_style(ctx, widget_width, y, node.size[1])
|
||||
get_position_style(ctx, widget_width, y, node.size[1], 0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+120
-107
@@ -1,10 +1,8 @@
|
||||
|
||||
import { app } from '../../../scripts/app.js'
|
||||
import { api } from '../../../scripts/api.js'
|
||||
import { ComfyWidgets } from '../../../scripts/widgets.js'
|
||||
import { $el } from '../../../scripts/ui.js'
|
||||
|
||||
|
||||
import { addValueControlWidget } from "../../../scripts/widgets.js";
|
||||
|
||||
const getLocalData = key => {
|
||||
let data = {}
|
||||
@@ -47,122 +45,137 @@ function get_position_style (ctx, widget_width, y, node_height) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
app.registerExtension({
|
||||
name: 'Mixlab.utils.Color',
|
||||
async getCustomWidgets (app) {
|
||||
return {
|
||||
TCOLOR (node, inputName, inputData, app) {
|
||||
// console.log('##node', node)
|
||||
const widget = {
|
||||
type: inputData[0], // the type, CHEESE
|
||||
name: inputName, // the name, slice
|
||||
size: [128, 32], // a default size
|
||||
draw (ctx, node, width, y) {},
|
||||
computeSize (...args) {
|
||||
return [128, 32] // a method to compute the current size of the widget
|
||||
},
|
||||
async serializeValue (nodeId, widgetIndex) {
|
||||
let data = getLocalData('_mixlab_utils_color')
|
||||
return data[node.id] || '#000000'
|
||||
}
|
||||
name: 'Mixlab.utils.Color',
|
||||
async getCustomWidgets (app) {
|
||||
return {
|
||||
TCOLOR (node, inputName, inputData, app) {
|
||||
// console.log('##node', node)
|
||||
const widget = {
|
||||
type: inputData[0], // the type, CHEESE
|
||||
name: inputName, // the name, slice
|
||||
size: [128, 32], // a default size
|
||||
draw (ctx, node, width, y) {},
|
||||
computeSize (...args) {
|
||||
return [128, 32] // a method to compute the current size of the widget
|
||||
},
|
||||
async serializeValue (nodeId, widgetIndex) {
|
||||
let data = getLocalData('_mixlab_utils_color')
|
||||
return data[node.id] || '#000000'
|
||||
}
|
||||
// widget.something = something; // maybe adds stuff to it
|
||||
node.addCustomWidget(widget) // adds it to the node
|
||||
return widget // and returns it.
|
||||
}
|
||||
// widget.something = something; // maybe adds stuff to it
|
||||
node.addCustomWidget(widget) // adds it to the node
|
||||
return widget // and returns it.
|
||||
}
|
||||
},
|
||||
|
||||
async beforeRegisterNodeDef (nodeType, nodeData, app) {
|
||||
if (nodeType.comfyClass == 'Color') {
|
||||
const orig_nodeCreated = nodeType.prototype.onNodeCreated
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
orig_nodeCreated?.apply(this, arguments)
|
||||
|
||||
console.log('Color nodeData', this.widgets)
|
||||
|
||||
const widget = {
|
||||
type: 'div',
|
||||
name: 'input_color',
|
||||
draw (ctx, node, widget_width, y, widget_height) {
|
||||
Object.assign(
|
||||
this.div.style,
|
||||
get_position_style(
|
||||
ctx,
|
||||
widget_width,
|
||||
44,
|
||||
node.size[1]
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async beforeRegisterNodeDef (nodeType, nodeData, app) {
|
||||
if (nodeType.comfyClass == 'Color') {
|
||||
const orig_nodeCreated = nodeType.prototype.onNodeCreated
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
orig_nodeCreated?.apply(this, arguments)
|
||||
|
||||
console.log('Color nodeData', this.widgets)
|
||||
|
||||
const widget = {
|
||||
type: 'div',
|
||||
name: 'input_color',
|
||||
draw (ctx, node, widget_width, y, widget_height) {
|
||||
Object.assign(
|
||||
this.div.style,
|
||||
get_position_style(ctx, widget_width, 44, node.size[1])
|
||||
)
|
||||
}
|
||||
|
||||
widget.div = $el('div', {})
|
||||
|
||||
document.body.appendChild(widget.div)
|
||||
|
||||
const inputDiv = (key, placeholder, value) => {
|
||||
let div = document.createElement('div')
|
||||
const ip = document.createElement('input')
|
||||
ip.type = 'color'
|
||||
ip.className = `${'comfy-multiline-input'} ${placeholder}`
|
||||
div.style = `display: flex;
|
||||
}
|
||||
|
||||
widget.div = $el('div', {})
|
||||
|
||||
document.body.appendChild(widget.div)
|
||||
|
||||
const inputDiv = (key, placeholder, value) => {
|
||||
let div = document.createElement('div')
|
||||
const ip = document.createElement('input')
|
||||
ip.type = 'color'
|
||||
ip.className = `${'comfy-multiline-input'} ${placeholder}`
|
||||
div.style = `display: flex;
|
||||
align-items: center;
|
||||
margin: 6px 8px;
|
||||
margin-top: 0;`
|
||||
ip.placeholder = placeholder
|
||||
ip.value = value
|
||||
|
||||
ip.style = `outline: none;
|
||||
ip.placeholder = placeholder
|
||||
ip.value = value
|
||||
|
||||
ip.style = `outline: none;
|
||||
border: none;
|
||||
padding: 4px;
|
||||
width: 100%;cursor: pointer;
|
||||
height: 32px;`
|
||||
const label = document.createElement('label')
|
||||
label.style = 'font-size: 10px;min-width:32px'
|
||||
label.innerText = placeholder
|
||||
div.appendChild(label)
|
||||
div.appendChild(ip)
|
||||
|
||||
ip.addEventListener('change', () => {
|
||||
let data = getLocalData(key)
|
||||
data[this.id] = ip.value.trim()
|
||||
localStorage.setItem(key, JSON.stringify(data))
|
||||
// console.log(this.id, ip.value.trim())
|
||||
})
|
||||
return div
|
||||
}
|
||||
|
||||
let inputColor = inputDiv('_mixlab_utils_color', 'Color', '#000000')
|
||||
|
||||
widget.div.appendChild(inputColor)
|
||||
|
||||
this.addCustomWidget(widget)
|
||||
|
||||
const onRemoved = this.onRemoved
|
||||
this.onRemoved = () => {
|
||||
inputColor.remove()
|
||||
widget.div.remove()
|
||||
return onRemoved?.()
|
||||
}
|
||||
|
||||
this.serialize_widgets = true //需要保存参数
|
||||
const label = document.createElement('label')
|
||||
label.style = 'font-size: 10px;min-width:32px'
|
||||
label.innerText = placeholder
|
||||
div.appendChild(label)
|
||||
div.appendChild(ip)
|
||||
|
||||
ip.addEventListener('change', () => {
|
||||
let data = getLocalData(key)
|
||||
data[this.id] = ip.value.trim()
|
||||
localStorage.setItem(key, JSON.stringify(data))
|
||||
// console.log(this.id, ip.value.trim())
|
||||
})
|
||||
return div
|
||||
}
|
||||
}
|
||||
},
|
||||
async loadedGraphNode (node, app) {
|
||||
// Fires every time a node is constructed
|
||||
// You can modify widgets/add handlers/etc here
|
||||
|
||||
if (node.type === 'Color') {
|
||||
let widget = node.widgets.filter(w => w.div)[0]
|
||||
|
||||
let data = getLocalData('_mixlab_utils_color')
|
||||
|
||||
let id = node.id
|
||||
|
||||
widget.div.querySelector('.Color').value = data[id] || '#000000'
|
||||
|
||||
let inputColor = inputDiv('_mixlab_utils_color', 'Color', '#000000')
|
||||
|
||||
widget.div.appendChild(inputColor)
|
||||
|
||||
this.addCustomWidget(widget)
|
||||
|
||||
const onRemoved = this.onRemoved
|
||||
this.onRemoved = () => {
|
||||
inputColor.remove()
|
||||
widget.div.remove()
|
||||
return onRemoved?.()
|
||||
}
|
||||
|
||||
this.serialize_widgets = true //需要保存参数
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
async loadedGraphNode (node, app) {
|
||||
// Fires every time a node is constructed
|
||||
// You can modify widgets/add handlers/etc here
|
||||
|
||||
if (node.type === 'Color') {
|
||||
let widget = node.widgets.filter(w => w.div)[0]
|
||||
|
||||
let data = getLocalData('_mixlab_utils_color')
|
||||
|
||||
let id = node.id
|
||||
|
||||
widget.div.querySelector('.Color').value = data[id] || '#000000'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.registerExtension({
|
||||
name: 'Mixlab.utils.TextToNumber',
|
||||
|
||||
async beforeRegisterNodeDef (nodeType, nodeData, app) {
|
||||
if (nodeType.comfyClass == 'TextToNumber') {
|
||||
|
||||
const onExecuted = nodeType.prototype.onExecuted
|
||||
nodeType.prototype.onExecuted = function (message) {
|
||||
onExecuted?.apply(this, arguments)
|
||||
const random_number=this.widgets.filter(w=>w.name==='random_number')[0]
|
||||
if(random_number.value==='enable'){
|
||||
const n=this.widgets.filter(w=>w.name==='number')[0]
|
||||
n.value=message.num[0]
|
||||
}
|
||||
|
||||
console.log('TextToNumber', random_number.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -295,7 +295,7 @@
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
1115769645491668,
|
||||
482859286431021,
|
||||
"randomize",
|
||||
4,
|
||||
1.6,
|
||||
@@ -479,10 +479,10 @@
|
||||
1928,
|
||||
295
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 58
|
||||
},
|
||||
"size": [
|
||||
315,
|
||||
58
|
||||
],
|
||||
"flags": {},
|
||||
"order": 12,
|
||||
"mode": 0,
|
||||
@@ -507,10 +507,10 @@
|
||||
-65,
|
||||
446
|
||||
],
|
||||
"size": {
|
||||
"0": 315,
|
||||
"1": 170
|
||||
},
|
||||
"size": [
|
||||
312.78457519531213,
|
||||
606.2132135620109
|
||||
],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
@@ -552,6 +552,7 @@
|
||||
},
|
||||
"widgets_values": [
|
||||
null,
|
||||
2018,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user