26 |
27 | {{ prediction_text }}
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021, PapiHack
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/app.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from flask import Flask, request, render_template, jsonify
3 | import pickle
4 |
5 | app = Flask(__name__)
6 | model = pickle.load(open('model.pkl', 'rb'))
7 |
8 | @app.route('/')
9 | def Home():
10 | return render_template('index.html')
11 |
12 | @app.route('/predict', methods=['POST'])
13 | def predict():
14 |
15 | int_feature = [int(x) for x in request.form.values()]
16 | final_feature = [np.array(int_feature)]
17 | prediction = model.predict(final_feature)
18 |
19 | output = round(prediction[0], 2)
20 |
21 | return render_template('index.html', prediction_text='Enploye salary sould be $ {}'.format(output))
22 |
23 | @app.route('/api/predict', methods=['POST'])
24 | def api_predict():
25 |
26 | data = request.get_json(force=True)
27 |
28 | prediction = model.predict([np.array([int(data['experience']), int(data['test_score']), int(data['interview_score'])])])
29 |
30 | output = round(prediction[0], 2)
31 |
32 | return jsonify({'salary': output, 'currency': '$'})
33 |
34 |
35 | if __name__== '__main__':
36 | app.run(host="0.0.0.0", debug=True)
37 |
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | # mypy
104 | .mypy_cache/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🚀 GalsenAI Demo Project 🚀
2 |
3 | [](https://img.shields.io/badge/Python-3776AB?style=for-the-badge&logo=python&logoColor=white)
4 | [](https://img.shields.io/badge/docker-3776AB?style=for-the-badge&logo=docker&logoColor=white)
5 | [](https://img.shields.io/badge/kubernetes-3776AB?style=for-the-badge&logo=kubernetes&logoColor=white)
6 | [](./LICENSE)
7 | 
8 | 
9 | [](https://github.com/ellerbrock/open-source-badges/)
10 |
11 | Demo project of my talk for GalsenAI Dakar community on `How to Deploy and Scale AI (ML or DL) Models with Kubernetes`.
12 |
13 | You can find the slides of my talk at .
14 |
15 | ## Description
16 |
17 | This repo contains a `REST API` built with `Flask` that expose a machine learning model that can predict salary based on `years of experience`, `test score` and `interview score`.
18 |
19 | ## Installation
20 |
21 | You have two ways in order to setup and run this project.
22 |
23 | ### Manual Setup
24 |
25 | For manual installation, you need to have `Python` (version 3 is preferable) on your system. Then you can clone this repo and follow the steps below :
26 |
27 | - Create a virtual environment with the command :
28 |
29 | python3 -m venv venv
30 |
31 | - Activate the virtual environment with the command :
32 |
33 | . venv/bin/activate or source venv/bin/activate
34 |
35 | - Install the necessary dependencies with the command :
36 |
37 | pip install -r requirements.txt
38 |
39 | - Start the server with the command :
40 |
41 | python app.py
42 |
43 | - Go to your browser at the following address :
44 |
45 | http://localhost:5000
46 |
47 | - Or make a `POST` request at with the following payload (change values if you want) :
48 |
49 | {
50 | "experience": 1.8,
51 | "test_score": 12,
52 | "interview_score": 10
53 | }
54 |
55 | ### Docker Setup
56 |
57 | If you have `Docker` on your system, you have two options after placing yourself in the directory of this project :
58 |
59 | - First option :
60 |
61 | - Build your image with the name you want like this :
62 |
63 | docker build . -t salary-prediction-service
64 |
65 | - Run it with the following command :
66 |
67 | docker run -d --name salary-prediction-service -p 5000:5000 salary-prediction-service
68 |
69 | - Second option :
70 |
71 | - Run the image that i already deploy on `docker hub` with the following command :
72 |
73 | docker run -d --name salary-prediction-model -p 5000:5000 papihack/galsenai-salary-prediction
74 |
75 |
76 | ### Kubernetes
77 |
78 | For the deployment of this project on `K8S`, i use a tool named [Kind](https://kind.sigs.k8s.io/docs/user/quick-start/) in order to create a local kubernetes cluster. You can also use other alternatives like `minikube` if you want it too.
79 |
80 | The manifest files are located in the `k8s` folder.
81 |
82 | - First and foremost, you need to have or create a kubernetes cluster. After you installed `kind` on your system, you can create one with the following command :
83 |
84 | kind create cluster --config k8s/cluster-config.yaml --name my-cluster
85 |
86 | The file `k8s/cluster-config.yaml` will allow you to have a cluster with `1 Master Node (Control Plane)` and `2 Worker Nodes`.
87 |
88 | - Then you can apply the `deployment` and `service` manifest files with the command :
89 |
90 | kubectl apply -f k8s/service.yaml -f k8s/deployment.yaml
91 |
92 | - Finally, since it is a `NodePort` type service, you can try to find the `IP` of one your nodes and the `generated PORT` of the service in order to try to access to the app.
93 |
94 | You can get those infos by running the following commands :
95 |
96 | kubectl get svc -o wide
97 |
98 | kubectl get no -o wide
99 |
100 | The url should look like at something like : `http://node-ip:svc-port` for the web page and `http://node-ip:svc-port/api/predict` for the `API`.
101 |
102 | ## Screenshots
103 |
104 |
105 |
106 |
API Interaction
107 |
Web interface
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | ## Contributing
116 |
117 | Feel free to make a PR or report an issue 😃
118 |
119 | Oh, one more thing, please do not forget to put a description when you make your PR 🙂
120 |
121 | ## Author
122 |
123 | - [M.B.C.M](https://itdev.sn)
124 | [](https://twitter.com/the_it_dev)
--------------------------------------------------------------------------------