DEV Community

Paul Crinigan
Paul Crinigan

Posted on

Three API Calls And A Model: Running Your Own Prediction Endpoint

If you have ever wired a classifier into an app, you know the model is the easy part and the plumbing around it is where the weekend goes. This is a walkthrough of a setup that keeps that plumbing small: a PHP front, a one file Python worker, and a JSON API you can call from anything.

A lot of everyday prediction work does not need a hosted AI service or a large language model at all. Routing a support ticket, scoring a lead or flagging a strange day in your metrics is a job for a small trained model, and a small trained model can run on the same box as the app that needs it. ML Prediction Engine is our free, MIT licensed take on that idea, and the rest of this post covers the three pieces you touch when you use it: getting it running, picking a model, and calling it.

Getting It Running

The engine is two parts that install together. A PHP app serves the admin area and the JSON API, and a single file Python worker runs the models. Storage is one SQLite file plus a data folder for datasets and trained models, so there is no database server to set up.

With Docker, you copy the sample config, set an API key and admin password, point mlServiceUrl at the worker container, and run docker compose up --build. Without Docker you start the worker yourself and serve the public folder with PHP's built in server. One config line, mlDriver, decides how the two halves talk: service runs the worker as a tiny HTTP service on localhost, and cli has PHP call Python once per request, which suits light traffic and means there is no daemon to babysit. The getting started guide walks through every setting on the way to a first trained model.

Picking A Model Is Mostly One Decision

The engine ships 18 model classes, which sounds like a lot of choice until you notice they sort into four answer shapes. If you want a label, you want a classifier. If you want a number, a regressor. If you want natural groups with no labels, a clusterer. If you want a normal or weird flag, an anomaly detector.

Inside each shape, start simple. For text classification that means Naive Bayes, moving to logistic regression or the neural network as rows pile up. For tabular classification, a random forest. For numbers, Ridge first and gradient boosting once you have a few hundred rows. For grouping, k means when you know how many groups you want and DBSCAN when you want the data to decide. For anomalies, Isolation Forest, or a robust z score when you need a rule you can explain in one sentence.

Starting simple is cheap here because the dataset is the source of truth. Every model's training rows live in a visible table, and switching a step to a different class keeps the rows and costs one retrain. The guide to choosing a model covers every class and its parameters in plain language.

The Three Calls You Actually Use

Everything the admin does, the API does too, and every endpoint is a POST with a JSON body and an X-API-Key header. Day to day, an integration comes down to three calls in a loop.

dataset/add appends a labeled row the moment a real event happens: a ticket gets solved, a deal closes, someone confirms a spam report. train rebuilds the model from the complete dataset and tells you how many rows it learned from. predict runs an input through a pipeline and hands back the answer.

curl -X POST http://localhost:8080/api.php/predict \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_KEY" \
  -d '{"pipelineID": 1, "input": "why was i charged twice"}'
Enter fullscreen mode Exit fullscreen mode

The response is about as small as it gets, something like {"output": "billing"}, with per step output included when a pipeline chains several models. Classifiers return a label, regressors a number, clusterers a group number, and anomaly detectors 1 or 0. There is also a pipelines call for discovery and a bulk dataset/set loader for first setups, all listed in the API reference.

The Takeaway

The useful mental model is that you are not deploying a model, you are deploying a dataset with a model attached. Keep the rows visible, start with the simplest class in the right shape, and let your app feed real outcomes back through dataset/add. Once that loop exists, turning a model into a better one is a data habit, not a project.

Top comments (0)