medilite / app.py
shrey2026's picture
Update app.py
4d80bbb verified
Raw
History Blame Contribute Delete
6.79 kB
import gradio as gr
import pytesseract
from PIL import Image
import torch
import re
import os
from transformers import T5ForConditionalGeneration, T5TokenizerFast
from gtts import gTTS
# --- Modular Imports ---
# Ensure these files are in the same folder as app.py
from utils import clean_text, strict_clean_ocr, is_medical_text
from nlp_utils import translate_to_malayalam, get_highlighted_summary
from medical_domain import HIGHLIGHT_TERMS
# =========================
# SETUP & MODELS
# =========================
# Update this path if your Tesseract installation is in a different folder
#pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
summarizer_model = T5ForConditionalGeneration.from_pretrained("t5-base").to(DEVICE)
summarizer_tokenizer = T5TokenizerFast.from_pretrained("t5-base", model_max_length=512)
# =========================
# MAIN PIPELINE
# =========================
def process_image(image, progress=gr.Progress()):
if image is None:
return "", "Please upload an image.", "Please upload an image.", None
# --- 1. OCR Extraction ---
progress(0.2, desc="Extracting Text...")
raw_text = pytesseract.image_to_string(image.convert("L"), config="--psm 6")
# Clean text (Handles clinical units like g/dL, blood pressure formats, etc.)
cleaned = strict_clean_ocr(clean_text(raw_text))[:1200]
# --- 2. Domain Validation ---
if not is_medical_text(cleaned):
return cleaned, "### ⚠️ ERROR\nINVALID MEDICAL REPORT DETECTED.\nPlease upload a valid clinical report.", "", None
# --- 3. Summarization (Memory Efficient) ---
progress(0.5, desc="Analyzing Report...")
input_text = "summarize: " + cleaned.strip()
inputs = summarizer_tokenizer(
input_text,
return_tensors="pt",
truncation=True,
max_length=512
).to(DEVICE)
with torch.no_grad():
outputs = summarizer_model.generate(
input_ids=inputs["input_ids"],
attention_mask=inputs["attention_mask"],
max_new_tokens=200,
min_length=50,
num_beams=6,
repetition_penalty=1.5,
no_repeat_ngram_size=3,
length_penalty=1.2,
early_stopping=True
)
raw_summary = summarizer_tokenizer.decode(outputs[0], skip_special_tokens=True).strip()
# Capitalize sentences for professionalism
raw_summary = re.sub(r'(^|[.!?]\s+)([a-z])', lambda m: m.group(1) + m.group(2).upper(), raw_summary)
# --- 4. Highlighting (English UI Only) ---
progress(0.7, desc="Processing Highlights...")
# Using the new multi-word phrase logic from nlp_utils
highlighted_eng = get_highlighted_summary(raw_summary, HIGHLIGHT_TERMS)
# --- 5. Translation (Clean Input) ---
progress(0.9, desc="Translating to Malayalam...")
mal_summary = translate_to_malayalam(raw_summary)
mal_summary = mal_summary.strip()
# Find the last occurrence of Malayalam punctuation (।) or English (.)
last_punc = max(mal_summary.rfind('।'), mal_summary.rfind('.'))
if last_punc != -1:
# Keep everything up to and including the last full stop
mal_summary = mal_summary[:last_punc + 1]
# ==========================================
# --- 6. Audio Generation ---
audio_file = "output.mp3"
try:
# Generate audio from the Malayalam translation
tts = gTTS(text=mal_summary, lang="ml")
tts.save(audio_file)
audio_output = audio_file
except Exception as e:
print(f"Audio Error: {e}")
audio_output = None
return cleaned, highlighted_eng, mal_summary, audio_output
# =========================
# UI & CSS
# =========================
custom_css = """
footer {visibility: hidden}
.gradio-container {background-color: #f0f4f8}
/* Hides all timers and 'Preparing Output' status text */
.timer, .meta-text, .meta-text-item, .status-tracker, .progress-text, .progress-container, .loading {
display: none !important;
visibility: hidden !important;
}
.output-box {
border-radius: 10px; padding: 10px; background: white;
margin-bottom: 10px; border: 1px solid #d1d9e0;
}
#medical-header {text-align: center; color: #004d99; font-family: 'Segoe UI', sans-serif; margin-bottom: 20px;}
"""
with gr.Blocks(title="MEDILITE") as demo:
gr.HTML("<div id='medical-header'><h1>🩺 MEDILITE - Medical Report Summarizer</h1></div>")
with gr.Tabs():
with gr.Tab("📋 Patient Summary"):
with gr.Row():
# LEFT COLUMN: Upload
with gr.Column(scale=1):
gr.Markdown("### Upload Medical Image")
input_img = gr.Image(type="pil", label=None)
with gr.Row():
clear_btn = gr.Button("Clear", variant="secondary")
submit_btn = gr.Button("Submit", variant="primary")
# RIGHT COLUMN: Boxed UI results
with gr.Column(scale=1):
with gr.Group(elem_classes="output-box"):
gr.Markdown("#### English Summary")
eng_display = gr.Markdown(value="*Results will appear here...*", container=True)
# Malayalam Section
with gr.Group(elem_classes="output-box"):
gr.Markdown("#### മലയാളം സംഗ്രഹം (Malayalam Summary)")
mal_display = gr.Markdown(value="*ഫലങ്ങൾ ഇവിടെ ദൃശ്യമാകും...*", container=True)
# Audio component without internal container
with gr.Group(elem_classes="output-box"):
gr.Markdown("#### Malayalam Audio")
audio_out = gr.Audio(label=None, type="filepath", container=True)
# Technical Tab
with gr.Tab("⚙️ OCR Extraction"):
gr.Markdown("#### Raw OCR Extraction")
extracted_text = gr.Textbox(lines=20, interactive=False)
# --- Button Actions ---
submit_btn.click(
fn=process_image,
inputs=input_img,
outputs=[extracted_text, eng_display, mal_display, audio_out]
)
clear_btn.click(
lambda: [None, "", "*Summary will appear here...*", "*മലയാളം സംഗ്രഹം ഇവിടെ കാണാം...*", None],
outputs=[input_img, extracted_text, eng_display, mal_display, audio_out]
)
if __name__ == "__main__":
# Final launch command
demo.launch(css=custom_css)