GABRIELSZK commited on
Commit
bd30344
·
verified ·
1 Parent(s): f522265

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -73
app.py CHANGED
@@ -1,35 +1,72 @@
1
  import fitz
2
  import re
3
  import gradio as gr
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  def extrair_exames_formatado(pdf_file):
6
  if pdf_file is None:
7
- return "Nenhum arquivo enviado."
8
 
9
  texto = ""
10
  with fitz.open(pdf_file.name) as doc:
11
  for page in doc:
12
  texto += page.get_text()
13
 
14
- # Remove quebras de linha para facilitar os regex
15
  texto = texto.replace('\n', ' ').replace('\r', ' ')
16
 
17
- def buscar(padrao):
18
- match = re.search(padrao, texto, re.IGNORECASE)
19
- if match:
20
- return match.group(1).replace(",", ".").strip()
 
 
 
21
  return None
22
 
23
  def k_format(v):
24
  try:
25
- n = float(v.replace(".", "").replace(",", "."))
26
  return f"{round(n / 1000, 1)}K" if n >= 1000 else str(n)
27
  except:
28
  return v
29
 
30
- leuco = buscar(r"leuc[óo]citos\s+(\d{3,5})")
31
- bastonetes = buscar(r"bastonetes\s+(\d+)\s*%")
32
- segmentados = buscar(r"segmentados\s+(\d+)\s*%")
33
  leuco_str = ""
34
  if leuco:
35
  leuco_str = f"LEUCO {k_format(leuco)}"
@@ -38,76 +75,62 @@ def extrair_exames_formatado(pdf_file):
38
  if segmentados:
39
  leuco_str += f" + {segmentados}% SS"
40
 
41
- exames = {
42
- "🟠 Renal / Eletrólitos": {
43
- "UREIA": buscar(r"ureia[^:\d]{0,10}[:=]?\s*([\d.,]+)\s*mg"),
44
- "CR": buscar(r"creatinina[^:\d]{0,10}[:=]?\s*([\d.,]+)\s*mg"),
45
- "K+": buscar(r"(?:pot[áa]ssio|k\+)[^:\d]{0,10}[:=]?\s*([\d.,]+)\s*mmol"),
46
- "NA+": buscar(r"(?:s[óo]dio|na\+)[^:\d]{0,10}[:=]?\s*([\d.,]+)\s*mmol"),
47
- "CL-": buscar(r"(?:cl[óo]ro|c\s*l\s*[óo]?)\s*[:=]?\s*([\d.,]+)"),
48
- "CAI": buscar(r"(?:c[áa]lcio ioniz[áa]vel|ioniz[áa]vel)[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
49
- "CA TOTAL": buscar(r"(?:c[áa]lcio total)[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
50
- "MG++": buscar(r"(?:magn[ée]sio)[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
51
- "FÓS": buscar(r"(?:f[óo]sforo)[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
52
- },
53
- "🟡 Hepático": {
54
- "BT": buscar(r"bilirrubina total[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
55
- "BD": buscar(r"bilirrubina direta[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
56
- "BI": buscar(r"bilirrubina indireta[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
57
- "TGO": buscar(r"TGO[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
58
- "TGP": buscar(r"TGP[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
59
- "GGT": buscar(r"gama[\- ]?gt[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
60
- "FAL": buscar(r"fosfatase alcalina[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
61
- "ALB": buscar(r"albumina[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
62
- "PTN TOTAL": buscar(r"prote[ií]nas? totais?[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
63
- "GLOB": buscar(r"globulina[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
64
- "RELAÇÃO": buscar(r"relaç[aã]o\s*(A\/G)?[^:\d]{0,10}[:=]?\s*([\d.,]+)")
65
- },
66
- "🔴 Hematológico": {
67
- "HB": buscar(r"hemoglobina[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
68
- "HT": buscar(r"hemat[óo]crito[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
69
- "PLT": buscar(r"plaquetas[^:\d]{0,10}[:=]?\s*([\d.,]+)")
70
- },
71
- "🔵 Coagulação": {
72
- "TAP": buscar(r"TP\s*[:=]?\s*([\d.,]+)\s*seg"), # Tempo de Protrombina
73
- "INR": buscar(r"INR\s*[:=]?\s*([\d.,]+)"),
74
- "TTP": buscar(r"TTPA.*?tempo[^:\d]{0,10}[:=]?\s*([\d.,]+)\s*seg"),
75
- "RELAÇÃO": buscar(r"relaç[aã]o\s*paciente.*?[:=]?\s*([\d.,]+)"),
76
- "D-DÍMERO": buscar(r"d[íi]mero[ -]?d.*?[:=]?\s*([<>]?\s*[\d.,]+)")
77
- },
78
- "🟢 Metabólico": {
79
- "GLI": buscar(r"(glicose)[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
80
- "LIP": buscar(r"lipase[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
81
- "AMIL": buscar(r"amilase[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
82
- "AC UR": buscar(r"[áa]cido[ \n]+[úu]rico[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
83
- "LAC": buscar(r"lactato[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
84
- "PCR": buscar(r"PCR[^:\d]{0,10}[:=]?\s*([\d.,]+)\s*mg")
85
- },
86
- "❤️ Cardíaco": {
87
- "CPK": buscar(r"creatinofosfoquinase.*?[:=]?\s*([\d.,]+)"),
88
- "CKMB": buscar(r"CKMB(?:\s*massa)?[^:\d]{0,10}[:=]?\s*([\d.,]+)"),
89
- "TROPO": buscar(r"troponina.*?[:=]?\s*([<>]?\s*[\d.,]+)")
90
- }
91
  }
92
 
93
- output = []
94
  if leuco_str:
95
- output.append(leuco_str)
96
- for sistema, dados in exames.items():
97
- linha = []
98
- for k, v in dados.items():
99
- linha.append(f"{k}: {v if v else '—'}")
100
- output.append(f"{sistema} " + " / ".join(linha))
 
 
 
 
 
 
 
 
 
 
101
 
102
- return "\n".join(output)
103
 
104
- # Interface Gradio
105
  with gr.Blocks() as demo:
106
- gr.Markdown("## 🧪 Extrator de Exames PDF Versão Robusta")
107
  pdf_file = gr.File(label="📄 PDF de exames", file_types=[".pdf"])
108
- output_text = gr.Textbox(label="📋 Resultado Estruturado", lines=25)
109
- extract_button = gr.Button("🔍 Extrair")
 
110
 
111
- extract_button.click(fn=extrair_exames_formatado, inputs=pdf_file, outputs=output_text)
112
 
113
  demo.launch()
 
1
  import fitz
2
  import re
3
  import gradio as gr
4
+ import pandas as pd
5
+ import tempfile
6
+
7
+ # Faixas de referência básicas para classificação (valores em mg/dL, g/dL, etc.)
8
+ faixas = {
9
+ "HB": (12, 17),
10
+ "HT": (36, 50),
11
+ "GLI": (70, 99),
12
+ "UREIA": (10, 50),
13
+ "CR": (0.6, 1.3),
14
+ "K+": (3.5, 5.5),
15
+ "NA+": (135, 145),
16
+ "TGO": (0, 40),
17
+ "TGP": (0, 40),
18
+ "ALB": (3.5, 5.0),
19
+ "INR": (0.8, 1.2),
20
+ "TAP": (10, 14),
21
+ "TTP": (25, 35),
22
+ "LAC": (0.5, 2.2),
23
+ "PLT": (150000, 450000),
24
+ "LEUCO": (4000, 11000)
25
+ }
26
+
27
+ def classificar(nome, valor):
28
+ try:
29
+ val = float(valor.replace("K", "000").replace(">", "").replace("<", "").strip())
30
+ if nome in faixas:
31
+ min_v, max_v = faixas[nome]
32
+ if val < min_v:
33
+ return f"{valor} ↓"
34
+ elif val > max_v:
35
+ return f"{valor} ↑"
36
+ return valor
37
+ except:
38
+ return valor
39
 
40
  def extrair_exames_formatado(pdf_file):
41
  if pdf_file is None:
42
+ return "Nenhum arquivo enviado.", None
43
 
44
  texto = ""
45
  with fitz.open(pdf_file.name) as doc:
46
  for page in doc:
47
  texto += page.get_text()
48
 
 
49
  texto = texto.replace('\n', ' ').replace('\r', ' ')
50
 
51
+ def buscar(padrao, excluir_protocolo=True):
52
+ matches = re.findall(padrao, texto, re.IGNORECASE)
53
+ for match in matches:
54
+ val = match.strip().replace(",", ".")
55
+ if excluir_protocolo and len(val.replace(".", "").replace(">", "").replace("<", "")) > 5:
56
+ continue # ignora IDs longos como 2500267046
57
+ return val
58
  return None
59
 
60
  def k_format(v):
61
  try:
62
+ n = float(v)
63
  return f"{round(n / 1000, 1)}K" if n >= 1000 else str(n)
64
  except:
65
  return v
66
 
67
+ leuco = buscar(r"leuc[óo]citos[^:\d]{0,10}[:=]?\s*(\d{3,5})")
68
+ bastonetes = buscar(r"bastonetes[^:\d]{0,10}[:=]?\s*(\d+)\s*%")
69
+ segmentados = buscar(r"segmentados[^:\d]{0,10}[:=]?\s*(\d+)\s*%")
70
  leuco_str = ""
71
  if leuco:
72
  leuco_str = f"LEUCO {k_format(leuco)}"
 
75
  if segmentados:
76
  leuco_str += f" + {segmentados}% SS"
77
 
78
+ campos = {
79
+ "UREIA": r"ureia[^:\d]{0,10}[:=]?\s*([\d.,]+)",
80
+ "CR": r"creatinina[^:\d]{0,10}[:=]?\s*([\d.,]+)",
81
+ "K+": r"(?:pot[áa]ssio|k\+)[^:\d]{0,10}[:=]?\s*([\d.,]+)",
82
+ "NA+": r"(?:s[óo]dio|na\+)[^:\d]{0,10}[:=]?\s*([\d.,]+)",
83
+ "CL-": r"(?:cl[óo]ro)[^:\d]{0,10}[:=]?\s*([\d.,]+)",
84
+ "CAI": r"ioniz[áa]vel[^:\d]{0,10}[:=]?\s*([\d.,]+)",
85
+ "CA TOTAL": r"c[áa]lcio total[^:\d]{0,10}[:=]?\s*([\d.,]+)",
86
+ "MG++": r"magn[ée]sio[^:\d]{0,10}[:=]?\s*([\d.,]+)",
87
+ "FÓS": r"f[óo]sforo[^:\d]{0,10}[:=]?\s*([\d.,]+)",
88
+ "GLI": r"glicose[^:\d]{0,10}[:=]?\s*([\d.,]+)",
89
+ "HB": r"hemoglobina[^:\d]{0,10}[:=]?\s*([\d.,]+)",
90
+ "HT": r"hemat[óo]crito[^:\d]{0,10}[:=]?\s*([\d.,]+)",
91
+ "PLT": r"plaquetas[^:\d]{0,10}[:=]?\s*([\d.,]+)",
92
+ "INR": r"INR[^:\d]{0,10}[:=]?\s*([\d.,]+)",
93
+ "TAP": r"\bTP[^:\d]{0,10}[:=]?\s*([\d.,]+)\s*seg",
94
+ "TTP": r"TTPA[^:\d]{0,10}[:=]?\s*([\d.,]+)\s*seg",
95
+ "RELAÇÃO": r"relaç[aã]o.*?(?:paciente|a\/g)[^:\d]{0,10}[:=]?\s*([\d.,]+)",
96
+ "LAC": r"lactato[^:\d]{0,10}[:=]?\s*([\d.,]+)",
97
+ "TGO": r"\bTGO[^:\d]{0,10}[:=]?\s*([\d.,]+)",
98
+ "TGP": r"\bTGP[^:\d]{0,10}[:=]?\s*([\d.,]+)",
99
+ "ALB": r"albumina[^:\d]{0,10}[:=]?\s*([\d.,]+)",
100
+ "PCR": r"PCR[^:\d]{0,10}[:=]?\s*([\d.,]+)",
101
+ "CPK": r"creatinofosfoquinase.*?[:=]?\s*([\d.,]+)",
102
+ "CKMB": r"CKMB(?:\s*massa)?[^:\d]{0,10}[:=]?\s*([\d.,]+)",
103
+ "TROPO": r"troponina.*?[:=]?\s*([<>]?\s*[\d.,]+)",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  }
105
 
106
+ resultados = []
107
  if leuco_str:
108
+ resultados.append(("LEUCO", leuco_str))
109
+
110
+ for rotulo, padrao in campos.items():
111
+ val = buscar(padrao)
112
+ if val:
113
+ val = classificar(rotulo, val)
114
+ resultados.append((rotulo, val))
115
+ else:
116
+ resultados.append((rotulo, "—"))
117
+
118
+ df = pd.DataFrame(resultados, columns=["Exame", "Valor"])
119
+ texto_final = "\n".join([f"{r[0]}: {r[1]}" for r in resultados])
120
+
121
+ # Exportação CSV temporária
122
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".csv")
123
+ df.to_csv(temp_file.name, index=False)
124
 
125
+ return texto_final, temp_file.name
126
 
 
127
  with gr.Blocks() as demo:
128
+ gr.Markdown("## 🧪 Extrator Inteligente de Exames Laboratoriais - PDF para Diagnóstico")
129
  pdf_file = gr.File(label="📄 PDF de exames", file_types=[".pdf"])
130
+ extract_button = gr.Button("🔍 Extrair Exames")
131
+ output_text = gr.Textbox(label="📋 Exames extraídos e classificados", lines=25)
132
+ download_button = gr.File(label="📥 Baixar CSV")
133
 
134
+ extract_button.click(fn=extrair_exames_formatado, inputs=pdf_file, outputs=[output_text, download_button])
135
 
136
  demo.launch()