File size: 3,645 Bytes
af3df0b
 
 
 
 
 
 
 
 
 
 
 
 
a18dfe6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
af3df0b
 
a18dfe6
 
 
 
af3df0b
 
a18dfe6
af3df0b
 
 
 
 
 
 
 
a18dfe6
 
af3df0b
a18dfe6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
af3df0b
a18dfe6
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import torch
from PIL import Image
import gradio as gr
from open_clip import create_model_from_pretrained, get_tokenizer

MODEL_NAME = "microsoft/BiomedCLIP-PubMedBERT_256-vit_base_patch16_224"

print("Loading BiomedCLIP...")
model, preprocess = create_model_from_pretrained(f"hf-hub:{MODEL_NAME}")
tokenizer = get_tokenizer(f"hf-hub:{MODEL_NAME}")
model.eval()
print("Model Loaded")

BASE_PROMPTS = {
    "Eczema": "a dermatology clinical image showing eczema with dry itchy inflamed patches",
    "Psoriasis": "a dermatology image of psoriasis with thick scaly plaques",
    "Fungal Infection (Tinea)": "a fungal skin infection with circular expanding ring like rash",
    "Acne": "a dermatology image showing acne with pimples and inflammation",
    "Dermatitis": "a dermatitis rash with redness irritation and inflammation",
    "Urticaria (Hives)": "raised itchy welts on skin like urticaria or hives",
    "Benign Mole": "a harmless benign mole on the skin",
    "Melanoma Suspicion": "a suspicious melanoma skin lesion with asymmetry border irregularity dark color",
    "Healthy Skin": "a healthy normal skin image with no lesions"
}

CONFIDENCE_THRESHOLD = 0.42   # tune if needed


def build_prompts(symptoms):
    prompts = []
    for label, base in BASE_PROMPTS.items():
        if symptoms and symptoms.strip() != "":
            enriched_prompt = f"{base}. Patient symptoms: {symptoms}"
        else:
            enriched_prompt = base
        prompts.append((label, enriched_prompt))
    return prompts


def predict(image, symptoms):
    if image is None:
        return "Please upload an image.", None

    image = preprocess(image).unsqueeze(0)

    prompts = build_prompts(symptoms)
    labels = [p[0] for p in prompts]
    text_list = [p[1] for p in prompts]

    with torch.no_grad():
        image_features = model.encode_image(image)
        text_tokens = tokenizer(text_list)
        text_features = model.encode_text(text_tokens)

        image_features /= image_features.norm(dim=-1, keepdim=True)
        text_features /= text_features.norm(dim=-1, keepdim=True)

        similarity = (100.0 * image_features @ text_features.T).softmax(dim=-1)
        probs = similarity.squeeze().tolist()

    label_scores = list(zip(labels, probs))
    label_scores.sort(key=lambda x: x[1], reverse=True)

    best_label, best_prob = label_scores[0]

    explanation = ""
    if best_prob < CONFIDENCE_THRESHOLD:
        explanation = (
            "⚠️ The model is uncertain about this case. "
            "Consider consulting a dermatologist, especially if symptoms are worsening, painful, rapidly spreading, "
            "bleeding, or changing in shape/color."
        )
        best_label = "Uncertain — Needs Clinical Evaluation"

    top3 = {label: round(score, 3) for label, score in label_scores[:3]}

    return (
        f"Prediction: {best_label}  (confidence: {round(best_prob,3)})\n\n"
        f"{explanation}\n\n"
        "🔒 Disclaimer: This is a research tool and NOT a medical diagnosis.",
        top3
    )


ui = gr.Interface(
    fn=predict,
    inputs=[
        gr.Image(type="pil", label="Upload Skin Image"),
        gr.Textbox(label="Describe Symptoms (optional)", placeholder="e.g., itchy red rash for 2 weeks, burning sensation, spreading, no bleeding")
    ],
    outputs=[
        gr.Textbox(label="Result"),
        gr.Label(num_top_classes=3, label="Top Predictions")
    ],
    title="BiomedCLIP Dermatology Assistant",
    description="Upload a skin image and optionally describe symptoms. Uses zero-shot BiomedCLIP for prediction. Research use only — not medical advice."
)

ui.launch()