MilanM commited on
Commit
ff6e676
·
verified ·
1 Parent(s): 3fe98fb

Delete app_v1.py

Browse files
Files changed (1) hide show
  1. app_v1.py +0 -1152
app_v1.py DELETED
@@ -1,1152 +0,0 @@
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
- def setup_task_credentials(deployment_client):
138
- # Get existing task credentials
139
- existing_credentials = deployment_client.task_credentials.get_details()
140
-
141
- # Delete existing credentials if any
142
- if "resources" in existing_credentials and existing_credentials["resources"]:
143
- for cred in existing_credentials["resources"]:
144
- cred_id = deployment_client.task_credentials.get_id(cred)
145
- deployment_client.task_credentials.delete(cred_id)
146
-
147
- # Store new credentials
148
- return deployment_client.task_credentials.store()
149
-
150
- if client_instantiation_form.value:
151
- ### Instantiate the watsonx.ai client
152
- wx_credentials = Credentials(
153
- url=client_instantiation_form.value["wx_region"],
154
- api_key=client_instantiation_form.value["wx_api_key"]
155
- )
156
-
157
- # project_client = APIClient(credentials=wx_credentials, project_id=client_instantiation_form.value["project_id"])
158
- deployment_client = APIClient(credentials=wx_credentials, space_id=client_instantiation_form.value["space_id"])
159
-
160
- task_credentials_details = setup_task_credentials(deployment_client)
161
- else:
162
- # project_client = None
163
- deployment_client = None
164
- task_credentials_details = None
165
-
166
- template_variant = mo.ui.dropdown(["Base","Stream Files to IBM COS [Example]"], label="Code Template:", value="Base")
167
-
168
- if deployment_client is not None:
169
- client_callout_kind = "success"
170
- else:
171
- client_callout_kind = "neutral"
172
-
173
- client_callout = mo.callout(template_variant, kind=client_callout_kind)
174
-
175
- client_callout
176
- return (
177
- APIClient,
178
- Credentials,
179
- client_callout,
180
- client_callout_kind,
181
- deployment_client,
182
- # project_client,
183
- task_credentials_details,
184
- template_variant,
185
- wx_credentials,
186
- )
187
-
188
-
189
- @app.cell
190
- def _(mo, template_variant):
191
- # Template for WatsonX.ai deployable function
192
- if template_variant.value == "Stream Files to IBM COS [Example]":
193
- with open("stream_files_to_cos.py", "r") as file:
194
- template = file.read()
195
- else:
196
- template = '''def your_function_name():
197
-
198
- import subprocess
199
- subprocess.check_output('pip install gensim', shell=True)
200
- import gensim
201
-
202
- def score(input_data):
203
- message_from_input_payload = payload.get("input_data")[0].get("values")[0][0]
204
- response_message = "Received message - {0}".format(message_from_input_payload)
205
-
206
- # Score using the pre-defined model
207
- score_response = {
208
- 'predictions': [{'fields': ['Response_message_field', 'installed_lib_version'],
209
- 'values': [[response_message, gensim.__version__]]
210
- }]
211
- }
212
- return score_response
213
-
214
- return score
215
-
216
- score = your_function_name()
217
- '''
218
-
219
- function_editor = (
220
- mo.md('''
221
- #### **Create your function by editing the template:**
222
-
223
- {editor}
224
-
225
- ''')
226
- .batch(
227
- editor = mo.ui.code_editor(value=template, language="python", min_height=50)
228
- )
229
- .form(show_clear_button=True, bordered=False)
230
- )
231
-
232
- function_editor
233
- return file, function_editor, template
234
-
235
-
236
- @app.cell
237
- def _(function_editor, mo, os):
238
- if function_editor.value:
239
- # Get the edited code from the function editor
240
- code = function_editor.value['editor']
241
- # Create a namespace to execute the code in
242
- namespace = {}
243
- # Execute the code
244
- exec(code, namespace)
245
-
246
- # Find the first function defined in the namespace
247
- function_name = None
248
- for name, obj in namespace.items():
249
- if callable(obj) and name != "__builtins__":
250
- function_name = name
251
- break
252
-
253
- if function_name:
254
- # Instantiate the deployable function
255
- deployable_function = namespace[function_name]
256
- # Now deployable_function contains the score function
257
- mo.md(f"Created deployable function from '{function_name}'")
258
- # Create the directory if it doesn't exist
259
- save_dir = "/tmp/notebook_functions"
260
- os.makedirs(save_dir, exist_ok=True)
261
- # Save the function code to a file
262
- file_path = os.path.join(save_dir, f"{function_name}.py")
263
- with open(file_path, "w") as f:
264
- f.write(code)
265
- else:
266
- mo.md("No function found in the editor code")
267
- return (
268
- code,
269
- deployable_function,
270
- f,
271
- file_path,
272
- function_name,
273
- name,
274
- namespace,
275
- obj,
276
- save_dir,
277
- )
278
-
279
-
280
- @app.cell
281
- def _(deployment_client, mo, pd):
282
- if deployment_client:
283
- supported_specs = deployment_client.software_specifications.list()[
284
- deployment_client.software_specifications.list()['STATE'] == 'supported'
285
- ]
286
-
287
- # Reset the index to start from 0
288
- supported_specs = supported_specs.reset_index(drop=True)
289
-
290
- # Create a mapping dictionary for framework names based on software specifications
291
- framework_mapping = {
292
- "tensorflow_rt24.1-py3.11": "TensorFlow",
293
- "pytorch-onnx_rt24.1-py3.11": "PyTorch",
294
- "onnxruntime_opset_19": "ONNX or ONNXRuntime",
295
- "runtime-24.1-py3.11": "AI Services/Python Functions/Python Scripts",
296
- "autoai-ts_rt24.1-py3.11": "AutoAI",
297
- "autoai-kb_rt24.1-py3.11": "AutoAI",
298
- "runtime-24.1-py3.11-cuda": "CUDA-enabled (GPU) Python Runtime",
299
- "runtime-24.1-r4.3": "R Runtime 4.3",
300
- "spark-mllib_3.4": "Apache Spark 3.4",
301
- "autoai-rag_rt24.1-py3.11": "AutoAI RAG"
302
- }
303
-
304
- # Define the preferred order for items to appear at the top
305
- preferred_order = [
306
- "runtime-24.1-py3.11",
307
- "runtime-24.1-py3.11-cuda",
308
- "runtime-24.1-r4.3",
309
- "ai-service-v5-software-specification",
310
- "autoai-rag_rt24.1-py3.11",
311
- "autoai-ts_rt24.1-py3.11",
312
- "autoai-kb_rt24.1-py3.11",
313
- "tensorflow_rt24.1-py3.11",
314
- "pytorch-onnx_rt24.1-py3.11",
315
- "onnxruntime_opset_19",
316
- "spark-mllib_3.4",
317
- ]
318
-
319
- # Create a new column for sorting
320
- supported_specs['SORT_ORDER'] = supported_specs['NAME'].apply(
321
- lambda x: preferred_order.index(x) if x in preferred_order else len(preferred_order)
322
- )
323
-
324
- # Sort the DataFrame by the new column
325
- supported_specs = supported_specs.sort_values('SORT_ORDER').reset_index(drop=True)
326
-
327
- # Drop the sorting column as it's no longer needed
328
- supported_specs = supported_specs.drop(columns=['SORT_ORDER'])
329
-
330
- # Drop the REPLACEMENT column if it exists and add NOTES column
331
- if 'REPLACEMENT' in supported_specs.columns:
332
- supported_specs = supported_specs.drop(columns=['REPLACEMENT'])
333
-
334
- # Add NOTES column with framework information
335
- supported_specs['NOTES'] = supported_specs['NAME'].map(framework_mapping).fillna("Other")
336
-
337
- # Create a table with single-row selection
338
- selection_table = mo.ui.table(
339
- supported_specs,
340
- selection="single", # Only allow selecting one row
341
- label="#### **Select a supported software_spec runtime for your function asset** (For Python Functions select - *'runtime-24.1-py3.11'* ):",
342
- initial_selection=[0], # Now selecting the first row, which should be runtime-24.1-py3.11
343
- page_size=6
344
- )
345
- else:
346
- sel_df = pd.DataFrame(
347
- data=[["ID", "Activate deployment_client."]],
348
- columns=["ID", "VALUE"]
349
- )
350
-
351
- selection_table = mo.ui.table(
352
- sel_df,
353
- selection="single", # Only allow selecting one row
354
- label="You haven't activated the Deployment_Client",
355
- initial_selection=[0]
356
- )
357
-
358
- # Display the table
359
- mo.md(f"""---
360
- <br>
361
- <br>
362
- {selection_table}
363
- <br>
364
- <br>
365
- ---
366
- <br>
367
- <br>
368
- """)
369
- return (
370
- framework_mapping,
371
- preferred_order,
372
- sel_df,
373
- selection_table,
374
- supported_specs,
375
- )
376
-
377
-
378
- @app.cell
379
- def _(mo):
380
- input_schema_checkbox = mo.ui.checkbox(label="Add input schema (optional)")
381
- output_schema_checkbox = mo.ui.checkbox(label="Add output schema (optional)")
382
- sample_input_checkbox = mo.ui.checkbox(label="Add sample input example (optional)")
383
- return input_schema_checkbox, output_schema_checkbox, sample_input_checkbox
384
-
385
-
386
- @app.cell
387
- def _(
388
- input_schema_checkbox,
389
- mo,
390
- output_schema_checkbox,
391
- sample_input_checkbox,
392
- selection_table,
393
- template_variant,
394
- ):
395
- if selection_table.value['ID'].iloc[0]:
396
- # Create the input fields
397
- if template_variant.value == "Stream Files to IBM COS [Example]":
398
- fnc_nm = "stream_file_to_cos"
399
- else:
400
- fnc_nm = "your_function_name"
401
-
402
- 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)
403
- tags_editor = mo.ui.array(
404
- [mo.ui.text(placeholder="Metadata Tags..."), mo.ui.text(), mo.ui.text()],
405
- label="Optional Metadata Tags"
406
- )
407
- software_spec = selection_table.value['ID'].iloc[0]
408
-
409
- description_input = mo.ui.text_area(
410
- placeholder="Write a description for your function...)",
411
- label="Description",
412
- max_length=256,
413
- rows=5,
414
- full_width=True
415
- )
416
-
417
-
418
- func_metadata=mo.hstack([
419
- description_input,
420
- mo.hstack([
421
- uploaded_function_name,
422
- tags_editor,
423
- ], justify="start", gap=1, align="start", wrap=True)
424
- ],
425
- widths=[0.6,0.4],
426
- gap=2.75
427
- )
428
-
429
- schema_metadata=mo.hstack([
430
- input_schema_checkbox,
431
- output_schema_checkbox,
432
- sample_input_checkbox
433
- ],
434
- justify="center", gap=1, align="center", wrap=True
435
- )
436
-
437
- # Display the metadata inputs
438
- mo.vstack([
439
- func_metadata,
440
- mo.md("**Make sure to click the checkboxes before filling in descriptions and tags or they will reset.**"),
441
- schema_metadata
442
- ],
443
- align="center",
444
- gap=2
445
- )
446
- return (
447
- description_input,
448
- fnc_nm,
449
- func_metadata,
450
- schema_metadata,
451
- software_spec,
452
- tags_editor,
453
- uploaded_function_name,
454
- )
455
-
456
-
457
- @app.cell
458
- def _(json, mo):
459
- if template_variant.value == "Stream Files to IBM COS [Example]":
460
- from cos_stream_schema_examples import input_schema, output_schema, sample_input
461
- else:
462
- input_schema = [
463
- {
464
- 'id': '1',
465
- 'type': 'struct',
466
- 'fields': [
467
- {
468
- 'name': '<variable name 1>',
469
- 'type': 'string',
470
- 'nullable': False,
471
- 'metadata': {}
472
- },
473
- {
474
- 'name': '<variable name 2>',
475
- 'type': 'string',
476
- 'nullable': False,
477
- 'metadata': {}
478
- }
479
- ]
480
- }
481
- ]
482
-
483
- output_schema = [
484
- {
485
- 'id': '1',
486
- 'type': 'struct',
487
- 'fields': [
488
- {
489
- 'name': '<output return name>',
490
- 'type': 'string',
491
- 'nullable': False,
492
- 'metadata': {}
493
- }
494
- ]
495
- }
496
- ]
497
-
498
- sample_input = {
499
- 'input_data': [
500
- {
501
- 'fields': ['<variable name 1>', '<variable name 2>'],
502
- 'values': [
503
- ['<sample input value for variable 1>', '<sample input value for variable 2>']
504
- ]
505
- }
506
- ]
507
- }
508
-
509
-
510
- input_schema_editor = mo.ui.code_editor(value=json.dumps(input_schema, indent=4), language="python", min_height=25)
511
- output_schema_editor = mo.ui.code_editor(value=json.dumps(output_schema, indent=4), language="python", min_height=25)
512
- sample_input_editor = mo.ui.code_editor(value=json.dumps(sample_input, indent=4), language="python", min_height=25)
513
-
514
- schema_editors = mo.accordion(
515
- {
516
- """**Input Schema Metadata Editor**""": input_schema_editor,
517
- """**Output Schema Metadata Editor**""": output_schema_editor,
518
- """**Sample Input Metadata Editor**""": sample_input_editor
519
- }, multiple=True
520
- )
521
-
522
- schema_editors
523
- return (
524
- input_schema,
525
- input_schema_editor,
526
- output_schema,
527
- output_schema_editor,
528
- sample_input,
529
- sample_input_editor,
530
- schema_editors,
531
- )
532
-
533
-
534
- @app.cell
535
- def _(
536
- ast,
537
- deployment_client,
538
- description_input,
539
- function_editor,
540
- input_schema_checkbox,
541
- input_schema_editor,
542
- json,
543
- mo,
544
- os,
545
- output_schema_checkbox,
546
- output_schema_editor,
547
- sample_input_checkbox,
548
- sample_input_editor,
549
- selection_table,
550
- software_spec,
551
- tags_editor,
552
- uploaded_function_name,
553
- ):
554
- get_upload_status, set_upload_status = mo.state("No uploads yet")
555
-
556
- function_meta = {}
557
-
558
- if selection_table.value['ID'].iloc[0] and deployment_client is not None:
559
- # Start with the base required fields
560
- function_meta = {
561
- deployment_client.repository.FunctionMetaNames.NAME: f"{uploaded_function_name.value}" or "your_function_name",
562
- deployment_client.repository.FunctionMetaNames.SOFTWARE_SPEC_ID: software_spec or "45f12dfe-aa78-5b8d-9f38-0ee223c47309"
563
- }
564
-
565
- # Add optional fields if they exist
566
- if tags_editor.value:
567
- # Filter out empty strings from the tags list
568
- filtered_tags = [tag for tag in tags_editor.value if tag and tag.strip()]
569
- if filtered_tags: # Only add if there are non-empty tags
570
- function_meta[deployment_client.repository.FunctionMetaNames.TAGS] = filtered_tags
571
-
572
-
573
- if description_input.value:
574
- function_meta[deployment_client.repository.FunctionMetaNames.DESCRIPTION] = description_input.value
575
-
576
- # Add input schema if checkbox is checked
577
- if input_schema_checkbox.value:
578
- try:
579
- function_meta[deployment_client.repository.FunctionMetaNames.INPUT_DATA_SCHEMAS] = json.loads(input_schema_editor.value)
580
- except json.JSONDecodeError:
581
- # If JSON parsing fails, try Python literal evaluation as fallback
582
- function_meta[deployment_client.repository.FunctionMetaNames.INPUT_DATA_SCHEMAS] = ast.literal_eval(input_schema_editor.value)
583
-
584
- # Add output schema if checkbox is checked
585
- if output_schema_checkbox.value:
586
- try:
587
- function_meta[deployment_client.repository.FunctionMetaNames.OUTPUT_DATA_SCHEMAS] = json.loads(output_schema_editor.value)
588
- except json.JSONDecodeError:
589
- # If JSON parsing fails, try Python literal evaluation as fallback
590
- function_meta[deployment_client.repository.FunctionMetaNames.OUTPUT_DATA_SCHEMAS] = ast.literal_eval(output_schema_editor.value)
591
-
592
- # Add sample input if checkbox is checked
593
- if sample_input_checkbox.value:
594
- try:
595
- function_meta[deployment_client.repository.FunctionMetaNames.SAMPLE_SCORING_INPUT] = json.loads(sample_input_editor.value)
596
- except json.JSONDecodeError:
597
- # If JSON parsing fails, try Python literal evaluation as fallback
598
- function_meta[deployment_client.repository.FunctionMetaNames.SAMPLE_SCORING_INPUT] = ast.literal_eval(sample_input_editor.value)
599
-
600
- def upload_function(function_meta, use_function_object=True):
601
- """
602
- Uploads a Python function to watsonx.ai as a deployable asset.
603
- Parameters:
604
- function_meta (dict): Metadata for the function
605
- use_function_object (bool): Whether to use function object (True) or file path (False)
606
- Returns:
607
- dict: Details of the uploaded function
608
- """
609
- # Store the original working directory
610
- original_dir = os.getcwd()
611
-
612
- try:
613
- # Create temp file from the code in the editor
614
- code_to_deploy = function_editor.value['editor']
615
- # This function is defined elsewhere in the notebook
616
- func_name = uploaded_function_name.value or "your_function_name"
617
- # Ensure function_meta has the correct function name
618
- function_meta[deployment_client.repository.FunctionMetaNames.NAME] = func_name
619
- # Save the file locally first
620
- save_dir = "/tmp/notebook_functions"
621
- os.makedirs(save_dir, exist_ok=True)
622
- file_path = f"{save_dir}/{func_name}.py"
623
- with open(file_path, "w", encoding="utf-8") as f:
624
- f.write(code_to_deploy)
625
-
626
- if use_function_object:
627
- # Import the function from the file
628
- import sys
629
- import importlib.util
630
- # Add the directory to Python's path
631
- sys.path.append(save_dir)
632
- # Import the module
633
- spec = importlib.util.spec_from_file_location(func_name, file_path)
634
- module = importlib.util.module_from_spec(spec)
635
- spec.loader.exec_module(module)
636
- # Get the function object
637
- function_object = getattr(module, func_name)
638
-
639
- # Change to /tmp directory before calling IBM Watson SDK functions
640
- os.chdir('/tmp')
641
-
642
- # Upload the function object
643
- mo.md(f"Uploading function object: {func_name}")
644
- func_details = deployment_client.repository.store_function(function_object, function_meta)
645
- else:
646
- # Change to /tmp directory before calling IBM Watson SDK functions
647
- os.chdir('/tmp')
648
-
649
- # Upload using the file path approach
650
- mo.md(f"Uploading function from file: {file_path}")
651
- func_details = deployment_client.repository.store_function(file_path, function_meta)
652
-
653
- set_upload_status(f"Latest Upload - id - {func_details['metadata']['id']}")
654
- return func_details
655
- except Exception as e:
656
- set_upload_status(f"Error uploading function: {str(e)}")
657
- mo.md(f"Detailed error: {str(e)}")
658
- raise
659
- finally:
660
- # Always change back to the original directory, even if an exception occurs
661
- os.chdir(original_dir)
662
-
663
- upload_status = mo.state("No uploads yet")
664
-
665
- upload_button = mo.ui.button(
666
- label="Upload Function",
667
- on_click=lambda _: upload_function(function_meta, use_function_object=True),
668
- kind="success",
669
- tooltip="Click to upload function to watsonx.ai"
670
- )
671
-
672
- function_meta
673
- return (
674
- filtered_tags,
675
- function_meta,
676
- get_upload_status,
677
- set_upload_status,
678
- upload_button,
679
- upload_function,
680
- upload_status,
681
- )
682
-
683
-
684
- @app.cell
685
- def _(get_upload_status, mo, upload_button):
686
- # Upload your function
687
- if upload_button.value:
688
- try:
689
- upload_result = upload_button.value
690
- artifact_id = upload_result['metadata']['id']
691
- except Exception as e:
692
- mo.md(f"Error: {str(e)}")
693
-
694
- upload_func = mo.vstack([
695
- upload_button,
696
- mo.md(f"**Status:** {get_upload_status()}")
697
- ], justify="space-around", align="center")
698
- return artifact_id, upload_func, upload_result
699
-
700
-
701
- @app.cell
702
- def _(deployment_client, mo, pd, upload_button, upload_func, uuid):
703
- def reorder_hardware_specifications(df):
704
- """
705
- Reorders a hardware specifications dataframe by type and size of environment
706
- without hardcoding specific hardware types.
707
-
708
- Parameters:
709
- df (pandas.DataFrame): The hardware specifications dataframe to reorder
710
-
711
- Returns:
712
- pandas.DataFrame: Reordered dataframe with reset index
713
- """
714
- # Create a copy to avoid modifying the original dataframe
715
- result_df = df.copy()
716
-
717
- # Define a function to extract the base type and size
718
- def get_sort_key(name):
719
- # Create a custom ordering list
720
- custom_order = [
721
- "XXS", "XS", "S", "M", "L", "XL",
722
- "XS-Spark", "S-Spark", "M-Spark", "L-Spark", "XL-Spark",
723
- "K80", "K80x2", "K80x4",
724
- "V100", "V100x2",
725
- "WXaaS-XS", "WXaaS-S", "WXaaS-M", "WXaaS-L", "WXaaS-XL",
726
- "Default Spark", "Notebook Default Spark", "ML"
727
- ]
728
-
729
- # If name is in the custom order list, use its index
730
- if name in custom_order:
731
- return (0, custom_order.index(name))
732
-
733
- # For any name not in the custom order, put it at the end
734
- return (1, name)
735
-
736
- # Add a temporary column for sorting
737
- result_df['sort_key'] = result_df['NAME'].apply(get_sort_key)
738
-
739
- # Sort the dataframe and drop the temporary column
740
- result_df = result_df.sort_values('sort_key').drop('sort_key', axis=1)
741
-
742
- # Reset the index
743
- result_df = result_df.reset_index(drop=True)
744
-
745
- return result_df
746
-
747
- if deployment_client and upload_button.value:
748
-
749
- hardware_specs = deployment_client.hardware_specifications.list()
750
- hardware_specs_df = reorder_hardware_specifications(hardware_specs)
751
-
752
- # Create a table with single-row selection
753
- hw_selection_table = mo.ui.table(
754
- hardware_specs_df,
755
- selection="single", # Only allow selecting one row
756
- label="#### **Select a supported hardware_specification for your deployment** *(Default: 'XS' - 1vCPU_4GB Ram)*",
757
- initial_selection=[1],
758
- page_size=6,
759
- wrapped_columns=['DESCRIPTION']
760
- )
761
-
762
- deployment_type = mo.ui.radio(
763
- options={"Function":"Online (Function Endpoint)","Runnable Job":"Batch (Runnable Jobs)"}, value="Function", label="Select the Type of Deployment:", inline=True
764
- )
765
- uuid_suffix = str(uuid.uuid4())[:4]
766
-
767
- deployment_name = mo.ui.text(value=f"deployed_func_{uuid_suffix}", label="Deployment Name:", placeholder="<Must be completely unique>")
768
- else:
769
- hw_df = pd.DataFrame(
770
- data=[["ID", "Activate deployment_client."]],
771
- columns=["ID", "VALUE"]
772
- )
773
-
774
- hw_selection_table = mo.ui.table(
775
- hw_df,
776
- selection="single", # Only allow selecting one row
777
- label="You haven't activated the Deployment_Client",
778
- initial_selection=[0]
779
- )
780
-
781
-
782
- mo.md(f"""
783
- <br>
784
- <br>
785
- {upload_func}
786
- <br>
787
- <br>
788
- ---
789
- {hw_selection_table}
790
- <br>
791
- <br>
792
-
793
-
794
- """)
795
- return (
796
- deployment_name,
797
- deployment_type,
798
- hardware_specs,
799
- hardware_specs_df,
800
- hw_df,
801
- hw_selection_table,
802
- reorder_hardware_specifications,
803
- uuid_suffix,
804
- )
805
-
806
-
807
- @app.cell
808
- def _(
809
- artifact_id,
810
- deployment_client,
811
- deployment_details,
812
- deployment_name,
813
- deployment_type,
814
- hw_selection_table,
815
- mo,
816
- print,
817
- upload_button,
818
- ):
819
- def deploy_function(artifact_id, deployment_type):
820
- """
821
- Deploys a function asset to watsonx.ai.
822
-
823
- Parameters:
824
- artifact_id (str): ID of the function artifact to deploy
825
- deployment_type (object): Type of deployment (online or batch)
826
-
827
- Returns:
828
- dict: Details of the deployed function
829
- """
830
- if not artifact_id:
831
- print("Error: No artifact ID provided. Please upload a function first.")
832
- return None
833
-
834
- if deployment_type.value == "Online (Function Endpoint)": # Changed from "Online (Function Endpoint)"
835
- deployment_props = {
836
- deployment_client.deployments.ConfigurationMetaNames.NAME: deployment_name.value,
837
- deployment_client.deployments.ConfigurationMetaNames.ONLINE: {},
838
- deployment_client.deployments.ConfigurationMetaNames.HARDWARE_SPEC: {"id": selected_hw_config},
839
- deployment_client.deployments.ConfigurationMetaNames.SERVING_NAME: deployment_name.value,
840
- }
841
- else: # "Runnable Job" instead of "Batch (Runnable Jobs)"
842
- deployment_props = {
843
- deployment_client.deployments.ConfigurationMetaNames.NAME: deployment_name.value,
844
- deployment_client.deployments.ConfigurationMetaNames.BATCH: {},
845
- deployment_client.deployments.ConfigurationMetaNames.HARDWARE_SPEC: {"id": selected_hw_config},
846
- # batch does not use serving names
847
- }
848
-
849
- try:
850
- print(deployment_props)
851
- # First, get the asset details to confirm it exists
852
- asset_details = deployment_client.repository.get_details(artifact_id)
853
- print(f"Asset found: {asset_details['metadata']['name']} with ID: {asset_details['metadata']['id']}")
854
-
855
- # Create the deployment
856
- deployed_function = deployment_client.deployments.create(artifact_id, deployment_props)
857
- print(f"Creating deployment from Asset: {artifact_id} with deployment properties {str(deployment_props)}")
858
- return deployed_function
859
- except Exception as e:
860
- print(f"Deployment error: {str(e)}")
861
- return None
862
-
863
- def get_deployment_id(deployed_function):
864
- deployment_id = deployment_client.deployments.get_uid(deployment_details)
865
- return deployment_id
866
-
867
- def get_deployment_info(deployment_id):
868
- deployment_info = deployment_client.deployments.get_details(deployment_id)
869
- return deployment_info
870
-
871
- deployment_status = mo.state("No deployments yet")
872
-
873
- if hw_selection_table.value['ID'].iloc[0]:
874
- selected_hw_config = hw_selection_table.value['ID'].iloc[0]
875
-
876
- deploy_button = mo.ui.button(
877
- label="Deploy Function",
878
- on_click=lambda _: deploy_function(artifact_id, deployment_type),
879
- kind="success",
880
- tooltip="Click to deploy function to watsonx.ai"
881
- )
882
-
883
- if deployment_client and upload_button.value:
884
- deployment_definition = mo.hstack([
885
- deployment_type,
886
- deployment_name
887
- ], justify="space-around")
888
- else:
889
- deployment_definition = mo.hstack([
890
- "No Deployment Type Selected",
891
- "No Deployment Name Provided"
892
- ], justify="space-around")
893
-
894
- # deployment_definition
895
- return (
896
- deploy_button,
897
- deploy_function,
898
- deployment_definition,
899
- deployment_status,
900
- get_deployment_id,
901
- get_deployment_info,
902
- selected_hw_config,
903
- )
904
-
905
-
906
- @app.cell
907
- def _(deploy_button, deployment_definition, mo):
908
- _ = deployment_definition
909
-
910
- deploy_fnc = mo.vstack([
911
- deploy_button,
912
- deploy_button.value
913
- ], justify="space-around", align="center")
914
-
915
- mo.md(f"""
916
- {deployment_definition}
917
- <br>
918
- <br>
919
- {deploy_fnc}
920
-
921
- ---
922
- """)
923
- return (deploy_fnc,)
924
-
925
-
926
- @app.cell(hide_code=True)
927
- def _(deployment_client, mo):
928
- ### Functions to List , Get ID's as a list and Purge of Assets
929
-
930
- def get_deployment_list():
931
- deployment_df = deployment_client.deployments.list()
932
- return deployment_df
933
-
934
- def get_deployment_ids(df):
935
- dep_list = df['ID'].tolist()
936
- return dep_list
937
-
938
- def get_data_assets_list():
939
- data_assets_df = deployment_client.data_assets.list()
940
- return data_assets_df
941
-
942
- def get_data_asset_ids(df):
943
- data_asset_list = df['ASSET_ID'].tolist()
944
- return data_asset_list
945
-
946
- ### List Repository Assets, Get ID's as a list and Purge Repository Assets (AI Services, Functions, Models, etc.)
947
- def get_repository_list():
948
- repository_df = deployment_client.repository.list()
949
- return repository_df
950
-
951
- def get_repository_ids(df):
952
- repository_list = df['ID'].tolist()
953
- return repository_list
954
-
955
- def delete_with_progress(ids_list, delete_function, item_type="items"):
956
- """
957
- Generic wrapper that adds a progress bar to any deletion function
958
-
959
- Parameters:
960
- ids_list: List of IDs to delete
961
- delete_function: Function that deletes a single ID
962
- item_type: String describing what's being deleted (for display)
963
- """
964
- with mo.status.progress_bar(
965
- total=len(ids_list) or 1,
966
- title=f"Purging {item_type}",
967
- subtitle=f"Deleting {item_type}...",
968
- completion_title="Purge Complete",
969
- completion_subtitle=f"Successfully deleted {len(ids_list)} {item_type}"
970
- ) as progress:
971
- for item_id in ids_list:
972
- delete_function(item_id)
973
- progress.update(increment=1)
974
- return f"Deleted {len(ids_list)} {item_type} successfully"
975
-
976
- # Use with existing deletion functions
977
- def delete_deployments(deployment_ids):
978
- return delete_with_progress(
979
- deployment_ids,
980
- lambda id: deployment_client.deployments.delete(id),
981
- "deployments"
982
- )
983
-
984
- def delete_data_assets(data_asset_ids):
985
- return delete_with_progress(
986
- data_asset_ids,
987
- lambda id: deployment_client.data_assets.delete(id),
988
- "data assets"
989
- )
990
-
991
- def delete_repository_items(repository_ids):
992
- return delete_with_progress(
993
- repository_ids,
994
- lambda id: deployment_client.repository.delete(id),
995
- "repository items"
996
- )
997
- return (
998
- delete_data_assets,
999
- delete_deployments,
1000
- delete_repository_items,
1001
- delete_with_progress,
1002
- get_data_asset_ids,
1003
- get_data_assets_list,
1004
- get_deployment_ids,
1005
- get_deployment_list,
1006
- get_repository_ids,
1007
- get_repository_list,
1008
- )
1009
-
1010
-
1011
- @app.cell
1012
- def _(get_deployment_id_list, get_deployments_button, mo, purge_deployments):
1013
- deployments_purge_stack = mo.hstack([get_deployments_button, get_deployment_id_list, purge_deployments])
1014
- deployments_purge_stack_results = mo.vstack([get_deployments_button.value, get_deployment_id_list.value, purge_deployments.value])
1015
-
1016
- deployments_purge_tab = mo.vstack([deployments_purge_stack, deployments_purge_stack_results])
1017
- return (
1018
- deployments_purge_stack,
1019
- deployments_purge_stack_results,
1020
- deployments_purge_tab,
1021
- )
1022
-
1023
-
1024
- @app.cell
1025
- def _(get_repository_button, get_repository_id_list, mo, purge_repository):
1026
- repository_purge_stack = mo.hstack([get_repository_button, get_repository_id_list, purge_repository])
1027
-
1028
- repository_purge_stack_results = mo.vstack([get_repository_button.value, get_repository_id_list.value, purge_repository.value])
1029
-
1030
- repository_purge_tab = mo.vstack([repository_purge_stack, repository_purge_stack_results])
1031
- return (
1032
- repository_purge_stack,
1033
- repository_purge_stack_results,
1034
- repository_purge_tab,
1035
- )
1036
-
1037
-
1038
- @app.cell
1039
- def _(get_data_asset_id_list, get_data_assets_button, mo, purge_data_assets):
1040
- data_assets_purge_stack = mo.hstack([get_data_assets_button, get_data_asset_id_list, purge_data_assets])
1041
- data_assets_purge_stack_results = mo.vstack([get_data_assets_button.value, get_data_asset_id_list.value, purge_data_assets.value])
1042
-
1043
- data_assets_purge_tab = mo.vstack([data_assets_purge_stack, data_assets_purge_stack_results])
1044
- return (
1045
- data_assets_purge_stack,
1046
- data_assets_purge_stack_results,
1047
- data_assets_purge_tab,
1048
- )
1049
-
1050
-
1051
- @app.cell
1052
- def _(data_assets_purge_tab, deployments_purge_tab, mo, repository_purge_tab):
1053
- purge_tabs = mo.ui.tabs(
1054
- {"Purge Deployments": deployments_purge_tab, "Purge Repository Assets": repository_purge_tab,"Purge Data Assets": data_assets_purge_tab }, lazy=False
1055
- )
1056
-
1057
- asset_purge = mo.accordion(
1058
- {
1059
- """<br>
1060
- #### **Supporting Cleanup Functionality, lists of different assets and purge them if needed** *(purges all detected)*
1061
- <br>""": purge_tabs,
1062
- }
1063
- )
1064
-
1065
- asset_purge
1066
- return asset_purge, purge_tabs
1067
-
1068
-
1069
- @app.cell(hide_code=True)
1070
- def _(
1071
- delete_data_assets,
1072
- delete_deployments,
1073
- delete_repository_items,
1074
- get_data_asset_ids,
1075
- get_data_assets_list,
1076
- get_deployment_ids,
1077
- get_deployment_list,
1078
- get_repository_ids,
1079
- get_repository_list,
1080
- mo,
1081
- ):
1082
- ### Temporary Function Purge - Assets
1083
- get_data_assets_button = mo.ui.button(
1084
- label="Get Data Assets Dataframe",
1085
- on_click=lambda _: get_data_assets_list(),
1086
- kind="neutral",
1087
- )
1088
-
1089
- get_data_asset_id_list = mo.ui.button(
1090
- label="Turn Dataframe into List of IDs",
1091
- on_click=lambda _: get_data_asset_ids(get_data_assets_button.value),
1092
- kind="neutral",
1093
- )
1094
-
1095
- purge_data_assets = mo.ui.button(
1096
- label="Purge Data Assets",
1097
- on_click=lambda _: delete_data_assets(get_data_asset_id_list.value),
1098
- kind="danger",
1099
- )
1100
-
1101
- ### Temporary Function Purge - Deployments
1102
- get_deployments_button = mo.ui.button(
1103
- label="Get Deployments Dataframe",
1104
- on_click=lambda _: get_deployment_list(),
1105
- kind="neutral",
1106
- )
1107
-
1108
- get_deployment_id_list = mo.ui.button(
1109
- label="Turn Dataframe into List of IDs",
1110
- on_click=lambda _: get_deployment_ids(get_deployments_button.value),
1111
- kind="neutral",
1112
- )
1113
-
1114
- purge_deployments = mo.ui.button(
1115
- label="Purge Deployments",
1116
- on_click=lambda _: delete_deployments(get_deployment_id_list.value),
1117
- kind="danger",
1118
- )
1119
-
1120
- ### Repository Items Purge
1121
- get_repository_button = mo.ui.button(
1122
- label="Get Repository Dataframe",
1123
- on_click=lambda _: get_repository_list(),
1124
- kind="neutral",
1125
- )
1126
-
1127
- get_repository_id_list = mo.ui.button(
1128
- label="Turn Dataframe into List of IDs",
1129
- on_click=lambda _: get_repository_ids(get_repository_button.value),
1130
- kind="neutral",
1131
- )
1132
-
1133
- purge_repository = mo.ui.button(
1134
- label="Purge Repository Items",
1135
- on_click=lambda _: delete_repository_items(get_repository_id_list.value),
1136
- kind="danger",
1137
- )
1138
- return (
1139
- get_data_asset_id_list,
1140
- get_data_assets_button,
1141
- get_deployment_id_list,
1142
- get_deployments_button,
1143
- get_repository_button,
1144
- get_repository_id_list,
1145
- purge_data_assets,
1146
- purge_deployments,
1147
- purge_repository,
1148
- )
1149
-
1150
-
1151
- if __name__ == "__main__":
1152
- app.run()