MilanM commited on
Commit
b510b15
·
verified ·
1 Parent(s): f5bb885

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1028 -359
app.py CHANGED
@@ -1,469 +1,1138 @@
1
  import marimo
2
 
3
- __generated_with = "0.9.2"
4
- app = marimo.App()
5
 
6
 
7
  @app.cell
8
- def __():
9
  import marimo as mo
10
-
11
- mo.md("# Welcome to marimo! 🌊🍃")
12
- return (mo,)
13
 
14
 
15
  @app.cell
16
- def __(mo):
17
- slider = mo.ui.slider(1, 22)
18
- return (slider,)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
 
21
  @app.cell
22
- def __(mo, slider):
23
- mo.md(
24
- f"""
25
- marimo is a **reactive** Python notebook.
 
 
 
 
 
 
 
 
 
26
 
27
- This means that unlike traditional notebooks, marimo notebooks **run
28
- automatically** when you modify them or
29
- interact with UI elements, like this slider: {slider}.
 
30
 
31
- {"##" + "🍃" * slider.value}
32
- """
33
- )
34
- return
35
 
 
36
 
37
- @app.cell(hide_code=True)
38
- def __(mo):
39
- mo.accordion(
40
- {
41
- "Tip: disabling automatic execution": mo.md(
42
- rf"""
43
- marimo lets you disable automatic execution: just go into the
44
- notebook settings and set
45
-
46
- "Runtime > On Cell Change" to "lazy".
47
-
48
- When the runtime is lazy, after running a cell, marimo marks its
49
- descendants as stale instead of automatically running them. The
50
- lazy runtime puts you in control over when cells are run, while
51
- still giving guarantees about the notebook state.
52
- """
53
- )
54
- }
55
  )
56
- return
57
 
58
 
59
- @app.cell(hide_code=True)
60
- def __(mo):
61
- mo.md(
62
- """
63
- Tip: This is a tutorial notebook. You can create your own notebooks
64
- by entering `marimo edit` at the command line.
65
- """
66
- ).callout()
67
- return
68
 
69
 
70
- @app.cell(hide_code=True)
71
- def __(mo):
72
- mo.md(
73
- """
74
- ## 1. Reactive execution
 
 
 
 
 
75
 
76
- A marimo notebook is made up of small blocks of Python code called
77
- cells.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
- marimo reads your cells and models the dependencies among them: whenever
80
- a cell that defines a global variable is run, marimo
81
- **automatically runs** all cells that reference that variable.
82
 
83
- Reactivity keeps your program state and outputs in sync with your code,
84
- making for a dynamic programming environment that prevents bugs before they
85
- happen.
86
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  )
88
- return
89
 
90
 
91
- @app.cell(hide_code=True)
92
- def __(changed, mo):
93
- (
94
- mo.md(
95
- f"""
96
- **✨ Nice!** The value of `changed` is now {changed}.
97
-
98
- When you updated the value of the variable `changed`, marimo
99
- **reacted** by running this cell automatically, because this cell
100
- references the global variable `changed`.
101
-
102
- Reactivity ensures that your notebook state is always
103
- consistent, which is crucial for doing good science; it's also what
104
- enables marimo notebooks to double as tools and apps.
105
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  )
107
- if changed
108
- else mo.md(
109
- """
110
- **🌊 See it in action.** In the next cell, change the value of the
111
- variable `changed` to `True`, then click the run button.
112
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  )
115
- return
116
 
117
 
118
  @app.cell
119
- def __():
120
- changed = False
121
- return (changed,)
 
 
122
 
123
 
124
- @app.cell(hide_code=True)
125
- def __(mo):
126
- mo.accordion(
127
- {
128
- "Tip: execution order": (
129
- """
130
- The order of cells on the page has no bearing on
131
- the order in which cells are executed: marimo knows that a cell
132
- reading a variable must run after the cell that defines it. This
133
- frees you to organize your code in the way that makes the most
134
- sense for you.
135
- """
136
- )
137
- }
138
- )
139
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
 
141
 
142
- @app.cell(hide_code=True)
143
- def __(mo):
144
- mo.md(
145
- """
146
- **Global names must be unique.** To enable reactivity, marimo imposes a
147
- constraint on how names appear in cells: no two cells may define the same
148
- variable.
149
- """
150
- )
151
- return
152
 
 
 
 
 
 
 
 
153
 
154
- @app.cell(hide_code=True)
155
- def __(mo):
156
- mo.accordion(
157
- {
158
- "Tip: encapsulation": (
159
- """
160
- By encapsulating logic in functions, classes, or Python modules,
161
- you can minimize the number of global variables in your notebook.
162
- """
163
- )
164
- }
 
 
 
 
 
 
165
  )
166
- return
167
 
168
 
169
- @app.cell(hide_code=True)
170
- def __(mo):
171
- mo.accordion(
172
- {
173
- "Tip: private variables": (
174
- """
175
- Variables prefixed with an underscore are "private" to a cell, so
176
- they can be defined by multiple cells.
177
- """
178
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  }
180
- )
181
- return
182
 
183
 
184
- @app.cell(hide_code=True)
185
- def __(mo):
186
- mo.md(
187
- """
188
- ## 2. UI elements
189
 
190
- Cells can output interactive UI elements. Interacting with a UI
191
- element **automatically triggers notebook execution**: when
192
- you interact with a UI element, its value is sent back to Python, and
193
- every cell that references that element is re-run.
 
 
 
194
 
195
- marimo provides a library of UI elements to choose from under
196
- `marimo.ui`.
197
- """
 
 
 
 
 
 
198
  )
199
- return
200
 
201
 
202
  @app.cell
203
- def __(mo):
204
- mo.md("""**🌊 Some UI elements.** Try interacting with the below elements.""")
205
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
- @app.cell
209
- def __(mo):
210
- icon = mo.ui.dropdown(["🍃", "🌊", "✨"], value="🍃")
211
- return (icon,)
 
 
 
 
 
 
212
 
213
 
214
  @app.cell
215
- def __(icon, mo):
216
- repetitions = mo.ui.slider(1, 16, label=f"number of {icon.value}: ")
217
- return (repetitions,)
 
 
 
 
 
 
 
 
 
 
 
218
 
219
 
220
  @app.cell
221
- def __(icon, repetitions):
222
- icon, repetitions
223
- return
 
 
224
 
 
 
225
 
226
- @app.cell
227
- def __(icon, mo, repetitions):
228
- mo.md("# " + icon.value * repetitions.value)
229
- return
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
 
 
 
 
231
 
232
- @app.cell(hide_code=True)
233
- def __(mo):
234
- mo.md(
235
- """
236
- ## 3. marimo is just Python
 
237
 
238
- marimo cells parse Python (and only Python), and marimo notebooks are
239
- stored as pure Python files — outputs are _not_ included. There's no
240
- magical syntax.
 
 
 
241
 
242
- The Python files generated by marimo are:
243
 
244
- - easily versioned with git, yielding minimal diffs
245
- - legible for both humans and machines
246
- - formattable using your tool of choice,
247
- - usable as Python scripts, with UI elements taking their default
248
- values, and
249
- - importable by other modules (more on that in the future).
250
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  )
252
- return
253
 
254
 
255
- @app.cell(hide_code=True)
256
- def __(mo):
257
- mo.md(
 
 
 
 
 
 
 
 
 
 
258
  """
259
- ## 4. Running notebooks as apps
260
 
261
- marimo notebooks can double as apps. Click the app window icon in the
262
- bottom-right to see this notebook in "app view."
 
263
 
264
- Serve a notebook as an app with `marimo run` at the command-line.
265
- Of course, you can use marimo just to level-up your
266
- notebooking, without ever making apps.
267
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  )
269
- return
270
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
 
272
- @app.cell(hide_code=True)
273
- def __(mo):
274
- mo.md(
275
- """
276
- ## 5. The `marimo` command-line tool
277
 
278
- **Creating and editing notebooks.** Use
 
 
279
 
280
- ```
281
- marimo edit
282
- ```
 
283
 
284
- in a terminal to start the marimo notebook server. From here
285
- you can create a new notebook or edit existing ones.
 
 
 
286
 
 
 
 
287
 
288
- **Running as apps.** Use
289
 
290
- ```
291
- marimo run notebook.py
292
- ```
293
 
294
- to start a webserver that serves your notebook as an app in read-only mode,
295
- with code cells hidden.
 
296
 
297
- **Convert a Jupyter notebook.** Convert a Jupyter notebook to a marimo
298
- notebook using `marimo convert`:
 
299
 
300
- ```
301
- marimo convert your_notebook.ipynb > your_app.py
302
- ```
303
 
304
- **Tutorials.** marimo comes packaged with tutorials:
 
 
305
 
306
- - `dataflow`: more on marimo's automatic execution
307
- - `ui`: how to use UI elements
308
- - `markdown`: how to write markdown, with interpolated values and
309
- LaTeX
310
- - `plots`: how plotting works in marimo
311
- - `sql`: how to use SQL
312
- - `layout`: layout elements in marimo
313
- - `fileformat`: how marimo's file format works
314
- - `markdown-format`: for using `.md` files in marimo
315
- - `for-jupyter-users`: if you are coming from Jupyter
316
 
317
- Start a tutorial with `marimo tutorial`; for example,
 
 
318
 
319
- ```
320
- marimo tutorial dataflow
321
- ```
322
 
323
- In addition to tutorials, we have examples in our
324
- [our GitHub repo](https://www.github.com/marimo-team/marimo/tree/main/examples).
 
 
325
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
  )
327
- return
328
 
329
 
330
- @app.cell(hide_code=True)
331
- def __(mo):
332
- mo.md(
333
- """
334
- ## 6. The marimo editor
 
 
 
 
 
 
335
 
336
- Here are some tips to help you get started with the marimo editor.
337
- """
 
 
 
 
 
 
 
 
 
 
338
  )
339
- return
340
 
341
 
342
  @app.cell
343
- def __(mo, tips):
344
- mo.accordion(tips)
345
- return
 
 
 
 
 
 
 
346
 
347
 
348
- @app.cell(hide_code=True)
349
- def __(mo):
350
- mo.md("""## Finally, a fun fact""")
351
- return
 
 
 
 
 
 
 
 
 
 
 
 
352
 
353
 
354
  @app.cell(hide_code=True)
355
- def __(mo):
356
- mo.md(
357
- """
358
- The name "marimo" is a reference to a type of algae that, under
359
- the right conditions, clumps together to form a small sphere
360
- called a "marimo moss ball". Made of just strands of algae, these
361
- beloved assemblages are greater than the sum of their parts.
362
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  )
364
- return
365
 
 
 
 
 
 
366
 
367
- @app.cell(hide_code=True)
368
- def __():
369
- tips = {
370
- "Saving": (
371
- """
372
- **Saving**
373
-
374
- - _Name_ your app using the box at the top of the screen, or
375
- with `Ctrl/Cmd+s`. You can also create a named app at the
376
- command line, e.g., `marimo edit app_name.py`.
377
-
378
- - _Save_ by clicking the save icon on the bottom right, or by
379
- inputting `Ctrl/Cmd+s`. By default marimo is configured
380
- to autosave.
381
- """
382
- ),
383
- "Running": (
384
- """
385
- 1. _Run a cell_ by clicking the play ( ▷ ) button on the top
386
- right of a cell, or by inputting `Ctrl/Cmd+Enter`.
387
-
388
- 2. _Run a stale cell_ by clicking the yellow run button on the
389
- right of the cell, or by inputting `Ctrl/Cmd+Enter`. A cell is
390
- stale when its code has been modified but not run.
391
-
392
- 3. _Run all stale cells_ by clicking the play ( ▷ ) button on
393
- the bottom right of the screen, or input `Ctrl/Cmd+Shift+r`.
394
- """
395
- ),
396
- "Console Output": (
397
- """
398
- Console output (e.g., `print()` statements) is shown below a
399
- cell.
400
- """
401
- ),
402
- "Creating, Moving, and Deleting Cells": (
403
- """
404
- 1. _Create_ a new cell above or below a given one by clicking
405
- the plus button to the left of the cell, which appears on
406
- mouse hover.
407
-
408
- 2. _Move_ a cell up or down by dragging on the handle to the
409
- right of the cell, which appears on mouse hover.
410
-
411
- 3. _Delete_ a cell by clicking the trash bin icon. Bring it
412
- back by clicking the undo button on the bottom right of the
413
- screen, or with `Ctrl/Cmd+Shift+z`.
414
- """
415
- ),
416
- "Disabling Automatic Execution": (
417
- """
418
- Via the notebook settings (gear icon) or footer panel, you
419
- can disable automatic execution. This is helpful when
420
- working with expensive notebooks or notebooks that have
421
- side-effects like database transactions.
422
- """
423
- ),
424
- "Disabling Cells": (
425
- """
426
- You can disable a cell via the cell context menu.
427
- marimo will never run a disabled cell or any cells that depend on it.
428
- This can help prevent accidental execution of expensive computations
429
- when editing a notebook.
430
- """
431
- ),
432
- "Code Folding": (
433
- """
434
- You can collapse or fold the code in a cell by clicking the arrow
435
- icons in the line number column to the left, or by using keyboard
436
- shortcuts.
437
-
438
- Use the command palette (`Ctrl/Cmd+k`) or a keyboard shortcut to
439
- quickly fold or unfold all cells.
440
- """
441
- ),
442
- "Code Formatting": (
443
- """
444
- If you have [ruff](https://github.com/astral-sh/ruff) installed,
445
- you can format a cell with the keyboard shortcut `Ctrl/Cmd+b`.
446
- """
447
- ),
448
- "Command Palette": (
449
- """
450
- Use `Ctrl/Cmd+k` to open the command palette.
451
- """
452
- ),
453
- "Keyboard Shortcuts": (
454
- """
455
- Open the notebook menu (top-right) or input `Ctrl/Cmd+Shift+h` to
456
- view a list of all keyboard shortcuts.
457
- """
458
- ),
459
- "Configuration": (
460
- """
461
- Configure the editor by clicking the gears icon near the top-right
462
- of the screen.
463
- """
464
- ),
465
- }
466
- return (tips,)
467
 
468
 
469
  if __name__ == "__main__":
 
1
  import marimo
2
 
3
+ __generated_with = "0.11.17"
4
+ app = marimo.App(width="medium")
5
 
6
 
7
  @app.cell
8
+ def _():
9
  import marimo as mo
10
+ import os
11
+ return mo, os
 
12
 
13
 
14
  @app.cell
15
+ def _(os):
16
+ ### Imports
17
+ from typing import (
18
+ Any, Dict, List, Optional, Pattern, Set, Union, Tuple
19
+ )
20
+ from pathlib import Path
21
+ from urllib.request import urlopen
22
+ # from rich.markdown import Markdown as Markd
23
+ from rich.console import Console
24
+ from rich.theme import Theme
25
+ from rich.text import Text
26
+ from rich import print
27
+ from tqdm import tqdm
28
+ from enum import Enum
29
+ import pandas as pd
30
+ import tempfile
31
+ import requests
32
+ import getpass
33
+ import urllib3
34
+ import base64
35
+ import time
36
+ import json
37
+ import uuid
38
+ import ssl
39
+ import ast
40
+ import re
41
+
42
+ pd.set_option('display.max_columns', None)
43
+ pd.set_option('display.max_rows', None)
44
+ pd.set_option('display.max_colwidth', None)
45
+ pd.set_option('display.width', None)
46
+
47
+ custom_theme = Theme({
48
+ "info": "blue_violet", "warning": "yellow", "danger": "red", "python": "blue_violet", "string": "cyan", "number": "magenta", "keyword": "bright_blue", "comment": "dim blue_violet", "json":"blue_violet"
49
+ })
50
+
51
+ # Set explicit temporary directory
52
+ os.environ['TMPDIR'] = '/tmp'
53
+
54
+ # Make sure Python's tempfile module also uses this directory
55
+ tempfile.tempdir = '/tmp'
56
+
57
+ ### Prepares the console
58
+ console = Console(width=250, color_system="auto", force_jupyter=True)
59
+ return (
60
+ Any,
61
+ Console,
62
+ Dict,
63
+ Enum,
64
+ List,
65
+ Optional,
66
+ Path,
67
+ Pattern,
68
+ Set,
69
+ Text,
70
+ Theme,
71
+ Tuple,
72
+ Union,
73
+ ast,
74
+ base64,
75
+ console,
76
+ custom_theme,
77
+ getpass,
78
+ json,
79
+ pd,
80
+ print,
81
+ re,
82
+ requests,
83
+ ssl,
84
+ tempfile,
85
+ time,
86
+ tqdm,
87
+ urllib3,
88
+ urlopen,
89
+ uuid,
90
+ )
91
 
92
 
93
  @app.cell
94
+ def _(mo):
95
+ ### Credentials for the watsonx.ai SDK client
96
+
97
+ # Endpoints
98
+ wx_platform_url = "https://api.dataplatform.cloud.ibm.com"
99
+ regions = {
100
+ "US": "https://us-south.ml.cloud.ibm.com",
101
+ "EU": "https://eu-de.ml.cloud.ibm.com",
102
+ "GB": "https://eu-gb.ml.cloud.ibm.com",
103
+ "JP": "https://jp-tok.ml.cloud.ibm.com",
104
+ "AU": "https://au-syd.ml.cloud.ibm.com",
105
+ "CA": "https://ca-tor.ml.cloud.ibm.com"
106
+ }
107
 
108
+ # Create a form with multiple elements
109
+ client_instantiation_form = (
110
+ mo.md('''
111
+ ###**watsonx.ai credentials:**
112
 
113
+ {wx_region}
 
 
 
114
 
115
+ {wx_api_key}
116
 
117
+ {space_id}
118
+ ''').style(max_height="300px", overflow="auto", border_color="blue")
119
+ .batch(
120
+ wx_region = mo.ui.dropdown(regions, label="Select your watsonx.ai region:", value="US", searchable=True),
121
+ wx_api_key = mo.ui.text(placeholder="Add your IBM Cloud api-key...", label="IBM Cloud Api-key:", kind="password"),
122
+ # project_id = mo.ui.text(placeholder="Add your watsonx.ai project_id...", label="Project_ID:", kind="text"),
123
+ space_id = mo.ui.text(placeholder="Add your watsonx.ai space_id...", label="Space_ID:", kind="text")
124
+ ,)
125
+ .form(show_clear_button=True, bordered=False)
 
 
 
 
 
 
 
 
 
126
  )
 
127
 
128
 
129
+ client_instantiation_form
130
+ return client_instantiation_form, regions, wx_platform_url
 
 
 
 
 
 
 
131
 
132
 
133
+ @app.cell
134
+ def _(client_instantiation_form, mo):
135
+ from ibm_watsonx_ai import APIClient, Credentials
136
+
137
+ if client_instantiation_form.value:
138
+ ### Instantiate the watsonx.ai client
139
+ wx_credentials = Credentials(
140
+ url=client_instantiation_form.value["wx_region"],
141
+ api_key=client_instantiation_form.value["wx_api_key"]
142
+ )
143
 
144
+ # project_client = APIClient(credentials=wx_credentials, project_id=client_instantiation_form.value["project_id"])
145
+ deployment_client = APIClient(credentials=wx_credentials, space_id=client_instantiation_form.value["space_id"])
146
+
147
+ task_credentials_details = deployment_client.task_credentials.store()
148
+ else:
149
+ # project_client = None
150
+ deployment_client = None
151
+ task_credentials_details = None
152
+
153
+ template_variant = mo.ui.dropdown(["Base","Get Watsonx Token - Example"], label="Code Template:", value="Base")
154
+
155
+ if deployment_client is not None:
156
+ client_callout_kind = "success"
157
+ else:
158
+ client_callout_kind = "neutral"
159
+
160
+ client_callout = mo.callout(template_variant, kind=client_callout_kind)
161
+
162
+ client_callout
163
+ return (
164
+ APIClient,
165
+ Credentials,
166
+ client_callout,
167
+ client_callout_kind,
168
+ deployment_client,
169
+ # project_client,
170
+ task_credentials_details,
171
+ template_variant,
172
+ wx_credentials,
173
+ )
174
 
 
 
 
175
 
176
+ @app.cell
177
+ def _(mo, template_variant):
178
+ # Template for WatsonX.ai deployable function
179
+ if template_variant.value == "Stream Files to IBM COS [Example]":
180
+ with open("stream_files_to_cos.py", "r") as file:
181
+ template = file.read()
182
+ else:
183
+ template = '''def your_function_name():
184
+
185
+ import subprocess
186
+ subprocess.check_output('pip install gensim', shell=True)
187
+ import gensim
188
+
189
+ def score(input_data):
190
+ message_from_input_payload = payload.get("input_data")[0].get("values")[0][0]
191
+ response_message = "Received message - {0}".format(message_from_input_payload)
192
+
193
+ # Score using the pre-defined model
194
+ score_response = {
195
+ 'predictions': [{'fields': ['Response_message_field', 'installed_lib_version'],
196
+ 'values': [[response_message, gensim.__version__]]
197
+ }]
198
+ }
199
+ return score_response
200
+
201
+ return score
202
+
203
+ score = your_function_name()
204
+ '''
205
+
206
+ function_editor = (
207
+ mo.md('''
208
+ #### **Create your function by editing the template:**
209
+
210
+ {editor}
211
+
212
+ ''')
213
+ .batch(
214
+ editor = mo.ui.code_editor(value=template, language="python", min_height=50)
215
+ )
216
+ .form(show_clear_button=True, bordered=False)
217
+ )
218
+
219
+ function_editor
220
+ return file, function_editor, template
221
+
222
+
223
+ @app.cell
224
+ def _(function_editor, mo, os):
225
+ if function_editor.value:
226
+ # Get the edited code from the function editor
227
+ code = function_editor.value['editor']
228
+ # Create a namespace to execute the code in
229
+ namespace = {}
230
+ # Execute the code
231
+ exec(code, namespace)
232
+
233
+ # Find the first function defined in the namespace
234
+ function_name = None
235
+ for name, obj in namespace.items():
236
+ if callable(obj) and name != "__builtins__":
237
+ function_name = name
238
+ break
239
+
240
+ if function_name:
241
+ # Instantiate the deployable function
242
+ deployable_function = namespace[function_name]
243
+ # Now deployable_function contains the score function
244
+ mo.md(f"Created deployable function from '{function_name}'")
245
+ # Create the directory if it doesn't exist
246
+ save_dir = "/tmp/notebook_functions"
247
+ os.makedirs(save_dir, exist_ok=True)
248
+ # Save the function code to a file
249
+ file_path = os.path.join(save_dir, f"{function_name}.py")
250
+ with open(file_path, "w") as f:
251
+ f.write(code)
252
+ else:
253
+ mo.md("No function found in the editor code")
254
+ return (
255
+ code,
256
+ deployable_function,
257
+ f,
258
+ file_path,
259
+ function_name,
260
+ name,
261
+ namespace,
262
+ obj,
263
+ save_dir,
264
  )
 
265
 
266
 
267
+ @app.cell
268
+ def _(deployment_client, mo, pd):
269
+ if deployment_client:
270
+ supported_specs = deployment_client.software_specifications.list()[
271
+ deployment_client.software_specifications.list()['STATE'] == 'supported'
272
+ ]
273
+
274
+ # Reset the index to start from 0
275
+ supported_specs = supported_specs.reset_index(drop=True)
276
+
277
+ # Create a mapping dictionary for framework names based on software specifications
278
+ framework_mapping = {
279
+ "tensorflow_rt24.1-py3.11": "TensorFlow",
280
+ "pytorch-onnx_rt24.1-py3.11": "PyTorch",
281
+ "onnxruntime_opset_19": "ONNX or ONNXRuntime",
282
+ "runtime-24.1-py3.11": "AI Services/Python Functions/Python Scripts",
283
+ "autoai-ts_rt24.1-py3.11": "AutoAI",
284
+ "autoai-kb_rt24.1-py3.11": "AutoAI",
285
+ "runtime-24.1-py3.11-cuda": "CUDA-enabled (GPU) Python Runtime",
286
+ "runtime-24.1-r4.3": "R Runtime 4.3",
287
+ "spark-mllib_3.4": "Apache Spark 3.4",
288
+ "autoai-rag_rt24.1-py3.11": "AutoAI RAG"
289
+ }
290
+
291
+ # Define the preferred order for items to appear at the top
292
+ preferred_order = [
293
+ "runtime-24.1-py3.11",
294
+ "runtime-24.1-py3.11-cuda",
295
+ "runtime-24.1-r4.3",
296
+ "ai-service-v5-software-specification",
297
+ "autoai-rag_rt24.1-py3.11",
298
+ "autoai-ts_rt24.1-py3.11",
299
+ "autoai-kb_rt24.1-py3.11",
300
+ "tensorflow_rt24.1-py3.11",
301
+ "pytorch-onnx_rt24.1-py3.11",
302
+ "onnxruntime_opset_19",
303
+ "spark-mllib_3.4",
304
+ ]
305
+
306
+ # Create a new column for sorting
307
+ supported_specs['SORT_ORDER'] = supported_specs['NAME'].apply(
308
+ lambda x: preferred_order.index(x) if x in preferred_order else len(preferred_order)
309
  )
310
+
311
+ # Sort the DataFrame by the new column
312
+ supported_specs = supported_specs.sort_values('SORT_ORDER').reset_index(drop=True)
313
+
314
+ # Drop the sorting column as it's no longer needed
315
+ supported_specs = supported_specs.drop(columns=['SORT_ORDER'])
316
+
317
+ # Drop the REPLACEMENT column if it exists and add NOTES column
318
+ if 'REPLACEMENT' in supported_specs.columns:
319
+ supported_specs = supported_specs.drop(columns=['REPLACEMENT'])
320
+
321
+ # Add NOTES column with framework information
322
+ supported_specs['NOTES'] = supported_specs['NAME'].map(framework_mapping).fillna("Other")
323
+
324
+ # Create a table with single-row selection
325
+ selection_table = mo.ui.table(
326
+ supported_specs,
327
+ selection="single", # Only allow selecting one row
328
+ label="#### **Select a supported software_spec runtime for your function asset** (For Python Functions select - *'runtime-24.1-py3.11'* ):",
329
+ initial_selection=[0], # Now selecting the first row, which should be runtime-24.1-py3.11
330
+ page_size=6
331
+ )
332
+ else:
333
+ sel_df = pd.DataFrame(
334
+ data=[["ID", "Activate deployment_client."]],
335
+ columns=["ID", "VALUE"]
336
+ )
337
+
338
+ selection_table = mo.ui.table(
339
+ sel_df,
340
+ selection="single", # Only allow selecting one row
341
+ label="You haven't activated the Deployment_Client",
342
+ initial_selection=[0]
343
  )
344
+
345
+ # Display the table
346
+ mo.md(f"""---
347
+ <br>
348
+ <br>
349
+ {selection_table}
350
+ <br>
351
+ <br>
352
+ ---
353
+ <br>
354
+ <br>
355
+ """)
356
+ return (
357
+ framework_mapping,
358
+ preferred_order,
359
+ sel_df,
360
+ selection_table,
361
+ supported_specs,
362
  )
 
363
 
364
 
365
  @app.cell
366
+ def _(mo):
367
+ input_schema_checkbox = mo.ui.checkbox(label="Add input schema (optional)")
368
+ output_schema_checkbox = mo.ui.checkbox(label="Add output schema (optional)")
369
+ sample_input_checkbox = mo.ui.checkbox(label="Add sample input example (optional)")
370
+ return input_schema_checkbox, output_schema_checkbox, sample_input_checkbox
371
 
372
 
373
+ @app.cell
374
+ def _(
375
+ input_schema_checkbox,
376
+ mo,
377
+ output_schema_checkbox,
378
+ sample_input_checkbox,
379
+ selection_table,
380
+ template_variant,
381
+ ):
382
+ if selection_table.value['ID'].iloc[0]:
383
+ # Create the input fields
384
+ if template_variant.value == "Stream Files to IBM COS [Example]":
385
+ fnc_nm = "stream_file_to_cos"
386
+ else:
387
+ fnc_nm = "your_function_name"
388
+
389
+ uploaded_function_name = mo.ui.text(placeholder="<Must be the same as the name in editor>", label="Function Name:", kind="text", value=f"{fnc_nm}", full_width=False)
390
+ tags_editor = mo.ui.array(
391
+ [mo.ui.text(placeholder="Metadata Tags..."), mo.ui.text(), mo.ui.text()],
392
+ label="Optional Metadata Tags"
393
+ )
394
+ software_spec = selection_table.value['ID'].iloc[0]
395
+
396
+ description_input = mo.ui.text_area(
397
+ placeholder="Write a description for your function...)",
398
+ label="Description",
399
+ max_length=256,
400
+ rows=5,
401
+ full_width=True
402
+ )
403
 
404
 
405
+ func_metadata=mo.hstack([
406
+ description_input,
407
+ mo.hstack([
408
+ uploaded_function_name,
409
+ tags_editor,
410
+ ], justify="start", gap=1, align="start", wrap=True)
411
+ ],
412
+ widths=[0.6,0.4],
413
+ gap=2.75
414
+ )
415
 
416
+ schema_metadata=mo.hstack([
417
+ input_schema_checkbox,
418
+ output_schema_checkbox,
419
+ sample_input_checkbox
420
+ ],
421
+ justify="center", gap=1, align="center", wrap=True
422
+ )
423
 
424
+ # Display the metadata inputs
425
+ mo.vstack([
426
+ func_metadata,
427
+ mo.md("**Make sure to click the checkboxes before filling in descriptions and tags or they will reset.**"),
428
+ schema_metadata
429
+ ],
430
+ align="center",
431
+ gap=2
432
+ )
433
+ return (
434
+ description_input,
435
+ fnc_nm,
436
+ func_metadata,
437
+ schema_metadata,
438
+ software_spec,
439
+ tags_editor,
440
+ uploaded_function_name,
441
  )
 
442
 
443
 
444
+ @app.cell
445
+ def _(json, mo):
446
+ if template_variant.value == "Stream Files to IBM COS [Example]":
447
+ from cos_stream_schema_examples import input_schema, output_schema, sample_input
448
+ else:
449
+ input_schema = [
450
+ {
451
+ 'id': '1',
452
+ 'type': 'struct',
453
+ 'fields': [
454
+ {
455
+ 'name': '<variable name 1>',
456
+ 'type': 'string',
457
+ 'nullable': False,
458
+ 'metadata': {}
459
+ },
460
+ {
461
+ 'name': '<variable name 2>',
462
+ 'type': 'string',
463
+ 'nullable': False,
464
+ 'metadata': {}
465
+ }
466
+ ]
467
+ }
468
+ ]
469
+
470
+ output_schema = [
471
+ {
472
+ 'id': '1',
473
+ 'type': 'struct',
474
+ 'fields': [
475
+ {
476
+ 'name': '<output return name>',
477
+ 'type': 'string',
478
+ 'nullable': False,
479
+ 'metadata': {}
480
+ }
481
+ ]
482
+ }
483
+ ]
484
+
485
+ sample_input = {
486
+ 'input_data': [
487
+ {
488
+ 'fields': ['<variable name 1>', '<variable name 2>'],
489
+ 'values': [
490
+ ['<sample input value for variable 1>', '<sample input value for variable 2>']
491
+ ]
492
+ }
493
+ ]
494
  }
 
 
495
 
496
 
497
+ input_schema_editor = mo.ui.code_editor(value=json.dumps(input_schema, indent=4), language="python", min_height=25)
498
+ output_schema_editor = mo.ui.code_editor(value=json.dumps(output_schema, indent=4), language="python", min_height=25)
499
+ sample_input_editor = mo.ui.code_editor(value=json.dumps(sample_input, indent=4), language="python", min_height=25)
 
 
500
 
501
+ schema_editors = mo.accordion(
502
+ {
503
+ """**Input Schema Metadata Editor**""": input_schema_editor,
504
+ """**Output Schema Metadata Editor**""": output_schema_editor,
505
+ """**Sample Input Metadata Editor**""": sample_input_editor
506
+ }, multiple=True
507
+ )
508
 
509
+ schema_editors
510
+ return (
511
+ input_schema,
512
+ input_schema_editor,
513
+ output_schema,
514
+ output_schema_editor,
515
+ sample_input,
516
+ sample_input_editor,
517
+ schema_editors,
518
  )
 
519
 
520
 
521
  @app.cell
522
+ def _(
523
+ ast,
524
+ deployment_client,
525
+ description_input,
526
+ function_editor,
527
+ input_schema_checkbox,
528
+ input_schema_editor,
529
+ json,
530
+ mo,
531
+ os,
532
+ output_schema_checkbox,
533
+ output_schema_editor,
534
+ sample_input_checkbox,
535
+ sample_input_editor,
536
+ selection_table,
537
+ software_spec,
538
+ tags_editor,
539
+ uploaded_function_name,
540
+ ):
541
+ get_upload_status, set_upload_status = mo.state("No uploads yet")
542
+
543
+ function_meta = {}
544
+
545
+ if selection_table.value['ID'].iloc[0] and deployment_client is not None:
546
+ # Start with the base required fields
547
+ function_meta = {
548
+ deployment_client.repository.FunctionMetaNames.NAME: f"{uploaded_function_name.value}" or "your_function_name",
549
+ deployment_client.repository.FunctionMetaNames.SOFTWARE_SPEC_ID: software_spec or "45f12dfe-aa78-5b8d-9f38-0ee223c47309"
550
+ }
551
 
552
+ # Add optional fields if they exist
553
+ if tags_editor.value:
554
+ # Filter out empty strings from the tags list
555
+ filtered_tags = [tag for tag in tags_editor.value if tag and tag.strip()]
556
+ if filtered_tags: # Only add if there are non-empty tags
557
+ function_meta[deployment_client.repository.FunctionMetaNames.TAGS] = filtered_tags
558
+
559
+
560
+ if description_input.value:
561
+ function_meta[deployment_client.repository.FunctionMetaNames.DESCRIPTION] = description_input.value
562
+
563
+ # Add input schema if checkbox is checked
564
+ if input_schema_checkbox.value:
565
+ try:
566
+ function_meta[deployment_client.repository.FunctionMetaNames.INPUT_DATA_SCHEMAS] = json.loads(input_schema_editor.value)
567
+ except json.JSONDecodeError:
568
+ # If JSON parsing fails, try Python literal evaluation as fallback
569
+ function_meta[deployment_client.repository.FunctionMetaNames.INPUT_DATA_SCHEMAS] = ast.literal_eval(input_schema_editor.value)
570
+
571
+ # Add output schema if checkbox is checked
572
+ if output_schema_checkbox.value:
573
+ try:
574
+ function_meta[deployment_client.repository.FunctionMetaNames.OUTPUT_DATA_SCHEMAS] = json.loads(output_schema_editor.value)
575
+ except json.JSONDecodeError:
576
+ # If JSON parsing fails, try Python literal evaluation as fallback
577
+ function_meta[deployment_client.repository.FunctionMetaNames.OUTPUT_DATA_SCHEMAS] = ast.literal_eval(output_schema_editor.value)
578
+
579
+ # Add sample input if checkbox is checked
580
+ if sample_input_checkbox.value:
581
+ try:
582
+ function_meta[deployment_client.repository.FunctionMetaNames.SAMPLE_SCORING_INPUT] = json.loads(sample_input_editor.value)
583
+ except json.JSONDecodeError:
584
+ # If JSON parsing fails, try Python literal evaluation as fallback
585
+ function_meta[deployment_client.repository.FunctionMetaNames.SAMPLE_SCORING_INPUT] = ast.literal_eval(sample_input_editor.value)
586
+
587
+ def upload_function(function_meta, use_function_object=True):
588
+ """
589
+ Uploads a Python function to watsonx.ai as a deployable asset.
590
+ Parameters:
591
+ function_meta (dict): Metadata for the function
592
+ use_function_object (bool): Whether to use function object (True) or file path (False)
593
+ Returns:
594
+ dict: Details of the uploaded function
595
+ """
596
+ # Store the original working directory
597
+ original_dir = os.getcwd()
598
+
599
+ try:
600
+ # Create temp file from the code in the editor
601
+ code_to_deploy = function_editor.value['editor']
602
+ # This function is defined elsewhere in the notebook
603
+ func_name = uploaded_function_name.value or "your_function_name"
604
+ # Ensure function_meta has the correct function name
605
+ function_meta[deployment_client.repository.FunctionMetaNames.NAME] = func_name
606
+ # Save the file locally first
607
+ save_dir = "/tmp/notebook_functions"
608
+ os.makedirs(save_dir, exist_ok=True)
609
+ file_path = f"{save_dir}/{func_name}.py"
610
+ with open(file_path, "w", encoding="utf-8") as f:
611
+ f.write(code_to_deploy)
612
+
613
+ if use_function_object:
614
+ # Import the function from the file
615
+ import sys
616
+ import importlib.util
617
+ # Add the directory to Python's path
618
+ sys.path.append(save_dir)
619
+ # Import the module
620
+ spec = importlib.util.spec_from_file_location(func_name, file_path)
621
+ module = importlib.util.module_from_spec(spec)
622
+ spec.loader.exec_module(module)
623
+ # Get the function object
624
+ function_object = getattr(module, func_name)
625
+
626
+ # Change to /tmp directory before calling IBM Watson SDK functions
627
+ os.chdir('/tmp')
628
+
629
+ # Upload the function object
630
+ mo.md(f"Uploading function object: {func_name}")
631
+ func_details = deployment_client.repository.store_function(function_object, function_meta)
632
+ else:
633
+ # Change to /tmp directory before calling IBM Watson SDK functions
634
+ os.chdir('/tmp')
635
+
636
+ # Upload using the file path approach
637
+ mo.md(f"Uploading function from file: {file_path}")
638
+ func_details = deployment_client.repository.store_function(file_path, function_meta)
639
+
640
+ set_upload_status(f"Latest Upload - id - {func_details['metadata']['id']}")
641
+ return func_details
642
+ except Exception as e:
643
+ set_upload_status(f"Error uploading function: {str(e)}")
644
+ mo.md(f"Detailed error: {str(e)}")
645
+ raise
646
+ finally:
647
+ # Always change back to the original directory, even if an exception occurs
648
+ os.chdir(original_dir)
649
+
650
+ upload_status = mo.state("No uploads yet")
651
+
652
+ upload_button = mo.ui.button(
653
+ label="Upload Function",
654
+ on_click=lambda _: upload_function(function_meta, use_function_object=True),
655
+ kind="success",
656
+ tooltip="Click to upload function to watsonx.ai"
657
+ )
658
 
659
+ function_meta
660
+ return (
661
+ filtered_tags,
662
+ function_meta,
663
+ get_upload_status,
664
+ set_upload_status,
665
+ upload_button,
666
+ upload_function,
667
+ upload_status,
668
+ )
669
 
670
 
671
  @app.cell
672
+ def _(get_upload_status, mo, upload_button):
673
+ # Upload your function
674
+ if upload_button.value:
675
+ try:
676
+ upload_result = upload_button.value
677
+ artifact_id = upload_result['metadata']['id']
678
+ except Exception as e:
679
+ mo.md(f"Error: {str(e)}")
680
+
681
+ upload_func = mo.vstack([
682
+ upload_button,
683
+ mo.md(f"**Status:** {get_upload_status()}")
684
+ ], justify="space-around", align="center")
685
+ return artifact_id, upload_func, upload_result
686
 
687
 
688
  @app.cell
689
+ def _(deployment_client, mo, pd, upload_button, upload_func, uuid):
690
+ def reorder_hardware_specifications(df):
691
+ """
692
+ Reorders a hardware specifications dataframe by type and size of environment
693
+ without hardcoding specific hardware types.
694
 
695
+ Parameters:
696
+ df (pandas.DataFrame): The hardware specifications dataframe to reorder
697
 
698
+ Returns:
699
+ pandas.DataFrame: Reordered dataframe with reset index
700
+ """
701
+ # Create a copy to avoid modifying the original dataframe
702
+ result_df = df.copy()
703
+
704
+ # Define a function to extract the base type and size
705
+ def get_sort_key(name):
706
+ # Create a custom ordering list
707
+ custom_order = [
708
+ "XXS", "XS", "S", "M", "L", "XL",
709
+ "XS-Spark", "S-Spark", "M-Spark", "L-Spark", "XL-Spark",
710
+ "K80", "K80x2", "K80x4",
711
+ "V100", "V100x2",
712
+ "WXaaS-XS", "WXaaS-S", "WXaaS-M", "WXaaS-L", "WXaaS-XL",
713
+ "Default Spark", "Notebook Default Spark", "ML"
714
+ ]
715
+
716
+ # If name is in the custom order list, use its index
717
+ if name in custom_order:
718
+ return (0, custom_order.index(name))
719
+
720
+ # For any name not in the custom order, put it at the end
721
+ return (1, name)
722
+
723
+ # Add a temporary column for sorting
724
+ result_df['sort_key'] = result_df['NAME'].apply(get_sort_key)
725
+
726
+ # Sort the dataframe and drop the temporary column
727
+ result_df = result_df.sort_values('sort_key').drop('sort_key', axis=1)
728
+
729
+ # Reset the index
730
+ result_df = result_df.reset_index(drop=True)
731
+
732
+ return result_df
733
+
734
+ if deployment_client and upload_button.value:
735
+
736
+ hardware_specs = deployment_client.hardware_specifications.list()
737
+ hardware_specs_df = reorder_hardware_specifications(hardware_specs)
738
+
739
+ # Create a table with single-row selection
740
+ hw_selection_table = mo.ui.table(
741
+ hardware_specs_df,
742
+ selection="single", # Only allow selecting one row
743
+ label="#### **Select a supported hardware_specification for your deployment** *(Default: 'XS' - 1vCPU_4GB Ram)*",
744
+ initial_selection=[1],
745
+ page_size=6,
746
+ wrapped_columns=['DESCRIPTION']
747
+ )
748
 
749
+ deployment_type = mo.ui.radio(
750
+ options={"Function":"Online (Function Endpoint)","Runnable Job":"Batch (Runnable Jobs)"}, value="Function", label="Select the Type of Deployment:", inline=True
751
+ )
752
+ uuid_suffix = str(uuid.uuid4())[:4]
753
 
754
+ deployment_name = mo.ui.text(value=f"deployed_func_{uuid_suffix}", label="Deployment Name:", placeholder="<Must be completely unique>")
755
+ else:
756
+ hw_df = pd.DataFrame(
757
+ data=[["ID", "Activate deployment_client."]],
758
+ columns=["ID", "VALUE"]
759
+ )
760
 
761
+ hw_selection_table = mo.ui.table(
762
+ hw_df,
763
+ selection="single", # Only allow selecting one row
764
+ label="You haven't activated the Deployment_Client",
765
+ initial_selection=[0]
766
+ )
767
 
 
768
 
769
+ mo.md(f"""
770
+ <br>
771
+ <br>
772
+ {upload_func}
773
+ <br>
774
+ <br>
775
+ ---
776
+ {hw_selection_table}
777
+ <br>
778
+ <br>
779
+
780
+
781
+ """)
782
+ return (
783
+ deployment_name,
784
+ deployment_type,
785
+ hardware_specs,
786
+ hardware_specs_df,
787
+ hw_df,
788
+ hw_selection_table,
789
+ reorder_hardware_specifications,
790
+ uuid_suffix,
791
  )
 
792
 
793
 
794
+ @app.cell
795
+ def _(
796
+ artifact_id,
797
+ deployment_client,
798
+ deployment_details,
799
+ deployment_name,
800
+ deployment_type,
801
+ hw_selection_table,
802
+ mo,
803
+ print,
804
+ upload_button,
805
+ ):
806
+ def deploy_function(artifact_id, deployment_type):
807
  """
808
+ Deploys a function asset to watsonx.ai.
809
 
810
+ Parameters:
811
+ artifact_id (str): ID of the function artifact to deploy
812
+ deployment_type (object): Type of deployment (online or batch)
813
 
814
+ Returns:
815
+ dict: Details of the deployed function
 
816
  """
817
+ if not artifact_id:
818
+ print("Error: No artifact ID provided. Please upload a function first.")
819
+ return None
820
+
821
+ if deployment_type.value == "Online (Function Endpoint)": # Changed from "Online (Function Endpoint)"
822
+ deployment_props = {
823
+ deployment_client.deployments.ConfigurationMetaNames.NAME: deployment_name.value,
824
+ deployment_client.deployments.ConfigurationMetaNames.ONLINE: {},
825
+ deployment_client.deployments.ConfigurationMetaNames.HARDWARE_SPEC: {"id": selected_hw_config},
826
+ deployment_client.deployments.ConfigurationMetaNames.SERVING_NAME: deployment_name.value,
827
+ }
828
+ else: # "Runnable Job" instead of "Batch (Runnable Jobs)"
829
+ deployment_props = {
830
+ deployment_client.deployments.ConfigurationMetaNames.NAME: deployment_name.value,
831
+ deployment_client.deployments.ConfigurationMetaNames.BATCH: {},
832
+ deployment_client.deployments.ConfigurationMetaNames.HARDWARE_SPEC: {"id": selected_hw_config},
833
+ # batch does not use serving names
834
+ }
835
+
836
+ try:
837
+ print(deployment_props)
838
+ # First, get the asset details to confirm it exists
839
+ asset_details = deployment_client.repository.get_details(artifact_id)
840
+ print(f"Asset found: {asset_details['metadata']['name']} with ID: {asset_details['metadata']['id']}")
841
+
842
+ # Create the deployment
843
+ deployed_function = deployment_client.deployments.create(artifact_id, deployment_props)
844
+ print(f"Creating deployment from Asset: {artifact_id} with deployment properties {str(deployment_props)}")
845
+ return deployed_function
846
+ except Exception as e:
847
+ print(f"Deployment error: {str(e)}")
848
+ return None
849
+
850
+ def get_deployment_id(deployed_function):
851
+ deployment_id = deployment_client.deployments.get_uid(deployment_details)
852
+ return deployment_id
853
+
854
+ def get_deployment_info(deployment_id):
855
+ deployment_info = deployment_client.deployments.get_details(deployment_id)
856
+ return deployment_info
857
+
858
+ deployment_status = mo.state("No deployments yet")
859
+
860
+ if hw_selection_table.value['ID'].iloc[0]:
861
+ selected_hw_config = hw_selection_table.value['ID'].iloc[0]
862
+
863
+ deploy_button = mo.ui.button(
864
+ label="Deploy Function",
865
+ on_click=lambda _: deploy_function(artifact_id, deployment_type),
866
+ kind="success",
867
+ tooltip="Click to deploy function to watsonx.ai"
868
  )
 
869
 
870
+ if deployment_client and upload_button.value:
871
+ deployment_definition = mo.hstack([
872
+ deployment_type,
873
+ deployment_name
874
+ ], justify="space-around")
875
+ else:
876
+ deployment_definition = mo.hstack([
877
+ "No Deployment Type Selected",
878
+ "No Deployment Name Provided"
879
+ ], justify="space-around")
880
+
881
+ # deployment_definition
882
+ return (
883
+ deploy_button,
884
+ deploy_function,
885
+ deployment_definition,
886
+ deployment_status,
887
+ get_deployment_id,
888
+ get_deployment_info,
889
+ selected_hw_config,
890
+ )
891
 
 
 
 
 
 
892
 
893
+ @app.cell
894
+ def _(deploy_button, deployment_definition, mo):
895
+ _ = deployment_definition
896
 
897
+ deploy_fnc = mo.vstack([
898
+ deploy_button,
899
+ deploy_button.value
900
+ ], justify="space-around", align="center")
901
 
902
+ mo.md(f"""
903
+ {deployment_definition}
904
+ <br>
905
+ <br>
906
+ {deploy_fnc}
907
 
908
+ ---
909
+ """)
910
+ return (deploy_fnc,)
911
 
 
912
 
913
+ @app.cell(hide_code=True)
914
+ def _(deployment_client, mo):
915
+ ### Functions to List , Get ID's as a list and Purge of Assets
916
 
917
+ def get_deployment_list():
918
+ deployment_df = deployment_client.deployments.list()
919
+ return deployment_df
920
 
921
+ def get_deployment_ids(df):
922
+ dep_list = df['ID'].tolist()
923
+ return dep_list
924
 
925
+ def get_data_assets_list():
926
+ data_assets_df = deployment_client.data_assets.list()
927
+ return data_assets_df
928
 
929
+ def get_data_asset_ids(df):
930
+ data_asset_list = df['ASSET_ID'].tolist()
931
+ return data_asset_list
932
 
933
+ ### List Repository Assets, Get ID's as a list and Purge Repository Assets (AI Services, Functions, Models, etc.)
934
+ def get_repository_list():
935
+ repository_df = deployment_client.repository.list()
936
+ return repository_df
 
 
 
 
 
 
937
 
938
+ def get_repository_ids(df):
939
+ repository_list = df['ID'].tolist()
940
+ return repository_list
941
 
942
+ def delete_with_progress(ids_list, delete_function, item_type="items"):
943
+ """
944
+ Generic wrapper that adds a progress bar to any deletion function
945
 
946
+ Parameters:
947
+ ids_list: List of IDs to delete
948
+ delete_function: Function that deletes a single ID
949
+ item_type: String describing what's being deleted (for display)
950
  """
951
+ with mo.status.progress_bar(
952
+ total=len(ids_list) or 1,
953
+ title=f"Purging {item_type}",
954
+ subtitle=f"Deleting {item_type}...",
955
+ completion_title="Purge Complete",
956
+ completion_subtitle=f"Successfully deleted {len(ids_list)} {item_type}"
957
+ ) as progress:
958
+ for item_id in ids_list:
959
+ delete_function(item_id)
960
+ progress.update(increment=1)
961
+ return f"Deleted {len(ids_list)} {item_type} successfully"
962
+
963
+ # Use with existing deletion functions
964
+ def delete_deployments(deployment_ids):
965
+ return delete_with_progress(
966
+ deployment_ids,
967
+ lambda id: deployment_client.deployments.delete(id),
968
+ "deployments"
969
+ )
970
+
971
+ def delete_data_assets(data_asset_ids):
972
+ return delete_with_progress(
973
+ data_asset_ids,
974
+ lambda id: deployment_client.data_assets.delete(id),
975
+ "data assets"
976
+ )
977
+
978
+ def delete_repository_items(repository_ids):
979
+ return delete_with_progress(
980
+ repository_ids,
981
+ lambda id: deployment_client.repository.delete(id),
982
+ "repository items"
983
+ )
984
+ return (
985
+ delete_data_assets,
986
+ delete_deployments,
987
+ delete_repository_items,
988
+ delete_with_progress,
989
+ get_data_asset_ids,
990
+ get_data_assets_list,
991
+ get_deployment_ids,
992
+ get_deployment_list,
993
+ get_repository_ids,
994
+ get_repository_list,
995
  )
 
996
 
997
 
998
+ @app.cell
999
+ def _(get_deployment_id_list, get_deployments_button, mo, purge_deployments):
1000
+ deployments_purge_stack = mo.hstack([get_deployments_button, get_deployment_id_list, purge_deployments])
1001
+ deployments_purge_stack_results = mo.vstack([get_deployments_button.value, get_deployment_id_list.value, purge_deployments.value])
1002
+
1003
+ deployments_purge_tab = mo.vstack([deployments_purge_stack, deployments_purge_stack_results])
1004
+ return (
1005
+ deployments_purge_stack,
1006
+ deployments_purge_stack_results,
1007
+ deployments_purge_tab,
1008
+ )
1009
 
1010
+
1011
+ @app.cell
1012
+ def _(get_repository_button, get_repository_id_list, mo, purge_repository):
1013
+ repository_purge_stack = mo.hstack([get_repository_button, get_repository_id_list, purge_repository])
1014
+
1015
+ repository_purge_stack_results = mo.vstack([get_repository_button.value, get_repository_id_list.value, purge_repository.value])
1016
+
1017
+ repository_purge_tab = mo.vstack([repository_purge_stack, repository_purge_stack_results])
1018
+ return (
1019
+ repository_purge_stack,
1020
+ repository_purge_stack_results,
1021
+ repository_purge_tab,
1022
  )
 
1023
 
1024
 
1025
  @app.cell
1026
+ def _(get_data_asset_id_list, get_data_assets_button, mo, purge_data_assets):
1027
+ data_assets_purge_stack = mo.hstack([get_data_assets_button, get_data_asset_id_list, purge_data_assets])
1028
+ data_assets_purge_stack_results = mo.vstack([get_data_assets_button.value, get_data_asset_id_list.value, purge_data_assets.value])
1029
+
1030
+ data_assets_purge_tab = mo.vstack([data_assets_purge_stack, data_assets_purge_stack_results])
1031
+ return (
1032
+ data_assets_purge_stack,
1033
+ data_assets_purge_stack_results,
1034
+ data_assets_purge_tab,
1035
+ )
1036
 
1037
 
1038
+ @app.cell
1039
+ def _(data_assets_purge_tab, deployments_purge_tab, mo, repository_purge_tab):
1040
+ purge_tabs = mo.ui.tabs(
1041
+ {"Purge Deployments": deployments_purge_tab, "Purge Repository Assets": repository_purge_tab,"Purge Data Assets": data_assets_purge_tab }, lazy=False
1042
+ )
1043
+
1044
+ asset_purge = mo.accordion(
1045
+ {
1046
+ """<br>
1047
+ #### **Supporting Cleanup Functionality, lists of different assets and purge them if needed** *(purges all detected)*
1048
+ <br>""": purge_tabs,
1049
+ }
1050
+ )
1051
+
1052
+ asset_purge
1053
+ return asset_purge, purge_tabs
1054
 
1055
 
1056
  @app.cell(hide_code=True)
1057
+ def _(
1058
+ delete_data_assets,
1059
+ delete_deployments,
1060
+ delete_repository_items,
1061
+ get_data_asset_ids,
1062
+ get_data_assets_list,
1063
+ get_deployment_ids,
1064
+ get_deployment_list,
1065
+ get_repository_ids,
1066
+ get_repository_list,
1067
+ mo,
1068
+ ):
1069
+ ### Temporary Function Purge - Assets
1070
+ get_data_assets_button = mo.ui.button(
1071
+ label="Get Data Assets Dataframe",
1072
+ on_click=lambda _: get_data_assets_list(),
1073
+ kind="neutral",
1074
+ )
1075
+
1076
+ get_data_asset_id_list = mo.ui.button(
1077
+ label="Turn Dataframe into List of IDs",
1078
+ on_click=lambda _: get_data_asset_ids(get_data_assets_button.value),
1079
+ kind="neutral",
1080
  )
 
1081
 
1082
+ purge_data_assets = mo.ui.button(
1083
+ label="Purge Data Assets",
1084
+ on_click=lambda _: delete_data_assets(get_data_asset_id_list.value),
1085
+ kind="danger",
1086
+ )
1087
 
1088
+ ### Temporary Function Purge - Deployments
1089
+ get_deployments_button = mo.ui.button(
1090
+ label="Get Deployments Dataframe",
1091
+ on_click=lambda _: get_deployment_list(),
1092
+ kind="neutral",
1093
+ )
1094
+
1095
+ get_deployment_id_list = mo.ui.button(
1096
+ label="Turn Dataframe into List of IDs",
1097
+ on_click=lambda _: get_deployment_ids(get_deployments_button.value),
1098
+ kind="neutral",
1099
+ )
1100
+
1101
+ purge_deployments = mo.ui.button(
1102
+ label="Purge Deployments",
1103
+ on_click=lambda _: delete_deployments(get_deployment_id_list.value),
1104
+ kind="danger",
1105
+ )
1106
+
1107
+ ### Repository Items Purge
1108
+ get_repository_button = mo.ui.button(
1109
+ label="Get Repository Dataframe",
1110
+ on_click=lambda _: get_repository_list(),
1111
+ kind="neutral",
1112
+ )
1113
+
1114
+ get_repository_id_list = mo.ui.button(
1115
+ label="Turn Dataframe into List of IDs",
1116
+ on_click=lambda _: get_repository_ids(get_repository_button.value),
1117
+ kind="neutral",
1118
+ )
1119
+
1120
+ purge_repository = mo.ui.button(
1121
+ label="Purge Repository Items",
1122
+ on_click=lambda _: delete_repository_items(get_repository_id_list.value),
1123
+ kind="danger",
1124
+ )
1125
+ return (
1126
+ get_data_asset_id_list,
1127
+ get_data_assets_button,
1128
+ get_deployment_id_list,
1129
+ get_deployments_button,
1130
+ get_repository_button,
1131
+ get_repository_id_list,
1132
+ purge_data_assets,
1133
+ purge_deployments,
1134
+ purge_repository,
1135
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1136
 
1137
 
1138
  if __name__ == "__main__":