| """ |
| export_tool.py β Assemble and export caregiver data summaries. |
| |
| Combines selected data (meds, appointments, food chart, and an optional |
| document summary) into a formatted text block ready for copy, email, or print. |
| """ |
|
|
| from __future__ import annotations |
|
|
| import textwrap |
| from datetime import datetime |
| from typing import Optional |
|
|
| from config import load_patient_config |
| from med_tracker import get_medications |
| from appointment_tracker import get_upcoming |
| from food_tracker import get_food |
| from profiles import get_profile |
|
|
|
|
| |
|
|
| def assemble_export( |
| include_meds: bool = True, |
| include_appointments: bool = True, |
| include_food: bool = True, |
| document_summary: Optional[str] = None, |
| custom_note: Optional[str] = None, |
| profile_id: Optional[str] = None, |
| ) -> str: |
| """ |
| Assemble a formatted text export block. |
| |
| Returns a multi-line string suitable for copy-to-clipboard, email body, |
| or print. |
| """ |
| cfg = load_patient_config() |
| today = datetime.now().strftime("%B %d, %Y at %I:%M %p") |
| profile = get_profile(profile_id) if profile_id else None |
| patient_label = "" |
| if profile: |
| patient_label = profile.get("full_name") or profile.get("label") or "" |
|
|
| lines = [] |
|
|
| |
| lines.append("=" * 60) |
| lines.append(" CAREGIVER SUMMARY REPORT") |
| lines.append(f" Generated: {today}") |
| if patient_label: |
| lines.append(f" Patient: {patient_label}") |
| elif cfg.get("patient_name"): |
| lines.append(f" Patient: {cfg['patient_name']}") |
| lines.append("=" * 60) |
| lines.append("") |
|
|
| |
| if custom_note and custom_note.strip(): |
| lines.append("NOTES") |
| lines.append("-" * 40) |
| lines.append(custom_note.strip()) |
| lines.append("") |
|
|
| |
| if include_meds: |
| meds = get_medications(filter="current", profile_id=profile_id) |
| lines.append("CURRENT MEDICATIONS") |
| lines.append("-" * 40) |
| if meds: |
| for med in meds: |
| parts = [med["name"]] |
| if med.get("dosage"): |
| parts.append(med["dosage"]) |
| if med.get("frequency"): |
| parts.append(f"({med['frequency']})") |
| lines.append("β’ " + " ".join(parts)) |
| if med.get("side_effects"): |
| lines.append(f" β³ Side effects: {med['side_effects']}") |
| if med.get("personal_notes"): |
| lines.append(f" β³ Notes: {med['personal_notes']}") |
| else: |
| lines.append("No current medications on file.") |
| lines.append("") |
|
|
| |
| if include_appointments: |
| appts = get_upcoming(profile_id=profile_id) |
| lines.append("UPCOMING APPOINTMENTS") |
| lines.append("-" * 40) |
| if appts: |
| for appt in appts: |
| date_str = appt.get("date", "") |
| time_str = appt.get("time", "") |
| when = date_str + (f" at {time_str}" if time_str else "") |
| lines.append(f"β’ {appt['title']} β {when}") |
| if appt.get("location"): |
| lines.append(f" Location: {appt['location']}") |
| if appt.get("notes"): |
| lines.append(f" Notes: {appt['notes']}") |
| else: |
| lines.append("No upcoming appointments.") |
| lines.append("") |
|
|
| |
| if include_food: |
| food_data = get_food(profile_id=profile_id) |
| lines.append("FOOD CHART") |
| lines.append("-" * 40) |
|
|
| liked = food_data.get("liked_foods", []) |
| disliked = food_data.get("disliked_foods", []) |
| allergies = food_data.get("allergies", []) |
|
|
| if allergies: |
| lines.append("β Allergies:") |
| for e in allergies: |
| note_part = f" ({e['notes']})" if e.get("notes") else "" |
| lines.append(f" β’ {e['name']}{note_part}") |
|
|
| if liked: |
| lines.append("β Liked Foods:") |
| for e in liked: |
| note_part = f" ({e['notes']})" if e.get("notes") else "" |
| lines.append(f" β’ {e['name']}{note_part}") |
|
|
| if disliked: |
| lines.append("β Disliked Foods:") |
| for e in disliked: |
| note_part = f" ({e['notes']})" if e.get("notes") else "" |
| lines.append(f" β’ {e['name']}{note_part}") |
|
|
| if not allergies and not liked and not disliked: |
| lines.append("No food data on file.") |
| lines.append("") |
|
|
| |
| if document_summary and document_summary.strip(): |
| lines.append("DOCUMENT SUMMARY") |
| lines.append("-" * 40) |
| |
| for para in document_summary.strip().split("\n"): |
| wrapped = textwrap.fill(para, width=58) if len(para) > 58 else para |
| lines.append(wrapped) |
| lines.append("") |
|
|
| |
| lines.append("=" * 60) |
| lines.append("Built for the Build Small Hackathon β Backyard AI Track") |
| lines.append("All data is stored locally. Nothing leaves this device.") |
| lines.append("=" * 60) |
|
|
| return "\n".join(lines) |
|
|
|
|
| def build_mailto_link( |
| to: str = "", |
| subject: str = "Caregiver Summary Report", |
| body: str = "", |
| ) -> str: |
| """ |
| Build a mailto: URL with pre-filled subject and body. |
| The body is URL-encoded so it works in href attributes. |
| """ |
| import urllib.parse |
| encoded_body = urllib.parse.quote(body) |
| encoded_subject = urllib.parse.quote(subject) |
| return f"mailto:{to}?subject={encoded_subject}&body={encoded_body}" |
|
|