Compare commits

..

2 Commits
ocr ... main

Author SHA1 Message Date
67fae641a3 Models Asafe 2025-05-22 20:23:14 -04:00
9e9d8958c1 Template MVC básico com Jinja 2025-04-03 11:59:32 -04:00
15 changed files with 246 additions and 211 deletions

View File

@ -1,4 +1,25 @@
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 app.database import db
from app.models.user import User

View File

@ -1,49 +0,0 @@
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)

15
app/models/Documento.py Normal file
View File

@ -0,0 +1,15 @@
# 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')

13
app/models/Organizacao.py Normal file
View File

@ -0,0 +1,13 @@
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')

24
app/models/usuario.py Normal file
View File

@ -0,0 +1,24 @@
# 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}>'

44
app/routes/documentos.py Normal file
View File

@ -0,0 +1,44 @@
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

43
app/routes/organizacao.py Normal file
View File

@ -0,0 +1,43 @@
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

44
app/routes/usuario.py Normal file
View File

@ -0,0 +1,44 @@
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

@ -1,72 +0,0 @@
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)}

View File

@ -1,27 +0,0 @@
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;
}

View File

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

View File

@ -1,22 +1,32 @@
{% extends "base.html" %}
<!DOCTYPE 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 %}
{% block title %}Login - OCR App{% endblock %}
<form method="POST">
<label for="email">E-mail:</label>
<input type="email" name="email" required>
{% block content %}
<div class="row justify-content-center">
<div class="col-md-4">
<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>
<label for="password">Senha:</label>
<input type="password" name="password" required>
<button type="submit">Entrar</button>
</form>
</div>
</div>
{% endblock %}
</body>
</html>

View File

@ -1,14 +0,0 @@
{% 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()
print("Banco de dados criado com sucesso!")
app.run(debug=True, port=5003)
app.run(debug=True)