Daniel Jarvis commited on
Commit
83ab419
·
1 Parent(s): f4a907c

app.py rename

Browse files
Files changed (1) hide show
  1. app.py +321 -0
app.py ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import time
3
+ import random
4
+ from PIL import Image, ImageDraw, ImageFont
5
+ import io
6
+ import base64
7
+
8
+ class ImageGeneratorBot:
9
+ def __init__(self):
10
+ self.conversation_history = []
11
+ self.current_images = {}
12
+ self.job_counter = 0
13
+
14
+ def generate_mock_image(self, prompt, width=512, height=512, seed=None):
15
+ """Generate a mock image with the prompt text overlay"""
16
+ if seed:
17
+ random.seed(seed)
18
+
19
+ # Create a random colored background
20
+ colors = [(255, 200, 200), (200, 255, 200), (200, 200, 255),
21
+ (255, 255, 200), (255, 200, 255), (200, 255, 255)]
22
+ bg_color = random.choice(colors)
23
+
24
+ img = Image.new('RGB', (width, height), bg_color)
25
+ draw = ImageDraw.Draw(img)
26
+
27
+ # Add some random shapes
28
+ for _ in range(5):
29
+ x1, y1 = random.randint(0, width//2), random.randint(0, height//2)
30
+ x2, y2 = random.randint(width//2, width), random.randint(height//2, height)
31
+ shape_color = tuple(random.randint(100, 255) for _ in range(3))
32
+ draw.rectangle([x1, y1, x2, y2], fill=shape_color, outline=(0,0,0))
33
+
34
+ # Add prompt text
35
+ try:
36
+ font = ImageFont.load_default()
37
+ except:
38
+ font = None
39
+
40
+ # Wrap text
41
+ words = prompt.split()
42
+ lines = []
43
+ current_line = []
44
+ for word in words:
45
+ current_line.append(word)
46
+ if len(' '.join(current_line)) > 30:
47
+ lines.append(' '.join(current_line[:-1]))
48
+ current_line = [word]
49
+ if current_line:
50
+ lines.append(' '.join(current_line))
51
+
52
+ y_offset = height // 2 - len(lines) * 10
53
+ for line in lines:
54
+ bbox = draw.textbbox((0, 0), line, font=font)
55
+ text_width = bbox[2] - bbox[0]
56
+ x_offset = (width - text_width) // 2
57
+ draw.text((x_offset, y_offset), line, fill=(0, 0, 0), font=font)
58
+ y_offset += 20
59
+
60
+ return img
61
+
62
+ def process_prompt(self, prompt, chat_history):
63
+ """Process the user prompt and generate images"""
64
+ if not prompt.strip():
65
+ return chat_history, "", gr.update(visible=False)
66
+
67
+ self.job_counter += 1
68
+ job_id = f"job_{self.job_counter}"
69
+
70
+ # Add user message to chat
71
+ chat_history.append([prompt, None])
72
+
73
+ # Simulate processing time
74
+ processing_msg = f"🎨 Generating images for: '{prompt}'\n⏳ Processing..."
75
+ chat_history.append([None, processing_msg])
76
+
77
+ # Generate 4 mock images
78
+ images = []
79
+ for i in range(4):
80
+ img = self.generate_mock_image(prompt, seed=hash(prompt + str(i)))
81
+ images.append(img)
82
+
83
+ # Store images for upscaling/variations
84
+ self.current_images[job_id] = {
85
+ 'prompt': prompt,
86
+ 'images': images,
87
+ 'original_prompt': prompt
88
+ }
89
+
90
+ # Create response with images
91
+ response_html = self.create_image_response(job_id, prompt, images)
92
+ chat_history[-1] = [None, response_html]
93
+
94
+ return chat_history, "", gr.update(visible=True)
95
+
96
+ def create_image_response(self, job_id, prompt, images):
97
+ """Create HTML response with images in a grid"""
98
+ html = f"""
99
+ <div style="border: 1px solid #ddd; padding: 15px; border-radius: 10px; background: #f9f9f9;">
100
+ <h4 style="margin-top: 0; color: #333;">✅ Generated Images</h4>
101
+ <p style="margin: 5px 0; color: #666;"><strong>Prompt:</strong> {prompt}</p>
102
+ <p style="margin: 5px 0 15px 0; color: #666;"><strong>Job ID:</strong> {job_id}</p>
103
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; max-width: 400px;">
104
+ """
105
+
106
+ for i, img in enumerate(images):
107
+ # Convert PIL image to base64 for HTML display
108
+ buffered = io.BytesIO()
109
+ img.save(buffered, format="PNG")
110
+ img_str = base64.b64encode(buffered.getvalue()).decode()
111
+
112
+ html += f"""
113
+ <div style="text-align: center;">
114
+ <img src="data:image/png;base64,{img_str}"
115
+ style="width: 100%; border-radius: 5px; border: 2px solid #ddd;">
116
+ <div style="margin-top: 5px; font-size: 12px; color: #666;">Image {i+1}</div>
117
+ </div>
118
+ """
119
+
120
+ html += """
121
+ </div>
122
+ <p style="margin: 15px 0 5px 0; color: #666; font-size: 14px;">
123
+ Use the buttons below to upscale (U) or create variations (V) of specific images.
124
+ </p>
125
+ </div>
126
+ """
127
+
128
+ return html
129
+
130
+
131
+
132
+ def upscale_image(self, job_id, image_index, chat_history):
133
+ """Upscale a specific image"""
134
+ if job_id not in self.current_images:
135
+ return chat_history
136
+
137
+ original_data = self.current_images[job_id]
138
+ original_img = original_data['images'][image_index]
139
+ prompt = original_data['prompt']
140
+
141
+ # Generate upscaled version (2x size)
142
+ upscaled_img = self.generate_mock_image(
143
+ f"{prompt} (Upscaled)",
144
+ width=1024,
145
+ height=1024,
146
+ seed=hash(prompt + str(image_index) + "upscale")
147
+ )
148
+
149
+ # Create response
150
+ buffered = io.BytesIO()
151
+ upscaled_img.save(buffered, format="PNG")
152
+ img_str = base64.b64encode(buffered.getvalue()).decode()
153
+
154
+ response_html = f"""
155
+ <div style="border: 1px solid #ddd; padding: 15px; border-radius: 10px; background: #f0f8ff;">
156
+ <h4 style="margin-top: 0; color: #333;">🔍 Upscaled Image {image_index + 1}</h4>
157
+ <p style="margin: 5px 0; color: #666;"><strong>Original Prompt:</strong> {prompt}</p>
158
+ <div style="text-align: center; margin: 15px 0;">
159
+ <img src="data:image/png;base64,{img_str}"
160
+ style="max-width: 100%; border-radius: 5px; border: 2px solid #4CAF50;">
161
+ </div>
162
+ <p style="margin: 10px 0 5px 0; color: #666; font-size: 14px;">
163
+ ✨ Image upscaled to higher resolution!
164
+ </p>
165
+ </div>
166
+ """
167
+
168
+ chat_history.append([None, response_html])
169
+ return chat_history
170
+
171
+ def create_variation(self, job_id, image_index, chat_history):
172
+ """Create variations of a specific image"""
173
+ if job_id not in self.current_images:
174
+ return chat_history
175
+
176
+ original_data = self.current_images[job_id]
177
+ prompt = original_data['prompt']
178
+
179
+ # Generate 4 variations
180
+ variation_images = []
181
+ for i in range(4):
182
+ var_img = self.generate_mock_image(
183
+ f"{prompt} (Variation)",
184
+ seed=hash(prompt + str(image_index) + "variation" + str(i))
185
+ )
186
+ variation_images.append(var_img)
187
+
188
+ # Store variations
189
+ new_job_id = f"job_{self.job_counter}_var_{image_index + 1}"
190
+ self.current_images[new_job_id] = {
191
+ 'prompt': f"{prompt} (Variations of Image {image_index + 1})",
192
+ 'images': variation_images,
193
+ 'original_prompt': prompt
194
+ }
195
+
196
+ # Create response
197
+ response_html = self.create_image_response(
198
+ new_job_id,
199
+ f"{prompt} (Variations of Image {image_index + 1})",
200
+ variation_images
201
+ )
202
+
203
+ chat_history.append([None, response_html])
204
+ return chat_history
205
+
206
+ # Initialize the bot
207
+ bot = ImageGeneratorBot()
208
+
209
+ # Create the Gradio interface
210
+ with gr.Blocks(title="AI Image Generator Chat", theme=gr.themes.Soft()) as demo:
211
+ gr.Markdown("""
212
+ # 🎨 AI Image Generator Chat
213
+ ### Midjourney-style interface for image generation
214
+
215
+ Enter your prompt below and get 4 generated images. Use the U buttons to upscale specific images,
216
+ or V buttons to create variations of specific images.
217
+ """)
218
+
219
+ with gr.Row():
220
+ with gr.Column(scale=4):
221
+ chatbot = gr.Chatbot(
222
+ height=500,
223
+ show_label=False,
224
+ container=True,
225
+ bubble_full_width=False
226
+ )
227
+
228
+ with gr.Row():
229
+ prompt_input = gr.Textbox(
230
+ placeholder="Enter your image prompt (e.g., 'a cat wearing a space suit on Mars --ar 16:9')",
231
+ show_label=False,
232
+ scale=4
233
+ )
234
+ generate_btn = gr.Button("Generate", variant="primary")
235
+
236
+ action_buttons_container = gr.Column(visible=False)
237
+ with action_buttons_container:
238
+ gr.Markdown("### 🔧 Image Actions")
239
+ gr.Markdown("**Upscale (U):** Get higher resolution version")
240
+ upscale_row = gr.Row()
241
+ with upscale_row:
242
+ u1_btn = gr.Button("U1", size="sm")
243
+ u2_btn = gr.Button("U2", size="sm")
244
+ u3_btn = gr.Button("U3", size="sm")
245
+ u4_btn = gr.Button("U4", size="sm")
246
+
247
+ gr.Markdown("**Variations (V):** Generate variations of specific image")
248
+ variation_row = gr.Row()
249
+ with variation_row:
250
+ v1_btn = gr.Button("V1", size="sm", variant="secondary")
251
+ v2_btn = gr.Button("V2", size="sm", variant="secondary")
252
+ v3_btn = gr.Button("V3", size="sm", variant="secondary")
253
+ v4_btn = gr.Button("V4", size="sm", variant="secondary")
254
+
255
+ with gr.Column(scale=1):
256
+ gr.Markdown("""
257
+ ### 💡 Tips
258
+ - Be descriptive in your prompts
259
+ - Use aspect ratios like `--ar 16:9`
260
+ - Try artistic styles: "in the style of..."
261
+ - Add quality modifiers: "--quality high"
262
+
263
+ ### 🎯 Example Prompts
264
+ - "a magical forest with glowing mushrooms"
265
+ - "cyberpunk city at night --ar 16:9"
266
+ - "portrait of a wise owl wearing glasses"
267
+ - "abstract art with vibrant colors"
268
+ """)
269
+
270
+ current_job_id = gr.State(None)
271
+
272
+ # Event handlers
273
+ def handle_generate(prompt, history):
274
+ result = bot.process_prompt(prompt, history)
275
+ # Extract job_id from the last response to store in state
276
+ if bot.current_images:
277
+ latest_job = list(bot.current_images.keys())[-1]
278
+ return result + (latest_job,)
279
+ return result + (None,)
280
+
281
+ def handle_upscale(job_id, image_idx, history):
282
+ if job_id:
283
+ return bot.upscale_image(job_id, image_idx, history)
284
+ return history
285
+
286
+ def handle_variation(job_id, image_idx, history):
287
+ if job_id:
288
+ new_history = bot.create_variation(job_id, image_idx, history)
289
+ # Update job_id to the new variation job
290
+ if bot.current_images:
291
+ new_job_id = list(bot.current_images.keys())[-1]
292
+ return new_history, new_job_id
293
+ return history, job_id
294
+
295
+ # Connect events
296
+ generate_btn.click(
297
+ handle_generate,
298
+ inputs=[prompt_input, chatbot],
299
+ outputs=[chatbot, prompt_input, action_buttons_container, current_job_id]
300
+ )
301
+
302
+ prompt_input.submit(
303
+ handle_generate,
304
+ inputs=[prompt_input, chatbot],
305
+ outputs=[chatbot, prompt_input, action_buttons_container, current_job_id]
306
+ )
307
+
308
+ # Upscale button events
309
+ u1_btn.click(lambda job_id, hist: handle_upscale(job_id, 0, hist), [current_job_id, chatbot], [chatbot])
310
+ u2_btn.click(lambda job_id, hist: handle_upscale(job_id, 1, hist), [current_job_id, chatbot], [chatbot])
311
+ u3_btn.click(lambda job_id, hist: handle_upscale(job_id, 2, hist), [current_job_id, chatbot], [chatbot])
312
+ u4_btn.click(lambda job_id, hist: handle_upscale(job_id, 3, hist), [current_job_id, chatbot], [chatbot])
313
+
314
+ # Variation button events
315
+ v1_btn.click(lambda job_id, hist: handle_variation(job_id, 0, hist), [current_job_id, chatbot], [chatbot, current_job_id])
316
+ v2_btn.click(lambda job_id, hist: handle_variation(job_id, 1, hist), [current_job_id, chatbot], [chatbot, current_job_id])
317
+ v3_btn.click(lambda job_id, hist: handle_variation(job_id, 2, hist), [current_job_id, chatbot], [chatbot, current_job_id])
318
+ v4_btn.click(lambda job_id, hist: handle_variation(job_id, 3, hist), [current_job_id, chatbot], [chatbot, current_job_id])
319
+
320
+ if __name__ == "__main__":
321
+ demo.launch()