aiagents4pharma 1.13.1__py3-none-any.whl → 1.14.1__py3-none-any.whl

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 (34) hide show
  1. aiagents4pharma/configs/config.yaml +2 -1
  2. aiagents4pharma/configs/talk2biomodels/__init__.py +1 -0
  3. aiagents4pharma/configs/talk2biomodels/agents/t2b_agent/default.yaml +2 -3
  4. aiagents4pharma/configs/talk2biomodels/tools/__init__.py +4 -0
  5. aiagents4pharma/configs/talk2biomodels/tools/ask_question/__init__.py +3 -0
  6. aiagents4pharma/talk2biomodels/__init__.py +1 -0
  7. aiagents4pharma/talk2biomodels/agents/t2b_agent.py +4 -2
  8. aiagents4pharma/talk2biomodels/api/__init__.py +6 -0
  9. aiagents4pharma/talk2biomodels/api/kegg.py +83 -0
  10. aiagents4pharma/talk2biomodels/api/ols.py +72 -0
  11. aiagents4pharma/talk2biomodels/api/uniprot.py +35 -0
  12. aiagents4pharma/talk2biomodels/states/state_talk2biomodels.py +21 -6
  13. aiagents4pharma/talk2biomodels/tests/test_api.py +57 -0
  14. aiagents4pharma/talk2biomodels/tests/test_ask_question.py +44 -0
  15. aiagents4pharma/talk2biomodels/tests/test_get_annotation.py +171 -0
  16. aiagents4pharma/talk2biomodels/tests/test_getmodelinfo.py +26 -0
  17. aiagents4pharma/talk2biomodels/tests/test_integration.py +126 -0
  18. aiagents4pharma/talk2biomodels/tests/test_param_scan.py +68 -0
  19. aiagents4pharma/talk2biomodels/tests/test_search_models.py +28 -0
  20. aiagents4pharma/talk2biomodels/tests/test_simulate_model.py +39 -0
  21. aiagents4pharma/talk2biomodels/tests/test_steady_state.py +90 -0
  22. aiagents4pharma/talk2biomodels/tools/__init__.py +1 -0
  23. aiagents4pharma/talk2biomodels/tools/ask_question.py +29 -8
  24. aiagents4pharma/talk2biomodels/tools/get_annotation.py +304 -0
  25. aiagents4pharma/talk2biomodels/tools/load_arguments.py +114 -0
  26. aiagents4pharma/talk2biomodels/tools/parameter_scan.py +91 -96
  27. aiagents4pharma/talk2biomodels/tools/simulate_model.py +14 -81
  28. aiagents4pharma/talk2biomodels/tools/steady_state.py +48 -89
  29. {aiagents4pharma-1.13.1.dist-info → aiagents4pharma-1.14.1.dist-info}/METADATA +1 -1
  30. {aiagents4pharma-1.13.1.dist-info → aiagents4pharma-1.14.1.dist-info}/RECORD +33 -17
  31. aiagents4pharma/talk2biomodels/tests/test_langgraph.py +0 -384
  32. {aiagents4pharma-1.13.1.dist-info → aiagents4pharma-1.14.1.dist-info}/LICENSE +0 -0
  33. {aiagents4pharma-1.13.1.dist-info → aiagents4pharma-1.14.1.dist-info}/WHEEL +0 -0
  34. {aiagents4pharma-1.13.1.dist-info → aiagents4pharma-1.14.1.dist-info}/top_level.txt +0 -0
@@ -6,7 +6,7 @@ Tool for parameter scan.
6
6
 
7
7
  import logging
8
8
  from dataclasses import dataclass
9
- from typing import Type, Union, List, Annotated
9
+ from typing import Type, Union, List, Annotated, Optional
10
10
  import pandas as pd
11
11
  import basico
12
12
  from pydantic import BaseModel, Field
@@ -16,61 +16,37 @@ from langchain_core.tools import BaseTool
16
16
  from langchain_core.messages import ToolMessage
17
17
  from langchain_core.tools.base import InjectedToolCallId
18
18
  from .load_biomodel import ModelData, load_biomodel
19
+ from .load_arguments import TimeData, SpeciesInitialData
19
20
 
20
21
  # Initialize logger
21
22
  logging.basicConfig(level=logging.INFO)
22
23
  logger = logging.getLogger(__name__)
23
24
 
24
- @dataclass
25
- class TimeData:
26
- """
27
- Dataclass for storing the time data.
28
- """
29
- duration: Union[int, float] = 100
30
- interval: Union[int, float] = 10
31
-
32
- @dataclass
33
- class SpeciesData:
34
- """
35
- Dataclass for storing the species data.
36
- """
37
- species_name: List[str] = Field(description="species name", default=[])
38
- species_concentration: List[Union[int, float]] = Field(
39
- description="initial species concentration",
40
- default=[])
41
-
42
- @dataclass
43
- class TimeSpeciesNameConcentration:
44
- """
45
- Dataclass for storing the time, species name, and concentration data.
46
- """
47
- time: Union[int, float] = Field(description="time point where the event occurs")
48
- species_name: str = Field(description="species name")
49
- species_concentration: Union[int, float] = Field(
50
- description="species concentration at the time point")
51
-
52
- @dataclass
53
- class ReocurringData:
54
- """
55
- Dataclass for species that reoccur. In other words, the concentration
56
- of the species resets to a certain value after a certain time interval.
57
- """
58
- data: List[TimeSpeciesNameConcentration] = Field(
59
- description="time, name, and concentration data of species that reoccur",
60
- default=[])
61
-
62
25
  @dataclass
63
26
  class ParameterScanData(BaseModel):
64
27
  """
65
28
  Dataclass for storing the parameter scan data.
66
29
  """
67
- species_names: List[str] = Field(description="species names to scan",
68
- default=[])
69
- parameter_name: str = Field(description="Parameter name to scan",
70
- default_factory=None)
71
- parameter_values: List[Union[int, float]] = Field(
72
- description="Parameter values to scan",
73
- default_factory=None)
30
+ species_names: List[str] = Field(
31
+ description="species to be observed after each scan."
32
+ " These are the species whose concentration"
33
+ " will be observed after the parameter scan."
34
+ " Do not make up this data.",
35
+ default=[])
36
+ species_parameter_name: str = Field(
37
+ description="Species or parameter name to be scanned."
38
+ " This is the species or parameter whose value will be scanned"
39
+ " over a range of values. This does not include the species"
40
+ " that are to be observed after the scan."
41
+ "Do not make up this data.",
42
+ default=None)
43
+ species_parameter_values: List[Union[int, float]] = Field(
44
+ description="Species or parameter values to be scanned."
45
+ " These are the values of the species or parameters that will be"
46
+ " scanned over a range of values. This does not include the "
47
+ "species that are to be observed after the scan."
48
+ "Do not make up this data.",
49
+ default=None)
74
50
 
75
51
  @dataclass
76
52
  class ArgumentData:
@@ -78,30 +54,20 @@ class ArgumentData:
78
54
  Dataclass for storing the argument data.
79
55
  """
80
56
  time_data: TimeData = Field(description="time data", default=None)
81
- species_data: SpeciesData = Field(
82
- description="species name and initial concentration data",
83
- default=None)
84
- reocurring_data: ReocurringData = Field(
85
- description="""Concentration and time data of species that reoccur
86
- For example, a species whose concentration resets to a certain value
87
- after a certain time interval""")
57
+ species_to_be_analyzed_before_experiment: Optional[SpeciesInitialData] = Field(
58
+ description=" This is the initial condition of the model."
59
+ " This does not include species that reoccur or the species"
60
+ " whose concentration is to be determined/observed at the end"
61
+ " of the experiment. This also does not include the species"
62
+ " or the parameter that is to be scanned. Do not make up this data.",
63
+ default=None)
88
64
  parameter_scan_data: ParameterScanData = Field(
89
- description="parameter scan data",
90
- default=None)
91
- scan_name: str = Field(
92
- description="""An AI assigned `_` separated name of
93
- the parameter scan experiment based on human query""")
94
-
95
- def add_rec_events(model_object, reocurring_data):
96
- """
97
- Add reocurring events to the model.
98
- """
99
- for row in reocurring_data.data:
100
- tp, sn, sc = row.time, row.species_name, row.species_concentration
101
- basico.add_event(f'{sn}_{tp}',
102
- f'Time > {tp}',
103
- [[sn, str(sc)]],
104
- model=model_object.copasi_model)
65
+ description="parameter scan data",
66
+ default=None)
67
+ experiment_name: str = Field(
68
+ description="An AI assigned `_` separated unique name of"
69
+ " the parameter scan experiment based on human query."
70
+ " This must be unique for each experiment.")
105
71
 
106
72
  def make_list_dic_scanned_data(dic_param_scan, arg_data, sys_bio_model, tool_call_id):
107
73
  """
@@ -125,13 +91,18 @@ def make_list_dic_scanned_data(dic_param_scan, arg_data, sys_bio_model, tool_cal
125
91
  # Prepare the list dictionary of scanned data
126
92
  # that will be passed to the state of the graph
127
93
  list_dic_scanned_data.append({
128
- 'name': arg_data.scan_name+':'+species_name,
94
+ 'name': arg_data.experiment_name+':'+species_name,
129
95
  'source': sys_bio_model.biomodel_id if sys_bio_model.biomodel_id else 'upload',
130
96
  'tool_call_id': tool_call_id,
131
97
  'data': df_param_scan.to_dict()
132
98
  })
133
99
  return list_dic_scanned_data
134
- def run_parameter_scan(model_object, arg_data, dic_species_data, duration, interval) -> dict:
100
+
101
+ def run_parameter_scan(model_object,
102
+ arg_data,
103
+ dic_species_data,
104
+ duration,
105
+ interval) -> dict:
135
106
  """
136
107
  Run parameter scan on the model.
137
108
 
@@ -146,44 +117,61 @@ def run_parameter_scan(model_object, arg_data, dic_species_data, duration, inter
146
117
  dict: Dictionary of parameter scan results. Each key is a species name
147
118
  and each value is a DataFrame containing the results of the parameter scan.
148
119
  """
149
- # Extract all parameter names from the model and verify if the given parameter name is valid
120
+ # Extract all parameter names from the model
150
121
  df_all_parameters = basico.model_info.get_parameters(model=model_object.copasi_model)
151
122
  all_parameters = df_all_parameters.index.tolist()
152
- if arg_data.parameter_scan_data.parameter_name not in all_parameters:
153
- logger.error(
154
- "Invalid parameter name: %s", arg_data.parameter_scan_data.parameter_name)
155
- raise ValueError(
156
- f"Invalid parameter name: {arg_data.parameter_scan_data.parameter_name}")
157
- # Extract all species name from the model and verify if the given species name is valid
123
+
124
+ # Extract all species name from the model
158
125
  df_all_species = basico.model_info.get_species(model=model_object.copasi_model)
159
126
  all_species = df_all_species['display_name'].tolist()
127
+
128
+ # Verify if the given species or parameter names to be scanned are valid
129
+ if arg_data.parameter_scan_data.species_parameter_name not in all_parameters + all_species:
130
+ logger.error(
131
+ "Invalid species or parameter name: %s",
132
+ arg_data.parameter_scan_data.species_parameter_name)
133
+ raise ValueError(
134
+ "Invalid species or parameter name: "
135
+ f"{arg_data.parameter_scan_data.species_parameter_name}.")
136
+
160
137
  # Dictionary to store the parameter scan results
161
138
  dic_param_scan_results = {}
139
+
140
+ # Loop through the species names that are to be observed
162
141
  for species_name in arg_data.parameter_scan_data.species_names:
142
+ # Verify if the given species name to be observed is valid
163
143
  if species_name not in all_species:
164
144
  logger.error("Invalid species name: %s", species_name)
165
- raise ValueError(f"Invalid species name: {species_name}")
145
+ raise ValueError(f"Invalid species name: {species_name}.")
146
+
147
+ # Copy the model object to avoid modifying the original model
148
+ model_object_copy = model_object.model_copy()
149
+
166
150
  # Update the fixed model species and parameters
167
151
  # These are the initial conditions of the model
168
152
  # set by the user
169
- model_object.update_parameters(dic_species_data)
153
+ model_object_copy.update_parameters(dic_species_data)
154
+
170
155
  # Initialize empty DataFrame to store results
171
156
  # of the parameter scan
172
157
  df_param_scan = pd.DataFrame()
173
- for param_value in arg_data.parameter_scan_data.parameter_values:
158
+
159
+ # Loop through the parameter that are to be scanned
160
+ for param_value in arg_data.parameter_scan_data.species_parameter_values:
174
161
  # Update the parameter value in the model
175
- model_object.update_parameters(
176
- {arg_data.parameter_scan_data.parameter_name: param_value})
162
+ model_object_copy.update_parameters(
163
+ {arg_data.parameter_scan_data.species_parameter_name: param_value})
177
164
  # Simulate the model
178
- model_object.simulate(duration=duration, interval=interval)
165
+ model_object_copy.simulate(duration=duration, interval=interval)
179
166
  # If the column name 'Time' is not present in the results DataFrame
180
167
  if 'Time' not in df_param_scan.columns:
181
- df_param_scan['Time'] = model_object.simulation_results['Time']
168
+ df_param_scan['Time'] = model_object_copy.simulation_results['Time']
182
169
  # Add the simulation results to the results DataFrame
183
- col_name = f"{arg_data.parameter_scan_data.parameter_name}_{param_value}"
184
- df_param_scan[col_name] = model_object.simulation_results[species_name]
170
+ col_name = f"{arg_data.parameter_scan_data.species_parameter_name}_{param_value}"
171
+ df_param_scan[col_name] = model_object_copy.simulation_results[species_name]
185
172
 
186
173
  logger.log(logging.INFO, "Parameter scan results with shape %s", df_param_scan.shape)
174
+
187
175
  # Add the results of the parameter scan to the dictionary
188
176
  dic_param_scan_results[species_name] = df_param_scan
189
177
  # return df_param_scan
@@ -210,8 +198,9 @@ class ParameterScanTool(BaseTool):
210
198
  Tool for parameter scan.
211
199
  """
212
200
  name: str = "parameter_scan"
213
- description: str = """A tool to perform parameter scan
214
- of a list of parameter values for a given species."""
201
+ description: str = """A tool to perform scanning of a given
202
+ parameter over a range of values and observe the effect on
203
+ the concentration of a given species"""
215
204
  args_schema: Type[BaseModel] = ParameterScanInput
216
205
 
217
206
  def _run(self,
@@ -245,12 +234,18 @@ class ParameterScanTool(BaseTool):
245
234
  dic_species_data = {}
246
235
  if arg_data:
247
236
  # Prepare the dictionary of species data
248
- if arg_data.species_data is not None:
249
- dic_species_data = dict(zip(arg_data.species_data.species_name,
250
- arg_data.species_data.species_concentration))
251
- # Add reocurring events (if any) to the model
252
- if arg_data.reocurring_data is not None:
253
- add_rec_events(model_object, arg_data.reocurring_data)
237
+ if arg_data.species_to_be_analyzed_before_experiment is not None:
238
+ dic_species_data = dict(
239
+ zip(
240
+ arg_data.species_to_be_analyzed_before_experiment.species_name,
241
+ arg_data.species_to_be_analyzed_before_experiment.species_concentration
242
+ )
243
+ )
244
+
245
+ # # Add reocurring events (if any) to the model
246
+ # if arg_data.reocurring_data is not None:
247
+ # add_rec_events(model_object, arg_data.reocurring_data)
248
+
254
249
  # Set the duration and interval
255
250
  if arg_data.time_data is not None:
256
251
  duration = arg_data.time_data.duration
@@ -284,7 +279,7 @@ class ParameterScanTool(BaseTool):
284
279
  # update the message history
285
280
  "messages": [
286
281
  ToolMessage(
287
- content=f"Parameter scan results of {arg_data.scan_name}",
282
+ content=f"Parameter scan results of {arg_data.experiment_name}",
288
283
  tool_call_id=tool_call_id
289
284
  )
290
285
  ],
@@ -5,9 +5,7 @@ Tool for simulating a model.
5
5
  """
6
6
 
7
7
  import logging
8
- from dataclasses import dataclass
9
- from typing import Type, Union, List, Annotated
10
- import basico
8
+ from typing import Type, Annotated
11
9
  from pydantic import BaseModel, Field
12
10
  from langgraph.types import Command
13
11
  from langgraph.prebuilt import InjectedState
@@ -15,76 +13,12 @@ from langchain_core.tools import BaseTool
15
13
  from langchain_core.messages import ToolMessage
16
14
  from langchain_core.tools.base import InjectedToolCallId
17
15
  from .load_biomodel import ModelData, load_biomodel
16
+ from .load_arguments import ArgumentData, add_rec_events
18
17
 
19
18
  # Initialize logger
20
19
  logging.basicConfig(level=logging.INFO)
21
20
  logger = logging.getLogger(__name__)
22
21
 
23
- @dataclass
24
- class TimeData:
25
- """
26
- Dataclass for storing the time data.
27
- """
28
- duration: Union[int, float] = 100
29
- interval: Union[int, float] = 10
30
-
31
- @dataclass
32
- class SpeciesData:
33
- """
34
- Dataclass for storing the species data.
35
- """
36
- species_name: List[str] = Field(description="species name", default=None)
37
- species_concentration: List[Union[int, float]] = Field(
38
- description="initial species concentration",
39
- default=None)
40
-
41
- @dataclass
42
- class TimeSpeciesNameConcentration:
43
- """
44
- Dataclass for storing the time, species name, and concentration data.
45
- """
46
- time: Union[int, float] = Field(description="time point where the event occurs")
47
- species_name: str = Field(description="species name")
48
- species_concentration: Union[int, float] = Field(
49
- description="species concentration at the time point")
50
-
51
- @dataclass
52
- class RecurringData:
53
- """
54
- Dataclass for storing the species and time data
55
- on reocurring basis.
56
- """
57
- data: List[TimeSpeciesNameConcentration] = Field(
58
- description="species and time data on reocurring basis",
59
- default=None)
60
-
61
- @dataclass
62
- class ArgumentData:
63
- """
64
- Dataclass for storing the argument data.
65
- """
66
- time_data: TimeData = Field(description="time data", default=None)
67
- species_data: SpeciesData = Field(
68
- description="species name and initial concentration data",
69
- default=None)
70
- recurring_data: RecurringData = Field(
71
- description="species and time data on reocurring basis",
72
- default=None)
73
- simulation_name: str = Field(
74
- description="""An AI assigned `_` separated name of
75
- the simulation based on human query""")
76
-
77
- def add_rec_events(model_object, recurring_data):
78
- """
79
- Add reocurring events to the model.
80
- """
81
- for row in recurring_data.data:
82
- tp, sn, sc = row.time, row.species_name, row.species_concentration
83
- basico.add_event(f'{sn}_{tp}',
84
- f'Time > {tp}',
85
- [[sn, str(sc)]],
86
- model=model_object.copasi_model)
87
-
88
22
  class SimulateModelInput(BaseModel):
89
23
  """
90
24
  Input schema for the SimulateModel tool.
@@ -138,29 +72,30 @@ class SimulateModelTool(BaseTool):
138
72
  # of the BasicoModel class
139
73
  duration = 100.0
140
74
  interval = 10
141
- dic_species_data = {}
75
+ dic_species_to_be_analyzed_before_experiment = {}
142
76
  if arg_data:
143
77
  # Prepare the dictionary of species data
144
- if arg_data.species_data is not None:
145
- dic_species_data = dict(zip(arg_data.species_data.species_name,
146
- arg_data.species_data.species_concentration))
147
- # Add recurring events (if any) to the model
148
- if arg_data.recurring_data is not None:
149
- add_rec_events(model_object, arg_data.recurring_data)
78
+ if arg_data.species_to_be_analyzed_before_experiment is not None:
79
+ dic_species_to_be_analyzed_before_experiment = dict(
80
+ zip(arg_data.species_to_be_analyzed_before_experiment.species_name,
81
+ arg_data.species_to_be_analyzed_before_experiment.species_concentration))
82
+ # Add reocurring events (if any) to the model
83
+ if arg_data.reocurring_data is not None:
84
+ add_rec_events(model_object, arg_data.reocurring_data)
150
85
  # Set the duration and interval
151
86
  if arg_data.time_data is not None:
152
87
  duration = arg_data.time_data.duration
153
88
  interval = arg_data.time_data.interval
154
89
  # Update the model parameters
155
- model_object.update_parameters(dic_species_data)
90
+ model_object.update_parameters(dic_species_to_be_analyzed_before_experiment)
156
91
  logger.log(logging.INFO,
157
92
  "Following species/parameters updated in the model %s",
158
- dic_species_data)
93
+ dic_species_to_be_analyzed_before_experiment)
159
94
  # Simulate the model
160
95
  df = model_object.simulate(duration=duration, interval=interval)
161
96
  logger.log(logging.INFO, "Simulation results ready with shape %s", df.shape)
162
97
  dic_simulated_data = {
163
- 'name': arg_data.simulation_name,
98
+ 'name': arg_data.experiment_name,
164
99
  'source': sys_bio_model.biomodel_id if sys_bio_model.biomodel_id else 'upload',
165
100
  'tool_call_id': tool_call_id,
166
101
  'data': df.to_dict()
@@ -177,12 +112,10 @@ class SimulateModelTool(BaseTool):
177
112
  # Return the updated state of the tool
178
113
  return Command(
179
114
  update=dic_updated_state_for_model|{
180
- # update the state keys
181
- # "dic_simulated_data": df.to_dict(),
182
115
  # update the message history
183
116
  "messages": [
184
117
  ToolMessage(
185
- content=f"Simulation results of {arg_data.simulation_name}",
118
+ content=f"Simulation results of {arg_data.experiment_name}",
186
119
  tool_call_id=tool_call_id
187
120
  )
188
121
  ],
@@ -5,8 +5,7 @@ Tool for parameter scan.
5
5
  """
6
6
 
7
7
  import logging
8
- from dataclasses import dataclass
9
- from typing import Type, Union, List, Annotated
8
+ from typing import Type, Annotated
10
9
  import basico
11
10
  from pydantic import BaseModel, Field
12
11
  from langgraph.types import Command
@@ -15,83 +14,20 @@ from langchain_core.tools import BaseTool
15
14
  from langchain_core.messages import ToolMessage
16
15
  from langchain_core.tools.base import InjectedToolCallId
17
16
  from .load_biomodel import ModelData, load_biomodel
17
+ from .load_arguments import ArgumentData, add_rec_events
18
18
 
19
19
  # Initialize logger
20
20
  logging.basicConfig(level=logging.INFO)
21
21
  logger = logging.getLogger(__name__)
22
22
 
23
- @dataclass
24
- class TimeData:
25
- """
26
- Dataclass for storing the time data.
27
- """
28
- duration: Union[int, float] = 100
29
- interval: Union[int, float] = 10
30
-
31
- @dataclass
32
- class SpeciesData:
33
- """
34
- Dataclass for storing the species data.
35
- """
36
- species_name: List[str] = Field(description="species name", default=[])
37
- species_concentration: List[Union[int, float]] = Field(
38
- description="initial species concentration",
39
- default=[])
40
-
41
- @dataclass
42
- class TimeSpeciesNameConcentration:
43
- """
44
- Dataclass for storing the time, species name, and concentration data.
45
- """
46
- time: Union[int, float] = Field(description="time point where the event occurs")
47
- species_name: str = Field(description="species name")
48
- species_concentration: Union[int, float] = Field(
49
- description="species concentration at the time point")
50
-
51
- @dataclass
52
- class ReocurringData:
53
- """
54
- Dataclass for species that reoccur. In other words, the concentration
55
- of the species resets to a certain value after a certain time interval.
56
- """
57
- data: List[TimeSpeciesNameConcentration] = Field(
58
- description="time, name, and concentration data of species that reoccur",
59
- default=[])
60
-
61
- @dataclass
62
- class ArgumentData:
63
- """
64
- Dataclass for storing the argument data.
65
- """
66
- time_data: TimeData = Field(description="time data", default=None)
67
- species_data: SpeciesData = Field(
68
- description="species name and initial concentration data")
69
- reocurring_data: ReocurringData = Field(
70
- description="""Concentration and time data of species that reoccur
71
- For example, a species whose concentration resets to a certain value
72
- after a certain time interval""")
73
- steadystate_name: str = Field(
74
- description="""An AI assigned `_` separated name of
75
- the steady state experiment based on human query""")
76
-
77
- def add_rec_events(model_object, reocurring_data):
78
- """
79
- Add reocurring events to the model.
80
- """
81
- for row in reocurring_data.data:
82
- tp, sn, sc = row.time, row.species_name, row.species_concentration
83
- basico.add_event(f'{sn}_{tp}',
84
- f'Time > {tp}',
85
- [[sn, str(sc)]],
86
- model=model_object.copasi_model)
87
-
88
- def run_steady_state(model_object, dic_species_data):
23
+ def run_steady_state(model_object,
24
+ dic_species_to_be_analyzed_before_experiment):
89
25
  """
90
26
  Run the steady state analysis.
91
27
 
92
28
  Args:
93
29
  model_object: The model object.
94
- dic_species_data: Dictionary of species data.
30
+ dic_species_to_be_analyzed_before_experiment: Dictionary of species data.
95
31
 
96
32
  Returns:
97
33
  DataFrame: The results of the steady state analysis.
@@ -99,7 +35,7 @@ def run_steady_state(model_object, dic_species_data):
99
35
  # Update the fixed model species and parameters
100
36
  # These are the initial conditions of the model
101
37
  # set by the user
102
- model_object.update_parameters(dic_species_data)
38
+ model_object.update_parameters(dic_species_to_be_analyzed_before_experiment)
103
39
  logger.log(logging.INFO, "Running steady state analysis")
104
40
  # Run the steady state analysis
105
41
  output = basico.task_steadystate.run_steadystate(model=model_object.copasi_model)
@@ -108,7 +44,30 @@ def run_steady_state(model_object, dic_species_data):
108
44
  raise ValueError("A steady state was not found")
109
45
  logger.log(logging.INFO, "Steady state analysis successful")
110
46
  # Store the steady state results in a DataFrame
111
- df_steady_state = basico.model_info.get_species(model=model_object.copasi_model)
47
+ df_steady_state = basico.model_info.get_species(model=model_object.copasi_model).reset_index()
48
+ # print (df_steady_state)
49
+ # Rename the column name to species_name
50
+ df_steady_state.rename(columns={'name': 'species_name'},
51
+ inplace=True)
52
+ # Rename the column concentration to steady_state_concentration
53
+ df_steady_state.rename(columns={'concentration': 'steady_state_concentration'},
54
+ inplace=True)
55
+ # Rename the column transition_time to steady_state_transition_time
56
+ df_steady_state.rename(columns={'transition_time': 'steady_state_transition_time'},
57
+ inplace=True)
58
+ # Drop some columns
59
+ df_steady_state.drop(columns=
60
+ [
61
+ 'initial_particle_number',
62
+ 'initial_expression',
63
+ 'expression',
64
+ 'particle_number',
65
+ 'type',
66
+ 'particle_number_rate',
67
+ 'key',
68
+ 'sbml_id',
69
+ 'display_name'],
70
+ inplace=True)
112
71
  logger.log(logging.INFO, "Steady state results with shape %s", df_steady_state.shape)
113
72
  return df_steady_state
114
73
 
@@ -118,10 +77,10 @@ class SteadyStateInput(BaseModel):
118
77
  """
119
78
  sys_bio_model: ModelData = Field(description="model data",
120
79
  default=None)
121
- arg_data: ArgumentData = Field(description=
122
- """time, species, and reocurring data
123
- as well as the steady state data""",
124
- default=None)
80
+ arg_data: ArgumentData = Field(
81
+ description="time, species, and reocurring data"
82
+ " that must be set before the steady state analysis"
83
+ " as well as the experiment name", default=None)
125
84
  tool_call_id: Annotated[str, InjectedToolCallId]
126
85
  state: Annotated[dict, InjectedState]
127
86
 
@@ -129,12 +88,10 @@ class SteadyStateInput(BaseModel):
129
88
  # Pydantic class and not having type hints can lead to unexpected behavior.
130
89
  class SteadyStateTool(BaseTool):
131
90
  """
132
- Tool for steady state analysis.
91
+ Tool to bring a model to steady state.
133
92
  """
134
93
  name: str = "steady_state"
135
- description: str = """A tool to simulate a model and perform
136
- steady state analysisto answer questions
137
- about the steady state of species."""
94
+ description: str = "A tool to bring a model to steady state."
138
95
  args_schema: Type[BaseModel] = SteadyStateInput
139
96
 
140
97
  def _run(self,
@@ -155,7 +112,7 @@ class SteadyStateTool(BaseTool):
155
112
  Returns:
156
113
  Command: The updated state of the tool.
157
114
  """
158
- logger.log(logging.INFO, "Calling steady_state tool %s, %s",
115
+ logger.log(logging.INFO, "Calling the steady_state tool %s, %s",
159
116
  sys_bio_model, arg_data)
160
117
  # print (f'Calling steady_state tool {sys_bio_model}, {arg_data}, {tool_call_id}')
161
118
  sbml_file_path = state['sbml_file_path'][-1] if len(state['sbml_file_path']) > 0 else None
@@ -164,21 +121,23 @@ class SteadyStateTool(BaseTool):
164
121
  # Prepare the dictionary of species data
165
122
  # that will be passed to the simulate method
166
123
  # of the BasicoModel class
167
- dic_species_data = {}
124
+ dic_species_to_be_analyzed_before_experiment = {}
168
125
  if arg_data:
169
126
  # Prepare the dictionary of species data
170
- if arg_data.species_data is not None:
171
- dic_species_data = dict(zip(arg_data.species_data.species_name,
172
- arg_data.species_data.species_concentration))
127
+ if arg_data.species_to_be_analyzed_before_experiment is not None:
128
+ dic_species_to_be_analyzed_before_experiment = dict(
129
+ zip(arg_data.species_to_be_analyzed_before_experiment.species_name,
130
+ arg_data.species_to_be_analyzed_before_experiment.species_concentration))
173
131
  # Add reocurring events (if any) to the model
174
132
  if arg_data.reocurring_data is not None:
175
133
  add_rec_events(model_object, arg_data.reocurring_data)
176
134
  # Run the parameter scan
177
- df_steady_state = run_steady_state(model_object, dic_species_data)
135
+ df_steady_state = run_steady_state(model_object,
136
+ dic_species_to_be_analyzed_before_experiment)
178
137
  # Prepare the dictionary of scanned data
179
138
  # that will be passed to the state of the graph
180
139
  dic_steady_state_data = {
181
- 'name': arg_data.steadystate_name,
140
+ 'name': arg_data.experiment_name,
182
141
  'source': sys_bio_model.biomodel_id if sys_bio_model.biomodel_id else 'upload',
183
142
  'tool_call_id': tool_call_id,
184
143
  'data': df_steady_state.to_dict(orient='records')
@@ -198,9 +157,9 @@ class SteadyStateTool(BaseTool):
198
157
  # Update the message history
199
158
  "messages": [
200
159
  ToolMessage(
201
- content=f'''Steady state analysis of
202
- {arg_data.steadystate_name}
203
- are ready''',
160
+ content=f"Steady state analysis of"
161
+ f" {arg_data.experiment_name}"
162
+ " was successful.",
204
163
  tool_call_id=tool_call_id
205
164
  )
206
165
  ],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: aiagents4pharma
3
- Version: 1.13.1
3
+ Version: 1.14.1
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