Skip to content

Commit 0790b76

Browse files
Merge pull request #1 from Quantum-Software-Development/FabianaCampanari-patch-1
Implement server for model inference and client handling
2 parents 6f5c7f1 + df24eef commit 0790b76

1 file changed

Lines changed: 176 additions & 0 deletions

File tree

Codes/servidor_central.py

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
2+
import socket
3+
import threading
4+
import json
5+
import pickle
6+
import numpy as np
7+
import os
8+
from datetime import datetime
9+
10+
HOST = "127.0.0.1"
11+
PORT = 5000
12+
MODEL_PATH = "modelo_falha_rf.pkl"
13+
14+
alertas_totais = 0
15+
lock_alertas = threading.Lock()
16+
17+
18+
def log(level, message, client=None):
19+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
20+
if client:
21+
ip, port = client
22+
print(f"[{timestamp}] [{level}] [{ip}:{port}] {message}")
23+
else:
24+
print(f"[{timestamp}] [{level}] {message}")
25+
26+
27+
def verificar_modelo(path):
28+
if not os.path.exists(path):
29+
raise FileNotFoundError(
30+
f"Arquivo de modelo não encontrado: {path}. "
31+
f"Execute 'python3 treinar_modelo.py' primeiro."
32+
)
33+
34+
if os.path.getsize(path) == 0:
35+
raise ValueError(f"O arquivo de modelo está vazio: {path}")
36+
37+
try:
38+
with open(path, "rb") as f:
39+
modelo = pickle.load(f)
40+
except pickle.UnpicklingError:
41+
raise ValueError(f"O arquivo {path} não é um pickle válido.")
42+
except Exception as e:
43+
raise RuntimeError(f"Falha ao carregar o modelo: {e}")
44+
45+
if not hasattr(modelo, "predict"):
46+
raise TypeError("O objeto carregado não possui o método '.predict()'.")
47+
48+
return modelo
49+
50+
51+
def classificar_dados(dados):
52+
campos_obrigatorios = ["temperatura", "vibracao", "rpm"]
53+
54+
for campo in campos_obrigatorios:
55+
if campo not in dados:
56+
raise KeyError(f"Campo obrigatório ausente: {campo}")
57+
58+
temperatura = float(dados["temperatura"])
59+
vibracao = float(dados["vibracao"])
60+
rpm = float(dados["rpm"])
61+
62+
X = np.array([[temperatura, vibracao, rpm]])
63+
pred = modelo.predict(X)[0]
64+
65+
return "FALHA" if pred == 1 else "NORMAL"
66+
67+
68+
def tratar_cliente(conn, addr):
69+
global alertas_totais
70+
71+
log("INFO", "Nova conexão aceita.", addr)
72+
73+
try:
74+
while True:
75+
dados_brutos = conn.recv(1024)
76+
77+
if not dados_brutos:
78+
log("INFO", "Cliente encerrou a conexão.", addr)
79+
break
80+
81+
try:
82+
mensagem = dados_brutos.decode("utf-8")
83+
dados = json.loads(mensagem)
84+
except UnicodeDecodeError:
85+
erro = {"erro": "Falha ao decodificar mensagem em UTF-8."}
86+
conn.send(json.dumps(erro).encode("utf-8"))
87+
log("ERROR", "Mensagem não pôde ser decodificada.", addr)
88+
continue
89+
except json.JSONDecodeError:
90+
erro = {"erro": "JSON inválido enviado pelo cliente."}
91+
conn.send(json.dumps(erro).encode("utf-8"))
92+
log("ERROR", f"JSON inválido recebido: {dados_brutos!r}", addr)
93+
continue
94+
95+
try:
96+
diagnostico = classificar_dados(dados)
97+
98+
if diagnostico == "FALHA":
99+
with lock_alertas:
100+
alertas_totais += 1
101+
total_atual = alertas_totais
102+
else:
103+
with lock_alertas:
104+
total_atual = alertas_totais
105+
106+
resposta = {
107+
"robot_id": dados.get("robot_id", "desconhecido"),
108+
"diagnostico": diagnostico,
109+
"alertas_totais": total_atual,
110+
"status": "ok"
111+
}
112+
113+
conn.send(json.dumps(resposta).encode("utf-8"))
114+
115+
log(
116+
"ALERT" if diagnostico == "FALHA" else "INFO",
117+
f"Dados={dados} | Diagnóstico={diagnostico} | Alertas={total_atual}",
118+
addr
119+
)
120+
121+
except KeyError as e:
122+
erro = {"erro": str(e), "status": "bad_request"}
123+
conn.send(json.dumps(erro).encode("utf-8"))
124+
log("ERROR", f"Campo ausente: {e}", addr)
125+
126+
except ValueError as e:
127+
erro = {"erro": f"Valor inválido: {e}", "status": "bad_request"}
128+
conn.send(json.dumps(erro).encode("utf-8"))
129+
log("ERROR", f"Erro de conversão: {e}", addr)
130+
131+
except Exception as e:
132+
erro = {"erro": "Falha interna na inferência.", "status": "server_error"}
133+
conn.send(json.dumps(erro).encode("utf-8"))
134+
log("ERROR", f"Erro interno durante inferência: {e}", addr)
135+
136+
except ConnectionResetError:
137+
log("WARN", "Conexão resetada pelo cliente.", addr)
138+
139+
except Exception as e:
140+
log("ERROR", f"Erro inesperado na thread do cliente: {e}", addr)
141+
142+
finally:
143+
conn.close()
144+
log("INFO", "Conexão encerrada.", addr)
145+
146+
147+
def iniciar_servidor():
148+
global modelo
149+
150+
try:
151+
log("INFO", "Verificando arquivo do modelo...")
152+
modelo = verificar_modelo(MODEL_PATH)
153+
log("INFO", f"Modelo carregado com sucesso: {MODEL_PATH}")
154+
155+
servidor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
156+
servidor.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
157+
servidor.bind((HOST, PORT))
158+
servidor.listen()
159+
160+
log("INFO", f"Servidor escutando em {HOST}:{PORT}")
161+
162+
while True:
163+
conn, addr = servidor.accept()
164+
thread = threading.Thread(target=tratar_cliente, args=(conn, addr), daemon=True)
165+
thread.start()
166+
log("INFO", f"Thread iniciada. Threads ativas: {threading.active_count() - 1}")
167+
168+
except KeyboardInterrupt:
169+
log("WARN", "Servidor interrompido manualmente.")
170+
171+
except Exception as e:
172+
log("ERROR", f"Falha ao iniciar o servidor: {e}")
173+
174+
175+
if __name__ == "__main__":
176+
iniciar_servidor()

0 commit comments

Comments
 (0)