carlosh10 commited on
Commit
6a5233b
·
verified ·
1 Parent(s): 57b3c2b

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +248 -0
app.py ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()