pEyeON-Analytics is a local analytics stack for EyeOn output.
It combines:
dltto load EyeOn JSON into DuckDBdbtto build analysis-friendly modelsStreamlitto explore batches, metadata, schema changes, and certificate data
The upstream EyeOn scanner lives separately in pEyeON.
EyeOn emits one JSON observation per scanned file. This repository turns those JSON files into queryable tables with a simple local workflow:
- Generate a batch of EyeOn JSON
- Launch the Streamlit app
- Select one or more batches and click
Load Selected - Explore the loaded data
The pipeline is organized into three layers:
bronze: raw JSON retained for traceabilitysilver: normalized observation and metadata tables loaded from EyeOn JSONgold: dbt models for reporting and exploration
- Python 3.13
uv- Install UV- Docker or Podman
- a directory of files to scan with EyeOn
uv syncCopy the sample config and update the dataset location.
cp EyeOnData.toml-template EyeOnData.tomlAt minimum, set datasets.dataset_path in EyeOnData.toml to the directory where EyeOn batch folders should be written.
Example:
[datasets]
dataset_path = "/path/to/eyeon/batches"
[db]
db_file = "eyeon.duckdb"
db_path = "database"Use the wrapper script to run eyeon parse in a container:
./eyeon-parse.sh --util-cd UTIL_CD --dir /path/to/files --threads 8The script writes a timestamped batch directory under datasets.dataset_path.
You can also use positional arguments:
./eyeon-parse.sh UTIL_CD /path/to/files 8For more options:
./eyeon-parse.sh --helpOptional: print a quick summary of the newest batch:
./eyeon-batch-summary.shuv run streamlit run EyeOnData.pyThe preferred workflow is to use the Streamlit app to run the load pipeline.
From the app:
- choose the dataset root / database location if prompted
- select one or more EyeOn batch directories
- click
Load Selectedto run the load workflow
This path handles the DLT load and the dbt modeling steps for normal usage.
The direct CLI commands below are still useful for development, troubleshooting, or incremental reruns.
Run the loader against a specific batch directory:
uv run python load_eyeon.py --utility_id UTIL_CD --source /path/to/batch --log-level INFOUseful log levels:
INFOfor normal runsDEBUGfor more verbose troubleshooting
uv run dbt build --project-dir dbt_eyeon_gold --profiles-dir dbt_eyeon_goldload_eyeon.py: loads EyeOn JSON into DuckDB viadlteyeon-parse.sh: container wrapper aroundeyeon parseeyeon-batch-summary.sh: quick batch inspection helperdbt_eyeon_gold/: dbt project for modeled analytics tablespages/: Streamlit pagesutils/: shared app and schema utilitiesschemas/: generated DLT schema plus bootstrap SQLextras/: notebooks and scratch utilities for ad hoc exploration
flowchart TD
%% Node Definitions
A["EyeOn JSON batch"] --> B[load_eyeon.py]
B --> C
B --> D
D --> E[dbt_eyeon_gold]
E --> F
F --> G["Streamlit pages"]
%% Labels with Schema naming
C("fa:fa-database bronze.raw_json")
D("fa:fa-layer-group silver.raw_obs & metadata")
F("fa:fa-coins gold.*")
%% Style Classes
classDef bronze fill:#cd7f32,stroke:#333,stroke-width:2px,color:#fff
classDef silver fill:#c0c0c0,stroke:#333,stroke-width:2px,color:#000
classDef gold fill:#ffd700,stroke:#333,stroke-width:2px,color:#000
classDef tool fill:#f9f9f9,stroke:#333,stroke-dasharray: 5 5
%% Applying Classes
class C bronze
class D silver
class F gold
class B,E,G tool
schemas/eyeon_metadata.schema.yamlis generated as part of the DLT workflow and is intentionally checked in.EyeOnData.tomlis local configuration and should not be committed.test.shis a simple local smoke-test script and assumes local sample data paths exist.
Run linting and formatting with Ruff:
uv run ruff check .
uv run ruff format .