diff --git a/README.md b/README.md index 6002010..f22634b 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,73 @@ -# Model Deployment as API | The Iris Dataset +# **Model Deployment as API | The Iris Dataset** +### **Streamlit App Interface** +![Streamlit App](imgs/img1.png) + +![Streamlit App](imgs/img2.png) + Deploying a Machine Learning Model as a REST API with Flask ![Iris](https://s3.amazonaws.com/assets.datacamp.com/blog_assets/Machine+Learning+R/iris-machinelearning.png "Iris") +--- + +## **Data Set Information** + +This is perhaps the best-known database in the pattern recognition literature. The data set contains 3 classes of 50 instances each, where each class refers to a type of iris plant. One class is linearly separable from the other two; the latter are NOT linearly separable from each other. + +**Predicted attribute**: Class of iris plant. + +--- + +## **Attribute Information** + +1. Sepal length in cm +2. Sepal width in cm +3. Petal length in cm +4. Petal width in cm +5. Class: + - Iris Setosa + - Iris Versicolour + - Iris Virginica + +--- + +## **Features** -## Data Set Information +- **Flask API**: + - Endpoint `/predict` accepts feature arrays and returns predictions. + - Enabled **CORS** to allow cross-origin requests from the Streamlit app. +- **Streamlit Frontend**: + - Interactive UI for users to input feature values (Sepal Length, Sepal Width, Petal Length, Petal Width). + - Displays prediction results dynamically. + - Includes a visually appealing background and project-specific design. +- Pre-trained model based on the Iris dataset. -This is perhaps the best known database to be found in the pattern recognition literature. The data set contains 3 classes of 50 instances each, where each class refers to a type of iris plant. One class is linearly separable from the other 2; the latter are NOT linearly separable from each other. +--- -Predicted attribute: class of iris plant. +## **Steps** -## Attribute Information +1. Build and train the machine learning model in a Jupyter Notebook (file: `_model/Iris_model.ipynb`). +2. Save the model in a (pickle) file (file: `api/iris_model.pkl`). +3. Create an API application that uses the pre-trained model to generate predictions (file: `api/api.py`). +4. Add a **Streamlit frontend** for user interaction (file: `streamlit_app.py`). +5. Encapsulate the application in a Docker container (file: `api/Dockerfile`). +6. Deploy the application to a cloud server. -1. sepal length in cm -2. sepal width in cm -3. petal length in cm -4. petal width in cm -5. class: --- Iris Setosa --- Iris Versicolour --- Iris Virginica +--- -## Steps -1. Build and train the machine learning model in a Jupyter Notebook (file: _model/Iris_model.ipynb_), -2. save the model in a (pickle) file (file: _api/iris_model.pkl_) -3. create an API application that uses the pre-trained model to generate predictions (file: _api/api.py_), -3. encapsulate the application in a Docker container (file: _api/Dockerfile_), -4. deploy the application to a cloud server. +## **Technical Requirements** -## Technical Requirements + Python 3.4+, + Docker, -+ The required Python libraries used can be installed from the included _requirements.txt_ file: ++ The required Python libraries can be installed from the included `requirements.txt` file. +--- + +## **Running the Application Locally** + +### **Directly** -## Running the application locally -### Directly ```bash # Clone the project git clone https://github.com/AchilleasKn/flask_api_python.git @@ -50,26 +81,24 @@ apt install python3-pip # Install the requirements pip3 install -r requirements.txt -# Run the script in Python +# Run the Flask API python3 api.py ``` -### On Docker +### **On Docker** ###### Available images: -- achilleaskn/flask_api_python:latest - -This image is based on the python:3.6-jessie official image +- `achilleaskn/flask_api_python:latest` + - This image is based on the `python:3.6-jessie` official image. -[![](https://images.microbadger.com/badges/image/achilleaskn/flask_api_python.svg)](https://microbadger.com/images/achilleaskn/flask_api_python "Get your own image badge on microbadger.com") + [![](https://images.microbadger.com/badges/image/achilleaskn/flask_api_python.svg)](https://microbadger.com/images/achilleaskn/flask_api_python "Get your own image badge on microbadger.com") -- achilleaskn/flask_api_python:alpine.latest +- `achilleaskn/flask_api_python:alpine.latest` + - This image is based on the Alpine Linux image, which is a lightweight version of Linux. -This image is based on Alpine Linux image which is a lightweight version of Linux + [![](https://images.microbadger.com/badges/image/achilleaskn/flask_api_python:alpine.latest.svg)](https://microbadger.com/images/achilleaskn/flask_api_python:alpine.latest "Get your own image badge on microbadger.com") -[![](https://images.microbadger.com/badges/image/achilleaskn/flask_api_python:alpine.latest.svg)](https://microbadger.com/images/achilleaskn/flask_api_python:alpine.latest "Get your own image badge on microbadger.com") - -##### From scratch +##### From Scratch ```bash # Clone the project @@ -78,93 +107,158 @@ git clone https://github.com/AchilleasKn/flask_api_python.git # Change Directory cd flask_api_python/api -# Build the docker image +# Build the Docker image docker build -t flask_api . -# For the alpine version run the following -#docker build -f Dockerfile.alpine -t flask_api . +# For the Alpine version, run the following: +# docker build -f Dockerfile.alpine -t flask_api . -# Run the flask_api image and expose the 5000 port +# Run the Flask API image and expose port 5000 docker run -d -p 5000:5000 flask_api # To see the running containers -docker ps +docker ps -# To see the logs of our running container +# To see the logs of the running container docker logs ``` ##### With Docker Pull + ```bash -# Pull the docker image +# Pull the Docker image docker pull achilleaskn/flask_api_python:latest -# For the alpine version run the following -#docker pull achilleaskn/flask_api_python:alpine.latest +# For the Alpine version, run the following: +# docker pull achilleaskn/flask_api_python:alpine.latest -# Run the flask_api image and expose the 5000 port +# Run the Flask API image and expose port 5000 docker run -d -p 5000:5000 achilleaskn/flask_api_python:latest -# For the alpine version run the following -#docker run -d -p 5000:5000 achilleaskn/flask_api_python:alpine.latest +# For the Alpine version, run the following: +# docker run -d -p 5000:5000 achilleaskn/flask_api_python:alpine.latest # To see the running containers -docker ps +docker ps -# To see the logs of our running container +# To see the logs of the running container docker logs ``` -### Testing the application -Once it is running, the API can be queried using HTTP POST requests. -I recommend using [postman](https://www.getpostman.com/) for testing. +--- -URL: `http://0.0.0.0:5000/predict` +## **Testing the Application** -- Sample query for "Setosa" type: -```json -{ - "feature_array":[4.9, 2.9, 1.2, 0.3] -} -``` +Once it is running, the API can be queried using HTTP POST requests. I recommend using [Postman](https://www.getpostman.com/) for testing. -The response should look like this: -```json -{ - "prediction": [ - 0 - ] -} -``` +**URL**: `http://0.0.0.0:5000/predict` -- Sample query for "Versicolour" type: -```json -{ - "feature_array":[6.4, 3.2, 4.5, 1.5] -} -``` +- **Sample query for "Setosa" type**: + ```json + { + "feature_array": [4.9, 2.9, 1.2, 0.3] + } + ``` -The response should look like this: -```json -{ - "prediction": [ - 1 - ] -} -``` + **Response**: + ```json + { + "prediction": [0] + } + ``` -- Sample query for "Virginica" type: -```json -{ - "feature_array":[6.2, 3.1, 5.3, 2.4] -} -``` +- **Sample query for "Versicolour" type**: + ```json + { + "feature_array": [6.4, 3.2, 4.5, 1.5] + } + ``` -The response should look like this: -```json -{ - "prediction": [ - 2 - ] -} -``` + **Response**: + ```json + { + "prediction": [1] + } + ``` + +- **Sample query for "Virginica" type**: + ```json + { + "feature_array": [6.2, 3.1, 5.3, 2.4] + } + ``` + + **Response**: + ```json + { + "prediction": [2] + } + ``` + +--- + +## **Using the Streamlit Frontend** + +The Streamlit app provides an interactive UI for users to input feature values and view predictions. + +### **How to Run the Streamlit App** + +1. Ensure the Flask API is running locally or deployed. +2. Start the Streamlit app: + ```bash + streamlit run streamlit_app.py + ``` +3. The app will open in your default browser at: + ``` + http://localhost:8501 + ``` + +### **Streamlit App Features** +- Input fields for Sepal Length, Sepal Width, Petal Length, and Petal Width. +- A "Predict" button to send the input to the Flask API and display the result. +- Displays the predicted Iris species along with an image of the corresponding flower. + +--- + + + + + +## **Deployment** + +### **Deploying the Flask API** +You can deploy the Flask API to platforms like **Heroku**, **AWS**, or **Render**: +1. Create a `Procfile`: + ``` + web: gunicorn api:app + ``` +2. Deploy to Heroku: + ```bash + heroku create your-app-name + git push heroku main + ``` + +### **Deploying the Streamlit App** +Deploy the Streamlit app to [Streamlit Cloud](https://streamlit.io/cloud): +1. Sign up for Streamlit Cloud. +2. Connect your GitHub repository. +3. Select `streamlit_app.py` as the entry point. +4. Deploy the app. + +--- + +## **Contributing** + +If you'd like to contribute, follow these steps: +1. Fork the repository. +2. Create a new branch for your changes: + ```bash + git checkout -b feature/your-feature-name + ``` +3. Push your changes and submit a pull request. + +--- + +## **License** + +This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details. diff --git a/api/App.py b/api/App.py new file mode 100644 index 0000000..69d42e4 --- /dev/null +++ b/api/App.py @@ -0,0 +1,95 @@ +import streamlit as st +import requests + +# Inject custom CSS for background +def set_background(): + st.markdown( + """ + + """, + unsafe_allow_html=True + ) + +# Call the function to set the background +set_background() + +# Title of the app +st.title("IRIS Flower Classifier 🌸") + +# Add a description +st.markdown(""" + Enter the feature values below to classify the Iris flower species. + The model will predict whether the flower is **Setosa**, **Versicolor**, or **Virginica**. +""") + +# Input fields for feature_array +feature_1 = st.number_input("Sepal Length (cm)", value=5.1, step=0.1) +feature_2 = st.number_input("Sepal Width (cm)", value=3.5, step=0.1) +feature_3 = st.number_input("Petal Length (cm)", value=1.4, step=0.1) +feature_4 = st.number_input("Petal Width (cm)", value=0.2, step=0.1) + +# Button to trigger prediction +if st.button("Predict"): + # Prepare the payload + payload = { + "feature_array": [feature_1, feature_2, feature_3, feature_4] + } + + try: + # Send POST request to Flask API + response = requests.post("http://localhost:5000/predict", json=payload) + if response.status_code == 200: + result = response.json() + prediction = result['prediction'][0] # Extract the prediction + st.success(f"Prediction: **{['Setosa', 'Versicolor', 'Virginica'][prediction]}**") + + # Display the corresponding image + if prediction == 0: + st.image("https://upload.wikimedia.org/wikipedia/commons/5/56/Kosaciec_szczecinkowaty_Iris_setosa.jpg", + caption="Setosa", width=300) + elif prediction == 1: + st.image("https://upload.wikimedia.org/wikipedia/commons/4/41/Iris_versicolor_3.jpg", + caption="Versicolor", width=300) + elif prediction == 2: + st.image("https://upload.wikimedia.org/wikipedia/commons/9/9f/Iris_virginica.jpg", + caption="Virginica", width=300) + else: + st.error(f"Error: {response.json().get('error', 'Unknown error')}") + except Exception as e: + st.error(f"An error occurred: {str(e)}") + +# Add a footer +st.markdown(""" + --- + 🌟 Built with ❤️ using [Streamlit](https://streamlit.io) and [Flask](https://flask.palletsprojects.com) +""") \ No newline at end of file diff --git a/demo.mp4 b/demo.mp4 new file mode 100644 index 0000000..3c35294 Binary files /dev/null and b/demo.mp4 differ diff --git a/imgs/Iris_versicolor_3.jpg b/imgs/Iris_versicolor_3.jpg new file mode 100644 index 0000000..2da6292 Binary files /dev/null and b/imgs/Iris_versicolor_3.jpg differ diff --git a/imgs/Iris_virginica.jpg b/imgs/Iris_virginica.jpg new file mode 100644 index 0000000..5b39834 Binary files /dev/null and b/imgs/Iris_virginica.jpg differ diff --git a/imgs/Kosaciec_szczecinkowaty_Iris_setosa.jpg b/imgs/Kosaciec_szczecinkowaty_Iris_setosa.jpg new file mode 100644 index 0000000..f1b521a Binary files /dev/null and b/imgs/Kosaciec_szczecinkowaty_Iris_setosa.jpg differ diff --git a/imgs/Screenshot (2240).png b/imgs/Screenshot (2240).png new file mode 100644 index 0000000..f53ed7a Binary files /dev/null and b/imgs/Screenshot (2240).png differ diff --git a/imgs/img1.png b/imgs/img1.png new file mode 100644 index 0000000..a84da1a Binary files /dev/null and b/imgs/img1.png differ diff --git a/imgs/img2.png b/imgs/img2.png new file mode 100644 index 0000000..d2832c5 Binary files /dev/null and b/imgs/img2.png differ