Compare commits

..

3 Commits
main ... ocr

Author SHA1 Message Date
8a68a6b652 ajustado 2025-05-26 19:47:39 -03:00
f0ea5b282b Ajustando telas de login 2025-05-12 16:27:47 -03:00
32e4770ac7 ocr 2025-04-14 21:13:40 -03:00
15 changed files with 211 additions and 246 deletions

View File

@ -1,25 +1,4 @@
from flask import Flask from flask import Flask
from app.database import db
# Importação dos blueprints
from app.routes.usuario import usuarios_bp
from app.routes.organizacao import organizacoes_bp
from app.routes.documentos import documentos_bp
def create_app():
app = Flask(__name__)
app.config.from_object("config")
# Inicializa a extensão SQLAlchemy
db.init_app(app)
# Registra os blueprints
app.register_blueprint(usuarios_bp)
app.register_blueprint(organizacoes_bp)
app.register_blueprint(documentos_bp)
return app
from flask import Flask
from flasgger import Swagger from flasgger import Swagger
from app.database import db from app.database import db
from app.models.user import User from app.models.user import User

49
app/app.py Normal file
View File

@ -0,0 +1,49 @@
from flask import Flask, render_template, request, redirect, url_for, session, flash
import os
app = Flask(__name__)
app.secret_key = 'segredo-super-seguro'
# Rota de login
@app.route('/', methods=['GET', 'POST'])
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
email = request.form['email']
password = request.form['password']
if email == 'admin@admin.com' and password == '123456':
session['user'] = 'Admin'
return redirect(url_for('dashboard'))
else:
flash('Credenciais inválidas.', 'danger')
return render_template('login.html')
# Rota protegida
@app.route('/dashboard')
def dashboard():
if 'user' not in session:
return redirect(url_for('login'))
return render_template('dashboard.html', user_name=session['user'])
# Rota de upload
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if 'user' not in session:
return redirect(url_for('login'))
if request.method == 'POST':
file = request.files['file']
if file:
filepath = os.path.join('uploads', file.filename)
os.makedirs('uploads', exist_ok=True)
file.save(filepath)
flash('Arquivo enviado com sucesso!', 'success')
return render_template('upload.html')
# Logout
@app.route('/logout')
def logout():
session.clear()
return redirect(url_for('login'))
if __name__ == '__main__':
app.run(debug=True, port=5003)

View File

@ -1,15 +0,0 @@
# documento.py
from app.database import db
import uuid
class Documento(db.Model): #
__tablename__ = 'documentos'
id = db.Column(db.UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, unique=True, nullable=False)
nome_arquivo = db.Column(db.String, nullable=False)
caminho_arquivo = db.Column(db.String, nullable=False)
usuario_id = db.Column(db.Integer, db.ForeignKey('usuario.id'), nullable=False)
criado_em = db.Column(db.DateTime(timezone=True), server_default=db.func.now(), nullable=False)
usuario = db.relationship('Usuario', back_populates='documentos')

View File

@ -1,13 +0,0 @@
from app.database import db
class Organizacao(db.Model):
__tablename__ = 'organizacao'
id = db.Column(db.Integer, primary_key=True,
autoincrement=True, unique=True)
nome = db.Column(db.String, nullable=False, unique=True)
criado_em = db.Column(db.DateTime(timezone=True),
server_default=db.func.now(), nullable=False)
usuarios = db.relationship('Usuario', back_populates='organizacao')

View File

@ -1,24 +0,0 @@
# usuario.py
from app.database import db
class Usuario(db.Model):
__tablename__ = 'usuario'
id = db.Column(db.Integer, primary_key=True,
autoincrement=True, unique=True)
nome = db.Column(db.String, nullable=False)
email = db.Column(db.String, nullable=False, unique=True)
senha_hash = db.Column(db.String, nullable=False)
organizacao_id = db.Column(db.Integer, db.ForeignKey(
'organizacao.id'), nullable=False)
criado_em = db.Column(db.DateTime(timezone=True),
server_default=db.func.now(), nullable=False)
atualizado_em = db.Column(db.DateTime(
timezone=True), onupdate=db.func.now())
organizacao = db.relationship('Organizacao', back_populates='usuarios')
documentos = db.relationship('Documento', back_populates='usuario')
def __repr__(self):
return f'<Usuario {self.nome}>'

View File

@ -1,44 +0,0 @@
from flask import Blueprint, request, jsonify
from app.database import db
from app.models import Documento
documentos_bp = Blueprint('documentos', __name__, url_prefix='/documentos')
@documentos_bp.route('/', methods=['GET'])
def get_documentos():
documentos = Documento.query.all()
documentos_data = [
{
'id': str(doc.id),
'nome_arquivo': doc.nome_arquivo,
'caminho_arquivo': doc.caminho_arquivo,
'usuario_id': doc.usuario_id,
'criado_em': doc.criado_em
}
for doc in documentos
]
return jsonify(documentos_data), 200
@documentos_bp.route('/', methods=['POST'])
def create_documento():
data = request.get_json()
if not all(k in data for k in ('nome_arquivo', 'caminho_arquivo', 'usuario_id')):
return jsonify({'error': 'Campos obrigatórios ausentes'}), 400
try:
novo_documento = Documento(
nome_arquivo=data['nome_arquivo'],
caminho_arquivo=data['caminho_arquivo'],
usuario_id=data['usuario_id']
)
db.session.add(novo_documento)
db.session.commit()
return jsonify({
'message': 'documento criado com sucesso',
'id': str(novo_documento.id)
}), 201
except Exception as e:
db.session.rollback()
return jsonify({'error': str(e)}), 500

View File

@ -1,43 +0,0 @@
from flask import Blueprint, request, jsonify
from app.database import db
from app.models import Organizacao # ajuste conforme sua estrutura
organizacoes_bp = Blueprint(
'organizacoes', __name__, url_prefix='/organizacoes')
@organizacoes_bp.route('/', methods=['GET'])
def get_organizacoes():
organizacoes = Organizacao.query.all()
data = [
{
'id': org.id,
'nome': org.nome,
'criado_em': org.criado_em
}
for org in organizacoes
]
return jsonify(data), 200
@organizacoes_bp.route('/', methods=['POST'])
def create_organizacao():
data = request.get_json()
if not data or 'nome' not in data:
return jsonify({'error': 'O campo "nome" é obrigatório'}), 400
if Organizacao.query.filter_by(nome=data['nome']).first():
return jsonify({'error': 'Já existe uma organização com este nome'}), 409
try:
nova_org = Organizacao(nome=data['nome'])
db.session.add(nova_org)
db.session.commit()
return jsonify({
'message': 'Organização criada com sucesso',
'id': nova_org.id
}), 201
except Exception as e:
db.session.rollback()
return jsonify({'error': str(e)}), 500

View File

@ -1,44 +0,0 @@
from flask import Blueprint, request, jsonify
from app.database import db
from app.models.usuario import Usuario # nome correto do modelo
usuarios_bp = Blueprint('usuarios', __name__, url_prefix='/usuarios')
@usuarios_bp.route('/', methods=['GET'])
def get_usuarios():
usuarios = Usuario.query.all()
usuarios_data = [
{
'id': usuario.id,
'nome': usuario.nome,
'email': usuario.email,
'organizacao_id': usuario.organizacao_id,
'criado_em': usuario.criado_em,
'atualizado_em': usuario.atualizado_em
}
for usuario in usuarios
]
return jsonify(usuarios_data), 200
@usuarios_bp.route('/', methods=['POST'])
def create_usuario():
data = request.get_json()
if not all(k in data for k in ('nome', 'email', 'senha_hash', 'organizacao_id')):
return jsonify({'error': 'Campos obrigatórios ausentes'}), 400
if Usuario.query.filter_by(email=data['email']).first():
return jsonify({'error': 'E-mail já está em uso'}), 409
novo_usuario = Usuario(
nome=data['nome'],
email=data['email'],
senha_hash=data['senha_hash'],
organizacao_id=data['organizacao_id']
)
db.session.add(novo_usuario)
db.session.commit()
return jsonify({'message': 'Usuário criado com sucesso', 'id': novo_usuario.id}), 201

View File

@ -0,0 +1,72 @@
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]:
"""
Processa um arquivo PDF ou imagem, aplica OCR com diferentes engines e salva os textos extraídos.
Retorna os textos por engine e o texto corrigido.
Args:
file_path (str): Caminho do arquivo a ser processado.
Returns:
Dict[str, str]: Dicionário com os textos por engine e o texto corrigido.
"""
try:
if not os.path.exists(file_path):
raise FileNotFoundError(f"Arquivo não encontrado: {file_path}")
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)
# Converte PDF para imagens ou carrega imagem única
images = convert_from_path(file_path) if file_path.lower().endswith(".pdf") else [Image.open(file_path)]
results = {
"tesseract": "",
"easyocr": "",
"paddleocr": "",
# "mmocr": ""
}
# Processa cada página/imagem
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)
# Salva os textos extraídos
for engine, text in results.items():
save_text_file(text, os.path.join(output_folder, f"{engine}.txt"))
# Aplica correção no texto do tesseract
corrected = correct_text(results["tesseract"])
save_text_file(corrected, os.path.join(output_folder, "corrigido.txt"))
results["corrigido"] = corrected
return results
except Exception as e:
print(f"[ERRO] Falha ao processar documento: {e}")
return {"error": str(e)}

27
app/statics/css/style.css Normal file
View File

@ -0,0 +1,27 @@
body {
background-color: #f8f9fa;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
h3 {
color: #343a40;
}
form {
background: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 0px 3px 10px rgba(0, 0, 0, 0.1);
}
.navbar-brand {
font-weight: bold;
}
button.btn {
transition: background-color 0.3s ease;
}
button.btn:hover {
opacity: 0.9;
}

21
app/templates/base.html Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<title>{% block title %}OCR App{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark px-4">
<a class="navbar-brand" href="#">OCR App</a>
</nav>
<div class="container mt-4">
{% block content %}{% endblock %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -1,13 +1,9 @@
<!DOCTYPE html> {% extends "base.html" %}
<html lang="pt">
<head> {% block title %}Dashboard - OCR App{% endblock %}
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> {% block content %}
<title>Dashboard</title> <h3>Bem-vindo(a), {{ user_name }}</h3>
</head> <p>Escolha uma ação no menu ou envie um novo documento para OCR.</p>
<body> <a href="/upload" class="btn btn-outline-primary">Enviar novo documento</a>
<h1>Bem-vindo ao Dashboard!</h1> {% endblock %}
<p>Usuário logado: {{ user_email }}</p>
<a href="{{ url_for('login_form.login') }}">Sair</a>
</body>
</html>

View File

@ -1,32 +1,22 @@
<!DOCTYPE html> {% extends "base.html" %}
<html lang="pt">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="login-container">
<h2>Login</h2>
{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
<form method="POST"> {% block title %}Login - OCR App{% endblock %}
<label for="email">E-mail:</label>
<input type="email" name="email" required>
<label for="password">Senha:</label> {% block content %}
<input type="password" name="password" required> <div class="row justify-content-center">
<div class="col-md-4">
<button type="submit">Entrar</button> <h3 class="mb-4">Login</h3>
<form method="POST" action="/login">
<div class="mb-3">
<label>Email:</label>
<input type="email" name="email" class="form-control" required>
</div>
<div class="mb-3">
<label>Senha:</label>
<input type="password" name="password" class="form-control" required>
</div>
<button class="btn btn-primary w-100" type="submit">Entrar</button>
</form> </form>
</div> </div>
</body> </div>
</html> {% endblock %}

14
app/templates/upload.html Normal file
View File

@ -0,0 +1,14 @@
{% extends "base.html" %}
{% block title %}Upload de Arquivo - OCR App{% endblock %}
{% block content %}
<h3>Upload de Documento</h3>
<form method="POST" action="/upload" enctype="multipart/form-data">
<div class="mb-3">
<label for="file" class="form-label">Selecionar Arquivo</label>
<input class="form-control" type="file" id="file" name="file" accept=".pdf,.jpg,.png,.jpeg" required>
</div>
<button class="btn btn-success" type="submit">Enviar</button>
</form>
{% endblock %}

2
run.py
View File

@ -10,4 +10,4 @@ if __name__ == "__main__":
create_default_user() create_default_user()
print("Banco de dados criado com sucesso!") print("Banco de dados criado com sucesso!")
app.run(debug=True) app.run(debug=True, port=5003)