tooluniverse 0.1.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.
Potentially problematic release.
This version of tooluniverse might be problematic. Click here for more details.
- tooluniverse/__init__.py +17 -0
- tooluniverse/base_tool.py +32 -0
- tooluniverse/data/__init__.py +0 -0
- tooluniverse/data/fda_drug_labeling_tools.json +6529 -0
- tooluniverse/data/fda_drugs_with_brand_generic_names_for_tool.py +201670 -0
- tooluniverse/data/monarch_tools.json +118 -0
- tooluniverse/data/opentarget_tools.json +1415 -0
- tooluniverse/data/special_tools.json +48 -0
- tooluniverse/execute_function.py +216 -0
- tooluniverse/graphql_tool.py +122 -0
- tooluniverse/openfda_tool.py +421 -0
- tooluniverse/restful_tool.py +95 -0
- tooluniverse/utils.py +172 -0
- tooluniverse-0.1.0.dist-info/METADATA +54 -0
- tooluniverse-0.1.0.dist-info/RECORD +17 -0
- tooluniverse-0.1.0.dist-info/WHEEL +5 -0
- tooluniverse-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from .base_tool import BaseTool
|
|
3
|
+
import copy
|
|
4
|
+
import re
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
def check_keys_present(api_capabilities_dict, keys):
|
|
8
|
+
for key in keys:
|
|
9
|
+
levels = key.split('.')
|
|
10
|
+
current_dict = api_capabilities_dict
|
|
11
|
+
key_present = True
|
|
12
|
+
for level in levels:
|
|
13
|
+
if level not in current_dict:
|
|
14
|
+
print(f"Key '{level}' not found in dictionary.")
|
|
15
|
+
key_present = False
|
|
16
|
+
break
|
|
17
|
+
if 'properties' in current_dict[level]:
|
|
18
|
+
current_dict = current_dict[level]['properties']
|
|
19
|
+
else:
|
|
20
|
+
current_dict = current_dict[level]
|
|
21
|
+
return key_present
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def extract_nested_fields(records, fields, keywords=None):
|
|
25
|
+
"""
|
|
26
|
+
Recursively extracts nested fields from a list of dictionaries.
|
|
27
|
+
|
|
28
|
+
:param records: List of dictionaries from which to extract fields
|
|
29
|
+
:param fields: List of nested fields to extract, each specified with dot notation (e.g., 'openfda.brand_name')
|
|
30
|
+
|
|
31
|
+
:return: List of dictionaries containing only the specified fields
|
|
32
|
+
"""
|
|
33
|
+
extracted_records = []
|
|
34
|
+
for record in records:
|
|
35
|
+
extracted_record = {}
|
|
36
|
+
for field in fields:
|
|
37
|
+
keys = field.split('.')
|
|
38
|
+
# print("keys", keys)
|
|
39
|
+
value = record
|
|
40
|
+
try:
|
|
41
|
+
for key in keys:
|
|
42
|
+
value = value[key]
|
|
43
|
+
if key != 'openfda' and key !='generic_name' and key !='brand_name':
|
|
44
|
+
if len(keywords)>0:
|
|
45
|
+
# print("key words:", keywords)
|
|
46
|
+
# print(value)
|
|
47
|
+
# print(type(value))
|
|
48
|
+
value = extract_sentences_with_keywords(value, keywords)
|
|
49
|
+
extracted_record[field] = value
|
|
50
|
+
except KeyError:
|
|
51
|
+
extracted_record[field] = None
|
|
52
|
+
if any(extracted_record.values()):
|
|
53
|
+
extracted_records.append(extracted_record)
|
|
54
|
+
return extracted_records
|
|
55
|
+
|
|
56
|
+
def map_properties_to_openfda_fields(arguments, search_fields):
|
|
57
|
+
"""
|
|
58
|
+
Maps the provided arguments to the corresponding openFDA fields based on the search_fields mapping.
|
|
59
|
+
|
|
60
|
+
:param arguments: The input arguments containing property names and values.
|
|
61
|
+
:param search_fields: The mapping of property names to openFDA fields.
|
|
62
|
+
|
|
63
|
+
:return: A dictionary with openFDA fields and corresponding values.
|
|
64
|
+
"""
|
|
65
|
+
mapped_arguments = {}
|
|
66
|
+
|
|
67
|
+
for key, value in list(arguments.items()):
|
|
68
|
+
if key in search_fields:
|
|
69
|
+
# print("key in search_fields:", key)
|
|
70
|
+
openfda_fields = search_fields[key]
|
|
71
|
+
if isinstance(openfda_fields, list):
|
|
72
|
+
for field in openfda_fields:
|
|
73
|
+
mapped_arguments[field] = value
|
|
74
|
+
else:
|
|
75
|
+
mapped_arguments[openfda_fields] = value
|
|
76
|
+
del arguments[key]
|
|
77
|
+
arguments['search_fields'] = mapped_arguments
|
|
78
|
+
return arguments
|
|
79
|
+
|
|
80
|
+
def extract_sentences_with_keywords(text_list, keywords):
|
|
81
|
+
"""
|
|
82
|
+
Extracts sentences containing any of the specified keywords from the text.
|
|
83
|
+
|
|
84
|
+
Parameters:
|
|
85
|
+
- text (str): The input text from which to extract sentences.
|
|
86
|
+
- keywords (list): A list of keywords to search for in the text.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
- list: A list of sentences containing any of the keywords.
|
|
90
|
+
"""
|
|
91
|
+
sentences_with_keywords = []
|
|
92
|
+
for text in text_list:
|
|
93
|
+
# Compile a regular expression pattern for sentence splitting
|
|
94
|
+
sentence_pattern = re.compile(r'(?<=[.!?]) +')
|
|
95
|
+
# Split the text into sentences
|
|
96
|
+
sentences = sentence_pattern.split(text)
|
|
97
|
+
# Initialize a list to hold sentences with keywords
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# Iterate through each sentence
|
|
101
|
+
for sentence in sentences:
|
|
102
|
+
# Check if any of the keywords are present in the sentence
|
|
103
|
+
if any(keyword.lower() in sentence.lower() for keyword in keywords):
|
|
104
|
+
# If a keyword is found, add the sentence to the list
|
|
105
|
+
sentences_with_keywords.append(sentence)
|
|
106
|
+
|
|
107
|
+
return "......".join(sentences_with_keywords)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def search_openfda(params=None, endpoint_url=None, api_key=None, sort=None, limit=5,
|
|
111
|
+
skip=None, count=None, exists=None, return_fields=None,
|
|
112
|
+
exist_option='OR', search_keyword_option='AND', keywords_filter=True):
|
|
113
|
+
# Initialize params if not provided
|
|
114
|
+
if params is None:
|
|
115
|
+
params = {}
|
|
116
|
+
|
|
117
|
+
if return_fields=='ALL':
|
|
118
|
+
exists = None
|
|
119
|
+
|
|
120
|
+
# Initialize search fields and construct search query
|
|
121
|
+
search_fields = params.get('search_fields', {})
|
|
122
|
+
search_query = []
|
|
123
|
+
keywords_list = []
|
|
124
|
+
if search_fields:
|
|
125
|
+
for field, value in search_fields.items():
|
|
126
|
+
# Merge multiple continuous black spaces into one and use one '+'
|
|
127
|
+
if keywords_filter and field !='openfda.brand_name' and field !='openfda.generic_name':
|
|
128
|
+
keywords_list.extend(value.split())
|
|
129
|
+
if field == 'openfda.generic_name':
|
|
130
|
+
value = value.upper() # all generic names are in uppercase
|
|
131
|
+
value = value.replace(" and ", " ") # remove 'and' in the search query
|
|
132
|
+
value = value.replace(" AND ", " ") # remove 'AND' in the search query
|
|
133
|
+
value = ' '.join(value.split())
|
|
134
|
+
if search_keyword_option=='AND':
|
|
135
|
+
search_query.append(f'{field}:({value.replace(" ", "+AND+")})')
|
|
136
|
+
elif search_keyword_option=='OR':
|
|
137
|
+
search_query.append(f'{field}:({value.replace(" ", "+")})')
|
|
138
|
+
else:
|
|
139
|
+
print("Invalid search_keyword_option. Please use 'AND' or 'OR'.")
|
|
140
|
+
del params['search_fields']
|
|
141
|
+
if search_query:
|
|
142
|
+
params['search'] = "+".join(search_query)
|
|
143
|
+
params['search'] = '(' + params['search'] + ')'
|
|
144
|
+
# Validate the presence of at least one of search, count, or sort
|
|
145
|
+
if not (params.get('search') or params.get('count') or params.get('sort') or search_fields):
|
|
146
|
+
return {"error": "You must provide at least one of 'search', 'count', or 'sort' parameters."}
|
|
147
|
+
|
|
148
|
+
# Set additional query parameters
|
|
149
|
+
params['limit'] = params.get('limit', limit)
|
|
150
|
+
params['sort'] = params.get('sort', sort)
|
|
151
|
+
params['skip'] = params.get('skip', skip)
|
|
152
|
+
params['count'] = params.get('count', count)
|
|
153
|
+
if exists is not None:
|
|
154
|
+
if isinstance(exists, str):
|
|
155
|
+
exists = [exists]
|
|
156
|
+
if 'search' in params:
|
|
157
|
+
if exist_option == 'AND':
|
|
158
|
+
params['search'] += "+AND+(" + "+AND+".join(
|
|
159
|
+
[f"_exists_:{keyword}" for keyword in exists])+")"
|
|
160
|
+
elif exist_option == 'OR':
|
|
161
|
+
params['search'] += "+AND+(" + "+".join(
|
|
162
|
+
[f"_exists_:{keyword}" for keyword in exists])+")"
|
|
163
|
+
else:
|
|
164
|
+
if exist_option == 'AND':
|
|
165
|
+
params['search'] = "+AND+".join(
|
|
166
|
+
[f"_exists_:{keyword}" for keyword in exists])
|
|
167
|
+
elif exist_option == 'OR':
|
|
168
|
+
params['search'] = "+".join(
|
|
169
|
+
[f"_exists_:{keyword}" for keyword in exists])
|
|
170
|
+
# Ensure that at least one of the search fields exists
|
|
171
|
+
params['search'] += "+AND+(" + "+".join(
|
|
172
|
+
[f"_exists_:{field}" for field in search_fields.keys()]) +")"
|
|
173
|
+
# params['search']+="+AND+_exists_:openfda"
|
|
174
|
+
|
|
175
|
+
# Construct full query with additional parameters
|
|
176
|
+
query = "&".join(
|
|
177
|
+
[f"{key}={value}" for key, value in params.items() if value is not None])
|
|
178
|
+
full_url = f"{endpoint_url}?{query}"
|
|
179
|
+
if api_key:
|
|
180
|
+
full_url += f"&api_key={api_key}"
|
|
181
|
+
|
|
182
|
+
print(full_url)
|
|
183
|
+
|
|
184
|
+
response = requests.get(full_url)
|
|
185
|
+
|
|
186
|
+
# Get the JSON response
|
|
187
|
+
response_data = response.json()
|
|
188
|
+
if 'error' in response_data:
|
|
189
|
+
print("Invalid Query: ", response_data['error'])
|
|
190
|
+
return None
|
|
191
|
+
|
|
192
|
+
# Extract meta information
|
|
193
|
+
meta_info = response_data.get('meta', {})
|
|
194
|
+
meta_info = meta_info.get('results', {})
|
|
195
|
+
|
|
196
|
+
# Extract results and return only the specified return fields
|
|
197
|
+
results = response_data.get('results', [])
|
|
198
|
+
if return_fields == 'ALL':
|
|
199
|
+
return {
|
|
200
|
+
'meta': meta_info,
|
|
201
|
+
'results': results
|
|
202
|
+
}
|
|
203
|
+
required_fields = list(search_fields.keys()) + return_fields
|
|
204
|
+
extracted_results = extract_nested_fields(
|
|
205
|
+
results, required_fields, keywords_list)
|
|
206
|
+
return {
|
|
207
|
+
'meta': meta_info,
|
|
208
|
+
'results': extracted_results
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class FDATool(BaseTool):
|
|
213
|
+
def __init__(self, tool_config, endpoint_url, api_key=None):
|
|
214
|
+
super().__init__(tool_config)
|
|
215
|
+
fields = tool_config['fields']
|
|
216
|
+
self.search_fields = fields.get('search_fields', {})
|
|
217
|
+
self.return_fields = fields.get('return_fields', [])
|
|
218
|
+
self.exists = fields.get('exists', None)
|
|
219
|
+
if self.exists is None:
|
|
220
|
+
self.exists = self.return_fields
|
|
221
|
+
self.endpoint_url = endpoint_url
|
|
222
|
+
self.api_key = api_key
|
|
223
|
+
|
|
224
|
+
def run(self, arguments):
|
|
225
|
+
arguments = copy.deepcopy(arguments)
|
|
226
|
+
mapped_arguments = map_properties_to_openfda_fields(
|
|
227
|
+
arguments, self.search_fields)
|
|
228
|
+
return search_openfda(mapped_arguments,
|
|
229
|
+
endpoint_url=self.endpoint_url,
|
|
230
|
+
api_key=self.api_key,
|
|
231
|
+
exists=self.exists,
|
|
232
|
+
return_fields=self.return_fields, exist_option='OR')
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class FDADrugLabelTool(FDATool):
|
|
236
|
+
def __init__(self, tool_config, api_key=None):
|
|
237
|
+
endpoint_url = 'https://api.fda.gov/drug/label.json'
|
|
238
|
+
super().__init__(tool_config, endpoint_url, api_key)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class FDADrugLabelSearchTool(FDATool):
|
|
242
|
+
def __init__(self, tool_config=None, api_key=None):
|
|
243
|
+
self.tool_config = {
|
|
244
|
+
"name": "FDADrugLabelSearch",
|
|
245
|
+
"description": "Retrieve information of a specific drug.",
|
|
246
|
+
"label": ["search", "drug"],
|
|
247
|
+
"type": "FDADrugLabelSearch",
|
|
248
|
+
"parameter": {
|
|
249
|
+
"type": "object",
|
|
250
|
+
"properties": {
|
|
251
|
+
"drug_name": {
|
|
252
|
+
"type": "string",
|
|
253
|
+
"description": "The name of the drug.",
|
|
254
|
+
"required": True
|
|
255
|
+
},
|
|
256
|
+
"return_fields": {
|
|
257
|
+
"type": "array",
|
|
258
|
+
"items": {
|
|
259
|
+
"type": "string",
|
|
260
|
+
"enum": ['ALL', 'abuse', 'accessories', 'active_ingredient', 'adverse_reactions', 'alarms', 'animal_pharmacology_and_or_toxicology', 'ask_doctor', 'ask_doctor_or_pharmacist', 'assembly_or_installation_instructions', 'boxed_warning', 'calibration_instructions', 'carcinogenesis_and_mutagenesis_and_impairment_of_fertility', 'cleaning', 'clinical_pharmacology', 'clinical_studies', 'compatible_accessories', 'components', 'contraindications', 'controlled_substance', 'dependence', 'description', 'diagram_of_device', 'disposal_and_waste_handling', 'do_not_use', 'dosage_and_administration', 'dosage_forms_and_strengths', 'drug_abuse_and_dependence', 'drug_and_or_laboratory_test_interactions', 'drug_interactions', 'effective_time', 'environmental_warning', 'food_safety_warning', 'general_precautions', 'geriatric_use', 'guaranteed_analysis_of_feed', 'health_care_provider_letter', 'health_claim', 'how_supplied', 'id', 'inactive_ingredient', 'indications_and_usage', 'information_for_owners_or_caregivers', 'information_for_patients', 'instructions_for_use', 'intended_use_of_the_device', 'keep_out_of_reach_of_children', 'labor_and_delivery', 'laboratory_tests', 'mechanism_of_action', 'microbiology', 'nonclinical_toxicology', 'nonteratogenic_effects', 'nursing_mothers', 'openfda', 'other_safety_information', 'overdosage', 'package_label_principal_display_panel', 'patient_medication_information', 'pediatric_use', 'pharmacodynamics', 'pharmacogenomics', 'pharmacokinetics', 'precautions', 'pregnancy', 'pregnancy_or_breast_feeding', 'purpose', 'questions', 'recent_major_changes', 'references', 'residue_warning', 'risks', 'route', 'safe_handling_warning', 'set_id', 'spl_indexing_data_elements', 'spl_medguide', 'spl_patient_package_insert', 'spl_product_data_elements', 'spl_unclassified_section', 'statement_of_identity', 'stop_use', 'storage_and_handling', 'summary_of_safety_and_effectiveness', 'teratogenic_effects', 'troubleshooting', 'use_in_specific_populations', 'user_safety_warnings', 'version', 'warnings', 'warnings_and_cautions', 'when_using', 'meta'],
|
|
261
|
+
"description": "Searchable field."
|
|
262
|
+
},
|
|
263
|
+
"description": "Fields to search within drug labels.",
|
|
264
|
+
"required": True
|
|
265
|
+
},
|
|
266
|
+
"limit": {
|
|
267
|
+
"type": "integer",
|
|
268
|
+
"description": "The number of records to return.",
|
|
269
|
+
"required": False
|
|
270
|
+
},
|
|
271
|
+
"skip": {
|
|
272
|
+
"type": "integer",
|
|
273
|
+
"description": "The number of records to skip.",
|
|
274
|
+
"required": False
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
"fields": {
|
|
279
|
+
"search_fields": {
|
|
280
|
+
"drug_name": ["openfda.brand_name", "openfda.generic_name"]
|
|
281
|
+
},
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
endpoint_url = 'https://api.fda.gov/drug/label.json'
|
|
285
|
+
super().__init__(self.tool_config, endpoint_url, api_key)
|
|
286
|
+
|
|
287
|
+
def run(self, arguments):
|
|
288
|
+
arguments = copy.deepcopy(arguments)
|
|
289
|
+
mapped_arguments = map_properties_to_openfda_fields(
|
|
290
|
+
arguments, self.search_fields)
|
|
291
|
+
return_fields = arguments['return_fields']
|
|
292
|
+
del arguments['return_fields']
|
|
293
|
+
return search_openfda(mapped_arguments,
|
|
294
|
+
endpoint_url=self.endpoint_url,
|
|
295
|
+
api_key=self.api_key,
|
|
296
|
+
return_fields=return_fields, exists=return_fields, exist_option='OR')
|
|
297
|
+
|
|
298
|
+
class FDADrugLabelSearchIDTool(FDATool):
|
|
299
|
+
def __init__(self, tool_config=None, api_key=None):
|
|
300
|
+
self.tool_config = {
|
|
301
|
+
"name": "FDADrugLabelSearchALLTool",
|
|
302
|
+
"description": "Retrieve any related information to the query.",
|
|
303
|
+
"label": ["search", "drug"],
|
|
304
|
+
"type": "FDADrugLabelSearch",
|
|
305
|
+
"parameter": {
|
|
306
|
+
"type": "object",
|
|
307
|
+
"properties": {
|
|
308
|
+
"query": {
|
|
309
|
+
"type": "string",
|
|
310
|
+
"description": "key words need to be searched.",
|
|
311
|
+
"required": True
|
|
312
|
+
},
|
|
313
|
+
"return_fields": {
|
|
314
|
+
"type": "array",
|
|
315
|
+
"items": {
|
|
316
|
+
"type": "string",
|
|
317
|
+
"enum": ['ALL', 'abuse', 'accessories', 'active_ingredient', 'adverse_reactions', 'alarms', 'animal_pharmacology_and_or_toxicology', 'ask_doctor', 'ask_doctor_or_pharmacist', 'assembly_or_installation_instructions', 'boxed_warning', 'calibration_instructions', 'carcinogenesis_and_mutagenesis_and_impairment_of_fertility', 'cleaning', 'clinical_pharmacology', 'clinical_studies', 'compatible_accessories', 'components', 'contraindications', 'controlled_substance', 'dependence', 'description', 'diagram_of_device', 'disposal_and_waste_handling', 'do_not_use', 'dosage_and_administration', 'dosage_forms_and_strengths', 'drug_abuse_and_dependence', 'drug_and_or_laboratory_test_interactions', 'drug_interactions', 'effective_time', 'environmental_warning', 'food_safety_warning', 'general_precautions', 'geriatric_use', 'guaranteed_analysis_of_feed', 'health_care_provider_letter', 'health_claim', 'how_supplied', 'id', 'inactive_ingredient', 'indications_and_usage', 'information_for_owners_or_caregivers', 'information_for_patients', 'instructions_for_use', 'intended_use_of_the_device', 'keep_out_of_reach_of_children', 'labor_and_delivery', 'laboratory_tests', 'mechanism_of_action', 'microbiology', 'nonclinical_toxicology', 'nonteratogenic_effects', 'nursing_mothers', 'openfda', 'other_safety_information', 'overdosage', 'package_label_principal_display_panel', 'patient_medication_information', 'pediatric_use', 'pharmacodynamics', 'pharmacogenomics', 'pharmacokinetics', 'precautions', 'pregnancy', 'pregnancy_or_breast_feeding', 'purpose', 'questions', 'recent_major_changes', 'references', 'residue_warning', 'risks', 'route', 'safe_handling_warning', 'set_id', 'spl_indexing_data_elements', 'spl_medguide', 'spl_patient_package_insert', 'spl_product_data_elements', 'spl_unclassified_section', 'statement_of_identity', 'stop_use', 'storage_and_handling', 'summary_of_safety_and_effectiveness', 'teratogenic_effects', 'troubleshooting', 'use_in_specific_populations', 'user_safety_warnings', 'version', 'warnings', 'warnings_and_cautions', 'when_using', 'meta'],
|
|
318
|
+
"description": "Searchable field."
|
|
319
|
+
},
|
|
320
|
+
"description": "Fields to search within drug labels.",
|
|
321
|
+
"required": True
|
|
322
|
+
},
|
|
323
|
+
"limit": {
|
|
324
|
+
"type": "integer",
|
|
325
|
+
"description": "The number of records to return.",
|
|
326
|
+
"required": False
|
|
327
|
+
},
|
|
328
|
+
"skip": {
|
|
329
|
+
"type": "integer",
|
|
330
|
+
"description": "The number of records to skip.",
|
|
331
|
+
"required": False
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
"fields": {
|
|
336
|
+
"search_fields": {
|
|
337
|
+
"query": ['id']
|
|
338
|
+
},
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
endpoint_url = 'https://api.fda.gov/drug/label.json'
|
|
342
|
+
super().__init__(self.tool_config, endpoint_url, api_key)
|
|
343
|
+
|
|
344
|
+
def run(self, arguments):
|
|
345
|
+
arguments = copy.deepcopy(arguments)
|
|
346
|
+
mapped_arguments = map_properties_to_openfda_fields(
|
|
347
|
+
arguments, self.search_fields)
|
|
348
|
+
return_fields = arguments['return_fields']
|
|
349
|
+
del arguments['return_fields']
|
|
350
|
+
return search_openfda(mapped_arguments,
|
|
351
|
+
endpoint_url=self.endpoint_url,
|
|
352
|
+
api_key=self.api_key,
|
|
353
|
+
return_fields=return_fields, exists=return_fields, exist_option='OR')
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
class FDADrugLabelGetDrugGenericNameTool(FDADrugLabelTool):
|
|
357
|
+
def __init__(self, tool_config=None, api_key=None):
|
|
358
|
+
|
|
359
|
+
if tool_config is None:
|
|
360
|
+
tool_config = {
|
|
361
|
+
"name": "get_drug_generic_name",
|
|
362
|
+
"description": "Get the drug’s generic name based on the drug's generic or brand name.",
|
|
363
|
+
"parameter": {
|
|
364
|
+
"type": "object",
|
|
365
|
+
"properties": {
|
|
366
|
+
"drug_name": {
|
|
367
|
+
"type": "string",
|
|
368
|
+
"description": "The generic or brand name of the drug.",
|
|
369
|
+
"required": True
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
"fields": {
|
|
374
|
+
"search_fields": {
|
|
375
|
+
"drug_name": [
|
|
376
|
+
"openfda.brand_name",
|
|
377
|
+
"openfda.generic_name"
|
|
378
|
+
]
|
|
379
|
+
},
|
|
380
|
+
"return_fields": [
|
|
381
|
+
"openfda.generic_name"
|
|
382
|
+
]
|
|
383
|
+
},
|
|
384
|
+
"type": "FDADrugLabelGetDrugGenericNameTool",
|
|
385
|
+
"label": [
|
|
386
|
+
"FDADrugLabel",
|
|
387
|
+
"purpose",
|
|
388
|
+
"FDA"
|
|
389
|
+
]
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
from data.fda_drugs_with_brand_generic_names_for_tool import drug_list
|
|
394
|
+
|
|
395
|
+
self.brand_to_generic = {drug['brand_name']: drug['generic_name'] for drug in drug_list}
|
|
396
|
+
self.generic_to_brand = {drug['generic_name']: drug['brand_name'] for drug in drug_list}
|
|
397
|
+
|
|
398
|
+
super().__init__(tool_config, api_key)
|
|
399
|
+
|
|
400
|
+
def run(self, arguments):
|
|
401
|
+
|
|
402
|
+
drug_info = {}
|
|
403
|
+
|
|
404
|
+
drug_name = arguments.get('drug_name')
|
|
405
|
+
if '-' in drug_name:
|
|
406
|
+
drug_name = drug_name.split('-')[0] # to handle some drug names such as tarlatamab-dlle
|
|
407
|
+
if drug_name in self.brand_to_generic:
|
|
408
|
+
drug_info['openfda.generic_name'] = self.brand_to_generic[drug_name]
|
|
409
|
+
drug_info['openfda.brand_name'] = drug_name
|
|
410
|
+
elif drug_name in self.generic_to_brand:
|
|
411
|
+
drug_info['openfda.brand_name'] = self.generic_to_brand[drug_name]
|
|
412
|
+
drug_info['openfda.generic_name'] = drug_name
|
|
413
|
+
else:
|
|
414
|
+
results = super().run(arguments)
|
|
415
|
+
if results is not None:
|
|
416
|
+
drug_info['openfda.generic_name'] = results['results'][0]['openfda.generic_name'][0]
|
|
417
|
+
drug_info['openfda.brand_name'] = results['results'][0]['openfda.brand_name'][0]
|
|
418
|
+
print("drug_info", drug_info)
|
|
419
|
+
else:
|
|
420
|
+
drug_info = None
|
|
421
|
+
return drug_info
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from .graphql_tool import GraphQLTool
|
|
2
|
+
import requests
|
|
3
|
+
import copy
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
def execute_RESTful_query(endpoint_url, variables=None):
|
|
7
|
+
response = requests.get(
|
|
8
|
+
endpoint_url, params = variables)
|
|
9
|
+
try:
|
|
10
|
+
result = response.json()
|
|
11
|
+
|
|
12
|
+
# Check if the response contains errors
|
|
13
|
+
if 'error' in result:
|
|
14
|
+
print("Invalid Query: ", result['error'])
|
|
15
|
+
return False
|
|
16
|
+
else:
|
|
17
|
+
return result
|
|
18
|
+
except requests.exceptions.JSONDecodeError as e:
|
|
19
|
+
print("JSONDecodeError: Could not decode the response as JSON")
|
|
20
|
+
return False
|
|
21
|
+
except requests.exceptions.HTTPError as e:
|
|
22
|
+
print(f"HTTP error occurred: {e}")
|
|
23
|
+
except Exception as e:
|
|
24
|
+
print(f"An error occurred: {e}")
|
|
25
|
+
|
|
26
|
+
class RESTfulTool(GraphQLTool):
|
|
27
|
+
def __init__(self, tool_config, endpoint_url):
|
|
28
|
+
super().__init__(tool_config, endpoint_url)
|
|
29
|
+
|
|
30
|
+
def run(self, arguments):
|
|
31
|
+
arguments = copy.deepcopy(arguments)
|
|
32
|
+
return execute_RESTful_query(endpoint_url=self.endpoint_url, variables=arguments)
|
|
33
|
+
|
|
34
|
+
class MonarchTool(RESTfulTool):
|
|
35
|
+
def __init__(self, tool_config):
|
|
36
|
+
endpoint_url = 'https://api.monarchinitiative.org/v3/api' + tool_config['tool_url']
|
|
37
|
+
super().__init__(tool_config, endpoint_url)
|
|
38
|
+
|
|
39
|
+
def run(self, arguments):
|
|
40
|
+
arguments = copy.deepcopy(arguments)
|
|
41
|
+
query_schema_runtime = copy.deepcopy(self.query_schema)
|
|
42
|
+
for key in query_schema_runtime:
|
|
43
|
+
if key in arguments:
|
|
44
|
+
query_schema_runtime[key] = arguments[key]
|
|
45
|
+
if "url_key" in query_schema_runtime:
|
|
46
|
+
url_key_name = query_schema_runtime['url_key']
|
|
47
|
+
formatted_endpoint_url = self.endpoint_url.format(url_key = query_schema_runtime[url_key_name])
|
|
48
|
+
del query_schema_runtime['url_key']
|
|
49
|
+
else:
|
|
50
|
+
formatted_endpoint_url = self.endpoint_url
|
|
51
|
+
if isinstance(query_schema_runtime, dict):
|
|
52
|
+
print(query_schema_runtime)
|
|
53
|
+
if 'query' in query_schema_runtime:
|
|
54
|
+
query_schema_runtime['q'] = query_schema_runtime['query'] # match with the api
|
|
55
|
+
response = execute_RESTful_query(endpoint_url=formatted_endpoint_url, variables=query_schema_runtime)
|
|
56
|
+
if 'facet_fields' in response:
|
|
57
|
+
del response['facet_fields']
|
|
58
|
+
def remove_empty_values(obj):
|
|
59
|
+
if isinstance(obj, dict):
|
|
60
|
+
return {k: remove_empty_values(v) for k, v in obj.items()
|
|
61
|
+
if v not in [0, [], None]}
|
|
62
|
+
elif isinstance(obj, list):
|
|
63
|
+
return [remove_empty_values(v) for v in obj if v not in [0, [], None]]
|
|
64
|
+
else:
|
|
65
|
+
return obj
|
|
66
|
+
response = remove_empty_values(response)
|
|
67
|
+
return response
|
|
68
|
+
|
|
69
|
+
class MonarchDiseasesForMultiplePhenoTool(MonarchTool):
|
|
70
|
+
def __init__(self, tool_config):
|
|
71
|
+
super().__init__(tool_config)
|
|
72
|
+
|
|
73
|
+
def run(self, arguments):
|
|
74
|
+
arguments = copy.deepcopy(arguments)
|
|
75
|
+
query_schema_runtime = copy.deepcopy(self.query_schema)
|
|
76
|
+
for key in query_schema_runtime:
|
|
77
|
+
if (key!="HPO_ID_list") and (key in arguments):
|
|
78
|
+
query_schema_runtime[key] = arguments[key]
|
|
79
|
+
all_diseases = []
|
|
80
|
+
for HPOID in arguments['HPO_ID_list']:
|
|
81
|
+
each_query_schema_runtime = copy.deepcopy(query_schema_runtime)
|
|
82
|
+
each_query_schema_runtime['object'] = HPOID
|
|
83
|
+
each_query_schema_runtime['limit'] = 500
|
|
84
|
+
each_output = execute_RESTful_query(endpoint_url=self.endpoint_url, variables=each_query_schema_runtime)
|
|
85
|
+
each_output = each_output['items']
|
|
86
|
+
each_output_names = [disease['subject_label'] for disease in each_output]
|
|
87
|
+
all_diseases.append(each_output_names)
|
|
88
|
+
|
|
89
|
+
intersection = set(all_diseases[0])
|
|
90
|
+
for element in all_diseases[1:]:
|
|
91
|
+
intersection &= set(element)
|
|
92
|
+
intersection = list(intersection)
|
|
93
|
+
if query_schema_runtime['limit'] < len(intersection):
|
|
94
|
+
intersection = intersection[:query_schema_runtime['limit']]
|
|
95
|
+
return intersection
|