AWARE Narrator is a comprehensive Python toolkit that processes sensor data from mobile devices, performs DBSCAN clustering on location data, and generates detailed narrative descriptions of user mobility and activity patterns. The toolkit integrates multiple sensors including location, applications, keyboard input, screen usage, calls, messages, and more. It includes Google Maps API integration for reverse geocoding and uses a configuration file (config.yaml) to customize parameters.
If you plan to use Google Maps API for reverse geocoding (requires a valid API key in config.yaml), you may need to manually update the geocoding module due to recent changes in the Google Maps Services Python library:
- Check for updates on the GitHub repository: https://github.com/googlemaps/google-maps-services-python.git
- Find your local geocoding.py file path (typically in your mamba/conda environment)
- Example:
/home/ubuntu/miniforge3/envs/mv_env/lib/python3.13/site-packages/googlemaps/geocoding.py
- Example:
- Replace your local geocoding.py with the latest version from: https://github.com/googlemaps/google-maps-services-python/blob/master/googlemaps/geocoding.py
Alternative: A copy of the updated geocoding.py file has been included in this project for convenience. You can copy it directly to replace the installed package in your current environment:
# Make sure you're in the correct environment first
mamba activate my_env # or conda activate my_env
# Find your googlemaps package location in the current environment
python -c "import googlemaps; print(googlemaps.__file__)"
# Copy the included geocoding.py to replace the installed version
cp geocoding.py $(python -c "import googlemaps; import os; print(os.path.dirname(googlemaps.__file__))")/geocoding.pyThis manual update ensures compatibility with the address descriptor feature in geocoding.py
Note: This setup is only required if you plan to use Google Maps API for reverse geocoding. If you leave the GOOGLE_MAP_KEY empty in your config.yaml, the toolkit will work without this update.
This project supports Mamba and Conda for managing and installing dependencies. We recommend using Mamba for faster package resolution and installation.
-
Ensure you have Mamba installed.
-
Activate your Mamba environment (or create one if needed):
mamba create -n my_env python=3.13 mamba activate my_env
-
Create (or update) your environment from the file:
# Create a new environment with the name defined in the file: mamba env create --file environment.yml # Or create under a custom name: mamba env create -n <my_env> --file environment.yml # To update an existing environment to match environment.yml: mamba env update -n <my_env> --file environment.yml --prune
-
Activate your Conda environment (or create one if needed):
conda create -n my_env python=3.13 conda activate my_env
-
Create (or update) your environment from the file:
# Create a new environment with the name defined in the file: conda env create --file environment.yml # Or create under a custom name: conda env create -n <my_env> --file environment.yml # To update an existing environment to match environment.yml: conda env update -n <mv_env> --file environment.yml --prune
Note:
environment.ymlwas generated with:conda env export --from-history > environment.yml
The project includes several Python scripts:
aware_narrator.py- Main script that processes sensor data and generates narrativesextract_sessions.py- Extracts session boundaries from screen on/off eventsjson2jsonl.py- Utility to convert JSON files to JSONL formatsplit_description.py- Splits output narratives by sensor typemap_pid_deviceid.py- Generate the participant ID to device ID mapping filerun_screentext_preprocess_pipeline.py- Master pipeline for screentext data preprocessingsplit_by_participant.py- Split JSONL files by participant ID based on device mapping
The scripts require a YAML configuration file with the following structure:
# Configuration for Aware Narrator
# Two modes: manual or auto
# Manual mode: Uses P_IDs, START_TIME, and END_TIME for all participants
# Auto mode: Uses pid_timerange_file for participant-specific time ranges
MODE: "manual" # Options: "manual" or "auto"
# Manual mode configuration (used when MODE: "manual")
P_IDs:
- SS001
START_TIME: "2025-05-25 06:00:00"
END_TIME: "2025-06-04 23:59:00"
# Auto mode configuration (used when MODE: "auto")
# File containing participant-specific time ranges
pid_timerange_file: "resources/pid_timerange_60m.json"
# Replace by your own mapping csv.
# Must contain device_id and pid columns.
# Multiple device ids need to be splitted by ";"
# For example:
# Header: pid,device_id
# Row 1: 1234,aaaa-bbbb-cccc;1111-082a-4a73-8ee3
# Row 2: SS11,fa1da-3adrv-123a
pid_to_deviceid_map: "resources/pid_deviceid_mapping.csv" # generated by running map_pid_deviceid.py. See README for instructions.
timezone: "Australia/Melbourne" # replace by actual timezone
input_directory: "participant_data/{P_ID}"
session_data_file: "step1_data/{P_ID}/sessions.jsonl" # required for applicaion and keyboard analysis; generated by running extract_sessions.py with screen.jsonl for the corresponding P_ID
cleaned_screentext_file: "step1_data/{P_ID}/clean_input.jsonl" # required for screen text description; generated by using screen text preprocessing pipeline
reverse_geocoding_output_dir: "locations_query_results/{P_ID}"
output_file: "description/{P_ID}_output.txt"
daily_output_dir: "daily_description/{P_ID}"
sensor_integration_time_window: 60 # minutes
gate_time_window: 5 # minutes; required for wifi and bluetooth scan data integration.
sensors:
- "applications_foreground"
- "applications_notifications"
- "battery"
- "bluetooth"
- "calls"
- "installations"
- "keyboard"
- "messages"
- "screen"
- "screentext"
- "wifi"
- "sensor_wifi"
- "locations"
DISCARD_SYSTEM_UI: true # Applied to 'applications_foreground', 'applications_notifications', 'installations' based on system_ui_apps
GOOGLE_MAP_KEY: "" # Used for Google API Reverse geocoding
eps: 0.000047 # DBSCAN clustering parameter: radians (0.000047 radians × 6371000 m ≈ 300m)
min_samples: 3 # DBSCAN clustering parameter: mininum number of points to form a cluster
location_minimum_data_points: 3 # Minimum number of location data points to display a place in location description
location_minimum_stay_minutes: 3 # Minimum stay duration in minutes to display a place in location description
night_time_start: 22 # Start of nighttime in 24-hour format, used for determining home location
night_time_end: 6 # End of nighttime in 24-hour format, used for determining home location
merge_distance_threshold: 300 # Distance threshold in meters to merge home candidates and clusters with no night points
# Using package instead of app name in case of locales (different languages for the same app name)
blacklist_apps:
- com.aware.phone # AWARE-Light
system_ui_apps:
- com.android.systemui # System UI
- com.sec.android.app.launcher # One UI Home / One UI 首頁 / One UI 主屏幕 / TouchWiz home / Samsung Experience Home / Écran d'accueil One UI
- com.samsung.android.app.cocktailbarservice # Edge panels
- com.huawei.android.launcher # 华为桌面 / Huawei Home / Beranda Huawei
- com.miui.home # System launcher / Peluncur sistem / 系统桌面
- com.oppo.launcher # System Launcher / システムランチャー
- com.google.android.apps.nexuslauncher # Pixel Launcher / Peluncur Pixel / Lanceur d'applications Pixel
- com.motorola.launcher3 # Moto App Launcher
- net.oneplus.launcher # OnePlus Launcher
- jp.co.sharp.android.launcher3 # AQUOS Home
- com.android.launcher3 # Quickstep
- com.android.launcher # System Launcher
- com.vivo.hiboard # Jovi Home
- com.mi.android.globallauncher # POCO Launcher
- com.bbk.launcher2 # System launcher / 系统桌面
- com.sec.android.app.desktoplauncher # Samsung DeX home
- com.sec.android.emergencylauncher # Launcher
- com.hihonor.android.launcher # 荣耀桌面 / HONOR Home
- com.sonymobile.launcher # Xperia主屏幕 / Xperia Home
- com.google.android.inputmethod.latin # Gboard
pid_to_deviceid_map: CSV file mapping participant IDs to device IDsP_IDs: List of Participant IDs to processSTART_TIME/END_TIME: Time range for data processing (YYYY-MM-DD HH:MM:SS format)timezone: Timezone for timestamp conversion (e.g., "Australia/Melbourne")input_directory: Path to participant data folder (supports {P_ID} placeholder)session_data_file: Path to sessions.jsonl file for application and keyboard analysis
sensor_integration_time_window: Time window in minutes for sensor data integrationgate_time_window: Time window in minutes for WiFi and Bluetooth scan integrationsensors: List of sensors to include in analysis
output_file: Path for the main narrative output (supports {P_ID} placeholder)daily_output_dir: Directory for daily output files (supports {P_ID} placeholder)DISCARD_SYSTEM_UI: Whether to filter out system UI applications
GOOGLE_MAP_KEY: (Optional) API key for Google Maps reverse geocodingeps: DBSCAN epsilon parameter (distance threshold in radians, ~300m = 0.000047)min_samples: DBSCAN minimum samples to form a clusternight_time_start/night_time_end: Hours defining nighttime for home location identificationmerge_distance_threshold: Distance threshold in meters to merge home candidates and clusters with no night pointslocation_minimum_data_points: Minimum number of location data points required to display a place in location description (default: 3)location_minimum_stay_minutes: Minimum stay duration in minutes required to display a place in location description (default: 3)
Generate the participant ID to device ID mapping file required by the main analysis script:
python map_pid_deviceid.pyThis script processes a CSV file containing participant information and creates a mapping file used by aware_narrator.py.
Input Requirements:
- CSV file with at least 2 columns:
pid: Participant IDdevice_id: Device ID (multiple device IDs can be separated by ";")
Default behavior:
- Input file:
resources/participants.csv - Output file:
resources/pid_deviceid_mapping.csv
The output mapping file is referenced in config.yaml as pid_to_deviceid_map and is required for the main analysis script to function properly.
Split JSONL files from the exported data into participant-specific directories:
# Split all JSONL files for all participants
python split_by_participant.py
# Split specific JSONL files only
python split_by_participant.py --jsonl-files locations applications_foreground
# Process only specific participants
python split_by_participant.py --pids SS001 SS002 SS003
# Run threshold analysis mode to analyze data distribution
python split_by_participant.py --threshold-analysis
# Custom input/output directories
python split_by_participant.py --input-dir exported_jsonl --output-dir participant_dataThis script processes JSONL files from the exported_jsonl directory and splits them into the participant_data/{P_ID}/ structure required by the main analysis.
Features:
- Parallel processing for large datasets
- Threshold analysis mode for data quality assessment
- Unknown device reporting
- Participant filtering options
Process screentext data through the complete preprocessing pipeline:
# Process a single participant
python run_screentext_preprocess_pipeline.py --participant SS001
# Process all participants (Step 1 sequential, Steps 2-5 parallel)
python run_screentext_preprocess_pipeline.py --all
# Process specific participants only
python run_screentext_preprocess_pipeline.py --all --include SS001 SS002 SS003
# Process all participants except specific ones
python run_screentext_preprocess_pipeline.py --all --exclude SS001 SS002
# Custom timezone and worker threads
python run_screentext_preprocess_pipeline.py --all --timezone "Australia/Melbourne" --workers 8Pipeline Steps:
- Generate app package pairs (participant-specific)
- Clean screentext data
- Generate filtered system app transition files
- Add day IDs
- Calculate session metrics
Note: The screentext preprocessing pipeline includes session extraction functionality, so you do NOT need to run extract_sessions.py separately if you're using the screentext pipeline. The pipeline generates the required sessions.jsonl file as part of Step 5.
If you're not using the screentext preprocessing pipeline, you can extract session boundaries separately:
# Process a single participant
python extract_sessions.py --participant SS001
# Process all participants in the input directory
python extract_sessions.py --all
# Custom session threshold (default: 45000ms = 45 seconds)
python extract_sessions.py --participant SS001 --threshold 45000
# Custom input/output directories
python extract_sessions.py --participant SS001 --input-dir custom_data --output-dir custom_outputImportant: Only run this script if you're NOT using the screentext preprocessing pipeline, as the pipeline already includes session extraction.
Convert JSON files to JSONL format:
# Convert all JSON files in a folder
python json2jsonl.py /path/to/json/folder
# Specify output folder
python json2jsonl.py /path/to/json/folder -o /path/to/output/folder
# Search recursively in subdirectories
python json2jsonl.py /path/to/json/folder -r -o /path/to/output/folderpython aware_narrator.pyThis processes all sensor data according to the configuration and generates comprehensive narratives.
Split output narratives by sensor type:
python split_description.pyThis creates separate files for each sensor type in the description_split/{PID}/ folder.
The project expects the following directory structure:
exported_jsonl/ # Raw exported JSONL files (for split_by_participant.py)
├── applications_foreground.jsonl
├── applications_notifications.jsonl
├── battery.jsonl
├── bluetooth.jsonl
├── calls.jsonl
├── installations.jsonl
├── keyboard.jsonl
├── locations.jsonl
├── messages.jsonl
├── screen.jsonl
├── screentext.jsonl # Required for screentext analysis
├── wifi.jsonl
└── sensor_wifi.jsonl
participant_data/ # After running split_by_participant.py
├── {P_ID}/
│ ├── applications_foreground.jsonl
│ ├── applications_notifications.jsonl
│ ├── battery.jsonl
│ ├── bluetooth.jsonl
│ ├── calls.jsonl
│ ├── installations.jsonl
│ ├── keyboard.jsonl
│ ├── locations.jsonl
│ ├── messages.jsonl
│ ├── screen.jsonl
│ ├── screentext.jsonl # Required for screentext analysis
│ ├── wifi.jsonl
│ └── sensor_wifi.jsonl
step1_data/ # After running screentext pipeline or extract_sessions.py
├── {P_ID}/
│ ├── sessions.jsonl # Generated by screentext pipeline or extract_sessions.py
│ └── clean_input.jsonl # Generated by screentext pipeline
resources/
├── pid_deviceid_mapping.csv # Generated by map_pid_deviceid.py
└── app_package_pairs.jsonl # Generated by screentext pipeline
The toolkit generates several types of output:
- Main narrative file: Comprehensive narrative saved to
output_filepath - Daily narratives: Separate daily files in
daily_output_dir - Session data: Screen usage sessions in
step1_data/{P_ID}/sessions.jsonl - Split narratives: Sensor-specific files in
description_split/{P_ID}/ - Reverse geocoding: Location data with address information (if Google Maps API is enabled)
- Clustering analysis: Location clusters with home detection
The toolkit analyzes the following sensor types:
- Location: GPS and network-based location with DBSCAN clustering
- Applications: Foreground app usage with session correlation
- Keyboard: Typing patterns and text input analysis with improved human-readable descriptions
- Screen: Screen on/off events and usage sessions
- Screentext: Text content displayed on screen during app usage
- Battery: Battery level and charging status
- Calls: Phone call events and durations
- Messages: SMS and messaging activity
- WiFi/Bluetooth: Network scanning and connectivity
- Notifications: Application notification events with proper text display handling
- JSONDecodeError: Ensure
config.yamlis properly formatted YAML (no JSON-style comments) - ModuleNotFoundError: Install dependencies using
mamba env create --file environment.ymlorconda env create --file environment.yml - Google Maps API errors: Ensure a valid API key is provided in
GOOGLE_MAP_KEY(or leave empty if not using Google Maps API) - File not found errors: Check that participant data follows the expected directory structure
- Session data missing: Run
extract_sessions.pyfirst to generate session boundaries - Empty sensor files: Verify JSONL files contain valid JSON objects, one per line
- Geocoding issues: If you encounter geocoding errors and are using Google Maps API, follow the manual setup instructions above to update the geocoding.py file
This project is for research purposes. Contact the developers for usage permissions.
For questions, reach out to the maintainers of the AWARE Narrator project.