Skip to content

Commit

Permalink
Merge pull request #26 from MLOps-essi-upc/dev
Browse files Browse the repository at this point in the history
Merging dev into main
  • Loading branch information
Rudiio authored Dec 12, 2023
2 parents b82c947 + 3a85a3f commit 9e27ff3
Show file tree
Hide file tree
Showing 22 changed files with 574 additions and 55 deletions.
55 changes: 55 additions & 0 deletions .github/workflows/ci-cd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Run tests CI
on:
push:
branches:
- main
- dev
pull_request:
branches:
- main
- dev
jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Use python
uses: actions/setup-python@v4
with:
python-version: '3.9'

- name: Install dependencies
run: pip install -r requirements.txt

- name: show cwd
run : python -c "import os; print('\n',os.getcwd())"

- name : pull data from dvc
run : python -m dvc pull -r origin

- name: Run tests
run: python -m pytest

cd:
runs-on: ubuntu-latest
needs : ci
steps :
- name : Checkout repository
uses: actions/checkout@v4

- name: Docker login
run: docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} -p ${{ secrets.DOCKER_HUB_TOKEN }}

- name: Build
run: docker build -t sentibites .
- name: Tags
run: |
docker tag sentibites ${{ secrets.DOCKER_HUB_USERNAME }}/sentibites:${{ github.sha }}
docker tag sentibites ${{ secrets.DOCKER_HUB_USERNAME }}/sentibites:latest
- name: Push
run: |
docker push ${{ secrets.DOCKER_HUB_USERNAME }}/sentibites:${{ github.sha }}
docker push ${{ secrets.DOCKER_HUB_USERNAME }}/sentibites:latest
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,6 @@ cython_debug/
# Report
out/
reports/

# DS_STORE
.DS_Store
15 changes: 15 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM python:3.10

ENV PYTHONUNBUFFERED 1

COPY requirements.txt .

WORKDIR /app

COPY . /app/

RUN pip install --no-cache-dir -r requirements.txt

EXPOSE 5000

CMD ["python3", "run_servers.py"]
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,20 @@ dvc pull -r origin
pytest tests/
```

## Usage
## Deployment with Docker

1. Create the docker image

```sh
docker build -t Sentibites:1.0 .
```

2. Run the container
```sh
docker run -p 5000:5000 -p 8000:8000 Sentibites
```

## Usage without App

For training :

Expand All @@ -50,5 +63,5 @@ python3 src/models/train_model.py --model "roberta-base" --dataset data/processe
For inference :

```sh
python3 src/models/predict_model.py --input "text"
python3 src/models/predict_model.py --model "models/SentiBites" --input "text"
```
Empty file removed data/external/.gitkeep
Empty file.
Empty file removed data/interim/.gitkeep
Empty file.
21 changes: 21 additions & 0 deletions dvc.lock
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,24 @@ stages:
md5: 18b4f7b1478054e92600037d8b716956.dir
size: 502103967
nfiles: 10
evaluation:
cmd: python3 src/models/evaluate.py --model models/SentiBites --dataset data/processed
deps:
- path: data/processed/test.csv
hash: md5
md5: adffff99092202d7a587660718f62ea7
size: 7212513
- path: models/SentiBites
hash: md5
md5: 18b4f7b1478054e92600037d8b716956.dir
size: 502103967
nfiles: 10
- path: src/models/evaluate_model.py
hash: md5
md5: c94a08fa59debe1c0405d2aa5b63908b
size: 3515
outs:
- path: metrics/evaluation_scores.csv
hash: md5
md5: 9fd0ecf8f1e3e187bc6fe055758cc600
size: 89
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ omit = ["src/data/*",'src/features/*',"src/visualization/*","src/models/model.py

[tool.pytest.ini_options]
testpaths = "tests"
addopts = "--junitxml=out/tests-report.xml --cov=src --cov-report=html:reports/coverage"
addopts = "--junitxml=out/tests-report.xml"
16 changes: 10 additions & 6 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# local package
-e .

# Packages needed
--extra-index-url https://download.pytorch.org/whl/cpu
torch

transformers
mlflow
botocore==1.31.47
botocore
tensorflow
fsspec==2023.9.2
datasets==2.11
accelerate>=0.20.1
evaluate
Expand All @@ -17,9 +18,12 @@ pytest-cov

# external requirements
click
# Sphinx>=6.0
Sphinx
coverage
awscli==1.29.47
flake8
python-dotenv>=0.5.1
great-expectations
great-expectations
uvicorn
gunicorn
fastapi
13 changes: 13 additions & 0 deletions run_servers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from subprocess import Popen

# Start uvicorn
uvicorn_cmd = ["uvicorn", "--host", "0.0.0.0", "--port", "8000", "src.app.api:app"]
uvicorn_process = Popen(uvicorn_cmd)

# Start gunicorn
gunicorn_cmd = ["gunicorn", "-b", "0.0.0.0:5000", "src.app.app:app"]
gunicorn_process = Popen(gunicorn_cmd)

# Wait for the processes to finish
uvicorn_process.wait()
gunicorn_process.wait()
10 changes: 0 additions & 10 deletions setup.py

This file was deleted.

103 changes: 103 additions & 0 deletions src/app/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""Main script: it includes our API initialization and endpoints."""

import pickle
from datetime import datetime
from functools import wraps
from http import HTTPStatus
from typing import List
import os
import sys

from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException, Request
from src.models.predict_model import SentiBites
from src.app.schemas import Review

# Get the parent directory
parent_dir = os.path.dirname(os.path.realpath(__file__))

# Add the parent directory to sys.path
sys.path.append(parent_dir)

model = None

# Define application
app = FastAPI(
title="SentiBites",
description="This API lets you make predictions on sentiment analysis of Amazon food reviews.",
version="0.1",
)


def construct_response(f):
"""Construct a JSON response for an endpoint's results."""

@wraps(f)
def wrap(request: Request, *args, **kwargs):
results = f(request, *args, **kwargs)

# Construct response
response = {
"message": results["message"],
"method": request.method,
"status-code": results["status-code"],
"timestamp": datetime.now().isoformat(),
"url": request.url._url,
}

# Add data
if "data" in results:
response["data"] = results["data"]

return response

return wrap


@app.on_event("startup")
def _load_model():
"""Loads the model"""

global model
model = SentiBites("models/SentiBites/")


@app.get("/", tags=["General"]) # path operation decorator
@construct_response
def _index(request: Request):
"""Root endpoint."""

response = {
"message": HTTPStatus.OK.phrase,
"status-code": HTTPStatus.OK,
"data": {"message": "Welcome to SentiBites! Please, read the `/docs`!"},
}
return response

@app.post("/models/", tags=["Prediction"])
@construct_response
def _predict(request: Request, payload: Review):
"""Performs sentiment analysis based on the food review."""

if model:
prediction,scores = model.predict(payload.msg)

response = {
"message": HTTPStatus.OK.phrase,
"status-code": HTTPStatus.OK,
"data": {
"model-type": "RoBERTaSB",
"payload": payload.msg,
"prediction": prediction,
"Scores" : {
"positive" : scores['positive'],
"neutral" : scores['neutral'],
"negative" : scores['negative']
}
},
}
else:
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST, detail="Model not found"
)
return response
35 changes: 35 additions & 0 deletions src/app/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from flask import Flask, render_template, request, jsonify
import requests

app = Flask(__name__, static_folder="static")

# The URL of FastAPI API
api_url = "http://127.0.0.1:8000/models/"

@app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
# Get the text entered by the user
text = request.form.get("text")

# Build the URL with the text as a parameter
payload = {'msg':text}

# Call your FastAPI API
response = requests.post(api_url,json=payload)

if response.status_code == 200:
# Get the results from the API
data = response.json()
prediction = data["data"]["prediction"]
model_type = data["data"]["model-type"]

return render_template("index.html", prediction=prediction, model_type=model_type, text=text)
else:
error_message = "Error when calling API."
return render_template("index.html", error_message=error_message, text=text)

return render_template("index.html")

if __name__ == "__main__":
app.run(debug=False)
4 changes: 4 additions & 0 deletions src/app/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from pydantic import BaseModel

class Review(BaseModel):
msg : str
Binary file added src/app/static/image1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 9e27ff3

Please sign in to comment.