Spaces:
Sleeping
Sleeping
| import uvicorn | |
| import pickle | |
| import os | |
| import json | |
| import logging | |
| from fastapi import FastAPI, Request | |
| from fastapi.responses import HTMLResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from fastapi.templating import Jinja2Templates | |
| from typing import List, Literal, Optional | |
| from pydantic import BaseModel | |
| import pandas as pd | |
| # 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 | |
| async def root(request: Request): | |
| return templates.TemplateResponse("index.html", {'request': request}) | |
| 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) | |