Skip to content
goutham.dechineni

Freelance project

Drug–Drug Interaction

Problem
Someone holding a prescription with several drugs on it has no quick way to see whether two of them interact, or why.
Approach
OCR reads the drug names from a photo, each drug is turned into a molecular graph, and one shared graph attention encoder feeds two heads: does this pair interact, and through which of five mechanisms. Gemini then explains the result in plain language.
Result
On the held-out test set the interaction model reached AUC 0.910, F1 0.832 and accuracy 0.826.
My role
Freelance AI engineer (2024–2025). Built the system end to end for a client: data pipeline, model, training and app.
Stack
  • Python
  • EasyOCR
  • PubChem + RxNav APIs
  • RDKit
  • PyTorch Geometric (GATv2)
  • scikit-learn
  • Gemini
  • Streamlit
Links

Code private (client work)

01

Architecture

  1. Prescription photo: the user uploads a photo of a prescription in the Streamlit app.
  2. EasyOCR reads the text in the photo and the drug names are picked out of it.
  3. Drug lookup: each name is resolved through PubChem to a SMILES string (the molecule's structure) and through RxNav to its drug class.
  4. RDKit graphs: RDKit parses each SMILES into a molecular graph, with atoms as nodes (carrying features such as element, degree, charge and aromaticity) and bonds as edges.
  5. Shared GATv2 encoder: both drugs go through the same 3-layer GATv2 graph attention network (4 attention heads in the first two layers, one in the last), and mean pooling turns each molecule into one embedding.
  6. Two heads: the pair of embeddings feeds an interaction head (does this pair interact?) and a mechanism head that picks one of five types: pharmacokinetic, pharmacodynamic, CYP450 inhibition, protein binding or transporter effect.
  7. Gemini turns the prediction and the mechanism into a short explanation a non-specialist can read.
  8. Streamlit app: the results page shows the prediction, the mechanism and the explanation for each pair.

02

Key decisions

  • One shared GNN encoder for both drugs

    Encoding drug A and drug B with the same weights means every molecule in the training set trains one encoder, and a drug gets the same embedding whichever side of the pair it is on. The cost is that the encoder cannot learn role-specific features by itself (for example, which drug inhibits the other's metabolism); that has to come from the heads.

  • Predict from molecular structure, not from a table of known pairs

    Working from the molecular graph lets the model score a pair it never saw in training, as long as both structures can be looked up. The trade-off is a dependency on PubChem returning a SMILES string for the OCR'd name, and structure alone knows nothing about dose or the patient.

  • The LLM explains; it does not decide

    Gemini only rephrases the model's output, so the yes/no and the mechanism always come from the trained model, which has measured test scores. The explanation reads well, but it can still sound more certain than the model is, so it is shown next to the prediction rather than instead of it.

03

Results

  • Interaction prediction on the held-out test set: AUC 0.910, F1 0.832, accuracy 0.826.
  • Covers the full path from a photo of a prescription to a readable explanation in one app.
  • Five mechanism classes predicted alongside the interaction: pharmacokinetic, pharmacodynamic, CYP450 inhibition, protein binding and transporter effect.

04

What I'd do next

  • Report the mechanism head's accuracy separately; the published test scores are for the interaction prediction.
  • Add a confirmation step after OCR so the user can fix a misread drug name before it is looked up.
  • Calibrate the interaction probability so the score shown to the user means what it says.