awacke1 commited on
Commit
5f1c8f8
·
verified ·
1 Parent(s): 2b24cdf

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +256 -0
app.py ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ from __future__ import annotations
3
+ import os, random, glob, re, json, base64
4
+ from datetime import datetime
5
+ import gradio as gr
6
+ import numpy as np
7
+ import PIL.Image
8
+ import spaces
9
+ import torch
10
+ import pandas as pd
11
+ from diffusers import AutoencoderKL, DiffusionPipeline
12
+
13
+ DESCRIPTION = """
14
+ # 🎨 ArtForge: AI-Powered Masterpiece Gallery
15
+
16
+ Create, curate, and compete with AI-generated art using OpenDalle V1.1. Join our creative multiplayer experience! 🖼️🏆✨
17
+
18
+ This demo showcases the capabilities of [OpenDalle V1.1](https://huggingface.co/dataautogpt3/OpenDalleV1.1) by @dataautogpt3, a powerful merge of several models designed for excellent performance.
19
+
20
+ **NOTE: The model is licensed under a non-commercial license**
21
+
22
+ Created by [mrfakename](https://mrfake.name/) - [Twitter](https://twitter.com/realmrfakename) - [GitHub](https://github.com/fakerybakery/) - [Hugging Face](https://huggingface.co/mrfakename)
23
+ """
24
+
25
+ if not torch.cuda.is_available():
26
+ DESCRIPTION += "\n<p>Running on CPU 🥶 This demo does not work on CPU. Please use <a href=\"https://huggingface.co/spaces/mrfakename/OpenDalleV1.1-GPU-Demo\">the online demo</a> instead.</p>"
27
+
28
+ MAX_SEED = np.iinfo(np.int32).max
29
+ CACHE_EXAMPLES = torch.cuda.is_available() and os.getenv("CACHE_EXAMPLES", "0") == "1"
30
+ MAX_IMAGE_SIZE = int(os.getenv("MAX_IMAGE_SIZE", "1024"))
31
+ USE_TORCH_COMPILE = os.getenv("USE_TORCH_COMPILE") == "1"
32
+ ENABLE_CPU_OFFLOAD = os.getenv("ENABLE_CPU_OFFLOAD") == "1"
33
+ ENABLE_REFINER = os.getenv("ENABLE_REFINER", "0") == "1"
34
+
35
+ # Global variables for metadata and likes cache
36
+ image_metadata = pd.DataFrame(columns=['Filename', 'Prompt', 'Likes', 'Dislikes', 'Hearts', 'Created'])
37
+ LIKES_CACHE_FILE = "likes_cache.json"
38
+
39
+ def load_likes_cache():
40
+ if os.path.exists(LIKES_CACHE_FILE):
41
+ with open(LIKES_CACHE_FILE, 'r') as f:
42
+ return json.load(f)
43
+ return {}
44
+
45
+ def save_likes_cache(cache):
46
+ with open(LIKES_CACHE_FILE, 'w') as f:
47
+ json.dump(cache, f)
48
+
49
+ likes_cache = load_likes_cache()
50
+
51
+ device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
52
+ if torch.cuda.is_available():
53
+ vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16)
54
+ pipe = DiffusionPipeline.from_pretrained("dataautogpt3/OpenDalleV1.1", vae=vae, torch_dtype=torch.float16, use_safetensors=True, variant="fp16")
55
+ if ENABLE_REFINER:
56
+ refiner = DiffusionPipeline.from_pretrained("stabilityai/stable-diffusion-xl-refiner-1.0", vae=vae, torch_dtype=torch.float16, use_safetensors=True, variant="fp16")
57
+ if ENABLE_CPU_OFFLOAD:
58
+ pipe.enable_model_cpu_offload()
59
+ if ENABLE_REFINER: refiner.enable_model_cpu_offload()
60
+ else:
61
+ pipe.to(device)
62
+ if ENABLE_REFINER: refiner.to(device)
63
+ if USE_TORCH_COMPILE:
64
+ pipe.unet = torch.compile(pipe.unet, mode="reduce-overhead", fullgraph=True)
65
+ if ENABLE_REFINER: refiner.unet = torch.compile(refiner.unet, mode="reduce-overhead", fullgraph=True)
66
+
67
+ def randomize_seed_fn(seed: int, randomize_seed: bool) -> int:
68
+ return random.randint(0, MAX_SEED) if randomize_seed else seed
69
+
70
+ def create_download_link(filename):
71
+ with open(filename, "rb") as file:
72
+ encoded_string = base64.b64encode(file.read()).decode('utf-8')
73
+ download_link = f'<a href="data:image/png;base64,{encoded_string}" download="{filename}">Download Image</a>'
74
+ return download_link
75
+
76
+ def save_image(image: PIL.Image.Image, prompt: str) -> str:
77
+ global image_metadata, likes_cache
78
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
79
+ safe_prompt = re.sub(r'[^\w\s-]', '', prompt.lower())[:50]
80
+ safe_prompt = re.sub(r'[-\s]+', '-', safe_prompt).strip('-')
81
+ filename = f"{timestamp}_{safe_prompt}.png"
82
+ image.save(filename)
83
+ new_row = pd.DataFrame({
84
+ 'Filename': [filename],
85
+ 'Prompt': [prompt],
86
+ 'Likes': [0],
87
+ 'Dislikes': [0],
88
+ 'Hearts': [0],
89
+ 'Created': [datetime.now()]
90
+ })
91
+ image_metadata = pd.concat([image_metadata, new_row], ignore_index=True)
92
+ likes_cache[filename] = {'likes': 0, 'dislikes': 0, 'hearts': 0}
93
+ save_likes_cache(likes_cache)
94
+ return filename
95
+
96
+ def get_image_gallery():
97
+ global image_metadata
98
+ image_files = image_metadata['Filename'].tolist()
99
+ return [(file, get_image_caption(file)) for file in image_files if os.path.exists(file)]
100
+
101
+ def get_image_caption(filename):
102
+ global likes_cache, image_metadata
103
+ if filename in likes_cache:
104
+ likes = likes_cache[filename]['likes']
105
+ dislikes = likes_cache[filename]['dislikes']
106
+ hearts = likes_cache[filename]['hearts']
107
+ prompt = image_metadata[image_metadata['Filename'] == filename]['Prompt'].values[0]
108
+ return f"{filename}\nPrompt: {prompt}\n👍 {likes} 👎 {dislikes} ❤️ {hearts}"
109
+ return filename
110
+
111
+ def delete_all_images():
112
+ global image_metadata, likes_cache
113
+ for file in image_metadata['Filename']:
114
+ if os.path.exists(file):
115
+ os.remove(file)
116
+ image_metadata = pd.DataFrame(columns=['Filename', 'Prompt', 'Likes', 'Dislikes', 'Hearts', 'Created'])
117
+ likes_cache = {}
118
+ save_likes_cache(likes_cache)
119
+ return get_image_gallery(), image_metadata.values.tolist()
120
+
121
+ def delete_image(filename):
122
+ global image_metadata, likes_cache
123
+ if filename and os.path.exists(filename):
124
+ os.remove(filename)
125
+ image_metadata = image_metadata[image_metadata['Filename'] != filename]
126
+ if filename in likes_cache:
127
+ del likes_cache[filename]
128
+ save_likes_cache(likes_cache)
129
+ return get_image_gallery(), image_metadata.values.tolist()
130
+
131
+ def vote(filename, vote_type):
132
+ global likes_cache
133
+ if filename in likes_cache:
134
+ likes_cache[filename][vote_type.lower()] += 1
135
+ save_likes_cache(likes_cache)
136
+ return get_image_gallery(), image_metadata.values.tolist()
137
+
138
+ @spaces.GPU(enable_queue=True)
139
+ def generate(prompt: str, negative_prompt: str = "", prompt_2: str = "", negative_prompt_2: str = "", use_negative_prompt: bool = False, use_prompt_2: bool = False, use_negative_prompt_2: bool = False, seed: int = 0, width: int = 1024, height: int = 1024, guidance_scale_base: float = 5.0, guidance_scale_refiner: float = 5.0, num_inference_steps_base: int = 25, num_inference_steps_refiner: int = 25, apply_refiner: bool = False, progress=gr.Progress(track_tqdm=True)) -> PIL.Image.Image:
140
+ print(f"** Generating image for: \"{prompt}\" **")
141
+ generator = torch.Generator().manual_seed(seed)
142
+ if not use_negative_prompt: negative_prompt = None
143
+ if not use_prompt_2: prompt_2 = None
144
+ if not use_negative_prompt_2: negative_prompt_2 = None
145
+ if not apply_refiner:
146
+ image = pipe(prompt=prompt, negative_prompt=negative_prompt, prompt_2=prompt_2, negative_prompt_2=negative_prompt_2, width=width, height=height, guidance_scale=guidance_scale_base, num_inference_steps=num_inference_steps_base, generator=generator, output_type="pil").images[0]
147
+ else:
148
+ latents = pipe(prompt=prompt, negative_prompt=negative_prompt, prompt_2=prompt_2, negative_prompt_2=negative_prompt_2, width=width, height=height, guidance_scale=guidance_scale_base, num_inference_steps=num_inference_steps_base, generator=generator, output_type="latent").images
149
+ image = refiner(prompt=prompt, negative_prompt=negative_prompt, prompt_2=prompt_2, negative_prompt_2=negative_prompt_2, guidance_scale=guidance_scale_refiner, num_inference_steps=num_inference_steps_refiner, image=latents, generator=generator).images[0]
150
+ filename = save_image(image, prompt)
151
+ download_link = create_download_link(filename)
152
+ return image, get_image_gallery(), download_link, image_metadata.values.tolist()
153
+
154
+ examples = [
155
+ f"{random.choice(['Impressionist', 'Cubist', 'Surrealist', 'Abstract Expressionist', 'Pop Art', 'Minimalist', 'Baroque', 'Art Nouveau', 'Pointillist', 'Fauvism'])} painting of a majestic lighthouse on a rocky coast. Use bold brushstrokes and a vibrant color palette to capture the interplay of light and shadow as the lighthouse beam cuts through a stormy night sky.",
156
+ f"{random.choice(['Impressionist', 'Cubist', 'Surrealist', 'Abstract Expressionist', 'Pop Art', 'Minimalist', 'Baroque', 'Art Nouveau', 'Pointillist', 'Fauvism'])} still life featuring a pair of vintage eyeglasses. Focus on the intricate details of the frames and lenses, using a warm color scheme to evoke a sense of nostalgia and wisdom.",
157
+ f"{random.choice(['Impressionist', 'Cubist', 'Surrealist', 'Abstract Expressionist', 'Pop Art', 'Minimalist', 'Baroque', 'Art Nouveau', 'Pointillist', 'Fauvism'])} depiction of a rustic wooden stool in a sunlit artist's studio. Emphasize the texture of the wood and the interplay of light and shadow, using a mix of earthy tones and highlights.",
158
+ f"{random.choice(['Impressionist', 'Cubist', 'Surrealist', 'Abstract Expressionist', 'Pop Art', 'Minimalist', 'Baroque', 'Art Nouveau', 'Pointillist', 'Fauvism'])} scene viewed through an ornate window frame. Contrast the intricate details of the window with a dreamy, soft-focus landscape beyond, using a palette that transitions from cool interior tones to warm exterior hues.",
159
+ f"{random.choice(['Impressionist', 'Cubist', 'Surrealist', 'Abstract Expressionist', 'Pop Art', 'Minimalist', 'Baroque', 'Art Nouveau', 'Pointillist', 'Fauvism'])} close-up study of interlaced fingers. Use a monochromatic color scheme to emphasize the form and texture of the hands, with dramatic lighting to create depth and emotion.",
160
+ f"{random.choice(['Impressionist', 'Cubist', 'Surrealist', 'Abstract Expressionist', 'Pop Art', 'Minimalist', 'Baroque', 'Art Nouveau', 'Pointillist', 'Fauvism'])} composition featuring a set of dice in motion. Capture the energy and randomness of the throw, using a dynamic color palette and blurred lines to convey movement.",
161
+ f"{random.choice(['Impressionist', 'Cubist', 'Surrealist', 'Abstract Expressionist', 'Pop Art', 'Minimalist', 'Baroque', 'Art Nouveau', 'Pointillist', 'Fauvism'])} interpretation of heaven. Create an ethereal atmosphere with soft, billowing clouds and radiant light, using a palette of celestial blues, golds, and whites.",
162
+ f"{random.choice(['Impressionist', 'Cubist', 'Surrealist', 'Abstract Expressionist', 'Pop Art', 'Minimalist', 'Baroque', 'Art Nouveau', 'Pointillist', 'Fauvism'])} portrayal of an ancient, mystical gate. Combine architectural details with elements of fantasy, using a rich, jewel-toned palette to create an air of mystery and magic.",
163
+ f"{random.choice(['Impressionist', 'Cubist', 'Surrealist', 'Abstract Expressionist', 'Pop Art', 'Minimalist', 'Baroque', 'Art Nouveau', 'Pointillist', 'Fauvism'])} portrait of a curious cat. Focus on capturing the feline's expressive eyes and sleek form, using a mix of bold and subtle colors to bring out the cat's personality.",
164
+ f"{random.choice(['Impressionist', 'Cubist', 'Surrealist', 'Abstract Expressionist', 'Pop Art', 'Minimalist', 'Baroque', 'Art Nouveau', 'Pointillist', 'Fauvism'])} abstract representation of toes in sand. Use textured brushstrokes to convey the feeling of warm sand, with a palette inspired by a sun-drenched beach."
165
+ ]
166
+
167
+ css = '''
168
+ .gradio-container {max-width: 1024px !important}
169
+ h1 {text-align: center}
170
+ footer {visibility: hidden}
171
+ '''
172
+
173
+ theme = gr.themes.Soft()
174
+ with gr.Blocks(css=css, theme=theme) as demo:
175
+ gr.Markdown(DESCRIPTION)
176
+ gr.DuplicateButton(value="Duplicate Space for private use", elem_id="duplicate-button", visible=os.getenv("SHOW_DUPLICATE_BUTTON") == "1")
177
+
178
+ with gr.Tab("Generate Images"):
179
+ with gr.Group():
180
+ with gr.Row():
181
+ prompt = gr.Text(label="Prompt", show_label=False, max_lines=1, placeholder="Enter your prompt", container=False)
182
+ run_button = gr.Button("Generate", scale=0)
183
+ result = gr.Image(label="Result", show_label=False)
184
+ download_link = gr.HTML(label="Download", show_label=False)
185
+
186
+ with gr.Accordion("Advanced options", open=False):
187
+ with gr.Row():
188
+ use_negative_prompt = gr.Checkbox(label="Use negative prompt", value=False)
189
+ use_prompt_2use_prompt_2 = gr.Checkbox(label="Use prompt 2", value=False)
190
+ use_negative_prompt_2 = gr.Checkbox(label="Use negative prompt 2", value=False)
191
+ negative_prompt = gr.Text(label="Negative prompt", max_lines=1, placeholder="Enter a negative prompt", visible=False)
192
+ prompt_2 = gr.Text(label="Prompt 2", max_lines=1, placeholder="Enter your second prompt", visible=False)
193
+ negative_prompt_2 = gr.Text(label="Negative prompt 2", max_lines=1, placeholder="Enter a second negative prompt", visible=False)
194
+ seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
195
+ randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
196
+ with gr.Row():
197
+ width = gr.Slider(label="Width", minimum=256, maximum=MAX_IMAGE_SIZE, step=32, value=1024)
198
+ height = gr.Slider(label="Height", minimum=256, maximum=MAX_IMAGE_SIZE, step=32, value=1024)
199
+ apply_refiner = gr.Checkbox(label="Apply refiner", value=False, visible=ENABLE_REFINER)
200
+ with gr.Row():
201
+ guidance_scale_base = gr.Slider(label="Guidance scale for base", minimum=1, maximum=20, step=0.1, value=5.0)
202
+ num_inference_steps_base = gr.Slider(label="Number of inference steps for base", minimum=10, maximum=100, step=1, value=25)
203
+ with gr.Row(visible=False) as refiner_params:
204
+ guidance_scale_refiner = gr.Slider(label="Guidance scale for refiner", minimum=1, maximum=20, step=0.1, value=5.0)
205
+ num_inference_steps_refiner = gr.Slider(label="Number of inference steps for refiner", minimum=10, maximum=100, step=1, value=25)
206
+
207
+ with gr.Tab("Gallery and Voting"):
208
+ image_gallery = gr.Gallery(label="Generated Images", show_label=True, columns=4, height="auto")
209
+
210
+ with gr.Row():
211
+ like_button = gr.Button("👍 Like")
212
+ dislike_button = gr.Button("👎 Dislike")
213
+ heart_button = gr.Button("❤️ Heart")
214
+ delete_image_button = gr.Button("🗑️ Delete Selected Image")
215
+
216
+ selected_image = gr.State(None)
217
+
218
+ with gr.Tab("Metadata and Management"):
219
+ metadata_df = gr.Dataframe(
220
+ label="Image Metadata",
221
+ headers=["Filename", "Prompt", "Likes", "Dislikes", "Hearts", "Created"],
222
+ interactive=False
223
+ )
224
+ delete_all_button = gr.Button("🗑️ Delete All Images")
225
+
226
+ gr.Examples(examples=examples, inputs=prompt, outputs=[result, image_gallery, download_link, metadata_df], fn=generate, cache_examples=CACHE_EXAMPLES)
227
+
228
+ use_negative_prompt.change(fn=lambda x: gr.update(visible=x), inputs=use_negative_prompt, outputs=negative_prompt, queue=False, api_name=False)
229
+ use_prompt_2.change(fn=lambda x: gr.update(visible=x), inputs=use_prompt_2, outputs=prompt_2, queue=False, api_name=False)
230
+ use_negative_prompt_2.change(fn=lambda x: gr.update(visible=x), inputs=use_negative_prompt_2, outputs=negative_prompt_2, queue=False, api_name=False)
231
+ apply_refiner.change(fn=lambda x: gr.update(visible=x), inputs=apply_refiner, outputs=refiner_params, queue=False, api_name=False)
232
+
233
+ prompt.submit(fn=randomize_seed_fn, inputs=[seed, randomize_seed], outputs=seed, queue=False, api_name=False).then(
234
+ fn=generate,
235
+ inputs=[prompt, negative_prompt, prompt_2, negative_prompt_2, use_negative_prompt, use_prompt_2, use_negative_prompt_2, seed, width, height, guidance_scale_base, guidance_scale_refiner, num_inference_steps_base, num_inference_steps_refiner, apply_refiner],
236
+ outputs=[result, image_gallery, download_link, metadata_df]
237
+ )
238
+
239
+ run_button.click(fn=randomize_seed_fn, inputs=[seed, randomize_seed], outputs=seed, queue=False, api_name=False).then(
240
+ fn=generate,
241
+ inputs=[prompt, negative_prompt, prompt_2, negative_prompt_2, use_negative_prompt, use_prompt_2, use_negative_prompt_2, seed, width, height, guidance_scale_base, guidance_scale_refiner, num_inference_steps_base, num_inference_steps_refiner, apply_refiner],
242
+ outputs=[result, image_gallery, download_link, metadata_df]
243
+ )
244
+
245
+ image_gallery.select(fn=lambda evt: evt, inputs=[], outputs=[selected_image])
246
+
247
+ like_button.click(fn=lambda x: vote(x, 'likes'), inputs=[selected_image], outputs=[image_gallery, metadata_df])
248
+ dislike_button.click(fn=lambda x: vote(x, 'dislikes'), inputs=[selected_image], outputs=[image_gallery, metadata_df])
249
+ heart_button.click(fn=lambda x: vote(x, 'hearts'), inputs=[selected_image], outputs=[image_gallery, metadata_df])
250
+ delete_image_button.click(fn=delete_image, inputs=[selected_image], outputs=[image_gallery, metadata_df])
251
+ delete_all_button.click(fn=delete_all_images, inputs=[], outputs=[image_gallery, metadata_df])
252
+
253
+ demo.load(fn=lambda: (get_image_gallery(), image_metadata.values.tolist()), outputs=[image_gallery, metadata_df])
254
+
255
+ if __name__ == "__main__":
256
+ demo.queue(max_size=20).launch(share=True, debug=False)