File size: 6,764 Bytes
b7cb53b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
"""

DGG NWN Custom Nodes for ComfyUI

Specialized nodes for Neverwinter Nights character enhancement workflow.

"""

class NWNCharacterEnhancePrompt:
    """

    Generate optimized prompts for NWN character enhancement.

    Automatically creates prompt/negative prompt pairs based on character archetype.

    """
    
    CHARACTER_PRESETS = {
        "paladin_female": {
            "base": "female paladin warrior, ornate silver plate armor with golden trim",
            "features": "noble elven features, determined expression, flowing hair",
        },
        "paladin_male": {
            "base": "male paladin warrior, heavy plate armor with holy symbols",
            "features": "strong jawline, short hair, battle-worn face",
        },
        "mage_female": {
            "base": "female arcane mage, flowing magical robes with arcane patterns",
            "features": "intelligent eyes, mysterious aura, elegant features",
        },
        "mage_male": {
            "base": "male wizard, elaborate robes with mystical symbols",
            "features": "wise expression, aged features, long beard",
        },
        "rogue_female": {
            "base": "female rogue assassin, dark leather armor with hidden blades",
            "features": "cunning eyes, agile build, sharp features",
        },
        "rogue_male": {
            "base": "male thief, practical leather gear with pouches",
            "features": "shadowy expression, quick reflexes, scarred face",
        },
        "warrior_female": {
            "base": "female barbarian warrior, fur-lined armor with battle damage",
            "features": "fierce expression, muscular build, war paint",
        },
        "warrior_male": {
            "base": "male fighter, practical plate mail with sword and shield",
            "features": "battle-hardened face, strong build, short cropped hair",
        },
    }
    
    QUALITY_SUFFIXES = {
        "ultra": "masterpiece, best quality, ultra detailed, 8k uhd, ray tracing, photorealistic",
        "high": "high quality, detailed, 4k, professional lighting, realistic",
        "medium": "good quality, detailed, sharp focus",
    }
    
    NEGATIVE_BASE = "low quality, blurry, pixelated, low poly, cartoonish, anime style, deformed, bad anatomy, extra limbs, watermark, signature, text"
    
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "character_class": (["paladin", "mage", "rogue", "warrior"],),
                "gender": (["female", "male"],),
                "race": (["human", "elf", "dwarf", "halfling", "half-elf", "half-orc"],),
                "quality": (["ultra", "high", "medium"],),
                "custom_details": ("STRING", {"default": "", "multiline": True}),
            }
        }
    
    RETURN_TYPES = ("STRING", "STRING")
    RETURN_NAMES = ("positive_prompt", "negative_prompt")
    FUNCTION = "generate_prompt"
    CATEGORY = "DGG/NWN"
    
    def generate_prompt(self, character_class, gender, race, quality, custom_details):
        # Get preset
        preset_key = f"{character_class}_{gender}"
        preset = self.CHARACTER_PRESETS.get(preset_key, self.CHARACTER_PRESETS["warrior_male"])
        
        # Build prompt
        race_desc = f"{race} " if race != "human" else ""
        
        positive = f"photorealistic {race_desc}{preset['base']}, {preset['features']}"
        
        if custom_details.strip():
            positive += f", {custom_details.strip()}"
        
        positive += f", {self.QUALITY_SUFFIXES[quality]}"
        
        negative = self.NEGATIVE_BASE
        
        return (positive, negative)


class NWNImagePreprocess:
    """

    Preprocess NWN screenshots for better enhancement results.

    - Removes UI elements

    - Normalizes lighting

    - Isolates character

    """
    
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "image": ("IMAGE",),
                "remove_background": ("BOOLEAN", {"default": True}),
                "normalize_lighting": ("BOOLEAN", {"default": True}),
                "upscale_first": ("BOOLEAN", {"default": False}),
            }
        }
    
    RETURN_TYPES = ("IMAGE",)
    FUNCTION = "preprocess"
    CATEGORY = "DGG/NWN"
    
    def preprocess(self, image, remove_background, normalize_lighting, upscale_first):
        import torch
        import numpy as np
        
        # Convert to numpy
        if isinstance(image, torch.Tensor):
            img_np = image.cpu().numpy()
            if img_np.ndim == 4:
                img_np = img_np[0]  # Remove batch dimension
        else:
            img_np = np.array(image)
        
        # Normalize to 0-1 if needed
        if img_np.max() > 1.0:
            img_np = img_np / 255.0
        
        if normalize_lighting:
            # Simple contrast normalization
            for c in range(3):
                channel = img_np[:, :, c]
                min_val = channel.min()
                max_val = channel.max()
                if max_val > min_val:
                    img_np[:, :, c] = (channel - min_val) / (max_val - min_val)
        
        # Convert back to tensor
        result = torch.from_numpy(img_np).unsqueeze(0)
        
        return (result,)


class NWNBatchProcessor:
    """

    Process multiple NWN character images in batch.

    Useful for generating front/side/back views consistently.

    """
    
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "images": ("IMAGE",),
                "prompt_template": ("STRING", {"default": "photorealistic fantasy character, {view} view"}),
                "views": ("STRING", {"default": "front,side,back"}),
            }
        }
    
    RETURN_TYPES = ("IMAGE", "STRING")
    RETURN_NAMES = ("images", "view_prompts")
    FUNCTION = "process_batch"
    CATEGORY = "DGG/NWN"
    
    def process_batch(self, images, prompt_template, views):
        view_list = [v.strip() for v in views.split(",")]
        prompts = [prompt_template.format(view=v) for v in view_list]
        return (images, "\n".join(prompts))


# Node mappings for ComfyUI
NODE_CLASS_MAPPINGS = {
    "NWNCharacterEnhancePrompt": NWNCharacterEnhancePrompt,
    "NWNImagePreprocess": NWNImagePreprocess,
    "NWNBatchProcessor": NWNBatchProcessor,
}

NODE_DISPLAY_NAME_MAPPINGS = {
    "NWNCharacterEnhancePrompt": "🎮 NWN Character Prompt",
    "NWNImagePreprocess": "🎮 NWN Image Preprocess",
    "NWNBatchProcessor": "🎮 NWN Batch Processor",
}