Spaces:
Sleeping
Sleeping
Siddharth Mishra commited on
Commit Β·
b1b29cb
1
Parent(s): 0e171ce
ae OOD
Browse files- app.py +245 -18
- requirements.txt +2 -1
app.py
CHANGED
|
@@ -1,32 +1,61 @@
|
|
| 1 |
-
# app.py for Gradio Space with Gemini 2.5 Flash Integration +
|
| 2 |
import gradio as gr
|
| 3 |
import torch
|
|
|
|
| 4 |
from PIL import Image
|
| 5 |
from torchvision import transforms
|
| 6 |
from huggingface_hub import hf_hub_download
|
| 7 |
from model import StoolNetTriple
|
| 8 |
import os
|
|
|
|
|
|
|
|
|
|
| 9 |
from google import genai
|
| 10 |
|
| 11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
# ========================================
|
| 13 |
# MODEL SETUP - Download from HF Hub
|
| 14 |
# ========================================
|
| 15 |
-
HF_TOKEN=os.getenv("HF_TOKEN")
|
| 16 |
|
| 17 |
print("Downloading model from Hugging Face Hub...")
|
| 18 |
model_path = hf_hub_download(
|
| 19 |
repo_id="Sid3503/stoolnet-bristol-scale-triple-attn",
|
| 20 |
filename="pytorch_model.bin",
|
| 21 |
-
token=HF_TOKEN
|
| 22 |
)
|
| 23 |
|
| 24 |
print("Loading model...")
|
|
|
|
| 25 |
model = StoolNetTriple()
|
| 26 |
-
state = torch.load(model_path, map_location=
|
| 27 |
model.load_state_dict(state)
|
| 28 |
model.eval()
|
| 29 |
-
|
|
|
|
| 30 |
|
| 31 |
# Define transform
|
| 32 |
transform = transforms.Compose([
|
|
@@ -36,12 +65,118 @@ transform = transforms.Compose([
|
|
| 36 |
])
|
| 37 |
|
| 38 |
|
| 39 |
-
#
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
|
| 46 |
|
| 47 |
# ========================================
|
|
@@ -117,6 +252,7 @@ if not GEMINI_API_KEY:
|
|
| 117 |
else:
|
| 118 |
try:
|
| 119 |
gemini_client = genai.Client(api_key=GEMINI_API_KEY)
|
|
|
|
| 120 |
except Exception as e:
|
| 121 |
print(f"Error initializing Gemini client: {e}")
|
| 122 |
gemini_client = None
|
|
@@ -133,14 +269,18 @@ def generate_gemini_prompt(type_name, shape_name, color_name, type_conf, shape_c
|
|
| 133 |
color_desc = COLOR_DESCRIPTIONS[color_name]
|
| 134 |
|
| 135 |
prompt = f"""You are a board-certified gastroenterologist with over 15 years of clinical experience specializing in digestive health and bowel disorders. A gastroenterologist is a medical doctor who specializes in the diagnosis and treatment of disorders of the digestive system, which includes organs from the mouth to the anus. They treat a wide range of conditions, such as irritable bowel syndrome (IBS), ulcers, heartburn, and liver diseases. To do so, they use a combination of clinical examinations, blood tests, imaging, and procedures like endoscopy.
|
|
|
|
| 136 |
**What You Do as a Gastroenterologist:**
|
| 137 |
**Diagnose and treat digestive disorders:** You identify and manage diseases affecting the esophagus, stomach, intestines, pancreas, liver, gallbladder, and bile ducts, with particular expertise in stool-related conditions and bowel health.
|
| 138 |
**Perform diagnostic procedures:** You utilize tools like endoscopes, CT scans, MRIs, and ultrasounds to examine the digestive tract, and you are highly skilled in analyzing stool characteristics as diagnostic indicators.
|
| 139 |
**Manage complex conditions:** You handle chronic diseases like hepatitis, colitis, and pancreatitis, as well as cancer and nutritional problems, with extensive experience in conditions that affect stool consistency, frequency, and appearance.
|
| 140 |
**Provide treatment:** You prescribe medication and recommend dietary modifications, lifestyle changes, fiber supplementation, and hydration strategies specifically tailored to improve stool consistency and bowel regularity. You also perform endoscopic procedures like colonoscopy and sigmoidoscopy when stool analysis indicates the need for further investigation.
|
|
|
|
| 141 |
You have a warm, empathetic approach and excel at explaining complex medical concepts in accessible language. Your patients appreciate your thoroughness, compassion, and practical guidance.
|
|
|
|
| 142 |
**YOUR ROLE:**
|
| 143 |
Provide a comprehensive, evidence-based analysis of the Bristol Stool Chart classification while maintaining a supportive, non-judgmental tone. Your goal is to educate, reassure, and empower the patient with actionable insights based on your extensive experience in stool analysis and bowel health.
|
|
|
|
| 144 |
**REASONING FRAMEWORK (Chain of Thought):**
|
| 145 |
Before providing your analysis, consider:
|
| 146 |
1. What does this stool type indicate about gut transit time?
|
|
@@ -148,47 +288,68 @@ Before providing your analysis, consider:
|
|
| 148 |
3. What immediate and long-term health implications should be addressed?
|
| 149 |
4. What evidence-based interventions are most effective?
|
| 150 |
5. When should professional medical evaluation be prioritized?
|
|
|
|
| 151 |
---
|
|
|
|
| 152 |
**CURRENT CLASSIFICATION RESULT:**
|
|
|
|
| 153 |
**Bristol Stool Type:** {type_name}
|
| 154 |
**Description:** {type_info['description']}
|
| 155 |
**Clinical Significance:** {type_info['condition']}
|
| 156 |
**Confidence:** {type_conf:.1f}%
|
|
|
|
| 157 |
**Stool Shape:** {shape_name}
|
| 158 |
**Shape Analysis:** {shape_desc}
|
| 159 |
**Shape Confidence:** {shape_conf:.1f}%
|
|
|
|
| 160 |
**Stool Color:** {color_name}
|
| 161 |
**Color Analysis:** {color_desc}
|
| 162 |
**Color Confidence:** {color_conf:.1f}%
|
|
|
|
| 163 |
---
|
|
|
|
| 164 |
**INSTRUCTIONS:**
|
| 165 |
Provide a comprehensive gastroenterological analysis. Structure your response naturally with appropriate markdown headers (##, ###) for main sections. Do NOT include instructional labels like "Warm, Professional Greeting" or "Encouragement & Empowerment" as headers - these are content guidelines, not section titles to display.
|
|
|
|
| 166 |
Your response should naturally flow through these topics:
|
|
|
|
| 167 |
1. Begin with a warm, professional greeting that acknowledges the person compassionately
|
|
|
|
| 168 |
2. Explain the Bristol Type classification in accessible terms, including what it indicates about gut transit time
|
|
|
|
| 169 |
3. **IMPORTANT:** Integrate the shape analysis ({shape_name}: {shape_desc}) and color analysis ({color_name}: {color_desc}) into your explanation, discussing how these characteristics provide additional clinical insights
|
|
|
|
| 170 |
4. Describe the physiological mechanisms at play (use analogies where helpful)
|
|
|
|
| 171 |
5. Explain clinical implications, both short-term and long-term health considerations, taking into account the combination of type, shape, and color
|
|
|
|
| 172 |
6. Provide an action plan divided into:
|
| 173 |
- Immediate Steps (24-72 hours)
|
| 174 |
- Medium-Term Strategy (1-4 weeks)
|
| 175 |
- Long-term Maintenance
|
|
|
|
| 176 |
7. Include evidence-based recommendations covering:
|
| 177 |
- Specific dietary changes with examples
|
| 178 |
- Hydration guidelines
|
| 179 |
- Physical activity suggestions
|
| 180 |
- Lifestyle modifications
|
| 181 |
- Supplement considerations (if appropriate)
|
|
|
|
| 182 |
8. Provide clear criteria for when to seek medical attention, including red flags (pay special attention if color is abnormal)
|
|
|
|
| 183 |
9. Set timeline expectations - what changes to expect and when
|
|
|
|
| 184 |
10. End with supportive closing remarks emphasizing patient agency
|
|
|
|
| 185 |
Use descriptive section headers like "Understanding Your Classification", "What's Happening in Your Body", "Your Action Plan", etc.
|
|
|
|
| 186 |
**TONE GUIDELINES:**
|
| 187 |
- Warm, empathetic, non-judgmental
|
| 188 |
- Professional yet accessible
|
| 189 |
- Evidence-based but not overly technical
|
| 190 |
- Empowering and action-oriented
|
| 191 |
- Balanced (acknowledge concerns without causing alarm)
|
|
|
|
| 192 |
**FORMATTING:**
|
| 193 |
- Use clear markdown headers (##, ###) and subheaders
|
| 194 |
- Bullet points for actionable items
|
|
@@ -196,6 +357,7 @@ Use descriptive section headers like "Understanding Your Classification", "What'
|
|
| 196 |
- Maintain readability with short paragraphs
|
| 197 |
- Do NOT include HTML tags - use markdown only
|
| 198 |
- Do NOT repeat section instruction labels as headers
|
|
|
|
| 199 |
Please provide your comprehensive analysis now."""
|
| 200 |
|
| 201 |
return prompt
|
|
@@ -205,14 +367,39 @@ Please provide your comprehensive analysis now."""
|
|
| 205 |
# PREDICTION FUNCTION
|
| 206 |
# ========================================
|
| 207 |
def predict(image):
|
| 208 |
-
"""Predict Bristol type, shape, color, and get detailed AI analysis."""
|
| 209 |
if image is None:
|
| 210 |
return None, None, None, "β οΈ **Please upload an image to analyze.**"
|
| 211 |
|
| 212 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 213 |
# Preprocess and run inference
|
| 214 |
img = image.convert("RGB")
|
| 215 |
-
x = transform(img).unsqueeze(0)
|
| 216 |
|
| 217 |
with torch.no_grad():
|
| 218 |
type_out, shape_out, color_out = model(x)
|
|
@@ -239,18 +426,29 @@ def predict(image):
|
|
| 239 |
# Generate AI analysis
|
| 240 |
if gemini_client is None:
|
| 241 |
analysis = f"""## β οΈ AI Analysis Unavailable
|
|
|
|
| 242 |
**Classification Summary:**
|
|
|
|
| 243 |
{BRISTOL_DESCRIPTIONS[type_name]['emoji']} **{type_name}**
|
| 244 |
- **Description:** {BRISTOL_DESCRIPTIONS[type_name]['description']}
|
| 245 |
- **Condition:** {BRISTOL_DESCRIPTIONS[type_name]['condition']}
|
| 246 |
- **Confidence:** {type_conf:.1f}%
|
|
|
|
| 247 |
**Shape:** {shape_name} ({shape_conf:.1f}% confidence)
|
| 248 |
- {SHAPE_DESCRIPTIONS[shape_name]}
|
|
|
|
| 249 |
**Color:** {color_name} ({color_conf:.1f}% confidence)
|
| 250 |
- {COLOR_DESCRIPTIONS[color_name]}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
---
|
|
|
|
| 252 |
*Note: Set GEMINI_API_KEY environment variable to enable detailed AI-powered gastroenterological analysis.*
|
|
|
|
| 253 |
### Quick Health Tips Based on Your Classification:
|
|
|
|
| 254 |
**For {type_name}:**
|
| 255 |
- {'Increase fiber intake and hydration' if 'Type 1' in type_name or 'Type 2' in type_name else 'Maintain balanced diet and regular exercise'}
|
| 256 |
- {'Consider consulting a gastroenterologist if symptoms persist' if 'Type 1' in type_name or 'Type 7' in type_name else 'Monitor changes over time'}
|
|
@@ -263,29 +461,48 @@ def predict(image):
|
|
| 263 |
)
|
| 264 |
|
| 265 |
response = gemini_client.models.generate_content(
|
| 266 |
-
model="gemini-2.
|
| 267 |
contents=prompt
|
| 268 |
)
|
| 269 |
|
| 270 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 271 |
|
| 272 |
except Exception as e:
|
| 273 |
analysis = f"""## β οΈ Error Generating AI Analysis
|
|
|
|
| 274 |
**Error:** {str(e)}
|
|
|
|
| 275 |
**Classification Summary:**
|
|
|
|
| 276 |
{BRISTOL_DESCRIPTIONS[type_name]['emoji']} **{type_name}**
|
| 277 |
- **Description:** {BRISTOL_DESCRIPTIONS[type_name]['description']}
|
| 278 |
- **Condition:** {BRISTOL_DESCRIPTIONS[type_name]['condition']}
|
| 279 |
- **Confidence:** {type_conf:.1f}%
|
|
|
|
| 280 |
**Shape:** {shape_name} ({shape_conf:.1f}% confidence)
|
| 281 |
**Color:** {color_name} ({color_conf:.1f}% confidence)
|
|
|
|
|
|
|
| 282 |
"""
|
| 283 |
|
| 284 |
return type_dict, shape_dict, color_dict, analysis
|
| 285 |
|
| 286 |
except Exception as e:
|
| 287 |
error_msg = f"""## β Error Processing Image
|
|
|
|
| 288 |
**Error:** {str(e)}
|
|
|
|
| 289 |
Please ensure you've uploaded a valid image file and try again.
|
| 290 |
"""
|
| 291 |
return None, None, None, error_msg
|
|
@@ -321,9 +538,10 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
|
|
| 321 |
gr.Markdown("""
|
| 322 |
# π₯ StoolNet Triple Attention β AI-Powered Bristol Stool Scale Classifier
|
| 323 |
|
| 324 |
-
### Advanced Multi-Task Deep Learning Model
|
| 325 |
|
| 326 |
-
This application combines **Triple Attention ResNet34** with **Google Gemini 2.
|
|
|
|
| 327 |
""")
|
| 328 |
|
| 329 |
# ========================================
|
|
@@ -342,6 +560,8 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
|
|
| 342 |
1. Upload your image OR select from samples below
|
| 343 |
2. Click "Analyze Sample"
|
| 344 |
3. View results on the right
|
|
|
|
|
|
|
| 345 |
""")
|
| 346 |
|
| 347 |
# Sample Images Section
|
|
@@ -397,9 +617,16 @@ with gr.Blocks(theme=gr.themes.Soft(), css="""
|
|
| 397 |
### π¬ Model Information
|
| 398 |
|
| 399 |
**Architecture:** Triple Attention ResNet34 (Position, Channel, Type Attention) + Multi-Task Learning
|
| 400 |
-
**AI Analysis:** Powered by Google Gemini 2.
|
|
|
|
| 401 |
**Model Repository:** [Sid3503/stoolnet-bristol-scale-triple-attn](https://huggingface.co/Sid3503/stoolnet-bristol-scale-triple-attn)
|
| 402 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 403 |
### π Bristol Stool Scale Quick Reference
|
| 404 |
|
| 405 |
| Type | Description | Indication |
|
|
|
|
| 1 |
+
# app.py for Gradio Space with Gemini 2.5 Flash Integration + OOD Detection
|
| 2 |
import gradio as gr
|
| 3 |
import torch
|
| 4 |
+
import torch.nn as nn
|
| 5 |
from PIL import Image
|
| 6 |
from torchvision import transforms
|
| 7 |
from huggingface_hub import hf_hub_download
|
| 8 |
from model import StoolNetTriple
|
| 9 |
import os
|
| 10 |
+
import numpy as np
|
| 11 |
+
import json
|
| 12 |
+
import joblib
|
| 13 |
from google import genai
|
| 14 |
|
| 15 |
|
| 16 |
+
# ========================================
|
| 17 |
+
# FEATURE AUTOENCODER ARCHITECTURE
|
| 18 |
+
# ========================================
|
| 19 |
+
class FeatureAutoencoder(nn.Module):
|
| 20 |
+
def __init__(self, input_dim: int = 512, latent_dim: int = 128, hidden_dim: int = 256):
|
| 21 |
+
super().__init__()
|
| 22 |
+
self.encoder = nn.Sequential(
|
| 23 |
+
nn.Linear(input_dim, hidden_dim),
|
| 24 |
+
nn.ReLU(inplace=True),
|
| 25 |
+
nn.Linear(hidden_dim, latent_dim),
|
| 26 |
+
)
|
| 27 |
+
self.decoder = nn.Sequential(
|
| 28 |
+
nn.Linear(latent_dim, hidden_dim),
|
| 29 |
+
nn.ReLU(inplace=True),
|
| 30 |
+
nn.Linear(hidden_dim, input_dim),
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 34 |
+
z = self.encoder(x)
|
| 35 |
+
xhat = self.decoder(z)
|
| 36 |
+
return xhat
|
| 37 |
+
|
| 38 |
+
|
| 39 |
# ========================================
|
| 40 |
# MODEL SETUP - Download from HF Hub
|
| 41 |
# ========================================
|
| 42 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 43 |
|
| 44 |
print("Downloading model from Hugging Face Hub...")
|
| 45 |
model_path = hf_hub_download(
|
| 46 |
repo_id="Sid3503/stoolnet-bristol-scale-triple-attn",
|
| 47 |
filename="pytorch_model.bin",
|
| 48 |
+
token=HF_TOKEN
|
| 49 |
)
|
| 50 |
|
| 51 |
print("Loading model...")
|
| 52 |
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 53 |
model = StoolNetTriple()
|
| 54 |
+
state = torch.load(model_path, map_location=device)
|
| 55 |
model.load_state_dict(state)
|
| 56 |
model.eval()
|
| 57 |
+
model = model.to(device)
|
| 58 |
+
print(f"Model loaded successfully on {device}!")
|
| 59 |
|
| 60 |
# Define transform
|
| 61 |
transform = transforms.Compose([
|
|
|
|
| 65 |
])
|
| 66 |
|
| 67 |
|
| 68 |
+
# ========================================
|
| 69 |
+
# LOAD AUTOENCODER ARTIFACTS FOR OOD DETECTION
|
| 70 |
+
# ========================================
|
| 71 |
+
print("Loading autoencoder artifacts for outlier detection...")
|
| 72 |
+
ae_dir = 'ae_artifacts_triple_attn'
|
| 73 |
+
ae_path = os.path.join(ae_dir, 'feature_ae.pth')
|
| 74 |
+
scaler_path = os.path.join(ae_dir, 'scaler.pkl')
|
| 75 |
+
thr_path = os.path.join(ae_dir, 'threshold.json')
|
| 76 |
+
|
| 77 |
+
feature_ae = None
|
| 78 |
+
feature_ae_scaler = None
|
| 79 |
+
feature_ae_threshold = None
|
| 80 |
+
|
| 81 |
+
try:
|
| 82 |
+
if os.path.isfile(ae_path) and os.path.isfile(scaler_path) and os.path.isfile(thr_path):
|
| 83 |
+
# Load autoencoder
|
| 84 |
+
feature_ae = FeatureAutoencoder(input_dim=512, latent_dim=128, hidden_dim=256).to(device)
|
| 85 |
+
ae_state = torch.load(ae_path, map_location=device)
|
| 86 |
+
feature_ae.load_state_dict(ae_state['model_state_dict'])
|
| 87 |
+
feature_ae.eval()
|
| 88 |
+
|
| 89 |
+
# Load scaler
|
| 90 |
+
feature_ae_scaler = joblib.load(scaler_path)
|
| 91 |
+
|
| 92 |
+
# Load threshold
|
| 93 |
+
with open(thr_path, 'r') as f:
|
| 94 |
+
thr_data = json.load(f)
|
| 95 |
+
feature_ae_threshold = float(thr_data.get('threshold', 0.0))
|
| 96 |
+
|
| 97 |
+
print(f"β Autoencoder artifacts loaded successfully (threshold: {feature_ae_threshold:.5f})")
|
| 98 |
+
else:
|
| 99 |
+
print("β Autoencoder artifact files not found. OOD detection will be disabled.")
|
| 100 |
+
except Exception as e:
|
| 101 |
+
print(f"β Error loading autoencoder: {e}")
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
# ========================================
|
| 105 |
+
# FEATURE EXTRACTION FUNCTION
|
| 106 |
+
# ========================================
|
| 107 |
+
@torch.no_grad()
|
| 108 |
+
def extract_feature_vector(image: Image.Image) -> np.ndarray:
|
| 109 |
+
"""Extract 512-D feature vector from StoolNetTriple model"""
|
| 110 |
+
image_tensor = transform(image).unsqueeze(0).to(device)
|
| 111 |
+
|
| 112 |
+
# Forward pass through backbone
|
| 113 |
+
x = model.conv1(image_tensor)
|
| 114 |
+
x = model.bn1(x)
|
| 115 |
+
x = model.relu(x)
|
| 116 |
+
x = model.maxpool(x)
|
| 117 |
+
x = model.layer1(x)
|
| 118 |
+
x = model.layer2(x)
|
| 119 |
+
x = model.layer3(x)
|
| 120 |
+
x = model.layer4(x)
|
| 121 |
+
|
| 122 |
+
# Pass through triple attention
|
| 123 |
+
x, _ = model.triple_attention(x)
|
| 124 |
+
|
| 125 |
+
# Global average pooling
|
| 126 |
+
x = model.avgpool(x)
|
| 127 |
+
feats = torch.flatten(x, 1)
|
| 128 |
+
|
| 129 |
+
# Normalize features
|
| 130 |
+
feats = torch.nn.functional.normalize(feats, dim=1)
|
| 131 |
+
return feats.squeeze(0).cpu().numpy()
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
# ========================================
|
| 135 |
+
# OUTLIER DETECTION FUNCTION
|
| 136 |
+
# ========================================
|
| 137 |
+
def check_outlier(image: Image.Image) -> dict:
|
| 138 |
+
"""Check if image is an outlier using autoencoder reconstruction error"""
|
| 139 |
+
if feature_ae is None or feature_ae_scaler is None or feature_ae_threshold is None:
|
| 140 |
+
return {
|
| 141 |
+
'is_outlier': False,
|
| 142 |
+
'ae_residual': None,
|
| 143 |
+
'ae_threshold': None,
|
| 144 |
+
'message': None
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
try:
|
| 148 |
+
# Extract feature vector
|
| 149 |
+
fv = extract_feature_vector(image).astype(np.float32)
|
| 150 |
+
|
| 151 |
+
# Standardize features
|
| 152 |
+
fv_std = feature_ae_scaler.transform(fv.reshape(1, -1)).astype(np.float32)
|
| 153 |
+
|
| 154 |
+
# Compute reconstruction error
|
| 155 |
+
x = torch.from_numpy(fv_std).to(device)
|
| 156 |
+
with torch.no_grad():
|
| 157 |
+
recon = feature_ae(x)
|
| 158 |
+
ae_residual = torch.mean((recon - x) ** 2, dim=1).item()
|
| 159 |
+
|
| 160 |
+
# Check if outlier
|
| 161 |
+
is_outlier = ae_residual > feature_ae_threshold
|
| 162 |
+
|
| 163 |
+
return {
|
| 164 |
+
'is_outlier': is_outlier,
|
| 165 |
+
'ae_residual': ae_residual,
|
| 166 |
+
'ae_threshold': feature_ae_threshold,
|
| 167 |
+
'message': (
|
| 168 |
+
f"β οΈ **Outlier Detected**: This image does not appear to be a valid stool sample. "
|
| 169 |
+
f"Reconstruction error ({ae_residual:.5f}) exceeds threshold ({feature_ae_threshold:.5f})."
|
| 170 |
+
) if is_outlier else None
|
| 171 |
+
}
|
| 172 |
+
except Exception as e:
|
| 173 |
+
print(f"Error in outlier detection: {e}")
|
| 174 |
+
return {
|
| 175 |
+
'is_outlier': False,
|
| 176 |
+
'ae_residual': None,
|
| 177 |
+
'ae_threshold': None,
|
| 178 |
+
'message': None
|
| 179 |
+
}
|
| 180 |
|
| 181 |
|
| 182 |
# ========================================
|
|
|
|
| 252 |
else:
|
| 253 |
try:
|
| 254 |
gemini_client = genai.Client(api_key=GEMINI_API_KEY)
|
| 255 |
+
print("β Gemini API client initialized")
|
| 256 |
except Exception as e:
|
| 257 |
print(f"Error initializing Gemini client: {e}")
|
| 258 |
gemini_client = None
|
|
|
|
| 269 |
color_desc = COLOR_DESCRIPTIONS[color_name]
|
| 270 |
|
| 271 |
prompt = f"""You are a board-certified gastroenterologist with over 15 years of clinical experience specializing in digestive health and bowel disorders. A gastroenterologist is a medical doctor who specializes in the diagnosis and treatment of disorders of the digestive system, which includes organs from the mouth to the anus. They treat a wide range of conditions, such as irritable bowel syndrome (IBS), ulcers, heartburn, and liver diseases. To do so, they use a combination of clinical examinations, blood tests, imaging, and procedures like endoscopy.
|
| 272 |
+
|
| 273 |
**What You Do as a Gastroenterologist:**
|
| 274 |
**Diagnose and treat digestive disorders:** You identify and manage diseases affecting the esophagus, stomach, intestines, pancreas, liver, gallbladder, and bile ducts, with particular expertise in stool-related conditions and bowel health.
|
| 275 |
**Perform diagnostic procedures:** You utilize tools like endoscopes, CT scans, MRIs, and ultrasounds to examine the digestive tract, and you are highly skilled in analyzing stool characteristics as diagnostic indicators.
|
| 276 |
**Manage complex conditions:** You handle chronic diseases like hepatitis, colitis, and pancreatitis, as well as cancer and nutritional problems, with extensive experience in conditions that affect stool consistency, frequency, and appearance.
|
| 277 |
**Provide treatment:** You prescribe medication and recommend dietary modifications, lifestyle changes, fiber supplementation, and hydration strategies specifically tailored to improve stool consistency and bowel regularity. You also perform endoscopic procedures like colonoscopy and sigmoidoscopy when stool analysis indicates the need for further investigation.
|
| 278 |
+
|
| 279 |
You have a warm, empathetic approach and excel at explaining complex medical concepts in accessible language. Your patients appreciate your thoroughness, compassion, and practical guidance.
|
| 280 |
+
|
| 281 |
**YOUR ROLE:**
|
| 282 |
Provide a comprehensive, evidence-based analysis of the Bristol Stool Chart classification while maintaining a supportive, non-judgmental tone. Your goal is to educate, reassure, and empower the patient with actionable insights based on your extensive experience in stool analysis and bowel health.
|
| 283 |
+
|
| 284 |
**REASONING FRAMEWORK (Chain of Thought):**
|
| 285 |
Before providing your analysis, consider:
|
| 286 |
1. What does this stool type indicate about gut transit time?
|
|
|
|
| 288 |
3. What immediate and long-term health implications should be addressed?
|
| 289 |
4. What evidence-based interventions are most effective?
|
| 290 |
5. When should professional medical evaluation be prioritized?
|
| 291 |
+
|
| 292 |
---
|
| 293 |
+
|
| 294 |
**CURRENT CLASSIFICATION RESULT:**
|
| 295 |
+
|
| 296 |
**Bristol Stool Type:** {type_name}
|
| 297 |
**Description:** {type_info['description']}
|
| 298 |
**Clinical Significance:** {type_info['condition']}
|
| 299 |
**Confidence:** {type_conf:.1f}%
|
| 300 |
+
|
| 301 |
**Stool Shape:** {shape_name}
|
| 302 |
**Shape Analysis:** {shape_desc}
|
| 303 |
**Shape Confidence:** {shape_conf:.1f}%
|
| 304 |
+
|
| 305 |
**Stool Color:** {color_name}
|
| 306 |
**Color Analysis:** {color_desc}
|
| 307 |
**Color Confidence:** {color_conf:.1f}%
|
| 308 |
+
|
| 309 |
---
|
| 310 |
+
|
| 311 |
**INSTRUCTIONS:**
|
| 312 |
Provide a comprehensive gastroenterological analysis. Structure your response naturally with appropriate markdown headers (##, ###) for main sections. Do NOT include instructional labels like "Warm, Professional Greeting" or "Encouragement & Empowerment" as headers - these are content guidelines, not section titles to display.
|
| 313 |
+
|
| 314 |
Your response should naturally flow through these topics:
|
| 315 |
+
|
| 316 |
1. Begin with a warm, professional greeting that acknowledges the person compassionately
|
| 317 |
+
|
| 318 |
2. Explain the Bristol Type classification in accessible terms, including what it indicates about gut transit time
|
| 319 |
+
|
| 320 |
3. **IMPORTANT:** Integrate the shape analysis ({shape_name}: {shape_desc}) and color analysis ({color_name}: {color_desc}) into your explanation, discussing how these characteristics provide additional clinical insights
|
| 321 |
+
|
| 322 |
4. Describe the physiological mechanisms at play (use analogies where helpful)
|
| 323 |
+
|
| 324 |
5. Explain clinical implications, both short-term and long-term health considerations, taking into account the combination of type, shape, and color
|
| 325 |
+
|
| 326 |
6. Provide an action plan divided into:
|
| 327 |
- Immediate Steps (24-72 hours)
|
| 328 |
- Medium-Term Strategy (1-4 weeks)
|
| 329 |
- Long-term Maintenance
|
| 330 |
+
|
| 331 |
7. Include evidence-based recommendations covering:
|
| 332 |
- Specific dietary changes with examples
|
| 333 |
- Hydration guidelines
|
| 334 |
- Physical activity suggestions
|
| 335 |
- Lifestyle modifications
|
| 336 |
- Supplement considerations (if appropriate)
|
| 337 |
+
|
| 338 |
8. Provide clear criteria for when to seek medical attention, including red flags (pay special attention if color is abnormal)
|
| 339 |
+
|
| 340 |
9. Set timeline expectations - what changes to expect and when
|
| 341 |
+
|
| 342 |
10. End with supportive closing remarks emphasizing patient agency
|
| 343 |
+
|
| 344 |
Use descriptive section headers like "Understanding Your Classification", "What's Happening in Your Body", "Your Action Plan", etc.
|
| 345 |
+
|
| 346 |
**TONE GUIDELINES:**
|
| 347 |
- Warm, empathetic, non-judgmental
|
| 348 |
- Professional yet accessible
|
| 349 |
- Evidence-based but not overly technical
|
| 350 |
- Empowering and action-oriented
|
| 351 |
- Balanced (acknowledge concerns without causing alarm)
|
| 352 |
+
|
| 353 |
**FORMATTING:**
|
| 354 |
- Use clear markdown headers (##, ###) and subheaders
|
| 355 |
- Bullet points for actionable items
|
|
|
|
| 357 |
- Maintain readability with short paragraphs
|
| 358 |
- Do NOT include HTML tags - use markdown only
|
| 359 |
- Do NOT repeat section instruction labels as headers
|
| 360 |
+
|
| 361 |
Please provide your comprehensive analysis now."""
|
| 362 |
|
| 363 |
return prompt
|
|
|
|
| 367 |
# PREDICTION FUNCTION
|
| 368 |
# ========================================
|
| 369 |
def predict(image):
|
| 370 |
+
"""Predict Bristol type, shape, color, check for outliers, and get detailed AI analysis."""
|
| 371 |
if image is None:
|
| 372 |
return None, None, None, "β οΈ **Please upload an image to analyze.**"
|
| 373 |
|
| 374 |
try:
|
| 375 |
+
# Check for outliers first
|
| 376 |
+
outlier_result = check_outlier(image)
|
| 377 |
+
|
| 378 |
+
if outlier_result['is_outlier']:
|
| 379 |
+
# Return outlier warning without predictions
|
| 380 |
+
outlier_message = f"""## β οΈ Invalid Image Detected
|
| 381 |
+
|
| 382 |
+
{outlier_result['message']}
|
| 383 |
+
|
| 384 |
+
### Quality Check Details:
|
| 385 |
+
- **Reconstruction Error:** {outlier_result['ae_residual']:.5f}
|
| 386 |
+
- **Threshold:** {outlier_result['ae_threshold']:.5f}
|
| 387 |
+
|
| 388 |
+
**Please upload a clear image of a stool sample for accurate analysis.**
|
| 389 |
+
|
| 390 |
+
---
|
| 391 |
+
|
| 392 |
+
**Tips for Better Images:**
|
| 393 |
+
- Ensure good lighting
|
| 394 |
+
- Image should clearly show stool sample
|
| 395 |
+
- Avoid blurry or unclear images
|
| 396 |
+
- Image should contain actual stool content
|
| 397 |
+
"""
|
| 398 |
+
return None, None, None, outlier_message
|
| 399 |
+
|
| 400 |
# Preprocess and run inference
|
| 401 |
img = image.convert("RGB")
|
| 402 |
+
x = transform(img).unsqueeze(0).to(device)
|
| 403 |
|
| 404 |
with torch.no_grad():
|
| 405 |
type_out, shape_out, color_out = model(x)
|
|
|
|
| 426 |
# Generate AI analysis
|
| 427 |
if gemini_client is None:
|
| 428 |
analysis = f"""## β οΈ AI Analysis Unavailable
|
| 429 |
+
|
| 430 |
**Classification Summary:**
|
| 431 |
+
|
| 432 |
{BRISTOL_DESCRIPTIONS[type_name]['emoji']} **{type_name}**
|
| 433 |
- **Description:** {BRISTOL_DESCRIPTIONS[type_name]['description']}
|
| 434 |
- **Condition:** {BRISTOL_DESCRIPTIONS[type_name]['condition']}
|
| 435 |
- **Confidence:** {type_conf:.1f}%
|
| 436 |
+
|
| 437 |
**Shape:** {shape_name} ({shape_conf:.1f}% confidence)
|
| 438 |
- {SHAPE_DESCRIPTIONS[shape_name]}
|
| 439 |
+
|
| 440 |
**Color:** {color_name} ({color_conf:.1f}% confidence)
|
| 441 |
- {COLOR_DESCRIPTIONS[color_name]}
|
| 442 |
+
|
| 443 |
+
**Quality Check:** β
Image passed outlier detection
|
| 444 |
+
- Reconstruction Error: {outlier_result['ae_residual']:.5f} (threshold: {outlier_result['ae_threshold']:.5f})
|
| 445 |
+
|
| 446 |
---
|
| 447 |
+
|
| 448 |
*Note: Set GEMINI_API_KEY environment variable to enable detailed AI-powered gastroenterological analysis.*
|
| 449 |
+
|
| 450 |
### Quick Health Tips Based on Your Classification:
|
| 451 |
+
|
| 452 |
**For {type_name}:**
|
| 453 |
- {'Increase fiber intake and hydration' if 'Type 1' in type_name or 'Type 2' in type_name else 'Maintain balanced diet and regular exercise'}
|
| 454 |
- {'Consider consulting a gastroenterologist if symptoms persist' if 'Type 1' in type_name or 'Type 7' in type_name else 'Monitor changes over time'}
|
|
|
|
| 461 |
)
|
| 462 |
|
| 463 |
response = gemini_client.models.generate_content(
|
| 464 |
+
model="gemini-2.0-flash-exp",
|
| 465 |
contents=prompt
|
| 466 |
)
|
| 467 |
|
| 468 |
+
# Add quality check info to analysis
|
| 469 |
+
analysis = response.text + f"""
|
| 470 |
+
|
| 471 |
+
---
|
| 472 |
+
|
| 473 |
+
### π Quality Assurance
|
| 474 |
+
|
| 475 |
+
β
**Image Quality Check Passed**
|
| 476 |
+
- **Reconstruction Error:** {outlier_result['ae_residual']:.5f}
|
| 477 |
+
- **Threshold:** {outlier_result['ae_threshold']:.5f}
|
| 478 |
+
- **Status:** Valid stool sample detected
|
| 479 |
+
"""
|
| 480 |
|
| 481 |
except Exception as e:
|
| 482 |
analysis = f"""## β οΈ Error Generating AI Analysis
|
| 483 |
+
|
| 484 |
**Error:** {str(e)}
|
| 485 |
+
|
| 486 |
**Classification Summary:**
|
| 487 |
+
|
| 488 |
{BRISTOL_DESCRIPTIONS[type_name]['emoji']} **{type_name}**
|
| 489 |
- **Description:** {BRISTOL_DESCRIPTIONS[type_name]['description']}
|
| 490 |
- **Condition:** {BRISTOL_DESCRIPTIONS[type_name]['condition']}
|
| 491 |
- **Confidence:** {type_conf:.1f}%
|
| 492 |
+
|
| 493 |
**Shape:** {shape_name} ({shape_conf:.1f}% confidence)
|
| 494 |
**Color:** {color_name} ({color_conf:.1f}% confidence)
|
| 495 |
+
|
| 496 |
+
**Quality Check:** β
Passed (AE Error: {outlier_result['ae_residual']:.5f})
|
| 497 |
"""
|
| 498 |
|
| 499 |
return type_dict, shape_dict, color_dict, analysis
|
| 500 |
|
| 501 |
except Exception as e:
|
| 502 |
error_msg = f"""## β Error Processing Image
|
| 503 |
+
|
| 504 |
**Error:** {str(e)}
|
| 505 |
+
|
| 506 |
Please ensure you've uploaded a valid image file and try again.
|
| 507 |
"""
|
| 508 |
return None, None, None, error_msg
|
|
|
|
| 538 |
gr.Markdown("""
|
| 539 |
# π₯ StoolNet Triple Attention β AI-Powered Bristol Stool Scale Classifier
|
| 540 |
|
| 541 |
+
### Advanced Multi-Task Deep Learning Model with Outlier Detection
|
| 542 |
|
| 543 |
+
This application combines **Triple Attention ResNet34** with **Google Gemini 2.0 Flash AI** for comprehensive gastroenterological assessment.
|
| 544 |
+
Features built-in **outlier detection** to identify invalid or unclear images.
|
| 545 |
""")
|
| 546 |
|
| 547 |
# ========================================
|
|
|
|
| 560 |
1. Upload your image OR select from samples below
|
| 561 |
2. Click "Analyze Sample"
|
| 562 |
3. View results on the right
|
| 563 |
+
|
| 564 |
+
**Note:** Images undergo automatic quality validation using autoencoder-based outlier detection.
|
| 565 |
""")
|
| 566 |
|
| 567 |
# Sample Images Section
|
|
|
|
| 617 |
### π¬ Model Information
|
| 618 |
|
| 619 |
**Architecture:** Triple Attention ResNet34 (Position, Channel, Type Attention) + Multi-Task Learning
|
| 620 |
+
**AI Analysis:** Powered by Google Gemini 2.0 Flash
|
| 621 |
+
**Outlier Detection:** Feature-space Autoencoder (trained on reference dataset)
|
| 622 |
**Model Repository:** [Sid3503/stoolnet-bristol-scale-triple-attn](https://huggingface.co/Sid3503/stoolnet-bristol-scale-triple-attn)
|
| 623 |
|
| 624 |
+
### π‘οΈ Quality Assurance Features
|
| 625 |
+
|
| 626 |
+
- **Autoencoder-based OOD Detection**: Identifies images that don't match training distribution
|
| 627 |
+
- **Reconstruction Error Threshold**: Images with high reconstruction error are flagged as invalid
|
| 628 |
+
- **Real-time Quality Feedback**: Immediate notification if uploaded image is not a valid stool sample
|
| 629 |
+
|
| 630 |
### π Bristol Stool Scale Quick Reference
|
| 631 |
|
| 632 |
| Type | Description | Indication |
|
requirements.txt
CHANGED
|
@@ -3,4 +3,5 @@ torch>=2.0.0
|
|
| 3 |
torchvision>=0.15.0
|
| 4 |
pillow>=9.0.0
|
| 5 |
huggingface-hub>=0.19.0
|
| 6 |
-
google-genai>=1.0.0
|
|
|
|
|
|
| 3 |
torchvision>=0.15.0
|
| 4 |
pillow>=9.0.0
|
| 5 |
huggingface-hub>=0.19.0
|
| 6 |
+
google-genai>=1.0.0
|
| 7 |
+
joblib>=1.3.0
|