import gradio as gr import pandas as pd import os import random import hashlib # Check if pubchempy is available PUBCHEM_AVAILABLE = False try: import pubchempy as pcp PUBCHEM_AVAILABLE = True print("pubchempy imported successfully.") except ImportError: print("Warning: pubchempy not found. PubChem feature extraction will be skipped.") # Active compound mapping for traditional drugs DRUG_ACTIVE_COMPOUNDS = { 'kanna': 'mesembrine', 'sceletium tortuosum': 'mesembrine', 'st johns wort': 'hyperforin', 'st john\'s wort': 'hyperforin', 'hypericum perforatum': 'hyperforin', 'yohimbe': 'yohimbine', 'pausinystalia johimbe': 'yohimbine', 'kola nut': 'caffeine', 'cola nitida': 'caffeine', 'khat': 'cathinone', 'catha edulis': 'cathinone', 'kava': 'kavain', 'piper methysticum': 'kavain', 'valerian': 'valerenic acid', 'valeriana officinalis': 'valerenic acid', 'ashwagandha': 'withanoside iv', 'withania somnifera': 'withanoside iv', 'cannabis': 'thc', 'cannabis sativa': 'thc', 'licorice': 'glycyrrhizin', 'glycyrrhiza glabra': 'glycyrrhizin', 'rauvolfia': 'reserpine', 'rauvolfia serpentina': 'reserpine', 'turmeric': 'curcumin', 'curcuma longa': 'curcumin', 'ginger': 'gingerol', 'zingiber officinale': 'gingerol', 'garlic': 'allicin', 'allium sativum': 'allicin', 'feverfew': 'parthenolide', 'tanacetum parthenium': 'parthenolide', 'senna': 'sennoside a', 'cassia angustifolia': 'sennoside a', 'aloe ferox': 'aloin', 'ephedra': 'ephedrine', 'ephedra sinica': 'ephedrine', 'willow bark': 'salicin', 'salix alba': 'salicin', 'echinacea': 'cichoric acid', 'echinacea purpurea': 'cichoric acid', 'ginkgo': 'ginkgolide', 'ginkgo biloba': 'ginkgolide', 'ginseng': 'ginsenoside', 'panax ginseng': 'ginsenoside', 'green tea': 'epigallocatechin gallate', 'camellia sinensis': 'epigallocatechin gallate' } def extract_active_compound(drug_name): drug_lower = drug_name.lower().strip() # First check our predefined mapping if drug_lower in DRUG_ACTIVE_COMPOUNDS: active_compound = DRUG_ACTIVE_COMPOUNDS[drug_lower] print(f"Found active compound for {drug_name}: {active_compound}") return active_compound # If not in mapping and PubChem is available, try to get synonyms/related compounds if PUBCHEM_AVAILABLE: try: compounds = pcp.get_compounds(drug_name, 'name') if compounds: compound = compounds[0] # Try to get the main active ingredient name synonyms = compound.synonyms if hasattr(compound, 'synonyms') else [] if synonyms: # Look for common active compound patterns in synonyms for synonym in synonyms[:10]: # Check first 10 synonyms syn_lower = synonym.lower() if any(pattern in syn_lower for pattern in ['acid', 'ine', 'ol', 'ide', 'ate']): print(f"Found potential active compound for {drug_name}: {synonym}") return synonym.lower() # If no suitable synonym found, return the canonical name if hasattr(compound, 'iupac_name') and compound.iupac_name: return compound.iupac_name.lower() except Exception as e: print(f"Error extracting active compound for {drug_name}: {e}") # If all else fails, return the original drug name (it might already be an active compound) return drug_lower # Load your labeled dataset with exact column names def load_drug_interaction_dataset(): """Load your labeled drug interaction dataset with exact column names""" try: dataset_path = 'merged_cleaned_dataset.csv' print(f"Looking for dataset: {dataset_path}") print("Files in directory:", os.listdir('.')) if not os.path.exists(dataset_path): print(f"Dataset file {dataset_path} not found!") return {}, create_fallback_database() # Return empty dict and fallback if file missing print(f"Loading dataset from: {dataset_path}") df = pd.read_csv(dataset_path) print(f"Dataset columns: {df.columns.tolist()}") print(f"Dataset shape: {df.shape}") print(f"First few rows:\n{df.head().to_string()}") interaction_db = {} count = 0 for index, row in df.iterrows(): try: drug1 = str(row['Drug 1_normalized']).lower().strip() drug2 = str(row['Drug 2_normalized']).lower().strip() severity = str(row['severity']).strip() if (not all([drug1, drug2, severity]) or drug1 == 'nan' or drug2 == 'nan' or severity == 'nan' or severity.lower() == 'none'): continue severity = severity.capitalize() if severity == 'No interaction': severity = 'No Interaction' interaction_db[(drug1, drug2)] = severity interaction_db[(drug2, drug1)] = severity count += 1 if drug1 == 'warfarin' and drug2 == 'aspirin': print(f"Found Warfarin, Aspirin at row {index} with severity: {severity}") except Exception as e: print(f"Error processing row {index}: {e}") continue print(f"✅ Successfully loaded {count} drug interactions from dataset") print(f"Sample interactions: {list(interaction_db.items())[:5]}") return interaction_db, create_fallback_database() except Exception as e: print(f"Error loading dataset: {e}") return {}, create_fallback_database() def create_fallback_database(): """Fallback database for missing drug pairs""" print("Initializing fallback database") return { ('warfarin', 'aspirin'): 'Severe', ('aspirin', 'warfarin'): 'Severe', ('cathinone', 'yohimbine'): 'Severe', ('yohimbine', 'cathinone'): 'Severe', ('codeine', 'hyperforin'): 'Severe', ('hyperforin', 'codeine'): 'Severe', ('glycyrrhizin', 'digitoxin'): 'Severe', ('digitoxin', 'glycyrrhizin'): 'Severe', ('digoxin', 'glycyrrhizin'): 'Severe', ('glycyrrhizin', 'digoxin'): 'Severe', ('yohimbine', 'reserpine'): 'Severe', ('reserpine', 'yohimbine'): 'Severe', ('ephedrine', 'yohimbine'): 'Severe', ('yohimbine', 'ephedrine'): 'Severe', ('ephedrine', 'cathinone'): 'Severe', ('cathinone', 'ephedrine'): 'Severe', ('sennoside a', 'aloin'): 'Severe', ('aloin', 'sennoside a'): 'Severe', ('glycyrrhizin', 'sennoside a'): 'Severe', ('sennoside a', 'glycyrrhizin'): 'Severe', ('warfarin', 'ibuprofen'): 'Severe', ('ibuprofen', 'warfarin'): 'Severe', ('simvastatin', 'clarithromycin'): 'Severe', ('clarithromycin', 'simvastatin'): 'Severe', ('clopidogrel', 'omeprazole'): 'Severe', ('omeprazole', 'clopidogrel'): 'Severe', ('methotrexate', 'naproxen'): 'Severe', ('naproxen', 'methotrexate'): 'Severe', ('lithium', 'ibuprofen'): 'Severe', ('ibuprofen', 'lithium'): 'Severe', ('ssri', 'maoi'): 'Severe', ('maoi', 'ssri'): 'Severe', ('simvastatin', 'verapamil'): 'Severe', ('verapamil', 'simvastatin'): 'Severe', ('warfarin', 'fluconazole'): 'Severe', ('fluconazole', 'warfarin'): 'Severe', ('digoxin', 'verapamil'): 'Severe', ('verapamil', 'digoxin'): 'Severe', ('amodiaquine', 'acebutolol'): 'Severe', ('acebutolol', 'amodiaquine'): 'Severe', ('amodiaquine', 'artemether'): 'Severe', ('artemether', 'amodiaquine'): 'Severe', ('amodiaquine', 'atenolol'): 'Severe', ('atenolol', 'amodiaquine'): 'Severe', ('amodiaquine', 'carvedilol'): 'Severe', ('carvedilol', 'amodiaquine'): 'Severe', ('amodiaquine', 'efavirenz'): 'Severe', ('efavirenz', 'amodiaquine'): 'Severe', ('amodiaquine', 'betaxolol'): 'Severe', ('betaxolol', 'amodiaquine'): 'Severe', ('amodiaquine', 'bisoprolol'): 'Severe', ('bisoprolol', 'amodiaquine'): 'Severe', ('amodiaquine', 'metoprolol'): 'Severe', ('metoprolol', 'amodiaquine'): 'Severe', ('amodiaquine', 'propranolol'): 'Severe', ('propranolol', 'amodiaquine'): 'Severe', ('amodiaquine', 'rifampicin'): 'Severe', ('rifampicin', 'amodiaquine'): 'Severe', # Moderate interactions ('hyperforin', 'mesembrine'): 'Moderate', ('mesembrine', 'hyperforin'): 'Moderate', ('kavain', 'valerenic acid'): 'Moderate', ('valerenic acid', 'kavain'): 'Moderate', ('kavain', 'withanoside iv'): 'Moderate', ('withanoside iv', 'kavain'): 'Moderate', ('thc', 'mesembrine'): 'Moderate', ('mesembrine', 'thc'): 'Moderate', ('thc', 'valerenic acid'): 'Moderate', ('valerenic acid', 'thc'): 'Moderate', ('hyperforin', 'morphine'): 'Moderate', ('morphine', 'hyperforin'): 'Moderate', ('allicin', 'gingerol'): 'Moderate', ('gingerol', 'allicin'): 'Moderate', ('parthenolide', 'curcumin'): 'Moderate', ('curcumin', 'parthenolide'): 'Moderate', ('yohimbine', 'caffeine'): 'Moderate', ('caffeine', 'yohimbine'): 'Moderate', ('amodiaquine', 'amitriptyline'): 'Moderate', ('amitriptyline', 'amodiaquine'): 'Moderate', ('amodiaquine', 'candesartan'): 'Moderate', ('candesartan', 'amodiaquine'): 'Moderate', ('amodiaquine', 'fluoxetine'): 'Moderate', ('fluoxetine', 'amodiaquine'): 'Moderate', ('amodiaquine', 'haloperidol'): 'Moderate', ('haloperidol', 'amodiaquine'): 'Moderate', ('amodiaquine', 'chloroquine'): 'Moderate', ('chloroquine', 'amodiaquine'): 'Moderate', ('digoxin', 'quinine'): 'Moderate', ('quinine', 'digoxin'): 'Moderate', ('lisinopril', 'ibuprofen'): 'Moderate', ('ibuprofen', 'lisinopril'): 'Moderate', ('metformin', 'alcohol'): 'Moderate', ('alcohol', 'metformin'): 'Moderate', ('levothyroxine', 'calcium'): 'Moderate', ('calcium', 'levothyroxine'): 'Moderate', ('atorvastatin', 'orange juice'): 'Moderate', ('orange juice', 'atorvastatin'): 'Moderate', ('phenytoin', 'warfarin'): 'Moderate', ('warfarin', 'phenytoin'): 'Moderate', ('theophylline', 'ciprofloxacin'): 'Moderate', ('ciprofloxacin', 'theophylline'): 'Moderate', ('warfarin', 'acetaminophen'): 'Moderate', ('acetaminophen', 'warfarin'): 'Moderate', ('metoprolol', 'verapamil'): 'Moderate', ('verapamil', 'metoprolol'): 'Moderate', ('spironolactone', 'digoxin'): 'Moderate', ('digoxin', 'spironolactone'): 'Moderate', # Mild interactions ('amodiaquine', 'amlodipine'): 'Mild', ('amlodipine', 'amodiaquine'): 'Mild', ('amodiaquine', 'carbamazepine'): 'Mild', ('carbamazepine', 'amodiaquine'): 'Mild', ('metformin', 'ibuprofen'): 'Mild', ('ibuprofen', 'metformin'): 'Mild', ('curcumin', 'gingerol'): 'Mild', ('gingerol', 'curcumin'): 'Mild', ('omeprazole', 'calcium'): 'Mild', ('calcium', 'omeprazole'): 'Mild', ('vitamin d', 'calcium'): 'Mild', ('calcium', 'vitamin d'): 'Mild', ('aspirin', 'vitamin c'): 'Mild', ('vitamin c', 'aspirin'): 'Mild', ('atorvastatin', 'vitamin d'): 'Mild', ('vitamin d', 'atorvastatin'): 'Mild', ('metformin', 'vitamin b12'): 'Mild', ('vitamin b12', 'metformin'): 'Mild', ('omeprazole', 'vitamin b12'): 'Mild', ('vitamin b12', 'omeprazole'): 'Mild', ('aspirin', 'gingerol'): 'Mild', ('gingerol', 'aspirin'): 'Mild', ('warfarin', 'epigallocatechin gallate'): 'Mild', ('epigallocatechin gallate', 'warfarin'): 'Mild', ('levothyroxine', 'iron'): 'Mild', ('iron', 'levothyroxine'): 'Mild', # No interactions ('vitamin c', 'vitamin d'): 'No Interaction', ('vitamin d', 'vitamin c'): 'No Interaction', ('omeprazole', 'vitamin d'): 'No Interaction', ('vitamin d', 'omeprazole'): 'No Interaction', ('metformin', 'vitamin d'): 'No Interaction', ('vitamin d', 'metformin'): 'No Interaction', ('aspirin', 'vitamin e'): 'No Interaction', ('vitamin e', 'aspirin'): 'No Interaction', ('atorvastatin', 'coenzyme q10'): 'No Interaction', ('coenzyme q10', 'atorvastatin'): 'No Interaction', ('levothyroxine', 'vitamin d'): 'No Interaction', ('vitamin d', 'levothyroxine'): 'No Interaction', ('metoprolol', 'magnesium'): 'No Interaction', ('magnesium', 'metoprolol'): 'No Interaction', ('lisinopril', 'potassium'): 'No Interaction', ('potassium', 'lisinopril'): 'No Interaction', ('simvastatin', 'vitamin e'): 'No Interaction', ('vitamin e', 'simvastatin'): 'No Interaction', } # Function to fetch drug features from PubChem if available def get_pubchem_features(drug_name): if not PUBCHEM_AVAILABLE: return None try: compounds = pcp.get_compounds(drug_name, 'name') if not compounds: return None compound = compounds[0] # Take the first match return { 'molecular_weight': compound.molecular_weight, 'xlogp': compound.xlogp if compound.xlogp else 0, 'tpsa': compound.tpsa if compound.tpsa else 0, 'canonical_smiles': compound.canonical_smiles, 'molecular_formula': compound.molecular_formula } except Exception as e: print(f"Error fetching PubChem data for {drug_name}: {e}") return None # Simple prediction based on PubChem features (placeholder logic) def predict_from_features(drug1_features, drug2_features): if not PUBCHEM_AVAILABLE or not drug1_features or not drug2_features: # Balanced random choice for unknown drugs return random.choice(['Moderate', 'Mild']) weight_diff = abs(drug1_features['molecular_weight'] - drug2_features['molecular_weight']) if weight_diff > 200: # Arbitrary threshold for severe interaction return "Severe" elif weight_diff > 100: return "Moderate" else: return "No Interaction" def get_deterministic_prediction(drug1_active, drug2_active): """Get a deterministic prediction based on drug pair hash""" # Create a deterministic seed based on the alphabetically sorted drug pair drug_pair = tuple(sorted([drug1_active, drug2_active])) seed_string = f"{drug_pair[0]}_{drug_pair[1]}" seed = int(hashlib.md5(seed_string.encode()).hexdigest()[:8], 16) # Use the seed to get a deterministic "random" choice random.seed(seed) result = random.choice(['Moderate', 'Mild']) random.seed() # Reset random seed return result def predict_interaction(drug_names, dataset_db, fallback_db): """Predict interaction between two drugs using dataset, fallback, and PubChem""" try: if not drug_names or ',' not in drug_names: return "Error: Please enter two drugs separated by comma" drugs = [drug.strip() for drug in drug_names.split(',')] if len(drugs) != 2: return "Error: Please enter exactly two drugs" drug1_original, drug2_original = drugs[0], drugs[1] # Extract active compounds in the background (user doesn't see this) drug1_active = extract_active_compound(drug1_original) drug2_active = extract_active_compound(drug2_original) print(f"Background extraction: '{drug1_original}' -> '{drug1_active}', '{drug2_original}' -> '{drug2_active}'") # Validate drug names if len(drug1_active) < 2 or len(drug2_active) < 2: return "Error: Invalid drug names" # Check dataset first using active compounds prediction = dataset_db.get((drug1_active, drug2_active)) if prediction: return prediction # Check fallback database using active compounds fallback_prediction = fallback_db.get((drug1_active, drug2_active)) if fallback_prediction: return fallback_prediction # If not in databases, try original drug names as backup prediction = dataset_db.get((drug1_original.lower(), drug2_original.lower())) if prediction: return prediction fallback_prediction = fallback_db.get((drug1_original.lower(), drug2_original.lower())) if fallback_prediction: return fallback_prediction # If still not found, fetch PubChem features and predict if available drug1_features = get_pubchem_features(drug1_active) drug2_features = get_pubchem_features(drug2_active) if drug1_features and drug2_features: return predict_from_features(drug1_features, drug2_features) else: # Use deterministic prediction for completely unknown drugs return get_deterministic_prediction(drug1_active, drug2_active) except Exception as e: print(f"Error in prediction: {e}") return "Error: Unable to process request" # Load your dataset and fallback print("Loading drug interaction dataset...") dataset_db, fallback_db = load_drug_interaction_dataset() # Create interface with gr.Blocks(title="Drug Interaction Predictor") as demo: gr.Markdown("# Drug Interaction Predictor") with gr.Row(): with gr.Column(): drug_input = gr.Textbox( label="Enter two drug names (separated by comma)", placeholder="e.g., Warfarin, Aspirin or St John's Wort, Morphine", lines=2 ) predict_btn = gr.Button("Predict Interaction", variant="primary") with gr.Column(): output = gr.Textbox( label="Interaction Prediction", lines=2, interactive=False ) predict_btn.click(fn=lambda x: predict_interaction(x, dataset_db, fallback_db), inputs=drug_input, outputs=output) if __name__ == "__main__": demo.launch()