BptkServer

BPTK API Documentation for the BptkServer class

BptkServer

The REST API server is essentially a wrapper around the regular bptkclass. The server is implemented using Flask and provides all the REST Endpoints / Routes that you need to interact with a simulation scenario.

Overview

The BptkServer class provides a REST-API using the Flask framework.

It is essentially a wrapper around the bptk class that forwards REST API calls to bptk.

You will typically start the framework by instantiating the bptk class within a Jupyer notebook, as follows:

from BPTK_Py.server import BptkServer
from flask_cors import CORS

from model import bptk # assuming your model is in a file called model.py that sets up bptk

# Calling the BptkServer class
application = BptkServer(__name__, bptk)
CORS(application)

if __name__ == "__main__":
   application.run()

Assuming you save that code in a file called application.py, you can then start the server fro the command line as follows:

export FLASK_ENV=development

BptkServer Constructor

BptkServer(import_name, bptk_factory=None, external_state_adapter=None, bearer_token=None)

This class provides a Flask-based server that provides a REST-API for running bptk scenarios. The class inherts the properties and methods of Flask and doesn’t expose any further public methods.

agents

POST /agents

For an agent-based or hybrid model, this endpoint returns all the agents in the model with their corresponding states and properties.

begin-session

POST /{instance_uuid}/begin-session

This endpoint starts a session for single step simulation. There can only be one session per instance at a time.

end-ession

POST /{instance_uuid}/end-session

This endpoint ends a session for single step simulation and resets the internal cache.

equations

POST /equations

This endpoint returns all available equations given the name of a scenario manager and of a scenario.

flat-session-results

GET /{instance_uuid}/flat-session-results

Returns the accumulated results of a session, from the first step to the last step that was run in a flat format.

full-metrics

GET /full-metrics

Returns metrics in JSON format. This endpoint is unprotected.

The following metrics are returned: - Instance count - Creation time und current timestep of each instance

healthy

GET /healthy

Unprotected endpoint useful for health checks, e.g. when running as a Kubernetes pod. It simply returns a HTTP 200 response and doesn’t interact with the bptk factory.

keep-alive

POST /{instance_uuid}/keep-alive This endpoint sets the “last accessed time” of the instance to the current time to prevent the instance from timeing out.

Arguments: None

load-state

GET /load-state

Loads all instances using the external state adapter

root

GET /

The root endpoint returns a simple html page that can be used for test purposes. The root endpoint is unprotected even if bearer token authorization is turned on.

run-step

POST /{instance_uuid}/run-step

This endpoint advances the relevant scenarios by one timestep and returns the data for that timestep.

Arguments:

instance_uuid: string

    The id of the instance to advance.

run-steps

POST /{instance_uuid}/run-steps

This endpoint advances the relevant scenarios by one timestep and returns the data for that timestep.

Arguments:

instance_uuid: string

    The id of the instance to advance.

session-results

GET /{instance_uuid}/session-results

Returns the accumulated results of a session, from the first step to the last step that was run.

metrics

GET /metrics

Returns metrics in a Prometheus compatible format. This endpoint is unprotected.

run

POST /run

Given a JSON dictionary that defines the relevant simulation scenarios and equations, this endpoint runs those scenarios and returns the data generated by the simulations.

save-state

GET /save-state

Save all instances with the provided external state adapter.

scenarios

GET /scenarios

The endpoint returns all available scenarios for the current simulation. ## start-instance

POST /start-instance

This endpoint starts a new instance of BPTK on the server side, so that simulations can run in a “private” session. The endpoint returns an instance_id, which is needed to identify the instance in later calls.

  • Arguments:

    • timeout (dict,optional). The timeout period after which the instance is delete if it is not accessed in the meantime. The timer is reset every time the instance is accessed. The timeout dictionary can have the following keys: weeks, days, hours, minutes, seconds, milliseconds, microseconds. Values must be integers.

stream-steps

POST /{instance_uuid}/stream-steps

This endpoint is used to stream a simulation. This is useful for long-running simulations, the result of each simulation step is streamed accross the API:

Arguments:

instance_uuid: string

The id of the instance to stream.

Usage

The following illustrates how to use the BPTK REST API. To get started you first need to start the server for the customer acquisition model from a Terminal console by running the run_server.sh script in this directory. The server should then be running on port 5000.

# find documentation for the requests library on https://docs.python-requests.org/
import requests
import json

List scenarios

Get a list of scenarios that the server knows about:

response = requests.get("http://localhost:5000/scenarios")
response
<Response [200]>
response.json()
{'sddsl_customer_acquisition': ['base',
  'low_word_of_mouth',
  'high_word_of_mouth',
  'interactive_scenario']}

List equations

Get the equations known to the dashboard scenario:

response = requests.post(
    url="http://localhost:5000/equations",
    json = {
    "scenarioManager": "sddsl_customer_acquisition",
    "scenario":"interactive_scenario"
}
)

Check the response

response
<Response [200]>

Read the response content

response.json()
{'constants': ['word_of_mouth_success',
  'target_market',
  'advertising_success',
  'contact_rate',
  'consumers_reached_per_ruro',
  'advertising_budget',
  'initial_customers'],
 'converters': ['consumers_reached_through_word_of_mouth',
  'acquisition_through_word_of_mouth',
  'consumers_reached_through_advertising',
  'market_saturation',
  'acquisition_through_advertising'],
 'flows': ['customer_acquisition'],
 'points': [],
 'stocks': ['potential_customers', 'customers']}

Run some scenarios

Get some data for a scenario and some equations:

response = requests.post(
    url="http://localhost:5000/run",
    json = {
    "scenario_managers": [
        "sddsl_customer_acquisition"
    ],
    "scenarios": [
        "base",
        'low_word_of_mouth',
        'high_word_of_mouth',
        "interactive_scenario"
        
    ],
    "equations": [
        "customers",
        "customer_acquisition",
        "market_saturation"
    ],
    "settings":{
        "sddsl_customer_acquisition":{
            "interactive_scenario":
            {
                "constants":{
                    "word_of_mouth_success":0.5
                }
            }
            
        }
    }
}
)
response
<Response [200]>
response.json()['sddsl_customer_acquisition']['base']['equations']['market_saturation']
{'1.0': 0.0,
 '2.0': 0.016666666666666666,
 '3.0': 0.034694444444444444,
 '4.0': 0.05413194436728395,
 '5.0': 0.07501657965779268,
 '6.0': 0.09737187924025335,
 '7.0': 0.1212047408902633,
 '8.0': 0.14650274370969096,
 '9.0': 0.17323166696071848,
 '10.0': 0.20133338483031274,
 '11.0': 0.23072432038144908,
 '12.0': 0.26129464254502166,
 '13.0': 0.29290837373483375,
 '14.0': 0.32540454000567137,
 '15.0': 0.35859944020718043,
 '16.0': 0.39229003770608845,
 '17.0': 0.42625839347991806,
 '18.0': 0.46027697113536986,
 '19.0': 0.49411456304756235,
 '20.0': 0.5275425231599575,
 '21.0': 0.5603409553824232,
 '22.0': 0.5923045030364031,
 '23.0': 0.6232474158577167,
 '24.0': 0.653007633041861,
 '25.0': 0.6814497055809227,
 '26.0': 0.7084664775890336,
 '27.0': 0.7339795424013784,
 '28.0': 0.757938574068453,
 '29.0': 0.7803197003680654,
 '30.0': 0.80112312525382,
 '31.0': 0.8203702261766603,
 '32.0': 0.8381003475583342,
 '33.0': 0.8543674905971219,
 '34.0': 0.8692370672479597,
 '35.0': 0.8827828482775062,
 '36.0': 0.8950841965793371,
 '37.0': 0.9062236410643408,
 '38.0': 0.9162848157239781,
 '39.0': 0.9253507640150104,
 '40.0': 0.9335025907032782,
 '41.0': 0.9408184312435781,
 '42.0': 0.947372701790447,
 '43.0': 0.9532355899965443,
 '44.0': 0.9584727468259837,
 '45.0': 0.9631451417540011,
 '46.0': 0.967309047158401,
 '47.0': 0.9710161218168184,
 '48.0': 0.9743135677520691,
 '49.0': 0.9772443389008316,
 '50.0': 0.979847384017862,
 '51.0': 0.9821579097560191,
 '52.0': 0.9842076529327227,
 '53.0': 0.9860251536013157,
 '54.0': 0.9876360227146422,
 '55.0': 0.9890631999378361,
 '56.0': 0.9903271985855285,
 '57.0': 0.9914463357751633,
 '58.0': 0.9924369467508938,
 '59.0': 0.9933135829858447,
 '60.0': 0.9940891941535807}
response = requests.post(
    url="http://localhost:5000/start-instance"
)
response
<Response [200]>
instance_uuid=response.json()["instance_uuid"]
instance_uuid
'3c796b4200f911ec8108acde48001122'
response = requests.post(
    url=f"http://localhost:5000/{instance_uuid}/begin-session",
    json = {
    "scenario_managers": ["sddsl_customer_acquisition"],
    "scenarios":["interactive_scenario"],
    "equations":["customers","word_of_mouth_success"]
}
)
response
<Response [200]>
response.json()
{'msg': 'session started'}
response = requests.post(
    url=f"http://localhost:5000/{instance_uuid}/run-step"
)
response
<Response [200]>
response.json()
{'sddsl_customer_acquisition': {'interactive_scenario': {'customers': {'3.0': 2081.6666666666665},
   'word_of_mouth_success': {'3.0': 0.01}}}}
response = requests.post(
    url=f"http://localhost:5000/{instance_uuid}/run-step",
    json = {
    "settings": {
        "sddsl_customer_acquisition":
        {
            "interactive_scenario":{
                "constants":{
                 "word_of_mouth_success":0.7
                }
            }
        }
    }
}
)
response.json()
{'sddsl_customer_acquisition': {'interactive_scenario': {'customers': {'4.0': 3247.916662037037},
   'word_of_mouth_success': {'4.0': 0.7}}}}

You can start as many instances as you like - typically one for every user that starts an interactive session via a front-end. Let’s sart another session to illustrate this.

response = requests.post(
    url="http://localhost:5000/start-instance"
)
another_instance_uuid=response.json()["instance_uuid"]
another_instance_uuid
'ba6e9e5000f911ec8108acde48001122'
response = requests.post(
    url=f"http://localhost:5000/{another_instance_uuid}/begin-session",
    json = {
    "scenario_managers": ["sddsl_customer_acquisition"],
    "scenarios":["interactive_scenario"],
    "equations":["customers","word_of_mouth_success"]
}
)
response = requests.post(
    url=f"http://localhost:5000/{another_instance_uuid}/run-step",
    json = {
        "settings": {
            "sddsl_customer_acquisition":
            {
                "interactive_scenario":{
                    "constants":{
                     "word_of_mouth_success":0.1
                    }
                }
            }
        }
    }
)
response.json()
{'sddsl_customer_acquisition': {'interactive_scenario': {'customers': {'1.0': 0.0},
   'word_of_mouth_success': {'1.0': 0.1}}}}
response = requests.post(
    url=f"http://localhost:5000/{instance_uuid}/run-step",
    json = {
        "settings": {
            "sddsl_customer_acquisition":
            {
                "interactive_scenario":{
                    "constants":{
                     "word_of_mouth_success":0.07
                    }
                }
            }
        }
    }
)
response.json()
{'sddsl_customer_acquisition': {'interactive_scenario': {'customers': {'5.0': 25698.489043516267},
   'word_of_mouth_success': {'5.0': 0.07}}}}