Spaces:
Sleeping
Sleeping
| """ | |
| 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() |