aiagents4pharma 1.6.1__tar.gz → 1.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/PKG-INFO +10 -2
  2. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/README.md +8 -1
  3. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2biomodels/models/basico_model.py +24 -21
  4. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2biomodels/models/sys_bio_model.py +5 -5
  5. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2biomodels/tools/__init__.py +3 -5
  6. aiagents4pharma-1.7.0/aiagents4pharma/talk2biomodels/tools/ask_question.py +72 -0
  7. aiagents4pharma-1.7.0/aiagents4pharma/talk2biomodels/tools/custom_plotter.py +84 -0
  8. aiagents4pharma-1.7.0/aiagents4pharma/talk2biomodels/tools/get_modelinfo.py +130 -0
  9. aiagents4pharma-1.7.0/aiagents4pharma/talk2biomodels/tools/load_biomodel.py +29 -0
  10. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2biomodels/tools/search_models.py +9 -29
  11. aiagents4pharma-1.7.0/aiagents4pharma/talk2biomodels/tools/simulate_model.py +178 -0
  12. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma.egg-info/PKG-INFO +10 -2
  13. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma.egg-info/SOURCES.txt +2 -2
  14. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma.egg-info/requires.txt +1 -0
  15. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/pyproject.toml +1 -0
  16. aiagents4pharma-1.7.0/release_version.txt +1 -0
  17. aiagents4pharma-1.6.1/aiagents4pharma/talk2biomodels/tools/ask_question.py +0 -113
  18. aiagents4pharma-1.6.1/aiagents4pharma/talk2biomodels/tools/custom_plotter.py +0 -79
  19. aiagents4pharma-1.6.1/aiagents4pharma/talk2biomodels/tools/fetch_parameters.py +0 -84
  20. aiagents4pharma-1.6.1/aiagents4pharma/talk2biomodels/tools/model_description.py +0 -135
  21. aiagents4pharma-1.6.1/aiagents4pharma/talk2biomodels/tools/simulate_model.py +0 -190
  22. aiagents4pharma-1.6.1/release_version.txt +0 -1
  23. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/LICENSE +0 -0
  24. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/__init__.py +0 -0
  25. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2biomodels/__init__.py +0 -0
  26. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2biomodels/models/__init__.py +0 -0
  27. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2cells/__init__.py +0 -0
  28. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2cells/agents/__init__.py +0 -0
  29. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2cells/agents/scp_agent.py +0 -0
  30. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2cells/states/__init__.py +0 -0
  31. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2cells/states/state_talk2cells.py +0 -0
  32. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2cells/tools/__init__.py +0 -0
  33. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2knowledgegraphs/__init__.py +0 -0
  34. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2knowledgegraphs/datasets/__init__.py +0 -0
  35. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2knowledgegraphs/datasets/biobridge_primekg.py +0 -0
  36. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2knowledgegraphs/datasets/dataset.py +0 -0
  37. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2knowledgegraphs/datasets/primekg.py +0 -0
  38. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2knowledgegraphs/datasets/starkqa_primekg.py +0 -0
  39. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2knowledgegraphs/utils/__init__.py +0 -0
  40. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2knowledgegraphs/utils/embeddings/__init__.py +0 -0
  41. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2knowledgegraphs/utils/embeddings/embeddings.py +0 -0
  42. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2knowledgegraphs/utils/embeddings/huggingface.py +0 -0
  43. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2knowledgegraphs/utils/embeddings/sentence_transformer.py +0 -0
  44. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma/talk2knowledgegraphs/utils/kg_utils.py +0 -0
  45. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma.egg-info/dependency_links.txt +0 -0
  46. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/aiagents4pharma.egg-info/top_level.txt +0 -0
  47. {aiagents4pharma-1.6.1 → aiagents4pharma-1.7.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: aiagents4pharma
3
- Version: 1.6.1
3
+ Version: 1.7.0
4
4
  Summary: AI Agents for drug discovery, drug development, and other pharmaceutical R&D
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -13,6 +13,7 @@ Requires-Dist: coverage==7.6.4
13
13
  Requires-Dist: einops==0.8.0
14
14
  Requires-Dist: gdown==5.2.0
15
15
  Requires-Dist: huggingface_hub==0.26.5
16
+ Requires-Dist: hydra-core==1.3.2
16
17
  Requires-Dist: joblib==1.4.2
17
18
  Requires-Dist: langchain==0.3.7
18
19
  Requires-Dist: langchain-community==0.3.5
@@ -43,7 +44,10 @@ Requires-Dist: mkdocs-include-markdown-plugin==7.1.2
43
44
  Requires-Dist: mkdocstrings==0.27.0
44
45
  Requires-Dist: streamlit-feedback
45
46
 
46
- [![TESTS](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests.yml/badge.svg?branch=feat%2Finitial-setup)](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests.yml)
47
+ [![Talk2BioModels](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2biomodels.yml/badge.svg)](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2biomodels.yml)
48
+ [![Talk2Cells](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2cells.yml/badge.svg)](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2cells.yml)
49
+ [![Talk2KnowledgeGraphs](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2knowledgegraphs.yml/badge.svg)](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2knowledgegraphs.yml)
50
+ [![Talk2Competitors](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2competitors.yml/badge.svg)](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2competitors.yml)
47
51
 
48
52
  <h1 align="center" style="border-bottom: none;">🤖 AIAgents4Pharma</h1>
49
53
 
@@ -54,6 +58,7 @@ Our toolkit currently consists of three intelligent agents, each designed to sim
54
58
  - **Talk2BioModels**: Engage directly with mathematical models in systems biology.
55
59
  - **Talk2Cells** *(Work in progress)*: Query and analyze sequencing data with ease.
56
60
  - **Talk2KnowledgeGraphs** *(Work in progress)*: Access and explore complex biological knowledge graphs for insightful data connections.
61
+ - **Talk2Competitors** *(Coming soon)*: Get recommendations for articles related to your choice. Download, query, and write/retrieve them to your reference manager (currently supporting Zotero).
57
62
 
58
63
  ---
59
64
 
@@ -75,6 +80,8 @@ Our toolkit currently consists of three intelligent agents, each designed to sim
75
80
 
76
81
  **Talk2KnowledgeGraphs** is an agent designed to enable interaction with biological knowledge graphs (KGs). KGs integrate vast amounts of structured biological data into a format that highlights relationships between entities, such as proteins, genes, and diseases.
77
82
 
83
+ ### 4. Talk2KnowledgeGraphs *(Coming soon)*
84
+
78
85
  ## Getting Started
79
86
 
80
87
  ### Prerequisites
@@ -173,6 +180,7 @@ Check out our [CONTRIBUTING.md](CONTRIBUTING.md) for more information.
173
180
  - **User Interface**: Interactive web UI for all agents.
174
181
  - **Talk2Cells**: Integration of sequencing data analysis tools.
175
182
  - **Talk2KnowledgeGraphs**: Interface for biological knowledge graph interaction.
183
+ - **Talk2Competitors**
176
184
 
177
185
  We’re excited to bring AIAgents4Pharma to the bioinformatics and pharmaceutical research community. Together, let’s make data-driven biological research more accessible and insightful.
178
186
 
@@ -1,4 +1,7 @@
1
- [![TESTS](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests.yml/badge.svg?branch=feat%2Finitial-setup)](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests.yml)
1
+ [![Talk2BioModels](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2biomodels.yml/badge.svg)](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2biomodels.yml)
2
+ [![Talk2Cells](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2cells.yml/badge.svg)](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2cells.yml)
3
+ [![Talk2KnowledgeGraphs](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2knowledgegraphs.yml/badge.svg)](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2knowledgegraphs.yml)
4
+ [![Talk2Competitors](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2competitors.yml/badge.svg)](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2competitors.yml)
2
5
 
3
6
  <h1 align="center" style="border-bottom: none;">🤖 AIAgents4Pharma</h1>
4
7
 
@@ -9,6 +12,7 @@ Our toolkit currently consists of three intelligent agents, each designed to sim
9
12
  - **Talk2BioModels**: Engage directly with mathematical models in systems biology.
10
13
  - **Talk2Cells** *(Work in progress)*: Query and analyze sequencing data with ease.
11
14
  - **Talk2KnowledgeGraphs** *(Work in progress)*: Access and explore complex biological knowledge graphs for insightful data connections.
15
+ - **Talk2Competitors** *(Coming soon)*: Get recommendations for articles related to your choice. Download, query, and write/retrieve them to your reference manager (currently supporting Zotero).
12
16
 
13
17
  ---
14
18
 
@@ -30,6 +34,8 @@ Our toolkit currently consists of three intelligent agents, each designed to sim
30
34
 
31
35
  **Talk2KnowledgeGraphs** is an agent designed to enable interaction with biological knowledge graphs (KGs). KGs integrate vast amounts of structured biological data into a format that highlights relationships between entities, such as proteins, genes, and diseases.
32
36
 
37
+ ### 4. Talk2KnowledgeGraphs *(Coming soon)*
38
+
33
39
  ## Getting Started
34
40
 
35
41
  ### Prerequisites
@@ -128,6 +134,7 @@ Check out our [CONTRIBUTING.md](CONTRIBUTING.md) for more information.
128
134
  - **User Interface**: Interactive web UI for all agents.
129
135
  - **Talk2Cells**: Integration of sequencing data analysis tools.
130
136
  - **Talk2KnowledgeGraphs**: Interface for biological knowledge graph interaction.
137
+ - **Talk2Competitors**
131
138
 
132
139
  We’re excited to bring AIAgents4Pharma to the bioinformatics and pharmaceutical research community. Together, let’s make data-driven biological research more accessible and insightful.
133
140
 
@@ -5,20 +5,23 @@ BasicoModel class for loading and simulating SBML models
5
5
  using the basico package.
6
6
  """
7
7
 
8
+ import logging
8
9
  from typing import Optional, Dict, Union
9
- from time import sleep
10
- from urllib.error import URLError
11
10
  from pydantic import Field, model_validator
12
11
  import pandas as pd
13
12
  import basico
14
13
  from .sys_bio_model import SysBioModel
15
14
 
15
+ # Initialize logger
16
+ logging.basicConfig(level=logging.INFO)
17
+ logger = logging.getLogger(__name__)
18
+
16
19
  class BasicoModel(SysBioModel):
17
20
  """
18
21
  Model that loads and simulates SBML models using the basico package.
19
- Can load models from an SBML file or download them using a BioModels model_id.
22
+ Can load models from an SBML file or download them using a BioModels biomodel_id.
20
23
  """
21
- model_id: Optional[int] = Field(None, description="BioModels model ID to download and load")
24
+ biomodel_id: Optional[int] = Field(None, description="BioModels model ID to download and load")
22
25
  sbml_file_path: Optional[str] = Field(None, description="Path to an SBML file to load")
23
26
  simulation_results: Optional[str] = None
24
27
  name: Optional[str] = Field("", description="Name of the model")
@@ -28,27 +31,21 @@ class BasicoModel(SysBioModel):
28
31
  copasi_model: Optional[object] = None # Holds the loaded Copasi model
29
32
 
30
33
  @model_validator(mode="after")
31
- def check_model_id_or_sbml_file_path(self):
34
+ def check_biomodel_id_or_sbml_file_path(self):
32
35
  """
33
- Validate that either model_id or sbml_file_path is provided.
36
+ Validate that either biomodel_id or sbml_file_path is provided.
34
37
  """
35
- if not self.model_id and not self.sbml_file_path:
36
- raise ValueError("Either model_id or sbml_file_path must be provided.")
37
- if self.model_id:
38
- attempts = 0
39
- max_retries = 5
40
- while attempts < max_retries:
41
- try:
42
- self.copasi_model = basico.load_biomodel(self.model_id)
43
- break
44
- except URLError as e:
45
- attempts += 1
46
- sleep(10*attempts)
47
- if attempts >= max_retries:
48
- raise e
49
- self.description = basico.biomodels.get_model_info(self.model_id)["description"]
38
+ if not self.biomodel_id and not self.sbml_file_path:
39
+ logger.error("Either biomodel_id or sbml_file_path must be provided.")
40
+ raise ValueError("Either biomodel_id or sbml_file_path must be provided.")
41
+ if self.biomodel_id:
42
+ self.copasi_model = basico.load_biomodel(self.biomodel_id)
43
+ self.description = basico.biomodels.get_model_info(self.biomodel_id)["description"]
44
+ self.name = basico.model_info.get_model_name(model=self.copasi_model)
50
45
  elif self.sbml_file_path:
51
46
  self.copasi_model = basico.load_model(self.sbml_file_path)
47
+ self.description = basico.model_info.get_notes(model=self.copasi_model)
48
+ self.name = basico.model_info.get_model_name(model=self.copasi_model)
52
49
  return self
53
50
 
54
51
  def simulate(self,
@@ -92,10 +89,16 @@ class BasicoModel(SysBioModel):
92
89
  df_result = basico.run_time_course(model=self.copasi_model,
93
90
  intervals=interval,
94
91
  duration=duration)
92
+ # Replace curly braces in column headers with square brackets
93
+ # Because curly braces in the world of LLMS are used for
94
+ # structured output
95
95
  df_result.columns = df_result.columns.str.replace('{', '[', regex=False).\
96
96
  str.replace('}', ']', regex=False)
97
+ # Reset the index
97
98
  df_result.reset_index(inplace=True)
99
+ # Store the simulation results
98
100
  self.simulation_results = df_result
101
+ # Return copy of the simulation results
99
102
  return df_result.copy()
100
103
 
101
104
  def get_model_metadata(self) -> Dict[str, Union[str, int]]:
@@ -12,18 +12,18 @@ class SysBioModel(ABC, BaseModel):
12
12
  This class serves as a general structure for models, allowing
13
13
  different mathematical approaches to be implemented in subclasses.
14
14
  """
15
- model_id: Optional[int] = Field(None, description="BioModel ID of the model")
15
+ biomodel_id: Optional[int] = Field(None, description="BioModel ID of the model")
16
16
  sbml_file_path: Optional[str] = Field(None, description="Path to an SBML file")
17
17
  name: Optional[str] = Field(..., description="Name of the model")
18
18
  description: Optional[str] = Field("", description="Description of the model")
19
19
 
20
20
  @model_validator(mode="after")
21
- def check_model_id_or_sbml_file_path(self):
21
+ def check_biomodel_id_or_sbml_file_path(self):
22
22
  """
23
- Validate that either model_id or sbml_file_path is provided.
23
+ Validate that either biomodel_id or sbml_file_path is provided.
24
24
  """
25
- if not self.model_id and not self.sbml_file_path:
26
- raise ValueError("Either model_id or sbml_file_path must be provided.")
25
+ if not self.biomodel_id and not self.sbml_file_path:
26
+ raise ValueError("Either biomodel_id or sbml_file_path must be provided.")
27
27
  return self
28
28
 
29
29
  @abstractmethod
@@ -1,10 +1,8 @@
1
1
  '''
2
2
  This file is used to import all the modules in the package.
3
3
  '''
4
- # import everything from the module
5
- from . import ask_question
4
+ from . import search_models
6
5
  from . import simulate_model
6
+ from . import ask_question
7
7
  from . import custom_plotter
8
- from . import fetch_parameters
9
- from . import model_description
10
- from . import search_models
8
+ from . import get_modelinfo
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """
4
+ Tool for asking a question about the simulation results.
5
+ """
6
+
7
+ import logging
8
+ from typing import Type, Annotated
9
+ import pandas as pd
10
+ from pydantic import BaseModel, Field
11
+ from langchain_core.tools.base import BaseTool
12
+ from langchain.agents.agent_types import AgentType
13
+ from langchain_experimental.agents import create_pandas_dataframe_agent
14
+ from langchain_openai import ChatOpenAI
15
+ from langgraph.prebuilt import InjectedState
16
+
17
+ # Initialize logger
18
+ logging.basicConfig(level=logging.INFO)
19
+ logger = logging.getLogger(__name__)
20
+
21
+ class AskQuestionInput(BaseModel):
22
+ """
23
+ Input schema for the AskQuestion tool.
24
+ """
25
+ question: str = Field(description="question about the simulation results")
26
+ state: Annotated[dict, InjectedState]
27
+
28
+ # Note: It's important that every field has type hints.
29
+ # BaseTool is a Pydantic class and not having type hints
30
+ # can lead to unexpected behavior.
31
+ class AskQuestionTool(BaseTool):
32
+ """
33
+ Tool for calculating the product of two numbers.
34
+ """
35
+ name: str = "ask_question"
36
+ description: str = "A tool to ask question about the simulation results."
37
+ args_schema: Type[BaseModel] = AskQuestionInput
38
+ return_direct: bool = False
39
+
40
+ def _run(self,
41
+ question: str,
42
+ state: Annotated[dict, InjectedState]) -> str:
43
+ """
44
+ Run the tool.
45
+
46
+ Args:
47
+ question (str): The question to ask about the simulation results.
48
+ state (dict): The state of the graph.
49
+ run_manager (Optional[CallbackManagerForToolRun]): The CallbackManagerForToolRun object.
50
+
51
+ Returns:
52
+ str: The answer to the question.
53
+ """
54
+ logger.log(logging.INFO,
55
+ "Calling ask_question tool %s", question)
56
+ # Check if the simulation results are available
57
+ if 'dic_simulated_data' not in state:
58
+ return "Please run the simulation first before \
59
+ asking a question about the simulation results."
60
+ df = pd.DataFrame.from_dict(state['dic_simulated_data'])
61
+ prompt_content = None
62
+ # if run_manager and 'prompt' in run_manager.metadata:
63
+ # prompt_content = run_manager.metadata['prompt']
64
+ # Create a pandas dataframe agent with OpenAI
65
+ df_agent = create_pandas_dataframe_agent(
66
+ ChatOpenAI(model=state['llm_model']),
67
+ allow_dangerous_code=True,
68
+ agent_type=AgentType.OPENAI_FUNCTIONS,
69
+ df=df,
70
+ prefix=prompt_content)
71
+ llm_result = df_agent.invoke(question)
72
+ return llm_result["output"]
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """
4
+ Tool for plotting a custom figure.
5
+ """
6
+
7
+ import logging
8
+ from typing import Type, List, TypedDict, Annotated, Tuple, Union, Literal
9
+ from pydantic import BaseModel, Field
10
+ import pandas as pd
11
+ from langchain_openai import ChatOpenAI
12
+ from langchain_core.tools import BaseTool
13
+ from langgraph.prebuilt import InjectedState
14
+
15
+ # Initialize logger
16
+ logging.basicConfig(level=logging.INFO)
17
+ logger = logging.getLogger(__name__)
18
+
19
+ class CustomPlotterInput(BaseModel):
20
+ """
21
+ Input schema for the PlotImage tool.
22
+ """
23
+ question: str = Field(description="Description of the plot")
24
+ state: Annotated[dict, InjectedState]
25
+
26
+ # Note: It's important that every field has type hints.
27
+ # BaseTool is a Pydantic class and not having type hints
28
+ # can lead to unexpected behavior.
29
+ class CustomPlotterTool(BaseTool):
30
+ """
31
+ Tool for plotting a custom plot.
32
+ """
33
+ name: str = "custom_plotter"
34
+ description: str = "A tool to plot a custom figure."
35
+ args_schema: Type[BaseModel] = CustomPlotterInput
36
+ response_format: str = "content_and_artifact"
37
+
38
+ def _run(self,
39
+ question: str,
40
+ state: Annotated[dict, InjectedState]
41
+ ) -> Tuple[str, Union[None, List[str]]]:
42
+ """
43
+ Run the tool.
44
+
45
+ Args:
46
+ question (str): The question about the custom plot.
47
+ state (dict): The state of the graph.
48
+
49
+ Returns:
50
+ str: The answer to the question
51
+ """
52
+ logger.log(logging.INFO, "Calling custom_plotter tool %s", question)
53
+ # Check if the simulation results are available
54
+ # if 'dic_simulated_data' not in state:
55
+ # return "Please run the simulation first before plotting the figure.", None
56
+ df = pd.DataFrame.from_dict(state['dic_simulated_data'])
57
+ species_names = df.columns.tolist()
58
+ # Exclude the time column
59
+ species_names.remove('Time')
60
+ # In the following code, we extract the species
61
+ # from the user question. We use Literal to restrict
62
+ # the species names to the ones available in the
63
+ # simulation results.
64
+ class CustomHeader(TypedDict):
65
+ """
66
+ A list of species based on user question.
67
+ """
68
+ relevant_species: Union[None, List[Literal[*species_names]]] = Field(
69
+ description="List of species based on user question.")
70
+ # Create an instance of the LLM model
71
+ llm = ChatOpenAI(model=state['llm_model'], temperature=0)
72
+ llm_with_structured_output = llm.with_structured_output(CustomHeader)
73
+ results = llm_with_structured_output.invoke(question)
74
+ extracted_species = []
75
+ # Extract the species from the results
76
+ # that are available in the simulation results
77
+ for species in results['relevant_species']:
78
+ if species in species_names:
79
+ extracted_species.append(species)
80
+ logger.info("Extracted species: %s", extracted_species)
81
+ if len(extracted_species) == 0:
82
+ return "No species found in the simulation results that matches the user prompt.", None
83
+ content = f"Plotted custom figure with species: {', '.join(extracted_species)}"
84
+ return content, extracted_species
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """
4
+ Tool for get model information.
5
+ """
6
+
7
+ import logging
8
+ from typing import Type, Optional, Annotated
9
+ from dataclasses import dataclass
10
+ import basico
11
+ from pydantic import BaseModel, Field
12
+ from langchain_core.tools import BaseTool
13
+ from langchain_core.messages import ToolMessage
14
+ from langchain_core.tools.base import InjectedToolCallId
15
+ from langgraph.prebuilt import InjectedState
16
+ from langgraph.types import Command
17
+ from .load_biomodel import ModelData, load_biomodel
18
+
19
+ # Initialize logger
20
+ logging.basicConfig(level=logging.INFO)
21
+ logger = logging.getLogger(__name__)
22
+
23
+ @dataclass
24
+ class RequestedModelInfo:
25
+ """
26
+ Dataclass for storing the requested model information.
27
+ """
28
+ species: bool = Field(description="Get species from the model.")
29
+ parameters: bool = Field(description="Get parameters from the model.")
30
+ compartments: bool = Field(description="Get compartments from the model.")
31
+ units: bool = Field(description="Get units from the model.")
32
+ description: bool = Field(description="Get description from the model.")
33
+ name: bool = Field(description="Get name from the model.")
34
+
35
+ class GetModelInfoInput(BaseModel):
36
+ """
37
+ Input schema for the GetModelInfo tool.
38
+ """
39
+ requested_model_info: RequestedModelInfo = Field(description="requested model information")
40
+ sys_bio_model: ModelData = Field(description="model data")
41
+ tool_call_id: Annotated[str, InjectedToolCallId]
42
+ state: Annotated[dict, InjectedState]
43
+
44
+ # Note: It's important that every field has type hints. BaseTool is a
45
+ # Pydantic class and not having type hints can lead to unexpected behavior.
46
+ class GetModelInfoTool(BaseTool):
47
+ """
48
+ This tool ise used extract model information.
49
+ """
50
+ name: str = "get_parameters"
51
+ description: str = "A tool for extracting model information."
52
+ args_schema: Type[BaseModel] = GetModelInfoInput
53
+
54
+ def _run(self,
55
+ requested_model_info: RequestedModelInfo,
56
+ tool_call_id: Annotated[str, InjectedToolCallId],
57
+ state: Annotated[dict, InjectedState],
58
+ sys_bio_model: Optional[ModelData] = None,
59
+ ) -> Command:
60
+ """
61
+ Run the tool.
62
+
63
+ Args:
64
+ requested_model_info (RequestedModelInfo): The requested model information.
65
+ tool_call_id (str): The tool call ID. This is injected by the system.
66
+ state (dict): The state of the tool.
67
+ sys_bio_model (ModelData): The model data.
68
+
69
+ Returns:
70
+ Command: The updated state of the tool.
71
+ """
72
+ logger.log(logging.INFO,
73
+ "Calling get_modelinfo tool %s, %s",
74
+ sys_bio_model,
75
+ requested_model_info)
76
+ # print (state, 'state')
77
+ sbml_file_path = state['sbml_file_path'][-1] if len(state['sbml_file_path']) > 0 else None
78
+ model_obj = load_biomodel(sys_bio_model,
79
+ sbml_file_path=sbml_file_path)
80
+ dic_results = {}
81
+ # Extract species from the model
82
+ if requested_model_info.species:
83
+ df_species = basico.model_info.get_species(model=model_obj.copasi_model)
84
+ dic_results['Species'] = df_species.index.tolist()
85
+ dic_results['Species'] = ','.join(dic_results['Species'])
86
+
87
+ # Extract parameters from the model
88
+ if requested_model_info.parameters:
89
+ df_parameters = basico.model_info.get_parameters(model=model_obj.copasi_model)
90
+ dic_results['Parameters'] = df_parameters.index.tolist()
91
+ dic_results['Parameters'] = ','.join(dic_results['Parameters'])
92
+
93
+ # Extract compartments from the model
94
+ if requested_model_info.compartments:
95
+ df_compartments = basico.model_info.get_compartments(model=model_obj.copasi_model)
96
+ dic_results['Compartments'] = df_compartments.index.tolist()
97
+ dic_results['Compartments'] = ','.join(dic_results['Compartments'])
98
+
99
+ # Extract description from the model
100
+ if requested_model_info.description:
101
+ dic_results['Description'] = model_obj.description
102
+
103
+ # Extract description from the model
104
+ if requested_model_info.name:
105
+ dic_results['Name'] = model_obj.name
106
+
107
+ # Extract time unit from the model
108
+ if requested_model_info.units:
109
+ dic_results['Units'] = basico.model_info.get_model_units(model=model_obj.copasi_model)
110
+
111
+ # Prepare the dictionary of updated state for the model
112
+ dic_updated_state_for_model = {}
113
+ for key, value in {
114
+ "model_id": [sys_bio_model.biomodel_id],
115
+ "sbml_file_path": [sbml_file_path],
116
+ }.items():
117
+ if value:
118
+ dic_updated_state_for_model[key] = value
119
+
120
+ return Command(
121
+ update=dic_updated_state_for_model|{
122
+ # update the message history
123
+ "messages": [
124
+ ToolMessage(
125
+ content=dic_results,
126
+ tool_call_id=tool_call_id
127
+ )
128
+ ],
129
+ }
130
+ )
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """
4
+ Function for loading the BioModel.
5
+ """
6
+
7
+ from dataclasses import dataclass
8
+ from ..models.basico_model import BasicoModel
9
+
10
+ @dataclass
11
+ class ModelData:
12
+ """
13
+ Dataclass for storing the model data.
14
+ """
15
+ biomodel_id: int = None
16
+ # sbml_file_path: Optional[str] = None
17
+ use_uploaded_sbml_file: bool = False
18
+
19
+ def load_biomodel(sys_bio_model, sbml_file_path=None):
20
+ """
21
+ Load the BioModel.
22
+ """
23
+ model_object = None
24
+ if sys_bio_model.biomodel_id:
25
+ model_object = BasicoModel(biomodel_id=sys_bio_model.biomodel_id)
26
+ elif sbml_file_path:
27
+ model_object = BasicoModel(sbml_file_path=sbml_file_path)
28
+ return model_object
29
+ # return None
@@ -4,21 +4,21 @@
4
4
  Tool for searching models based on search query.
5
5
  """
6
6
 
7
- from urllib.error import URLError
8
- from time import sleep
9
- from typing import Type
7
+ from typing import Type, Annotated
10
8
  from pydantic import BaseModel, Field
11
9
  from basico import biomodels
12
10
  from langchain_core.tools import BaseTool
13
11
  from langchain_core.output_parsers import StrOutputParser
14
12
  from langchain_core.prompts import ChatPromptTemplate
15
13
  from langchain_openai import ChatOpenAI
14
+ from langgraph.prebuilt import InjectedState
16
15
 
17
16
  class SearchModelsInput(BaseModel):
18
17
  """
19
18
  Input schema for the search models tool.
20
19
  """
21
20
  query: str = Field(description="Search models query", default=None)
21
+ state: Annotated[dict, InjectedState]
22
22
 
23
23
  # Note: It's important that every field has type hints. BaseTool is a
24
24
  # Pydantic class and not having type hints can lead to unexpected behavior.
@@ -31,7 +31,9 @@ class SearchModelsTool(BaseTool):
31
31
  args_schema: Type[BaseModel] = SearchModelsInput
32
32
  return_direct: bool = True
33
33
 
34
- def _run(self, query: str) -> str:
34
+ def _run(self,
35
+ query: str,
36
+ state: Annotated[dict, InjectedState]) -> dict:
35
37
  """
36
38
  Run the tool.
37
39
 
@@ -39,20 +41,10 @@ class SearchModelsTool(BaseTool):
39
41
  query (str): The search query.
40
42
 
41
43
  Returns:
42
- str: The answer to the question.
44
+ dict: The answer to the question in the form of a dictionary.
43
45
  """
44
- attempts = 0
45
- max_retries = 3
46
- while attempts < max_retries:
47
- try:
48
- search_results = biomodels.search_for_model(query)
49
- break
50
- except URLError as e:
51
- attempts += 1
52
- sleep(10)
53
- if attempts >= max_retries:
54
- raise e
55
- llm = ChatOpenAI(model="gpt-4o-mini")
46
+ search_results = biomodels.search_for_model(query)
47
+ llm = ChatOpenAI(model=state['llm_model'])
56
48
  # Check if run_manager's metadata has the key 'prompt_content'
57
49
  prompt_content = f'''
58
50
  Convert the input into a table.
@@ -80,15 +72,3 @@ class SearchModelsTool(BaseTool):
80
72
  parser = StrOutputParser()
81
73
  chain = prompt_template | llm | parser
82
74
  return chain.invoke({"input": search_results})
83
-
84
- def get_metadata(self):
85
- """
86
- Get metadata for the tool.
87
-
88
- Returns:
89
- dict: The metadata for the tool.
90
- """
91
- return {
92
- "name": self.name,
93
- "description": self.description
94
- }