ttndigitalworld commited on
Commit
889a32f
1 Parent(s): 65a3eb6

First version

Browse files
Files changed (2) hide show
  1. app.py +301 -0
  2. requirements.txt +8 -0
app.py ADDED
@@ -0,0 +1,301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Created for https://www.aiqrgenerator.com/ as a public beta version for embedding.
2
+ # I wanted to make the model more accessable for public users and commercialized. Feel free to share at https://www.aiqrgenerator.com/generator.
3
+ # May update again but will probably remain the final public version as I am still working on features and consider this a minimum viable product
4
+ # Further updates and custom models will be updated privately.
5
+
6
+
7
+ # derivative and edited from QR-code-AI-art-generator by patrickvonplaten - customized AND COPYRIGHTED UNDER COMMERCIAL LICENSE
8
+ # ControlNet model is controlnet_qrcode-control_v1p_sd15 by DionTimmer from under OPENRAIL license
9
+ # to do - remove stable diff 2 API and use my custom model for generation for init image
10
+ # add init image !!!
11
+ # custom controlnetmodel implementation
12
+ # V1.02 public, not recent version
13
+
14
+
15
+ import torch
16
+ import gradio as gr
17
+ from PIL import Image
18
+ import qrcode
19
+ from pathlib import Path
20
+ from multiprocessing import cpu_count
21
+ import requests
22
+ import io
23
+ import os
24
+ from PIL import Image
25
+
26
+ from diffusers import (
27
+ StableDiffusionPipeline,
28
+ StableDiffusionControlNetImg2ImgPipeline,
29
+ ControlNetModel,
30
+ DDIMScheduler,
31
+ DPMSolverMultistepScheduler,
32
+ DEISMultistepScheduler,
33
+ HeunDiscreteScheduler,
34
+ EulerDiscreteScheduler,
35
+ )
36
+
37
+ API_URL = "https://api-inference.huggingface.co/models/stabilityai/stable-diffusion-2-1"
38
+ HF_TOKEN = os.environ.get("HF_TOKEN")
39
+
40
+ headers = {"Authorization": f"Bearer {HF_TOKEN}"}
41
+
42
+
43
+ def query(payload):
44
+ response = requests.post(API_URL, headers=headers, json=payload)
45
+ return response.content
46
+
47
+
48
+ qrcode_generator = qrcode.QRCode(
49
+ version=1,
50
+ error_correction=qrcode.ERROR_CORRECT_H,
51
+ box_size=10,
52
+ border=4,
53
+ )
54
+
55
+ controlnet = ControlNetModel.from_pretrained(
56
+ "DionTimmer/controlnet_qrcode-control_v1p_sd15", torch_dtype=torch.float16
57
+ )
58
+
59
+ pipe = StableDiffusionControlNetImg2ImgPipeline.from_pretrained(
60
+ "runwayml/stable-diffusion-v1-5",
61
+ controlnet=controlnet,
62
+ safety_checker=None,
63
+ torch_dtype=torch.float16,
64
+ ).to("cuda")
65
+ pipe.enable_xformers_memory_efficient_attention()
66
+
67
+
68
+ def resize_for_condition_image(input_image: Image.Image, resolution: int = 512):
69
+ input_image = input_image.convert("RGB")
70
+ W, H = input_image.size
71
+ k = float(resolution) / min(H, W)
72
+ H *= k
73
+ W *= k
74
+ H = int(round(H / 32.0)) * 32
75
+ W = int(round(W / 32.0)) * 32
76
+ img = input_image.resize((W, H), resample=Image.LANCZOS)
77
+ return img
78
+
79
+
80
+ SAMPLER_MAP = {
81
+ "DPM++ Karras SDE": lambda config: DPMSolverMultistepScheduler.from_config(config, use_karras=True,
82
+ algorithm_type="sde-dpmsolver++"),
83
+ "DPM++ Karras": lambda config: DPMSolverMultistepScheduler.from_config(config, use_karras=True),
84
+ "Heun": lambda config: HeunDiscreteScheduler.from_config(config),
85
+ "Euler": lambda config: EulerDiscreteScheduler.from_config(config),
86
+ "DDIM": lambda config: DDIMScheduler.from_config(config),
87
+ "DEIS": lambda config: DEISMultistepScheduler.from_config(config),
88
+ }
89
+
90
+
91
+ def inference(
92
+ qr_code_content: str,
93
+ prompt: str,
94
+ negative_prompt: str,
95
+ guidance_scale: float = 10.0,
96
+ controlnet_conditioning_scale: float = 2.0,
97
+ strength: float = 0.8,
98
+ seed: int = -1,
99
+ init_image: Image.Image | None = None,
100
+ qrcode_image: Image.Image | None = None,
101
+ use_qr_code_as_init_image=True,
102
+ sampler="DDIM",
103
+ ):
104
+ if prompt is None or prompt == "":
105
+ raise gr.Error("Prompt is required")
106
+
107
+ if qrcode_image is None and qr_code_content == "":
108
+ raise gr.Error("QR Code Image or QR Code Content is required")
109
+
110
+ pipe.scheduler = SAMPLER_MAP[sampler](pipe.scheduler.config)
111
+
112
+ generator = torch.manual_seed(seed) if seed != -1 else torch.Generator()
113
+
114
+ if qr_code_content != "" or qrcode_image.size == (1, 1):
115
+ print("Generating QR Code from content")
116
+ qr = qrcode.QRCode(
117
+ version=1,
118
+ error_correction=qrcode.constants.ERROR_CORRECT_H,
119
+ box_size=10,
120
+ border=4,
121
+ )
122
+ qr.add_data(qr_code_content)
123
+ qr.make(fit=True)
124
+
125
+ qrcode_image = qr.make_image(fill_color="black", back_color="white")
126
+ qrcode_image = resize_for_condition_image(qrcode_image, 512)
127
+ else:
128
+ print("Using QR Code Image")
129
+ qrcode_image = resize_for_condition_image(qrcode_image, 512)
130
+
131
+ # hack due to gradio examples
132
+ if use_qr_code_as_init_image:
133
+ init_image = qrcode_image
134
+ elif init_image is None or init_image.size == (1, 1):
135
+ print("Generating random image from prompt using Stable Diffusion 2.1 via Inference API")
136
+ # generate image from prompt
137
+ image_bytes = query({"inputs": prompt})
138
+ init_image = Image.open(io.BytesIO(image_bytes))
139
+ else:
140
+ print("Using provided init image")
141
+ init_image = resize_for_condition_image(init_image, 512)
142
+
143
+ # promptstart = ""
144
+ promptend = ", high quality, high resolution"
145
+ prompt += promptend
146
+
147
+ negative_promptend = ", butt, nipple, nsfw, nude, nudity, naked"
148
+ negative_prompt += negative_promptend
149
+
150
+ out = pipe(
151
+ prompt=prompt,
152
+ negative_prompt=negative_prompt,
153
+ image=qrcode_image,
154
+ control_image=qrcode_image, # type: ignore
155
+ width=512, # type: ignore
156
+ height=512, # type: ignore
157
+ guidance_scale=float(guidance_scale),
158
+ controlnet_conditioning_scale=float(controlnet_conditioning_scale), # type: ignore
159
+ generator=generator,
160
+ strength=float(strength),
161
+ num_inference_steps=25,
162
+ )
163
+ return out.images[0] # type: ignore
164
+
165
+
166
+ # removed text
167
+ with gr.Blocks() as blocks:
168
+ gr.Markdown(
169
+ """
170
+ # CREATED FOR HTTPS://WWW.AIQRGENERATOR.COM/ EARLY BETA PUBLIC ACCESS V1.02 - NONCOMMERCIAL USE
171
+ ==================================**DISCLAIMER - By using this model you agree to waive any liability and are assuming all responsibility for generated images.**===================================
172
+
173
+ This generator is trained using SD 1.5. To use SD 2.1 for better quality and other features like upscaling and initial image generation, check out our newest model.
174
+ When sharing generated QR codes, please credit aiqrgenerator.com.
175
+
176
+ Type in what you want the QR code to look like. Use major subjects seperated by commas like the example below - you can even include styles!
177
+ Type your QR code information such as a website link or if you have a QR image, upload it.
178
+ Feel free to test custom settings as well to make the QR work or try changing your prompt. Change the seed to any number to completely change your generation.
179
+ **Hit run!**
180
+
181
+
182
+ ==============================================================================================================================================================================
183
+
184
+
185
+ """
186
+ )
187
+ prompt = gr.Textbox(
188
+ label="Prompt",
189
+ info="Input subjects or styles you want to see that describes your image - Ex. Mountian, snow, morning, trees, art, painting, digital",
190
+ )
191
+
192
+ negative_prompt = gr.Textbox(visible=True, label="Negative Prompt",
193
+ info="Input things you don't want to see in your image for the model.",
194
+ value="poorly drawn, blurry image, deformed, low resolution, disfigured, low quality, blurry")
195
+
196
+ with gr.Row():
197
+ with gr.Column():
198
+ qr_code_content = gr.Textbox(
199
+ label="QR Code Content",
200
+ info="QR Code Content or URL",
201
+ value="",
202
+ )
203
+ with gr.Accordion(label="QR Code Image (Optional)", open=False):
204
+ qr_code_image = gr.Image(
205
+ label="QR Code Image (Optional). Leave blank to automatically generate QR code",
206
+ type="pil",
207
+ )
208
+
209
+ # negative_prompt = gr.Textbox(
210
+ # label="Negative Prompt",
211
+ # value="disfigured, low quality, blurry, nsfw",
212
+ # )
213
+
214
+ use_qr_code_as_init_image = gr.Checkbox(visible=False, label="QR Code is used as initial image.",
215
+ value=True, interactive=False,
216
+ info="Whether init image should be QR code. Unclick to pass init image or generate init image with Stable Diffusion 2.1")
217
+
218
+ with gr.Accordion(label="Init Images (Optional)", open=False, visible=False) as init_image_acc:
219
+ init_image = gr.Image(visible=False,
220
+ label="Init Image (Optional). Leave blank to generate image with SD 2.1",
221
+ type="pil")
222
+
223
+ # def change_view(qr_code_as_image: bool):
224
+ # if not qr_code_as_image:
225
+ # return {init_image_acc: gr.update(visible=True)}
226
+ # else:
227
+ # return {init_image_acc: gr.update(visible=False)}
228
+
229
+ # use_qr_code_as_init_image.change(change_view, inputs=[use_qr_code_as_init_image], outputs=[init_image_acc])
230
+
231
+ with gr.Accordion(
232
+ label="You can modify the generation slightly using the below sliders. See details below. \n ",
233
+ open=True,
234
+ ):
235
+ controlnet_conditioning_scale = gr.Slider(
236
+ minimum=0.6,
237
+ maximum=2.0,
238
+ step=0.01,
239
+ value=1.00,
240
+ label="QR High Pass",
241
+ )
242
+ strength = gr.Slider(
243
+ minimum=0.8, maximum=.95, step=0.01, value=0.9, label="QR Initial Weight"
244
+ )
245
+ guidance_scale = gr.Slider(
246
+ minimum=5.0,
247
+ maximum=15.0,
248
+ step=0.25,
249
+ value=8.0,
250
+ label="Prompt Weight",
251
+ )
252
+ sampler = gr.Textbox(visible=False,
253
+ value="DDIM") # gr.Dropdown(choices=list(SAMPLER_MAP.keys()), value="DPM++ Karras SDE")
254
+ seed = gr.Slider(
255
+ minimum=-1,
256
+ maximum=9999999999,
257
+ step=1,
258
+ value=2313123,
259
+ label="Seed",
260
+ randomize=True,
261
+ )
262
+ with gr.Row():
263
+ run_btn = gr.Button("Run")
264
+ with gr.Column():
265
+ result_image = gr.Image(label="Result Image")
266
+ run_btn.click(
267
+ inference,
268
+ inputs=[
269
+ qr_code_content,
270
+ prompt,
271
+ negative_prompt,
272
+ guidance_scale,
273
+ controlnet_conditioning_scale,
274
+ strength,
275
+ seed,
276
+ init_image,
277
+ qr_code_image,
278
+ use_qr_code_as_init_image,
279
+ sampler,
280
+ ],
281
+ outputs=[result_image],
282
+ )
283
+ gr.Markdown(
284
+ """
285
+ ### Settings Details
286
+ **QR High Pass** - Change this to affect how much the QR code is overlayed to your image in a second pass. Controlnet model.
287
+ (Higher setting is more QR code, lower setting is less QR code.)
288
+
289
+ **QR Initial Weight** - Change this to affect how much your image starts looking like a QR code!
290
+ (Higher settings mean your image starts with less QR, lower means the QR will appear sharper)
291
+
292
+ **Prompt Weight** - This determines how much the AI "Listens" to your prompt and try to put what you described into your image.
293
+ (Lower means it is more absract and higher follows your directions more.)
294
+
295
+ **Seed** - This is a randomizer! Use the same seed to generate the same image over and over. Change the seed to change up your image!
296
+ (You can copy your seed from a previous generation to get the same image.)
297
+ """
298
+ )
299
+
300
+ blocks.queue(concurrency_count=1, max_size=20)
301
+ blocks.launch(share=False)
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ diffusers
2
+ transformers
3
+ accelerate
4
+ torch
5
+ xformers
6
+ gradio
7
+ Pillow
8
+ qrcode