Spaces:
Sleeping
Sleeping
Update enhanced_search_v2.py
Browse files- enhanced_search_v2.py +19 -17
enhanced_search_v2.py
CHANGED
|
@@ -5,10 +5,10 @@
|
|
| 5 |
#
|
| 6 |
# Funcionalidades Principais:
|
| 7 |
# 1. Correção Ortográfica PRÉ-BUSCA: Corrige termos inválidos ANTES de qualquer busca.
|
| 8 |
-
# 2. Camada 0 para Busca
|
| 9 |
# ignorando caixa, acentos, pontuação e espaçamento.
|
| 10 |
# 3. Early Exit Otimizado: Interrompe a busca com log claro e correto.
|
| 11 |
-
# 4. Busca em Múltiplas Camadas: Da mais restrita (
|
| 12 |
# 5. Pontuação por Relevância (IDF): Palavras raras têm mais peso.
|
| 13 |
# 6. Limpeza de Dados: Zera campos do Rol para procedimentos que não são do Rol.
|
| 14 |
# 7. Reordenação Semântica: Usa o MiniLM-L6-v2 para entender o significado e reordenar.
|
|
@@ -28,14 +28,17 @@ from collections import defaultdict
|
|
| 28 |
|
| 29 |
# --- FUNÇÕES AUXILIARES DE NORMALIZAÇÃO ---
|
| 30 |
|
|
|
|
| 31 |
def literal_normalize_text(text):
|
| 32 |
"""
|
| 33 |
Normaliza o texto para busca literal (Camada 0): minúsculas, sem acentos,
|
| 34 |
-
|
| 35 |
"""
|
| 36 |
if pd.isna(text): return ""
|
| 37 |
normalized = unidecode(str(text).lower())
|
| 38 |
-
|
|
|
|
|
|
|
| 39 |
return re.sub(r'\s+', ' ', normalized).strip()
|
| 40 |
|
| 41 |
def normalize_text(text):
|
|
@@ -206,31 +209,31 @@ def _run_search_layers(literal_query, normalized_query, response, df_original, d
|
|
| 206 |
stopwords = {'de', 'do', 'da', 'dos', 'das', 'a', 'o', 'e', 'em', 'um', 'uma', 'para', 'com'}
|
| 207 |
query_words = [word for word in normalized_query.split() if word not in stopwords and len(word) > 1]
|
| 208 |
|
| 209 |
-
|
|
|
|
|
|
|
| 210 |
if literal_query:
|
| 211 |
temp_results = []
|
| 212 |
literal_cols = ['Codigo_TUSS_literal', 'Descricao_TUSS_literal', 'Procedimento_Rol_literal']
|
| 213 |
for col in literal_cols:
|
| 214 |
if col in df_normalized.columns:
|
| 215 |
-
|
| 216 |
-
#
|
| 217 |
-
#
|
| 218 |
-
#
|
| 219 |
-
mask = df_normalized[col]
|
| 220 |
-
|
| 221 |
matches = df_normalized[mask]
|
| 222 |
for index, _ in matches.iterrows():
|
| 223 |
if index not in matched_indices:
|
| 224 |
-
|
| 225 |
-
match_type = "Código Exato" if "Codigo" in col else "Texto Exato"
|
| 226 |
temp_results.append(format_result(df_original.loc[index], match_type, 100))
|
| 227 |
matched_indices.add(index)
|
| 228 |
if temp_results:
|
| 229 |
response["results_by_layer"]["literal_matches"] = sorted(temp_results, key=lambda x: x['Codigo_TUSS'])[:limit_per_layer]
|
| 230 |
-
|
| 231 |
-
return "Busca Exata"
|
| 232 |
|
| 233 |
# --- CAMADA 1: Busca Normalizada Exata ---
|
|
|
|
| 234 |
temp_results = []
|
| 235 |
if normalized_query:
|
| 236 |
exact_code_matches = df_normalized[df_normalized['Codigo_TUSS_norm'] == normalized_query]
|
|
@@ -433,8 +436,7 @@ def search_procedure_with_log(query, df_original, df_normalized, fuzzy_search_co
|
|
| 433 |
all_candidates = []
|
| 434 |
layer_order = ["literal_matches", "exact_matches", "logical_matches", "almost_exact_matches", "contains_matches", "term_matches", "keyword_matches"]
|
| 435 |
|
| 436 |
-
|
| 437 |
-
layer_names_map = {"literal_matches": "0. Busca Exata", "exact_matches": "1. Normalizada Exata", "logical_matches": "2. Lógica 'E'",
|
| 438 |
"almost_exact_matches": "3. Quase Exatos (Fuzzy)", "contains_matches": "4. Termos Validados",
|
| 439 |
"term_matches": "5. Busca Ponderada (IDF)", "keyword_matches": "6. Fallback (Palavra-Chave)"}
|
| 440 |
|
|
|
|
| 5 |
#
|
| 6 |
# Funcionalidades Principais:
|
| 7 |
# 1. Correção Ortográfica PRÉ-BUSCA: Corrige termos inválidos ANTES de qualquer busca.
|
| 8 |
+
# 2. Camada 0 para Busca Literal Robusta: Encontra correspondências exatas da frase,
|
| 9 |
# ignorando caixa, acentos, pontuação e espaçamento.
|
| 10 |
# 3. Early Exit Otimizado: Interrompe a busca com log claro e correto.
|
| 11 |
+
# 4. Busca em Múltiplas Camadas: Da mais restrita (literal) à mais abrangente (ponderada).
|
| 12 |
# 5. Pontuação por Relevância (IDF): Palavras raras têm mais peso.
|
| 13 |
# 6. Limpeza de Dados: Zera campos do Rol para procedimentos que não são do Rol.
|
| 14 |
# 7. Reordenação Semântica: Usa o MiniLM-L6-v2 para entender o significado e reordenar.
|
|
|
|
| 28 |
|
| 29 |
# --- FUNÇÕES AUXILIARES DE NORMALIZAÇÃO ---
|
| 30 |
|
| 31 |
+
### ALTERAÇÃO ###
|
| 32 |
def literal_normalize_text(text):
|
| 33 |
"""
|
| 34 |
Normaliza o texto para busca literal (Camada 0): minúsculas, sem acentos,
|
| 35 |
+
substitui pontuação por espaço e padroniza espaços em branco.
|
| 36 |
"""
|
| 37 |
if pd.isna(text): return ""
|
| 38 |
normalized = unidecode(str(text).lower())
|
| 39 |
+
# CORREÇÃO: Substitui caracteres não-alfanuméricos por um espaço em vez de removê-los.
|
| 40 |
+
# Isso impede que palavras como "sangue." e "O" se fundam em "sangueO".
|
| 41 |
+
normalized = re.sub(r'[^\w\s]', ' ', normalized)
|
| 42 |
return re.sub(r'\s+', ' ', normalized).strip()
|
| 43 |
|
| 44 |
def normalize_text(text):
|
|
|
|
| 209 |
stopwords = {'de', 'do', 'da', 'dos', 'das', 'a', 'o', 'e', 'em', 'um', 'uma', 'para', 'com'}
|
| 210 |
query_words = [word for word in normalized_query.split() if word not in stopwords and len(word) > 1]
|
| 211 |
|
| 212 |
+
### ALTERAÇÃO ###
|
| 213 |
+
# --- CAMADA 0: Busca Literal (Contida) ---
|
| 214 |
+
# Esta é a lógica correta para encontrar uma frase inteira dentro de um texto maior.
|
| 215 |
if literal_query:
|
| 216 |
temp_results = []
|
| 217 |
literal_cols = ['Codigo_TUSS_literal', 'Descricao_TUSS_literal', 'Procedimento_Rol_literal']
|
| 218 |
for col in literal_cols:
|
| 219 |
if col in df_normalized.columns:
|
| 220 |
+
# Lógica restaurada: Busca pela frase/palavra inteira contida no texto.
|
| 221 |
+
# O '\b' (word boundary) garante que "sulta" não encontre "consulta",
|
| 222 |
+
# mas "consulta" encontre "consulta com especialista".
|
| 223 |
+
# Isso agora funciona corretamente graças à correção em literal_normalize_text.
|
| 224 |
+
mask = df_normalized[col].str.contains(r'\b' + re.escape(literal_query) + r'\b', na=False)
|
|
|
|
| 225 |
matches = df_normalized[mask]
|
| 226 |
for index, _ in matches.iterrows():
|
| 227 |
if index not in matched_indices:
|
| 228 |
+
match_type = "Código Literal" if "Codigo" in col else "Texto Literal"
|
|
|
|
| 229 |
temp_results.append(format_result(df_original.loc[index], match_type, 100))
|
| 230 |
matched_indices.add(index)
|
| 231 |
if temp_results:
|
| 232 |
response["results_by_layer"]["literal_matches"] = sorted(temp_results, key=lambda x: x['Codigo_TUSS'])[:limit_per_layer]
|
| 233 |
+
return "Busca Literal"
|
|
|
|
| 234 |
|
| 235 |
# --- CAMADA 1: Busca Normalizada Exata ---
|
| 236 |
+
# Esta camada agora serve para quando o texto da busca é *exatamente* igual ao da célula.
|
| 237 |
temp_results = []
|
| 238 |
if normalized_query:
|
| 239 |
exact_code_matches = df_normalized[df_normalized['Codigo_TUSS_norm'] == normalized_query]
|
|
|
|
| 436 |
all_candidates = []
|
| 437 |
layer_order = ["literal_matches", "exact_matches", "logical_matches", "almost_exact_matches", "contains_matches", "term_matches", "keyword_matches"]
|
| 438 |
|
| 439 |
+
layer_names_map = {"literal_matches": "0. Busca Literal", "exact_matches": "1. Normalizada Exata", "logical_matches": "2. Lógica 'E'",
|
|
|
|
| 440 |
"almost_exact_matches": "3. Quase Exatos (Fuzzy)", "contains_matches": "4. Termos Validados",
|
| 441 |
"term_matches": "5. Busca Ponderada (IDF)", "keyword_matches": "6. Fallback (Palavra-Chave)"}
|
| 442 |
|