Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ’Š MedShield β€” Counterfeit Medicine Detection Agent for India

Protecting India's medicine supply, one batch at a time. Google Cloud Rapid Agent Hackathon Β· Track: MongoDB


The problem

Roughly 1 in 4 drugs sold in developing markets are counterfeit or substandard. A chemist in tier-2/tier-3 India has no practical tool to verify a drug batch before dispensing it. The official CDSCO verification route is inaccessible at the last mile, and individual suspicious reports are never connected β€” so counterfeit clusters spread silently.

The solution

MedShield is an AI agent a chemist can use to verify any medicine by entering a drug name and/or batch number. The agent:

  1. Validates the batch-number format.
  2. Looks the medicine up in a real verified drug database (253K+ Indian medicines).
  3. Cross-checks the manufacturer and runs a production-capacity anomaly check (impossible batch sizes).
  4. Checks whether the batch is already CDSCO NSQ-flagged.
  5. Positively verifies the batch against the registry β€” authenticity must be proven, never assumed from the absence of red flags.
  6. Detects nearby counterfeit clusters using MongoDB geospatial + vector search.
  7. Scores supplier credibility.
  8. Returns a clear verdict β€” GENUINE / UNVERIFIED / SUSPICIOUS / LIKELY COUNTERFEIT / NSQ-FLAGGED β€” with a confidence score, plain-English reasons, and an auto-generated CDSCO complaint PDF when needed.

Security posture. A real, well-known drug name printed on a box proves nothing β€” a forger can print anything. MedShield only returns GENUINE when the exact batch is positively confirmed in the verified registry and is consistent with the claimed drug, manufacturer, serial range and dates. A batch it cannot confirm is UNVERIFIED ("we cannot confirm this is genuine"), never a silent pass.


Architecture

                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                β”‚              Streamlit UI (app.py)            β”‚
                β”‚   Verify tab  β€’  Map tab  β€’  metrics/badges   β”‚
                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚                  β”‚ (read-only)
                      agent/runner.py              β”‚
                  (ADK Runner + sessions)          β”‚
                                β”‚                  β”‚
                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
                β”‚   ADK Agent (Gemini 2.5 Flash- β”‚  β”‚
                β”‚   Lite)     agent/agent.py     β”‚  β”‚
                β”‚  instruction = prompts.py      β”‚  β”‚
                β””β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜  β”‚
                    β”‚                       β”‚        β”‚
     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
     β”‚   MongoDB MCP server    β”‚   β”‚  8 custom tools     β”‚
     β”‚ (npx, find/aggregate/   β”‚   β”‚  agent/tools.py     β”‚
     β”‚  vector search)         β”‚   β”‚  validators /       β”‚
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚  pdf_generator      β”‚
                    β”‚              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚                        β”‚
              β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”
              β”‚      utils/repositories.py          β”‚  ← all queries
              β”‚  Medicine / Report / Mfr / Supplier β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚ utils/mongodb.py (pooled client)
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚     MongoDB Atlas       β”‚
                    β”‚  medicines Β· suppliers  β”‚
                    β”‚  manufacturers Β·        β”‚
                    β”‚  suspicious_reports     β”‚
                    β”‚  (+2dsphere +vector idx)β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       Embeddings: Google gemini-embedding-001 (768-dim) β€” agent/embeddings.py

Design principles. Configuration is centralised (agent/config.py, single source of truth). All persistence goes through a repository layer (utils/repositories.py) β€” tools and scripts never write raw pymongo. Domain entities and the Verdict/ReportSource enums live in agent/models.py (defined once, used everywhere). Pure logic (batch validation, risk scoring) is I/O-free and unit-testable. This keeps the codebase SRP/DIP/DRY-aligned and easy to extend.


Tech stack

Layer Technology
Agent framework Google ADK (google-adk)
LLM Gemini 2.5 Flash-Lite (gemini-2.5-flash-lite)
Embeddings Google gemini-embedding-001 (768-dim, cosine)
Database MongoDB Atlas (M0) + Vector Search + 2dsphere
DB tool surface mongodb-mcp-server (via npx, MCP/stdio)
UI Streamlit + pydeck
PDF generation ReportLab
PDF parsing PyMuPDF (fitz)
Deployment Google Cloud Run (Docker)
Language Python 3.11+

Data sources (real, not synthetic)

Generated fields (batch numbers, manufacturing/expiry dates, serial ranges, manufacturer capacities, distributor records, and the 15 demo suspicious cases) are clearly produced by the ingestion/seed scripts and are reproducible via a fixed RNG seed.


Setup

1. Prerequisites

2. MongoDB Atlas β€” step by step

  1. Create an M0 cluster. Atlas β†’ Build a Database β†’ M0 (Free) β†’ pick a cloud/region β†’ Create.
  2. Create a database user. Database Access β†’ Add New Database User β†’ username + password (Atlas auth). Save these.
  3. Whitelist your IP. Network Access β†’ Add IP Address β†’ 0.0.0.0/0 (allow-all is fine for the hackathon; tighten for prod).
  4. Get the connection string. Database β†’ Connect β†’ Drivers β†’ copy the mongodb+srv://… string. Insert your username/password and append the database name medshield:
    mongodb+srv://<user>:<pass>@<cluster>.mongodb.net/medshield?retryWrites=true&w=majority
    
  5. The medshield database + collections are created automatically the first time scripts/ingest_data.py writes to them β€” no manual creation needed.
  6. Standard indexes are created automatically by ingestion (ensure_all_indexes()): the compound {batch_number, manufacturer_name} on medicines, a text index on medicines.name, and the 2dsphere index on suspicious_reports.location.
  7. Create the Vector Search index manually (Atlas UI): Atlas Search β†’ Create Search Index β†’ JSON Editor β†’ choose the suspicious_reports collection β†’ Vector Search type β†’ name it report_vector_index β†’ paste:
    {
      "fields": [
        {
          "type": "vector",
          "path": "embedding",
          "numDimensions": 768,
          "similarity": "cosine"
        }
      ]
    }
    (Atlas Search indexes cannot be created reliably via pymongo on M0, which is why this one step is manual.)

3. Install & configure

cd medshield
python3.11 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

cp .env.example .env        # then edit .env with real values

.env:

MONGODB_URI=mongodb+srv://<user>:<pass>@<cluster>.mongodb.net/medshield?retryWrites=true&w=majority
MONGODB_DB=medshield
GOOGLE_API_KEY=your_gemini_api_key
GOOGLE_CLOUD_PROJECT=your_gcp_project_id   # only for Cloud Run

4. Ingest data & seed demo cases

# Full ingest (downloads 253K-row CSV + CDSCO PDFs, builds all collections).
python -m scripts.ingest_data --drop

# Quick subset while testing (no embeddings, ~2k medicines):
python -m scripts.ingest_data --limit 2000 --skip-embeddings

# Seed the 15 curated demo suspicious cases (needs the vector index for
# semantic search; geospatial works regardless).
python -m scripts.seed_suspicious --reset

# Seed the 2 genuine, in-registry demo medicines (so the GENUINE demo has a
# real verified batch with future expiry β€” Augmentin GSK-202503-00421).
python -m scripts.seed_demo_medicines

5. Test the agent

# Fast, no LLM β€” exercises every tool directly against MongoDB:
python -m scripts.test_agent --tools-only

# Full end-to-end through Gemini + MCP (runs the 3 demo scenarios):
python -m scripts.test_agent

6. Run the UI

streamlit run app.py
# open http://localhost:8501

Demo scenarios

# Input Expected verdict
1 Augmentin 625 Duo Tablet, batch GSK-202503-00421, city Mumbai GENUINE β€” exact batch positively verified in the registry, no nearby flags
2 Augmentin 625 Duo Tablet, batch GSK-202403-99999, city Mumbai UNVERIFIED β€” real drug name but the batch is not in the registry; cannot confirm
3 Telmisartan 40mg Tablet, batch GSK-202503-00421, city Delhi LIKELY_COUNTERFEIT β€” that batch belongs to a different product (cloned batch number)
4 Telmisartan 40mg Tablet, batch TEL-202309-04412, mfr Hetero Labs, city Hyderabad NSQ_FLAGGED β€” matches a seeded CDSCO NSQ flag; complaint generated
5 Ranitidine 150mg Tablet, batch RAN-202310-03021, mfr JB Chemicals, supplier Surya Pharma Supplies, city Mumbai LIKELY_COUNTERFEIT β€” 3-city cluster within 200 km; complaint generated

(Scenario 1 relies on scripts/seed_demo_medicines.py; scenarios 3–5 rely on scripts/seed_suspicious.py + seed_demo_medicines.py having been run.)


Deploy to Cloud Run

gcloud run deploy medshield \
  --source . \
  --region asia-south1 \
  --allow-unauthenticated \
  --set-env-vars "MONGODB_URI=...,MONGODB_DB=medshield,GOOGLE_API_KEY=..."

The image bundles Node.js so the MCP server runs inside the container.


Project layout

medshield/
β”œβ”€β”€ app.py                     # Streamlit UI (Verify + Map tabs)
β”œβ”€β”€ agent/
β”‚   β”œβ”€β”€ agent.py               # ADK agent (Gemini + MCP + custom tools)
β”‚   β”œβ”€β”€ runner.py              # shared ADK Runner / streaming helpers
β”‚   β”œβ”€β”€ tools.py               # 8 custom tools
β”‚   β”œβ”€β”€ prompts.py             # system prompt (11-step reasoning)
β”‚   β”œβ”€β”€ embeddings.py          # gemini-embedding-001 wrapper
β”‚   β”œβ”€β”€ config.py              # single source of truth (settings/weights)
β”‚   └── models.py              # domain entities + Verdict/ReportSource enums
β”œβ”€β”€ utils/
β”‚   β”œβ”€β”€ mongodb.py             # pooled client + health check
β”‚   β”œβ”€β”€ repositories.py        # data-access layer (one repo per collection)
β”‚   β”œβ”€β”€ pdf_generator.py       # CDSCO complaint PDF (ReportLab)
β”‚   └── validators.py          # batch-format validation (pure)
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ ingest_data.py         # download + parse real data β†’ MongoDB
β”‚   β”œβ”€β”€ seed_suspicious.py     # 15 curated demo suspicious cases
β”‚   β”œβ”€β”€ seed_demo_medicines.py # 2 genuine, in-registry demo medicines
β”‚   └── test_agent.py          # CLI test harness
β”œβ”€β”€ data/                      # downloaded datasets + generated PDFs (gitignored)
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ .env.example
└── README.md

Disclaimer

MedShield is a decision-support tool, not a legal authority. Verdicts are guidance to help a chemist decide. Final confirmation of a spurious or substandard drug rests with CDSCO and State Drug Control authorities. When in doubt, do not dispense β€” verify.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages