#!/usr/bin/env python3 """ scripts/build_chunks.py Constroi chunks de texto da NT-01/2025 para o sistema RAG do Agente CBMGO Suporta: extracao de PDF, chunks sinteticos e base de conhecimento embutida """ import json import re import argparse from pathlib import Path # ============================================================================= # BASE DE CONHECIMENTO NT-01/2025 EMBUTIDA # ============================================================================= NT01_CONHECIMENTO = [ { "id": "nt01_objetivo", "section": "Art. 1 - Objetivo e Aplicacao", "text": "A NT-01/2025 estabelece criterios para classificacao das edificacoes quanto a ocupacao, altura, area construida e caracteristicas construtivas para aplicacao das medidas de seguranca contra incendio pelo CBMGO. Aplica-se a edificacoes novas, ampliacao, reforma ou mudanca de uso no Estado de Goias conforme Lei Estadual 15.802/2006." }, { "id": "nt01_grupo_A", "section": "Tabela 1 - Divisao A: Residencial", "text": "GRUPO A-1 Residencial unifamiliar: casa, sobrado, chale. GRUPO A-2 Residencial multifamiliar: apartamento, flat, kitnet, condominio. Caracteristica: uso exclusivamente residencial permanente. Risco: baixo. Exigencias minimas: extintores, saidas de emergencia, sinalizacao." }, { "id": "nt01_grupo_B", "section": "Tabela 1 - Divisao B: Hospedagem", "text": "GRUPO B-1 Hospedagem transitoria: hotel, motel, pousada, hostel. GRUPO B-2 Hospedagem longa permanencia: apart-hotel, residencial senior. Caracteristica: populacao flutuante e dificuldade de evacuacao noturna. Exigencias: extintores, hidrantes (acima 750m2), iluminacao emergencia, alarme." }, { "id": "nt01_grupo_C", "section": "Tabela 1 - Divisao C: Comercial", "text": "GRUPO C-1 Comercio pequeno porte (ate 750m2): loja, farmacia, padaria, sapataria. GRUPO C-2 Comercio medio/grande porte (acima 750m2): supermercado, shopping center, hipermercado. Risco: medio. Exigencias: extintores, hidrantes obrigatorios C-2, rotas evacuacao, brigada acima 750m2." }, { "id": "nt01_grupo_D", "section": "Tabela 1 - Divisao D: Reuniao de Publico", "text": "GRUPO D-1 Esporte e lazer: ginasio, estadio, arena. GRUPO D-2 Cultura e religiao: teatro, cinema, igreja, museu. GRUPO D-3 Ensino: escola, universidade, creche. Caracteristica: alta densidade de ocupacao. Risco: medio a alto. Exigencias rigorosas para evacuacao rapida." }, { "id": "nt01_grupo_E", "section": "Tabela 1 - Divisao E: Saude", "text": "GRUPO E-1 Saude e assistencia: hospital, clinica, UBS, casa de repouso, abrigo. Caracteristica: pacientes com mobilidade reduzida necessitam evacuacao assistida. Risco especial. Exigencias: sprinklers, alarme, brigada treinada, area de refugio, sistema de hidrantes." }, { "id": "nt01_grupo_F", "section": "Tabela 1 - Divisao F: Servicos", "text": "GRUPO F-1 Servico profissional: escritorio, banco, consultorio, salon. GRUPO F-2 Transporte: aeroporto, rodoviaria, terminal. Risco: baixo a medio. Extintores obrigatorios, iluminacao emergencia acima de 200m2, sinalizacao conforme NBR 13434." }, { "id": "nt01_grupo_G", "section": "Tabela 1 - Divisao G: Automotivo", "text": "GRUPO G-1 Servicos automotivos: garagem, estacionamento coberto, posto de combustivel, oficina. Caracteristica: presenca de combustiveis inflamaveis. Risco: medio a alto. Exigencias: extintores especificos, ventilacao, detector de gas, distancias de seguranca." }, { "id": "nt01_grupo_H", "section": "Tabela 1 - Divisao H: Industrial", "text": "GRUPO H-1 Industrial baixo risco (ate 500 MJ/m2): alimenticio, textil. GRUPO H-2 Industrial medio risco (500-1000 MJ/m2): metalurgica, moveleira. GRUPO H-3 Industrial alto risco (acima 1000 MJ/m2): quimica, petroquimica. Brigada obrigatoria, sprinklers H-2 e H-3." }, { "id": "nt01_grupo_I", "section": "Tabela 1 - Divisao I: Deposito", "text": "GRUPO I-1 Deposito baixo risco: arquivo, papel, cereais. GRUPO I-2 Deposito medio risco: madeira, borracha. GRUPO I-3 Deposito alto risco: liquidos inflamaveis, produtos quimicos. Carga de incendio elevada. Sprinklers obrigatorios I-2 acima 750m2, I-3 sempre." }, { "id": "nt01_extintores", "section": "Extintores de Incendio - NT-01/2025 e NBR 12693", "text": "Extintores obrigatorios em todas edificacoes. Calculo por risco: BAIXO (A,B,F) = 1 extintor a cada 500m2; MEDIO (C,D,G) = 1 extintor a cada 250m2; ALTO (H,I,J) = 1 extintor a cada 150m2. Minimo: 2 extintores por pavimento. Tipo ABC (po quimico) para uso geral. Manutencao anual obrigatoria. Sinalizar conforme NBR 13434." }, { "id": "nt01_hidrantes", "section": "Sistema de Hidrantes - NT-01/2025 e NBR 13714", "text": "Hidrantes obrigatorios: area acima 750m2 ou altura acima 12m (aprox 4 pavimentos). Pressao minima: 10 m.c.a. Vazao minima: 300 L/min. Mangueira DN 65mm (externa), DN 40mm (interna). Distancia maxima entre hidrantes: 30m. Reservatorio tecnico de incendio (RTI) obrigatorio. Manutencao semestral." }, { "id": "nt01_spda", "section": "SPDA - Sistema de Protecao contra Descargas Atmosfericas - NBR 5419", "text": "SPDA obrigatorio: altura acima 15m ou area acima 1000m2 ou densidade de raios elevada. Projeto por engenheiro eletricista. Tipos: Franklin (captores), Gaiola Faraday, ESE (nao reconhecido NBR). Aterramento conforme NBR 5419. Manutencao anual." }, { "id": "nt01_saidas", "section": "Saidas de Emergencia - NBR 9077", "text": "Largura minima: 1,10m para ate 60 pessoas + 0,55m por 60 pessoas. Portas abertura no sentido do escape. Escadas: enclausuradas acima de 2 pavimentos (H>9m). Distancia maxima percorrida: 30m risco baixo / 20m risco alto. Rampas: inclinacao maxima 1:8 (12,5%). Portas corta-fogo: nas escadas enclausuradas." }, { "id": "nt01_iluminacao", "section": "Iluminacao de Emergencia - NBR 10898", "text": "Iluminacao emergencia obrigatoria: edificacoes acima 200m2 ou acima 1 pavimento. Autonomia minima: 1 hora. Nivel de iluminamento: 30 lux nas rotas de saida, 15 lux demais areas. Blocos autonomos com bateria selada. Teste mensal e semestral obrigatorios. Instalar em: corredores, escadas, saidas." }, { "id": "nt01_sinalizacao", "section": "Sinalizacao de Seguranca - NBR 13434", "text": "Sinalizacao obrigatoria em todas edificacoes. Categorias: saida de emergencia (verde), equipamentos de combate (vermelho), riscos especificos (amarelo), orientacao/salvamento (verde). Fotoluminescencia em rotas de evacuacao. Altura de fixacao: 1,80m a 2,10m do piso. Manutencao trimestral." }, { "id": "nt01_brigada", "section": "Brigada de Incendio - NBR 14276", "text": "Brigada obrigatoria: area acima 750m2 ou lotacao acima 100 pessoas. Composicao: brigadistas treinados em prevencao, primeiros socorros e evacuacao. Reciclagem anual. Numero de brigadistas: 5% da populacao (minimo 2 por pavimento). Lider de brigada: supervisor certificado. Simulacros anuais." }, { "id": "nt01_sprinklers", "section": "Sprinklers - Sistema Automatico de Supressao - NBR 10897", "text": "Sprinklers obrigatorios: residencial acima 30m altura, comercial acima 12m, industrial H-2 e H-3 acima 750m2, deposito I-2 acima 750m2, deposito I-3 sempre. Temperatura de acionamento: 57-79 graus C (padrao). Densidade de descarga conforme risco. Reservatorio dedicado obrigatorio." }, { "id": "nt01_alarme", "section": "Sistema de Deteccao e Alarme - NBR 17240 e NBR 9441", "text": "Alarme obrigatorio: hospitais, hoteis acima 750m2, escritorios acima 1500m2, industrias H-3, depositos I-3. Detectores de fumaca (ionicos ou fotoeletricos). Central de alarme incendio (CAIG). Acionadores manuais em rotas de saida. Aviso sonoro minimo 65 dB. Manutencao trimestral." }, { "id": "nt01_ppci", "section": "PPCI - Plano de Prevencao contra Incendio e Panico", "text": "PPCI obrigatorio para todas edificacoes antes de ocupar. Elaborado por Engenheiro (CREA) ou Arquiteto (CAU) com ART/RRT. Conteudo: memorial descritivo, calculos, plantas (baixa, cortes, fachadas), especificacoes tecnicas. Aprovacao pelo CBMGO antes inicio obras. Renovacao: 3 anos (baixo risco) ou 1 ano (alto risco). Taxas: DARM - CBMGO." }, { "id": "nt01_altura", "section": "Altura da Edificacao - Definicao NT-01/2025", "text": "Altura medida do nivel do passeio publico ate o piso do ultimo pavimento habitavel. Excluem-se: tico, cobertura, pavimento tecnico, casa de maquinas. Para edificacoes em terreno inclinado: considera-se o ponto de acesso do veiculo do Corpo de Bombeiros. Altura influencia: tipo de escada, sistemas obrigatorios." }, { "id": "nt01_carga_incendio", "section": "Carga de Incendio Especifica", "text": "Carga de incendio especifica (MJ/m2) determinada pelo uso: Residencial/Escritorio = 500 MJ/m2; Comercio = 750 MJ/m2; Industrial baixo = 500 MJ/m2; Industrial medio = 1000 MJ/m2; Industrial alto = 2000 MJ/m2; Deposito = variavel conforme material. Influencia na determinacao do tipo de estrutura resistente ao fogo." }, ] def extrair_texto_pdf(pdf_path): """Extrai texto de PDF da NT-01/2025""" try: import pypdf texto = "" with open(pdf_path, "rb") as f: reader = pypdf.PdfReader(f) for page in reader.pages: texto += page.extract_text() + "\n" return texto except ImportError: print("[WARN] pypdf nao instalado. Use: pip install pypdf") return None except Exception as e: print(f"[ERRO] Erro ao ler PDF: {e}") return None def chunkar_texto(texto, chunk_size=500, overlap=50): """Divide texto em chunks com sobreposicao""" palavras = texto.split() chunks = [] i = 0 while i < len(palavras): chunk_palavras = palavras[i:i + chunk_size] chunk_texto = " ".join(chunk_palavras) chunks.append({ "id": f"pdf_chunk_{len(chunks):04d}", "section": f"Chunk {len(chunks)+1} (PDF)", "text": chunk_texto }) i += chunk_size - overlap return chunks def gerar_chunks_sinteticos(): """Gera chunks sinteticos baseados na base de conhecimento embutida""" chunks = [] for item in NT01_CONHECIMENTO: chunks.append({ "id": item["id"], "source": "NT-01/2025 CBMGO", "section": item["section"], "text": item["text"], "tokens_estimados": len(item["text"].split()) }) return chunks def salvar_chunks(chunks, output_path): """Salva chunks em formato JSONL""" with open(output_path, "w", encoding="utf-8") as f: for chunk in chunks: f.write(json.dumps(chunk, ensure_ascii=False) + "\n") print(f"Chunks salvos: {output_path} ({len(chunks)} chunks)") return output_path def main(): parser = argparse.ArgumentParser(description="Construtor de chunks NT-01/2025 para RAG") parser.add_argument("--pdf", type=str, help="Caminho para o PDF da NT-01/2025 (opcional)") parser.add_argument("--synthetic", action="store_true", help="Usar base de conhecimento sintetica") parser.add_argument("--output", type=str, default="data", help="Diretorio de saida") parser.add_argument("--chunk-size", type=int, default=500, help="Tamanho do chunk em palavras") args = parser.parse_args() Path(args.output).mkdir(parents=True, exist_ok=True) output_file = Path(args.output) / "chunks.jsonl" if args.pdf: print(f"Extraindo texto do PDF: {args.pdf}") texto = extrair_texto_pdf(args.pdf) if texto: chunks = chunkar_texto(texto, chunk_size=args.chunk_size) print(f"Extraidos {len(chunks)} chunks do PDF") else: print("Falha na extracao do PDF. Usando base sintetica.") chunks = gerar_chunks_sinteticos() else: print("Usando base de conhecimento embutida NT-01/2025") chunks = gerar_chunks_sinteticos() salvar_chunks(chunks, output_file) print(f"\nTotal: {len(chunks)} chunks salvos em {output_file}") print("Execute scripts/build_embeddings.py para construir o indice FAISS") if __name__ == "__main__": main()