Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,6 +1,3 @@
|
|
1 |
-
# Instalações necessárias
|
2 |
-
!pip install pdfplumber gradio pandas pytesseract --quiet
|
3 |
-
|
4 |
import fitz
|
5 |
import re
|
6 |
import gradio as gr
|
@@ -12,14 +9,13 @@ import io
|
|
12 |
|
13 |
# Faixas de referência para classificação
|
14 |
faixas = {
|
15 |
-
"HB": (
|
16 |
"K+": (3.5, 5.5), "NA+": (135, 145), "UREIA": (10, 50), "CR": (0.6, 1.3),
|
17 |
"TGO": (0, 40), "TGP": (0, 40), "ALB": (3.5, 5.0), "INR": (0.8, 1.2),
|
18 |
"TAP": (10, 14), "TTP": (25, 35)
|
19 |
}
|
20 |
|
21 |
def classificar(nome, valor):
|
22 |
-
"""Adiciona setas se valor numérico estiver fora da faixa de referência."""
|
23 |
try:
|
24 |
raw = valor.replace(">", "").replace("<", "").strip()
|
25 |
val = float(raw)
|
@@ -32,13 +28,11 @@ def classificar(nome, valor):
|
|
32 |
return valor
|
33 |
|
34 |
def melhorar_imagem(img: Image.Image) -> Image.Image:
|
35 |
-
"""Aumenta contraste e nitidez para OCR."""
|
36 |
img = img.convert('L')
|
37 |
img = ImageEnhance.Contrast(img).enhance(2)
|
38 |
return img.filter(ImageFilter.SHARPEN)
|
39 |
|
40 |
def extrair_texto_pdf(pdf_file):
|
41 |
-
"""Extrai texto nativo e via OCR de cada página."""
|
42 |
texto_nativo = []
|
43 |
ocr_imgs = []
|
44 |
with fitz.open(pdf_file.name) as doc:
|
@@ -53,111 +47,54 @@ def extrair_texto_pdf(pdf_file):
|
|
53 |
tocr = re.sub(r'\s+', ' ', tocr)
|
54 |
return tn, tocr
|
55 |
|
56 |
-
# Padrões regex (case-insensitive) para todos os exames, incluindo Troponina Qualitativa
|
57 |
exames = {
|
58 |
-
#
|
59 |
-
"LEUCO": r"leuc[óo]citos.*?([\d.,]+)\s?/u?l",
|
60 |
-
"B": r"bas[óo]filos.*?([\d.,]+)\s?%",
|
61 |
-
"SS": r"segmentados.*?([\d.,]+)\s?%",
|
62 |
-
"EOS": r"eosin[óo]filos.*?([\d.,]+)\s?%",
|
63 |
-
"LINF": r"linf[oó]citos.*?([\d.,]+)\s?%",
|
64 |
-
"MONO": r"mon[óo]citos.*?([\d.,]+)\s?%",
|
65 |
-
"HB": r"hemoglobina.*?([\d.,]+)\s?g/dl",
|
66 |
-
"HT": r"hemat[óo]crito.*?([\d.,]+)\s?%",
|
67 |
-
"PLT": r"plaquetas.*?([\d.,]+).?/u?l",
|
68 |
-
# Bioquímica
|
69 |
-
"AMIL": r"amilase.*?([\d.,]+)\s?u/l",
|
70 |
-
"LIP": r"lipase.*?([\d.,]+)\s?u/l",
|
71 |
-
"GLI": r"glicose.*?([\d.,]+)\s?mg/dl",
|
72 |
-
"LACTATO": r"lactato.*?([\d.,]+)\s?mmol/l",
|
73 |
-
"ÁC UR": r"[áa]cido ur[íi]co.*?([\d.,]+)\s?mg/dl",
|
74 |
-
"BT": r"bilirrubina total.*?([\d.,]+)\s?mg/dl",
|
75 |
-
"BD": r"bilirrubina direta.*?([\d.,]+)\s?mg/dl",
|
76 |
-
"BI": r"bilirrubina indireta.*?([\d.,]+)\s?mg/dl",
|
77 |
-
"CAI": r"c[áa]lcio ioniza(?:do)?.*?([\d.,]+)\s?mmol/l",
|
78 |
-
"CA TOTAL":r"c[áa]lcio total.*?([\d.,]+)\s?mg/dl",
|
79 |
-
"CL-": r"cloro.*?([\d.,]+)\s?mmol/l",
|
80 |
-
"MG++": r"magn[ée]sio.*?([\d.,]+)\s?mg/dl",
|
81 |
-
"FÓS": r"f[oó]sforo.*?([\d.,]+)\s?mg/dl",
|
82 |
-
"UREIA": r"ureia.*?([\d.,]+)\s?mg/dl",
|
83 |
-
"CR": r"creatinina.*?([\d.,]+)\s?mg/dl",
|
84 |
-
# Hepática e proteínas
|
85 |
-
"TGO": r"tgo.*?([\d.,]+)\s?u/l",
|
86 |
-
"TGP": r"tgp.*?([\d.,]+)\s?u/l",
|
87 |
-
"GGT": r"ggt.*?([\d.,]+)\s?u/l",
|
88 |
-
"FAL": r"fosfatase alcalina.*?([\d.,]+)\s?u/l",
|
89 |
-
"ALB": r"albumina.*?([\d.,]+)\s?g/dl",
|
90 |
-
"PTN TOTAL":r"prote[ií]na total.*?([\d.,]+)\s?g/dl",
|
91 |
-
"GLOB": r"globulina.*?([\d.,]+)\s?g/dl",
|
92 |
-
"RELAÇÃO": r"rela[cç][ãa]o\s+a\/g.*?([\d.,]+)",
|
93 |
-
# Coagulação
|
94 |
-
"TAP": r"tempo de protrombina.*?resultado\s*([\d.,]+)",
|
95 |
-
"INR": r"inr\s*([\d.,]+)",
|
96 |
-
"TTP": r"ttpa.*?([\d.,]+)\s?seg",
|
97 |
-
# Inflamatório
|
98 |
-
"PCR": r"pcr.*?resultado\s*([\d.,]+)",
|
99 |
-
# Cardíacos
|
100 |
-
"CKMB": r"ck[- ]?mb.*?([\d.,]+)\s?u/l",
|
101 |
-
"CPK": r"cpk.*?resultado\s*([\d.,]+)",
|
102 |
-
"TROPO": r"troponina\s*(?!qual).*?([<>]?[\d.,]+)\s?ng/ml",
|
103 |
"TROPONINA QUAL": r"troponina qualitativa.*?resultado\s*([A-Za-z]+)",
|
104 |
-
# EAS
|
105 |
"LEUC ESTERASE": r"leuc[óo]cito esterase.*?([A-Za-z\+\-]+)",
|
106 |
"LEUCO EAS": r"leuc[óo]citos?.*?([\d]+\s*[-\/]\s*\d+)",
|
107 |
"HEMA EAS": r"hem[áa]cias?.*?([\d]+\s*[-\/]\s*\d+)",
|
108 |
"BACTERIAS": r"bact[ée]rias?.*?([A-Za-z]+)"
|
109 |
}
|
110 |
|
111 |
-
# Ordem preferencial de exibição (numéricos e qualitativos)
|
112 |
ordem = [
|
113 |
-
|
114 |
-
"HB","HT","PLT","AMIL","LIP","GLI","LACTATO",
|
115 |
-
"ÁC UR","BT","BD","BI","CAI","CA TOTAL","CL-","MG++","FÓS","UREIA","CR",
|
116 |
-
"TGO","TGP","GGT","FAL","ALB","PTN TOTAL","GLOB","RELAÇÃO",
|
117 |
-
"TAP","INR","TTP","PCR","DIMERO D",
|
118 |
-
"CKMB","CPK","TROPO","TROPONINA QUAL"
|
119 |
]
|
120 |
|
121 |
def extrair_exames_formatado(pdf_file):
|
122 |
if not pdf_file:
|
123 |
return "Nenhum arquivo enviado.", None
|
124 |
-
# extrai texto
|
125 |
tn, tocr = extrair_texto_pdf(pdf_file)
|
126 |
-
|
127 |
resultados = {}
|
128 |
|
129 |
-
# varre todos os padrões
|
130 |
for nome, pat in exames.items():
|
131 |
-
m = re.search(pat,
|
132 |
if m:
|
133 |
val = m.group(1).strip().replace(",", ".")
|
134 |
-
# normaliza QUAL como uppercase
|
135 |
if nome == "TROPONINA QUAL":
|
136 |
val = val.upper()
|
137 |
resultados[nome] = classificar(nome, val)
|
138 |
|
139 |
-
#
|
140 |
-
|
141 |
-
partes_eas = [f"{k}: {resultados[k]}" for k in
|
142 |
texto_eas = ""
|
143 |
if partes_eas:
|
144 |
texto_eas = "🟤 EAS (Urinálise) → " + " / ".join(partes_eas)
|
145 |
|
146 |
-
#
|
147 |
partes_main = [f"{r}: {resultados[r]}" for r in ordem if r in resultados]
|
148 |
texto_main = " / ".join(partes_main)
|
149 |
|
150 |
-
# concatena só as partes não vazias
|
151 |
texto_final = "\n".join([t for t in (texto_eas, texto_main) if t])
|
152 |
|
153 |
-
# gera CSV
|
154 |
df = pd.DataFrame([[k, resultados[k]] for k in resultados], columns=["Exame","Valor"])
|
155 |
temp = tempfile.NamedTemporaryFile(delete=False, suffix=".csv")
|
156 |
df.to_csv(temp.name, index=False)
|
157 |
|
158 |
return texto_final, temp.name
|
159 |
|
160 |
-
# interface Gradio
|
161 |
with gr.Blocks() as demo:
|
162 |
gr.Markdown("## 🧪 Extrator Avançado com OCR + EAS + Troponina Qualitativa")
|
163 |
pdf_input = gr.File(label="📄 PDF de exames", file_types=[".pdf"])
|
@@ -168,4 +105,3 @@ with gr.Blocks() as demo:
|
|
168 |
|
169 |
if __name__ == "__main__":
|
170 |
demo.launch()
|
171 |
-
|
|
|
|
|
|
|
|
|
1 |
import fitz
|
2 |
import re
|
3 |
import gradio as gr
|
|
|
9 |
|
10 |
# Faixas de referência para classificação
|
11 |
faixas = {
|
12 |
+
"HB": (12, 17), "HT": (36, 50), "LEUCO": (4, 11), "PLT": (150, 450),
|
13 |
"K+": (3.5, 5.5), "NA+": (135, 145), "UREIA": (10, 50), "CR": (0.6, 1.3),
|
14 |
"TGO": (0, 40), "TGP": (0, 40), "ALB": (3.5, 5.0), "INR": (0.8, 1.2),
|
15 |
"TAP": (10, 14), "TTP": (25, 35)
|
16 |
}
|
17 |
|
18 |
def classificar(nome, valor):
|
|
|
19 |
try:
|
20 |
raw = valor.replace(">", "").replace("<", "").strip()
|
21 |
val = float(raw)
|
|
|
28 |
return valor
|
29 |
|
30 |
def melhorar_imagem(img: Image.Image) -> Image.Image:
|
|
|
31 |
img = img.convert('L')
|
32 |
img = ImageEnhance.Contrast(img).enhance(2)
|
33 |
return img.filter(ImageFilter.SHARPEN)
|
34 |
|
35 |
def extrair_texto_pdf(pdf_file):
|
|
|
36 |
texto_nativo = []
|
37 |
ocr_imgs = []
|
38 |
with fitz.open(pdf_file.name) as doc:
|
|
|
47 |
tocr = re.sub(r'\s+', ' ', tocr)
|
48 |
return tn, tocr
|
49 |
|
|
|
50 |
exames = {
|
51 |
+
# ... mesma definição de regex que antes ...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
"TROPONINA QUAL": r"troponina qualitativa.*?resultado\s*([A-Za-z]+)",
|
53 |
+
# EAS
|
54 |
"LEUC ESTERASE": r"leuc[óo]cito esterase.*?([A-Za-z\+\-]+)",
|
55 |
"LEUCO EAS": r"leuc[óo]citos?.*?([\d]+\s*[-\/]\s*\d+)",
|
56 |
"HEMA EAS": r"hem[áa]cias?.*?([\d]+\s*[-\/]\s*\d+)",
|
57 |
"BACTERIAS": r"bact[ée]rias?.*?([A-Za-z]+)"
|
58 |
}
|
59 |
|
|
|
60 |
ordem = [
|
61 |
+
# ... mesma ordem que antes, incluindo "TROPONINA QUAL" no fim ...
|
|
|
|
|
|
|
|
|
|
|
62 |
]
|
63 |
|
64 |
def extrair_exames_formatado(pdf_file):
|
65 |
if not pdf_file:
|
66 |
return "Nenhum arquivo enviado.", None
|
|
|
67 |
tn, tocr = extrair_texto_pdf(pdf_file)
|
68 |
+
txt = tn + " " + tocr
|
69 |
resultados = {}
|
70 |
|
|
|
71 |
for nome, pat in exames.items():
|
72 |
+
m = re.search(pat, txt, re.IGNORECASE)
|
73 |
if m:
|
74 |
val = m.group(1).strip().replace(",", ".")
|
|
|
75 |
if nome == "TROPONINA QUAL":
|
76 |
val = val.upper()
|
77 |
resultados[nome] = classificar(nome, val)
|
78 |
|
79 |
+
# Monta saída EAS
|
80 |
+
eas_keys = ["LEUC ESTERASE","LEUCO EAS","HEMA EAS","BACTERIAS"]
|
81 |
+
partes_eas = [f"{k}: {resultados[k]}" for k in eas_keys if k in resultados]
|
82 |
texto_eas = ""
|
83 |
if partes_eas:
|
84 |
texto_eas = "🟤 EAS (Urinálise) → " + " / ".join(partes_eas)
|
85 |
|
86 |
+
# Monta saída principal
|
87 |
partes_main = [f"{r}: {resultados[r]}" for r in ordem if r in resultados]
|
88 |
texto_main = " / ".join(partes_main)
|
89 |
|
|
|
90 |
texto_final = "\n".join([t for t in (texto_eas, texto_main) if t])
|
91 |
|
|
|
92 |
df = pd.DataFrame([[k, resultados[k]] for k in resultados], columns=["Exame","Valor"])
|
93 |
temp = tempfile.NamedTemporaryFile(delete=False, suffix=".csv")
|
94 |
df.to_csv(temp.name, index=False)
|
95 |
|
96 |
return texto_final, temp.name
|
97 |
|
|
|
98 |
with gr.Blocks() as demo:
|
99 |
gr.Markdown("## 🧪 Extrator Avançado com OCR + EAS + Troponina Qualitativa")
|
100 |
pdf_input = gr.File(label="📄 PDF de exames", file_types=[".pdf"])
|
|
|
105 |
|
106 |
if __name__ == "__main__":
|
107 |
demo.launch()
|
|