Spaces:
Sleeping
Sleeping
Upload 2 files
Browse files- app.py +1 -136
- requirements.txt +4 -1
app.py
CHANGED
@@ -1,136 +1 @@
|
|
1 |
-
|
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)}"
|
73 |
-
if bastonetes:
|
74 |
-
leuco_str += f" + {bastonetes}% B"
|
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()
|
|
|
1 |
+
<CÓDIGO FINAL COM OCR INSERIDO AQUI (reduzido para visualização)>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
@@ -1,2 +1,5 @@
|
|
1 |
gradio>=5.26.0
|
2 |
-
|
|
|
|
|
|
|
|
1 |
gradio>=5.26.0
|
2 |
+
pymupdf
|
3 |
+
pytesseract
|
4 |
+
pillow
|
5 |
+
pandas
|