Minekooooooooooo2 commited on
Commit
f737e2c
·
verified ·
1 Parent(s): af34724

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. app.py +457 -0
  2. requirements.txt +10 -0
app.py ADDED
@@ -0,0 +1,457 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import requests
4
+ from PIL import Image, ImageDraw, ImageFont
5
+ import random
6
+ import io
7
+ import os
8
+ from pathlib import Path
9
+
10
+ # Set up static paths for faster loading
11
+ gr.set_static_paths(["assets"])
12
+
13
+ # Download some fonts if not available
14
+ FONT_PATH = "assets/fonts"
15
+ os.makedirs(FONT_PATH, exist_ok=True)
16
+
17
+ # Download Impact font (common meme font)
18
+ IMPACT_URL = "https://github.com/google/fonts/raw/main/apache/impact/Impact.ttf"
19
+ IMPACT_PATH = os.path.join(FONT_PATH, "Impact.ttf")
20
+
21
+ if not os.path.exists(IMPACT_PATH):
22
+ response = requests.get(IMPACT_URL)
23
+ with open(IMPACT_PATH, "wb") as f:
24
+ f.write(response.content)
25
+
26
+ # Download some other fonts
27
+ FONT_URLS = {
28
+ "Arial": "https://github.com/google/fonts/raw/main/apache/arial/Arial.ttf",
29
+ "ComicSans": "https://github.com/google/fonts/raw/main/apache/comicsansms/ComicSansMS.ttf",
30
+ "TimesNewRoman": "https://github.com/google/fonts/raw/main/apache/timesnewroman/TimesNewRoman.ttf"
31
+ }
32
+
33
+ for font_name, url in FONT_URLS.items():
34
+ font_path = os.path.join(FONT_PATH, f"{font_name}.ttf")
35
+ if not os.path.exists(font_path):
36
+ try:
37
+ response = requests.get(url)
38
+ with open(font_path, "wb") as f:
39
+ f.write(response.content)
40
+ except:
41
+ pass # Skip if font download fails
42
+
43
+ # Load meme templates and quotes
44
+ MEME_TEMPLATES = [
45
+ {"name": "Distracted Boyfriend", "image": "https://i.imgur.com/5e3qY.jpg", "boxes": [{"x": 0.1, "y": 0.1, "width": 0.3, "height": 0.2}, {"x": 0.6, "y": 0.1, "width": 0.3, "height": 0.2}, {"x": 0.4, "y": 0.6, "width": 0.2, "height": 0.2}]},
46
+ {"name": "Drake Hotline Bling", "image": "https://i.imgur.com/5e3qY.jpg", "boxes": [{"x": 0.1, "y": 0.1, "width": 0.8, "height": 0.3}, {"x": 0.1, "y": 0.6, "width": 0.8, "height": 0.3}]},
47
+ {"name": "Two Buttons", "image": "https://i.imgur.com/5e3qY.jpg", "boxes": [{"x": 0.1, "y": 0.4, "width": 0.3, "height": 0.2}, {"x": 0.6, "y": 0.4, "width": 0.3, "height": 0.2}]},
48
+ {"name": "Expanding Brain", "image": "https://i.imgur.com/5e3qY.jpg", "boxes": [{"x": 0.1, "y": 0.1, "width": 0.2, "height": 0.2}, {"x": 0.4, "y": 0.3, "width": 0.2, "height": 0.2}, {"x": 0.7, "y": 0.5, "width": 0.2, "height": 0.2}]},
49
+ {"name": "Woman Yelling at Cat", "image": "https://i.imgur.com/5e3qY.jpg", "boxes": [{"x": 0.1, "y": 0.1, "width": 0.3, "height": 0.2}, {"x": 0.6, "y": 0.6, "width": 0.3, "height": 0.2}]}
50
+ ]
51
+
52
+ QUOTES = [
53
+ "When you realize you left the oven on",
54
+ "Me trying to adult",
55
+ "When the WiFi is slow",
56
+ "My brain at 3 AM",
57
+ "When someone says 'just relax'",
58
+ "Me pretending I understand",
59
+ "When you find money in your pocket",
60
+ "My motivation level",
61
+ "When the food is finally ready",
62
+ "Me avoiding responsibilities",
63
+ "When you hear a funny joke",
64
+ "My reaction to Mondays",
65
+ "When the weekend is over",
66
+ "Me trying to be productive",
67
+ "When you see a cute animal",
68
+ "My face when I see my bank account",
69
+ "When someone cancels plans",
70
+ "Me trying to parallel park",
71
+ "When you remember an embarrassing moment",
72
+ "My reaction to bad news"
73
+ ]
74
+
75
+ SHITPOST_PHRASES = [
76
+ "This is fine",
77
+ "I have no idea what I'm doing",
78
+ "Send help",
79
+ "Why is this happening?",
80
+ "I need adult supervision",
81
+ "This is my life now",
82
+ "I regret my choices",
83
+ "I'm not okay",
84
+ "This is the worst",
85
+ "I give up",
86
+ "Why me?",
87
+ "I'm dying inside",
88
+ "This is a disaster",
89
+ "I'm not ready",
90
+ "This is too much",
91
+ "I can't even",
92
+ "This is ridiculous",
93
+ "I'm over it",
94
+ "This is insane",
95
+ "I'm done"
96
+ ]
97
+
98
+ def get_random_font():
99
+ """Get a random font from available fonts"""
100
+ font_files = [f for f in os.listdir(FONT_PATH) if f.endswith('.ttf')]
101
+ if font_files:
102
+ return os.path.join(FONT_PATH, random.choice(font_files))
103
+ return IMPACT_PATH
104
+
105
+ def add_text_to_image(image, text, font_path=IMPACT_PATH, font_size=40, color=(255, 255, 255), stroke_width=2, stroke_color=(0, 0, 0), position="center", max_width=0.8):
106
+ """
107
+ Add text to an image with various styling options
108
+ """
109
+ # Convert to PIL Image if it's a numpy array
110
+ if isinstance(image, np.ndarray):
111
+ image = Image.fromarray(image)
112
+
113
+ # Create a draw object
114
+ draw = ImageDraw.Draw(image)
115
+
116
+ # Load font
117
+ try:
118
+ font = ImageFont.truetype(font_path, font_size)
119
+ except:
120
+ font = ImageFont.load_default()
121
+
122
+ # Calculate text size and position
123
+ text_width, text_height = draw.textsize(text, font=font)
124
+
125
+ # Calculate position based on max_width percentage
126
+ img_width, img_height = image.size
127
+ max_text_width = int(img_width * max_width)
128
+
129
+ # Wrap text if needed
130
+ if text_width > max_text_width:
131
+ # Simple text wrapping
132
+ words = text.split()
133
+ lines = []
134
+ current_line = []
135
+
136
+ for word in words:
137
+ test_line = ' '.join(current_line + [word])
138
+ test_width, _ = draw.textsize(test_line, font=font)
139
+
140
+ if test_width <= max_text_width:
141
+ current_line.append(word)
142
+ else:
143
+ lines.append(' '.join(current_line))
144
+ current_line = [word]
145
+
146
+ if current_line:
147
+ lines.append(' '.join(current_line))
148
+
149
+ text = '\n'.join(lines)
150
+ text_width, text_height = draw.textsize(text, font=font)
151
+
152
+ # Calculate position
153
+ if position == "center":
154
+ x = (img_width - text_width) // 2
155
+ y = (img_height - text_height) // 2
156
+ elif position == "top":
157
+ x = (img_width - text_width) // 2
158
+ y = 20
159
+ elif position == "bottom":
160
+ x = (img_width - text_width) // 2
161
+ y = img_height - text_height - 20
162
+ elif position == "left":
163
+ x = 20
164
+ y = (img_height - text_height) // 2
165
+ elif position == "right":
166
+ x = img_width - text_width - 20
167
+ y = (img_height - text_height) // 2
168
+ else:
169
+ # Custom position format: "x,y" where x and y are percentages
170
+ try:
171
+ x_percent, y_percent = map(float, position.split(','))
172
+ x = int((img_width * x_percent) - (text_width / 2))
173
+ y = int((img_height * y_percent) - (text_height / 2))
174
+ except:
175
+ x = (img_width - text_width) // 2
176
+ y = (img_height - text_height) // 2
177
+
178
+ # Draw text with stroke
179
+ for dx in range(-stroke_width, stroke_width + 1):
180
+ for dy in range(-stroke_width, stroke_width + 1):
181
+ if dx != 0 or dy != 0:
182
+ draw.text((x + dx, y + dy), text, font=font, fill=stroke_color)
183
+
184
+ # Draw main text
185
+ draw.text((x, y), text, font=font, fill=color)
186
+
187
+ return image
188
+
189
+ def create_meme(image, meme_type="random", custom_text=None, font_size=40, text_color=(255, 255, 255), stroke_color=(0, 0, 0), stroke_width=2):
190
+ """
191
+ Create a meme from an image
192
+ """
193
+ # Convert to PIL Image if it's a numpy array
194
+ if isinstance(image, np.ndarray):
195
+ image = Image.fromarray(image)
196
+
197
+ # Get meme template
198
+ if meme_type == "random":
199
+ template = random.choice(MEME_TEMPLATES)
200
+ else:
201
+ template = next((t for t in MEME_TEMPLATES if t["name"] == meme_type), MEME_TEMPLATES[0])
202
+
203
+ # Get text for each box
204
+ texts = []
205
+ if custom_text:
206
+ # Split custom text by newlines
207
+ texts = custom_text.split('\n')
208
+ else:
209
+ # Use random quotes
210
+ texts = [random.choice(QUOTES) for _ in template["boxes"]]
211
+
212
+ # Add text to image for each box
213
+ for i, box in enumerate(template["boxes"]):
214
+ if i < len(texts):
215
+ text = texts[i]
216
+ # Calculate position from box coordinates
217
+ x_percent = box["x"] + box["width"] / 2
218
+ y_percent = box["y"] + box["height"] / 2
219
+ position = f"{x_percent},{y_percent}"
220
+
221
+ image = add_text_to_image(
222
+ image, text,
223
+ font_path=get_random_font(),
224
+ font_size=font_size,
225
+ color=text_color,
226
+ stroke_color=stroke_color,
227
+ stroke_width=stroke_width,
228
+ position=position,
229
+ max_width=box["width"] * 0.9
230
+ )
231
+
232
+ return image
233
+
234
+ def create_quote_image(image, quote_type="inspirational", custom_text=None, font_size=40, text_color=(255, 255, 255), stroke_color=(0, 0, 0), stroke_width=2, position="center"):
235
+ """
236
+ Create a quote image
237
+ """
238
+ # Get quote text
239
+ if custom_text:
240
+ text = custom_text
241
+ else:
242
+ if quote_type == "inspirational":
243
+ text = random.choice([
244
+ "Believe you can and you're halfway there",
245
+ "The only way to do great work is to love what you do",
246
+ "Don't watch the clock; do what it does. Keep going",
247
+ "Success is not final, failure is not fatal",
248
+ "You are never too old to set another goal",
249
+ "The future belongs to those who believe in their dreams",
250
+ "Everything you've ever wanted is on the other side of fear",
251
+ "Hardships often prepare ordinary people for extraordinary destiny",
252
+ "Don't be pushed around by the fears in your mind",
253
+ "The only limit to our realization of tomorrow is our doubts of today"
254
+ ])
255
+ elif quote_type == "funny":
256
+ text = random.choice([
257
+ "I'm not lazy, I'm on energy saving mode",
258
+ "I put the 'pro' in procrastination",
259
+ "I'm not arguing, I'm just explaining why I'm right",
260
+ "I don't need anger management, I need people to stop pissing me off",
261
+ "I'm not short, I'm just more down to earth than you",
262
+ "I'm not bossy, I just have better ideas",
263
+ "I'm not crazy, my reality is just different than yours",
264
+ "I'm not a regular mom, I'm a cool mom",
265
+ "I'm not a morning person, I'm a coffee person",
266
+ "I'm not a shopaholic, I'm helping the economy"
267
+ ])
268
+ elif quote_type == "shitpost":
269
+ text = random.choice(SHITPOST_PHRASES)
270
+ else:
271
+ text = random.choice(QUOTES)
272
+
273
+ # Add text to image
274
+ image = add_text_to_image(
275
+ image, text,
276
+ font_path=get_random_font(),
277
+ font_size=font_size,
278
+ color=text_color,
279
+ stroke_color=stroke_color,
280
+ stroke_width=stroke_width,
281
+ position=position
282
+ )
283
+
284
+ return image
285
+
286
+ def process_image(image, content_type, custom_text=None, font_size=40, text_color=(255, 255, 255), stroke_color=(0, 0, 0), stroke_width=2, position="center", meme_type="random"):
287
+ """
288
+ Main processing function
289
+ """
290
+ if image is None:
291
+ raise gr.Error("Please upload an image first!")
292
+
293
+ try:
294
+ if content_type == "meme":
295
+ result = create_meme(image, meme_type=meme_type, custom_text=custom_text, font_size=font_size, text_color=text_color, stroke_color=stroke_color, stroke_width=stroke_width)
296
+ else:
297
+ result = create_quote_image(image, quote_type=content_type, custom_text=custom_text, font_size=font_size, text_color=text_color, stroke_color=stroke_color, stroke_width=stroke_width, position=position)
298
+
299
+ return result
300
+ except Exception as e:
301
+ raise gr.Error(f"Error processing image: {str(e)}")
302
+
303
+ # Create custom theme
304
+ custom_theme = gr.themes.Soft(
305
+ primary_hue="blue",
306
+ secondary_hue="indigo",
307
+ neutral_hue="slate",
308
+ font=gr.themes.GoogleFont("Inter"),
309
+ text_size="lg",
310
+ spacing_size="lg",
311
+ radius_size="md"
312
+ ).set(
313
+ button_primary_background_fill="*primary_600",
314
+ button_primary_background_fill_hover="*primary_700",
315
+ block_title_text_weight="600",
316
+ )
317
+
318
+ # Create the Gradio interface
319
+ with gr.Blocks() as demo:
320
+ gr.Markdown("""
321
+ # 🎨 Neural Network Image Editor
322
+
323
+ Upload an image and let our neural networks add random quotes, memes, or shitposts to it!
324
+
325
+ [![Built with anycoder](https://img.shields.io/badge/Built%20with-anycoder-%23FF6B6B.svg?style=for-the-badge)](https://huggingface.co/spaces/akhaliq/anycoder)
326
+ """)
327
+
328
+ with gr.Row():
329
+ with gr.Column():
330
+ # Image upload
331
+ input_image = gr.Image(label="Upload your image", type="numpy", sources=["upload", "webcam", "clipboard"])
332
+
333
+ # Content type selection
334
+ content_type = gr.Radio(
335
+ choices=["meme", "inspirational", "funny", "shitpost"],
336
+ value="meme",
337
+ label="Content Type"
338
+ )
339
+
340
+ # Meme type selection (only shown for memes)
341
+ meme_type = gr.Dropdown(
342
+ choices=[t["name"] for t in MEME_TEMPLATES],
343
+ value="random",
344
+ label="Meme Template",
345
+ visible=True
346
+ )
347
+
348
+ # Custom text
349
+ custom_text = gr.Textbox(
350
+ label="Custom Text (optional)",
351
+ placeholder="Enter your own text or leave blank for random",
352
+ lines=3
353
+ )
354
+
355
+ # Text styling options
356
+ with gr.Accordion("Text Styling Options", open=False):
357
+ font_size = gr.Slider(
358
+ minimum=20,
359
+ maximum=100,
360
+ value=40,
361
+ step=5,
362
+ label="Font Size"
363
+ )
364
+
365
+ text_color = gr.ColorPicker(
366
+ value="#FFFFFF",
367
+ label="Text Color"
368
+ )
369
+
370
+ stroke_color = gr.ColorPicker(
371
+ value="#000000",
372
+ label="Stroke Color"
373
+ )
374
+
375
+ stroke_width = gr.Slider(
376
+ minimum=0,
377
+ maximum=10,
378
+ value=2,
379
+ step=1,
380
+ label="Stroke Width"
381
+ )
382
+
383
+ position = gr.Dropdown(
384
+ choices=["center", "top", "bottom", "left", "right"],
385
+ value="center",
386
+ label="Text Position"
387
+ )
388
+
389
+ # Process button
390
+ process_btn = gr.Button("Generate Image", variant="primary")
391
+
392
+ with gr.Column():
393
+ # Output
394
+ output_image = gr.Image(label="Result", type="pil")
395
+ status = gr.Textbox(label="Status", value="Ready to process your image!")
396
+
397
+ # Examples
398
+ gr.Markdown("## Examples")
399
+ examples = gr.Examples(
400
+ examples=[
401
+ ["https://i.imgur.com/5e3qY.jpg", "meme", "When you realize you left the oven on"],
402
+ ["https://i.imgur.com/5e3qY.jpg", "inspirational", None],
403
+ ["https://i.imgur.com/5e3qY.jpg", "funny", None],
404
+ ["https://i.imgur.com/5e3qY.jpg", "shitpost", None]
405
+ ],
406
+ inputs=[input_image, content_type, custom_text],
407
+ outputs=[output_image],
408
+ fn=process_image,
409
+ cache_examples=True,
410
+ label="Try these examples!"
411
+ )
412
+
413
+ # Update meme type visibility based on content type
414
+ def update_meme_visibility(content_type):
415
+ return gr.Dropdown(visible=content_type == "meme")
416
+
417
+ content_type.change(
418
+ fn=update_meme_visibility,
419
+ inputs=[content_type],
420
+ outputs=[meme_type]
421
+ )
422
+
423
+ # Process button click
424
+ process_btn.click(
425
+ fn=process_image,
426
+ inputs=[input_image, content_type, custom_text, font_size, text_color, stroke_color, stroke_width, position, meme_type],
427
+ outputs=[output_image, status],
428
+ api_visibility="public"
429
+ )
430
+
431
+ # Deep link button
432
+ gr.DeepLinkButton()
433
+
434
+ # Launch the app
435
+ demo.launch(
436
+ theme=custom_theme,
437
+ footer_links=[
438
+ {"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"},
439
+ {"label": "GitHub", "url": "https://github.com/akhaliq/anycoder"},
440
+ {"label": "Gradio Docs", "url": "https://gradio.app/docs"}
441
+ ],
442
+ css="""
443
+ .gradio-container {
444
+ max-width: 1200px !important;
445
+ }
446
+ .gr-button-primary {
447
+ background: linear-gradient(90deg, #3b82f6 0%, #8b5cf6 100%) !important;
448
+ border: none !important;
449
+ }
450
+ .gr-button-primary:hover {
451
+ background: linear-gradient(90deg, #2563eb 0%, #7c3aed 100%) !important;
452
+ }
453
+ """,
454
+ js="""
455
+ console.log("Neural Network Image Editor loaded!");
456
+ """
457
+ )
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ requests
2
+ Pillow
3
+ gradio>=6.0
4
+ numpy
5
+ pandas
6
+ matplotlib
7
+ scipy
8
+ fastapi
9
+ uvicorn
10
+ opencv-python