faizee07 commited on
Commit
afdcc12
Β·
verified Β·
1 Parent(s): 31cdfe0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -58
app.py CHANGED
@@ -4,12 +4,23 @@ import re
4
  from typing import Dict, List, Tuple
5
  import os
6
 
7
- from crewai import Agent, Task, Crew, Process
8
- from langchain_openai import ChatOpenAI
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  # --- Configuration ---
11
- # Set a default model. Using a fast and capable one is best.
12
- # Claude 3 Haiku is excellent for this and very cheap.
13
  DEFAULT_MODEL = "minimax/minimax-m2:free"
14
 
15
  # --- Agent Definitions ---
@@ -19,10 +30,10 @@ color_specialist = Agent(
19
  role='Expert Color Palette Designer',
20
  goal="""Select a visually appealing and contextually appropriate color palette
21
  based on the user's website description. The palette must include primary,
22
- secondary, accent, background, surface, and text colors.""",
23
  backstory="""You are a world-renowned graphic designer with a deep understanding of
24
  color theory and its psychological impact. You create palettes that are not
25
- only beautiful but also functional and accessible (WCAG compliant).""",
26
  verbose=True,
27
  allow_delegation=False
28
  )
@@ -30,11 +41,11 @@ color_specialist = Agent(
30
  # 2. Typography Specialist Agent
31
  typography_specialist = Agent(
32
  role='Master Typographer for Digital Interfaces',
33
- goal="""Define a complete and harmonious typography system, including font families
34
- and a responsive size scale (h1, h2, body, small).""",
35
- backstory="""With decades of experience from print to digital, you excel at choosing
36
- fonts that are readable, stylish, and appropriate for the brand's voice.
37
- You create clear typographic hierarchies that work perfectly on the web.""",
38
  verbose=True,
39
  allow_delegation=False
40
  )
@@ -43,11 +54,11 @@ typography_specialist = Agent(
43
  design_system_architect = Agent(
44
  role='Senior UI Design System Architect',
45
  goal="""Consolidate the color and typography schemes into a single, comprehensive,
46
- and developer-friendly JSON design system. Also add standard spacing and
47
- border-radius systems.""",
48
  backstory="""You are a meticulous senior UI designer who creates robust and scalable
49
- design systems for large tech companies. Your work ensures absolute consistency
50
- and serves as the single source of truth for the entire development team.""",
51
  verbose=True,
52
  allow_delegation=False
53
  )
@@ -60,36 +71,34 @@ web_developer = Agent(
60
  responsive, and modern.""",
61
  backstory="""You are a pixel-perfect frontend developer who translates design systems
62
  into clean, responsive, and maintainable HTML and CSS. You never deviate from
63
- the design specifications and your work is always of the highest quality.""",
64
  verbose=True,
65
  allow_delegation=False
66
  )
67
 
68
-
69
  # --- Task Definitions ---
70
 
71
  def create_design_tasks(prompt):
72
  task_colors = Task(
73
  description=f"""Analyze the user's prompt: '{prompt}'.
74
- Generate a JSON object representing the color palette.
75
- The JSON must contain keys: 'primary', 'secondary', 'accent',
76
- 'background', 'surface', 'text', 'textLight', 'border'.""",
77
- expected_output="A single, valid JSON object containing the color palette with 8 specified keys.",
78
  agent=color_specialist
79
  )
80
 
81
  task_typography = Task(
82
  description=f"""Analyze the user's prompt: '{prompt}'.
83
  Generate a JSON object for the typography system.
84
- It must include 'fontFamily' (web-safe), and sizes for 'h1', 'h2', 'body', and 'small'.""",
85
- expected_output="A single, valid JSON object containing the typography system with 5 specified keys.",
86
  agent=typography_specialist
87
  )
88
 
89
  task_architect = Task(
90
  description="""Take the color palette and typography system from the specialists.
91
  Combine them into a single, final JSON object. Also, add standard 'spacing'
92
- (sm, md, lg, xl) and 'borderRadius' (sm, md, lg) systems.
93
  Your final output must be ONLY this complete JSON object and nothing else.""",
94
  expected_output="A single, valid JSON object representing the complete design system.",
95
  agent=design_system_architect,
@@ -113,7 +122,10 @@ def create_developer_task(design_system_json, page_description):
113
 
114
  def create_ui_design(prompt: str, api_key: str, progress=gr.Progress(track_tqdm=True)):
115
  if not api_key:
116
- return ("Missing API Key",) * 5
 
 
 
117
 
118
  # Configure the LLM to use OpenRouter
119
  openrouter_llm = ChatOpenAI(
@@ -123,12 +135,10 @@ def create_ui_design(prompt: str, api_key: str, progress=gr.Progress(track_tqdm=
123
  )
124
 
125
  try:
126
- # --- Part 1: Run the Design Crew to create the Design System ---
127
  progress(0.1, desc="Briefing the design team...")
128
- design_agents = [color_specialist, typography_specialist, design_system_architect]
129
  design_tasks = create_design_tasks(prompt)
130
  design_crew = Crew(
131
- agents=design_agents,
132
  tasks=list(design_tasks),
133
  process=Process.sequential,
134
  verbose=2,
@@ -138,10 +148,8 @@ def create_ui_design(prompt: str, api_key: str, progress=gr.Progress(track_tqdm=
138
  progress(0.3, desc="Architecting the Design System...")
139
  design_system_json_string = design_crew.kickoff(inputs={'prompt': prompt})
140
 
141
- # Parse the final JSON from the architect
142
  design_system = json.loads(design_system_json_string)
143
 
144
- # --- Part 2: Run the Developer Agent for each page ---
145
  progress(0.6, desc="Briefing the Web Developer...")
146
  page_descriptions = re.findall(r'\d+\)([^0-9]+?)(?=\d+\)|$)', prompt) or [prompt]
147
  while len(page_descriptions) < 3:
@@ -164,39 +172,31 @@ def create_ui_design(prompt: str, api_key: str, progress=gr.Progress(track_tqdm=
164
  return generated_pages[0], generated_pages[1], generated_pages[2], design_system_json_string, visualizer_html
165
 
166
  except Exception as e:
167
- error_html = f"An error occurred with the CrewAI agents: {e}"
168
  print(error_html)
169
  return (error_html,) * 5
170
 
171
- # --- Visualizer (from previous answer, it's perfect) ---
172
  def visualize_design_system(design_system: Dict) -> str:
173
- # This function is the same as the previous answer. It works perfectly.
174
- # [Paste the entire visualize_design_system function from the previous answer here]
175
- if not design_system or not isinstance(design_system, dict):
176
- return "<div class='error-box'>No valid design system to display.</div>"
177
  colors = design_system.get('colors', {})
178
  typography = design_system.get('typography', {})
179
- # ... rest of the function ...
180
- html = """
181
- <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Design System</title><style>body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;background-color:#f9fafb;color:#374151;padding:1.5rem;line-height:1.6}.section{margin-bottom:2.5rem}h2{font-size:1.5rem;font-weight:600;color:#111827;border-bottom:1px solid #e5e7eb;padding-bottom:.5rem;margin-bottom:1.5rem}.swatch-container{display:flex;flex-wrap:wrap;gap:1.5rem}.swatch{width:120px;height:120px;border-radius:.75rem;display:flex;flex-direction:column;justify-content:flex-end;padding:.75rem;font-size:.875rem;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1)}.swatch .name{font-weight:600}.swatch .hex{opacity:.8}.type-container .sample{padding:1rem;background-color:#fff;border:1px solid #e5e7eb;border-radius:.5rem;margin-bottom:1rem}.type-container .label{font-size:.9rem;color:#6b7280;margin-bottom:.25rem}.component-container{display:flex;flex-direction:column;gap:2rem;background-color:#fff;padding:2rem;border-radius:.75rem;border:1px solid #e5e7eb}.error-box{padding:1rem;background:#fee2e2;color:#b91c1c;border-radius:.5rem}</style></head><body>
182
- """
183
  html += "<div class='section'><h2>Color Palette</h2><div class='swatch-container'>"
184
  for name, hex_val in colors.items():
185
- try: r,g,b=int(hex_val[1:3],16),int(hex_val[3:5],16),int(hex_val[5:7],16); text_color='#ffffff' if (0.299*r+0.587*g+0.114*b)/255<0.5 else '#000000'
186
- except: text_color='#000000'
187
- html+=f'<div class="swatch" style="background-color:{hex_val};color:{text_color};"><span class="name">{name.capitalize()}</span><span class="hex">{hex_val}</span></div>'
188
  html += "</div></div>"
189
  font_family = typography.get('fontFamily', 'sans-serif')
190
- html += f"<div class='section type-container'><h2>Typography</h2><p style='margin-bottom:1.5rem;'>Font Family: <code>{font_family}</code></p>"
191
- for name, sample_text in {'h1':'Heading 1','h2':'Heading 2','body':'This is a paragraph of body text.','small':'Small utility text'}.items():
192
- html+=f'<div class="sample"><div class="label">{name.capitalize()} ({typography.get(name,"1rem")})</div><div style="font-family:{font_family};font-size:{typography.get(name,"1rem")};">{sample_text}</div></div>'
193
- html += "</div>"
194
- html += "</body></html>"
195
  return html
196
 
197
  # --- Gradio Interface ---
198
  def create_interface():
199
- # This UI layout is the same as the previous answer.
200
  with gr.Blocks(title="CrewAI UI Designer", theme=gr.themes.Soft()) as demo:
201
  gr.Markdown("# πŸ€– CrewAI Powered UI Designer")
202
  with gr.Row():
@@ -205,20 +205,14 @@ def create_interface():
205
  prompt_input = gr.Textbox(label="Website Description", placeholder="e.g., A dark-mode, futuristic site for a synthwave musician: 1) landing page, 2) music, 3) tour dates", lines=4)
206
  generate_btn = gr.Button("πŸš€ Assemble the Crew!", variant="primary")
207
  with gr.Tabs():
208
- with gr.TabItem("Visualizer"):
209
- design_system_visualizer = gr.HTML(label="Design System Visualizer")
210
- with gr.TabItem("JSON"):
211
- design_system_output = gr.Code(label="Design System JSON", language="json", lines=15)
212
  with gr.Column(scale=2):
213
  with gr.Tabs():
214
  with gr.TabItem("πŸ“„ Page 1"): page1_output = gr.HTML()
215
  with gr.TabItem("πŸ“„ Page 2"): page2_output = gr.HTML()
216
  with gr.TabItem("πŸ“„ Page 3"): page3_output = gr.HTML()
217
- generate_btn.click(
218
- fn=create_ui_design,
219
- inputs=[prompt_input, api_key_input],
220
- outputs=[page1_output, page2_output, page3_output, design_system_output, design_system_visualizer]
221
- )
222
  return demo
223
 
224
  if __name__ == "__main__":
 
4
  from typing import Dict, List, Tuple
5
  import os
6
 
7
+ # Important: Make sure you have python-dotenv installed (`pip install python-dotenv`)
8
+ # and a .env file if you run locally. On HF Spaces, use secrets.
9
+ from dotenv import load_dotenv
10
+
11
+ # Try to import CrewAI libraries. If they fail, it means they are not installed.
12
+ try:
13
+ from crewai import Agent, Task, Crew, Process
14
+ from langchain_openai import ChatOpenAI
15
+ except ImportError:
16
+ raise ImportError(
17
+ "CrewAI or LangChain not installed. Please ensure your requirements.txt is correct and dependencies are installed."
18
+ )
19
+
20
+ load_dotenv()
21
 
22
  # --- Configuration ---
23
+ # You can change the model here. Claude 3 Haiku is fast, cheap, and very capable.
 
24
  DEFAULT_MODEL = "minimax/minimax-m2:free"
25
 
26
  # --- Agent Definitions ---
 
30
  role='Expert Color Palette Designer',
31
  goal="""Select a visually appealing and contextually appropriate color palette
32
  based on the user's website description. The palette must include primary,
33
+ secondary, background, surface, and text colors.""",
34
  backstory="""You are a world-renowned graphic designer with a deep understanding of
35
  color theory and its psychological impact. You create palettes that are not
36
+ only beautiful but also functional and accessible.""",
37
  verbose=True,
38
  allow_delegation=False
39
  )
 
41
  # 2. Typography Specialist Agent
42
  typography_specialist = Agent(
43
  role='Master Typographer for Digital Interfaces',
44
+ goal="""Define a complete and harmonious typography system, including a web-safe
45
+ font family and a responsive size scale (h1, h2, body, small).""",
46
+ backstory="""With decades of experience, you excel at choosing fonts that are readable,
47
+ stylish, and appropriate for a brand's voice. You create clear typographic
48
+ hierarchies that work perfectly on the web.""",
49
  verbose=True,
50
  allow_delegation=False
51
  )
 
54
  design_system_architect = Agent(
55
  role='Senior UI Design System Architect',
56
  goal="""Consolidate the color and typography schemes into a single, comprehensive,
57
+ and developer-friendly JSON design system. Also add standard 'spacing' and
58
+ 'borderRadius' systems.""",
59
  backstory="""You are a meticulous senior UI designer who creates robust and scalable
60
+ design systems. Your work ensures absolute consistency and serves as the single
61
+ source of truth for the entire development team.""",
62
  verbose=True,
63
  allow_delegation=False
64
  )
 
71
  responsive, and modern.""",
72
  backstory="""You are a pixel-perfect frontend developer who translates design systems
73
  into clean, responsive, and maintainable HTML and CSS. You never deviate from
74
+ the design specifications.""",
75
  verbose=True,
76
  allow_delegation=False
77
  )
78
 
 
79
  # --- Task Definitions ---
80
 
81
  def create_design_tasks(prompt):
82
  task_colors = Task(
83
  description=f"""Analyze the user's prompt: '{prompt}'.
84
+ Generate a JSON object for the color palette.
85
+ The JSON must contain keys: 'primary', 'secondary', 'background', 'surface', 'text'.""",
86
+ expected_output="A single, valid JSON object containing the color palette.",
 
87
  agent=color_specialist
88
  )
89
 
90
  task_typography = Task(
91
  description=f"""Analyze the user's prompt: '{prompt}'.
92
  Generate a JSON object for the typography system.
93
+ It must include 'fontFamily', and sizes for 'h1', 'h2', 'body', 'small'.""",
94
+ expected_output="A single, valid JSON object for the typography system.",
95
  agent=typography_specialist
96
  )
97
 
98
  task_architect = Task(
99
  description="""Take the color palette and typography system from the specialists.
100
  Combine them into a single, final JSON object. Also, add standard 'spacing'
101
+ (sm, md, lg) and 'borderRadius' (md, lg) systems.
102
  Your final output must be ONLY this complete JSON object and nothing else.""",
103
  expected_output="A single, valid JSON object representing the complete design system.",
104
  agent=design_system_architect,
 
122
 
123
  def create_ui_design(prompt: str, api_key: str, progress=gr.Progress(track_tqdm=True)):
124
  if not api_key:
125
+ error_msg = "API Key is missing. Please enter your OpenRouter API key."
126
+ return (error_msg,) * 5
127
+
128
+ os.environ["OPENROUTER_API_KEY"] = api_key
129
 
130
  # Configure the LLM to use OpenRouter
131
  openrouter_llm = ChatOpenAI(
 
135
  )
136
 
137
  try:
 
138
  progress(0.1, desc="Briefing the design team...")
 
139
  design_tasks = create_design_tasks(prompt)
140
  design_crew = Crew(
141
+ agents=[color_specialist, typography_specialist, design_system_architect],
142
  tasks=list(design_tasks),
143
  process=Process.sequential,
144
  verbose=2,
 
148
  progress(0.3, desc="Architecting the Design System...")
149
  design_system_json_string = design_crew.kickoff(inputs={'prompt': prompt})
150
 
 
151
  design_system = json.loads(design_system_json_string)
152
 
 
153
  progress(0.6, desc="Briefing the Web Developer...")
154
  page_descriptions = re.findall(r'\d+\)([^0-9]+?)(?=\d+\)|$)', prompt) or [prompt]
155
  while len(page_descriptions) < 3:
 
172
  return generated_pages[0], generated_pages[1], generated_pages[2], design_system_json_string, visualizer_html
173
 
174
  except Exception as e:
175
+ error_html = f"An error occurred with the CrewAI agents: {str(e)}. Check the logs for details."
176
  print(error_html)
177
  return (error_html,) * 5
178
 
179
+ # --- Visualizer Function ---
180
  def visualize_design_system(design_system: Dict) -> str:
181
+ if not design_system or not isinstance(design_system, dict): return "<div class='error-box'>No valid design system to display.</div>"
 
 
 
182
  colors = design_system.get('colors', {})
183
  typography = design_system.get('typography', {})
184
+ html = """<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Design System</title><style>body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background-color:#f9fafb;color:#374151;padding:1.5rem;}.section{margin-bottom:2rem;}h2{font-size:1.5rem;font-weight:600;border-bottom:1px solid #e5e7eb;padding-bottom:.5rem;margin-bottom:1rem;}.swatch-container{display:flex;flex-wrap:wrap;gap:1rem;}.swatch{width:100px;height:100px;border-radius:.5rem;display:flex;flex-direction:column;justify-content:flex-end;padding:.5rem;font-size:.8rem;box-shadow:0 2px 4px rgba(0,0,0,0.1);}.swatch .name{font-weight:600;}.type-container .sample{padding:1rem;background-color:#fff;border:1px solid #e5e7eb;border-radius:.5rem;margin-bottom:1rem;}</style></head><body>"""
 
 
 
185
  html += "<div class='section'><h2>Color Palette</h2><div class='swatch-container'>"
186
  for name, hex_val in colors.items():
187
+ try: r,g,b=int(hex_val[1:3],16),int(hex_val[3:5],16),int(hex_val[5:7],16); text_color='#fff' if (0.299*r+0.587*g+0.114*b)/255<0.5 else '#000'
188
+ except: text_color='#000'
189
+ html+=f'<div class="swatch" style="background-color:{hex_val};color:{text_color};"><span class="name">{name.capitalize()}</span><span>{hex_val}</span></div>'
190
  html += "</div></div>"
191
  font_family = typography.get('fontFamily', 'sans-serif')
192
+ html += f"<div class='section'><h2>Typography</h2><p>Font: <code>{font_family}</code></p>"
193
+ for name, sample_text in {'h1':'Heading 1','h2':'Heading 2','body':'This is a paragraph of body text.'}.items():
194
+ html+=f'<div class="sample"><div style="font-family:{font_family};font-size:{typography.get(name,"1rem")};">{sample_text}</div></div>'
195
+ html += "</div></body></html>"
 
196
  return html
197
 
198
  # --- Gradio Interface ---
199
  def create_interface():
 
200
  with gr.Blocks(title="CrewAI UI Designer", theme=gr.themes.Soft()) as demo:
201
  gr.Markdown("# πŸ€– CrewAI Powered UI Designer")
202
  with gr.Row():
 
205
  prompt_input = gr.Textbox(label="Website Description", placeholder="e.g., A dark-mode, futuristic site for a synthwave musician: 1) landing page, 2) music, 3) tour dates", lines=4)
206
  generate_btn = gr.Button("πŸš€ Assemble the Crew!", variant="primary")
207
  with gr.Tabs():
208
+ with gr.TabItem("Visualizer"): design_system_visualizer = gr.HTML()
209
+ with gr.TabItem("JSON"): design_system_output = gr.Code(language="json", lines=15)
 
 
210
  with gr.Column(scale=2):
211
  with gr.Tabs():
212
  with gr.TabItem("πŸ“„ Page 1"): page1_output = gr.HTML()
213
  with gr.TabItem("πŸ“„ Page 2"): page2_output = gr.HTML()
214
  with gr.TabItem("πŸ“„ Page 3"): page3_output = gr.HTML()
215
+ generate_btn.click(fn=create_ui_design, inputs=[prompt_input, api_key_input], outputs=[page1_output, page2_output, page3_output, design_system_output, design_system_visualizer])
 
 
 
 
216
  return demo
217
 
218
  if __name__ == "__main__":