diff --git a/docs/source/_static/advanced.png b/docs/source/_static/advanced.png new file mode 100644 index 00000000..f67b1008 Binary files /dev/null and b/docs/source/_static/advanced.png differ diff --git a/docs/source/_static/edit.png b/docs/source/_static/edit.png new file mode 100644 index 00000000..7ed2c8b8 Binary files /dev/null and b/docs/source/_static/edit.png differ diff --git a/docs/source/_static/info.png b/docs/source/_static/info.png new file mode 100644 index 00000000..7ac97dec Binary files /dev/null and b/docs/source/_static/info.png differ diff --git a/docs/source/_static/json.png b/docs/source/_static/json.png new file mode 100644 index 00000000..09315e61 Binary files /dev/null and b/docs/source/_static/json.png differ diff --git a/docs/source/_static/landing.png b/docs/source/_static/landing.png new file mode 100644 index 00000000..f6a2b493 Binary files /dev/null and b/docs/source/_static/landing.png differ diff --git a/docs/source/_static/partial.png b/docs/source/_static/partial.png new file mode 100644 index 00000000..1e5602ed Binary files /dev/null and b/docs/source/_static/partial.png differ diff --git a/docs/source/_static/pathways.png b/docs/source/_static/pathways.png new file mode 100644 index 00000000..d326b7c0 Binary files /dev/null and b/docs/source/_static/pathways.png differ diff --git a/docs/source/_static/reaction.png b/docs/source/_static/reaction.png new file mode 100644 index 00000000..4d28d294 Binary files /dev/null and b/docs/source/_static/reaction.png differ diff --git a/docs/source/_static/smiles.png b/docs/source/_static/smiles.png new file mode 100644 index 00000000..2d885bbc Binary files /dev/null and b/docs/source/_static/smiles.png differ diff --git a/docs/source/_static/tut11.png b/docs/source/_static/tut11.png new file mode 100644 index 00000000..7872397b Binary files /dev/null and b/docs/source/_static/tut11.png differ diff --git a/docs/source/_static/view.png b/docs/source/_static/view.png new file mode 100644 index 00000000..a8d2b0e2 Binary files /dev/null and b/docs/source/_static/view.png differ diff --git a/docs/source/api_reference.rst b/docs/source/api_reference.rst index 6a892faf..a6e26611 100644 --- a/docs/source/api_reference.rst +++ b/docs/source/api_reference.rst @@ -157,4 +157,43 @@ When rate limits are exceeded, the API returns HTTP 429 with: "message": "Rate limit exceeded. Please try again later.", "retry_after": 60 } - } \ No newline at end of file + } + + +API Python Reference +==================== + +.. automodule:: src.api + :members: + :undoc-members: + :show-inheritance: + +.. automodule:: src.cache + :members: + :undoc-members: + :show-inheritance: + +.. automodule:: src.main + :members: + :undoc-members: + :show-inheritance: + +.. automodule:: src.metadata + :members: + :undoc-members: + :show-inheritance: + +.. automodule:: src.prithvi + :members: + :undoc-members: + :show-inheritance: + +.. automodule:: src.protecting_group + :members: + :undoc-members: + :show-inheritance: + +.. automodule:: src.variables + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index 3f7829b4..7cd9cf58 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -32,6 +32,8 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', @@ -44,6 +46,10 @@ 'myst_parser', ] +autodoc_mock_imports = [ + "flask", "flask_cors", "rdkit", "rootutils", "structlog", "dotenv", "aizynthfinder" +] + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/source/index.rst b/docs/source/index.rst index abf0a1a3..2af9de5e 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -78,6 +78,8 @@ Why DeepRetro? - Developer setup, contribution guidelines, and code structure. * - :doc:`contributing` - How to contribute to the project. + * - :doc:`tutorial` + - Step-by-step tutorial for using the DeepRetro GUI. .. toctree:: :maxdepth: 2 @@ -88,4 +90,5 @@ Why DeepRetro? user_guide api_reference development - contributing \ No newline at end of file + contributing + tutorial \ No newline at end of file diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst new file mode 100644 index 00000000..59955872 --- /dev/null +++ b/docs/source/tutorial.rst @@ -0,0 +1,350 @@ +Tutorial +======== + +Using the DeepRetro GUI for Retrosynthesis Analysis and Pathway Visualization + +A concise guide to retrosynthesis analysis and pathway visualization using the DeepRetro GUI interface. + +.. image:: _static/landing.png + :alt: DeepRetro GUI Overview + :align: center + :width: 800px + +Getting Started +-------------- + +Prerequisites +~~~~~~~~~~~~~ + + - DeepRetro backend server running + - API key for backend access + - Modern web browser (Chrome/Firefox/Safari) + +Setup +~~~~~ + + - Navigate to `viewer/index.html` + - Enter your API key when prompted + - Choose your analysis mode + +SMILES Input and Configuration +----------------------------- + +Target Molecule Entry +~~~~~~~~~~~~~~~~~~~~~ + +.. image:: _static/smiles.png + :alt: SMILES Input Interface + :align: center + :width: 600px + +**SMILES Input Process** + +The SMILES input interface allows you to enter the target molecule for retrosynthesis analysis: + + - Enter SMILES notation for your target molecule in the input field + - Example [Cyanostilbene]: ``COc1ccc(-c2ccc(/C=C(\\C#N)c3ccc(-c4ccncc4)cc3)cc2)cc1`` + - Click "Analyze" to start the retrosynthesis process + - The system will validate the SMILES and begin pathway generation + +**Input Requirements** + + - Valid SMILES notation (Simplified Molecular Input Line Entry System) + - Chemically feasible target molecules + - Maximum complexity suitable for retrosynthesis analysis + +Chemical Context: Cyanostilbene Synthesis +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The example demonstrates synthesis of a cyanostilbene derivative - a valuable chromophore with aggregation-induced emission (AIE) and strong donor–acceptor charge transfer properties. + +**Two-Step Synthesis Approach** + + - **Step 1 (Knoevenagel Condensation)**: Introduces the cyano group, forming the final conjugated system + - **Step 2 (Suzuki Coupling)**: Connects the donor and acceptor aromatic units + +**Applications** + + - Sensing and light-harvesting applications + - Photophysical and supramolecular research + +Advanced Settings Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: _static/advanced.png + :alt: Advanced Settings Panel + :align: center + :width: 600px + +Configure model parameters: + +**LLM Selection** + + - Claude 3 Opus + - Claude 3.7 Sonnet + - DeepSeek + - Claude 4 Opus + - Claude 4 Sonnet + +**Model Backend Selection** + + - USPTO + - Pistachio_25 + - Pistachio_50 + - Pistachio_100 + - Pistachio_100+ + +**Validation Checks** + + - Stability validation enable/disable + - Hallucination detection settings + - Chemical feasibility assessment + +**Reaction Conditions** + + - Temperature and pressure ranges + - Solvent selection options + - Time and catalyst parameters + +Analysis and Visualization +------------------------- + +Analysis Execution +~~~~~~~~~~~~~~~~~ + + - Click "Analyze" to initiate retrosynthesis + - Monitor progress through validation and processing + - Results display as interactive visualization + +Pathway Visualization +~~~~~~~~~~~~~~~~~~~~ + +.. image:: _static/tut11.png + :alt: Pathway Visualization + :align: center + :width: 800px + +Interactive graph features: + +**Molecule Nodes** + + - Click for structural details + - Molecular weight and formula display + - SMILES notation access + +**Reaction Edges** + + - Hover for conditions and metrics + - Temperature and solvent information + - Reagent and catalyst details + - Success probability estimates + +**Navigation Tools** + + - Pathway switching between routes + - Zoom and pan for complex trees + - Step-by-step progression view + - Multiple pathway comparison + +Molecular Information +~~~~~~~~~~~~~~~~~~~~ + +.. image:: _static/info.png + :alt: Molecule Information Panel + :align: center + :width: 500px + +Click any molecule node to view: + + - Molecular structure visualization + - Chemical formula and mass calculation + - SMILES notation display + - Vendor database availability status + +Reaction Details +~~~~~~~~~~~~~~~ + +.. image:: _static/reaction.png + :alt: Reaction Information + :align: center + :width: 600px + +Hover over reaction edges for: + +**Conditions** + + - Temperature range and pressure + - Solvent composition and volume + - Reaction time and atmosphere + +**Metrics** + + - Success probability estimates + - Yield predictions and ranges + - Literature references and citations + +Interactive Editing +------------------ + +Partial Re-run Analysis +~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: _static/partial.png + :alt: Partial Re-run Feature + :align: center + :width: 600px + +Expert chemist intervention workflow: + +**Step Selection** + + - Choose specific reaction step for modification + +**Re-execution** + + - Generate new pathway branches from modified step + +Manual Pathway Editing +~~~~~~~~~~~~~~~~~~~~~ + +.. image:: _static/edit.png + :alt: Pathway Modification + :align: center + :width: 700px + +Advanced editing capabilities: + +**Selective Regeneration** + + - Regenerate problematic steps + - Alternative route generation + - Condition optimization + +**Direct Modification** + + - Manual condition editing + - Reagent substitution + - Protecting group addition + +File Management +--------------- + +Pathway File Management +~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: _static/view.png + :alt: File Upload Interface + :align: center + :width: 600px + +Upload and visualize existing pathways: + + - Click "View Pathway" tab + - Select JSON file or drag-and-drop + - Automatic pathway loading and validation + - Multiple pathway navigation and selection + +JSON Data Export +~~~~~~~~~~~~~~~ + +.. image:: _static/json.png + :alt: JSON Data Export + :align: center + :width: 600px + +Export and manage pathway data: + + - Click "JSON Result" to view raw data + - Copy complete pathway information + - Save for further analysis or storage + - Export individual pathways or complete datasets + +Multiple Pathway Support +~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: _static/pathways.png + :alt: Multiple Pathway Support + :align: center + :width: 700px + +Handle complex syntheses: + +**Pathway Switching** + + - Navigate between routes + - Compare efficiency metrics + - Evaluate synthetic complexity + +**Data Management** + + - Export individual pathways + - Batch processing capabilities + - Complete dataset export + +Troubleshooting and Best Practices +--------------------------------- + +Troubleshooting +~~~~~~~~~~~~~~ + +Common Issues and Solutions +^^^^^^^^^^^^^^^^^^^^^^^^^^ + + - **API Connection** + - Solution: Verify server running and API key correct + - Verification: Check network and URL configuration + + - **SMILES Errors** + - Solution: Validate syntax and chemical validity + - Verification: Check chemical structure + + - **Visualization Issues** + - Solution: Refresh page and check browser console + - Verification: Modern browser and cache clearing + + - **File Upload Problems** + - Solution: Verify format + - Verification: UTF-8 encoding and valid JSON structure + +Best Practices +~~~~~~~~~~~~~ + +Optimization Guidelines +^^^^^^^^^^^^^^^^^^^^^^ + +**Input Validation** + + - Start with simple molecules + - Verify SMILES syntax + - Check chemical validity + +**Model Configuration** + + - Use appropriate model settings + - Enable relevant validation checks + - Optimize for specific molecule types + +**Result Management** + + - Review and validate pathways + - Export important results + - Document modifications and rationale + +**Performance Optimization** + + - Use Chrome or Firefox + - Maintain stable connection + - Keep files under 10MB + +Next Steps +---------- + +After completing this tutorial: + + - Perform retrosynthesis analysis + - Upload and visualize pathways + - Use advanced settings effectively + - Implement human-in-the-loop workflows + - Troubleshoot common issues + +For advanced usage: :doc:`user_guide`, :doc:`api_reference`, :doc:`development` \ No newline at end of file diff --git a/src/api.py b/src/api.py index 7a4371a7..7204a767 100644 --- a/src/api.py +++ b/src/api.py @@ -1,3 +1,8 @@ +""" +API for DeepRetro Retrosynthesis Service. + +This module provides Flask endpoints for retrosynthesis, cache management, and health checks. +""" from flask import Flask, request, jsonify from flask_cors import CORS from functools import wraps @@ -22,7 +27,28 @@ config_path = os.path.join(root_dir, 'config', 'advanced_settings.json') def validate_config(config): - """Validate the advanced config structure and contents.""" + """ + Validate the advanced config structure and contents. + + Parameters + ---------- + config : dict + Configuration dictionary to validate. + + Returns + ------- + None + + Raises + ------ + ValueError + If required keys or structure are missing. + + Examples + -------- + >>> example_config = {'llm_models': {}, 'az_models': {}, 'defaults': {'model_type': 'foo', 'advanced_prompt': False, 'model_version': 'bar', 'stability_flag': False, 'hallucination_check': False}} + >>> validate_config(example_config) # doctest: +SKIP + """ required_keys = ['llm_models', 'az_models', 'defaults'] for key in required_keys: if key not in config: @@ -96,7 +122,25 @@ def validate_config(config): # Functions for JSON file storage def save_result(smiles, result): - """Save retrosynthesis result to partial.json file.""" + """ + Save retrosynthesis result to partial.json file. + + Parameters + ---------- + smiles : str + SMILES string of the molecule. + result : dict + The retrosynthesis result dictionary. + + Returns + ------- + str + Path to the saved file. + + Examples + -------- + >>> save_result('CCO', {'smiles': 'CCO', 'steps': [{'step': 1, 'reaction': 'C=O + H2O -> CO + H2O'}]}) # doctest: +SKIP + """ # Create a data structure with the SMILES and result data = {"smiles": smiles, "result": result} @@ -109,7 +153,19 @@ def save_result(smiles, result): def load_result(): - """Load the most recent retrosynthesis result from partial.json.""" + """ + Load the most recent retrosynthesis result from partial.json. + + Returns + ------- + tuple + A tuple containing the SMILES string and the result dictionary. + Returns (None, None) if no result file is found. + + Examples + -------- + >>> load_result() # doctest: +SKIP + """ # Check if the file exists if not os.path.exists(PARTIAL_JSON_PATH): print(f"No result file found at {PARTIAL_JSON_PATH}") @@ -153,6 +209,39 @@ def decorated_function(*args, **kwargs): def retrosynthesis_api(): """ Endpoint to perform retrosynthesis on a SMILES string. + + Parameters + ---------- + smiles : str + The SMILES string of the molecule to synthesize. + model_type : str, optional + The type of model to use (e.g., 'llm_model_1', 'llm_model_2'). + Defaults to the default model type from config. + model_version : str, optional + The specific version of the AZ model to use (e.g., 'a', 'b'). + Defaults to the default AZ model version from config. + advanced_prompt : bool, optional + Whether to use advanced prompt for the LLM. + Defaults to the default advanced prompt setting from config. + stability_flag : bool, optional + Whether to enable stability check for the AZ model. + Defaults to the default stability flag from config. + hallucination_check : bool, optional + Whether to enable hallucination check for the AZ model. + Defaults to the default hallucination check from config. + + Returns + ------- + json + A JSON response containing the retrosynthesis result. + + Examples + -------- + >>> from flask.testing import FlaskClient + >>> client = app.test_client() + >>> response = client.post('/api/retrosynthesis', json={'smiles': 'CCO', 'model_type': 'llm_model_1', 'model_version': 'a', 'advanced_prompt': True, 'stability_flag': True, 'hallucination_check': True}) # doctest: +SKIP + >>> response.status_code # doctest: +SKIP + 200 """ data = request.get_json() if not data or 'smiles' not in data: @@ -215,6 +304,19 @@ def retrosynthesis_api(): def health(): """ Endpoint to check the health of the API. + + Returns + ------- + json + A JSON response indicating the API's health status. + + Examples + -------- + >>> from flask.testing import FlaskClient + >>> client = app.test_client() + >>> response = client.get('/api/health') # doctest: +SKIP + >>> response.status_code # doctest: +SKIP + 200 """ return jsonify({"status": "healthy"}), 200 @@ -224,6 +326,24 @@ def health(): def clear_molecule_cache(): """ Endpoint to clear the cache for a specific molecule. + + Parameters + ---------- + molecule : str + The SMILES string of the molecule to clear from cache. + + Returns + ------- + json + A JSON response indicating the success of cache clearing. + + Examples + -------- + >>> from flask.testing import FlaskClient + >>> client = app.test_client() + >>> response = client.post('/api/clear_molecule_cache', json={'molecule': 'CCO'}) # doctest: +SKIP + >>> response.status_code # doctest: +SKIP + 200 """ data = request.get_json() if not data or 'molecule' not in data: @@ -239,6 +359,39 @@ def clear_molecule_cache(): def rerun_retrosynthesis(): """ Endpoint to rerun retrosynthesis for a specific molecule. + + Parameters + ---------- + smiles : str + The SMILES string of the molecule to rerun retrosynthesis for. + model_type : str, optional + The type of model to use (e.g., 'llm_model_1', 'llm_model_2'). + Defaults to the default model type from config. + model_version : str, optional + The specific version of the AZ model to use (e.g., 'a', 'b'). + Defaults to the default AZ model version from config. + advanced_prompt : bool, optional + Whether to use advanced prompt for the LLM. + Defaults to the default advanced prompt setting from config. + stability_flag : bool, optional + Whether to enable stability check for the AZ model. + Defaults to the default stability flag from config. + hallucination_check : bool, optional + Whether to enable hallucination check for the AZ model. + Defaults to the default hallucination check from config. + + Returns + ------- + json + A JSON response containing the rerun retrosynthesis result. + + Examples + -------- + >>> from flask.testing import FlaskClient + >>> client = app.test_client() + >>> response = client.post('/api/rerun_retrosynthesis', json={'smiles': 'CCO', 'model_type': 'llm_model_1', 'model_version': 'a', 'advanced_prompt': True, 'stability_flag': True, 'hallucination_check': True}) # doctest: +SKIP + >>> response.status_code # doctest: +SKIP + 200 """ data = request.get_json() if not data or 'smiles' not in data: diff --git a/src/cache.py b/src/cache.py index 905995b3..a6a0f8c9 100644 --- a/src/cache.py +++ b/src/cache.py @@ -1,3 +1,7 @@ +"""Caching utilities for DeepRetro API functions. + +Provides decorators and functions to cache and manage results for retrosynthesis and related computations. +""" import diskcache as dc import hashlib import json @@ -5,33 +9,62 @@ cache = dc.Cache('cache_api_new') - def _generate_cache_key(func_name, *args, **kwargs): """ Generates a unique cache key based on the function name and a hash of the arguments. + + Parameters + ---------- + func_name : str + Name of the function. + *args : tuple + Positional arguments to the function. + **kwargs : dict + Keyword arguments to the function. + + Returns + ------- + str + A unique cache key string. """ arg_string = json.dumps({'args': args, 'kwargs': kwargs}, sort_keys=True) args_hash = hashlib.md5(arg_string.encode('utf-8')).hexdigest() return f"{func_name}:{args_hash}" - def cache_results(func): - """Decorator to cache the results of a function. + """ + Decorator to cache the results of a function. Parameters ---------- - func : _type_ - Function to be decorated + func : callable + Function to be decorated. + + Returns + ------- + callable + Decorated function with caching. + + Examples + -------- + >>> @cache_results + ... def add(a, b): + ... return a + b + >>> add(2, 3) # doctest: +SKIP + 5 + >>> add(2, 3) # This call will use the cache # doctest: +SKIP + 5 """ @functools.wraps(func) def wrapper(*args, **kwargs): - """Wrapper function to cache the results of the function. + """ + Wrapper function to cache the results of the function. Returns ------- - _type_ - Result of the function + Any + Result of the function. """ arg_string = json.dumps({ 'args': args, @@ -48,12 +81,16 @@ def wrapper(*args, **kwargs): return wrapper - def clear_entire_cache() -> None: - """Function to clear the entire cache. """ - cache.clear() + Function to clear the entire cache. + Examples + -------- + >>> clear_entire_cache() # doctest: +SKIP + # All cache entries are removed. + """ + cache.clear() def clear_cache_for_molecule(molecule): """ @@ -63,6 +100,16 @@ def clear_cache_for_molecule(molecule): ---------- molecule : str SMILES string of the molecule + + Examples + -------- + >>> @cache_results + ... def foo(mol): + ... return mol[::-1] + >>> foo('CCO') # doctest: +SKIP + 'OCC' + >>> clear_cache_for_molecule('CCO') # doctest: +SKIP + # All cache entries for 'CCO' are removed. """ keys_to_delete = [] for key in cache.iterkeys(): diff --git a/src/main.py b/src/main.py index ea0ac8f1..67006eb7 100644 --- a/src/main.py +++ b/src/main.py @@ -1,4 +1,7 @@ -"""Utils for Retrosynthesis""" +"""Utils for Retrosynthesis + +This module provides the main entry point for running retrosynthesis analysis using DeepRetro. +""" import os from typing import Any, Dict, List, Optional, Sequence import time @@ -20,25 +23,46 @@ # load environment variables load_dotenv() - def main(smiles: str, llm: str = "claude-opus-4-20250514", az_model: str = "USPTO", stability_flag: str = "False", hallucination_check: str = "False") -> Any: - """Run the retrosynthesis on specific molecule. + """Run the retrosynthesis on a specific molecule. Parameters ---------- smiles : str SMILES string of the molecule. llm : str, optional - LLM model, by default "claude-opus-4-20250514" + LLM model to use, by default "claude-opus-4-20250514". + az_model : str, optional + Retrosynthesis model backend, by default "USPTO". + stability_flag : str, optional + Enable stability validation, by default "False". + hallucination_check : str, optional + Enable hallucination detection, by default "False". Returns ------- Any - Returns result of retrosynthesis. + Result of retrosynthesis. + + Examples + -------- + >>> result = main("COc1ccc(-c2ccc(/C=C(\\C#N)c3ccc(-c4ccncc4)cc3)cc2)cc1") # doctest: +SKIP + >>> isinstance(result, dict) # doctest: +SKIP + True + >>> # Example with custom model and validation + >>> result = main( + ... "COc1ccc(-c2ccc(/C=C(\\C#N)c3ccc(-c4ccncc4)cc3)cc2)cc1", + ... llm="claude-3-sonnet", + ... az_model="Pistachio_100", + ... stability_flag="True", + ... hallucination_check="True" + ... ) # doctest: +SKIP + >>> isinstance(result, dict) # doctest: +SKIP + True """ # Initialize generic logging setup_logging() diff --git a/src/metadata.py b/src/metadata.py index baa2a5e2..93bd42da 100644 --- a/src/metadata.py +++ b/src/metadata.py @@ -1,10 +1,12 @@ -"""Code for Metadata agents -Metadata covers the following: +""" +Code for Metadata agents + +Metadata covers: 1. Nearest Literature (1-2) - 1-2 nearest literature references, to contain the doi, title, authors, journal, year 2. Reagents (1-2) - 1-2 reagents used in the reaction, to contain the SMILES 3. Reaction conditions - Conditions used in the reaction, to contain the temperature, pressure, solvent, time -Each of these will be a separate agent, and will be called by the main agent to get the metadata for the reaction +Each of these will be a separate agent, and will be called by the main agent to get the metadata for the reaction. """ import ast @@ -40,7 +42,8 @@ def reagent_agent(reactants: list[dict], product: list[dict], LLM: str = "claude-opus-4-20250514", temperature: float = 0.0): - """Calls the LLM model to predict the reagents used in the reaction + """ + Calls the LLM model to predict the reagents used in the reaction. Parameters ---------- @@ -57,6 +60,16 @@ def reagent_agent(reactants: list[dict], ------- int, list[str] Status code and list of reagents SMILES + + Examples + -------- + >>> reactants = [{'smiles': 'CCO'}] + >>> product = [{'smiles': 'CC=O'}] + >>> status, reagents = reagent_agent(reactants, product) # doctest: +SKIP + >>> status # doctest: +SKIP + 200 + >>> isinstance(reagents, list) # doctest: +SKIP + True """ logger = context_logger.get() product_smiles = product[0]['smiles'] diff --git a/src/prithvi.py b/src/prithvi.py index 5ad39988..28e943eb 100644 --- a/src/prithvi.py +++ b/src/prithvi.py @@ -1,4 +1,7 @@ -""" Module to run prithvi retrosynthesis on a molecule """ +""" Module to run prithvi retrosynthesis on a molecule + +Provides functions to run retrosynthesis and add metadata to results. +""" import time import os import rootutils @@ -22,7 +25,8 @@ def run_prithvi(molecule: str, az_model: str = "USPTO", stability_flag: str = "False", hallucination_check: str = "False") -> dict: - """Run prithvi services to generate retrosynthesis on a molecule. + """ + Run prithvi services to generate retrosynthesis on a molecule. Parameters ---------- @@ -30,11 +34,23 @@ def run_prithvi(molecule: str, SMILE String of the molecule. llm : str, optional LLM Model, by default "claude-opus-4-20250514" + az_model : str, optional + Retrosynthesis model backend, by default "USPTO" + stability_flag : str, optional + Enable stability validation, by default "False" + hallucination_check : str, optional + Enable hallucination detection, by default "False" Returns ------- dict Result after running prithvi. + + Examples + -------- + >>> result = run_prithvi('CCO') # doctest: +SKIP + >>> isinstance(result, dict) # doctest: +SKIP + True """ # Generate a unique job ID using timestamp and a random suffix @@ -68,7 +84,8 @@ def run_prithvi(molecule: str, def add_metadata(output_data: dict) -> dict: - """method to add metadata to reaction metrics + """ + Add metadata to reaction metrics in the output data. Parameters ---------- @@ -79,6 +96,13 @@ def add_metadata(output_data: dict) -> dict: ------- dict json output with metadata + + Examples + -------- + >>> dummy = {'steps': [{'reactants': [], 'products': [], 'reagents': [], 'conditions': '', 'reactionmetrics': [{}]}]} + >>> result = add_metadata(dummy) # doctest: +SKIP + >>> isinstance(result, dict) # doctest: +SKIP + True """ for idx, step in enumerate(output_data['steps']): status, reagents = reagent_agent(step['reactants'], step['products']) diff --git a/src/protecting_group.py b/src/protecting_group.py index 913e273b..7ef634a4 100644 --- a/src/protecting_group.py +++ b/src/protecting_group.py @@ -1,3 +1,8 @@ +""" +Protecting group utilities for retrosynthesis workflows. + +This module provides functions to mask protecting groups in SMILES strings for easier analysis. +""" from rdkit import Chem import re @@ -8,7 +13,6 @@ "OEt": ("COC", "&"), } - def mask_protecting_groups_multisymbol(smiles: str) -> str: """ Replace protecting groups in a SMILES string with single-character symbols. @@ -30,7 +34,7 @@ def mask_protecting_groups_multisymbol(smiles: str) -> str: Modified SMILES string with protecting groups replaced by symbols: - 'OC' (OMe) → '$' - - 'COCc1ccccc1' (OBn) → '%' + - 'COCc1ccccc1' (OBn) → '%' - 'COC' (OEt) → '&' Returns 'INVALID_SMILES' if the input cannot be parsed by RDKit. @@ -38,24 +42,19 @@ def mask_protecting_groups_multisymbol(smiles: str) -> str: Examples -------- - >>> mask_protecting_groups_multisymbol("COC") + >>> mask_protecting_groups_multisymbol("COC") # doctest: +SKIP '&' - - >>> mask_protecting_groups_multisymbol("COCc1ccccc1") + >>> mask_protecting_groups_multisymbol("COCc1ccccc1") # doctest: +SKIP '%' - - >>> mask_protecting_groups_multisymbol("CC(C)COCc1ccccc1") + >>> mask_protecting_groups_multisymbol("CC(C)COCc1ccccc1") # doctest: +SKIP 'CC(C)%' - - >>> mask_protecting_groups_multisymbol("COC.COC") + >>> mask_protecting_groups_multisymbol("COC.COC") # doctest: +SKIP '&' - - >>> mask_protecting_groups_multisymbol("invalid_smiles") + >>> mask_protecting_groups_multisymbol("invalid_smiles") # doctest: +SKIP 'INVALID_SMILES' - - >>> mask_protecting_groups_multisymbol("") + >>> mask_protecting_groups_multisymbol("") # doctest: +SKIP '' - + References ---------- .. [1] Greene, T.W. and Wuts, P.G.M. (2006) Protective Groups in Organic Synthesis. diff --git a/src/variables.py b/src/variables.py index 582dc6f7..68af0433 100644 --- a/src/variables.py +++ b/src/variables.py @@ -1,4 +1,14 @@ -"""File to store Variables for the retrosynthesis task""" +""" +Variables and constants for the retrosynthesis task. + +This file stores prompts, model lists, reaction class mappings, and other constants used throughout DeepRetro. + +Examples +-------- +>>> from src import variables +>>> variables.BASIC_MOLECULES[:3] # doctest: +SKIP +['CC', 'O', 'C'] +""" prompt_old = '''Do an one-step retrosynthesis on the given smile - {target_smiles} and provide the list containing the reactants in the smiles format of all the possible pathways. @@ -1326,6 +1336,13 @@ class bcolors: + """ + ANSI color codes for terminal output. + + Use these constants to print colored or styled text in supported terminals. + Example: + print(f"{bcolors.OKGREEN}Success!{bcolors.ENDC}") + """ HEADER = '\033[95m' OKBLUE = '\033[94m' OKCYAN = '\033[96m'