Spaces:
Sleeping
Sleeping
| """ | |
| Gradio UI Builder for Homeopathic Analyzer | |
| """ | |
| import gradio as gr | |
| from config import APP_NAME, APP_DESCRIPTION, THEME_CONFIG | |
| from analyzer import analyzer | |
| from database import search_remedies, get_remedy_details | |
| class UIBuilder: | |
| def __init__(self): | |
| self.css = self._get_css() | |
| def _get_css(self): | |
| """Return custom CSS""" | |
| return """ | |
| .gradio-container { | |
| max-width: 1400px !important; | |
| margin: 0 auto !important; | |
| font-family: 'Inter', -apple-system, sans-serif !important; | |
| } | |
| .main-header { | |
| background: linear-gradient(135deg, #1e40af 0%, #1e3a8a 100%); | |
| padding: 32px; | |
| color: white; | |
| border-radius: 0 0 20px 20px; | |
| margin: -20px -20px 30px -20px; | |
| } | |
| .tab-nav { | |
| display: flex; | |
| gap: 2px; | |
| margin-bottom: 30px; | |
| background: #f3f4f6; | |
| padding: 4px; | |
| border-radius: 12px; | |
| } | |
| .tab-button { | |
| flex: 1; | |
| padding: 16px; | |
| border: none; | |
| background: transparent; | |
| font-weight: 500; | |
| color: #6b7280; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| transition: all 0.2s ease; | |
| } | |
| .tab-button:hover { | |
| background: #e5e7eb; | |
| } | |
| .tab-button.active { | |
| background: white; | |
| color: #1e40af; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.1); | |
| } | |
| .analysis-card { | |
| background: white; | |
| border-radius: 12px; | |
| padding: 28px; | |
| margin-bottom: 24px; | |
| border: 1px solid #e5e7eb; | |
| box-shadow: 0 2px 8px rgba(0,0,0,0.05); | |
| } | |
| .primary-btn { | |
| background: linear-gradient(135deg, #1e40af 0%, #1e3a8a 100%); | |
| color: white; | |
| border: none; | |
| padding: 16px 32px; | |
| border-radius: 10px; | |
| font-weight: 600; | |
| font-size: 16px; | |
| width: 100%; | |
| margin-top: 20px; | |
| transition: all 0.3s ease; | |
| } | |
| .primary-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 8px 16px rgba(30, 64, 175, 0.2); | |
| } | |
| .results-container { | |
| margin-top: 30px; | |
| animation: fadeIn 0.5s ease; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .medicine-card { | |
| background: white; | |
| border-radius: 12px; | |
| padding: 20px; | |
| margin-bottom: 16px; | |
| border: 1px solid #e5e7eb; | |
| transition: all 0.2s ease; | |
| } | |
| .medicine-card:hover { | |
| border-color: #3b82f6; | |
| box-shadow: 0 4px 12px rgba(59, 130, 246, 0.1); | |
| } | |
| .potency-badge { | |
| display: inline-block; | |
| padding: 6px 12px; | |
| border-radius: 20px; | |
| font-size: 13px; | |
| font-weight: 500; | |
| margin: 2px; | |
| } | |
| .potency-high { | |
| background: #d1fae5; | |
| color: #065f46; | |
| } | |
| .potency-medium { | |
| background: #fef3c7; | |
| color: #92400e; | |
| } | |
| .potency-low { | |
| background: #e5e7eb; | |
| color: #6b7280; | |
| } | |
| .grid-2 { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 20px; | |
| } | |
| .grid-3 { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); | |
| gap: 20px; | |
| } | |
| @media (max-width: 768px) { | |
| .grid-2, .grid-3 { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| """ | |
| def create_header(self): | |
| """Create application header""" | |
| return gr.Markdown(f""" | |
| <div class="main-header"> | |
| <div style="display: flex; align-items: center; justify-content: space-between;"> | |
| <div> | |
| <h1 style="margin: 0; font-size: 32px; font-weight: 700;">🏥 {APP_NAME}</h1> | |
| <p style="margin: 8px 0 0 0; opacity: 0.9; font-size: 16px;"> | |
| {APP_DESCRIPTION} | |
| </p> | |
| </div> | |
| <div style="font-size: 40px;">🌿</div> | |
| </div> | |
| </div> | |
| """) | |
| def create_analysis_tab(self): | |
| """Create symptom analysis tab""" | |
| with gr.Column(elem_id="analysis-tab") as tab: | |
| # Patient Information | |
| with gr.Group(elem_classes="analysis-card"): | |
| gr.Markdown("### 👤 Patient Information") | |
| with gr.Row(): | |
| age = gr.Slider(label="Age", minimum=0, maximum=120, value=35, step=1) | |
| gender = gr.Dropdown(label="Gender", choices=["Male", "Female", "Other"], value="Male") | |
| constitution = gr.Dropdown( | |
| label="Constitutional Type", | |
| choices=["Lean/Nervous", "Average", "Robust/Plethoric", "Not sure"], | |
| value="Average" | |
| ) | |
| # Symptom Assessment | |
| with gr.Group(elem_classes="analysis-card"): | |
| gr.Markdown("### 🔍 Symptom Assessment") | |
| chief_complaint = gr.Textbox( | |
| label="Chief Complaint", | |
| placeholder="Describe your main health concern...", | |
| lines=3 | |
| ) | |
| with gr.Row(): | |
| location = gr.Textbox( | |
| label="Location", | |
| placeholder="Where exactly are symptoms?", | |
| lines=2 | |
| ) | |
| sensation = gr.Textbox( | |
| label="Sensation", | |
| placeholder="What does it feel like?", | |
| lines=2 | |
| ) | |
| intensity = gr.Slider(label="Intensity (1-10)", minimum=1, maximum=10, value=5) | |
| # Modalities | |
| with gr.Group(elem_classes="analysis-card"): | |
| gr.Markdown("### 📈 Modalities") | |
| with gr.Row(): | |
| aggravations = gr.Textbox( | |
| label="Aggravating Factors", | |
| placeholder="What makes it worse?", | |
| lines=2 | |
| ) | |
| ameliorations = gr.Textbox( | |
| label="Ameliorating Factors", | |
| placeholder="What makes it better?", | |
| lines=2 | |
| ) | |
| timing = gr.Textbox( | |
| label="Timing & Periodicity", | |
| placeholder="When do symptoms occur?", | |
| lines=2 | |
| ) | |
| # Emotional State | |
| with gr.Group(elem_classes="analysis-card"): | |
| gr.Markdown("### 😊 Emotional & Mental State") | |
| emotional_state = gr.Textbox( | |
| label="Emotional State", | |
| placeholder="Describe emotions, fears, mental symptoms...", | |
| lines=2 | |
| ) | |
| generalities = gr.Textbox( | |
| label="General Symptoms", | |
| placeholder="Thermal preferences, food desires/aversions...", | |
| lines=2 | |
| ) | |
| # Analysis Button | |
| analyze_btn = gr.Button( | |
| "🔬 Start Enhanced Analysis", | |
| variant="primary", | |
| elem_classes="primary-btn" | |
| ) | |
| # Results Display | |
| results = gr.HTML( | |
| label="Analysis Results", | |
| elem_classes="results-container" | |
| ) | |
| # Analysis function | |
| def analyze_symptoms( | |
| age_val, gender_val, constitution_val, | |
| complaint_val, location_val, sensation_val, intensity_val, | |
| aggravations_val, ameliorations_val, timing_val, | |
| emotional_val, generalities_val | |
| ): | |
| patient_data = { | |
| "age": age_val, | |
| "gender": gender_val, | |
| "constitution": constitution_val, | |
| "chief_complaint": complaint_val, | |
| "location": location_val, | |
| "sensation": sensation_val, | |
| "intensity": intensity_val, | |
| "aggravations": aggravations_val, | |
| "ameliorations": ameliorations_val, | |
| "timing": timing_val, | |
| "emotional_state": emotional_val, | |
| "generalities": generalities_val | |
| } | |
| result = analyzer.analyze_case(patient_data) | |
| return self._generate_results_html(result) | |
| # Connect button | |
| analyze_btn.click( | |
| fn=analyze_symptoms, | |
| inputs=[ | |
| age, gender, constitution, | |
| chief_complaint, location, sensation, intensity, | |
| aggravations, ameliorations, timing, | |
| emotional_state, generalities | |
| ], | |
| outputs=results | |
| ) | |
| return tab | |
| def create_medicine_tab(self): | |
| """Create medicine database tab""" | |
| with gr.Column(elem_id="medicine-tab") as tab: | |
| gr.Markdown("### 💊 Homeopathic Medicine Database") | |
| gr.Markdown("Search and explore detailed information about homeopathic remedies") | |
| # Search interface | |
| with gr.Row(): | |
| search_input = gr.Textbox( | |
| label="Search Remedies", | |
| placeholder="Search by remedy name or indication (e.g., fever, headache, arnica)...", | |
| scale=4 | |
| ) | |
| search_btn = gr.Button("Search", variant="primary", scale=1) | |
| # Search results | |
| search_results = gr.HTML( | |
| label="Search Results", | |
| elem_classes="results-container" | |
| ) | |
| # Medicine details | |
| medicine_details = gr.HTML( | |
| label="Medicine Details", | |
| visible=False | |
| ) | |
| # Search function | |
| def perform_search(query): | |
| if not query or len(query.strip()) < 2: | |
| return "", gr.HTML(visible=False) | |
| results = search_remedies(query, max_results=10) | |
| if not results: | |
| return "<div style='text-align: center; padding: 40px; color: #666;'>No remedies found. Try a different search term.</div>", gr.HTML(visible=False) | |
| html = "<div style='margin-bottom: 30px;'>" | |
| html += f"<h3 style='color: #374151; margin-bottom: 20px;'>Found {len(results)} remedies:</h3>" | |
| for name, data, match_type in results: | |
| html += f""" | |
| <div class='medicine-card' onclick='selectRemedy("{name}")' style='cursor: pointer;'> | |
| <div style='display: flex; justify-content: space-between; align-items: start;'> | |
| <div> | |
| <h4 style='margin: 0 0 8px 0; color: #1e40af;'>{name}</h4> | |
| <p style='margin: 0 0 8px 0; color: #6b7280; font-size: 14px;'>{data['description']}</p> | |
| <div style='display: flex; gap: 8px; flex-wrap: wrap;'> | |
| """ | |
| for indication in data['indications'][:3]: | |
| html += f'<span style="background: #f3f4f6; color: #4b5563; padding: 4px 8px; border-radius: 6px; font-size: 12px;">{indication}</span>' | |
| html += f""" | |
| </div> | |
| </div> | |
| <div style='background: #f0f9ff; color: #0369a1; padding: 6px 12px; border-radius: 6px; font-size: 12px; font-weight: 500;'> | |
| {data['potencies'].get('first_aid', '30C')} | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| html += "</div>" | |
| html += """ | |
| <script> | |
| function selectRemedy(name) { | |
| // This would trigger a Gradio event in a real implementation | |
| console.log('Selected remedy:', name); | |
| // For now, we'll use a simple approach | |
| document.querySelectorAll('.medicine-card').forEach(card => { | |
| card.style.borderColor = '#e5e7eb'; | |
| }); | |
| event.currentTarget.style.borderColor = '#3b82f6'; | |
| // In a full implementation, this would trigger a Gradio event | |
| // For the demo, we'll just show an alert | |
| alert('Click would show details for: ' + name); | |
| } | |
| </script> | |
| """ | |
| return html, gr.HTML(visible=False) | |
| # Details function | |
| def show_remedy_details(name): | |
| if not name: | |
| return "" | |
| data = get_remedy_details(name) | |
| if not data: | |
| return "<div style='color: #666; text-align: center; padding: 40px;'>Remedy not found</div>" | |
| return self._generate_medicine_details_html(name, data) | |
| # Connect events | |
| search_input.submit( | |
| fn=perform_search, | |
| inputs=[search_input], | |
| outputs=[search_results, medicine_details] | |
| ) | |
| search_btn.click( | |
| fn=perform_search, | |
| inputs=[search_input], | |
| outputs=[search_results, medicine_details] | |
| ) | |
| return tab | |
| def _generate_results_html(self, analysis_result): | |
| """Generate HTML for analysis results""" | |
| if not analysis_result.get("success", False): | |
| return f""" | |
| <div style="text-align: center; padding: 40px; background: #f8f9fa; border-radius: 12px;"> | |
| <div style="font-size: 48px; margin-bottom: 20px;">🏥</div> | |
| <h3 style="color: #6b7280; margin-bottom: 10px;">{analysis_result.get('message', 'Analysis Failed')}</h3> | |
| <p style="color: #9ca3af;">Please provide more detailed symptoms.</p> | |
| </div> | |
| """ | |
| matches = analysis_result["matches"] | |
| if not matches: | |
| return """ | |
| <div style="text-align: center; padding: 40px; background: #f8f9fa; border-radius: 12px;"> | |
| <div style="font-size: 48px; margin-bottom: 20px;">🏥</div> | |
| <h3 style="color: #6b7280; margin-bottom: 10px;">No Clear Matches Found</h3> | |
| <p style="color: #9ca3af;">Try providing more specific symptom details.</p> | |
| </div> | |
| """ | |
| top_match = matches[0] | |
| case_type = analysis_result.get("case_type", "acute") | |
| html = f""" | |
| <div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;"> | |
| <!-- Report Header --> | |
| <div style="background: linear-gradient(135deg, #1e40af 0%, #1e3a8a 100%); | |
| padding: 28px; border-radius: 12px; margin-bottom: 24px; color: white;"> | |
| <div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 20px;"> | |
| <div> | |
| <h2 style="margin: 0; font-size: 24px; font-weight: 600;">Enhanced Homeopathic Analysis</h2> | |
| <p style="margin: 8px 0 0 0; opacity: 0.9; font-size: 15px;"> | |
| Case Type: <strong>{case_type.upper()}</strong> • Confidence: <strong>{top_match['score']:.1f}%</strong> | |
| </p> | |
| </div> | |
| <div style="display: flex; gap: 16px;"> | |
| <div style="background: rgba(255,255,255,0.15); padding: 12px 20px; border-radius: 10px; text-align: center;"> | |
| <div style="font-size: 12px; opacity: 0.8;">Top Match</div> | |
| <div style="font-size: 20px; font-weight: 700;">{top_match['name']}</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Primary Recommendation --> | |
| <div style="background: white; border-radius: 12px; padding: 28px; margin-bottom: 24px; | |
| box-shadow: 0 2px 8px rgba(0,0,0,0.05); border: 1px solid #e5e7eb;"> | |
| <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 24px; flex-wrap: wrap; gap: 16px;"> | |
| <div style="display: flex; align-items: center; gap: 16px;"> | |
| <div style="width: 60px; height: 60px; background: linear-gradient(135deg, #10b981, #059669); | |
| border-radius: 12px; display: flex; align-items: center; justify-content: center; | |
| color: white; font-size: 28px; font-weight: 700;"> | |
| 1 | |
| </div> | |
| <div> | |
| <h3 style="margin: 0; color: #1f2937; font-size: 22px; font-weight: 600;">{top_match['name']}</h3> | |
| <p style="margin: 4px 0 0 0; color: #6b7280; font-size: 16px;">{top_match['data']['description']}</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Recommendations --> | |
| <div style="margin-bottom: 24px;"> | |
| <h4 style="color: #1e40af; margin: 0 0 16px 0; font-size: 18px;">💊 Recommendations</h4> | |
| <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px;"> | |
| """ | |
| rec = top_match.get("recommendations", {}) | |
| if rec: | |
| html += f""" | |
| <div style="background: #f0f9ff; border-radius: 10px; padding: 20px; border-left: 4px solid #0ea5e9;"> | |
| <div style="font-weight: 600; color: #0369a1; margin-bottom: 8px;">Primary Potency</div> | |
| <div style="font-size: 24px; font-weight: 700; color: #1e40af; margin-bottom: 4px;">{rec.get('primary_potency', '30C')}</div> | |
| <div style="color: #6b7280; font-size: 14px;">For {case_type} cases</div> | |
| </div> | |
| <div style="background: #f8fafc; border-radius: 10px; padding: 20px;"> | |
| <div style="font-weight: 600; color: #4b5563; margin-bottom: 8px;">Administration</div> | |
| <div style="color: #1f2937; font-size: 16px; font-weight: 500; margin-bottom: 4px;">{rec.get('frequency', '3 times daily')}</div> | |
| <div style="color: #6b7280; font-size: 14px;">Duration: {rec.get('duration', '1-2 weeks')}</div> | |
| </div> | |
| <div style="background: #f8fafc; border-radius: 10px; padding: 20px;"> | |
| <div style="font-weight: 600; color: #4b5563; margin-bottom: 8px;">Dosage</div> | |
| <div style="color: #6b7280; font-size: 14px;">{rec.get('dosage', '3-5 pellets sublingually')}</div> | |
| </div> | |
| """ | |
| html += """ | |
| </div> | |
| </div> | |
| <!-- Match Reasons --> | |
| <div style="margin-bottom: 24px;"> | |
| <h4 style="color: #1e40af; margin: 0 0 12px 0; font-size: 18px;">🔍 Key Match Factors</h4> | |
| <div style="background: #f8fafc; border-radius: 10px; padding: 20px;"> | |
| <ul style="margin: 0; padding-left: 20px;"> | |
| """ | |
| for reason in top_match.get("match_reasons", []): | |
| html += f'<li style="margin-bottom: 8px; color: #4b5563;">{reason}</li>' | |
| html += """ | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Alternative Remedies --> | |
| <div style="background: white; border-radius: 12px; padding: 28px; margin-bottom: 24px; | |
| box-shadow: 0 2px 8px rgba(0,0,0,0.05); border: 1px solid #e5e7eb;"> | |
| <h3 style="color: #1f2937; margin: 0 0 20px 0; font-size: 20px; font-weight: 600;">Alternative Considerations</h3> | |
| <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px;"> | |
| """ | |
| for i, match in enumerate(matches[1:4], 2): | |
| color = "#f59e0b" if match["score"] > 60 else "#6b7280" | |
| html += f""" | |
| <div style="border: 1px solid #e5e7eb; border-radius: 10px; padding: 20px;"> | |
| <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;"> | |
| <div style="display: flex; align-items: center; gap: 12px;"> | |
| <div style="width: 36px; height: 36px; background: {color}20; color: {color}; | |
| border-radius: 8px; display: flex; align-items: center; justify-content: center; | |
| font-weight: 700;"> | |
| {i} | |
| </div> | |
| <div style="font-weight: 600; color: #1f2937;">{match['name']}</div> | |
| </div> | |
| <div style="background: {color}10; color: {color}; padding: 4px 12px; border-radius: 20px; | |
| font-size: 13px; font-weight: 500;"> | |
| {match['score']:.1f}% | |
| </div> | |
| </div> | |
| <div style="color: #6b7280; font-size: 14px; margin-bottom: 12px;">{match['data']['description']}</div> | |
| <div style="display: flex; gap: 8px; flex-wrap: wrap;"> | |
| """ | |
| for indication in match["data"]["indications"][:2]: | |
| html += f'<span style="background: #f3f4f6; color: #6b7280; padding: 4px 8px; border-radius: 6px; font-size: 12px;">{indication}</span>' | |
| html += """ | |
| </div> | |
| </div> | |
| """ | |
| html += """ | |
| </div> | |
| </div> | |
| <!-- Disclaimer --> | |
| <div style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 12px; padding: 20px;"> | |
| <div style="display: flex; align-items: flex-start;"> | |
| <div style="color: #dc2626; font-size: 24px; margin-right: 16px;">⚠️</div> | |
| <div> | |
| <div style="font-weight: 600; color: #991b1b; margin-bottom: 8px; font-size: 16px;">Medical Disclaimer</div> | |
| <div style="color: #7f1d1d; font-size: 14px; line-height: 1.5;"> | |
| This analysis is generated by AI for educational purposes only. It is not a substitute for | |
| professional medical advice, diagnosis, or treatment. Always consult a qualified homeopath | |
| or medical professional for health concerns. | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| return html | |
| def _generate_medicine_details_html(self, name, data): | |
| """Generate HTML for medicine details""" | |
| html = f""" | |
| <div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;"> | |
| <div style="background: linear-gradient(135deg, #1e40af 0%, #1e3a8a 100%); | |
| padding: 24px; border-radius: 12px; margin-bottom: 24px; color: white;"> | |
| <h2 style="margin: 0; font-size: 24px; font-weight: 600;">{name}</h2> | |
| <p style="margin: 8px 0 0 0; opacity: 0.9; font-size: 16px;">{data['description']}</p> | |
| </div> | |
| <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-bottom: 24px;"> | |
| <div style="background: white; border-radius: 10px; padding: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);"> | |
| <h3 style="color: #1e40af; margin: 0 0 12px 0; font-size: 18px;">🔍 Key Indications</h3> | |
| <ul style="margin: 0; padding-left: 20px;"> | |
| """ | |
| for indication in data["indications"][:6]: | |
| html += f"<li style='margin-bottom: 6px; color: #4b5563;'>{indication}</li>" | |
| html += """ | |
| </ul> | |
| </div> | |
| <div style="background: white; border-radius: 10px; padding: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);"> | |
| <h3 style="color: #1e40af; margin: 0 0 12px 0; font-size: 18px;">📈 Modalities</h3> | |
| <div style="margin-bottom: 16px;"> | |
| <div style="color: #ef4444; font-weight: 600; margin-bottom: 4px;">Worse:</div> | |
| <div style="color: #6b7280;">""" | |
| html += ', '.join(data["modalities"]["worse"]) | |
| html += """</div> | |
| </div> | |
| <div> | |
| <div style="color: #10b981; font-weight: 600; margin-bottom: 4px;">Better:</div> | |
| <div style="color: #6b7280;">""" | |
| html += ', '.join(data["modalities"]["better"]) | |
| html += """</div> | |
| </div> | |
| </div> | |
| <div style="background: white; border-radius: 10px; padding: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);"> | |
| <h3 style="color: #1e40af; margin: 0 0 12px 0; font-size: 18px;">💊 Potency Guide</h3> | |
| <div style="display: grid; gap: 12px;"> | |
| """ | |
| for case_type, potencies in data["potencies"].items(): | |
| if case_type != "recommended": | |
| html += f""" | |
| <div style="background: #f8fafc; padding: 12px; border-radius: 8px;"> | |
| <div style="font-weight: 600; color: #4b5563; text-transform: capitalize;">{case_type}:</div> | |
| <div style="color: #6b7280;"> | |
| """ | |
| if isinstance(potencies, list): | |
| html += ', '.join(potencies) | |
| else: | |
| html += potencies | |
| html += "</div></div>" | |
| html += f""" | |
| </div> | |
| <div style="margin-top: 16px; padding: 12px; background: #f0f9ff; border-radius: 8px; border-left: 4px solid #0ea5e9;"> | |
| <div style="font-weight: 600; color: #0369a1;">Recommended:</div> | |
| <div style="color: #0c4a6e;">{data['potencies'].get('recommended', '30C for acute cases')}</div> | |
| </div> | |
| </div> | |
| </div> | |
| <div style="background: #fef2f2; border: 1px solid #fecaca; border-radius: 12px; padding: 20px; margin-top: 24px;"> | |
| <div style="color: #991b1b; font-size: 14px; line-height: 1.5;"> | |
| <strong>Disclaimer:</strong> This information is for educational purposes only. | |
| Always consult a qualified homeopathic practitioner for treatment recommendations. | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| return html |