| | 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 |
| |
|
| | |
| | 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: |
| | |
| | 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 |
| | |
| | try: |
| | reader = PdfReader(arquivo_pdf.name) |
| | ano_limite = datetime.now().year - anos_retroativos |
| | |
| | for i, page in enumerate(reader.pages): |
| | text = page.extract_text() |
| | |
| | |
| | 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 |
| | |
| | |
| | if "%" in text: eh_porcentagem = True |
| | |
| | |
| | |
| | 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." |
| |
|
| | |
| | colunas = sorted(set(c for _, c in dados_globais.keys())) |
| | wb = Workbook() |
| | ws = wb.active |
| | ws.title = "Dados CUB-RS" |
| | |
| | |
| | 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 |
| |
|
| | |
| | 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)}" |
| |
|
| | |
| | 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() |