diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..63c91e9 --- /dev/null +++ b/__init__.py @@ -0,0 +1,12 @@ +import os +from .modules.textbatch import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS + +# 獲取當前目錄路徑 +EXTENSION_FOLDER = os.path.dirname(os.path.realpath(__file__)) + +# 定義 Web UI 相關設定 +WEB_DIRECTORY = os.path.join(EXTENSION_FOLDER, "js") +NODE_CLASS_MAPPINGS = NODE_CLASS_MAPPINGS +NODE_DISPLAY_NAME_MAPPINGS = NODE_DISPLAY_NAME_MAPPINGS + +__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"] \ No newline at end of file diff --git a/js/textbatch.js b/js/textbatch.js new file mode 100644 index 0000000..51148ee --- /dev/null +++ b/js/textbatch.js @@ -0,0 +1,158 @@ +import { app } from "../../scripts/app.js"; +import { api } from "../../scripts/api.js"; + +// 用於存儲節點 ID 映射 +const nodeIdMap = new Map(); + +// 註冊自定義事件處理器 +api.addEventListener("textbatch-node-feedback", (event) => { + console.log("Received node feedback:", event); + try { + // 從 CustomEvent 中獲取 data + const data = event.detail; + + // 檢查 data 物件的完整性 + if (!data || !data.node_id) { + console.error("Invalid data received:", data); + return; + } + + const nodeId = data.node_id; + console.log("Looking for node:", nodeId, "Data received:", data); + + // 嘗試從 nodeIdMap 中獲取節點 + let node = nodeIdMap.get(nodeId); + + // 如果在 Map 中找不到,再嘗試其他方法 + if (!node) { + node = app.graph._nodes_by_id[nodeId] || + app.graph.getNodeById(parseInt(nodeId)) || + [...app.graph.nodes].find(n => n.id == nodeId); + } + + if (!node) { + console.warn("Node not found by ID:", nodeId, "Available nodes:", + Array.from(nodeIdMap.keys())); + return; + } + + console.log("Found node:", node); + const widget = node.widgets.find(w => w.name === data.widget_name); + if (!widget) { + console.warn("Widget not found:", data.widget_name); + return; + } + + if (data.type === "int") { + console.log("Updating widget value:", data.value); + widget.value = parseInt(data.value); + } else { + widget.value = data.value; + } + + // 觸發小部件的變更事件 + if (widget.callback) { + widget.callback(widget.value); + } + } catch (error) { + console.error("Error in node feedback handler:", error); + } +}); + +// 註冊佇列事件處理器 +api.addEventListener("textbatch-add-queue", (data) => { + try { + console.log("Received queue event:", data); + + // 檢查是否正在處理中 + if (app.isProcessing) { + console.log("Already processing, queueing next prompt"); + } + + // 獲取當前工作流程 + const workflow = app.graph.serialize(); + console.log("Current workflow:", workflow); + + // 確保在下一個事件循環中執行 + setTimeout(() => { + try { + console.log("Executing queued prompt"); + // 使用 queuePrompt 的完整參數 + app.queuePrompt(0, 1); + console.log("Queue prompt executed"); + } catch (queueError) { + console.error("Error queueing prompt:", queueError); + } + }, 100); + } catch (error) { + console.error("Error in textbatch-add-queue handler:", error); + console.error("Error details:", { + message: error.message, + stack: error.stack + }); + } +}); + +// 為特定節點添加自定義行為 +app.registerExtension({ + name: "TextBatch.TextBatchNode", + async beforeRegisterNodeDef(nodeType, nodeData, app) { + //console.log("Registering node type:", nodeData.name); + + if (nodeData.name === "TextBatch" || + nodeData.name === "TextQueueProcessor" || + nodeData.name === "ZippedPromptBatch" || + nodeData.name === "ZippedPromptBatchAdvanced") { + + console.log("Adding custom behavior to node:", nodeData.name); + + // 添加自定義小部件行為 + const onNodeCreated = nodeType.prototype.onNodeCreated; + nodeType.prototype.onNodeCreated = function() { + const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined; + + // 確保節點有有效的 ID + if (!this.id || this.id === -1) { + console.warn("Invalid node ID detected, waiting for proper initialization"); + // 等待下一個事件循環再進行初始化 + setTimeout(() => { + console.log("Retrying node initialization:", nodeData.name, "ID:", this.id); + // 存儲節點 ID + if (this.id && this.id !== -1) { + nodeIdMap.set(this.id, this); + // 為節點添加自定義標題 + this.addWidget("text", "status", "", (v) => { + console.log("Status widget updated:", v); + this.status = v; + }); + } + }, 0); + } else { + console.log("Node created:", nodeData.name, "ID:", this.id); + nodeIdMap.set(this.id, this); + this.addWidget("text", "status", "", (v) => { + console.log("Status widget updated:", v); + this.status = v; + }); + } + + return r; + }; + + // 添加節點刪除處理 + const onNodeRemoved = nodeType.prototype.onRemoved; + nodeType.prototype.onRemoved = function() { + console.log("Node removed:", this.id); + nodeIdMap.delete(this.id); + if (onNodeRemoved) { + onNodeRemoved.apply(this, arguments); + } + }; + } + } +}); + +// api.addEventListener('executed', async ({ detail }) => { +// console.log('#executed', detail) +// console.log(output) +// }) \ No newline at end of file diff --git a/modules/textbatch/__init__.py b/modules/textbatch/__init__.py new file mode 100644 index 0000000..ceb0e38 --- /dev/null +++ b/modules/textbatch/__init__.py @@ -0,0 +1,3 @@ +from .nodes import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS + +__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] \ No newline at end of file diff --git a/modules/textbatch/nodes.py b/modules/textbatch/nodes.py new file mode 100644 index 0000000..ce7dabc --- /dev/null +++ b/modules/textbatch/nodes.py @@ -0,0 +1,457 @@ +import os +import json +import logging +from server import PromptServer +import torch +import numpy as np +from typing import List, Union + +# 設定基本的日誌記錄格式和級別 +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +class TextBatchNode: + """ + 文本批次處理節點 + 用於將大型文本文件按照指定分隔符分割成多個部分 + 支持狀態保存和恢復,可以記住上次處理的位置 + """ + def __init__(self): + # 初始化狀態文件路徑,用於保存處理進度 + self.state_file = os.path.join(os.path.dirname(__file__), "text_batch_state.json") + self.state = self.load_state() + self.reset_state() # 添加初始化重置 + + def reset_state(self): + """重置狀態到初始值""" + self.state = { + "prompts": [], + "current_index": 0, + "last_input": "", + "last_input_mode": "", + "last_separator": "", + "last_separator_type": "newline", + "last_start_index": 0, + "completed": False + } + self.save_state() + + @classmethod + def INPUT_TYPES(cls): + """ + 定義節點的輸入參數類型和預設值 + """ + return { + "required": { + # 修改預設值為 text + "input_mode": (["text", "file"], {"default": "text"}), + # 文本文件路徑輸入 + "text_file": ("STRING", {"multiline": False, "default": "Enter the path to your text file here"}), + # 直接輸入文本 + "input_text": ("STRING", { + "multiline": True, + "default": "Enter your text here...", + "placeholder": "Enter multiple prompts, one per line" + }), + # 分隔符類型 + "separator_type": (["newline", "custom"], {"default": "newline"}), + # 文本分隔符 + "separator": ("STRING", {"default": "---"}), + # 起始索引位置 + "start_index": ("INT", {"default": 0, "min": 0, "max": 10000}), + # 新增自動終止選項 + "auto_stop": ("BOOLEAN", {"default": True}), + }, + "hidden": {"unique_id": "UNIQUE_ID"} + } + + # 定義輸出類型 + RETURN_TYPES = ("STRING", "STRING", "INT", "INT", "BOOLEAN") + # 定義輸出名稱 + RETURN_NAMES = ("prompt", "status", "current_index", "total", "completed") + FUNCTION = "process_text" + CATEGORY = "TextBatch" + OUTPUT_NODE = True # 添加這行 + + def process_text(self, input_mode, text_file, input_text, separator_type, separator, start_index, auto_stop): + """ + 處理文本文件或直接輸入文本的主要方法 + 參數: + input_mode: 輸入模式(file或text) + text_file: 要處理的文本文件路徑 + input_text: 直接輸入的文本 + separator_type: 分隔符類型(custom或newline) + separator: 用於分割文本的分隔符 + start_index: 開始處理的索引位置 + auto_stop: 是否自動終止 + 返回: + tuple: (提示文本, 狀態信息, 當前索引, 總數, 是否完成) + """ + try: + # 檔案模式的驗證 + if input_mode == "file": + if not text_file.strip() or text_file == "Enter the path to your text file here": + return ("", "Error: Please provide a valid file path", -1, 0, True) + if not os.path.exists(text_file): + return ("", f"Error: File not found: {text_file}", -1, 0, True) + with open(text_file, 'r', encoding='utf-8') as file: + content = file.read().strip() + if not content: + return ("", "Error: File is empty", -1, 0, True) + current_input = text_file + else: + if not input_text.strip() or input_text == "Enter your text here...": + return ("", "Error: Please provide input text", -1, 0, True) + current_input = input_text + + # 檢查是否需要重置 + need_reset = ( + self.state.get("last_input") != current_input or + self.state.get("last_input_mode") != input_mode or + self.state.get("last_separator") != separator or + self.state.get("last_separator_type") != separator_type or + self.state.get("completed", False) + ) + + # 如果需要重置,重新加載所有數據 + if need_reset: + self.reset_state() + if input_mode == "file": + self.load_prompts(text_file, separator_type, separator) + else: + self.load_text_input(input_text, separator_type, separator) + + # 檢查是否成功加載了提示 + if len(self.state["prompts"]) == 0: + return ("", "Error: No valid prompts found", -1, 0, True) + + self.state.update({ + "last_input": current_input, + "last_input_mode": input_mode, + "last_separator": separator, + "last_separator_type": separator_type, + "current_index": 0 + }) + + total = len(self.state["prompts"]) + if total == 0: + return ("", "No prompts loaded", 0, 0, True) + + # 安全獲取當前索引 + current_index = min(self.state.get("current_index", 0), total - 1) + + try: + # 安全獲取當前提示 + prompt = self.state["prompts"][current_index] + except IndexError: + # 如果發生索引錯誤,重置到最後一個有效索引 + current_index = total - 1 + prompt = self.state["prompts"][current_index] + self.state["current_index"] = current_index + + # 檢查是否完成 + is_last = current_index >= total - 1 + + # 更新狀態 + if not is_last and auto_stop: + self.state["current_index"] = current_index + 1 + completed = False + else: + completed = True + + self.state["completed"] = completed + + # 生成狀態信息 + status = f"Processing {current_index + 1}/{total}" + if input_mode == "file": + status += f" | File: {os.path.basename(text_file)}" + if completed: + status += " | Completed" + + # 保存狀態 + self.save_state() + + # 更新節點顯示的當前索引 + if not completed: + PromptServer.instance.send_sync("textbatch-node-feedback", + {"node_id": unique_id, "widget_name": "start_index", "type": "int", "value": self.state["current_index"]}) + + return (prompt, status, current_index, total, completed) + + except Exception as e: + logger.error(f"Error in process_text: {str(e)}") + return ("", f"Error: {str(e)}", -1, 0, True) + + def load_prompts(self, text_file, separator_type, separator): + """ + 從文件中加載並分割提示文本 + 參數: + text_file: 文本文件路徑 + separator_type: 分隔符類型(custom或newline) + separator: 用於分割文本的分隔符 + """ + try: + with open(text_file, 'r', encoding='utf-8') as file: + content = file.read() + + # 根據分隔符類型選擇分割方式 + if separator_type == "newline": + self.state["prompts"] = [prompt.strip() for prompt in content.splitlines() if prompt.strip()] + else: + self.state["prompts"] = [prompt.strip() for prompt in content.split(separator) if prompt.strip()] + + logger.info(f"Loaded {len(self.state['prompts'])} prompts from {text_file}") + except Exception as e: + logger.error(f"Error loading prompts: {str(e)}") + raise + + def load_text_input(self, input_text, separator_type, separator): + """ + 處理直接輸入的文本 + 參數: + input_text: 輸入的文本 + separator_type: 分隔符類型(custom或newline) + separator: 用於分割文本的分隔符 + """ + try: + # 根據分隔符類型選擇分割方式 + if separator_type == "newline": + self.state["prompts"] = [prompt.strip() for prompt in input_text.splitlines() if prompt.strip()] + else: + self.state["prompts"] = [prompt.strip() for prompt in input_text.split(separator) if prompt.strip()] + + logger.info(f"Loaded {len(self.state['prompts'])} prompts from direct input") + except Exception as e: + logger.error(f"Error processing input text: {str(e)}") + raise + + def load_state(self): + """ + 從狀態文件中加載之前的處理狀態 + """ + try: + if os.path.exists(self.state_file): + with open(self.state_file, 'r') as f: + return json.load(f) + except Exception as e: + logger.error(f"Error loading state file: {str(e)}") + return { + "prompts": [], + "current_index": 0, + "last_input": "", + "last_input_mode": "file", + "last_separator": "", + "last_separator_type": "newline", + "last_start_index": 0, + "completed": False # 添加完成狀態標記 + } + + def save_state(self): + """ + 將當前處理狀態保存到狀態文件 + """ + try: + with open(self.state_file, 'w') as f: + json.dump(self.state, f) + except Exception as e: + logger.error(f"Error saving state file: {str(e)}") + + @classmethod + def IS_CHANGED(cls, **kwargs): + """ + 控制節點的執行頻率 + 返回不同的值會觸發節點重新執行 + """ + current_index = kwargs.get("current_index", 0) + total = kwargs.get("total", 0) + completed = kwargs.get("completed", False) + auto_stop = kwargs.get("auto_stop", True) + + # 如果啟用了自動停止且未完成,返回 float("nan") 觸發重新執行 + if auto_stop and not completed and current_index < total - 1: + return float("nan") # 使用 nan 確保每次都會觸發重新執行 + + return current_index # 返回當前索引,不會觸發重新執行 + +class TextSplitCounterNode: + """ + 文本分割計數節點 + 用於計算分割後的文本總數 + """ + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "input_mode": (["file", "text"], {"default": "file"}), + "text_file": ("STRING", {"multiline": False, "default": "Enter the path to your text file here"}), + "input_text": ("STRING", { + "multiline": True, + "default": "Enter your text here...", + }), + "separator_type": (["newline", "custom"], {"default": "newline"}), + "separator": ("STRING", {"default": "---"}), + } + } + + RETURN_TYPES = ("INT", "STRING",) + RETURN_NAMES = ("count", "status") + FUNCTION = "count_splits" + CATEGORY = "TextBatch" + + def count_splits(self, input_mode, text_file, input_text, separator_type, separator): + try: + if input_mode == "file": + if not os.path.exists(text_file): + return (0, f"Error: File not found: {text_file}") + with open(text_file, 'r', encoding='utf-8') as file: + content = file.read() + else: + content = input_text + + # 根據分隔符類型計算分割數 + if separator_type == "newline": + splits = [x.strip() for x in content.splitlines() if x.strip()] + else: + splits = [x.strip() for x in content.split(separator) if x.strip()] + + count = len(splits) + status = f"Total splits: {count}" + return (count, status) + except Exception as e: + logger.error(f"Error in count_splits: {str(e)}") + return (0, f"Error: {str(e)}") + + + + + +class TextQueueProcessor: + """處理文字佇列的節點""" + def __init__(self): + self.state_file = os.path.join(os.path.dirname(__file__), "text_queue_processor_state.json") + self.state = self.load_state() + self.reset_state() + + def reset_state(self): + """重置狀態到初始值""" + self.state = { + "current_index": 0, + "last_input": "", + "completed": False + } + self.save_state() + + def load_state(self): + """從狀態文件中加載之前的處理狀態""" + try: + if os.path.exists(self.state_file): + with open(self.state_file, 'r') as f: + return json.load(f) + except Exception as e: + logger.error(f"Error loading state file: {str(e)}") + return { + "current_index": 0, + "last_input": "", + "completed": False + } + + def save_state(self): + """將當前處理狀態保存到狀態文件""" + try: + with open(self.state_file, 'w') as f: + json.dump(self.state, f) + except Exception as e: + logger.error(f"Error saving state file: {str(e)}") + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "text": ("STRING", { + "multiline": True, + "default": "1girl\n1cat\n1dog", + "placeholder": "每行輸入一個提示詞" + }), + "start_index": ("INT", {"default": 0, "min": 0, "max": 10000}), + "trigger_next": ("BOOLEAN", {"default": True, "label_on": "Trigger", "label_off": "Don't trigger"}), + }, + "hidden": {"unique_id": "UNIQUE_ID"} + } + + RETURN_TYPES = ("STRING", "INT", "INT", "BOOLEAN", "STRING") + RETURN_NAMES = ("text", "current_index", "total", "completed", "status") + FUNCTION = "process" + CATEGORY = "TextBatch" + OUTPUT_NODE = True + + def process(self, text, start_index, trigger_next, unique_id): + try: + # 檢查是否需要重置 + need_reset = ( + self.state.get("last_input") != text or + self.state.get("completed", False) + ) + + if need_reset: + self.reset_state() + self.state["last_input"] = text + + # 分割文本為行 + lines = [line.strip() for line in text.splitlines() if line.strip()] + total = len(lines) + + if total == 0: + return ("", -1, 0, True, "No valid text found") + + # 獲取當前索引 + current_index = min(max(start_index, self.state.get("current_index", 0)), total - 1) + + # 獲取當前行 + current_text = lines[current_index] + + # 檢查是否是最後一行 + is_last = current_index >= total - 1 + + # 更新狀態 + if not is_last and trigger_next: + self.state["current_index"] = current_index + 1 + completed = False + # 使用自己的事件名稱 + PromptServer.instance.send_sync("textbatch-add-queue", {}) + else: + completed = True + self.state["current_index"] = 0 + + self.state["completed"] = completed + self.save_state() + + # 生成狀態信息 + status = f"Processing {current_index + 1}/{total}" + if completed: + status += " | Completed" + + # 更新節點顯示的當前索引 + if not completed: + PromptServer.instance.send_sync("textbatch-node-feedback", + {"node_id": unique_id, "widget_name": "start_index", "type": "int", "value": self.state["current_index"]}) + + return (current_text, current_index, total, completed, status) + + except Exception as e: + logger.error(f"Error in process: {str(e)}") + return ("", -1, 0, True, f"Error: {str(e)}") + +# 節點類映射 +NODE_CLASS_MAPPINGS = { + "TextBatch": TextBatchNode, + "TextQueueProcessor": TextQueueProcessor, + "TextSplitCounter": TextSplitCounterNode +} + +# 節點顯示名稱映射 +NODE_DISPLAY_NAME_MAPPINGS = { + "TextBatch": "Text Batch", + "TextQueueProcessor": "Text Queue Processor", + "TextSplitCounter": "Text Split Counter" +} \ No newline at end of file diff --git a/modules/textbatch/text_batch_state.json b/modules/textbatch/text_batch_state.json new file mode 100644 index 0000000..4b71db0 --- /dev/null +++ b/modules/textbatch/text_batch_state.json @@ -0,0 +1 @@ +{"prompts": ["1girl", "1cat", "1dog"], "current_index": 2, "last_input": "1girl\n1cat\n1dog", "last_input_mode": "text", "last_separator": "---", "last_separator_type": "newline", "last_start_index": 0, "completed": true} \ No newline at end of file diff --git a/modules/textbatch/text_queue_processor_state.json b/modules/textbatch/text_queue_processor_state.json new file mode 100644 index 0000000..5b7f3ea --- /dev/null +++ b/modules/textbatch/text_queue_processor_state.json @@ -0,0 +1 @@ +{"current_index": 0, "last_input": "realistic, high quality,A silver-haired woman with sleek, glowing strands and fox ears perched atop her head, covered in soft fur that adds a playful charm. She wears a translucent white robe embroidered with ancient fox patterns. Behind her, nine lush, fluffy silver fox tails sway gently, their tips shimmering with subtle silver light. She stands barefoot on the grass, her fingertips glowing with pale blue energy, exuding a regal yet mysteriously enchanting aura, like a moonlit spirit.\n\nrealistic, high quality,A muscular man with molten, lava-like skin and fissures glowing faintly with flowing firelight. His shoulders and back are covered in scale-like patterns resembling snake skin, glinting with a metallic sheen. His magma horns branch out like ancient lantern structures, glowing with molten energy. His ember-like eyes burn deeply, and he wields a flaming spear with a molten gold tip, surrounded by coiling flames and smoke, exuding an air of fiery power and authority.\n\nrealistic, high quality,A one-legged giant with storm-gray, rough-textured skin resembling cowhide. A curved bull-like horn juts from his forehead, faintly glowing with blue-white lightning. His single, sturdy leg is tree-like, surrounded by swirling arcs of lightning at the knee. His deep-set eyes resemble dark pools, and an ancient thunder rune is etched across his chest. Draped in a tattered storm-cloud cloak, he holds a wooden staff engraved with lightning runes, emanating the commanding presence of a thunder god.\n\nrealistic, high quality,A headless warrior whose crimson eyes blaze from his chest, and a gaping mouth on his abdomen features jagged, sharp fangs in a perpetual snarl. His shoulders and back sprout jagged bone spikes, resembling shattered axe fragments. His bronze-like skin is hardened and scarred from battles. He wields a massive, jagged double-edged axe with a blade resembling beastly fangs. Broken chains drape from his back, radiating the unrelenting spirit of a warrior.\n\nrealistic, high quality,A bronze-skinned giant draped in animal pelts, with antler-like tree branches growing from his forehead, symbolizing life\u2019s resilience. A massive clay water gourd hangs at his waist, with droplets trickling down its surface. His large, calloused hands clutch a wooden staff adorned with green leaves and wild fruits. His muscular legs resemble ancient tree roots, standing firmly on cracked earth. Sunlight streams around him, and his resolute expression conveys strength and hope.\n\nrealistic, high quality,A woman draped in a nine-colored feathered robe, with glowing flame-like edges on her sleeves. Phoenix feathers of vivid hues are intricately woven into her long hair. Behind her, nine pairs of phoenix wings spread wide like a peacock fan, each feather bearing golden patterns with fiery tips. Her arms are slender yet strong like bird talons, and her feet subtly resemble bird claws. She cradles a glowing golden orb in her hands, standing amidst multicolored mist, with phoenix cries echoing softly in the air.\n\nrealistic, high quality,A towering man with a twisted, beastly face, his eyes glowing with a ravenous hunger. His face is concealed by a heavy metallic mask adorned with large tusks and deep claw marks. His muscular body, with skin as hard as iron, is surrounded by a dark red energy aura. On his back, powerful beast-like wings curve outward. A golden chain-like charm drapes across his chest, and whenever he opens his mouth, flames seem to consume everything around him.\n\nrealistic, high quality,A beastly man with a powerful, muscular body resembling a bear and a head like a fierce tiger, his face contorted in a savage expression, sharp fangs bared. His limbs are robust, and his claws resemble iron pincers. His back is covered with hard fur, spotted like a leopard\u2019s, and his eyes burn with a challenging fire. Lightning-like patterns pulse across his body, as if ready to unleash a thunderstorm. Heavy metallic ornaments hang from his shoulders, marking his dominance as a wild creature.\n\nrealistic, high quality,A tall, slender man draped in a translucent robe that gleams with light, embroidered with intricate runes and symbols of wisdom. On his forehead, he wears a helmet with multiple horns, signifying mystical knowledge. His pale, deep-set face exudes an aura of wisdom and serenity, his eyes filled with accumulated knowledge. In his hands, he holds an ancient book, with golden light particles floating around him. Behind him, delicate, crystalline butterfly-like wings unfurl, making him appear godlike and distant.\n\nrealistic, high quality,A tall, elongated man with a body like a dragon, his back adorned with massive, magnificent dragon wings. His arms are covered in dragon scale patterns, and his claws are as strong as steel. His eyes burn like fire, and his face bears horns and scales, a dragon's regal appearance. Wisps of steam and clouds swirl around his body. He wears a gradient-colored scale armor that seems ready to take flight at any moment, radiating the power to control storms, wind, and lightning.\n\nrealistic, high quality,A petite and graceful young woman with delicate features and a slender body, adorned with red ornaments symbolizing flames around her waist. Her skin gleams with a golden shine, and small snake-like horns sprout from her head. Her eyes glow with a fiery red intensity, exuding a dangerous aura. Serpentine metal adornments wind around her wrists, and her feet are light, leaving scorched marks with every step. A dragon-like flame tail extends from her back, radiating dazzling light.\n\nrealistic, high quality,A man dressed in simple farmer's clothing, his face calm and steady. His strong, muscular arms are adorned with golden rice charm symbols. His back seems to embody the bounty of fertile fields, and he wears woven straw garments on his shoulders, as if he could transform into the power of nature at any moment. His eyes carry the essence of the earth, and in his hand, he holds an intricately designed sickle. Surrounded by ripe grains and blooming flowers, he represents a deep connection with the land.\n\nrealistic, high quality,A massive man with smooth, deep blue skin resembling the vast ocean, his eyes as deep as the abyss, seemingly able to devour everything. Behind him, two pairs of wide fish fins spread, shimmering with silvery light, as if he moves gracefully through water. His long hair sways like seaweed, dancing with the ocean breeze. In his hand, he holds a coral staff. His lower body resembles the powerful tail of a shark, surrounded by the energy of crashing waves. He exudes the aura of a sea god, strong and enigmatic.\n\nrealistic, high quality, A tall and muscular man draped in an ancient dragon-scale cloak, his head crowned with thick antlers, symbolizing the power of nature. His eyes are as deep as twilight, and his skin carries the rich green hue of the earth, emanating the essence of forests and nature. In his hand, he holds a long wooden staff, its tip bent like the branch of an ancient tree. His broad shoulders exude vitality, and his steps are solid and purposeful, each one seemingly waking the earth beneath him.\n\nrealistic, high quality,A graceful woman with a bird-like form, dressed in a robe made of delicate blue feathers, her wings spread wide behind her, each feather shimmering like jade. Her eyes resemble clear lake waters, reflecting wisdom and freedom. Her long hair flows with the wind, resembling clouds in the sky. Her legs are slender and elegant, moving with the lightness of clouds beneath her feet. Her entire presence embodies the free and dynamic spirit of a bird soaring through the sky.\n\nrealistic, high quality,A colossal man with skin that transitions into deep blue shades, his body massive and imposing, with a chest as vast as the ocean. His face exudes the power and authority of a sea god. His arms are broad, and his hands are as nimble as fish fins. Behind him, massive whale-like fins unfurl, and his lower body is robust, with feet resembling the sturdy, unshakable rocks of the sea floor. His eyes are deep like the ocean, enigmatic and all-encompassing, as if guiding one into the endless sea.\n\nrealistic, high quality,A magnificent woman with hair ablaze like flames, wearing a robe of intertwined red and gold feathers. Behind her, a pair of fiery wings flicker with golden light, their edges glowing with intense heat. Her face is both beautiful and resolute, her eyes burning with the unyielding power of rebirth and eternal hope. Her long, graceful arms dance with an energy that stirs the wind and fire around her. With every step, a trail of scorching light is left behind, radiating immense vitality and a divine presence.\n\nrealistic, high quality,A strong man with a muscular frame like that of a wild beast, his head crowned with a lion-like mane and eyes sharp as daggers, a faint glimpse of sharp teeth visible in his mouth. His arms are thick and powerful, his fingers like iron. He wears armor resembling scales, shimmering as he moves. Behind him, dragon-like wings extend, robust and formidable, while his tail, resembling that of a lion, sways with strength. His entire presence radiates power and authority, like an invincible warrior.\n\nrealistic, high quality,A woman dressed in blue feathers that resemble lightning, the edges of her feathers glowing like thunderbolts. Her eyes burn with the intensity of a storm\u2019s lightning, exuding immense energy. Her head is adorned with sharp bird-like ears, making her appear alert and keen. Her arms are slender yet strong, resembling bird talons. Her body moves with agility and speed, and she hovers in the air, as if ready to summon a thunderstorm with every step, lightning flashing beneath her feet.\n\nrealistic, high quality,A robust man with a solid, muscular body, his skin tinted green like ancient stone. His head is crowned with curved bull horns, their sharp tips seeming capable of piercing through any obstacle. His eyes burn with determination and strength. His arms are massive, with defined muscles, and his hands are adorned with metallic armor resembling bull hooves. Behind him, a powerful tail extends, his steps firm and forceful as if shaking the very earth beneath him. His overall presence exudes the resilience and force of the earth itself.\n\nrealistic, high quality,A slender man with skin resembling bronze-colored dragon scales, his eyes deep like the sea. He wears dragon-like horns on his head, sharp as stones. A long dragon tail extends behind him, its scales shimmering in golden light under the sun. He wears light armor, appearing like a floating dragon figure, both graceful and authoritative. In his hand, he holds a weapon resembling a dragon's claw, emanating a power that controls winds and thunder.\n\nrealistic, high quality,A slender woman dressed in a long robe made of deep purple feathers, adorned with sparkling golden gemstones. Her beauty is both captivating and eerie, with eyes that resemble a moonlit lake, shimmering with an enchanting allure. Her hands are long and delicate, her fingertips sharp as blades. On her head, sharp claw-like horns extend, and behind her, two pairs of jet-black wings unfurl, glistening with silver light. She exudes an irresistible charm, yet concealed beneath it is a deadly danger.\n\nrealistic, high quality,A woman clad in white feathers, her back adorned with a pair of pristine crane wings that shimmer with golden light at the edges. Her face is delicate, her eyes gentle and serene, like ripples on a calm lake. Her arms stretch gracefully, every movement filled with harmony and natural beauty. Her legs are slender, her steps light as if she could take flight at any moment. Her presence exudes peace and divinity, as if she were the embodiment of nature itself.\n\nrealistic, high quality,A muscular man covered in hard, shell-like scales, his skin a dark red hue. On his head, he bears massive serpent-like horns, bent like bows, his eyes burning with fiery intensity. His arms are thick and powerful, with hands as hard as steel, the fingertips capable of shattering anything. Behind him, huge dragon-like wings extend, their scales gleaming with light. Beneath his feet lies a scorching land, and his presence radiates unmatched strength and dominance.\n\nrealistic, high quality,A slender and energetic woman dressed in shimmering attire resembling metal, adorned with small, pointed scales. On her head, several pairs of long antennae extend, her eyes insect-like, sharp and constantly shifting. Her arms take on the shape of insect limbs, highly agile and able to quickly change positions. Behind her, a long, insect-like tail trails, and her steps are rapid, her entire presence filled with dynamic energy. \n\nrealistic, high quality,A tall man dressed in black leather armor, with golden copper coins adorning his chest, exuding an aura of power. His head is crowned with a pair of upright bull horns, their sharp tips like knives, and his eyes burn brightly like a blazing fire, emanating fearlessness. His jaw and eyebrows are thick and strong, adding to his resolute appearance, his face thoughtful and focused. He holds a sword that gleams with a cold light, its tip as hard as steel, symbolizing justice and strength. His overall presence radiates a deep sense of righteousness, as if he could see through the injustices of the world.\nrealistic, high quality,A strong man dressed in mottled tiger fur clothing, his eyes gleaming with a fierce, tiger-like intensity. His face is rugged, with sharply defined facial muscles that carry a wild aura. On his head, small but powerful tiger ears extend outward. His hands resemble sharp tiger claws, and his steps are firm and controlled, emanating an overwhelming sense of menace. His overall image is one of a beast, full of raw power and dominance.\n\nrealistic, high quality,A man with the overwhelming presence of thunder, dressed in dark gray armor marked with lightning-like streaks across his chest. His entire body crackles with electric energy, muscles defined, as though ready to unleash immense power. His head is crowned with gleaming lightning horns, resembling the stormy skies, flashing bright with energy. His hands are as powerful as a thunder strike, holding a thunder sword that constantly emits electric sparks. Underfoot, he treads upon a special storm cloud, emitting deafening roars. His presence exudes an undeniable sense of threat.\n\nrealistic, high quality,A mysterious woman dressed in a black silk robe, intricately embroidered with ancient patterns. Her long, black hair spreads like a shadow, and her eyes are deep as an abyss, emitting a faint, eerie glow. Behind her floats an ancient ghost carriage, its wheels made of metal and bone, emitting a low, rumbling sound. Her arms are slender, with elongated fingers that seem to control the carriage with magic. An aura of stillness and coldness surrounds her, making it clear that one should not approach.\n\nrealistic, high quality,A man with bird-like features, dressed in dark feathered armor, his back adorned with massive, sharp wings that glimmer with metallic sheen. His facial features are sharp, with eyebrows like blades and eyes as piercing as a bird of prey, always ready to strike down his enemies. His arms are long and powerful, with fingers resembling sharp claws. His legs are strong, resembling those of a bird, covered in tough scales. His overall appearance exudes the aura of a predator, radiating an unchallenged presence wherever he goes.\n\nrealistic, high quality,A massive and powerful man, with a rounded, strong body shaped by the sea and storms. His skin is deep ocean blue, with scale-like details on his shoulders that give off an indestructible aura. His head is shaped like that of a fish, with sharp fins on his forehead and shark-like teeth on either side. His hands resemble the fins of a large fish, strong and capable of tearing through the ocean. His entire presence radiates the power of the vast sea, embodying an enduring and unstoppable force.\n\nrealistic, high quality,A man of both wisdom and strength, dressed in simple green robes with herbs and tools hanging from his waist. His face is kind, with thick eyebrows and eyes full of warmth and deep wisdom. In his hand, he holds a long herbal staff, adorned with intricate plant carvings. His back is covered with small grasses and vine-like plants, as if he is one with nature. His presence radiates peace and vitality, as if he can heal any wound or disease.", "completed": true} \ No newline at end of file