TagMedX is an open-source web app built with FastAPI, Next.js, and MySQL, designed for medical image tagging β both classification and detection. It's a tool for healthcare professionals, such as doctors and medical experts, to annotate medical images remotely for AI systems.
git clone https://github.com/heyimjustalex/TagMedX.git
cd TagMedX
Start without frontend, just backend, DB, and DBAdmin
docker-compose up --build
Start whole project (with frontend)
docker-compose -f docker-compose_all.yml up --build
- Database - mysql:8.1.0
- Database Admin Panel - phpmyadmin:5.2.1
- Backend (FastAPI) - python:3.8 - (additional dependencies in ./backend/requirements.txt)
- Frontend (Next.js + TS) - node:20 - (additional dependencies in ./frontend/package.json)
SQL file in /DB/setup.sql (with some random data loading).
In /DB folder there are also screenshots of scheme and dbdiagram.io code if modification of scheme is needed.
Scheme might also be viewed in PHPMyadmin
The structure of the database is as follows:
User:
- Fields: id, e_mail, password_hash, name, surname, title, role, description, experience
- Purpose: Represents a doctor or an admin who controls datasets.
- Relationships:
- One-to-Many with Membership
- One-to-Many with Examination
- One-to-Many with Package
Group:
- Fields: id, name, description
- Purpose: Represents a group or team of users that will work on a specific dataset. For example, a group of dentists marking a teeth dataset.
- Relationships:
- One-to-Many with Set
- One-to-Many with Membership
Membership:
- Fields: id_user, id_group
- Purpose: Represents the membership of users in groups.
- Relationships:
- Many-to-One with User
- Many-to-One with Group
Set:
- Fields: id, id_group, name, description, type
- Purpose: Represents sets that are created by users with the role "admin/manager." A Group is linked with Set, allowing a group of doctors to have many sets assigned. Set is a representation of activity dataset marking.
- Relationships:
- Many-to-One with Group
- One-to-Many with Package (each set has multiple packages)
- One-to-Many with Label (a set has some labels assigned by the admin, which doctors can later choose from)
Package:
- Fields: id, id_set, id_user, is_ready
- Purpose: Represents sets that are created by users with the role "admin/manager." A Group is linked with Set, allowing a group of doctors to have many sets assigned. Set is a representation of activity dataset marking.
- Relationships:
- Many-to-One with Set (Package belongs to a Set (previously called Task))
- Many-to-One with User (Package has user that owns it)
- One-to-Many with Sample (each Package has multiple Samples)
Sample:
- Fields: id, id_set, path, format
- Purpose: Represents samples, which contain information about added photos to be examined.
- Relationships:
- Many-to-One with Package
- Many-to-One with User - each sample has a user that it was firstly assigned to
- One-to-Many with Examination - each sample might have different examination by different users, with different BBox
Examination:
- Fields: id, id_user, id_sample, tentative, bad_quality
- Purpose: Records information about Sample Examination by User (doctor). It might involve detection or classification. If it's classification, there is just one bounding box (BBox).
- Relationships:
- Many-to-One with User
- Many-to-One with Sample
- One-to-Many with BBox (during a single Sample Examination by a particular User, they might crop some data on the Sample with one BBox or with many, depending on the type of sample)
Label:
- Fields: id, id_set, name, description
- Purpose: Represents labels for sets that are constrained by the admin/manager who creates the Set.
- Relationships:
- Many-to-One with Set
- One-to-Many with BBox
BBox:
- Fields: id, id_examination, id_label, comment, x1, y1, x2, y2
- Purpose: Stores bounding box details. The coordinates x1, y1 represent the bottom-left corner, and x2, y2 represent the top-right corner.
- Relationships:
- Many-to-One with Examination
- Many-to-One with Label
Project has hot-reload with Docker and it gets started with compose. Written with FastAPI.
- Use typing and linter.
- Try to stick to PEP8.
- Methods: snake_case
- Classes: PascalCase
Backend project is divided into 3 main folders: features, models, repositories. Features have user-domain specific folders like groups, users or sets. Each of these subfolders has it's own controllers, schemas and services. Some facts:
- If you want to make new feature make new folder in feature folder
- Models are mapped to MySQL database entities defined in /DB/setup.sql. Any change made to model any of these means the other needs to be changed.
- Backend is dockerized and avaliable at localhost:8000 (You can test endpoints users/1 or /users)
βββ backend <- FastAPI backend
β βββ features <- Domain specific features
| | βββ exceptions <- Our defined exceptions
| | | βββ definitions <- Exceptions definitions (used by services)
| | | βββ handlers <- Excaptions hanlders used by app.py
| | βββ examination <- Sample examination related features
| | βββ groups <- Group related features
| | βββ sets <- Sets related features
| | βββ users <- Users related features
| | | βββ controllers <- Router and endpoints /users /users/id
| | | βββ schemas <- Pydantic schemas for response
| | | βββ services <- Layer talking to Repositories
β βββ models <- SQLAlchemy data models
β βββ repositories <- SQLAlchemy queries
β βββ utilities <- Utilities like database connector or session
β βββ requirements.txt <- Packages to install
β βββ Dockerfile <- Dockerfile for Docker image
- FastAPI (0.103.1): A fast web framework for building APIs with automatic documentation.
- SQLAlchemy (2.0.21): A powerful SQL toolkit and ORM for Python.
- aiomysql (0.2.0): An asyncio driver for MySQL databases.
- Pydantic (2.4.2): Data validation and parsing library for Python.
- Uvicorn (0.23.2): A lightweight ASGI server for asynchronous Python web apps.
- mysql-connector-python (8.1.0): A Python driver for MySQL databases.
- mysqlclient: A MySQL database adapter for Python.
https://levelup.gitconnected.com/structuring-fastapi-project-using-3-tier-design-pattern-4d2e88a55757
https://github.com/fastapi-practices/fastapi_best_architecture
https://github.com/zhanymkanov/fastapi-best-practices#2-excessively-use-pydantic-for-data-validation
Project has hot-reload with Docker and it gets started with command:
docker-compose -f docker-compose_all.yml up --build
- Next.js
- TypeScript
- Tailwind CSS
- NextUI
- Components functions and files should start with capital letter.
- Every component file should be in folder with the same name.
- Component folder should contains no more than 4 files:
- component.css - component styling
- Component.tsx - component
- ComponentConsts.ts - component consts
- ComponentUtils.ts - component utils (functions)
- Components: camelCase, function() {}
- Functions: camelCase, function() {}
- CSS classes: dash-case (ex. class-name__sub-class--variant)
Frontend source folder is divided into 7 main folders: app, assets, components, consts, contexts hooks and utils. App folder defines app structure. Assets stores media files. Components contains subfolders with components. Consts folder is intended for global consts and interfaces. Contexts includes React contexts and providers. Hooks folder contains React hooks. In utils folder utility functions can be found. Frontend is dockerized and avaliable at localhost:3000.
βββ frontend <- Next.js frontend
β βββ src <- Source folder
| | βββ app <- App structure
| | βββ assets <- Media folder
| | βββ components <- Components folder
| | βββ consts <- Consts folder
| | βββ contexts <- Contexts and Providers folder
| | βββ hooks <- React hooks folder
| | βββ utils <- Utility functions folder
β βββ public <- Media folder
β βββ next.config.js <- Next.js config
β βββ package.json <- Packages to install
β βββ tsconfig.json <- TypeScript config
β βββ tailwind.config.json <- Tailwind CSS config
β βββ Dockerfile <- Dockerfile for Docker image
In order to start developing, please create your own branch:
git checkout -b "<type>/<branch-name>"
- Type: feature, fix, build, chore, ci, docs, style, refactor, test
- Name: dash-case
ex. feature/login-page
Please use following commits name convention:
<type>: commit name
- Type: feature, fix, build, chore, ci, docs, style, refactor, test
- Name: lowercase
ex. feature: add login button
Please use following pull request name convention:
<Type>: commit name
- Type: Feature, Fix, Build, Chore, CI, Docs, Style, Refactor, Test
- Name: lowercase
ex. Feature: add login page
Additionally list in pull request description main changes.
β Use squash and merge β