simonduerr commited on
Commit
514575e
1 Parent(s): 40b62b9

Upload folder using huggingface_hub

Browse files
.gitignore ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .eggs/
2
+ dist/
3
+ *.pyc
4
+ __pycache__/
5
+ *.py[cod]
6
+ *$py.class
7
+ __tmp/*
8
+ *.pyi
9
+ .mypycache
10
+ .ruff_cache
11
+ node_modules
12
+ backend/**/templates/
README.md CHANGED
@@ -1,17 +1,427 @@
1
-
2
  ---
3
- tags: [gradio-custom-component,machine learning,reproducibility,visualization,gradio,gradio-template-File,protein]
4
- title: gradio_molecule3d V0.0.5
5
- colorFrom: purple
6
- colorTo: pink
7
- sdk: docker
 
8
  pinned: false
9
- license: apache-2.0
10
  ---
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
- # Name: gradio_molecule3d
14
 
15
- Description: Molecule3D custom component to visualize pdb or sdf files using 3Dmol.js
 
16
 
17
- Install with: pip install gradio_molecule3d
 
 
 
 
 
 
 
 
1
  ---
2
+ tags: [gradio-custom-component, File]
3
+ title: gradio_molecule3d
4
+ short_description: A gradio custom component
5
+ colorFrom: blue
6
+ colorTo: yellow
7
+ sdk: gradio
8
  pinned: false
9
+ app_file: space.py
10
  ---
11
 
12
+ # `gradio_molecule3d`
13
+ <a href="https://pypi.org/project/gradio_molecule3d/" target="_blank"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/gradio_molecule3d"></a>
14
+
15
+ Python library for easily interacting with trained machine learning models
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install gradio_molecule3d
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```python
26
+
27
+ import gradio as gr
28
+ from gradio_molecule3d import Molecule3D
29
+
30
+
31
+ example = Molecule3D().example_value()
32
+
33
+
34
+ reps = [
35
+ {
36
+ "model": 0,
37
+ "chain": "",
38
+ "resname": "",
39
+ "style": "stick",
40
+ "color": "whiteCarbon",
41
+ "residue_range": "",
42
+ "around": 0,
43
+ "byres": False,
44
+ "visible": False
45
+ }
46
+ ]
47
+
48
+
49
+
50
+ def predict(x):
51
+ print("predict function", x)
52
+ print(x.name)
53
+ return x
54
+
55
+ with gr.Blocks() as demo:
56
+ gr.Markdown("# Molecule3D")
57
+ inp = Molecule3D(label="Molecule3D", reps=reps)
58
+ out = Molecule3D(label="Output", reps=reps)
59
+
60
+ btn = gr.Button("Predict")
61
+ gr.Markdown("""
62
+ You can configure the default rendering of the molecule by adding a list of representations
63
+ <pre>
64
+ reps = [
65
+ {
66
+ "model": 0,
67
+ "style": "cartoon",
68
+ "color": "whiteCarbon",
69
+ "residue_range": "",
70
+ "around": 0,
71
+ "byres": False,
72
+ },
73
+ {
74
+ "model": 0,
75
+ "chain": "A",
76
+ "resname": "HIS",
77
+ "style": "stick",
78
+ "color": "red"
79
+ }
80
+ ]
81
+ </pre>
82
+ """)
83
+ btn.click(predict, inputs=inp, outputs=out)
84
+
85
+
86
+ if __name__ == "__main__":
87
+ demo.launch()
88
+
89
+ ```
90
+
91
+ ## `Molecule3D`
92
+
93
+ ### Initialization
94
+
95
+ <table>
96
+ <thead>
97
+ <tr>
98
+ <th align="left">name</th>
99
+ <th align="left" style="width: 25%;">type</th>
100
+ <th align="left">default</th>
101
+ <th align="left">description</th>
102
+ </tr>
103
+ </thead>
104
+ <tbody>
105
+ <tr>
106
+ <td align="left"><code>value</code></td>
107
+ <td align="left" style="width: 25%;">
108
+
109
+ ```python
110
+ str | list[str] | Callable | None
111
+ ```
112
+
113
+ </td>
114
+ <td align="left"><code>None</code></td>
115
+ <td align="left">Default file(s) to display, given as a str file path or URL, or a list of str file paths / URLs. If callable, the function will be called whenever the app loads to set the initial value of the component.</td>
116
+ </tr>
117
+
118
+ <tr>
119
+ <td align="left"><code>reps</code></td>
120
+ <td align="left" style="width: 25%;">
121
+
122
+ ```python
123
+ Any | None
124
+ ```
125
+
126
+ </td>
127
+ <td align="left"><code>[]</code></td>
128
+ <td align="left">None</td>
129
+ </tr>
130
+
131
+ <tr>
132
+ <td align="left"><code>config</code></td>
133
+ <td align="left" style="width: 25%;">
134
+
135
+ ```python
136
+ Any | None
137
+ ```
138
+
139
+ </td>
140
+ <td align="left"><code>{
141
+ "backgroundColor": "white",
142
+ "orthographic": False,
143
+ "disableFog": False,
144
+ }</code></td>
145
+ <td align="left">dictionary of config options</td>
146
+ </tr>
147
+
148
+ <tr>
149
+ <td align="left"><code>confidenceLabel</code></td>
150
+ <td align="left" style="width: 25%;">
151
+
152
+ ```python
153
+ str | None
154
+ ```
155
+
156
+ </td>
157
+ <td align="left"><code>"pLDDT"</code></td>
158
+ <td align="left">label for confidence values stored in the bfactor column of a pdb file</td>
159
+ </tr>
160
+
161
+ <tr>
162
+ <td align="left"><code>file_count</code></td>
163
+ <td align="left" style="width: 25%;">
164
+
165
+ ```python
166
+ Literal["single", "multiple", "directory"]
167
+ ```
168
+
169
+ </td>
170
+ <td align="left"><code>"single"</code></td>
171
+ <td align="left">if single, allows user to upload one file. If "multiple", user uploads multiple files. If "directory", user uploads all files in selected directory. Return type will be list for each file in case of "multiple" or "directory".</td>
172
+ </tr>
173
+
174
+ <tr>
175
+ <td align="left"><code>file_types</code></td>
176
+ <td align="left" style="width: 25%;">
177
+
178
+ ```python
179
+ list[str] | None
180
+ ```
181
+
182
+ </td>
183
+ <td align="left"><code>None</code></td>
184
+ <td align="left">List of file extensions or types of files to be uploaded (e.g. ['image', '.json', '.mp4']). "file" allows any file to be uploaded, "image" allows only image files to be uploaded, "audio" allows only audio files to be uploaded, "video" allows only video files to be uploaded, "text" allows only text files to be uploaded.</td>
185
+ </tr>
186
+
187
+ <tr>
188
+ <td align="left"><code>type</code></td>
189
+ <td align="left" style="width: 25%;">
190
+
191
+ ```python
192
+ Literal["filepath", "binary"]
193
+ ```
194
+
195
+ </td>
196
+ <td align="left"><code>"filepath"</code></td>
197
+ <td align="left">Type of value to be returned by component. "file" returns a temporary file object with the same base name as the uploaded file, whose full path can be retrieved by file_obj.name, "binary" returns an bytes object.</td>
198
+ </tr>
199
+
200
+ <tr>
201
+ <td align="left"><code>label</code></td>
202
+ <td align="left" style="width: 25%;">
203
+
204
+ ```python
205
+ str | None
206
+ ```
207
+
208
+ </td>
209
+ <td align="left"><code>None</code></td>
210
+ <td align="left">The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.</td>
211
+ </tr>
212
+
213
+ <tr>
214
+ <td align="left"><code>every</code></td>
215
+ <td align="left" style="width: 25%;">
216
+
217
+ ```python
218
+ Timer | float | None
219
+ ```
220
+
221
+ </td>
222
+ <td align="left"><code>None</code></td>
223
+ <td align="left">Continously calls `value` to recalculate it if `value` is a function (has no effect otherwise). Can provide a Timer whose tick resets `value`, or a float that provides the regular interval for the reset Timer.</td>
224
+ </tr>
225
+
226
+ <tr>
227
+ <td align="left"><code>inputs</code></td>
228
+ <td align="left" style="width: 25%;">
229
+
230
+ ```python
231
+ Component | Sequence[Component] | set[Component] | None
232
+ ```
233
+
234
+ </td>
235
+ <td align="left"><code>None</code></td>
236
+ <td align="left">Components that are used as inputs to calculate `value` if `value` is a function (has no effect otherwise). `value` is recalculated any time the inputs change.</td>
237
+ </tr>
238
+
239
+ <tr>
240
+ <td align="left"><code>show_label</code></td>
241
+ <td align="left" style="width: 25%;">
242
+
243
+ ```python
244
+ bool | None
245
+ ```
246
+
247
+ </td>
248
+ <td align="left"><code>None</code></td>
249
+ <td align="left">if True, will display label.</td>
250
+ </tr>
251
+
252
+ <tr>
253
+ <td align="left"><code>container</code></td>
254
+ <td align="left" style="width: 25%;">
255
+
256
+ ```python
257
+ bool
258
+ ```
259
+
260
+ </td>
261
+ <td align="left"><code>True</code></td>
262
+ <td align="left">If True, will place the component in a container - providing some extra padding around the border.</td>
263
+ </tr>
264
+
265
+ <tr>
266
+ <td align="left"><code>scale</code></td>
267
+ <td align="left" style="width: 25%;">
268
+
269
+ ```python
270
+ int | None
271
+ ```
272
+
273
+ </td>
274
+ <td align="left"><code>None</code></td>
275
+ <td align="left">relative size compared to adjacent Components. For example if Components A and B are in a Row, and A has scale=2, and B has scale=1, A will be twice as wide as B. Should be an integer. scale applies in Rows, and to top-level Components in Blocks where fill_height=True.</td>
276
+ </tr>
277
+
278
+ <tr>
279
+ <td align="left"><code>min_width</code></td>
280
+ <td align="left" style="width: 25%;">
281
+
282
+ ```python
283
+ int
284
+ ```
285
+
286
+ </td>
287
+ <td align="left"><code>160</code></td>
288
+ <td align="left">minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.</td>
289
+ </tr>
290
+
291
+ <tr>
292
+ <td align="left"><code>height</code></td>
293
+ <td align="left" style="width: 25%;">
294
+
295
+ ```python
296
+ int | float | None
297
+ ```
298
+
299
+ </td>
300
+ <td align="left"><code>None</code></td>
301
+ <td align="left">The maximum height of the file component, specified in pixels if a number is passed, or in CSS units if a string is passed. If more files are uploaded than can fit in the height, a scrollbar will appear.</td>
302
+ </tr>
303
+
304
+ <tr>
305
+ <td align="left"><code>interactive</code></td>
306
+ <td align="left" style="width: 25%;">
307
+
308
+ ```python
309
+ bool | None
310
+ ```
311
+
312
+ </td>
313
+ <td align="left"><code>None</code></td>
314
+ <td align="left">if True, will allow users to upload a file; if False, can only be used to display files. If not provided, this is inferred based on whether the component is used as an input or output.</td>
315
+ </tr>
316
+
317
+ <tr>
318
+ <td align="left"><code>visible</code></td>
319
+ <td align="left" style="width: 25%;">
320
+
321
+ ```python
322
+ bool
323
+ ```
324
+
325
+ </td>
326
+ <td align="left"><code>True</code></td>
327
+ <td align="left">If False, component will be hidden.</td>
328
+ </tr>
329
+
330
+ <tr>
331
+ <td align="left"><code>elem_id</code></td>
332
+ <td align="left" style="width: 25%;">
333
+
334
+ ```python
335
+ str | None
336
+ ```
337
+
338
+ </td>
339
+ <td align="left"><code>None</code></td>
340
+ <td align="left">An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.</td>
341
+ </tr>
342
+
343
+ <tr>
344
+ <td align="left"><code>elem_classes</code></td>
345
+ <td align="left" style="width: 25%;">
346
+
347
+ ```python
348
+ list[str] | str | None
349
+ ```
350
+
351
+ </td>
352
+ <td align="left"><code>None</code></td>
353
+ <td align="left">An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.</td>
354
+ </tr>
355
+
356
+ <tr>
357
+ <td align="left"><code>render</code></td>
358
+ <td align="left" style="width: 25%;">
359
+
360
+ ```python
361
+ bool
362
+ ```
363
+
364
+ </td>
365
+ <td align="left"><code>True</code></td>
366
+ <td align="left">If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.</td>
367
+ </tr>
368
+
369
+ <tr>
370
+ <td align="left"><code>key</code></td>
371
+ <td align="left" style="width: 25%;">
372
+
373
+ ```python
374
+ int | str | None
375
+ ```
376
+
377
+ </td>
378
+ <td align="left"><code>None</code></td>
379
+ <td align="left">if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.</td>
380
+ </tr>
381
+
382
+ <tr>
383
+ <td align="left"><code>showviewer</code></td>
384
+ <td align="left" style="width: 25%;">
385
+
386
+ ```python
387
+ bool
388
+ ```
389
+
390
+ </td>
391
+ <td align="left"><code>True</code></td>
392
+ <td align="left">If True, will display the 3Dmol.js viewer. If False, will not display the 3Dmol.js viewer.</td>
393
+ </tr>
394
+ </tbody></table>
395
+
396
+
397
+ ### Events
398
+
399
+ | name | description |
400
+ |:-----|:------------|
401
+ | `change` | Triggered when the value of the Molecule3D changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
402
+ | `select` | Event listener for when the user selects or deselects the Molecule3D. Uses event data gradio.SelectData to carry `value` referring to the label of the Molecule3D, and `selected` to refer to state of the Molecule3D. See EventData documentation on how to use this event data |
403
+ | `clear` | This listener is triggered when the user clears the Molecule3D using the clear button for the component. |
404
+ | `upload` | This listener is triggered when the user uploads a file into the Molecule3D. |
405
+ | `delete` | This listener is triggered when the user deletes and item from the Molecule3D. Uses event data gradio.DeletedFileData to carry `value` referring to the file that was deleted as an instance of FileData. See EventData documentation on how to use this event data |
406
+
407
+
408
+
409
+ ### User function
410
+
411
+ The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
412
+
413
+ - When used as an Input, the component only impacts the input signature of the user function.
414
+ - When used as an output, the component only impacts the return signature of the user function.
415
 
416
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
417
 
418
+ - **As output:** Is passed, passes the file as a `str` or `bytes` object, or a list of `str` or list of `bytes` objects, depending on `type` and `file_count`.
419
+ - **As input:** Should return, expects a `str` filepath or URL, or a `list[str]` of filepaths/URLs.
420
 
421
+ ```python
422
+ def predict(
423
+ value: bytes | str | list[bytes] | list[str] | None
424
+ ) -> str | list[str] | None:
425
+ return value
426
+ ```
427
+
app.py CHANGED
@@ -2,9 +2,8 @@
2
  import gradio as gr
3
  from gradio_molecule3d import Molecule3D
4
 
5
- import os
6
 
7
- example = Molecule3D().example_inputs()
8
 
9
 
10
  reps = [
@@ -40,25 +39,18 @@ with gr.Blocks() as demo:
40
  reps = [
41
  {
42
  "model": 0,
43
- "chain": "",
44
- "resname": "",
45
  "style": "cartoon",
46
  "color": "whiteCarbon",
47
  "residue_range": "",
48
  "around": 0,
49
  "byres": False,
50
- "visible": False,
51
  },
52
  {
53
  "model": 0,
54
  "chain": "A",
55
  "resname": "HIS",
56
  "style": "stick",
57
- "color": "red",
58
- "residue_range": "",
59
- "around": 0,
60
- "byres": False,
61
- "visible": False,
62
  }
63
  ]
64
  </pre>
@@ -66,5 +58,5 @@ with gr.Blocks() as demo:
66
  btn.click(predict, inputs=inp, outputs=out)
67
 
68
 
69
- if __name__ == '__main__':
70
- demo.launch()
 
2
  import gradio as gr
3
  from gradio_molecule3d import Molecule3D
4
 
 
5
 
6
+ example = Molecule3D().example_value()
7
 
8
 
9
  reps = [
 
39
  reps = [
40
  {
41
  "model": 0,
 
 
42
  "style": "cartoon",
43
  "color": "whiteCarbon",
44
  "residue_range": "",
45
  "around": 0,
46
  "byres": False,
 
47
  },
48
  {
49
  "model": 0,
50
  "chain": "A",
51
  "resname": "HIS",
52
  "style": "stick",
53
+ "color": "red"
 
 
 
 
54
  }
55
  ]
56
  </pre>
 
58
  btn.click(predict, inputs=inp, outputs=out)
59
 
60
 
61
+ if __name__ == "__main__":
62
+ demo.launch()
requirements.txt CHANGED
@@ -1 +1 @@
1
- gradio_molecule3d==0.0.5
 
1
+ gradio_molecule3d
space.py CHANGED
@@ -3,7 +3,7 @@ import gradio as gr
3
  from app import demo as app
4
  import os
5
 
6
- _docs = {'Molecule3D': {'description': 'Creates a file component that allows uploading generic file (when used as an input) and or displaying generic files (output).', 'members': {'__init__': {'value': {'type': 'str | list[str] | Callable | None', 'default': 'None', 'description': 'Default file to display, given as str file path. If callable, the function will be called whenever the app loads to set the initial value of the component.'}, 'reps': {'type': 'Any | None', 'default': '[]', 'description': None}, 'config': {'type': 'Any | None', 'default': '{\n "backgroundColor": "white",\n "orthographic": False,\n "disableFog": False,\n}', 'description': 'dictionary of config options'}, 'confidenceLabel': {'type': 'str | None', 'default': '"pLDDT"', 'description': 'label for confidence values stored in the bfactor column of a pdb file'}, 'file_count': {'type': '"single" | "multiple" | "directory"', 'default': '"single"', 'description': 'if single, allows user to upload one file. If "multiple", user uploads multiple files. If "directory", user uploads all files in selected directory. Return type will be list for each file in case of "multiple" or "directory".'}, 'file_types': {'type': 'list[str] | None', 'default': 'None', 'description': 'List of file extensions or types of files to be uploaded (e.g. [\'image\', \'.json\', \'.mp4\']). "file" allows any file to be uploaded, "image" allows only image files to be uploaded, "audio" allows only audio files to be uploaded, "video" allows only video files to be uploaded, "text" allows only text files to be uploaded.'}, 'type': {'type': '"filepath" | "binary"', 'default': '"filepath"', 'description': 'Type of value to be returned by component. "file" returns a temporary file object with the same base name as the uploaded file, whose full path can be retrieved by file_obj.name, "binary" returns an bytes object.'}, 'label': {'type': 'str | None', 'default': 'None', 'description': 'The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.'}, 'every': {'type': 'float | None', 'default': 'None', 'description': "If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. Queue must be enabled. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute."}, 'show_label': {'type': 'bool | None', 'default': 'None', 'description': 'if True, will display label.'}, 'container': {'type': 'bool', 'default': 'True', 'description': 'If True, will place the component in a container - providing some extra padding around the border.'}, 'scale': {'type': 'int | None', 'default': 'None', 'description': 'relative width compared to adjacent Components in a Row. For example, if Component A has scale=2, and Component B has scale=1, A will be twice as wide as B. Should be an integer.'}, 'min_width': {'type': 'int', 'default': '160', 'description': 'minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.'}, 'height': {'type': 'int | float | None', 'default': 'None', 'description': 'The maximum height of the file component, in pixels. If more files are uploaded than can fit in the height, a scrollbar will appear.'}, 'interactive': {'type': 'bool | None', 'default': 'None', 'description': 'if True, will allow users to upload a file; if False, can only be used to display files. If not provided, this is inferred based on whether the component is used as an input or output.'}, 'visible': {'type': 'bool', 'default': 'True', 'description': 'If False, component will be hidden.'}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': 'An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': 'An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'render': {'type': 'bool', 'default': 'True', 'description': 'If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.'}, 'showviewer': {'type': 'bool', 'default': 'True', 'description': 'If True, will display the 3Dmol.js viewer. If False, will not display the 3Dmol.js viewer.'}}, 'postprocess': {'value': {'type': 'str | list[str] | None', 'description': "The output data received by the component from the user's function in the backend."}}, 'preprocess': {'return': {'type': 'bytes\n | gradio.utils.NamedString\n | list[bytes | gradio.utils.NamedString]\n | None', 'description': "The preprocessed input data sent to the user's function in the backend."}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the Molecule3D changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}, 'select': {'type': None, 'default': None, 'description': 'Event listener for when the user selects or deselects the Molecule3D. Uses event data gradio.SelectData to carry `value` referring to the label of the Molecule3D, and `selected` to refer to state of the Molecule3D. See EventData documentation on how to use this event data'}, 'clear': {'type': None, 'default': None, 'description': 'This listener is triggered when the user clears the Molecule3D using the X button for the component.'}, 'upload': {'type': None, 'default': None, 'description': 'This listener is triggered when the user uploads a file into the Molecule3D.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'Molecule3D': []}}}
7
 
8
  abs_path = os.path.join(os.path.dirname(__file__), "css.css")
9
 
@@ -24,7 +24,7 @@ with gr.Blocks(
24
  <a href="https://pypi.org/project/gradio_molecule3d/" target="_blank"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/gradio_molecule3d"></a>
25
  </div>
26
 
27
- Molecule3D custom component to visualize pdb or sdf files using 3Dmol.js
28
  """, elem_classes=["md-custom"], header_links=True)
29
  app.render()
30
  gr.Markdown(
@@ -42,9 +42,8 @@ pip install gradio_molecule3d
42
  import gradio as gr
43
  from gradio_molecule3d import Molecule3D
44
 
45
- import os
46
 
47
- example = Molecule3D().example_inputs()
48
 
49
 
50
  reps = [
@@ -80,25 +79,18 @@ with gr.Blocks() as demo:
80
  reps = [
81
  {
82
  "model": 0,
83
- "chain": "",
84
- "resname": "",
85
  "style": "cartoon",
86
  "color": "whiteCarbon",
87
  "residue_range": "",
88
  "around": 0,
89
  "byres": False,
90
- "visible": False,
91
  },
92
  {
93
  "model": 0,
94
  "chain": "A",
95
  "resname": "HIS",
96
  "style": "stick",
97
- "color": "red",
98
- "residue_range": "",
99
- "around": 0,
100
- "byres": False,
101
- "visible": False,
102
  }
103
  ]
104
  </pre>
@@ -106,8 +98,8 @@ with gr.Blocks() as demo:
106
  btn.click(predict, inputs=inp, outputs=out)
107
 
108
 
109
- if __name__ == '__main__':
110
- demo.launch()
111
 
112
  ```
113
  """, elem_classes=["md-custom"], header_links=True)
@@ -139,15 +131,12 @@ The impact on the users predict function varies depending on whether the compone
139
 
140
  The code snippet below is accurate in cases where the component is used as both an input and an output.
141
 
142
- - **As input:** Is passed, the preprocessed input data sent to the user's function in the backend.
143
- - **As output:** Should return, the output data received by the component from the user's function in the backend.
144
 
145
  ```python
146
  def predict(
147
- value: bytes
148
- | gradio.utils.NamedString
149
- | list[bytes | gradio.utils.NamedString]
150
- | None
151
  ) -> str | list[str] | None:
152
  return value
153
  ```
 
3
  from app import demo as app
4
  import os
5
 
6
+ _docs = {'Molecule3D': {'description': 'Creates a file component that allows uploading one or more generic files (when used as an input) or displaying generic files or URLs for download (as output).\n', 'members': {'__init__': {'value': {'type': 'str | list[str] | Callable | None', 'default': 'None', 'description': 'Default file(s) to display, given as a str file path or URL, or a list of str file paths / URLs. If callable, the function will be called whenever the app loads to set the initial value of the component.'}, 'reps': {'type': 'Any | None', 'default': '[]', 'description': None}, 'config': {'type': 'Any | None', 'default': '{\n "backgroundColor": "white",\n "orthographic": False,\n "disableFog": False,\n}', 'description': 'dictionary of config options'}, 'confidenceLabel': {'type': 'str | None', 'default': '"pLDDT"', 'description': 'label for confidence values stored in the bfactor column of a pdb file'}, 'file_count': {'type': 'Literal["single", "multiple", "directory"]', 'default': '"single"', 'description': 'if single, allows user to upload one file. If "multiple", user uploads multiple files. If "directory", user uploads all files in selected directory. Return type will be list for each file in case of "multiple" or "directory".'}, 'file_types': {'type': 'list[str] | None', 'default': 'None', 'description': 'List of file extensions or types of files to be uploaded (e.g. [\'image\', \'.json\', \'.mp4\']). "file" allows any file to be uploaded, "image" allows only image files to be uploaded, "audio" allows only audio files to be uploaded, "video" allows only video files to be uploaded, "text" allows only text files to be uploaded.'}, 'type': {'type': 'Literal["filepath", "binary"]', 'default': '"filepath"', 'description': 'Type of value to be returned by component. "file" returns a temporary file object with the same base name as the uploaded file, whose full path can be retrieved by file_obj.name, "binary" returns an bytes object.'}, 'label': {'type': 'str | None', 'default': 'None', 'description': 'The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.'}, 'every': {'type': 'Timer | float | None', 'default': 'None', 'description': 'Continously calls `value` to recalculate it if `value` is a function (has no effect otherwise). Can provide a Timer whose tick resets `value`, or a float that provides the regular interval for the reset Timer.'}, 'inputs': {'type': 'Component | Sequence[Component] | set[Component] | None', 'default': 'None', 'description': 'Components that are used as inputs to calculate `value` if `value` is a function (has no effect otherwise). `value` is recalculated any time the inputs change.'}, 'show_label': {'type': 'bool | None', 'default': 'None', 'description': 'if True, will display label.'}, 'container': {'type': 'bool', 'default': 'True', 'description': 'If True, will place the component in a container - providing some extra padding around the border.'}, 'scale': {'type': 'int | None', 'default': 'None', 'description': 'relative size compared to adjacent Components. For example if Components A and B are in a Row, and A has scale=2, and B has scale=1, A will be twice as wide as B. Should be an integer. scale applies in Rows, and to top-level Components in Blocks where fill_height=True.'}, 'min_width': {'type': 'int', 'default': '160', 'description': 'minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.'}, 'height': {'type': 'int | float | None', 'default': 'None', 'description': 'The maximum height of the file component, specified in pixels if a number is passed, or in CSS units if a string is passed. If more files are uploaded than can fit in the height, a scrollbar will appear.'}, 'interactive': {'type': 'bool | None', 'default': 'None', 'description': 'if True, will allow users to upload a file; if False, can only be used to display files. If not provided, this is inferred based on whether the component is used as an input or output.'}, 'visible': {'type': 'bool', 'default': 'True', 'description': 'If False, component will be hidden.'}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': 'An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': 'An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'render': {'type': 'bool', 'default': 'True', 'description': 'If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.'}, 'key': {'type': 'int | str | None', 'default': 'None', 'description': 'if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.'}, 'showviewer': {'type': 'bool', 'default': 'True', 'description': 'If True, will display the 3Dmol.js viewer. If False, will not display the 3Dmol.js viewer.'}}, 'postprocess': {'value': {'type': 'str | list[str] | None', 'description': 'Expects a `str` filepath or URL, or a `list[str]` of filepaths/URLs.'}}, 'preprocess': {'return': {'type': 'bytes | str | list[bytes] | list[str] | None', 'description': 'Passes the file as a `str` or `bytes` object, or a list of `str` or list of `bytes` objects, depending on `type` and `file_count`.'}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the Molecule3D changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}, 'select': {'type': None, 'default': None, 'description': 'Event listener for when the user selects or deselects the Molecule3D. Uses event data gradio.SelectData to carry `value` referring to the label of the Molecule3D, and `selected` to refer to state of the Molecule3D. See EventData documentation on how to use this event data'}, 'clear': {'type': None, 'default': None, 'description': 'This listener is triggered when the user clears the Molecule3D using the clear button for the component.'}, 'upload': {'type': None, 'default': None, 'description': 'This listener is triggered when the user uploads a file into the Molecule3D.'}, 'delete': {'type': None, 'default': None, 'description': 'This listener is triggered when the user deletes and item from the Molecule3D. Uses event data gradio.DeletedFileData to carry `value` referring to the file that was deleted as an instance of FileData. See EventData documentation on how to use this event data'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'Molecule3D': []}}}
7
 
8
  abs_path = os.path.join(os.path.dirname(__file__), "css.css")
9
 
 
24
  <a href="https://pypi.org/project/gradio_molecule3d/" target="_blank"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/gradio_molecule3d"></a>
25
  </div>
26
 
27
+ Python library for easily interacting with trained machine learning models
28
  """, elem_classes=["md-custom"], header_links=True)
29
  app.render()
30
  gr.Markdown(
 
42
  import gradio as gr
43
  from gradio_molecule3d import Molecule3D
44
 
 
45
 
46
+ example = Molecule3D().example_value()
47
 
48
 
49
  reps = [
 
79
  reps = [
80
  {
81
  "model": 0,
 
 
82
  "style": "cartoon",
83
  "color": "whiteCarbon",
84
  "residue_range": "",
85
  "around": 0,
86
  "byres": False,
 
87
  },
88
  {
89
  "model": 0,
90
  "chain": "A",
91
  "resname": "HIS",
92
  "style": "stick",
93
+ "color": "red"
 
 
 
 
94
  }
95
  ]
96
  </pre>
 
98
  btn.click(predict, inputs=inp, outputs=out)
99
 
100
 
101
+ if __name__ == "__main__":
102
+ demo.launch()
103
 
104
  ```
105
  """, elem_classes=["md-custom"], header_links=True)
 
131
 
132
  The code snippet below is accurate in cases where the component is used as both an input and an output.
133
 
134
+ - **As input:** Is passed, passes the file as a `str` or `bytes` object, or a list of `str` or list of `bytes` objects, depending on `type` and `file_count`.
135
+ - **As output:** Should return, expects a `str` filepath or URL, or a `list[str]` of filepaths/URLs.
136
 
137
  ```python
138
  def predict(
139
+ value: bytes | str | list[bytes] | list[str] | None
 
 
 
140
  ) -> str | list[str] | None:
141
  return value
142
  ```
src/.gitignore CHANGED
@@ -6,5 +6,7 @@ __pycache__/
6
  *$py.class
7
  __tmp/*
8
  *.pyi
 
 
9
  node_modules
10
- flagged
 
6
  *$py.class
7
  __tmp/*
8
  *.pyi
9
+ .mypycache
10
+ .ruff_cache
11
  node_modules
12
+ backend/**/templates/
src/README.md CHANGED
@@ -1,8 +1,18 @@
 
 
 
 
 
 
 
 
 
 
1
 
2
  # `gradio_molecule3d`
3
  <a href="https://pypi.org/project/gradio_molecule3d/" target="_blank"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/gradio_molecule3d"></a>
4
 
5
- Molecule3D custom component to visualize pdb or sdf files using 3Dmol.js
6
 
7
  ## Installation
8
 
@@ -17,9 +27,8 @@ pip install gradio_molecule3d
17
  import gradio as gr
18
  from gradio_molecule3d import Molecule3D
19
 
20
- import os
21
 
22
- example = Molecule3D().example_inputs()
23
 
24
 
25
  reps = [
@@ -55,25 +64,18 @@ with gr.Blocks() as demo:
55
  reps = [
56
  {
57
  "model": 0,
58
- "chain": "",
59
- "resname": "",
60
  "style": "cartoon",
61
  "color": "whiteCarbon",
62
  "residue_range": "",
63
  "around": 0,
64
  "byres": False,
65
- "visible": False,
66
  },
67
  {
68
  "model": 0,
69
  "chain": "A",
70
  "resname": "HIS",
71
  "style": "stick",
72
- "color": "red",
73
- "residue_range": "",
74
- "around": 0,
75
- "byres": False,
76
- "visible": False,
77
  }
78
  ]
79
  </pre>
@@ -81,8 +83,8 @@ with gr.Blocks() as demo:
81
  btn.click(predict, inputs=inp, outputs=out)
82
 
83
 
84
- if __name__ == '__main__':
85
- demo.launch()
86
 
87
  ```
88
 
@@ -110,7 +112,7 @@ str | list[str] | Callable | None
110
 
111
  </td>
112
  <td align="left"><code>None</code></td>
113
- <td align="left">Default file to display, given as str file path. If callable, the function will be called whenever the app loads to set the initial value of the component.</td>
114
  </tr>
115
 
116
  <tr>
@@ -161,7 +163,7 @@ str | None
161
  <td align="left" style="width: 25%;">
162
 
163
  ```python
164
- "single" | "multiple" | "directory"
165
  ```
166
 
167
  </td>
@@ -187,7 +189,7 @@ list[str] | None
187
  <td align="left" style="width: 25%;">
188
 
189
  ```python
190
- "filepath" | "binary"
191
  ```
192
 
193
  </td>
@@ -213,12 +215,25 @@ str | None
213
  <td align="left" style="width: 25%;">
214
 
215
  ```python
216
- float | None
217
  ```
218
 
219
  </td>
220
  <td align="left"><code>None</code></td>
221
- <td align="left">If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. Queue must be enabled. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute.</td>
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  </tr>
223
 
224
  <tr>
@@ -257,7 +272,7 @@ int | None
257
 
258
  </td>
259
  <td align="left"><code>None</code></td>
260
- <td align="left">relative width compared to adjacent Components in a Row. For example, if Component A has scale=2, and Component B has scale=1, A will be twice as wide as B. Should be an integer.</td>
261
  </tr>
262
 
263
  <tr>
@@ -283,7 +298,7 @@ int | float | None
283
 
284
  </td>
285
  <td align="left"><code>None</code></td>
286
- <td align="left">The maximum height of the file component, in pixels. If more files are uploaded than can fit in the height, a scrollbar will appear.</td>
287
  </tr>
288
 
289
  <tr>
@@ -351,6 +366,19 @@ bool
351
  <td align="left">If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.</td>
352
  </tr>
353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  <tr>
355
  <td align="left"><code>showviewer</code></td>
356
  <td align="left" style="width: 25%;">
@@ -372,8 +400,9 @@ bool
372
  |:-----|:------------|
373
  | `change` | Triggered when the value of the Molecule3D changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
374
  | `select` | Event listener for when the user selects or deselects the Molecule3D. Uses event data gradio.SelectData to carry `value` referring to the label of the Molecule3D, and `selected` to refer to state of the Molecule3D. See EventData documentation on how to use this event data |
375
- | `clear` | This listener is triggered when the user clears the Molecule3D using the X button for the component. |
376
  | `upload` | This listener is triggered when the user uploads a file into the Molecule3D. |
 
377
 
378
 
379
 
@@ -386,15 +415,12 @@ The impact on the users predict function varies depending on whether the compone
386
 
387
  The code snippet below is accurate in cases where the component is used as both an input and an output.
388
 
389
- - **As output:** Is passed, the preprocessed input data sent to the user's function in the backend.
390
- - **As input:** Should return, the output data received by the component from the user's function in the backend.
391
 
392
  ```python
393
  def predict(
394
- value: bytes
395
- | gradio.utils.NamedString
396
- | list[bytes | gradio.utils.NamedString]
397
- | None
398
  ) -> str | list[str] | None:
399
  return value
400
  ```
 
1
+ ---
2
+ tags: [gradio-custom-component, File]
3
+ title: gradio_molecule3d
4
+ short_description: A gradio custom component
5
+ colorFrom: blue
6
+ colorTo: yellow
7
+ sdk: gradio
8
+ pinned: false
9
+ app_file: space.py
10
+ ---
11
 
12
  # `gradio_molecule3d`
13
  <a href="https://pypi.org/project/gradio_molecule3d/" target="_blank"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/gradio_molecule3d"></a>
14
 
15
+ Python library for easily interacting with trained machine learning models
16
 
17
  ## Installation
18
 
 
27
  import gradio as gr
28
  from gradio_molecule3d import Molecule3D
29
 
 
30
 
31
+ example = Molecule3D().example_value()
32
 
33
 
34
  reps = [
 
64
  reps = [
65
  {
66
  "model": 0,
 
 
67
  "style": "cartoon",
68
  "color": "whiteCarbon",
69
  "residue_range": "",
70
  "around": 0,
71
  "byres": False,
 
72
  },
73
  {
74
  "model": 0,
75
  "chain": "A",
76
  "resname": "HIS",
77
  "style": "stick",
78
+ "color": "red"
 
 
 
 
79
  }
80
  ]
81
  </pre>
 
83
  btn.click(predict, inputs=inp, outputs=out)
84
 
85
 
86
+ if __name__ == "__main__":
87
+ demo.launch()
88
 
89
  ```
90
 
 
112
 
113
  </td>
114
  <td align="left"><code>None</code></td>
115
+ <td align="left">Default file(s) to display, given as a str file path or URL, or a list of str file paths / URLs. If callable, the function will be called whenever the app loads to set the initial value of the component.</td>
116
  </tr>
117
 
118
  <tr>
 
163
  <td align="left" style="width: 25%;">
164
 
165
  ```python
166
+ Literal["single", "multiple", "directory"]
167
  ```
168
 
169
  </td>
 
189
  <td align="left" style="width: 25%;">
190
 
191
  ```python
192
+ Literal["filepath", "binary"]
193
  ```
194
 
195
  </td>
 
215
  <td align="left" style="width: 25%;">
216
 
217
  ```python
218
+ Timer | float | None
219
  ```
220
 
221
  </td>
222
  <td align="left"><code>None</code></td>
223
+ <td align="left">Continously calls `value` to recalculate it if `value` is a function (has no effect otherwise). Can provide a Timer whose tick resets `value`, or a float that provides the regular interval for the reset Timer.</td>
224
+ </tr>
225
+
226
+ <tr>
227
+ <td align="left"><code>inputs</code></td>
228
+ <td align="left" style="width: 25%;">
229
+
230
+ ```python
231
+ Component | Sequence[Component] | set[Component] | None
232
+ ```
233
+
234
+ </td>
235
+ <td align="left"><code>None</code></td>
236
+ <td align="left">Components that are used as inputs to calculate `value` if `value` is a function (has no effect otherwise). `value` is recalculated any time the inputs change.</td>
237
  </tr>
238
 
239
  <tr>
 
272
 
273
  </td>
274
  <td align="left"><code>None</code></td>
275
+ <td align="left">relative size compared to adjacent Components. For example if Components A and B are in a Row, and A has scale=2, and B has scale=1, A will be twice as wide as B. Should be an integer. scale applies in Rows, and to top-level Components in Blocks where fill_height=True.</td>
276
  </tr>
277
 
278
  <tr>
 
298
 
299
  </td>
300
  <td align="left"><code>None</code></td>
301
+ <td align="left">The maximum height of the file component, specified in pixels if a number is passed, or in CSS units if a string is passed. If more files are uploaded than can fit in the height, a scrollbar will appear.</td>
302
  </tr>
303
 
304
  <tr>
 
366
  <td align="left">If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.</td>
367
  </tr>
368
 
369
+ <tr>
370
+ <td align="left"><code>key</code></td>
371
+ <td align="left" style="width: 25%;">
372
+
373
+ ```python
374
+ int | str | None
375
+ ```
376
+
377
+ </td>
378
+ <td align="left"><code>None</code></td>
379
+ <td align="left">if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.</td>
380
+ </tr>
381
+
382
  <tr>
383
  <td align="left"><code>showviewer</code></td>
384
  <td align="left" style="width: 25%;">
 
400
  |:-----|:------------|
401
  | `change` | Triggered when the value of the Molecule3D changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
402
  | `select` | Event listener for when the user selects or deselects the Molecule3D. Uses event data gradio.SelectData to carry `value` referring to the label of the Molecule3D, and `selected` to refer to state of the Molecule3D. See EventData documentation on how to use this event data |
403
+ | `clear` | This listener is triggered when the user clears the Molecule3D using the clear button for the component. |
404
  | `upload` | This listener is triggered when the user uploads a file into the Molecule3D. |
405
+ | `delete` | This listener is triggered when the user deletes and item from the Molecule3D. Uses event data gradio.DeletedFileData to carry `value` referring to the file that was deleted as an instance of FileData. See EventData documentation on how to use this event data |
406
 
407
 
408
 
 
415
 
416
  The code snippet below is accurate in cases where the component is used as both an input and an output.
417
 
418
+ - **As output:** Is passed, passes the file as a `str` or `bytes` object, or a list of `str` or list of `bytes` objects, depending on `type` and `file_count`.
419
+ - **As input:** Should return, expects a `str` filepath or URL, or a `list[str]` of filepaths/URLs.
420
 
421
  ```python
422
  def predict(
423
+ value: bytes | str | list[bytes] | list[str] | None
 
 
 
424
  ) -> str | list[str] | None:
425
  return value
426
  ```
src/backend/gradio_molecule3d/molecule3d.py CHANGED
@@ -5,44 +5,35 @@ from __future__ import annotations
5
  import tempfile
6
  import warnings
7
  from pathlib import Path
8
- from typing import Any, Callable, List, Literal
9
 
10
- from gradio_client.documentation import document, set_documentation_group
 
 
11
 
 
12
  from gradio.components.base import Component
13
- from gradio.data_classes import FileData, GradioRootModel
14
  from gradio.events import Events
15
  from gradio.utils import NamedString
16
 
17
- set_documentation_group("component")
 
18
 
19
 
20
- class ListFiles(GradioRootModel):
21
- root: List[FileData]
22
-
23
- def __getitem__(self, index):
24
- return self.root[index]
25
-
26
- def __iter__(self):
27
- return iter(self.root)
28
-
29
-
30
- @document()
31
  class Molecule3D(Component):
32
  """
33
- Creates a file component that allows uploading generic file (when used as an input) and or displaying generic files (output).
34
- Preprocessing: passes the uploaded file as a {tempfile._TemporaryFileWrapper} or {List[tempfile._TemporaryFileWrapper]} depending on `file_count` (or a {bytes}/{List[bytes]} depending on `type`)
35
- Postprocessing: expects function to return a {str} path to a file, or {List[str]} consisting of paths to files.
36
- Examples-format: a {str} path to a local file that populates the component.
37
- Demos: zip_to_json, zip_files
38
  """
39
 
40
- EVENTS = [Events.change, Events.select, Events.clear, Events.upload]
41
 
42
  def __init__(
43
  self,
44
  value: str | list[str] | Callable | None = None,
45
- reps: Any | None = [],
46
  config: Any | None = {
47
  "backgroundColor": "white",
48
  "orthographic": False,
@@ -54,7 +45,8 @@ class Molecule3D(Component):
54
  file_types: list[str] | None = None,
55
  type: Literal["filepath", "binary"] = "filepath",
56
  label: str | None = None,
57
- every: float | None = None,
 
58
  show_label: bool | None = None,
59
  container: bool = True,
60
  scale: int | None = None,
@@ -65,11 +57,12 @@ class Molecule3D(Component):
65
  elem_id: str | None = None,
66
  elem_classes: list[str] | str | None = None,
67
  render: bool = True,
68
- showviewer: bool = True
 
69
  ):
70
  """
71
  Parameters:
72
- value: Default file to display, given as str file path. If callable, the function will be called whenever the app loads to set the initial value of the component.
73
  file_count: if single, allows user to upload one file. If "multiple", user uploads multiple files. If "directory", user uploads all files in selected directory. Return type will be list for each file in case of "multiple" or "directory".
74
  file_types: List of file extensions or types of files to be uploaded (e.g. ['image', '.json', '.mp4']). "file" allows any file to be uploaded, "image" allows only image files to be uploaded, "audio" allows only audio files to be uploaded, "video" allows only video files to be uploaded, "text" allows only text files to be uploaded.
75
  representations: list of representation objects
@@ -77,21 +70,29 @@ class Molecule3D(Component):
77
  confidenceLabel: label for confidence values stored in the bfactor column of a pdb file
78
  type: Type of value to be returned by component. "file" returns a temporary file object with the same base name as the uploaded file, whose full path can be retrieved by file_obj.name, "binary" returns an bytes object.
79
  label: The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.
80
- every: If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. Queue must be enabled. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute.
 
81
  show_label: if True, will display label.
82
  container: If True, will place the component in a container - providing some extra padding around the border.
83
- scale: relative width compared to adjacent Components in a Row. For example, if Component A has scale=2, and Component B has scale=1, A will be twice as wide as B. Should be an integer.
84
  min_width: minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.
85
- height: The maximum height of the file component, in pixels. If more files are uploaded than can fit in the height, a scrollbar will appear.
86
  interactive: if True, will allow users to upload a file; if False, can only be used to display files. If not provided, this is inferred based on whether the component is used as an input or output.
87
  visible: If False, component will be hidden.
88
  elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
89
  elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
90
  render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
 
91
  showviewer: If True, will display the 3Dmol.js viewer. If False, will not display the 3Dmol.js viewer.
92
  """
 
93
  self.file_count = file_count
94
- if self.file_count == "multiple":
 
 
 
 
 
95
  self.data_model = ListFiles
96
  else:
97
  self.data_model = FileData
@@ -115,6 +116,7 @@ class Molecule3D(Component):
115
  super().__init__(
116
  label=label,
117
  every=every,
 
118
  show_label=show_label,
119
  container=container,
120
  scale=scale,
@@ -124,6 +126,7 @@ class Molecule3D(Component):
124
  elem_id=elem_id,
125
  elem_classes=elem_classes,
126
  render=render,
 
127
  value=value,
128
  )
129
  self.type = type
@@ -133,7 +136,6 @@ class Molecule3D(Component):
133
  self.confidenceLabel = confidenceLabel
134
  self.showviewer = showviewer
135
 
136
-
137
  def _process_single_file(self, f: FileData) -> NamedString | bytes:
138
  file_name = f.path
139
  if self.type == "filepath":
@@ -152,25 +154,54 @@ class Molecule3D(Component):
152
 
153
  def preprocess(
154
  self, payload: ListFiles | FileData | None
155
- ) -> bytes | NamedString | list[bytes | NamedString] | None:
 
 
 
 
 
 
156
  if payload is None:
157
  return None
 
158
  if self.file_count == "single":
159
  if isinstance(payload, ListFiles):
160
  return self._process_single_file(payload[0])
161
- else:
162
- return self._process_single_file(payload)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  else:
164
- if isinstance(payload, ListFiles):
165
- return [self._process_single_file(f) for f in payload]
166
- else:
167
- return [self._process_single_file(payload)]
168
 
169
  def postprocess(self, value: str | list[str] | None) -> ListFiles | FileData | None:
 
 
 
 
 
 
170
  if value is None:
171
  return None
172
-
173
-
174
  if isinstance(value, list):
175
  return ListFiles(
176
  root=[
@@ -189,18 +220,30 @@ class Molecule3D(Component):
189
  size=Path(value).stat().st_size,
190
  )
191
 
192
- def as_example(self, input_data: str | list | None) -> str:
193
- if input_data is None:
194
  return ""
195
- elif isinstance(input_data, list):
196
- return ", ".join([Path(file).name for file in input_data])
197
  else:
198
- return Path(input_data).name
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
- def example_inputs(self) -> Any:
201
  if self.file_count == "single":
202
- return "/home/duerr/Dev/GradioBio/molecule3d/demo/sample_file.pdf"
203
  else:
204
  return [
205
- "sample_file.pdf"
206
  ]
 
5
  import tempfile
6
  import warnings
7
  from pathlib import Path
8
+ from typing import TYPE_CHECKING, Any, Callable, Literal, Sequence
9
 
10
+ import gradio_client.utils as client_utils
11
+ from gradio_client import handle_file
12
+ from gradio_client.documentation import document
13
 
14
+ from gradio import processing_utils
15
  from gradio.components.base import Component
16
+ from gradio.data_classes import FileData, ListFiles
17
  from gradio.events import Events
18
  from gradio.utils import NamedString
19
 
20
+ if TYPE_CHECKING:
21
+ from gradio.components import Timer
22
 
23
 
 
 
 
 
 
 
 
 
 
 
 
24
  class Molecule3D(Component):
25
  """
26
+ Creates a file component that allows uploading one or more generic files (when used as an input) or displaying generic files or URLs for download (as output).
27
+
28
+ Demo: zip_files, zip_to_json
 
 
29
  """
30
 
31
+ EVENTS = [Events.change, Events.select, Events.clear, Events.upload, Events.delete]
32
 
33
  def __init__(
34
  self,
35
  value: str | list[str] | Callable | None = None,
36
+ reps: Any | None = [],
37
  config: Any | None = {
38
  "backgroundColor": "white",
39
  "orthographic": False,
 
45
  file_types: list[str] | None = None,
46
  type: Literal["filepath", "binary"] = "filepath",
47
  label: str | None = None,
48
+ every: Timer | float | None = None,
49
+ inputs: Component | Sequence[Component] | set[Component] | None = None,
50
  show_label: bool | None = None,
51
  container: bool = True,
52
  scale: int | None = None,
 
57
  elem_id: str | None = None,
58
  elem_classes: list[str] | str | None = None,
59
  render: bool = True,
60
+ key: int | str | None = None,
61
+ showviewer: bool = True
62
  ):
63
  """
64
  Parameters:
65
+ value: Default file(s) to display, given as a str file path or URL, or a list of str file paths / URLs. If callable, the function will be called whenever the app loads to set the initial value of the component.
66
  file_count: if single, allows user to upload one file. If "multiple", user uploads multiple files. If "directory", user uploads all files in selected directory. Return type will be list for each file in case of "multiple" or "directory".
67
  file_types: List of file extensions or types of files to be uploaded (e.g. ['image', '.json', '.mp4']). "file" allows any file to be uploaded, "image" allows only image files to be uploaded, "audio" allows only audio files to be uploaded, "video" allows only video files to be uploaded, "text" allows only text files to be uploaded.
68
  representations: list of representation objects
 
70
  confidenceLabel: label for confidence values stored in the bfactor column of a pdb file
71
  type: Type of value to be returned by component. "file" returns a temporary file object with the same base name as the uploaded file, whose full path can be retrieved by file_obj.name, "binary" returns an bytes object.
72
  label: The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.
73
+ every: Continously calls `value` to recalculate it if `value` is a function (has no effect otherwise). Can provide a Timer whose tick resets `value`, or a float that provides the regular interval for the reset Timer.
74
+ inputs: Components that are used as inputs to calculate `value` if `value` is a function (has no effect otherwise). `value` is recalculated any time the inputs change.
75
  show_label: if True, will display label.
76
  container: If True, will place the component in a container - providing some extra padding around the border.
77
+ scale: relative size compared to adjacent Components. For example if Components A and B are in a Row, and A has scale=2, and B has scale=1, A will be twice as wide as B. Should be an integer. scale applies in Rows, and to top-level Components in Blocks where fill_height=True.
78
  min_width: minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.
79
+ height: The maximum height of the file component, specified in pixels if a number is passed, or in CSS units if a string is passed. If more files are uploaded than can fit in the height, a scrollbar will appear.
80
  interactive: if True, will allow users to upload a file; if False, can only be used to display files. If not provided, this is inferred based on whether the component is used as an input or output.
81
  visible: If False, component will be hidden.
82
  elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
83
  elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
84
  render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
85
+ key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
86
  showviewer: If True, will display the 3Dmol.js viewer. If False, will not display the 3Dmol.js viewer.
87
  """
88
+ file_count_valid_types = ["single", "multiple", "directory"]
89
  self.file_count = file_count
90
+
91
+ if self.file_count not in file_count_valid_types:
92
+ raise ValueError(
93
+ f"Parameter file_count must be one of them: {file_count_valid_types}"
94
+ )
95
+ elif self.file_count in ["multiple", "directory"]:
96
  self.data_model = ListFiles
97
  else:
98
  self.data_model = FileData
 
116
  super().__init__(
117
  label=label,
118
  every=every,
119
+ inputs=inputs,
120
  show_label=show_label,
121
  container=container,
122
  scale=scale,
 
126
  elem_id=elem_id,
127
  elem_classes=elem_classes,
128
  render=render,
129
+ key=key,
130
  value=value,
131
  )
132
  self.type = type
 
136
  self.confidenceLabel = confidenceLabel
137
  self.showviewer = showviewer
138
 
 
139
  def _process_single_file(self, f: FileData) -> NamedString | bytes:
140
  file_name = f.path
141
  if self.type == "filepath":
 
154
 
155
  def preprocess(
156
  self, payload: ListFiles | FileData | None
157
+ ) -> bytes | str | list[bytes] | list[str] | None:
158
+ """
159
+ Parameters:
160
+ payload: molecule3d information as a FileData object, or a list of FileData objects.
161
+ Returns:
162
+ Passes the file as a `str` or `bytes` object, or a list of `str` or list of `bytes` objects, depending on `type` and `file_count`.
163
+ """
164
  if payload is None:
165
  return None
166
+
167
  if self.file_count == "single":
168
  if isinstance(payload, ListFiles):
169
  return self._process_single_file(payload[0])
170
+ return self._process_single_file(payload)
171
+ if isinstance(payload, ListFiles):
172
+ return [self._process_single_file(f) for f in payload] # type: ignore
173
+ return [self._process_single_file(payload)] # type: ignore
174
+
175
+ def _download_files(self, value: str | list[str]) -> str | list[str]:
176
+ downloaded_files = []
177
+ if isinstance(value, list):
178
+ for file in value:
179
+ if client_utils.is_http_url_like(file):
180
+ downloaded_file = processing_utils.save_url_to_cache(
181
+ file, self.GRADIO_CACHE
182
+ )
183
+ downloaded_files.append(downloaded_file)
184
+ else:
185
+ downloaded_files.append(file)
186
+ return downloaded_files
187
+ if client_utils.is_http_url_like(value):
188
+ downloaded_file = processing_utils.save_url_to_cache(
189
+ value, self.GRADIO_CACHE
190
+ )
191
+ return downloaded_file
192
  else:
193
+ return value
 
 
 
194
 
195
  def postprocess(self, value: str | list[str] | None) -> ListFiles | FileData | None:
196
+ """
197
+ Parameters:
198
+ value: Expects a `str` filepath or URL, or a `list[str]` of filepaths/URLs.
199
+ Returns:
200
+ molecule3d information as a FileData object, or a list of FileData objects.
201
+ """
202
  if value is None:
203
  return None
204
+ value = self._download_files(value)
 
205
  if isinstance(value, list):
206
  return ListFiles(
207
  root=[
 
220
  size=Path(value).stat().st_size,
221
  )
222
 
223
+ def process_example(self, value: str | list | None) -> str:
224
+ if value is None:
225
  return ""
226
+ elif isinstance(value, list):
227
+ return ", ".join([Path(file).name for file in value])
228
  else:
229
+ return Path(value).name
230
+
231
+ def example_payload(self) -> Any:
232
+ if self.file_count == "single":
233
+ return handle_file(
234
+ "https://files.rcsb.org/view/1PGA.pdb"
235
+ )
236
+ else:
237
+ return [
238
+ handle_file(
239
+ "https://files.rcsb.org/view/1PGA.pdb"
240
+ )
241
+ ]
242
 
243
+ def example_value(self) -> Any:
244
  if self.file_count == "single":
245
+ return "https://files.rcsb.org/view/1PGA.pdb"
246
  else:
247
  return [
248
+ "https://files.rcsb.org/view/1PGA.pdb"
249
  ]
src/backend/gradio_molecule3d/templates/component/index.js CHANGED
The diff for this file is too large to render. See raw diff
 
src/backend/gradio_molecule3d/templates/component/style.css CHANGED
The diff for this file is too large to render. See raw diff
 
src/backend/gradio_molecule3d/templates/example/index.js CHANGED
@@ -1,53 +1,68 @@
1
  const {
2
  SvelteComponent: f,
3
- append: u,
4
- attr: d,
5
- detach: o,
6
- element: y,
 
 
 
7
  init: g,
8
- insert: v,
9
- noop: r,
10
- safe_not_equal: c,
11
- set_data: m,
12
- text: b,
13
- toggle_class: _
14
  } = window.__gradio__svelte__internal;
15
- function A(t) {
16
- let e, n = (Array.isArray(
17
  /*value*/
18
- t[0]
19
- ) ? (
20
- /*value*/
21
- t[0].join(", ")
22
- ) : (
23
- /*value*/
24
- t[0]
25
- )) + "", s;
 
 
 
26
  return {
27
  c() {
28
- e = y("div"), s = b(n), d(e, "class", "svelte-1hgn91n"), _(
 
 
 
 
 
 
 
 
29
  e,
30
  "table",
31
  /*type*/
32
- t[1] === "table"
33
- ), _(
34
  e,
35
  "gallery",
36
  /*type*/
37
- t[1] === "gallery"
38
- ), _(
39
  e,
40
  "selected",
41
  /*selected*/
42
- t[2]
43
  );
44
  },
45
- m(l, a) {
46
- v(l, e, a), u(e, s);
47
  },
48
- p(l, [a]) {
49
- a & /*value*/
50
- 1 && n !== (n = (Array.isArray(
 
51
  /*value*/
52
  l[0]
53
  ) ? (
@@ -56,44 +71,44 @@ function A(t) {
56
  ) : (
57
  /*value*/
58
  l[0]
59
- )) + "") && m(s, n), a & /*type*/
60
- 2 && _(
61
  e,
62
  "table",
63
  /*type*/
64
  l[1] === "table"
65
- ), a & /*type*/
66
- 2 && _(
67
  e,
68
  "gallery",
69
  /*type*/
70
  l[1] === "gallery"
71
- ), a & /*selected*/
72
- 4 && _(
73
  e,
74
  "selected",
75
  /*selected*/
76
  l[2]
77
  );
78
  },
79
- i: r,
80
- o: r,
81
  d(l) {
82
- l && o(e);
83
  }
84
  };
85
  }
86
- function h(t, e, n) {
87
- let { value: s } = e, { type: l } = e, { selected: a = !1 } = e;
88
- return t.$$set = (i) => {
89
- "value" in i && n(0, s = i.value), "type" in i && n(1, l = i.type), "selected" in i && n(2, a = i.selected);
90
- }, [s, l, a];
91
  }
92
- class j extends f {
93
  constructor(e) {
94
- super(), g(this, e, h, A, c, { value: 0, type: 1, selected: 2 });
95
  }
96
  }
97
  export {
98
- j as default
99
  };
 
1
  const {
2
  SvelteComponent: f,
3
+ append_hydration: o,
4
+ attr: u,
5
+ children: h,
6
+ claim_element: c,
7
+ claim_text: y,
8
+ detach: _,
9
+ element: v,
10
  init: g,
11
+ insert_hydration: m,
12
+ noop: d,
13
+ safe_not_equal: b,
14
+ set_data: A,
15
+ text: j,
16
+ toggle_class: r
17
  } = window.__gradio__svelte__internal;
18
+ function w(a) {
19
+ let e, n = (
20
  /*value*/
21
+ (a[0] ? Array.isArray(
22
+ /*value*/
23
+ a[0]
24
+ ) ? (
25
+ /*value*/
26
+ a[0].join(", ")
27
+ ) : (
28
+ /*value*/
29
+ a[0]
30
+ ) : "") + ""
31
+ ), i;
32
  return {
33
  c() {
34
+ e = v("div"), i = j(n), this.h();
35
+ },
36
+ l(l) {
37
+ e = c(l, "DIV", { class: !0 });
38
+ var t = h(e);
39
+ i = y(t, n), t.forEach(_), this.h();
40
+ },
41
+ h() {
42
+ u(e, "class", "svelte-1hgn91n"), r(
43
  e,
44
  "table",
45
  /*type*/
46
+ a[1] === "table"
47
+ ), r(
48
  e,
49
  "gallery",
50
  /*type*/
51
+ a[1] === "gallery"
52
+ ), r(
53
  e,
54
  "selected",
55
  /*selected*/
56
+ a[2]
57
  );
58
  },
59
+ m(l, t) {
60
+ m(l, e, t), o(e, i);
61
  },
62
+ p(l, [t]) {
63
+ t & /*value*/
64
+ 1 && n !== (n = /*value*/
65
+ (l[0] ? Array.isArray(
66
  /*value*/
67
  l[0]
68
  ) ? (
 
71
  ) : (
72
  /*value*/
73
  l[0]
74
+ ) : "") + "") && A(i, n), t & /*type*/
75
+ 2 && r(
76
  e,
77
  "table",
78
  /*type*/
79
  l[1] === "table"
80
+ ), t & /*type*/
81
+ 2 && r(
82
  e,
83
  "gallery",
84
  /*type*/
85
  l[1] === "gallery"
86
+ ), t & /*selected*/
87
+ 4 && r(
88
  e,
89
  "selected",
90
  /*selected*/
91
  l[2]
92
  );
93
  },
94
+ i: d,
95
+ o: d,
96
  d(l) {
97
+ l && _(e);
98
  }
99
  };
100
  }
101
+ function E(a, e, n) {
102
+ let { value: i } = e, { type: l } = e, { selected: t = !1 } = e;
103
+ return a.$$set = (s) => {
104
+ "value" in s && n(0, i = s.value), "type" in s && n(1, l = s.type), "selected" in s && n(2, t = s.selected);
105
+ }, [i, l, t];
106
  }
107
+ class q extends f {
108
  constructor(e) {
109
+ super(), g(this, e, E, w, b, { value: 0, type: 1, selected: 2 });
110
  }
111
  }
112
  export {
113
+ q as default
114
  };
src/demo/app.py CHANGED
@@ -2,9 +2,8 @@
2
  import gradio as gr
3
  from gradio_molecule3d import Molecule3D
4
 
5
- import os
6
 
7
- example = Molecule3D().example_inputs()
8
 
9
 
10
  reps = [
@@ -40,25 +39,18 @@ with gr.Blocks() as demo:
40
  reps = [
41
  {
42
  "model": 0,
43
- "chain": "",
44
- "resname": "",
45
  "style": "cartoon",
46
  "color": "whiteCarbon",
47
  "residue_range": "",
48
  "around": 0,
49
  "byres": False,
50
- "visible": False,
51
  },
52
  {
53
  "model": 0,
54
  "chain": "A",
55
  "resname": "HIS",
56
  "style": "stick",
57
- "color": "red",
58
- "residue_range": "",
59
- "around": 0,
60
- "byres": False,
61
- "visible": False,
62
  }
63
  ]
64
  </pre>
@@ -66,5 +58,5 @@ with gr.Blocks() as demo:
66
  btn.click(predict, inputs=inp, outputs=out)
67
 
68
 
69
- if __name__ == '__main__':
70
- demo.launch()
 
2
  import gradio as gr
3
  from gradio_molecule3d import Molecule3D
4
 
 
5
 
6
+ example = Molecule3D().example_value()
7
 
8
 
9
  reps = [
 
39
  reps = [
40
  {
41
  "model": 0,
 
 
42
  "style": "cartoon",
43
  "color": "whiteCarbon",
44
  "residue_range": "",
45
  "around": 0,
46
  "byres": False,
 
47
  },
48
  {
49
  "model": 0,
50
  "chain": "A",
51
  "resname": "HIS",
52
  "style": "stick",
53
+ "color": "red"
 
 
 
 
54
  }
55
  ]
56
  </pre>
 
58
  btn.click(predict, inputs=inp, outputs=out)
59
 
60
 
61
+ if __name__ == "__main__":
62
+ demo.launch()
src/demo/requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ gradio_molecule3d
src/demo/space.py CHANGED
@@ -3,7 +3,7 @@ import gradio as gr
3
  from app import demo as app
4
  import os
5
 
6
- _docs = {'Molecule3D': {'description': 'Creates a file component that allows uploading generic file (when used as an input) and or displaying generic files (output).', 'members': {'__init__': {'value': {'type': 'str | list[str] | Callable | None', 'default': 'None', 'description': 'Default file to display, given as str file path. If callable, the function will be called whenever the app loads to set the initial value of the component.'}, 'reps': {'type': 'Any | None', 'default': '[]', 'description': None}, 'config': {'type': 'Any | None', 'default': '{\n "backgroundColor": "white",\n "orthographic": False,\n "disableFog": False,\n}', 'description': 'dictionary of config options'}, 'confidenceLabel': {'type': 'str | None', 'default': '"pLDDT"', 'description': 'label for confidence values stored in the bfactor column of a pdb file'}, 'file_count': {'type': '"single" | "multiple" | "directory"', 'default': '"single"', 'description': 'if single, allows user to upload one file. If "multiple", user uploads multiple files. If "directory", user uploads all files in selected directory. Return type will be list for each file in case of "multiple" or "directory".'}, 'file_types': {'type': 'list[str] | None', 'default': 'None', 'description': 'List of file extensions or types of files to be uploaded (e.g. [\'image\', \'.json\', \'.mp4\']). "file" allows any file to be uploaded, "image" allows only image files to be uploaded, "audio" allows only audio files to be uploaded, "video" allows only video files to be uploaded, "text" allows only text files to be uploaded.'}, 'type': {'type': '"filepath" | "binary"', 'default': '"filepath"', 'description': 'Type of value to be returned by component. "file" returns a temporary file object with the same base name as the uploaded file, whose full path can be retrieved by file_obj.name, "binary" returns an bytes object.'}, 'label': {'type': 'str | None', 'default': 'None', 'description': 'The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.'}, 'every': {'type': 'float | None', 'default': 'None', 'description': "If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. Queue must be enabled. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute."}, 'show_label': {'type': 'bool | None', 'default': 'None', 'description': 'if True, will display label.'}, 'container': {'type': 'bool', 'default': 'True', 'description': 'If True, will place the component in a container - providing some extra padding around the border.'}, 'scale': {'type': 'int | None', 'default': 'None', 'description': 'relative width compared to adjacent Components in a Row. For example, if Component A has scale=2, and Component B has scale=1, A will be twice as wide as B. Should be an integer.'}, 'min_width': {'type': 'int', 'default': '160', 'description': 'minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.'}, 'height': {'type': 'int | float | None', 'default': 'None', 'description': 'The maximum height of the file component, in pixels. If more files are uploaded than can fit in the height, a scrollbar will appear.'}, 'interactive': {'type': 'bool | None', 'default': 'None', 'description': 'if True, will allow users to upload a file; if False, can only be used to display files. If not provided, this is inferred based on whether the component is used as an input or output.'}, 'visible': {'type': 'bool', 'default': 'True', 'description': 'If False, component will be hidden.'}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': 'An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': 'An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'render': {'type': 'bool', 'default': 'True', 'description': 'If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.'}, 'showviewer': {'type': 'bool', 'default': 'True', 'description': 'If True, will display the 3Dmol.js viewer. If False, will not display the 3Dmol.js viewer.'}}, 'postprocess': {'value': {'type': 'str | list[str] | None', 'description': "The output data received by the component from the user's function in the backend."}}, 'preprocess': {'return': {'type': 'bytes\n | gradio.utils.NamedString\n | list[bytes | gradio.utils.NamedString]\n | None', 'description': "The preprocessed input data sent to the user's function in the backend."}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the Molecule3D changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}, 'select': {'type': None, 'default': None, 'description': 'Event listener for when the user selects or deselects the Molecule3D. Uses event data gradio.SelectData to carry `value` referring to the label of the Molecule3D, and `selected` to refer to state of the Molecule3D. See EventData documentation on how to use this event data'}, 'clear': {'type': None, 'default': None, 'description': 'This listener is triggered when the user clears the Molecule3D using the X button for the component.'}, 'upload': {'type': None, 'default': None, 'description': 'This listener is triggered when the user uploads a file into the Molecule3D.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'Molecule3D': []}}}
7
 
8
  abs_path = os.path.join(os.path.dirname(__file__), "css.css")
9
 
@@ -24,7 +24,7 @@ with gr.Blocks(
24
  <a href="https://pypi.org/project/gradio_molecule3d/" target="_blank"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/gradio_molecule3d"></a>
25
  </div>
26
 
27
- Molecule3D custom component to visualize pdb or sdf files using 3Dmol.js
28
  """, elem_classes=["md-custom"], header_links=True)
29
  app.render()
30
  gr.Markdown(
@@ -42,9 +42,8 @@ pip install gradio_molecule3d
42
  import gradio as gr
43
  from gradio_molecule3d import Molecule3D
44
 
45
- import os
46
 
47
- example = Molecule3D().example_inputs()
48
 
49
 
50
  reps = [
@@ -80,25 +79,18 @@ with gr.Blocks() as demo:
80
  reps = [
81
  {
82
  "model": 0,
83
- "chain": "",
84
- "resname": "",
85
  "style": "cartoon",
86
  "color": "whiteCarbon",
87
  "residue_range": "",
88
  "around": 0,
89
  "byres": False,
90
- "visible": False,
91
  },
92
  {
93
  "model": 0,
94
  "chain": "A",
95
  "resname": "HIS",
96
  "style": "stick",
97
- "color": "red",
98
- "residue_range": "",
99
- "around": 0,
100
- "byres": False,
101
- "visible": False,
102
  }
103
  ]
104
  </pre>
@@ -106,8 +98,8 @@ with gr.Blocks() as demo:
106
  btn.click(predict, inputs=inp, outputs=out)
107
 
108
 
109
- if __name__ == '__main__':
110
- demo.launch()
111
 
112
  ```
113
  """, elem_classes=["md-custom"], header_links=True)
@@ -139,15 +131,12 @@ The impact on the users predict function varies depending on whether the compone
139
 
140
  The code snippet below is accurate in cases where the component is used as both an input and an output.
141
 
142
- - **As input:** Is passed, the preprocessed input data sent to the user's function in the backend.
143
- - **As output:** Should return, the output data received by the component from the user's function in the backend.
144
 
145
  ```python
146
  def predict(
147
- value: bytes
148
- | gradio.utils.NamedString
149
- | list[bytes | gradio.utils.NamedString]
150
- | None
151
  ) -> str | list[str] | None:
152
  return value
153
  ```
 
3
  from app import demo as app
4
  import os
5
 
6
+ _docs = {'Molecule3D': {'description': 'Creates a file component that allows uploading one or more generic files (when used as an input) or displaying generic files or URLs for download (as output).\n', 'members': {'__init__': {'value': {'type': 'str | list[str] | Callable | None', 'default': 'None', 'description': 'Default file(s) to display, given as a str file path or URL, or a list of str file paths / URLs. If callable, the function will be called whenever the app loads to set the initial value of the component.'}, 'reps': {'type': 'Any | None', 'default': '[]', 'description': None}, 'config': {'type': 'Any | None', 'default': '{\n "backgroundColor": "white",\n "orthographic": False,\n "disableFog": False,\n}', 'description': 'dictionary of config options'}, 'confidenceLabel': {'type': 'str | None', 'default': '"pLDDT"', 'description': 'label for confidence values stored in the bfactor column of a pdb file'}, 'file_count': {'type': 'Literal["single", "multiple", "directory"]', 'default': '"single"', 'description': 'if single, allows user to upload one file. If "multiple", user uploads multiple files. If "directory", user uploads all files in selected directory. Return type will be list for each file in case of "multiple" or "directory".'}, 'file_types': {'type': 'list[str] | None', 'default': 'None', 'description': 'List of file extensions or types of files to be uploaded (e.g. [\'image\', \'.json\', \'.mp4\']). "file" allows any file to be uploaded, "image" allows only image files to be uploaded, "audio" allows only audio files to be uploaded, "video" allows only video files to be uploaded, "text" allows only text files to be uploaded.'}, 'type': {'type': 'Literal["filepath", "binary"]', 'default': '"filepath"', 'description': 'Type of value to be returned by component. "file" returns a temporary file object with the same base name as the uploaded file, whose full path can be retrieved by file_obj.name, "binary" returns an bytes object.'}, 'label': {'type': 'str | None', 'default': 'None', 'description': 'The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.'}, 'every': {'type': 'Timer | float | None', 'default': 'None', 'description': 'Continously calls `value` to recalculate it if `value` is a function (has no effect otherwise). Can provide a Timer whose tick resets `value`, or a float that provides the regular interval for the reset Timer.'}, 'inputs': {'type': 'Component | Sequence[Component] | set[Component] | None', 'default': 'None', 'description': 'Components that are used as inputs to calculate `value` if `value` is a function (has no effect otherwise). `value` is recalculated any time the inputs change.'}, 'show_label': {'type': 'bool | None', 'default': 'None', 'description': 'if True, will display label.'}, 'container': {'type': 'bool', 'default': 'True', 'description': 'If True, will place the component in a container - providing some extra padding around the border.'}, 'scale': {'type': 'int | None', 'default': 'None', 'description': 'relative size compared to adjacent Components. For example if Components A and B are in a Row, and A has scale=2, and B has scale=1, A will be twice as wide as B. Should be an integer. scale applies in Rows, and to top-level Components in Blocks where fill_height=True.'}, 'min_width': {'type': 'int', 'default': '160', 'description': 'minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.'}, 'height': {'type': 'int | float | None', 'default': 'None', 'description': 'The maximum height of the file component, specified in pixels if a number is passed, or in CSS units if a string is passed. If more files are uploaded than can fit in the height, a scrollbar will appear.'}, 'interactive': {'type': 'bool | None', 'default': 'None', 'description': 'if True, will allow users to upload a file; if False, can only be used to display files. If not provided, this is inferred based on whether the component is used as an input or output.'}, 'visible': {'type': 'bool', 'default': 'True', 'description': 'If False, component will be hidden.'}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': 'An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': 'An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.'}, 'render': {'type': 'bool', 'default': 'True', 'description': 'If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.'}, 'key': {'type': 'int | str | None', 'default': 'None', 'description': 'if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.'}, 'showviewer': {'type': 'bool', 'default': 'True', 'description': 'If True, will display the 3Dmol.js viewer. If False, will not display the 3Dmol.js viewer.'}}, 'postprocess': {'value': {'type': 'str | list[str] | None', 'description': 'Expects a `str` filepath or URL, or a `list[str]` of filepaths/URLs.'}}, 'preprocess': {'return': {'type': 'bytes | str | list[bytes] | list[str] | None', 'description': 'Passes the file as a `str` or `bytes` object, or a list of `str` or list of `bytes` objects, depending on `type` and `file_count`.'}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the Molecule3D changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}, 'select': {'type': None, 'default': None, 'description': 'Event listener for when the user selects or deselects the Molecule3D. Uses event data gradio.SelectData to carry `value` referring to the label of the Molecule3D, and `selected` to refer to state of the Molecule3D. See EventData documentation on how to use this event data'}, 'clear': {'type': None, 'default': None, 'description': 'This listener is triggered when the user clears the Molecule3D using the clear button for the component.'}, 'upload': {'type': None, 'default': None, 'description': 'This listener is triggered when the user uploads a file into the Molecule3D.'}, 'delete': {'type': None, 'default': None, 'description': 'This listener is triggered when the user deletes and item from the Molecule3D. Uses event data gradio.DeletedFileData to carry `value` referring to the file that was deleted as an instance of FileData. See EventData documentation on how to use this event data'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'Molecule3D': []}}}
7
 
8
  abs_path = os.path.join(os.path.dirname(__file__), "css.css")
9
 
 
24
  <a href="https://pypi.org/project/gradio_molecule3d/" target="_blank"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/gradio_molecule3d"></a>
25
  </div>
26
 
27
+ Python library for easily interacting with trained machine learning models
28
  """, elem_classes=["md-custom"], header_links=True)
29
  app.render()
30
  gr.Markdown(
 
42
  import gradio as gr
43
  from gradio_molecule3d import Molecule3D
44
 
 
45
 
46
+ example = Molecule3D().example_value()
47
 
48
 
49
  reps = [
 
79
  reps = [
80
  {
81
  "model": 0,
 
 
82
  "style": "cartoon",
83
  "color": "whiteCarbon",
84
  "residue_range": "",
85
  "around": 0,
86
  "byres": False,
 
87
  },
88
  {
89
  "model": 0,
90
  "chain": "A",
91
  "resname": "HIS",
92
  "style": "stick",
93
+ "color": "red"
 
 
 
 
94
  }
95
  ]
96
  </pre>
 
98
  btn.click(predict, inputs=inp, outputs=out)
99
 
100
 
101
+ if __name__ == "__main__":
102
+ demo.launch()
103
 
104
  ```
105
  """, elem_classes=["md-custom"], header_links=True)
 
131
 
132
  The code snippet below is accurate in cases where the component is used as both an input and an output.
133
 
134
+ - **As input:** Is passed, passes the file as a `str` or `bytes` object, or a list of `str` or list of `bytes` objects, depending on `type` and `file_count`.
135
+ - **As output:** Should return, expects a `str` filepath or URL, or a `list[str]` of filepaths/URLs.
136
 
137
  ```python
138
  def predict(
139
+ value: bytes | str | list[bytes] | list[str] | None
 
 
 
140
  ) -> str | list[str] | None:
141
  return value
142
  ```
src/frontend/Example.svelte CHANGED
@@ -1,7 +1,7 @@
1
  <script lang="ts">
2
  import type { FileData } from "@gradio/client";
3
 
4
- export let value: FileData;
5
  export let type: "gallery" | "table";
6
  export let selected = false;
7
  </script>
@@ -11,7 +11,7 @@
11
  class:gallery={type === "gallery"}
12
  class:selected
13
  >
14
- {Array.isArray(value) ? value.join(", ") : value}
15
  </div>
16
 
17
  <style>
 
1
  <script lang="ts">
2
  import type { FileData } from "@gradio/client";
3
 
4
+ export let value: FileData | null;
5
  export let type: "gallery" | "table";
6
  export let selected = false;
7
  </script>
 
11
  class:gallery={type === "gallery"}
12
  class:selected
13
  >
14
+ {value ? (Array.isArray(value) ? value.join(", ") : value) : ""}
15
  </div>
16
 
17
  <style>
src/frontend/Index.svelte CHANGED
@@ -8,27 +8,34 @@
8
  </script>
9
 
10
  <script lang="ts">
 
 
11
  import type { Gradio, SelectData } from "@gradio/utils";
12
  import File from "./shared/File.svelte";
13
  import FileUpload from "./shared/FileUpload.svelte";
14
- import { type FileData } from "@gradio/client";
15
  import { Block, UploadText } from "@gradio/atoms";
 
16
  import { StatusTracker } from "@gradio/statustracker";
17
  import type { LoadingStatus } from "@gradio/statustracker";
 
18
  export let elem_id = "";
19
  export let elem_classes: string[] = [];
20
  export let visible = true;
21
  export let value: null | FileData | FileData[];
 
22
  export let interactive: boolean;
23
  export let root: string;
24
  export let label: string;
25
  export let show_label: boolean;
26
  export let height: number | undefined = undefined;
 
27
  //Molecule3D specific arguments
28
  export let reps: any = [];
29
  export let config: any = {};
30
  export let confidenceLabel: string = "";
31
  export let showviewer: boolean = true;
 
32
  export let _selectable = false;
33
  export let loading_status: LoadingStatus;
34
  export let container = true;
@@ -40,20 +47,24 @@
40
  upload: never;
41
  clear: never;
42
  select: SelectData;
 
 
43
  }>;
44
- export let file_count: string;
45
  export let file_types: string[] = ["file"];
 
46
  let old_value = value;
47
  $: if (JSON.stringify(old_value) !== JSON.stringify(value)) {
48
  gradio.dispatch("change");
49
  old_value = value;
50
- console.log("value change", value);
51
  moldata = null;
52
  retrieveContent(value);
53
  }
 
54
  let dragging = false;
55
  let pending_upload = false;
56
- //check for missing keys in reps
57
  let keys_for_reps = {
58
  model: {
59
  type: Number,
@@ -198,7 +209,7 @@
198
 
199
  <Block
200
  {visible}
201
- variant={value === null ? "dashed" : "solid"}
202
  border_mode={dragging ? "focus" : "base"}
203
  padding={false}
204
  {elem_id}
@@ -215,8 +226,8 @@
215
  status={pending_upload
216
  ? "generating"
217
  : loading_status?.status || "complete"}
 
218
  />
219
-
220
  {#if !interactive}
221
  <File
222
  on:select={({ detail }) => gradio.dispatch("select", detail)}
@@ -235,6 +246,8 @@
235
  />
236
  {:else}
237
  <FileUpload
 
 
238
  {label}
239
  {show_label}
240
  {value}
@@ -248,8 +261,8 @@
248
  {confidenceLabel}
249
  {moldata}
250
  molviewer={showviewer}
 
251
  on:change={({ detail }) => {
252
- errors = [];
253
  value = detail;
254
  }}
255
  on:drag={({ detail }) => (dragging = detail)}
@@ -261,6 +274,14 @@
261
  "identifier not found in database, check spelling"
262
  )}
263
  on:upload={() => gradio.dispatch("upload")}
 
 
 
 
 
 
 
 
264
  i18n={gradio.i18n}
265
  >
266
  <UploadText i18n={gradio.i18n} type="file" />
@@ -301,93 +322,3 @@
301
  </div>
302
  {/if}
303
  </Block>
304
-
305
- <style>
306
- .sr-only {
307
- position: absolute;
308
- width: 1px;
309
- height: 1px;
310
- padding: 0;
311
- margin: -1px;
312
- overflow: hidden;
313
- clip: rect(0, 0, 0, 0);
314
- white-space: nowrap;
315
- border-width: 0;
316
- }
317
- .mb-4 {
318
- margin-bottom: 1rem;
319
- }
320
- .ml-4 {
321
- margin-left: 1rem;
322
- }
323
- .mr-3 {
324
- margin-right: 0.75rem;
325
- }
326
- .mt-1 {
327
- margin-top: 0.25rem;
328
- }
329
- .mt-1\.5 {
330
- margin-top: 0.375rem;
331
- }
332
- .mt-\[2px\] {
333
- margin-top: 2px;
334
- }
335
- .inline {
336
- display: inline;
337
- }
338
- .flex {
339
- display: flex;
340
- }
341
- .h-4 {
342
- height: 1rem;
343
- }
344
- .w-4 {
345
- width: 1rem;
346
- }
347
- .flex-shrink-0 {
348
- flex-shrink: 0;
349
- }
350
- .list-inside {
351
- list-style-position: inside;
352
- }
353
- .list-disc {
354
- list-style-type: disc;
355
- }
356
- .rounded-lg {
357
- border-radius: 0.5rem;
358
- }
359
- .bg-red-50 {
360
- --tw-bg-opacity: 1;
361
- background-color: rgb(254 242 242 / var(--tw-bg-opacity));
362
- }
363
- .m-2 {
364
- margin: 0.5rem;
365
- }
366
- .p-4 {
367
- padding: 1rem;
368
- }
369
- .text-sm {
370
- font-size: 0.875rem;
371
- line-height: 1.25rem;
372
- }
373
- .font-medium {
374
- font-weight: 500;
375
- }
376
- .lowercase {
377
- text-transform: lowercase;
378
- }
379
- .text-red-800 {
380
- --tw-text-opacity: 1;
381
- color: rgb(153 27 27 / var(--tw-text-opacity));
382
- }
383
- @media (prefers-color-scheme: dark) {
384
- .dark\:bg-gray-800 {
385
- --tw-bg-opacity: 1;
386
- background-color: rgb(31 41 55 / var(--tw-bg-opacity));
387
- }
388
- .dark\:text-red-400 {
389
- --tw-text-opacity: 1;
390
- color: rgb(248 113 113 / var(--tw-text-opacity));
391
- }
392
- }
393
- </style>
 
8
  </script>
9
 
10
  <script lang="ts">
11
+ import "./style.css";
12
+
13
  import type { Gradio, SelectData } from "@gradio/utils";
14
  import File from "./shared/File.svelte";
15
  import FileUpload from "./shared/FileUpload.svelte";
16
+ import type { FileData } from "@gradio/client";
17
  import { Block, UploadText } from "@gradio/atoms";
18
+
19
  import { StatusTracker } from "@gradio/statustracker";
20
  import type { LoadingStatus } from "@gradio/statustracker";
21
+
22
  export let elem_id = "";
23
  export let elem_classes: string[] = [];
24
  export let visible = true;
25
  export let value: null | FileData | FileData[];
26
+
27
  export let interactive: boolean;
28
  export let root: string;
29
  export let label: string;
30
  export let show_label: boolean;
31
  export let height: number | undefined = undefined;
32
+
33
  //Molecule3D specific arguments
34
  export let reps: any = [];
35
  export let config: any = {};
36
  export let confidenceLabel: string = "";
37
  export let showviewer: boolean = true;
38
+
39
  export let _selectable = false;
40
  export let loading_status: LoadingStatus;
41
  export let container = true;
 
47
  upload: never;
48
  clear: never;
49
  select: SelectData;
50
+ clear_status: LoadingStatus;
51
+ delete: FileData;
52
  }>;
53
+ export let file_count: "single" | "multiple" | "directory";
54
  export let file_types: string[] = ["file"];
55
+
56
  let old_value = value;
57
  $: if (JSON.stringify(old_value) !== JSON.stringify(value)) {
58
  gradio.dispatch("change");
59
  old_value = value;
60
+
61
  moldata = null;
62
  retrieveContent(value);
63
  }
64
+
65
  let dragging = false;
66
  let pending_upload = false;
67
+
68
  let keys_for_reps = {
69
  model: {
70
  type: Number,
 
209
 
210
  <Block
211
  {visible}
212
+ variant={value ? "solid" : "dashed"}
213
  border_mode={dragging ? "focus" : "base"}
214
  padding={false}
215
  {elem_id}
 
226
  status={pending_upload
227
  ? "generating"
228
  : loading_status?.status || "complete"}
229
+ on:clear_status={() => gradio.dispatch("clear_status", loading_status)}
230
  />
 
231
  {#if !interactive}
232
  <File
233
  on:select={({ detail }) => gradio.dispatch("select", detail)}
 
246
  />
247
  {:else}
248
  <FileUpload
249
+ upload={gradio.client.upload}
250
+ stream_handler={gradio.client.stream}
251
  {label}
252
  {show_label}
253
  {value}
 
261
  {confidenceLabel}
262
  {moldata}
263
  molviewer={showviewer}
264
+ max_file_size={gradio.max_file_size}
265
  on:change={({ detail }) => {
 
266
  value = detail;
267
  }}
268
  on:drag={({ detail }) => (dragging = detail)}
 
274
  "identifier not found in database, check spelling"
275
  )}
276
  on:upload={() => gradio.dispatch("upload")}
277
+ on:error={({ detail }) => {
278
+ loading_status = loading_status || {};
279
+ loading_status.status = "error";
280
+ gradio.dispatch("error", detail);
281
+ }}
282
+ on:delete={({ detail }) => {
283
+ gradio.dispatch("delete", detail);
284
+ }}
285
  i18n={gradio.i18n}
286
  >
287
  <UploadText i18n={gradio.i18n} type="file" />
 
322
  </div>
323
  {/if}
324
  </Block>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/frontend/gradio.config.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tailwindcss from "@tailwindcss/vite";
2
+
3
+ export default {
4
+ plugins: [tailwindcss()],
5
+ svelte: {
6
+ preprocess: [],
7
+ },
8
+ build: {
9
+ target: "modules",
10
+ },
11
+ };
src/frontend/package-lock.json CHANGED
The diff for this file is too large to render. See raw diff
 
src/frontend/package.json CHANGED
@@ -1,25 +1,36 @@
1
  {
2
  "name": "gradio_molecule3d",
3
- "version": "0.2.1",
4
  "description": "Gradio UI packages",
5
  "type": "module",
6
  "author": "",
7
  "license": "ISC",
8
  "private": false,
9
  "dependencies": {
10
- "@gradio/atoms": "0.2.0",
11
- "@gradio/client": "0.13.0",
12
- "@gradio/icons": "0.2.0",
13
- "@gradio/statustracker": "0.3.0",
14
- "@gradio/upload": "0.3.1",
15
- "@gradio/utils": "0.2.0",
16
- "3dmol": "^2.0.6"
 
 
 
 
 
 
 
17
  },
18
  "main": "./Index.svelte",
19
  "main_changeset": true,
20
  "exports": {
21
- ".": "./Index.svelte",
22
- "./example": "./Example.svelte",
 
 
 
 
23
  "./package.json": "./package.json"
24
  }
25
- }
 
1
  {
2
  "name": "gradio_molecule3d",
3
+ "version": "0.9.2",
4
  "description": "Gradio UI packages",
5
  "type": "module",
6
  "author": "",
7
  "license": "ISC",
8
  "private": false,
9
  "dependencies": {
10
+ "@gradio/atoms": "0.9.0",
11
+ "@gradio/client": "1.6.0",
12
+ "@gradio/icons": "0.8.0",
13
+ "@gradio/markdown": "^0.10.1",
14
+ "@gradio/statustracker": "0.8.1",
15
+ "@gradio/upload": "0.13.1",
16
+ "@gradio/utils": "0.7.0",
17
+ "@gradio/wasm": "0.14.1",
18
+ "@tailwindcss/vite": "^4.0.0-alpha.30",
19
+ "3dmol": "^2.4.0",
20
+ "tailwindcss": "^4.0.0-alpha.30"
21
+ },
22
+ "devDependencies": {
23
+ "@gradio/preview": "0.12.0"
24
  },
25
  "main": "./Index.svelte",
26
  "main_changeset": true,
27
  "exports": {
28
+ ".": {
29
+ "gradio": "./Index.svelte"
30
+ },
31
+ "./example": {
32
+ "gradio": "./Example.svelte"
33
+ },
34
  "./package.json": "./package.json"
35
  }
36
+ }
src/frontend/shared/File.svelte CHANGED
@@ -3,23 +3,22 @@
3
  import { BlockLabel, Empty } from "@gradio/atoms";
4
  import { File } from "@gradio/icons";
5
  import FilePreview from "./FilePreview.svelte";
 
6
 
7
  import MolecularViewer from "./MolecularViewer.svelte";
8
 
9
- import type { I18nFormatter } from "@gradio/utils";
10
-
11
  export let value: FileData | FileData[] | null = null;
12
  export let label: string;
13
  export let show_label = true;
14
  export let selectable = false;
15
  export let height: number | undefined = undefined;
16
  export let i18n: I18nFormatter;
 
17
  export let config = {};
18
  export let confidenceLabel = "";
19
  export let representations = [];
20
  export let moldata = null;
21
  export let molviewer = false;
22
- export let errors = [];
23
  </script>
24
 
25
  <BlockLabel
@@ -29,10 +28,9 @@
29
  label={label || "File"}
30
  />
31
 
32
- {#if value}
33
  <FilePreview {i18n} {selectable} on:select {value} {height} />
34
 
35
- <!-- {JSON.stringify(moldata)} -->
36
  {#if moldata != null && molviewer}
37
  <MolecularViewer {moldata} {config} {confidenceLabel} {representations} />
38
  {/if}
 
3
  import { BlockLabel, Empty } from "@gradio/atoms";
4
  import { File } from "@gradio/icons";
5
  import FilePreview from "./FilePreview.svelte";
6
+ import type { I18nFormatter } from "@gradio/utils";
7
 
8
  import MolecularViewer from "./MolecularViewer.svelte";
9
 
 
 
10
  export let value: FileData | FileData[] | null = null;
11
  export let label: string;
12
  export let show_label = true;
13
  export let selectable = false;
14
  export let height: number | undefined = undefined;
15
  export let i18n: I18nFormatter;
16
+
17
  export let config = {};
18
  export let confidenceLabel = "";
19
  export let representations = [];
20
  export let moldata = null;
21
  export let molviewer = false;
 
22
  </script>
23
 
24
  <BlockLabel
 
28
  label={label || "File"}
29
  />
30
 
31
+ {#if value && (Array.isArray(value) ? value.length > 0 : true)}
32
  <FilePreview {i18n} {selectable} on:select {value} {height} />
33
 
 
34
  {#if moldata != null && molviewer}
35
  <MolecularViewer {moldata} {config} {confidenceLabel} {representations} />
36
  {/if}
src/frontend/shared/FilePreview.svelte CHANGED
@@ -1,16 +1,60 @@
1
  <script lang="ts">
2
  import type { FileData } from "@gradio/client";
3
- import { display_file_name, display_file_size } from "./utils";
4
  import { createEventDispatcher } from "svelte";
5
  import type { I18nFormatter, SelectData } from "@gradio/utils";
 
6
 
7
  const dispatch = createEventDispatcher<{
8
  select: SelectData;
 
 
9
  }>();
10
  export let value: FileData | FileData[];
11
  export let selectable = false;
12
  export let height: number | undefined = undefined;
13
  export let i18n: I18nFormatter;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  </script>
15
 
16
  <div
@@ -19,33 +63,51 @@
19
  >
20
  <table class="file-preview">
21
  <tbody>
22
- {#each Array.isArray(value) ? value : [value] as file, i}
23
  <tr
24
  class="file"
25
  class:selectable
26
- on:click={() =>
27
- dispatch("select", {
28
- value: file.orig_name,
29
- index: i
30
- })}
31
  >
32
- <td>
33
- {display_file_name(file)}
 
34
  </td>
35
 
36
  <td class="download">
37
  {#if file.url}
38
- <a
39
  href={file.url}
40
- target="_blank"
41
  download={window.__is_colab__ ? null : file.orig_name}
42
  >
43
- {@html display_file_size(file)}&nbsp;&#8675;
44
- </a>
 
 
45
  {:else}
46
  {i18n("file.uploading")}
47
  {/if}
48
  </td>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  </tr>
50
  {/each}
51
  </tbody>
@@ -53,26 +115,31 @@
53
  </div>
54
 
55
  <style>
56
- td {
57
- width: 45%;
 
 
58
  }
59
 
60
- td:last-child {
61
- width: 10%;
62
- text-align: right;
63
- }
64
- .file-preview-holder {
65
- overflow-x: auto;
66
- overflow-y: auto;
67
  }
 
68
  .file-preview {
 
69
  width: var(--size-full);
70
  max-height: var(--size-60);
71
  overflow-y: auto;
72
  margin-top: var(--size-1);
73
  color: var(--body-text-color);
74
  }
 
 
 
 
 
75
  .file {
 
76
  width: var(--size-full);
77
  }
78
 
@@ -80,20 +147,40 @@
80
  padding: var(--size-1) var(--size-2-5);
81
  }
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  .download:hover {
84
  text-decoration: underline;
85
  }
86
- .download > a {
87
  color: var(--link-text-color);
88
  }
89
 
90
- .download > a:hover {
91
  color: var(--link-text-color-hover);
92
  }
93
- .download > a:visited {
94
  color: var(--link-text-color-visited);
95
  }
96
- .download > a:active {
97
  color: var(--link-text-color-active);
98
  }
99
  .selectable {
 
1
  <script lang="ts">
2
  import type { FileData } from "@gradio/client";
3
+ import { prettyBytes } from "./utils";
4
  import { createEventDispatcher } from "svelte";
5
  import type { I18nFormatter, SelectData } from "@gradio/utils";
6
+ import { DownloadLink } from "@gradio/wasm/svelte";
7
 
8
  const dispatch = createEventDispatcher<{
9
  select: SelectData;
10
+ change: FileData[] | FileData;
11
+ delete: FileData;
12
  }>();
13
  export let value: FileData | FileData[];
14
  export let selectable = false;
15
  export let height: number | undefined = undefined;
16
  export let i18n: I18nFormatter;
17
+
18
+ function split_filename(filename: string): [string, string] {
19
+ const last_dot = filename.lastIndexOf(".");
20
+ if (last_dot === -1) {
21
+ return [filename, ""];
22
+ }
23
+ return [filename.slice(0, last_dot), filename.slice(last_dot)];
24
+ }
25
+
26
+ $: normalized_files = (Array.isArray(value) ? value : [value]).map((file) => {
27
+ const [filename_stem, filename_ext] = split_filename(file.orig_name ?? "");
28
+ return {
29
+ ...file,
30
+ filename_stem,
31
+ filename_ext
32
+ };
33
+ });
34
+
35
+ function handle_row_click(
36
+ event: MouseEvent & { currentTarget: HTMLTableRowElement },
37
+ index: number
38
+ ): void {
39
+ const tr = event.currentTarget;
40
+ const should_select =
41
+ event.target === tr || // Only select if the click is on the row itself
42
+ (tr &&
43
+ tr.firstElementChild &&
44
+ event.composedPath().includes(tr.firstElementChild)); // Or if the click is on the name column
45
+
46
+ if (should_select) {
47
+ dispatch("select", { value: normalized_files[index].orig_name, index });
48
+ }
49
+ }
50
+
51
+ function remove_file(index: number): void {
52
+ const removed = normalized_files.splice(index, 1);
53
+ normalized_files = [...normalized_files];
54
+ value = normalized_files;
55
+ dispatch("delete", removed[0]);
56
+ dispatch("change", normalized_files);
57
+ }
58
  </script>
59
 
60
  <div
 
63
  >
64
  <table class="file-preview">
65
  <tbody>
66
+ {#each normalized_files as file, i (file)}
67
  <tr
68
  class="file"
69
  class:selectable
70
+ on:click={(event) => {
71
+ handle_row_click(event, i);
72
+ }}
 
 
73
  >
74
+ <td class="filename" aria-label={file.orig_name}>
75
+ <span class="stem">{file.filename_stem}</span>
76
+ <span class="ext">{file.filename_ext}</span>
77
  </td>
78
 
79
  <td class="download">
80
  {#if file.url}
81
+ <DownloadLink
82
  href={file.url}
 
83
  download={window.__is_colab__ ? null : file.orig_name}
84
  >
85
+ {@html file.size != null
86
+ ? prettyBytes(file.size)
87
+ : "(size unknown)"}&nbsp;&#8675;
88
+ </DownloadLink>
89
  {:else}
90
  {i18n("file.uploading")}
91
  {/if}
92
  </td>
93
+
94
+ {#if normalized_files.length > 1}
95
+ <td>
96
+ <button
97
+ class="label-clear-button"
98
+ aria-label="Remove this file"
99
+ on:click={() => {
100
+ remove_file(i);
101
+ }}
102
+ on:keydown={(event) => {
103
+ if (event.key === "Enter") {
104
+ remove_file(i);
105
+ }
106
+ }}
107
+
108
+ </button>
109
+ </td>
110
+ {/if}
111
  </tr>
112
  {/each}
113
  </tbody>
 
115
  </div>
116
 
117
  <style>
118
+ .label-clear-button {
119
+ color: var(--body-text-color-subdued);
120
+ position: relative;
121
+ left: -3px;
122
  }
123
 
124
+ .label-clear-button:hover {
125
+ color: var(--body-text-color);
 
 
 
 
 
126
  }
127
+
128
  .file-preview {
129
+ table-layout: fixed;
130
  width: var(--size-full);
131
  max-height: var(--size-60);
132
  overflow-y: auto;
133
  margin-top: var(--size-1);
134
  color: var(--body-text-color);
135
  }
136
+
137
+ .file-preview-holder {
138
+ overflow: auto;
139
+ }
140
+
141
  .file {
142
+ display: flex;
143
  width: var(--size-full);
144
  }
145
 
 
147
  padding: var(--size-1) var(--size-2-5);
148
  }
149
 
150
+ .filename {
151
+ flex-grow: 1;
152
+ display: flex;
153
+ overflow: hidden;
154
+ }
155
+ .filename .stem {
156
+ overflow: hidden;
157
+ text-overflow: ellipsis;
158
+ white-space: nowrap;
159
+ }
160
+ .filename .ext {
161
+ white-space: nowrap;
162
+ }
163
+
164
+ .download {
165
+ min-width: 8rem;
166
+ width: 10%;
167
+ white-space: nowrap;
168
+ text-align: right;
169
+ }
170
  .download:hover {
171
  text-decoration: underline;
172
  }
173
+ .download > :global(a) {
174
  color: var(--link-text-color);
175
  }
176
 
177
+ .download > :global(a:hover) {
178
  color: var(--link-text-color-hover);
179
  }
180
+ .download > :global(a:visited) {
181
  color: var(--link-text-color-visited);
182
  }
183
+ .download > :global(a:active) {
184
  color: var(--link-text-color-active);
185
  }
186
  .selectable {
src/frontend/shared/FileRetrieval.svelte CHANGED
@@ -1,16 +1,19 @@
1
  <script lang="ts">
2
  import { createEventDispatcher, tick, getContext } from "svelte";
3
 
4
- import { upload_files, upload, FileData } from "@gradio/client";
5
  import LoadingSpinner from "./loading_spinner.svelte";
6
  let uploaded_files;
7
  const dispatch = createEventDispatcher();
8
- const upload_fn = getContext<typeof upload_files>("upload_files");
 
 
 
9
  export let root: string;
10
  async function handle_upload(file_data: FileData): Promise<void> {
11
  await tick();
12
  const upload_id = Math.random().toString(36).substring(2, 15);
13
- uploaded_files = await upload([file_data], root, upload_id, upload_fn);
14
  dispatch("load", uploaded_files[0]);
15
  }
16
  let loading = false;
 
1
  <script lang="ts">
2
  import { createEventDispatcher, tick, getContext } from "svelte";
3
 
4
+ import { FileData } from "@gradio/client";
5
  import LoadingSpinner from "./loading_spinner.svelte";
6
  let uploaded_files;
7
  const dispatch = createEventDispatcher();
8
+
9
+ import type { Client } from "@Gradio Uptime/client";
10
+ export let upload: Client["upload"];
11
+
12
  export let root: string;
13
  async function handle_upload(file_data: FileData): Promise<void> {
14
  await tick();
15
  const upload_id = Math.random().toString(36).substring(2, 15);
16
+ uploaded_files = await upload([file_data], root, upload_id);
17
  dispatch("load", uploaded_files[0]);
18
  }
19
  let loading = false;
src/frontend/shared/FileUpload.svelte CHANGED
@@ -1,7 +1,7 @@
1
  <script lang="ts">
2
  import { createEventDispatcher, tick } from "svelte";
3
  import { Upload, ModifyUpload } from "@gradio/upload";
4
- import type { FileData } from "@gradio/client";
5
  import { BlockLabel } from "@gradio/atoms";
6
  import { File } from "@gradio/icons";
7
  import FileRetrieval from "./FileRetrieval.svelte";
@@ -14,12 +14,15 @@
14
 
15
  export let label: string;
16
  export let show_label = true;
17
- export let file_count = "single";
18
  export let file_types: string[] | null = null;
19
  export let selectable = false;
20
  export let root: string;
21
  export let height: number | undefined = undefined;
22
  export let i18n: I18nFormatter;
 
 
 
23
 
24
  export let config = {};
25
  export let confidenceLabel = "";
@@ -31,15 +34,16 @@
31
  detail,
32
  }: CustomEvent<FileData | FileData[]>): Promise<void> {
33
  value = detail;
 
 
34
  await tick();
35
  dispatch("change", value);
36
  dispatch("upload", detail);
37
- console.log("upload", detail);
38
  }
39
 
40
  function handle_clear(): void {
41
  value = null;
42
- moldata = null;
43
  dispatch("change", null);
44
  dispatch("clear");
45
  }
@@ -53,34 +57,23 @@
53
  error: string;
54
  }>();
55
 
56
- let accept_file_types: string | null;
57
- if (file_types == null) {
58
- accept_file_types = null;
59
- } else {
60
- file_types = file_types.map((x) => {
61
- if (x.startsWith(".")) {
62
- return x;
63
- }
64
- return x + "/*";
65
- });
66
- accept_file_types = file_types.join(", ");
67
- }
68
-
69
  let dragging = false;
70
  $: dispatch("drag", dragging);
71
  </script>
72
 
73
- <BlockLabel
74
- {show_label}
75
- Icon={File}
76
- float={value === null}
77
- label={label || "File"}
78
- />
79
 
80
- {#if value}
81
  <ModifyUpload {i18n} on:clear={handle_clear} absolute />
82
- <FilePreview {i18n} on:select {selectable} {value} {height} />
83
-
 
 
 
 
 
 
 
84
  {#if moldata != null && molviewer}
85
  <MolecularViewer {moldata} {config} {confidenceLabel} {representations} />
86
  {/if}
@@ -88,14 +81,19 @@
88
  <FileRetrieval
89
  {root}
90
  on:load={handle_upload}
 
91
  on:notfound={() => dispatch("notfound")}
92
  />
93
  <Upload
94
  on:load={handle_upload}
95
- filetype={accept_file_types}
96
  {file_count}
 
97
  {root}
98
  bind:dragging
 
 
 
99
  >
100
  <slot />
101
  </Upload>
 
1
  <script lang="ts">
2
  import { createEventDispatcher, tick } from "svelte";
3
  import { Upload, ModifyUpload } from "@gradio/upload";
4
+ import type { FileData, Client } from "@gradio/client";
5
  import { BlockLabel } from "@gradio/atoms";
6
  import { File } from "@gradio/icons";
7
  import FileRetrieval from "./FileRetrieval.svelte";
 
14
 
15
  export let label: string;
16
  export let show_label = true;
17
+ export let file_count: "single" | "multiple" | "directory" = "single";
18
  export let file_types: string[] | null = null;
19
  export let selectable = false;
20
  export let root: string;
21
  export let height: number | undefined = undefined;
22
  export let i18n: I18nFormatter;
23
+ export let max_file_size: number | null = null;
24
+ export let upload: Client["upload"];
25
+ export let stream_handler: Client["stream"];
26
 
27
  export let config = {};
28
  export let confidenceLabel = "";
 
34
  detail,
35
  }: CustomEvent<FileData | FileData[]>): Promise<void> {
36
  value = detail;
37
+ console.log("upload", detail);
38
+
39
  await tick();
40
  dispatch("change", value);
41
  dispatch("upload", detail);
 
42
  }
43
 
44
  function handle_clear(): void {
45
  value = null;
46
+ oldata = null;
47
  dispatch("change", null);
48
  dispatch("clear");
49
  }
 
57
  error: string;
58
  }>();
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  let dragging = false;
61
  $: dispatch("drag", dragging);
62
  </script>
63
 
64
+ <BlockLabel {show_label} Icon={File} float={!value} label={label || "File"} />
 
 
 
 
 
65
 
66
+ {#if value && (Array.isArray(value) ? value.length > 0 : true)}
67
  <ModifyUpload {i18n} on:clear={handle_clear} absolute />
68
+ <FilePreview
69
+ {i18n}
70
+ on:select
71
+ {selectable}
72
+ {value}
73
+ {height}
74
+ on:change
75
+ on:delete
76
+ />
77
  {#if moldata != null && molviewer}
78
  <MolecularViewer {moldata} {config} {confidenceLabel} {representations} />
79
  {/if}
 
81
  <FileRetrieval
82
  {root}
83
  on:load={handle_upload}
84
+ {upload}
85
  on:notfound={() => dispatch("notfound")}
86
  />
87
  <Upload
88
  on:load={handle_upload}
89
+ filetype={file_types}
90
  {file_count}
91
+ {max_file_size}
92
  {root}
93
  bind:dragging
94
+ on:error
95
+ {stream_handler}
96
+ {upload}
97
  >
98
  <slot />
99
  </Upload>
src/frontend/shared/MolecularViewer.svelte CHANGED
@@ -1,21 +1,13 @@
1
  <script lang="ts">
2
  import * as mol from "3dmol/build/3Dmol.js";
3
- let TDmol = mol.default;
4
 
5
  import { onMount, onDestroy } from "svelte";
6
 
7
- // import RepresentationsIcon from "../static/RepresentationsIcon.svelte";
8
- // import JSZip from "jszip";
9
- // import { saveAs } from "file-saver";
10
-
11
  let viewer;
12
  export let confidenceLabel = null;
13
 
14
  export let moldata = null;
15
- // [
16
- // { data: propdata, name: "Input", format: "pdb", asFrames: false },
17
- // { data: moldata2, name: "Output", format: "pdb", asFrames: true },
18
- // ];
19
 
20
  let settings = {
21
  backgroundColor: {
@@ -29,13 +21,11 @@
29
  type: "toggle",
30
  },
31
  };
32
- export let config = {};
33
-
34
- // {
35
- // backgroundColor: "white",
36
- // orthographic: false,
37
- // disableFog: false,
38
- // };
39
 
40
  $: {
41
  if (view != undefined) {
@@ -159,6 +149,7 @@
159
  and: [selObj, { atom: ["N", "C", "O"], invert: true }],
160
  };
161
  }
 
162
  if (rep.style === "surface") {
163
  colorObj.opacity = 0.8;
164
  view.addSurface(TDmol.SurfaceType.VDW, colorObj, selObj);
@@ -220,7 +211,7 @@
220
  applyStyles(representations);
221
  view.zoomTo();
222
  view.render();
223
- view.zoom(0.8, 2000);
224
 
225
  representations.forEach((rep) => {
226
  if (rep.color === "alphafold") {
 
1
  <script lang="ts">
2
  import * as mol from "3dmol/build/3Dmol.js";
3
+ let TDmol = mol;
4
 
5
  import { onMount, onDestroy } from "svelte";
6
 
 
 
 
 
7
  let viewer;
8
  export let confidenceLabel = null;
9
 
10
  export let moldata = null;
 
 
 
 
11
 
12
  let settings = {
13
  backgroundColor: {
 
21
  type: "toggle",
22
  },
23
  };
24
+ export let config = {
25
+ backgroundColor: "white",
26
+ orthographic: false,
27
+ disableFog: false,
28
+ };
 
 
29
 
30
  $: {
31
  if (view != undefined) {
 
149
  and: [selObj, { atom: ["N", "C", "O"], invert: true }],
150
  };
151
  }
152
+
153
  if (rep.style === "surface") {
154
  colorObj.opacity = 0.8;
155
  view.addSurface(TDmol.SurfaceType.VDW, colorObj, selObj);
 
211
  applyStyles(representations);
212
  view.zoomTo();
213
  view.render();
214
+ view.zoom(0.9, 100);
215
 
216
  representations.forEach((rep) => {
217
  if (rep.color === "alphafold") {
src/frontend/shared/utils.ts CHANGED
@@ -10,32 +10,3 @@ export const prettyBytes = (bytes: number): string => {
10
  let unit = units[i];
11
  return bytes.toFixed(1) + "&nbsp;" + unit;
12
  };
13
-
14
- export const display_file_name = (value: FileData): string => {
15
- var str: string;
16
- str = value.orig_name;
17
- const max_length = 30;
18
-
19
- if (str.length > max_length) {
20
- const truncated_name = str.substring(0, max_length);
21
- const file_extension_index = str.lastIndexOf(".");
22
- if (file_extension_index !== -1) {
23
- const file_extension = str.slice(file_extension_index);
24
- return `${truncated_name}..${file_extension}`;
25
- }
26
- return truncated_name;
27
- }
28
- return str;
29
- };
30
-
31
- export const display_file_size = (value: FileData | FileData[]): string => {
32
- var total_size = 0;
33
- if (Array.isArray(value)) {
34
- for (var file of value) {
35
- if (file.size !== undefined) total_size += file.size;
36
- }
37
- } else {
38
- total_size = value.size || 0;
39
- }
40
- return prettyBytes(total_size);
41
- };
 
10
  let unit = units[i];
11
  return bytes.toFixed(1) + "&nbsp;" + unit;
12
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/frontend/style.css ADDED
@@ -0,0 +1 @@
 
 
1
+ @import "tailwindcss";
src/pyproject.toml CHANGED
@@ -8,12 +8,12 @@ build-backend = "hatchling.build"
8
 
9
  [project]
10
  name = "gradio_molecule3d"
11
- version = "0.0.5"
12
- description = "Molecule3D custom component to visualize pdb or sdf files using 3Dmol.js"
13
  readme = "README.md"
14
- license = "MIT"
15
  requires-python = ">=3.8"
16
- authors = [{ name = "Simon Dürr", email = "dev@simonduerr.eu" }]
17
  keywords = [
18
  "machine learning",
19
  "reproducibility",
@@ -24,10 +24,9 @@ keywords = [
24
  "protein"
25
  ]
26
  # Add dependencies here
27
- dependencies = ["gradio>=4.0,<5.0"]
28
  classifiers = [
29
  'Development Status :: 3 - Alpha',
30
- 'License :: OSI Approved :: Apache Software License',
31
  'Operating System :: OS Independent',
32
  'Programming Language :: Python :: 3',
33
  'Programming Language :: Python :: 3 :: Only',
@@ -40,11 +39,12 @@ classifiers = [
40
  'Topic :: Scientific/Engineering :: Visualization',
41
  ]
42
 
 
43
  [project.optional-dependencies]
44
  dev = ["build", "twine"]
45
 
46
  [tool.hatch.build]
47
- artifacts = ["/backend/gradio_molecule3d/templates", "*.pyi", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates", "backend/gradio_molecule3d/templates"]
48
 
49
  [tool.hatch.build.targets.wheel]
50
  packages = ["/backend/gradio_molecule3d"]
 
8
 
9
  [project]
10
  name = "gradio_molecule3d"
11
+ version = "0.0.6"
12
+ description = "Python library for easily interacting with trained machine learning models"
13
  readme = "README.md"
14
+ license = "Apache-2.0"
15
  requires-python = ">=3.8"
16
+ authors = [{ name = "YOUR NAME", email = "YOUREMAIL@domain.com" }]
17
  keywords = [
18
  "machine learning",
19
  "reproducibility",
 
24
  "protein"
25
  ]
26
  # Add dependencies here
27
+ dependencies = ["gradio>=4.0,<6.0"]
28
  classifiers = [
29
  'Development Status :: 3 - Alpha',
 
30
  'Operating System :: OS Independent',
31
  'Programming Language :: Python :: 3',
32
  'Programming Language :: Python :: 3 :: Only',
 
39
  'Topic :: Scientific/Engineering :: Visualization',
40
  ]
41
 
42
+
43
  [project.optional-dependencies]
44
  dev = ["build", "twine"]
45
 
46
  [tool.hatch.build]
47
+ artifacts = ["/backend/gradio_molecule3d/templates", "*.pyi"]
48
 
49
  [tool.hatch.build.targets.wheel]
50
  packages = ["/backend/gradio_molecule3d"]