1
+ import json
2
+ import ads .common
3
+ import oci
4
+ import pytz
5
+ import datetime
6
+ import os
7
+ from oci .data_science .models import Metadata
8
+ import ads
9
+
10
+ class ModelDescription :
11
+
12
+ region = ''
13
+
14
+ empty_json = {
15
+ "version" : "1.0" ,
16
+ "type" : "modelOSSReferenceDescription" ,
17
+ "models" : []
18
+ }
19
+
20
+ def auth (self ):
21
+ authData = ads .common .auth .default_signer ()
22
+ signer = authData ['signer' ]
23
+ self .region = authData ['config' ]['region' ]
24
+
25
+ # data science client
26
+ self .data_science_client = oci .data_science .DataScienceClient ({'region' : self .region }, signer = signer )
27
+ # oss client
28
+ self .object_storage_client = oci .object_storage .ObjectStorageClient ({'region' : self .region }, signer = signer )
29
+
30
+ def __init__ (self , model_ocid = None ):
31
+
32
+ self .auth ()
33
+
34
+ if model_ocid == None :
35
+ # if no model given then start from scratch
36
+ self .modelDescriptionJson = self .empty_json
37
+ else :
38
+ # if model given then get that as the starting reference point
39
+ print ("Getting model details from backend" )
40
+ destination_file_path = "downloaded_artifact.json"
41
+ get_model_artifact_content_response = self .data_science_client .get_model_artifact_content (
42
+ model_id = model_ocid ,
43
+ )
44
+ try :
45
+ with open (destination_file_path , "wb" ) as f :
46
+ f .write (get_model_artifact_content_response .data .content )
47
+ with open (destination_file_path , 'r' ) as f :
48
+ self .modelDescriptionJson = json .load (f )
49
+ except FileNotFoundError :
50
+ print (f"File '{ destination_file_path } ' not found." )
51
+ except IOError as e :
52
+ print (f"Error reading or writing to file: { e } " )
53
+ except json .JSONDecodeError as e :
54
+ print (f"Error decoding JSON: { e } " )
55
+ except Exception as e :
56
+ print (f"An unexpected error occurred: { e } " )
57
+
58
+ def add (self , namespace , bucket , prefix = None , files = None ):
59
+ # Remove if the model already exists
60
+ self .remove (namespace , bucket , prefix )
61
+
62
+ def checkIfFileExists (fileName ):
63
+ isExists = False
64
+ try :
65
+ headResponse = self .object_storage_client .head_object (namespace , bucket , object_name = fileName )
66
+ if headResponse .status == 200 :
67
+ isExists = True
68
+ except Exception as e :
69
+ if hasattr (e , 'status' ) and e .status == 404 :
70
+ print (f"File not found in bucket: { fileName } " )
71
+ else :
72
+ print (f"An error occured: { e } " )
73
+ return isExists
74
+
75
+ # Function to un-paginate the api call with while loop
76
+ def listObjectVersionsUnpaginated ():
77
+ objectStorageList = []
78
+ has_next_page , opc_next_page = True , None
79
+ while has_next_page :
80
+ response = self .object_storage_client .list_object_versions (
81
+ namespace_name = namespace ,
82
+ bucket_name = bucket ,
83
+ prefix = prefix ,
84
+ fields = "name,size" ,
85
+ page = opc_next_page
86
+ )
87
+ objectStorageList .extend (response .data .items )
88
+ has_next_page = response .has_next_page
89
+ opc_next_page = response .next_page
90
+ return objectStorageList
91
+
92
+ # Fetch object details and put it into the objects variable
93
+ objectStorageList = []
94
+ if files == None :
95
+ objectStorageList = listObjectVersionsUnpaginated ()
96
+ else :
97
+ for fileName in files :
98
+ if checkIfFileExists (fileName = fileName ):
99
+ objectStorageList .append (self .object_storage_client .list_object_versions (
100
+ namespace_name = namespace ,
101
+ bucket_name = bucket ,
102
+ prefix = fileName ,
103
+ fields = "name,size" ,
104
+ ).data .items [0 ])
105
+
106
+ objects = [{
107
+ "name" : obj .name ,
108
+ "version" : obj .version_id ,
109
+ "sizeInBytes" : obj .size
110
+ } for obj in objectStorageList if obj .size > 0 ]
111
+
112
+ if len (objects ) == 0 :
113
+ print ("No files to add in the bucket: " , bucket , " with namespace: " , namespace , " and prefix: " , prefix , " file names: " , files )
114
+ return
115
+
116
+ self .modelDescriptionJson ['models' ].append ({
117
+ "namespace" : namespace ,
118
+ "bucketName" : bucket ,
119
+ "prefix" : prefix ,
120
+ "objects" : objects
121
+ })
122
+
123
+ def remove (self , namespace , bucket , prefix = None ):
124
+ def findModelIdx ():
125
+ for idx , model in enumerate (self .modelDescriptionJson ['models' ]):
126
+ if (model ['namespace' ], model ['bucketName' ], (model ['prefix' ] if ('prefix' in model ) else None ) ) == (namespace , bucket , prefix ):
127
+ return idx
128
+ return - 1
129
+
130
+ modelSearchIdx = findModelIdx ()
131
+ if modelSearchIdx == - 1 :
132
+ return
133
+ else :
134
+ # model found case
135
+ self .modelDescriptionJson ['models' ].pop (modelSearchIdx )
136
+
137
+ def show (self ):
138
+ print (json .dumps (self .modelDescriptionJson , indent = 4 ))
139
+
140
+ def build (self ):
141
+ print ("Building..." )
142
+ file_path = "resultModelDescription.json"
143
+ try :
144
+ with open (file_path , "w" ) as json_file :
145
+ json .dump (self .modelDescriptionJson , json_file , indent = 2 )
146
+ except IOError as e :
147
+ print (f"Error writing to file '{ file_path } ': { e } " ) # Handle the exception accordingly, e.g., log the error, retry writing, etc.
148
+ except Exception as e :
149
+ print (f"An unexpected error occurred: { e } " ) # Handle other unexpected exceptions
150
+ print ("Model Artifact stored at location: 'resultModelDescription.json'" )
151
+ return os .path .abspath (file_path )
152
+
153
+ def save (self , project_ocid , compartment_ocid , display_name = None ):
154
+ display_name = 'Created by MMS SDK on ' + datetime .datetime .now (pytz .utc ).strftime ('%Y-%m-%d %H:%M:%S %Z' ) if (display_name == None ) else display_name
155
+ customMetadataList = [
156
+ Metadata (key = "modelDescription" , value = "true" )
157
+ ]
158
+ model_details = oci .data_science .models .CreateModelDetails (
159
+ compartment_id = compartment_ocid ,
160
+ project_id = project_ocid ,
161
+ display_name = display_name ,
162
+ custom_metadata_list = customMetadataList
163
+ )
164
+ print ("Created model details" )
165
+ model = self .data_science_client .create_model (model_details )
166
+ print ("Created model" )
167
+ self .data_science_client .create_model_artifact (
168
+ model .data .id ,
169
+ json .dumps (self .modelDescriptionJson ),
170
+ content_disposition = 'attachment; filename="modelDescription.json"'
171
+ )
172
+ print ('Successfully created model with OCID: ' , model .data .id )
173
+ return model .data .id
0 commit comments