| |
| """ |
| 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 |
|
|
| |
| |
| |
|
|
| 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() |
|
|