jupyterlab-biolm 1.2.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.
- jupyterlab_biolm/__init__.py +23 -0
- jupyterlab_biolm/_hatchling.py +37 -0
- jupyterlab_biolm/serverextension.py +318 -0
- jupyterlab_biolm-1.2.0.data/data/etc/jupyter/jupyter_server_config.d/jupyterlab-biolm.json +8 -0
- jupyterlab_biolm-1.2.0.data/data/share/jupyter/lab/schemas/jupyterlab-biolm/plugin.json +49 -0
- jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/install.json +5 -0
- jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/package.json +124 -0
- jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/schemas/jupyterlab-biolm/package.json.orig +119 -0
- jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/schemas/jupyterlab-biolm/plugin.json +49 -0
- jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/462.26eef2cc68d48d263539.js +1 -0
- jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/665.57bb7975881a83531c46.js +1 -0
- jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/remoteEntry.8d19a58608019bf31dd9.js +1 -0
- jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/style.js +4 -0
- jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/third-party-licenses.json +22 -0
- jupyterlab_biolm-1.2.0.dist-info/METADATA +169 -0
- jupyterlab_biolm-1.2.0.dist-info/RECORD +17 -0
- jupyterlab_biolm-1.2.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BioLM JupyterLab Extension
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
def _jupyter_labextension_paths():
|
|
6
|
+
"""Called by Jupyter Lab Server to detect if it is a valid labextension and
|
|
7
|
+
to install the widget
|
|
8
|
+
|
|
9
|
+
Returns
|
|
10
|
+
=======
|
|
11
|
+
src: Source directory name to copy files from. Webpack outputs generated files
|
|
12
|
+
into this directory and Jupyter Lab copies from this directory during
|
|
13
|
+
widget installation
|
|
14
|
+
"""
|
|
15
|
+
return [{"src": "labextension", "dest": "jupyterlab-biolm"}]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _jupyter_server_extension_points():
|
|
19
|
+
"""Return server extension points - this enables auto-discovery in Jupyter Server 2.x"""
|
|
20
|
+
return [{
|
|
21
|
+
'module': 'jupyterlab_biolm.serverextension',
|
|
22
|
+
}]
|
|
23
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Hatchling build hook to include labextension files
|
|
3
|
+
"""
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_shared_data():
|
|
8
|
+
"""Return shared-data mapping for labextension files"""
|
|
9
|
+
root = Path(__file__).parent.parent
|
|
10
|
+
shared_data = {}
|
|
11
|
+
|
|
12
|
+
# Add labextension directory recursively
|
|
13
|
+
labextension_dir = root / "jupyterlab_biolm" / "labextension"
|
|
14
|
+
if labextension_dir.exists():
|
|
15
|
+
for file_path in labextension_dir.rglob("*"):
|
|
16
|
+
if file_path.is_file():
|
|
17
|
+
rel_path = file_path.relative_to(labextension_dir)
|
|
18
|
+
source = f"jupyterlab_biolm/labextension/{rel_path}"
|
|
19
|
+
dest = f"share/jupyter/labextensions/jupyterlab-biolm/{rel_path}"
|
|
20
|
+
shared_data[source] = dest
|
|
21
|
+
|
|
22
|
+
# Add install.json
|
|
23
|
+
install_json = root / "install.json"
|
|
24
|
+
if install_json.exists():
|
|
25
|
+
shared_data["install.json"] = "share/jupyter/labextensions/jupyterlab-biolm/install.json"
|
|
26
|
+
|
|
27
|
+
# Add schema files
|
|
28
|
+
schema_dir = root / "schema"
|
|
29
|
+
if schema_dir.exists():
|
|
30
|
+
for file_path in schema_dir.glob("*.json"):
|
|
31
|
+
rel_path = file_path.relative_to(schema_dir)
|
|
32
|
+
source = f"schema/{rel_path}"
|
|
33
|
+
dest = f"share/jupyter/lab/schemas/jupyterlab-biolm/{rel_path}"
|
|
34
|
+
shared_data[source] = dest
|
|
35
|
+
|
|
36
|
+
return shared_data
|
|
37
|
+
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"""
|
|
2
|
+
JupyterLab Server Extension for BioLM API Proxy
|
|
3
|
+
This server extension provides API endpoints to proxy requests to the BioLM API,
|
|
4
|
+
avoiding CORS issues by making requests from the server side.
|
|
5
|
+
"""
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
from typing import Optional
|
|
9
|
+
from urllib.request import Request, urlopen
|
|
10
|
+
from urllib.error import HTTPError, URLError
|
|
11
|
+
|
|
12
|
+
from jupyter_server.base.handlers import APIHandler
|
|
13
|
+
from jupyter_server.utils import url_path_join
|
|
14
|
+
from jupyter_server.base.handlers import JupyterHandler
|
|
15
|
+
import tornado
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BioLMModelsHandler(APIHandler):
|
|
19
|
+
"""Handler for fetching BioLM models"""
|
|
20
|
+
|
|
21
|
+
# Disable XSRF for API endpoints
|
|
22
|
+
def check_xsrf_cookie(self):
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
@tornado.web.authenticated
|
|
26
|
+
def get(self):
|
|
27
|
+
"""Fetch models from BioLM API"""
|
|
28
|
+
try:
|
|
29
|
+
# Get API key from Authorization header or query parameter
|
|
30
|
+
api_key = None
|
|
31
|
+
auth_header = self.request.headers.get('Authorization', '')
|
|
32
|
+
if auth_header.startswith('Bearer '):
|
|
33
|
+
api_key = auth_header[7:]
|
|
34
|
+
else:
|
|
35
|
+
api_key = self.get_query_argument('api_key', None)
|
|
36
|
+
|
|
37
|
+
# Build request to BioLM API
|
|
38
|
+
url = 'https://biolm.ai/api/ui/community-api-models/'
|
|
39
|
+
headers = {
|
|
40
|
+
'Content-Type': 'application/json',
|
|
41
|
+
'User-Agent': 'JupyterLab-BioLM-Extension/0.1.0',
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if api_key:
|
|
45
|
+
headers['Authorization'] = f'Bearer {api_key}'
|
|
46
|
+
|
|
47
|
+
# Make request
|
|
48
|
+
req = Request(url, headers=headers)
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
with urlopen(req, timeout=10) as response:
|
|
52
|
+
data = json.loads(response.read().decode('utf-8'))
|
|
53
|
+
self.set_status(200)
|
|
54
|
+
self.set_header('Content-Type', 'application/json')
|
|
55
|
+
self.finish(json.dumps(data))
|
|
56
|
+
except HTTPError as e:
|
|
57
|
+
error_data = {
|
|
58
|
+
'error': True,
|
|
59
|
+
'message': f'API request failed: {e.code} {e.reason}',
|
|
60
|
+
'status': e.code,
|
|
61
|
+
}
|
|
62
|
+
self.set_status(e.code)
|
|
63
|
+
self.set_header('Content-Type', 'application/json')
|
|
64
|
+
self.finish(json.dumps(error_data))
|
|
65
|
+
except URLError as e:
|
|
66
|
+
error_data = {
|
|
67
|
+
'error': True,
|
|
68
|
+
'message': f'Network error: {str(e)}',
|
|
69
|
+
}
|
|
70
|
+
self.set_status(500)
|
|
71
|
+
self.set_header('Content-Type', 'application/json')
|
|
72
|
+
self.finish(json.dumps(error_data))
|
|
73
|
+
|
|
74
|
+
except Exception as e:
|
|
75
|
+
error_data = {
|
|
76
|
+
'error': True,
|
|
77
|
+
'message': f'Server error: {str(e)}',
|
|
78
|
+
}
|
|
79
|
+
self.set_status(500)
|
|
80
|
+
self.set_header('Content-Type', 'application/json')
|
|
81
|
+
self.finish(json.dumps(error_data))
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class BioLMModelDetailsHandler(APIHandler):
|
|
85
|
+
"""Handler for fetching individual model details with code examples"""
|
|
86
|
+
|
|
87
|
+
# Disable XSRF for API endpoints
|
|
88
|
+
def check_xsrf_cookie(self):
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
@tornado.web.authenticated
|
|
92
|
+
def get(self, model_slug):
|
|
93
|
+
"""Fetch model details from BioLM API"""
|
|
94
|
+
try:
|
|
95
|
+
# Get API key from Authorization header or query parameter
|
|
96
|
+
api_key = None
|
|
97
|
+
auth_header = self.request.headers.get('Authorization', '')
|
|
98
|
+
if auth_header.startswith('Bearer '):
|
|
99
|
+
api_key = auth_header[7:]
|
|
100
|
+
else:
|
|
101
|
+
api_key = self.get_query_argument('api_key', None)
|
|
102
|
+
|
|
103
|
+
# Build request to BioLM API with code_examples and exclude_docs_html
|
|
104
|
+
url = f'https://biolm.ai/api/ui/community-api-models/{model_slug}/?code_examples=true&exclude_docs_html=true'
|
|
105
|
+
headers = {
|
|
106
|
+
'Content-Type': 'application/json',
|
|
107
|
+
'User-Agent': 'JupyterLab-BioLM-Extension/0.1.0',
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if api_key:
|
|
111
|
+
headers['Authorization'] = f'Bearer {api_key}'
|
|
112
|
+
|
|
113
|
+
# Make request
|
|
114
|
+
req = Request(url, headers=headers)
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
with urlopen(req, timeout=10) as response:
|
|
118
|
+
data = json.loads(response.read().decode('utf-8'))
|
|
119
|
+
|
|
120
|
+
# Transform example_payload fields into code_examples format
|
|
121
|
+
code_examples = []
|
|
122
|
+
model_slug_from_data = data.get('model_slug', model_slug)
|
|
123
|
+
|
|
124
|
+
# Map action types to their example payload fields
|
|
125
|
+
action_mapping = {
|
|
126
|
+
'predict': 'predictor_example_payload',
|
|
127
|
+
'encode': 'encoder_example_payload',
|
|
128
|
+
'generate': 'generator_example_payload',
|
|
129
|
+
'classify': 'classifier_example_payload',
|
|
130
|
+
'similarity': 'similarity_example_payload',
|
|
131
|
+
'explain': 'explainer_example_payload',
|
|
132
|
+
'transform': 'transformer_example_payload',
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
for action, payload_key in action_mapping.items():
|
|
136
|
+
payload = data.get(payload_key)
|
|
137
|
+
if payload and payload.get('items'):
|
|
138
|
+
items = payload['items']
|
|
139
|
+
|
|
140
|
+
# Determine item type and format
|
|
141
|
+
if isinstance(items, list) and len(items) > 0:
|
|
142
|
+
# Check if items are objects with 'sequence' field
|
|
143
|
+
if isinstance(items[0], dict) and 'sequence' in items[0]:
|
|
144
|
+
sequences = [item['sequence'] for item in items]
|
|
145
|
+
if len(sequences) == 1:
|
|
146
|
+
code = f'result = biolm(entity="{model_slug_from_data}", action="{action}", type="sequence", items="{sequences[0]}")\n\nprint(result)'
|
|
147
|
+
else:
|
|
148
|
+
seq_list = ', '.join([f'"{seq}"' for seq in sequences])
|
|
149
|
+
code = f'result = biolm(entity="{model_slug_from_data}", action="{action}", type="sequence", items=[{seq_list}])\n\nprint(result)'
|
|
150
|
+
else:
|
|
151
|
+
# Handle other item formats
|
|
152
|
+
if len(items) == 1:
|
|
153
|
+
code = f'result = biolm(entity="{model_slug_from_data}", action="{action}", type="sequence", items={json.dumps(items[0])})\n\nprint(result)'
|
|
154
|
+
else:
|
|
155
|
+
code = f'result = biolm(entity="{model_slug_from_data}", action="{action}", type="sequence", items={json.dumps(items)})\n\nprint(result)'
|
|
156
|
+
|
|
157
|
+
code_examples.append({
|
|
158
|
+
'action': action,
|
|
159
|
+
'code': code
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
# Add setup example for environment variable (if API key is provided)
|
|
163
|
+
api_key = None
|
|
164
|
+
auth_header = self.request.headers.get('Authorization', '')
|
|
165
|
+
if auth_header.startswith('Bearer '):
|
|
166
|
+
api_key = auth_header[7:]
|
|
167
|
+
else:
|
|
168
|
+
api_key = self.get_query_argument('api_key', None)
|
|
169
|
+
|
|
170
|
+
if api_key:
|
|
171
|
+
# Add setup example as the first example
|
|
172
|
+
setup_code = f"import os\nos.environ['BIOLMAI_TOKEN'] = 'YOUR_API_KEY_HERE' # Replace with your actual API key"
|
|
173
|
+
code_examples.insert(0, {
|
|
174
|
+
'action': 'setup',
|
|
175
|
+
'code': setup_code
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
# Add code_examples to the response
|
|
179
|
+
if code_examples:
|
|
180
|
+
data['code_examples'] = code_examples
|
|
181
|
+
|
|
182
|
+
self.set_status(200)
|
|
183
|
+
self.set_header('Content-Type', 'application/json')
|
|
184
|
+
self.finish(json.dumps(data))
|
|
185
|
+
except HTTPError as e:
|
|
186
|
+
error_data = {
|
|
187
|
+
'error': True,
|
|
188
|
+
'message': f'API request failed: {e.code} {e.reason}',
|
|
189
|
+
'status': e.code,
|
|
190
|
+
}
|
|
191
|
+
self.set_status(e.code)
|
|
192
|
+
self.set_header('Content-Type', 'application/json')
|
|
193
|
+
self.finish(json.dumps(error_data))
|
|
194
|
+
except URLError as e:
|
|
195
|
+
error_data = {
|
|
196
|
+
'error': True,
|
|
197
|
+
'message': f'Network error: {str(e)}',
|
|
198
|
+
}
|
|
199
|
+
self.set_status(500)
|
|
200
|
+
self.set_header('Content-Type', 'application/json')
|
|
201
|
+
self.finish(json.dumps(error_data))
|
|
202
|
+
|
|
203
|
+
except Exception as e:
|
|
204
|
+
error_data = {
|
|
205
|
+
'error': True,
|
|
206
|
+
'message': f'Server error: {str(e)}',
|
|
207
|
+
}
|
|
208
|
+
self.set_status(500)
|
|
209
|
+
self.set_header('Content-Type', 'application/json')
|
|
210
|
+
self.finish(json.dumps(error_data))
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class BioLMTestConnectionHandler(APIHandler):
|
|
214
|
+
"""Handler for testing API connection"""
|
|
215
|
+
|
|
216
|
+
# Disable XSRF for API endpoints
|
|
217
|
+
def check_xsrf_cookie(self):
|
|
218
|
+
pass
|
|
219
|
+
|
|
220
|
+
@tornado.web.authenticated
|
|
221
|
+
def post(self):
|
|
222
|
+
"""Test connection with API key"""
|
|
223
|
+
try:
|
|
224
|
+
data = json.loads(self.request.body.decode('utf-8'))
|
|
225
|
+
api_key = data.get('api_key')
|
|
226
|
+
|
|
227
|
+
if not api_key:
|
|
228
|
+
self.set_status(400)
|
|
229
|
+
self.finish(json.dumps({
|
|
230
|
+
'error': True,
|
|
231
|
+
'message': 'API key is required',
|
|
232
|
+
}))
|
|
233
|
+
return
|
|
234
|
+
|
|
235
|
+
# Test connection by making a request
|
|
236
|
+
url = 'https://biolm.ai/api/ui/community-api-models/'
|
|
237
|
+
headers = {
|
|
238
|
+
'Authorization': f'Bearer {api_key}',
|
|
239
|
+
'Content-Type': 'application/json',
|
|
240
|
+
'User-Agent': 'JupyterLab-BioLM-Extension/0.1.0',
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
req = Request(url, headers=headers)
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
with urlopen(req, timeout=10) as response:
|
|
247
|
+
result = {
|
|
248
|
+
'valid': response.status == 200,
|
|
249
|
+
'message': 'Connection successful' if response.status == 200 else f'HTTP {response.status}',
|
|
250
|
+
}
|
|
251
|
+
self.set_status(200)
|
|
252
|
+
self.set_header('Content-Type', 'application/json')
|
|
253
|
+
self.finish(json.dumps(result))
|
|
254
|
+
except HTTPError as e:
|
|
255
|
+
result = {
|
|
256
|
+
'valid': False,
|
|
257
|
+
'message': f'Authentication failed: {e.code} {e.reason}',
|
|
258
|
+
}
|
|
259
|
+
self.set_status(200) # Return 200 with error in body
|
|
260
|
+
self.set_header('Content-Type', 'application/json')
|
|
261
|
+
self.finish(json.dumps(result))
|
|
262
|
+
except URLError as e:
|
|
263
|
+
result = {
|
|
264
|
+
'valid': False,
|
|
265
|
+
'message': f'Connection failed: {str(e)}',
|
|
266
|
+
}
|
|
267
|
+
self.set_status(200)
|
|
268
|
+
self.set_header('Content-Type', 'application/json')
|
|
269
|
+
self.finish(json.dumps(result))
|
|
270
|
+
|
|
271
|
+
except Exception as e:
|
|
272
|
+
error_data = {
|
|
273
|
+
'error': True,
|
|
274
|
+
'message': f'Server error: {str(e)}',
|
|
275
|
+
}
|
|
276
|
+
self.set_status(500)
|
|
277
|
+
self.set_header('Content-Type', 'application/json')
|
|
278
|
+
self.finish(json.dumps(error_data))
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _jupyter_server_extension_points():
|
|
282
|
+
"""Return server extension points - this enables auto-discovery in Jupyter Server 2.x"""
|
|
283
|
+
return [{
|
|
284
|
+
'module': 'jupyterlab_biolm.serverextension',
|
|
285
|
+
}]
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _load_jupyter_server_extension(server_app):
|
|
289
|
+
"""Load the server extension"""
|
|
290
|
+
web_app = server_app.web_app
|
|
291
|
+
base_url = web_app.settings['base_url']
|
|
292
|
+
|
|
293
|
+
# Register handlers
|
|
294
|
+
handlers = [
|
|
295
|
+
(url_path_join(base_url, 'biolm', 'api', 'models'), BioLMModelsHandler),
|
|
296
|
+
(url_path_join(base_url, 'biolm', 'api', 'models', r'([^/]+)'), BioLMModelDetailsHandler),
|
|
297
|
+
(url_path_join(base_url, 'biolm', 'api', 'test-connection'), BioLMTestConnectionHandler),
|
|
298
|
+
]
|
|
299
|
+
|
|
300
|
+
web_app.add_handlers('.*$', handlers)
|
|
301
|
+
|
|
302
|
+
server_app.log.info('BioLM server extension loaded')
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
# For JupyterLab 4.x compatibility
|
|
306
|
+
def _jupyter_server_extension_paths():
|
|
307
|
+
"""Return server extension paths"""
|
|
308
|
+
return [{
|
|
309
|
+
'module': 'jupyterlab_biolm.serverextension',
|
|
310
|
+
}]
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
# For JupyterLab 4.x / Jupyter Server 2.x
|
|
314
|
+
load_jupyter_server_extension = _load_jupyter_server_extension
|
|
315
|
+
|
|
316
|
+
# Also register as a function that can be called directly
|
|
317
|
+
__all__ = ['_load_jupyter_server_extension', 'load_jupyter_server_extension']
|
|
318
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"jupyter.lab.setting-icon": "biolm:plugin",
|
|
3
|
+
"jupyter.lab.setting-icon-label": "BioLM",
|
|
4
|
+
"title": "BioLM Extension Settings",
|
|
5
|
+
"description": "Settings for the BioLM JupyterLab extension",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"profiles": {
|
|
9
|
+
"type": "array",
|
|
10
|
+
"title": "API Key Profiles",
|
|
11
|
+
"description": "List of API key profiles",
|
|
12
|
+
"items": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"name": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"title": "Profile Name"
|
|
18
|
+
},
|
|
19
|
+
"apiKey": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"title": "API Key"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"required": ["name", "apiKey"]
|
|
25
|
+
},
|
|
26
|
+
"default": []
|
|
27
|
+
},
|
|
28
|
+
"activeProfile": {
|
|
29
|
+
"type": ["string", "null"],
|
|
30
|
+
"title": "Active Profile",
|
|
31
|
+
"description": "Name of the currently active API key profile",
|
|
32
|
+
"default": null
|
|
33
|
+
},
|
|
34
|
+
"defaultModel": {
|
|
35
|
+
"type": ["string", "null"],
|
|
36
|
+
"title": "Default Model",
|
|
37
|
+
"description": "Default model ID to use",
|
|
38
|
+
"default": null
|
|
39
|
+
},
|
|
40
|
+
"defaultAction": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"title": "Default Action",
|
|
43
|
+
"description": "Default action to use (predict, generate, embed, etc.)",
|
|
44
|
+
"default": "predict"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"additionalProperties": false
|
|
48
|
+
}
|
|
49
|
+
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jupyterlab-biolm",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "JupyterLab extension for BioLM API integration",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"jupyter",
|
|
7
|
+
"jupyterlab",
|
|
8
|
+
"jupyterlab-extension",
|
|
9
|
+
"biolm"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/BioLM/jupyterlab-biolm",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/BioLM/jupyterlab-biolm/issues"
|
|
14
|
+
},
|
|
15
|
+
"license": "BSD-3-Clause",
|
|
16
|
+
"author": "BioLM",
|
|
17
|
+
"files": [
|
|
18
|
+
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf,woff,woff2}",
|
|
19
|
+
"style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf,woff,woff2}",
|
|
20
|
+
"schema/*.json"
|
|
21
|
+
],
|
|
22
|
+
"main": "lib/index.js",
|
|
23
|
+
"types": "lib/index.d.ts",
|
|
24
|
+
"style": "style/index.css",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/BioLM/jupyterlab-biolm.git"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "npm run build:lib && npm run build:labextension:dev",
|
|
31
|
+
"build:prod": "npm run clean && npm run build:lib && npm run build:labextension",
|
|
32
|
+
"build:labextension": "jupyter labextension build .",
|
|
33
|
+
"build:labextension:dev": "python3 -m jupyterlab labextension build --development .",
|
|
34
|
+
"build:lib": "tsc",
|
|
35
|
+
"build:lib:watch": "tsc --watch",
|
|
36
|
+
"clean": "npm run clean:lib",
|
|
37
|
+
"clean:lib": "rimraf lib tsconfig.tsbuildinfo",
|
|
38
|
+
"clean:labextension": "rimraf jupyterlab_biolm/labextension",
|
|
39
|
+
"clean:all": "npm run clean:lib && npm run clean:labextension",
|
|
40
|
+
"eslint": "eslint . --ext .ts,.tsx --fix",
|
|
41
|
+
"eslint:check": "eslint . --ext .ts,.tsx",
|
|
42
|
+
"prepack": "npm run clean && npm run build:prod",
|
|
43
|
+
"watch": "run-p watch:src watch:labextension",
|
|
44
|
+
"watch:src": "tsc --watch",
|
|
45
|
+
"watch:labextension": "jupyter labextension watch ."
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@jupyterlab/application": "^4.0.0",
|
|
49
|
+
"@jupyterlab/apputils": "^4.0.0",
|
|
50
|
+
"@jupyterlab/notebook": "^4.0.0",
|
|
51
|
+
"@jupyterlab/ui-components": "^4.0.0",
|
|
52
|
+
"@lumino/widgets": "^2.0.0",
|
|
53
|
+
"react": "^18.0.0",
|
|
54
|
+
"react-dom": "^18.0.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@jupyterlab/builder": "^4.0.0",
|
|
58
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
59
|
+
"@semantic-release/git": "^10.0.1",
|
|
60
|
+
"@semantic-release/github": "^11.0.6",
|
|
61
|
+
"@semantic-release/npm": "^12.0.2",
|
|
62
|
+
"@semantic-release/release-notes-generator": "^12.1.0",
|
|
63
|
+
"@types/react": "^18.0.0",
|
|
64
|
+
"@types/react-dom": "^18.0.0",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
|
66
|
+
"@typescript-eslint/parser": "^5.0.0",
|
|
67
|
+
"eslint": "^8.0.0",
|
|
68
|
+
"eslint-config-prettier": "^8.0.0",
|
|
69
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
70
|
+
"prettier": "^2.0.0",
|
|
71
|
+
"rimraf": "^5.0.0",
|
|
72
|
+
"semantic-release": "^24.2.9",
|
|
73
|
+
"typescript": "~5.0.0"
|
|
74
|
+
},
|
|
75
|
+
"peerDependencies": {
|
|
76
|
+
"react": "^18.0.0",
|
|
77
|
+
"react-dom": "^18.0.0"
|
|
78
|
+
},
|
|
79
|
+
"jupyterlab": {
|
|
80
|
+
"extension": true,
|
|
81
|
+
"outputDir": "jupyterlab_biolm/labextension",
|
|
82
|
+
"schemaDir": "schema",
|
|
83
|
+
"sharedPackages": {
|
|
84
|
+
"react": {
|
|
85
|
+
"bundled": false,
|
|
86
|
+
"singleton": true
|
|
87
|
+
},
|
|
88
|
+
"react-dom": {
|
|
89
|
+
"bundled": false,
|
|
90
|
+
"singleton": true
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"_build": {
|
|
94
|
+
"load": "static/remoteEntry.8d19a58608019bf31dd9.js",
|
|
95
|
+
"extension": "./extension",
|
|
96
|
+
"style": "./style"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"release": {
|
|
100
|
+
"branches": [
|
|
101
|
+
"main",
|
|
102
|
+
"master"
|
|
103
|
+
],
|
|
104
|
+
"plugins": [
|
|
105
|
+
"@semantic-release/commit-analyzer",
|
|
106
|
+
"@semantic-release/release-notes-generator",
|
|
107
|
+
[
|
|
108
|
+
"@semantic-release/npm",
|
|
109
|
+
{
|
|
110
|
+
"npmPublish": false
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
[
|
|
114
|
+
"@semantic-release/git",
|
|
115
|
+
{
|
|
116
|
+
"assets": [
|
|
117
|
+
"package.json"
|
|
118
|
+
],
|
|
119
|
+
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jupyterlab-biolm",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "JupyterLab extension for BioLM API integration",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"jupyter",
|
|
7
|
+
"jupyterlab",
|
|
8
|
+
"jupyterlab-extension",
|
|
9
|
+
"biolm"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/BioLM/jupyterlab-biolm",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/BioLM/jupyterlab-biolm/issues"
|
|
14
|
+
},
|
|
15
|
+
"license": "BSD-3-Clause",
|
|
16
|
+
"author": "BioLM",
|
|
17
|
+
"files": [
|
|
18
|
+
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf,woff,woff2}",
|
|
19
|
+
"style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf,woff,woff2}",
|
|
20
|
+
"schema/*.json"
|
|
21
|
+
],
|
|
22
|
+
"main": "lib/index.js",
|
|
23
|
+
"types": "lib/index.d.ts",
|
|
24
|
+
"style": "style/index.css",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/BioLM/jupyterlab-biolm.git"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "npm run build:lib && npm run build:labextension:dev",
|
|
31
|
+
"build:prod": "npm run clean && npm run build:lib && npm run build:labextension",
|
|
32
|
+
"build:labextension": "jupyter labextension build .",
|
|
33
|
+
"build:labextension:dev": "python3 -m jupyterlab labextension build --development .",
|
|
34
|
+
"build:lib": "tsc",
|
|
35
|
+
"build:lib:watch": "tsc --watch",
|
|
36
|
+
"clean": "npm run clean:lib",
|
|
37
|
+
"clean:lib": "rimraf lib tsconfig.tsbuildinfo",
|
|
38
|
+
"clean:labextension": "rimraf jupyterlab_biolm/labextension",
|
|
39
|
+
"clean:all": "npm run clean:lib && npm run clean:labextension",
|
|
40
|
+
"eslint": "eslint . --ext .ts,.tsx --fix",
|
|
41
|
+
"eslint:check": "eslint . --ext .ts,.tsx",
|
|
42
|
+
"prepack": "npm run clean && npm run build:prod",
|
|
43
|
+
"watch": "run-p watch:src watch:labextension",
|
|
44
|
+
"watch:src": "tsc --watch",
|
|
45
|
+
"watch:labextension": "jupyter labextension watch ."
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@jupyterlab/application": "^4.0.0",
|
|
49
|
+
"@jupyterlab/apputils": "^4.0.0",
|
|
50
|
+
"@jupyterlab/notebook": "^4.0.0",
|
|
51
|
+
"@jupyterlab/ui-components": "^4.0.0",
|
|
52
|
+
"@lumino/widgets": "^2.0.0",
|
|
53
|
+
"react": "^18.0.0",
|
|
54
|
+
"react-dom": "^18.0.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@jupyterlab/builder": "^4.0.0",
|
|
58
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
59
|
+
"@semantic-release/git": "^10.0.1",
|
|
60
|
+
"@semantic-release/github": "^11.0.6",
|
|
61
|
+
"@semantic-release/npm": "^12.0.2",
|
|
62
|
+
"@semantic-release/release-notes-generator": "^12.1.0",
|
|
63
|
+
"@types/react": "^18.0.0",
|
|
64
|
+
"@types/react-dom": "^18.0.0",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
|
66
|
+
"@typescript-eslint/parser": "^5.0.0",
|
|
67
|
+
"eslint": "^8.0.0",
|
|
68
|
+
"eslint-config-prettier": "^8.0.0",
|
|
69
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
70
|
+
"prettier": "^2.0.0",
|
|
71
|
+
"rimraf": "^5.0.0",
|
|
72
|
+
"semantic-release": "^24.2.9",
|
|
73
|
+
"typescript": "~5.0.0"
|
|
74
|
+
},
|
|
75
|
+
"peerDependencies": {
|
|
76
|
+
"react": "^18.0.0",
|
|
77
|
+
"react-dom": "^18.0.0"
|
|
78
|
+
},
|
|
79
|
+
"jupyterlab": {
|
|
80
|
+
"extension": true,
|
|
81
|
+
"outputDir": "jupyterlab_biolm/labextension",
|
|
82
|
+
"schemaDir": "schema",
|
|
83
|
+
"sharedPackages": {
|
|
84
|
+
"react": {
|
|
85
|
+
"bundled": false,
|
|
86
|
+
"singleton": true
|
|
87
|
+
},
|
|
88
|
+
"react-dom": {
|
|
89
|
+
"bundled": false,
|
|
90
|
+
"singleton": true
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"release": {
|
|
95
|
+
"branches": [
|
|
96
|
+
"main",
|
|
97
|
+
"master"
|
|
98
|
+
],
|
|
99
|
+
"plugins": [
|
|
100
|
+
"@semantic-release/commit-analyzer",
|
|
101
|
+
"@semantic-release/release-notes-generator",
|
|
102
|
+
[
|
|
103
|
+
"@semantic-release/npm",
|
|
104
|
+
{
|
|
105
|
+
"npmPublish": false
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
[
|
|
109
|
+
"@semantic-release/git",
|
|
110
|
+
{
|
|
111
|
+
"assets": [
|
|
112
|
+
"package.json"
|
|
113
|
+
],
|
|
114
|
+
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"jupyter.lab.setting-icon": "biolm:plugin",
|
|
3
|
+
"jupyter.lab.setting-icon-label": "BioLM",
|
|
4
|
+
"title": "BioLM Extension Settings",
|
|
5
|
+
"description": "Settings for the BioLM JupyterLab extension",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"profiles": {
|
|
9
|
+
"type": "array",
|
|
10
|
+
"title": "API Key Profiles",
|
|
11
|
+
"description": "List of API key profiles",
|
|
12
|
+
"items": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"name": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"title": "Profile Name"
|
|
18
|
+
},
|
|
19
|
+
"apiKey": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"title": "API Key"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"required": ["name", "apiKey"]
|
|
25
|
+
},
|
|
26
|
+
"default": []
|
|
27
|
+
},
|
|
28
|
+
"activeProfile": {
|
|
29
|
+
"type": ["string", "null"],
|
|
30
|
+
"title": "Active Profile",
|
|
31
|
+
"description": "Name of the currently active API key profile",
|
|
32
|
+
"default": null
|
|
33
|
+
},
|
|
34
|
+
"defaultModel": {
|
|
35
|
+
"type": ["string", "null"],
|
|
36
|
+
"title": "Default Model",
|
|
37
|
+
"description": "Default model ID to use",
|
|
38
|
+
"default": null
|
|
39
|
+
},
|
|
40
|
+
"defaultAction": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"title": "Default Action",
|
|
43
|
+
"description": "Default action to use (predict, generate, embed, etc.)",
|
|
44
|
+
"default": "predict"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"additionalProperties": false
|
|
48
|
+
}
|
|
49
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(self.webpackChunkjupyterlab_biolm=self.webpackChunkjupyterlab_biolm||[]).push([[462],{462:(e,t,o)=>{"use strict";o.r(t),o.d(t,{default:()=>M});var a=o(762),n=o(986),i=o(345),s=o.n(i);const r="/biolm/api/test-connection";let l=null;function c(e){const t=[];return e.predictor&&t.push("predict"),e.encoder&&t.push("encode"),e.generator&&t.push("generate"),e.classifier&&t.push("classify"),e.similarity&&t.push("similarity"),e.explainer&&t.push("explain"),e.transformer&&t.push("transform"),0===t.length&&t.push("predict"),{id:e.model_slug,name:e.model_name,description:e.description,tags:e.tags||[],apiVersion:e.api_version,communityModel:e.community_model,companyModel:e.company_model,actions:t,apiDocsLink:e.api_docs_link}}var m=o(606);const d="jupyterlab-biolm:settings",p={profiles:[],activeProfile:void 0,defaultModel:void 0,defaultAction:"predict"};function u(){try{const e=localStorage.getItem(d);if(e)return{...p,...JSON.parse(e)}}catch(e){console.warn("Failed to load settings from localStorage:",e)}return{...p}}function y(e){try{localStorage.setItem(d,JSON.stringify(e))}catch(e){console.warn("Failed to save settings to localStorage:",e)}}function g(){if(void 0!==m&&m.env&&m.env.BIOLM_API_KEY)return m.env.BIOLM_API_KEY;const e=u(),t=e.activeProfile;if(t){const o=e.profiles.find(e=>e.name===t);if(o)return o.apiKey}}async function f(e){const t=u();t.profiles=e,y(t)}async function h(e){const t=u();t.activeProfile=e,y(t)}function b(e,t,o){if(o)return o;let a="sequence",n='"YOUR_SEQUENCE_HERE"';return"generate"===t&&(a="context",n='"YOUR_CONTEXT_HERE"'),`# Complete example not available\nresult = biolm(entity="${e}", action="${t}", type="${a}", items=${n})\n\nprint(result)`}async function v(e,t){var o;const a=e.currentWidget;if(!a)return!1;const n=a.sessionContext;if(!n||!(null===(o=n.session)||void 0===o?void 0:o.kernel))return!1;try{const e=n.session.kernel,o=`import os\nos.environ['BIOLMAI_TOKEN'] = '${t.replace(/'/g,"\\'").replace(/\\/g,"\\\\")}'`,a=e.requestExecute({code:o,silent:!0});return await a.done,!0}catch(e){return console.error("Failed to set BIOLMAI_TOKEN in kernel:",e),!1}}async function E(e,t,o=!0){const a=e.currentWidget;if(!a)return await(0,n.showErrorMessage)("No Active Notebook","Please open a notebook before inserting code."),!1;const i=a.content.activeCell;if(!i)return await(0,n.showErrorMessage)("No Active Cell","Please select a cell in the notebook."),!1;const s=i.model.sharedModel,r=s.getSource();return o&&r.trim()?s.setSource(r+"\n"+t):s.setSource(t),!0}const w=({notebookTracker:e})=>{const[t,o]=(0,i.useState)([]),[a,r]=(0,i.useState)(!0),[m,d]=(0,i.useState)(null),[p,u]=(0,i.useState)(""),[y,f]=(0,i.useState)(null),[h,v]=(0,i.useState)(new Set),[w,N]=(0,i.useState)(new Map);(0,i.useEffect)(()=>{k()},[]);const k=async()=>{r(!0),d(null);try{const e=g(),t=await async function(e){if(l&&Date.now()-l.timestamp<3e5)return l.data;let t="https://biolm.ai/api/ui/community-api-models/",o=!1;e&&(t+=`?api_key=${encodeURIComponent(e)}`),console.log("[BioLM] Fetching models via server proxy..."),o=!0,t="/biolm/api/models";const a={"Content-Type":"application/json"};e&&(t+=`?api_key=${encodeURIComponent(e)}`,a.Authorization=`Bearer ${e}`);try{let e=await fetch(t,{method:"GET",headers:a,credentials:"same-origin"});if(console.log("[BioLM] Proxy response received:",e.status),console.log("[BioLM] Response status:",e.status,e.statusText),console.log("[BioLM] Response URL:",e.url),console.log("[BioLM] Response ok:",e.ok),console.log("[BioLM] Using proxy:",!0),!e.ok){let t=`Failed to fetch models: ${e.status} ${e.statusText}`,o=null;try{const a=await e.text();console.log("[BioLM] Error response body:",a);try{o=JSON.parse(a),o.message?t=o.message:o.error&&(t=o.error)}catch(e){a&&(t=`${t}: ${a.substring(0,200)}`)}}catch(e){console.error("[BioLM] Error reading response:",e)}throw console.error("[BioLM] API Error:",t,o),{message:t,status:e.status}}const o=await e.json(),n=Array.isArray(o)?o.map(c):[];return l={data:n,timestamp:Date.now()},n}catch(e){if(console.error("[BioLM] Proxy fetch failed:",e),l)return console.warn("Using cached models due to fetch error:",e),l.data;if(e instanceof Error)throw{message:e.message.includes("fetch")||e.message.includes("CORS")||e.message.includes("Failed to fetch")?"Unable to connect to BioLM API via server proxy. Please check your internet connection and ensure the server extension is loaded.":e.message};throw e}}(e);o(t)}catch(e){d(e.message||"Failed to load models"),console.error("Error loading models:",e)}finally{r(!1)}},C=(0,i.useMemo)(()=>{let e=t;if(y&&(e=e.filter(e=>e.actions&&e.actions.includes(y)||e.tags&&e.tags.includes(y))),p.trim()){const t=p.toLowerCase();e=e.filter(e=>{const o=(e.name||e.id||"").toLowerCase(),a=(e.description||"").toLowerCase(),n=(e.tags||[]).join(" ").toLowerCase();return o.includes(t)||a.includes(t)||n.includes(t)})}return e.sort((e,t)=>{const o=(e.name||e.id||"").toLowerCase(),a=(t.name||t.id||"").toLowerCase();return o.localeCompare(a)})},[t,p,y]),j=(0,i.useMemo)(()=>{const e=new Set;return t.forEach(t=>{t.actions&&t.actions.forEach(t=>e.add(t))}),Array.from(e).sort()},[t]);return s().createElement("div",{className:"biolm-models-tab"},s().createElement("div",{className:"biolm-tab-header"},s().createElement("input",{type:"text",className:"jp-mod-styled jp-InputGroup-input",placeholder:"Search models...",value:p,onChange:e=>u(e.target.value),style:{width:"100%",marginBottom:"8px"}}),s().createElement("div",{className:"biolm-tag-filter"},s().createElement("button",{className:"jp-mod-styled jp-mod-minimal "+(y?"":"jp-mod-active"),onClick:()=>f(null),style:{marginRight:"4px",marginBottom:"4px"}},"All"),j.map(e=>s().createElement("button",{key:e,className:"jp-mod-styled jp-mod-minimal "+(y===e?"jp-mod-active":""),onClick:()=>f(e===y?null:e),style:{marginRight:"4px",marginBottom:"4px"}},e))),s().createElement("button",{className:"jp-mod-styled jp-mod-minimal",onClick:()=>{l=null,k()},style:{marginTop:"8px"}},"Refresh")),s().createElement("div",{className:"biolm-models-list"},a&&s().createElement("div",{className:"biolm-loading"},"Loading models..."),m&&s().createElement("div",{className:"biolm-error"},s().createElement("p",null,"Error: ",m),s().createElement("button",{className:"jp-mod-styled jp-mod-minimal",onClick:k},"Retry")),!a&&!m&&0===C.length&&s().createElement("div",{className:"biolm-empty"},p||y?"No models match your filters":"No models available"),!a&&!m&&C.map(t=>{const o=h.has(t.id),a=t.description||"",i=a.length>150,r=i&&!o?a.substring(0,150)+"...":a;return s().createElement("div",{key:t.id,className:"biolm-model-card"},s().createElement("div",{className:"biolm-model-header"},s().createElement("h3",{className:"biolm-model-name"},t.name||t.id),s().createElement("button",{className:"jp-mod-styled jp-mod-minimal",onClick:()=>(async e=>{try{await navigator.clipboard.writeText(e),console.log("Model ID copied to clipboard")}catch(e){(0,n.showErrorMessage)("Copy Failed","Failed to copy model ID to clipboard")}})(t.id),title:"Copy Model ID"},"Copy ID")),a&&s().createElement("div",{className:"biolm-model-description"},s().createElement("p",null,r),i&&s().createElement("button",{className:"jp-mod-styled jp-mod-minimal",onClick:()=>(e=>{const t=new Set(h);t.has(e)?t.delete(e):t.add(e),v(t)})(t.id)},o?"Show less":"Show more")),t.actions&&t.actions.length>0&&s().createElement("div",{className:"biolm-model-tags"},t.actions.map(o=>s().createElement("button",{key:o,className:"biolm-tag-button",onClick:()=>(async(t,o)=>{var a;try{let n;const i=w.get(t.id);if(null==i?void 0:i.code_examples){const e=i.code_examples.find(e=>e.action===o);n=null==e?void 0:e.code}else{const e=g(),i=await async function(e,t){console.log("[BioLM] Fetching model details via server proxy...");let o=`/biolm/api/models/${e}`;const a={"Content-Type":"application/json"};t&&(o+=`?api_key=${encodeURIComponent(t)}`,a.Authorization=`Bearer ${t}`);try{const e=await fetch(o,{method:"GET",headers:a,credentials:"same-origin"});if(console.log("[BioLM] Proxy response received:",e.status),!e.ok){let t=`Failed to fetch model details: ${e.status} ${e.statusText}`;try{const o=await e.text();try{const e=JSON.parse(o);e.message?t=e.message:e.error&&(t=e.error)}catch(e){o&&(t=`${t}: ${o.substring(0,200)}`)}}catch(e){console.error("[BioLM] Error reading response:",e)}throw{message:t,status:e.status}}return await e.json()}catch(e){if(console.error("[BioLM] Proxy fetch failed:",e),e instanceof Error)throw{message:e.message};throw e}}(t.id,e);N(e=>new Map(e).set(t.id,i));const s=null===(a=i.code_examples)||void 0===a?void 0:a.find(e=>e.action===o);n=null==s?void 0:s.code}const s=b(t.id,o,n);await E(e,s,!0)&&console.log(`Inserted ${o} snippet for ${t.name||t.id}`)}catch(a){console.error("Error fetching code example:",a);const n=b(t.id,o);await E(e,n,!0)&&console.log(`Inserted ${o} snippet for ${t.name||t.id}`)}})(t,o),title:`Insert ${o} code for ${t.name||t.id}`},o))),t.tags&&t.tags.length>0&&s().createElement("div",{className:"biolm-model-meta-tags",style:{marginTop:"8px",fontSize:"11px",color:"var(--biolm-text-secondary)"}},s().createElement("strong",null,"Tags:")," ",t.tags.join(", ")))})))},N=[{title:"Import BioLM",description:"Import the BioLM library (run this once at the top of your notebook)",category:"Setup",code:"from biolmai import biolm",parameters:[]},{title:"Encode Sequence",description:"Encode a single sequence into embeddings using ESM2-8M",category:"Encoding",code:'result = biolm(entity="esm2-8m", action="encode", type="sequence", items="MSILVTRPSPAGEEL")\n\nprint(result)',parameters:["entity","action","type","items"]},{title:"Encode Batch",description:"Encode multiple sequences in a batch",category:"Encoding",code:'result = biolm(entity="esm2-8m", action="encode", type="sequence", items=["SEQ1", "SEQ2"])\n\nprint(result)',parameters:["entity","action","type","items"]},{title:"Predict Structure",description:"Predict protein structure from sequence using ESMFold",category:"Prediction",code:'result = biolm(entity="esmfold", action="predict", type="sequence", items="MDNELE")\n\nprint(result)',parameters:["entity","action","type","items"]},{title:"Predict Batch",description:"Predict structures for multiple sequences",category:"Prediction",code:'result = biolm(entity="esmfold", action="predict", type="sequence", items=["MDNELE", "MENDEL"])\n\nprint(result)',parameters:["entity","action","type","items"]},{title:"Generate Sequence",description:"Generate new sequences from a context using ProGen2-OAS",category:"Generation",code:'result = biolm(\n entity="progen2-oas",\n action="generate",\n type="context",\n items="M",\n params={"temperature": 0.7, "top_p": 0.6, "num_samples": 2, "max_length": 17}\n)\n\nprint(result)',parameters:["entity","action","type","items","params"]},{title:"Write to Disk",description:"Save results directly to a file",category:"Output",code:'result = biolm(\n entity="esmfold",\n action="predict",\n type="sequence",\n items=["SEQ1", "SEQ2"],\n output=\'disk\',\n file_path="results.jsonl"\n)',parameters:["entity","action","type","items","output","file_path"]},{title:"Classify Sequence",description:"Classify a sequence",category:"Classification",code:'result = biolm(entity="your-model-id", action="classify", type="sequence", items="YOUR_SEQUENCE")\n\nprint(result)',parameters:["entity","action","type","items"]},{title:"Similarity Search",description:"Find similar sequences",category:"Similarity",code:'result = biolm(entity="your-model-id", action="similarity", type="sequence", items="YOUR_SEQUENCE")\n\nprint(result)',parameters:["entity","action","type","items"]}],k=({notebookTracker:e})=>{const[t,o]=(0,i.useState)(""),[a,r]=(0,i.useState)(null),l=(0,i.useMemo)(()=>{const e=new Set;return N.forEach(t=>e.add(t.category)),Array.from(e).sort()},[]),c=(0,i.useMemo)(()=>{let e=N;if(a&&(e=e.filter(e=>e.category===a)),t.trim()){const o=t.toLowerCase();e=e.filter(e=>{const t=e.title.toLowerCase(),a=e.description.toLowerCase(),n=e.category.toLowerCase();return t.includes(o)||a.includes(o)||n.includes(o)})}return e},[t,a]);return s().createElement("div",{className:"biolm-operations-tab"},s().createElement("div",{className:"biolm-tab-header"},s().createElement("input",{type:"text",className:"jp-mod-styled jp-InputGroup-input",placeholder:"Search operations...",value:t,onChange:e=>o(e.target.value),style:{width:"100%",marginBottom:"8px"}}),s().createElement("div",{className:"biolm-category-filter"},s().createElement("button",{className:"jp-mod-styled jp-mod-minimal "+(a?"":"jp-mod-active"),onClick:()=>r(null),style:{marginRight:"4px",marginBottom:"4px"}},"All"),l.map(e=>s().createElement("button",{key:e,className:"jp-mod-styled jp-mod-minimal "+(a===e?"jp-mod-active":""),onClick:()=>r(e===a?null:e),style:{marginRight:"4px",marginBottom:"4px"}},e)))),s().createElement("div",{className:"biolm-operations-list"},0===c.length&&s().createElement("div",{className:"biolm-empty"},t||a?"No operations match your filters":"No operations available"),c.map((t,o)=>s().createElement("div",{key:o,className:"biolm-operation-card"},s().createElement("div",{className:"biolm-operation-header"},s().createElement("h3",{className:"biolm-operation-title"},t.title),s().createElement("span",{className:"biolm-operation-category"},t.category)),s().createElement("p",{className:"biolm-operation-description"},t.description),t.parameters&&t.parameters.length>0&&s().createElement("div",{className:"biolm-operation-parameters"},s().createElement("strong",null,"Parameters:")," ",t.parameters.join(", ")),s().createElement("div",{className:"biolm-operation-code"},s().createElement("pre",null,s().createElement("code",null,t.code))),s().createElement("div",{className:"biolm-operation-actions"},s().createElement("button",{className:"jp-mod-styled jp-mod-accept",onClick:()=>(async t=>{await E(e,t.code,!0)&&console.log(`Inserted ${t.title} example`)})(t)},"Insert"),s().createElement("button",{className:"jp-mod-styled jp-mod-minimal",onClick:()=>(async e=>{try{await navigator.clipboard.writeText(e),console.log("Code snippet copied to clipboard")}catch(e){(0,n.showErrorMessage)("Copy Failed","Failed to copy code snippet to clipboard")}})(t.code)},"Copy"))))))};var C=o(606);const j=({notebookTracker:e})=>{const[t,o]=(0,i.useState)([]),[a,l]=(0,i.useState)(),[c,m]=(0,i.useState)(""),[d,p]=(0,i.useState)("predict"),[b,E]=(0,i.useState)(""),[w,N]=(0,i.useState)(""),[k,j]=(0,i.useState)(null),[S,x]=(0,i.useState)(""),[M,T]=(0,i.useState)(""),[I,L]=(0,i.useState)(!1),[B,P]=(0,i.useState)(null);(0,i.useEffect)(()=>{A()},[]),(0,i.useEffect)(()=>{const t=g();t&&v(e,t).catch(e=>{console.error("Failed to set token on mount:",e)})},[a,e]);const A=()=>{const e=u().profiles||[],t=u().activeProfile,a=u().defaultModel||"",n=u().defaultAction||"predict";o(e),l(t),m(a),p(n)},_=async()=>{if(!k||!S.trim()||!M.trim())return;const n=t.map(e=>e.name===k?{name:S.trim(),apiKey:M.trim()}:e);if(await f(n),o(n),a===k){await h(S.trim()),l(S.trim());const t=g();t&&await v(e,t)}j(null),x(""),T(""),console.log("Profile has been updated")},$=async t=>{await h(t),l(t),console.log(t?`Active profile: ${t}`:"Using environment variable");const o=g();o&&await v(e,o)},O=void 0!==C&&C.env&&!!C.env.BIOLM_API_KEY;return s().createElement("div",{className:"biolm-settings-tab"},s().createElement("div",{className:"biolm-settings-section"},s().createElement("h3",null,"API Key Profiles"),O&&s().createElement("div",{className:"biolm-env-notice"},s().createElement("p",null,"BIOLM_API_KEY environment variable is set and will be used if no profile is selected.")),s().createElement("div",{className:"biolm-profile-list"},0===t.length&&s().createElement("div",{className:"biolm-empty"},"No profiles configured. Add one below."),t.map(e=>s().createElement("div",{key:e.name,className:"biolm-profile-card"},k===e.name?s().createElement("div",{className:"biolm-profile-edit"},s().createElement("input",{type:"text",className:"jp-mod-styled jp-InputGroup-input",value:S,onChange:e=>x(e.target.value),placeholder:"Profile name",style:{marginBottom:"4px"}}),s().createElement("input",{type:"password",className:"jp-mod-styled jp-InputGroup-input",value:M,onChange:e=>T(e.target.value),placeholder:"API Key",style:{marginBottom:"4px"}}),s().createElement("div",null,s().createElement("button",{className:"jp-mod-styled jp-mod-accept",onClick:_},"Save"),s().createElement("button",{className:"jp-mod-styled jp-mod-minimal",onClick:()=>{j(null),x(""),T("")}},"Cancel"))):s().createElement(s().Fragment,null,s().createElement("div",{className:"biolm-profile-header"},s().createElement("strong",null,e.name),s().createElement("div",null,s().createElement("button",{className:"jp-mod-styled jp-mod-minimal "+(a===e.name?"jp-mod-active":""),onClick:()=>$(e.name),title:"Set as active"},a===e.name?"Active":"Set Active"),s().createElement("button",{className:"jp-mod-styled jp-mod-minimal",onClick:()=>(async e=>{L(!0),P(null);try{const t=await async function(e){let t="https://biolm.ai/api/ui/community-api-models/",o=!1;const a={"Content-Type":"application/json",Authorization:`Bearer ${e}`};try{let n=null,i=!1;try{n=await fetch(t,{method:"GET",headers:a,mode:"cors"}),0!==n.status&&"opaque"!==n.type||(i=!0,n=null)}catch(e){console.log("[BioLM] Direct API test failed with error:",e.message),i=!0,n=null}if(!i&&n||(console.log("[BioLM] Using server proxy for connection test due to CORS/network issue..."),o=!0,t=r,n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"same-origin",body:JSON.stringify({api_key:e})})),n.ok){const e=await n.json();return{valid:e.valid||!1,message:e.message||"Connection test completed",accountInfo:e.accountInfo}}{let e=`HTTP ${n.status}: ${n.statusText}`;try{const t=await n.json().catch(()=>({}));t.message&&(e=t.message)}catch(e){}return{valid:!1,message:e}}}catch(t){if(!o&&t instanceof Error&&(t.message.includes("CORS")||t.message.includes("Failed to fetch")||t.message.includes("network"))){console.log("[BioLM] CORS error detected for connection test, trying server proxy...");try{const t=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"same-origin",body:JSON.stringify({api_key:e})});if(t.ok){const e=await t.json();return{valid:e.valid||!1,message:e.message||"Connection test completed",accountInfo:e.accountInfo}}return{valid:!1,message:(await t.json().catch(()=>({}))).message||`HTTP ${t.status}: ${t.statusText}`}}catch(e){console.error("[BioLM] Proxy also failed:",e)}}return{valid:!1,message:t instanceof Error?t.message:"Connection failed"}}}(e);P(t),t.valid?console.log(t.message||"API key is valid"):(0,n.showErrorMessage)("Connection Failed",t.message||"Invalid API key")}catch(e){const t=e.message||"Connection test failed";P({valid:!1,message:t}),(0,n.showErrorMessage)("Connection Failed",t)}finally{L(!1)}})(e.apiKey),disabled:I},"Test"),s().createElement("button",{className:"jp-mod-styled jp-mod-minimal",onClick:()=>(e=>{j(e.name),x(e.name),T(e.apiKey)})(e)},"Edit"),s().createElement("button",{className:"jp-mod-styled jp-mod-minimal",onClick:()=>(async e=>{const n=t.filter(t=>t.name!==e);await f(n),o(n),a===e&&(await h(void 0),l(void 0)),console.log(`Profile "${e}" has been deleted`)})(e.name)},"Delete"))),B&&a===e.name&&s().createElement("div",{className:"biolm-connection-status "+(B.valid?"valid":"invalid")},B.message))))),s().createElement("div",{className:"biolm-add-profile"},s().createElement("h4",null,"Add New Profile"),s().createElement("input",{type:"text",className:"jp-mod-styled jp-InputGroup-input",value:b,onChange:e=>E(e.target.value),placeholder:"Profile name",style:{marginBottom:"4px"}}),s().createElement("input",{type:"password",className:"jp-mod-styled jp-InputGroup-input",value:w,onChange:e=>N(e.target.value),placeholder:"API Key",style:{marginBottom:"4px"}}),s().createElement("button",{className:"jp-mod-styled jp-mod-accept",onClick:async()=>{if(!b.trim()||!w.trim())return void(0,n.showErrorMessage)("Invalid Input","Please provide both profile name and API key");if(t.some(e=>e.name===b))return void(0,n.showErrorMessage)("Duplicate Profile","A profile with this name already exists");const i={name:b.trim(),apiKey:w.trim()},s=[...t,i];if(await f(s),o(s),E(""),N(""),console.log(`Profile "${i.name}" has been added`),!a){await h(i.name),l(i.name);const t=g();t&&await v(e,t)}}},"Add Profile")),s().createElement("div",{className:"biolm-env-option"},s().createElement("button",{className:"jp-mod-styled jp-mod-minimal "+(a?"":"jp-mod-active"),onClick:()=>$(void 0),disabled:!O},"Use Environment Variable ",O?"(Available)":"(Not Set)"))),s().createElement("div",{className:"biolm-settings-section"},s().createElement("h3",null,"Default Preferences"),s().createElement("div",{className:"biolm-defaults"},s().createElement("label",null,"Default Model ID:",s().createElement("input",{type:"text",className:"jp-mod-styled jp-InputGroup-input",value:c,onChange:e=>m(e.target.value),placeholder:"Optional",style:{marginLeft:"8px",width:"200px"}})),s().createElement("label",{style:{marginTop:"8px",display:"block"}},"Default Action:",s().createElement("select",{className:"jp-mod-styled",value:d,onChange:e=>p(e.target.value),style:{marginLeft:"8px"}},s().createElement("option",{value:"predict"},"predict"),s().createElement("option",{value:"generate"},"generate"),s().createElement("option",{value:"embed"},"embed"),s().createElement("option",{value:"encode"},"encode"),s().createElement("option",{value:"classify"},"classify"))),s().createElement("button",{className:"jp-mod-styled jp-mod-accept",onClick:async()=>{await async function(e){const t=u();t.defaultModel=e,y(t)}(c.trim()||void 0),await async function(e){const t=u();t.defaultAction=e,y(t)}(d),console.log("Default preferences have been saved")},style:{marginTop:"8px"}},"Save Defaults"))))};class S extends s().Component{constructor(e){super(e),this.state={activeTab:"models"}}render(){const{activeTab:e}=this.state,{notebookTracker:t}=this.props;return s().createElement("div",{className:"biolm-widget"},s().createElement("div",{className:"biolm-tabs"},s().createElement("button",{className:"biolm-tab-button "+("models"===e?"active":""),onClick:()=>this.setState({activeTab:"models"})},"🧠 Models"),s().createElement("button",{className:"biolm-tab-button "+("operations"===e?"active":""),onClick:()=>this.setState({activeTab:"operations"})},"⚙️ Operations"),s().createElement("button",{className:"biolm-tab-button "+("settings"===e?"active":""),onClick:()=>this.setState({activeTab:"settings"})},"🔑 Settings")),s().createElement("div",{className:"biolm-tab-content"},"models"===e&&s().createElement(w,{notebookTracker:t}),"operations"===e&&s().createElement(k,{notebookTracker:t}),"settings"===e&&s().createElement(j,{notebookTracker:t})))}}class x extends n.ReactWidget{constructor(e){super(),this._notebookTracker=e,this.addClass("biolm-widget-container"),this.id="biolm-widget",this.title.label="BioLM",this.title.caption="BioLM Model Browser",this.title.iconClass="jp-MaterialIcon jp-Icon jp-Icon-16",this.title.closable=!0}render(){return s().createElement(S,{notebookTracker:this._notebookTracker})}}const M={id:"jupyterlab-biolm:plugin",autoStart:!0,requires:[a.INotebookTracker],optional:[n.ICommandPalette],activate:async(e,t,o)=>{console.log("JupyterLab extension jupyterlab-biolm is activated!"),console.log("BioLM: Creating widget...");const a=new x(t);console.log("BioLM: Widget created with ID:",a.id),console.log("BioLM: Adding widget to left sidebar..."),e.shell.add(a,"left",{rank:1e3}),console.log("BioLM: Widget added to sidebar. Title:",a.title.label),e.commands.addCommand("biolm:open",{label:"Open BioLM",execute:()=>{e.shell.activateById(a.id)}}),o&&o.addItem({command:"biolm:open",category:"BioLM"});const n=async()=>{const e=g();if(e&&t.currentWidget)try{await v(t,e)}catch(e){console.error("Failed to set token for notebook:",e)}};t.widgetAdded.connect(()=>{n()}),t.currentWidget&&n()}}},606:e=>{var t,o,a=e.exports={};function n(){throw new Error("setTimeout has not been defined")}function i(){throw new Error("clearTimeout has not been defined")}function s(e){if(t===setTimeout)return setTimeout(e,0);if((t===n||!t)&&setTimeout)return t=setTimeout,setTimeout(e,0);try{return t(e,0)}catch(o){try{return t.call(null,e,0)}catch(o){return t.call(this,e,0)}}}!function(){try{t="function"==typeof setTimeout?setTimeout:n}catch(e){t=n}try{o="function"==typeof clearTimeout?clearTimeout:i}catch(e){o=i}}();var r,l=[],c=!1,m=-1;function d(){c&&r&&(c=!1,r.length?l=r.concat(l):m=-1,l.length&&p())}function p(){if(!c){var e=s(d);c=!0;for(var t=l.length;t;){for(r=l,l=[];++m<t;)r&&r[m].run();m=-1,t=l.length}r=null,c=!1,function(e){if(o===clearTimeout)return clearTimeout(e);if((o===i||!o)&&clearTimeout)return o=clearTimeout,clearTimeout(e);try{return o(e)}catch(t){try{return o.call(null,e)}catch(t){return o.call(this,e)}}}(e)}}function u(e,t){this.fun=e,this.array=t}function y(){}a.nextTick=function(e){var t=new Array(arguments.length-1);if(arguments.length>1)for(var o=1;o<arguments.length;o++)t[o-1]=arguments[o];l.push(new u(e,t)),1!==l.length||c||s(p)},u.prototype.run=function(){this.fun.apply(null,this.array)},a.title="browser",a.browser=!0,a.env={},a.argv=[],a.version="",a.versions={},a.on=y,a.addListener=y,a.once=y,a.off=y,a.removeListener=y,a.removeAllListeners=y,a.emit=y,a.prependListener=y,a.prependOnceListener=y,a.listeners=function(e){return[]},a.binding=function(e){throw new Error("process.binding is not supported")},a.cwd=function(){return"/"},a.chdir=function(e){throw new Error("process.chdir is not supported")},a.umask=function(){return 0}}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(self.webpackChunkjupyterlab_biolm=self.webpackChunkjupyterlab_biolm||[]).push([[665],{56:(n,o,e)=>{n.exports=function(n){var o=e.nc;o&&n.setAttribute("nonce",o)}},72:n=>{var o=[];function e(n){for(var e=-1,t=0;t<o.length;t++)if(o[t].identifier===n){e=t;break}return e}function t(n,t){for(var i={},a=[],l=0;l<n.length;l++){var c=n[l],p=t.base?c[0]+t.base:c[0],d=i[p]||0,s="".concat(p," ").concat(d);i[p]=d+1;var b=e(s),m={css:c[1],media:c[2],sourceMap:c[3],supports:c[4],layer:c[5]};if(-1!==b)o[b].references++,o[b].updater(m);else{var f=r(m,t);t.byIndex=l,o.splice(l,0,{identifier:s,updater:f,references:1})}a.push(s)}return a}function r(n,o){var e=o.domAPI(o);return e.update(n),function(o){if(o){if(o.css===n.css&&o.media===n.media&&o.sourceMap===n.sourceMap&&o.supports===n.supports&&o.layer===n.layer)return;e.update(n=o)}else e.remove()}}n.exports=function(n,r){var i=t(n=n||[],r=r||{});return function(n){n=n||[];for(var a=0;a<i.length;a++){var l=e(i[a]);o[l].references--}for(var c=t(n,r),p=0;p<i.length;p++){var d=e(i[p]);0===o[d].references&&(o[d].updater(),o.splice(d,1))}i=c}}},113:n=>{n.exports=function(n,o){if(o.styleSheet)o.styleSheet.cssText=n;else{for(;o.firstChild;)o.removeChild(o.firstChild);o.appendChild(document.createTextNode(n))}}},314:n=>{n.exports=function(n){var o=[];return o.toString=function(){return this.map(function(o){var e="",t=void 0!==o[5];return o[4]&&(e+="@supports (".concat(o[4],") {")),o[2]&&(e+="@media ".concat(o[2]," {")),t&&(e+="@layer".concat(o[5].length>0?" ".concat(o[5]):""," {")),e+=n(o),t&&(e+="}"),o[2]&&(e+="}"),o[4]&&(e+="}"),e}).join("")},o.i=function(n,e,t,r,i){"string"==typeof n&&(n=[[null,n,void 0]]);var a={};if(t)for(var l=0;l<this.length;l++){var c=this[l][0];null!=c&&(a[c]=!0)}for(var p=0;p<n.length;p++){var d=[].concat(n[p]);t&&a[d[0]]||(void 0!==i&&(void 0===d[5]||(d[1]="@layer".concat(d[5].length>0?" ".concat(d[5]):""," {").concat(d[1],"}")),d[5]=i),e&&(d[2]?(d[1]="@media ".concat(d[2]," {").concat(d[1],"}"),d[2]=e):d[2]=e),r&&(d[4]?(d[1]="@supports (".concat(d[4],") {").concat(d[1],"}"),d[4]=r):d[4]="".concat(r)),o.push(d))}},o}},540:n=>{n.exports=function(n){var o=document.createElement("style");return n.setAttributes(o,n.attributes),n.insert(o,n.options),o}},601:n=>{n.exports=function(n){return n[1]}},646:(n,o,e)=>{e.d(o,{A:()=>l});var t=e(601),r=e.n(t),i=e(314),a=e.n(i)()(r());a.push([n.id,"/**\n * BioLM JupyterLab Extension Styles\n */\n\n:root {\n --biolm-accent: #558BF7;\n --biolm-accent-hover: #3d6fd6;\n --biolm-accent-light: #e8f0ff;\n --biolm-border: var(--jp-border-color1);\n --biolm-background: var(--jp-layout-color0);\n --biolm-surface: var(--jp-layout-color1);\n --biolm-text: var(--jp-ui-font-color1);\n --biolm-text-secondary: var(--jp-ui-font-color2);\n}\n\n.biolm-widget-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.biolm-widget {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Tab Buttons */\n.biolm-tabs {\n display: flex;\n border-bottom: 1px solid var(--biolm-border);\n background: var(--biolm-surface);\n}\n\n.biolm-tab-button {\n flex: 1;\n padding: 8px 12px;\n border: none;\n background: transparent;\n color: var(--biolm-text-secondary);\n cursor: pointer;\n border-bottom: 2px solid transparent;\n transition: all 0.2s;\n font-size: 12px;\n}\n\n.biolm-tab-button:hover {\n background: var(--jp-layout-color2);\n color: var(--biolm-text);\n}\n\n.biolm-tab-button.active {\n color: var(--biolm-accent);\n border-bottom-color: var(--biolm-accent);\n font-weight: 500;\n}\n\n/* Tab Content */\n.biolm-tab-content {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n background: var(--biolm-background);\n}\n\n/* Tab Header (search, filters) */\n.biolm-tab-header {\n margin-bottom: 16px;\n}\n\n.biolm-tag-filter,\n.biolm-category-filter {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin-top: 8px;\n}\n\n/* Model Cards */\n.biolm-models-list,\n.biolm-operations-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.biolm-model-card,\n.biolm-operation-card {\n border: 1px solid var(--biolm-border);\n border-radius: 4px;\n padding: 12px;\n background: var(--biolm-surface);\n transition: box-shadow 0.2s;\n}\n\n.biolm-model-card:hover,\n.biolm-operation-card:hover {\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n.biolm-model-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.biolm-model-name {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--biolm-text);\n}\n\n.biolm-model-description {\n margin: 8px 0;\n font-size: 12px;\n color: var(--biolm-text-secondary);\n line-height: 1.4;\n}\n\n.biolm-model-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 8px;\n}\n\n.biolm-tag-button {\n padding: 4px 10px;\n border: 1px solid var(--biolm-accent);\n background: var(--biolm-accent-light);\n color: var(--biolm-accent);\n border-radius: 12px;\n font-size: 11px;\n cursor: pointer;\n transition: all 0.2s;\n font-weight: 500;\n}\n\n.biolm-tag-button:hover {\n background: var(--biolm-accent);\n color: white;\n transform: translateY(-1px);\n}\n\n/* Operation Cards */\n.biolm-operation-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 8px;\n}\n\n.biolm-operation-title {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--biolm-text);\n}\n\n.biolm-operation-category {\n font-size: 10px;\n padding: 2px 8px;\n background: var(--biolm-accent-light);\n color: var(--biolm-accent);\n border-radius: 10px;\n font-weight: 500;\n}\n\n.biolm-operation-description {\n margin: 8px 0;\n font-size: 12px;\n color: var(--biolm-text-secondary);\n line-height: 1.4;\n}\n\n.biolm-operation-parameters {\n margin: 8px 0;\n font-size: 11px;\n color: var(--biolm-text-secondary);\n}\n\n.biolm-operation-code {\n margin: 12px 0;\n padding: 8px;\n background: var(--jp-code-cell-background);\n border: 1px solid var(--biolm-border);\n border-radius: 4px;\n overflow-x: auto;\n}\n\n.biolm-operation-code pre {\n margin: 0;\n font-family: var(--jp-code-font-family);\n font-size: 11px;\n line-height: 1.4;\n color: var(--jp-content-font-color1);\n}\n\n.biolm-operation-code code {\n font-family: var(--jp-code-font-family);\n}\n\n.biolm-operation-actions {\n display: flex;\n gap: 8px;\n margin-top: 12px;\n}\n\n/* Settings */\n.biolm-settings-tab {\n display: flex;\n flex-direction: column;\n gap: 24px;\n}\n\n.biolm-settings-section {\n border-bottom: 1px solid var(--biolm-border);\n padding-bottom: 16px;\n}\n\n.biolm-settings-section:last-child {\n border-bottom: none;\n}\n\n.biolm-settings-section h3 {\n margin: 0 0 12px 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--biolm-text);\n}\n\n.biolm-env-notice {\n padding: 8px;\n background: var(--biolm-accent-light);\n border-left: 3px solid var(--biolm-accent);\n border-radius: 4px;\n margin-bottom: 12px;\n font-size: 11px;\n color: var(--biolm-text);\n}\n\n.biolm-profile-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-bottom: 16px;\n}\n\n.biolm-profile-card {\n border: 1px solid var(--biolm-border);\n border-radius: 4px;\n padding: 12px;\n background: var(--biolm-surface);\n}\n\n.biolm-profile-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.biolm-profile-header strong {\n color: var(--biolm-text);\n font-size: 13px;\n}\n\n.biolm-profile-edit {\n display: flex;\n flex-direction: column;\n}\n\n.biolm-connection-status {\n margin-top: 8px;\n padding: 6px;\n border-radius: 4px;\n font-size: 11px;\n}\n\n.biolm-connection-status.valid {\n background: #e8f5e9;\n color: #2e7d32;\n}\n\n.biolm-connection-status.invalid {\n background: #ffebee;\n color: #c62828;\n}\n\n.biolm-add-profile {\n margin-top: 16px;\n}\n\n.biolm-add-profile h4 {\n margin: 0 0 8px 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--biolm-text);\n}\n\n.biolm-env-option {\n margin-top: 12px;\n}\n\n.biolm-defaults {\n display: flex;\n flex-direction: column;\n}\n\n.biolm-defaults label {\n display: flex;\n align-items: center;\n font-size: 12px;\n color: var(--biolm-text);\n}\n\n/* Loading, Error, Empty States */\n.biolm-loading,\n.biolm-error,\n.biolm-empty {\n padding: 24px;\n text-align: center;\n color: var(--biolm-text-secondary);\n font-size: 12px;\n}\n\n.biolm-error {\n color: var(--jp-error-color1);\n}\n\n.biolm-error button {\n margin-top: 8px;\n}\n\n/* Scrollbar Styling */\n.biolm-tab-content::-webkit-scrollbar {\n width: 8px;\n}\n\n.biolm-tab-content::-webkit-scrollbar-track {\n background: var(--jp-layout-color1);\n}\n\n.biolm-tab-content::-webkit-scrollbar-thumb {\n background: var(--jp-border-color2);\n border-radius: 4px;\n}\n\n.biolm-tab-content::-webkit-scrollbar-thumb:hover {\n background: var(--jp-border-color1);\n}\n\n",""]);const l=a},659:n=>{var o={};n.exports=function(n,e){var t=function(n){if(void 0===o[n]){var e=document.querySelector(n);if(window.HTMLIFrameElement&&e instanceof window.HTMLIFrameElement)try{e=e.contentDocument.head}catch(n){e=null}o[n]=e}return o[n]}(n);if(!t)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");t.appendChild(e)}},665:(n,o,e)=>{e.r(o),e.d(o,{default:()=>g});var t=e(72),r=e.n(t),i=e(825),a=e.n(i),l=e(659),c=e.n(l),p=e(56),d=e.n(p),s=e(540),b=e.n(s),m=e(113),f=e.n(m),u=e(646),x={};x.styleTagTransform=f(),x.setAttributes=d(),x.insert=c().bind(null,"head"),x.domAPI=a(),x.insertStyleElement=b(),r()(u.A,x);const g=u.A&&u.A.locals?u.A.locals:void 0},825:n=>{n.exports=function(n){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var o=n.insertStyleElement(n);return{update:function(e){!function(n,o,e){var t="";e.supports&&(t+="@supports (".concat(e.supports,") {")),e.media&&(t+="@media ".concat(e.media," {"));var r=void 0!==e.layer;r&&(t+="@layer".concat(e.layer.length>0?" ".concat(e.layer):""," {")),t+=e.css,r&&(t+="}"),e.media&&(t+="}"),e.supports&&(t+="}");var i=e.sourceMap;i&&"undefined"!=typeof btoa&&(t+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),o.styleTagTransform(t,n,o.options)}(o,n,e)},remove:function(){!function(n){if(null===n.parentNode)return!1;n.parentNode.removeChild(n)}(o)}}}}}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var _JUPYTERLAB;(()=>{"use strict";var e,r,t,n,o,a,i,u,l,f,s,p,d,c,h,v,b,g,m,y={398:(e,r,t)=>{var n={"./index":()=>t.e(462).then(()=>()=>t(462)),"./extension":()=>t.e(462).then(()=>()=>t(462)),"./style":()=>t.e(665).then(()=>()=>t(665))},o=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then(()=>{throw new Error('Module "'+e+'" does not exist in container.')}),t.R=void 0,r),a=(e,r)=>{if(t.S){var n="default",o=t.S[n];if(o&&o!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[n]=e,t.I(n,r)}};t.d(r,{get:()=>o,init:()=>a})}},w={};function S(e){var r=w[e];if(void 0!==r)return r.exports;var t=w[e]={id:e,exports:{}};return y[e](t,t.exports,S),t.exports}S.m=y,S.c=w,S.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return S.d(r,{a:r}),r},S.d=(e,r)=>{for(var t in r)S.o(r,t)&&!S.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},S.f={},S.e=e=>Promise.all(Object.keys(S.f).reduce((r,t)=>(S.f[t](e,r),r),[])),S.u=e=>e+"."+{462:"26eef2cc68d48d263539",665:"57bb7975881a83531c46"}[e]+".js?v="+{462:"26eef2cc68d48d263539",665:"57bb7975881a83531c46"}[e],S.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),S.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="jupyterlab-biolm:",S.l=(t,n,o,a)=>{if(e[t])e[t].push(n);else{var i,u;if(void 0!==o)for(var l=document.getElementsByTagName("script"),f=0;f<l.length;f++){var s=l[f];if(s.getAttribute("src")==t||s.getAttribute("data-webpack")==r+o){i=s;break}}i||(u=!0,(i=document.createElement("script")).charset="utf-8",S.nc&&i.setAttribute("nonce",S.nc),i.setAttribute("data-webpack",r+o),i.src=t),e[t]=[n];var p=(r,n)=>{i.onerror=i.onload=null,clearTimeout(d);var o=e[t];if(delete e[t],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach(e=>e(n)),r)return r(n)},d=setTimeout(p.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=p.bind(null,i.onerror),i.onload=p.bind(null,i.onload),u&&document.head.appendChild(i)}},S.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{S.S={};var e={},r={};S.I=(t,n)=>{n||(n=[]);var o=r[t];if(o||(o=r[t]={}),!(n.indexOf(o)>=0)){if(n.push(o),e[t])return e[t];S.o(S.S,t)||(S.S[t]={});var a=S.S[t],i="jupyterlab-biolm",u=[];return"default"===t&&((e,r,t,n)=>{var o=a[e]=a[e]||{},u=o[r];(!u||!u.loaded&&(1!=!u.eager?n:i>u.from))&&(o[r]={get:()=>S.e(462).then(()=>()=>S(462)),from:i,eager:!1})})("jupyterlab-biolm","1.2.0"),e[t]=u.length?Promise.all(u).then(()=>e[t]=1):1}}})(),(()=>{var e;S.g.importScripts&&(e=S.g.location+"");var r=S.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),S.p=e})(),t=e=>{var r=e=>e.split(".").map(e=>+e==e?+e:e),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},n=(e,r)=>{e=t(e),r=t(r);for(var n=0;;){if(n>=e.length)return n<r.length&&"u"!=(typeof r[n])[0];var o=e[n],a=(typeof o)[0];if(n>=r.length)return"u"==a;var i=r[n],u=(typeof i)[0];if(a!=u)return"o"==a&&"n"==u||"s"==u||"u"==a;if("o"!=a&&"u"!=a&&o!=i)return o<i;n++}},o=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var n=1,a=1;a<e.length;a++)n--,t+="u"==(typeof(u=e[a]))[0]?"-":(n>0?".":"")+(n=2,u);return t}var i=[];for(a=1;a<e.length;a++){var u=e[a];i.push(0===u?"not("+l()+")":1===u?"("+l()+" || "+l()+")":2===u?i.pop()+" "+i.pop():o(u))}return l();function l(){return i.pop().replace(/^\((.+)\)$/,"$1")}},a=(e,r)=>{if(0 in e){r=t(r);var n=e[0],o=n<0;o&&(n=-n-1);for(var i=0,u=1,l=!0;;u++,i++){var f,s,p=u<e.length?(typeof e[u])[0]:"";if(i>=r.length||"o"==(s=(typeof(f=r[i]))[0]))return!l||("u"==p?u>n&&!o:""==p!=o);if("u"==s){if(!l||"u"!=p)return!1}else if(l)if(p==s)if(u<=n){if(f!=e[u])return!1}else{if(o?f>e[u]:f<e[u])return!1;f!=e[u]&&(l=!1)}else if("s"!=p&&"n"!=p){if(o||u<=n)return!1;l=!1,u--}else{if(u<=n||s<p!=o)return!1;l=!1}else"s"!=p&&"n"!=p&&(l=!1,u--)}}var d=[],c=d.pop.bind(d);for(i=1;i<e.length;i++){var h=e[i];d.push(1==h?c()|c():2==h?c()&c():h?a(h,r):!c())}return!!c()},i=(e,r)=>e&&S.o(e,r),u=e=>(e.loaded=1,e.get()),l=e=>Object.keys(e).reduce((r,t)=>(e[t].eager&&(r[t]=e[t]),r),{}),f=(e,r,t)=>{var o=t?l(e[r]):e[r];return Object.keys(o).reduce((e,r)=>!e||!o[e].loaded&&n(e,r)?r:e,0)},s=(e,r,t,n)=>"Unsatisfied version "+t+" from "+(t&&e[r][t].from)+" of shared singleton module "+r+" (required "+o(n)+")",p=e=>{throw new Error(e)},d=e=>{"undefined"!=typeof console&&console.warn&&console.warn(e)},c=(e,r,t)=>t?t():((e,r)=>p("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),h=(e=>function(r,t,n,o,a){var i=S.I(r);return i&&i.then&&!n?i.then(e.bind(e,r,S.S[r],t,!1,o,a)):e(r,S.S[r],t,n,o,a)})((e,r,t,n,o,l)=>{if(!i(r,t))return c(e,t,l);var p=f(r,t,n);return a(o,p)||d(s(r,t,p,o)),u(r[t][p])}),v={},b={345:()=>h("default","react",!1,[1,18,2,0]),762:()=>h("default","@jupyterlab/notebook",!1,[1,4,4,10]),986:()=>h("default","@jupyterlab/apputils",!1,[1,4,5,10])},g={462:[345,762,986]},m={},S.f.consumes=(e,r)=>{S.o(g,e)&&g[e].forEach(e=>{if(S.o(v,e))return r.push(v[e]);if(!m[e]){var t=r=>{v[e]=0,S.m[e]=t=>{delete S.c[e],t.exports=r()}};m[e]=!0;var n=r=>{delete v[e],S.m[e]=t=>{throw delete S.c[e],r}};try{var o=b[e]();o.then?r.push(v[e]=o.then(t).catch(n)):t(o)}catch(e){n(e)}}})},(()=>{var e={187:0};S.f.j=(r,t)=>{var n=S.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var o=new Promise((t,o)=>n=e[r]=[t,o]);t.push(n[2]=o);var a=S.p+S.u(r),i=new Error;S.l(a,t=>{if(S.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var o=t&&("load"===t.type?"missing":t.type),a=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+o+": "+a+")",i.name="ChunkLoadError",i.type=o,i.request=a,n[1](i)}},"chunk-"+r,r)}};var r=(r,t)=>{var n,o,[a,i,u]=t,l=0;if(a.some(r=>0!==e[r])){for(n in i)S.o(i,n)&&(S.m[n]=i[n]);u&&u(S)}for(r&&r(t);l<a.length;l++)o=a[l],S.o(e,o)&&e[o]&&e[o][0](),e[o]=0},t=self.webpackChunkjupyterlab_biolm=self.webpackChunkjupyterlab_biolm||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),S.nc=void 0;var j=S(398);(_JUPYTERLAB=void 0===_JUPYTERLAB?{}:_JUPYTERLAB)["jupyterlab-biolm"]=j})();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"packages": [
|
|
3
|
+
{
|
|
4
|
+
"name": "css-loader",
|
|
5
|
+
"versionInfo": "6.11.0",
|
|
6
|
+
"licenseId": "MIT",
|
|
7
|
+
"extractedText": "Copyright JS Foundation and other contributors\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"name": "process",
|
|
11
|
+
"versionInfo": "0.11.10",
|
|
12
|
+
"licenseId": "MIT",
|
|
13
|
+
"extractedText": "(The MIT License)\n\nCopyright (c) 2013 Roman Shtylman <shtylman@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "style-loader",
|
|
17
|
+
"versionInfo": "3.3.4",
|
|
18
|
+
"licenseId": "MIT",
|
|
19
|
+
"extractedText": "Copyright JS Foundation and other contributors\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: jupyterlab-biolm
|
|
3
|
+
Version: 1.2.0
|
|
4
|
+
Summary: JupyterLab extension for BioLM API integration
|
|
5
|
+
Project-URL: Homepage, https://github.com/BioLM/jupyterlab-biolm
|
|
6
|
+
Project-URL: Repository, https://github.com/BioLM/jupyterlab-biolm
|
|
7
|
+
Project-URL: Issues, https://github.com/BioLM/jupyterlab-biolm/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/BioLM/jupyterlab-biolm
|
|
9
|
+
Author: BioLM
|
|
10
|
+
License: BSD-3-Clause
|
|
11
|
+
Keywords: BioLM,Jupyter,JupyterLab,JupyterLab Extension
|
|
12
|
+
Classifier: Framework :: Jupyter
|
|
13
|
+
Classifier: Framework :: Jupyter :: JupyterLab
|
|
14
|
+
Classifier: Framework :: Jupyter :: JupyterLab :: 4
|
|
15
|
+
Classifier: Framework :: Jupyter :: JupyterLab :: Extensions
|
|
16
|
+
Classifier: Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt
|
|
17
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
18
|
+
Classifier: Programming Language :: Python
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Requires-Dist: biolmai
|
|
26
|
+
Requires-Dist: jupyter-server>=2.0.0
|
|
27
|
+
Requires-Dist: jupyterlab<5,>=4.0.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: jupyterlab<5,>=4.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-jupyter[server]>=0.5.0; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# BioLM JupyterLab Extension
|
|
35
|
+
|
|
36
|
+
A JupyterLab extension that provides a graphical interface for browsing BioLM models, inserting SDK code snippets, and managing authentication - all from within JupyterLab's sidebar.
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
### 🧠 Models Tab
|
|
41
|
+
- Browse all available BioLM models
|
|
42
|
+
- Search and filter models by name, description, or tags
|
|
43
|
+
- Click tags to insert code snippets with model + action pre-filled
|
|
44
|
+
- Copy model IDs to clipboard
|
|
45
|
+
- Expandable model descriptions
|
|
46
|
+
|
|
47
|
+
### ⚙️ Operations Tab
|
|
48
|
+
- Quick access to common SDK operation examples
|
|
49
|
+
- Searchable list of operations (Generate, Predict, Embed, etc.)
|
|
50
|
+
- One-click code insertion into notebook cells
|
|
51
|
+
- Organized by category
|
|
52
|
+
|
|
53
|
+
### 🔑 Settings Tab
|
|
54
|
+
- Manage multiple API key profiles
|
|
55
|
+
- Test API key connections
|
|
56
|
+
- Set default model and action preferences
|
|
57
|
+
- Respects `BIOLM_API_KEY` environment variable
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
### From PyPI (when available)
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install jupyterlab-biolm
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### From Source
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Clone the repository
|
|
71
|
+
git clone https://github.com/yourusername/jupyterlab-biolm.git
|
|
72
|
+
cd jupyterlab-biolm
|
|
73
|
+
|
|
74
|
+
# Install the extension
|
|
75
|
+
pip install -e .
|
|
76
|
+
|
|
77
|
+
# Build the extension
|
|
78
|
+
jlpm install
|
|
79
|
+
jlpm build
|
|
80
|
+
|
|
81
|
+
# Rebuild JupyterLab
|
|
82
|
+
jupyter lab build
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Usage
|
|
86
|
+
|
|
87
|
+
1. **Open the Extension**: The BioLM sidebar will appear in JupyterLab's left sidebar. If not visible, use the command palette (`Cmd/Ctrl + Shift + C`) and search for "Open BioLM".
|
|
88
|
+
|
|
89
|
+
2. **Configure API Key**:
|
|
90
|
+
- Go to the Settings tab
|
|
91
|
+
- Add a new profile with your API key
|
|
92
|
+
- Or use the `BIOLM_API_KEY` environment variable
|
|
93
|
+
|
|
94
|
+
3. **Browse Models**:
|
|
95
|
+
- Switch to the Models tab
|
|
96
|
+
- Search or filter by tags
|
|
97
|
+
- Click a tag button to insert code for that model + action
|
|
98
|
+
|
|
99
|
+
4. **Use Operations**:
|
|
100
|
+
- Switch to the Operations tab
|
|
101
|
+
- Browse common SDK operations
|
|
102
|
+
- Click "Insert" to add code to your active notebook cell
|
|
103
|
+
|
|
104
|
+
## Development
|
|
105
|
+
|
|
106
|
+
### Prerequisites
|
|
107
|
+
|
|
108
|
+
- Node.js >= 16
|
|
109
|
+
- Python >= 3.8
|
|
110
|
+
- JupyterLab >= 4.0.0
|
|
111
|
+
|
|
112
|
+
### Setup
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Install dependencies
|
|
116
|
+
jlpm install
|
|
117
|
+
|
|
118
|
+
# Build TypeScript
|
|
119
|
+
jlpm build:lib
|
|
120
|
+
|
|
121
|
+
# Build extension in development mode
|
|
122
|
+
jlpm build:labextension:dev
|
|
123
|
+
|
|
124
|
+
# Watch for changes
|
|
125
|
+
jlpm watch
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Project Structure
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
jupyterlab-biolm/
|
|
132
|
+
├── src/ # TypeScript source
|
|
133
|
+
│ ├── index.ts # Extension entry point
|
|
134
|
+
│ ├── widget.tsx # Main sidebar widget
|
|
135
|
+
│ ├── api/ # API client
|
|
136
|
+
│ ├── components/ # React components
|
|
137
|
+
│ ├── services/ # Business logic
|
|
138
|
+
│ └── data/ # Static data
|
|
139
|
+
├── style/ # CSS styles
|
|
140
|
+
├── schema/ # Settings schema
|
|
141
|
+
└── jupyterlab_biolm/ # Python package
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Configuration
|
|
145
|
+
|
|
146
|
+
The extension stores settings in JupyterLab's settings system. You can configure:
|
|
147
|
+
|
|
148
|
+
- **API Key Profiles**: Multiple named profiles with different API keys
|
|
149
|
+
- **Active Profile**: Which profile to use (or environment variable)
|
|
150
|
+
- **Default Model**: Default model ID for code generation
|
|
151
|
+
- **Default Action**: Default action (predict, generate, etc.)
|
|
152
|
+
|
|
153
|
+
## API Integration
|
|
154
|
+
|
|
155
|
+
The extension fetches model metadata from `https://api.biolm.ai/models`. Models are cached for 5 minutes to reduce API calls.
|
|
156
|
+
|
|
157
|
+
## Requirements
|
|
158
|
+
|
|
159
|
+
- JupyterLab >= 4.0.0
|
|
160
|
+
- React >= 18.0.0
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
BSD-3-Clause
|
|
165
|
+
|
|
166
|
+
## Support
|
|
167
|
+
|
|
168
|
+
For issues and feature requests, please visit the [GitHub repository](https://github.com/yourusername/jupyterlab-biolm).
|
|
169
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
jupyterlab_biolm/__init__.py,sha256=-5AVwh2WMMmrQScKD9vWSEimIFtWeYFiCXgzgoLE4wg,675
|
|
2
|
+
jupyterlab_biolm/_hatchling.py,sha256=Zy7ZAKbKeLNECa-YygPQFhmJ1gej3iNy1ViLjvtEvdU,1312
|
|
3
|
+
jupyterlab_biolm/serverextension.py,sha256=IGSGPpJaXr3618fAO13_s9c5yYNSFu8wW2obJQ2SFyA,13299
|
|
4
|
+
jupyterlab_biolm-1.2.0.data/data/etc/jupyter/jupyter_server_config.d/jupyterlab-biolm.json,sha256=M5cfhLivmNY3jQILemSspiTpVhllR6uOJ1EoSID9Pqc,108
|
|
5
|
+
jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/package.json,sha256=7jdOyUdGq_FWPulGqTfLIIEvimQdLkwCAFJaoj_d66s,3675
|
|
6
|
+
jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/schemas/jupyterlab-biolm/package.json.orig,sha256=tRaJg_4SFEBVK0VcdTbfSfMtuJUbWX8J5wkYFhziE7I,3533
|
|
7
|
+
jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/schemas/jupyterlab-biolm/plugin.json,sha256=8mqtH3mWiVcJoKFfkHlywZr8VS3cT8d5JS45WKv1RPA,1291
|
|
8
|
+
jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/462.26eef2cc68d48d263539.js,sha256=Ju7yzGjUjSY1ORdX4IUi0ywxnXNoHEaspmcmMPCOaWU,25670
|
|
9
|
+
jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/665.57bb7975881a83531c46.js,sha256=V7t5dYgag1McRpVgZxZa53bBQGZmKUeuAB9ugdmBdlM,10531
|
|
10
|
+
jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/remoteEntry.8d19a58608019bf31dd9.js,sha256=jRmlhggBm_Md2aCDB9ZBYcemq_4Pp55pyJgVz66JUYY,6689
|
|
11
|
+
jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/style.js,sha256=2Xz2qLXtkByHV8HDcpotagMYijddqRYOlfw8KF-3nl8,160
|
|
12
|
+
jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/third-party-licenses.json,sha256=ZFu42jcik5tb1abgGVbqHDx7XrVgqKf0NbubGeS3do8,3695
|
|
13
|
+
jupyterlab_biolm-1.2.0.data/data/share/jupyter/lab/schemas/jupyterlab-biolm/plugin.json,sha256=8mqtH3mWiVcJoKFfkHlywZr8VS3cT8d5JS45WKv1RPA,1291
|
|
14
|
+
jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/install.json,sha256=S7CqoJs728O7vb1q2kV17cMA4IKz0BCciTGMaVI3Rq4,68
|
|
15
|
+
jupyterlab_biolm-1.2.0.dist-info/METADATA,sha256=qPL6srUIhoVmtZESCkAvH4ZVy9iWDMkWsM1528LHtnM,4861
|
|
16
|
+
jupyterlab_biolm-1.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
17
|
+
jupyterlab_biolm-1.2.0.dist-info/RECORD,,
|