Callbacks enable the retrieval of a model’s status when it transitions to either ‘complete’ or ‘error’. This is accomplished by sending a POST request to the specified URL, with the payload structured as follows:

{
    "name": "my_model",
    "version": 1,
    "active": true,
    "predictor_id": 123,
    "project_name": "mindsdb",
    "predictor_created_at": "Fri, 09 Sep 2023 11:50:27 GMT",
    "old_status": "training",
    "new_status": "complete",
    "changed_at": "Fri, 09 Sep 2023 11:59:00 GMT"
}

Let’s break down each key:

  • name: name of the model
  • version: version of the trained model
  • active: indicates whether the newly trained model is active
  • predictor_id: unique identifier for the trained model
  • project_name: the name of the project in which the model was created
  • predictor_created_at: time at which the model was created
  • old_status: status the model had prior to receiving the new_status
  • new_status: current status of the model
  • changed_at: time when the model’s status transitioned from old_status to new_status

Please note that this feature works only in MinsdDB Cloud and only for MindsDB Starter users.

Callbacks API

Callback API provides information on how to add, get, edit, and delete callbacks.

Add a Callback

This is the Request format:

POST /cloud/callback/model_status
Content-Type: application/json
{
  // url will be called on model status change
  "url": "https://my.endpoint.com/",
  "filter": {
    "model_name": ".*",
    "project_name": ".*"
  },
  "attempt": {
    "count": 5,
    "http_timeout": 10,
    "interval": 10
  }
}

And this is the Response format:

Status: 200 OK  
Content-Type: application/json
{
  // id of created 'callback'
  "id": 123456
}

Only the url key is required in the Request. All others are optional.

  • url - this represents the address that will be utilized to send a POST request, containing detailed information about the model’s status
  • filter - this is used to restrict the triggering of callbacks:
    • model_name - python-style regular expression used to filter the names of models that trigger a callback
    • project_name - python-style regular expression used to filter the names of projects
  • attempt - this outlines the configuration of the number and frequency of attempts to send callbacks
    • count - maximum number of attempts
    • interval - represents the interval between failed attempts
    • http_timeout - time allotted to wait for a successful response.

Get a Callback

This is the Request format:

GET /cloud/callback/model_status

And this is the Response format:

Status: 200 OK  
Content-Type: application/json
[{
  "id": 123456,
  "created_at": "Fri, 09 Sep 2023 11:50:27 GMT",
  "url": "https://my.endpoint.com/"
}]

Edit a Callback

This is the Request format:

PUT /cloud/callback/model_status/<id>
Content-Type: application/json
{
  // new callback url
  "url": "https://my.endpoint.com/"
}

And this is the Response format:

Status: 200 OK

Delete a Callback

This is the Request format:

DELETE /cloud/callback/model_status/<id>

And this is the Response format:

Status: 200 OK

Handling Callbacks using Python SDK

Below is an example of using callbacks with the home_rentals model. Be sure that your endpoint HOSTNAME is accessible from the internet.

Please note that localhost is not accessible from the internet - you can make localhost accessible via multiple ways, like ngrok tunnel.

import requests
import mindsdb_sdk
from flask import Flask, request

MODEL_NAME = 'home_rentals'
HOSTNAME = 'my.endpoint.com'
PORT = 5000

app = Flask(__name__)

con = mindsdb_sdk.connect(
    'https://cloud.mindsdb.com',
    login='name@email.com',
    password='password'
)

# add callback
con.api.session.post(
    'https://cloud.mindsdb.com/cloud/callback/model_status',
    json={
        'url': f'https://{HOSTNAME}:{PORT}/'
    }
)

@app.route('/', methods=['POST'])
def callback():
    data = request.json
    if data['version'] == 1:
        # let retrain the model
        model = con.models.get(MODEL_NAME)
        model.retrain()
    elif data['version'] == 2:
        # let make a prediciton
        model = con.models.get(MODEL_NAME)
        prediction = model.predict({"sqft": 1000})
        print(prediction)
    return '', 200

# connect to database
db = con.databases.create(
    'example_db',
    engine='postgres',
    connection_args={
        "user": "demo_user",
        "password": "demo_password",
        "host": "samples.mindsdb.com",
        "port": "5432",
        "database": "demo"
    }
)

# train base model
model = con.models.create(
    MODEL_NAME,
    predict='rental_price',
    query=db.tables.get('demo_data.home_rentals')
)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=PORT)

Handling Callbacks using JavaScript SDK

Below is an example of using callbacks with the home_rentals model. Be sure that the callback HOSTNAME is accessible from MindsDB Cloud.

import express from 'express';
import axios from 'axios';
import * as MindsDB from 'mindsdb-js-sdk';
const mdb = MindsDB.default.default;

const app = express();
const PORT = 54321;
const MODEL_NAME = 'home_rentals';
const HOSTNAME = 'my.endpoint.com';

// Create an Axios instance with interceptors for timeout and error handling
const customAxios = axios.create();
customAxios.interceptors.request.use(config => {
  config.timeout = 120000; // Set a request timeout of 120 seconds
  return config;
});
customAxios.interceptors.response.use(
  response => response,
  error => {
    console.error('Axios Error:', error.message);
    return Promise.reject(error);
  }
);

// Connect to MindsDB Cloud
try {
  await mdb.connect({
    host: 'https://cloud.mindsdb.com',
    user: 'name@email.com',
    password: 'password',
    httpClient: customAxios,
  });
} catch (error) {
  console.error('MindsDB Cloud Connection Error:', error);
  process.exit(1);
}

// Connect to the database
await mdb.Databases.createDatabase('example_db', 'postgres', {
  user: 'demo_user',
  password: 'demo_password',
  host: 'samples.mindsdb.com',
  port: '5432',
  database: 'demo',
});

// Express Middleware to parse JSON requests
app.use(express.json());

// Define an Express route to handle model status updates
app.post('/model-status', async (req, res) => {
  const data = req.body;

  if (data.new_status !== 'complete') {
    console.error(`Error! Got model status: ${data.new_status}`);
    return res.status(400).send({ error: 'Invalid model status' });
  }

  const trained_model_version = data.version;
  console.log(`Model training completed, model version=${trained_model_version}`);

  if (trained_model_version === 1) {
    // Base model finished training, let's retrain it
    let model = await mdb.Models.getModel(MODEL_NAME, 'mindsdb');
    model.retrain();
  } else if (trained_model_version === 2) {
    // Model retraining finished, let's make a prediction
    let model = await mdb.Models.getModel(MODEL_NAME, 'mindsdb');
    let prediction = await model.query({
      where: [
        'sqft = 823',
        'location = "good"',
        'neighborhood = "downtown"',
        'days_on_market = 10',
      ],
    });
    console.log(`Prediction: ${JSON.stringify(prediction)}`);
  }

  res.sendStatus(200);
});

// Start the Express server
app.listen(PORT, () => {
  console.log(`Express server started on port ${PORT}`);
});

// Add a callback to notify MindsDB Cloud about the endpoint
try {
  await customAxios.post('https://cloud.mindsdb.com/cloud/callback/model_status', {
    url: `https://${HOSTNAME}:${PORT}/model-status`,
  });
} catch (error) {
  console.error('Callback Error:', error);
}

// Train a model
try {
  await mdb.Models.trainModel(MODEL_NAME, 'rental_price', 'mindsdb', {
    integration: 'example_db',
    select: 'SELECT * FROM demo_data.home_rentals',
  });
} catch (error) {
  console.error('Model Training Error:', error);
}