ViberLu commited on
Commit
6853a89
·
verified ·
1 Parent(s): af37309

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +162 -65
app.py CHANGED
@@ -4,7 +4,7 @@ import base64
4
  import requests
5
  from io import BytesIO
6
  from datetime import datetime
7
- from typing import Optional, Dict, Tuple
8
 
9
  import gradio as gr
10
  from PIL import Image, ImageDraw, ImageFont
@@ -16,8 +16,7 @@ from huggingface_hub import InferenceClient
16
  HF_TOKEN = os.environ.get("HUGGINGFACE_TOKEN")
17
  hf = InferenceClient(token=HF_TOKEN)
18
 
19
- # IMPORTANT: only models that actually work via Inference API
20
- DEFAULT_MODELS = [
21
  "stabilityai/stable-diffusion-xl-base-1.0",
22
  "runwayml/stable-diffusion-v1-5",
23
  ]
@@ -44,61 +43,67 @@ def wrap_text(text, max_chars=60, max_lines=4):
44
  # ---------------------------
45
  # Core Generator
46
  # ---------------------------
47
- class GraphicsGenerator:
48
  def __init__(self, client: InferenceClient):
49
  self.client = client
50
 
51
- def analyze_repo(self, url: str) -> Tuple[Optional[dict], Optional[str]]:
52
- try:
53
- parts = url.replace("https://github.com/", "").split("/")
54
- owner, repo = parts[0], parts[1]
55
- r = requests.get(f"https://api.github.com/repos/{owner}/{repo}", timeout=10)
56
- if r.status_code != 200:
57
- return None, r.text
58
- j = r.json()
59
- return {
60
- "name": j["name"],
61
- "description": j.get("description", ""),
62
- "stars": j["stargazers_count"],
63
- "forks": j["forks_count"],
64
- "language": j.get("language", "Mixed"),
65
- }, None
66
- except Exception as e:
67
- return None, str(e)
68
-
69
- def build_prompt(self, data, style, colors):
70
- return (
71
- f"{style} GitHub repository banner. "
72
- f"Project name: {data['name']}. "
73
- f"{data['description']}. "
74
- f"Color scheme: {colors}. "
75
- f"Clean layout, no text artifacts, no watermark."
76
- )
77
 
78
- def generate_ai_background(
 
79
  self,
80
- prompt: str,
81
- model: str,
82
- width: int,
83
- height: int,
 
84
  init_image: Optional[Image.Image] = None,
85
- ) -> Image.Image:
86
  if init_image:
87
  return self.client.image_to_image(
88
  image=init_image,
89
  prompt=prompt,
 
90
  model=model,
91
  width=width,
92
  height=height,
93
  )
94
  return self.client.text_to_image(
95
  prompt=prompt,
 
96
  model=model,
97
  width=width,
98
  height=height,
99
  )
100
 
101
- def compose_final(self, bg: Image.Image, data: dict) -> Image.Image:
 
 
 
 
 
 
 
 
102
  draw = ImageDraw.Draw(bg)
103
  try:
104
  title = ImageFont.truetype(
@@ -113,47 +118,139 @@ class GraphicsGenerator:
113
  draw.text((48, 40), data["name"], font=title, fill="white")
114
 
115
  y = 110
116
- for line in wrap_text(data["description"]):
117
- draw.text((48, y), line, font=body, fill="white")
118
- y += 28
 
 
 
 
 
 
 
 
 
 
119
 
120
- footer = f"★ {data['stars']} ⑂ {data['forks']} {data['language']}"
121
- draw.text((48, bg.height - 60), footer, font=body, fill="white")
122
  return bg
123
 
124
- generator = GraphicsGenerator(hf)
 
125
 
126
  # ---------------------------
127
- # Gradio
128
  # ---------------------------
129
- def generate(repo_url, style, colors, model, width, height):
130
- data, err = generator.analyze_repo(repo_url)
131
- if err:
132
- return None, err
 
 
 
 
 
 
 
 
 
 
 
133
 
134
- prompt = generator.build_prompt(data, style, colors)
135
- bg = generator.generate_ai_background(prompt, model, width, height)
136
- final = generator.compose_final(bg, data)
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
  buf = BytesIO()
139
- final.save(buf, format="PNG")
140
  link = "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode()
141
- return final, link
142
 
143
- with gr.Blocks() as demo:
144
- gr.Markdown("## GitHub Graphics Generator")
 
 
 
 
 
 
 
 
145
 
146
- repo = gr.Textbox(label="Repo URL")
147
- style = gr.Dropdown(["Modern", "Minimal", "Professional"], value="Modern")
148
- colors = gr.Textbox(value="Blue gradient")
149
- model = gr.Dropdown(DEFAULT_MODELS, value=DEFAULT_MODELS[0])
150
- width = gr.Slider(512, 1600, 1200, step=64)
151
- height = gr.Slider(256, 1000, 628, step=64)
 
 
 
152
 
153
- btn = gr.Button("Generate")
154
- img = gr.Image()
155
- link = gr.Textbox(label="Download link")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
- btn.click(generate, [repo, style, colors, model, width, height], [img, link])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
  demo.launch()
 
4
  import requests
5
  from io import BytesIO
6
  from datetime import datetime
7
+ from typing import Optional, Dict
8
 
9
  import gradio as gr
10
  from PIL import Image, ImageDraw, ImageFont
 
16
  HF_TOKEN = os.environ.get("HUGGINGFACE_TOKEN")
17
  hf = InferenceClient(token=HF_TOKEN)
18
 
19
+ MODELS = [
 
20
  "stabilityai/stable-diffusion-xl-base-1.0",
21
  "runwayml/stable-diffusion-v1-5",
22
  ]
 
43
  # ---------------------------
44
  # Core Generator
45
  # ---------------------------
46
+ class Generator:
47
  def __init__(self, client: InferenceClient):
48
  self.client = client
49
 
50
+ # ---- GitHub ----
51
+ def fetch_repo(self, url: str):
52
+ parts = url.replace("https://github.com/", "").split("/")
53
+ owner, repo = parts[0], parts[1]
54
+ r = requests.get(f"https://api.github.com/repos/{owner}/{repo}", timeout=10)
55
+ j = r.json()
56
+ return {
57
+ "name": j["name"],
58
+ "description": j.get("description") or "",
59
+ "stars": j["stargazers_count"],
60
+ "forks": j["forks_count"],
61
+ "language": j.get("language") or "Mixed",
62
+ }
63
+
64
+ # ---- Prompt ----
65
+ def build_prompt(self, base, style, colors, custom):
66
+ p = f"{style} GitHub graphic. {base}. Color scheme: {colors}. Clean background."
67
+ if custom:
68
+ p += " " + custom
69
+ return p
 
 
 
 
 
 
70
 
71
+ # ---- AI ----
72
+ def generate_background(
73
  self,
74
+ prompt,
75
+ model,
76
+ width,
77
+ height,
78
+ negative=None,
79
  init_image: Optional[Image.Image] = None,
80
+ ):
81
  if init_image:
82
  return self.client.image_to_image(
83
  image=init_image,
84
  prompt=prompt,
85
+ negative_prompt=negative,
86
  model=model,
87
  width=width,
88
  height=height,
89
  )
90
  return self.client.text_to_image(
91
  prompt=prompt,
92
+ negative_prompt=negative,
93
  model=model,
94
  width=width,
95
  height=height,
96
  )
97
 
98
+ # ---- Layout ----
99
+ def compose(
100
+ self,
101
+ bg: Image.Image,
102
+ data: Dict,
103
+ include_desc: bool,
104
+ include_stats: bool,
105
+ include_lang: bool,
106
+ ):
107
  draw = ImageDraw.Draw(bg)
108
  try:
109
  title = ImageFont.truetype(
 
118
  draw.text((48, 40), data["name"], font=title, fill="white")
119
 
120
  y = 110
121
+ if include_desc and data.get("description"):
122
+ for line in wrap_text(data["description"]):
123
+ draw.text((48, y), line, font=body, fill="white")
124
+ y += 28
125
+
126
+ footer = []
127
+ if include_stats:
128
+ footer.append(f"★ {data['stars']} ⑂ {data['forks']}")
129
+ if include_lang:
130
+ footer.append(data["language"])
131
+
132
+ if footer:
133
+ draw.text((48, bg.height - 60), " ".join(footer), font=body, fill="white")
134
 
 
 
135
  return bg
136
 
137
+
138
+ gen = Generator(hf)
139
 
140
  # ---------------------------
141
+ # Handlers
142
  # ---------------------------
143
+ def handle_github(
144
+ repo_url, style, colors, custom_prompt, negative,
145
+ include_desc, include_stats, include_lang,
146
+ model, width, height
147
+ ):
148
+ data = gen.fetch_repo(repo_url)
149
+ base = f"{data['name']}. {data['description']}"
150
+ prompt = gen.build_prompt(base, style, colors, custom_prompt)
151
+ bg = gen.generate_background(prompt, model, width, height, negative)
152
+ img = gen.compose(bg, data, include_desc, include_stats, include_lang)
153
+
154
+ buf = BytesIO()
155
+ img.save(buf, format="PNG")
156
+ link = "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode()
157
+ return img, link
158
 
159
+ def handle_prompt(
160
+ text, name, style, colors, custom_prompt, negative,
161
+ include_desc, model, width, height
162
+ ):
163
+ data = {
164
+ "name": name or "Custom Project",
165
+ "description": text,
166
+ "stars": 0,
167
+ "forks": 0,
168
+ "language": "N/A",
169
+ }
170
+ base = text
171
+ prompt = gen.build_prompt(base, style, colors, custom_prompt)
172
+ bg = gen.generate_background(prompt, model, width, height, negative)
173
+ img = gen.compose(bg, data, include_desc, False, False)
174
 
175
  buf = BytesIO()
176
+ img.save(buf, format="PNG")
177
  link = "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode()
178
+ return img, link
179
 
180
+ def handle_screenshot(
181
+ image, style, colors, custom_prompt, negative,
182
+ model, width, height
183
+ ):
184
+ prompt = gen.build_prompt("Application illustration", style, colors, custom_prompt)
185
+ bg = gen.generate_background(prompt, model, width, height, negative, image)
186
+ buf = BytesIO()
187
+ bg.save(buf, format="PNG")
188
+ link = "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode()
189
+ return bg, link
190
 
191
+ # ---------------------------
192
+ # UI
193
+ # ---------------------------
194
+ with gr.Blocks(title="GitHub Graphics Generator") as demo:
195
+ gr.Markdown("## 🎨 GitHub Graphics Generator")
196
+
197
+ model = gr.Dropdown(MODELS, value=MODELS[0], label="Model")
198
+ width = gr.Slider(512, 1600, 1200, step=64, label="Width")
199
+ height = gr.Slider(256, 1000, 628, step=64, label="Height")
200
 
201
+ negative = gr.Textbox(label="Negative prompt", lines=2)
202
+ custom_prompt = gr.Textbox(label="Custom prompt override", lines=2)
203
+
204
+ with gr.Tabs():
205
+ with gr.Tab("GitHub Repo"):
206
+ repo = gr.Textbox(label="Repository URL")
207
+ style = gr.Dropdown(["Modern", "Minimal", "Professional"], value="Modern")
208
+ colors = gr.Textbox(value="Blue gradient")
209
+ inc_desc = gr.Checkbox(True, label="Include description")
210
+ inc_stats = gr.Checkbox(True, label="Include stats")
211
+ inc_lang = gr.Checkbox(True, label="Include language")
212
+ btn = gr.Button("Generate")
213
+ out = gr.Image()
214
+ link = gr.Textbox(label="Download link")
215
+
216
+ btn.click(
217
+ handle_github,
218
+ [repo, style, colors, custom_prompt, negative,
219
+ inc_desc, inc_stats, inc_lang,
220
+ model, width, height],
221
+ [out, link],
222
+ )
223
 
224
+ with gr.Tab("README / Prompt"):
225
+ text = gr.Textbox(lines=8, label="Description or README")
226
+ name = gr.Textbox(label="Project name")
227
+ style2 = gr.Dropdown(["Modern", "Minimal", "Professional"], value="Modern")
228
+ colors2 = gr.Textbox(value="Neutral")
229
+ inc_desc2 = gr.Checkbox(True, label="Include text")
230
+ btn2 = gr.Button("Generate")
231
+ out2 = gr.Image()
232
+ link2 = gr.Textbox(label="Download link")
233
+
234
+ btn2.click(
235
+ handle_prompt,
236
+ [text, name, style2, colors2, custom_prompt, negative,
237
+ inc_desc2, model, width, height],
238
+ [out2, link2],
239
+ )
240
+
241
+ with gr.Tab("Screenshot"):
242
+ img = gr.Image(type="pil", label="Upload image")
243
+ style3 = gr.Dropdown(["Modern", "Minimal", "Professional"], value="Modern")
244
+ colors3 = gr.Textbox(value="Match image")
245
+ btn3 = gr.Button("Generate")
246
+ out3 = gr.Image()
247
+ link3 = gr.Textbox(label="Download link")
248
+
249
+ btn3.click(
250
+ handle_screenshot,
251
+ [img, style3, colors3, custom_prompt, negative,
252
+ model, width, height],
253
+ [out3, link3],
254
+ )
255
 
256
  demo.launch()