Ju-Am commited on
Commit
6b33fce
·
1 Parent(s): 2f77f03

Add confiança do diagnóstico

Browse files
Files changed (1) hide show
  1. main.py +34 -22
main.py CHANGED
@@ -74,7 +74,7 @@ async def root():
74
  @app.post("/classify/")
75
  async def classify_image(file: UploadFile = File(...), token: str = Depends(verify_token)):
76
  """
77
- Endpoint principal: Recebe uma imagem, extrai features e classifica.
78
  """
79
 
80
  print(f">> [{datetime.now().strftime('%d/%m %H:%M:%S')}] | Recebida imagem: {file.filename}.")
@@ -88,33 +88,39 @@ async def classify_image(file: UploadFile = File(...), token: str = Depends(veri
88
  raise HTTPException(status_code=500, detail=f"Erro ao salvar arquivo: {e}")
89
 
90
  try:
91
- #Extrai Features (ConvNext - 1536 dimensões)
92
- #(process_single_image vem do feature_extractor_single.py)
93
  features_array = process_single_image(temp_path)
94
 
95
- #Prepara o vetor para Scikit-learn
96
- #O sklearn espera um array 2D (1, 1536) e não (1536,)
97
  nova_feature = features_array.reshape(1, -1)
98
 
99
- #Executa o pipeline de classificação
100
- #Normaliza a nova feature com o mesmo scaler usado no treino
101
  nova_feature_scaled = SCALER.transform(nova_feature)
102
-
103
- #Reduz usando o mesmo UMAP já treinado
104
  nova_feature_umap = UMAP.transform(nova_feature_scaled)
105
 
106
- #Faz a predição
107
- pred_numerica = SVM.predict(nova_feature_umap)
 
 
 
 
 
 
108
 
109
- #Converte a predição numérica de volta para o nome da classe
110
- classe_predita_raw = ENCODER.inverse_transform(pred_numerica)[0]
 
 
 
111
 
112
- #NORMALIZA A STRING DO MODELO TAMBÉM
113
  classe_predita = normalize_string(str(classe_predita_raw))
114
 
115
- #DEBUG: o que exatamente o modelo cuspiu vs o que tem no banco
116
- #repr() para ver se tem caracteres escondidos como \n ou \r
117
- print(f"DEBUG CHAVES: Modelo='{repr(classe_predita)}'")
 
 
118
 
119
  #BUSCA AS INFORMAÇÕES
120
  info_adicional = DB_INFO.get(classe_predita, {
@@ -125,17 +131,24 @@ async def classify_image(file: UploadFile = File(...), token: str = Depends(veri
125
  })
126
 
127
  #PEGA O NOME "BONITO" DO JSON
128
- #Tenta pegar o campo 'nome'. Se não existir, usa a 'classe_predita'
129
  nome_exibicao = info_adicional.get("nome", classe_predita)
130
 
131
- print(f">> [{datetime.now().strftime('%d/%m %H:%M:%S')}] | Diagnóstico para {file.filename}: {classe_predita}")
132
 
133
  return {
134
- "diagnostico": nome_exibicao, #AQUI VAI O NOME CORRIGIDO, INDEPENDENTE DE RÓTULO DO DATASET
135
- "id_tecnico": classe_predita, #(Opcional) ID técnico caso necessário
 
136
  "info": info_adicional
137
  }
138
 
 
 
 
 
 
 
 
139
  except Exception as e:
140
  #Pega qualquer erro que acontecer durante a extração ou classificação
141
  raise HTTPException(status_code=500, detail=f"Erro no processamento: {e}")
@@ -145,7 +158,6 @@ async def classify_image(file: UploadFile = File(...), token: str = Depends(veri
145
  if os.path.exists(temp_path):
146
  os.remove(temp_path)
147
 
148
-
149
  @app.post("/extract_features/")
150
  async def extract_features(file: UploadFile = File(...), token: str = Depends(verify_token)):
151
  """
 
74
  @app.post("/classify/")
75
  async def classify_image(file: UploadFile = File(...), token: str = Depends(verify_token)):
76
  """
77
+ Endpoint principal: Recebe uma imagem, extrai features e classifica com % de confiança.
78
  """
79
 
80
  print(f">> [{datetime.now().strftime('%d/%m %H:%M:%S')}] | Recebida imagem: {file.filename}.")
 
88
  raise HTTPException(status_code=500, detail=f"Erro ao salvar arquivo: {e}")
89
 
90
  try:
91
+ #Extrai Features
 
92
  features_array = process_single_image(temp_path)
93
 
94
+ #Prepara o vetor
 
95
  nova_feature = features_array.reshape(1, -1)
96
 
97
+ #Normaliza e Reduz
 
98
  nova_feature_scaled = SCALER.transform(nova_feature)
 
 
99
  nova_feature_umap = UMAP.transform(nova_feature_scaled)
100
 
101
+ #MUDANÇA: LÓGICA DE PROBABILIDADE
102
+
103
+ #Obtém as probabilidades de TODAS as classes
104
+ #Retorna algo como [[0.05, 0.90, 0.05...]]
105
+ probs = SVM.predict_proba(nova_feature_umap)[0]
106
+
107
+ #Descobre o índice da maior probabilidade (o vencedor)
108
+ max_idx = np.argmax(probs)
109
 
110
+ #Pega o valor dessa probabilidade (a confiança)
111
+ confianca_valor = probs[max_idx] # Ex: 0.9542
112
+
113
+ #Converte o índice vencedor para o nome técnico
114
+ classe_predita_raw = ENCODER.inverse_transform([max_idx])[0]
115
 
116
+ #BLINDAGEM: normaliza a string
117
  classe_predita = normalize_string(str(classe_predita_raw))
118
 
119
+ #Formata a confiança para string (Ex: "95.42%")
120
+ confianca_str = f"{confianca_valor * 100:.2f}%"
121
+
122
+ #DEBUG: Verificando chaves
123
+ #print(f"DEBUG CHAVES: Modelo='{repr(classe_predita)}'")
124
 
125
  #BUSCA AS INFORMAÇÕES
126
  info_adicional = DB_INFO.get(classe_predita, {
 
131
  })
132
 
133
  #PEGA O NOME "BONITO" DO JSON
 
134
  nome_exibicao = info_adicional.get("nome", classe_predita)
135
 
136
+ print(f">> [{datetime.now().strftime('%d/%m %H:%M:%S')}] | Diagnóstico: {classe_predita} | Confiança: {confianca_str}")
137
 
138
  return {
139
+ "diagnostico": nome_exibicao,
140
+ "confianca": confianca_str, # <--- NOVO CAMPO
141
+ "id_tecnico": classe_predita,
142
  "info": info_adicional
143
  }
144
 
145
+ except Exception as e:
146
+ raise HTTPException(status_code=500, detail=f"Erro no processamento: {e}")
147
+
148
+ finally:
149
+ if os.path.exists(temp_path):
150
+ os.remove(temp_path)
151
+
152
  except Exception as e:
153
  #Pega qualquer erro que acontecer durante a extração ou classificação
154
  raise HTTPException(status_code=500, detail=f"Erro no processamento: {e}")
 
158
  if os.path.exists(temp_path):
159
  os.remove(temp_path)
160
 
 
161
  @app.post("/extract_features/")
162
  async def extract_features(file: UploadFile = File(...), token: str = Depends(verify_token)):
163
  """