diff --git a/.gitignore b/.gitignore index ad6020b2aecf562674fdd86e291fe4574633f692..de88a2b3adcdd604db49c8ff544b4427e4f935e9 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 0000000000000000000000000000000000000000..87b242d893e6e3072cdef3241e7f724a558ca5b6 --- /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 6082912258590e7cff0e793d1c89de9e1af23b51..24562b55dcb8cec9d44e73125fdabb5175c88b1f 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 0000000000000000000000000000000000000000..b90c047440b3ceabd6dbbaacfe6a1cb4ec24ad56 --- /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 0000000000000000000000000000000000000000..6f995021c61b44f28e3d48520cfa0a1a4e0ca536 --- /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 0000000000000000000000000000000000000000..55820de9e561fe85ec3abfa712e33464612e82f8 --- /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 0000000000000000000000000000000000000000..600efc71449952c86b53af757d92db826c9642f4 --- /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 0000000000000000000000000000000000000000..abb808ef2f917286858187652be7bb418806633c --- /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 19942641b99dfd5f6654c95962acbb4103ad8a41..9ad9db27f031ef7bf37d268444b4a88c91c38a26 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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 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