Commit ·
e898f0a
1
Parent(s): c90ac52
Use live retrieval result instead of Neuroxen fallback
Browse files- gradio_pharmacopilot_demo.py +28 -10
gradio_pharmacopilot_demo.py
CHANGED
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
| 2 |
|
| 3 |
import json
|
| 4 |
import os
|
|
|
|
| 5 |
import time
|
| 6 |
from difflib import SequenceMatcher, get_close_matches
|
| 7 |
from pathlib import Path
|
|
@@ -94,7 +95,9 @@ SESSION_SEARCHES = 0
|
|
| 94 |
|
| 95 |
|
| 96 |
def normalize(text: str) -> str:
|
| 97 |
-
|
|
|
|
|
|
|
| 98 |
|
| 99 |
|
| 100 |
def clean_prediction(raw_prediction: str) -> str:
|
|
@@ -128,12 +131,11 @@ def label_for_medicine(ocr_text: str, medicine: dict[str, Any]) -> str:
|
|
| 128 |
return brands[0] if brands else medicine["name"]
|
| 129 |
|
| 130 |
|
| 131 |
-
def find_medicine_from_ocr(ocr_text: str) -> tuple[dict[str, Any], list[dict[str, Any]], str]:
|
| 132 |
query = normalize(ocr_text)
|
| 133 |
corrected_query = query
|
| 134 |
canonical = BD_BRAND_TO_GENERIC.get(corrected_query, corrected_query)
|
| 135 |
-
|
| 136 |
-
display_name = label_for_medicine(ocr_text, medicine)
|
| 137 |
|
| 138 |
candidate_names = set()
|
| 139 |
for med in MEDICINES:
|
|
@@ -152,7 +154,21 @@ def find_medicine_from_ocr(ocr_text: str) -> tuple[dict[str, Any], list[dict[str
|
|
| 152 |
scored.append({"label": name, "medicine": med, "score": score})
|
| 153 |
|
| 154 |
scored.sort(key=lambda item: item["score"], reverse=True)
|
| 155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
seen_ids = {medicine["id"]}
|
| 157 |
for item in scored:
|
| 158 |
if item["medicine"]["id"] in seen_ids:
|
|
@@ -173,7 +189,8 @@ def find_medicine_from_ocr(ocr_text: str) -> tuple[dict[str, Any], list[dict[str
|
|
| 173 |
continue
|
| 174 |
break
|
| 175 |
|
| 176 |
-
|
|
|
|
| 177 |
|
| 178 |
|
| 179 |
def get_inventory(medicine: dict[str, Any]) -> dict[str, Any]:
|
|
@@ -291,6 +308,7 @@ def medicine_details_html(
|
|
| 291 |
inventory: dict[str, Any],
|
| 292 |
ocr_text: str,
|
| 293 |
display_name: str,
|
|
|
|
| 294 |
) -> str:
|
| 295 |
return f"""
|
| 296 |
<div class="result-card">
|
|
@@ -300,7 +318,7 @@ def medicine_details_html(
|
|
| 300 |
<dt>Generic</dt><dd>{medicine.get('name', 'Unknown')}</dd>
|
| 301 |
<dt>Strength</dt><dd>{first_strength(medicine.get('strength', ''))}</dd>
|
| 302 |
<dt>Manufacturer</dt><dd>{medicine.get('manufacturer') or 'Not listed'}</dd>
|
| 303 |
-
<dt>Confidence</dt><dd>
|
| 304 |
<dt>Category</dt><dd>{medicine.get('category', 'General')}</dd>
|
| 305 |
<dt>Price</dt><dd>PKR 145</dd>
|
| 306 |
</dl>
|
|
@@ -421,7 +439,7 @@ def analyze_prescription(image, progress=gr.Progress()):
|
|
| 421 |
progress(pct, desc=label)
|
| 422 |
time.sleep(0.25)
|
| 423 |
|
| 424 |
-
medicine, candidates, display_name = find_medicine_from_ocr(ocr_text)
|
| 425 |
inventory = get_inventory(medicine)
|
| 426 |
image_path = resolve_asset_path(medicine.get("image_path"))
|
| 427 |
package_image = str(image_path) if image_path else None
|
|
@@ -438,10 +456,10 @@ def analyze_prescription(image, progress=gr.Progress()):
|
|
| 438 |
return (
|
| 439 |
load_kpi_metrics(SESSION_SEARCHES),
|
| 440 |
pipeline_html(5),
|
| 441 |
-
medicine_details_html(medicine, inventory, ocr_text, display_name),
|
| 442 |
package_image,
|
| 443 |
package_status_html(inventory),
|
| 444 |
-
confidence_gauge(
|
| 445 |
candidates_html(candidates),
|
| 446 |
ocr_compare_html(medicine, ocr_text, display_name),
|
| 447 |
gr.update(visible=True),
|
|
|
|
| 2 |
|
| 3 |
import json
|
| 4 |
import os
|
| 5 |
+
import unicodedata
|
| 6 |
import time
|
| 7 |
from difflib import SequenceMatcher, get_close_matches
|
| 8 |
from pathlib import Path
|
|
|
|
| 95 |
|
| 96 |
|
| 97 |
def normalize(text: str) -> str:
|
| 98 |
+
text = unicodedata.normalize("NFKD", str(text or ""))
|
| 99 |
+
text = "".join(ch for ch in text if not unicodedata.combining(ch))
|
| 100 |
+
return " ".join(text.strip().lower().split())
|
| 101 |
|
| 102 |
|
| 103 |
def clean_prediction(raw_prediction: str) -> str:
|
|
|
|
| 131 |
return brands[0] if brands else medicine["name"]
|
| 132 |
|
| 133 |
|
| 134 |
+
def find_medicine_from_ocr(ocr_text: str) -> tuple[dict[str, Any], list[dict[str, Any]], str, int]:
|
| 135 |
query = normalize(ocr_text)
|
| 136 |
corrected_query = query
|
| 137 |
canonical = BD_BRAND_TO_GENERIC.get(corrected_query, corrected_query)
|
| 138 |
+
direct_medicine = MED_BY_NAME.get(normalize(canonical))
|
|
|
|
| 139 |
|
| 140 |
candidate_names = set()
|
| 141 |
for med in MEDICINES:
|
|
|
|
| 154 |
scored.append({"label": name, "medicine": med, "score": score})
|
| 155 |
|
| 156 |
scored.sort(key=lambda item: item["score"], reverse=True)
|
| 157 |
+
if direct_medicine:
|
| 158 |
+
medicine = direct_medicine
|
| 159 |
+
display_name = label_for_medicine(ocr_text, medicine)
|
| 160 |
+
primary_score = 0.97
|
| 161 |
+
elif scored:
|
| 162 |
+
best = scored[0]
|
| 163 |
+
medicine = best["medicine"]
|
| 164 |
+
display_name = best["label"]
|
| 165 |
+
primary_score = best["score"]
|
| 166 |
+
else:
|
| 167 |
+
medicine = MEDICINES[0]
|
| 168 |
+
display_name = clean_prediction(ocr_text) or "Needs review"
|
| 169 |
+
primary_score = 0.0
|
| 170 |
+
|
| 171 |
+
top = [{"label": display_name, "medicine": medicine, "score": primary_score}]
|
| 172 |
seen_ids = {medicine["id"]}
|
| 173 |
for item in scored:
|
| 174 |
if item["medicine"]["id"] in seen_ids:
|
|
|
|
| 189 |
continue
|
| 190 |
break
|
| 191 |
|
| 192 |
+
confidence = max(0, min(99, round(primary_score * 100)))
|
| 193 |
+
return medicine, top, display_name, confidence
|
| 194 |
|
| 195 |
|
| 196 |
def get_inventory(medicine: dict[str, Any]) -> dict[str, Any]:
|
|
|
|
| 308 |
inventory: dict[str, Any],
|
| 309 |
ocr_text: str,
|
| 310 |
display_name: str,
|
| 311 |
+
confidence: int,
|
| 312 |
) -> str:
|
| 313 |
return f"""
|
| 314 |
<div class="result-card">
|
|
|
|
| 318 |
<dt>Generic</dt><dd>{medicine.get('name', 'Unknown')}</dd>
|
| 319 |
<dt>Strength</dt><dd>{first_strength(medicine.get('strength', ''))}</dd>
|
| 320 |
<dt>Manufacturer</dt><dd>{medicine.get('manufacturer') or 'Not listed'}</dd>
|
| 321 |
+
<dt>Confidence</dt><dd>{confidence}%</dd>
|
| 322 |
<dt>Category</dt><dd>{medicine.get('category', 'General')}</dd>
|
| 323 |
<dt>Price</dt><dd>PKR 145</dd>
|
| 324 |
</dl>
|
|
|
|
| 439 |
progress(pct, desc=label)
|
| 440 |
time.sleep(0.25)
|
| 441 |
|
| 442 |
+
medicine, candidates, display_name, confidence = find_medicine_from_ocr(ocr_text)
|
| 443 |
inventory = get_inventory(medicine)
|
| 444 |
image_path = resolve_asset_path(medicine.get("image_path"))
|
| 445 |
package_image = str(image_path) if image_path else None
|
|
|
|
| 456 |
return (
|
| 457 |
load_kpi_metrics(SESSION_SEARCHES),
|
| 458 |
pipeline_html(5),
|
| 459 |
+
medicine_details_html(medicine, inventory, ocr_text, display_name, confidence),
|
| 460 |
package_image,
|
| 461 |
package_status_html(inventory),
|
| 462 |
+
confidence_gauge(confidence),
|
| 463 |
candidates_html(candidates),
|
| 464 |
ocr_compare_html(medicine, ocr_text, display_name),
|
| 465 |
gr.update(visible=True),
|