dina1 commited on
Commit
a245a66
·
verified ·
1 Parent(s): b4aa8ea

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -49
app.py CHANGED
@@ -165,45 +165,39 @@ SVG_FLUENT = {
165
  # -----------------------
166
  # Dynamic Top Bar Generator
167
  # -----------------------
168
- def generate_topbar(screen_name, user_name="Mauricio Moutinho"):
169
- """Generate top bar based on screen type."""
170
  initials = "".join([x[0] for x in user_name.split()[:2]]).upper()
171
 
172
  ICONS = {
173
- "back": """<svg viewBox="0 0 24 24"><path d="M15.41 7.41 14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>""",
174
- "menu": """<svg viewBox="0 0 24 24"><path d="M3 6h18v2H3zM3 12h18v2H3zM3 18h18v2H3z"/></svg>""",
175
- "share": """<svg viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7a2.5 2.5 0 000-1.4l7.02-4.11A2.5 2.5 0 0018 7.91a2.5 2.5 0 10-2.5-2.5 2.5 2.5 0 00-.1.71L8.59 10.3a2.5 2.5 0 100 3.4l7.02 4.11a2.5 2.5 0 00-.1.71 2.5 2.5 0 102.5-2.44z"/></svg>""",
176
- "add": """<svg viewBox="0 0 24 24"><path d="M19 11h-6V5h-2v6H5v2h6v6h2v-6h6z"/></svg>""",
177
- "check": """<svg viewBox="0 0 24 24"><path d="M9 16.17 4.83 12l-1.42 1.41L9 19l12-12-1.41-1.41z"/></svg>""",
178
- "info": """<svg viewBox="0 0 24 24"><path d="M11 9h2V7h-2v2zm1-7C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6z"/></svg>""",
179
- "filter": """<svg viewBox="0 0 24 24"><path d="M10 18h4v-2h-4v2zm-7-7v2h18v-2H3zm3-5v2h12V6H6z"/></svg>"""
 
180
  }
181
 
182
- name_lower = screen_name.lower()
183
- left_icon, right_icons = ICONS["menu"], ICONS["share"] + ICONS["info"]
 
184
 
185
- if "dashboard" in name_lower:
186
- left_icon = ICONS["menu"]
187
- right_icons = ICONS["share"] + ICONS["info"]
188
- elif "repository" in name_lower or "library" in name_lower:
189
- left_icon = ICONS["menu"]
190
- right_icons = ICONS["filter"] + ICONS["add"]
191
- elif "task" in name_lower:
192
- left_icon = ICONS["menu"]
193
- right_icons = ICONS["filter"]
194
- elif "form" in name_lower or "edit" in name_lower or "add" in name_lower:
195
  left_icon = ICONS["back"]
196
- right_icons = ICONS["check"]
197
- else:
198
- left_icon = ICONS["menu"]
199
- right_icons = ICONS["share"]
200
 
201
  return f"""
202
  <div class="topbar">
203
- <div class="topbar-left">
204
- {left_icon}
205
- <span>{screen_name}</span>
206
- </div>
207
  <div class="topbar-right">
208
  {right_icons}
209
  <div class="topbar-user">
@@ -274,6 +268,25 @@ def analyze_business_pdf(pdf_file):
274
  if (t := page.extract_text()):
275
  text += t + "\n"
276
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  try:
278
  app_title = model.generate_content(
279
  "From the following business requirements, infer a concise PowerApp title. Return only the title.\n\n" + text
@@ -281,50 +294,49 @@ def analyze_business_pdf(pdf_file):
281
  except Exception:
282
  app_title = "PowerApp Solution"
283
 
284
- # Ask Gemini to infer logical app structure (grouped screens)
285
  try:
286
  prompt = (
287
- "You are a PowerApps UI designer. Analyze the following business requirements and detect the app's structure. "
288
- "Return JSON in this format:\n"
289
  "["
290
  " {\"group\": \"Metadata\", \"screens\": ["
291
- " {\"screen_name\": \"Metadata Dashboard\", \"html\": \"<div>...</div>\"},"
292
- " {\"screen_name\": \"Document Metadata\", \"html\": \"<div>...</div>\"}"
293
- " ]},"
294
- " {\"group\": \"Settings\", \"screens\": ["
295
- " {\"screen_name\": \"User Preferences\", \"html\": \"<div>...</div>\"}"
296
  " ]}"
297
- "]\n\n"
298
- "If the app does not have clear groupings, return a single group called 'My Work'."
299
- "\n\n" + text
 
 
300
  )
 
301
  response = model.generate_content(prompt)
302
  cleaned = re.sub(r"```(?:json)?|```", "", response.text.strip())
303
  groups = eval(cleaned) if cleaned.strip().startswith("[") else []
 
304
  except Exception as e:
305
  print("⚠️ Gemini failed:", e)
306
  groups = [{
307
  "group": "My Work",
308
- "screens": [{"screen_name": "Dashboard", "html": "<h2>Error</h2>"}]
309
  }]
310
 
311
- return app_title, groups
312
 
313
  # -----------------------
314
  # Generate Mockups
315
  # -----------------------
316
- def generate_mockups(app_title, groups):
317
  image_paths = []
318
  for group in groups:
319
  for screen in group.get("screens", []):
320
  label = screen.get("screen_name", "Screen")
321
  html_content = screen.get("html", "<h2>Empty Screen</h2>")
322
  sidebar_html = generate_sidebar(app_title, groups, active_label=label)
323
- topbar_html = generate_topbar(label)
 
324
  full_html = BASE_TEMPLATE.replace("{user_sidebar}", sidebar_html)\
325
  .replace("{user_content}", html_content)\
326
  .replace("{user_topbar}", topbar_html)
327
-
328
  uid = str(uuid.uuid4())[:8]
329
  html_path = f"mockup_{label.replace(' ', '_')}_{uid}.html"
330
  img_path = f"mockup_{label.replace(' ', '_')}_{uid}.png"
@@ -340,15 +352,15 @@ def generate_mockups(app_title, groups):
340
  def generate_from_pdf(pdf_file):
341
  for attempt in range(3):
342
  try:
343
- app_title, screens = analyze_business_pdf(pdf_file)
344
- return generate_mockups(app_title, screens)
345
  except Exception as e:
346
  if "429" in str(e) or "quota" in str(e).lower():
347
- print("⏳ Waiting for Gemini quota reset...")
348
  time.sleep(10)
349
  else:
350
  raise e
351
- raise Exception("❌ Failed after retries.")
352
 
353
  # -----------------------
354
  # Gradio UI
 
165
  # -----------------------
166
  # Dynamic Top Bar Generator
167
  # -----------------------
168
+ def generate_topbar(screen_name, role="default", user_name="John Joe"):
169
+ """Generate dynamic PowerApps-style top bar with role-based icons and user avatar."""
170
  initials = "".join([x[0] for x in user_name.split()[:2]]).upper()
171
 
172
  ICONS = {
173
+ "menu": """<svg viewBox="0 0 24 24"><path fill="#fff" d="M3 6h18v2H3zM3 12h18v2H3zM3 18h18v2H3z"/></svg>""",
174
+ "back": """<svg viewBox="0 0 24 24"><path fill="#fff" d="M15.41 7.41 14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>""",
175
+ "share": """<svg viewBox="0 0 24 24"><path fill="#fff" d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7a2.5 2.5 0 000-1.4l7.02-4.11A2.5 2.5 0 0018 7.91a2.5 2.5 0 10-2.5-2.5 2.5 2.5 0 00-.1.71L8.59 10.3a2.5 2.5 0 100 3.4l7.02 4.11a2.5 2.5 0 00-.1.71 2.5 2.5 0 102.5-2.44z"/></svg>""",
176
+ "add": """<svg viewBox="0 0 24 24"><path fill="#fff" d="M19 11h-6V5h-2v6H5v2h6v6h2v-6h6z"/></svg>""",
177
+ "check": """<svg viewBox="0 0 24 24"><path fill="#fff" d="M9 16.17 4.83 12l-1.42 1.41L9 19l12-12-1.41-1.41z"/></svg>""",
178
+ "info": """<svg viewBox="0 0 24 24"><path fill="#fff" d="M11 9h2V7h-2v2zm1-7C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6z"/></svg>""",
179
+ "filter": """<svg viewBox="0 0 24 24"><path fill="#fff" d="M10 18h4v-2h-4v2zm-7-7v2h18v-2H3zm3-5v2h12V6H6z"/></svg>""",
180
+ "user_icon": """<svg viewBox="0 0 24 24"><path fill="#fff" d="M12 12c2.67 0 8 1.34 8 4v2H4v-2c0-2.66 5.33-4 8-4zm0-2a4 4 0 110-8 4 4 0 010 8z"/></svg>"""
181
  }
182
 
183
+ # Default icons
184
+ left_icon = ICONS["menu"]
185
+ right_icons = ICONS["user_icon"]
186
 
187
+ if role == "dashboard":
188
+ right_icons = ICONS["share"] + ICONS["info"] + ICONS["user_icon"]
189
+ elif role == "list":
190
+ right_icons = ICONS["add"] + ICONS["filter"] + ICONS["user_icon"]
191
+ elif role == "form":
 
 
 
 
 
192
  left_icon = ICONS["back"]
193
+ right_icons = ICONS["check"] + ICONS["user_icon"]
194
+ elif role == "settings":
195
+ left_icon = ICONS["back"]
196
+ right_icons = ICONS["info"] + ICONS["user_icon"]
197
 
198
  return f"""
199
  <div class="topbar">
200
+ <div class="topbar-left">{left_icon}<span>{screen_name}</span></div>
 
 
 
201
  <div class="topbar-right">
202
  {right_icons}
203
  <div class="topbar-user">
 
268
  if (t := page.extract_text()):
269
  text += t + "\n"
270
 
271
+ # Try extracting user name from the PDF text
272
+ user_name = None
273
+ possible_name_patterns = [
274
+ r"Prepared by[:\-]\s*([A-Z][a-z]+(?:\s[A-Z][a-z]+)+)",
275
+ r"Author[:\-]\s*([A-Z][a-z]+(?:\s[A-Z][a-z]+)+)",
276
+ r"Created by[:\-]\s*([A-Z][a-z]+(?:\s[A-Z][a-z]+)+)",
277
+ r"Owner[:\-]\s*([A-Z][a-z]+(?:\s[A-Z][a-z]+)+)"
278
+ ]
279
+
280
+ for pattern in possible_name_patterns:
281
+ match = re.search(pattern, text)
282
+ if match:
283
+ user_name = match.group(1).strip()
284
+ break
285
+
286
+ if not user_name:
287
+ user_name = "John Joe" # Default fallback name
288
+
289
+ # Generate concise app title
290
  try:
291
  app_title = model.generate_content(
292
  "From the following business requirements, infer a concise PowerApp title. Return only the title.\n\n" + text
 
294
  except Exception:
295
  app_title = "PowerApp Solution"
296
 
297
+ # Ask Gemini for structural, grouped analysis
298
  try:
299
  prompt = (
300
+ "You are a senior PowerApps architect. Analyze the business requirements and return JSON structure like:\n"
 
301
  "["
302
  " {\"group\": \"Metadata\", \"screens\": ["
303
+ " {\"screen_name\": \"Metadata Dashboard\", \"role\": \"dashboard\", \"html\": \"<div>...</div>\"}"
 
 
 
 
304
  " ]}"
305
+ "]\n"
306
+ "- Identify user roles (dashboard, list, form, settings, etc.)\n"
307
+ "- Group screens into modules (Metadata, Templates, Settings...)\n"
308
+ "- Return valid JSON only.\n\n"
309
+ f"Document:\n{text}"
310
  )
311
+
312
  response = model.generate_content(prompt)
313
  cleaned = re.sub(r"```(?:json)?|```", "", response.text.strip())
314
  groups = eval(cleaned) if cleaned.strip().startswith("[") else []
315
+
316
  except Exception as e:
317
  print("⚠️ Gemini failed:", e)
318
  groups = [{
319
  "group": "My Work",
320
+ "screens": [{"screen_name": "Dashboard", "role": "dashboard", "html": "<h2>Error</h2>"}]
321
  }]
322
 
323
+ return app_title, groups, user_name
324
 
325
  # -----------------------
326
  # Generate Mockups
327
  # -----------------------
328
+ def generate_mockups(app_title, groups, user_name):
329
  image_paths = []
330
  for group in groups:
331
  for screen in group.get("screens", []):
332
  label = screen.get("screen_name", "Screen")
333
  html_content = screen.get("html", "<h2>Empty Screen</h2>")
334
  sidebar_html = generate_sidebar(app_title, groups, active_label=label)
335
+ topbar_html = generate_topbar(label, role=screen.get("role", "default"), user_name=user_name)
336
+
337
  full_html = BASE_TEMPLATE.replace("{user_sidebar}", sidebar_html)\
338
  .replace("{user_content}", html_content)\
339
  .replace("{user_topbar}", topbar_html)
 
340
  uid = str(uuid.uuid4())[:8]
341
  html_path = f"mockup_{label.replace(' ', '_')}_{uid}.html"
342
  img_path = f"mockup_{label.replace(' ', '_')}_{uid}.png"
 
352
  def generate_from_pdf(pdf_file):
353
  for attempt in range(3):
354
  try:
355
+ app_title, groups, user_name = analyze_business_pdf(pdf_file)
356
+ return generate_mockups(app_title, groups, user_name)
357
  except Exception as e:
358
  if "429" in str(e) or "quota" in str(e).lower():
359
+ print("⏳ Waiting for Gemini quota reset... retrying in 10 seconds")
360
  time.sleep(10)
361
  else:
362
  raise e
363
+ raise Exception("❌ Failed after 3 retries due to Gemini API quota limits.")
364
 
365
  # -----------------------
366
  # Gradio UI