From ff8a13295b39565e5c71fe983b37e21e00686fb8 Mon Sep 17 00:00:00 2001 From: Antoine Gaudron-desjardins <antoine.gaudrondesjardins@student-cs.fr> Date: Mon, 4 Jul 2022 15:29:24 +0200 Subject: [PATCH] creation and connexion of db with the app --- .gitignore | 1 + backend/.env.template | 9 +++ backend/{app/api.py => app.py} | 59 +++++++++++++----- .../{app/model => assets}/keras_metadata.pb | 0 backend/{app/model => assets}/saved_model.pb | Bin .../variables/variables.data-00000-of-00001 | Bin .../variables/variables.index | Bin backend/{app => db}/__init__.py | 0 backend/db/crud.py | 20 ++++++ backend/db/database.py | 18 ++++++ backend/db/models.py | 17 +++++ backend/db/schemas.py | 21 +++++++ backend/docker-compose.yml | 11 ++++ backend/main.py | 6 +- backend/utils/__init__.py | 0 backend/{app => }/utils/preprocessing.py | 0 16 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 backend/.env.template rename backend/{app/api.py => app.py} (54%) rename backend/{app/model => assets}/keras_metadata.pb (100%) rename backend/{app/model => assets}/saved_model.pb (100%) rename backend/{app/model => assets}/variables/variables.data-00000-of-00001 (100%) rename backend/{app/model => assets}/variables/variables.index (100%) rename backend/{app => db}/__init__.py (100%) create mode 100644 backend/db/crud.py create mode 100644 backend/db/database.py create mode 100644 backend/db/models.py create mode 100644 backend/db/schemas.py create mode 100644 backend/docker-compose.yml create mode 100644 backend/utils/__init__.py rename backend/{app => }/utils/preprocessing.py (100%) diff --git a/.gitignore b/.gitignore index ad6020b..de88a2b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules/ build/ env/ +.env __pycache__ \ No newline at end of file diff --git a/backend/.env.template b/backend/.env.template new file mode 100644 index 0000000..87b242d --- /dev/null +++ b/backend/.env.template @@ -0,0 +1,9 @@ +MYSQL_DATABASE=eatfast +MYSQL_USER=user +MYSQL_PASSWORD=password +MYSQL_ROOT_PASSWORD=rootpassword + +DB_HOST=localhost +DB_PORT=3306 + +WEB_ROOT=http://localhost:8000 \ No newline at end of file diff --git a/backend/app/api.py b/backend/app.py similarity index 54% rename from backend/app/api.py rename to backend/app.py index 6082912..24562b5 100644 --- a/backend/app/api.py +++ b/backend/app.py @@ -1,29 +1,57 @@ -import cv2 -import numpy as np -import keras - -from fastapi import FastAPI +from typing import List +from fastapi import Body, Depends, FastAPI from fastapi.middleware.cors import CORSMiddleware +from sqlalchemy.orm import Session +from dotenv import load_dotenv +import os -from utils.preprocessing import fix_singular_shape, norm_by_imagenet +from db import crud, schemas, database -app = FastAPI() +# load environment variables +load_dotenv() + +app = FastAPI(docs_url="/api/docs", openapi_url="/api/openapi.json") origins = [ - "http://localhost:3000", - "localhost:3000" + os.getenv('WEB_ROOT'), ] - app.add_middleware( - CORSMiddleware, - allow_origins=origins, - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"] + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"] ) +def get_db(): + """Create a database session.""" + db = database.SessionLocal() + try: + yield db + finally: + db.close() + + +@app.get('/api/{place}', response_model=List[schemas.Record]) +async def eatfast(place: str, db: Session = Depends(get_db)): + return crud.get_records(place, db) + + +@app.post('/api/create', response_model=schemas.Record) +async def post(record: schemas.RecordBase = Body(...), db: Session = Depends(get_db)): + return crud.create_record(record, db) + + +""" +import cv2 +import numpy as np +import keras + +from utils.preprocessing import fix_singular_shape, norm_by_imagenet + + model = keras.models.load_model('model') # contours of the zone of a picture that should be analyzed by the model @@ -49,3 +77,4 @@ async def estimate_(id: str) -> float: pred_map = np.squeeze(model.predict(input_image)) count_prediction = np.sum(pred_map) return count_prediction +""" \ No newline at end of file diff --git a/backend/app/model/keras_metadata.pb b/backend/assets/keras_metadata.pb similarity index 100% rename from backend/app/model/keras_metadata.pb rename to backend/assets/keras_metadata.pb diff --git a/backend/app/model/saved_model.pb b/backend/assets/saved_model.pb similarity index 100% rename from backend/app/model/saved_model.pb rename to backend/assets/saved_model.pb diff --git a/backend/app/model/variables/variables.data-00000-of-00001 b/backend/assets/variables/variables.data-00000-of-00001 similarity index 100% rename from backend/app/model/variables/variables.data-00000-of-00001 rename to backend/assets/variables/variables.data-00000-of-00001 diff --git a/backend/app/model/variables/variables.index b/backend/assets/variables/variables.index similarity index 100% rename from backend/app/model/variables/variables.index rename to backend/assets/variables/variables.index diff --git a/backend/app/__init__.py b/backend/db/__init__.py similarity index 100% rename from backend/app/__init__.py rename to backend/db/__init__.py diff --git a/backend/db/crud.py b/backend/db/crud.py new file mode 100644 index 0000000..b90c047 --- /dev/null +++ b/backend/db/crud.py @@ -0,0 +1,20 @@ +""" +Module to interact with the database +""" +from sqlalchemy.orm import Session +from db import models, schemas + + +def get_records(place: str, db: Session): + """ Get all the records for the given place """ + records = db.query(models.Records).filter(models.Records.place == place).order_by(models.Records.date.desc()).all() + return records + + +def create_record(new_record: schemas.RecordBase, db: Session): + """ Add a new record to the database """ + db_record = models.Records(**new_record.dict()) + db.add(db_record) + db.commit() + db.refresh(db_record) + return db_record \ No newline at end of file diff --git a/backend/db/database.py b/backend/db/database.py new file mode 100644 index 0000000..6f99502 --- /dev/null +++ b/backend/db/database.py @@ -0,0 +1,18 @@ +""" +Database connection +""" +from dotenv import load_dotenv +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +import os + +# load environment variables +load_dotenv() +SQLALCHEMY_DATABASE_URL = f"mysql+pymysql://{os.getenv('MYSQL_USER')}:{os.getenv('MYSQL_PASSWORD')}@{os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}/{os.getenv('MYSQL_DATABASE')}?charset=utf8" + +engine = create_engine(SQLALCHEMY_DATABASE_URL) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +Base = declarative_base() + diff --git a/backend/db/models.py b/backend/db/models.py new file mode 100644 index 0000000..55820de --- /dev/null +++ b/backend/db/models.py @@ -0,0 +1,17 @@ +""" +Models of the database for magasin app +""" +from sqlalchemy import Column, Integer, DateTime, Float, Interval, String + +from db.database import Base + + +class Records(Base): + """Records sql table model""" + __tablename__ = "records" + + id = Column(Integer, primary_key=True, index=True) + place = Column(String(10)) + date = Column(DateTime) + density = Column(Float) + waiting_time = Column(Interval) \ No newline at end of file diff --git a/backend/db/schemas.py b/backend/db/schemas.py new file mode 100644 index 0000000..600efc7 --- /dev/null +++ b/backend/db/schemas.py @@ -0,0 +1,21 @@ +""" +Pydantic schemas for the magasin app +""" +from typing import Optional +from datetime import datetime, timedelta +from pydantic import BaseModel, Field + + +class RecordBase(BaseModel): + """Records base schema""" + place: str = Field(..., title="Name of the RU corresponding the given record") + date: datetime = Field(..., title="Date of the record") + density: float = Field(..., title="Estimated density of people") + waiting_time: Optional[timedelta] = Field(title="Estimated waiting time for people coming at this date") + +class Record(RecordBase): + """Database records schema""" + id: int + + class Config: + orm_mode = True \ No newline at end of file diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml new file mode 100644 index 0000000..abb808e --- /dev/null +++ b/backend/docker-compose.yml @@ -0,0 +1,11 @@ +version: "3.3" + +services: + db: + image: mysql + container_name: "db" + restart: always + env_file: .env + command: ["mysqld", "--authentication-policy=mysql_native_password"] + ports: + - "3306:3306" \ No newline at end of file diff --git a/backend/main.py b/backend/main.py index 1994264..9ad9db2 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,5 +1,9 @@ import uvicorn +from db import models, database +# Database creation +models.Base.metadata.create_all(bind=database.engine) + if __name__ == "__main__": - uvicorn.run("app.api:app", host="0.0.0.0", port=8000, reload=True) + uvicorn.run("app:app", host="0.0.0.0", port=3000, reload=True) diff --git a/backend/utils/__init__.py b/backend/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/app/utils/preprocessing.py b/backend/utils/preprocessing.py similarity index 100% rename from backend/app/utils/preprocessing.py rename to backend/utils/preprocessing.py -- GitLab