File size: 6,789 Bytes
0d30c79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4d80bbb
0d30c79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75cf37f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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)