#!/usr/bin/env python3 import torch from transformers import ViTImageProcessor, ViTForImageClassification from PIL import Image import gradio as gr import numpy as np from typing import Dict, Tuple, Optional import logging from pathlib import Path import spaces from gradio_client import Client import json # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Medical-grade CSS styling medical_css = """ .gradio-container { background: linear-gradient(135deg, #e8f4f8 0%, #d1e8e4 50%, #c3d9e1 100%); font-family: 'Inter', 'Segoe UI', sans-serif; } .main-header { background: linear-gradient(135deg, #2c5282 0%, #2d3748 100%); color: white; padding: 2rem; border-radius: 15px; margin-bottom: 2rem; box-shadow: 0 10px 30px rgba(0,0,0,0.1); } .diagnosis-card { background: white; border-radius: 15px; padding: 1.5rem; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 4px solid #3182ce; margin: 1rem 0; } .result-container { background: linear-gradient(to right, #f7fafc, #edf2f7); border-radius: 12px; padding: 1.5rem; margin-top: 1rem; border: 1px solid #cbd5e0; } .confidence-bar { background: linear-gradient(90deg, #48bb78 0%, #38a169 100%); height: 8px; border-radius: 4px; transition: width 0.5s ease; } .medical-badge { display: inline-block; padding: 0.5rem 1rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 25px; font-weight: 600; font-size: 0.9rem; margin: 0.25rem; } .warning-box { background: #fff5f5; border-left: 4px solid #fc8181; padding: 1rem; border-radius: 8px; margin: 1rem 0; } .info-box { background: #ebf8ff; border-left: 4px solid #4299e1; padding: 1rem; border-radius: 8px; margin: 1rem 0; } .button-primary { background: linear-gradient(135deg, #3182ce 0%, #2c5282 100%); color: white; border: none; padding: 0.75rem 2rem; border-radius: 8px; font-weight: 600; cursor: pointer; transition: transform 0.2s; } .button-primary:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(49, 130, 206, 0.3); } .status-indicator { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 8px; animation: pulse 2s infinite; } .status-ready { background-color: #48bb78; } .status-processing { background-color: #ed8936; } .status-error { background-color: #f56565; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(72, 187, 120, 0.7); } 70% { box-shadow: 0 0 0 10px rgba(72, 187, 120, 0); } 100% { box-shadow: 0 0 0 0 rgba(72, 187, 120, 0); } } .diagnosis-severity { padding: 0.25rem 0.75rem; border-radius: 15px; font-size: 0.85rem; font-weight: 600; display: inline-block; margin-left: 0.5rem; } .severity-low { background: #c6f6d5; color: #22543d; } .severity-medium { background: #fed7aa; color: #7c2d12; } .severity-high { background: #fed7d7; color: #742a2a; } """ class MedicalSkinDiagnosisSystem: """Medical-grade skin disease diagnosis system with GPT-OSS integration.""" def __init__(self, model_name: str = '0xnu/skincare-detection'): """Initialize the diagnosis system.""" self.model_name = model_name self.processor = None self.model = None self.id2label = None self.device = "cuda" if torch.cuda.is_available() else "cpu" self.gpt_client = None self.load_model() # Load disease database AFTER model is loaded to get actual classes self.disease_info_db = self._load_disease_database() self._init_gpt_client() def _load_disease_database(self) -> Dict: """Load comprehensive disease information database based on actual model classes.""" # Get actual classes from the loaded model if self.model and self.id2label: logger.info(f"Loaded classes from model: {list(self.id2label.values())}") # Comprehensive database covering common skin conditions found in skincare datasets database = { # Acne and related conditions "acne": { "name_ko": "여드름", "severity": "low", "description_ko": "모낭과 피지선의 만성 염증성 질환으로, 면포, 구진, 농포, 결절 등이 나타납니다.", "treatment_ko": "국소 레티노이드, 벤조일 퍼옥사이드, 항생제 연고, 심한 경우 이소트레티노인 경구 복용", "symptoms_ko": "블랙헤드, 화이트헤드, 붉은 구진, 농포, 통증성 결절" }, "blackhead": { "name_ko": "블랙헤드/개방면포", "severity": "low", "description_ko": "모공이 피지와 각질로 막혀 검게 보이는 개방성 면포입니다.", "treatment_ko": "살리실산, BHA 제품, 레티노이드, 정기적인 각질 제거", "symptoms_ko": "모공 내 검은 점, 주로 T존에 발생" }, "whitehead": { "name_ko": "화이트헤드/폐쇄면포", "severity": "low", "description_ko": "피지와 각질이 모공을 막아 생기는 폐쇄성 면포입니다.", "treatment_ko": "레티노이드, AHA/BHA 제품, 부드러운 각질 제거", "symptoms_ko": "피부 표면의 작은 흰색 돌기" }, "papule": { "name_ko": "구진", "severity": "low", "description_ko": "염증이 있는 작은 붉은 돌기로, 여드름의 한 형태입니다.", "treatment_ko": "항염증 치료제, 국소 항생제, 벤조일 퍼옥사이드", "symptoms_ko": "붉고 단단한 작은 돌기, 압통" }, "pustule": { "name_ko": "농포", "severity": "medium", "description_ko": "고름이 찬 염증성 병변으로, 여드름의 진행된 형태입니다.", "treatment_ko": "국소 또는 경구 항생제, 배농, 항염증 치료", "symptoms_ko": "중심부에 노란 고름이 있는 붉은 돌기" }, "nodule": { "name_ko": "결절", "severity": "medium", "description_ko": "피부 깊숙이 형성된 크고 단단한 염증성 병변입니다.", "treatment_ko": "경구 항생제, 이소트레티노인, 스테로이드 주사", "symptoms_ko": "크고 단단한 피하 덩어리, 심한 통증" }, # Eczema and dermatitis "eczema": { "name_ko": "습진", "severity": "medium", "description_ko": "가려움증과 염증을 동반한 만성 피부 질환으로, 피부 장벽 기능 저하가 특징입니다.", "treatment_ko": "보습제, 국소 스테로이드, 칼시뉴린 억제제, 항히스타민제", "symptoms_ko": "심한 가려움, 붉은 발진, 피부 건조, 인설" }, "atopic dermatitis": { "name_ko": "아토피 피부염", "severity": "medium", "description_ko": "유전적 소인과 환경 요인이 복합적으로 작용하는 만성 재발성 염증성 피부 질환입니다.", "treatment_ko": "보습제, 국소 스테로이드, 면역조절제, 생물학적 제제(듀피젠트)", "symptoms_ko": "극심한 가려움, 건조증, 태선화, 반복적 악화와 호전" }, "contact dermatitis": { "name_ko": "접촉 피부염", "severity": "medium", "description_ko": "특정 물질과의 접촉으로 인한 알레르기성 또는 자극성 피부 반응입니다.", "treatment_ko": "원인 물질 회피, 국소 스테로이드, 경구 항히스타민제", "symptoms_ko": "접촉 부위의 발적, 부종, 수포, 가려움" }, "seborrheic dermatitis": { "name_ko": "지루성 피부염", "severity": "low", "description_ko": "피지선이 발달한 부위에 발생하는 만성 염증성 질환입니다.", "treatment_ko": "항진균 샴푸(케토코나졸), 국소 스테로이드, 칼시뉴린 억제제", "symptoms_ko": "비듬, 두피 가려움, 얼굴 홍반, 기름진 인설" }, "perioral dermatitis": { "name_ko": "구주위 피부염", "severity": "low", "description_ko": "입 주변에 발생하는 염증성 피부 질환으로, 주로 젊은 여성에게 나타납니다.", "treatment_ko": "국소 항생제(메트로니다졸), 경구 테트라사이클린, 스테로이드 중단", "symptoms_ko": "입 주변의 작은 구진과 농포, 경미한 홍반" }, # Rosacea and vascular conditions "rosacea": { "name_ko": "주사비/장미증", "severity": "medium", "description_ko": "얼굴 중앙부의 만성 염증성 피부 질환으로, 홍조와 혈관 확장이 특징입니다.", "treatment_ko": "메트로니다졸 젤, 아젤라산, 독시사이클린, IPL 레이저", "symptoms_ko": "안면 홍조, 지속적 홍반, 구진, 농포, 모세혈관 확장" }, "skin redness": { "name_ko": "피부 홍반", "severity": "low", "description_ko": "다양한 원인으로 인한 피부의 붉어짐 현상입니다.", "treatment_ko": "원인 치료, 진정 크림, 항염증제, 냉찜질", "symptoms_ko": "피부의 붉은 변색, 열감, 경미한 부종" }, # Pigmentation disorders "melasma": { "name_ko": "기미", "severity": "low", "description_ko": "얼굴에 나타나는 대칭적인 갈색 색소 침착으로, 주로 임신이나 호르몬 변화와 관련됩니다.", "treatment_ko": "하이드로퀴논, 트레티노인, 화학 박피, 레이저 치료, 자외선 차단", "symptoms_ko": "뺨, 이마, 코, 상순부의 갈색 반점" }, "dark spots": { "name_ko": "색소 침착/기미", "severity": "low", "description_ko": "과도한 멜라닌 생성으로 인한 피부의 어두운 반점입니다.", "treatment_ko": "미백 크림, 비타민 C, 레티노이드, 화학 박피, 레이저", "symptoms_ko": "불규칙한 갈색 또는 검은 반점" }, "freckles": { "name_ko": "주근깨", "severity": "none", "description_ko": "유전적 소인과 자외선 노출로 인한 작은 갈색 반점입니다.", "treatment_ko": "자외선 차단, 레이저 치료, 미백 크림 (선택적)", "symptoms_ko": "얼굴과 팔의 작은 갈색 점" }, "vitiligo": { "name_ko": "백반증", "severity": "low", "description_ko": "멜라닌 세포 소실로 인한 피부 탈색소 질환입니다.", "treatment_ko": "국소 스테로이드, 칼시뉴린 억제제, 광선치료, 색소이식", "symptoms_ko": "경계가 명확한 흰색 반점, 대칭적 분포" }, # Infections "cellulitis": { "name_ko": "봉와직염", "severity": "high", "description_ko": "피부와 피하조직의 급성 세균 감염으로, 주로 연쇄상구균이나 포도상구균이 원인입니다.", "treatment_ko": "경구 또는 정맥 항생제, 휴식, 거상, 진통제, 입원 치료", "symptoms_ko": "발적, 부종, 열감, 통증, 발열, 오한" }, "impetigo": { "name_ko": "농가진", "severity": "medium", "description_ko": "표재성 세균 감염으로, 주로 어린이에게 발생하며 전염성이 강합니다.", "treatment_ko": "국소 항생제(무피로신), 경구 항생제, 위생 관리", "symptoms_ko": "꿀색 가피, 수포, 가려움, 주변 피부로 확산" }, "fungal": { "name_ko": "진균 감염/무좀", "severity": "low", "description_ko": "피부 진균에 의한 감염으로, 백선, 칸디다증 등이 포함됩니다.", "treatment_ko": "항진균제(국소 또는 경구), 위생 관리, 통풍 개선", "symptoms_ko": "인설, 가려움, 발적, 균열, 악취" }, "herpes": { "name_ko": "헤르페스", "severity": "medium", "description_ko": "헤르페스 바이러스에 의한 수포성 피부 감염입니다.", "treatment_ko": "항바이러스제(아시클로버, 발라시클로버), 진통제", "symptoms_ko": "군집성 수포, 통증, 작열감, 재발성" }, # Keratosis and scaling conditions "keratosis": { "name_ko": "각화증", "severity": "low", "description_ko": "피부의 각질층이 과도하게 두꺼워지는 상태입니다.", "treatment_ko": "각질용해제(살리실산, 요소), 레티노이드, 보습제", "symptoms_ko": "거친 피부, 인설, 두꺼워진 각질" }, "actinic keratosis": { "name_ko": "광선 각화증", "severity": "medium", "description_ko": "만성 자외선 노출로 인한 전암성 병변입니다.", "treatment_ko": "냉동치료, 5-FU 크림, 이미퀴모드, 광역학 치료", "symptoms_ko": "거친 인설성 반점, 주로 노출 부위" }, "psoriasis": { "name_ko": "건선", "severity": "medium", "description_ko": "피부세포의 과도한 증식으로 인한 만성 자가면역 질환입니다.", "treatment_ko": "국소 스테로이드, 비타민 D 유도체, 광선치료, 생물학적 제제", "symptoms_ko": "은백색 인설, 홍반성 판, 가려움, 관절통" }, # Skin cancers "melanoma": { "name_ko": "흑색종", "severity": "high", "description_ko": "멜라닌 세포에서 발생하는 악성 피부암으로, 전이 위험이 높습니다.", "treatment_ko": "수술적 절제, 면역치료, 표적치료, 방사선치료", "symptoms_ko": "비대칭 모양, 불규칙한 경계, 다양한 색조, 6mm 이상 크기" }, "basal cell carcinoma": { "name_ko": "기저세포암", "severity": "high", "description_ko": "가장 흔한 피부암으로, 천천히 성장하며 국소 침습성이 있습니다.", "treatment_ko": "모스 수술, 절제술, 방사선치료, 이미퀴모드", "symptoms_ko": "진주 광택 결절, 중심부 궤양, 출혈, 가피" }, "squamous cell carcinoma": { "name_ko": "편평세포암", "severity": "high", "description_ko": "두 번째로 흔한 피부암으로, 전이 가능성이 있습니다.", "treatment_ko": "수술적 절제, 방사선치료, 화학요법", "symptoms_ko": "인설성 홍반, 궤양, 출혈, 단단한 결절" }, "carcinoma": { "name_ko": "피부암", "severity": "high", "description_ko": "피부에서 발생하는 악성 종양을 총칭합니다.", "treatment_ko": "종양 유형에 따른 수술, 방사선, 화학요법", "symptoms_ko": "비정상적인 성장, 궤양, 출혈, 색조 변화" }, # Other common conditions "milia": { "name_ko": "비립종/쌀알종", "severity": "low", "description_ko": "각질이 피부 표면 아래 갇혀 생기는 작은 흰색 낭종입니다.", "treatment_ko": "자연 소실, 압출, 레티노이드, 화학 박피", "symptoms_ko": "1-2mm 크기의 흰색 또는 노란색 구진" }, "warts": { "name_ko": "사마귀", "severity": "low", "description_ko": "인유두종 바이러스(HPV)에 의한 피부 증식성 질환입니다.", "treatment_ko": "냉동치료, 살리실산, 레이저, 면역치료", "symptoms_ko": "거친 표면의 돌기, 검은 점, 군집성 병변" }, "urticaria": { "name_ko": "두드러기", "severity": "low", "description_ko": "피부의 일시적인 부종과 가려움을 동반한 알레르기 반응입니다.", "treatment_ko": "항히스타민제, 알레르기 원인 회피, 스테로이드", "symptoms_ko": "팽진, 심한 가려움, 혈관부종" }, "hives": { "name_ko": "두드러기", "severity": "low", "description_ko": "급성 알레르기 반응으로 인한 피부 팽진입니다.", "treatment_ko": "항히스타민제, 에피네프린(심한 경우)", "symptoms_ko": "붉고 부푼 팽진, 가려움, 이동성 병변" }, # Aging and cosmetic concerns "wrinkles": { "name_ko": "주름", "severity": "none", "description_ko": "노화와 자외선 노출로 인한 피부 탄력 감소와 주름 형성입니다.", "treatment_ko": "레티노이드, 보톡스, 필러, 레이저, 자외선 차단", "symptoms_ko": "미세주름, 깊은 주름, 탄력 감소" }, "dark circles": { "name_ko": "다크서클", "severity": "none", "description_ko": "눈 아래 피부가 어둡게 보이는 현상으로, 피로, 유전, 노화 등이 원인입니다.", "treatment_ko": "충분한 수면, 비타민 K 크림, 레티노이드, 필러", "symptoms_ko": "눈 아래 어두운 변색, 부종" }, "eye bags": { "name_ko": "눈밑 지방", "severity": "none", "description_ko": "눈 아래 지방이 돌출되어 생기는 부종입니다.", "treatment_ko": "냉찜질, 카페인 크림, 수술(심한 경우)", "symptoms_ko": "눈 아래 부풀어 오름, 처짐" }, "enlarged pores": { "name_ko": "모공 확대", "severity": "none", "description_ko": "피지 과다 분비와 탄력 감소로 인한 모공 확대입니다.", "treatment_ko": "레티노이드, BHA, 레이저, 모공 축소 시술", "symptoms_ko": "눈에 띄는 모공, 피지 과다" }, # Skin types "normal": { "name_ko": "정상 피부", "severity": "none", "description_ko": "균형잡힌 건강한 피부 상태입니다.", "treatment_ko": "기본 스킨케어 유지, 자외선 차단, 보습", "symptoms_ko": "특별한 문제 없음, 적절한 유수분 밸런스" }, "normal skin": { "name_ko": "정상 피부", "severity": "none", "description_ko": "건강하고 균형잡힌 피부 상태입니다.", "treatment_ko": "일반적인 스킨케어 루틴 유지", "symptoms_ko": "매끄러운 질감, 균일한 톤" }, "dry skin": { "name_ko": "건성 피부", "severity": "low", "description_ko": "수분과 피지가 부족한 피부 상태입니다.", "treatment_ko": "보습제, 세라마이드, 히알루론산, 부드러운 클렌저", "symptoms_ko": "당김, 각질, 칙칙함, 미세주름" }, "oily skin": { "name_ko": "지성 피부", "severity": "low", "description_ko": "피지 분비가 과도한 피부 상태입니다.", "treatment_ko": "오일프리 제품, BHA, 클레이 마스크, 가벼운 보습", "symptoms_ko": "번들거림, 넓은 모공, 여드름 발생" }, "combination skin": { "name_ko": "복합성 피부", "severity": "none", "description_ko": "T존은 지성, U존은 건성인 복합적 피부 상태입니다.", "treatment_ko": "부위별 맞춤 케어, 밸런싱 제품", "symptoms_ko": "T존 번들거림, 볼 건조" }, "sensitive skin": { "name_ko": "민감성 피부", "severity": "low", "description_ko": "외부 자극에 쉽게 반응하는 피부 상태입니다.", "treatment_ko": "저자극 제품, 무향료, 진정 성분", "symptoms_ko": "쉬운 자극, 붉어짐, 따가움" } } return database def _init_gpt_client(self): """Initialize GPT-OSS client for detailed explanations.""" try: # This would connect to the GPT-OSS API # For now, we'll use a placeholder self.gpt_client = None logger.info("GPT-OSS client initialized (placeholder)") except Exception as e: logger.error(f"Failed to initialize GPT client: {e}") def load_model(self) -> None: """Load the vision model for skin disease classification.""" try: logger.info(f"Loading model: {self.model_name}") self.processor = ViTImageProcessor.from_pretrained(self.model_name) self.model = ViTForImageClassification.from_pretrained(self.model_name) self.model.eval() self.id2label = self.model.config.id2label logger.info(f"Model loaded: {len(self.id2label)} disease classes") except Exception as e: logger.error(f"Failed to load model: {e}") raise RuntimeError(f"Model loading failed: {str(e)}") @spaces.GPU def diagnose(self, image: Image.Image) -> Tuple[Dict[str, float], str, str]: """ Perform diagnosis on the skin image. Returns: Tuple of (probabilities, formatted_output, gpt_analysis) """ if self.model is None or self.processor is None: return {}, "❌ 모델 로딩 실패 / Model not loaded", "" try: # Image preprocessing if image.mode != 'RGB': image = image.convert('RGB') # Move model to GPU device = "cuda" if torch.cuda.is_available() else "cpu" self.model = self.model.to(device) # Process image inputs = self.processor(images=image, return_tensors="pt") inputs = {k: v.to(device) for k, v in inputs.items()} # Get predictions with torch.no_grad(): outputs = self.model(**inputs) probabilities = torch.softmax(outputs.logits, dim=-1)[0] probabilities = probabilities.cpu() # Convert to dictionary class_probs = {} for class_id, prob in enumerate(probabilities): class_name = self.id2label[class_id] class_probs[class_name] = float(prob) # Sort by confidence sorted_probs = dict(sorted(class_probs.items(), key=lambda x: x[1], reverse=True)) # Format results with medical information formatted_output = self._format_medical_results(sorted_probs, image.size) # Generate GPT analysis gpt_analysis = self._generate_gpt_analysis(sorted_probs) return sorted_probs, formatted_output, gpt_analysis except Exception as e: error_msg = f"❌ 진단 실패 / Diagnosis failed: {str(e)}" logger.error(error_msg) return {}, error_msg, "" def _format_medical_results(self, class_probs: Dict[str, float], image_size: Tuple[int, int]) -> str: """Format results in medical report style with Korean.""" top_class = next(iter(class_probs)) top_confidence = class_probs[top_class] # Get disease info if available disease_info = self.disease_info_db.get(top_class.lower(), {}) name_ko = disease_info.get("name_ko", top_class) severity = disease_info.get("severity", "unknown") # Determine severity badge severity_badge = { "low": '경증 / Mild', "medium": '중등도 / Moderate', "high": '중증 / Severe', "unknown": '미분류 / Unclassified' }.get(severity, "") # Build medical report output = f"""

🏥 AI 피부 진단 결과 / AI Skin Diagnosis Report

📋 주요 진단 / Primary Diagnosis

질환명 / Condition: {top_class.title()} ({name_ko}) {severity_badge}

신뢰도 / Confidence: {top_confidence:.1%}

📊 상세 분석 / Detailed Analysis

이미지 크기 / Image Size: {image_size[0]} × {image_size[1]} pixels

분석 시간 / Analysis Time: 실시간 / Real-time

🔍 감별 진단 / Differential Diagnosis (Top 5)

""" # Add top 5 differential diagnoses for idx, (class_name, confidence) in enumerate(class_probs.items()): if idx >= 5: break disease_ko = self.disease_info_db.get(class_name.lower(), {}).get("name_ko", class_name) if confidence >= 0.01: # Only show > 1% bar_length = int(confidence * 20) bar = "█" * bar_length + "░" * (20 - bar_length) output += f"""

{idx+1}. {class_name.title()} ({disease_ko}): {confidence:.1%} {bar}

""" output += """
⚠️ 주의사항 / Important Notice:
이 결과는 AI 기반 예측이며, 실제 의학적 진단을 대체할 수 없습니다.
정확한 진단과 치료를 위해 반드시 피부과 전문의와 상담하세요.
This is an AI-based prediction and cannot replace actual medical diagnosis.
Please consult a dermatologist for accurate diagnosis and treatment.
""" return output def _generate_gpt_analysis(self, class_probs: Dict[str, float]) -> str: """Generate detailed analysis using GPT-OSS model.""" top_class = next(iter(class_probs)) top_confidence = class_probs[top_class] # Get disease information from database - check multiple variations disease_info = None # Try different case variations to find the disease search_keys = [ top_class.lower(), top_class.lower().replace('_', ' '), top_class.lower().replace('-', ' '), top_class.replace('_', ' ').lower(), top_class.replace('-', ' ').lower() ] for key in search_keys: if key in self.disease_info_db: disease_info = self.disease_info_db[key] logger.info(f"Found disease info for: {key}") break # If still not found, create comprehensive default information if disease_info is None: logger.warning(f"No database entry for: {top_class}") disease_info = self._create_default_disease_info(top_class) # Get detailed symptoms if available symptoms_text = disease_info.get('symptoms_ko', '') if symptoms_text: symptoms_html = f"""

🔍 주요 증상 / Key Symptoms

{symptoms_text}

""" else: symptoms_html = "" # Create comprehensive GPT analysis with all available information analysis = f"""

🤖 GPT-OSS 상세 분석 / GPT-OSS Detailed Analysis

📋 진단된 질환 정보 / Diagnosed Condition Information

질환명 / Disease: {top_class.title()} ({disease_info['name_ko']})

신뢰도 / Confidence: {top_confidence:.1%}

중증도 / Severity: {self._get_severity_badge(disease_info.get('severity', 'unknown'))}

📖 질환 설명 / Disease Description

{disease_info['name_ko']} ({top_class.title()})

{disease_info['description_ko']}

{symptoms_html}

📝 권장 치료법 / Recommended Treatment

치료 방법:

{disease_info['treatment_ko']}

💊 생활 관리 지침 / Lifestyle Management Guidelines

{self._get_lifestyle_guidelines(top_class, disease_info.get('severity', 'low'))}

🏥 의료진 상담 필요 시점 / When to Consult Healthcare Provider

{self._get_consultation_guidelines(disease_info.get('severity', 'low'))}

🔬 추가 검사 권장사항 / Recommended Additional Tests

{self._get_test_recommendations(top_class, disease_info.get('severity', 'low'))}

⚠️ 주의사항 / Precautions

{self._get_precautions(top_class, disease_info.get('severity', 'low'))}
""" return analysis def _create_default_disease_info(self, disease_name: str) -> Dict: """Create default disease information when not in database.""" # Try to infer information from the disease name name_lower = disease_name.lower() # Determine Korean name name_ko = self._translate_disease_name(disease_name) # Determine severity severity = self._estimate_severity(disease_name) # Create appropriate description based on keywords if 'cancer' in name_lower or 'carcinoma' in name_lower or 'melanoma' in name_lower: description = f"악성 종양의 가능성이 있는 피부 병변입니다. 즉시 전문의 진단이 필요합니다." treatment = "즉시 피부과 또는 종양 전문의 상담, 조직검사 필요, 조기 진단과 치료가 중요" elif 'infection' in name_lower or 'bacterial' in name_lower: description = f"세균 감염이 의심되는 피부 질환입니다. 적절한 항생제 치료가 필요할 수 있습니다." treatment = "항생제 치료(국소 또는 경구), 상처 소독, 위생 관리" elif 'fungal' in name_lower: description = f"진균 감염이 의심되는 피부 질환입니다." treatment = "항진균제 치료, 환부 건조 유지, 통풍 개선" elif 'dermatitis' in name_lower or 'eczema' in name_lower: description = f"피부의 염증성 질환으로, 가려움과 발적이 동반될 수 있습니다." treatment = "보습제 사용, 국소 스테로이드, 항히스타민제, 자극 물질 회피" elif 'acne' in name_lower or 'pimple' in name_lower: description = f"모낭과 피지선의 염증성 질환입니다." treatment = "적절한 클렌징, 국소 치료제(레티노이드, 벤조일 퍼옥사이드), 항생제" else: description = f"피부 질환으로 정확한 진단을 위해 전문의 상담이 권장됩니다." treatment = "피부과 전문의 상담을 통한 정확한 진단 후 적절한 치료" return { "name_ko": name_ko, "severity": severity, "description_ko": description, "treatment_ko": treatment, "symptoms_ko": "육안 검사와 추가 검사를 통해 정확한 증상 파악 필요" } def _get_severity_badge(self, severity: str) -> str: """Get HTML badge for severity level.""" badges = { "none": '정상 / Normal', "low": '경증 / Mild', "medium": '중등도 / Moderate', "high": '중증 / Severe', "unknown": '미분류 / Unclassified' } return badges.get(severity, badges["unknown"]) def _get_lifestyle_guidelines(self, disease: str, severity: str) -> str: """Get lifestyle management guidelines based on disease and severity.""" guidelines = "" return guidelines def _get_consultation_guidelines(self, severity: str) -> str: """Get consultation guidelines based on severity.""" guidelines = "" return guidelines def _get_test_recommendations(self, disease: str, severity: str) -> str: """Get test recommendations based on disease type.""" tests = "" return tests def _get_precautions(self, disease: str, severity: str) -> str: """Get precautions based on disease type.""" precautions = "" return precautions def _translate_disease_name(self, disease_name: str) -> str: """Translate disease name to Korean if not in database.""" # Common translations for diseases not in main database translations = { "healthy": "정상", "benign": "양성", "malignant": "악성", "infection": "감염", "inflammation": "염증", "allergy": "알레르기", "autoimmune": "자가면역", "bacterial": "세균성", "viral": "바이러스성" } # Check if any keyword matches lower_name = disease_name.lower() for key, value in translations.items(): if key in lower_name: return f"{value} 관련 질환" # Return original if no translation found return disease_name def _estimate_severity(self, disease_name: str) -> str: """Estimate severity based on disease name keywords.""" high_severity_keywords = ["cancer", "carcinoma", "melanoma", "malignant", "cellulitis", "severe"] medium_severity_keywords = ["infection", "inflammatory", "chronic", "dermatitis", "eczema", "psoriasis"] lower_name = disease_name.lower() for keyword in high_severity_keywords: if keyword in lower_name: return "high" for keyword in medium_severity_keywords: if keyword in lower_name: return "medium" return "low" # Initialize the system try: diagnosis_system = MedicalSkinDiagnosisSystem() system_ready = True except Exception as e: logger.error(f"Failed to initialize system: {e}") diagnosis_system = None system_ready = False def perform_diagnosis(image: Image.Image) -> Tuple[str, str]: """ Main diagnosis function for Gradio interface. Returns: Tuple of (diagnosis_result, gpt_analysis) """ if not system_ready or diagnosis_system is None: return "❌ 시스템을 사용할 수 없습니다 / System unavailable", "" if image is None: return "❌ 이미지를 업로드해주세요 / Please upload an image", "" try: class_probs, formatted_output, gpt_analysis = diagnosis_system.diagnose(image) if not class_probs: return formatted_output, "" return formatted_output, gpt_analysis except Exception as e: logger.error(f"Diagnosis error: {e}") return f"❌ 처리 실패 / Processing failed: {str(e)}", "" def create_medical_interface(): """Create medical-grade Gradio interface.""" with gr.Blocks( title="AI 피부 진단 시스템 / AI Skin Diagnosis System", theme=gr.themes.Soft(), css=medical_css ) as interface: # Header gr.HTML("""

🏥 AI 피부 질환 진단 시스템
AI-Powered Skin Disease Diagnosis System

GPT-OSS 120B 모델 통합 진단 / Integrated with GPT-OSS 120B Model

""") # System status with gr.Row(): gr.HTML(f"""
시스템 상태: {"정상" if system_ready else "오류"} / System: {"Ready" if system_ready else "Error"} Vision Model: {diagnosis_system.model_name if diagnosis_system else "N/A"} GPT-OSS: 120B Model GPU: {"활성화" if torch.cuda.is_available() else "비활성화"} / {"Enabled" if torch.cuda.is_available() else "Disabled"}
""") with gr.Row(): with gr.Column(scale=1): # Input section gr.Markdown("### 📸 이미지 업로드 / Image Upload") image_input = gr.Image( type="pil", label="피부 이미지 업로드 / Upload Skin Image", height=400 ) with gr.Row(): diagnose_btn = gr.Button( "🔬 AI 진단 시작 / Start AI Diagnosis", variant="primary", size="lg", elem_classes="button-primary" ) clear_btn = gr.Button( "🔄 초기화 / Clear", variant="secondary", size="lg" ) # Advanced settings with gr.Accordion("⚙️ 고급 설정 / Advanced Settings", open=False): confidence_threshold = gr.Slider( minimum=0.1, maximum=0.9, value=0.5, step=0.1, label="최소 신뢰도 임계값 / Minimum Confidence Threshold" ) analysis_depth = gr.Radio( choices=["기본 / Basic", "상세 / Detailed", "전문가 / Expert"], value="상세 / Detailed", label="분석 깊이 / Analysis Depth" ) with gr.Column(scale=2): # Results section gr.Markdown("### 📊 진단 결과 / Diagnosis Results") diagnosis_output = gr.HTML( label="Vision Model 진단 / Vision Model Diagnosis", value="
이미지를 업로드하고 진단을 시작하세요.
Upload an image and start diagnosis.
" ) gpt_analysis = gr.HTML( label="GPT-OSS 분석 / GPT-OSS Analysis", value="" ) # Example images with proper paths gr.Markdown("### 📁 예제 이미지 / Example Images") # Define the actual example images that were uploaded example_images = [ ["andrea.jpeg"], ["clare.jpeg"], ["disorder.jpeg"], ["joe.jpeg"], ["woman.jpeg"] ] # Check if images exist and create examples available_examples = [] for img_path in example_images: # Check various possible locations possible_paths = [ img_path[0], # Current directory f"examples/{img_path[0]}", # examples folder f"./{img_path[0]}", # Explicit current directory f"./examples/{img_path[0]}" # Explicit examples folder ] for path in possible_paths: if Path(path).exists(): available_examples.append([path]) break if available_examples: gr.Examples( examples=available_examples, inputs=[image_input], label="샘플 피부 이미지 / Sample Skin Images", examples_per_page=5 ) else: # If images not found in expected locations, show instructions gr.HTML("""

📸 샘플 이미지 위치 / Sample Image Location:

다음 이미지들이 프로젝트 폴더에 있어야 합니다 / The following images should be in your project folder:

이미지를 프로젝트 루트 또는 examples 폴더에 배치하세요
Place images in project root or examples folder

""") # Event handlers diagnose_btn.click( fn=perform_diagnosis, inputs=[image_input], outputs=[diagnosis_output, gpt_analysis] ) clear_btn.click( fn=lambda: (None, "
이미지를 업로드하고 진단을 시작하세요.
Upload an image and start diagnosis.
", ""), inputs=[], outputs=[image_input, diagnosis_output, gpt_analysis] ) image_input.change( fn=lambda x: ("
진단 버튼을 클릭하세요.
Click the diagnosis button.
", "") if x else ("", ""), inputs=[image_input], outputs=[diagnosis_output, gpt_analysis] ) # Footer gr.HTML("""

📋 의료 면책 조항 / Medical Disclaimer

본 시스템은 AI 기반 보조 도구이며, 의학적 진단을 대체하지 않습니다. 모든 결과는 참고용이며, 정확한 진단과 치료를 위해서는 반드시 의료 전문가와 상담하시기 바랍니다.

This system is an AI-based assistive tool and does not replace medical diagnosis. All results are for reference only. Please consult with healthcare professionals for accurate diagnosis and treatment.


Powered by Vision Transformer & GPT-OSS 120B | © 2024 Medical AI Systems

""") return interface # Health check function def health_check() -> Dict[str, str]: """System health check for monitoring.""" return { "status": "healthy" if system_ready else "unhealthy", "vision_model": diagnosis_system.model_name if diagnosis_system else "not_loaded", "gpt_model": "gpt-oss-120b", "classes": len(diagnosis_system.id2label) if diagnosis_system else 0, "device": diagnosis_system.device if diagnosis_system else "unknown", "gpu_available": str(torch.cuda.is_available()) } # Main execution if __name__ == "__main__": try: app = create_medical_interface() # Launch with HuggingFace Spaces configuration app.launch( server_name="0.0.0.0", server_port=7860, share=False, show_error=True ) except Exception as e: logger.error(f"Failed to launch interface: {e}") print(f"❌ 애플리케이션 시작 실패 / Application failed to start: {e}") # Export key functions __all__ = ['MedicalSkinDiagnosisSystem', 'perform_diagnosis', 'health_check']