From 8ac7a5129ab9f9510bcb42a69e1e4c6d363c4c60 Mon Sep 17 00:00:00 2001 From: chelsea Date: Tue, 17 Feb 2026 18:11:44 -0600 Subject: [PATCH] fixed spamming i hope --- ai/ai_config.json | 2 +- bot/commands/medications.py | 40 ++++++++++++++++++++++++++++++++++++- core/adaptive_meds.py | 18 ++++++++--------- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/ai/ai_config.json b/ai/ai_config.json index 9dedb04..f7220ad 100644 --- a/ai/ai_config.json +++ b/ai/ai_config.json @@ -4,7 +4,7 @@ "prompts": { "command_parser": { "system": "You are a helpful AI assistant that parses user commands into structured JSON. Extract the user's intent and relevant parameters from natural language. Return ONLY valid JSON, no explanations.\n\nBe flexible with language - handle typos, slang, and casual phrasing. Consider conversation context when available.\n\n=== TIME CONVERSION RULES ===\nConvert all times to 24-hour format HH:MM in a JSON array:\n- \"4:20pm\", \"4:20 PM\" → [\"16:20\"]\n- \"9am\", \"9 AM\" → [\"09:00\"]\n- \"morning\" → [\"09:00\"]\n- \"evening\", \"night\" → [\"20:00\"]\n- \"noon\" → [\"12:00\"]\n- \"midnight\" → [\"00:00\"]\n- \"4:20\" (ambiguous) → set needs_clarification: \"Is that 4:20 AM or PM?\"\n- Multiple times: \"9am and 9pm\" → [\"09:00\", \"21:00\"]\n\n=== FREQUENCY MAPPING ===\nMap natural language to exact enum values:\n- \"every day\", \"daily\" → frequency: \"daily\"\n- \"twice a day\", \"twice daily\", \"2x daily\" → frequency: \"twice_daily\", times: [\"08:00\", \"20:00\"] (unless specified otherwise)\n- \"every tuesday\", \"tuesdays\" → frequency: \"specific_days\", days_of_week: [\"tue\"]\n- \"monday wednesday friday\", \"m/w/f\" → frequency: \"specific_days\", days_of_week: [\"mon\", \"wed\", \"fri\"]\n- \"every 3 days\", \"every three days\" → frequency: \"every_n_days\", interval_days: 3\n- \"as needed\", \"prn\" → frequency: \"as_needed\", times: []\n\nDay abbreviations: mon, tue, wed, thu, fri, sat, sun\n\n=== DOSAGE EXTRACTION ===\n- \"50 mcg\" → dosage: 50, unit: \"mcg\"\n- \"1 pill\", \"one pill\" → dosage: 1, unit: \"pill\"\n- \"5mg\" → dosage: 5, unit: \"mg\"\n- \"100 micrograms\" → dosage: 100, unit: \"mcg\"\n- No dosage mentioned → set needs_clarification\n\n=== VALIDATION RULES ===\nSet needs_clarification if:\n1. Dosage is missing for 'add' action\n2. Time is ambiguous (e.g., just \"4:20\" without AM/PM)\n3. Frequency is unclear (e.g., \"sometimes\", \"often\")\n4. Name cannot be determined\n\n=== INTERACTION TYPES ===\n- \"routine\": habits, morning routines, task sequences\n- \"medication\": pills, prescriptions, supplements, dosages\n- \"knowledge\": questions about books, asking what a book says, referencing book content\n\n=== KNOWLEDGE BASE EXAMPLES ===\n- \"what does the book say about time management?\" → {\"interaction_type\": \"knowledge\", \"action\": \"query\", \"query\": \"time management\"}\n- \"ask atomic habits about habit formation\" → {\"interaction_type\": \"knowledge\", \"action\": \"query\", \"book\": \"atomic habits\", \"query\": \"habit formation\"}\n- \"list available books\" → {\"interaction_type\": \"knowledge\", \"action\": \"list\"}\n- \"select book 2\" → {\"interaction_type\": \"knowledge\", \"action\": \"select\", \"book\": \"2\"}\n- \"how does the ADHD book suggest handling procrastination?\" → {\"interaction_type\": \"knowledge\", \"action\": \"query\", \"book\": \"adhd\", \"query\": \"handling procrastination\"}\n- \"what does taking charge of adult adhd say about sleep?\" → {\"interaction_type\": \"knowledge\", \"action\": \"query\", \"book\": \"taking charge of adult adhd\", \"query\": \"sleep\"}\n- \"how do I handle ADHD at work according to the book?\" → {\"interaction_type\": \"knowledge\", \"action\": \"query\", \"query\": \"handling ADHD at work\"}", - "user_template": "Parse this command into structured JSON.\n\nCurrent conversation context:\n{history_context}\n\nUser message: \"{user_input}\"\n\nReturn JSON with these exact fields:\n{{\n \"interaction_type\": \"routine\" | \"medication\" | \"knowledge\",\n \"action\": \"string\",\n \"name\": \"string\" (med/routine name),\n \"routine_name\": \"string\" (for step-related actions),\n \"description\": \"string\" (optional),\n \"steps\": [\"step1\", \"step2\"] (for routine creation),\n \"dosage\": number (for meds),\n \"unit\": \"string\" (mg, mcg, pill, etc),\n \"frequency\": \"daily\" | \"twice_daily\" | \"specific_days\" | \"every_n_days\" | \"as_needed\",\n \"times\": [\"HH:MM\"],\n \"days_of_week\": [\"mon\", \"tue\", ...],\n \"interval_days\": number (for every_n_days),\n \"query\": \"string\" (for knowledge questions),\n \"book\": \"string\" (book name/number for knowledge queries),\n \"needs_confirmation\": boolean (true for destructive/create actions),\n \"confirmation_prompt\": \"string\" (what to ask user),\n \"confidence\": number (0-1),\n \"needs_clarification\": \"string\" (if confidence < 0.8 or missing required fields)\n}}\n\n=== EXAMPLES ===\n\nMedication examples:\n1. User: \"take a giant dab of THC\"\n {{\"interaction_type\": \"medication\", \"action\": \"take\", \"name\": \"THC\", \"confidence\": 0.9}}\n\n2. User: \"add lsd 50 mcg daily at 9am\"\n {{\"interaction_type\": \"medication\", \"action\": \"add\", \"name\": \"lsd\", \"dosage\": 50, \"unit\": \"mcg\", \"frequency\": \"daily\", \"times\": [\"09:00\"], \"confidence\": 0.95}}\n\n3. User: \"add wellbutrin 150 mg twice daily\"\n {{\"interaction_type\": \"medication\", \"action\": \"add\", \"name\": \"wellbutrin\", \"dosage\": 150, \"unit\": \"mg\", \"frequency\": \"twice_daily\", \"times\": [\"08:00\", \"20:00\"], \"confidence\": 0.95}}\n\n4. User: \"i took my spironolactone\"\n {{\"interaction_type\": \"medication\", \"action\": \"take\", \"name\": \"spironolactone\", \"confidence\": 0.95}}\n\n5. User: \"took my meds\" (ambiguous - needs clarification)\n {{\"interaction_type\": \"medication\", \"action\": \"take\", \"name\": null, \"needs_clarification\": \"Which medication did you take?\", \"confidence\": 0.6}}\n\n6. User: \"i took my 50mg spiro\"\n {{\"interaction_type\": \"medication\", \"action\": \"take\", \"name\": \"spiro\", \"dosage\": 50, \"unit\": \"mg\", \"confidence\": 0.9}}\n\n7. User: \"skip my wellbutrin today\"\n {{\"interaction_type\": \"medication\", \"action\": \"skip\", \"name\": \"wellbutrin\", \"confidence\": 0.9}}\n\n8. User: \"snooze my spironolactone reminder for 30 minutes\"\n {{\"interaction_type\": \"medication\", \"action\": \"snooze\", \"name\": \"spironolactone\", \"minutes\": 30, \"confidence\": 0.95}}\n\nRoutine examples:\n1. User: \"create morning routine with brush teeth, shower, eat\"\n {{\"interaction_type\": \"routine\", \"action\": \"create_with_steps\", \"name\": \"morning\", \"steps\": [\"brush teeth\", \"shower\", \"eat\"], \"confidence\": 0.95}}\n\n2. User: \"start my morning routine\"\n {{\"interaction_type\": \"routine\", \"action\": \"start\", \"name\": \"morning\", \"confidence\": 0.9}}\n\n3. User: \"done with step 3\"\n {{\"interaction_type\": \"routine\", \"action\": \"advance_step\", \"confidence\": 0.9}}\n\n4. User: \"skip this step\"\n {{\"interaction_type\": \"routine\", \"action\": \"skip_step\", \"confidence\": 0.9}}\n\n5. User: \"pause my routine\"\n {{\"interaction_type\": \"routine\", \"action\": \"pause\", \"confidence\": 0.9}}\n\nKnowledge examples:\n1. User: \"what does the book say about time management?\"\n {{\"interaction_type\": \"knowledge\", \"action\": \"query\", \"query\": \"time management\", \"confidence\": 0.9}}\n\n2. User: \"ask atomic habits about habit formation\"\n {{\"interaction_type\": \"knowledge\", \"action\": \"query\", \"book\": \"atomic habits\", \"query\": \"habit formation\", \"confidence\": 0.95}}\n\n3. User: \"list available books\"\n {{\"interaction_type\": \"knowledge\", \"action\": \"list\", \"confidence\": 0.95}}\n\n4. User: \"select book 2\"\n {{\"interaction_type\": \"knowledge\", \"action\": \"select\", \"book\": \"2\", \"confidence\": 0.95}}\n\n5. User: \"what does taking charge of adult adhd say about sleep?\"\n {{\"interaction_type\": \"knowledge\", \"action\": \"query\", \"book\": \"taking charge of adult adhd\", \"query\": \"sleep\", \"confidence\": 0.95}}\n\n6. User: \"how do I handle ADHD at work according to the book?\"\n {{\"interaction_type\": \"knowledge\", \"action\": \"query\", \"query\": \"handling ADHD at work\", \"confidence\": 0.9}}" + "user_template": "Parse this command into structured JSON.\n\nCurrent conversation context:\n{history_context}\n\nUser message: \"{user_input}\"\n\nReturn JSON with these exact fields:\n{{\n \"interaction_type\": \"routine\" | \"medication\" | \"knowledge\",\n \"action\": \"string\",\n \"name\": \"string\" (med/routine name),\n \"routine_name\": \"string\" (for step-related actions),\n \"description\": \"string\" (optional),\n \"steps\": [\"step1\", \"step2\"] (for routine creation),\n \"dosage\": number (for meds),\n \"unit\": \"string\" (mg, mcg, pill, etc),\n \"frequency\": \"daily\" | \"twice_daily\" | \"specific_days\" | \"every_n_days\" | \"as_needed\",\n \"times\": [\"HH:MM\"],\n \"days_of_week\": [\"mon\", \"tue\", ...],\n \"interval_days\": number (for every_n_days),\n \"query\": \"string\" (for knowledge questions),\n \"book\": \"string\" (book name/number for knowledge queries),\n \"needs_confirmation\": boolean (true for destructive/create actions),\n \"confirmation_prompt\": \"string\" (what to ask user),\n \"confidence\": number (0-1),\n \"needs_clarification\": \"string\" (if confidence < 0.8 or missing required fields)\n}}\n\n=== EXAMPLES ===\n\nMedication examples:\n1. User: \"take a giant dab of THC\"\n {{\"interaction_type\": \"medication\", \"action\": \"take\", \"name\": \"THC\", \"confidence\": 0.9}}\n\n2. User: \"add lsd 50 mcg daily at 9am\"\n {{\"interaction_type\": \"medication\", \"action\": \"add\", \"name\": \"lsd\", \"dosage\": 50, \"unit\": \"mcg\", \"frequency\": \"daily\", \"times\": [\"09:00\"], \"confidence\": 0.95}}\n\n3. User: \"add wellbutrin 150 mg twice daily\"\n {{\"interaction_type\": \"medication\", \"action\": \"add\", \"name\": \"wellbutrin\", \"dosage\": 150, \"unit\": \"mg\", \"frequency\": \"twice_daily\", \"times\": [\"08:00\", \"20:00\"], \"confidence\": 0.95}}\n\n4. User: \"i took my spironolactone\"\n {{\"interaction_type\": \"medication\", \"action\": \"take\", \"name\": \"spironolactone\", \"confidence\": 0.95}}\n\n5. User: \"took my meds\" or \"i took all my meds\" or \"all the due ones\" (batch - mark all pending doses as taken)\n {{\"interaction_type\": \"medication\", \"action\": \"take_all\", \"confidence\": 0.9}}\n\n6. User: \"i took my 50mg spiro\"\n {{\"interaction_type\": \"medication\", \"action\": \"take\", \"name\": \"spiro\", \"dosage\": 50, \"unit\": \"mg\", \"confidence\": 0.9}}\n\n7. User: \"skip my wellbutrin today\"\n {{\"interaction_type\": \"medication\", \"action\": \"skip\", \"name\": \"wellbutrin\", \"confidence\": 0.9}}\n\n8. User: \"snooze my spironolactone reminder for 30 minutes\"\n {{\"interaction_type\": \"medication\", \"action\": \"snooze\", \"name\": \"spironolactone\", \"minutes\": 30, \"confidence\": 0.95}}\n\nRoutine examples:\n1. User: \"create morning routine with brush teeth, shower, eat\"\n {{\"interaction_type\": \"routine\", \"action\": \"create_with_steps\", \"name\": \"morning\", \"steps\": [\"brush teeth\", \"shower\", \"eat\"], \"confidence\": 0.95}}\n\n2. User: \"start my morning routine\"\n {{\"interaction_type\": \"routine\", \"action\": \"start\", \"name\": \"morning\", \"confidence\": 0.9}}\n\n3. User: \"done with step 3\"\n {{\"interaction_type\": \"routine\", \"action\": \"advance_step\", \"confidence\": 0.9}}\n\n4. User: \"skip this step\"\n {{\"interaction_type\": \"routine\", \"action\": \"skip_step\", \"confidence\": 0.9}}\n\n5. User: \"pause my routine\"\n {{\"interaction_type\": \"routine\", \"action\": \"pause\", \"confidence\": 0.9}}\n\nKnowledge examples:\n1. User: \"what does the book say about time management?\"\n {{\"interaction_type\": \"knowledge\", \"action\": \"query\", \"query\": \"time management\", \"confidence\": 0.9}}\n\n2. User: \"ask atomic habits about habit formation\"\n {{\"interaction_type\": \"knowledge\", \"action\": \"query\", \"book\": \"atomic habits\", \"query\": \"habit formation\", \"confidence\": 0.95}}\n\n3. User: \"list available books\"\n {{\"interaction_type\": \"knowledge\", \"action\": \"list\", \"confidence\": 0.95}}\n\n4. User: \"select book 2\"\n {{\"interaction_type\": \"knowledge\", \"action\": \"select\", \"book\": \"2\", \"confidence\": 0.95}}\n\n5. User: \"what does taking charge of adult adhd say about sleep?\"\n {{\"interaction_type\": \"knowledge\", \"action\": \"query\", \"book\": \"taking charge of adult adhd\", \"query\": \"sleep\", \"confidence\": 0.95}}\n\n6. User: \"how do I handle ADHD at work according to the book?\"\n {{\"interaction_type\": \"knowledge\", \"action\": \"query\", \"query\": \"handling ADHD at work\", \"confidence\": 0.9}}" } }, "validation": { diff --git a/bot/commands/medications.py b/bot/commands/medications.py index ad52437..84dc38b 100644 --- a/bot/commands/medications.py +++ b/bot/commands/medications.py @@ -423,6 +423,44 @@ async def handle_medication(message, session, parsed): else: await message.channel.send(f"Error: {resp.get('error', 'Failed to log')}") + elif action == "take_all": + # Mark all currently pending (untaken, non-skipped, non-PRN) doses as taken + timezone_offset = await _get_user_timezone(message, session, token) + + resp, status = api_request("get", "/api/medications/today", token) + if status != 200: + await message.channel.send("Error fetching today's medications.") + return + + meds_today = resp if isinstance(resp, list) else [] + marked = [] + skipped_already = [] + + for item in meds_today: + med = item.get("medication", {}) + if item.get("is_prn"): + continue + times = item.get("scheduled_times", []) + taken = set(item.get("taken_times", [])) + skipped = set(item.get("skipped_times", [])) + med_id_local = med.get("id") + med_name = med.get("name", "Unknown") + + pending_times = [t for t in times if t not in taken and t not in skipped] + if not pending_times: + skipped_already.append(med_name) + continue + + for t in pending_times: + api_request("post", f"/api/medications/{med_id_local}/take", token, {"scheduled_time": t}) + marked.append(f"**{med_name}** ({', '.join(pending_times)})") + + if not marked: + await message.channel.send("✅ All medications are already logged for today!") + else: + lines = "\n".join(f"✅ {m}" for m in marked) + await message.channel.send(f"Logged as taken:\n{lines}") + elif action == "skip": med_id = parsed.get("medication_id") name = parsed.get("name") @@ -645,7 +683,7 @@ async def handle_medication(message, session, parsed): else: await message.channel.send( - f"Unknown action: {action}. Try: list, add, delete, take, skip, today, refills, snooze, or adherence." + f"Unknown action: {action}. Try: list, add, delete, take, take_all, skip, today, refills, snooze, or adherence." ) diff --git a/core/adaptive_meds.py b/core/adaptive_meds.py index 0de4e2f..5c83ce0 100644 --- a/core/adaptive_meds.py +++ b/core/adaptive_meds.py @@ -12,7 +12,7 @@ import json from datetime import datetime, timedelta, time from typing import Optional, Dict, List, Tuple import core.postgres as postgres -from core.tz import user_now +from core.tz import user_now, user_today_for def get_adaptive_settings(user_uuid: str) -> Optional[Dict]: @@ -249,12 +249,12 @@ def should_send_nag( if not presence.get("is_currently_online"): return False, "User offline" - # Get today's schedule record + # Get today's schedule record for this specific time slot today = current_time.date() - schedules = postgres.select( - "medication_schedules", - {"user_uuid": user_uuid, "medication_id": med_id, "adjustment_date": today}, - ) + query = {"user_uuid": user_uuid, "medication_id": med_id, "adjustment_date": today} + if scheduled_time is not None: + query["adjusted_time"] = scheduled_time + schedules = postgres.select("medication_schedules", query) if not schedules: return False, "No schedule found" @@ -295,7 +295,7 @@ def should_send_nag( def record_nag_sent(user_uuid: str, med_id: str, scheduled_time: str): """Record that a nag was sent.""" - today = datetime.utcnow().date() + today = user_today_for(user_uuid) schedules = postgres.select( "medication_schedules", @@ -315,7 +315,7 @@ def record_nag_sent(user_uuid: str, med_id: str, scheduled_time: str): def create_daily_schedule(user_uuid: str, med_id: str, base_times: List[str]): """Create today's medication schedule with adaptive adjustments.""" - today = datetime.utcnow().date() + today = user_today_for(user_uuid) # Check if schedule already exists existing = postgres.select( @@ -346,7 +346,7 @@ def create_daily_schedule(user_uuid: str, med_id: str, base_times: List[str]): def mark_med_taken(user_uuid: str, med_id: str, scheduled_time: str): """Mark a medication as taken.""" - today = datetime.utcnow().date() + today = user_today_for(user_uuid) postgres.update( "medication_schedules",