diff --git a/ai/ai_config.json b/ai/ai_config.json index 0bc7ef2..21fd4b6 100644 --- a/ai/ai_config.json +++ b/ai/ai_config.json @@ -3,8 +3,8 @@ "max_tokens": 8192, "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\nIf unclear, ask for clarification in the 'needs_clarification' field with confidence < 0.8.\n\nAvailable interaction types:\n- \"routine\": managing daily routines (create, start, complete steps, view history)\n- \"medication\": managing medications (add, take, skip, snooze, check schedule, refills)\n\nFor routine commands, extract: action (create|list|start|complete_step|skip_step|cancel|history|schedule), routine_name?, step_name?, duration_minutes?, days?, time?\nFor medication commands, extract: action (add|list|take|skip|snooze|today|adherence|refill), med_name?, dosage?, unit?, frequency?, times?, reason?, minutes?", - "user_template": "Parse this command into structured JSON.\n\nCurrent conversation context (if any):\n{history_context}\n\nUser message: \"{user_input}\"\n\nReturn JSON with:\n{{\n \"interaction_type\": \"routine\" or \"medication\",\n \"action\": \"string\",\n \"confidence\": number (0-1),\n \"needs_clarification\": \"string\" (if confidence < 0.8),\n ... other extracted fields ...\n}}\n\nIf unclear, ask for clarification in the needs_clarification field." + "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\nKEY RULES:\n1. 'habit' = 'routine' - treat these as the same thing\n2. Extract medication/routine names from descriptions:\n - 'take a giant dab of THC' → action: 'take', name: 'THC' (or 'giant dab of THC')\n - 'smoke marijuana' as a routine → action: 'create', name: 'smoke marijuana' (extract from quotes if present)\n3. If user says 'I want to...' or describes creating something, infer action: 'create'\n4. If user says 'called X' or 'named X', extract X as the name\n5. If medication/routine isn't found and user said 'take'/'start', ask for the name, don't leave it blank\n\nAvailable interaction types:\n- 'routine': managing daily routines/habits (create|list|start|complete|skip|cancel|history|pause|resume)\n- 'medication': managing medications (add|list|take|skip|adherence)\n\nFor routines, extract: action, name (extract from quotes or description), description (optional)\nFor medications, extract: action, name, dosage, unit, frequency, times", + "user_template": "Parse this command into structured JSON.\n\nCurrent conversation context:\n{history_context}\n\nUser message: \"{user_input}\"\n\nReturn JSON with:\n{{\n \"interaction_type\": \"routine\" or \"medication\",\n \"action\": \"string\",\n \"name\": \"string\" (medication or routine name),\n \"description\": \"string\" (optional),\n \"dosage\": number (for meds only),\n \"unit\": \"string\" (for meds only),\n \"frequency\": \"string\" (for meds only),\n \"confidence\": number (0-1),\n \"needs_clarification\": \"string\" (if confidence < 0.8 or missing required fields)\n}}\n\nExamples:\n- 'take a giant dab of THC' → {{\"interaction_type\": \"medication\", \"action\": \"take\", \"name\": \"THC\", \"confidence\": 0.9}}\n- 'I want to create a habit called smoke dope' → {{\"interaction_type\": \"routine\", \"action\": \"create\", \"name\": \"smoke dope\", \"confidence\": 0.95}}\n- 'start my morning routine' → {{\"interaction_type\": \"routine\", \"action\": \"start\", \"name\": \"morning routine\", \"confidence\": 0.9}}\n- 'which meds do I have?' → {{\"interaction_type\": \"medication\", \"action\": \"list\", \"confidence\": 0.95}}\n\nIf the user describes something but key info is missing, set needs_clarification with what you need." } }, "validation": { diff --git a/bot/commands/medications.py b/bot/commands/medications.py index f5fb18d..0db4002 100644 --- a/bot/commands/medications.py +++ b/bot/commands/medications.py @@ -44,9 +44,28 @@ async def handle_medication(message, session, parsed): elif action == "take": med_id = parsed.get("medication_id") - if not med_id: + name = parsed.get("name") + + if not med_id and name: + # Look up medication by name + resp, status = api_request("get", "/api/medications", token) + if status == 200: + meds = resp if isinstance(resp, list) else [] + # Find medication by name (case-insensitive partial match) + matching = [m for m in meds if name.lower() in m['name'].lower() or m['name'].lower() in name.lower()] + if matching: + med_id = matching[0]['id'] + name = matching[0]['name'] + else: + await message.channel.send(f"I couldn't find a medication called '{name}'. Use 'list' to see your medications.") + return + else: + await message.channel.send("Error looking up medication. Please try again.") + return + elif not med_id: await message.channel.send("Which medication did you take?") return + resp, status = api_request("post", f"/api/medications/{med_id}/take", token, {}) if status == 201: await message.channel.send("Logged it! Great job staying on track.") @@ -55,10 +74,29 @@ async def handle_medication(message, session, parsed): elif action == "skip": med_id = parsed.get("medication_id") + name = parsed.get("name") reason = parsed.get("reason", "Skipped by user") - if not med_id: + + if not med_id and name: + # Look up medication by name + resp, status = api_request("get", "/api/medications", token) + if status == 200: + meds = resp if isinstance(resp, list) else [] + # Find medication by name (case-insensitive partial match) + matching = [m for m in meds if name.lower() in m['name'].lower() or m['name'].lower() in name.lower()] + if matching: + med_id = matching[0]['id'] + name = matching[0]['name'] + else: + await message.channel.send(f"I couldn't find a medication called '{name}'. Use 'list' to see your medications.") + return + else: + await message.channel.send("Error looking up medication. Please try again.") + return + elif not med_id: await message.channel.send("Which medication are you skipping?") return + resp, status = api_request("post", f"/api/medications/{med_id}/skip", token, {"reason": reason}) if status == 201: await message.channel.send("OK, noted.") diff --git a/bot/commands/routines.py b/bot/commands/routines.py index 79437a7..410a785 100644 --- a/bot/commands/routines.py +++ b/bot/commands/routines.py @@ -40,7 +40,25 @@ async def handle_routine(message, session, parsed): elif action == "start": routine_id = parsed.get("routine_id") - if not routine_id: + name = parsed.get("name") + + if not routine_id and name: + # Look up routine by name + resp, status = api_request("get", "/api/routines", token) + if status == 200: + routines = resp if isinstance(resp, list) else [] + # Find routine by name (case-insensitive partial match) + matching = [r for r in routines if name.lower() in r['name'].lower() or r['name'].lower() in name.lower()] + if matching: + routine_id = matching[0]['id'] + name = matching[0]['name'] + else: + await message.channel.send(f"I couldn't find a routine called '{name}'. Use 'list' to see your routines.") + return + else: + await message.channel.send("Error looking up routine. Please try again.") + return + elif not routine_id: await message.channel.send("Which routine would you like to start?") return