ebuzz168
ebuzz168

Reputation: 1194

Build API using FastAPI for Classification Model produced using pycaret

I'm using pycaret as my ML workflow, I tried to create an API using FastAPI. This is my first time playing into production level, so I'm bit confused about API

I have 10 features; age: float, live_province: str, live_city: str, live_area_big: str, live_area_small: str, sex: float, marital: float, bank: str, salary: float, amount: float and a label which it contains the binary value (0 and 1).

This is what my script for building the API

from pydantic import BaseModel
import numpy as np
from pycaret.classification import *

import uvicorn
from fastapi import FastAPI

app = FastAPI()

model = load_model('catboost_cm_creditable')

class Data(BaseModel):
    age: float
    live_province: str
    live_city: str
    live_area_big: str
    live_area_small: str
    sex: float
    marital: float
    bank: str
    salary: float
    amount: float

input_dict = Data

@app.post("/predict")
def predict(model, input_dict):
    predictions_df = predict_model(estimator=model, data=input_dict)
    predictions = predictions_df['Score'][0]
    return predictions

When I tried to run uvicorn script:app and went to the documentation I can't find the parameter for my features, the parameters only show model and input_dict enter image description here

How to take my Features onto Parameters in the API?

Upvotes: 4

Views: 966

Answers (2)

Yagiz Degirmenci
Yagiz Degirmenci

Reputation: 20766

You need to Type-hint your Pydantic model to make it work with your FastAPI

Imagine like you are really working with Standard Python, when you need to documentate that function,

def some_function(price: int) ->int:
    return price

With Pydantic there is nothing different than the example above

Your class Data is actually a python @dataclass with super-powers(comes from Pydantic)

from fastapi import Depends

class Data(BaseModel):
    age: float
    live_province: str
    live_city: str
    live_area_big: str
    live_area_small: str
    sex: float
    marital: float
    bank: str
    salary: float
    amount: float


@app.post("/predict")
def predict(data: Data = Depends()):
    predictions_df = predict_model(estimator=model, data=data)
    predictions = predictions_df["Score"][0]
    return predictions

There is a one little trick, with Depends, you 'll get a single queries like when you are defining each field seperately.

With Depends

enter image description here

Without Depends

enter image description here

Upvotes: 3

Or Y
Or Y

Reputation: 2118

Your problem is with the definition of the API's function. You added an argument for you data input but you didn't tell FastAPI it's type. Also I assume that you mean't to use the model that you've loaded globally instead of received it as a parameter. Also you don't need to create a global instance for your input data, as you want to get it from the user.

Therefore, simply change the signature of your function to:

def predict(input_dict: Data):

and remove the line:

input_dict = Data

(Which just creates an Alias to your class Data, named input_dict)

You'll end up with:

app = FastAPI()

model = load_model('catboost_cm_creditable')

class Data(BaseModel):
    age: float
    live_province: str
    live_city: str
    live_area_big: str
    live_area_small: str
    sex: float
    marital: float
    bank: str
    salary: float
    amount: float

@app.post("/predict")
def predict(input_dict: Data):
    predictions_df = predict_model(estimator=model, data=input_dict)
    predictions = predictions_df['Score'][0]
    return predictions

Also, I would recommend changing the name of the class Data to something more clear and easier to understand, even DataUnit would be better in my opinion as Data is too general.

Upvotes: 1

Related Questions