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.
Files changed (17) hide show
  1. jupyterlab_biolm/__init__.py +23 -0
  2. jupyterlab_biolm/_hatchling.py +37 -0
  3. jupyterlab_biolm/serverextension.py +318 -0
  4. jupyterlab_biolm-1.2.0.data/data/etc/jupyter/jupyter_server_config.d/jupyterlab-biolm.json +8 -0
  5. jupyterlab_biolm-1.2.0.data/data/share/jupyter/lab/schemas/jupyterlab-biolm/plugin.json +49 -0
  6. jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/install.json +5 -0
  7. jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/package.json +124 -0
  8. jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/schemas/jupyterlab-biolm/package.json.orig +119 -0
  9. jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/schemas/jupyterlab-biolm/plugin.json +49 -0
  10. jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/462.26eef2cc68d48d263539.js +1 -0
  11. jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/665.57bb7975881a83531c46.js +1 -0
  12. jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/remoteEntry.8d19a58608019bf31dd9.js +1 -0
  13. jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/style.js +4 -0
  14. jupyterlab_biolm-1.2.0.data/data/share/jupyter/labextensions/jupyterlab-biolm/static/third-party-licenses.json +22 -0
  15. jupyterlab_biolm-1.2.0.dist-info/METADATA +169 -0
  16. jupyterlab_biolm-1.2.0.dist-info/RECORD +17 -0
  17. 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,8 @@
1
+ {
2
+ "ServerApp": {
3
+ "jpserver_extensions": {
4
+ "jupyterlab_biolm.serverextension": true
5
+ }
6
+ }
7
+ }
8
+
@@ -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,5 @@
1
+ {
2
+ "packageManager": "npm",
3
+ "packageName": "jupyterlab-biolm"
4
+ }
5
+
@@ -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,4 @@
1
+ /* This is a generated file of CSS imports */
2
+ /* It was generated by @jupyterlab/builder in Build.ensureAssets() */
3
+
4
+ import 'jupyterlab-biolm/style/index.css';
@@ -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,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any