eaedk's picture
previous root commented
81b6b88
raw
history blame
4.82 kB
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
import uvicorn
from typing import List, Literal, Optional
from pydantic import BaseModel
import pandas as pd
import pickle
import os
import json
import logging
# logger
logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.DEBUG)
# Util Functions & Classes
def loading(fp):
with open(fp, "rb") as f:
data = pickle.load(f)
print(f"INFO: Loaded data : {data}")
return data
def predict(df, endpoint="simple"):
"""Take a dataframe as input and use it to make predictions"""
print(
f"[Info] 'predict' function has been called through the endpoint '{endpoint}'.\n"
)
logging.info(f" \n{df.to_markdown()}")
# scaling
scaled_df = scaler.transform(df)
logging.info(f" Scaler output is of type {type(scaled_df)}")
# prediction
prediction = model.predict_proba(scaled_df)
print(f"INFO: Prediction output: {prediction}")
# Formatting of the prediction
## extract highest proba
highest_proba = prediction.max(axis=1)
print(f"INFO: Highest probabilities : {highest_proba}")
## extract indexes of the highest proba
highest_proba_idx = prediction.argmax(axis=1)
print(f"INFO: Highest probability indexes : {highest_proba_idx}")
## Maching prediction with classes
predicted_classes = [labels[i] for i in highest_proba_idx]
print(f"INFO: Predicted classes : {predicted_classes}")
# prediction[:, highest_proba_idx]
# save in df
df["predicted proba"] = highest_proba
df["predicted label"] = predicted_classes
print(f"INFO: dataframe filled with prediction\n{df.to_markdown()}\n")
# parsing prediction
# parsed = json.loads(df.to_json(orient="index")) # or
parsed = df.to_dict("records")
return parsed
## INPUT MODELING
class Land(BaseModel):
"""Modeling of one input data in a type-restricted dictionary-like format
column_name : variable type # strictly respect the name in the dataframe header.
eg.:
=========
customer_age : int
gender : Literal['male', 'female', 'other']
"""
N: float
P: float
K: float
temperature: float
humidity: float
ph: float
rainfall: float
class Lands(BaseModel):
inputs: List[Land]
def return_list_of_dict(
cls,
):
# return [land.dict() for land in cls.inputs]
return [i.dict() for i in cls.inputs]
# API Config
app = FastAPI(
title="Agri-Tech API",
description="This is a ML API for classification of crop to plant on a land regarding some features",
)
## Configure static and template files
app.mount(
"/static", StaticFiles(directory="assets/static"), name="static"
) # Mount static files
templates = Jinja2Templates(directory="assets/templates") # Mount templates for HTML
# ML Config
ml_objects = loading(fp=os.path.join("assets", "ml", "crop_recommandation2.pkl"))
## Extract the ml components
model = ml_objects["model"]
scaler = ml_objects["scaler"].set_output(transform="pandas")
labels = ml_objects["labels"]
# Endpoints
# @app.get("/")
# def root():
# return {
# "Description": " This is a ML API for classification of crop to plant on a land regarding some features.",
# "Documentation": "Go to the docs: https://eaedk-agri-tech-fastapi.hf.space/docs",
# }
# Root endpoint to serve index.html template
@app.get("/", response_class=HTMLResponse)
def root(request):
return templates.TemplateResponse("index.html", {"request": request})
@app.get("/checkup")
def test(a: Optional[int], b: int):
return {"a": a, "b": b}
## ML endpoint
@app.post("/predict")
def make_prediction(
N: float,
P: float,
K: float,
temperature: float,
humidity: float,
ph: float,
rainfall: float,
):
"""Make prediction with the passed data"""
df = pd.DataFrame(
{
"N": [N],
"P": [P],
"K": [K],
"temperature": [temperature],
"humidity": [humidity],
"ph": [ph],
"rainfall": [rainfall],
}
)
parsed = predict(df=df) # df.to_dict('records')
return {
"output": parsed,
}
@app.post("/predict_multi")
def make_multi_prediction(multi_lands: Lands):
"""Make prediction with the passed data"""
print(f"Mutiple inputs passed: {multi_lands}\n")
df = pd.DataFrame(multi_lands.return_list_of_dict())
parsed = predict(df=df, endpoint="multi inputs") # df.to_dict('records')
return {
"output": parsed,
"author": "Stella Archar",
"api_version": ";)",
}
if __name__ == "__main__":
uvicorn.run("main:app", reload=True)