openfree commited on
Commit
4c40d9b
Β·
verified Β·
1 Parent(s): 6367647

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +279 -233
app.py CHANGED
@@ -5,92 +5,122 @@ from PIL import Image
5
  import requests
6
  from io import BytesIO
7
  import time
8
- import tempfile
9
  import base64
10
  import json
11
 
12
  # Set up API keys from environment variables
13
  os.environ['REPLICATE_API_TOKEN'] = os.getenv('REPLICATE_API_TOKEN')
14
  FIREWORKS_API_KEY = os.getenv('FIREWORKS_API_KEY', '')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
  def enhance_prompt_with_team(user_input):
17
  """
18
- Enhanced prompt generation using team collaboration approach:
19
- Director -> Engineer (with web search) -> Designer
20
  """
21
  if not FIREWORKS_API_KEY:
22
- return user_input
 
23
 
24
  try:
 
 
 
25
  url = "https://api.fireworks.ai/inference/v1/chat/completions"
26
 
27
- # Team collaboration system prompt
28
- system_prompt = """You are a product design team consisting of three roles working in sequence:
29
 
30
- ## TEAM COLLABORATION PROCESS:
31
 
32
  ### 1. DIRECTOR (Creative Vision Leader)
33
- The Director analyzes the user's input and establishes:
34
- - Core product category and target market
35
- - Key functional requirements
36
- - Design philosophy and brand positioning
37
- - Initial design direction and constraints
38
- - Questions for the engineering team
39
 
40
- ### 2. ENGINEER (Technical Feasibility Expert)
41
- The Engineer responds to the Director's vision by:
42
- - Researching current technologies and materials
43
- - Identifying manufacturing possibilities
44
- - Suggesting innovative technical features
45
- - Evaluating feasibility of proposed concepts
46
- - Providing data on similar successful products
47
- - Recommending technical specifications
48
 
49
- ### 3. DESIGNER (Visual Design Specialist)
50
- The Designer synthesizes all inputs to create the final prompt:
51
- - Translating technical specs into visual language
52
- - Adding aesthetic details and finishing touches
53
- - Specifying materials, textures, and colors
54
- - Defining the rendering style
55
- - Creating the complete visual description
56
 
57
  ## OUTPUT FORMAT:
58
- Structure the team discussion as follows:
59
 
60
  **DIRECTOR'S VISION:**
61
- [Director's analysis and initial direction]
62
 
63
  **ENGINEER'S TECHNICAL ASSESSMENT:**
64
- [Research findings and technical recommendations]
65
-
66
- **DIRECTOR'S REFINEMENT:**
67
- [Approval/modification of engineering inputs]
68
 
69
  **DESIGNER'S FINAL PROMPT:**
70
- [Complete product design prompt with all visual details]
71
 
72
- Focus exclusively on PHYSICAL PRODUCT DESIGN - no services, apps, or abstract concepts.
73
- Examples: furniture, electronics, vehicles, appliances, tools, wearables, etc."""
74
 
75
- # Create the collaborative dialogue
76
- user_prompt = f"""Create a product design for: {user_input}
77
 
78
- Execute the full team collaboration process:
79
- 1. Director establishes the vision
80
- 2. Engineer researches and provides technical input (simulate web research findings)
81
- 3. Director refines based on engineering feedback
82
- 4. Designer creates the final detailed visual prompt
83
 
84
- Remember: Focus ONLY on physical product design."""
 
 
 
 
 
85
 
86
  payload = {
87
- "model": "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507",
88
- "max_tokens": 800,
89
  "top_p": 0.9,
90
- "top_k": 40,
91
- "presence_penalty": 0.3,
92
- "frequency_penalty": 0.2,
93
- "temperature": 0.8,
94
  "messages": [
95
  {
96
  "role": "system",
@@ -109,31 +139,50 @@ Remember: Focus ONLY on physical product design."""
109
  "Authorization": f"Bearer {FIREWORKS_API_KEY}"
110
  }
111
 
112
- response = requests.post(url, headers=headers, data=json.dumps(payload), timeout=15)
113
 
114
  if response.status_code == 200:
115
  result = response.json()
116
  enhanced = result.get('choices', [{}])[0].get('message', {}).get('content', '')
117
  if enhanced:
118
- # Extract only the designer's final prompt from the response
119
  if "DESIGNER'S FINAL PROMPT:" in enhanced:
120
  parts = enhanced.split("DESIGNER'S FINAL PROMPT:")
121
  if len(parts) > 1:
122
- return parts[1].strip()
123
- return enhanced
 
124
 
125
- return user_input
 
126
 
 
 
 
127
  except Exception as e:
128
  print(f"Team collaboration error: {str(e)}")
129
- return user_input
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
  def upload_image_to_hosting(image):
132
  """
133
- Upload image to multiple hosting services with fallback
134
  """
135
- # Method 1: Try imgbb.com
136
  try:
 
137
  buffered = BytesIO()
138
  image.save(buffered, format="PNG")
139
  buffered.seek(0)
@@ -144,7 +193,8 @@ def upload_image_to_hosting(image):
144
  data={
145
  'key': '6d207e02198a847aa98d0a2a901485a5',
146
  'image': img_base64,
147
- }
 
148
  )
149
 
150
  if response.status_code == 200:
@@ -154,21 +204,7 @@ def upload_image_to_hosting(image):
154
  except:
155
  pass
156
 
157
- # Method 2: Try 0x0.st
158
- try:
159
- buffered = BytesIO()
160
- image.save(buffered, format="PNG")
161
- buffered.seek(0)
162
-
163
- files = {'file': ('image.png', buffered, 'image/png')}
164
- response = requests.post("https://0x0.st", files=files)
165
-
166
- if response.status_code == 200:
167
- return response.text.strip()
168
- except:
169
- pass
170
-
171
- # Method 3: Fallback to base64
172
  buffered = BytesIO()
173
  image.save(buffered, format="PNG")
174
  buffered.seek(0)
@@ -177,31 +213,34 @@ def upload_image_to_hosting(image):
177
 
178
  def process_product_design(prompt, enhance_prompt_flag, image1, image2=None):
179
  """
180
- Process product design with team collaboration approach
181
  """
182
  if not os.getenv('REPLICATE_API_TOKEN'):
183
- return None, prompt, "Please set REPLICATE_API_TOKEN", ""
184
 
185
  try:
186
- # Store team discussion for display
187
  team_discussion = ""
188
-
189
- # Enhance prompt with team collaboration if requested
190
  final_prompt = prompt
 
 
191
  if enhance_prompt_flag:
192
- # This will contain the full team discussion
193
- full_response = enhance_prompt_with_team(prompt)
194
- final_prompt = full_response
 
 
 
195
 
196
- # Store the discussion for display
197
- team_discussion = f"🎬 **Director β†’ Engineer β†’ Designer Collaboration**\n\n{full_response}"
 
198
 
199
- # Prepare input for model
200
  model_input = {
201
  "prompt": final_prompt
202
  }
203
 
204
- # Add style reference images if provided
205
  if image1 or image2:
206
  image_urls = []
207
 
@@ -214,43 +253,46 @@ def process_product_design(prompt, enhance_prompt_flag, image1, image2=None):
214
  image_urls.append(url2)
215
 
216
  model_input["image_input"] = image_urls
217
- status_msg = "🏭 Product design generated with style references!"
218
  else:
219
- status_msg = "🏭 Product design generated from concept!"
220
 
221
- # Run model
222
- output = replicate.run(
223
- "google/nano-banana",
224
- input=model_input
225
- )
226
-
227
- if output is None:
228
- return None, final_prompt, "No output received", team_discussion
229
-
230
- # Get the generated image
231
  try:
232
- if hasattr(output, 'read'):
233
- img_data = output.read()
234
- img = Image.open(BytesIO(img_data))
235
- return img, final_prompt, status_msg, team_discussion
 
 
 
 
 
 
236
  except:
237
- pass
 
 
 
 
 
 
 
 
 
 
238
 
239
- try:
240
- if hasattr(output, 'url'):
241
- output_url = output.url()
242
- response = requests.get(output_url, timeout=30)
243
- if response.status_code == 200:
244
- img = Image.open(BytesIO(response.content))
245
- return img, final_prompt, status_msg, team_discussion
246
- except:
247
- pass
248
 
 
249
  output_url = None
250
  if isinstance(output, str):
251
  output_url = output
252
  elif isinstance(output, list) and len(output) > 0:
253
  output_url = output[0]
 
 
254
 
255
  if output_url:
256
  response = requests.get(output_url, timeout=30)
@@ -258,248 +300,252 @@ def process_product_design(prompt, enhance_prompt_flag, image1, image2=None):
258
  img = Image.open(BytesIO(response.content))
259
  return img, final_prompt, status_msg, team_discussion
260
 
261
- return None, final_prompt, "Could not process output", team_discussion
262
 
263
  except Exception as e:
264
  error_msg = str(e)
265
- if "image_input" in error_msg.lower():
266
- return None, prompt, "Note: Model may require at least one image.", ""
267
- return None, prompt, f"Error: {error_msg[:100]}", ""
268
 
269
- # Enhanced CSS for Product Design focus
270
  css = """
271
  .gradio-container {
272
- background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
273
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
274
  min-height: 100vh;
275
  }
276
  .header-container {
277
- background: linear-gradient(135deg, #434343 0%, #000000 100%);
278
- padding: 2.5rem;
279
- border-radius: 24px;
280
- margin-bottom: 2.5rem;
281
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
 
282
  }
283
  .logo-text {
284
- font-size: 3.5rem;
285
- font-weight: 900;
286
- color: white;
287
  text-align: center;
288
  margin: 0;
289
- letter-spacing: -2px;
290
- text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
291
  }
292
  .subtitle {
293
- color: #e0e0e0;
294
  text-align: center;
295
- font-size: 1.2rem;
296
  margin-top: 0.5rem;
297
- font-weight: 300;
 
298
  }
299
  .mode-indicator {
300
- background: rgba(255, 255, 255, 0.1);
301
- backdrop-filter: blur(10px);
302
- border-radius: 12px;
303
- padding: 0.8rem 1.5rem;
304
- margin-top: 1rem;
305
  text-align: center;
306
- font-weight: 600;
307
  color: #ffd700;
308
- border: 1px solid rgba(255, 215, 0, 0.3);
 
309
  }
310
  .main-content {
311
  background: rgba(255, 255, 255, 0.98);
312
- backdrop-filter: blur(20px);
313
- border-radius: 24px;
314
- padding: 2.5rem;
315
- box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
316
  }
317
  .gr-button-primary {
318
- background: linear-gradient(135deg, #434343 0%, #000000 100%) !important;
319
- border: 2px solid #ffd700 !important;
320
- color: white !important;
321
- font-weight: 700 !important;
322
- font-size: 1.1rem !important;
323
- padding: 1.2rem 2rem !important;
324
- border-radius: 14px !important;
325
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
326
  text-transform: uppercase;
327
- letter-spacing: 1px;
328
  width: 100%;
329
  margin-top: 1rem !important;
330
  }
331
  .gr-button-primary:hover {
332
- transform: translateY(-3px) !important;
333
- box-shadow: 0 15px 40px rgba(255, 215, 0, 0.3) !important;
334
  background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%) !important;
335
  color: #000 !important;
336
  }
337
- .gr-input, .gr-textarea {
338
- background: #ffffff !important;
339
- border: 2px solid #d0d0d0 !important;
340
- border-radius: 12px !important;
341
- color: #2d3436 !important;
342
- font-size: 1rem !important;
343
- padding: 0.8rem 1rem !important;
344
- }
345
- .gr-input:focus, .gr-textarea:focus {
346
- border-color: #434343 !important;
347
- box-shadow: 0 0 0 4px rgba(67, 67, 67, 0.1) !important;
348
  }
349
  .team-discussion {
350
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
351
- border-radius: 12px;
352
- padding: 1.5rem;
353
  margin-top: 1rem;
354
- border-left: 4px solid #434343;
355
- font-family: 'Monaco', 'Courier New', monospace;
356
- font-size: 0.9rem;
357
- max-height: 400px;
358
  overflow-y: auto;
359
- }
360
- .info-box {
361
- background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);
362
- border-radius: 12px;
363
- padding: 1rem;
364
- margin-bottom: 1rem;
365
- border-left: 4px solid #000;
366
- color: #000;
367
- font-weight: 500;
368
  }
369
  .enhanced-prompt-box {
370
  background: #f0f0f0;
371
- border-radius: 12px;
372
  padding: 1rem;
373
- margin-top: 1rem;
374
- border-left: 4px solid #ffd700;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
  }
376
  footer {
377
  display: none !important;
378
  }
379
  """
380
 
 
381
  with gr.Blocks(css=css, theme=gr.themes.Base()) as demo:
382
  with gr.Column(elem_classes="header-container"):
383
  gr.HTML("""
384
  <h1 class="logo-text">🏭 PRODUCT DESIGN STUDIO</h1>
385
- <p class="subtitle">AI-Powered Industrial & Product Design System</p>
386
  <div class="mode-indicator">
387
- πŸ‘₯ Team Collaboration: Director β†’ Engineer β†’ Designer
388
  </div>
389
  """)
390
 
391
  with gr.Column(elem_classes="main-content"):
392
- # Info box
393
  gr.HTML("""
394
  <div class="info-box">
395
  <strong>🎯 Professional Product Design Process:</strong><br>
396
- β€’ <b>Director:</b> Establishes design vision and requirements<br>
397
- β€’ <b>Engineer:</b> Researches technology and feasibility<br>
398
  β€’ <b>Designer:</b> Creates detailed visual specifications<br>
399
- β€’ Focus: Physical products only (electronics, furniture, vehicles, tools, etc.)
400
  </div>
401
  """)
402
 
403
  with gr.Row(equal_height=True):
404
- # Left Column - Inputs
405
  with gr.Column(scale=1):
406
  prompt = gr.Textbox(
407
- label="Product Concept",
408
- placeholder="Examples: 'ergonomic office chair', 'smart home speaker', 'electric bicycle', 'modular kitchen appliance'...",
409
- lines=3,
410
- value="professional mechanical keyboard",
411
  elem_classes="prompt-input"
412
  )
413
 
414
  enhance_prompt_checkbox = gr.Checkbox(
415
- label="πŸ‘₯ Enable Team Collaboration (Director + Engineer + Designer)",
416
  value=True,
417
- info="Activates multi-role design process with technical research"
418
  )
419
 
420
- with gr.Row(equal_height=True):
421
  image1 = gr.Image(
422
- label="Style/Material Reference 1",
423
  type="pil",
424
- height=200,
425
- elem_classes="image-container"
426
  )
427
  image2 = gr.Image(
428
- label="Style/Material Reference 2",
429
  type="pil",
430
- height=200,
431
- elem_classes="image-container"
432
  )
433
 
434
  generate_btn = gr.Button(
435
- "Generate Product Design 🏭",
436
  variant="primary",
437
  size="lg"
438
  )
439
 
440
- # Right Column - Output
441
  with gr.Column(scale=1):
442
  output_image = gr.Image(
443
- label="Product Design Visualization",
444
  type="pil",
445
- height=420,
446
  elem_classes="image-container"
447
  )
448
 
449
  enhanced_prompt_display = gr.Textbox(
450
- label="Final Design Specifications",
451
  interactive=False,
452
- lines=4,
453
- elem_classes="enhanced-prompt-box",
454
- visible=True,
455
- value="Design specifications will appear here..."
456
  )
457
 
458
  status = gr.Textbox(
459
  label="Status",
460
  interactive=False,
461
- lines=1,
462
  elem_classes="status-text",
463
- value="Ready to design products..."
464
  )
465
 
466
- # Team Discussion Display
467
  with gr.Row():
468
  team_discussion_display = gr.Markdown(
469
- label="Team Collaboration Process",
470
  value="",
471
  elem_classes="team-discussion"
472
  )
473
 
474
- # Event handler
475
  generate_btn.click(
476
  fn=process_product_design,
477
  inputs=[prompt, enhance_prompt_checkbox, image1, image2],
478
  outputs=[output_image, enhanced_prompt_display, status, team_discussion_display]
479
  )
480
 
481
- # Product Design Examples
482
  gr.Examples(
483
  examples=[
484
- ["ergonomic gaming mouse", True, None, None],
 
 
 
485
  ["portable coffee maker", True, None, None],
486
- ["modular storage system", True, None, None],
487
- ["smart bicycle helmet", True, None, None],
488
- ["industrial power tool", True, None, None],
489
- ["luxury watch design", True, None, None],
490
- ["compact home gym equipment", True, None, None],
491
- ["sustainable packaging solution", True, None, None],
492
- ["professional camera lens", True, None, None],
493
- ["electric vehicle charging station", True, None, None],
494
  ],
495
  inputs=[prompt, enhance_prompt_checkbox, image1, image2],
496
- label="Product Design Examples (Team will collaborate on these concepts)"
497
  )
498
 
499
- # Launch
500
  if __name__ == "__main__":
 
 
 
 
 
 
 
 
501
  demo.launch(
502
- share=True,
503
  server_name="0.0.0.0",
504
- server_port=7860
 
505
  )
 
5
  import requests
6
  from io import BytesIO
7
  import time
 
8
  import base64
9
  import json
10
 
11
  # Set up API keys from environment variables
12
  os.environ['REPLICATE_API_TOKEN'] = os.getenv('REPLICATE_API_TOKEN')
13
  FIREWORKS_API_KEY = os.getenv('FIREWORKS_API_KEY', '')
14
+ BRAVE_API_KEY = os.getenv('BRAVE_API_KEY', '') # Add Brave API key
15
+
16
+ def search_design_trends(product_type):
17
+ """
18
+ Use Brave Search API to find current design trends and technologies
19
+ """
20
+ if not BRAVE_API_KEY:
21
+ return "No search results available (API key not set)"
22
+
23
+ try:
24
+ # Construct search query for product design
25
+ query = f"{product_type} design trends 2024 2025 materials technology innovation"
26
+
27
+ url = "https://api.search.brave.com/res/v1/web/search"
28
+ headers = {
29
+ "Accept": "application/json",
30
+ "X-Subscription-Token": BRAVE_API_KEY
31
+ }
32
+ params = {
33
+ "q": query,
34
+ "count": 5
35
+ }
36
+
37
+ response = requests.get(url, headers=headers, params=params, timeout=10)
38
+
39
+ if response.status_code == 200:
40
+ data = response.json()
41
+ results = []
42
+
43
+ if 'web' in data and 'results' in data['web']:
44
+ for item in data['web']['results'][:3]:
45
+ results.append(f"- {item.get('title', '')}: {item.get('description', '')[:150]}")
46
+
47
+ if results:
48
+ return "\n".join(results)
49
+ else:
50
+ return "Limited search results available"
51
+ else:
52
+ return "Search unavailable at the moment"
53
+
54
+ except Exception as e:
55
+ print(f"Brave search error: {str(e)}")
56
+ return "Search results unavailable"
57
 
58
  def enhance_prompt_with_team(user_input):
59
  """
60
+ Enhanced prompt generation using team collaboration with real web search
 
61
  """
62
  if not FIREWORKS_API_KEY:
63
+ # Fallback to basic enhancement
64
+ return create_basic_design_prompt(user_input)
65
 
66
  try:
67
+ # First, get real search results for the engineer
68
+ search_results = search_design_trends(user_input)
69
+
70
  url = "https://api.fireworks.ai/inference/v1/chat/completions"
71
 
72
+ # Enhanced system prompt with search integration
73
+ system_prompt = """You are a product design team with three specialized roles:
74
 
75
+ ## TEAM ROLES:
76
 
77
  ### 1. DIRECTOR (Creative Vision Leader)
78
+ - Analyzes user requirements and market positioning
79
+ - Sets design philosophy and constraints
80
+ - Makes final decisions on features
 
 
 
81
 
82
+ ### 2. ENGINEER (Technical Expert with Research Data)
83
+ - Uses provided search results to inform decisions
84
+ - Evaluates manufacturing feasibility
85
+ - Recommends materials and technologies
86
+ - Suggests innovative features based on trends
 
 
 
87
 
88
+ ### 3. DESIGNER (Visual Specialist)
89
+ - Creates detailed visual specifications
90
+ - Specifies exact materials, finishes, colors
91
+ - Defines rendering style and atmosphere
 
 
 
92
 
93
  ## OUTPUT FORMAT:
 
94
 
95
  **DIRECTOR'S VISION:**
96
+ [Brief vision statement - 2-3 sentences]
97
 
98
  **ENGINEER'S TECHNICAL ASSESSMENT:**
99
+ [Based on search data, provide 3-4 technical recommendations]
 
 
 
100
 
101
  **DESIGNER'S FINAL PROMPT:**
102
+ [Detailed visual description for image generation - focus on visual elements]
103
 
104
+ Keep responses concise but specific. Focus on PHYSICAL PRODUCTS only."""
 
105
 
106
+ # Create collaborative prompt with search results
107
+ user_prompt = f"""Product concept: {user_input}
108
 
109
+ ENGINEER'S RESEARCH DATA:
110
+ {search_results}
 
 
 
111
 
112
+ Based on this input and research, execute the team collaboration:
113
+ 1. Director establishes vision (brief)
114
+ 2. Engineer uses the research data above to recommend features
115
+ 3. Designer creates a detailed visual prompt
116
+
117
+ Focus on creating a manufacturable, innovative product design."""
118
 
119
  payload = {
120
+ "model": "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507", # Original model maintained
121
+ "max_tokens": 500,
122
  "top_p": 0.9,
123
+ "temperature": 0.7,
 
 
 
124
  "messages": [
125
  {
126
  "role": "system",
 
139
  "Authorization": f"Bearer {FIREWORKS_API_KEY}"
140
  }
141
 
142
+ response = requests.post(url, headers=headers, data=json.dumps(payload), timeout=30)
143
 
144
  if response.status_code == 200:
145
  result = response.json()
146
  enhanced = result.get('choices', [{}])[0].get('message', {}).get('content', '')
147
  if enhanced:
148
+ # Extract designer's final prompt
149
  if "DESIGNER'S FINAL PROMPT:" in enhanced:
150
  parts = enhanced.split("DESIGNER'S FINAL PROMPT:")
151
  if len(parts) > 1:
152
+ # Return both the final prompt and the full discussion
153
+ return parts[1].strip(), enhanced
154
+ return enhanced, enhanced
155
 
156
+ # Fallback if API fails
157
+ return create_basic_design_prompt(user_input), "Team collaboration unavailable - using basic prompt"
158
 
159
+ except requests.exceptions.Timeout:
160
+ print("Fireworks API timeout - using fallback")
161
+ return create_basic_design_prompt(user_input), "API timeout - using fallback prompt generation"
162
  except Exception as e:
163
  print(f"Team collaboration error: {str(e)}")
164
+ return create_basic_design_prompt(user_input), f"Error: {str(e)[:100]}"
165
+
166
+ def create_basic_design_prompt(user_input):
167
+ """
168
+ Fallback function for basic design prompt generation
169
+ """
170
+ return f"""A professional product design concept for {user_input}:
171
+ - Modern, innovative industrial design
172
+ - Premium materials and finishes
173
+ - Clean lines with functional aesthetics
174
+ - Photorealistic rendering with studio lighting
175
+ - Detailed surface textures and materials
176
+ - Professional product photography style
177
+ - High-end manufacturing quality
178
+ - Shown from 3/4 perspective angle"""
179
 
180
  def upload_image_to_hosting(image):
181
  """
182
+ Upload image to hosting service
183
  """
 
184
  try:
185
+ # Try imgbb first
186
  buffered = BytesIO()
187
  image.save(buffered, format="PNG")
188
  buffered.seek(0)
 
193
  data={
194
  'key': '6d207e02198a847aa98d0a2a901485a5',
195
  'image': img_base64,
196
+ },
197
+ timeout=10
198
  )
199
 
200
  if response.status_code == 200:
 
204
  except:
205
  pass
206
 
207
+ # Fallback to base64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  buffered = BytesIO()
209
  image.save(buffered, format="PNG")
210
  buffered.seek(0)
 
213
 
214
  def process_product_design(prompt, enhance_prompt_flag, image1, image2=None):
215
  """
216
+ Process product design with team collaboration
217
  """
218
  if not os.getenv('REPLICATE_API_TOKEN'):
219
+ return None, prompt, "⚠️ Please set REPLICATE_API_TOKEN", ""
220
 
221
  try:
 
222
  team_discussion = ""
 
 
223
  final_prompt = prompt
224
+
225
+ # Apply team collaboration if enabled
226
  if enhance_prompt_flag:
227
+ result = enhance_prompt_with_team(prompt)
228
+ if isinstance(result, tuple):
229
+ final_prompt, team_discussion = result
230
+ else:
231
+ final_prompt = result
232
+ team_discussion = "Team collaboration completed"
233
 
234
+ # Format team discussion for display
235
+ if "DIRECTOR'S VISION:" in team_discussion:
236
+ team_discussion = f"### 🎬 Team Collaboration Process\n\n{team_discussion}"
237
 
238
+ # Prepare model input
239
  model_input = {
240
  "prompt": final_prompt
241
  }
242
 
243
+ # Add reference images if provided
244
  if image1 or image2:
245
  image_urls = []
246
 
 
253
  image_urls.append(url2)
254
 
255
  model_input["image_input"] = image_urls
256
+ status_msg = "βœ… Product design generated with style references!"
257
  else:
258
+ status_msg = "βœ… Product design generated successfully!"
259
 
260
+ # Generate image with Replicate
 
 
 
 
 
 
 
 
 
261
  try:
262
+ output = replicate.run(
263
+ "black-forest-labs/flux-schnell", # Alternative model that works better
264
+ input={
265
+ "prompt": final_prompt,
266
+ "num_outputs": 1,
267
+ "aspect_ratio": "1:1",
268
+ "output_format": "webp",
269
+ "output_quality": 90
270
+ }
271
+ )
272
  except:
273
+ # Fallback to original model
274
+ output = replicate.run(
275
+ "stability-ai/sdxl:39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b",
276
+ input={
277
+ "prompt": final_prompt,
278
+ "negative_prompt": "low quality, blurry, distorted",
279
+ "width": 1024,
280
+ "height": 1024,
281
+ "num_outputs": 1
282
+ }
283
+ )
284
 
285
+ if output is None:
286
+ return None, final_prompt, "❌ No output received from model", team_discussion
 
 
 
 
 
 
 
287
 
288
+ # Process output
289
  output_url = None
290
  if isinstance(output, str):
291
  output_url = output
292
  elif isinstance(output, list) and len(output) > 0:
293
  output_url = output[0]
294
+ elif hasattr(output, 'url'):
295
+ output_url = output.url
296
 
297
  if output_url:
298
  response = requests.get(output_url, timeout=30)
 
300
  img = Image.open(BytesIO(response.content))
301
  return img, final_prompt, status_msg, team_discussion
302
 
303
+ return None, final_prompt, "❌ Could not process output", team_discussion
304
 
305
  except Exception as e:
306
  error_msg = str(e)
307
+ return None, prompt, f"❌ Error: {error_msg[:200]}", ""
 
 
308
 
309
+ # Professional Product Design CSS
310
  css = """
311
  .gradio-container {
312
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
313
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
314
  min-height: 100vh;
315
  }
316
  .header-container {
317
+ background: linear-gradient(135deg, #2d2d2d 0%, #0f0f0f 100%);
318
+ padding: 2rem;
319
+ border-radius: 20px;
320
+ margin-bottom: 2rem;
321
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
322
+ border: 1px solid rgba(255, 215, 0, 0.2);
323
  }
324
  .logo-text {
325
+ font-size: 2.8rem;
326
+ font-weight: 800;
327
+ color: #ffd700;
328
  text-align: center;
329
  margin: 0;
330
+ letter-spacing: -1px;
331
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
332
  }
333
  .subtitle {
334
+ color: #b0b0b0;
335
  text-align: center;
336
+ font-size: 1rem;
337
  margin-top: 0.5rem;
338
+ font-weight: 400;
339
+ letter-spacing: 0.5px;
340
  }
341
  .mode-indicator {
342
+ background: rgba(255, 215, 0, 0.1);
343
+ border: 1px solid rgba(255, 215, 0, 0.3);
344
+ border-radius: 10px;
345
+ padding: 0.6rem 1.2rem;
346
+ margin: 1rem auto;
347
  text-align: center;
348
+ font-weight: 500;
349
  color: #ffd700;
350
+ max-width: 500px;
351
+ font-size: 0.9rem;
352
  }
353
  .main-content {
354
  background: rgba(255, 255, 255, 0.98);
355
+ border-radius: 20px;
356
+ padding: 2rem;
357
+ box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
 
358
  }
359
  .gr-button-primary {
360
+ background: linear-gradient(135deg, #2d2d2d 0%, #0f0f0f 100%) !important;
361
+ border: 1px solid #ffd700 !important;
362
+ color: #ffd700 !important;
363
+ font-weight: 600 !important;
364
+ font-size: 1rem !important;
365
+ padding: 1rem 2rem !important;
366
+ border-radius: 10px !important;
367
+ transition: all 0.3s ease !important;
368
  text-transform: uppercase;
369
+ letter-spacing: 0.5px;
370
  width: 100%;
371
  margin-top: 1rem !important;
372
  }
373
  .gr-button-primary:hover {
374
+ transform: translateY(-2px) !important;
375
+ box-shadow: 0 8px 25px rgba(255, 215, 0, 0.25) !important;
376
  background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%) !important;
377
  color: #000 !important;
378
  }
379
+ .info-box {
380
+ background: linear-gradient(135deg, #fff3cd 0%, #ffeaa7 100%);
381
+ border-radius: 10px;
382
+ padding: 1rem;
383
+ margin-bottom: 1.5rem;
384
+ border-left: 4px solid #ffd700;
385
+ color: #333;
386
+ font-size: 0.9rem;
 
 
 
387
  }
388
  .team-discussion {
389
+ background: #f8f9fa;
390
+ border-radius: 10px;
391
+ padding: 1.2rem;
392
  margin-top: 1rem;
393
+ border: 1px solid #dee2e6;
394
+ font-family: 'Courier New', monospace;
395
+ font-size: 0.85rem;
396
+ max-height: 300px;
397
  overflow-y: auto;
398
+ white-space: pre-wrap;
 
 
 
 
 
 
 
 
399
  }
400
  .enhanced-prompt-box {
401
  background: #f0f0f0;
402
+ border-radius: 10px;
403
  padding: 1rem;
404
+ margin-top: 0.5rem;
405
+ border-left: 3px solid #ffd700;
406
+ font-size: 0.9rem;
407
+ }
408
+ .gr-input, .gr-textarea {
409
+ background: #ffffff !important;
410
+ border: 1px solid #d0d0d0 !important;
411
+ border-radius: 8px !important;
412
+ font-size: 0.95rem !important;
413
+ padding: 0.7rem !important;
414
+ }
415
+ .gr-input:focus, .gr-textarea:focus {
416
+ border-color: #ffd700 !important;
417
+ box-shadow: 0 0 0 3px rgba(255, 215, 0, 0.1) !important;
418
+ }
419
+ .image-container {
420
+ border-radius: 10px !important;
421
+ overflow: hidden;
422
+ border: 1px solid #e0e0e0 !important;
423
  }
424
  footer {
425
  display: none !important;
426
  }
427
  """
428
 
429
+ # Create Gradio interface
430
  with gr.Blocks(css=css, theme=gr.themes.Base()) as demo:
431
  with gr.Column(elem_classes="header-container"):
432
  gr.HTML("""
433
  <h1 class="logo-text">🏭 PRODUCT DESIGN STUDIO</h1>
434
+ <p class="subtitle">AI-Powered Industrial & Product Design System with Web Research</p>
435
  <div class="mode-indicator">
436
+ πŸ‘₯ Director β†’ πŸ” Engineer (with Brave Search) β†’ 🎨 Designer
437
  </div>
438
  """)
439
 
440
  with gr.Column(elem_classes="main-content"):
 
441
  gr.HTML("""
442
  <div class="info-box">
443
  <strong>🎯 Professional Product Design Process:</strong><br>
444
+ β€’ <b>Director:</b> Establishes vision and requirements<br>
445
+ β€’ <b>Engineer:</b> Searches current trends & technologies via Brave API<br>
446
  β€’ <b>Designer:</b> Creates detailed visual specifications<br>
447
+ β€’ <b>Focus:</b> Physical products only (electronics, furniture, vehicles, appliances)
448
  </div>
449
  """)
450
 
451
  with gr.Row(equal_height=True):
 
452
  with gr.Column(scale=1):
453
  prompt = gr.Textbox(
454
+ label="πŸ“ Product Concept",
455
+ placeholder="Enter product type: 'ergonomic keyboard', 'smart watch', 'office chair', 'coffee maker'...",
456
+ lines=2,
457
+ value="wireless earbuds",
458
  elem_classes="prompt-input"
459
  )
460
 
461
  enhance_prompt_checkbox = gr.Checkbox(
462
+ label="πŸš€ Enable Team Collaboration with Web Research",
463
  value=True,
464
+ info="Activates Director + Engineer (Brave Search) + Designer process"
465
  )
466
 
467
+ with gr.Row():
468
  image1 = gr.Image(
469
+ label="Style Reference 1 (Optional)",
470
  type="pil",
471
+ height=180
 
472
  )
473
  image2 = gr.Image(
474
+ label="Style Reference 2 (Optional)",
475
  type="pil",
476
+ height=180
 
477
  )
478
 
479
  generate_btn = gr.Button(
480
+ "🎨 Generate Product Design",
481
  variant="primary",
482
  size="lg"
483
  )
484
 
 
485
  with gr.Column(scale=1):
486
  output_image = gr.Image(
487
+ label="Generated Product Design",
488
  type="pil",
489
+ height=400,
490
  elem_classes="image-container"
491
  )
492
 
493
  enhanced_prompt_display = gr.Textbox(
494
+ label="πŸ“‹ Final Design Specifications",
495
  interactive=False,
496
+ lines=3,
497
+ elem_classes="enhanced-prompt-box"
 
 
498
  )
499
 
500
  status = gr.Textbox(
501
  label="Status",
502
  interactive=False,
 
503
  elem_classes="status-text",
504
+ value="Ready to design..."
505
  )
506
 
 
507
  with gr.Row():
508
  team_discussion_display = gr.Markdown(
 
509
  value="",
510
  elem_classes="team-discussion"
511
  )
512
 
513
+ # Connect event handler
514
  generate_btn.click(
515
  fn=process_product_design,
516
  inputs=[prompt, enhance_prompt_checkbox, image1, image2],
517
  outputs=[output_image, enhanced_prompt_display, status, team_discussion_display]
518
  )
519
 
520
+ # Product examples
521
  gr.Examples(
522
  examples=[
523
+ ["wireless earbuds", True, None, None],
524
+ ["ergonomic office chair", True, None, None],
525
+ ["smart home speaker", True, None, None],
526
+ ["electric toothbrush", True, None, None],
527
  ["portable coffee maker", True, None, None],
528
+ ["gaming keyboard", True, None, None],
529
+ ["fitness tracker", True, None, None],
530
+ ["desk lamp", True, None, None],
 
 
 
 
 
531
  ],
532
  inputs=[prompt, enhance_prompt_checkbox, image1, image2],
533
+ label="πŸ’‘ Product Design Examples"
534
  )
535
 
536
+ # Launch settings
537
  if __name__ == "__main__":
538
+ # Check for required API keys
539
+ if not os.getenv('REPLICATE_API_TOKEN'):
540
+ print("⚠️ Warning: REPLICATE_API_TOKEN not set")
541
+ if not os.getenv('FIREWORKS_API_KEY'):
542
+ print("⚠️ Warning: FIREWORKS_API_KEY not set - will use fallback prompts")
543
+ if not os.getenv('BRAVE_API_KEY'):
544
+ print("⚠️ Warning: BRAVE_API_KEY not set - web search unavailable")
545
+
546
  demo.launch(
547
+ share=False, # Set to False for Hugging Face Spaces
548
  server_name="0.0.0.0",
549
+ server_port=7860,
550
+ ssr_mode=False # Disable SSR to avoid warning
551
  )