Apple Health Data에서 임상 스토리텔링으로: Python 및 Gemini로 AI 기반 보고서 작성

작성자

카테고리:

← 피드로
DEV Community · Romina Elena Mendez Escobar · 2026-07-20 개발(SW)

Introduction

At recent technology conferences, one topic has caught my attention: every year, more health-focused devices, sensors, and applications appear. Smartwatches track heart rate, smart scales measure body data, glucose monitors record blood sugar levels, and apps help users track sleep or nutrition. Today, the amount of information we can collect about our own bodies is enormous.

This article was inspired by an everyday experience with my father, Herminio ❤️. Whenever he has a medical appointment, he opens the Apple Health app and shows the doctor the evolution of his heart rate, physical activity, sleep hours, and other recorded metrics.

While watching this, I kept asking myself the same question: are we really making the most of all this information?

Showing a chart during a medical appointment can be useful, but the data could provide much more value if it were automatically processed, summarized, and transformed into a structured health report.

For this reason in this project, I use Gemini to transform previously calculated metrics into a clear and organized summary. The LLM does not analyze all the raw records or perform the main calculations. The pipeline processes the data, calculates the indicators, and generates the visualizations, while the model acts as a support layer for building the report narrative.

The goal is not to create a medical application or replace professional judgment. Instead, the purpose is to build a prototype that shows how Apple Health exports, deterministic data processing, visualizations, and an LLM can be combined to generate automated reports.

This project was developed using simulated data from three patients, so the complete pipeline can be reproduced without using real clinical information.

✨ Why Gemini?

This project uses an LLM to transform previously processed metrics into a structured narrative that can be reviewed more easily by a healthcare professional.
I chose Gemini for practical reasons:

  • 〰️ I was already familiar with its API, it integrates easily with Python, and Google AI Studio makes it simple to test and adjust prompts.
  • 〰️ It also offers a good balance between speed, performance, and cost for text-generation tasks.
  • 〰️ Its free tier also makes it easier to reproduce this MVP without initial costs.

In this case, I use a general-purpose model because all calculations are completed in Python before the data is sent to Gemini. The model only organizes the results into readable text.
For projects that need to analyze clinical documents or medical images directly, specialized models such as MedGemma could also be evaluated. MedGemma is a family of open Google models adapted for healthcare-related tasks. However, its implementation, evaluation, and validation are outside the scope of this tutorial.

2. HealthKit: The Framework Behind the Data

Although most users only interact with the Apple Health app, HealthKit is the framework behind it. Apple provides HealthKit so developers can securely access health information stored on the device.

HealthKit works as a central repository where the iPhone and Apple Watch store health and fitness data. With the user’s explicit permission, authorized applications can read and write information through a single API. This avoids the need for every app to maintain its own separate database.

HealthKit currently supports hundreds of data types across many areas of health and well-being. The following figure presents a simplified grouping of some of these categories to provide a clearer overview of the available information.

This taxonomy was created specifically for this article based on publicly available HealthKit documentation. It is not an official Apple classification and should be understood as a summarized, author-created interpretation for explanatory purposes.

Thanks to this architecture, HealthKit makes it possible to:

  • Collect and store health and fitness information.
  • Analyze and visualize how this data changes over time.
  • Share information between authorized applications, reducing duplication and enabling new user experiences.

One of the most interesting design decisions in HealthKit is its large catalog of predefined classes and data types for standardized health metrics.

At first, this may seem restrictive for developers. However, it is actually one of the platform’s main strengths because it ensures that all stored information follows a consistent data model. This means that heart rate, blood glucose, or body weight always represent the same type of information and use the same units, regardless of the device or application that created the record.

This standardization simplifies application development, improves interoperability between apps, and helps maintain consistency across the data stored in HealthKit.

2.1 Data Sources

One of HealthKit’s main benefits is its ability to bring data from multiple sources into a single repository.
The most common sources include:

  • iPhone: records steps, distance traveled, mobility data, and other indicators collected through its sensors.
  • Apple Watch: provides physiological metrics such as heart rate, electrocardiogram (ECG), blood oxygen saturation (SpO₂), body temperature, sleep data, workouts, and cardiorespiratory fitness (VO₂ Max).
  • Third-party apps: can add information related to nutrition, mental health, hydration, medication, menstrual cycles, or sports training.
  • Connected medical devices and wearables: HealthKit supports Bluetooth Low Energy (BLE) health devices and medical data profiles. It can also work with FHIR (Fast Healthcare Interoperability Resources), making it possible to integrate data from devices such as glucose meters and blood pressure monitors, as well as clinical records from authorized healthcare institutions.

3. HL7 / FHIR Compatibility

So far, we have mainly discussed data generated by devices and applications. However, in 2018 Apple expanded the Health app by introducing Health Records, a feature that allows users to import structured clinical information from supported healthcare institutions. That same year, Apple also opened access to these records for authorized applications through the HealthKit API.

Health Records is built on HL7 FHIR, which stands for Fast Healthcare Interoperability Resources. FHIR is a standard developed by HL7 International to represent and exchange health information electronically between hospitals, applications, and Electronic Health Record systems.

FHIR organizes information into modular resources such as Patient, Observation, Condition, Procedure, MedicationRequest, and Immunization. Each resource represents a specific piece of clinical information that can be connected, queried, and exchanged between systems. Although FHIR can also be used to build clinical documents, its architecture does not require the entire patient record to be handled as one large document.

When records are downloaded from a supported institution, HealthKit represents each one as an HKClinicalRecord object, which keeps the original FHIR resource. Authorized applications can request the clinical record types they need and process their content as FHIR JSON. However, these records are read-only, which means applications cannot create new HKClinicalRecord objects or modify existing ones.

Access to any HealthKit information requires user consent, but clinical records have additional requirements because of their sensitivity. An application must enable the Clinical Health Records capability, include the required entitlement, explain why the information is needed, and request permission for each record type it wants to access. The use of this capability is also subject to Apple’s review process.

In HealthKit, clinical records are represented as read-only HKClinicalRecord objects that preserve the original FHIR content. Access requires explicit user authorization and is subject to additional privacy and platform requirements.

This architecture makes it possible to bring together information from different sources while keeping access centered on user consent and privacy.

4. HealthKit: Clinical Use Cases

The availability of large volumes of physiological data, combined with interoperability standards such as FHIR, has created many opportunities for research and clinical applications.

The value of this data does not come only from individual measurements, but from how they are analyzed over time. Tracking changes in heart rate, sleep, mobility, or activity levels can help identify patterns, summarize relevant information, and support patient monitoring in different healthcare scenarios.

The following figure presents some representative use cases, including early anomaly detection, remote patient monitoring, clinical summary generation, and synthetic data generation for research.

5. Technical, Clinical, and Regulatory Considerations

Before running the tutorial or using the code presented in this article, it is important to understand its scope and consider several limitations related to privacy, data quality, and the use of artificial intelligence in healthcare contexts.

5.1 Privacy and Data Protection

Health information is one of the most sensitive categories of personal data. Depending on the country and the context of use, it may be subject to regulations such as HIPAA in the United States or GDPR in the European Union.

Although this article uses only simulated data, any implementation that processes real information should include suitable controls for:

  • User consent.
  • Access management.
  • Data minimization.
  • Anonymization or pseudonymization.
  • Encryption.
  • Secure storage and processing.

5.2 Consumer Data Is Not a Diagnosis

Measurements collected through consumer devices can provide useful information for identifying trends and supporting long-term monitoring.
However, these records do not represent a medical diagnosis on their own and should not replace measurements taken with certified clinical equipment.

5.3 Data Quality and Continuity

The quality of the measurements can be affected by factors such as incorrect device placement, low battery levels, synchronization failures, periods when the device is not used, or differences between sensors and applications.
These situations may produce:

  • Incomplete records.
  • Duplicate measurements.
  • Outliers.
  • Periods with missing information.
  • Differences in units or sampling frequency.

For this reason, the data should be validated, cleaned, and normalized before generating any analysis. It is also important to identify periods where the available information is not complete enough to support reliable conclusions.

5.4 Use and Limitations of the LLM

In this project, the large language model does not diagnose conditions or recommend treatments. Its role is to transform previously calculated metrics into a clear and structured summary that can be reviewed more easily by a healthcare professional.

Any generated output should be treated as a draft that requires human review. The model may omit information, misunderstand a result, or produce statements that are not fully supported by the input data.

5.2 Scope of the Code

The repository provided with this article should be understood as an educational and experimental MVP. It is designed to demonstrate the general processing flow using simulated data.

It is not a medical product, a diagnostic tool, or an implementation ready for direct use in a clinical environment.
Before adapting the code to a real use case, additional validation would be required in areas such as:

  • Security and access control.
  • Error handling and traceability.
  • Data quality and provenance.
  • Reproducibility of the results.
  • Evaluation of the model’s responses.
  • Compliance with applicable standards and regulations.
  • Review and approval by qualified professionals.

The goal of this project is to present one possible architecture and explore its main components, not to provide a production-ready clinical solution.

6. Building the Apple Health Reporting Pipeline

In this tutorial, we will build a Python pipeline that processes an Apple Health XML export and generates a structured PDF report.
The pipeline will:

  • read and normalize the exported health records;
  • calculate mobility, cardiovascular, and sleep metrics;
  • compare the results against configurable reference values;
  • generate charts;
  • use Gemini to create a structured narrative;
  • combine everything into a final PDF report.

The generated report contains four main sections:

  • 🚶 Mobility: daily steps, walking speed, steadiness, gait metrics, and caloric expenditure.
  • ❤️ Cardiovascular: resting heart rate, HRV, oxygen saturation, VO₂ Max, and recovery metrics.
  • 😴 Sleep: average sleep duration and nights above or below the configured references.
  • 🤖 AI-generated summary: a structured narrative with patient profile, mobility, cardiovascular, sleep, and overall assessment sections.

The following diagram shows the complete flow of the project:

The implementation follows a modular architecture in which each class is responsible for one stage of the pipeline:

  • 📥 HealthDataReader reads and processes the Apple Health export.
  • 📊 HealthChartBuilder generates the visualizations.
  • HealthSummaryGenerator creates the narrative using Gemini.
  • 📄 HealthReportPDF combines the metrics, charts, and generated text into the final report.

In the next sections, we will review each stage separately. To keep the article focused, I will only include the most relevant code fragments and design decisions. The complete implementation, configuration files, prompt template, and simulated data are available in the project repository.

6.1 Prerequisites

To follow the tutorial, you will need:

  1. The project repository cloned locally.
  2. An Apple Health XML export or one of the simulated files included in the repository.
  3. A Gemini API key created from Google AI Studio.
  4. The Python dependencies installed from the project requirements.txt file.

You can clone the repository and install the dependencies with:

GitHub logo RominaElenaMendezEscobar / apple-health-data

Python pipeline that processes Apple Health XML exports, calculates health metrics, generates visualizations, creates a structured narrative with Gemini, and builds a final PDF report using simulated patient data.

Buy Me A Coffee

From Apple Health Data to Clinical Storytelling: Building an AI-Powered Report with Python and Gemini

Apple Health Reporting Pipeline with Python and Gemini

A modular Python pipeline that processes Apple Health XML exports, calculates health metrics, generates visualizations, creates an AI-assisted narrative with Gemini, and builds a structured PDF report.

img

This repository is an educational MVP built with simulated data. It is not a medical device, diagnostic tool, or production-ready clinical solution.

Overview

The pipeline:

  1. Reads and normalizes Apple Health XML records.
  2. Calculates mobility, cardiovascular, and sleep metrics.
  3. Compares results with configurable reference values.
  4. Generates charts with Matplotlib.
  5. Creates a structured narrative with Gemini.
  6. Combines metrics, charts, and text into a PDF report.

HealthKit: The Framework Behind the Data

HealthKit is Apple’s framework for storing and sharing health and fitness information collected by the iPhone, Apple Watch, third-party apps, and compatible devices.

It provides standardized data types for metrics such…

✨Gemini API key
You can create an API key from Google AI Studio.
After creating it, add a .env file at the root of the project:

gemini_api_key=YOUR_CREDENTIAL

Enter fullscreen mode Exit fullscreen mode

6.2 Data source

Apple Health allows users to export their information as a ZIP file containing an XML document.

The export can be generated from the Health app:

  1. Open the Health app on the iPhone.
  2. Tap the profile icon.
  3. Select Export All Health Data.
  4. Confirm the export.
  5. Extract the generated ZIP file.

The tutorial uses the export.xml structure produced by this process. However, to avoid exposing real health information, the repository includes three simulated patient files:

  • alex_28m.xml: 28-year-old male patient.
  • carlos_68m.xml: 68-year-old male patient.
  • maria_61f.xml: 61-year-old female patient. These files are stored in the patients/ folder and allow the complete pipeline to be reproduced without using real clinical data.

6.3 Orchestrating the Pipeline

The complete project is coordinated from the main.py file, which works as the application entry point. Its responsibility is not to process the data directly, but to create the specialized classes and execute each stage of the pipeline in the correct order.

This file also defines the list of patients to be processed. For each patient, it includes the XML file path and the name that will appear in the final report. The files are declared explicitly to make the example easier to follow, although a more general implementation could discover them automatically from a folder.

The complete main.py file is shown below:

from healthChartBuilder import HealthChartBuilder
from healthDataReader import HealthDataReader
from healthReportPDF import HealthReportPDF
from healthSummaryGenerator import HealthSummaryGenerator
import utils
import os

if __name__ == "__main__":
   patients = [
       ("patients/alex_28m.xml",   "Alex Torres"),
       ("patients/maria_61f.xml",  "María González"),
       ("patients/carlos_68m.xml", "Carlos Mendez"),
   ]

   os.makedirs("reports", exist_ok=True)
   os.makedirs("charts",  exist_ok=True)
   os.makedirs("data",    exist_ok=True)

   env = utils.read_env()

   for xml_path, name in patients:
       print(f"\n── {name} ──")
       prefix = name.lower().replace(' ', '_')

       # Step 1: read and compute
       reader = HealthDataReader(xml_path).load()

       # Step 1.1: save the compact LLM-friendly summary for this patient
       reader.save(write_llm_summary=True, file_name=prefix)

       # Step 2: generate charts
       builder = HealthChartBuilder(
           metrics    = reader.metrics,
           output_dir = "charts",
           prefix     = prefix,
       )
       charts = builder.build_all()

       # Step: generate the narrative summary with Gemini
       generator = HealthSummaryGenerator(
           json_path   = f"data/{prefix}_llm_summary.json",
           yml_path    = "config/params_health.yml",
           prompt_path = "prompt/prompt_summary.txt",
           api_key     = env["gemini_api_key"],
       ).load()
       llm_text = generator.generate()

       # Step 3: build PDF
       HealthReportPDF(
           metrics        = reader.metrics,
           charts         = charts,
           patient_name   = name,
           date_of_birth  = reader.date_of_birth,
           biological_sex = reader.biological_sex,
           start_date     = reader.df['start'].min(),
           end_date       = reader.df['start'].max(),
           out_path       = f"reports/{prefix}_report.pdf",
           llm_summary    = llm_text,
       ).build()

Enter fullscreen mode Exit fullscreen mode

6.4 Reading and Processing the Apple Health Export

The HealthDataReader class reads the XML file exported from Apple Health and transforms it into a structure that can be analyzed with Python. During this process, it extracts the available records, normalizes dates and numeric values, limits the analysis to the configured period, and calculates the metrics used by the next stages of the pipeline.

The class receives the XML file path and, optionally, the number of months to include in the analysis:

reader = HealthDataReader( 
xml_path="patients/alex_28m.xml", months=6, 
).load()

Enter fullscreen mode Exit fullscreen mode

The load() method runs two main operations:

  • 📥 _parse_xml() reads the file, extracts the records, and transforms them into a Pandas DataFrame.
  • 📐 _compute_metrics() calculates the daily series and aggregated indicators used in the analysis.

Threshold Configuration

The values used to classify or compare the metrics are not hardcoded inside the class. Instead, they are loaded from config/params_health.yml.

This separation makes it possible to update the reference values without changing the Python implementation:

threshold_steps_low:
  description: Step count threshold for red zone.
  value: 3000
threshold_steps_mid:
  description: Step count threshold for orange zone.
  value: 5000
threshold_steps_goal:
  description: Step count goal line.
  value: 7000
threshold_speed_low:
  description: Walking speed considered critically low.
  value: 3.5
threshold_speed_goal:
  description: Walking speed reference value.
  value: 4.5
threshold_steadiness:
  description: Steadiness warning value.
  value: 0.60
threshold_spo2_low:
  description: SpO2 critical threshold.
  value: 95.0
threshold_spo2:
  description: Minimum SpO2 reference value.
  value: 96.0
threshold_sleep_min:
  description: Sleep duration for red zone.
  value: 5.0
threshold_sleep_mid:
  description: Sleep duration for orange zone.
  value: 6.0
threshold_sleep_goal:
  description: Sleep duration goal.
  value: 7.0
threshold_hrv:
  description: Minimum HRV reference value.
  value: 25.0

Enter fullscreen mode Exit fullscreen mode

These parameters affect several parts of the project. They are used, for example, to calculate how many days fall below a specific step count, identify periods of low walking speed, evaluate sleep duration, and define the reference zones later used in the charts and the final report.

⚠️ Note: The values included in the repository are only for demonstration and are intended to support the example with simulated data. They should not be treated as clinical criteria. Before adapting the code to a real use case, the thresholds should be reviewed and validated by healthcare professionals, considering the population, age group, clinical context, and specific purpose of the solution.

Metric Selection

The _compute_metrics() method defines which data types are processed and which indicators are calculated. In the current implementation, the metrics are mainly organized into three groups:

  • 🚶 Mobility and activity: steps, walking speed, step length, steadiness, asymmetry, active energy, and flights climbed.
  • ❤️ Cardiovascular: resting heart rate, HRV, oxygen saturation, respiratory rate, VO₂ Max, and heart rate recovery.
  • 😴 Sleep: daily duration, average sleep, and the number of nights below or above the configured thresholds. The daily series are calculated using sums or averages, depending on the type of record:
steps = self._daily_sum("StepCount")
speed = self._daily_mean("WalkingSpeed")
hr = self._daily_mean("RestingHeartRate")
hrv = self._daily_mean("HeartRateVariabilitySDNN")
spo2 = self._daily_mean("OxygenSaturation")

Enter fullscreen mode Exit fullscreen mode

⚠️ Note: The thresholds are not the only values that should be reviewed. It is also important to confirm that the statistical methods used by the class are appropriate for each metric. For example, the mean can be affected by outliers. Before using this approach in production, other measures such as the median or percentiles may need to be evaluated.

Preparing the Data for the LLM

In addition to the full set of metrics, the class generates a smaller JSON file through to_llm_summary().
Instead of sending the complete time series, Python creates a compact and deterministic representation that includes:

  • 📊 mean and standard deviation;
  • ↕️ minimum and maximum values;
  • 📈 trend over the analysis period;
  • 📅 best and worst weekly averages;
  • 🔄 weekly variability;
  • ⏱️ longest consecutive period below the configured threshold.

Not every metric includes all of these fields, because some calculations do not apply in the same way to every type of data. This decision has two main benefits:

1. Reducing the amount of data sent to the model. An Apple Health export may contain thousands of records. Sending all observations would increase the prompt size, token usage, and execution cost, while also adding repetitive information that may not improve the final summary.
2. Keeping the calculations in Python. Averages, trends, minimum and maximum values, weekly statistics, and threshold streaks are calculated in advance using deterministic code. The LLM receives fixed and verifiable values and is only responsible for turning them into a natural-language summary.

This separation also makes the project easier to maintain. If the trend calculation changes or a new metric is added, the update can be made in Python without changing the role of the language model.
For example, the model receives a structure like this:

{
  "steps": {
    "mean": 9498.53,
    "std": 1728.37,
    "min": 5667.0,
    "max": 14201.0,
    "trend": "stable",
    "worst_week_mean": 8214.29,
    "best_week_mean": 10672.71,
    "weekly_volatility": 576.09,
    "worst_streak_below_threshold": 0
  }
}

Enter fullscreen mode Exit fullscreen mode

6.5 Generating Clinical Charts

The HealthChartBuilder class receives the metrics calculated by HealthDataReader and generates the charts that are later included in the final report.
To keep the presentation logic separate from the data-processing logic, the class uses two configuration files:

  • 🎯 params_health.yml: defines the reference thresholds used for color zones and horizontal lines in each chart.
  • 🎨 params_styles.yml: stores the color palette applied consistently across all visualizations.

Generated Charts

The build_all() method coordinates the chart-generation process and delegates each visualization to an independent private method:

  • 🚶 Activity and mobility_chart_steps(), _chart_mobility(), and _chart_calories(): daily steps with threshold-based color zones, walking speed with a reference line, and active versus basal calories.
  • ❤️ Cardiovascular_chart_hrv() and _chart_spo2(): heart rate variability with a minimum reference value, and oxygen saturation with critical, low, and normal zones.
  • 😴 Sleep_chart_sleep(): nightly sleep duration displayed with threshold-based color zones. If no sleep data is available, the chart shows an alternative message. Each chart is implemented independently, so it can be modified or replaced without affecting the rest of the pipeline.

6.6 Generating the Narrative with Gemini

The HealthSummaryGenerator class receives the summary created by HealthDataReader and uses Gemini to transform it into structured natural-language text. At this stage, the original Apple Health records are not sent to the model. Instead, Gemini receives the metrics that were already calculated and summarized in the previous step.
To build the prompt, the class uses three input files:

  • 📊 json_path: contains the patient’s compact summary, including the previously calculated metrics and statistics.
  • 🎯 yml_path: points to params_health.yml, which contains the thresholds used to compare each metric.
  • 📝 prompt_path: contains the prompt template and the instructions the model must follow. The load() method reads these files and initializes the Gemini client:
self.datos = utils.read_json_file(self.json_path)
self.yml = utils.read_yml_file(self.yml_path)
self.prompt = utils.read_txt_file(self.prompt_path)
self.client = genai.Client(api_key=self.api_key)

Enter fullscreen mode Exit fullscreen mode

Prompt Structure

The prompt template defines how the report should be generated. Instead of including the complete prompt in the article, its main instructions can be summarized as follows:

  • 🧭 Patient context: calculates the patient’s age from the date of birth and considers biological sex and the analysis period.
  • 📐 Threshold comparison: defines which value from params_health.yml should be used to evaluate each metric.
  • 📑 Report structure: requires fixed sections for patient profile, mobility, cardiovascular data, sleep, and overall assessment.
  • 🔎 Trends and continuity: asks the model to consider metric trends, weekly variability, and consecutive periods below the configured thresholds.
  • 🚫 Restrictions: prevents the model from inventing data, using unavailable fields, or making general judgments about the patient’s health. It also avoids subjective terms such as “healthy” or “concerning.” The model should only report whether each value is above, within, or below its corresponding threshold.

This last point is especially important, because the model should describe the available values and their relationship to the configured thresholds without making a diagnosis or turning the summary into medical advice.

Building and Running the Prompt

The class separates prompt preparation from the model call:

  • _build_prompt()replaces the {datos} and {yml} placeholders with the actual JSON data and threshold configuration.
  • generate() sends the completed prompt to Gemini and returns the generated text.
prompt = self._build_prompt()

response = self.client.models.generate_content(
    model=self.model_id,
    contents=prompt,
    config=types.GenerateContentConfig(
        max_output_tokens=self.max_tokens,
        thinking_config=types.ThinkingConfig(
            thinking_budget=0
        ),
    ),
)

Enter fullscreen mode Exit fullscreen mode

6.7 Generating the Final PDF Report

The HealthReportPDF class combines the results produced during the previous stages and creates the final PDF report using ReportLab.
The class receives four main inputs:

  • 📊 Metrics and KPIs: obtained directly from the metrics dictionary generated by HealthDataReader. The class does not recalculate the main statistics. Instead, it organizes them into KPI cards, tables, alerts, and short descriptions.
  • 📈 Charts: receives the image paths generated by HealthChartBuilder and adds each chart to the corresponding report section.
  • ✨ Gemini summary: receives the narrative generated by HealthSummaryGenerator and includes it as a separate section.
  • 🎯 Configuration: uses params_health.yml and params_styles.yml to apply the same thresholds and visual styles used across the rest of the pipeline.

This class does not calculate averages, trends, or weekly statistics. Those values are already produced by HealthDataReader. It only performs simple comparisons against the configured thresholds to decide whether a table should display a ✓ or ⚠ status and whether an alert should be added to the report.

Report Structure

The generated document is divided into four sections:

  • 🚶 ① Mobility: KPIs for steps, walking speed, steadiness, gait asymmetry, and activity, together with the related charts and reference tables.
  • ❤️ ② Cardiovascular: resting heart rate, HRV, SpO₂, VO₂ Max, and recovery metrics. This section is adapted when Apple Watch data is not available.
  • 😴 ③ Sleep: average sleep duration, nights below the minimum threshold, and nights that meet the configured goal.
  • 🤖 ④ AI-Generated Summary: the narrative generated by Gemini, converted from simple Markdown into formatted PDF content.

Alerts and Reference Status

Before building the report sections, the build() method checks the main metrics against their configured thresholds.

For example, it can generate an alert when:

  • the average number of steps is below the target;
  • walking speed is below the reference value;
  • HRV or SpO₂ is below the configured threshold;
  • average sleep duration does not meet the expected value. These alerts are based on simple comparisons and do not represent medical diagnoses.

AI Disclaimer

The AI-generated section always includes a visible disclaimer. It explains that the text was created from device data, is not a clinical evaluation or diagnosis, and may contain errors or incorrect interpretations.
The disclaimer also reminds the reader that the generated narrative should be checked against the original metrics and reviewed by a qualified professional before being used in any health-related decision.

7. Conclusions

One of the main challenges of this project was transforming Apple Health records into useful and understandable information. HealthKit’s consistent data structure makes this processing easier and supports the creation of a reusable pipeline. It also opens the door to interoperability: in a real environment, representing the results with standards such as HL7 FHIR could simplify their exchange with applications, hospitals, and electronic health record systems.

Separating Calculation from Interpretation

A relevant design decision was to keep the calculations in Python and use Gemini only to generate the narrative. Averages, trends, threshold comparisons, and weekly statistics are calculated in a controlled way, while the model receives already processed values and turns them into readable text.
Summarizing the data before sending it to the LLM also reduces token usage, execution cost, and the risk of reaching the context window limit. This approach provides more control over the information used to generate the report.

Personalization and Data Quality

The same metrics and thresholds are not suitable for every patient or every use case. Making these values configurable allows the analysis to be adapted to the patient profile, the monitoring objective, and the specific needs of the project.
However, configuration alone does not guarantee reliable results. The statistical methods should also be validated, and the pipeline should measure data completeness. For example, it should be able to distinguish between a real reduction in activity and missing records caused by low battery, synchronization problems, or irregular device use.
In a real implementation, metrics, thresholds, and validation rules should be reviewed together with healthcare professionals.

Security and Responsible Data Use

Health data requires specific controls for privacy, access, storage, and retention. A real solution should define what information is collected, who can access it, how long it is stored, and which data may be sent to external services.
Although these topics are outside the scope of this article, they should be considered from the beginning of the design process. Consent, data minimization, and retention policies should not be added only after the technical implementation is complete. This principle is also reflected in Apple Health, which requires explicit permission to read and write health information.

Final Note

This project is an educational MVP built with simulated data. It is not ready for production and should not be used directly to make health-related decisions.
Its main purpose is to demonstrate how continuous health data, deterministic processing, visualizations, and a language model can be combined in a modular pipeline. The LLM can help communicate the results, but the calculations, validation rules, and data-quality controls should remain reproducible and verifiable.

8. 📚 Reference

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다