CelagenexResearch commited on
Commit
8ca6ff4
·
verified ·
1 Parent(s): e841214

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -71
app.py CHANGED
@@ -1,36 +1,34 @@
 
 
1
  import gradio as gr
2
  from PIL import Image
3
  import torch
4
  import numpy as np
5
  import cv2
6
- from transformers import CLIPProcessor, CLIPModel
7
- # Hypot MedGemma imports (ensure you have access and HF token)
8
- from medgem import MedGemmaProcessor, MedGemmaForImageClassification
9
 
10
  # Device setup
11
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
12
 
13
- # Load CLIP model for breed, age, and basic health aspects
14
  clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch16").to(device)
15
  clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch16")
16
 
17
- # Load MedGemma for advanced medical insights
18
- medgemma_processor = MedGemmaProcessor.from_pretrained("google/medgemma-v1").to(device)
19
- medgemma_model = MedGemmaForImageClassification.from_pretrained("google/medgemma-v1").to(device)
 
20
 
21
- # Stanford Dogs breeds list & lifespan dict
22
- STANFORD_BREEDS = [
23
- "afghan hound", "african hunting dog", "airedale", "american staffordshire terrier",
24
- # ... (full list from earlier)
25
- "wire-haired fox terrier", "yorkshire terrier"
26
- ]
27
  BREED_LIFESPAN = {
28
- "afghan hound": 11.1, "african hunting dog": 10.5, "airedale": 11.5,
29
- # ... (full dict from earlier)
30
- "yorkshire terrier": 13.3
 
 
31
  }
32
 
33
- # Healthspan questionnaire definitions
34
  QUESTIONNAIRE = [
35
  {"domain": "Mobility", "questions": [
36
  "Does your dog have difficulty rising from lying down?",
@@ -54,17 +52,18 @@ QUESTIONNAIRE = [
54
  ]}
55
  ]
56
 
57
- # Unified scoring map for questionnaire (0–5 scale)
58
  SCALE = ["0", "1", "2", "3", "4", "5"]
59
 
 
60
  def predict_biological_age(image: Image.Image, breed: str) -> int:
61
  avg = BREED_LIFESPAN.get(breed.lower(), 12)
62
- prompts = [f"a photo of a {age}-year-old {breed}" for age in range(1, int(avg * 2) + 1)]
63
  inputs = clip_processor(text=prompts, images=image, return_tensors="pt", padding=True).to(device)
64
  with torch.no_grad():
65
  logits = clip_model(**inputs).logits_per_image.softmax(dim=1)[0].cpu().numpy()
66
  return int(np.argmax(logits) + 1)
67
 
 
68
  def analyze_medical_image(image: Image.Image):
69
  inputs = medgemma_processor(images=image, return_tensors="pt").to(device)
70
  with torch.no_grad():
@@ -74,13 +73,11 @@ def analyze_medical_image(image: Image.Image):
74
  conf = float(np.max(probs))
75
  return label, conf
76
 
 
77
  def classify_breed_and_health(image: Image.Image, user_breed=None):
78
- # Image features
79
  inputs = clip_processor(images=image, return_tensors="pt").to(device)
80
  with torch.no_grad():
81
  img_feats = clip_model.get_image_features(**inputs)
82
-
83
- # Breed classification
84
  texts = [f"a photo of a {b}" for b in STANFORD_BREEDS]
85
  t_in = clip_processor(text=texts, return_tensors="pt", padding=True).to(device)
86
  with torch.no_grad():
@@ -90,11 +87,10 @@ def classify_breed_and_health(image: Image.Image, user_breed=None):
90
  breed = user_breed or STANFORD_BREEDS[idx]
91
  breed_conf = float(sims[idx])
92
 
93
- # Basic health aspects via CLIP
94
  aspects = {
95
  "Coat": ("shiny healthy coat", "dull patchy fur"),
96
  "Eyes": ("bright clear eyes", "cloudy milky eyes"),
97
- "Body": ("ideal muscle tone", "visible ribs or hip bones"),
98
  "Teeth": ("clean white teeth", "yellow stained teeth")
99
  }
100
  health = {}
@@ -107,87 +103,81 @@ def classify_breed_and_health(image: Image.Image, user_breed=None):
107
  health[name] = {"assessment": choice, "confidence": float(max(sim))}
108
  return breed, breed_conf, health
109
 
 
110
  def analyze_video_health(video_path: str):
111
  cap = cv2.VideoCapture(video_path)
112
  fps = cap.get(cv2.CAP_PROP_FPS) or 24
113
- total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
114
- duration = total_frames / fps
115
- # sample 10 frames evenly
116
- indices = np.linspace(0, total_frames - 1, num=10, dtype=int)
117
- gait_scores = []
118
  for i in indices:
119
  cap.set(cv2.CAP_PROP_POS_FRAMES, i)
120
  ret, frame = cap.read()
121
- if not ret: break
 
122
  img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
123
  _, conf = analyze_medical_image(img)
124
- gait_scores.append(conf)
125
  cap.release()
126
- avg_conf = float(np.mean(gait_scores)) if gait_scores else 0.0
127
- return {"duration_sec": round(duration, 1), "avg_gait_confidence": avg_conf}
128
 
129
  def compute_questionnaire_score(answers: list):
130
- # answers in order of QUESTIONNAIRE domains × questions
131
  scores = {}
132
  idx = 0
133
- for section in QUESTIONNAIRE:
134
- vals = list(map(int, answers[idx: idx + len(section["questions"])]))
135
- idx += len(section["questions"])
136
- scores[section["domain"]] = round(sum(vals) / len(vals), 2)
 
137
  return scores
138
 
139
- # Build Gradio interface
140
  with gr.Blocks(title="🐶 Dog Health & Age Analyzer") as demo:
141
- gr.Markdown("## Upload an Image or Video, or Record a Short Clip")
142
 
143
  with gr.Tab("Image Analysis"):
144
  img_in = gr.Image(type="pil", label="Upload Dog Image")
145
  breed_in = gr.Textbox(label="(Optional) Override Breed")
146
  age_in = gr.Number(label="Chronological Age (years)", precision=1)
147
- btn_img = gr.Button("Analyze Image")
148
- out_md = gr.Markdown()
149
 
150
- def run_image(img, breed_override, chrono_age):
151
- breed, b_conf, health = classify_breed_and_health(img, breed_override)
152
  med_label, med_conf = analyze_medical_image(img)
153
  bio_age = predict_biological_age(img, breed)
154
- pace = round(bio_age / chrono_age, 2) if chrono_age else None
155
-
156
- report = f"**Breed:** {breed} ({b_conf:.1%}) \n"
157
- report += f"**MedGemma Finding:** {med_label} ({med_conf:.1%}) \n\n"
158
- report += f"**Biological Age:** {bio_age} yrs \n"
159
- report += f"**Chronological Age:** {chrono_age or 'N/A'} yrs \n"
160
  if pace:
161
- report += f"**Pace of Aging:** {pace}× \n\n"
162
- report += "### Health Aspects\n"
163
  for k, v in health.items():
164
- report += f"- **{k}:** {v['assessment']} ({v['confidence']:.1%})\n"
165
- return report
166
 
167
- btn_img.click(run_image, inputs=[img_in, breed_in, age_in], outputs=out_md)
168
 
169
  with gr.Tab("Video Analysis"):
170
- video_in = gr.Video(label="Upload or Record Video (10–30s)")
171
- btn_vid = gr.Button("Analyze Video")
172
  vid_out = gr.JSON()
 
173
 
174
- btn_vid.click(lambda vid: analyze_video_health(vid), inputs=video_in, outputs=vid_out)
175
-
176
- with gr.Tab("Healthspan Questionnaire"):
177
  widgets = []
178
- for section in QUESTIONNAIRE:
179
- gr.Markdown(f"### {section['domain']}")
180
- for q in section["questions"]:
181
  w = gr.Radio(choices=SCALE, label=q)
182
  widgets.append(w)
183
- btn_q = gr.Button("Compute Score")
184
- q_out = gr.JSON()
185
-
186
- btn_q.click(
187
- fn=compute_questionnaire_score,
188
- inputs=widgets,
189
- outputs=q_out
190
- )
191
 
192
  with gr.Tab("About"):
193
  gr.Markdown("""
 
1
+ # app.py
2
+
3
  import gradio as gr
4
  from PIL import Image
5
  import torch
6
  import numpy as np
7
  import cv2
8
+ from transformers import CLIPProcessor, CLIPModel AutoProcessor, AutoModelForImageClassification
 
 
9
 
10
  # Device setup
11
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
12
 
13
+ # Load CLIP for breed, age, basic health
14
  clip_model = CLIPModel.from_pretrained("openai/clip-vit-base-patch16").to(device)
15
  clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch16")
16
 
17
+ # Load MedGemma via Hugging Face Transformers
18
+ # (no special pip package needed; uses AutoModel APIs)
19
+ medgemma_processor = AutoProcessor.from_pretrained("google/medgemma-v1")
20
+ medgemma_model = AutoModelForImageClassification.from_pretrained("google/medgemma-v1").to(device)
21
 
22
+ # Stanford Dogs breeds & lifespans (abbreviated here; include full lists)
23
+ STANFORD_BREEDS = ["afghan hound", "beagle", "golden retriever", "yorkshire terrier"] # etc.
 
 
 
 
24
  BREED_LIFESPAN = {
25
+ "afghan hound": 11.1,
26
+ "beagle": 12.5,
27
+ "golden retriever": 13.2,
28
+ "yorkshire terrier": 13.3,
29
+ # etc.
30
  }
31
 
 
32
  QUESTIONNAIRE = [
33
  {"domain": "Mobility", "questions": [
34
  "Does your dog have difficulty rising from lying down?",
 
52
  ]}
53
  ]
54
 
 
55
  SCALE = ["0", "1", "2", "3", "4", "5"]
56
 
57
+
58
  def predict_biological_age(image: Image.Image, breed: str) -> int:
59
  avg = BREED_LIFESPAN.get(breed.lower(), 12)
60
+ prompts = [f"a {age}-year-old {breed}" for age in range(1, int(avg * 2) + 1)]
61
  inputs = clip_processor(text=prompts, images=image, return_tensors="pt", padding=True).to(device)
62
  with torch.no_grad():
63
  logits = clip_model(**inputs).logits_per_image.softmax(dim=1)[0].cpu().numpy()
64
  return int(np.argmax(logits) + 1)
65
 
66
+
67
  def analyze_medical_image(image: Image.Image):
68
  inputs = medgemma_processor(images=image, return_tensors="pt").to(device)
69
  with torch.no_grad():
 
73
  conf = float(np.max(probs))
74
  return label, conf
75
 
76
+
77
  def classify_breed_and_health(image: Image.Image, user_breed=None):
 
78
  inputs = clip_processor(images=image, return_tensors="pt").to(device)
79
  with torch.no_grad():
80
  img_feats = clip_model.get_image_features(**inputs)
 
 
81
  texts = [f"a photo of a {b}" for b in STANFORD_BREEDS]
82
  t_in = clip_processor(text=texts, return_tensors="pt", padding=True).to(device)
83
  with torch.no_grad():
 
87
  breed = user_breed or STANFORD_BREEDS[idx]
88
  breed_conf = float(sims[idx])
89
 
 
90
  aspects = {
91
  "Coat": ("shiny healthy coat", "dull patchy fur"),
92
  "Eyes": ("bright clear eyes", "cloudy milky eyes"),
93
+ "Body": ("ideal muscle tone", "visible ribs or bones"),
94
  "Teeth": ("clean white teeth", "yellow stained teeth")
95
  }
96
  health = {}
 
103
  health[name] = {"assessment": choice, "confidence": float(max(sim))}
104
  return breed, breed_conf, health
105
 
106
+
107
  def analyze_video_health(video_path: str):
108
  cap = cv2.VideoCapture(video_path)
109
  fps = cap.get(cv2.CAP_PROP_FPS) or 24
110
+ total = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
111
+ duration = total / fps
112
+ indices = np.linspace(0, total - 1, num=10, dtype=int)
113
+ scores = []
 
114
  for i in indices:
115
  cap.set(cv2.CAP_PROP_POS_FRAMES, i)
116
  ret, frame = cap.read()
117
+ if not ret:
118
+ break
119
  img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
120
  _, conf = analyze_medical_image(img)
121
+ scores.append(conf)
122
  cap.release()
123
+ return {"duration_sec": round(duration, 1), "avg_gait_confidence": float(np.mean(scores))}
124
+
125
 
126
  def compute_questionnaire_score(answers: list):
 
127
  scores = {}
128
  idx = 0
129
+ for sec in QUESTIONNAIRE:
130
+ n = len(sec["questions"])
131
+ vals = list(map(int, answers[idx: idx + n]))
132
+ idx += n
133
+ scores[sec["domain"]] = round(sum(vals) / n, 2)
134
  return scores
135
 
136
+
137
  with gr.Blocks(title="🐶 Dog Health & Age Analyzer") as demo:
138
+ gr.Markdown("## Upload Image or Video, or Record a Short Clip")
139
 
140
  with gr.Tab("Image Analysis"):
141
  img_in = gr.Image(type="pil", label="Upload Dog Image")
142
  breed_in = gr.Textbox(label="(Optional) Override Breed")
143
  age_in = gr.Number(label="Chronological Age (years)", precision=1)
144
+ btn = gr.Button("Analyze")
145
+ out = gr.Markdown()
146
 
147
+ def run_image(img, override, chrono):
148
+ breed, b_conf, health = classify_breed_and_health(img, override)
149
  med_label, med_conf = analyze_medical_image(img)
150
  bio_age = predict_biological_age(img, breed)
151
+ pace = round(bio_age / chrono, 2) if chrono else None
152
+ rpt = f"**Breed:** {breed} ({b_conf:.1%}) \n"
153
+ rpt += f"**MedGemma Finding:** {med_label} ({med_conf:.1%}) \n\n"
154
+ rpt += f"**Biological Age:** {bio_age} yrs \n"
155
+ rpt += f"**Chronological Age:** {chrono or 'N/A'} yrs \n"
 
156
  if pace:
157
+ rpt += f"**Pace of Aging:** {pace}× \n\n"
158
+ rpt += "### Health Aspects\n"
159
  for k, v in health.items():
160
+ rpt += f"- **{k}:** {v['assessment']} ({v['confidence']:.1%})\n"
161
+ return rpt
162
 
163
+ btn.click(run_image, inputs=[img_in, breed_in, age_in], outputs=out)
164
 
165
  with gr.Tab("Video Analysis"):
166
+ vid_in = gr.Video(label="Upload or Record Video (10–30s)")
167
+ btn2 = gr.Button("Analyze Video")
168
  vid_out = gr.JSON()
169
+ btn2.click(lambda v: analyze_video_health(v), inputs=vid_in, outputs=vid_out)
170
 
171
+ with gr.Tab("Questionnaire"):
 
 
172
  widgets = []
173
+ for sec in QUESTIONNAIRE:
174
+ gr.Markdown(f"### {sec['domain']}")
175
+ for q in sec["questions"]:
176
  w = gr.Radio(choices=SCALE, label=q)
177
  widgets.append(w)
178
+ btn3 = gr.Button("Compute Score")
179
+ out_q = gr.JSON()
180
+ btn3.click(compute_questionnaire_score, inputs=widgets, outputs=out_q)
 
 
 
 
 
181
 
182
  with gr.Tab("About"):
183
  gr.Markdown("""