-
-
Notifications
You must be signed in to change notification settings - Fork 122
feat: implement medicine and BP handlers with clean history and intent fix #164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,51 @@ | ||||||
| import re | ||||||
| import sqlite3 | ||||||
| from db.db import open_db | ||||||
|
|
||||||
| def handle(query, user_context): | ||||||
| """ | ||||||
| Extracts BP readings, validates thresholds for pregnancy safety, | ||||||
| and logs data into the database. | ||||||
| """ | ||||||
| db = open_db() | ||||||
| try: | ||||||
| # Improved regex to capture systolic and diastolic values | ||||||
| match = re.search(r'(\d{1,3})\s*(?:/|over|-)\s*(\d{1,3})', query, re.IGNORECASE) | ||||||
| if not match: | ||||||
| return "Please provide BP in format like '120/80' or '120 over 80'." | ||||||
|
|
||||||
| systolic = int(match.group(1)) | ||||||
| diastolic = int(match.group(2)) | ||||||
|
|
||||||
| # Basic physiological range validation | ||||||
| if not (70 <= systolic <= 250 and 40 <= diastolic <= 150): | ||||||
| return "BP values out of valid range. Please check and try again." | ||||||
|
|
||||||
| week = user_context.get('week_number', 1) | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Inconsistent user context key across handlers. Line 24 uses 🔧 Proposed fix for context key consistency- week = user_context.get('week_number', 1)
+ week = user_context.get('current_week', 1)Apply the same fix to Backend/agent/handlers/medicine.py line 19 and Backend/agent/handlers/insights.py line 12. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
|
|
||||||
| # Database persistence | ||||||
| db.execute( | ||||||
| 'INSERT INTO blood_pressure_logs (week_number, systolic, diastolic, time) VALUES (?, ?, ?, datetime("now"))', | ||||||
| (week, systolic, diastolic) | ||||||
| ) | ||||||
| db.commit() | ||||||
|
|
||||||
| # --- MEDICAL ALERT LOGIC --- | ||||||
| # Thresholds based on pregnancy-induced hypertension (PIH) guidelines | ||||||
| if systolic >= 140 or diastolic >= 90: | ||||||
| return (f"🚨 **URGENT ALERT**: Your BP is {systolic}/{diastolic}. This is classified as High Blood Pressure (Hypertension). " | ||||||
| "In pregnancy, this requires immediate attention. Please rest and **contact your doctor right away**.") | ||||||
|
|
||||||
| elif systolic <= 90 or diastolic <= 60: | ||||||
| return (f"⚠️ **WARNING**: Your BP is {systolic}/{diastolic}, which is low. " | ||||||
| "Ensure you are hydrated and notify your healthcare provider if you feel faint.") | ||||||
|
|
||||||
| else: | ||||||
| return f"✅ Recorded BP: {systolic}/{diastolic} for week {week}. Your reading is within the healthy range." | ||||||
|
Comment on lines
+35
to
+44
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: Short answer — ACOG (current guidance) uses 140/90 mm Hg as the treatment/initiation threshold for chronic hypertension in pregnancy (based on the CHAP trial guidance) and retains ≥160/110 mm Hg as the definition of severe (acute) maternal hypertension that requires immediate evaluation/treatment. See ACOG acute‑hypertension/preeclampsia algorithms and related practice guidance for management details. [1][2][3] Sources
🌐 Web query:
💡 Result: Short answer: Major obstetric guidelines do not define a fixed numeric "hypotension" cutoff for pregnancy the way they do for hypertension. Clinically, values around <90/60 mmHg are commonly used as a practical threshold for low blood pressure, but trials and observational studies often use slightly different cutoffs (for example persistent SBP <100 mmHg and/or DBP <60 mmHg). Symptoms, hemodynamic instability, and fetal concerns determine evaluation and treatment rather than a single universal number. (acog.org) Key points:
If you’d like, I can pull specific guideline text or studies (PDFs) and list exact numeric cutoffs used in research or provide management steps for symptomatic hypotension. Citations:
Clarify BP alert thresholds and align with ACOG severity definitions. The high BP threshold (140/90 mmHg) aligns with ACOG's chronic hypertension treatment threshold but not acute hypertension. ACOG defines ≥160/110 mmHg as severe/urgent hypertension requiring immediate evaluation—yet the code labels 140/90 as "URGENT ALERT," which overstates the severity. The low BP threshold (≤90/60 mmHg) lacks formal ACOG guidance; clinically, <90/60 is used as a practical marker, but guidelines emphasize that symptoms, persistence, and clinical context should guide evaluation rather than numeric cutoffs alone. Consider:
|
||||||
|
|
||||||
| except sqlite3.Error as e: | ||||||
| return f"Database error: {str(e)}" | ||||||
| except Exception as e: | ||||||
| return f"Unexpected error: {str(e)}" | ||||||
| finally: | ||||||
| db.close() | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| import sqlite3 | ||
| from datetime import datetime, timedelta | ||
| from db.db import open_db | ||
|
|
||
| def handle(query, user_context): | ||
| """ | ||
| Analyzes data from the last 7 days across all logs to provide | ||
| a comprehensive health summary. | ||
| """ | ||
| db = open_db() | ||
| try: | ||
| week = user_context.get('week_number', 1) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Same context key inconsistency. This line has the same issue as the other handlers. Use 🤖 Prompt for AI Agents |
||
|
|
||
| # 1. Fetch Blood Pressure Data (Last 7 Days) | ||
| bp_rows = db.execute( | ||
| "SELECT systolic, diastolic FROM blood_pressure_logs WHERE time >= datetime('now', '-7 days')" | ||
| ).fetchall() | ||
|
|
||
| # 2. Fetch Medicine Data (Last 7 Days) | ||
| med_rows = db.execute( | ||
| "SELECT status FROM weekly_medicine_logs WHERE time >= datetime('now', '-7 days')" | ||
| ).fetchall() | ||
|
|
||
| # 3. Fetch Weight Data (Last 7 Days) | ||
| weight_rows = db.execute( | ||
| "SELECT weight_value FROM weight_logs WHERE time >= datetime('now', '-7 days')" | ||
| ).fetchall() | ||
|
|
||
| # --- ANALYSIS LOGIC --- | ||
|
|
||
| # BP Analysis | ||
| if bp_rows: | ||
| avg_sys = sum(r[0] for r in bp_rows) // len(bp_rows) | ||
| avg_dia = sum(r[1] for r in bp_rows) // len(bp_rows) | ||
|
Comment on lines
+33
to
+34
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Use float division for precise BP averages. Integer division ( 📊 Proposed fix for precision- avg_sys = sum(r[0] for r in bp_rows) // len(bp_rows)
- avg_dia = sum(r[1] for r in bp_rows) // len(bp_rows)
+ avg_sys = round(sum(r[0] for r in bp_rows) / len(bp_rows), 1)
+ avg_dia = round(sum(r[1] for r in bp_rows) / len(bp_rows), 1)Update the response format to handle float values: - f"🩺 **Blood Pressure:** Avg {avg_sys}/{avg_dia} mmHg\n"
+ f"🩺 **Blood Pressure:** Avg {avg_sys:.1f}/{avg_dia:.1f} mmHg\n"🤖 Prompt for AI Agents |
||
| bp_status = "Stable" if avg_sys < 140 else "High (Consult Doctor)" | ||
| else: | ||
| avg_sys, avg_dia, bp_status = "N/A", "N/A", "No data logged" | ||
|
|
||
| # Medicine Adherence | ||
| total_meds = len(med_rows) | ||
| taken_meds = sum(1 for r in med_rows if r[0] == 'taken') | ||
| adherence = (taken_meds / total_meds * 100) if total_meds > 0 else 0 | ||
|
|
||
| # Response Building | ||
| response = ( | ||
| f"📊 **Weekly Health Insights (Week {week})**\n\n" | ||
| f"🩺 **Blood Pressure:** Avg {avg_sys}/{avg_dia} mmHg\n" | ||
| f"💡 *Status:* {bp_status}\n\n" | ||
| f"💊 **Medicine Adherence:** {adherence:.1f}%\n" | ||
| f"💡 *Tip:* {'Great job staying consistent!' if adherence > 80 else 'Try to set reminders for your supplements.'}\n\n" | ||
| f"⚖️ **Weight Logs:** {len(weight_rows)} entries found this week." | ||
| ) | ||
|
|
||
| return response | ||
|
|
||
| except Exception as e: | ||
| return f"Error generating insights: {str(e)}" | ||
| finally: | ||
| db.close() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import sqlite3 | ||
| from datetime import datetime | ||
| from db.db import open_db | ||
|
|
||
| def handle(query, user_context): | ||
| """ | ||
| Records medicine intake and provides proactive reminders based | ||
| on standard pregnancy supplement requirements. | ||
| """ | ||
| db = open_db() | ||
| try: | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # Standard supplements for pregnancy | ||
| required_meds = ["iron", "folic acid", "calcium"] | ||
| query_lower = query.lower() | ||
|
|
||
| # Identify which medicine the user is logging | ||
| logged_med = next((med for med in required_meds if med in query_lower), "medicine") | ||
|
|
||
| week = user_context.get('week_number', 1) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Same context key inconsistency. This line has the same issue as Backend/agent/handlers/blood_pressure.py line 24. Use 🤖 Prompt for AI Agents |
||
|
|
||
| # Record the entry in the database | ||
| db.execute( | ||
| 'INSERT INTO weekly_medicine_logs (week_number, medicine_name, status, time) VALUES (?, ?, ?, datetime("now"))', | ||
| (week, logged_med, "taken") | ||
| ) | ||
| db.commit() | ||
|
|
||
| # --- PROACTIVE LOGIC --- | ||
| # Remind user about other important meds if they only logged one | ||
| missing_meds = [m for m in required_meds if m not in query_lower] | ||
|
|
||
| response = f"✅ Logged your {logged_med} intake for week {week}." | ||
|
|
||
| if missing_meds: | ||
| response += f"\n\n💡 **Tip**: Don't forget to also take your {', '.join(missing_meds)} today as prescribed for your pregnancy stage." | ||
|
|
||
| return response | ||
|
|
||
| except sqlite3.Error as e: | ||
| return f"Database error: {str(e)}" | ||
| except Exception as e: | ||
| return f"Unexpected error: {str(e)}" | ||
| finally: | ||
| db.close() | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,15 +1,23 @@ | ||||||||||
| # agent/intent.py | ||||||||||
| def classify_intent(query: str) -> str: | ||||||||||
| if not query or not isinstance(query, str): | ||||||||||
| return "general" | ||||||||||
|
|
||||||||||
| query = query.lower() | ||||||||||
|
|
||||||||||
| if any(word in query for word in ["summary", "report", "insight", "dashboard", "track"]): | ||||||||||
| return "get_insights" | ||||||||||
|
|
||||||||||
| if "appointment" in query: | ||||||||||
| return "appointments" | ||||||||||
| elif "weight" in query: | ||||||||||
| return "weight" | ||||||||||
| elif "symptom" in query: | ||||||||||
| return "symptoms" | ||||||||||
| elif "medicine" in query or "took" in query or "tablet" in query or "pill" in query: | ||||||||||
| return "medicine" | ||||||||||
|
Comment on lines
+16
to
+17
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The keyword "took" is too generic and may cause false positives. The word "took" appears in many non-medicine contexts (e.g., "I took a walk", "I took notes"). Consider requiring a combination of keywords or using a regex pattern that looks for medicine-related context. Suggested improvement- elif "medicine" in query or "took" in query or "tablet" in query or "pill" in query:
+ elif "medicine" in query or "tablet" in query or "pill" in query or ("took" in query and any(kw in query for kw in ["mg", "tablet", "pill", "capsule", "dose"])):
return "medicine"📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| elif "bp" in query or "blood pressure" in query or "/" in query: | ||||||||||
| return "blood_pressure" | ||||||||||
|
Comment on lines
+18
to
+19
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Overly broad "/" pattern will cause false positives. The "/" character alone as a trigger for Additionally, the ordering creates an issue: a query like "I took my BP 120/80" would be classified as "medicine" (due to "took") rather than "blood_pressure". Proposed fix: Use a more specific BP pattern- elif "bp" in query or "blood pressure" in query or "/" in query:
+ elif "bp" in query or "blood pressure" in query or re.search(r'\d{2,3}\s*/\s*\d{2,3}', query):
return "blood_pressure"This requires adding
🤖 Prompt for AI Agents |
||||||||||
| elif "vaccine" in query or "guideline" in query or "what tests" in query or "recommend" in query: | ||||||||||
| return "guidelines" | ||||||||||
| return "general" | ||||||||||
|
|
||||||||||
| return "general" | ||||||||||
Uh oh!
There was an error while loading. Please reload this page.