File size: 8,618 Bytes
3b2fcb1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
723c511
 
3b2fcb1
723c511
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b2fcb1
723c511
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
def inject(assembler, chain_definition, chain_items):
    if not chain_items:
        return

    final_settings = {}
    if chain_items and isinstance(chain_items[-1], dict) and chain_items[-1].get('is_final_settings'):
        final_settings = chain_items.pop()

    if not chain_items:
        return

    end_node_name = chain_definition.get('end')
    if not end_node_name or end_node_name not in assembler.node_map:
        print(f"Warning: Target node '{end_node_name}' for IPAdapter chain not found. Skipping chain injection.")
        return
        
    end_node_id = assembler.node_map[end_node_name]
    
    if 'model' not in assembler.workflow[end_node_id]['inputs']:
        print(f"Warning: Target node '{end_node_name}' is missing 'model' input. Skipping IPAdapter chain.")
        return
    
    current_model_connection = assembler.workflow[end_node_id]['inputs']['model']
    
    model_type = final_settings.get('model_type', 'sdxl')
    megapixels = 1.05 if model_type == 'sdxl' else 0.39

    first_preset = chain_items[0].get('preset', '')
    is_faceid_chain = 'FACEID' in first_preset.upper()

    if is_faceid_chain:
        for i, item_data in enumerate(chain_items):
            image_loader_id = assembler._get_unique_id()
            image_loader_node = assembler._get_node_template("LoadImage")
            image_loader_node['inputs']['image'] = item_data['image']
            assembler.workflow[image_loader_id] = image_loader_node
            
            image_scaler_id = assembler._get_unique_id()
            image_scaler_node = assembler._get_node_template("ImageScaleToTotalPixels")
            image_scaler_node['inputs']['image'] = [image_loader_id, 0]
            image_scaler_node['inputs']['megapixels'] = megapixels
            image_scaler_node['inputs']['upscale_method'] = "lanczos"
            assembler.workflow[image_scaler_id] = image_scaler_node

            ipadapter_loader_id = assembler._get_unique_id()
            ipadapter_loader_node = assembler._get_node_template("IPAdapterUnifiedLoaderFaceID")
            ipadapter_loader_node['inputs']['model'] = current_model_connection
            ipadapter_loader_node['inputs']['preset'] = item_data['preset']
            ipadapter_loader_node['inputs']['lora_strength'] = item_data.get('lora_strength', 0.6)
            ipadapter_loader_node['inputs']['provider'] = "CUDA"
            assembler.workflow[ipadapter_loader_id] = ipadapter_loader_node

            apply_id = assembler._get_unique_id()
            apply_node = assembler._get_node_template("IPAdapterFaceID")
            apply_node['inputs']['model'] = [ipadapter_loader_id, 0]
            apply_node['inputs']['ipadapter'] = [ipadapter_loader_id, 1]
            apply_node['inputs']['image'] = [image_scaler_id, 0]
            apply_node['inputs']['weight'] = item_data['weight']
            apply_node['inputs']['weight_faceidv2'] = final_settings.get('final_lora_strength', 0.6)
            apply_node['inputs']['weight_type'] = "linear"
            apply_node['inputs']['combine_embeds'] = final_settings.get('final_combine_method', 'concat')
            apply_node['inputs']['start_at'] = item_data.get('start_percent', 0.0)
            apply_node['inputs']['end_at'] = item_data.get('end_percent', 1.0)
            apply_node['inputs']['embeds_scaling'] = final_settings.get('final_embeds_scaling', 'V only')
            
            assembler.workflow[apply_id] = apply_node
            current_model_connection = [apply_id, 0]

        assembler.workflow[end_node_id]['inputs']['model'] = current_model_connection
        print(f"IPAdapter FaceID injector applied (Direct Apply). Redirected '{end_node_name}' model input through {len(chain_items)} FaceID node(s).")
        return

    else:
        pos_embed_outputs = []
        neg_embed_outputs = []

        for i, item_data in enumerate(chain_items):
            loader_type = 'FaceID' if 'FACEID' in item_data.get('preset', '') else 'Unified'
            loader_template_name = "IPAdapterUnifiedLoader"
            if loader_type == 'FaceID':
                loader_template_name = "IPAdapterUnifiedLoaderFaceID"

            image_loader_id = assembler._get_unique_id()
            image_loader_node = assembler._get_node_template("LoadImage")
            image_loader_node['inputs']['image'] = item_data['image']
            assembler.workflow[image_loader_id] = image_loader_node
            
            image_scaler_id = assembler._get_unique_id()
            image_scaler_node = assembler._get_node_template("ImageScaleToTotalPixels")
            image_scaler_node['inputs']['image'] = [image_loader_id, 0]
            image_scaler_node['inputs']['megapixels'] = megapixels
            image_scaler_node['inputs']['upscale_method'] = "lanczos"
            assembler.workflow[image_scaler_id] = image_scaler_node

            ipadapter_loader_id = assembler._get_unique_id()
            ipadapter_loader_node = assembler._get_node_template(loader_template_name)
            ipadapter_loader_node['inputs']['model'] = current_model_connection
            ipadapter_loader_node['inputs']['preset'] = item_data['preset']
            if loader_type == 'FaceID':
                 ipadapter_loader_node['inputs']['lora_strength'] = item_data.get('lora_strength', 0.6)
            assembler.workflow[ipadapter_loader_id] = ipadapter_loader_node
            
            encoder_id = assembler._get_unique_id()
            encoder_node = assembler._get_node_template("IPAdapterEncoder")
            encoder_node['inputs']['weight'] = item_data['weight']
            encoder_node['inputs']['ipadapter'] = [ipadapter_loader_id, 1]
            encoder_node['inputs']['image'] = [image_scaler_id, 0]
            assembler.workflow[encoder_id] = encoder_node
            
            pos_embed_outputs.append([encoder_id, 0])
            neg_embed_outputs.append([encoder_id, 1])

        pos_combiner_id = assembler._get_unique_id()
        pos_combiner_node = assembler._get_node_template("IPAdapterCombineEmbeds")
        pos_combiner_node['inputs']['method'] = final_settings.get('final_combine_method', 'concat')
        for i, conn in enumerate(pos_embed_outputs):
            pos_combiner_node['inputs'][f'embed{i+1}'] = conn
        assembler.workflow[pos_combiner_id] = pos_combiner_node

        neg_combiner_id = assembler._get_unique_id()
        neg_combiner_node = assembler._get_node_template("IPAdapterCombineEmbeds")
        neg_combiner_node['inputs']['method'] = final_settings.get('final_combine_method', 'concat')
        for i, conn in enumerate(neg_embed_outputs):
            neg_combiner_node['inputs'][f'embed{i+1}'] = conn
        assembler.workflow[neg_combiner_id] = neg_combiner_node
        
        final_loader_type = 'FaceID' if 'FACEID' in final_settings.get('final_preset', '') else 'Unified'
        final_loader_template_name = "IPAdapterUnifiedLoader"
        if final_loader_type == 'FaceID':
            final_loader_template_name = "IPAdapterUnifiedLoaderFaceID"

        final_loader_id = assembler._get_unique_id()
        final_loader_node = assembler._get_node_template(final_loader_template_name)
        final_loader_node['inputs']['model'] = current_model_connection
        final_loader_node['inputs']['preset'] = final_settings.get('final_preset', 'STANDARD (medium strength)')
        if final_loader_type == 'FaceID':
            final_loader_node['inputs']['lora_strength'] = final_settings.get('final_lora_strength', 0.6)
        assembler.workflow[final_loader_id] = final_loader_node

        apply_embeds_id = assembler._get_unique_id()
        apply_embeds_node = assembler._get_node_template("IPAdapterEmbeds")
        apply_embeds_node['inputs']['weight'] = final_settings.get('final_weight', 1.0)
        apply_embeds_node['inputs']['embeds_scaling'] = final_settings.get('final_embeds_scaling', 'V only')
        apply_embeds_node['inputs']['model'] = [final_loader_id, 0]
        apply_embeds_node['inputs']['ipadapter'] = [final_loader_id, 1]
        apply_embeds_node['inputs']['pos_embed'] = [pos_combiner_id, 0]
        apply_embeds_node['inputs']['neg_embed'] = [neg_combiner_id, 0]
        assembler.workflow[apply_embeds_id] = apply_embeds_node

        assembler.workflow[end_node_id]['inputs']['model'] = [apply_embeds_id, 0]
        print(f"IPAdapter Unified injector applied. Redirected '{end_node_name}' model input through {len(chain_items)} reference image(s).")