Machine learning lands in your apps: four directives, zero servers

· Cosimo Luigi Manes

A Reactive app already knew how to collect data, show it in tables, charts and maps, and let an AI answer questions about it. As of today it can also do machine learning on it — without writing code, without servers, without a single byte of data leaving the device.

Four directives, one principle

The new ml-* family brings scikit-learn into the browser (via Pyodide, the same engine as the Python blocks). Like everything in Reactive, it’s a line of Markdown:

::range[k]{min="2" max="8" value="4" legend="Numero di gruppi"}

::ml-cluster{data="comuni" features="reddito,eta,stranieri" k="#k" into="gruppi"}

::map{path="gruppi" geojson="geojson" fill="cluster"}
**{comune}** — gruppo {cluster}
::/map

Move the slider: the clustering recomputes and the map recolors. The results land in a normal collection (into=), so they work with any view — tables, charts, aggregations, even an AI summary.

The principle that governs them: the executed code is a fixed template — data and parameters never enter the code, the AI generates nothing at runtime, the same input always gives the same result. The very first run downloads scikit-learn (~60 MB, then cached) behind a click; from then on everything is automatic and reactive. And the computations stay on your device.

To try them out there’s a ready-made app in the catalog: Municipalities lab — pick a region, group its municipalities by income, age and foreign residents, find the ones that stand out, discover which indicators run together.

A warehouse that grows to 15 fact tables

The open data service has grown quite a bit. Alongside fuel prices, ANAC tenders, population and the PA registry it has gained:

A warehouse that describes itself

Underneath there’s a less visible but deeper novelty: a semantic layer. Three metadata tables — the conceptual keys (with the URIs of the OntoPiA ontologies), the formal relationships between the tables, and the annotated columns — queryable like everything else. The distinctive part: every declared relationship is verified against the real data on every update, and the join’s coverage percentage lands in the table itself. “How do X and Y join?” is a SELECT.

You can touch all of this on the Open data page, rebuilt as a live explorer: the choropleth map of Italy (population, density, average income — click a region to drill down to its municipalities), the navigable graph of relationships between the tables, the catalog with previews and, for those who want to get their hands dirty, a read-only SQL playground.

As always: apps are Markdown, your data stays yours, and everything you’ve read here also works offline after the first load.