Skip to content

Commit

Permalink
Merge pull request #11 from billsioros/feat--design-the-frontend
Browse files Browse the repository at this point in the history
feat: design the frontend
  • Loading branch information
billsioros authored Jul 25, 2024
2 parents b065d49 + 5c42a6b commit cff76c5
Show file tree
Hide file tree
Showing 68 changed files with 6,243 additions and 162 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,5 @@ Thumbs.db #thumbnail cache on Windows


# End of https://www.toptal.com/developers/gitignore/api/python

*.csv
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@

## :cd: Running the project

### NVM

```shell
nvm use --lts --global
npm install
npm run dev -- --host --port 3000
```

```bash
docker compose up
```
Expand Down
31 changes: 15 additions & 16 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
version: "3.8"
services:
# frontend:
# env_file: .env
# build: ../fe/
# restart: unless-stopped
# container_name: frontend
# ports:
# - 3000:3000
# networks:
# - network
# depends_on:
# backend:
# condition: service_healthy
# notifications:
# condition: service_started
frontend:
env_file: .env
build:
context: ./src/web
dockerfile: Dockerfile
restart: unless-stopped
container_name: frontend
ports:
- 80:80
networks:
- network
depends_on:
backend:
condition: service_healthy
backend:
env_file: .env
build:
context: .
dockerfile: ./src/heartbeat/Dockerfile
dockerfile: ./src/api/Dockerfile
restart: unless-stopped
container_name: backend
ports:
Expand All @@ -43,7 +43,6 @@ services:
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- pgdata:/var/lib/postgresql/data
- ./postgres/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
ports:
- "5432:5432"
networks:
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ requires = [

[tool.poetry]
name = "heartbeat"
packages = [ { include = "api", from = "src" } ]
version = "0.2.0"
description = "A heart failure detection system"
readme = "README.md"
Expand All @@ -25,7 +26,7 @@ classifiers = [
"Changelog" = "https://github.com/billsioros/heartbeat/releases"

[tool.poetry.scripts]
manage = "heartbeat.cli.manage:cli"
manage = "api.cli.manage:cli"

[tool.poetry.dependencies]
python = "^3.11"
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions src/heartbeat/Dockerfile → src/api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ ENV PORT=8000

COPY --from=build-base ${WORKSPACE} ${WORKSPACE}

COPY ./src ${WORKSPACE}
COPY ./src/api ${WORKSPACE}/api

EXPOSE ${PORT}

Expand All @@ -71,4 +71,4 @@ CMD poetry run gunicorn \
--timeout 30 \
--worker-tmp-dir /dev/shm \
--worker-class uvicorn.workers.UvicornWorker \
heartbeat.app:app
api.app:app
File renamed without changes.
20 changes: 17 additions & 3 deletions src/heartbeat/app.py → src/api/app.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import uvicorn
from fastapi import APIRouter, FastAPI
from fastapi.middleware.cors import CORSMiddleware

from heartbeat.controllers.heartbeat_controller import api as heartbeat_controller
from heartbeat.controllers.monitor_controller import api as monitor_controller
from heartbeat.settings import Settings
from api.controllers.heartbeat_controller import api as heartbeat_controller
from api.controllers.monitor_controller import api as monitor_controller
from api.settings import Settings


def initialize_api() -> FastAPI:
Expand Down Expand Up @@ -36,13 +37,26 @@ def register_controllers(app: FastAPI, prefix: str = "") -> FastAPI:
return app


def register_middlewares(app: FastAPI) -> FastAPI:
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

return app


def register_events(app: FastAPI) -> FastAPI:
return app


def create_app() -> FastAPI:
app = initialize_api()
app = register_configuration(app)
app = register_middlewares(app)
app = register_events(app)
app = register_controllers(app)

Expand Down
2 changes: 1 addition & 1 deletion src/heartbeat/bot/__init__.py → src/api/bot/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from heartbeat.schemas.heartbeat import HeartBeatCreateSchema
from api.schemas.heartbeat import HeartBeatCreateSchema


class Bot:
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import typer

from heartbeat.cli.utils.gui import show_error, show_table
from api.cli.utils.gui import show_error, show_table

if TYPE_CHECKING:
from heartbeat.resources.database import Database
from api.resources.database import Database

group: typer.Typer = typer.Typer()

Expand Down
6 changes: 3 additions & 3 deletions src/heartbeat/cli/manage.py → src/api/cli/manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

import typer

from heartbeat.cli.commands.database import group as database
from heartbeat.resources.database import Database
from heartbeat.settings import Settings
from api.cli.commands.database import group as database
from api.resources.database import Database
from api.settings import Settings

cli: typer.Typer = typer.Typer()

Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from fastapi import APIRouter, HTTPException
from fastapi.params import Depends

from heartbeat.core.error import Error, ErrorEnum
from api.core.error import Error, ErrorEnum

T = TypeVar("T", bound="Controller")

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from fastapi import Depends, status

from heartbeat.controllers import Controller, create_controller
from heartbeat.dependencies import get_heartbeat_service
from heartbeat.schemas.heartbeat import HeartBeatCreateSchema, HeartBeatSchema
from heartbeat.services.heartbeat_service import HeartBeatService
from api.controllers import Controller, create_controller
from api.dependencies import get_heartbeat_service
from api.schemas.heartbeat import HeartBeatCreateSchema, HeartBeatSchema
from api.services.heartbeat_service import HeartBeatService

api: Controller = create_controller(__file__)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from fastapi import Depends, status

from heartbeat.controllers import Controller, create_controller
from heartbeat.core.error import Error, ErrorEnum
from heartbeat.dependencies import get_database
from heartbeat.resources.database import Database
from api.controllers import Controller, create_controller
from api.core.error import Error, ErrorEnum
from api.dependencies import get_database
from api.resources.database import Database

api: Controller = create_controller(__file__, post_fix=None, tags=["Monitoring"])

Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from pydantic import BaseModel, ConfigDict

from heartbeat.core.error import Error, ErrorEnum
from api.core.error import Error, ErrorEnum

T = TypeVar("T", bound="ServiceResult")
A = TypeVar("A")
Expand Down
10 changes: 5 additions & 5 deletions src/heartbeat/dependencies.py → src/api/dependencies.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from fastapi import Depends
from fastapi.requests import Request

from heartbeat.bot import Bot
from heartbeat.repositories.heartbeat_repository import HeartBeatRepository
from heartbeat.resources.database import Database
from heartbeat.services.heartbeat_service import HeartBeatService
from heartbeat.settings import Settings
from api.bot import Bot
from api.repositories.heartbeat_repository import HeartBeatRepository
from api.resources.database import Database
from api.services.heartbeat_service import HeartBeatService
from api.settings import Settings


async def get_settings(request: Request):
Expand Down
2 changes: 2 additions & 0 deletions src/api/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from api.models._model import *
from api.models.heartbeat import *
File renamed without changes.
49 changes: 49 additions & 0 deletions src/api/models/heartbeat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from enum import IntEnum, auto

from sqlalchemy import Boolean, Column, Enum, Float, Integer
from sqlalchemy.orm import Mapped

from api.models._model import PkModel


class Sex(IntEnum):
MALE = auto()
FEMALE = auto()


class ChestPain(IntEnum):
TYPICAL_ANGINA = auto()
ATYPICAL_ANGINA = auto()
NON_ANGINAL_PAIN = auto()
ASYMPTOMATIC = auto()


class RestingElectrocardiogram(IntEnum):
NORMAL = auto()
STT = auto() # having ST-T wave abnormality (T wave inversions and/or ST elevation or depression of > 0.05 mV)
LVH = auto() # showing probable or definite left ventricular hypertrophy by Estes' criteria


class StSlope(IntEnum):
UP = auto()
FLAT = auto()
DOWN = auto()


class HeartBeatModel(PkModel):
__tablename__ = "heartbeats"

age: Mapped[int] = Column(Integer, nullable=False)
sex: Mapped[Sex] = Column(Enum(Sex), nullable=False)
chest_pain_type: Mapped[ChestPain] = Column(Enum(ChestPain), nullable=False)
resting_blood_pressure: Mapped[int] = Column(Integer, nullable=False)
cholesterol: Mapped[int] = Column(Integer, nullable=False)
fasting_blood_sugar: Mapped[bool] = Column(Boolean, nullable=False)
resting_electrocardiogram: Mapped[RestingElectrocardiogram] = Column(
Enum(RestingElectrocardiogram), nullable=False,
)
max_heart_rate: Mapped[int] = Column(Integer, nullable=False)
exercise_angina: Mapped[bool] = Column(Boolean, nullable=False)
old_peak: Mapped[float] = Column(Float, nullable=False)
st_slope: Mapped[StSlope] = Column(Enum(StSlope), nullable=False)
heart_disease: Mapped[bool] = Column(Boolean, nullable=False)
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

from sqlalchemy import exc

from heartbeat.models.heartbeat import HeartBeatModel
from heartbeat.repositories import Repository
from heartbeat.resources.database import Database
from api.models.heartbeat import HeartBeatModel
from api.repositories import Repository
from api.resources.database import Database


class HeartBeatRepository(Repository):
Expand Down Expand Up @@ -45,5 +45,5 @@ def create(
return heartbeat
except exc.IntegrityError as exception:
raise HeartBeatRepository.ConflictException(
heartbeatname=heartbeat.heartbeatname,
id=heartbeat.id,
) from exception
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from sqlalchemy import create_engine, inspect, orm, sql
from sqlalchemy.orm import Session

from heartbeat.models._model import Model
from api.models._model import Model


class Database:
Expand Down
Empty file added src/api/schemas/__init__.py
Empty file.
41 changes: 41 additions & 0 deletions src/api/schemas/heartbeat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from pydantic import BaseModel, Field

from api.models.heartbeat import (
ChestPain,
RestingElectrocardiogram,
Sex,
StSlope,
)


class HeartBeatCreateSchema(BaseModel):
class Config:
from_attributes = True

age: int = Field(..., ge=0, le=130, description="Age of the patient [years]")
sex: Sex
chest_pain_type: ChestPain
resting_blood_pressure: int = Field(
..., ge=0, le=250, description="Resting blood pressure [mm Hg]",
)
cholesterol: int = Field(..., ge=0, le=700, description="Serum cholesterol [mm/dl]")
fasting_blood_sugar: bool = Field(
..., description="Fasting blood sugar [1: if FastingBS > 120 mg/dl, 0: otherwise]",
)
resting_electrocardiogram: RestingElectrocardiogram
max_heart_rate: int = Field(
...,
ge=60,
le=202,
description="Maximum heart rate achieved [Numeric value between 60 and 202]",
)
exercise_angina: bool
old_peak: float = Field(
..., ge=-10, le=10, description="Oldpeak = ST [Numeric value measured in depression]",
)
st_slope: StSlope


class HeartBeatSchema(HeartBeatCreateSchema):
id: str
heart_disease: bool
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from collections.abc import Iterator

from heartbeat.bot import Bot
from heartbeat.core.service_result import ServiceResult
from heartbeat.models.heartbeat import HeartBeatModel
from heartbeat.repositories.heartbeat_repository import HeartBeatRepository
from heartbeat.schemas.heartbeat import HeartBeatCreateSchema
from heartbeat.services import Service
from api.bot import Bot
from api.core.service_result import ServiceResult
from api.models.heartbeat import HeartBeatModel
from api.repositories.heartbeat_repository import HeartBeatRepository
from api.schemas.heartbeat import HeartBeatCreateSchema
from api.services import Service


class HeartBeatService(Service):
Expand All @@ -32,13 +32,13 @@ def create(self, heartbeat_create: HeartBeatCreateSchema) -> ServiceResult[Heart
age=heartbeat_create.age,
sex=heartbeat_create.sex,
chest_pain_type=heartbeat_create.chest_pain_type,
resting_bp=heartbeat_create.resting_bp,
resting_blood_pressure=heartbeat_create.resting_blood_pressure,
cholesterol=heartbeat_create.cholesterol,
fasting_bs=heartbeat_create.fasting_bs,
resting_ecg=heartbeat_create.resting_ecg,
max_hr=heartbeat_create.max_hr,
fasting_blood_sugar=heartbeat_create.fasting_blood_sugar,
resting_electrocardiogram=heartbeat_create.resting_electrocardiogram,
max_heart_rate=heartbeat_create.max_heart_rate,
exercise_angina=heartbeat_create.exercise_angina,
oldpeak=heartbeat_create.oldpeak,
old_peak=heartbeat_create.old_peak,
st_slope=heartbeat_create.st_slope,
heart_disease=self._bot.predict(heartbeat_create),
)
Expand Down
File renamed without changes.
Loading

0 comments on commit cff76c5

Please sign in to comment.