History

OpenScience: an open-source AI research agent for the browser

A model-agnostic AI co-scientist for ML engineering and scientific research. Give it a goal and it reads the literature, writes and runs code, runs experiments, and writes up results. Run `openscience` to open the workspace in your browser. Bring your own API key from any provider, or use Atlas for managed models and compute. Built with Bun and TypeScript. Apache License 2.0.

ishaan1124 committed 4 months ago

Commit 79c26bcNo parent (first commit)3865 files · +912032 −-100Browse files

Showing the changes to backend/cli/skills/databases/string-database/scripts/string_api.py (1 of 3865 files). Show all

Unified · Split

backend/cli/skills/databases/string-database/scripts/string_api.py+369−0
@@ -0,0 +1,369 @@
1+"""
2+STRING Database REST API Helper Functions
3+
4+This module provides Python functions for interacting with the STRING database API.
5+All functions return raw response text or JSON which can be parsed as needed.
6+
7+API Base URL: https://string-db.org/api
8+Documentation: https://string-db.org/help/api/
9+
10+STRING provides protein-protein interaction data from over 40 sources covering
11+5000+ genomes with ~59.3 million proteins and 20+ billion interactions.
12+"""
13+
14+import urllib.request
15+import urllib.parse
16+import urllib.error
17+import json
18+from typing import Optional, List, Union, Dict
19+
20+
21+STRING_BASE_URL = "https://string-db.org/api"
22+
23+
24+def string_map_ids(identifiers: Union[str, List[str]],
25+ species: int = 9606,
26+ limit: int = 1,
27+ echo_query: int = 1,
28+ caller_identity: str = "claude_scientific_skills") -> str:
29+ """
30+ Map protein names, synonyms, and identifiers to STRING IDs.
31+
32+ Args:
33+ identifiers: Single protein identifier or list of identifiers
34+ species: NCBI taxon ID (default: 9606 for human)
35+ limit: Number of matches to return per identifier (default: 1)
36+ echo_query: Include query term in output (1) or not (0)
37+ caller_identity: Application identifier for tracking
38+
39+ Returns:
40+ str: TSV format with mapping results
41+
42+ Examples:
43+ # Map single protein
44+ result = string_map_ids('TP53', species=9606)
45+
46+ # Map multiple proteins
47+ result = string_map_ids(['TP53', 'BRCA1', 'EGFR'], species=9606)
48+ """
49+ if isinstance(identifiers, list):
50+ identifiers_str = '\n'.join(identifiers)
51+ else:
52+ identifiers_str = identifiers
53+
54+ params = {
55+ 'identifiers': identifiers_str,
56+ 'species': species,
57+ 'limit': limit,
58+ 'echo_query': echo_query,
59+ 'caller_identity': caller_identity
60+ }
61+
62+ url = f"{STRING_BASE_URL}/tsv/get_string_ids"
63+ data = urllib.parse.urlencode(params).encode('utf-8')
64+
65+ try:
66+ with urllib.request.urlopen(url, data=data) as response:
67+ return response.read().decode('utf-8')
68+ except urllib.error.HTTPError as e:
69+ return f"Error: {e.code} - {e.reason}"
70+
71+
72+def string_network(identifiers: Union[str, List[str]],
73+ species: int = 9606,
74+ required_score: int = 400,
75+ network_type: str = "functional",
76+ add_nodes: int = 0,
77+ caller_identity: str = "claude_scientific_skills") -> str:
78+ """
79+ Get protein-protein interaction network data.
80+
81+ Args:
82+ identifiers: Protein identifier(s) - use STRING IDs for best results
83+ species: NCBI taxon ID (default: 9606 for human)
84+ required_score: Confidence threshold 0-1000 (default: 400 = medium confidence)
85+ network_type: 'functional' or 'physical' (default: functional)
86+ add_nodes: Number of additional nodes to add to network (0-10)
87+ caller_identity: Application identifier for tracking
88+
89+ Returns:
90+ str: TSV format with interaction data
91+
92+ Examples:
93+ # Get network for single protein
94+ network = string_network('9606.ENSP00000269305')
95+
96+ # Get network with multiple proteins
97+ network = string_network(['9606.ENSP00000269305', '9606.ENSP00000275493'])
98+
99+ # Get network with additional interacting proteins
100+ network = string_network('TP53', add_nodes=5, required_score=700)
101+ """
102+ if isinstance(identifiers, list):
103+ identifiers_str = '%0d'.join(identifiers)
104+ else:
105+ identifiers_str = identifiers
106+
107+ params = {
108+ 'identifiers': identifiers_str,
109+ 'species': species,
110+ 'required_score': required_score,
111+ 'network_type': network_type,
112+ 'add_nodes': add_nodes,
113+ 'caller_identity': caller_identity
114+ }
115+
116+ url = f"{STRING_BASE_URL}/tsv/network?" + urllib.parse.urlencode(params)
117+
118+ try:
119+ with urllib.request.urlopen(url) as response:
120+ return response.read().decode('utf-8')
121+ except urllib.error.HTTPError as e:
122+ return f"Error: {e.code} - {e.reason}"
123+
124+
125+def string_network_image(identifiers: Union[str, List[str]],
126+ species: int = 9606,
127+ required_score: int = 400,
128+ network_flavor: str = "evidence",
129+ add_nodes: int = 0,
130+ caller_identity: str = "claude_scientific_skills") -> bytes:
131+ """
132+ Get network visualization as PNG image.
133+
134+ Args:
135+ identifiers: Protein identifier(s)
136+ species: NCBI taxon ID (default: 9606 for human)
137+ required_score: Confidence threshold 0-1000 (default: 400)
138+ network_flavor: 'evidence', 'confidence', or 'actions' (default: evidence)
139+ add_nodes: Number of additional nodes to add (0-10)
140+ caller_identity: Application identifier for tracking
141+
142+ Returns:
143+ bytes: PNG image data
144+
145+ Example:
146+ # Get network image
147+ img_data = string_network_image(['TP53', 'MDM2', 'ATM'])
148+ with open('network.png', 'wb') as f:
149+ f.write(img_data)
150+ """
151+ if isinstance(identifiers, list):
152+ identifiers_str = '%0d'.join(identifiers)
153+ else:
154+ identifiers_str = identifiers
155+
156+ params = {
157+ 'identifiers': identifiers_str,
158+ 'species': species,
159+ 'required_score': required_score,
160+ 'network_flavor': network_flavor,
161+ 'add_nodes': add_nodes,
162+ 'caller_identity': caller_identity
163+ }
164+
165+ url = f"{STRING_BASE_URL}/image/network?" + urllib.parse.urlencode(params)
166+
167+ try:
168+ with urllib.request.urlopen(url) as response:
169+ return response.read()
170+ except urllib.error.HTTPError as e:
171+ return f"Error: {e.code} - {e.reason}".encode()
172+
173+
174+def string_interaction_partners(identifiers: Union[str, List[str]],
175+ species: int = 9606,
176+ required_score: int = 400,
177+ limit: int = 10,
178+ caller_identity: str = "claude_scientific_skills") -> str:
179+ """
180+ Get all interaction partners for protein(s).
181+
182+ Args:
183+ identifiers: Protein identifier(s)
184+ species: NCBI taxon ID (default: 9606 for human)
185+ required_score: Confidence threshold 0-1000 (default: 400)
186+ limit: Maximum number of partners to return (default: 10)
187+ caller_identity: Application identifier for tracking
188+
189+ Returns:
190+ str: TSV format with interaction partners
191+
192+ Example:
193+ # Get top 20 interactors of TP53
194+ partners = string_interaction_partners('TP53', limit=20, required_score=700)
195+ """
196+ if isinstance(identifiers, list):
197+ identifiers_str = '%0d'.join(identifiers)
198+ else:
199+ identifiers_str = identifiers
200+
201+ params = {
202+ 'identifiers': identifiers_str,
203+ 'species': species,
204+ 'required_score': required_score,
205+ 'limit': limit,
206+ 'caller_identity': caller_identity
207+ }
208+
209+ url = f"{STRING_BASE_URL}/tsv/interaction_partners?" + urllib.parse.urlencode(params)
210+
211+ try:
212+ with urllib.request.urlopen(url) as response:
213+ return response.read().decode('utf-8')
214+ except urllib.error.HTTPError as e:
215+ return f"Error: {e.code} - {e.reason}"
216+
217+
218+def string_enrichment(identifiers: Union[str, List[str]],
219+ species: int = 9606,
220+ caller_identity: str = "claude_scientific_skills") -> str:
221+ """
222+ Perform functional enrichment analysis (Gene Ontology, KEGG, Pfam, etc.).
223+
224+ Args:
225+ identifiers: List of protein identifiers
226+ species: NCBI taxon ID (default: 9606 for human)
227+ caller_identity: Application identifier for tracking
228+
229+ Returns:
230+ str: TSV format with enrichment results
231+
232+ Example:
233+ # Enrichment for a list of proteins
234+ proteins = ['TP53', 'MDM2', 'ATM', 'CHEK2', 'BRCA1']
235+ enrichment = string_enrichment(proteins, species=9606)
236+ """
237+ if isinstance(identifiers, list):
238+ identifiers_str = '%0d'.join(identifiers)
239+ else:
240+ identifiers_str = identifiers
241+
242+ params = {
243+ 'identifiers': identifiers_str,
244+ 'species': species,
245+ 'caller_identity': caller_identity
246+ }
247+
248+ url = f"{STRING_BASE_URL}/tsv/enrichment?" + urllib.parse.urlencode(params)
249+
250+ try:
251+ with urllib.request.urlopen(url) as response:
252+ return response.read().decode('utf-8')
253+ except urllib.error.HTTPError as e:
254+ return f"Error: {e.code} - {e.reason}"
255+
256+
257+def string_ppi_enrichment(identifiers: Union[str, List[str]],
258+ species: int = 9606,
259+ required_score: int = 400,
260+ caller_identity: str = "claude_scientific_skills") -> str:
261+ """
262+ Test if network has more interactions than expected by chance.
263+
264+ Args:
265+ identifiers: List of protein identifiers
266+ species: NCBI taxon ID (default: 9606 for human)
267+ required_score: Confidence threshold 0-1000 (default: 400)
268+ caller_identity: Application identifier for tracking
269+
270+ Returns:
271+ str: JSON with PPI enrichment p-value
272+
273+ Example:
274+ # Test if proteins are more connected than random
275+ proteins = ['TP53', 'MDM2', 'ATM', 'CHEK2']
276+ ppi_result = string_ppi_enrichment(proteins)
277+ """
278+ if isinstance(identifiers, list):
279+ identifiers_str = '%0d'.join(identifiers)
280+ else:
281+ identifiers_str = identifiers
282+
283+ params = {
284+ 'identifiers': identifiers_str,
285+ 'species': species,
286+ 'required_score': required_score,
287+ 'caller_identity': caller_identity
288+ }
289+
290+ url = f"{STRING_BASE_URL}/json/ppi_enrichment?" + urllib.parse.urlencode(params)
291+
292+ try:
293+ with urllib.request.urlopen(url) as response:
294+ return response.read().decode('utf-8')
295+ except urllib.error.HTTPError as e:
296+ return f"Error: {e.code} - {e.reason}"
297+
298+
299+def string_homology(identifiers: Union[str, List[str]],
300+ species: int = 9606,
301+ caller_identity: str = "claude_scientific_skills") -> str:
302+ """
303+ Get homology/similarity scores between proteins.
304+
305+ Args:
306+ identifiers: Protein identifier(s)
307+ species: NCBI taxon ID (default: 9606 for human)
308+ caller_identity: Application identifier for tracking
309+
310+ Returns:
311+ str: TSV format with homology scores
312+
313+ Example:
314+ # Get homology data
315+ homology = string_homology(['TP53', 'TP63', 'TP73'])
316+ """
317+ if isinstance(identifiers, list):
318+ identifiers_str = '%0d'.join(identifiers)
319+ else:
320+ identifiers_str = identifiers
321+
322+ params = {
323+ 'identifiers': identifiers_str,
324+ 'species': species,
325+ 'caller_identity': caller_identity
326+ }
327+
328+ url = f"{STRING_BASE_URL}/tsv/homology?" + urllib.parse.urlencode(params)
329+
330+ try:
331+ with urllib.request.urlopen(url) as response:
332+ return response.read().decode('utf-8')
333+ except urllib.error.HTTPError as e:
334+ return f"Error: {e.code} - {e.reason}"
335+
336+
337+def string_version() -> str:
338+ """
339+ Get current STRING database version.
340+
341+ Returns:
342+ str: Version information
343+
344+ Example:
345+ version = string_version()
346+ """
347+ url = f"{STRING_BASE_URL}/tsv/version"
348+
349+ try:
350+ with urllib.request.urlopen(url) as response:
351+ return response.read().decode('utf-8')
352+ except urllib.error.HTTPError as e:
353+ return f"Error: {e.code} - {e.reason}"
354+
355+
356+if __name__ == "__main__":
357+ # Example usage
358+ print("STRING Version:")
359+ print(string_version())
360+ print()
361+
362+ print("Mapping protein names to STRING IDs:")
363+ mapping = string_map_ids(['TP53', 'BRCA1'], species=9606)
364+ print(mapping)
365+ print()
366+
367+ print("Getting interaction network:")
368+ network = string_network('TP53', species=9606, add_nodes=3)
369+ print(network[:500] + "...")