IFMedTechdemo commited on
Commit
aff30bc
·
verified ·
1 Parent(s): ad78c1f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +335 -87
app.py CHANGED
@@ -1,4 +1,5 @@
1
- #################################################################################################
 
2
 
3
  import spaces
4
  import gradio as gr
@@ -7,86 +8,109 @@ import numpy as np
7
  import cv2
8
  import re
9
 
10
- import re
 
 
 
 
 
 
 
 
11
 
12
  def extract_medication_lines(text):
13
  """
14
- Extracts medication/drug lines from text using flexible regex.
15
- Supports tablet, capsule, syrup, drops, injection, ointment, cream, gel, patch, solution, etc.
16
- Matches dose like '1/2/10/250/500 mg/ml/mcg/g/kg' or concentration '1%/2%/0.2%/0.5%/10%' w/w, w/v, v/v.
17
  """
18
-
19
  form_pattern = r"(TAB(L?ET)?|CAP(SULE)?|SYRUP|SYP|DROP(S)?|INJ(CTION)?|OINTMENT|CREAM|GEL|PATCH|SOL(UTION)?|ORAL)"
20
- # Drug name: starts with a word (alphanumeric, maybe a hyphen), up to 4 words (spaces, hyphens or slash)
21
  name_pattern = r"([A-Z0-9\-/]+(?:\s+[A-Z0-9\-/]+){0,4})"
22
- # Dose: e.g., 250mg, 10ml, 0.5%, 10 mcg, 150mcg, etc. and concentration/w/w/w/v/etc.
23
  dose_pattern = r"(\d{1,4}\s*(mg|ml|mcg|g|kg|units|IU)|\d{1,2}\s*%(\s*w\/w|\s*w\/v|\s*v\/v)?)"
24
- # concentration can appear for creams/gels: e.g. "1% w/w", "2%"
25
-
26
- # Main pattern: will attempt to capture form anywhere, then name, then dose/concentration
27
  main_pattern = (
28
- r"(?:" + form_pattern + r"\s+)?" + # Form prefix optional
29
- name_pattern + r"\s*" +
30
- r"(?:" + form_pattern + r"\s*)?" + # Form mid/suffix optional
31
- r"(?:" + dose_pattern + r")" # Dose/concentration required
32
  )
33
-
34
  med_regex = re.compile(main_pattern, re.IGNORECASE)
35
-
36
  meds = []
37
  for line in text.split('\n'):
38
  line_stripped = line.strip()
39
  match = med_regex.search(line_stripped)
40
  if match:
41
- meds.append(line_stripped)
 
 
42
  return '\n'.join(meds)
43
 
44
-
45
- def preprocess_image_for_ocr(image):
46
- image_rgb = image.convert("RGB")
47
- img_np = np.array(image_rgb)
48
- gray = cv2.cvtColor(img_np, cv2.COLOR_RGB2GRAY)
49
- adaptive_threshold = cv2.adaptiveThreshold(
50
- gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 85,35,
 
 
 
 
 
 
 
 
 
 
 
51
  )
52
- preprocessed_pil = Image.fromarray(adaptive_threshold)
53
- return preprocessed_pil
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
  @spaces.GPU
56
- def extract_text_from_image(image, temperature=0.2, use_ner=False):
57
- # Import and load within GPU context!
58
  import torch
59
- from transformers import (
60
- LightOnOCRForConditionalGeneration,
61
- LightOnOCRProcessor,
62
- AutoTokenizer, AutoModelForTokenClassification, pipeline,
63
- )
64
 
65
  device = "cuda" if torch.cuda.is_available() else "cpu"
66
- attn_implementation = "sdpa" if device == "cuda" else "eager"
67
  dtype = torch.bfloat16 if device == "cuda" else torch.float32
68
 
69
  ocr_model = LightOnOCRForConditionalGeneration.from_pretrained(
70
  "lightonai/LightOnOCR-1B-1025",
71
- attn_implementation=attn_implementation,
72
  torch_dtype=dtype,
73
  trust_remote_code=True,
74
  ).to(device).eval()
75
-
76
  processor = LightOnOCRProcessor.from_pretrained(
77
  "lightonai/LightOnOCR-1B-1025",
78
  trust_remote_code=True,
79
  )
80
- # NER only if requested
81
- if use_ner:
82
- ner_tokenizer = AutoTokenizer.from_pretrained("samrawal/bert-base-uncased_clinical-ner")
83
- ner_model = AutoModelForTokenClassification.from_pretrained("samrawal/bert-base-uncased_clinical-ner")
84
- ner_pipeline = pipeline(
85
- "ner", model=ner_model, tokenizer=ner_tokenizer, aggregation_strategy="simple"
86
- )
87
 
88
  processed_img = preprocess_image_for_ocr(image)
89
-
90
  chat = [
91
  {
92
  "role": "user",
@@ -122,38 +146,27 @@ def extract_text_from_image(image, temperature=0.2, use_ner=False):
122
  outputs = ocr_model.generate(**generation_kwargs)
123
 
124
  output_text = processor.decode(outputs[0], skip_special_tokens=True)
125
- cleaned_text = output_text.strip()
126
- # Extract medicines
127
- if use_ner:
128
- entities = ner_pipeline(cleaned_text)
129
- meds = []
130
- for ent in entities:
131
- if ent["entity_group"] == "treatment":
132
- word = ent["word"]
133
- if word.startswith("##") and meds:
134
- meds[-1] += word[2:]
135
- else:
136
- meds.append(word)
137
- result_meds = ", ".join(set(meds)) if meds else "None detected"
138
- else:
139
- result_meds = extract_medication_lines(cleaned_text) or "None detected"
140
-
141
- yield result_meds, processed_img # Only medicines and processed image
142
-
143
- def process_input(file_input, temperature, page_num, extraction_mode):
144
  if file_input is None:
145
- yield "Please upload an image or PDF first.", None
146
  return
147
- image_to_process = Image.open(file_input) if not str(file_input).lower().endswith(".pdf") else None # simplify to image only
148
- use_ner = extraction_mode == "Clinical NER"
149
-
150
- for meds_out, processed_img in extract_text_from_image(image_to_process, temperature, use_ner):
151
- yield meds_out, processed_img
152
 
153
  with gr.Blocks(title="💊 Medicine Extraction", theme=gr.themes.Soft()) as demo:
154
  file_input = gr.File(
155
- label="🖼️ Upload Image",
156
- file_types=[".png", ".jpg", ".jpeg"],
157
  type="filepath"
158
  )
159
  temperature = gr.Slider(
@@ -164,39 +177,274 @@ with gr.Blocks(title="💊 Medicine Extraction", theme=gr.themes.Soft()) as demo
164
  label="Temperature"
165
  )
166
  extraction_mode = gr.Radio(
167
- choices=["Clinical NER", "Regex"],
168
  value="Regex",
169
- label="Extraction Method",
170
- info="Clinical NER uses ML, Regex uses rules"
171
  )
172
  medicines_output = gr.Textbox(
173
- label="💊 Extracted Medicines/Drugs",
174
- placeholder="Medicine/drug names will appear here...",
175
- lines=2,
176
- max_lines=10,
 
 
 
 
177
  interactive=False,
178
  show_copy_button=True
179
  )
180
  rendered_image = gr.Image(
181
- label="Processed Image (Adaptive Thresholded for OCR)",
182
  interactive=False
183
  )
184
  submit_btn = gr.Button("Extract Medicines", variant="primary")
185
 
186
- page_slider = gr.Slider(minimum=1, maximum=20, value=1, step=1, label="Page Number")
187
-
188
  submit_btn.click(
189
- fn=process_input,
190
- inputs=[file_input, temperature, page_slider, extraction_mode],
191
- outputs=[medicines_output, rendered_image]
192
- )
193
-
194
 
195
  if __name__ == "__main__":
196
  demo.launch()
197
 
198
 
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  #################################################### running code only NER #######################
201
 
202
  #!/usr/bin/env python3
 
1
+ ###################################### version 4 NER change done #######################################################
2
+
3
 
4
  import spaces
5
  import gradio as gr
 
8
  import cv2
9
  import re
10
 
11
+ def preprocess_image_for_ocr(image):
12
+ image_rgb = image.convert("RGB")
13
+ img_np = np.array(image_rgb)
14
+ gray = cv2.cvtColor(img_np, cv2.COLOR_RGB2GRAY)
15
+ adaptive_threshold = cv2.adaptiveThreshold(
16
+ gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 85, 11,
17
+ )
18
+ preprocessed_pil = Image.fromarray(adaptive_threshold)
19
+ return preprocessed_pil
20
 
21
  def extract_medication_lines(text):
22
  """
23
+ Flexible regex: Find lines with [form], [name], [dose] anywhere.
24
+ Handles free text/table/mixed layouts.
 
25
  """
26
+ # Medicine forms
27
  form_pattern = r"(TAB(L?ET)?|CAP(SULE)?|SYRUP|SYP|DROP(S)?|INJ(CTION)?|OINTMENT|CREAM|GEL|PATCH|SOL(UTION)?|ORAL)"
28
+ # Name: up to 4 tokens (space/hyphen/slash), case/mixed
29
  name_pattern = r"([A-Z0-9\-/]+(?:\s+[A-Z0-9\-/]+){0,4})"
30
+ # Dose/concentration: 1-4 digits, optional space, units
31
  dose_pattern = r"(\d{1,4}\s*(mg|ml|mcg|g|kg|units|IU)|\d{1,2}\s*%(\s*w\/w|\s*w\/v|\s*v\/v)?)"
32
+ # Allow any order: form+name+dose/mid/suffix/prefix
 
 
33
  main_pattern = (
34
+ r"(?<!\w)(" + form_pattern + r")[\s\-]+"
35
+ r"" + name_pattern + r"" # name after form
36
+ r"[^|,\n]{0,50}?"
37
+ r"" + dose_pattern + r"" # dose somewhere after name
38
  )
 
39
  med_regex = re.compile(main_pattern, re.IGNORECASE)
 
40
  meds = []
41
  for line in text.split('\n'):
42
  line_stripped = line.strip()
43
  match = med_regex.search(line_stripped)
44
  if match:
45
+ # Compose: form + name + dose
46
+ cleaned = f"{match.group(1).upper()} {match.group(2).upper()} {match.group(5)}"
47
+ meds.append(cleaned.strip())
48
  return '\n'.join(meds)
49
 
50
+ def clinical_ner_extract(text, use_gpu=False):
51
+ """
52
+ Uses ClinicalNER for medicine name, then finds form/dose in source sentence.
53
+ Returns clean combinations: form + entity + dose (no unwanted text).
54
+ """
55
+ # Load models in GPU context if required
56
+ import torch
57
+ from transformers import AutoTokenizer, AutoModelForTokenClassification, pipeline
58
+
59
+ device = "cuda" if use_gpu and torch.cuda.is_available() else "cpu"
60
+ tokenizer = AutoTokenizer.from_pretrained("samrawal/bert-base-uncased_clinical-ner")
61
+ model = AutoModelForTokenClassification.from_pretrained("samrawal/bert-base-uncased_clinical-ner")
62
+ ner_pipeline = pipeline(
63
+ "ner",
64
+ model=model,
65
+ tokenizer=tokenizer,
66
+ aggregation_strategy="simple",
67
+ device=0 if device=="cuda" else -1
68
  )
69
+
70
+ text_lines = text.split('\n')
71
+ entities = ner_pipeline(text)
72
+ meds = []
73
+ for ent in entities:
74
+ if ent["entity_group"] == "treatment":
75
+ # For each detected medicine entity, scan lines for context
76
+ entity_name = ent["word"].lower()
77
+ for line in text_lines:
78
+ if entity_name in line.lower():
79
+ # Find form and dose
80
+ form_match = re.search(r"(TAB(L?ET)?|CAP(SULE)?|SYRUP|SYP|DROP(S)?|INJ(CTION)?|OINTMENT|CREAM|GEL|PATCH|SOL(UTION)?|ORAL)", line, re.IGNORECASE)
81
+ dose_match = re.search(r"(\d{1,4} ?(mg|ml|mcg|g|kg|units|IU)|\d{1,2} ?%( ?w\/w| ?w\/v| ?v\/v)?)", line, re.IGNORECASE)
82
+ tokens = []
83
+ if form_match:
84
+ tokens.append(form_match.group(0).upper())
85
+ tokens.append(ent["word"].upper())
86
+ if dose_match:
87
+ tokens.append(dose_match.group(0))
88
+ meds.append(" ".join(tokens).strip())
89
+ break
90
+ return '\n'.join(set(meds)) if meds else "None detected"
91
 
92
  @spaces.GPU
93
+ def run_ocr_and_extract(image, temperature=0.2, extraction_mode="Regex"):
94
+ # Load OCR model ONLY in GPU context!
95
  import torch
96
+ from transformers import LightOnOCRForConditionalGeneration, LightOnOCRProcessor
 
 
 
 
97
 
98
  device = "cuda" if torch.cuda.is_available() else "cpu"
99
+ attn = "sdpa" if device == "cuda" else "eager"
100
  dtype = torch.bfloat16 if device == "cuda" else torch.float32
101
 
102
  ocr_model = LightOnOCRForConditionalGeneration.from_pretrained(
103
  "lightonai/LightOnOCR-1B-1025",
104
+ attn_implementation=attn,
105
  torch_dtype=dtype,
106
  trust_remote_code=True,
107
  ).to(device).eval()
 
108
  processor = LightOnOCRProcessor.from_pretrained(
109
  "lightonai/LightOnOCR-1B-1025",
110
  trust_remote_code=True,
111
  )
 
 
 
 
 
 
 
112
 
113
  processed_img = preprocess_image_for_ocr(image)
 
114
  chat = [
115
  {
116
  "role": "user",
 
146
  outputs = ocr_model.generate(**generation_kwargs)
147
 
148
  output_text = processor.decode(outputs[0], skip_special_tokens=True)
149
+ raw_text = output_text.strip()
150
+
151
+ # Clean medicines using selected extraction method
152
+ if extraction_mode == "Clinical NER":
153
+ meds = clinical_ner_extract(raw_text, use_gpu=(device=="cuda"))
154
+ else: # Regex
155
+ meds = extract_medication_lines(raw_text)
156
+ yield meds, raw_text, processed_img
157
+
158
+ def process_input(file_input, temperature, extraction_mode):
 
 
 
 
 
 
 
 
 
159
  if file_input is None:
160
+ yield "Please upload an image/PDF.", "", None
161
  return
162
+ image_to_process = Image.open(file_input)
163
+ for meds_out, raw_text, processed_img in run_ocr_and_extract(image_to_process, temperature, extraction_mode):
164
+ yield meds_out, raw_text, processed_img
 
 
165
 
166
  with gr.Blocks(title="💊 Medicine Extraction", theme=gr.themes.Soft()) as demo:
167
  file_input = gr.File(
168
+ label="Upload Image (or PDF first page for OCR)",
169
+ file_types=[".png", ".jpg", ".jpeg"], # PDF support: requires render as image first
170
  type="filepath"
171
  )
172
  temperature = gr.Slider(
 
177
  label="Temperature"
178
  )
179
  extraction_mode = gr.Radio(
180
+ choices=["Regex", "Clinical NER"],
181
  value="Regex",
182
+ label="Extraction Method"
 
183
  )
184
  medicines_output = gr.Textbox(
185
+ label="💊 Cleaned Medicines",
186
+ lines=10,
187
+ interactive=False,
188
+ show_copy_button=True
189
+ )
190
+ raw_output = gr.Textbox(
191
+ label="Raw OCR Output",
192
+ lines=10,
193
  interactive=False,
194
  show_copy_button=True
195
  )
196
  rendered_image = gr.Image(
197
+ label="Processed Image (Thresholded for OCR)",
198
  interactive=False
199
  )
200
  submit_btn = gr.Button("Extract Medicines", variant="primary")
201
 
 
 
202
  submit_btn.click(
203
+ fn=process_input,
204
+ inputs=[file_input, temperature, extraction_mode],
205
+ outputs=[medicines_output, raw_output, rendered_image]
206
+ )
 
207
 
208
  if __name__ == "__main__":
209
  demo.launch()
210
 
211
 
212
 
213
+
214
+
215
+
216
+
217
+ ##################################### version 3 NER modification to be done ############################################################
218
+
219
+ # import spaces
220
+ # import gradio as gr
221
+ # from PIL import Image
222
+ # import numpy as np
223
+ # import cv2
224
+ # import re
225
+
226
+ # import re
227
+
228
+ # def extract_medication_lines(text):
229
+ # """
230
+ # Extracts medication/drug lines from text using flexible regex.
231
+ # Supports tablet, capsule, syrup, drops, injection, ointment, cream, gel, patch, solution, etc.
232
+ # Matches dose like '1/2/10/250/500 mg/ml/mcg/g/kg' or concentration '1%/2%/0.2%/0.5%/10%' w/w, w/v, v/v.
233
+ # """
234
+
235
+ # form_pattern = r"(TAB(L?ET)?|CAP(SULE)?|SYRUP|SYP|DROP(S)?|INJ(CTION)?|OINTMENT|CREAM|GEL|PATCH|SOL(UTION)?|ORAL)"
236
+ # # Drug name: starts with a word (alphanumeric, maybe a hyphen), up to 4 words (spaces, hyphens or slash)
237
+ # name_pattern = r"([A-Z0-9\-/]+(?:\s+[A-Z0-9\-/]+){0,4})"
238
+ # # Dose: e.g., 250mg, 10ml, 0.5%, 10 mcg, 150mcg, etc. and concentration/w/w/w/v/etc.
239
+ # dose_pattern = r"(\d{1,4}\s*(mg|ml|mcg|g|kg|units|IU)|\d{1,2}\s*%(\s*w\/w|\s*w\/v|\s*v\/v)?)"
240
+ # # concentration can appear for creams/gels: e.g. "1% w/w", "2%"
241
+
242
+ # # Main pattern: will attempt to capture form anywhere, then name, then dose/concentration
243
+ # main_pattern = (
244
+ # r"(?:" + form_pattern + r"\s+)?" + # Form prefix optional
245
+ # name_pattern + r"\s*" +
246
+ # r"(?:" + form_pattern + r"\s*)?" + # Form mid/suffix optional
247
+ # r"(?:" + dose_pattern + r")" # Dose/concentration required
248
+ # )
249
+
250
+ # med_regex = re.compile(main_pattern, re.IGNORECASE)
251
+
252
+ # meds = []
253
+ # for line in text.split('\n'):
254
+ # line_stripped = line.strip()
255
+ # match = med_regex.search(line_stripped)
256
+ # if match:
257
+ # meds.append(line_stripped)
258
+ # return '\n'.join(meds)
259
+
260
+
261
+ # ########################### added NER modification to be done ###################################
262
+
263
+ # def get_medicine_context(entities, text_lines):
264
+ # """
265
+ # For each medicine entity detected by NER, find its form and dose context from its source line.
266
+ # Returns list of strings like 'TAB ALDACTONE 25MG'.
267
+ # """
268
+ # output = []
269
+ # for ent in entities:
270
+ # if ent["entity_group"] == "treatment":
271
+ # # Find line containing the entity's word (robust for multiline output)
272
+ # for line in text_lines:
273
+ # if ent["word"].lower() in line.lower():
274
+ # # Search line for context
275
+ # match = re.search(r"((TAB(L?ET)?|CAP(SULE)?|SYRUP|SYP|DROP(S)?|INJ(CTION)?|OINTMENT|CREAM|GEL|PATCH|SOL(UTION)?|ORAL).{0,40})", line, re.IGNORECASE)
276
+ # dose = re.search(r"\d{1,4}\s*(mg|ml|mcg|g|kg|units|IU)|\d{1,2}\s*%(\s*w\/w|\s*w\/v|\s*v\/v)?", line, re.IGNORECASE)
277
+ # info = []
278
+ # if match:
279
+ # info.append(match.group(0).strip())
280
+ # else:
281
+ # info.append(ent["word"].strip())
282
+ # if dose:
283
+ # info.append(dose.group(0).strip())
284
+ # output.append(" ".join(info))
285
+ # break
286
+ # return "\n".join(set(output)) if output else "None detected"
287
+
288
+
289
+ # ################################
290
+
291
+
292
+
293
+ # def preprocess_image_for_ocr(image):
294
+ # image_rgb = image.convert("RGB")
295
+ # img_np = np.array(image_rgb)
296
+ # gray = cv2.cvtColor(img_np, cv2.COLOR_RGB2GRAY)
297
+ # adaptive_threshold = cv2.adaptiveThreshold(
298
+ # gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 85,35,
299
+ # )
300
+ # preprocessed_pil = Image.fromarray(adaptive_threshold)
301
+ # return preprocessed_pil
302
+
303
+ # @spaces.GPU
304
+ # def extract_text_from_image(image, temperature=0.2, use_ner=False):
305
+ # # Import and load within GPU context!
306
+ # import torch
307
+ # from transformers import (
308
+ # LightOnOCRForConditionalGeneration,
309
+ # LightOnOCRProcessor,
310
+ # AutoTokenizer, AutoModelForTokenClassification, pipeline,
311
+ # )
312
+
313
+ # device = "cuda" if torch.cuda.is_available() else "cpu"
314
+ # attn_implementation = "sdpa" if device == "cuda" else "eager"
315
+ # dtype = torch.bfloat16 if device == "cuda" else torch.float32
316
+
317
+ # ocr_model = LightOnOCRForConditionalGeneration.from_pretrained(
318
+ # "lightonai/LightOnOCR-1B-1025",
319
+ # attn_implementation=attn_implementation,
320
+ # torch_dtype=dtype,
321
+ # trust_remote_code=True,
322
+ # ).to(device).eval()
323
+
324
+ # processor = LightOnOCRProcessor.from_pretrained(
325
+ # "lightonai/LightOnOCR-1B-1025",
326
+ # trust_remote_code=True,
327
+ # )
328
+ # # NER only if requested
329
+ # if use_ner:
330
+ # ner_tokenizer = AutoTokenizer.from_pretrained("samrawal/bert-base-uncased_clinical-ner")
331
+ # ner_model = AutoModelForTokenClassification.from_pretrained("samrawal/bert-base-uncased_clinical-ner")
332
+ # ner_pipeline = pipeline(
333
+ # "ner", model=ner_model, tokenizer=ner_tokenizer, aggregation_strategy="simple"
334
+ # )
335
+
336
+ # processed_img = preprocess_image_for_ocr(image)
337
+
338
+ # chat = [
339
+ # {
340
+ # "role": "user",
341
+ # "content": [
342
+ # {"type": "image", "image": processed_img}
343
+ # ],
344
+ # }
345
+ # ]
346
+ # inputs = processor.apply_chat_template(
347
+ # chat,
348
+ # add_generation_prompt=True,
349
+ # tokenize=True,
350
+ # return_dict=True,
351
+ # return_tensors="pt",
352
+ # )
353
+
354
+ # inputs = {
355
+ # k: (v.to(device=device, dtype=dtype)
356
+ # if isinstance(v, torch.Tensor) and v.dtype in [torch.float32, torch.float16, torch.bfloat16]
357
+ # else v.to(device)
358
+ # if isinstance(v, torch.Tensor)
359
+ # else v)
360
+ # for k, v in inputs.items()
361
+ # }
362
+ # generation_kwargs = dict(
363
+ # **inputs,
364
+ # max_new_tokens=2048,
365
+ # temperature=temperature if temperature > 0 else 0.0,
366
+ # use_cache=True,
367
+ # do_sample=temperature > 0,
368
+ # )
369
+ # with torch.no_grad():
370
+ # outputs = ocr_model.generate(**generation_kwargs)
371
+
372
+ # output_text = processor.decode(outputs[0], skip_special_tokens=True)
373
+ # cleaned_text = output_text.strip()
374
+ # # Extract medicines
375
+ # if use_ner:
376
+ # entities = ner_pipeline(cleaned_text)
377
+ # meds = []
378
+ # for ent in entities:
379
+ # if ent["entity_group"] == "treatment":
380
+ # word = ent["word"]
381
+ # if word.startswith("##") and meds:
382
+ # meds[-1] += word[2:]
383
+ # else:
384
+ # meds.append(word)
385
+ # result_meds = ", ".join(set(meds)) if meds else "None detected"
386
+ # else:
387
+ # result_meds = extract_medication_lines(cleaned_text) or "None detected"
388
+
389
+ # yield result_meds, processed_img # Only medicines and processed image
390
+
391
+ # def process_input(file_input, temperature, page_num, extraction_mode):
392
+ # if file_input is None:
393
+ # yield "Please upload an image or PDF first.", None
394
+ # return
395
+ # image_to_process = Image.open(file_input) if not str(file_input).lower().endswith(".pdf") else None # simplify to image only
396
+ # use_ner = extraction_mode == "Clinical NER"
397
+
398
+ # for meds_out, processed_img in extract_text_from_image(image_to_process, temperature, use_ner):
399
+ # yield meds_out, processed_img
400
+
401
+ # with gr.Blocks(title="💊 Medicine Extraction", theme=gr.themes.Soft()) as demo:
402
+ # file_input = gr.File(
403
+ # label="🖼️ Upload Image",
404
+ # file_types=[".png", ".jpg", ".jpeg"],
405
+ # type="filepath"
406
+ # )
407
+ # temperature = gr.Slider(
408
+ # minimum=0.0,
409
+ # maximum=1.0,
410
+ # value=0.2,
411
+ # step=0.05,
412
+ # label="Temperature"
413
+ # )
414
+ # extraction_mode = gr.Radio(
415
+ # choices=["Clinical NER", "Regex"],
416
+ # value="Regex",
417
+ # label="Extraction Method",
418
+ # info="Clinical NER uses ML, Regex uses rules"
419
+ # )
420
+ # medicines_output = gr.Textbox(
421
+ # label="💊 Extracted Medicines/Drugs",
422
+ # placeholder="Medicine/drug names will appear here...",
423
+ # lines=2,
424
+ # max_lines=10,
425
+ # interactive=False,
426
+ # show_copy_button=True
427
+ # )
428
+ # rendered_image = gr.Image(
429
+ # label="Processed Image (Adaptive Thresholded for OCR)",
430
+ # interactive=False
431
+ # )
432
+ # submit_btn = gr.Button("Extract Medicines", variant="primary")
433
+
434
+ # page_slider = gr.Slider(minimum=1, maximum=20, value=1, step=1, label="Page Number")
435
+
436
+ # submit_btn.click(
437
+ # fn=process_input,
438
+ # inputs=[file_input, temperature, page_slider, extraction_mode],
439
+ # outputs=[medicines_output, rendered_image]
440
+ # )
441
+
442
+
443
+ # if __name__ == "__main__":
444
+ # demo.launch()
445
+
446
+
447
+
448
  #################################################### running code only NER #######################
449
 
450
  #!/usr/bin/env python3