How I Built an AI-Powered Anti-Counterfeit Drug Verification System with Python & Gradio
A comprehensive tutorial on combining official registry lookups, TF-IDF character n-grams, Random Forest, Anomaly Detection, and barcode scanning into a real-time web application.
1. The Problem: Counterfeit Pharmaceuticals
Counterfeit and substandard medications pose a severe threat to public health worldwide, particularly in developing economies. Fraudulent actors often replicate genuine packaging while altering active ingredients, spoofing brand names, or manufacturing fake registration numbers (e.g., NAFDAC Registration Numbers).
While official regulatory agencies maintain digital registries, manual verification can be slow, and traditional search engines fail when dealing with minor typos, corrupted registration formats, or novel counterfeit mutations.
2. System Architecture
The system operates on a multi-stage logic pipeline to ensure high accuracy and fast response times:
- Layer 1 (Exact Registry Match): Instantly checks the provided registration code against the official active database. If found, it immediately confirms authenticity with 100% confidence.
- Layer 2 (Machine Learning Engine): If the registration code is missing or unregistered, the input is passed to an NLP vectorizer and evaluated by two machine learning models:
- Supervised Random Forest Classifier: Evaluates structural similarity, character patterns, and brand-manufacturer alignments.
- Unsupervised Isolation Forest: Detects rare, out-of-distribution structural anomalies in drug descriptions and formatting.
- Interactive Web & Barcode Scanner UI: A Gradio interface enabling users to either manually enter drug details or upload barcode/QR code images for auto-decoding.
3. Step 1: Dataset Generation & Attack Simulation
To train our machine learning model, we first compiled a raw database of official product entries (e.g., the NAFDAC Greenbook catalog) and expanded it to 9,008 active records. Since machine learning requires balanced positive and negative examples, we synthetically generated counterfeit attack vectors matching common real-world forgery methods:
fake_nrn: Unregistered registration code patterns (e.g.,XX-9821).brand_spoof: Valid product names paired with unauthorized manufacturers.typo: Intentionally misspelled drug names to trick string matching algorithms.corrupted: Malformed registration numbers (e.g.,INVALID-CODE).
This yielded a balanced dataset of 17,216 samples (50% Genuine, 50% Counterfeit).
# Synthetic Attack Vector Generation Sample
for idx, row in genuine_df.iterrows():
attack_type = np.random.choice(['fake_nrn', 'brand_spoof', 'typo', 'corrupted', 'revoked'])
f_drug, f_nrn, f_mfg = str(row['Drug_Name']), str(row['NAFDAC_Code']), str(row['Manufacturer'])
if attack_type == 'fake_nrn':
f_nrn = f"XX-{np.random.randint(1000, 9999)}"
elif attack_type == 'brand_spoof':
f_mfg = np.random.choice([m for m in mfg_list if m != f_mfg])
elif attack_type == 'typo':
f_drug = f_drug[:3] + "X" + f_drug[4:]
elif attack_type == 'corrupted':
f_nrn = "INVALID-CODE"
fake_records.append({'Drug_Name': f_drug, 'NAFDAC_Code': f_nrn, 'Manufacturer': f_mfg, 'Label': 0})
4. Step 2: Feature Engineering & Model Training
Standard word-level vectorizers often fail on short alphanumeric codes like registration numbers. To capture sub-word character mutations and formatting patterns, we utilized TF-IDF Character N-Grams (range 2 to 4).
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.ensemble import RandomForestClassifier, IsolationForest
# 1. Feature Extraction (Character N-Grams)
vectorizer = TfidfVectorizer(analyzer='char', ngram_range=(2, 4), max_features=8000)
X_train_vec = vectorizer.fit_transform(X_train)
X_test_vec = vectorizer.transform(X_test)
# 2. Supervised Learning: Random Forest
rf_model = RandomForestClassifier(n_estimators=100, random_state=42, n_jobs=-1)
rf_model.fit(X_train_vec, y_train)
# 3. Unsupervised Learning: Isolation Forest (Trained on Genuine Data Only)
iso_forest = IsolationForest(contamination=0.1, random_state=42, n_jobs=-1)
genuine_mask = (y_train == 1).to_numpy()
iso_forest.fit(X_train_vec[genuine_mask])
5. Step 3: Evaluation & Results
The trained Random Forest model achieved exceptional diagnostic metrics on an independent test set of 3,444 samples:
| Metric | Score | Interpretation |
|---|---|---|
| Accuracy | 98.0% | Overall correct classifications across test cases. |
| ROC-AUC Score | 0.99 | Near-perfect class separation capability. |
| Precision / Recall | 0.98 / 0.98 | Balanced sensitivity with low false alarm rate. |
Visual Diagnostics
To ensure transparency, we saved and evaluated key visual diagnostics:
6. Step 4: Deploying with Gradio & PyZBar
A machine learning model is only useful if non-technical users (like pharmacists or consumers) can interact with it effortlessly. We built a full-featured web interface using Gradio and integrated computer vision barcode decoding with PyZBar.
import gradio as gr
from pyzbar.pyzbar import decode
def extract_text_from_barcode(img):
if img is None: return None
try:
decoded_objs = decode(img)
for obj in decoded_objs:
return obj.data.decode("utf-8").strip()
except Exception:
return None
def verify_drug_combined(img_input, product_name, nrn, manufacturer):
# Auto-extract NRN if barcode image is supplied
extracted_nrn = extract_text_from_barcode(img_input)
if extracted_nrn:
nrn = extracted_nrn
clean_nrn = str(nrn).strip().upper()
# Layer 1: Direct Registry Check
if clean_nrn in registry_lookup:
match = df_raw[df_raw['nrn_clean'] == clean_nrn].iloc[0]
return f"**STATUS: AUTHENTIC PRODUCT**\nConfidence: 100% (Official Match)"
# Layer 2: Machine Learning Inference
combined_input = f"{product_name} {clean_nrn} {manufacturer}"
input_vec = vectorizer.transform([combined_input])
prob_genuine = rf_model.predict_proba(input_vec)[0][1]
is_anomaly = (iso_forest.predict(input_vec)[0] == -1)
if prob_genuine >= 0.75 and not is_anomaly:
return "**STATUS: SUSPICIOUS PRODUCT** (Medium Risk)"
else:
return "**STATUS: CONFIRMED COUNTERFEIT** (Critical Risk)"
# Launch Gradio UI
demo = gr.Interface(
fn=verify_drug_combined,
inputs=[
gr.Image(type="pil", label="Upload Barcode / QR Image (Optional)"),
gr.Textbox(label="Drug Product Name"),
gr.Textbox(label="NAFDAC Registration Number (NRN)"),
gr.Textbox(label="Manufacturer Name")
],
outputs=gr.Markdown(label="Verification Result"),
title="NAFDAC AI Fake Drug Text/Barcode Checker"
)
demo.launch(share=True)
7. Key Takeaways & Future Scope
- Hybrid Systems Win: Combining deterministic rule-based checks (Layer 1) with probabilistic machine learning models (Layer 2) provides both safety guarantees and robust fallback protection.
- Sub-Word Features Matter: Character-level TF-IDF n-grams outperforms traditional word tokenizers when dealing with structured IDs, serial numbers, and typos.
- Next Steps: Integrating OCR (Optical Character Recognition) to extract full label text from package photos and scaling the backend API to microservices.
Comments
Post a Comment