diff --git a/README.md b/README.md index 005bd47..7664460 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# πŸ”— Comfyui : Bjornulf_custom_nodes v0.44 πŸ”— +# πŸ”— Comfyui : Bjornulf_custom_nodes v0.45 πŸ”— # Coffee : β˜•β˜•β˜•β˜•β˜• 5/5 @@ -17,6 +17,7 @@ `26.` [🎲 Random line from input](#26----random-line-from-input) `28.` [πŸ”’ Text with random Seed](#28----text-with-random-seed) `32.` [πŸ§‘πŸ“ Character Description Generator](#32----character-description-generator) +`48.` [πŸ”€πŸŽ² Text scrambler (πŸ§‘ Character)](#48) ## β™» Loop β™» `6.` [β™» Loop](#6----loop) @@ -39,6 +40,7 @@ `37.` [πŸŽ²πŸ–Ό Random Image](#37----random-image) `40.` [🎲 Random (Model+Clip+Vae) - aka Checkpoint / Model](#40----random-modelclipvae---aka-checkpoint--model) `41.` [🎲 Random Load checkpoint (Model Selector)](#41----random-load-checkpoint-model-selector) +`48.` [πŸ”€πŸŽ² Text scrambler (πŸ§‘ Character)](#48) ## πŸ–ΌπŸ’Ύ Image Save πŸ’ΎπŸ–Ό `16.` [πŸ’ΎπŸ–ΌπŸ’¬ Save image for Bjornulf LobeChat](#16----save-image-for-bjornulf-lobechat-for-my-custom-lobe-chat) @@ -214,6 +216,7 @@ cd /where/you/installed/ComfyUI && python main.py - **v0.42**: Better README with category nodes, changes some node titles - **v0.43**: Add control_after_generate to Ollama and allow to keep in VRAM for 1 minute if needed. (For chaining quick generations.) Add fallback to 0.0.0.0 - **v0.44**: Allow ollama to have a cusom url in the file `ollama_ip.txt` in the comfyui custom nodes folder. Minor changes, add details/updates to README. +- **v0.45**: Add a new node : Text scrambler (Character), change text randomly using the file `scrambler/scrambler_character.json` in the comfyui custom nodes folder. # πŸ“ Nodes descriptions @@ -745,4 +748,11 @@ Here is an example with `Load images from folder` node, `Image details` node and Here another simple example taking a few selected images from a folder and combining them (For later processing for example) : -![combine images](screenshots/combine_images_4.png) \ No newline at end of file +![combine images](screenshots/combine_images_4.png) + +### 48 - πŸ”€πŸŽ² Text scrambler (πŸ§‘ Character) + +![scrambler character](screenshots/scrambler_character.png) + +**Description:** +Take text as input and scramble (randomize) the text by using the file `scrambler/character_scrambler.json` in the comfyui custom nodes folder. diff --git a/__init__.py b/__init__.py index f3aece9..bc91911 100644 --- a/__init__.py +++ b/__init__.py @@ -50,9 +50,11 @@ from .if_else import IfElse from .image_details import ImageDetails from .combine_images import CombineImages # from .pass_preview_image import PassPreviewImage +from .text_scramble_character import ScramblerCharacter NODE_CLASS_MAPPINGS = { "Bjornulf_ollamaLoader": ollamaLoader, + "Bjornulf_ScramblerCharacter": ScramblerCharacter, "Bjornulf_CombineImages": CombineImages, "Bjornulf_ImageDetails": ImageDetails, "Bjornulf_IfElse": IfElse, @@ -104,6 +106,7 @@ NODE_CLASS_MAPPINGS = { NODE_DISPLAY_NAME_MAPPINGS = { "Bjornulf_WriteText": "βœ’ Write Text", + "Bjornulf_ScramblerCharacter": "πŸ”€πŸŽ² Text scrambler (πŸ§‘ Character)", "Bjornulf_WriteTextAdvanced": "βœ’πŸ—” Advanced Write Text", "Bjornulf_LoopWriteText": "β™» Loop (βœ’πŸ—” Advanced Write Text)", "Bjornulf_LoopModelClipVae": "β™» Loop (Model+Clip+Vae)", diff --git a/pyproject.toml b/pyproject.toml index a37f042..81e8676 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "bjornulf_custom_nodes" description = "Nodes: Ollama, Text to Speech, Combine Texts, Random Texts, Save image for Bjornulf LobeChat, Text with random Seed, Random line from input, Combine images, Image to grayscale (black & white), Remove image Transparency (alpha), Resize Image, ..." -version = "0.44" +version = "0.45" license = {file = "LICENSE"} [project.urls] diff --git a/scrambler/character_scrambler.json b/scrambler/character_scrambler.json new file mode 100644 index 0000000..2698621 --- /dev/null +++ b/scrambler/character_scrambler.json @@ -0,0 +1,496 @@ +{ + "image_styles": { + "enabled": true, + "words": [ + "drawing", + "photography", + "manga", + "comic", + "watercolor", + "sketch", + "oil painting", + "digital art", + "3D render", + "pixel art", + "charcoal", + "pastel", + "anime", + "realistic", + "cartoon", + "impressionist", + "abstract", + "surreal", + "minimalist", + "collage" + ] + }, + "ages": { + "words": ["child", "teenager", "young", "adult", "middle-aged", "elderly"] + }, + "sex": { + "words": ["boy", "girl", "man", "woman"] + }, + "body_types": { + "words": [ + "slim", + "muscular", + "curvaceous", + "fat", + "athletic", + "chubby", + "lean", + "bulky", + "stocky", + "petite", + "hourglass", + "pear-shaped", + "rectangular", + "broad-shouldered", + "thin", + "plump", + "fit", + "lanky", + "buff", + "overweight" + ] + }, + "colors": { + "words": [ + "red", + "blue", + "green", + "yellow", + "purple", + "orange", + "pink", + "brown", + "black", + "white", + "gray", + "cyan", + "magenta", + "teal", + "turquoise", + "lavender", + "maroon", + "navy", + "olive", + "silver", + "gold", + "bronze", + "beige", + "cream", + "indigo", + "violet", + "chartreuse", + "lime", + "salmon", + "coral", + "ivory", + "khaki", + "mustard", + "peach", + "platinum", + "tan", + "aquamarine", + "burgundy", + "crimson", + "fuchsia" + ] + }, + "nationalities": { + "words": [ + "american", + "canadian", + "mexican", + "brazilian", + "argentinian", + "british", + "french", + "german", + "italian", + "spanish", + "russian", + "chinese", + "japanese", + "indian", + "australian", + "egyptian", + "south african", + "nigerian", + "kenyan", + "moroccan", + "swedish", + "norwegian", + "finnish", + "polish", + "dutch", + "belgian", + "swiss", + "austrian", + "greek", + "turkish", + "portuguese", + "colombian", + "chilean", + "venezuelan", + "peruvian", + "cuban", + "jamaican", + "filipino", + "thai", + "korean", + "vietnamese", + "indonesian", + "malaysian", + "pakistani", + "bangladeshi", + "saudi", + "iranian", + "iraqi", + "syrian", + "lebanese", + "israeli", + "palestinian", + "ethiopian", + "tanzanian", + "ugandan", + "ivorian", + "guyanese", + "haitian", + "dominican", + "bahamian", + "fijian", + "new zealander", + "icelandic", + "danish", + "luxembourgish", + "czech", + "slovak", + "hungarian", + "romanian", + "bulgarian", + "serbian", + "croatian", + "slovenian", + "bosnian", + "montenegrin", + "albanian", + "georgian", + "armenian", + "azerbaijani", + "kazakh", + "uzbek", + "afghan", + "nepali", + "sri lankan" + ] + }, + "occupations": { + "words": [ + "doctor", + "nurse", + "teacher", + "engineer", + "scientist", + "lawyer", + "accountant", + "architect", + "chef", + "mechanic", + "pilot", + "firefighter", + "police officer", + "soldier", + "artist", + "musician", + "writer", + "journalist", + "programmer", + "designer", + "photographer", + "videographer", + "graphic designer", + "web developer", + "data analyst", + "statistician", + "biologist", + "chemist", + "physicist", + "mathematician", + "pharmacist", + "dentist", + "veterinarian", + "paramedic", + "surgeon", + "psychologist", + "psychiatrist", + "social worker", + "therapist", + "electrician", + "plumber", + "carpenter", + "construction worker", + "truck driver", + "taxi driver", + "bus driver", + "train conductor", + "air traffic controller", + "real estate agent", + "salesperson", + "cashier", + "retail worker", + "bartender", + "waiter", + "barista", + "cleaner", + "security guard", + "janitor", + "farmer", + "fisherman", + "librarian", + "translator", + "interpreter", + "diplomat", + "consultant", + "project manager", + "marketing specialist", + "advertising executive", + "public relations officer", + "event planner", + "receptionist", + "customer service representative", + "stockbroker", + "banker", + "investment analyst", + "economist", + "actuary", + "financial advisor", + "loan officer", + "insurance agent", + "fitness trainer", + "yoga instructor", + "dancer", + "actor", + "director", + "producer", + "sound engineer", + "lighting technician", + "video editor", + "makeup artist", + "fashion designer", + "stylist", + "model", + "florist", + "baker", + "butcher", + "pastry chef", + "food critic", + "tour guide", + "historian", + "archaeologist", + "anthropologist", + "sociologist", + "political scientist", + "geologist", + "meteorologist", + "astronomer", + "marine biologist", + "zoologist", + "entomologist", + "forester", + "park ranger", + "urban planner", + "civil engineer", + "environmental engineer", + "software engineer", + "systems administrator", + "network engineer", + "database administrator", + "game developer", + "app developer", + "ethical hacker", + "technical support specialist", + "UX/UI designer", + "copywriter", + "editor", + "publisher", + "researcher", + "professor", + "lecturer", + "principal", + "school counselor", + "curriculum developer" + ] + }, + "emotions": { + "words": [ + "happy", + "sad", + "angry", + "afraid", + "surprised", + "disgusted", + "confused", + "excited", + "bored", + "nervous", + "proud", + "ashamed", + "jealous", + "content", + "lonely", + "anxious", + "frustrated", + "hopeful", + "curious", + "grateful" + ] + }, + "sizes": { + "enabled": true, + "words": [ + "very small", + "small", + "medium", + "large", + "very large", + "extra small", + "extra large", + "extra extra large", + "tiny", + "huge", + "gigantic", + "petite", + "oversized", + "minuscule", + "massive", + "colossal", + "slim", + "bulky" + ] + }, + "clothing_head": { + "enabled": true, + "words": [ + "beanie", + "baseball cap", + "fedora", + "sun hat", + "bucket hat", + "beret", + "scarf", + "headband", + "bandana", + "visor", + "wool hat", + "earmuffs", + "helmet", + "turban", + "veil", + "cowboy hat" + ] + }, + "clothing_top": { + "enabled": true, + "words": [ + "t-shirt", + "tank top", + "shirt", + "blouse", + "dress shirt", + "polo shirt", + "sweater", + "hoodie", + "cardigan", + "jacket", + "blazer", + "denim jacket", + "leather jacket", + "trench coat", + "pea coat", + "overcoat", + "sports coat", + "vest", + "suit jacket", + "puffer jacket", + "windbreaker", + "parka", + "gown", + "cocktail dress", + "sundress", + "maxi dress", + "mini dress", + "wrap dress", + "romper", + "jumpsuit", + "bodysuit", + "swimsuit", + "bra", + "bralette", + "corset", + "undershirt", + "thermal underwear", + "robe", + "nightgown", + "pajamas", + "tunic" + ] + }, + "clothing_bottom": { + "enabled": true, + "words": [ + "jeans", + "chinos", + "cargo pants", + "dress pants", + "shorts", + "khakis", + "sweatpants", + "joggers", + "leggings", + "yoga pants", + "track pants", + "culottes", + "capri pants", + "skirt", + "pencil skirt", + "pleated skirt", + "a-line skirt", + "mini skirt", + "maxi skirt", + "swim trunks", + "boxers", + "briefs", + "boxer briefs", + "panties", + "stockings", + "tights", + "slips", + "thermal leggings", + "overalls", + "jeggings" + ] + }, + "image_types": { + "words": [ + "portrait", + "macro", + "wide angle", + "close-up", + "aerial", + "panorama", + "action shot", + "long exposure", + "silhouette", + "black and white", + "night", + "fisheye", + "fashion", + "sports", + "still life", + "bokeh", + "dynamic" + ] + } +} diff --git a/screenshots/scrambler_character.png b/screenshots/scrambler_character.png new file mode 100644 index 0000000..d21f9c3 Binary files /dev/null and b/screenshots/scrambler_character.png differ diff --git a/text_scramble_character.py b/text_scramble_character.py new file mode 100644 index 0000000..10127f8 --- /dev/null +++ b/text_scramble_character.py @@ -0,0 +1,54 @@ +import random +import json +import os +import re + +class ScramblerCharacter: + def __init__(self): + self.scramble_config = self.load_scramble_config() + + def load_scramble_config(self): + script_dir = os.path.dirname(os.path.realpath(__file__)) + config_path = os.path.join(script_dir, "scrambler/character_scrambler.json") + with open(config_path, "r") as f: + return json.load(f) + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "text": ("STRING", {"multiline": True, "default": "photography portrait of a happy middle-aged swedish woman nurse with a fit body, wearing a black headband, large blue parka and orange jeans."}), + "seed": ("INT", {"default": 0}), + }, + "optional": { + "image_styles": ("BOOLEAN", {"default": False}), + "ages": ("BOOLEAN", {"default": False}), + "sex": ("BOOLEAN", {"default": False}), + "body_types": ("BOOLEAN", {"default": False}), + "colors": ("BOOLEAN", {"default": False}), + "emotions": ("BOOLEAN", {"default": False}), + "nationalities": ("BOOLEAN", {"default": False}), + "clothing_head": ("BOOLEAN", {"default": False}), + "clothing_top": ("BOOLEAN", {"default": False}), + "clothing_bottom": ("BOOLEAN", {"default": False}), + "occupations": ("BOOLEAN", {"default": False}), + "sizes": ("BOOLEAN", {"default": False}), + "image_types": ("BOOLEAN", {"default": False}), + } + } + + RETURN_TYPES = ("STRING",) + FUNCTION = "scramble_words" + CATEGORY = "Bjornulf" + + def scramble_words(self, text, seed=None, **kwargs): + if seed is not None: + random.seed(seed) + + for category, config in self.scramble_config.items(): + if kwargs.get(f"{category}", config.get("enabled", False)): + words = config["words"] + pattern = r'\b(' + '|'.join(re.escape(word) for word in words) + r')\b' + text = re.sub(pattern, lambda m: random.choice(words), text, flags=re.IGNORECASE) + + return (text,) \ No newline at end of file