Spaces:
Sleeping
Sleeping
from fastapi import FastAPI | |
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") | |
# 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 | |
def root(): | |
return {"Description": " This is a ML API for classification of crop to plant on a land regarding some features."} | |
def test(a: Optional[int], b: int): | |
return {"a": a, "b": b} | |
## ML endpoint | |
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, | |
} | |
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) | |