cgauss commited on
Commit
b51a719
·
verified ·
1 Parent(s): 0313b9a

Upload 2 files

Browse files
Files changed (2) hide show
  1. api_example.py +168 -0
  2. workflow_api_format.json +189 -0
api_example.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import json
3
+ import random
4
+ import time
5
+ import requests
6
+ import base64
7
+ from io import BytesIO
8
+
9
+ def get_image_as_base64(url):
10
+ try:
11
+ response = requests.get(url)
12
+ response.raise_for_status()
13
+ image_data = BytesIO(response.content)
14
+ base64_image = base64.b64encode(image_data.getvalue()).decode('utf-8')
15
+ return base64_image
16
+ except requests.exceptions.RequestException as ex:
17
+ print(f'Failed to retrieve image: {ex}')
18
+ return None
19
+
20
+ def queue_prompt(url, prompt):
21
+ p = {"prompt": prompt}
22
+ data = json.dumps(p).encode('utf-8')
23
+ prompt_url = f"{url}/prompt"
24
+ try:
25
+ r = requests.post(prompt_url, data=data)
26
+ r.raise_for_status()
27
+ return r.json()
28
+ except requests.exceptions.RequestException as ex:
29
+ print(f'POST {prompt_url} failed: {ex}')
30
+ return None
31
+
32
+ def get_queue(url):
33
+ queue_url = f"{url}/queue"
34
+ try:
35
+ r = requests.get(queue_url)
36
+ r.raise_for_status()
37
+ return r.json()
38
+ except requests.exceptions.RequestException as ex:
39
+ print(f'GET {queue_url} failed: {ex}')
40
+ return None
41
+
42
+
43
+ def get_history(url, prompt_id):
44
+ history_url = f"{url}/history/{prompt_id}"
45
+ try:
46
+ r = requests.get(history_url)
47
+ r.raise_for_status()
48
+ return r.json()
49
+ except requests.exceptions.RequestException as ex:
50
+ print(f'GET {history_url} failed: {ex}')
51
+ return None
52
+
53
+
54
+ def main(ip, port, filepath, prompt=None, steps=None, seed=None, cfg=None, width=None, height=None, lora_name=None, lora_scale=None):
55
+ url = f"http://{ip}:{port}"
56
+
57
+ with open(filepath, 'r') as file:
58
+ prompt_text = json.load(file)
59
+
60
+ # Update prompt_text with provided arguments
61
+ if prompt is not None:
62
+ prompt_text["6"]["inputs"]["text"] = prompt
63
+ if steps is not None:
64
+ prompt_text["17"]["inputs"]["steps"] = steps
65
+ if seed is not None:
66
+ prompt_text["25"]["inputs"]["noise_seed"] = seed
67
+ else:
68
+ prompt_text["25"]["inputs"]["noise_seed"] = random.randint(0, 1000000000000000)
69
+ if cfg is not None:
70
+ prompt_text["26"]["inputs"]["guidance"] = cfg
71
+ if width is not None:
72
+ prompt_text["27"]["inputs"]["width"] = width
73
+ if height is not None:
74
+ prompt_text["27"]["inputs"]["height"] = height
75
+ if lora_name is not None:
76
+ prompt_text["30"]["inputs"]["lora_name"] = lora_name
77
+ if lora_scale is not None:
78
+ prompt_text["30"]["inputs"]["strength_model"] = lora_scale
79
+
80
+ # Print the updated values
81
+ print(f'Prompt: {prompt_text["6"]["inputs"]["text"]}')
82
+ print(f'Steps: {prompt_text["17"]["inputs"]["steps"]}')
83
+ print(f'Seed: {prompt_text["25"]["inputs"]["noise_seed"]}')
84
+ print(f'CFG: {prompt_text["26"]["inputs"]["guidance"]}')
85
+ print(f'Width: {prompt_text["27"]["inputs"]["width"]}')
86
+ print(f'Height: {prompt_text["27"]["inputs"]["height"]}')
87
+ print(f'LoRA Name: {prompt_text["30"]["inputs"]["lora_name"]}')
88
+ print(f'LoRA Scale: {prompt_text["30"]["inputs"]["strength_model"]}')
89
+
90
+ response1 = queue_prompt(url, prompt_text)
91
+ if response1 is None:
92
+ print("Failed to queue the prompt.")
93
+ return
94
+
95
+ prompt_id = response1['prompt_id']
96
+ print(f'Prompt ID: {prompt_id}')
97
+ print('-' * 20)
98
+
99
+ while True:
100
+ time.sleep(5)
101
+ queue_response = get_queue(url)
102
+ if queue_response is None:
103
+ continue
104
+
105
+ queue_pending = queue_response.get('queue_pending', [])
106
+ queue_running = queue_response.get('queue_running', [])
107
+
108
+ # Check position in queue
109
+ for position, item in enumerate(queue_pending):
110
+ if item[1] == prompt_id:
111
+ print(f'Queue running: {len(queue_running)}, Queue pending: {len(queue_pending)}, Workflow is in position {position + 1} in the queue.')
112
+
113
+ # Check if the prompt is currently running
114
+ for item in queue_running:
115
+ if item[1] == prompt_id:
116
+ print(f'Queue running: {len(queue_running)}, Queue pending: {len(queue_pending)}, Workflow is currently running.')
117
+ break
118
+
119
+ if not any(prompt_id in item for item in queue_pending + queue_running):
120
+ break
121
+
122
+ history_response = get_history(url, prompt_id)
123
+ if history_response is None:
124
+ print("Failed to retrieve history.")
125
+ return
126
+
127
+ output_info = history_response.get(prompt_id, {}).get('outputs', {}).get('9', {}).get('images', [{}])[0]
128
+ filename = output_info.get('filename', 'unknown.png')
129
+ output_url = f"{url}/output/{filename}"
130
+
131
+ print(f"Output URL: {output_url}")
132
+
133
+ # Get base64 encoded image
134
+ base64_image = get_image_as_base64(output_url)
135
+ if base64_image:
136
+ print("Base64 encoded image:")
137
+ print(base64_image)
138
+ else:
139
+ print("Failed to retrieve base64 encoded image.")
140
+
141
+ return {
142
+ "output_url": output_url,
143
+ "base64_image": base64_image
144
+ }
145
+
146
+
147
+ if __name__ == "__main__":
148
+ parser = argparse.ArgumentParser(description='Add a prompt to the queue and wait for the output.')
149
+ parser.add_argument('--ip', type=str, required=True, help='The public IP address of the pod')
150
+ parser.add_argument('--port', type=int, required=True, help='The external port of the pod')
151
+ parser.add_argument('--filepath', type=str, required=True, help='The path to the JSON file containing the workflow in api format')
152
+ parser.add_argument('--prompt', type=str, help='The prompt to use for the workflow')
153
+ parser.add_argument('--steps', type=int, help='Number of steps for the sampler')
154
+ parser.add_argument('--seed', type=int, help='Seed for the noise generator')
155
+ parser.add_argument('--cfg', type=float, help='Classifier-free guidance scale')
156
+ parser.add_argument('--width', type=int, help='Width of the output image')
157
+ parser.add_argument('--height', type=int, help='Height of the output image')
158
+ parser.add_argument('--lora_name', type=str, help='Name of the LoRA to use')
159
+ parser.add_argument('--lora_scale', type=float, help='Scale of the LoRA effect')
160
+
161
+ args = parser.parse_args()
162
+ result = main(args.ip, args.port, args.filepath, args.prompt, args.steps, args.seed, args.cfg, args.width, args.height, args.lora_name, args.lora_scale)
163
+
164
+ # If you want to save the base64 image to a file
165
+ if result and result["base64_image"]:
166
+ with open("output_image.txt", "w") as f:
167
+ f.write(result["base64_image"])
168
+ print("Base64 image saved to output_image.txt")
workflow_api_format.json ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "6": {
3
+ "inputs": {
4
+ "text": "Beautiful young woman, age 25, with long braided platinum blonde hair and bright magenta eyes, looking seductively and holding a large red-scaled dragon egg. The words \"Valyrian Tech\" are in a large sleek and stylistic font in the middle of the image.",
5
+ "clip": [
6
+ "11",
7
+ 0
8
+ ]
9
+ },
10
+ "class_type": "CLIPTextEncode",
11
+ "_meta": {
12
+ "title": "CLIP Text Encode (Positive Prompt)"
13
+ }
14
+ },
15
+ "8": {
16
+ "inputs": {
17
+ "samples": [
18
+ "13",
19
+ 0
20
+ ],
21
+ "vae": [
22
+ "10",
23
+ 0
24
+ ]
25
+ },
26
+ "class_type": "VAEDecode",
27
+ "_meta": {
28
+ "title": "VAE Decode"
29
+ }
30
+ },
31
+ "9": {
32
+ "inputs": {
33
+ "filename_prefix": "ComfyUI",
34
+ "images": [
35
+ "8",
36
+ 0
37
+ ]
38
+ },
39
+ "class_type": "SaveImage",
40
+ "_meta": {
41
+ "title": "Save Image"
42
+ }
43
+ },
44
+ "10": {
45
+ "inputs": {
46
+ "vae_name": "ae.sft"
47
+ },
48
+ "class_type": "VAELoader",
49
+ "_meta": {
50
+ "title": "Load VAE"
51
+ }
52
+ },
53
+ "11": {
54
+ "inputs": {
55
+ "clip_name1": "t5xxl_fp16.safetensors",
56
+ "clip_name2": "clip_l.safetensors",
57
+ "type": "flux"
58
+ },
59
+ "class_type": "DualCLIPLoader",
60
+ "_meta": {
61
+ "title": "DualCLIPLoader"
62
+ }
63
+ },
64
+ "12": {
65
+ "inputs": {
66
+ "unet_name": "flux1-dev.sft",
67
+ "weight_dtype": "default"
68
+ },
69
+ "class_type": "UNETLoader",
70
+ "_meta": {
71
+ "title": "Load Diffusion Model"
72
+ }
73
+ },
74
+ "13": {
75
+ "inputs": {
76
+ "noise": [
77
+ "25",
78
+ 0
79
+ ],
80
+ "guider": [
81
+ "22",
82
+ 0
83
+ ],
84
+ "sampler": [
85
+ "16",
86
+ 0
87
+ ],
88
+ "sigmas": [
89
+ "17",
90
+ 0
91
+ ],
92
+ "latent_image": [
93
+ "27",
94
+ 0
95
+ ]
96
+ },
97
+ "class_type": "SamplerCustomAdvanced",
98
+ "_meta": {
99
+ "title": "SamplerCustomAdvanced"
100
+ }
101
+ },
102
+ "16": {
103
+ "inputs": {
104
+ "sampler_name": "euler"
105
+ },
106
+ "class_type": "KSamplerSelect",
107
+ "_meta": {
108
+ "title": "KSamplerSelect"
109
+ }
110
+ },
111
+ "17": {
112
+ "inputs": {
113
+ "scheduler": "simple",
114
+ "steps": 30,
115
+ "denoise": 1,
116
+ "model": [
117
+ "12",
118
+ 0
119
+ ]
120
+ },
121
+ "class_type": "BasicScheduler",
122
+ "_meta": {
123
+ "title": "BasicScheduler"
124
+ }
125
+ },
126
+ "22": {
127
+ "inputs": {
128
+ "model": [
129
+ "30",
130
+ 0
131
+ ],
132
+ "conditioning": [
133
+ "26",
134
+ 0
135
+ ]
136
+ },
137
+ "class_type": "BasicGuider",
138
+ "_meta": {
139
+ "title": "BasicGuider"
140
+ }
141
+ },
142
+ "25": {
143
+ "inputs": {
144
+ "noise_seed": 1198860368
145
+ },
146
+ "class_type": "RandomNoise",
147
+ "_meta": {
148
+ "title": "RandomNoise"
149
+ }
150
+ },
151
+ "26": {
152
+ "inputs": {
153
+ "guidance": 3.5,
154
+ "conditioning": [
155
+ "6",
156
+ 0
157
+ ]
158
+ },
159
+ "class_type": "FluxGuidance",
160
+ "_meta": {
161
+ "title": "FluxGuidance"
162
+ }
163
+ },
164
+ "27": {
165
+ "inputs": {
166
+ "width": 1344,
167
+ "height": 768,
168
+ "batch_size": 1
169
+ },
170
+ "class_type": "EmptySD3LatentImage",
171
+ "_meta": {
172
+ "title": "EmptySD3LatentImage"
173
+ }
174
+ },
175
+ "30": {
176
+ "inputs": {
177
+ "lora_name": "FLUXTest2-000009.safetensors",
178
+ "strength_model": 0.8,
179
+ "model": [
180
+ "12",
181
+ 0
182
+ ]
183
+ },
184
+ "class_type": "LoraLoaderModelOnly",
185
+ "_meta": {
186
+ "title": "LoraLoaderModelOnly"
187
+ }
188
+ }
189
+ }