|
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 |
|
|
|
|
|
logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.DEBUG) |
|
|
|
|
|
|
|
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()}") |
|
|
|
|
|
scaled_df = scaler.transform(df) |
|
logging.info(f" Scaler output is of type {type(scaled_df)}") |
|
|
|
|
|
prediction = model.predict_proba(scaled_df) |
|
print(f"INFO: Prediction output: {prediction}") |
|
|
|
|
|
|
|
highest_proba = prediction.max(axis=1) |
|
print(f"INFO: Highest probabilities : {highest_proba}") |
|
|
|
|
|
highest_proba_idx = prediction.argmax(axis=1) |
|
print(f"INFO: Highest probability indexes : {highest_proba_idx}") |
|
|
|
|
|
predicted_classes = [labels[i] for i in highest_proba_idx] |
|
print(f"INFO: Predicted classes : {predicted_classes}") |
|
|
|
|
|
|
|
df["predicted proba"] = highest_proba |
|
df["predicted label"] = predicted_classes |
|
|
|
print(f"INFO: dataframe filled with prediction\n{df.to_markdown()}\n") |
|
|
|
|
|
|
|
parsed = df.to_dict("records") |
|
|
|
return parsed |
|
|
|
|
|
|
|
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 [i.dict() for i in cls.inputs] |
|
|
|
|
|
|
|
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_objects = loading(fp=os.path.join("assets", "ml", "crop_recommandation2.pkl")) |
|
|
|
model = ml_objects["model"] |
|
scaler = ml_objects["scaler"].set_output(transform="pandas") |
|
labels = ml_objects["labels"] |
|
|
|
|
|
|
|
@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", |
|
} |
|
|
|
|
|
|
|
app.mount( |
|
"/static", StaticFiles(directory="assets/static"), name="static" |
|
) |
|
templates = Jinja2Templates(directory="assets/templates") |
|
|
|
|
|
|
|
@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} |
|
|
|
|
|
|
|
@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) |
|
|
|
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") |
|
|
|
return { |
|
"output": parsed, |
|
"author": "Stella Archar", |
|
"api_version": ";)", |
|
} |
|
|
|
|
|
if __name__ == "__main__": |
|
uvicorn.run("main:app", reload=True) |
|
|