File size: 4,888 Bytes
10d228a 6a9e928 10d228a f527499 10d228a 1b3ebf8 10d228a 1b3ebf8 10d228a f527499 1b3ebf8 f527499 10d228a 1b3ebf8 10d228a f527499 10d228a 1b3ebf8 10d228a 1b3ebf8 f527499 1b3ebf8 f527499 1b3ebf8 10d228a 1b3ebf8 f527499 10d228a 1b3ebf8 f527499 1b3ebf8 10d228a 1b3ebf8 10d228a 1b3ebf8 10d228a 1b3ebf8 10d228a 1b3ebf8 10d228a 1b3ebf8 6a9e928 f527499 1b3ebf8 f527499 6a9e928 1b3ebf8 f527499 10d228a 1b3ebf8 f527499 10d228a 1b3ebf8 10d228a 1b3ebf8 6d76bf1 1b3ebf8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | import re
import os
import tempfile
from datetime import datetime
from pypdf import PdfReader
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment
import gradio as gr
# --- CONFIGURAÇÕES SINDUSCON ---
LINHAS = [
"R 1-B (Res. Unifamiliar)", "R 1-N (Res. Unifamiliar)", "R 1-A (Res. Unifamiliar)",
"PP 4-B (Prédio Popular)", "PP 4-N (Prédio Popular)", "R 8-B (Res. Multifamiliar)",
"R 8-N (Res. Multifamiliar)", "R 8-A (Res. Multifamiliar)", "R 16-N (Res. Multifamiliar)",
"R 16-A (Res. Multifamiliar)", "PIS (Projeto Inter. Social)", "RP1Q (Residência Popular)",
"CAL 8-N (Com. Andar Livres)", "CAL 8-A (Com. Andar Livres)", "CSL 8-N (Com.Salas e Lojas)",
"CSL 8-A (Com.Salas e Lojas)", "CSL 16-N (Com.Salas e Lojas)", "CSL 16-A (Com.Salas e Lojas)",
"GI (Galpão Industrial)"
]
NUM_LINHAS = len(LINHAS)
MESES_PT = {i: m for i, m in enumerate(["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], 1)}
CINZA = PatternFill(start_color="D9D9D9", end_color="D9D9D9", fill_type="solid")
def limpar_e_converter(valor_str):
"""Converte string '1.234,56' ou '-0,45' em float."""
try:
# Remove pontos de milhar e troca vírgula por ponto
return float(valor_str.replace(".", "").replace(",", "."))
except:
return None
def processar_pdf_universal(arquivo_pdf, anos_retroativos):
if arquivo_pdf is None: return None, "Aguardando arquivo..."
log = []
dados_globais = {}
eh_porcentagem = False # Flag para detectar tipo de dado
try:
reader = PdfReader(arquivo_pdf.name)
ano_limite = datetime.now().year - anos_retroativos
for i, page in enumerate(reader.pages):
text = page.extract_text()
# Busca o ano na página
ano_match = re.search(r"(?:20)\d{2}", text)
if not ano_match: continue
ano_pag = int(ano_match.group(0))
if ano_pag < ano_limite: continue
# Detecta se é PDF de variação (geralmente contém o símbolo % no texto)
if "%" in text: eh_porcentagem = True
# REGEX UNIVERSAL: Pega números como 2.500,00 | 900,00 | 0,45 | -0,10
# Explicação: Sinal opcional | dígitos com pontos opcionais | vírgula | 2 decimais
padrao = r"-?\d{1,3}(?:\.\d{3})*,\d{2}"
valores_encontrados = re.findall(padrao, text)
valores_float = [limpar_e_converter(v) for v in valores_encontrados]
if not valores_float: continue
num_meses = len(valores_float) // NUM_LINHAS
if num_meses == 0: continue
for linha_idx in range(NUM_LINHAS):
for mes_off in range(num_meses):
pos = (linha_idx * num_meses) + mes_off
if pos < len(valores_float):
mes_idx = mes_off + 1
dados_globais[(linha_idx, f"{ano_pag}-{mes_idx:02d}")] = valores_float[pos]
log.append(f"Página {i+1} (Ano {ano_pag}) processada.")
if not dados_globais: return None, "Nenhum dado extraído."
# Gerar Excel
colunas = sorted(set(c for _, c in dados_globais.keys()))
wb = Workbook()
ws = wb.active
ws.title = "Dados CUB-RS"
# Cabeçalho
ws.append(["PROJETO-PADRÃO"] + [f"{MESES_PT[int(c.split('-')[1])]}/{c.split('-')[0]}" for c in colunas])
for l_idx, nome in enumerate(LINHAS):
row = [nome] + [dados_globais.get((l_idx, c)) for c in colunas]
ws.append(row)
if (l_idx // 3) % 2 == 0:
for c_idx in range(1, len(colunas) + 2):
ws.cell(row=ws.max_row, column=c_idx).fill = CINZA
# Formatação de Células
for r in range(2, ws.max_row + 1):
for c in range(2, ws.max_column + 1):
cell = ws.cell(r, c)
if eh_porcentagem:
cell.number_format = '0.00"%"'
else:
cell.number_format = '#,##0.00'
ws.column_dimensions['A'].width = 30
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx")
wb.save(temp_file.name)
tipo = "Variação (%)" if eh_porcentagem else "Valores (R$)"
return temp_file.name, f"Tipo detectado: {tipo}\n" + "\n".join(log)
except Exception as e:
return None, f"Erro: {str(e)}"
# Interface Gradio permanece a mesma...
demo = gr.Interface(
fn=processar_pdf_universal,
inputs=[gr.File(label="Suba o PDF (Valores ou Variação)"), gr.Slider(1, 25, 5, label="Anos")],
outputs=[gr.File(label="Download"), gr.Textbox(label="Log")],
title="🏗️ Extrator CUB-RS"
)
demo.launch() |