dina1 commited on
Commit
1338ec8
Β·
verified Β·
1 Parent(s): a95a9b9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +180 -61
app.py CHANGED
@@ -3,7 +3,6 @@ import gradio as gr
3
  from html2image import Html2Image
4
  import uuid
5
  import os
6
- import json
7
 
8
  # -----------------------
9
  # Configure Gemini API
@@ -16,91 +15,212 @@ model = genai.GenerativeModel("gemini-2.0-flash")
16
  # -----------------------
17
  hti = Html2Image(browser_executable="/usr/bin/chromium")
18
 
 
 
 
 
 
 
 
 
 
19
  # -----------------------
20
  # Base PowerApps Layout
21
  # -----------------------
22
  BASE_TEMPLATE = """
23
- <!DOCTYPE html>
24
- <html lang="en">
25
  <head>
26
- <meta charset="UTF-8">
27
- <title>Power Apps Mockup</title>
28
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
29
  <style>
30
- body { margin:0; font-family:Segoe UI, sans-serif; display:flex; height:100vh; background:#f9f9f9; }
31
- .sidebar { width:220px; background:#f4f4f4; padding:15px; border-right:1px solid #ddd; }
32
- .sidebar h3 { margin-top:20px; margin-bottom:10px; font-size:13px; color:#666; font-weight:bold; text-transform:uppercase; }
33
- .sidebar ul { list-style:none; padding:0; margin:0; }
34
- .sidebar li { margin:10px 0; color:#333; cursor:pointer; display:flex; align-items:center; gap:10px; padding:5px 8px; border-radius:6px; }
35
- .sidebar li:hover { background:#e6e6e6; }
36
- .main { flex:1; display:flex; flex-direction:column; }
37
- .content { flex:1; padding:25px; overflow:auto; background:white; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  </style>
39
  </head>
40
  <body>
41
- <div class="sidebar">
42
- <h3>Home</h3>
43
- <ul>
44
- <li><i class="fas fa-home"></i> Home</li>
45
- <li><i class="fas fa-clock"></i> Recent</li>
46
- <li><i class="fas fa-thumbtack"></i> Pinned</li>
47
- </ul>
48
-
49
- <h3>My Works</h3>
50
- <ul>
51
- {sidebar_items}
52
- </ul>
53
- </div>
54
-
55
  <div class="main">
56
- <div class="content">
57
- {user_content}
58
- </div>
59
  </div>
60
  </body>
61
  </html>
62
  """
63
 
64
  # -----------------------
65
- # Function: Generate Mockup
66
  # -----------------------
67
- def generate_mockup(user_prompt):
68
- system_prompt = (
69
- "You are a Power Apps mockup generator. "
70
- "Always respond with valid JSON only, no explanations. "
71
- "Format: { \"sidebar\": [list of sidebar items for 'My Works'], \"content\": \"<div>...</div>\" }. "
72
- "The sidebar always includes fixed defaults: Home, Recent, Pinned. "
73
- "You only generate the dynamic 'My Works' items depending on the user request. "
74
- "The 'content' field must contain the mockup HTML for the main screen. "
75
- )
76
 
77
- try:
78
- response = model.generate_content(system_prompt + "\nUser Request: " + user_prompt)
79
- raw_output = response.text.strip()
80
 
81
- # Parse JSON safely
82
- try:
83
- parsed = json.loads(raw_output)
84
- except json.JSONDecodeError:
85
- return f"Error: Model did not return valid JSON.\n\nOutput:\n{raw_output}"
86
 
87
- sidebar_items = ""
88
- for item in parsed.get("sidebar", []):
89
- sidebar_items += f"<li><i class='fas fa-circle'></i> {item}</li>"
90
 
91
- user_html = parsed.get("content", "<div>No content generated</div>")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
- # Final HTML
94
- full_html = BASE_TEMPLATE.replace("{sidebar_items}", sidebar_items)
95
- full_html = full_html.replace("{user_content}", user_html)
 
 
 
 
 
 
96
 
97
- # Save and screenshot
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  unique_id = str(uuid.uuid4())
99
  html_file, img_file = f"mockup_{unique_id}.html", f"mockup_{unique_id}.png"
100
  with open(html_file, "w", encoding="utf-8") as f:
101
  f.write(full_html)
102
- hti.screenshot(html_file=html_file, save_as=img_file)
103
 
 
104
  return img_file
105
 
106
  except Exception as e:
@@ -110,15 +230,14 @@ def generate_mockup(user_prompt):
110
  # Gradio UI
111
  # -----------------------
112
  with gr.Blocks() as demo:
113
- gr.Markdown("## ⚑ Power Apps Mockup Generator with Dynamic Sidebar")
114
  user_input = gr.Textbox(
115
  label="Describe your Power Apps mockup screen",
116
  lines=4,
117
- placeholder="Example: An employee leave management app with leave requests, approvals, and reports"
118
  )
119
  generate_btn = gr.Button("Generate Mockup")
120
  image_output = gr.Image(label="Mockup Preview")
121
-
122
  generate_btn.click(fn=generate_mockup, inputs=user_input, outputs=image_output)
123
 
124
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
3
  from html2image import Html2Image
4
  import uuid
5
  import os
 
6
 
7
  # -----------------------
8
  # Configure Gemini API
 
15
  # -----------------------
16
  hti = Html2Image(browser_executable="/usr/bin/chromium")
17
 
18
+ # -----------------------
19
+ # Default Chart Snippets (Fallbacks)
20
+ # -----------------------
21
+ DEFAULT_BAR_CHART = """ ... same as before ... """
22
+ DEFAULT_LINE_CHART = """ ... same as before ... """
23
+ DEFAULT_PIE_CHART = """ ... same as before ... """
24
+ DEFAULT_STACKED_BAR_CHART = """ ... same as before ... """
25
+ DEFAULT_DONUT_CHART = """ ... same as before ... """
26
+
27
  # -----------------------
28
  # Base PowerApps Layout
29
  # -----------------------
30
  BASE_TEMPLATE = """
31
+ <html>
 
32
  <head>
 
 
 
33
  <style>
34
+ body {
35
+ margin: 0;
36
+ font-family: 'Segoe UI', sans-serif;
37
+ background: #f5f5f5;
38
+ }
39
+ .sidebar {
40
+ width: 240px;
41
+ height: 100vh;
42
+ background: #2c2c2c;
43
+ color: #fff;
44
+ float: left;
45
+ display: flex;
46
+ flex-direction: column;
47
+ }
48
+ .sidebar-header {
49
+ display: flex;
50
+ align-items: center;
51
+ padding: 12px 16px;
52
+ font-size: 16px;
53
+ font-weight: bold;
54
+ background: #1e1e1e;
55
+ }
56
+ .sidebar-header span {
57
+ margin-right: 10px;
58
+ font-size: 20px;
59
+ }
60
+ .sidebar-item {
61
+ padding: 12px 20px;
62
+ cursor: pointer;
63
+ display: flex;
64
+ align-items: center;
65
+ }
66
+ .sidebar-item span {
67
+ margin-right: 10px;
68
+ }
69
+ .sidebar-item:hover {
70
+ background: #444;
71
+ }
72
+ .sidebar-section {
73
+ margin-top: 15px;
74
+ padding: 8px 20px;
75
+ font-size: 12px;
76
+ font-weight: bold;
77
+ text-transform: uppercase;
78
+ color: #aaa;
79
+ }
80
+ .topbar {
81
+ height: 50px;
82
+ background: #0078d4;
83
+ color: #fff;
84
+ display: flex;
85
+ align-items: center;
86
+ padding: 0 20px;
87
+ font-weight: bold;
88
+ }
89
+ .main {
90
+ margin-left: 240px;
91
+ padding: 20px;
92
+ }
93
+ .table-container table {
94
+ width: 100%;
95
+ border-collapse: collapse;
96
+ }
97
+ .table-container th, .table-container td {
98
+ border: 1px solid #ddd;
99
+ padding: 8px;
100
+ }
101
+ .card-grid {
102
+ display: grid;
103
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
104
+ gap: 15px;
105
+ }
106
+ .card {
107
+ background: #fff;
108
+ border-radius: 8px;
109
+ padding: 15px;
110
+ box-shadow: 0 1px 4px rgba(0,0,0,0.1);
111
+ }
112
+ .status.active { color: green; font-weight: bold; }
113
+ .status.inactive { color: red; font-weight: bold; }
114
+ .chart-container { margin: 20px 0; }
115
  </style>
116
  </head>
117
  <body>
118
+ {user_sidebar}
119
+ <div class="topbar">PowerApps Mockup</div>
 
 
 
 
 
 
 
 
 
 
 
 
120
  <div class="main">
121
+ {user_content}
 
 
122
  </div>
123
  </body>
124
  </html>
125
  """
126
 
127
  # -----------------------
128
+ # Function: Generate Sidebar
129
  # -----------------------
130
+ def generate_sidebar(user_prompt):
131
+ # Default fixed items with icons
132
+ fixed_items = [
133
+ ("🏠", "Home"),
134
+ ("⏱", "Recent"),
135
+ ("πŸ“Œ", "Pinned")
136
+ ]
 
 
137
 
138
+ sidebar_html = "<div class='sidebar'>"
139
+ sidebar_html += "<div class='sidebar-header'><span>☰</span> App Title</div>"
 
140
 
141
+ # Add fixed items
142
+ for icon, label in fixed_items:
143
+ sidebar_html += f"<div class='sidebar-item'><span>{icon}</span> {label}</div>"
 
 
144
 
145
+ # Separator for "My Work"
146
+ sidebar_html += "<div class='sidebar-section'>My Work</div>"
 
147
 
148
+ # Ask Gemini for dynamic items
149
+ system_prompt = (
150
+ "You are a Microsoft PowerApps UI assistant. "
151
+ "From the user requirements, extract 3-6 sidebar items for 'My Work'. "
152
+ "Output only a comma-separated list of names."
153
+ )
154
+ try:
155
+ response = model.generate_content(system_prompt + "\n" + user_prompt)
156
+ dynamic_items = response.text.strip().split(",")
157
+ dynamic_items = [item.strip() for item in dynamic_items if item.strip()]
158
+ except:
159
+ dynamic_items = ["Dashboard", "Reports"]
160
+
161
+ # Add icons dynamically (basic mapping, fallback βœ…)
162
+ icon_map = {
163
+ "dashboard": "πŸ“Š",
164
+ "reports": "πŸ“‘",
165
+ "activities": "βœ…",
166
+ "approvals": "βœ”οΈ",
167
+ "sales": "πŸ’°",
168
+ "leads": "πŸ‘₯",
169
+ "analytics": "πŸ“ˆ",
170
+ "requests": "πŸ“©"
171
+ }
172
+
173
+ for item in dynamic_items:
174
+ icon = icon_map.get(item.lower(), "πŸ“") # default folder icon
175
+ sidebar_html += f"<div class='sidebar-item'><span>{icon}</span> {item}</div>"
176
+
177
+ sidebar_html += "</div>"
178
+ return sidebar_html
179
 
180
+ # -----------------------
181
+ # Function: Generate Mockup Image
182
+ # -----------------------
183
+ def generate_mockup(user_prompt):
184
+ system_prompt = (
185
+ "You are a Power Apps mockup generator. "
186
+ "Generate ONLY the inner HTML for the main screen content. "
187
+ "Do NOT include <html>, <head>, or <body>. "
188
+ )
189
 
190
+ try:
191
+ response = model.generate_content(system_prompt + "\n" + user_prompt)
192
+ user_html = response.text.strip()
193
+
194
+ # Clean Gemini formatting
195
+ if user_html.startswith("```"):
196
+ user_html = user_html.split("```")[1]
197
+ user_html = user_html.replace("html", "").strip()
198
+
199
+ # Fallback chart injection
200
+ if "bar chart" in user_prompt.lower() and "<div class=\"bar-chart\"" not in user_html:
201
+ user_html += DEFAULT_BAR_CHART
202
+ if "line chart" in user_prompt.lower() and "<div class=\"line-chart\"" not in user_html:
203
+ user_html += DEFAULT_LINE_CHART
204
+ if "pie chart" in user_prompt.lower() and "<div class=\"pie-chart\"" not in user_html:
205
+ user_html += DEFAULT_PIE_CHART
206
+ if "stacked bar" in user_prompt.lower() and "<div class=\"stacked-bar-chart\"" not in user_html:
207
+ user_html += DEFAULT_STACKED_BAR_CHART
208
+ if "donut" in user_prompt.lower() and "<div class=\"donut-chart\"" not in user_html:
209
+ user_html += DEFAULT_DONUT_CHART
210
+
211
+ # Generate sidebar dynamically
212
+ sidebar_html = generate_sidebar(user_prompt)
213
+
214
+ # Wrap inside base template
215
+ full_html = BASE_TEMPLATE.replace("{user_sidebar}", sidebar_html).replace("{user_content}", user_html)
216
+
217
+ # Save files
218
  unique_id = str(uuid.uuid4())
219
  html_file, img_file = f"mockup_{unique_id}.html", f"mockup_{unique_id}.png"
220
  with open(html_file, "w", encoding="utf-8") as f:
221
  f.write(full_html)
 
222
 
223
+ hti.screenshot(html_file=html_file, save_as=img_file)
224
  return img_file
225
 
226
  except Exception as e:
 
230
  # Gradio UI
231
  # -----------------------
232
  with gr.Blocks() as demo:
233
+ gr.Markdown("## ⚑ Power Apps Mockup Generator (Gemini + Gradio)")
234
  user_input = gr.Textbox(
235
  label="Describe your Power Apps mockup screen",
236
  lines=4,
237
+ placeholder="Example: A login form, OR a requests table, OR a dashboard with charts"
238
  )
239
  generate_btn = gr.Button("Generate Mockup")
240
  image_output = gr.Image(label="Mockup Preview")
 
241
  generate_btn.click(fn=generate_mockup, inputs=user_input, outputs=image_output)
242
 
243
  demo.launch(server_name="0.0.0.0", server_port=7860)