From 1172c4b722787b73d511cffb554ce0af0da155af Mon Sep 17 00:00:00 2001 From: rafittu Date: Fri, 11 Oct 2024 16:20:20 -0300 Subject: [PATCH 01/22] build: setup docker postgres database --- docker-compose.yml | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 15811d6..4412c78 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,9 +2,29 @@ version: '3.8' services: app: - build: . - env_file: .env + build: + context: . + dockerfile: Dockerfile + command: python src/main.py volumes: - - ./src:/app/src + - .:/app ports: - "8000:8000" + env_file: + - .env + depends_on: + - db + + db: + image: postgres:15.3 + environment: + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + volumes: + - pgdata:/var/lib/postgresql/data + ports: + - "5432:5432" + +volumes: + pgdata: \ No newline at end of file From 7a1623736ab0c1851ccdec28d61d703d2da9b5c3 Mon Sep 17 00:00:00 2001 From: rafittu Date: Fri, 11 Oct 2024 16:24:44 -0300 Subject: [PATCH 02/22] chore: update secrets --- .env.example | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.env.example b/.env.example index e69de29..e4f156a 100644 --- a/.env.example +++ b/.env.example @@ -0,0 +1,4 @@ +# PostgreSQL database setup +POSTGRES_DB=database_name +POSTGRES_USER=user +POSTGRES_PASSWORD=password \ No newline at end of file From 5db895404eea9bace9a8df798335aaa66b469b42 Mon Sep 17 00:00:00 2001 From: rafittu Date: Mon, 14 Oct 2024 11:18:30 -0300 Subject: [PATCH 03/22] build: add flask as requirement --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index f8e7061..4330b54 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ python-dotenv==1.0.0 +flask-socketio==5.4.1 From 58f8b7b6bd9f74e750b5d5152c2fd300bb85580c Mon Sep 17 00:00:00 2001 From: rafittu Date: Mon, 14 Oct 2024 11:18:47 -0300 Subject: [PATCH 04/22] chore: update docker ignore --- .dockerignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.dockerignore b/.dockerignore index e69de29..8d01a77 100644 --- a/.dockerignore +++ b/.dockerignore @@ -0,0 +1,5 @@ +venv +__pycache__ +*.pyc +*.pyo +*.pyd From b9ab3511db5e292059454e21b3855484f66a679f Mon Sep 17 00:00:00 2001 From: rafittu Date: Mon, 14 Oct 2024 13:46:48 -0300 Subject: [PATCH 05/22] feat: setup websocket to receive random color --- src/api/color_api.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/api/color_api.py diff --git a/src/api/color_api.py b/src/api/color_api.py new file mode 100644 index 0000000..3cd5160 --- /dev/null +++ b/src/api/color_api.py @@ -0,0 +1,16 @@ +from flask_socketio import SocketIO, emit +from flask import Blueprint + +color_api_bp = Blueprint('color_api', __name__) +socketio = SocketIO(cors_allowed_origins="*") + + +def init_sockets(app): + socketio.init_app(app) + + +@socketio.on('send_color') +def handle_receive_color(data): + color = data.get('color') + print(f"Received: {color}") + emit('Response', {'message': f"Color {color} received successfully!"}) From ee6eaaf3b8901618a6573aa4a1ba9238963b54c1 Mon Sep 17 00:00:00 2001 From: rafittu Date: Mon, 14 Oct 2024 14:13:54 -0300 Subject: [PATCH 06/22] chore: setup flask app --- src/main.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main.py b/src/main.py index a92213b..eb62b3a 100644 --- a/src/main.py +++ b/src/main.py @@ -1,6 +1,23 @@ +from flask import Flask +from api.color_api import color_api_bp, init_sockets, socketio + + +def create_app(): + app = Flask(__name__) + + app.register_blueprint(color_api_bp) + + init_sockets(app) + + return app + + def main(): print("🎨 Genius!") + app = create_app() + socketio.run(app, host='0.0.0.0', port=8000, debug=True) + if __name__ == "__main__": main() From bc11d56b8be9e4792883663e328bb389695a74b3 Mon Sep 17 00:00:00 2001 From: rafittu Date: Mon, 14 Oct 2024 14:14:42 -0300 Subject: [PATCH 07/22] build: add eventlet as requirement --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 4330b54..2cde0c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ python-dotenv==1.0.0 flask-socketio==5.4.1 +eventlet==0.37.0 From f6cb530c178eb97c0210fcddb02251c6cfa1c23f Mon Sep 17 00:00:00 2001 From: rafittu Date: Mon, 14 Oct 2024 15:02:14 -0300 Subject: [PATCH 08/22] feat: receive color timestamp --- src/api/color_api.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/api/color_api.py b/src/api/color_api.py index 3cd5160..f5d1d2a 100644 --- a/src/api/color_api.py +++ b/src/api/color_api.py @@ -1,4 +1,4 @@ -from flask_socketio import SocketIO, emit +from flask_socketio import SocketIO from flask import Blueprint color_api_bp = Blueprint('color_api', __name__) @@ -12,5 +12,6 @@ def init_sockets(app): @socketio.on('send_color') def handle_receive_color(data): color = data.get('color') - print(f"Received: {color}") - emit('Response', {'message': f"Color {color} received successfully!"}) + timestamp = data.get('timestamp') + + print(f"Received color: {color} at timestamp: {timestamp}") From 7417c7dce3d66849c07e0dc5d6dc9a8f06c3ab51 Mon Sep 17 00:00:00 2001 From: rafittu Date: Tue, 15 Oct 2024 15:09:08 -0300 Subject: [PATCH 09/22] feat: setup db with sql alchemy --- src/database/database.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/database/database.py diff --git a/src/database/database.py b/src/database/database.py new file mode 100644 index 0000000..19dcec5 --- /dev/null +++ b/src/database/database.py @@ -0,0 +1,10 @@ +from flask_sqlalchemy import SQLAlchemy +from flask import Flask +import os + +db = SQLAlchemy() + +def init_app(app: Flask): + app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("DATABASE_URL") + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + db.init_app(app) From b3f11f8b365299752aead6e44b73e432936f67a2 Mon Sep 17 00:00:00 2001 From: rafittu Date: Wed, 16 Oct 2024 10:57:40 -0300 Subject: [PATCH 10/22] feat: color model --- src/database/models/color.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/database/models/color.py diff --git a/src/database/models/color.py b/src/database/models/color.py new file mode 100644 index 0000000..6b05e9d --- /dev/null +++ b/src/database/models/color.py @@ -0,0 +1,11 @@ +from sqlalchemy import Column, Integer, String, DateTime, func +from src.db.database import db + +class Color(db.Model): + __tablename__ = 'colors' + id = Column(Integer, primary_key=True, index=True) + color_name = Column(String(50), nullable=False) + red = Column(Integer, nullable=False) + green = Column(Integer, nullable=False) + blue = Column(Integer, nullable=False) + timestamp = Column(DateTime(timezone=True), server_default=func.now()) From e4e2ac442f0eb8ba80e6aff80c2f97a0bc46606e Mon Sep 17 00:00:00 2001 From: rafittu Date: Wed, 16 Oct 2024 11:12:29 -0300 Subject: [PATCH 11/22] feat: color map dict --- src/api/color_api.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/api/color_api.py b/src/api/color_api.py index f5d1d2a..8e2a734 100644 --- a/src/api/color_api.py +++ b/src/api/color_api.py @@ -4,6 +4,18 @@ color_api_bp = Blueprint('color_api', __name__) socketio = SocketIO(cors_allowed_origins="*") +COLOR_MAP = { + "rgb(0, 0, 255)": "blue", + "rgb(0, 255, 255)": "blue-green", + "rgb(0, 255, 0)": "green", + "rgb(128, 255, 0)": "yellow-green", + "rgb(255, 255, 0)": "yellow", + "rgb(255, 192, 0)": "yellow-orange", + "rgb(255, 128, 0)": "orange", + "rgb(255, 64, 0)": "red-orange", + "rgb(255, 0, 0)": "red" +} + def init_sockets(app): socketio.init_app(app) From 8fe593dc16303cdf6663b9b4276842eb2c4c8fb3 Mon Sep 17 00:00:00 2001 From: rafittu Date: Wed, 16 Oct 2024 11:19:36 -0300 Subject: [PATCH 12/22] feat: function to parse rgb --- src/api/color_api.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/api/color_api.py b/src/api/color_api.py index 8e2a734..8b522fd 100644 --- a/src/api/color_api.py +++ b/src/api/color_api.py @@ -1,5 +1,6 @@ from flask_socketio import SocketIO from flask import Blueprint +import re color_api_bp = Blueprint('color_api', __name__) socketio = SocketIO(cors_allowed_origins="*") @@ -17,6 +18,13 @@ } +def parse_rgb(color_str): + match = re.match(r'rgb\((\d+),\s*(\d+),\s*(\d+)\)', color_str) + if match: + return int(match.group(1)), int(match.group(2)), int(match.group(3)) + raise ValueError("Invalid color format") + + def init_sockets(app): socketio.init_app(app) From 165e2804d272e891d860af2618f98138f8f66d9f Mon Sep 17 00:00:00 2001 From: rafittu Date: Wed, 16 Oct 2024 11:24:30 -0300 Subject: [PATCH 13/22] feat: function to get color name --- src/api/color_api.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/api/color_api.py b/src/api/color_api.py index 8b522fd..9b63dd8 100644 --- a/src/api/color_api.py +++ b/src/api/color_api.py @@ -25,6 +25,10 @@ def parse_rgb(color_str): raise ValueError("Invalid color format") +def get_color_name(color_str): + return COLOR_MAP.get(color_str, "unknown") + + def init_sockets(app): socketio.init_app(app) From 12a25abfd6507098da0695d393b6a0c7e2870ef2 Mon Sep 17 00:00:00 2001 From: rafittu Date: Wed, 16 Oct 2024 11:43:56 -0300 Subject: [PATCH 14/22] feat: function to save color in database --- src/api/color_api.py | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/api/color_api.py b/src/api/color_api.py index 9b63dd8..77e36d1 100644 --- a/src/api/color_api.py +++ b/src/api/color_api.py @@ -1,9 +1,13 @@ +import re +import logging from flask_socketio import SocketIO from flask import Blueprint -import re +from src.database.models.color import Color +from src.database.database import db color_api_bp = Blueprint('color_api', __name__) socketio = SocketIO(cors_allowed_origins="*") +logger = logging.getLogger(__name__) COLOR_MAP = { "rgb(0, 0, 255)": "blue", @@ -18,6 +22,10 @@ } +def init_sockets(app): + socketio.init_app(app) + + def parse_rgb(color_str): match = re.match(r'rgb\((\d+),\s*(\d+),\s*(\d+)\)', color_str) if match: @@ -29,13 +37,23 @@ def get_color_name(color_str): return COLOR_MAP.get(color_str, "unknown") -def init_sockets(app): - socketio.init_app(app) - - @socketio.on('send_color') def handle_receive_color(data): - color = data.get('color') + color_str = data.get('color') timestamp = data.get('timestamp') - print(f"Received color: {color} at timestamp: {timestamp}") + try: + red, green, blue = parse_rgb(color_str) + color_name = get_color_name(color_str) + + new_color = Color( + color_name=color_name, + red=red, + green=green, + blue=blue, + timestamp=timestamp + ) + db.session.add(new_color) + db.session.commit() + except ValueError as e: + logger.error(f"Error processing color: {e}") From 2efc6bcf995b72bbdcbcda7498a6b0f133c2c4e2 Mon Sep 17 00:00:00 2001 From: rafittu Date: Wed, 16 Oct 2024 13:32:39 -0300 Subject: [PATCH 15/22] feat: start database on app init --- src/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main.py b/src/main.py index eb62b3a..a80cf0a 100644 --- a/src/main.py +++ b/src/main.py @@ -1,14 +1,17 @@ from flask import Flask from api.color_api import color_api_bp, init_sockets, socketio +from database.database import init_app, db def create_app(): app = Flask(__name__) - + init_app(app) app.register_blueprint(color_api_bp) - init_sockets(app) + with app.app_context(): + db.create_all() + return app From a33548af3a8a3123b00f0e15677465e8485ef49f Mon Sep 17 00:00:00 2001 From: rafittu Date: Wed, 16 Oct 2024 13:35:36 -0300 Subject: [PATCH 16/22] build: add new app requirements --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 2cde0c9..dd508f0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ python-dotenv==1.0.0 flask-socketio==5.4.1 eventlet==0.37.0 +Flask-SQLAlchemy==2.5.1 +SQLAlchemy==1.4.22 From d1ee3c69bef752788a921b5cf876aee3e7cdd3b1 Mon Sep 17 00:00:00 2001 From: rafittu Date: Wed, 16 Oct 2024 14:51:47 -0300 Subject: [PATCH 17/22] fix: update imports --- src/api/color_api.py | 4 ++-- src/database/models/color.py | 2 +- src/main.py | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/api/color_api.py b/src/api/color_api.py index 77e36d1..42bf6d1 100644 --- a/src/api/color_api.py +++ b/src/api/color_api.py @@ -2,8 +2,8 @@ import logging from flask_socketio import SocketIO from flask import Blueprint -from src.database.models.color import Color -from src.database.database import db +from database.models.color import Color +from database.database import db color_api_bp = Blueprint('color_api', __name__) socketio = SocketIO(cors_allowed_origins="*") diff --git a/src/database/models/color.py b/src/database/models/color.py index 6b05e9d..47cad50 100644 --- a/src/database/models/color.py +++ b/src/database/models/color.py @@ -1,5 +1,5 @@ from sqlalchemy import Column, Integer, String, DateTime, func -from src.db.database import db +from database.database import db class Color(db.Model): __tablename__ = 'colors' diff --git a/src/main.py b/src/main.py index a80cf0a..886ed58 100644 --- a/src/main.py +++ b/src/main.py @@ -1,7 +1,10 @@ +from dotenv import load_dotenv from flask import Flask from api.color_api import color_api_bp, init_sockets, socketio from database.database import init_app, db +load_dotenv() + def create_app(): app = Flask(__name__) From 173bc2876037d6264a9aa6fd2c42c60f2ae22441 Mon Sep 17 00:00:00 2001 From: rafittu Date: Wed, 16 Oct 2024 14:52:18 -0300 Subject: [PATCH 18/22] build: add new app requirements --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index dd508f0..8fdca55 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ python-dotenv==1.0.0 flask-socketio==5.4.1 eventlet==0.37.0 +Flask==2.2.5 Flask-SQLAlchemy==2.5.1 SQLAlchemy==1.4.22 +psycopg2-binary==2.9.10 From 5ac263b6ab2df0b35013c7884e3c08fc37bde533 Mon Sep 17 00:00:00 2001 From: rafittu Date: Wed, 16 Oct 2024 14:55:31 -0300 Subject: [PATCH 19/22] build: remove obsolete version line --- docker-compose.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4412c78..366366f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: app: build: From 2abf67b4c30e91d90a92849326b9f56b1dc13857 Mon Sep 17 00:00:00 2001 From: rafittu Date: Wed, 16 Oct 2024 14:58:17 -0300 Subject: [PATCH 20/22] chore: new env examples --- .env.example | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index e4f156a..d68d0f7 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,8 @@ # PostgreSQL database setup POSTGRES_DB=database_name POSTGRES_USER=user -POSTGRES_PASSWORD=password \ No newline at end of file +POSTGRES_PASSWORD=password +POSTGRES_HOST=database_host +POSTGRES_PORT=port_number + +DATABASE_URL=postgresql+psycopg2://user:password@db:port_number/database_name \ No newline at end of file From 6ca03a9358bf02a19e3a8782535417447b7e1bf0 Mon Sep 17 00:00:00 2001 From: rafittu Date: Wed, 16 Oct 2024 15:15:24 -0300 Subject: [PATCH 21/22] feat: __init__ file --- src/api/__init__.py | 0 src/database/__init__.py | 0 src/database/models/__init__.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/api/__init__.py create mode 100644 src/database/__init__.py create mode 100644 src/database/models/__init__.py diff --git a/src/api/__init__.py b/src/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/database/__init__.py b/src/database/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/database/models/__init__.py b/src/database/models/__init__.py new file mode 100644 index 0000000..e69de29 From 0d3e4b11903360c35e27e6bbaed4cdd419d4599d Mon Sep 17 00:00:00 2001 From: Rafael Ribeiro Date: Thu, 17 Oct 2024 09:56:19 -0300 Subject: [PATCH 22/22] Update README.md --- README.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b5a835..bc30092 100644 --- a/README.md +++ b/README.md @@ -1 +1,64 @@ -# 🎨 Genius \ No newline at end of file +# 🎨 Genius + +### + +
+ +O projeto **Genius** é um sistema que prevê a próxima cor e sequência de cores em padrões similares ao clássico jogo **Genius**! + +Utilizando redes neurais e aprendizado incremental em tempo real, o sistema aprende continuamente a partir de sequências de cores geradas dinamicamente, proporcionando uma experiência única de predição baseada em cores. + +
+ +## Tecnologias + +Este projeto utiliza as seguintes tecnologias: + +- **Python** como linguagem principal; +- **SQLAlchemy ORM** para integração com o banco de dados **PostgreSQL**; +- **Flask** para construção de uma aplicação web responsiva; +- **Socket.IO** para comunicação em tempo real entre o servidor e o cliente; +- **TensorFlow** para criação e treinamento de uma rede neural do tipo **LSTM (Long Short-Term Memory)**, +- **Docker** como uma ferramenta de containerização; + +
+ +## Arquitetura do Sistema + +A rede neural LSTM é configurada para realizar **aprendizado incremental**, processando novas entradas de dados continuamente. A cada nova cor recebida, o modelo é atualizado com o histórico e re-treinado, garantindo que a predição de padrões e sequência de cores se torne mais precisa à medida que o sistema evolui. + +O banco de dados registra as cores em suas respectivas componentes RGB, assim como o `timestamp` de cada entrada, facilitando a análise e o processamento dos dados em tempo real. + +
+ +## Configuração do Projeto + +### Requisitos para rodar a aplicação + +- Python (versão 3.11 ou superior) +- Docker e Docker Compose; + + ### Instalação + +1. Clonando o repositório: + +```bash +$ git clone git@github.com:rafittu/python-genius.git +$ cd python-genius +``` + +2. Crie um arquivo `.env` na raiz do projeto e preencha as informações de acordo com o arquivo `.env.example` disponível. + +3. Inicie o ambiente de desenvolvimento: + +```bash +$ docker-compose up --build +``` + +
+ +## + +

+ Rafael Ribeiro 🚀 +