3morixd commited on
Commit
db30d92
·
verified ·
1 Parent(s): d9ebb82

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +113 -35
app.py CHANGED
@@ -1,3 +1,8 @@
 
 
 
 
 
1
  import os
2
  import io
3
  import random
@@ -17,25 +22,53 @@ ACCENT = "#1FE0E6"
17
  # Preset templates: name -> (base_image_prompt, default_top, default_bottom)
18
  TEMPLATES = {
19
  "This is Fine AI": (
20
- "A cartoon character sitting in a burning AI server room surrounded by flames, smiling and saying 'this is fine', meme style, comic illustration",
 
21
  "MY GPU IS ON FIRE",
22
  "THIS IS FINE",
23
  ),
24
- "Distracted Boyfriend AI": (
25
- "A meme photo of a boyfriend walking with his girlfriend but looking back at a passing robot labeled 'NEW AI MODEL', girlfriend labeled 'MY CURRENT MODEL', meme style",
 
26
  "MY CURRENT MODEL",
27
  "NEW HYPED AI MODEL",
28
  ),
29
- "Drake Hotline AI": (
30
- "Drake hotline bling meme format, Drake disapproving panel on top and Drake approving panel on bottom, left panel says 'Writing code myself', right panel says 'Asking ChatGPT to do it', meme template",
 
31
  "WRITING CODE MYSELF",
32
  "ASKING AI TO DO IT",
33
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  }
35
 
36
  # Random AI topics for the Random AI Topic button
37
  AI_TOPICS = [
38
- "AGI is coming next year",
39
  "My model hallucinated a whole paper",
40
  "Prompt engineering is real engineering",
41
  "I fine-tuned on my DMs",
@@ -55,6 +88,9 @@ AI_TOPICS = [
55
  "The tokenizer hates Arabic",
56
  "I spent $0 on training and won the benchmark",
57
  "Agents are just while loops with vibes",
 
 
 
58
  ]
59
 
60
  # Try to find a usable font
@@ -70,7 +106,6 @@ def load_font(size):
70
  for path in FONT_CANDIDATES:
71
  if os.path.exists(path):
72
  return ImageFont.truetype(path, size)
73
- # fallback default
74
  return ImageFont.load_default()
75
 
76
 
@@ -101,7 +136,6 @@ def generate_meme(top_caption, bottom_caption, template_name):
101
  d = ImageDraw.Draw(image)
102
  d.text((20, h // 2), f"Error: {e}", fill=ACCENT)
103
 
104
- # Overlay meme text (classic Impact style)
105
  image = overlay_meme_text(image, top.upper(), bot.upper())
106
  return image, f"✅ Meme generated! Top: '{top}' | Bottom: '{bot}'"
107
 
@@ -112,28 +146,47 @@ def overlay_meme_text(img, top_text, bottom_text):
112
  draw = ImageDraw.Draw(img)
113
  W, H = img.size
114
 
115
- # Font sizes proportional to image
116
  font_size = max(24, int(W / 12))
117
  font = load_font(font_size)
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  def draw_text_with_outline(text, y, anchor="ma"):
120
- # Outline (black)
121
- for dx in (-2, -1, 1, 2):
122
- for dy in (-2, -1, 1, 2):
123
  draw.text((W // 2 + dx, y + dy), text, fill="black", font=font, anchor=anchor)
124
- # Fill (white)
125
  draw.text((W // 2, y), text, fill="white", font=font, anchor=anchor)
126
 
127
- # Top text near top
128
- draw_text_with_outline(top_text, int(H * 0.08), anchor="ma")
129
- # Bottom text near bottom
130
- draw_text_with_outline(bottom_text, int(H * 0.92), anchor="ma")
 
 
 
 
 
 
 
 
131
 
132
  return img
133
 
134
 
135
  def load_template(template_name):
136
- """Load default captions from a template."""
137
  if template_name and template_name in TEMPLATES:
138
  _, def_top, def_bot = TEMPLATES[template_name]
139
  return def_top, def_bot
@@ -141,35 +194,59 @@ def load_template(template_name):
141
 
142
 
143
  # --- UI -----------------------------------------------------------------------
144
- CUSTOM_CSS = f"""
145
- .gradio-container {{background-color: {BG_COLOR} !important;}}
146
- h1, h2, h3 {{color: {ACCENT} !important;}}
 
 
 
 
 
147
  """
148
 
149
  with gr.Blocks(
150
- title="Dispatch AI Meme Lab",
151
  theme=gr.themes.Base(
152
  primary_hue="cyan",
 
153
  neutral_hue="slate",
154
- font=("Inter", "system-ui", "sans-serif"),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  ),
156
- css=CUSTOM_CSS,
157
  ) as demo:
158
- gr.Markdown(
159
- f"""
160
- <div style="text-align:center;">
161
- <h1>Dispatch AI Meme Lab</h1>
162
- <p style="color:{ACCENT};">Generate AI/tech memes with FLUX.1-schnell + PIL text overlay · Dispatch AI (FZE)</p>
163
- </div>
164
- """
165
- )
166
 
167
  with gr.Row():
168
  with gr.Column(scale=1):
169
  template_select = gr.Dropdown(
170
  list(TEMPLATES.keys()),
171
  label="Meme Template",
172
- value=None,
173
  info="Pick a template to auto-fill captions and base image",
174
  )
175
  load_template_btn = gr.Button("Load Template Captions", variant="secondary")
@@ -193,11 +270,12 @@ with gr.Blocks(
193
 
194
  gr.Markdown(
195
  """
196
- <div style="text-align:center; opacity:0.6; padding-top:20px;">
197
- <small>Dispatch AI (FZE) · UAE · Model: FLUX.1-schnell · Text overlay via Pillow</small>
198
  </div>
199
  """
200
  )
201
 
202
  if __name__ == "__main__":
 
203
  demo.launch()
 
1
+ """
2
+ Dispatch AI — Meme Generator
3
+ Gradio app for AI/tech memes. Top+bottom caption input, FLUX image gen, PIL text overlay.
4
+ """
5
+
6
  import os
7
  import io
8
  import random
 
22
  # Preset templates: name -> (base_image_prompt, default_top, default_bottom)
23
  TEMPLATES = {
24
  "This is Fine AI": (
25
+ "A cartoon character sitting in a burning AI server room surrounded by flames and melting GPUs, "
26
+ "smiling calmly and saying 'this is fine', meme style, comic illustration, white background panels",
27
  "MY GPU IS ON FIRE",
28
  "THIS IS FINE",
29
  ),
30
+ "Distracted Developer": (
31
+ "A meme photo of a developer walking with his laptop but looking back at a passing shiny new robot "
32
+ "labeled 'NEW AI MODEL', laptop labeled 'MY CURRENT MODEL', meme style photo",
33
  "MY CURRENT MODEL",
34
  "NEW HYPED AI MODEL",
35
  ),
36
+ "Drake Format": (
37
+ "Drake hotline bling meme format two-panel image, top panel Drake disapproving with hand up, "
38
+ "bottom panel Drake approving pointing finger, meme template",
39
  "WRITING CODE MYSELF",
40
  "ASKING AI TO DO IT",
41
  ),
42
+ "Expanding Brain": (
43
+ "Expanding brain meme format, four panels showing progressively glowing brighter brains, meme template",
44
+ "USING AI",
45
+ "FINE-TUNING AI ON MY DATA",
46
+ ),
47
+ "Galaxy Brain": (
48
+ "Galaxy brain meme format, three panels with progressively more cosmic brain, meme template",
49
+ "PROMPTING CHATGPT",
50
+ "TRAINING MY OWN MODEL",
51
+ ),
52
+ "Stonks": (
53
+ "Stonks meme format, crudely drawn man in suit standing in front of upward arrow chart, meme meme",
54
+ "CLOUD API COSTS",
55
+ "ON-DEVICE INFERENCE",
56
+ ),
57
+ "Two Buttons": (
58
+ "Two buttons meme format, sweating man deciding between two red buttons, meme template",
59
+ "PAY $0.06 PER 1K TOKENS",
60
+ "RUN ON MY PHONE",
61
+ ),
62
+ "Is This a Pigeon": (
63
+ "Is this a pigeon meme format, anime character looking at butterfly confused, meme template",
64
+ "IS THIS AN AGENT?",
65
+ "IT'S A WHILE LOOP",
66
+ ),
67
  }
68
 
69
  # Random AI topics for the Random AI Topic button
70
  AI_TOPICS = [
71
+ "AGI is coming next year (again)",
72
  "My model hallucinated a whole paper",
73
  "Prompt engineering is real engineering",
74
  "I fine-tuned on my DMs",
 
88
  "The tokenizer hates Arabic",
89
  "I spent $0 on training and won the benchmark",
90
  "Agents are just while loops with vibes",
91
+ "My gradient exploded and so did my career",
92
+ "I asked the model to debug itself",
93
+ "The embedding space is just vibes in high dimensions",
94
  ]
95
 
96
  # Try to find a usable font
 
106
  for path in FONT_CANDIDATES:
107
  if os.path.exists(path):
108
  return ImageFont.truetype(path, size)
 
109
  return ImageFont.load_default()
110
 
111
 
 
136
  d = ImageDraw.Draw(image)
137
  d.text((20, h // 2), f"Error: {e}", fill=ACCENT)
138
 
 
139
  image = overlay_meme_text(image, top.upper(), bot.upper())
140
  return image, f"✅ Meme generated! Top: '{top}' | Bottom: '{bot}'"
141
 
 
146
  draw = ImageDraw.Draw(img)
147
  W, H = img.size
148
 
 
149
  font_size = max(24, int(W / 12))
150
  font = load_font(font_size)
151
 
152
+ def wrap_text(text, max_chars):
153
+ words = text.split()
154
+ lines = []
155
+ current = ""
156
+ for word in words:
157
+ if len(current + " " + word) <= max_chars:
158
+ current = current + " " + word if current else word
159
+ else:
160
+ if current:
161
+ lines.append(current)
162
+ current = word
163
+ if current:
164
+ lines.append(current)
165
+ return lines
166
+
167
  def draw_text_with_outline(text, y, anchor="ma"):
168
+ for dx in (-3, -2, -1, 1, 2, 3):
169
+ for dy in (-3, -2, -1, 1, 2, 3):
 
170
  draw.text((W // 2 + dx, y + dy), text, fill="black", font=font, anchor=anchor)
 
171
  draw.text((W // 2, y), text, fill="white", font=font, anchor=anchor)
172
 
173
+ # Top text
174
+ max_chars = int(W / (font_size * 0.55))
175
+ top_lines = wrap_text(top_text, max_chars)
176
+ for i, line in enumerate(top_lines):
177
+ draw_text_with_outline(line, int(H * 0.06) + i * (font_size + 4), anchor="ma")
178
+
179
+ # Bottom text
180
+ bot_lines = wrap_text(bottom_text, max_chars)
181
+ total_h = len(bot_lines) * (font_size + 4)
182
+ for i, line in enumerate(bot_lines):
183
+ y = int(H * 0.94) - total_h + i * (font_size + 4) + font_size
184
+ draw_text_with_outline(line, y, anchor="ma")
185
 
186
  return img
187
 
188
 
189
  def load_template(template_name):
 
190
  if template_name and template_name in TEMPLATES:
191
  _, def_top, def_bot = TEMPLATES[template_name]
192
  return def_top, def_bot
 
194
 
195
 
196
  # --- UI -----------------------------------------------------------------------
197
+ CSS = """
198
+ #dispatch-header h1 {
199
+ color: #FFFFFF; font-size: 2.2rem; margin: 0;
200
+ background: linear-gradient(90deg, #1FE0E6 0%, #FFFFFF 60%);
201
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent;
202
+ }
203
+ #dispatch-header p { color: #1FE0E6; font-size: 1.05rem; margin: 6px 0 0 0; }
204
+ .dispatch-footer { text-align: center; color: #8A8F9C; font-size: 0.9rem; padding-top: 8px; }
205
  """
206
 
207
  with gr.Blocks(
208
+ title="Dispatch AI Meme Generator",
209
  theme=gr.themes.Base(
210
  primary_hue="cyan",
211
+ secondary_hue="cyan",
212
  neutral_hue="slate",
213
+ font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui"],
214
+ ).set(
215
+ body_background_fill="#0A0F1A",
216
+ body_background_fill_dark="#0A0F1A",
217
+ body_text_color="#FFFFFF",
218
+ body_text_color_dark="#FFFFFF",
219
+ block_background_fill="#0E1424",
220
+ block_background_fill_dark="#0E1424",
221
+ block_border_color="#1FE0E6",
222
+ block_border_width="1px",
223
+ block_label_text_color="#1FE0E6",
224
+ block_title_text_color="#1FE0E6",
225
+ button_primary_background_fill="#1FE0E6",
226
+ button_primary_background_fill_dark="#1FE0E6",
227
+ button_primary_text_color="#0A0F1A",
228
+ button_primary_border_color="#1FE0E6",
229
+ input_background_fill="#0E1424",
230
+ input_background_fill_dark="#0E1424",
231
+ input_border_color="#1FE0E6",
232
+ input_border_width="1px",
233
  ),
234
+ css=CSS,
235
  ) as demo:
236
+ with gr.Column(elem_id="dispatch-header"):
237
+ gr.Markdown(
238
+ """
239
+ # Dispatch AI Meme Generator
240
+ Generate AI/tech memes with FLUX.1-schnell + PIL text overlay · Dispatch AI (FZE) · UAE
241
+ """
242
+ )
 
243
 
244
  with gr.Row():
245
  with gr.Column(scale=1):
246
  template_select = gr.Dropdown(
247
  list(TEMPLATES.keys()),
248
  label="Meme Template",
249
+ value="This is Fine AI",
250
  info="Pick a template to auto-fill captions and base image",
251
  )
252
  load_template_btn = gr.Button("Load Template Captions", variant="secondary")
 
270
 
271
  gr.Markdown(
272
  """
273
+ <div class="dispatch-footer">
274
+ © 2026 Dispatch AI (FZE) · UAE · License 10818 · Model: FLUX.1-schnell · Text overlay via Pillow
275
  </div>
276
  """
277
  )
278
 
279
  if __name__ == "__main__":
280
+ demo.queue()
281
  demo.launch()