AshBlanc commited on
Commit
57e6f0b
·
verified ·
1 Parent(s): fc6ed76

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +281 -883
app.py CHANGED
@@ -13,7 +13,7 @@ from functools import lru_cache
13
  # Load environment variables
14
  load_dotenv()
15
 
16
- # ### 1. Enhanced Configuration with Error Handling
17
  class APIManager:
18
  """Centralized API management with connection pooling and error handling."""
19
 
@@ -60,7 +60,7 @@ class APIManager:
60
  # Global API manager instance
61
  api_manager = APIManager()
62
 
63
- # ### 2. OPTIMIZED System Instructions - Short, Clear, High-Quality
64
  VISION_SYSTEM_INSTRUCTION = """Extract key actionable insights from screenshots or descriptions in 3-4 bullet points:
65
 
66
  • UI/UX elements and layout structure
@@ -101,1097 +101,495 @@ VARIATION STRATEGY:
101
  OUTPUT FORMAT: Return ONLY valid JSON array of exactly 3 strings:
102
  ["Variation 1", "Variation 2", "Variation 3"]"""
103
 
104
- # ### 3. Enhanced Processing Functions with Better Error Handling
105
  def analyze_screenshot(pil_image: Image.Image) -> str:
106
  """Enhanced screenshot analysis with concise output."""
107
  if not isinstance(pil_image, Image.Image):
108
  return "Error: Invalid image provided."
109
-
110
  if not api_manager.is_configured:
111
  return "Error: API not configured. Please check your API key."
112
-
113
  try:
114
- model = api_manager.models.get('vision') or genai.GenerativeModel(
115
- 'gemini-2.0-flash-exp',
116
- system_instruction=VISION_SYSTEM_INSTRUCTION
117
- )
118
-
119
  response = model.generate_content([
120
  "Analyze this screenshot and extract key insights for prompt creation:",
121
  pil_image
122
  ])
123
-
124
  result = response.text.strip()
125
  return result if result else "No meaningful content detected in the screenshot."
126
-
127
  except Exception as e:
128
- error_msg = f"Error in vision analysis: {str(e)}"
129
- print(error_msg)
130
- return error_msg
131
 
132
  def analyze_text_description(text: str) -> str:
133
  """Analyze text description for context insights."""
134
  if not text.strip():
135
  return "Error: No text provided for analysis."
136
-
137
  if not api_manager.is_configured:
138
  return "Error: API not configured."
139
-
140
  try:
141
- model = api_manager.models.get('vision') or genai.GenerativeModel(
142
- 'gemini-2.0-flash-exp',
143
- system_instruction=VISION_SYSTEM_INSTRUCTION
144
- )
145
-
146
  response = model.generate_content(f"Analyze this description for prompt creation insights:\n\n{text}")
147
-
148
  result = response.text.strip()
149
  return result if result else "Unable to extract meaningful insights from the description."
150
-
151
  except Exception as e:
152
- error_msg = f"Error in text analysis: {str(e)}"
153
- print(error_msg)
154
- return error_msg
155
 
156
  def initial_prompt_stream(analysis_text: str, goal: str):
157
  """Enhanced streaming prompt generation with concise output."""
158
  if not api_manager.is_configured:
159
  yield "Error: API not configured. Please check your API key."
160
  return
161
-
162
  try:
163
- model = api_manager.models.get('initial') or genai.GenerativeModel(
164
- 'gemini-2.0-flash-exp',
165
- system_instruction=PROMPT_ENGINEER_SYSTEM_INSTRUCTION
166
- )
167
-
168
- # Construct concise prompt
169
  user_goal = goal.strip() if goal else "Create an optimized prompt based on the analysis"
170
-
171
- prompt = f"""CONTEXT: {analysis_text}
172
-
173
- GOAL: {user_goal}
174
-
175
- Create a concise, high-performance prompt that achieves this goal."""
176
-
177
  final_prompt_full = ""
178
-
179
  for chunk in model.generate_content(prompt, stream=True):
180
  if chunk.text:
181
  final_prompt_full += chunk.text
182
  yield final_prompt_full.strip()
183
-
184
  if not final_prompt_full.strip():
185
- fallback = f"You are an expert assistant. {user_goal}. Provide clear, actionable guidance with specific examples."
186
- yield fallback
187
-
188
  except Exception as e:
189
- error_msg = f"Error in prompt generation: {str(e)}"
190
- print(error_msg)
191
- yield error_msg
192
 
193
  def refinement_prompt_stream(original_prompt: str, feedback: str):
194
  """Enhanced prompt refinement with concise output."""
195
  if not api_manager.is_configured:
196
  yield "Error: API not configured. Please check your API key."
197
  return
198
-
199
  try:
200
- model = api_manager.models.get('refiner') or genai.GenerativeModel(
201
- 'gemini-2.0-flash-exp',
202
- system_instruction=PROMPT_REFINER_SYSTEM_INSTRUCTION
203
- )
204
-
205
- refinement_prompt = f"""ORIGINAL: {original_prompt}
206
-
207
- FEEDBACK: {feedback}
208
-
209
- Refine the prompt based on this feedback."""
210
-
211
  final_prompt_full = ""
212
  for chunk in model.generate_content(refinement_prompt, stream=True):
213
  if chunk.text:
214
  final_prompt_full += chunk.text
215
  yield final_prompt_full.strip()
216
-
217
  if not final_prompt_full.strip():
218
- yield original_prompt # Fallback to original
219
-
220
  except Exception as e:
221
- error_msg = f"Error in prompt refinement: {str(e)}"
222
- print(error_msg)
223
- yield error_msg
224
 
225
  def rewrite_prompt_with_prewrite(original_prompt: str) -> List[str]:
226
  """Enhanced prompt rewriting with better JSON parsing."""
227
  if not api_manager.is_configured:
228
  return ["Error: API not configured. Please check your API key.", "", ""]
229
-
230
  try:
231
- model = api_manager.models.get('rewriter') or genai.GenerativeModel(
232
- 'gemini-2.0-flash-exp',
233
- system_instruction=META_PROMPT_SYSTEM_INSTRUCTION
234
- )
235
-
236
- rewrite_prompt = f"""ORIGINAL PROMPT: {original_prompt}
237
-
238
- Generate 3 improved variations. Output ONLY JSON array of 3 strings."""
239
-
240
  response = model.generate_content(rewrite_prompt)
 
241
 
242
- # Enhanced JSON parsing
243
- response_text = response.text.strip()
244
-
245
- # Clean up common formatting issues
246
- response_text = response_text.replace("```json", "").replace("```text", "").replace("```", "").strip()
247
-
248
- # Try to extract JSON if it's wrapped in other text
249
  if not response_text.startswith('['):
250
  import re
251
  json_match = re.search(r'\[.*\]', response_text, re.DOTALL)
252
  if json_match:
253
  response_text = json_match.group(0)
254
-
255
  variations = json.loads(response_text)
256
-
257
  if isinstance(variations, list) and len(variations) >= 1:
258
- # Ensure we have exactly 3 variations
259
  while len(variations) < 3:
260
  variations.append("")
261
  return variations[:3]
262
-
263
  return ["Error: AI returned an invalid format.", "", ""]
264
-
265
  except json.JSONDecodeError:
266
  return ["Error: Could not parse AI response as JSON.", "", ""]
267
  except Exception as e:
268
- error_msg = f"Error in prompt rewriting: {str(e)}"
269
- print(error_msg)
270
- return [error_msg, "", ""]
271
 
272
- # ### 4. Enhanced Gradio Interface Functions
273
  def create_enhanced_interface():
274
- """Create the ultra-modern Gradio interface with cutting-edge design."""
275
 
276
- # Ultra-modern CSS with glassmorphism, animations, and premium styling
277
  custom_css = """
278
- /* Import Google Fonts */
279
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;500&display=swap');
280
-
281
- /* Global Styles */
282
  :root {
283
- --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
284
- --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
285
- --success-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
286
- --glass-bg: rgba(255, 255, 255, 0.1);
287
- --glass-border: rgba(255, 255, 255, 0.2);
288
- --shadow-soft: 0 8px 32px rgba(0, 0, 0, 0.1);
289
- --shadow-hard: 0 20px 40px rgba(0, 0, 0, 0.15);
290
- --text-primary: #1a1a1a;
291
- --text-secondary: #6b7280;
292
- --surface-primary: #ffffff;
293
- --surface-secondary: #f8fafc;
294
- --accent-blue: #3b82f6;
295
- --accent-purple: #8b5cf6;
296
- --accent-pink: #ec4899;
297
- --accent-green: #10b981;
 
 
 
 
 
298
  }
299
 
300
- * {
301
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
302
- }
303
-
304
- /* Dark mode support */
305
- @media (prefers-color-scheme: dark) {
306
- :root {
307
- --text-primary: #ffffff;
308
- --text-secondary: #9ca3af;
309
- --surface-primary: #1f2937;
310
- --surface-secondary: #111827;
311
- --glass-bg: rgba(0, 0, 0, 0.2);
312
- --glass-border: rgba(255, 255, 255, 0.1);
313
- }
314
- }
315
-
316
- /* Main Container */
317
- .gradio-container {
318
- max-width: 1400px !important;
319
- margin: 0 auto !important;
320
- padding: 2rem !important;
321
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%) !important;
322
- min-height: 100vh !important;
323
  font-family: 'Inter', sans-serif !important;
324
  }
325
-
326
- /* Header Styling */
327
- .main-header {
328
- text-align: center;
329
- margin-bottom: 3rem;
330
- padding: 2rem;
331
- background: var(--glass-bg);
332
- backdrop-filter: blur(20px);
333
- border-radius: 24px;
334
- border: 1px solid var(--glass-border);
335
- box-shadow: var(--shadow-soft);
336
- }
337
-
338
  .main-header h1 {
339
- font-size: 3.5rem !important;
340
- font-weight: 700 !important;
341
- background: var(--primary-gradient);
342
- -webkit-background-clip: text;
343
- -webkit-text-fill-color: transparent;
344
- background-clip: text;
345
- margin-bottom: 1rem !important;
346
- letter-spacing: -0.02em;
347
  }
348
-
349
- .main-header p {
350
- font-size: 1.25rem !important;
351
- color: var(--text-secondary) !important;
352
- font-weight: 400 !important;
353
- margin: 0 !important;
354
- }
355
-
356
- /* Status Indicator */
357
  .status-indicator {
358
- display: inline-flex;
359
- align-items: center;
360
- gap: 0.5rem;
361
- padding: 0.75rem 1.5rem;
362
- border-radius: 50px;
363
- font-size: 0.875rem;
364
- font-weight: 500;
365
- margin: 1rem 0;
366
- transition: all 0.3s ease;
367
  backdrop-filter: blur(10px);
368
  }
369
-
370
- .status-success {
371
- background: linear-gradient(135deg, rgba(16, 185, 129, 0.1), rgba(5, 150, 105, 0.1));
372
- color: var(--accent-green);
373
- border: 1px solid rgba(16, 185, 129, 0.3);
374
- box-shadow: 0 4px 12px rgba(16, 185, 129, 0.2);
375
- }
376
-
377
- .status-error {
378
- background: linear-gradient(135deg, rgba(239, 68, 68, 0.1), rgba(220, 38, 38, 0.1));
379
- color: #ef4444;
380
- border: 1px solid rgba(239, 68, 68, 0.3);
381
- box-shadow: 0 4px 12px rgba(239, 68, 68, 0.2);
382
- }
383
-
384
- /* Card Styling */
385
  .glass-card {
386
  background: var(--glass-bg) !important;
387
- backdrop-filter: blur(20px) !important;
388
  border: 1px solid var(--glass-border) !important;
389
- border-radius: 20px !important;
 
 
390
  padding: 2rem !important;
391
- margin: 1rem 0 !important;
392
- box-shadow: var(--shadow-soft) !important;
393
- transition: all 0.3s ease !important;
394
- }
395
-
396
- .glass-card:hover {
397
- transform: translateY(-2px) !important;
398
- box-shadow: var(--shadow-hard) !important;
399
- }
400
-
401
- /* Input Styling */
402
- .custom-input {
403
- border: 2px solid transparent !important;
404
- border-radius: 16px !important;
405
- padding: 1rem !important;
406
- font-size: 1rem !important;
407
- background: var(--surface-primary) !important;
408
- color: var(--text-primary) !important;
409
- transition: all 0.3s ease !important;
410
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05) !important;
411
- }
412
-
413
- .custom-input:focus {
414
- border-color: var(--accent-blue) !important;
415
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1) !important;
416
- outline: none !important;
417
- }
418
-
419
- /* Button Styling */
420
- .btn-primary {
421
- background: var(--primary-gradient) !important;
422
- border: none !important;
423
- border-radius: 16px !important;
424
- padding: 1rem 2rem !important;
425
- font-size: 1rem !important;
426
- font-weight: 600 !important;
427
- color: white !important;
428
- transition: all 0.3s ease !important;
429
- box-shadow: 0 8px 24px rgba(102, 126, 234, 0.3) !important;
430
- position: relative !important;
431
- overflow: hidden !important;
432
- }
433
-
434
- .btn-primary:hover {
435
- transform: translateY(-3px) !important;
436
- box-shadow: 0 12px 32px rgba(102, 126, 234, 0.4) !important;
437
- }
438
-
439
- .btn-primary:active {
440
- transform: translateY(-1px) !important;
441
- }
442
-
443
- .btn-secondary {
444
- background: var(--surface-primary) !important;
445
- border: 2px solid var(--glass-border) !important;
446
- border-radius: 16px !important;
447
- padding: 0.75rem 1.5rem !important;
448
- font-size: 0.875rem !important;
449
- font-weight: 500 !important;
450
- color: var(--text-primary) !important;
451
- transition: all 0.3s ease !important;
452
- backdrop-filter: blur(10px) !important;
453
- }
454
-
455
- .btn-secondary:hover {
456
- background: var(--glass-bg) !important;
457
- transform: translateY(-2px) !important;
458
- box-shadow: var(--shadow-soft) !important;
459
- }
460
-
461
- .btn-success {
462
- background: var(--success-gradient) !important;
463
- border: none !important;
464
- border-radius: 16px !important;
465
- padding: 0.75rem 1.5rem !important;
466
- font-weight: 600 !important;
467
- color: white !important;
468
- transition: all 0.3s ease !important;
469
- box-shadow: 0 6px 20px rgba(79, 172, 254, 0.3) !important;
470
  }
471
-
472
- .btn-success:hover {
473
- transform: translateY(-2px) !important;
474
- box-shadow: 0 10px 28px rgba(79, 172, 254, 0.4) !important;
 
 
 
 
 
475
  }
476
-
477
- .btn-accent {
478
- background: var(--secondary-gradient) !important;
479
- border: none !important;
480
- border-radius: 16px !important;
481
- padding: 0.75rem 1.5rem !important;
482
- font-weight: 600 !important;
483
- color: white !important;
484
- transition: all 0.3s ease !important;
485
- box-shadow: 0 6px 20px rgba(240, 147, 251, 0.3) !important;
486
  }
487
-
488
- .btn-accent:hover {
489
- transform: translateY(-2px) !important;
490
- box-shadow: 0 10px 28px rgba(240, 147, 251, 0.4) !important;
491
  }
492
-
493
  /* Image Upload Area */
494
  .image-upload {
495
  border: 2px dashed var(--glass-border) !important;
496
- border-radius: 20px !important;
497
- padding: 2rem !important;
498
  background: var(--glass-bg) !important;
499
- backdrop-filter: blur(10px) !important;
500
- transition: all 0.3s ease !important;
501
- text-align: center !important;
502
- }
503
-
504
- .image-upload:hover {
505
- border-color: var(--accent-blue) !important;
506
- background: rgba(59, 130, 246, 0.05) !important;
507
- transform: translateY(-2px) !important;
508
- }
509
-
510
- /* Output Areas */
511
- .analysis-output {
512
- background: linear-gradient(135deg, rgba(16, 185, 129, 0.05), rgba(5, 150, 105, 0.05)) !important;
513
- border: 1px solid rgba(16, 185, 129, 0.2) !important;
514
- border-radius: 20px !important;
515
- padding: 1.5rem !important;
516
- font-family: 'Inter', sans-serif !important;
517
- font-size: 0.95rem !important;
518
- line-height: 1.6 !important;
519
- color: var(--text-primary) !important;
520
- backdrop-filter: blur(10px) !important;
521
- }
522
-
523
- .prompt-output {
524
- background: linear-gradient(135deg, rgba(59, 130, 246, 0.05), rgba(139, 92, 246, 0.05)) !important;
525
- border: 2px solid rgba(59, 130, 246, 0.2) !important;
526
- border-radius: 20px !important;
527
- padding: 2rem !important;
528
- font-family: 'JetBrains Mono', 'Monaco', 'Consolas', monospace !important;
529
- font-size: 0.9rem !important;
530
- line-height: 1.7 !important;
531
- color: var(--text-primary) !important;
532
- backdrop-filter: blur(10px) !important;
533
- position: relative !important;
534
- overflow: hidden !important;
535
- }
536
-
537
- .prompt-output::before {
538
- content: '';
539
- position: absolute;
540
- top: 0;
541
- left: 0;
542
- right: 0;
543
- height: 4px;
544
- background: var(--primary-gradient);
545
- border-radius: 20px 20px 0 0;
546
- }
547
-
548
- /* Section Headers */
549
- .section-header {
550
- font-size: 1.25rem !important;
551
- font-weight: 600 !important;
552
- color: var(--text-primary) !important;
553
- margin-bottom: 1rem !important;
554
- padding-bottom: 0.5rem !important;
555
- border-bottom: 2px solid var(--glass-border) !important;
556
- display: flex !important;
557
- align-items: center !important;
558
- gap: 0.5rem !important;
559
- }
560
-
561
- /* Refinement Section */
562
- .refinement-section {
563
- background: var(--glass-bg) !important;
564
- backdrop-filter: blur(20px) !important;
565
- border: 1px solid var(--glass-border) !important;
566
- border-radius: 20px !important;
567
- padding: 2rem !important;
568
- margin-top: 2rem !important;
569
- }
570
-
571
- /* Radio Buttons */
572
- .radio-group {
573
- display: flex !important;
574
- flex-direction: column !important;
575
- gap: 1rem !important;
576
- margin: 1rem 0 !important;
577
- }
578
-
579
- .radio-option {
580
- background: var(--surface-primary) !important;
581
- border: 2px solid var(--glass-border) !important;
582
  border-radius: 16px !important;
583
- padding: 1rem !important;
584
- transition: all 0.3s ease !important;
585
- cursor: pointer !important;
586
- }
587
-
588
- .radio-option:hover {
589
- border-color: var(--accent-blue) !important;
590
- background: rgba(59, 130, 246, 0.05) !important;
591
- }
592
-
593
- .radio-option.selected {
594
- border-color: var(--accent-blue) !important;
595
- background: rgba(59, 130, 246, 0.1) !important;
596
- }
597
-
598
- /* Animations */
599
- @keyframes fadeInUp {
600
- from {
601
- opacity: 0;
602
- transform: translateY(20px);
603
- }
604
- to {
605
- opacity: 1;
606
- transform: translateY(0);
607
- }
608
- }
609
-
610
- @keyframes pulse {
611
- 0%, 100% {
612
- opacity: 1;
613
- }
614
- 50% {
615
- opacity: 0.7;
616
- }
617
- }
618
-
619
- .animate-fade-in {
620
- animation: fadeInUp 0.5s ease-out !important;
621
- }
622
-
623
- .animate-pulse {
624
- animation: pulse 2s ease-in-out infinite !important;
625
- }
626
-
627
- /* Loading States */
628
- .loading-spinner {
629
- display: inline-block;
630
- width: 20px;
631
- height: 20px;
632
- border: 2px solid var(--glass-border);
633
- border-radius: 50%;
634
- border-top-color: var(--accent-blue);
635
- animation: spin 1s linear infinite;
636
- }
637
-
638
- @keyframes spin {
639
- to {
640
- transform: rotate(360deg);
641
- }
642
- }
643
-
644
- /* Responsive Design */
645
- @media (max-width: 768px) {
646
- .gradio-container {
647
- padding: 1rem !important;
648
- }
649
-
650
- .main-header h1 {
651
- font-size: 2.5rem !important;
652
- }
653
-
654
- .glass-card {
655
- padding: 1.5rem !important;
656
- }
657
-
658
- .btn-primary {
659
- padding: 0.875rem 1.5rem !important;
660
- }
661
  }
662
-
663
- /* Scrollbar Styling */
664
- ::-webkit-scrollbar {
665
- width: 8px;
 
 
 
666
  }
667
-
668
- ::-webkit-scrollbar-track {
669
- background: var(--surface-secondary);
670
- border-radius: 4px;
671
  }
 
 
672
 
673
- ::-webkit-scrollbar-thumb {
674
- background: var(--glass-border);
675
- border-radius: 4px;
676
- transition: background 0.3s ease;
677
- }
678
 
679
- ::-webkit-scrollbar-thumb:hover {
680
- background: var(--accent-blue);
 
 
681
  }
682
-
683
- /* Custom styling for specific elements */
684
- .gr-button {
685
- transition: all 0.3s ease !important;
 
686
  }
687
-
688
- .gr-textbox {
689
- transition: all 0.3s ease !important;
690
  }
691
-
692
- .gr-file-upload {
693
- transition: all 0.3s ease !important;
694
  }
695
 
696
- /* Hide default gradio styling */
697
- .gradio-container .gr-button:not(.btn-primary):not(.btn-secondary):not(.btn-success):not(.btn-accent) {
698
- background: var(--surface-primary) !important;
699
- border: 2px solid var(--glass-border) !important;
700
- border-radius: 12px !important;
701
- color: var(--text-primary) !important;
702
- }
703
  """
704
-
705
- # Ultra-modern theme with custom colors
 
706
  theme = gr.themes.Soft(
707
- primary_hue=gr.themes.colors.blue,
708
- secondary_hue=gr.themes.colors.purple,
709
  neutral_hue=gr.themes.colors.slate,
710
  font=(gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"),
711
  font_mono=(gr.themes.GoogleFont("JetBrains Mono"), "ui-monospace", "Consolas", "monospace")
712
- ).set(
713
- # Button styling
714
- button_primary_background_fill="linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
715
- button_primary_background_fill_hover="linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%)",
716
- button_primary_text_color="white",
717
- button_secondary_background_fill="rgba(255, 255, 255, 0.1)",
718
- button_secondary_background_fill_hover="rgba(255, 255, 255, 0.2)",
719
- # Input styling
720
- input_background_fill="rgba(255, 255, 255, 0.9)",
721
- input_background_fill_focus="rgba(255, 255, 255, 1)",
722
- input_border_color="rgba(255, 255, 255, 0.2)",
723
- input_border_color_focus="#3b82f6",
724
- # Block styling
725
- block_background_fill="rgba(255, 255, 255, 0.1)",
726
- block_border_color="rgba(255, 255, 255, 0.2)",
727
- block_border_width="1px",
728
- block_radius="20px",
729
  )
730
-
731
- with gr.Blocks(theme=theme, css=custom_css, title="SuperKontext AI - Context is All You Need") as interface:
 
732
  # State management
733
  analysis_state = gr.State()
734
  first_prompt_state = gr.State()
735
-
736
- # Modern Header with glassmorphism effect
737
- with gr.Row():
738
- with gr.Column():
739
- gr.HTML("""
740
- <div class="main-header animate-fade-in">
741
- <h1>🚀 SuperKontext AI</h1>
742
- <p>Transform your ideas into crystal-clear prompts with AI-powered context analysis</p>
743
- </div>
744
- """)
745
-
746
- # Status indicator with modern styling
747
- with gr.Row():
748
- with gr.Column():
749
- if api_manager.is_configured:
750
- gr.HTML("""
751
- <div class="status-indicator status-success animate-fade-in">
752
- <div class="loading-spinner" style="border-top-color: var(--accent-green); animation: none; width: 12px; height: 12px; background: var(--accent-green); border-radius: 50%;"></div>
753
- <span>API Connected & Ready</span>
754
- </div>
755
- """)
756
- else:
757
- gr.HTML("""
758
- <div class="status-indicator status-error animate-fade-in">
759
- <span>❌ API Configuration Error - Check your GEMINI_API_KEY</span>
760
- </div>
761
- """)
762
-
763
- # Main interface with modern card design
764
- with gr.Row(equal_height=False):
765
- # Input column with glassmorphism
766
  with gr.Column(scale=5, min_width=500):
767
- with gr.Group(elem_classes=["glass-card"]):
768
- gr.HTML('<div class="section-header">📝 Input Context</div>')
769
 
770
- # Screenshot section with modern upload area
771
- with gr.Group():
772
- gr.HTML('<h4 style="margin: 1rem 0 0.5rem 0; color: var(--text-secondary); font-weight: 500;">📸 Screenshot (Optional)</h4>')
773
- image_input = gr.Image(
774
- type="pil",
775
- label="Upload Screenshot",
776
- sources=['upload'],
777
- interactive=True,
778
- height=250,
779
- elem_classes=["image-upload"]
780
- )
781
 
782
- # Text description section
783
- with gr.Group():
784
- gr.HTML('<h4 style="margin: 1rem 0 0.5rem 0; color: var(--text-secondary); font-weight: 500;">✍️ Describe Your Task</h4>')
785
- situation_input = gr.Textbox(
786
- label="What do you need help with?",
787
- placeholder="Example: Create a marketing email for a new product launch, Write code documentation, Analyze customer feedback data, etc.",
788
- lines=5,
789
- max_lines=8,
790
- elem_classes=["custom-input"]
791
- )
792
 
793
- # Optional goal input
794
- with gr.Accordion("🎯 Specific Goal (Optional)", open=False):
795
  goal_input = gr.Textbox(
796
- label="Specific outcome you want",
797
- placeholder="e.g., 'Generate 5 subject line options' or 'Create step-by-step instructions'",
798
- lines=2,
799
- elem_classes=["custom-input"]
800
  )
801
 
802
- # Buttons
803
  with gr.Row():
804
- submit_btn = gr.Button(
805
- "🚀 Generate Prompt",
806
- variant="primary",
807
- scale=3,
808
- elem_classes=["btn-primary"]
809
- )
810
- clear_btn = gr.Button(
811
- "🔄 Reset",
812
- scale=1,
813
- elem_classes=["btn-secondary"]
814
- )
815
-
816
- # Output column
817
  with gr.Column(scale=7, min_width=700):
818
- with gr.Group(elem_classes=["glass-card"]):
819
- gr.HTML('<div class="section-header">🔍 Context Analysis</div>')
820
  analysis_output = gr.Textbox(
821
- label="Key Insights",
822
- lines=4,
823
- interactive=False,
824
- show_copy_button=True,
825
- placeholder="Context analysis will appear here...",
826
  elem_classes=["analysis-output"]
827
  )
828
 
829
- with gr.Group(elem_classes=["glass-card"]):
830
- gr.HTML('<div class="section-header">✅ Optimized Prompt</div>')
831
  final_prompt_output = gr.Textbox(
832
- label="Your Crystal-Clear Prompt",
833
- lines=8,
834
- interactive=False,
835
- show_copy_button=True,
836
- placeholder="Your optimized prompt will appear here...",
837
  elem_classes=["prompt-output"]
838
  )
839
 
840
- # Refinement interface
841
- with gr.Row(visible=False, elem_classes=["refinement-section"]) as satisfaction_row:
842
  with gr.Column():
843
- gr.HTML('<div class="section-header">🎨 Refinement Options</div>')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
844
  with gr.Row():
845
- like_btn = gr.Button(
846
- "👍 Perfect!",
847
- variant="secondary",
848
- scale=1,
849
- elem_classes=["btn-success"]
850
- )
851
- auto_refine_btn = gr.Button(
852
- "🤖 Auto-Refine",
853
- variant="primary",
854
- scale=1,
855
- elem_classes=["btn-primary"]
856
- )
857
- dislike_btn = gr.Button(
858
- "✏️ Custom Feedback",
859
- variant="secondary",
860
- scale=1,
861
- elem_classes=["btn-secondary"]
862
- )
863
-
864
- # Auto-refinement section
865
- with gr.Column(visible=False, elem_classes=["glass-card"]) as prewrite_col:
866
- gr.HTML('<div class="section-header">🔄 Choose Your Preferred Version</div>')
867
- prewrite_choices = gr.Radio(
868
- label="Select the best variation:",
869
- type="value",
870
- interactive=True,
871
- elem_classes=["radio-group"]
872
- )
873
- select_version_btn = gr.Button(
874
- "✅ Use This Version",
875
- variant="primary",
876
- elem_classes=["btn-success"]
877
- )
878
-
879
- # Manual feedback section
880
- with gr.Column(visible=False, elem_classes=["glass-card"]) as feedback_col:
881
- gr.HTML('<div class="section-header">💬 Custom Refinement</div>')
882
- feedback_input = gr.Textbox(
883
- label="How should we improve it?",
884
- placeholder="e.g., 'Make it more specific', 'Add examples', 'Change tone to professional'",
885
- lines=2,
886
- elem_classes=["custom-input"]
887
- )
888
- refine_btn = gr.Button(
889
- "🛠️ Refine Prompt",
890
- variant="primary",
891
- elem_classes=["btn-accent"]
892
- )
893
-
894
- # ### Enhanced Interface Functions
895
- def run_analysis_step(pil_image: Optional[Image.Image], situation_text: str):
896
- """Enhanced analysis step with concise output."""
897
- # Reset UI state
898
  yield {
899
- satisfaction_row: gr.update(visible=False),
 
 
900
  feedback_col: gr.update(visible=False),
901
  prewrite_col: gr.update(visible=False),
902
- analysis_output: "🔍 Analyzing context...",
903
- final_prompt_output: ""
904
  }
905
-
906
- # Validation
907
  if not api_manager.is_configured:
908
- yield {
909
- analysis_output: "❌ Error: API Key not configured. Please check your GEMINI_API_KEY environment variable.",
910
- final_prompt_output: "",
911
- satisfaction_row: gr.update(visible=False),
912
- feedback_col: gr.update(visible=False),
913
- prewrite_col: gr.update(visible=False),
914
- analysis_state: None
915
- }
916
- return
917
-
918
- if pil_image is None and not situation_text.strip():
919
- yield {
920
- analysis_output: "⚠️ Please provide either a screenshot or task description to proceed.",
921
- final_prompt_output: "",
922
- satisfaction_row: gr.update(visible=False),
923
- feedback_col: gr.update(visible=False),
924
- prewrite_col: gr.update(visible=False),
925
- analysis_state: None
926
- }
927
  return
928
-
929
- # Perform analysis
930
- try:
931
- if pil_image and situation_text.strip():
932
- # Both provided - analyze screenshot and add text context
933
- screenshot_analysis = analyze_screenshot(pil_image)
934
- analysis_text = f"SCREENSHOT: {screenshot_analysis}\n\nTEXT CONTEXT: {situation_text.strip()}"
935
- elif pil_image:
936
- # Only screenshot
937
- analysis_text = analyze_screenshot(pil_image)
938
- else:
939
- # Only text description
940
- analysis_text = analyze_text_description(situation_text.strip())
941
-
942
- if not analysis_text or analysis_text.startswith("Error"):
943
- analysis_text = analysis_text or "Unable to generate analysis. Please try again."
944
-
945
- yield {
946
- analysis_output: analysis_text,
947
- final_prompt_output: "",
948
- satisfaction_row: gr.update(visible=False),
949
- feedback_col: gr.update(visible=False),
950
- prewrite_col: gr.update(visible=False),
951
- analysis_state: analysis_text
952
- }
953
-
954
- except Exception as e:
955
- error_msg = f"❌ Error during analysis: {str(e)}"
956
- print(error_msg)
957
- yield {
958
- analysis_output: error_msg,
959
- final_prompt_output: "",
960
- satisfaction_row: gr.update(visible=False),
961
- feedback_col: gr.update(visible=False),
962
- prewrite_col: gr.update(visible=False),
963
- analysis_state: None
964
- }
965
 
966
- def run_streaming_generation(analysis: str, goal: str):
967
- """Enhanced streaming generation with concise output."""
968
- if not analysis:
969
- yield {
970
- final_prompt_output: "❌ Error: No analysis available for prompt generation.",
971
- first_prompt_state: None,
972
- satisfaction_row: gr.update(visible=False)
973
- }
974
  return
975
 
 
 
 
 
 
 
 
 
 
976
  yield {
977
- final_prompt_output: "🚀 Generating optimized prompt...",
978
- satisfaction_row: gr.update(visible=False)
 
979
  }
980
 
 
981
  final_prompt_full = ""
982
- for chunk in initial_prompt_stream(analysis, goal):
983
  final_prompt_full = chunk
984
  yield {final_prompt_output: final_prompt_full}
985
 
 
986
  yield {
987
  final_prompt_output: final_prompt_full,
988
  first_prompt_state: final_prompt_full,
989
- satisfaction_row: gr.update(visible=True)
990
  }
991
 
992
  def handle_auto_refine(original_prompt: str):
993
- """Enhanced auto-refinement with better user feedback."""
994
- if not original_prompt:
995
- return {
996
- prewrite_col: gr.update(visible=False),
997
- satisfaction_row: gr.update(visible=True),
998
- feedback_col: gr.update(visible=False)
999
- }
1000
-
1001
- variations = rewrite_prompt_with_prewrite(original_prompt)
1002
-
1003
- # Filter out empty variations
1004
- valid_variations = [v for v in variations if v.strip()]
1005
-
1006
- if not valid_variations:
1007
- return {
1008
- prewrite_col: gr.update(visible=False),
1009
- satisfaction_row: gr.update(visible=True),
1010
- feedback_col: gr.update(visible=False)
1011
- }
1012
 
1013
  return {
1014
  prewrite_col: gr.update(visible=True),
1015
- prewrite_choices: gr.update(choices=valid_variations, value=valid_variations[0]),
1016
- satisfaction_row: gr.update(visible=False),
1017
- feedback_col: gr.update(visible=False)
1018
  }
1019
 
1020
  def select_rewritten_prompt(selected_prompt: str):
1021
- """Enhanced prompt selection with validation."""
1022
- if not selected_prompt or not selected_prompt.strip():
1023
- return {
1024
- final_prompt_output: "❌ Error: No prompt selected.",
1025
- first_prompt_state: None,
1026
- satisfaction_row: gr.update(visible=False),
1027
- prewrite_col: gr.update(visible=False)
1028
- }
1029
-
1030
  return {
1031
  final_prompt_output: selected_prompt,
1032
  first_prompt_state: selected_prompt,
1033
- satisfaction_row: gr.update(visible=True),
1034
  prewrite_col: gr.update(visible=False)
1035
  }
1036
 
1037
- def handle_manual_feedback():
1038
- """Show feedback input area."""
1039
  return {
1040
  feedback_col: gr.update(visible=True),
1041
- satisfaction_row: gr.update(visible=False),
1042
- prewrite_col: gr.update(visible=False)
1043
  }
1044
 
1045
- def handle_like():
1046
- """Hide refinement options when user is satisfied."""
1047
  return {
1048
- satisfaction_row: gr.update(visible=False),
1049
  feedback_col: gr.update(visible=False),
1050
  prewrite_col: gr.update(visible=False)
1051
  }
1052
 
1053
  def refine_with_manual_feedback(original_prompt: str, feedback: str):
1054
- """Enhanced manual refinement with concise output."""
1055
  if not feedback.strip():
1056
- yield {
1057
- final_prompt_output: original_prompt,
1058
- first_prompt_state: original_prompt,
1059
- satisfaction_row: gr.update(visible=True),
1060
- feedback_col: gr.update(visible=False)
1061
- }
1062
  return
1063
 
1064
  yield {
1065
- final_prompt_output: "🛠️ Refining prompt based on your feedback...",
1066
- satisfaction_row: gr.update(visible=False)
1067
  }
1068
-
1069
  final_prompt_full = ""
1070
  for chunk in refinement_prompt_stream(original_prompt, feedback):
1071
  final_prompt_full = chunk
1072
- yield {
1073
- final_prompt_output: final_prompt_full,
1074
- first_prompt_state: final_prompt_full
1075
- }
1076
 
1077
  yield {
1078
- satisfaction_row: gr.update(visible=True),
1079
- feedback_col: gr.update(visible=False)
1080
  }
1081
 
1082
  def clear_all():
1083
- """Enhanced reset function with complete state clearing."""
1084
  return {
1085
- image_input: None,
1086
- situation_input: "",
1087
- goal_input: "",
1088
- analysis_output: "",
1089
- final_prompt_output: "",
1090
- satisfaction_row: gr.update(visible=False),
1091
- feedback_col: gr.update(visible=False),
1092
- prewrite_col: gr.update(visible=False),
1093
- prewrite_choices: gr.update(choices=[], value=None),
1094
- feedback_input: "",
1095
- analysis_state: None,
1096
- first_prompt_state: None
1097
  }
1098
 
1099
- # Event handlers
1100
- analysis_outputs = [
1101
- satisfaction_row, feedback_col, prewrite_col,
1102
- analysis_output, final_prompt_output, analysis_state
1103
- ]
1104
-
1105
- streaming_outputs = [final_prompt_output, first_prompt_state, satisfaction_row]
1106
-
1107
- # Event bindings
1108
  submit_btn.click(
1109
- fn=run_analysis_step,
1110
- inputs=[image_input, situation_input],
1111
- outputs=analysis_outputs,
1112
- show_progress="minimal"
1113
- ).then(
1114
- fn=run_streaming_generation,
1115
- inputs=[analysis_state, goal_input],
1116
- outputs=streaming_outputs,
1117
- show_progress="minimal"
1118
  )
 
1119
 
1120
- # Auto-submission on goal input
1121
- goal_input.submit(
1122
- fn=run_analysis_step,
1123
- inputs=[image_input, situation_input],
1124
- outputs=analysis_outputs,
1125
- show_progress="minimal"
1126
- ).then(
1127
- fn=run_streaming_generation,
1128
- inputs=[analysis_state, goal_input],
1129
- outputs=streaming_outputs,
1130
- show_progress="minimal"
1131
- )
1132
-
1133
- # Refinement handlers
1134
- like_btn.click(
1135
- fn=handle_like,
1136
- outputs=[satisfaction_row, feedback_col, prewrite_col]
1137
- )
1138
-
1139
- auto_refine_btn.click(
1140
- fn=handle_auto_refine,
1141
- inputs=[first_prompt_state],
1142
- outputs=[prewrite_col, prewrite_choices, satisfaction_row, feedback_col]
1143
- )
1144
-
1145
- dislike_btn.click(
1146
- fn=handle_manual_feedback,
1147
- outputs=[feedback_col, satisfaction_row, prewrite_col]
1148
- )
1149
 
1150
- select_version_btn.click(
1151
- fn=select_rewritten_prompt,
1152
- inputs=[prewrite_choices],
1153
- outputs=[final_prompt_output, first_prompt_state, satisfaction_row, prewrite_col]
1154
- )
1155
-
1156
- refine_btn.click(
1157
- fn=refine_with_manual_feedback,
1158
- inputs=[first_prompt_state, feedback_input],
1159
- outputs=[final_prompt_output, first_prompt_state, satisfaction_row, feedback_col]
1160
- )
1161
 
1162
- feedback_input.submit(
1163
- fn=refine_with_manual_feedback,
1164
- inputs=[first_prompt_state, feedback_input],
1165
- outputs=[final_prompt_output, first_prompt_state, satisfaction_row, feedback_col]
1166
- )
1167
-
1168
- # Reset functionality
1169
- clear_btn.click(
1170
- fn=clear_all,
1171
- outputs=[
1172
- image_input, situation_input, goal_input,
1173
- analysis_output, final_prompt_output, satisfaction_row,
1174
- feedback_col, prewrite_col, prewrite_choices, feedback_input,
1175
- analysis_state, first_prompt_state
1176
- ]
1177
- )
1178
 
1179
  return interface
1180
 
1181
  # ### 5. Launch Configuration
1182
  if __name__ == "__main__":
1183
- # Create and launch the enhanced interface
1184
  demo = create_enhanced_interface()
1185
-
1186
- # Launch with optimal settings
1187
- demo.launch(
1188
- debug=True,
1189
- share=False,
1190
- inbrowser=True,
1191
- server_name="0.0.0.0",
1192
- server_port=7860,
1193
- show_error=True,
1194
- favicon_path=None,
1195
- ssl_verify=False,
1196
- quiet=False
1197
- )
 
13
  # Load environment variables
14
  load_dotenv()
15
 
16
+ # ### 1. Enhanced Configuration with Error Handling (No changes to logic)
17
  class APIManager:
18
  """Centralized API management with connection pooling and error handling."""
19
 
 
60
  # Global API manager instance
61
  api_manager = APIManager()
62
 
63
+ # ### 2. OPTIMIZED System Instructions (No changes to logic)
64
  VISION_SYSTEM_INSTRUCTION = """Extract key actionable insights from screenshots or descriptions in 3-4 bullet points:
65
 
66
  • UI/UX elements and layout structure
 
101
  OUTPUT FORMAT: Return ONLY valid JSON array of exactly 3 strings:
102
  ["Variation 1", "Variation 2", "Variation 3"]"""
103
 
104
+ # ### 3. Enhanced Processing Functions (No changes to logic)
105
  def analyze_screenshot(pil_image: Image.Image) -> str:
106
  """Enhanced screenshot analysis with concise output."""
107
  if not isinstance(pil_image, Image.Image):
108
  return "Error: Invalid image provided."
 
109
  if not api_manager.is_configured:
110
  return "Error: API not configured. Please check your API key."
 
111
  try:
112
+ model = api_manager.models.get('vision')
 
 
 
 
113
  response = model.generate_content([
114
  "Analyze this screenshot and extract key insights for prompt creation:",
115
  pil_image
116
  ])
 
117
  result = response.text.strip()
118
  return result if result else "No meaningful content detected in the screenshot."
 
119
  except Exception as e:
120
+ return f"Error in vision analysis: {str(e)}"
 
 
121
 
122
  def analyze_text_description(text: str) -> str:
123
  """Analyze text description for context insights."""
124
  if not text.strip():
125
  return "Error: No text provided for analysis."
 
126
  if not api_manager.is_configured:
127
  return "Error: API not configured."
 
128
  try:
129
+ model = api_manager.models.get('vision')
 
 
 
 
130
  response = model.generate_content(f"Analyze this description for prompt creation insights:\n\n{text}")
 
131
  result = response.text.strip()
132
  return result if result else "Unable to extract meaningful insights from the description."
 
133
  except Exception as e:
134
+ return f"Error in text analysis: {str(e)}"
 
 
135
 
136
  def initial_prompt_stream(analysis_text: str, goal: str):
137
  """Enhanced streaming prompt generation with concise output."""
138
  if not api_manager.is_configured:
139
  yield "Error: API not configured. Please check your API key."
140
  return
 
141
  try:
142
+ model = api_manager.models.get('initial')
 
 
 
 
 
143
  user_goal = goal.strip() if goal else "Create an optimized prompt based on the analysis"
144
+ prompt = f"""CONTEXT: {analysis_text}\n\nGOAL: {user_goal}\n\nCreate a concise, high-performance prompt that achieves this goal."""
 
 
 
 
 
 
145
  final_prompt_full = ""
 
146
  for chunk in model.generate_content(prompt, stream=True):
147
  if chunk.text:
148
  final_prompt_full += chunk.text
149
  yield final_prompt_full.strip()
 
150
  if not final_prompt_full.strip():
151
+ yield f"You are an expert assistant. {user_goal}. Provide clear, actionable guidance with specific examples."
 
 
152
  except Exception as e:
153
+ yield f"Error in prompt generation: {str(e)}"
 
 
154
 
155
  def refinement_prompt_stream(original_prompt: str, feedback: str):
156
  """Enhanced prompt refinement with concise output."""
157
  if not api_manager.is_configured:
158
  yield "Error: API not configured. Please check your API key."
159
  return
 
160
  try:
161
+ model = api_manager.models.get('refiner')
162
+ refinement_prompt = f"""ORIGINAL: {original_prompt}\n\nFEEDBACK: {feedback}\n\nRefine the prompt based on this feedback."""
 
 
 
 
 
 
 
 
 
163
  final_prompt_full = ""
164
  for chunk in model.generate_content(refinement_prompt, stream=True):
165
  if chunk.text:
166
  final_prompt_full += chunk.text
167
  yield final_prompt_full.strip()
 
168
  if not final_prompt_full.strip():
169
+ yield original_prompt
 
170
  except Exception as e:
171
+ yield f"Error in prompt refinement: {str(e)}"
 
 
172
 
173
  def rewrite_prompt_with_prewrite(original_prompt: str) -> List[str]:
174
  """Enhanced prompt rewriting with better JSON parsing."""
175
  if not api_manager.is_configured:
176
  return ["Error: API not configured. Please check your API key.", "", ""]
 
177
  try:
178
+ model = api_manager.models.get('rewriter')
179
+ rewrite_prompt = f"""ORIGINAL PROMPT: {original_prompt}\n\nGenerate 3 improved variations. Output ONLY JSON array of 3 strings."""
 
 
 
 
 
 
 
180
  response = model.generate_content(rewrite_prompt)
181
+ response_text = response.text.strip().replace("```json", "").replace("```", "").strip()
182
 
 
 
 
 
 
 
 
183
  if not response_text.startswith('['):
184
  import re
185
  json_match = re.search(r'\[.*\]', response_text, re.DOTALL)
186
  if json_match:
187
  response_text = json_match.group(0)
188
+
189
  variations = json.loads(response_text)
 
190
  if isinstance(variations, list) and len(variations) >= 1:
 
191
  while len(variations) < 3:
192
  variations.append("")
193
  return variations[:3]
 
194
  return ["Error: AI returned an invalid format.", "", ""]
 
195
  except json.JSONDecodeError:
196
  return ["Error: Could not parse AI response as JSON.", "", ""]
197
  except Exception as e:
198
+ return [f"Error in prompt rewriting: {str(e)}", "", ""]
 
 
199
 
200
+ # ### 4. REFACTORED Gradio Interface
201
  def create_enhanced_interface():
202
+ """Create the ultra-modern Gradio interface with glassmorphism and enhanced UX."""
203
 
204
+ # --- Start of UI/UX Refactoring: Custom CSS ---
205
  custom_css = """
206
+ /* Import Google Fonts for a modern look */
207
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
208
+
209
+ /* CSS Variables for easy theming and dark mode */
210
  :root {
211
+ --glass-bg: rgba(255, 255, 255, 0.5);
212
+ --glass-border: rgba(255, 255, 255, 0.3);
213
+ --text-primary: #1f2937;
214
+ --text-secondary: #4b5563;
215
+ --accent-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
216
+ --app-bg: #f0f2f5; /* Light mode background */
217
+ --card-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.1);
218
+ --card-radius: 24px;
219
+ --input-bg: rgba(255, 255, 255, 0.8);
220
+ }
221
+
222
+ /* Dark Mode Theme */
223
+ .dark {
224
+ --glass-bg: rgba(31, 41, 55, 0.4);
225
+ --glass-border: rgba(255, 255, 255, 0.1);
226
+ --text-primary: #e5e7eb;
227
+ --text-secondary: #9ca3af;
228
+ --app-bg: #111827; /* Dark mode background */
229
+ --card-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.2);
230
+ --input-bg: rgba(31, 41, 55, 0.5);
231
  }
232
 
233
+ /* Global Styles */
234
+ gradio-app {
235
+ background: var(--app-bg) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  font-family: 'Inter', sans-serif !important;
237
  }
238
+
239
+ /* Main Header */
240
+ .main-header { text-align: center; margin: 2rem auto 3rem auto; }
 
 
 
 
 
 
 
 
 
 
241
  .main-header h1 {
242
+ font-size: 3.5rem; font-weight: 700; letter-spacing: -0.02em;
243
+ background: var(--accent-gradient);
244
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent;
245
+ margin-bottom: 0.5rem;
 
 
 
 
246
  }
247
+ .main-header p { font-size: 1.2rem; color: var(--text-secondary); margin-top: 0; }
248
+
249
+ /* Status Indicators */
 
 
 
 
 
 
250
  .status-indicator {
251
+ display: flex; align-items: center; justify-content: center; gap: 0.75rem;
252
+ padding: 0.5rem 1rem; border-radius: 9999px; font-weight: 500;
253
+ margin: -1rem auto 1rem auto; max-width: 400px;
 
 
 
 
 
 
254
  backdrop-filter: blur(10px);
255
  }
256
+ .status-success { background: rgba(16, 185, 129, 0.1); border: 1px solid rgba(16, 185, 129, 0.2); color: #10b981; }
257
+ .status-error { background: rgba(239, 68, 68, 0.1); border: 1px solid rgba(239, 68, 68, 0.2); color: #ef4444; }
258
+ .status-indicator-dot { width: 10px; height: 10px; border-radius: 50%; animation: pulse 2s infinite; }
259
+ .status-success .status-indicator-dot { background-color: #10b981; }
260
+ .status-error .status-indicator-dot { background-color: #ef4444; animation: none; }
261
+ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
262
+
263
+ /* Glassmorphism Card Style */
 
 
 
 
 
 
 
 
264
  .glass-card {
265
  background: var(--glass-bg) !important;
266
+ border-radius: var(--card-radius) !important;
267
  border: 1px solid var(--glass-border) !important;
268
+ box-shadow: var(--card-shadow) !important;
269
+ backdrop-filter: blur(16px) !important;
270
+ -webkit-backdrop-filter: blur(16px) !important;
271
  padding: 2rem !important;
272
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  }
274
+ .glass-card:hover { transform: translateY(-4px); box-shadow: 0 12px 40px 0 rgba(31, 38, 135, 0.15); }
275
+ .dark .glass-card:hover { box-shadow: 0 12px 40px 0 rgba(0, 0, 0, 0.25); }
276
+
277
+
278
+ /* Section Headers */
279
+ .section-header {
280
+ font-size: 1.5rem; font-weight: 600; color: var(--text-primary);
281
+ margin-bottom: 1.5rem; padding-bottom: 0.75rem;
282
+ border-bottom: 1px solid var(--glass-border);
283
  }
284
+
285
+ /* Input & Textbox Styling */
286
+ .gradio-textbox textarea {
287
+ background: var(--input-bg) !important;
288
+ border: 1px solid var(--glass-border) !important;
289
+ border-radius: 12px !important; color: var(--text-primary) !important;
290
+ transition: border-color 0.3s ease, box-shadow 0.3s ease;
 
 
 
291
  }
292
+ .gradio-textbox textarea:focus {
293
+ border-color: #667eea !important;
294
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2) !important;
 
295
  }
296
+
297
  /* Image Upload Area */
298
  .image-upload {
299
  border: 2px dashed var(--glass-border) !important;
 
 
300
  background: var(--glass-bg) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  border-radius: 16px !important;
302
+ transition: border-color 0.3s ease, background-color 0.3s ease;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
  }
304
+ .image-upload:hover { border-color: #667eea !important; background: rgba(102, 126, 234, 0.1) !important; }
305
+
306
+ /* Button Styling with Hover Animations */
307
+ .gr-button { border-radius: 12px !important; font-weight: 600 !important; transition: all 0.2s ease-in-out !important; }
308
+ .btn-primary {
309
+ background: var(--accent-gradient) !important; color: white !important;
310
+ box-shadow: 0 4px 15px rgba(118, 75, 162, 0.2);
311
  }
312
+ .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(118, 75, 162, 0.35); }
313
+ .btn-secondary {
314
+ background: var(--glass-bg) !important; color: var(--text-primary) !important;
315
+ border: 1px solid var(--glass-border) !important;
316
  }
317
+ .btn-secondary:hover { background: rgba(255, 255, 255, 0.2) !important; transform: translateY(-2px); }
318
+ .dark .btn-secondary:hover { background: rgba(255, 255, 255, 0.1) !important; }
319
 
320
+ /* Output Area Styling */
321
+ .prompt-output, .analysis-output { font-size: 1rem !important; line-height: 1.6 !important; }
322
+ .prompt-output textarea { font-family: 'JetBrains Mono', monospace !important; }
 
 
323
 
324
+ /* Radio Button Customization */
325
+ .gr-radio {
326
+ border: none !important; background: none !important;
327
+ gap: 1rem !important;
328
  }
329
+ .gr-radio > .gr-form {
330
+ border: 1px solid var(--glass-border) !important;
331
+ background: var(--glass-bg) !important;
332
+ border-radius: 12px !important;
333
+ transition: border-color 0.3s, background-color 0.3s;
334
  }
335
+ .gr-radio > .gr-form:hover {
336
+ border-color: #764ba2 !important;
 
337
  }
338
+ .gr-radio > .gr-form.selected {
339
+ border-color: #667eea !important;
340
+ background: rgba(102, 126, 234, 0.15) !important;
341
  }
342
 
343
+ /* General Animations */
344
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
345
+ .fade-in { animation: fadeIn 0.5s ease-out forwards; }
 
 
 
 
346
  """
347
+ # --- End of UI/UX Refactoring: Custom CSS ---
348
+
349
+ # --- Start of UI/UX Refactoring: Gradio Theme ---
350
  theme = gr.themes.Soft(
351
+ primary_hue=gr.themes.colors.purple,
352
+ secondary_hue=gr.themes.colors.indigo,
353
  neutral_hue=gr.themes.colors.slate,
354
  font=(gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"),
355
  font_mono=(gr.themes.GoogleFont("JetBrains Mono"), "ui-monospace", "Consolas", "monospace")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356
  )
357
+ # --- End of UI/UX Refactoring: Gradio Theme ---
358
+
359
+ with gr.Blocks(theme=theme, css=custom_css, title="SuperKontext AI") as interface:
360
  # State management
361
  analysis_state = gr.State()
362
  first_prompt_state = gr.State()
363
+
364
+ # --- UI REFACTOR: Header and Status Indicator ---
365
+ gr.HTML("""
366
+ <div class="main-header fade-in">
367
+ <h1>SuperKontext AI</h1>
368
+ <p>Transform ideas into high-performance prompts with AI context analysis.</p>
369
+ </div>
370
+ """)
371
+
372
+ if api_manager.is_configured:
373
+ gr.HTML("""
374
+ <div class="status-indicator status-success fade-in">
375
+ <div class="status-indicator-dot"></div>
376
+ <span>API Connected & Ready</span>
377
+ </div>""")
378
+ else:
379
+ gr.HTML("""
380
+ <div class="status-indicator status-error fade-in">
381
+ <div class="status-indicator-dot"></div>
382
+ <span>API Configuration Error: Check GEMINI_API_KEY</span>
383
+ </div>""")
384
+
385
+ # --- UI REFACTOR: Main Two-Column Layout ---
386
+ with gr.Row(equal_height=False, variant='panel'):
387
+ # --- Input Column ---
 
 
 
 
 
 
388
  with gr.Column(scale=5, min_width=500):
389
+ with gr.Group(elem_classes=["glass-card", "fade-in"]):
390
+ gr.HTML('<div class="section-header">1. Provide Context</div>')
391
 
392
+ image_input = gr.Image(
393
+ type="pil", label="Upload a Screenshot (Optional)", sources=['upload'],
394
+ elem_classes=["image-upload"]
395
+ )
 
 
 
 
 
 
 
396
 
397
+ situation_input = gr.Textbox(
398
+ label="Or Describe Your Task / Goal",
399
+ placeholder="e.g., 'Draft a marketing email for a new SaaS feature launch.'",
400
+ lines=5,
401
+ max_lines=15
402
+ )
 
 
 
 
403
 
404
+ with gr.Accordion("Advanced: Specify a Detailed Goal (Optional)", open=False):
 
405
  goal_input = gr.Textbox(
406
+ label="Define the exact output format or constraints",
407
+ placeholder="e.g., 'The email should be under 150 words and have 3 catchy subject line options.'",
408
+ lines=2
 
409
  )
410
 
 
411
  with gr.Row():
412
+ clear_btn = gr.Button("Clear", elem_classes=["btn-secondary"])
413
+ submit_btn = gr.Button("Generate Prompt", variant="primary", elem_classes=["btn-primary"])
414
+
415
+ # --- Output Column ---
 
 
 
 
 
 
 
 
 
416
  with gr.Column(scale=7, min_width=700):
417
+ with gr.Group(elem_classes=["glass-card", "fade-in"]):
418
+ gr.HTML('<div class="section-header">2. Context Analysis</div>')
419
  analysis_output = gr.Textbox(
420
+ label="AI-Generated Insights",
421
+ placeholder="Key insights from your input will appear here...",
422
+ lines=5, interactive=False, show_copy_button=True,
 
 
423
  elem_classes=["analysis-output"]
424
  )
425
 
426
+ with gr.Group(elem_classes=["glass-card", "fade-in"]):
427
+ gr.HTML('<div class="section-header">3. Optimized Prompt</div>')
428
  final_prompt_output = gr.Textbox(
429
+ label="Your Ready-to-Use Prompt",
430
+ placeholder="The final, optimized prompt will be generated here...",
431
+ lines=8, interactive=True, show_copy_button=True,
 
 
432
  elem_classes=["prompt-output"]
433
  )
434
 
435
+ # --- UI REFACTOR: Refinement Section ---
436
+ with gr.Row(visible=False) as refinement_area:
437
  with gr.Column():
438
+ with gr.Group(elem_classes=["glass-card", "fade-in"]):
439
+ gr.HTML('<div class="section-header">4. Refine Your Prompt</div>')
440
+ gr.Markdown("Is the prompt good? Or would you like to improve it?", elem_id="refine-md")
441
+
442
+ with gr.Row():
443
+ like_btn = gr.Button("👍 It's Perfect!", elem_classes=["btn-secondary"])
444
+ auto_refine_btn = gr.Button("🤖 Suggest Alternatives", elem_classes=["btn-secondary"])
445
+ dislike_btn = gr.Button("✍️ Custom Feedback", elem_classes=["btn-secondary"])
446
+
447
+ with gr.Column(visible=False) as prewrite_col:
448
+ with gr.Group(elem_classes=["glass-card", "fade-in"]):
449
+ gr.HTML('<div class="section-header">Choose an Alternative</div>')
450
+ prewrite_choices = gr.Radio(
451
+ label="Select the best variation:", type="value", interactive=True
452
+ )
453
  with gr.Row():
454
+ select_version_btn = gr.Button("✅ Use This Version", elem_classes=["btn-primary"])
455
+
456
+ with gr.Column(visible=False) as feedback_col:
457
+ with gr.Group(elem_classes=["glass-card", "fade-in"]):
458
+ gr.HTML('<div class="section-header">Provide Custom Feedback</div>')
459
+ feedback_input = gr.Textbox(
460
+ label="How can we improve the prompt?",
461
+ placeholder="e.g., 'Make it more formal', 'Add a step-by-step example', 'Focus on the benefit for developers'"
462
+ )
463
+ refine_btn = gr.Button("✨ Refine with Feedback", elem_classes=["btn-primary"])
464
+
465
+ # ### Enhanced Interface Functions (Logic mostly unchanged, just updating UI state)
466
+ def run_analysis_and_generation(pil_image: Optional[Image.Image], situation_text: str, goal: str):
467
+ # --- UI FEEDBACK: Show processing status ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  yield {
469
+ analysis_output: "🔍 Analyzing context...",
470
+ final_prompt_output: "",
471
+ refinement_area: gr.update(visible=False),
472
  feedback_col: gr.update(visible=False),
473
  prewrite_col: gr.update(visible=False),
 
 
474
  }
475
+
 
476
  if not api_manager.is_configured:
477
+ yield {analysis_output: "❌ Error: API Key not configured. Check environment variables."}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
478
  return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
479
 
480
+ if pil_image is None and not situation_text.strip():
481
+ yield {analysis_output: "⚠️ Please provide a screenshot or a description to begin."}
 
 
 
 
 
 
482
  return
483
 
484
+ # Analysis Step
485
+ if pil_image and situation_text.strip():
486
+ analysis_text = f"SCREENSHOT ANALYSIS:\n{analyze_screenshot(pil_image)}\n\nUSER DESCRIPTION:\n{situation_text.strip()}"
487
+ elif pil_image:
488
+ analysis_text = analyze_screenshot(pil_image)
489
+ else:
490
+ analysis_text = analyze_text_description(situation_text.strip())
491
+
492
+ # --- UI FEEDBACK: Show analysis results ---
493
  yield {
494
+ analysis_output: analysis_text,
495
+ analysis_state: analysis_text,
496
+ final_prompt_output: "🚀 Generating optimized prompt..."
497
  }
498
 
499
+ # Generation Step
500
  final_prompt_full = ""
501
+ for chunk in initial_prompt_stream(analysis_text, goal):
502
  final_prompt_full = chunk
503
  yield {final_prompt_output: final_prompt_full}
504
 
505
+ # --- UI FEEDBACK: Final state after generation ---
506
  yield {
507
  final_prompt_output: final_prompt_full,
508
  first_prompt_state: final_prompt_full,
509
+ refinement_area: gr.update(visible=True) # Show refinement options
510
  }
511
 
512
  def handle_auto_refine(original_prompt: str):
513
+ variations = [v for v in rewrite_prompt_with_prewrite(original_prompt) if v.strip()]
514
+ if not variations:
515
+ return { prewrite_col: gr.update(visible=False) }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
516
 
517
  return {
518
  prewrite_col: gr.update(visible=True),
519
+ prewrite_choices: gr.update(choices=variations, value=variations[0]),
520
+ refinement_area: gr.update(visible=False)
 
521
  }
522
 
523
  def select_rewritten_prompt(selected_prompt: str):
 
 
 
 
 
 
 
 
 
524
  return {
525
  final_prompt_output: selected_prompt,
526
  first_prompt_state: selected_prompt,
527
+ refinement_area: gr.update(visible=True),
528
  prewrite_col: gr.update(visible=False)
529
  }
530
 
531
+ def show_manual_feedback():
 
532
  return {
533
  feedback_col: gr.update(visible=True),
534
+ refinement_area: gr.update(visible=False)
 
535
  }
536
 
537
+ def hide_refinement():
 
538
  return {
539
+ refinement_area: gr.update(visible=False),
540
  feedback_col: gr.update(visible=False),
541
  prewrite_col: gr.update(visible=False)
542
  }
543
 
544
  def refine_with_manual_feedback(original_prompt: str, feedback: str):
 
545
  if not feedback.strip():
546
+ yield { final_prompt_output: original_prompt }
 
 
 
 
 
547
  return
548
 
549
  yield {
550
+ final_prompt_output: "🛠️ Refining prompt with your feedback...",
551
+ feedback_col: gr.update(visible=False)
552
  }
553
+
554
  final_prompt_full = ""
555
  for chunk in refinement_prompt_stream(original_prompt, feedback):
556
  final_prompt_full = chunk
557
+ yield { final_prompt_output: final_prompt_full }
 
 
 
558
 
559
  yield {
560
+ first_prompt_state: final_prompt_full,
561
+ refinement_area: gr.update(visible=True)
562
  }
563
 
564
  def clear_all():
 
565
  return {
566
+ image_input: None, situation_input: "", goal_input: "",
567
+ analysis_output: "", final_prompt_output: "",
568
+ refinement_area: gr.update(visible=False),
569
+ feedback_col: gr.update(visible=False), prewrite_col: gr.update(visible=False),
570
+ feedback_input: "", analysis_state: None, first_prompt_state: None
 
 
 
 
 
 
 
571
  }
572
 
573
+ # ### Event Handlers
 
 
 
 
 
 
 
 
574
  submit_btn.click(
575
+ fn=run_analysis_and_generation,
576
+ inputs=[image_input, situation_input, goal_input],
577
+ outputs=[analysis_output, final_prompt_output, refinement_area, feedback_col, prewrite_col, analysis_state, first_prompt_state]
 
 
 
 
 
 
578
  )
579
+ clear_btn.click(fn=clear_all, outputs=list(clear_all().keys()))
580
 
581
+ like_btn.click(fn=hide_refinement, outputs=[refinement_area, feedback_col, prewrite_col])
582
+ auto_refine_btn.click(fn=handle_auto_refine, inputs=[first_prompt_state], outputs=[prewrite_col, prewrite_choices, refinement_area])
583
+ dislike_btn.click(fn=show_manual_feedback, outputs=[feedback_col, refinement_area])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
584
 
585
+ select_version_btn.click(fn=select_rewritten_prompt, inputs=[prewrite_choices], outputs=[final_prompt_output, first_prompt_state, refinement_area, prewrite_col])
 
 
 
 
 
 
 
 
 
 
586
 
587
+ refine_btn.click(fn=refine_with_manual_feedback, inputs=[first_prompt_state, feedback_input], outputs=[final_prompt_output, first_prompt_state, refinement_area, feedback_col])
588
+ feedback_input.submit(fn=refine_with_manual_feedback, inputs=[first_prompt_state, feedback_input], outputs=[final_prompt_output, first_prompt_state, refinement_area, feedback_col])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
 
590
  return interface
591
 
592
  # ### 5. Launch Configuration
593
  if __name__ == "__main__":
 
594
  demo = create_enhanced_interface()
595
+ demo.launch(debug=True, inbrowser=True)