diff --git a/app/__init__.py b/app/__init__.py index 5299b5b..90d7fb3 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -3,6 +3,8 @@ from flasgger import Swagger from app.database import db from app.models.user import User from app.routes.user_routes import user_bp +from app.routes.login_form import login_bp +from app.routes.dashboard import dashboard_bp from app.routes.invoice_routes import invoice_bp from werkzeug.security import generate_password_hash @@ -54,5 +56,7 @@ def create_app(): # Registrar Blueprints app.register_blueprint(user_bp, url_prefix="/users") app.register_blueprint(invoice_bp, url_prefix="/invoices") + app.register_blueprint(login_bp, url_prefix="/login_bp") + app.register_blueprint(dashboard_bp, url_prefix="/dashboard") return app diff --git a/app/controllers/__init__.py b/app/controllers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/controllers/auth_controller.py b/app/controllers/auth_controller.py new file mode 100644 index 0000000..85395b2 --- /dev/null +++ b/app/controllers/auth_controller.py @@ -0,0 +1,13 @@ +from app.auth import generate_token +from app.models.user import User +from werkzeug.security import check_password_hash +from flask import jsonify + +def authenticate_user(email, password): + user = User.query.filter_by(email=email).first() + + if not user or not check_password_hash(user.password, password): + return None, None + + token = generate_token(user) + return user, token diff --git a/app/routes/dashboard.py b/app/routes/dashboard.py new file mode 100644 index 0000000..3931a6b --- /dev/null +++ b/app/routes/dashboard.py @@ -0,0 +1,12 @@ +from flask import Blueprint, render_template, session, redirect, url_for, flash + +dashboard_bp = Blueprint("dashboard", __name__, template_folder="templates") + +@dashboard_bp.route("/") +def dashboard(): + """Protege a rota do dashboard""" + if "user_id" not in session: + flash("Faça login para acessar o dashboard.", "warning") + return redirect(url_for("login_form.login")) + + return render_template("dashboard.html", user_email=session.get("user_email")) diff --git a/app/routes/login_form.py b/app/routes/login_form.py new file mode 100644 index 0000000..ed265e9 --- /dev/null +++ b/app/routes/login_form.py @@ -0,0 +1,30 @@ +from flask import Blueprint, render_template, request, redirect, url_for, flash, session +from app.controllers.auth_controller import authenticate_user + +login_bp = Blueprint("login_form", __name__, template_folder="templates") + +@login_bp.route("/", methods=["GET", "POST"]) +def login(): + """Rota de login""" + if request.method == "POST": + email = request.form.get("email") + password = request.form.get("password") + + user, token = authenticate_user(email, password) + + if user: + session["user_id"] = user.id + session["user_email"] = user.email + flash("Login bem-sucedido!", "success") + return redirect(url_for("dashboard.dashboard")) + + flash("Credenciais inválidas!", "danger") + + return render_template("login.html") + +@login_bp.route("/logout") +def logout(): + """Rota de logout""" + session.clear() + flash("Você saiu da conta.", "info") + return redirect(url_for("login_form.login")) diff --git a/app/services/ocr_service.py b/app/services/ocr_service.py new file mode 100644 index 0000000..389c439 --- /dev/null +++ b/app/services/ocr_service.py @@ -0,0 +1,53 @@ +import os +import uuid +from typing import Dict +from PIL import Image +from pdf2image import convert_from_path +from app.services.correction_service import correct_text +from app.services.engines.tesseract_ocr import ocr_tesseract +from app.services.engines.easyocr_ocr import ocr_easyocr +from app.services.engines.paddleocr_ocr import ocr_paddleocr +# from app.services.engines.mmocr_ocr import ocr_mmocr # Opcional +from app.utils import save_text_file + +UPLOAD_DIR = "app/static/uploads" +TEXTS_DIR = "app/static/texts" + +def process_document(file_path: str) -> Dict[str, str]: + filename = os.path.basename(file_path) + base_name = os.path.splitext(filename)[0] + output_folder = os.path.join(TEXTS_DIR, base_name) + os.makedirs(output_folder, exist_ok=True) + + images = [] + if file_path.lower().endswith(".pdf"): + images = convert_from_path(file_path) + else: + images = [Image.open(file_path)] + + results = { + "tesseract": "", + "easyocr": "", + "paddleocr": "", + # "mmocr": "" + } + + for i, image in enumerate(images): + temp_img_path = os.path.join(output_folder, f"page_{i}.png") + image.save(temp_img_path) + + results["tesseract"] += ocr_tesseract(image) + "\n" + results["easyocr"] += ocr_easyocr(temp_img_path) + "\n" + results["paddleocr"] += ocr_paddleocr(temp_img_path) + "\n" + # results["mmocr"] += ocr_mmocr(temp_img_path) + "\n" + + os.remove(temp_img_path) + + for engine, text in results.items(): + save_text_file(text, os.path.join(output_folder, f"{engine}.txt")) + + corrected = correct_text(results["tesseract"]) + save_text_file(corrected, os.path.join(output_folder, "corrigido.txt")) + results["corrigido"] = corrected + + return results diff --git a/app/templates/dashboard.html b/app/templates/dashboard.html new file mode 100644 index 0000000..a4f6e3c --- /dev/null +++ b/app/templates/dashboard.html @@ -0,0 +1,13 @@ + + + + + + Dashboard + + +

Bem-vindo ao Dashboard!

+

Usuário logado: {{ user_email }}

+ Sair + + diff --git a/app/templates/login.html b/app/templates/login.html new file mode 100644 index 0000000..6384905 --- /dev/null +++ b/app/templates/login.html @@ -0,0 +1,32 @@ + + + + + + Login + + + +
+

Login

+ + {% with messages = get_flashed_messages(with_categories=True) %} + {% if messages %} + {% for category, message in messages %} +
{{ message }}
+ {% endfor %} + {% endif %} + {% endwith %} + +
+ + + + + + + +
+
+ + diff --git a/requirements.txt b/requirements.txt index 9e4be8f..2ea97f6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,16 @@ attrs==25.1.0 blinker==1.9.0 click==8.1.8 +exceptiongroup==1.2.2 factory_boy==3.3.3 Faker==36.2.2 flasgger==0.9.7.1 Flask==3.1.0 +Flask-JWT-Extended==4.7.1 Flask-SQLAlchemy==3.1.1 Flask-Testing==0.8.1 greenlet==3.1.1 +importlib_metadata==8.6.1 iniconfig==2.0.0 itsdangerous==2.2.0 Jinja2==3.1.6 @@ -17,12 +20,15 @@ MarkupSafe==3.0.2 mistune==3.1.2 packaging==24.2 pluggy==1.5.0 +PyJWT==2.10.1 pytest==8.3.5 PyYAML==6.0.2 referencing==0.36.2 rpds-py==0.23.1 six==1.17.0 SQLAlchemy==2.0.38 +tomli==2.2.1 typing_extensions==4.12.2 tzdata==2025.1 Werkzeug==3.1.3 +zipp==3.21.0