This commit is contained in:
MeeeyoAI
2025-04-25 14:52:49 +08:00
parent c384ac85fd
commit 3e17752185
3 changed files with 220 additions and 34 deletions
+8
View File
@@ -15,7 +15,10 @@ NODE_CLASS_MAPPINGS = {
#字符串处理:meyo_node_String
"SingleTextInput": SingleTextInput,
"TextConcatenator": TextConcatenator,
"MultiParamInputNode": MultiParamInputNode,
"NumberExtractor": NumberExtractor,
"AddPrefixSuffix": AddPrefixSuffix,
"ExtractSubstring": ExtractSubstring,
"ExtractSubstringByIndices": ExtractSubstringByIndices,
@@ -42,6 +45,7 @@ NODE_CLASS_MAPPINGS = {
"TextConcatenation": TextConcatenation,
"ExtractSpecificData": ExtractSpecificData,
"FindFirstLineContent": FindFirstLineContent,
"GenerateVideoPrompt": GenerateVideoPrompt,
#文件处理:meyo_node_File
"LoadAndAdjustImage": LoadAndAdjustImage,
@@ -74,7 +78,10 @@ NODE_DISPLAY_NAME_MAPPINGS = {
#字符串处理:meyo_node_String
"SingleTextInput": "文本输入(meeeyo.com)",
"TextConcatenator": "文本拼接(meeeyo.com)",
"MultiParamInputNode": "多参数输入(meeeyo.com)",
"NumberExtractor": "整数参数(meeeyo.com)",
"AddPrefixSuffix": "添加前后缀(meeeyo.com)",
"ExtractSubstring": "提取标签之间(meeeyo.com)",
"ExtractSubstringByIndices": "按数字范围提取(meeeyo.com)",
@@ -101,6 +108,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"TextConcatenation": "文本组合(meeeyo.com)",
"ExtractSpecificData": "提取多层指定数据(meeeyo.com)",
"FindFirstLineContent": "指定字符行参数(meeeyo.com)",
"GenerateVideoPrompt": "视频指令词模板(meeeyo.com)",
#文件处理:meyo_node_File
"LoadAndAdjustImage": "加载重置图像(meeeyo.com)",
+48 -33
View File
@@ -155,6 +155,10 @@ class LoadAndAdjustImage:
#======重置图像
import torch
import numpy as np
from PIL import Image, ImageOps
class ImageAdjuster:
@classmethod
def INPUT_TYPES(s):
@@ -165,7 +169,8 @@ class ImageAdjuster:
"size_option": ([
"Custom", "Million Pixels", "Small", "Medium", "Large",
"480P-H(vid 4:3)", "480P-V(vid 3:4)", "720P-H(vid 16:9)", "720P-V(vid 9:16)", "832×480", "480×832"],
{"default": "Million Pixels"})
{"default": "Million Pixels"}
)
}
}
@@ -179,18 +184,23 @@ class ImageAdjuster:
return float("NaN")
def process_image(self, image, max_dimension=1024, size_option="Custom"):
input_image = Image.fromarray((image.squeeze(0).numpy() * 255).astype(np.uint8))
W, H = input_image.size
batch_size = image.shape[0]
processed_images = []
widths = []
heights = []
for frame in [input_image]:
frame = ImageOps.exif_transpose(frame)
for i in range(batch_size):
current_image = image[i]
input_pil_image = Image.fromarray((current_image.numpy() * 255).astype(np.uint8))
W, H = input_pil_image.size
if frame.mode == 'P':
frame = frame.convert("RGBA")
elif 'A' in frame.getbands():
frame = frame.convert("RGBA")
processed_image_pil = input_pil_image.copy()
processed_image_pil = ImageOps.exif_transpose(processed_image_pil)
if processed_image_pil.mode == 'P':
processed_image_pil = processed_image_pil.convert("RGBA")
elif 'A' in processed_image_pil.getbands():
processed_image_pil = processed_image_pil.convert("RGBA")
if size_option != "Custom":
aspect_ratio = W / H
@@ -211,50 +221,55 @@ class ImageAdjuster:
(1120, 1600) if aspect_ratio <= 0.82 else
(1600, 1600)
),
"Million Pixels": self._resize_to_million_pixels(W, H), # Million Pixels option
"480P-H(vid 4:3)": (640, 480), # 480P-H, 640x480
"480P-V(vid 3:4)": (480, 640), # 480P-V, 480x640
"720P-H(vid 16:9)": (1280, 720), # 720P-H, 1280x720
"720P-V(vid 9:16)": (720, 1280), # 720P-V, 720x1280
"832×480": (832, 480), # 832x480
"480×832": (480, 832), # 480x832
"Million Pixels": self._resize_to_million_pixels(W, H),
"480P-H(vid 4:3)": (640, 480),
"480P-V(vid 3:4)": (480, 640),
"720P-H(vid 16:9)": (1280, 720),
"720P-V(vid 9:16)": (720, 1280),
"832×480": (832, 480),
"480×832": (480, 832)
}
target_width, target_height = size_options[size_option]
processed_image = frame.convert("RGB")
processed_image = ImageOps.fit(processed_image, (target_width, target_height), method=Image.Resampling.BILINEAR, centering=(0.5, 0.5))
processed_image_pil = processed_image_pil.convert("RGB")
processed_image_pil = ImageOps.fit(processed_image_pil, (target_width, target_height), method=Image.Resampling.BILINEAR, centering=(0.5, 0.5))
else:
ratio = min(max_dimension / W, max_dimension / H)
adjusted_width = round(W * ratio)
adjusted_height = round(H * ratio)
processed_image = frame.convert("RGB")
processed_image = processed_image.resize((adjusted_width, adjusted_height), Image.Resampling.BILINEAR)
processed_image_pil = processed_image_pil.convert("RGB")
processed_image_pil = processed_image_pil.resize((adjusted_width, adjusted_height), Image.Resampling.BILINEAR)
processed_image = np.array(processed_image).astype(np.float32) / 255.0
processed_image = torch.from_numpy(processed_image)[None,]
processed_image = np.array(processed_image_pil).astype(np.float32) / 255.0
processed_image = torch.from_numpy(processed_image)
processed_images.append(processed_image)
output_image = torch.cat(processed_images, dim=0) if len(processed_images) > 1 else processed_images[0]
if size_option != "Custom":
return (output_image, target_width, target_height)
if size_option != "Custom":
widths.append(target_width)
heights.append(target_height)
else:
widths.append(adjusted_width)
heights.append(adjusted_height)
output_image = torch.stack(processed_images)
if all(w == widths[0] for w in widths) and all(h == heights[0] for h in heights):
return (output_image, widths[0], heights[0])
else:
return (output_image, adjusted_width, adjusted_height)
return (output_image, widths[0], heights[0])
def _resize_to_million_pixels(self, W, H):
# Calculate the aspect ratio of the original image
aspect_ratio = W / H
target_area = 1000000 # 1 million pixels
target_area = 1000000
# Calculate the new width and height while maintaining the aspect ratio
if aspect_ratio > 1: # Landscape
if aspect_ratio > 1:
width = int(np.sqrt(target_area * aspect_ratio))
height = int(target_area / width)
else: # Portrait
else:
height = int(np.sqrt(target_area / aspect_ratio))
width = int(target_area / height)
# Round width and height to the nearest multiple of 8
width = (width + 7) // 8 * 8
height = (height + 7) // 8 * 8
+164 -1
View File
@@ -27,6 +27,52 @@ class SingleTextInput:
return (text,)
#======文本拼接
class TextConcatenator:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text1": ("STRING", {"multiline": True, "default": ""}),
"text2": ("STRING", {"multiline": True, "default": ""}),
"text3": ("STRING", {"multiline": True, "default": ""}),
"text4": ("STRING", {"multiline": True, "default": ""}),
"combine_order": ("STRING", {"default": ""})
},
}
RETURN_TYPES = ("STRING",)
FUNCTION = "combine_texts"
CATEGORY = "Meeeyo/String"
DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo"
def combine_texts(self, text1, text2, text3, text4, combine_order):
try:
text_map = {
"1": text1,
"2": text2,
"3": text3,
"4": text4
}
if not combine_order:
combine_order = "1+2+3+4"
parts = combine_order.split("+")
valid_parts = []
for part in parts:
if part in text_map:
valid_parts.append(part)
else:
return (f"Error: Invalid input '{part}' in combine_order. Valid options are 1, 2, 3, 4.",)
non_empty_texts = [text_map[part] for part in valid_parts if text_map[part]]
result = ",".join(non_empty_texts)
return (result,)
except Exception as e:
return (f"Error: {str(e)}",)
#======多参数输入
class MultiParamInputNode:
@classmethod
@@ -50,6 +96,28 @@ class MultiParamInputNode:
return (text1, text2, int1, int2)
#======整数参数
class NumberExtractor:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"int1": ("INT", {"default": 0, "min": -1000000, "max": 1000000}), # 第一个整数输入框
"int2": ("INT", {"default": 0, "min": -1000000, "max": 1000000}), # 第二个整数输入框
}
}
RETURN_TYPES = ("INT", "INT") # 返回两个整数
FUNCTION = "process_inputs"
CATEGORY = "Meeeyo/String"
DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo"
OUTPUT_NODE = False
def process_inputs(self, int1, int2):
return (int1, int2)
#======添加前后缀
class AddPrefixSuffix:
def __init__(self):
@@ -1106,4 +1174,99 @@ class FindFirstLineContent:
return ("",)
except Exception as e:
return (f"Error: {str(e)}",)
return (f"Error: {str(e)}",)
#======视频指令词模板
class GenerateVideoPrompt:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"input_text": ("STRING", {"multiline": True, "default": ""}),
"mode": (["原文本", "文生视频", "图生视频", "首尾帧视频", "视频负面词"],)
},
"optional": {}
}
RETURN_TYPES = ("STRING",)
FUNCTION = "generate_prompt"
CATEGORY = "Meeeyo/String"
DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo"
def generate_prompt(self, input_text, mode):
try:
if mode == "原文本":
return (input_text,)
elif mode == "文生视频":
prefix = """You are a highly experienced cinematic director, skilled in creating detailed and engaging visual narratives. When crafting prompts for text-to-video generation based on user input, your goal is to provide precise, chronological descriptions that guide the generation process. Your prompt should focus on clear visual details, including specific movements, appearances, camera angles, and environmental context.
- Main Action: Start with a clear, concise description of the core action or event in the scene. This should be the focal point of the video.
- Movement and Gestures: Describe any movements or gestures in the scene, whether from characters, objects, or the environment. Include specifics about how these movements are executed.
- Appearance of Characters or Objects: Provide detailed descriptions of any characters or objects, focusing on aspects such as their physical appearance, clothing, and visual characteristics.
- Background and Environment: Elaborate on the surrounding environment, highlighting important visual elements such as landscape features, architecture, or significant objects. These should support the action and enrich the scene.
- Camera Angles and Movements: Specify the camera perspective (e.g., wide shot, close-up) and any movements (e.g., tracking, zooming, panning).
- Lighting and Colors: Detail the lighting setup—whether natural, artificial, or dramatic—and how it impacts the scene’s atmosphere. Describe color tones that contribute to the mood.
- Sudden Changes or Events: If any major shifts occur during the scene (e.g., a lighting change, weather shift, or emotional change), describe these transitions in detail.
By structuring your prompt in this way, you ensure that the video output will be both engaging and professionally aligned with the user’s intended vision. The description should remain within the 200-word limit while maintaining a smooth flow and cinematic quality.
The following is the main content of mine:
"""
return (prefix + input_text,)
elif mode == "图生视频":
prefix = """You are tasked with creating a cinematic, highly detailed video scene based on a given image or user description. This prompt is designed to generate an immersive and visually dynamic video experience by focusing on precise, chronological details. The goal is to build a vivid and realistic portrayal of the scene, paying close attention to every element, from the main action to environmental nuances. The description should flow seamlessly, focusing on essential visual and cinematic aspects while adhering to the 200-word limit.
- Main Action/Focus:
Begin with a clear, concise description of the central action or key object in the scene. This could be a person, an object, or an event taking place, providing the core of the scene’s narrative.
- Environment and Objects:
Describe the surrounding environment or objects in detail. Focus on their textures, colors, scale, and positioning. These details should support the main action and contribute to the atmosphere of the scene.
- Background Details:
Provide a vivid depiction of the background. This could include natural or architectural elements, distant landscapes, or other features that add context to the main subject. These details should enrich the visual storytelling.
- Camera Perspective and Movements:
Specify the camera angle or perspective being used—whether it’s a wide shot, a close-up, or something more dynamic like a tracking shot or pan. Include any camera movements, such as zooms, tilts, or dollies, if applicable.
- Lighting and Colors:
Detail the lighting in the scene, explaining whether it’s natural, artificial, or a combination of both. Consider how the lighting affects the mood, the shadows it creates, and the color temperature (warm or cool).
- Atmospheric or Environmental Changes:
If there are any shifts in the scene, like a sudden change in weather, lighting, or emotion, describe these transitions clearly. These environmental changes add dynamic elements to the video.
- Final Details:
Ensure that all visual and contextual elements are cohesive and align with the image or input provided. Make sure the description transitions smoothly from one point to the next.
By following this structure, you ensure that every aspect of the scene is addressed with precision, providing a detailed, cinematic prompt that is easily translated into a video. Keep the descriptions concise, ensuring all visual and environmental factors come together to create a fluid and engaging cinematic experience.
The following is the main content of mine:
"""
return (prefix + input_text,)
elif mode == "首尾帧视频":
prefix = """You are an expert filmmaker renowned for transforming static imagery into compelling cinematic sequences. Using two images provided by the user, your task is to create a seamless visual narrative that bridges Image One to Image Two. Focus on the dynamic transition, highlighting actions, environmental shifts, and visual elements that unfold in chronological order. Craft your description with the language of cinematography, ensuring a fluid and immersive narrative.
Requirements:
Scene Continuity:
- Begin with a detailed description of Image One’s setting, including central characters, objects, or key visual elements.
- Follow with a smooth narrative of the transition, emphasizing movement, visual progression, or any changes between the images.
- Conclude with a description of Image Two’s key details, noting the evolution of the environment, characters, or visual composition.
Richly Detailed Description:
- Capture notable actions, expressions, or gestures of characters or subjects.
- Describe environmental details such as lighting, color palette, weather, and atmosphere.
- Incorporate cinematographic techniques, including camera angles, zooms, tracking shots, or any dynamic movements.
Emotional and Contextual Flow:
- Highlight the emotional connection between the two images or the tone shift (e.g., from calm to tense, or from chaotic to serene).
- Prioritize visual coherence, even if there are discrepancies between the user’s input and the images.
Output Format:
- Begin by detailing Image One’s core elements and actions.
- Smoothly transition, describing visual progressions and movements.
- End with the details and conclusion of Image Two.
- Limit to 200 words in a single cohesive paragraph.
The following is the main content of mine:
"""
return (prefix + input_text,)
elif mode == "视频负面词":
return (
"""Overexposure, static artifacts, blurred details, visible subtitles, low-resolution paintings, still imagery, overly gray tones, poor quality, JPEG compression artifacts, unsightly distortions, mutilated features, redundant or extra fingers, poorly rendered hands, poorly depicted faces, anatomical deformities, facial disfigurements, misshapen limbs, fused or distorted fingers, cluttered and distracting background elements, extra or missing limbs (e.g., three legs), overcrowded backgrounds with excessive figures, reversed or upside-down compositions""",)
else:
return ("",)
except Exception as e:
return (f"Error: {str(e)}",)