import gradio as gr from CDK_pywrapper import CDK from rdkit import Chem from rdkit.Chem import Descriptors, Draw, AllChem, rdMolDescriptors from rdkit.DataStructs import TanimotoSimilarity import pandas as pd import numpy as np import tempfile # Function to convert SMILES to MolFile def convert_smiles_to_mol(smiles_list, checkbox): if checkbox == True: cdk = CDK(ignore_3D=False) else: cdk = CDK(ignore_3D=True) smiles_list = list(smiles_list.split(',')) try: mols = [Chem.AddHs(Chem.MolFromSmiles(smiles)) for smiles in smiles_list] molfile = cdk.calculate(mols) try: with tempfile.NamedTemporaryFile(delete=False, suffix='.xlsx') as tmp: file_path = tmp.name molfile.to_excel(file_path, index=False) return molfile,file_path except Exception as e: return molfile,str(e) except Exception as e: return str(e), None # Function to calculate Molecular Weight def calculate_molecular_weight(smiles): if smiles is None: return "SMILES string is None" try: molecule = Chem.MolFromSmiles(smiles) if molecule is None: return "Invalid SMILES" mol_weight = Descriptors.MolWt(molecule) img = Draw.MolToImage(molecule) return mol_weight, img except Exception as e: return str(e) def get_geometric_descriptors(smiles): try: mol = Chem.MolFromSmiles(smiles) if mol is None: return "Invalid SMILES string", None # Add hydrogens and compute 3D coordinates mol = Chem.AddHs(mol) AllChem.EmbedMolecule(mol, AllChem.ETKDG()) AllChem.UFFOptimizeMolecule(mol) # Calculate geometric descriptors conformer = mol.GetConformer() coords = conformer.GetPositions() centroid = np.mean(coords, axis=0) centroid = np.round(centroid, 12) distances = np.linalg.norm(coords - centroid, axis=1) mol_weight = Descriptors.MolWt(mol) geometric_descriptors = { 'Molecular Weight': mol_weight, 'Centroid': centroid.tolist(), 'Mean Distance To Centroid': np.mean(distances), 'Max Distance To Centroid': np.max(distances) } img = Draw.MolToImage(mol) df = pd.DataFrame([geometric_descriptors]) return df.T,img except Exception as e: return str(e), None # Function to check if a substructure is present def check_substructure(smiles, substructure_smiles): # Convert the SMILES strings to RDKit molecule objects molecule = Chem.MolFromSmiles(smiles) substructure = Chem.MolFromSmiles(substructure_smiles) # Check if the molecule is None (invalid SMILES) if molecule is None or substructure is None: return None,None,"Invalid SMILES string provided." # Use RDKit's HasSubstructMatch to check for the substructure val = molecule.HasSubstructMatch(substructure) img1 = Draw.MolToImage(molecule) if val: try: molecule = Chem.MolFromSmiles(smiles) sub_molecule = Chem.MolFromSmiles(substructure_smiles) img1 = Draw.MolToImage(molecule) img2 = Draw.MolToImage(sub_molecule) return img1, img2, "Substructure is present." except Exception as e: return None, None, "Substructure is present." else: return img1,None,"Substructure is not present." def calculate_similarity(smiles1, smiles2): try: mol1 = Chem.MolFromSmiles(smiles1) mol2 = Chem.MolFromSmiles(smiles2) if mol1 is None or mol2 is None: return "Invalid SMILES string" fp1 = rdMolDescriptors.GetMorganFingerprintAsBitVect(mol1, radius=2, nBits=2048) fp2 = rdMolDescriptors.GetMorganFingerprintAsBitVect(mol2, radius=2, nBits=2048) similarity = TanimotoSimilarity(fp1, fp2) return similarity except Exception as e: return str(e) def perform_reaction(reactant1_smiles, reactant2_smiles, reaction_smarts): try: # Define the reaction using SMARTS provided by the user reaction = AllChem.ReactionFromSmarts(reaction_smarts) # Convert SMILES to RDKit molecules reactant1 = Chem.MolFromSmiles(reactant1_smiles) reactant2 = Chem.MolFromSmiles(reactant2_smiles) if reactant1 is None or reactant2 is None: return "Invalid SMILES string(s)", None # Run the reaction products = reaction.RunReactants((reactant1, reactant2)) # Create a grid image of reactants and products all_mols = [reactant1, reactant2] legends = ["Reactant 1", "Reactant 2"] for i, product_set in enumerate(products): for j, product in enumerate(product_set): all_mols.append(product) legends.append(f'Product {i+1}.{j+1}') img = Draw.MolsToGridImage(all_mols, molsPerRow=4, subImgSize=(300, 300), legends=legends) return "Reaction Successful", img except Exception as e: return str(e), None # Gradio Interface def generate_reaction_image(reaction_smarts,reactant1_smiles, reactant2_smiles): result, img = perform_reaction(reactant1_smiles, reactant2_smiles, reaction_smarts) return result, img # Gradio Interface with gr.Blocks(theme='earneleh/paris') as demo: gr.Markdown("### CDK Functionality with Gradio Interface") with gr.Tab("Calculate Descriptors"): smiles_input = gr.Textbox(label="SMILES", info="Enter SMILES separated by comma") checkbox = gr.Checkbox(label="Include 3D Coordinates") molfile_output = gr.Textbox(label="MolFile", lines=10) convert_button = gr.Button("Calculate") download_link = gr.File(label="Download Descriptors as Excel") convert_button.click(fn=convert_smiles_to_mol, inputs=[smiles_input, checkbox], outputs=[molfile_output,download_link]) with gr.Tab("Geometric Values"): with gr.Row(): with gr.Column(min_width=800): smiles_input_mw = gr.Textbox(label="SMILE") weight_output = gr.TextArea(label="Geometric Values", lines=8, show_copy_button=True) calculate_button = gr.Button("Calculate") with gr.Column(): image_output = gr.Image(label="Molecular Structure", height=400, width=500, interactive=True) calculate_button.click(fn=get_geometric_descriptors, inputs=smiles_input_mw,outputs=[weight_output, image_output]) with gr.Tab("Check Substructure"): with gr.Row(): with gr.Column(): smiles_input_sub = gr.Textbox(label="SMILES") substructure_input = gr.Textbox(label="Substructure SMILES") substructure_output = gr.Label(label="Is Substructure Present?") check_button = gr.Button("Check") with gr.Column(): image_output1 = gr.Image(label="Molecular Structure", height=350, width=500, interactive=True) image_output2 = gr.Image(label="Sub_Molecular Structure", height=350, width=500, interactive=True) check_button.click(fn=check_substructure, inputs=[smiles_input_sub, substructure_input], outputs=[image_output1, image_output2, substructure_output]) with gr.Tab("Calculate Similarity"): smiles_input1 = gr.Textbox(label="SMILES 1") smiles_input2 = gr.Textbox(label="SMILES 2") similarity_output = gr.Label(label="Similarity (Tanimoto)") calculate_button_sim = gr.Button("Calculate Similarity") calculate_button_sim.click(fn=calculate_similarity, inputs=[smiles_input1, smiles_input2], outputs=similarity_output) with gr.Tab("Chemical Reaction"): reaction_smarts_input = gr.Textbox(label="Reaction SMARTS",value="[O:2]=[C:1][OH].[N:3]>>[O:2]=[C:1][N:3]") smiles_input1 = gr.Textbox(label="Reactant 1 SMILES", value="OC=O") smiles_input2 = gr.Textbox(label="Reactant 2 SMILES", value= "NCC") calculate_button = gr.Button("Perform Reaction") result_output = gr.Label(label="Result") image_output = gr.Image(label="Reaction Image", interactive=True) calculate_button.click(fn=generate_reaction_image, inputs=[reaction_smarts_input, smiles_input1, smiles_input2], outputs=[result_output, image_output]) # Launch Gradio Interface demo.launch()