CERCON / scripts /build_chunks.py
carlosh10's picture
fix: Adiciona conteudo completo do build_chunks.py com NT-01/2025
473972a verified
#!/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()