Homoeopathy-Bot / analyzer.py
yekkala's picture
analysis improvement
9353b00 verified
"""
Enhanced Homeopathic Analysis Engine with AI-like matching
"""
import re
from typing import Dict, List
from datetime import datetime
from database import REMEDY_DATABASE
class EnhancedAnalyzer:
def __init__(self):
# Weighted scoring system
self.weights = {
"chief_complaint": 0.35, # 35%
"modalities": 0.40, # 40%
"emotional": 0.15, # 15%
"generalities": 0.10 # 10%
}
# Keywords for different categories
self.keywords = {
"pain": ["pain", "ache", "sore", "hurt", "tender"],
"inflammation": ["inflam", "red", "swell", "hot", "burn"],
"digestive": ["stomach", "digest", "nausea", "vomit", "diarrhea"],
"respiratory": ["cough", "breath", "lung", "chest", "throat"],
"emotional": ["anxious", "fear", "worry", "sad", "angry", "irritable"]
}
def analyze_case(self, patient_data: Dict, use_ai: bool = True) -> Dict:
"""
Main analysis function
"""
# Validate input
if not patient_data.get("chief_complaint"):
return self._error_result("Please describe your main complaint")
# Calculate matches
matches = self._calculate_matches(patient_data)
if not matches:
return self._error_result("No remedies found matching the symptoms")
# Enhance with recommendations
enhanced_matches = []
for match in matches[:6]: # Top 6 only
enhanced = self._enhance_match(match, patient_data)
enhanced_matches.append(enhanced)
# Generate comprehensive report
report = self._generate_report(enhanced_matches, patient_data)
return {
"success": True,
"matches": enhanced_matches,
"report": report,
"analysis_id": f"ANA{datetime.now().strftime('%Y%m%d%H%M%S')}",
"timestamp": datetime.now().isoformat()
}
def _calculate_matches(self, patient_data: Dict) -> List[Dict]:
"""Calculate remedy matches with advanced scoring"""
matches = []
for remedy_name, remedy_data in REMEDY_DATABASE.items():
score = self._calculate_remedy_score(patient_data, remedy_data, remedy_name)
if score >= 25: # Minimum threshold
matches.append({
"name": remedy_name,
"data": remedy_data,
"score": min(99, score),
"match_reasons": self._get_match_reasons(patient_data, remedy_data)
})
# Sort by score
matches.sort(key=lambda x: x["score"], reverse=True)
return matches
def _calculate_remedy_score(self, patient: Dict, remedy: Dict, remedy_name: str) -> float:
"""Calculate weighted score for a remedy"""
total_score = 0
# 1. Chief complaint matching
complaint_score = self._score_complaint(patient, remedy)
total_score += complaint_score * self.weights["chief_complaint"]
# 2. Modality matching
modality_score = self._score_modalities(patient, remedy)
total_score += modality_score * self.weights["modalities"]
# 3. Emotional matching
emotional_score = self._score_emotional(patient, remedy)
total_score += emotional_score * self.weights["emotional"]
# 4. General symptoms matching
general_score = self._score_generals(patient, remedy)
total_score += general_score * self.weights["generalities"]
return total_score
def _score_complaint(self, patient: Dict, remedy: Dict) -> float:
"""Score chief complaint matching"""
complaint = patient.get("chief_complaint", "").lower()
if not complaint:
return 0
score = 0
# Check remedy indications
for indication in remedy.get("indications", []):
indication_lower = indication.lower()
# Direct match
if indication_lower in complaint:
score += 20
# Word overlap
indication_words = set(re.findall(r'\b\w{4,}\b', indication_lower))
complaint_words = set(re.findall(r'\b\w{4,}\b', complaint))
common_words = indication_words.intersection(complaint_words)
if common_words:
score += len(common_words) * 5
return min(100, score)
def _score_modalities(self, patient: Dict, remedy: Dict) -> float:
"""Score modality matching"""
score = 0
# Patient aggravations
patient_worse = patient.get("aggravations", "").lower()
remedy_worse = [w.lower() for w in remedy.get("modalities", {}).get("worse", [])]
for modality in remedy_worse:
if modality in patient_worse:
score += 15
# Patient ameliorations
patient_better = patient.get("ameliorations", "").lower()
remedy_better = [b.lower() for b in remedy.get("modalities", {}).get("better", [])]
for modality in remedy_better:
if modality in patient_better:
score += 15
return min(100, score)
def _score_emotional(self, patient: Dict, remedy: Dict) -> float:
"""Score emotional state matching"""
emotional = patient.get("emotional_state", "").lower()
if not emotional:
return 0
remedy_mental = remedy.get("mental", "").lower()
if not remedy_mental:
return 0
score = 0
# Check for emotional keywords
emotional_words = ["anxious", "fear", "worry", "sad", "depressed",
"angry", "irritable", "restless", "weepy"]
for word in emotional_words:
if word in emotional and word in remedy_mental:
score += 10
return min(100, score)
def _score_generals(self, patient: Dict, remedy: Dict) -> float:
"""Score general symptoms"""
generalities = patient.get("generalities", "").lower()
if not generalities:
return 0
score = 0
# Thermal preferences
thermals = {
"worse_cold": ["worse cold", "chilly", "cold aggravates"],
"better_cold": ["better cold", "likes cold"],
"worse_heat": ["worse heat", "heat aggravates"],
"better_heat": ["better heat", "likes warmth"]
}
remedy_text = f"{remedy.get('physical', '')} {remedy.get('description', '')}".lower()
for thermal_type, keywords in thermals.items():
patient_has = any(k in generalities for k in keywords)
remedy_has = any(k in remedy_text for k in keywords)
if patient_has and remedy_has:
score += 10
return min(100, score)
def _get_match_reasons(self, patient: Dict, remedy: Dict) -> List[str]:
"""Get reasons why remedy matches"""
reasons = []
# Check modalities
patient_worse = patient.get("aggravations", "").lower()
remedy_worse = [w.lower() for w in remedy.get("modalities", {}).get("worse", [])]
for modality in remedy_worse:
if modality in patient_worse:
reasons.append(f"Worse from {modality}")
break
# Check indications
complaint = patient.get("chief_complaint", "").lower()
for indication in remedy.get("indications", [])[:2]:
if indication.lower() in complaint:
reasons.append(f"Indication: {indication}")
break
return reasons[:3]
def _enhance_match(self, match: Dict, patient_data: Dict) -> Dict:
"""Add recommendations and details to match"""
remedy = match["data"]
score = match["score"]
# Determine case type
timing = patient_data.get("timing", "").lower()
intensity = patient_data.get("intensity", 5)
if any(word in timing for word in ["acute", "sudden", "today"]) and intensity >= 7:
case_type = "acute"
elif any(word in timing for word in ["chronic", "months", "years"]):
case_type = "chronic"
else:
case_type = "subacute"
# Determine potency based on score and case type
if case_type == "acute":
if score > 80:
potency = "200C"
elif score > 60:
potency = "30C"
else:
potency = "6C"
frequency = "Every 2-4 hours"
duration = "24-48 hours"
elif case_type == "chronic":
if score > 80:
potency = "1M"
elif score > 60:
potency = "200C"
else:
potency = "30C"
frequency = "Once daily or weekly"
duration = "4-6 weeks"
else:
potency = "30C"
frequency = "3 times daily"
duration = "1-2 weeks"
# Get remedy's potencies
remedy_potencies = remedy.get("potencies", [])
if isinstance(remedy_potencies, list):
alternative_potencies = [p for p in remedy_potencies if p != potency][:2]
else:
alternative_potencies = []
match["recommendations"] = {
"primary_potency": potency,
"alternative_potencies": alternative_potencies,
"frequency": frequency,
"duration": duration,
"case_type": case_type,
"confidence_level": self._get_confidence_level(score),
"administration": "3-5 pellets sublingually, away from meals",
"cautions": "Avoid coffee, mint, camphor during treatment"
}
return match
def _get_confidence_level(self, score: float) -> str:
"""Convert score to confidence level"""
if score >= 80:
return "High"
elif score >= 60:
return "Moderate"
elif score >= 40:
return "Fair"
else:
return "Low"
def _generate_report(self, matches: List[Dict], patient_data: Dict) -> Dict:
"""Generate analysis report"""
if not matches:
return {}
top_match = matches[0]
return {
"summary": {
"top_remedy": top_match["name"],
"confidence_score": top_match["score"],
"confidence_level": top_match["recommendations"]["confidence_level"],
"case_type": top_match["recommendations"]["case_type"],
"analysis_date": datetime.now().strftime("%Y-%m-%d %H:%M"),
"remedies_considered": len(matches)
},
"key_findings": [
f"Primary match: {top_match['name']} ({top_match['score']:.1f}%)",
f"Case type: {top_match['recommendations']['case_type'].upper()}",
f"Recommended potency: {top_match['recommendations']['primary_potency']}",
f"Administration: {top_match['recommendations']['frequency']}"
],
"clinical_notes": [
"Stop when improvement begins",
"Repeat only if symptoms return",
"Monitor for initial aggravation",
"Consult practitioner if no improvement in 1 week"
],
"differentiation": self._get_differentiation(matches[:3])
}
def _get_differentiation(self, top_matches: List[Dict]) -> List[str]:
"""Get differentiation between top remedies"""
if len(top_matches) < 2:
return []
differentiations = []
primary = top_matches[0]
for match in top_matches[1:3]:
diff = self._compare_remedies(primary, match)
if diff:
differentiations.append(f"vs {match['name']}: {diff}")
return differentiations[:2]
def _compare_remedies(self, remedy1: Dict, remedy2: Dict) -> str:
"""Compare two remedies"""
differences = []
# Compare modalities
worse1 = remedy1["data"].get("modalities", {}).get("worse", [])
worse2 = remedy2["data"].get("modalities", {}).get("worse", [])
unique1 = [w for w in worse1 if w not in worse2]
if unique1:
differences.append(f"Unique worse: {unique1[0]}")
# Compare mental states
mental1 = remedy1["data"].get("mental", "")
mental2 = remedy2["data"].get("mental", "")
words1 = set(re.findall(r'\b\w{4,}\b', mental1.lower()))
words2 = set(re.findall(r'\b\w{4,}\b', mental2.lower()))
unique_mental = words1 - words2
if unique_mental:
differences.append(f"Mental: {list(unique_mental)[0]}")
return "; ".join(differences) if differences else "Similar picture"
def _error_result(self, message: str) -> Dict:
"""Return error result"""
return {
"success": False,
"error": message,
"matches": [],
"timestamp": datetime.now().isoformat()
}
# Global instance
analyzer = EnhancedAnalyzer()