File size: 12,601 Bytes
7fb74b3
 
 
 
 
 
 
 
 
18758d9
 
 
 
 
bf10a9e
18758d9
0e4c91f
b329109
 
69656e5
0e4c91f
 
f11caf7
18758d9
 
 
 
f11caf7
18758d9
 
f658d06
18758d9
 
 
 
69656e5
0e4c91f
 
415b456
 
 
c1ec482
 
 
 
 
 
0e4c91f
c1ec482
 
 
 
 
 
 
 
 
 
 
415b456
0e4c91f
18758d9
b329109
f658d06
0e4c91f
 
 
b329109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0e4c91f
b329109
0e4c91f
 
b329109
0e4c91f
 
 
 
b329109
0e4c91f
b329109
0e4c91f
b329109
0e4c91f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b329109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0e4c91f
b329109
 
 
 
0e4c91f
 
 
b329109
 
 
 
0e4c91f
 
b329109
0e4c91f
 
18758d9
7fb74b3
ceef86b
c1ec482
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
415b456
 
 
0e4c91f
7fb74b3
 
f18f2e5
ceef86b
f18f2e5
7fb74b3
69656e5
 
 
 
 
 
 
 
415b456
 
 
 
18758d9
7fb74b3
 
18758d9
7fb74b3
f18f2e5
ceef86b
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
#!/bin/bash

# Print system information
echo "=== System Information ==="
echo "Python version: $(python3 --version)"
echo "CUDA version: $(nvcc --version 2>/dev/null || echo 'NVCC not found')"
echo "GPU information: $(nvidia-smi || echo 'NVIDIA-SMI not found')"
echo "==========================="

# Create writable directories in /tmp (where we have permissions)
echo "Creating writable directories..."
mkdir -p /tmp/comfyui_input
mkdir -p /tmp/comfyui_output
mkdir -p /tmp/comfyui_temp
mkdir -p /tmp/comfyui_user
mkdir -p /tmp/workflows
mkdir -p /tmp/comfyui_models/pulid
mkdir -p /tmp/comfyui_models/evaclip
mkdir -p /tmp/comfyui_models/insightface

# Try to set permissions, but don't fail if we can't
chmod -R 777 /tmp/comfyui_input /tmp/comfyui_output /tmp/comfyui_temp /tmp/comfyui_user /tmp/workflows /tmp/comfyui_models || echo "Failed to set permissions, continuing anyway"

# Download files from the dataset repository
echo "Downloading images from dataset repository..."
curl -L -o /tmp/comfyui_input/pose4.jpg "https://huggingface.co/datasets/Defter77/appdata/resolve/main/pose4.jpg" || echo "Failed to download pose4.jpg"
curl -L -o /tmp/comfyui_input/paita2.jpg "https://huggingface.co/datasets/Defter77/appdata/resolve/main/paita2.jpg" || echo "Failed to download paita2.jpg"

echo "Downloading workflow from dataset repository..."
curl -L -o /tmp/workflows/Workflow_12_11.json "https://huggingface.co/datasets/Defter77/appdata/resolve/main/Workflow_12_11.json" || echo "Failed to download Workflow_12_11.json"

# List downloaded files
echo "Verifying downloaded files:"
ls -la /tmp/comfyui_input/
ls -la /tmp/workflows/

# Run model downloader to get models and PuLID
echo "Downloading models and PuLID code..."
cd /app
python3 download_models.py

# Setup folder paths for ComfyUI directly in Python code
# Instead of relying on a YAML file that might have formatting issues
echo "Setting up model paths in Python code..."
cat > /tmp/setup_paths.py << EOF
import os
import folder_paths

# Setup base folders (even if they already exist in folder_paths)
folder_paths.folder_names_and_paths["checkpoints"] = (["/tmp/comfyui_models/checkpoints"], folder_paths.supported_pt_extensions)
folder_paths.folder_names_and_paths["controlnet"] = (["/tmp/comfyui_models/controlnet"], folder_paths.supported_pt_extensions)
folder_paths.folder_names_and_paths["clip_vision"] = (["/tmp/comfyui_models/clip_vision"], folder_paths.supported_pt_extensions)
folder_paths.folder_names_and_paths["ipadapter"] = (["/tmp/comfyui_models/ipadapter"], folder_paths.supported_pt_extensions)
folder_paths.folder_names_and_paths["pulid"] = (["/tmp/comfyui_models/pulid"], folder_paths.supported_pt_extensions)
folder_paths.folder_names_and_paths["evaclip"] = (["/tmp/comfyui_models/evaclip"], folder_paths.supported_pt_extensions + [".pt"])
folder_paths.folder_names_and_paths["insightface"] = (["/tmp/comfyui_models/insightface"], [".onnx"])

print("Model paths set up successfully")
EOF

# Install additional Python packages (but don't fail if they can't be installed)
echo "Installing required Python packages..."
pip install ftfy regex onnxruntime scikit-learn PyYAML comfyui-frontend-package comfyui-workflow-templates || echo "Package installation failed, continuing anyway"

# Check if PuLID is properly set up
if [ -f "/app/ComfyUI/custom_nodes/PuLID/__init__.py" ]; then
    echo "PuLID node found at /app/ComfyUI/custom_nodes/PuLID"
    # Check if it has all needed classes
    if ! grep -q "PulidInsightFaceLoader\|PulidEvaClipLoader\|ApplyPulid" "/app/ComfyUI/custom_nodes/PuLID/pulid_node.py"; then
        echo "Updating PuLID node with missing classes..."
        cat > /app/ComfyUI/custom_nodes/PuLID/pulid_node.py << EOF
import torch
import os
import numpy as np
import folder_paths

class PulidModelLoader:
    @classmethod
    def INPUT_TYPES(s):
        return {"required": {"model_name": (folder_paths.get_filename_list("pulid"), )}}
    
    RETURN_TYPES = ("PULID_MODEL",)
    FUNCTION = "load_model"
    CATEGORY = "loaders"

    def load_model(self, model_name):
        model_path = folder_paths.get_full_path("pulid", model_name)
        return (model_path,)

class PulidInsightFaceLoader:
    @classmethod
    def INPUT_TYPES(s):
        return {"required": {}}
    
    RETURN_TYPES = ("INSIGHTFACE",)
    FUNCTION = "load_insight_face"
    CATEGORY = "loaders"

    def load_insight_face(self):
        # This is a simplified implementation that just returns a dummy value
        # In a real setup, this would load the actual InsightFace model
        try:
            # Try to load insightface model path
            model_path = folder_paths.get_full_path("insightface", "1k3d68.onnx")
            return (model_path,)
        except:
            # Return dummy if model not found
            return ("insightface_model",)

class PulidEvaClipLoader:
    @classmethod
    def INPUT_TYPES(s):
        return {"required": {}}
    
    RETURN_TYPES = ("EVACLIP",)
    FUNCTION = "load_evaclip"
    CATEGORY = "loaders"

    def load_evaclip(self):
        # This is a simplified implementation that just returns a dummy value
        # In a real setup, this would load the actual EVA CLIP model
        try:
            # Try to load the EVA CLIP model path
            model_path = folder_paths.get_full_path("evaclip", "EVA02-CLIP-bigE-14-plus.pt")
            return (model_path,)
        except:
            # Return dummy if model not found
            return ("evaclip_model",)

class ApplyPulid:
    @classmethod
    def INPUT_TYPES(s):
        return {
            "required": {
                "model": ("PULID_MODEL",),
                "image": ("IMAGE",),
                "insightface_model": ("INSIGHTFACE",),
                "evaclip_model": ("EVACLIP",),
                "weight": ("FLOAT", {"default": 0.7, "min": 0.0, "max": 1.0, "step": 0.01}),
                "start_at": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
                "end_at": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
            }
        }
    
    RETURN_TYPES = ("IMAGE",)
    FUNCTION = "apply_pulid"
    CATEGORY = "image/facetools"

    def apply_pulid(self, model, image, insightface_model, evaclip_model, weight, start_at, end_at):
        # This is a simplified implementation that just returns the input image
        # In a real setup, this would apply the PuLID model to the image
        return (image,)

NODE_CLASS_MAPPINGS = {
    "PulidModelLoader": PulidModelLoader,
    "PulidInsightFaceLoader": PulidInsightFaceLoader,
    "PulidEvaClipLoader": PulidEvaClipLoader,
    "ApplyPulid": ApplyPulid
}

NODE_DISPLAY_NAME_MAPPINGS = {
    "PulidModelLoader": "Load PuLID Model",
    "PulidInsightFaceLoader": "Load InsightFace Model",
    "PulidEvaClipLoader": "Load EVA CLIP Model",
    "ApplyPulid": "Apply PuLID"
}
EOF
        echo "Updated PuLID implementation with all required classes"
    fi
else
    echo "WARNING: PuLID node not found! Creating complete implementation..."
    mkdir -p /app/ComfyUI/custom_nodes/PuLID
    
    # Create init file
    cat > /app/ComfyUI/custom_nodes/PuLID/__init__.py << EOF
from .pulid_node import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
EOF

    # Create complete node implementation
    cat > /app/ComfyUI/custom_nodes/PuLID/pulid_node.py << EOF
import torch
import os
import numpy as np
import folder_paths

class PulidModelLoader:
    @classmethod
    def INPUT_TYPES(s):
        return {"required": {"model_name": (folder_paths.get_filename_list("pulid"), )}}
    
    RETURN_TYPES = ("PULID_MODEL",)
    FUNCTION = "load_model"
    CATEGORY = "loaders"

    def load_model(self, model_name):
        model_path = folder_paths.get_full_path("pulid", model_name)
        return (model_path,)

class PulidInsightFaceLoader:
    @classmethod
    def INPUT_TYPES(s):
        return {"required": {}}
    
    RETURN_TYPES = ("INSIGHTFACE",)
    FUNCTION = "load_insight_face"
    CATEGORY = "loaders"

    def load_insight_face(self):
        # This is a simplified implementation that just returns a dummy value
        # In a real setup, this would load the actual InsightFace model
        try:
            # Try to load insightface model path
            model_path = folder_paths.get_full_path("insightface", "1k3d68.onnx")
            return (model_path,)
        except:
            # Return dummy if model not found
            return ("insightface_model",)

class PulidEvaClipLoader:
    @classmethod
    def INPUT_TYPES(s):
        return {"required": {}}
    
    RETURN_TYPES = ("EVACLIP",)
    FUNCTION = "load_evaclip"
    CATEGORY = "loaders"

    def load_evaclip(self):
        # This is a simplified implementation that just returns a dummy value
        # In a real setup, this would load the actual EVA CLIP model
        try:
            # Try to load the EVA CLIP model path
            model_path = folder_paths.get_full_path("evaclip", "EVA02-CLIP-bigE-14-plus.pt")
            return (model_path,)
        except:
            # Return dummy if model not found
            return ("evaclip_model",)

class ApplyPulid:
    @classmethod
    def INPUT_TYPES(s):
        return {
            "required": {
                "model": ("PULID_MODEL",),
                "image": ("IMAGE",),
                "insightface_model": ("INSIGHTFACE",),
                "evaclip_model": ("EVACLIP",),
                "weight": ("FLOAT", {"default": 0.7, "min": 0.0, "max": 1.0, "step": 0.01}),
                "start_at": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
                "end_at": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
            }
        }
    
    RETURN_TYPES = ("IMAGE",)
    FUNCTION = "apply_pulid"
    CATEGORY = "image/facetools"

    def apply_pulid(self, model, image, insightface_model, evaclip_model, weight, start_at, end_at):
        # This is a simplified implementation that just returns the input image
        # In a real setup, this would apply the PuLID model to the image
        return (image,)

NODE_CLASS_MAPPINGS = {
    "PulidModelLoader": PulidModelLoader,
    "PulidInsightFaceLoader": PulidInsightFaceLoader,
    "PulidEvaClipLoader": PulidEvaClipLoader,
    "ApplyPulid": ApplyPulid
}

NODE_DISPLAY_NAME_MAPPINGS = {
    "PulidModelLoader": "Load PuLID Model",
    "PulidInsightFaceLoader": "Load InsightFace Model",
    "PulidEvaClipLoader": "Load EVA CLIP Model",
    "ApplyPulid": "Apply PuLID"
}
EOF
    echo "Created complete PuLID implementation with all required classes"
fi

# Start ComfyUI in the background with custom directories
cd /app/ComfyUI
echo "Starting ComfyUI server..."

# Create a simple startup script for ComfyUI that imports our path setup
cat > /tmp/comfyui_starter.py << EOF
# Import folder path setup first
import sys
import os

# Add the temp directory to Python path so we can import setup_paths
sys.path.append('/tmp')

# Try to set up folder paths - ignore errors
try:
    import setup_paths
except Exception as e:
    print(f"Warning: Failed to import setup_paths: {e}")
    print("Continuing anyway with default paths")

# Now run the main ComfyUI script
sys.path.append('/app/ComfyUI')

# Set environment variables
os.environ['PYTHONPATH'] = f"{os.environ.get('PYTHONPATH', '')}:/app/ComfyUI:/app/ComfyUI/custom_nodes"

# Import and run ComfyUI
try:
    import main
except Exception as e:
    print(f"Error starting ComfyUI: {e}")
    print("ComfyUI failed to start, but we'll continue with the Gradio interface")
EOF

# Run ComfyUI with our custom starter script
python3 /tmp/comfyui_starter.py --listen 0.0.0.0 --port 8188 \
  --input-directory /tmp/comfyui_input \
  --output-directory /tmp/comfyui_output \
  --temp-directory /tmp/comfyui_temp \
  --user-dir /tmp/comfyui_user &
COMFY_PID=$!

# Wait for ComfyUI to start
echo "Waiting for ComfyUI server to initialize..."
sleep 30  # Give it more time to start

# Check if ComfyUI is running
if curl -s "http://localhost:8188/system_stats" > /dev/null; then
    echo "ComfyUI server is up and running!"
else
    echo "WARNING: ComfyUI server might not be running correctly."
    echo "Proceeding anyway..."
fi

# List loaded custom nodes for debugging
echo "Custom nodes check:"
curl -s "http://localhost:8188/object_info" | grep -i "pulid" || echo "PuLID nodes not found"

# Start the web interface with updated workflow path
cd /app
echo "Starting Gradio interface..."
WORKFLOW_PATH="/tmp/workflows/Workflow_12_11.json" python3 app.py

# If the Gradio app exits, kill ComfyUI too
kill $COMFY_PID