dina1 commited on
Commit
4736882
·
verified ·
1 Parent(s): 4b70aa6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -125
app.py CHANGED
@@ -1,6 +1,6 @@
1
  # =========================================================
2
  # Intelligent PowerApps Mockup Generator
3
- # From Business Requirement PDF → PowerApps-Style Mockup Image
4
  # =========================================================
5
 
6
  import google.generativeai as genai
@@ -10,7 +10,6 @@ import pdfplumber
10
  import uuid
11
  import os
12
  import re
13
- import json
14
  import time
15
 
16
  # -----------------------
@@ -87,37 +86,6 @@ body {
87
  font-weight: bold;
88
  }
89
  .main { margin-left: 240px; padding: 20px; }
90
- .card-grid {
91
- display: grid;
92
- grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
93
- gap: 15px;
94
- }
95
- .card {
96
- background: #fff;
97
- border-radius: 8px;
98
- padding: 15px;
99
- box-shadow: 0 1px 4px rgba(0,0,0,0.1);
100
- }
101
- button.primary-btn {
102
- background: #0078d4;
103
- color: #fff;
104
- padding: 10px 18px;
105
- border: none;
106
- border-radius: 4px;
107
- font-weight: bold;
108
- cursor: pointer;
109
- }
110
- button.primary-btn:hover { background: #005ea0; }
111
- .chart-container {
112
- height: 150px;
113
- background: linear-gradient(to right, #e1eaff, #cce0ff);
114
- border-radius: 6px;
115
- display: flex;
116
- align-items: center;
117
- justify-content: center;
118
- color: #0078d4;
119
- font-weight: bold;
120
- }
121
  </style>
122
  </head>
123
  <body>
@@ -141,60 +109,19 @@ SVG_FLUENT = {
141
  # -----------------------
142
  # Sidebar Generator
143
  # -----------------------
144
- def generate_sidebar(ui_description, app_title):
145
  sidebar_html = "<div class='sidebar'>"
146
  sidebar_html += f"<div class='sidebar-header'>{SVG_FLUENT['hamburger']} {app_title}</div>"
147
-
148
  defaults = [("home", "Home"), ("recent", "Recent"), ("pinned", "Pinned")]
149
  for key, label in defaults:
150
  sidebar_html += f"<div class='sidebar-item'>{SVG_FLUENT[key]}<span>{label}</span></div>"
151
-
152
  sidebar_html += "<div class='sidebar-section'>My Work</div>"
153
-
154
- sidebar_prompt = (
155
- "You are a PowerApps designer. Based on this app description, generate 3–6 realistic items "
156
- "for the 'My Work' section. Each should include label, icon (Fluent-style SVG, color #c5c5c5), "
157
- "and one active: true. Return JSON only."
158
- )
159
- try:
160
- response = model.generate_content(sidebar_prompt + "\n\n" + ui_description)
161
- text = re.sub(r"```(?:json)?|```", "", response.text.strip())
162
- items = json.loads(text)
163
- except:
164
- items = [{"label": "Dashboard", "icon": "<svg viewBox='0 0 24 24'><circle cx='12' cy='12' r='5' fill='#c5c5c5'/></svg>", "active": True}]
165
-
166
- for item in items:
167
- active_class = "active" if item.get("active") else ""
168
- sidebar_html += f"<div class='sidebar-item {active_class}'>{item['icon']}<span>{item['label']}</span></div>"
169
  sidebar_html += "</div>"
170
  return sidebar_html
171
 
172
  # -----------------------
173
- # Build HTML Components from JSON Requirements
174
- # -----------------------
175
- def build_ui_from_requirements(ui_json):
176
- html = ""
177
- for screen in ui_json:
178
- html += f"<h2>{screen['screen_name']}</h2><p>{screen['purpose']}</p><div class='card-grid'>"
179
- for comp in screen['main_UI_elements']:
180
- c = comp.lower()
181
- if "form" in c:
182
- html += "<div class='card'><h3>Form</h3><input placeholder='Enter value' /><br><br><button class='primary-btn'>Submit</button></div>"
183
- elif "table" in c:
184
- html += "<div class='card'><h3>Data Table</h3><table><tr><th>Name</th><th>Status</th></tr><tr><td>Example</td><td>Active</td></tr></table></div>"
185
- elif "chart" in c:
186
- html += "<div class='card'><h3>Chart</h3><div class='chart-container'>📊 Chart Preview</div></div>"
187
- elif "button" in c:
188
- html += "<button class='primary-btn'>Action</button>"
189
- elif "dropdown" in c:
190
- html += "<div class='card'><h3>Dropdown</h3><select><option>Option A</option><option>Option B</option></select></div>"
191
- else:
192
- html += f"<div class='card'><h3>{comp}</h3><p>Placeholder Component</p></div>"
193
- html += "</div>"
194
- return html
195
-
196
- # -----------------------
197
- # Robust Analyze Business PDF
198
  # -----------------------
199
  def analyze_business_pdf(pdf_file):
200
  text = ""
@@ -207,69 +134,67 @@ def analyze_business_pdf(pdf_file):
207
  # Step 1: Infer App Title
208
  try:
209
  app_title = model.generate_content(
210
- "Read the following business requirements and infer a concise PowerApp title. Return only the title text."
211
  + "\n\n" + text
212
  ).text.strip()
213
  except Exception:
214
  app_title = "PowerApp Solution"
215
 
216
- # Step 2: Infer UI JSON
217
  try:
218
- ui_req_response = model.generate_content(
219
- "You are a PowerApps business analyst. Analyze the following business requirements "
220
- "and return detailed UI requirements in JSON format. "
221
- "Each item should include: screen_name, purpose, main_UI_elements (form, table, chart, button, dropdown), interactions."
222
- "Return only valid JSON."
 
223
  + "\n\n" + text
224
  )
225
- cleaned = re.sub(r"```(?:json)?|```", "", ui_req_response.text.strip())
226
-
227
  try:
228
- ui_json = json.loads(cleaned)
229
- except json.JSONDecodeError:
230
- ui_json = [{
231
- "screen_name": "Main Screen",
232
- "purpose": "Auto-generated layout",
233
- "main_UI_elements": ["Form", "Table", "Chart", "Button"],
234
- "interactions": ["Submit", "Search", "Filter"]
235
- }]
236
-
237
  except Exception as e:
238
- print("⚠️ Gemini parsing failed:", e)
239
- ui_json = [{
240
- "screen_name": "Fallback Screen",
241
- "purpose": "Gemini quota exceeded or invalid response",
242
- "main_UI_elements": ["Form", "Button"],
243
- "interactions": ["Submit"]
244
- }]
245
 
246
- return app_title, ui_json
247
 
248
  # -----------------------
249
- # Generate Mockup Image
250
  # -----------------------
251
- def generate_mockup(app_title, ui_json):
252
- sidebar_html = generate_sidebar(json.dumps(ui_json), app_title)
253
- user_html = build_ui_from_requirements(ui_json)
254
- full_html = BASE_TEMPLATE.replace("{user_sidebar}", sidebar_html)\
255
- .replace("{user_content}", user_html)\
256
- .replace("{app_title}", app_title)
257
- uid = str(uuid.uuid4())
258
- html_path, img_path = f"mockup_{uid}.html", f"mockup_{uid}.png"
259
- with open(html_path, "w", encoding="utf-8") as f:
260
- f.write(full_html)
261
- hti.screenshot(html_file=html_path, save_as=img_path)
262
- return img_path
 
 
 
 
 
 
 
 
263
 
264
  # -----------------------
265
- # Full Pipeline with Retry Logic (Option 1)
266
  # -----------------------
267
  def generate_from_pdf(pdf_file):
268
  for attempt in range(3):
269
  try:
270
- app_title, ui_json = analyze_business_pdf(pdf_file)
271
- mockup_img = generate_mockup(app_title, ui_json)
272
- return mockup_img
273
  except Exception as e:
274
  if "429" in str(e) or "quota" in str(e).lower():
275
  print("⏳ Waiting for Gemini quota reset... retrying in 10 seconds")
@@ -282,11 +207,11 @@ def generate_from_pdf(pdf_file):
282
  # Gradio UI
283
  # -----------------------
284
  with gr.Blocks() as demo:
285
- gr.Markdown("## 🧠 Intelligent PowerApps Mockup Generator (Business PDF → UI Image)")
286
- gr.Markdown("Upload a **Business Requirement PDF**. Gemini 2.5 Pro will infer app needs, extract screens & components, and render a PowerApps-style mockup image.")
287
  pdf_input = gr.File(label="📄 Upload Business Requirement PDF", file_types=[".pdf"])
288
- generate_btn = gr.Button("🚀 Generate Mockup")
289
- image_output = gr.Image(label="Generated PowerApps Mockup Preview")
290
- generate_btn.click(fn=generate_from_pdf, inputs=pdf_input, outputs=image_output)
291
 
292
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
1
  # =========================================================
2
  # Intelligent PowerApps Mockup Generator
3
+ # From Business Requirement PDF → Multi-Screen PowerApps-Style Mockup Images
4
  # =========================================================
5
 
6
  import google.generativeai as genai
 
10
  import uuid
11
  import os
12
  import re
 
13
  import time
14
 
15
  # -----------------------
 
86
  font-weight: bold;
87
  }
88
  .main { margin-left: 240px; padding: 20px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  </style>
90
  </head>
91
  <body>
 
109
  # -----------------------
110
  # Sidebar Generator
111
  # -----------------------
112
+ def generate_sidebar(app_title, active_label="Dashboard"):
113
  sidebar_html = "<div class='sidebar'>"
114
  sidebar_html += f"<div class='sidebar-header'>{SVG_FLUENT['hamburger']} {app_title}</div>"
 
115
  defaults = [("home", "Home"), ("recent", "Recent"), ("pinned", "Pinned")]
116
  for key, label in defaults:
117
  sidebar_html += f"<div class='sidebar-item'>{SVG_FLUENT[key]}<span>{label}</span></div>"
 
118
  sidebar_html += "<div class='sidebar-section'>My Work</div>"
119
+ sidebar_html += f"<div class='sidebar-item active'><svg viewBox='0 0 24 24'><circle cx='12' cy='12' r='5' fill='#c5c5c5'/></svg><span>{active_label}</span></div>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  sidebar_html += "</div>"
121
  return sidebar_html
122
 
123
  # -----------------------
124
+ # Analyze Business PDF Generate Multi-Screen HTML
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  # -----------------------
126
  def analyze_business_pdf(pdf_file):
127
  text = ""
 
134
  # Step 1: Infer App Title
135
  try:
136
  app_title = model.generate_content(
137
+ "From the following business requirements, infer a concise PowerApp title. Return only the title."
138
  + "\n\n" + text
139
  ).text.strip()
140
  except Exception:
141
  app_title = "PowerApp Solution"
142
 
143
+ # Step 2: Ask Gemini to identify screens and their HTML layouts
144
  try:
145
+ response = model.generate_content(
146
+ "You are a PowerApps UI designer. Analyze the following business requirements and infer multiple PowerApps screens if applicable. "
147
+ "Return structured JSON like this:\n"
148
+ "[{\"screen_name\": \"Dashboard\", \"html\": \"<div>...</div>\"}, {\"screen_name\": \"Reports\", \"html\": \"<div>...</div>\"}]\n\n"
149
+ "Each HTML should represent a PowerApps-style UI (forms, tables, charts, buttons, labels). "
150
+ "Do not include explanations. Return valid JSON only."
151
  + "\n\n" + text
152
  )
153
+ cleaned = re.sub(r"```(?:json)?|```", "", response.text.strip())
154
+ screens = []
155
  try:
156
+ screens = eval(cleaned) if cleaned.strip().startswith("[") else []
157
+ except Exception:
158
+ screens = [{"screen_name": "Dashboard", "html": "<h2>Fallback Layout</h2><p>Unable to parse screen data.</p>"}]
 
 
 
 
 
 
159
  except Exception as e:
160
+ print("⚠️ Gemini failed to create screens:", e)
161
+ screens = [{"screen_name": "Dashboard", "html": "<h2>Error</h2><p>Gemini failed to process this PDF.</p>"}]
 
 
 
 
 
162
 
163
+ return app_title, screens
164
 
165
  # -----------------------
166
+ # Generate HTML + Image per Screen
167
  # -----------------------
168
+ def generate_mockups(app_title, screens):
169
+ image_paths = []
170
+ for screen in screens:
171
+ label = screen.get("screen_name", "Screen")
172
+ html_content = screen.get("html", "<h2>Empty Screen</h2>")
173
+
174
+ sidebar_html = generate_sidebar(app_title, active_label=label)
175
+ full_html = BASE_TEMPLATE.replace("{user_sidebar}", sidebar_html)\
176
+ .replace("{user_content}", html_content)\
177
+ .replace("{app_title}", app_title)
178
+
179
+ uid = str(uuid.uuid4())[:8]
180
+ html_path = f"mockup_{label.replace(' ', '_')}_{uid}.html"
181
+ img_path = f"mockup_{label.replace(' ', '_')}_{uid}.png"
182
+ with open(html_path, "w", encoding="utf-8") as f:
183
+ f.write(full_html)
184
+ hti.screenshot(html_file=html_path, save_as=img_path)
185
+ image_paths.append(img_path)
186
+
187
+ return image_paths
188
 
189
  # -----------------------
190
+ # Full Pipeline with Retry Logic
191
  # -----------------------
192
  def generate_from_pdf(pdf_file):
193
  for attempt in range(3):
194
  try:
195
+ app_title, screens = analyze_business_pdf(pdf_file)
196
+ image_paths = generate_mockups(app_title, screens)
197
+ return image_paths
198
  except Exception as e:
199
  if "429" in str(e) or "quota" in str(e).lower():
200
  print("⏳ Waiting for Gemini quota reset... retrying in 10 seconds")
 
207
  # Gradio UI
208
  # -----------------------
209
  with gr.Blocks() as demo:
210
+ gr.Markdown("## 🧩 Intelligent PowerApps Mockup Generator (Multi-Screen Mode)")
211
+ gr.Markdown("Upload a **Business Requirement PDF**. Gemini 2.5 Pro will infer all screens, UI elements, and layouts — then render separate PowerApps-style mockup images for each screen.")
212
  pdf_input = gr.File(label="📄 Upload Business Requirement PDF", file_types=[".pdf"])
213
+ generate_btn = gr.Button("🚀 Generate Mockups")
214
+ gallery_output = gr.Gallery(label="Generated Screens", show_label=True, columns=2)
215
+ generate_btn.click(fn=generate_from_pdf, inputs=pdf_input, outputs=gallery_output)
216
 
217
  demo.launch(server_name="0.0.0.0", server_port=7860)