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("