tuliodisanto commited on
Commit
d761fa8
·
verified ·
1 Parent(s): 2f64469

Update enhanced_search_v2.py

Browse files
Files changed (1) hide show
  1. 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 Exata Robusta: Encontra correspondências exatas do conteúdo,
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 (exata) à 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,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
- sem pontuação e com espaços padronizados.
35
  """
36
  if pd.isna(text): return ""
37
  normalized = unidecode(str(text).lower())
38
- normalized = re.sub(r'[^\w\s]', '', normalized)
 
 
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
- # --- CAMADA 0: Busca Exata (Normalizada) --- ### ALTERAÇÃO NO TÍTULO ###
 
 
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
- ### ALTERAÇÃO PRINCIPAL AQUI ###
216
- # Trocamos a busca por 'contains' com regex por uma comparação exata '=='.
217
- # Isso funciona porque tanto 'literal_query' quanto as colunas '*_literal'
218
- # foram normalizadas da mesma forma (sem acentos, caixa baixa, espaços padronizados).
219
- mask = df_normalized[col] == literal_query
220
-
221
  matches = df_normalized[mask]
222
  for index, _ in matches.iterrows():
223
  if index not in matched_indices:
224
- ### ALTERAÇÃO ### - Atualiza o tipo de match para refletir a nova lógica.
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
- ### ALTERAÇÃO ### - Atualiza o nome da camada de saída para o log.
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
- ### ALTERAÇÃO ### - Atualiza o nome da camada no log final
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