gosign commited on
Commit
1e9882c
·
verified ·
1 Parent(s): fe85107

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +20 -0
  2. app.py +146 -0
  3. requirements.txt +5 -0
  4. workflow_api.json +107 -0
Dockerfile ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python runtime as a parent image
2
+ FROM python:3.9-slim
3
+
4
+ # Set the working directory in the container
5
+ WORKDIR /app
6
+
7
+ # Switch to root user to ensure installation permissions
8
+ USER root
9
+
10
+ # Copy the current directory contents into the container at /app
11
+ COPY . /app
12
+
13
+ # Install any needed packages specified in requirements.txt
14
+ RUN pip install --no-cache-dir -r requirements.txt
15
+
16
+ # Make port 7860 available to the world outside this container
17
+ EXPOSE 7860
18
+
19
+ # Run app.py when the container launches
20
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify, send_file
2
+ import websocket
3
+ import uuid
4
+ import json
5
+ import urllib.request
6
+ import urllib.parse
7
+ import random
8
+ from PIL import Image
9
+ import io
10
+ import base64
11
+
12
+ # Initialize Flask app
13
+ app = Flask(__name__)
14
+
15
+ # Set server and websocket addresses
16
+ server_address = "127.0.0.1:8188"
17
+ ws_address = "ws://127.0.0.1:8188/ws"
18
+ client_id = str(uuid.uuid4())
19
+
20
+ def make_request(url, data=None, headers=None):
21
+ req = urllib.request.Request(url, data=data, headers=headers)
22
+ with urllib.request.urlopen(req) as response:
23
+ return json.loads(response.read())
24
+
25
+ def queue_prompt(prompt, token):
26
+ payload = {"prompt": prompt, "client_id": client_id}
27
+ data = json.dumps(payload).encode('utf-8')
28
+ headers = {
29
+ 'Authorization': f'Bearer {token}', # Bearer token
30
+ 'Content-Type': 'application/json'
31
+ }
32
+ return make_request(f"http://{server_address}/prompt", data=data, headers=headers)
33
+
34
+ def get_image(filename, subfolder, image_type, token):
35
+ url_values = {'filename': filename, 'subfolder': subfolder, 'type': image_type}
36
+ url = f"http://{server_address}/view?{urllib.parse.urlencode(url_values)}"
37
+
38
+ req = urllib.request.Request(url)
39
+ req.add_header("Authorization", f"Bearer {token}")
40
+
41
+ # Debugging output
42
+ print(f"Request URL: {url}")
43
+ print(f"Request Headers: {req.headers}")
44
+
45
+ try:
46
+ return urllib.request.urlopen(req).read()
47
+ except urllib.error.HTTPError as e:
48
+ print(f"HTTP Error: {e.code} - {e.reason}")
49
+ print(e.read()) # This will give you more context about the error
50
+ raise
51
+
52
+ def get_history(prompt_id, token):
53
+ headers = {
54
+ 'Authorization': f'Bearer {token}',
55
+ 'Content-Type': 'application/json'
56
+ }
57
+ return make_request(f"http://{server_address}/history/{prompt_id}", headers=headers)
58
+
59
+ def get_images(ws, prompt, token):
60
+ prompt_id = queue_prompt(prompt, token)['prompt_id']
61
+ output_images = {}
62
+
63
+ while True:
64
+ out = ws.recv()
65
+ if isinstance(out, str):
66
+ message = json.loads(out)
67
+ if message['type'] == 'executing':
68
+ data = message['data']
69
+ if data['node'] is None and data['prompt_id'] == prompt_id:
70
+ break # Execution is done
71
+
72
+ history = get_history(prompt_id, token)[prompt_id]
73
+ for node_id in history['outputs']:
74
+ node_output = history['outputs'][node_id]
75
+ images_output = []
76
+ if 'images' in node_output:
77
+ for image in node_output['images']:
78
+ image_data = get_image(image['filename'], image['subfolder'], image['type'], token)
79
+ images_output.append(image_data)
80
+ output_images[node_id] = images_output
81
+
82
+ return output_images
83
+ # Default route for home welcome
84
+ @app.route('/')
85
+ def home():
86
+ return "Welcome to ComfyUI API Interface!"
87
+
88
+ # Generate image route
89
+ @app.route('/generate_image', methods=['POST'])
90
+ def generate_image():
91
+ data = request.json
92
+
93
+ # Extract the token from the request headers
94
+ token = request.headers.get('Authorization')
95
+
96
+ # Ensure the token is present and in the correct format
97
+ if token is None:
98
+ return jsonify({'error': 'No token provided'}), 400
99
+ # If the token does not have a 'Bearer' prefix, use the entire token
100
+ if token.startswith("Bearer "):
101
+ token = token.split(" ")[1] # Extract the actual token if 'Bearer ' exists
102
+ else:
103
+ token = token # Use the entire token if there's no 'Bearer ' prefix
104
+
105
+ # Base64 decode the encoded token
106
+ token = base64.b64decode(token).decode("utf-8")
107
+
108
+ if 'text_prompt' not in data:
109
+ return jsonify({'error': 'No text prompt provided'}), 400
110
+
111
+ text_prompt = data['text_prompt']
112
+ file_path = '/Users/muhammadwaqas/gosign/comfyui-api/workflow_api.json'
113
+
114
+ with open(file_path, 'r', encoding='utf-8') as file:
115
+ workflow_jsondata = file.read()
116
+
117
+ prompt = json.loads(workflow_jsondata)
118
+ prompt["6"]["inputs"]["text"] = text_prompt
119
+ prompt["7"]["inputs"]["text"] = "text, watermark, low quality, extra hands, extra legs."
120
+
121
+ seednum = random.randint(1, 9999999999999)
122
+ prompt["3"]["inputs"]["seed"] = seednum
123
+
124
+ ws = websocket.WebSocket()
125
+ ws.connect(f"{ws_address}?clientId={client_id}&token={token}")
126
+ images = get_images(ws, prompt, token)
127
+ ws.close()
128
+
129
+ output_image_paths = []
130
+
131
+ for node_id in images:
132
+ for image_data in images[node_id]:
133
+ image = Image.open(io.BytesIO(image_data))
134
+ image_path = f'image-output-{seednum}-{node_id}.png'
135
+ image.show()
136
+ image.save(image_path)
137
+ output_image_paths.append(image_path)
138
+
139
+ return jsonify({'images': output_image_paths})
140
+
141
+ @app.route('/get_image/<filename>', methods=['GET'])
142
+ def get_image_file(filename):
143
+ return send_file(filename, mimetype='image/png')
144
+
145
+ if __name__ == '__main__':
146
+ app.run(debug=True, port=7860)
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Flask==2.0.2
2
+ websocket-client
3
+ Pillow
4
+ uuid
5
+ gunicorn
workflow_api.json ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "3": {
3
+ "inputs": {
4
+ "seed": 1099951066657758,
5
+ "steps": 20,
6
+ "cfg": 8,
7
+ "sampler_name": "euler",
8
+ "scheduler": "normal",
9
+ "denoise": 1,
10
+ "model": [
11
+ "4",
12
+ 0
13
+ ],
14
+ "positive": [
15
+ "6",
16
+ 0
17
+ ],
18
+ "negative": [
19
+ "7",
20
+ 0
21
+ ],
22
+ "latent_image": [
23
+ "5",
24
+ 0
25
+ ]
26
+ },
27
+ "class_type": "KSampler",
28
+ "_meta": {
29
+ "title": "KSampler"
30
+ }
31
+ },
32
+ "4": {
33
+ "inputs": {
34
+ "ckpt_name": "Deliberate_v2.safetensors"
35
+ },
36
+ "class_type": "CheckpointLoaderSimple",
37
+ "_meta": {
38
+ "title": "Load Checkpoint"
39
+ }
40
+ },
41
+ "5": {
42
+ "inputs": {
43
+ "width": 512,
44
+ "height": 512,
45
+ "batch_size": 1
46
+ },
47
+ "class_type": "EmptyLatentImage",
48
+ "_meta": {
49
+ "title": "Empty Latent Image"
50
+ }
51
+ },
52
+ "6": {
53
+ "inputs": {
54
+ "text": "beautiful scenery nature glass bottle landscape, purple galaxy bottle,",
55
+ "clip": [
56
+ "4",
57
+ 1
58
+ ]
59
+ },
60
+ "class_type": "CLIPTextEncode",
61
+ "_meta": {
62
+ "title": "CLIP Text Encode (Prompt)"
63
+ }
64
+ },
65
+ "7": {
66
+ "inputs": {
67
+ "text": "text, watermark",
68
+ "clip": [
69
+ "4",
70
+ 1
71
+ ]
72
+ },
73
+ "class_type": "CLIPTextEncode",
74
+ "_meta": {
75
+ "title": "CLIP Text Encode (Prompt)"
76
+ }
77
+ },
78
+ "8": {
79
+ "inputs": {
80
+ "samples": [
81
+ "3",
82
+ 0
83
+ ],
84
+ "vae": [
85
+ "4",
86
+ 2
87
+ ]
88
+ },
89
+ "class_type": "VAEDecode",
90
+ "_meta": {
91
+ "title": "VAE Decode"
92
+ }
93
+ },
94
+ "9": {
95
+ "inputs": {
96
+ "filename_prefix": "ComfyUI",
97
+ "images": [
98
+ "8",
99
+ 0
100
+ ]
101
+ },
102
+ "class_type": "SaveImage",
103
+ "_meta": {
104
+ "title": "Save Image"
105
+ }
106
+ }
107
+ }