carlosh10 commited on
Commit
2ac47b0
·
verified ·
1 Parent(s): 16e2ec0

feat: Adiciona gerador de memorial descritivo PSCIP

Browse files
Files changed (1) hide show
  1. modules/memorial_generator.py +253 -0
modules/memorial_generator.py ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Gerador de Memorial Descritivo - PSCIP NT-01/2025 CBMGO
3
+ Gera texto estruturado do memorial com todos os sistemas exigidos.
4
+ Com LLM (cbmgo/memorial-generator) ou template local (fallback).
5
+ """
6
+ import os
7
+ import re
8
+ from datetime import datetime
9
+ from typing import Dict, List
10
+
11
+ try:
12
+ from transformers import pipeline
13
+ HAS_TRANSFORMERS = True
14
+ except ImportError:
15
+ HAS_TRANSFORMERS = False
16
+
17
+
18
+ class MemorialGenerator:
19
+ """
20
+ Gerador de memorial descritivo para projetos PSCIP.
21
+ Usa LLM fine-tunado ou template estruturado como fallback.
22
+ """
23
+
24
+ def __init__(self, model_id="cbmgo/memorial-generator", use_llm=False):
25
+ self.model_id = model_id
26
+ self.use_llm = use_llm and HAS_TRANSFORMERS
27
+ self._pipe = None
28
+
29
+ def _load_llm(self):
30
+ if self._pipe is None and self.use_llm:
31
+ print(f"Carregando modelo: {self.model_id}")
32
+ self._pipe = pipeline("text-generation", model=self.model_id,
33
+ device_map="auto", max_new_tokens=1500, temperature=0.2)
34
+
35
+ def gerar_llm(self, dados: Dict) -> str:
36
+ self._load_llm()
37
+ prompt = self._montar_prompt_llm(dados)
38
+ saida = self._pipe(prompt)[0]["generated_text"]
39
+ # Extrair apenas a parte gerada (apos o prompt)
40
+ if "MEMORIAL DESCRITIVO" in saida:
41
+ idx = saida.find("MEMORIAL DESCRITIVO")
42
+ return saida[idx:]
43
+ return saida
44
+
45
+ def _montar_prompt_llm(self, d: Dict) -> str:
46
+ exig = ", ".join(d.get("exigencias", []))
47
+ return f"""Gere memorial descritivo completo de prevencao de incendio:
48
+
49
+ Edificacao: {d.get("nome_edificacao","Edificio")}
50
+ Uso/Ocupacao: {d.get("ocupacao","comercial")}
51
+ Grupo NT-01: {d.get("grupo","D")} | Divisao: {d.get("divisao","D-1")}
52
+ Area total: {d.get("area_m2",0):.1f} m2
53
+ Altura: {d.get("altura_m",0):.1f} m
54
+ Numero de pavimentos: {d.get("pavimentos",1)}
55
+ Lotacao estimada: {d.get("lotacao",50)} pessoas
56
+ Sistemas exigidos: {exig}
57
+
58
+ MEMORIAL DESCRITIVO - PSCIP:"""
59
+
60
+ def gerar_template(self, dados: Dict) -> str:
61
+ """Gera memorial usando template estruturado (sem LLM)."""
62
+ d = dados
63
+ nome = d.get("nome_edificacao", "Edificacao")
64
+ ocupacao = d.get("ocupacao", "Comercial").title()
65
+ grupo = d.get("grupo", "D")
66
+ divisao = d.get("divisao", "D-1")
67
+ area = d.get("area_m2", 0)
68
+ altura = d.get("altura_m", 0)
69
+ pavimentos = d.get("pavimentos", 1)
70
+ lotacao = d.get("lotacao", 0)
71
+ exigencias = d.get("exigencias", [])
72
+ qtd_ext = d.get("qtd_extintores", max(1, int(area / 400)))
73
+ cap_ext = d.get("capacidade_extintor", "2-A:20-B:C")
74
+ sist_hid = d.get("sistema_hidrante", "Coluna Seca")
75
+ vazao = d.get("vazao_lpm", 300)
76
+ reserva = d.get("reserva_m3", round(vazao * 60 / 1000, 1))
77
+ rt_nome = d.get("rt_nome", "___________________________")
78
+ rt_crea = d.get("rt_crea", "_______________")
79
+ data_hoje = datetime.now().strftime("%d/%m/%Y")
80
+
81
+ # Construir secoes condicionalmente
82
+ sec_ilum = ""
83
+ if "iluminacao_emergencia" in exigencias:
84
+ sec_ilum = f"""
85
+ 6. ILUMINACAO DE EMERGENCIA
86
+ Sistema de iluminacao de emergencia instalado nas rotas de fuga,
87
+ saidas de emergencia e areas criticas.
88
+ - Autonomia minima: 1 (uma) hora
89
+ - Nivel de iluminamento rota de fuga: >= 3 lux
90
+ - Nivel de iluminamento areas de acesso: >= 10 lux
91
+ - Blocos autonomos com bateria selada, recarregavel
92
+ - Conforme ABNT NBR 10898
93
+ Ref: NT-01/2025 CBMGO Art. 20
94
+ """
95
+
96
+ sec_spda = ""
97
+ if "spda" in exigencias:
98
+ sec_spda = f"""
99
+ 7. SPDA - SISTEMA DE PROTECAO CONTRA DESCARGAS ATMOSFERICAS
100
+ SPDA obrigatorio para esta edificacao (area > 1.000m2).
101
+ - Nivel de protecao: a definir conforme ABNT NBR 5419
102
+ - Sistema captacao, descida e aterramento independente
103
+ - Projeto especifico assinado por profissional habilitado
104
+ Ref: NT-01/2025 CBMGO Art. 25 | ABNT NBR 5419
105
+ """
106
+
107
+ sec_alarme = ""
108
+ if "alarme_incendio" in exigencias:
109
+ sec_alarme = f"""
110
+ 8. SISTEMA DE ALARME E DETECCAO DE INCENDIO
111
+ Sistema de alarme de incendio com:
112
+ - Central de alarme endereçavel
113
+ - Acionadores manuais nas saidas de emergencia (espacamento <= 30m)
114
+ - Detectores de fumaca nos ambientes cobertos
115
+ - Sirenes audiovisuais
116
+ Conforme ABNT NBR 17240
117
+ Ref: NT-01/2025 CBMGO Art. 22
118
+ """
119
+
120
+ sec_chuveiros = ""
121
+ if "chuveiros_automaticos" in exigencias:
122
+ sec_chuveiros = f"""
123
+ 9. SISTEMA DE CHUVEIROS AUTOMATICOS (SPRINKLERS)
124
+ Sistema de chuveiros automaticos cobrindo toda a area edificada.
125
+ - Tipo: Resposta rapida, temperatura de ativacao 68 graus C
126
+ - Densidade minima: 5 mm/min
127
+ - Area de atuacao: 144 m2
128
+ - Reservatorio exclusivo para incendio
129
+ Conforme ABNT NBR 10897
130
+ Ref: NT-01/2025 CBMGO
131
+ """
132
+
133
+ memorial = f"""MEMORIAL DESCRITIVO
134
+ SISTEMA DE PREVENCAO E COMBATE A INCENDIO E PANICO - PSCIP
135
+
136
+ Data de elaboracao: {data_hoje}
137
+ Referencia normativa principal: NT-01/2025 - Procedimentos Administrativos CBMGO
138
+
139
+ ============================================================
140
+ 1. IDENTIFICACAO DA EDIFICACAO
141
+ ============================================================
142
+ Denominacao: {nome}
143
+ Uso/Ocupacao: {ocupacao}
144
+ Classificacao NT-01/2025: Grupo {grupo} - Divisao {divisao}
145
+ Endereco: _______________________________________________
146
+ Area total construida: {area:.2f} m2
147
+ Altura da edificacao: {altura:.2f} m
148
+ Numero de pavimentos: {pavimentos}
149
+ Lotacao maxima estimada: {lotacao} pessoas
150
+
151
+ ============================================================
152
+ 2. BASE LEGAL E NORMATIVA
153
+ ============================================================
154
+ - NT-01/2025 - Procedimentos Administrativos - CBMGO
155
+ - ABNT NBR 12693:2013 - Sistemas de protecao por extintores
156
+ - ABNT NBR 13714:2003 - Sistemas de hidrantes e mangotinhos
157
+ - ABNT NBR 13434:2004 - Sinalizacao de seguranca contra incendio
158
+ - ABNT NBR 10898:2013 - Iluminacao de emergencia
159
+ - ABNT NBR 5419:2015 - SPDA
160
+ - ABNT NBR 17240:2010 - Deteccao e alarme de incendio
161
+ - ABNT NBR 9077:2001 - Saidas de emergencia
162
+ - Codigo de Obras e Postura Municipal vigente
163
+
164
+ ============================================================
165
+ 3. SISTEMAS DE PROTECAO EXIGIDOS
166
+ ============================================================
167
+ Conforme classificacao Grupo {grupo} - NT-01/2025, para edificacao
168
+ com area de {area:.0f} m2 e altura de {altura:.1f} m, sao exigidos os
169
+ seguintes sistemas de protecao:
170
+ {chr(10).join([' - ' + e.replace('_',' ').title() for e in exigencias])}
171
+
172
+ ============================================================
173
+ 4. EXTINTORES PORTATEIS
174
+ ============================================================
175
+ Quantidade minima instalada: {qtd_ext} (unidades)
176
+ Capacidade extintora: {cap_ext}
177
+ Distribuicao: instalados em locais visiveis, sinalizados e de
178
+ facil acesso, com distancia maxima de 15 metros entre eles.
179
+ Altura de instalacao: entre 1,0m e 1,60m do piso ao manometro.
180
+ Manutencao: anual conforme ABNT NBR 12962.
181
+ Conforme ABNT NBR 12693 e NT-01/2025 Anexo B - Grupo {grupo.upper()}
182
+
183
+ ============================================================
184
+ 5. SISTEMA DE HIDRANTES E MANGOTINHOS
185
+ ============================================================
186
+ Sistema instalado: {sist_hid}
187
+ Vazao minima: {vazao} L/min por hidrante
188
+ Pressao dinamica minima: 15 mca no hidrante mais desfavoravel
189
+ Reserva tecnica de incendio: {reserva} m3 (exclusiva para incendio)
190
+ Tubulacao: aco galvanizado/PRFV, DN 65mm (rede principal)
191
+ Registro de recalque externo para CBMGO
192
+ Conforme ABNT NBR 13714 e NT-01/2025 Art. 18
193
+ {sec_ilum}{sec_spda}{sec_alarme}{sec_chuveiros}
194
+ ============================================================
195
+ {len([e for e in exigencias if e not in ['iluminacao_emergencia','spda','alarme_incendio','chuveiros_automaticos']]) + 6}. SINALIZACAO DE EMERGENCIA
196
+ ============================================================
197
+ Sinalizacao fotoluminescente instalada em:
198
+ - Saidas de emergencia (indicacao de saida e seta direcional)
199
+ - Rotas de fuga em todos os corredores
200
+ - Localizacao dos extintores e hidrantes
201
+ - Instrucoes de emergencia e prohibicoes
202
+ - Planta de localizacao com rotas de evacuacao
203
+ Conforme ABNT NBR 13434 Partes 1, 2 e 3
204
+
205
+ ============================================================
206
+ ASSINATURAS
207
+ ============================================================
208
+
209
+ Responsavel Tecnico: {rt_nome}
210
+ CREA/CAU N.: {rt_crea}
211
+ Empresa: _____________________________________________
212
+ Data: {data_hoje}
213
+
214
+ Profissional habilitado conforme resolucao CONFEA/CREA.
215
+ Este memorial e parte integrante do projeto de PSCIP e
216
+ deve ser lido em conjunto com as pranchas tecnicas.
217
+
218
+ ============================================================
219
+ FIM DO MEMORIAL DESCRITIVO
220
+ ============================================================
221
+ """
222
+ return memorial
223
+
224
+ def gerar(self, dados: Dict) -> str:
225
+ """Interface principal: LLM se disponivel, template caso contrario."""
226
+ if self.use_llm and self._pipe is not None:
227
+ return self.gerar_llm(dados)
228
+ return self.gerar_template(dados)
229
+
230
+
231
+ _memorial_gen = None
232
+
233
+ def get_memorial_generator(use_llm=False):
234
+ global _memorial_gen
235
+ if _memorial_gen is None:
236
+ _memorial_gen = MemorialGenerator(use_llm=use_llm)
237
+ return _memorial_gen
238
+
239
+
240
+ if __name__ == "__main__":
241
+ gen = MemorialGenerator()
242
+ dados = {
243
+ "nome_edificacao": "Edificio Comercial Exemplo",
244
+ "ocupacao": "comercial",
245
+ "grupo": "D", "divisao": "D-1",
246
+ "area_m2": 1200, "altura_m": 8, "pavimentos": 2, "lotacao": 120,
247
+ "exigencias": ["extintores_portateis", "hidrantes", "sinalizacao_emergencia",
248
+ "alarme_incendio", "spda"],
249
+ "qtd_extintores": 4, "capacidade_extintor": "2-A:20-B:C",
250
+ "sistema_hidrante": "Coluna Seca", "vazao_lpm": 300, "reserva_m3": 18.0,
251
+ "rt_nome": "Eng. Carlos Silva", "rt_crea": "GO-12345"
252
+ }
253
+ print(gen.gerar(dados))