forked from runpod-workers/worker-sdxl
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathhandler.py
More file actions
147 lines (117 loc) · 4.73 KB
/
Copy pathhandler.py
File metadata and controls
147 lines (117 loc) · 4.73 KB
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
import base64
import os
import runpod
import torch
from pruna import PrunaModel
from runpod.serverless.utils import rp_cleanup, rp_upload
from runpod.serverless.utils.rp_validator import validate
from schemas import INPUT_SCHEMA
torch.cuda.empty_cache()
class ModelHandler:
def __init__(self):
self.pipe = None
self.load_models()
def load_models(self):
# Load FLUX.1-dev pipeline from cache using identifier
self.pipe = PrunaModel.from_hub(
os.environ.get("HF_MODEL", "PrunaAI/FLUX.1-dev-smashed-no-compile"),
local_files_only=True,
)
self.pipe.move_to_device("cuda")
MODELS = ModelHandler()
def _save_and_upload_images(images, job_id):
os.makedirs(f"/{job_id}", exist_ok=True)
image_urls = []
for index, image in enumerate(images):
image_path = os.path.join(f"/{job_id}", f"{index}.png")
image.save(image_path)
if os.environ.get("BUCKET_ENDPOINT_URL", False):
image_url = rp_upload.upload_image(job_id, image_path)
image_urls.append(image_url)
else:
with open(image_path, "rb") as image_file:
image_data = base64.b64encode(image_file.read()).decode("utf-8")
image_urls.append(f"data:image/png;base64,{image_data}")
rp_cleanup.clean([f"/{job_id}"])
return image_urls
@torch.inference_mode()
def generate_image(job):
"""
Generate an image from text using FLUX.1-dev Model
"""
# -------------------------------------------------------------------------
# 🐞 DEBUG LOGGING
# -------------------------------------------------------------------------
import json
import pprint
# Log the exact structure RunPod delivers so we can see every nesting level.
print("[generate_image] RAW job dict:")
try:
print(json.dumps(job, indent=2, default=str), flush=True)
except Exception:
pprint.pprint(job, depth=4, compact=False)
# -------------------------------------------------------------------------
# Original (strict) behaviour – assume the expected single wrapper exists.
# -------------------------------------------------------------------------
job_input = job["input"]
print("[generate_image] job['input'] payload:")
try:
print(json.dumps(job_input, indent=2, default=str), flush=True)
except Exception:
pprint.pprint(job_input, depth=4, compact=False)
# Input validation
try:
validated_input = validate(job_input, INPUT_SCHEMA)
except Exception as err:
import traceback
print("[generate_image] validate(...) raised an exception:", err, flush=True)
traceback.print_exc()
# Re-raise so RunPod registers the failure (but logs are now visible).
raise
print("[generate_image] validate(...) returned:")
try:
print(json.dumps(validated_input, indent=2, default=str), flush=True)
except Exception:
pprint.pprint(validated_input, depth=4, compact=False)
if "errors" in validated_input:
return {"error": validated_input["errors"]}
job_input = validated_input["validated_input"]
if job_input["seed"] is None:
job_input["seed"] = int.from_bytes(os.urandom(2), "big")
# Create generator with proper device handling
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
generator = torch.Generator(device).manual_seed(job_input["seed"])
try:
# Generate image using FLUX.1-dev pipeline
with torch.inference_mode():
result = MODELS.pipe(
prompt=job_input["prompt"],
negative_prompt=job_input["negative_prompt"],
height=job_input["height"],
width=job_input["width"],
num_inference_steps=job_input["num_inference_steps"],
guidance_scale=job_input["guidance_scale"],
num_images_per_prompt=job_input["num_images"],
generator=generator,
)
output = result.images
except RuntimeError as err:
print(f"[ERROR] RuntimeError in generation pipeline: {err}", flush=True)
return {
"error": f"RuntimeError: {err}, Stack Trace: {err.__traceback__}",
"refresh_worker": True,
}
except Exception as err:
print(f"[ERROR] Unexpected error in generation pipeline: {err}", flush=True)
return {
"error": f"Unexpected error: {err}",
"refresh_worker": True,
}
image_urls = _save_and_upload_images(output, job["id"])
results = {
"images": image_urls,
"image_url": image_urls[0],
"seed": job_input["seed"],
}
return results
runpod.serverless.start({"handler": generate_image})