carlosh10 commited on
Commit
eaac35d
·
verified ·
1 Parent(s): 0968ab6

refactor: Atualiza app.py com imports dos modulos e fallback completo

Browse files
Files changed (1) hide show
  1. app.py +509 -219
app.py CHANGED
@@ -1,248 +1,538 @@
1
  """
2
- Agente CBMGO - Interface Principal Gradio
3
  Sistema Inteligente de Prevencao de Incendio - NT-01/2025
 
4
  """
 
5
  import gradio as gr
6
  import math
7
  from datetime import datetime
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- def calcular_extintores(area_m2, grupo):
11
- tabela = {
12
- "A": (500, "2-A:10-B:C"), "B": (250, "2-A:20-B:C"),
13
- "C": (750, "1-A:5-B:C"), "D": (400, "2-A:20-B:C"),
14
- "E": (500, "2-A:10-B:C"), "F": (300, "4-A:20-B:C"),
15
- "G": (600, "1-A:5-B:C"), "H": (200, "2-A:20-B:C"),
 
 
 
16
  }
17
- ua, cap = tabela.get(grupo.upper(), (500, "2-A:10-B:C"))
18
- return max(1, math.ceil(area_m2 / ua)), cap
19
- def calcular_hidrantes(altura_m):
20
- if altura_m < 12:
21
- return "Mangueira / Coluna Seca", 300
22
- elif altura_m < 30:
23
- return "Hidrante com Reservatorio", 450
24
- return "Chuveiros Automaticos + Hidrante", 600
25
-
26
-
27
- def aplicar_regras(area_m2, altura_m, ocupacao, lotacao):
28
- ex = ["extintores_portateis", "sinalizacao_emergencia"]
29
- ocup = ocupacao.lower()
30
- if area_m2 > 750 or ocup in ["comercial", "servicos"]:
31
- ex.append("hidrantes")
32
- if altura_m > 12:
33
- ex += ["iluminacao_emergencia", "saidas_emergencia"]
34
- if area_m2 > 1000:
35
- ex.append("spda")
36
- if ocup == "industrial" and area_m2 > 2000:
37
- ex += ["chuveiros_automaticos", "reservatorio_incendio"]
38
- if lotacao > 100:
39
- ex += ["alarme_incendio", "deteccao_automatica"]
40
- return list(set(ex))
41
-
42
- def aba_calculadora(nome, area_m2, altura_m, ocupacao, lotacao):
43
- if area_m2 <= 0:
44
- return "Erro: Informe a area total valida.", "", ""
45
- grupos = {"residencial":"A","comercial":"D","servicos":"D",
46
- "educacional":"G","saude":"H","industrial":"F",
47
- "deposito":"J","reuniao":"C","esporte":"C"}
48
- grupo = grupos.get(ocupacao.lower(), "D")
49
- qtd, cap = calcular_extintores(area_m2, grupo)
50
- sist, vazao = calcular_hidrantes(altura_m)
51
- reserva = round(vazao * 60 / 1000, 1)
52
- ex = aplicar_regras(area_m2, altura_m, ocupacao, lotacao)
53
- data = datetime.now().strftime("%d/%m/%Y")
54
-
55
- calc = (
56
- "=== CALCULOS NT-01/2025 ===\n"
57
- + f"Edificacao: {nome}\n"
58
- + f"Ocupacao: {ocupacao} | Grupo: {grupo}\n"
59
- + f"Area: {area_m2:.1f} m2 | Altura: {altura_m:.1f} m | Lot: {int(lotacao)}\n\n"
60
- + f"EXTINTORES: {qtd} un. | Cap: {cap} | Dist.max: 15m\n"
61
- + f"HIDRANTES: {sist} | Vazao: {vazao} L/min | Reserva: {reserva} m3\n"
62
- + ("SPDA: OBRIGATORIO\n" if area_m2 > 1000 else "SPDA: Verificar\n")
63
- + ("ILUM.EMERG: OBRIGATORIA\n" if altura_m > 12 else "ILUM.EMERG: Verificar\n")
64
- )
65
- exig_txt = "\n".join([f" - {e.replace('_',' ').title()}" for e in ex])
66
- exig = f"=== EXIGENCIAS ({len(ex)} sistemas) ===\n{exig_txt}\n\nRef: NT-01/2025 CBMGO"
67
- exig_desc = ", ".join([e.replace("_"," ") for e in ex])
68
- memorial = (
69
- "MEMORIAL DESCRITIVO - PSCIP\n"
70
- + f"Data: {data} | Edificacao: {nome} | Ref: NT-01/2025 CBMGO\n\n"
71
- + "1. IDENTIFICACAO\n"
72
- + f" Uso: {ocupacao.title()} | Grupo NT-01: {grupo}\n"
73
- + f" Area: {area_m2:.2f} m2 | Altura: {altura_m:.2f} m\n\n"
74
- + f"2. SISTEMAS EXIGIDOS (Grupo {grupo})\n"
75
- + f" {exig_desc}\n\n"
76
- + "3. EXTINTORES PORTATEIS\n"
77
- + f" Qtd: {qtd} un. | Cap: {cap} | Dist.max: 15m\n"
78
- + " Distribuicao conforme Anexo B NT-01/2025\n\n"
79
- + "4. SISTEMA DE HIDRANTES\n"
80
- + f" Sistema: {sist} | Vazao: {vazao} L/min | Reserva: {reserva} m3\n"
81
- + " Conforme ABNT NBR 13714 e NT especifica CBMGO.\n\n"
82
- + "5. SINALIZACAO DE EMERGENCIA\n"
83
- + " Conforme ABNT NBR 13434.\n\n"
84
- + "6. ILUMINACAO DE EMERGENCIA\n"
85
- + (" Obrigatoria. ABNT NBR 10898.\n\n" if altura_m > 12 else " Verificar necessidade.\n\n")
86
- + "7. SPDA\n"
87
- + (" Obrigatorio. ABNT NBR 5419.\n\n" if area_m2 > 1000 else " Verificar necessidade.\n\n")
88
- + "Responsavel Tecnico: _______________ CREA/CAU: ___________\n"
89
- )
90
- return calc, exig, memorial
91
-
92
- def aba_auditoria(memorial_txt, area_m2, altura_m, ocupacao, lotacao):
93
- if not memorial_txt or len(memorial_txt) < 30:
94
- return "Insira o texto do memorial para auditar."
95
- ex = aplicar_regras(area_m2, altura_m, ocupacao, lotacao)
96
- termos = {
97
- "extintores_portateis": ["extintor"],
98
- "hidrantes": ["hidrante","mangotinho"],
99
- "sinalizacao_emergencia": ["sinalizacao","sinaliza"],
100
- "iluminacao_emergencia": ["iluminacao de emergencia"],
101
- "spda": ["spda","para-raios"],
102
- "alarme_incendio": ["alarme","deteccao"],
103
- "chuveiros_automaticos": ["chuveiro","sprinkler"],
104
- "saidas_emergencia": ["saida de emergencia","rota de fuga"],
105
  }
106
- ml = memorial_txt.lower()
107
- ok, erros = [], []
108
- for e in ex:
109
- ts = termos.get(e, [e.replace("_"," ")])
110
- (ok if any(t in ml for t in ts) else erros).append(e)
111
- status = "APTO PARA PROTOCOLO" if not erros else "PENDENCIAS ENCONTRADAS"
112
- rel = (
113
- "=== AUDITORIA NT-01/2025 ===\n"
114
- + f"Data: {datetime.now().strftime('%d/%m/%Y %H:%M')}\n"
115
- + f"STATUS: {status}\n\n"
116
- + f"CONFORMES ({len(ok)}):\n"
117
- + "\n".join([f" [OK] {i.replace('_',' ').title()}" for i in ok])
118
- )
119
- if erros:
120
- rel += f"\n\nERROS CRITICOS ({len(erros)}):\n"
121
- rel += "\n".join([f" [!!] {e.replace('_',' ').title()} - NAO ENCONTRADO" for e in erros])
122
- return rel + "\n\nRef: NT-01/2025 CBMGO"
123
-
124
- def aba_siapi(nome, processo, rt_nome, rt_crea, tem_mem, tem_pran, tem_form):
125
- faltam = []
126
- if not tem_mem: faltam.append("Memorial Descritivo")
127
- if not tem_pran: faltam.append("Pranchas/Plantas")
128
- if not tem_form: faltam.append("Formulario RT")
129
- ts = datetime.now().strftime("%Y%m%d_%H%M%S")
130
- pid = f"CBMGO_{processo}_{ts}" if processo else f"CBMGO_{ts}"
131
- apto = not faltam
132
- rel = (
133
- "=== VERIFICACAO PACOTE SIAPI ===\n"
134
- + f"Data: {datetime.now().strftime('%d/%m/%Y %H:%M')}\n"
135
- + f"ID: {pid}\n"
136
- + f"Edificacao: {nome} | RT: {rt_nome} | CREA: {rt_crea}\n\n"
137
- + "DOCUMENTOS:\n"
138
- + f" {'[OK]' if tem_mem else '[FALTA]'} Memorial Descritivo\n"
139
- + f" {'[OK]' if tem_pran else '[FALTA]'} Pranchas / Plantas\n"
140
- + f" {'[OK]' if tem_form else '[FALTA]'} Formulario RT\n\n"
141
- + ("STATUS: APTO PARA PROTOCOLO NO SIAPI\n\n" if apto
142
- else f"STATUS: INCOMPLETO\nFaltam: {', '.join(faltam)}\n\n")
143
- + "NOMENCLATURA PADRAO CBMGO:\n"
144
- + " [PROCESSO]_memorial_pscip.pdf\n"
145
- + " [PROCESSO]_prancha_01.dwg\n"
146
- + " [PROCESSO]_formulario_rt.pdf\n"
147
- + " [PROCESSO]_art.pdf\n\n"
148
- + "ATENCAO: Protocolo final deve ser realizado pelo RT no portal SIAPI/CBMGO.\n"
149
- )
150
- return rel
151
-
152
- # ============================================================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  # INTERFACE GRADIO
154
- # ============================================================
155
- with gr.Blocks(title="Agente CBMGO - NT-01/2025", theme=gr.themes.Base()) as demo:
156
- gr.Markdown(
157
- "# Agente CBMGO\n"
158
- "### Sistema Inteligente de Prevencao de Incendio - NT-01/2025\n"
159
- "> Apoio a Responsaveis Tecnicos (RT) - CBMGO Goias"
160
- )
161
 
 
 
 
 
 
 
 
 
 
 
 
162
  with gr.Tabs():
163
- with gr.TabItem("Calculadora NT-01"):
 
 
 
164
  with gr.Row():
165
  with gr.Column():
166
- i_nome = gr.Textbox(label="Nome da Edificacao")
167
- i_area = gr.Number(label="Area Total (m2)", value=500)
168
- i_alt = gr.Number(label="Altura (m)", value=6)
169
- i_ocup = gr.Dropdown(
170
- label="Ocupacao",
171
- choices=["comercial","residencial","industrial","educacional",
172
- "saude","servicos","reuniao","esporte","deposito"],
173
- value="comercial"
174
  )
175
- i_lot = gr.Number(label="Lotacao (pessoas)", value=50)
176
- btn1 = gr.Button("Calcular Exigencias", variant="primary")
177
  with gr.Column():
178
- o_calc = gr.Textbox(label="Calculos NT-01/2025", lines=14)
 
 
 
 
 
179
  with gr.Row():
180
- o_exig = gr.Textbox(label="Exigencias Identificadas", lines=10)
181
- o_mem = gr.Textbox(label="Memorial Descritivo Gerado", lines=10)
182
- btn1.click(aba_calculadora,
183
- inputs=[i_nome, i_area, i_alt, i_ocup, i_lot],
184
- outputs=[o_calc, o_exig, o_mem])
185
- with gr.TabItem("Auditoria de Memorial"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  with gr.Row():
187
  with gr.Column():
188
- a_mem = gr.Textbox(label="Memorial para Auditar", lines=14,
189
- placeholder="Cole o texto do memorial descritivo aqui...")
190
- a_area = gr.Number(label="Area (m2)", value=500)
191
- a_alt = gr.Number(label="Altura (m)", value=6)
192
- a_ocup = gr.Dropdown(
193
- label="Ocupacao",
194
- choices=["comercial","residencial","industrial","educacional",
195
- "saude","servicos","reuniao","esporte","deposito"],
196
- value="comercial"
 
 
 
 
 
 
 
 
 
 
197
  )
198
- a_lot = gr.Number(label="Lotacao", value=50)
199
- btn2 = gr.Button("Auditar Memorial", variant="primary")
200
  with gr.Column():
201
- o_aud = gr.Textbox(label="Relatorio de Auditoria", lines=20)
202
- btn2.click(aba_auditoria,
203
- inputs=[a_mem, a_area, a_alt, a_ocup, a_lot],
204
- outputs=[o_aud])
205
-
206
- with gr.TabItem("Preparacao SIAPI"):
207
  with gr.Row():
208
  with gr.Column():
209
- s_nome = gr.Textbox(label="Nome da Edificacao")
210
- s_proc = gr.Textbox(label="N. Processo CBMGO")
211
- s_rt = gr.Textbox(label="Nome do Responsavel Tecnico")
212
- s_crea = gr.Textbox(label="CREA/CAU")
213
- gr.Markdown("**Documentos do Pacote:**")
214
- s_mem = gr.Checkbox(label="Memorial Descritivo (PDF)")
215
- s_pran = gr.Checkbox(label="Pranchas/Plantas (DWG/PDF)")
216
- s_form = gr.Checkbox(label="Formulario RT")
217
- btn3 = gr.Button("Verificar Pacote", variant="primary")
218
  with gr.Column():
219
- o_siapi = gr.Textbox(label="Relatorio SIAPI", lines=20)
220
- btn3.click(aba_siapi,
221
- inputs=[s_nome, s_proc, s_rt, s_crea, s_mem, s_pran, s_form],
222
- outputs=[o_siapi])
223
- with gr.TabItem("Sobre"):
224
  gr.Markdown("""
225
- ## Agente CBMGO
226
- Ferramenta de apoio para elaboracao de projetos de PSCIP conforme NT-01/2025 CBMGO.
227
-
228
- ### Modulos Disponiveis
229
- - **Calculadora NT-01**: Calculos de extintores, hidrantes, reserva tecnica e lista de exigencias
230
- - **Auditoria**: Verifica conformidade do memorial descritivo com NT-01/2025
231
- - **Preparacao SIAPI**: Valida completude do pacote para protocolo no SIAPI
232
-
233
- ### Em Desenvolvimento
234
- - RAG Normativo com FAISS (consulta semantica a NT-01/2025)
235
- - Classificador LLM (fine-tune Llama-3.1-8B via LoRA)
236
- - Gerador de Memorial LLM (fine-tune Mistral-7B)
237
- - Assistente CAD (scripts AutoCAD / Dynamo Revit)
238
-
239
- ### Referencias Normativas
240
- NT-01/2025 CBMGO | ABNT NBR 13714 | NBR 10897 | NBR 13434 | NBR 10898 | NBR 5419
241
-
242
- Repositorio: https://huggingface.co/carlosh10/CERCON
243
-
244
- *Aviso Legal: Ferramenta auxiliar. O RT deve verificar conformidade com legislacao vigente.*
245
- """)
 
246
 
247
  if __name__ == "__main__":
248
  demo.launch()
 
1
  """
2
+ app.py - Agente CBMGO - Interface Principal Gradio
3
  Sistema Inteligente de Prevencao de Incendio - NT-01/2025
4
+ CERCON - Corpo de Bombeiros Militar de Goias
5
  """
6
+
7
  import gradio as gr
8
  import math
9
  from datetime import datetime
10
 
11
+ # Importar modulos com fallback gracioso
12
+ try:
13
+ from modules.classificador import ClassificadorOcupacao
14
+ _classificador = ClassificadorOcupacao()
15
+ USE_CLASSIFICADOR = True
16
+ except Exception as e:
17
+ print(f"[WARN] Modulo classificador nao disponivel: {e}")
18
+ USE_CLASSIFICADOR = False
19
+
20
+ try:
21
+ from modules.calculadora import CalculadoraIncendio
22
+ _calculadora = CalculadoraIncendio()
23
+ USE_CALCULADORA = True
24
+ except Exception as e:
25
+ print(f"[WARN] Modulo calculadora nao disponivel: {e}")
26
+ USE_CALCULADORA = False
27
+
28
+ try:
29
+ from modules.rag_normas import RAGNormas
30
+ _rag = RAGNormas()
31
+ USE_RAG = True
32
+ except Exception as e:
33
+ print(f"[WARN] Modulo RAG nao disponivel: {e}")
34
+ USE_RAG = False
35
+
36
+ try:
37
+ from modules.auditor import AuditorProjetos
38
+ _auditor = AuditorProjetos()
39
+ USE_AUDITOR = True
40
+ except Exception as e:
41
+ print(f"[WARN] Modulo auditor nao disponivel: {e}")
42
+ USE_AUDITOR = False
43
+
44
+ try:
45
+ from modules.memorial_generator import MemorialGenerator
46
+ _memorial = MemorialGenerator()
47
+ USE_MEMORIAL = True
48
+ except Exception as e:
49
+ print(f"[WARN] Modulo memorial nao disponivel: {e}")
50
+ USE_MEMORIAL = False
51
+
52
+ try:
53
+ from modules.submissao import SubmissaoSIAPI
54
+ _submissao = SubmissaoSIAPI()
55
+ USE_SUBMISSAO = True
56
+ except Exception as e:
57
+ print(f"[WARN] Modulo submissao nao disponivel: {e}")
58
+ USE_SUBMISSAO = False
59
+
60
+
61
+ # =============================================================================
62
+ # FALLBACKS LOCAIS (quando modulos nao estao disponiveis)
63
+ # =============================================================================
64
+
65
+ GRUPOS_OCUPACAO = {
66
+ "A-1": "Residencial unifamiliar (casa, sobrado)",
67
+ "A-2": "Residencial multifamiliar (apartamento, flat)",
68
+ "B-1": "Hospedagem transitoria (hotel, motel, pousada)",
69
+ "B-2": "Hospedagem longa permanencia (apart-hotel)",
70
+ "C-1": "Comercio pequeno porte (loja, farmacia, padaria)",
71
+ "C-2": "Comercio medio/grande porte (supermercado, shopping)",
72
+ "D-1": "Reuniao publica - esporte/lazer (ginasio, estadio)",
73
+ "D-2": "Reuniao publica - cultura/religiao (teatro, igreja)",
74
+ "D-3": "Reuniao publica - ensino (escola, universidade)",
75
+ "E-1": "Saude e assistencia (hospital, clinica, UBS)",
76
+ "F-1": "Servico profissional (escritorio, banco, consultorio)",
77
+ "F-2": "Servico de transporte (aeroporto, rodoviaria)",
78
+ "G-1": "Servicos automotivos (garagem, posto, oficina)",
79
+ "H-1": "Industrial baixo risco (alimenticio, textil)",
80
+ "H-2": "Industrial medio risco (metalurgica, moveleira)",
81
+ "H-3": "Industrial alto risco (quimica, petroquimica)",
82
+ "I-1": "Deposito baixo risco (arquivo, papel)",
83
+ "I-2": "Deposito medio risco (madeira, borracha)",
84
+ "I-3": "Deposito alto risco (inflamaveis, quimicos)",
85
+ "J-1": "Explosivos e inflamaveis especiais (refinaria)",
86
+ }
87
 
88
+
89
+ def calcular_extintores_fallback(area_m2, grupo):
90
+ letra = grupo.split("-")[0] if "-" in grupo else grupo[0]
91
+ risco = "alto" if letra in ["H","I","J"] else ("medio" if letra in ["C","D","G"] else "baixo")
92
+ area_por_ext = 150 if risco == "alto" else (250 if risco == "medio" else 500)
93
+ quantidade = max(2, math.ceil(area_m2 / area_por_ext))
94
+ return {
95
+ "risco": risco, "area_por_extintor": area_por_ext,
96
+ "quantidade": quantidade, "tipo": "ABC 6kg"
97
  }
98
+
99
+
100
+ def verificar_sistemas_fallback(area_m2, pavimentos, grupo):
101
+ altura = pavimentos * 3.0
102
+ letra = grupo.split("-")[0] if "-" in grupo else grupo[0]
103
+ return {
104
+ "hidrante": area_m2 > 750 or pavimentos >= 3,
105
+ "spda": altura > 15 or area_m2 > 1000,
106
+ "iluminacao_emergencia": area_m2 > 200 or pavimentos >= 2,
107
+ "sprinkler": altura > 30 or (letra in ["H","I"] and area_m2 > 2500),
108
+ "brigada": area_m2 > 750,
109
+ "alarme": letra in ["E","B"] or area_m2 > 1500,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  }
111
+
112
+
113
+ # =============================================================================
114
+ # FUNCOES DA INTERFACE
115
+ # =============================================================================
116
+
117
+ def calcular_medidas(area_m2, pavimentos, grupo_codigo):
118
+ """Calcula todas as medidas de seguranca para a edificacao"""
119
+ try:
120
+ if USE_CALCULADORA:
121
+ return _calculadora.calcular_completo(area_m2, pavimentos, grupo_codigo)
122
+ except Exception as e:
123
+ print(f"Erro no modulo calculadora: {e}")
124
+
125
+ # Fallback local
126
+ ext = calcular_extintores_fallback(area_m2, grupo_codigo)
127
+ sis = verificar_sistemas_fallback(area_m2, pavimentos, grupo_codigo)
128
+ altura = pavimentos * 3.0
129
+
130
+ resultado = f"""CALCULOS DE SEGURANCA CONTRA INCENDIO - NT-01/2025 CBMGO
131
+ {"="*60}
132
+
133
+ EDIFICACAO:
134
+ Grupo de Ocupacao: {grupo_codigo}
135
+ Area Total: {area_m2:.1f} m2
136
+ Pavimentos: {pavimentos}
137
+ Altura Estimada: {altura:.1f} m
138
+ Risco: {ext["risco"].upper()}
139
+
140
+ EXTINTORES DE INCENDIO:
141
+ Quantidade minima: {ext["quantidade"]} extintores
142
+ Tipo: {ext["tipo"]} (Classe ABC)
143
+ Area por extintor: {ext["area_por_extintor"]} m2
144
+ Base: ABNT NBR 12693
145
+
146
+ SISTEMAS OBRIGATORIOS:
147
+ Hidrantes/Mangotinhos: {"OBRIGATORIO" if sis["hidrante"] else "Nao obrigatorio"}
148
+ SPDA (Para-raios): {"OBRIGATORIO" if sis["spda"] else "Verificar necessidade"}
149
+ Iluminacao Emergencia: {"OBRIGATORIA" if sis["iluminacao_emergencia"] else "Recomendada"}
150
+ Sprinklers: {"OBRIGATORIO" if sis["sprinkler"] else "Nao obrigatorio para esta area"}
151
+ Brigada de Incendio: {"OBRIGATORIA" if sis["brigada"] else "Recomendada"}
152
+ Sistema de Alarme: {"OBRIGATORIO" if sis["alarme"] else "Verificar necessidade"}
153
+
154
+ SAIDAS DE EMERGENCIA (ABNT NBR 9077):
155
+ Largura minima: 1,20 m
156
+ Distancia maxima: 30 m (baixo risco) / 20 m (alto risco)
157
+
158
+ {"="*60}
159
+ Nota: Estes calculos sao estimativas. O PPCI completo deve ser
160
+ elaborado por profissional habilitado com ART/RRT registrada.
161
+ Data: {datetime.now().strftime("%d/%m/%Y %H:%M")}"""
162
+
163
+ return resultado
164
+
165
+
166
+ def consultar_normas(pergunta):
167
+ """Consulta o RAG de normas NT-01/2025"""
168
+ if not pergunta.strip():
169
+ return "Por favor, digite uma pergunta sobre as normas de prevencao de incendio."
170
+
171
+ try:
172
+ if USE_RAG:
173
+ return _rag.consultar(pergunta)
174
+ except Exception as e:
175
+ print(f"Erro no modulo RAG: {e}")
176
+
177
+ # Fallback: respostas baseadas em palavras-chave
178
+ pergunta_lower = pergunta.lower()
179
+
180
+ if any(w in pergunta_lower for w in ["extintor", "extintores"]):
181
+ return """EXTINTORES DE INCENDIO - NT-01/2025 CBMGO
182
+
183
+ Conforme NT-01/2025 e ABNT NBR 12693:
184
+ - BAIXO RISCO (A, B, F): 1 extintor a cada 500 m2
185
+ - MEDIO RISCO (C, D, G): 1 extintor a cada 250 m2
186
+ - ALTO RISCO (H, I, J): 1 extintor a cada 150 m2
187
+ - Minimo: 2 extintores por pavimento
188
+ - Tipo: ABC (po quimico) para uso geral
189
+ - Manutencao: Anual obrigatoria
190
+ - Sinalizar conforme ABNT NBR 13434"""
191
+
192
+ elif any(w in pergunta_lower for w in ["hidrante", "hidrantes"]):
193
+ return """SISTEMA DE HIDRANTES - NT-01/2025 CBMGO
194
+
195
+ Obrigatorio quando:
196
+ - Area total > 750 m2, OU
197
+ - Altura > 12 metros (aprox. 4 pavimentos)
198
+
199
+ Especificacoes (ABNT NBR 13714):
200
+ - Pressao minima: 10 m.c.a. no ponto mais desfavoravel
201
+ - Vazao minima: 300 L/min por hidrante
202
+ - Mangueira: DN 65mm para hidrante externo
203
+ - Distancia maxima entre hidrantes: 30 metros"""
204
+
205
+ elif any(w in pergunta_lower for w in ["spda", "para-raios", "pararaios"]):
206
+ return """SPDA - SISTEMA DE PROTECAO CONTRA DESCARGAS ATMOSFERICAS
207
+
208
+ Obrigatorio conforme ABNT NBR 5419 quando:
209
+ - Altura > 15 metros
210
+ - Area construida > 1.000 m2
211
+ - Edificacoes em areas de alta densidade de raios
212
+
213
+ O SPDA deve ser projetado por engenheiro eletricista habilitado."""
214
+
215
+ elif any(w in pergunta_lower for w in ["memorial", "ppci"]):
216
+ return """MEMORIAL DESCRITIVO (PPCI) - NT-01/2025 CBMGO
217
+
218
+ O PPCI deve conter:
219
+ 1. Identificacao da edificacao e responsavel tecnico
220
+ 2. Classificacao de ocupacao (Tabela 1 - NT-01/2025)
221
+ 3. Medidas de seguranca adotadas
222
+ 4. Memorial de calculos
223
+ 5. Plantas tecnicas (planta baixa, cortes, fachadas)
224
+ 6. ART/RRT do responsavel tecnico
225
+
226
+ Elaborado por: Engenheiro (CREA) ou Arquiteto (CAU) habilitado.
227
+ Aprovacao: CBMGO antes do inicio das obras."""
228
+
229
+ else:
230
+ return f"""CONSULTA NT-01/2025 CBMGO
231
+
232
+ Sua pergunta: "{pergunta}"
233
+
234
+ Nao encontrei uma resposta especifica para esta consulta.
235
+
236
+ Para perguntas sobre a NT-01/2025, voce pode pesquisar sobre:
237
+ - Classificacao de ocupacao (grupos A a J)
238
+ - Extintores de incendio (NBR 12693)
239
+ - Sistema de hidrantes (NBR 13714)
240
+ - Saidas de emergencia (NBR 9077)
241
+ - Iluminacao de emergencia (NBR 10898)
242
+ - PPCI e memorial descritivo
243
+
244
+ Para consultas especificas, entre em contato com o CBMGO:
245
+ Site: www.bombeiros.go.gov.br"""
246
+
247
+
248
+ def auditar_projeto(descricao_projeto):
249
+ """Audita um projeto contra as normas NT-01/2025"""
250
+ if not descricao_projeto.strip():
251
+ return "Por favor, descreva o projeto para auditoria."
252
+
253
+ try:
254
+ if USE_AUDITOR:
255
+ return _auditor.auditar(descricao_projeto)
256
+ except Exception as e:
257
+ print(f"Erro no modulo auditor: {e}")
258
+
259
+ # Fallback local
260
+ verificacoes = []
261
+ desc_lower = descricao_projeto.lower()
262
+
263
+ checks = [
264
+ ("extintor", "Extintores de incendio", "Verificar quantidade e distribuicao conforme NBR 12693"),
265
+ ("saida", "Saidas de emergencia", "Verificar largura minima 1,20m e sinalizar conforme NBR 9077"),
266
+ ("iluminacao", "Iluminacao de emergencia", "Autonomia minima 1h, 30 lux nas rotas de saida"),
267
+ ("sinaliza", "Sinalizacao de seguranca", "Placas conforme ABNT NBR 13434"),
268
+ ("hidrante", "Sistema de hidrantes", "Verificar obrigatoriedade pela area/altura"),
269
+ ("spda", "SPDA para-raios", "Verificar necessidade pela altura/area"),
270
+ ]
271
+
272
+ for keyword, item, obs in checks:
273
+ if keyword in desc_lower:
274
+ verificacoes.append(f"[OK] {item}: Mencionado no projeto")
275
+ else:
276
+ verificacoes.append(f"[ATENCAO] {item}: Nao mencionado - {obs}")
277
+
278
+ itens_str = chr(10).join(verificacoes)
279
+ return f"""AUDITORIA DO PROJETO - NT-01/2025 CBMGO
280
+ {"="*60}
281
+
282
+ PROJETO ANALISADO:
283
+ {descricao_projeto[:300]}{"..." if len(descricao_projeto) > 300 else ""}
284
+
285
+ VERIFICACOES:
286
+ {itens_str}
287
+
288
+ RECOMENDACOES:
289
+ - Verifique todos os itens marcados como [ATENCAO]
290
+ - Consulte a NT-01/2025 CBMGO para requisitos especificos
291
+ - O PPCI completo deve ser aprovado pelo CBMGO
292
+
293
+ Data: {datetime.now().strftime("%d/%m/%Y %H:%M")}"""
294
+
295
+
296
+ def gerar_memorial_func(tipo_edificacao, area, pavimentos, cidade, responsavel):
297
+ """Gera memorial descritivo de PPCI"""
298
+ if not tipo_edificacao.strip():
299
+ return "Por favor, informe o tipo de edificacao."
300
+
301
+ try:
302
+ if USE_MEMORIAL:
303
+ return _memorial.gerar(tipo_edificacao, float(area), int(pavimentos), cidade, responsavel)
304
+ except Exception as e:
305
+ print(f"Erro no modulo memorial: {e}")
306
+
307
+ # Fallback local
308
+ grupo = "F-1"
309
+ for cod, desc in GRUPOS_OCUPACAO.items():
310
+ if any(w in tipo_edificacao.lower() for w in desc.lower().split()):
311
+ grupo = cod
312
+ break
313
+
314
+ area_f = float(area) if area else 200.0
315
+ pav_i = int(pavimentos) if pavimentos else 1
316
+ altura = pav_i * 3.0
317
+ ext = calcular_extintores_fallback(area_f, grupo)
318
+ sis = verificar_sistemas_fallback(area_f, pav_i, grupo)
319
+
320
+ return f"""MEMORIAL DESCRITIVO DE PREVENCAO E PROTECAO CONTRA INCENDIO E PANICO
321
+ PLANO DE PREVENCAO CONTRA INCENDIO - PPCI
322
+ {"="*70}
323
+
324
+ 1. IDENTIFICACAO DO PROJETO
325
+ Edificacao: {tipo_edificacao}
326
+ Endereco: [Endereco completo], {cidade} - GO
327
+ Ocupacao: Grupo {grupo} - {GRUPOS_OCUPACAO.get(grupo, "Verificar classificacao")}
328
+ Area Total: {area_f:.2f} m2 | Pavimentos: {pav_i} | Altura: {altura:.2f} m
329
+ Data: {datetime.now().strftime("%d/%m/%Y")}
330
+ Responsavel Tecnico: {responsavel}
331
+ ART/RRT No: [A PREENCHER]
332
+
333
+ 2. BASE LEGAL
334
+ - NT-01/2025 CBMGO (Norma Tecnica 01/2025)
335
+ - ABNT NBR 9077:2001 (Saidas de emergencia)
336
+ - Lei Estadual n. 15.802/2006
337
+
338
+ 3. CLASSIFICACAO
339
+ - Grupo: {grupo} | Risco: {ext["risco"].upper()}
340
+
341
+ 4. MEDIDAS DE SEGURANCA
342
+ 4.1 Extintores: {ext["quantidade"]} extintores {ext["tipo"]}
343
+ (1 a cada {ext["area_por_extintor"]}m2, conforme NBR 12693)
344
+ 4.2 Hidrantes: {"Sistema de hidrantes obrigatorio (NBR 13714)" if sis["hidrante"] else "Verificar necessidade com CBMGO"}
345
+ 4.3 SPDA: {"Obrigatorio (ABNT NBR 5419)" if sis["spda"] else "Verificar necessidade"}
346
+ 4.4 Iluminacao Emergencia: {"Obrigatoria - 1h autonomia (NBR 10898)" if sis["iluminacao_emergencia"] else "Recomendada"}
347
+ 4.5 Sinalizacao: Conforme ABNT NBR 13434
348
+ 4.6 Saidas de Emergencia: Largura minima 1,20m (ABNT NBR 9077)
349
+
350
+ 5. RESPONSABILIDADE TECNICA
351
+ {cidade}, {datetime.now().strftime("%d/%m/%Y")}
352
+ {responsavel}
353
+ ART/RRT No: [A PREENCHER]
354
+ {"="*70}
355
+ FIM DO MEMORIAL DESCRITIVO"""
356
+
357
+
358
+ def preparar_siapi(tipo_edificacao, area, responsavel, cpf_responsavel, crea_cau):
359
+ """Prepara documentos para submissao no SIAPI"""
360
+ try:
361
+ if USE_SUBMISSAO:
362
+ return _submissao.preparar_documentos(tipo_edificacao, float(area), responsavel, cpf_responsavel, crea_cau)
363
+ except Exception as e:
364
+ print(f"Erro no modulo submissao: {e}")
365
+
366
+ # Fallback
367
+ protocolo = f"CBMGO-{datetime.now().strftime('%Y%m%d')}-{hash(tipo_edificacao) % 10000:04d}"
368
+
369
+ return f"""PREPARACAO PARA SUBMISSAO SIAPI - CBMGO
370
+ {"="*60}
371
+
372
+ PROTOCOLO PROVISORIO: {protocolo}
373
+ Data: {datetime.now().strftime("%d/%m/%Y %H:%M")}
374
+
375
+ DADOS DA EDIFICACAO:
376
+ - Tipo: {tipo_edificacao}
377
+ - Area: {area} m2
378
+ - Responsavel Tecnico: {responsavel}
379
+ - Registro Profissional: {crea_cau}
380
+
381
+ DOCUMENTOS NECESSARIOS:
382
+ [x] PPCI completo (memorial + plantas)
383
+ [x] ART/RRT do responsavel tecnico
384
+ [x] Requerimento padrao CBMGO
385
+ [x] DARM quitado (taxa de vistoria)
386
+ [ ] Laudo de aprovacao do corpo tecnico
387
+
388
+ CHECKLIST DE PLANTAS:
389
+ [ ] Planta baixa cotada (escala 1:100 ou 1:50)
390
+ [ ] Planta de situacao e localizacao
391
+ [ ] Cortes transversal e longitudinal
392
+ [ ] Memorial descritivo assinado
393
+ [ ] Especificacoes tecnicas dos sistemas
394
+
395
+ COMO SUBMETER NO SIAPI:
396
+ 1. Acesse: https://siapi.goias.gov.br
397
+ 2. Faca login com CPF/CNPJ
398
+ 3. Selecione "Novo Protocolo de Analise"
399
+ 4. Preencha os dados da edificacao
400
+ 5. Anexe os documentos em PDF (max 10MB cada)
401
+ 6. Confirme e salve o protocolo
402
+ 7. Aguarde analise do CBMGO (prazo: 30 dias)
403
+
404
+ Para duvidas: (62) 3201-5959 | cbmgo@bombeiros.go.gov.br
405
+ {"="*60}"""
406
+
407
+
408
+ # =============================================================================
409
  # INTERFACE GRADIO
410
+ # =============================================================================
 
 
 
 
 
 
411
 
412
+ with gr.Blocks(
413
+ title="CERCON - Agente CBMGO",
414
+ theme=gr.themes.Soft(primary_hue="red"),
415
+ ) as demo:
416
+
417
+ gr.Markdown("""
418
+ # CERCON - Agente CBMGO
419
+ ### Sistema Inteligente de Prevencao e Protecao contra Incendio e Panico
420
+ **Base normativa: NT-01/2025 | CBMGO - Corpo de Bombeiros Militar de Goias**
421
+ """)
422
+
423
  with gr.Tabs():
424
+
425
+ # Tab 1: Calculadora
426
+ with gr.Tab("Calculadora de Seguranca"):
427
+ gr.Markdown("### Calcule as medidas de seguranca obrigatorias para sua edificacao")
428
  with gr.Row():
429
  with gr.Column():
430
+ area_input = gr.Number(label="Area Total (m2)", value=200.0, minimum=1)
431
+ pav_input = gr.Number(label="Numero de Pavimentos", value=1, minimum=1, step=1)
432
+ grupo_input = gr.Dropdown(
433
+ choices=list(GRUPOS_OCUPACAO.keys()),
434
+ value="F-1",
435
+ label="Grupo de Ocupacao (NT-01/2025)"
 
 
436
  )
437
+ calc_btn = gr.Button("Calcular Medidas de Seguranca", variant="primary")
 
438
  with gr.Column():
439
+ calc_output = gr.Textbox(label="Resultado", lines=25, show_copy_button=True)
440
+ calc_btn.click(calcular_medidas, inputs=[area_input, pav_input, grupo_input], outputs=calc_output)
441
+
442
+ # Tab 2: Consulta Normas
443
+ with gr.Tab("Consulta NT-01/2025"):
444
+ gr.Markdown("### Tire duvidas sobre a NT-01/2025 e normas de prevencao de incendio")
445
  with gr.Row():
446
+ with gr.Column():
447
+ norma_input = gr.Textbox(
448
+ label="Sua pergunta",
449
+ placeholder="Ex: Quantos extintores preciso para um escritorio de 300m2?",
450
+ lines=3
451
+ )
452
+ norma_btn = gr.Button("Consultar", variant="primary")
453
+ gr.Examples(
454
+ examples=[
455
+ ["Quantos extintores preciso para um escritorio de 500m2?"],
456
+ ["Quando e obrigatorio instalar hidrantes?"],
457
+ ["O que e SPDA e quando e obrigatorio?"],
458
+ ["Como elaborar um PPCI para um hotel?"],
459
+ ],
460
+ inputs=norma_input
461
+ )
462
+ with gr.Column():
463
+ norma_output = gr.Textbox(label="Resposta", lines=20, show_copy_button=True)
464
+ norma_btn.click(consultar_normas, inputs=norma_input, outputs=norma_output)
465
+
466
+ # Tab 3: Memorial PPCI
467
+ with gr.Tab("Gerar Memorial PPCI"):
468
+ gr.Markdown("### Gere um memorial descritivo de PPCI automaticamente")
469
  with gr.Row():
470
  with gr.Column():
471
+ mem_tipo = gr.Textbox(label="Tipo de Edificacao", placeholder="Ex: Escritorio comercial, Hotel, Escola")
472
+ mem_area = gr.Number(label="Area Total (m2)", value=200.0)
473
+ mem_pav = gr.Number(label="Pavimentos", value=1, step=1)
474
+ mem_cidade = gr.Textbox(label="Cidade", value="Goiania")
475
+ mem_resp = gr.Textbox(label="Responsavel Tecnico (Nome - CREA/CAU)")
476
+ mem_btn = gr.Button("Gerar Memorial", variant="primary")
477
+ with gr.Column():
478
+ mem_output = gr.Textbox(label="Memorial Descritivo", lines=30, show_copy_button=True)
479
+ mem_btn.click(gerar_memorial_func, inputs=[mem_tipo, mem_area, mem_pav, mem_cidade, mem_resp], outputs=mem_output)
480
+
481
+ # Tab 4: Auditoria
482
+ with gr.Tab("Auditoria de Projeto"):
483
+ gr.Markdown("### Audite seu projeto contra os requisitos da NT-01/2025")
484
+ with gr.Row():
485
+ with gr.Column():
486
+ audit_input = gr.Textbox(
487
+ label="Descreva seu projeto",
488
+ placeholder="Descreva os sistemas de seguranca previstos...",
489
+ lines=8
490
  )
491
+ audit_btn = gr.Button("Auditar Projeto", variant="primary")
 
492
  with gr.Column():
493
+ audit_output = gr.Textbox(label="Resultado da Auditoria", lines=20, show_copy_button=True)
494
+ audit_btn.click(auditar_projeto, inputs=audit_input, outputs=audit_output)
495
+
496
+ # Tab 5: SIAPI
497
+ with gr.Tab("Preparar SIAPI"):
498
+ gr.Markdown("### Prepare a documentacao para submissao no SIAPI/CBMGO")
499
  with gr.Row():
500
  with gr.Column():
501
+ siapi_tipo = gr.Textbox(label="Tipo de Edificacao")
502
+ siapi_area = gr.Number(label="Area Total (m2)", value=200.0)
503
+ siapi_resp = gr.Textbox(label="Nome do Responsavel Tecnico")
504
+ siapi_cpf = gr.Textbox(label="CPF do Responsavel (apenas numeros)", placeholder="00000000000")
505
+ siapi_reg = gr.Textbox(label="Registro Profissional (CREA/CAU)", placeholder="CREA-GO 12345-D")
506
+ siapi_btn = gr.Button("Preparar Documentacao", variant="primary")
 
 
 
507
  with gr.Column():
508
+ siapi_output = gr.Textbox(label="Checklist de Submissao", lines=25, show_copy_button=True)
509
+ siapi_btn.click(preparar_siapi, inputs=[siapi_tipo, siapi_area, siapi_resp, siapi_cpf, siapi_reg], outputs=siapi_output)
510
+
511
+ # Tab 6: Sobre
512
+ with gr.Tab("Sobre o CERCON"):
513
  gr.Markdown("""
514
+ ## CERCON - Agente CBMGO
515
+
516
+ **Versao:** 1.0.0 | **Base normativa:** NT-01/2025 CBMGO
517
+
518
+ ### Funcionalidades
519
+ - **Calculadora de Seguranca**: Calcula extintores, hidrantes, SPDA e sistemas obrigatorios
520
+ - **Consulta NT-01/2025**: RAG sobre normas de prevencao de incendio
521
+ - **Gerador de Memorial**: Cria memoriais PPCI conforme NT-01/2025
522
+ - **Auditoria de Projetos**: Verifica conformidade com as normas
523
+ - **Preparacao SIAPI**: Checklists para submissao ao CBMGO
524
+
525
+ ### Tecnologia
526
+ - Interface: Gradio | Busca: FAISS + Sentence Transformers
527
+ - LLM: Llama-3.1-8B (com GPU) | Fallback: Regras declarativas (sem GPU)
528
+ - Repositorio: https://huggingface.co/carlosh10/CERCON
529
+
530
+ ### Importante
531
+ Este agente e uma ferramenta de apoio tecnico. O PPCI oficial deve
532
+ sempre ser elaborado por profissional habilitado com ART/RRT.
533
+
534
+ **CBMGO**: www.bombeiros.go.gov.br | (62) 3201-5959
535
+ """)
536
 
537
  if __name__ == "__main__":
538
  demo.launch()