aiagents4pharma 1.15.1__py3-none-any.whl → 1.16.0__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.
- aiagents4pharma/__init__.py +1 -1
- aiagents4pharma/configs/config.yaml +2 -1
- aiagents4pharma/configs/talk2biomodels/tools/__init__.py +2 -1
- aiagents4pharma/configs/talk2biomodels/tools/get_annotation/__init__.py +3 -0
- aiagents4pharma/configs/talk2biomodels/tools/get_annotation/default.yaml +6 -0
- aiagents4pharma/talk2biomodels/tests/test_get_annotation.py +29 -14
- aiagents4pharma/talk2biomodels/tests/test_getmodelinfo.py +32 -1
- aiagents4pharma/talk2biomodels/tests/test_integration.py +3 -4
- aiagents4pharma/talk2biomodels/tools/get_annotation.py +59 -37
- aiagents4pharma/talk2biomodels/tools/get_modelinfo.py +23 -4
- aiagents4pharma/{talk2competitors → talk2scholars}/agents/main_agent.py +7 -7
- aiagents4pharma/{talk2competitors → talk2scholars}/agents/s2_agent.py +4 -4
- aiagents4pharma/{talk2competitors → talk2scholars}/state/__init__.py +1 -1
- aiagents4pharma/{talk2competitors/state/state_talk2competitors.py → talk2scholars/state/state_talk2scholars.py} +3 -3
- aiagents4pharma/{talk2competitors → talk2scholars}/tests/test_langgraph.py +2 -2
- {aiagents4pharma-1.15.1.dist-info → aiagents4pharma-1.16.0.dist-info}/METADATA +7 -6
- {aiagents4pharma-1.15.1.dist-info → aiagents4pharma-1.16.0.dist-info}/RECORD +31 -29
- /aiagents4pharma/{talk2competitors → talk2scholars}/__init__.py +0 -0
- /aiagents4pharma/{talk2competitors → talk2scholars}/agents/__init__.py +0 -0
- /aiagents4pharma/{talk2competitors → talk2scholars}/config/__init__.py +0 -0
- /aiagents4pharma/{talk2competitors → talk2scholars}/config/config.py +0 -0
- /aiagents4pharma/{talk2competitors → talk2scholars}/tests/__init__.py +0 -0
- /aiagents4pharma/{talk2competitors → talk2scholars}/tools/__init__.py +0 -0
- /aiagents4pharma/{talk2competitors → talk2scholars}/tools/s2/__init__.py +0 -0
- /aiagents4pharma/{talk2competitors → talk2scholars}/tools/s2/display_results.py +0 -0
- /aiagents4pharma/{talk2competitors → talk2scholars}/tools/s2/multi_paper_rec.py +0 -0
- /aiagents4pharma/{talk2competitors → talk2scholars}/tools/s2/search.py +0 -0
- /aiagents4pharma/{talk2competitors → talk2scholars}/tools/s2/single_paper_rec.py +0 -0
- {aiagents4pharma-1.15.1.dist-info → aiagents4pharma-1.16.0.dist-info}/LICENSE +0 -0
- {aiagents4pharma-1.15.1.dist-info → aiagents4pharma-1.16.0.dist-info}/WHEEL +0 -0
- {aiagents4pharma-1.15.1.dist-info → aiagents4pharma-1.16.0.dist-info}/top_level.txt +0 -0
aiagents4pharma/__init__.py
CHANGED
@@ -0,0 +1,6 @@
|
|
1
|
+
_target_: talk2biomodels.tools.get_annotation.GetAnnotationTool
|
2
|
+
prompt: >
|
3
|
+
Given the user question, extract the relevant species names.
|
4
|
+
If the user aks for a specific species, extract that species.
|
5
|
+
If none of the species match the user question, return None.
|
6
|
+
If the user asks for all species, return all species.
|
@@ -16,6 +16,7 @@ def make_graph_fixture():
|
|
16
16
|
unique_id = random.randint(1000, 9999)
|
17
17
|
graph = get_app(unique_id)
|
18
18
|
config = {"configurable": {"thread_id": unique_id}}
|
19
|
+
graph.update_state(config, {"llm_model": "gpt-4o-mini"})
|
19
20
|
return graph, config
|
20
21
|
|
21
22
|
def test_no_model_provided(make_graph):
|
@@ -34,7 +35,7 @@ def test_no_model_provided(make_graph):
|
|
34
35
|
# Assert that the state key model_id is empty.
|
35
36
|
assert current_state.values["model_id"] == []
|
36
37
|
|
37
|
-
def
|
38
|
+
def test_valid_species_provided(make_graph):
|
38
39
|
'''
|
39
40
|
Test the tool by providing a specific species name.
|
40
41
|
We are testing a condition where the user asks for annotations
|
@@ -54,9 +55,15 @@ def test_specific_species_provided(make_graph):
|
|
54
55
|
# The assert statement checks if IL6 is present in the returned annotations.
|
55
56
|
assert dic_annotations_data[0]['data']["Species Name"][0] == "IL6"
|
56
57
|
|
58
|
+
def test_invalid_species_provided(make_graph):
|
59
|
+
'''
|
60
|
+
Test the tool by providing an invalid species name.
|
61
|
+
We are testing a condition where the user asks for annotations
|
62
|
+
of an invalid species in a specific model.
|
63
|
+
'''
|
57
64
|
# Test with an invalid species name
|
58
65
|
app, config = make_graph
|
59
|
-
prompt = "Extract annotations of species NADH in model 537."
|
66
|
+
prompt = "Extract annotations of only species NADH in model 537."
|
60
67
|
app.invoke(
|
61
68
|
{"messages": [HumanMessage(content=prompt)]},
|
62
69
|
config=config
|
@@ -73,15 +80,20 @@ def test_specific_species_provided(make_graph):
|
|
73
80
|
if isinstance(msg, ToolMessage) and msg.name == "get_annotation":
|
74
81
|
#If a ToolMessage exists and artifact is None (meaning no valid annotation was found)
|
75
82
|
#and the rejected species (NADH) is mentioned, the test passes.
|
76
|
-
if msg.artifact is None and
|
83
|
+
if msg.artifact is None and msg.status == "error":
|
77
84
|
#If artifact is None, it means no annotation was found
|
78
85
|
# (likely due to an invalid species).
|
79
|
-
#If artifact contains data, the tool successfully retrieved annotations.
|
80
86
|
test_condition = True
|
81
87
|
break
|
82
88
|
# assert test_condition
|
83
|
-
assert test_condition
|
89
|
+
assert test_condition
|
84
90
|
|
91
|
+
def test_invalid_and_valid_species_provided(make_graph):
|
92
|
+
'''
|
93
|
+
Test the tool by providing an invalid species name and a valid species name.
|
94
|
+
We are testing a condition where the user asks for annotations
|
95
|
+
of an invalid species and a valid species in a specific model.
|
96
|
+
'''
|
85
97
|
# Test with an invalid species name and a valid species name
|
86
98
|
app, config = make_graph
|
87
99
|
prompt = "Extract annotations of species NADH, NAD, and IL7 in model 64."
|
@@ -90,21 +102,24 @@ def test_specific_species_provided(make_graph):
|
|
90
102
|
config=config
|
91
103
|
)
|
92
104
|
current_state = app.get_state(config)
|
93
|
-
|
105
|
+
dic_annotations_data = current_state.values["dic_annotations_data"]
|
106
|
+
# List of species that are expected to be found in the annotations
|
107
|
+
extracted_species = []
|
108
|
+
for idx in dic_annotations_data[0]['data']["Species Name"]:
|
109
|
+
extracted_species.append(dic_annotations_data[0]['data']["Species Name"][idx])
|
94
110
|
reversed_messages = current_state.values["messages"][::-1]
|
95
111
|
# Loop through the reversed messages until a
|
96
112
|
# ToolMessage is found.
|
97
|
-
|
113
|
+
tool_status_success = False
|
98
114
|
for msg in reversed_messages:
|
99
115
|
# Assert that the one of the messages is a ToolMessage
|
100
116
|
# and its artifact is None.
|
101
117
|
if isinstance(msg, ToolMessage) and msg.name == "get_annotation":
|
102
|
-
|
103
|
-
|
104
|
-
if msg.artifact is True and 'IL7' in msg.content:
|
105
|
-
artifact_was_none = True
|
118
|
+
if msg.artifact is True and msg.status == "success":
|
119
|
+
tool_status_success = True
|
106
120
|
break
|
107
|
-
assert
|
121
|
+
assert tool_status_success
|
122
|
+
assert set(extracted_species) == set(["NADH", "NAD"])
|
108
123
|
|
109
124
|
def test_all_species_annotations(make_graph):
|
110
125
|
'''
|
@@ -146,7 +161,7 @@ def test_all_species_annotations(make_graph):
|
|
146
161
|
# Expect a successful extraction (artifact is True) and that the content
|
147
162
|
# matches what is returned by prepare_content_msg for species.
|
148
163
|
# And that the first or second description of the LacI protein is missing.
|
149
|
-
if (msg.artifact is True and msg.content == prepare_content_msg([]
|
164
|
+
if (msg.artifact is True and msg.content == prepare_content_msg([])
|
150
165
|
and msg.status=="success" and (first_descp_laci_protein == '-' or
|
151
166
|
second_descp_laci_protein == '-')):
|
152
167
|
test_condition = True
|
@@ -164,7 +179,7 @@ def test_all_species_annotations(make_graph):
|
|
164
179
|
# Expect a successful extraction (artifact is True) and that the content
|
165
180
|
# matches for for missing description ['ORI'].
|
166
181
|
if (msg.artifact is True and
|
167
|
-
msg.content == prepare_content_msg([
|
182
|
+
msg.content == prepare_content_msg(['ORI'])
|
168
183
|
and msg.status == "success"):
|
169
184
|
test_condition = True
|
170
185
|
break
|
@@ -2,7 +2,7 @@
|
|
2
2
|
Test cases for Talk2Biomodels get_modelinfo tool.
|
3
3
|
'''
|
4
4
|
|
5
|
-
from langchain_core.messages import HumanMessage
|
5
|
+
from langchain_core.messages import HumanMessage, ToolMessage
|
6
6
|
from ..agents.t2b_agent import get_app
|
7
7
|
|
8
8
|
def test_get_modelinfo_tool():
|
@@ -24,3 +24,34 @@ def test_get_modelinfo_tool():
|
|
24
24
|
assistant_msg = response["messages"][-1].content
|
25
25
|
# Check if the assistant message is a string
|
26
26
|
assert isinstance(assistant_msg, str)
|
27
|
+
|
28
|
+
def test_model_with_no_species():
|
29
|
+
'''
|
30
|
+
Test the get_modelinfo tool with a model that does not
|
31
|
+
return any species.
|
32
|
+
|
33
|
+
This should raise a tool error.
|
34
|
+
'''
|
35
|
+
unique_id = 12345
|
36
|
+
app = get_app(unique_id)
|
37
|
+
config = {"configurable": {"thread_id": unique_id}}
|
38
|
+
prompt = "Extract all species from model 20"
|
39
|
+
# Test the tool get_modelinfo
|
40
|
+
app.invoke(
|
41
|
+
{"messages": [HumanMessage(content=prompt)]},
|
42
|
+
config=config
|
43
|
+
)
|
44
|
+
current_state = app.get_state(config)
|
45
|
+
reversed_messages = current_state.values["messages"][::-1]
|
46
|
+
# Loop through the reversed messages until a
|
47
|
+
# ToolMessage is found.
|
48
|
+
test_condition = False
|
49
|
+
for msg in reversed_messages:
|
50
|
+
# Check if the message is a ToolMessage from the get_modelinfo tool
|
51
|
+
if isinstance(msg, ToolMessage) and msg.name == "get_modelinfo":
|
52
|
+
# Check if the message is an error message
|
53
|
+
if (msg.status == "error" and
|
54
|
+
"ValueError('Unable to extract species from the model.')" in msg.content):
|
55
|
+
test_condition = True
|
56
|
+
break
|
57
|
+
assert test_condition
|
@@ -17,10 +17,9 @@ def test_integration():
|
|
17
17
|
# ##########################################
|
18
18
|
# ## Test simulate_model tool
|
19
19
|
# ##########################################
|
20
|
-
prompt = '''Simulate the model 537 for 100 hours and intervals
|
21
|
-
100 with an initial concentration of `DoseQ2W`
|
22
|
-
set to
|
23
|
-
of `Ab{serum}` to 100 every 25 hours.'''
|
20
|
+
prompt = '''Simulate the model 537 for 100 hours and time intervals
|
21
|
+
100 with an initial concentration of `DoseQ2W` set to 300 and `Dose`
|
22
|
+
set to 0. Reset the concentration of `Ab{serum}` to 100 every 25 hours.'''
|
24
23
|
# Test the tool get_modelinfo
|
25
24
|
response = app.invoke(
|
26
25
|
{"messages": [HumanMessage(content=prompt)]},
|
@@ -5,9 +5,10 @@ This module contains the `GetAnnotationTool` for fetching species annotations
|
|
5
5
|
based on the provided model and species names.
|
6
6
|
"""
|
7
7
|
import math
|
8
|
-
from typing import List, Annotated, Type
|
8
|
+
from typing import List, Annotated, Type, TypedDict, Union, Literal
|
9
9
|
import logging
|
10
10
|
from dataclasses import dataclass
|
11
|
+
import hydra
|
11
12
|
from pydantic import BaseModel, Field
|
12
13
|
import basico
|
13
14
|
import pandas as pd
|
@@ -16,6 +17,7 @@ from langgraph.prebuilt import InjectedState
|
|
16
17
|
from langchain_core.tools.base import BaseTool
|
17
18
|
from langchain_core.tools.base import InjectedToolCallId
|
18
19
|
from langchain_core.messages import ToolMessage
|
20
|
+
from langchain_openai import ChatOpenAI
|
19
21
|
from .load_biomodel import ModelData, load_biomodel
|
20
22
|
from ..api.uniprot import search_uniprot_labels
|
21
23
|
from ..api.ols import search_ols_labels
|
@@ -27,16 +29,56 @@ logger = logging.getLogger(__name__)
|
|
27
29
|
|
28
30
|
ols_ontology_abbreviations = {'pato', 'chebi', 'sbo', 'fma', 'pr','go'}
|
29
31
|
|
30
|
-
def
|
31
|
-
|
32
|
+
def extract_relevant_species_names(model_object, arg_data, state):
|
33
|
+
"""
|
34
|
+
Extract relevant species names based on the user question.
|
35
|
+
"""
|
36
|
+
# Load hydra configuration
|
37
|
+
with hydra.initialize(version_base=None, config_path="../../configs"):
|
38
|
+
cfg = hydra.compose(config_name='config',
|
39
|
+
overrides=['talk2biomodels/tools/get_annotation=default'])
|
40
|
+
cfg = cfg.talk2biomodels.tools.get_annotation
|
41
|
+
logger.info("Loaded the following system prompt for the LLM"
|
42
|
+
" to get a structured output: %s", cfg.prompt)
|
43
|
+
|
44
|
+
# Extract all the species names from the model
|
45
|
+
df_species = basico.model_info.get_species(model=model_object.copasi_model)
|
46
|
+
if df_species is None:
|
47
|
+
raise ValueError("Unable to extract species from the model.")
|
48
|
+
# Get all the species names
|
49
|
+
all_species_names = df_species.index.tolist()
|
50
|
+
|
51
|
+
# Define a structured output for the LLM model
|
52
|
+
class CustomHeader(TypedDict):
|
53
|
+
"""
|
54
|
+
A list of species based on user question.
|
55
|
+
"""
|
56
|
+
relevant_species: Union[None, List[Literal[*all_species_names]]] = Field(
|
57
|
+
description="""List of species based on user question.
|
58
|
+
If no relevant species are found, it must be None.""")
|
59
|
+
|
60
|
+
# Create an instance of the LLM model
|
61
|
+
llm = ChatOpenAI(model=state['llm_model'], temperature=0)
|
62
|
+
# Get the structured output from the LLM model
|
63
|
+
llm_with_structured_output = llm.with_structured_output(CustomHeader)
|
64
|
+
# Define the question for the LLM model using the prompt
|
65
|
+
question = cfg.prompt
|
66
|
+
question += f'Here is the user question: {arg_data.user_question}'
|
67
|
+
# Invoke the LLM model with the user question
|
68
|
+
dic = llm_with_structured_output.invoke(question)
|
69
|
+
extracted_species = []
|
70
|
+
# Extract all the species names from the model
|
71
|
+
for species in dic['relevant_species']:
|
72
|
+
if species in all_species_names:
|
73
|
+
extracted_species.append(species)
|
74
|
+
logger.info("Extracted species: %s", extracted_species)
|
75
|
+
return extracted_species
|
76
|
+
|
77
|
+
def prepare_content_msg(species_without_description: List[str]):
|
32
78
|
"""
|
33
79
|
Prepare the content message.
|
34
80
|
"""
|
35
81
|
content = 'Successfully extracted annotations for the species.'
|
36
|
-
if species_not_found:
|
37
|
-
content += f'''The following species do not exist, and
|
38
|
-
hence their annotations were not extracted:
|
39
|
-
{', '.join(species_not_found)}.'''
|
40
82
|
if species_without_description:
|
41
83
|
content += f'''The descriptions for the following species
|
42
84
|
were not found:
|
@@ -52,12 +94,7 @@ class ArgumentData:
|
|
52
94
|
" the experiment based on human query"
|
53
95
|
" and the context of the experiment."
|
54
96
|
" This must be set before the experiment is run."]
|
55
|
-
|
56
|
-
default=None,
|
57
|
-
description='''List of species names to fetch annotations for.
|
58
|
-
If not provided, annotations for all
|
59
|
-
species in the model will be fetched.'''
|
60
|
-
)
|
97
|
+
user_question: Annotated[str, "Description of the user question"]
|
61
98
|
|
62
99
|
class GetAnnotationInput(BaseModel):
|
63
100
|
"""
|
@@ -90,31 +127,22 @@ class GetAnnotationTool(BaseTool):
|
|
90
127
|
Run the tool.
|
91
128
|
"""
|
92
129
|
logger.info("Running the GetAnnotationTool tool for species %s, %s",
|
93
|
-
arg_data.
|
130
|
+
arg_data.user_question,
|
94
131
|
arg_data.experiment_name)
|
95
132
|
|
96
133
|
# Prepare the model object
|
97
134
|
sbml_file_path = state['sbml_file_path'][-1] if state['sbml_file_path'] else None
|
98
135
|
model_object = load_biomodel(sys_bio_model, sbml_file_path=sbml_file_path)
|
99
136
|
|
100
|
-
# Extract
|
101
|
-
|
137
|
+
# Extract relevant species names based on the user question
|
138
|
+
list_species_names = extract_relevant_species_names(model_object, arg_data, state)
|
102
139
|
|
103
|
-
if
|
104
|
-
|
105
|
-
raise ValueError("
|
106
|
-
# Fetch annotations for the species names
|
107
|
-
arg_data.list_species_names = arg_data.list_species_names or df_species.index.tolist()
|
140
|
+
# Check if the returned species names are empty
|
141
|
+
if not list_species_names:
|
142
|
+
raise ValueError("Model does not contain the requested species.")
|
108
143
|
|
109
144
|
(annotations_df,
|
110
|
-
|
111
|
-
species_without_description) = self._fetch_annotations(arg_data.list_species_names)
|
112
|
-
|
113
|
-
# Check if annotations are empty
|
114
|
-
# If empty, return a message
|
115
|
-
if annotations_df.empty:
|
116
|
-
logger.warning("The annotations dataframe is empty.")
|
117
|
-
return prepare_content_msg(species_not_found, species_without_description)
|
145
|
+
species_without_description) = self._fetch_annotations(list_species_names)
|
118
146
|
|
119
147
|
# Process annotations
|
120
148
|
annotations_df = self._process_annotations(annotations_df)
|
@@ -141,8 +169,7 @@ class GetAnnotationTool(BaseTool):
|
|
141
169
|
update=dic_updated_state_for_model | {
|
142
170
|
"messages": [
|
143
171
|
ToolMessage(
|
144
|
-
content=prepare_content_msg(
|
145
|
-
species_without_description),
|
172
|
+
content=prepare_content_msg(species_without_description),
|
146
173
|
artifact=True,
|
147
174
|
tool_call_id=tool_call_id
|
148
175
|
)
|
@@ -165,7 +192,6 @@ class GetAnnotationTool(BaseTool):
|
|
165
192
|
tuple: A tuple containing the annotations dataframe, species not found list,
|
166
193
|
and description not found list.
|
167
194
|
"""
|
168
|
-
species_not_found = []
|
169
195
|
description_not_found = []
|
170
196
|
data = []
|
171
197
|
|
@@ -173,10 +199,6 @@ class GetAnnotationTool(BaseTool):
|
|
173
199
|
for species in list_species_names:
|
174
200
|
# Get the MIRIAM annotation for the species
|
175
201
|
annotation = basico.get_miriam_annotation(name=species)
|
176
|
-
# If the annotation is not found, add the species to the list
|
177
|
-
if annotation is None:
|
178
|
-
species_not_found.append(species)
|
179
|
-
continue
|
180
202
|
|
181
203
|
# Extract the descriptions from the annotation
|
182
204
|
descriptions = annotation.get("descriptions", [])
|
@@ -197,7 +219,7 @@ class GetAnnotationTool(BaseTool):
|
|
197
219
|
annotations_df = pd.DataFrame(data)
|
198
220
|
|
199
221
|
# Return the annotations dataframe and the species not found list
|
200
|
-
return annotations_df,
|
222
|
+
return annotations_df, description_not_found
|
201
223
|
|
202
224
|
def _process_annotations(self, annotations_df: pd.DataFrame) -> pd.DataFrame:
|
203
225
|
"""
|
@@ -83,14 +83,33 @@ class GetModelInfoTool(BaseTool):
|
|
83
83
|
# Extract species from the model
|
84
84
|
if requested_model_info.species:
|
85
85
|
df_species = basico.model_info.get_species(model=model_obj.copasi_model)
|
86
|
-
|
87
|
-
|
86
|
+
if df_species is None:
|
87
|
+
raise ValueError("Unable to extract species from the model.")
|
88
|
+
# Convert index into a column
|
89
|
+
df_species.reset_index(inplace=True)
|
90
|
+
dic_results['Species'] = df_species[
|
91
|
+
['name',
|
92
|
+
'compartment',
|
93
|
+
'type',
|
94
|
+
'unit',
|
95
|
+
'initial_concentration',
|
96
|
+
'display_name']]
|
97
|
+
# Convert this into a dictionary
|
98
|
+
dic_results['Species'] = dic_results['Species'].to_dict(orient='records')
|
88
99
|
|
89
100
|
# Extract parameters from the model
|
90
101
|
if requested_model_info.parameters:
|
91
102
|
df_parameters = basico.model_info.get_parameters(model=model_obj.copasi_model)
|
92
|
-
|
93
|
-
|
103
|
+
# Convert index into a column
|
104
|
+
df_parameters.reset_index(inplace=True)
|
105
|
+
dic_results['Parameters'] = df_parameters[
|
106
|
+
['name',
|
107
|
+
'type',
|
108
|
+
'unit',
|
109
|
+
'initial_value',
|
110
|
+
'display_name']]
|
111
|
+
# Convert this into a dictionary
|
112
|
+
dic_results['Parameters'] = dic_results['Parameters'].to_dict(orient='records')
|
94
113
|
|
95
114
|
# Extract compartments from the model
|
96
115
|
if requested_model_info.compartments:
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
|
3
3
|
"""
|
4
|
-
Main agent for the
|
4
|
+
Main agent for the talk2scholars app.
|
5
5
|
"""
|
6
6
|
|
7
7
|
import logging
|
@@ -15,7 +15,7 @@ from langgraph.graph import END, START, StateGraph
|
|
15
15
|
from langgraph.types import Command
|
16
16
|
from ..agents import s2_agent
|
17
17
|
from ..config.config import config
|
18
|
-
from ..state.
|
18
|
+
from ..state.state_talk2scholars import Talk2Scholars
|
19
19
|
|
20
20
|
logging.basicConfig(level=logging.INFO)
|
21
21
|
logger = logging.getLogger(__name__)
|
@@ -34,12 +34,12 @@ def make_supervisor_node(llm: BaseChatModel) -> str:
|
|
34
34
|
"""
|
35
35
|
# options = ["FINISH", "s2_agent"]
|
36
36
|
|
37
|
-
def supervisor_node(state:
|
37
|
+
def supervisor_node(state: Talk2Scholars) -> Command[Literal["s2_agent", "__end__"]]:
|
38
38
|
"""
|
39
39
|
Supervisor node that routes to appropriate sub-agents.
|
40
40
|
|
41
41
|
Args:
|
42
|
-
state (
|
42
|
+
state (Talk2Scholars): The current state of the conversation.
|
43
43
|
|
44
44
|
Returns:
|
45
45
|
Command[Literal["s2_agent", "__end__"]]: The command to execute next.
|
@@ -91,12 +91,12 @@ def get_app(thread_id: str, llm_model ='gpt-4o-mini') -> StateGraph:
|
|
91
91
|
Returns:
|
92
92
|
The compiled langraph app.
|
93
93
|
"""
|
94
|
-
def call_s2_agent(state:
|
94
|
+
def call_s2_agent(state: Talk2Scholars) -> Command[Literal["__end__"]]:
|
95
95
|
"""
|
96
96
|
Node for calling the S2 agent.
|
97
97
|
|
98
98
|
Args:
|
99
|
-
state (
|
99
|
+
state (Talk2Scholars): The current state of the conversation.
|
100
100
|
|
101
101
|
Returns:
|
102
102
|
Command[Literal["__end__"]]: The command to execute next.
|
@@ -115,7 +115,7 @@ def get_app(thread_id: str, llm_model ='gpt-4o-mini') -> StateGraph:
|
|
115
115
|
},
|
116
116
|
)
|
117
117
|
llm = ChatOpenAI(model=llm_model, temperature=0)
|
118
|
-
workflow = StateGraph(
|
118
|
+
workflow = StateGraph(Talk2Scholars)
|
119
119
|
|
120
120
|
supervisor = make_supervisor_node(llm)
|
121
121
|
workflow.add_node("supervisor", supervisor)
|
@@ -11,7 +11,7 @@ from langgraph.graph import START, StateGraph
|
|
11
11
|
from langgraph.prebuilt import create_react_agent
|
12
12
|
from langgraph.checkpoint.memory import MemorySaver
|
13
13
|
from ..config.config import config
|
14
|
-
from ..state.
|
14
|
+
from ..state.state_talk2scholars import Talk2Scholars
|
15
15
|
# from ..tools.s2 import s2_tools
|
16
16
|
from ..tools.s2.search import search_tool
|
17
17
|
from ..tools.s2.display_results import display_results
|
@@ -28,7 +28,7 @@ def get_app(uniq_id, llm_model='gpt-4o-mini'):
|
|
28
28
|
'''
|
29
29
|
This function returns the langraph app.
|
30
30
|
'''
|
31
|
-
def agent_s2_node(state:
|
31
|
+
def agent_s2_node(state: Talk2Scholars):
|
32
32
|
'''
|
33
33
|
This function calls the model.
|
34
34
|
'''
|
@@ -47,13 +47,13 @@ def get_app(uniq_id, llm_model='gpt-4o-mini'):
|
|
47
47
|
model = create_react_agent(
|
48
48
|
llm,
|
49
49
|
tools=tools,
|
50
|
-
state_schema=
|
50
|
+
state_schema=Talk2Scholars,
|
51
51
|
state_modifier=config.S2_AGENT_PROMPT,
|
52
52
|
checkpointer=MemorySaver()
|
53
53
|
)
|
54
54
|
|
55
55
|
# Define a new graph
|
56
|
-
workflow = StateGraph(
|
56
|
+
workflow = StateGraph(Talk2Scholars)
|
57
57
|
|
58
58
|
# Define the two nodes we will cycle between
|
59
59
|
workflow.add_node("agent_s2", agent_s2_node)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
"""
|
2
|
-
This is the state file for the
|
2
|
+
This is the state file for the talk2scholars agent.
|
3
3
|
"""
|
4
4
|
|
5
5
|
import logging
|
@@ -19,9 +19,9 @@ def replace_dict(existing: Dict[str, Any], new: Dict[str, Any]) -> Dict[str, Any
|
|
19
19
|
return new
|
20
20
|
|
21
21
|
|
22
|
-
class
|
22
|
+
class Talk2Scholars(AgentState):
|
23
23
|
"""
|
24
|
-
The state for the
|
24
|
+
The state for the talk2scholars agent, inheriting from AgentState.
|
25
25
|
"""
|
26
26
|
|
27
27
|
papers: Annotated[Dict[str, Any], replace_dict] # Changed from List to Dict
|
@@ -1,5 +1,5 @@
|
|
1
1
|
"""
|
2
|
-
Unit and integration tests for
|
2
|
+
Unit and integration tests for Talk2Scholars system.
|
3
3
|
Each test focuses on a single, specific functionality.
|
4
4
|
Tests are deterministic and independent of each other.
|
5
5
|
"""
|
@@ -10,7 +10,7 @@ import pytest
|
|
10
10
|
from langchain_core.messages import AIMessage, HumanMessage
|
11
11
|
|
12
12
|
from ..agents.main_agent import get_app, make_supervisor_node
|
13
|
-
from ..state.
|
13
|
+
from ..state.state_talk2scholars import replace_dict
|
14
14
|
from ..tools.s2.display_results import display_results
|
15
15
|
from ..tools.s2.multi_paper_rec import get_multi_paper_recommendations
|
16
16
|
from ..tools.s2.search import search_tool
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: aiagents4pharma
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.16.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
|
@@ -50,11 +50,10 @@ Requires-Dist: streamlit-feedback
|
|
50
50
|
[](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2biomodels.yml)
|
51
51
|
[](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2cells.yml)
|
52
52
|
[](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2knowledgegraphs.yml)
|
53
|
-
[](https://github.com/VirtualPatientEngine/AIAgents4Pharma/actions/workflows/tests_talk2scholars.yml)
|
54
54
|

|
55
55
|

|
56
56
|
|
57
|
-
|
58
57
|
<h1 align="center" style="border-bottom: none;">🤖 AIAgents4Pharma</h1>
|
59
58
|
|
60
59
|
Welcome to **AIAgents4Pharma** – an open-source project by [Team VPE](https://github.com/VirtualPatientEngine) that brings together AI-driven tools to help researchers and pharma interact seamlessly with complex biological data.
|
@@ -64,7 +63,7 @@ Our toolkit currently consists of three intelligent agents, each designed to sim
|
|
64
63
|
- **Talk2BioModels**: Engage directly with mathematical models in systems biology.
|
65
64
|
- **Talk2Cells** _(Work in progress)_: Query and analyze sequencing data with ease.
|
66
65
|
- **Talk2KnowledgeGraphs** _(Work in progress)_: Access and explore complex biological knowledge graphs for insightful data connections.
|
67
|
-
- **
|
66
|
+
- **Talk2Scholars** _(Coming soon)_: Get recommendations for articles related to your choice. Download, query, and write/retrieve them to your reference manager (currently supporting Zotero).
|
68
67
|
|
69
68
|
---
|
70
69
|
|
@@ -87,7 +86,9 @@ Our toolkit currently consists of three intelligent agents, each designed to sim
|
|
87
86
|
|
88
87
|
**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.
|
89
88
|
|
90
|
-
### 4.
|
89
|
+
### 4. Talk2Scholars _(Work in Progress)_
|
90
|
+
|
91
|
+
Talk2Scholars is an AI-powered hierarchical agent system designed to revolutionize academic paper search and analysis. Through intelligent conversation, users can discover, analyze, and receive recommendations for academic papers using state-of-the-art natural language processing.
|
91
92
|
|
92
93
|
## Getting Started
|
93
94
|
|
@@ -198,7 +199,7 @@ Check out our [CONTRIBUTING.md](CONTRIBUTING.md) for more information.
|
|
198
199
|
- **User Interface**: Interactive web UI for all agents.
|
199
200
|
- **Talk2Cells**: Integration of sequencing data analysis tools.
|
200
201
|
- **Talk2KnowledgeGraphs**: Interface for biological knowledge graph interaction.
|
201
|
-
- **
|
202
|
+
- **Talk2Scholars**: Interface for exploring articles
|
202
203
|
|
203
204
|
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.
|
204
205
|
|
@@ -1,13 +1,15 @@
|
|
1
|
-
aiagents4pharma/__init__.py,sha256=
|
1
|
+
aiagents4pharma/__init__.py,sha256=nFCe1As_SuRkmhcdZVsU0aYjYccHxk1DbduLpy8XulY,174
|
2
2
|
aiagents4pharma/configs/__init__.py,sha256=hNkSrXw1Ix1HhkGn_aaidr2coBYySfM0Hm_pMeRcX7k,76
|
3
|
-
aiagents4pharma/configs/config.yaml,sha256=
|
3
|
+
aiagents4pharma/configs/config.yaml,sha256=e0w2GOBVWcoPDtX-z4S6yKbv2rja5PfGRBhmTPVIXNU,161
|
4
4
|
aiagents4pharma/configs/talk2biomodels/__init__.py,sha256=safyFKhkd5Wlirl9dMZIHWDLTpY2oLw9wjIM7ZtLIHk,88
|
5
5
|
aiagents4pharma/configs/talk2biomodels/agents/__init__.py,sha256=_ZoG8snICK2bidWtc2KOGs738LWg9_r66V9mOMnEb-E,71
|
6
6
|
aiagents4pharma/configs/talk2biomodels/agents/t2b_agent/__init__.py,sha256=-fAORvyFmG2iSvFOFDixmt9OTQRR58y89uhhu2EgbA8,46
|
7
7
|
aiagents4pharma/configs/talk2biomodels/agents/t2b_agent/default.yaml,sha256=eLrJIezoPJ6_DvrSYsi3eALl03o0hJhntej3ESoeKKg,551
|
8
|
-
aiagents4pharma/configs/talk2biomodels/tools/__init__.py,sha256=
|
8
|
+
aiagents4pharma/configs/talk2biomodels/tools/__init__.py,sha256=B08KWjj7bpizuTETGnnngrEVK4nzdWGREdoCCSw1Sm4,102
|
9
9
|
aiagents4pharma/configs/talk2biomodels/tools/ask_question/__init__.py,sha256=-fAORvyFmG2iSvFOFDixmt9OTQRR58y89uhhu2EgbA8,46
|
10
10
|
aiagents4pharma/configs/talk2biomodels/tools/ask_question/default.yaml,sha256=yy-Sq1u4dBlTFi_UeoWYoHkWRDWueJWVNK_rcUCC5bw,1747
|
11
|
+
aiagents4pharma/configs/talk2biomodels/tools/get_annotation/__init__.py,sha256=-fAORvyFmG2iSvFOFDixmt9OTQRR58y89uhhu2EgbA8,46
|
12
|
+
aiagents4pharma/configs/talk2biomodels/tools/get_annotation/default.yaml,sha256=8vUlzU5Y3BPggId5bVMo9B23VG4mp2ziTglb4LmLCsc,319
|
11
13
|
aiagents4pharma/talk2biomodels/__init__.py,sha256=2ICwVh1u07SZv31Jd2DKHobauOxWNWY29_Gqq3kOnNQ,159
|
12
14
|
aiagents4pharma/talk2biomodels/agents/__init__.py,sha256=sn5-fREjMdEvb-OUan3iOqrgYGjplNx3J8hYOaW0Po8,128
|
13
15
|
aiagents4pharma/talk2biomodels/agents/t2b_agent.py,sha256=5h4n7dF13KuT5f9vzfK7EQTu_b0a0hB7ScLFlTKaNko,3449
|
@@ -24,9 +26,9 @@ aiagents4pharma/talk2biomodels/tests/__init__.py,sha256=Jbw5tJxSrjGoaK5IX3pJWDCN
|
|
24
26
|
aiagents4pharma/talk2biomodels/tests/test_api.py,sha256=7Kz2r5F5tjmn3F0LoM33oP-21W633936YHiyf5toGg0,1716
|
25
27
|
aiagents4pharma/talk2biomodels/tests/test_ask_question.py,sha256=yRkKK9HLB1bGGWm_WwOckwaUmmRfRAD9z2NFFGLIGTY,1560
|
26
28
|
aiagents4pharma/talk2biomodels/tests/test_basico_model.py,sha256=y82fpTJMPHwtXxlle1cGQ_2Bewwpxi0aJSVrVAYLhN0,2060
|
27
|
-
aiagents4pharma/talk2biomodels/tests/test_get_annotation.py,sha256=
|
28
|
-
aiagents4pharma/talk2biomodels/tests/test_getmodelinfo.py,sha256=
|
29
|
-
aiagents4pharma/talk2biomodels/tests/test_integration.py,sha256=
|
29
|
+
aiagents4pharma/talk2biomodels/tests/test_get_annotation.py,sha256=GqS3kCxxTTMTJFjTnJhilrxT6jbNb7Yi0fbaKkadU4E,8159
|
30
|
+
aiagents4pharma/talk2biomodels/tests/test_getmodelinfo.py,sha256=Y1sFhoMF4mbvlag7D-dEvv6ytjmAqzMLPvSvaVEI_Qk,2045
|
31
|
+
aiagents4pharma/talk2biomodels/tests/test_integration.py,sha256=QHGOKrKyd0kBGy1tOMmkNSqN2Jc2oIXoUrAMpv-elBc,5058
|
30
32
|
aiagents4pharma/talk2biomodels/tests/test_param_scan.py,sha256=vRbnn4uVWFbfZbU4gVCjHi5WDCUrErut8ElzAPE5y84,2648
|
31
33
|
aiagents4pharma/talk2biomodels/tests/test_query_article.py,sha256=HhFgU5HzCipecEYlfbpPxN-SCIPKep22gpXCutWXRb8,2820
|
32
34
|
aiagents4pharma/talk2biomodels/tests/test_search_models.py,sha256=8ODFubLxWYD3I3KQWuUnJ2GZRzMjFpXInFBLxKxG_ME,929
|
@@ -36,8 +38,8 @@ aiagents4pharma/talk2biomodels/tests/test_sys_bio_model.py,sha256=HSmBBViMi0jYf4
|
|
36
38
|
aiagents4pharma/talk2biomodels/tools/__init__.py,sha256=6H2HWv5Q4NZYEmw-Ti5KZnJlEqhaC2HXSDZa6kiSl-U,350
|
37
39
|
aiagents4pharma/talk2biomodels/tools/ask_question.py,sha256=hWXg7o0sTMDWH1ZnxtashTALvXpvNoaomfcniEhw-Bw,4684
|
38
40
|
aiagents4pharma/talk2biomodels/tools/custom_plotter.py,sha256=HWwKTX3o4dk0GcRVTO2hPrFSu98mtJ4TKC_hbHXOe1c,4018
|
39
|
-
aiagents4pharma/talk2biomodels/tools/get_annotation.py,sha256=
|
40
|
-
aiagents4pharma/talk2biomodels/tools/get_modelinfo.py,sha256=
|
41
|
+
aiagents4pharma/talk2biomodels/tools/get_annotation.py,sha256=l6gN_Urf-EJ5a_ZobIBeJB68BvLznsPUZR5sV04XR70,13420
|
42
|
+
aiagents4pharma/talk2biomodels/tools/get_modelinfo.py,sha256=57dkXrBeRpyiaW3dYkoWIfr6zSsFHcWRhvUVNyLcvUs,6363
|
41
43
|
aiagents4pharma/talk2biomodels/tools/load_arguments.py,sha256=bffNIlBDTCSFYiZprA73yi8Jbb8z3Oh2decVNh1UnZc,4162
|
42
44
|
aiagents4pharma/talk2biomodels/tools/load_biomodel.py,sha256=pyVzLQoMnuJYEwsjeOlqcUrbU1F1Z-pNlgkhFaoKpy0,689
|
43
45
|
aiagents4pharma/talk2biomodels/tools/parameter_scan.py,sha256=aNh94LgBgVXBIczuNkbSsOZ9j54YVEdZWmZbZr7Nk8k,12465
|
@@ -55,22 +57,6 @@ aiagents4pharma/talk2cells/tools/__init__.py,sha256=38nK2a_lEFRjO3qD6Fo9a3983ZCY
|
|
55
57
|
aiagents4pharma/talk2cells/tools/scp_agent/__init__.py,sha256=s7g0lyH1lMD9pcWHLPtwRJRvzmTh2II7DrxyLulpjmQ,163
|
56
58
|
aiagents4pharma/talk2cells/tools/scp_agent/display_studies.py,sha256=6q59gh_NQaiOU2rn55A3sIIFKlXi4SK3iKgySvUDrtQ,600
|
57
59
|
aiagents4pharma/talk2cells/tools/scp_agent/search_studies.py,sha256=MLe-twtFnOu-P8P9diYq7jvHBHbWFRRCZLcfpUzqPMg,2806
|
58
|
-
aiagents4pharma/talk2competitors/__init__.py,sha256=haaikzND3c0Euqq86ndA4fl9q42aOop5rYG_8Zh1D-o,119
|
59
|
-
aiagents4pharma/talk2competitors/agents/__init__.py,sha256=ykszlVGxz3egLHZAttlNoTPxIrnQJZYva_ssR8fwIFk,117
|
60
|
-
aiagents4pharma/talk2competitors/agents/main_agent.py,sha256=UoHCpZd-HoeG0B6_gAF1cEP2OqMvrTuGe7MZDwL_u1U,3878
|
61
|
-
aiagents4pharma/talk2competitors/agents/s2_agent.py,sha256=eTrhc4ZPvWOUWMHNYxK0WltsZedZUnAWNu-TeUa-ruk,2501
|
62
|
-
aiagents4pharma/talk2competitors/config/__init__.py,sha256=HyM6paOpKZ5_tZnyVheSAFmxjT6Mb3PxvWKfP0rz-dE,113
|
63
|
-
aiagents4pharma/talk2competitors/config/config.py,sha256=jd4ltMBJyTztm9wT7j3ujOyYxL2SXRgxQJ4OZUBmCG4,5387
|
64
|
-
aiagents4pharma/talk2competitors/state/__init__.py,sha256=DzFjV3hZNes_pL4bDW2_8RsyK9BJcj6ejfBzU0KWn1k,106
|
65
|
-
aiagents4pharma/talk2competitors/state/state_talk2competitors.py,sha256=GUl1ZfM77XsjIEu-3xy4dtvaiMTA1pXf6i1ozVcX5Gg,993
|
66
|
-
aiagents4pharma/talk2competitors/tests/__init__.py,sha256=U3PsTiUZaUBD1IZanFGkDIOdFieDVJtGKQ5-woYUo8c,45
|
67
|
-
aiagents4pharma/talk2competitors/tests/test_langgraph.py,sha256=sEROK1aU3wFqJhZohONVI6Pr7t1d3PSqs-4erVIyiJw,9283
|
68
|
-
aiagents4pharma/talk2competitors/tools/__init__.py,sha256=YudBDRwaEzDnAcpxGZvEOfyh5-6xd51CTvTKTkywgXw,68
|
69
|
-
aiagents4pharma/talk2competitors/tools/s2/__init__.py,sha256=9RQH3efTj6qkXk0ICKSc7Mzpkitt4gRGsQ1pGPrrREU,181
|
70
|
-
aiagents4pharma/talk2competitors/tools/s2/display_results.py,sha256=B8JJGohi1Eyx8C3MhO_SiyQP3R6hPyUKJOAzcHmq3FU,584
|
71
|
-
aiagents4pharma/talk2competitors/tools/s2/multi_paper_rec.py,sha256=FYLt47DAk6WOKfEk1Gj9zVvJGNyxA283PCp8IKW9U5M,4262
|
72
|
-
aiagents4pharma/talk2competitors/tools/s2/search.py,sha256=pppjrQv5-8ep4fnqgTSBNgnbSnQsVIcNrRrH0p2TP1o,4025
|
73
|
-
aiagents4pharma/talk2competitors/tools/s2/single_paper_rec.py,sha256=dAfUQxI7T5eu0eDxK8VAl7-JH0Wnw24CVkOQqwj-hXc,4810
|
74
60
|
aiagents4pharma/talk2knowledgegraphs/__init__.py,sha256=4smVQoSMM6rflVnNkABqlDAAlSn4bYsq7rMVWjRGvis,103
|
75
61
|
aiagents4pharma/talk2knowledgegraphs/datasets/__init__.py,sha256=L3gPuHskSegmtXskVrLIYr7FXe_ibKgJ2GGr1_Wok6k,173
|
76
62
|
aiagents4pharma/talk2knowledgegraphs/datasets/biobridge_primekg.py,sha256=QlzDXmXREoa9MA6-GwzqRjdzndQeGBAF11Td6NFk_9Y,23426
|
@@ -96,8 +82,24 @@ aiagents4pharma/talk2knowledgegraphs/utils/embeddings/sentence_transformer.py,sh
|
|
96
82
|
aiagents4pharma/talk2knowledgegraphs/utils/enrichments/__init__.py,sha256=tW426knki2DBIHcWyF_K04iMMdbpIn_e_TpPmTgz2dI,113
|
97
83
|
aiagents4pharma/talk2knowledgegraphs/utils/enrichments/enrichments.py,sha256=Bx8x6zzk5614ApWB90N_iv4_Y_Uq0-KwUeBwYSdQMU4,924
|
98
84
|
aiagents4pharma/talk2knowledgegraphs/utils/enrichments/ollama.py,sha256=8eoxR-VHo0G7ReQIwje7xEhE-SJlHdef7_wJRpnvFIc,4116
|
99
|
-
aiagents4pharma
|
100
|
-
aiagents4pharma
|
101
|
-
aiagents4pharma
|
102
|
-
aiagents4pharma
|
103
|
-
aiagents4pharma
|
85
|
+
aiagents4pharma/talk2scholars/__init__.py,sha256=haaikzND3c0Euqq86ndA4fl9q42aOop5rYG_8Zh1D-o,119
|
86
|
+
aiagents4pharma/talk2scholars/agents/__init__.py,sha256=ykszlVGxz3egLHZAttlNoTPxIrnQJZYva_ssR8fwIFk,117
|
87
|
+
aiagents4pharma/talk2scholars/agents/main_agent.py,sha256=HN3MkfHSDDlfzCKP79yAkpf3uyz3ZOCDGNRQ4gRL5RI,3854
|
88
|
+
aiagents4pharma/talk2scholars/agents/s2_agent.py,sha256=HI037q-bq-bGf5DqtraSCWO493fAzUZ81lOEOCbMAaM,2486
|
89
|
+
aiagents4pharma/talk2scholars/config/__init__.py,sha256=HyM6paOpKZ5_tZnyVheSAFmxjT6Mb3PxvWKfP0rz-dE,113
|
90
|
+
aiagents4pharma/talk2scholars/config/config.py,sha256=jd4ltMBJyTztm9wT7j3ujOyYxL2SXRgxQJ4OZUBmCG4,5387
|
91
|
+
aiagents4pharma/talk2scholars/state/__init__.py,sha256=S6SxlszIMZSIMJehjevPF9sKyR-PAwWb5TEdo6xWXE8,103
|
92
|
+
aiagents4pharma/talk2scholars/state/state_talk2scholars.py,sha256=nwNRKdhoTXAtBGMMp6coMyUCaQVOnoGNqyjpKKw_FVM,998
|
93
|
+
aiagents4pharma/talk2scholars/tests/__init__.py,sha256=U3PsTiUZaUBD1IZanFGkDIOdFieDVJtGKQ5-woYUo8c,45
|
94
|
+
aiagents4pharma/talk2scholars/tests/test_langgraph.py,sha256=HcnahbazwaLaZg71OyCho2FLZ0ePedmv3XGvARFNe0g,9277
|
95
|
+
aiagents4pharma/talk2scholars/tools/__init__.py,sha256=YudBDRwaEzDnAcpxGZvEOfyh5-6xd51CTvTKTkywgXw,68
|
96
|
+
aiagents4pharma/talk2scholars/tools/s2/__init__.py,sha256=9RQH3efTj6qkXk0ICKSc7Mzpkitt4gRGsQ1pGPrrREU,181
|
97
|
+
aiagents4pharma/talk2scholars/tools/s2/display_results.py,sha256=B8JJGohi1Eyx8C3MhO_SiyQP3R6hPyUKJOAzcHmq3FU,584
|
98
|
+
aiagents4pharma/talk2scholars/tools/s2/multi_paper_rec.py,sha256=FYLt47DAk6WOKfEk1Gj9zVvJGNyxA283PCp8IKW9U5M,4262
|
99
|
+
aiagents4pharma/talk2scholars/tools/s2/search.py,sha256=pppjrQv5-8ep4fnqgTSBNgnbSnQsVIcNrRrH0p2TP1o,4025
|
100
|
+
aiagents4pharma/talk2scholars/tools/s2/single_paper_rec.py,sha256=dAfUQxI7T5eu0eDxK8VAl7-JH0Wnw24CVkOQqwj-hXc,4810
|
101
|
+
aiagents4pharma-1.16.0.dist-info/LICENSE,sha256=IcIbyB1Hyk5ZDah03VNQvJkbNk2hkBCDqQ8qtnCvB4Q,1077
|
102
|
+
aiagents4pharma-1.16.0.dist-info/METADATA,sha256=XH5jLQYNhAKOc4ixt5KovsExcjX14eEBrzTp40YluKY,8906
|
103
|
+
aiagents4pharma-1.16.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
104
|
+
aiagents4pharma-1.16.0.dist-info/top_level.txt,sha256=-AH8rMmrSnJtq7HaAObS78UU-cTCwvX660dSxeM7a0A,16
|
105
|
+
aiagents4pharma-1.16.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|