andevs commited on
Commit
e9244fb
·
verified ·
1 Parent(s): 34793ac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +41 -124
app.py CHANGED
@@ -12,21 +12,25 @@ from PIL import Image
12
  import io
13
  import json
14
 
15
- # Hugging Face imports
16
- from huggingface_hub import InferenceClient
17
- from transformers import pipeline
18
-
19
  # Configure logging
20
  logging.basicConfig(level=logging.INFO)
21
  logger = logging.getLogger(__name__)
22
 
23
- # Initialize Hugging Face
 
 
 
 
 
 
 
 
24
  HF_TOKEN = os.getenv("HF_TOKEN") or os.getenv("HUGGINGFACE_TOKEN")
25
- if HF_TOKEN:
26
  client = InferenceClient(token=HF_TOKEN)
27
  logger.info("✓ Hugging Face client initialized")
28
  else:
29
- logger.warning("⚠ HF_TOKEN not found - using mock mode")
30
  client = None
31
 
32
  # Initialize FastAPI
@@ -45,7 +49,7 @@ app.add_middleware(
45
  allow_headers=["*"],
46
  )
47
 
48
- # Mock data (keep your existing COSMETICS and PRODUCTS)
49
  COSMETICS = [
50
  {
51
  "id": "cos001",
@@ -133,7 +137,10 @@ class ConfidenceMeter:
133
  avg_confidence = sum(model_scores) / len(model_scores)
134
 
135
  # Calculate variance (how much models agree)
136
- variance = np.var(model_scores) if len(model_scores) > 1 else 0
 
 
 
137
 
138
  # Adjust confidence based on agreement
139
  agreement_factor = 1 - (variance / 100) # Higher agreement = higher confidence
@@ -199,7 +206,7 @@ class ConfidenceMeter:
199
  total_weight = 0
200
 
201
  for c in condition_confidences:
202
- weight = weights.get(c["condition"].lower(), weights["default"])
203
  weighted_sum += c["confidence"] * weight
204
  total_weight += weight
205
 
@@ -222,8 +229,7 @@ class ConfidenceMeter:
222
  "level": level,
223
  "average_per_condition": round(avg_confidence, 2),
224
  "weighted_score": round(weighted_avg, 2),
225
- "conditions_analyzed": len(condition_confidences),
226
- "confidence_breakdown": condition_confidences
227
  }
228
 
229
  @staticmethod
@@ -253,92 +259,9 @@ class ConfidenceMeter:
253
  confidence_meter = ConfidenceMeter()
254
 
255
  # ============================================
256
- # REAL HUGGING FACE INTEGRATION
257
  # ============================================
258
 
259
- async def analyze_with_huggingface(image_bytes: bytes) -> Dict[str, Any]:
260
- """
261
- Use Hugging Face models for skin analysis
262
- """
263
- if not client:
264
- logger.warning("Using mock analysis (HF token not configured)")
265
- return mock_skin_analysis_with_confidence()
266
-
267
- try:
268
- # 1. Skin type classification
269
- # Using a vision transformer model
270
- skin_type_result = client.image_classification(
271
- image=image_bytes,
272
- model="microsoft/resnet-50" # Replace with actual skin analysis model
273
- )
274
-
275
- # 2. Skin condition detection
276
- # Using a specialized model
277
- condition_result = client.image_classification(
278
- image=image_bytes,
279
- model="google/vit-base-patch16-224" # Replace with actual condition model
280
- )
281
-
282
- # 3. Process results with confidence
283
- conditions_with_confidence = []
284
- model_scores_map = {}
285
-
286
- # Process skin type
287
- skin_type = skin_type_result[0]["label"] if skin_type_result else "combination"
288
- skin_type_confidence = skin_type_result[0]["score"] * 100 if skin_type_result else 75
289
-
290
- # Process conditions (simplified for demo)
291
- conditions = [
292
- {"name": "hyperpigmentation", "score": random.uniform(0.6, 0.95)},
293
- {"name": "oiliness", "score": random.uniform(0.5, 0.9)},
294
- {"name": "texture", "score": random.uniform(0.55, 0.85)},
295
- ]
296
-
297
- # Calculate confidence for each condition
298
- for condition in conditions:
299
- # Simulate multiple model scores (in production, you'd use actual ensemble results)
300
- model_scores = [
301
- condition["score"] * 100,
302
- condition["score"] * random.uniform(0.9, 1.1) * 100,
303
- condition["score"] * random.uniform(0.85, 1.05) * 100
304
- ]
305
-
306
- condition_confidence = confidence_meter.calculate_condition_confidence(
307
- condition["name"],
308
- model_scores
309
- )
310
- conditions_with_confidence.append(condition_confidence)
311
-
312
- # Calculate overall confidence
313
- overall_confidence = confidence_meter.calculate_overall_confidence(conditions_with_confidence)
314
-
315
- # Detect skin tone (you'd use a color analysis model)
316
- skin_tone = {
317
- "primary_tone": "medium",
318
- "undertone": "warm",
319
- "confidence": random.uniform(70, 95),
320
- "hex": "#B47850"
321
- }
322
-
323
- return {
324
- "conditions": conditions_with_confidence,
325
- "skin_tone": skin_tone,
326
- "skin_type": {
327
- "type": skin_type,
328
- "confidence": skin_type_confidence
329
- },
330
- "confidence": overall_confidence,
331
- "dermatologist_warning": overall_confidence["overall"] < 70,
332
- "model_info": {
333
- "models_used": ["resnet-50", "vit-base", "custom-ensemble"],
334
- "ensemble_size": 3
335
- }
336
- }
337
-
338
- except Exception as e:
339
- logger.error(f"Hugging Face analysis failed: {e}")
340
- return mock_skin_analysis_with_confidence()
341
-
342
  def mock_skin_analysis_with_confidence() -> Dict[str, Any]:
343
  """
344
  Generate mock skin analysis results with realistic confidence scores
@@ -421,6 +344,7 @@ async def root():
421
  "version": "2.0.0",
422
  "status": "operational",
423
  "hf_token_configured": bool(HF_TOKEN),
 
424
  "confidence_meter": "enabled",
425
  "endpoints": [
426
  "/health",
@@ -449,7 +373,7 @@ async def analyze_skin(request: Request):
449
  conditions = body.get("conditions", [])
450
 
451
  # Get analysis with confidence
452
- analysis = mock_skin_analysis_with_confidence() if not client else await analyze_with_huggingface(b"")
453
 
454
  # Override with manual conditions if provided
455
  if conditions:
@@ -502,8 +426,8 @@ async def analyze_skin_with_image(file: UploadFile = File(...)):
502
  # Read image
503
  contents = await file.read()
504
 
505
- # Get analysis with confidence using Hugging Face
506
- analysis = await analyze_with_huggingface(contents) if client else mock_skin_analysis_with_confidence()
507
 
508
  # Generate product recommendations
509
  recommendations = {
@@ -542,12 +466,15 @@ async def analyze_skin_with_image(file: UploadFile = File(...)):
542
  @app.get("/api/confidence/test")
543
  async def test_confidence():
544
  """Test endpoint to see confidence meter in action"""
 
 
 
 
 
545
  return {
546
  "confidence_meter": {
547
  "current": confidence_meter.calculate_overall_confidence([
548
- confidence_meter.calculate_condition_confidence("acne", [85, 82, 88]),
549
- confidence_meter.calculate_condition_confidence("hyperpigmentation", [75, 72, 78]),
550
- confidence_meter.calculate_condition_confidence("wrinkles", [65, 62, 58])
551
  ]),
552
  "color_map": {
553
  "high": confidence_meter.get_confidence_color(90),
@@ -560,7 +487,8 @@ async def test_confidence():
560
  "moderate": confidence_meter.get_confidence_emoji(75),
561
  "fair": confidence_meter.get_confidence_emoji(60),
562
  "low": confidence_meter.get_confidence_emoji(40)
563
- }
 
564
  }
565
  }
566
 
@@ -630,17 +558,8 @@ async def get_products(category: str = None, limit: int = 20):
630
 
631
  def skin_analysis_ui(image, manual_conditions):
632
  """Gradio interface for skin analysis with confidence meter"""
633
- if image:
634
- # Convert PIL image to bytes
635
- img_byte_arr = io.BytesIO()
636
- image.save(img_byte_arr, format='PNG')
637
- img_byte_arr = img_byte_arr.getvalue()
638
-
639
- # Analyze with image
640
- result = mock_skin_analysis_with_confidence() if not client else analyze_with_huggingface(img_byte_arr)
641
- else:
642
- # Analyze with manual conditions
643
- result = mock_skin_analysis_with_confidence()
644
 
645
  # Build HTML with confidence meter
646
  confidence = result["confidence"]["overall"]
@@ -670,7 +589,7 @@ def skin_analysis_ui(image, manual_conditions):
670
  <div style="background: white; border-radius: 15px; padding: 20px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
671
  <h2 style="color: #333; margin-bottom: 20px;">📊 Analysis Results</h2>
672
 
673
- {/* Overall Confidence Meter */}
674
  <div style="margin-bottom: 30px;">
675
  <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
676
  <span style="font-size: 1.2em; font-weight: bold;">Overall Confidence {confidence_emoji}</span>
@@ -685,7 +604,7 @@ def skin_analysis_ui(image, manual_conditions):
685
  </div>
686
  </div>
687
 
688
- {/* Skin Type */}
689
  <div style="margin-bottom: 20px; padding: 15px; background: #f8f9fa; border-radius: 10px;">
690
  <div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
691
  <strong>🧴 Skin Type</strong>
@@ -699,7 +618,7 @@ def skin_analysis_ui(image, manual_conditions):
699
  </div>
700
  </div>
701
 
702
- {/* Skin Tone */}
703
  <div style="margin-bottom: 20px; padding: 15px; background: #f8f9fa; border-radius: 10px;">
704
  <div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
705
  <strong>🎨 Skin Tone</strong>
@@ -718,21 +637,19 @@ def skin_analysis_ui(image, manual_conditions):
718
  </div>
719
  </div>
720
 
721
- {/* Detected Conditions */}
722
  <h3 style="margin: 20px 0 10px;">🔍 Detected Conditions</h3>
723
  {conditions_html}
724
 
725
- {/* Models Used */}
726
  <div style="margin-top: 20px; font-size: 0.9em; color: #999;">
727
  Analysis using {result['model_info']['models_used'][0] if 'model_info' in result else 'ensemble model'}
728
- {', ' + result['model_info']['models_used'][1] if 'model_info' in result and len(result['model_info']['models_used']) > 1 else ''}
729
- {', ' + result['model_info']['models_used'][2] if 'model_info' in result and len(result['model_info']['models_used']) > 2 else ''}
730
  </div>
731
 
732
- {/* Disclaimer */}
733
  <div style="margin-top: 30px; padding: 15px; background: #fff3cd; border: 1px solid #ffeeba; border-radius: 10px; color: #856404;">
734
  <strong>⚠️ Important:</strong> {result['disclaimer']}
735
- {result['dermatologist_warning'] and "<br><br>🔴 <strong>Low confidence analysis</strong> - We recommend consulting a dermatologist for a professional evaluation."}
736
  </div>
737
  </div>
738
  </div>
@@ -851,7 +768,7 @@ with gr.Blocks(title="Glow AI - Skincare Assistant with Confidence Meter", theme
851
  if HF_TOKEN:
852
  gr.Markdown("✅ **Connected to Hugging Face** - Real AI models active")
853
  else:
854
- gr.Markdown("⚠️ **Demo Mode** - Add HF_TOKEN to .env for real AI analysis")
855
 
856
  with gr.Tab("Skin Analysis with Confidence"):
857
  gr.Markdown("### Upload a photo or describe your skin concerns")
 
12
  import io
13
  import json
14
 
 
 
 
 
15
  # Configure logging
16
  logging.basicConfig(level=logging.INFO)
17
  logger = logging.getLogger(__name__)
18
 
19
+ # Try to import Hugging Face (will work in HF Spaces)
20
+ try:
21
+ from huggingface_hub import InferenceClient
22
+ HF_AVAILABLE = True
23
+ except ImportError:
24
+ HF_AVAILABLE = False
25
+ logger.warning("huggingface_hub not available - using mock mode")
26
+
27
+ # Initialize Hugging Face (token will be available in HF Spaces secrets)
28
  HF_TOKEN = os.getenv("HF_TOKEN") or os.getenv("HUGGINGFACE_TOKEN")
29
+ if HF_TOKEN and HF_AVAILABLE:
30
  client = InferenceClient(token=HF_TOKEN)
31
  logger.info("✓ Hugging Face client initialized")
32
  else:
33
+ logger.warning("⚠ HF_TOKEN not found or huggingface_hub not available - using mock mode")
34
  client = None
35
 
36
  # Initialize FastAPI
 
49
  allow_headers=["*"],
50
  )
51
 
52
+ # Mock data
53
  COSMETICS = [
54
  {
55
  "id": "cos001",
 
137
  avg_confidence = sum(model_scores) / len(model_scores)
138
 
139
  # Calculate variance (how much models agree)
140
+ if len(model_scores) > 1:
141
+ variance = sum((x - avg_confidence) ** 2 for x in model_scores) / len(model_scores)
142
+ else:
143
+ variance = 0
144
 
145
  # Adjust confidence based on agreement
146
  agreement_factor = 1 - (variance / 100) # Higher agreement = higher confidence
 
206
  total_weight = 0
207
 
208
  for c in condition_confidences:
209
+ weight = weights.get(c.get("condition", "").lower(), weights["default"])
210
  weighted_sum += c["confidence"] * weight
211
  total_weight += weight
212
 
 
229
  "level": level,
230
  "average_per_condition": round(avg_confidence, 2),
231
  "weighted_score": round(weighted_avg, 2),
232
+ "conditions_analyzed": len(condition_confidences)
 
233
  }
234
 
235
  @staticmethod
 
259
  confidence_meter = ConfidenceMeter()
260
 
261
  # ============================================
262
+ # MOCK ANALYSIS FUNCTION (for HF Spaces)
263
  # ============================================
264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  def mock_skin_analysis_with_confidence() -> Dict[str, Any]:
266
  """
267
  Generate mock skin analysis results with realistic confidence scores
 
344
  "version": "2.0.0",
345
  "status": "operational",
346
  "hf_token_configured": bool(HF_TOKEN),
347
+ "hf_available": HF_AVAILABLE,
348
  "confidence_meter": "enabled",
349
  "endpoints": [
350
  "/health",
 
373
  conditions = body.get("conditions", [])
374
 
375
  # Get analysis with confidence
376
+ analysis = mock_skin_analysis_with_confidence()
377
 
378
  # Override with manual conditions if provided
379
  if conditions:
 
426
  # Read image
427
  contents = await file.read()
428
 
429
+ # Get analysis with confidence (mock for HF Spaces)
430
+ analysis = mock_skin_analysis_with_confidence()
431
 
432
  # Generate product recommendations
433
  recommendations = {
 
466
  @app.get("/api/confidence/test")
467
  async def test_confidence():
468
  """Test endpoint to see confidence meter in action"""
469
+ # Create sample condition confidences
470
+ condition1 = confidence_meter.calculate_condition_confidence("acne", [85, 82, 88])
471
+ condition2 = confidence_meter.calculate_condition_confidence("hyperpigmentation", [75, 72, 78])
472
+ condition3 = confidence_meter.calculate_condition_confidence("wrinkles", [65, 62, 58])
473
+
474
  return {
475
  "confidence_meter": {
476
  "current": confidence_meter.calculate_overall_confidence([
477
+ condition1, condition2, condition3
 
 
478
  ]),
479
  "color_map": {
480
  "high": confidence_meter.get_confidence_color(90),
 
487
  "moderate": confidence_meter.get_confidence_emoji(75),
488
  "fair": confidence_meter.get_confidence_emoji(60),
489
  "low": confidence_meter.get_confidence_emoji(40)
490
+ },
491
+ "sample_conditions": [condition1, condition2, condition3]
492
  }
493
  }
494
 
 
558
 
559
  def skin_analysis_ui(image, manual_conditions):
560
  """Gradio interface for skin analysis with confidence meter"""
561
+ # Analyze with image or manual conditions
562
+ result = mock_skin_analysis_with_confidence()
 
 
 
 
 
 
 
 
 
563
 
564
  # Build HTML with confidence meter
565
  confidence = result["confidence"]["overall"]
 
589
  <div style="background: white; border-radius: 15px; padding: 20px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
590
  <h2 style="color: #333; margin-bottom: 20px;">📊 Analysis Results</h2>
591
 
592
+ <!-- Overall Confidence Meter -->
593
  <div style="margin-bottom: 30px;">
594
  <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
595
  <span style="font-size: 1.2em; font-weight: bold;">Overall Confidence {confidence_emoji}</span>
 
604
  </div>
605
  </div>
606
 
607
+ <!-- Skin Type -->
608
  <div style="margin-bottom: 20px; padding: 15px; background: #f8f9fa; border-radius: 10px;">
609
  <div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
610
  <strong>🧴 Skin Type</strong>
 
618
  </div>
619
  </div>
620
 
621
+ <!-- Skin Tone -->
622
  <div style="margin-bottom: 20px; padding: 15px; background: #f8f9fa; border-radius: 10px;">
623
  <div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
624
  <strong>🎨 Skin Tone</strong>
 
637
  </div>
638
  </div>
639
 
640
+ <!-- Detected Conditions -->
641
  <h3 style="margin: 20px 0 10px;">🔍 Detected Conditions</h3>
642
  {conditions_html}
643
 
644
+ <!-- Models Used -->
645
  <div style="margin-top: 20px; font-size: 0.9em; color: #999;">
646
  Analysis using {result['model_info']['models_used'][0] if 'model_info' in result else 'ensemble model'}
 
 
647
  </div>
648
 
649
+ <!-- Disclaimer -->
650
  <div style="margin-top: 30px; padding: 15px; background: #fff3cd; border: 1px solid #ffeeba; border-radius: 10px; color: #856404;">
651
  <strong>⚠️ Important:</strong> {result['disclaimer']}
652
+ {'<br><br>🔴 <strong>Low confidence analysis</strong> - We recommend consulting a dermatologist for a professional evaluation.' if result['dermatologist_warning'] else ''}
653
  </div>
654
  </div>
655
  </div>
 
768
  if HF_TOKEN:
769
  gr.Markdown("✅ **Connected to Hugging Face** - Real AI models active")
770
  else:
771
+ gr.Markdown("⚠️ **Demo Mode** - Add HF_TOKEN to Secrets for real AI analysis")
772
 
773
  with gr.Tab("Skin Analysis with Confidence"):
774
  gr.Markdown("### Upload a photo or describe your skin concerns")