Upgrading API Download and Upload Model to support ModelVersion and ArtifactVersion 95/14495/6
authorashishj1729 <jain.ashish@samsung.com>
Thu, 22 May 2025 07:41:47 +0000 (13:11 +0530)
committerashishj1729 <jain.ashish@samsung.com>
Fri, 23 May 2025 11:13:52 +0000 (16:43 +0530)
Issue-id: AIMLFW-208
Change-Id: Ia38af79eaf63fb6546b7b2dc580115e2fe29fe56
Signed-off-by: ashishj1729 <jain.ashish@samsung.com>
apis/mmes_apis.go
core/s3_manager.go
routers/router.go

index e0aeda6..96f9c0d 100644 (file)
@@ -23,6 +23,7 @@ import (
        "io"
        "net/http"
        "os"
+       "strings"
 
        "gerrit.o-ran-sc.org/r/aiml-fw/awmf/modelmgmtservice/core"
        "gerrit.o-ran-sc.org/r/aiml-fw/awmf/modelmgmtservice/db"
@@ -236,7 +237,14 @@ func (m *MmeApiHandler) GetModelInfoByName(cont *gin.Context) {
        logging.INFO("Get model info by name API ...")
        modelName := cont.Param("modelName")
 
-       bucketObj := m.dbmgr.GetBucketObject(modelName+os.Getenv("INFO_FILE_POSTFIX"), modelName)
+       bucketObj, err := m.dbmgr.GetBucketObject(modelName+os.Getenv("INFO_FILE_POSTFIX"), modelName)
+       if err != nil {
+               logging.ERROR("Unable to GetModelInfoByName: Error ", err)
+               cont.JSON(http.StatusInternalServerError, gin.H{
+                       "code":    http.StatusInternalServerError,
+                       "message": err.Error(),
+               })
+       }
        modelInfoListResp := models.ModelInfoResponse{
                Name: modelName,
                Data: string(bucketObj),
@@ -249,11 +257,14 @@ func (m *MmeApiHandler) GetModelInfoByName(cont *gin.Context) {
 }
 
 // API to upload the trained model in zip format
-// TODO : Model version as input
-
 func (m *MmeApiHandler) UploadModel(cont *gin.Context) {
        logging.INFO("Uploading model API ...")
        modelName := cont.Param("modelName")
+       modelVersion := cont.Param("modelVersion")
+       artifactVersion := cont.Param("artifactVersion")
+
+       modelKey := fmt.Sprintf("%s_%s_%s", modelName, modelVersion, artifactVersion)
+       exportBucket := strings.ToLower(modelName)
        //TODO convert multipart.FileHeader to []byted
        fileHeader, _ := cont.FormFile("file")
        //TODO : Accept only .zip file for trained model
@@ -261,8 +272,8 @@ func (m *MmeApiHandler) UploadModel(cont *gin.Context) {
        defer file.Close()
        byteFile, _ := io.ReadAll((file))
 
-       logging.INFO("Uploading model : " + modelName)
-       if err := m.dbmgr.UploadFile(byteFile, modelName+os.Getenv("MODEL_FILE_POSTFIX"), modelName); err != nil {
+       logging.INFO("Uploading model : " + modelKey)
+       if err := m.dbmgr.UploadFile(byteFile, modelKey+os.Getenv("MODEL_FILE_POSTFIX"), exportBucket); err != nil {
                logging.ERROR("Failed to Upload Model : ", err)
                cont.JSON(http.StatusInternalServerError, gin.H{
                        "code":    http.StatusInternalServerError,
@@ -283,9 +294,21 @@ Input: model name in path params as "modelName"
 func (m *MmeApiHandler) DownloadModel(cont *gin.Context) {
        logging.INFO("Download model API ...")
        modelName := cont.Param("modelName")
-       fileName := modelName + os.Getenv("MODEL_FILE_POSTFIX")
-       fileByes := m.dbmgr.GetBucketObject(fileName, modelName)
+       modelVersion := cont.Param("modelVersion")
+       artifactVersion := cont.Param("artifactVersion")
 
+       modelKey := fmt.Sprintf("%s_%s_%s", modelName, modelVersion, artifactVersion)
+       exportBucket := strings.ToLower(modelName)
+
+       fileName := modelKey + os.Getenv("MODEL_FILE_POSTFIX")
+       fileByes, err := m.dbmgr.GetBucketObject(fileName, exportBucket)
+       if err != nil {
+               cont.JSON(http.StatusInternalServerError, gin.H{
+                       "code":    http.StatusInternalServerError,
+                       "message": err.Error(),
+               })
+               return
+       }
        //Return file in api reponse using byte slice
        cont.Header("Content-Disposition", "attachment;"+fileName)
        cont.Header("Content-Type", "application/zip")
index 558b56d..5f25d89 100644 (file)
@@ -46,7 +46,7 @@ type S3Manager struct {
 
 type DBMgr interface {
        CreateBucket(bucketName string) (err error)
-       GetBucketObject(objectName string, bucketName string) BucketObject
+       GetBucketObject(objectName string, bucketName string) (BucketObject, error)
        DeleteBucket(client *s3.S3, objectName string, bucketName string)
        DeleteBucketObject(client *s3.S3, objectName string, bucketName string) bool
        UploadFile(dataBytes []byte, file_name string, bucketName string) error
@@ -115,7 +115,7 @@ func (s3manager *S3Manager) CreateBucket(bucketName string) (err error) {
 // objectName : Name of file/object under given bucket
 // bucketName : Name of s3 bucket
 // TODO: Return error
-func (s3manager *S3Manager) GetBucketObject(objectName string, bucketName string) BucketObject {
+func (s3manager *S3Manager) GetBucketObject(objectName string, bucketName string) (BucketObject, error) {
 
        var response []byte
        getInputs := &s3.GetObjectInput{
@@ -125,15 +125,16 @@ func (s3manager *S3Manager) GetBucketObject(objectName string, bucketName string
        result, err := s3manager.S3Client.GetObject(getInputs)
        if err != nil {
                logging.ERROR("Error, can't get fetch object..")
-               return response
+               return response, err
        }
        defer result.Body.Close()
        logging.INFO("Successfully retrieved object...")
        response, err = io.ReadAll(result.Body)
        if err != nil {
                logging.ERROR("Recived error while reading body:", err)
+               return nil, err
        }
-       return response
+       return response, nil
 }
 
 func (s3manager *S3Manager) DeleteBucket(client *s3.S3, objectName string, bucketName string) {
@@ -229,7 +230,11 @@ func (s3manager *S3Manager) ListBucket(bucketObjPostfix string) ([]Bucket, error
                        continue
                }
 
-               bucketObject := s3manager.GetBucketObject(*bucket.Name+bucketObjPostfix, *bucket.Name)
+               bucketObject, err := s3manager.GetBucketObject(*bucket.Name+bucketObjPostfix, *bucket.Name)
+               if err != nil {
+                       logging.ERROR("Unable to list bucketname ", *bucket.Name, ": Error : ", err.Error())
+                       continue
+               }
                if len(bucketObject) == 0 {
                        continue
                }
index a8d0bff..07115ba 100644 (file)
@@ -27,21 +27,21 @@ func InitRouter(handler *apis.MmeApiHandler) *gin.Engine {
        r.Use(gin.Logger())
        r.Use(gin.Recovery())
        api := r.Group("/ai-ml-model-registration/v1")
-    {
-        api.POST("/model-registrations", handler.RegisterModel)
-        api.POST("/model-registrations/updateArtifact/:modelname/:modelversion/:artifactversion", handler.UpdateArtifact)
-        api.GET("/model-registrations/:modelRegistrationId", handler.GetModelInfoById)
-        api.PUT("/model-registrations/:modelRegistrationId", handler.UpdateModel)
-        api.DELETE("/model-registrations/:modelRegistrationId", handler.DeleteModel)
-        api.GET("/getModelInfo/:modelName", handler.GetModelInfoByName)
-        api.POST("/uploadModel/:modelName", handler.UploadModel)
-        api.GET("/downloadModel/:modelName/model.zip", handler.DownloadModel)
-    }
+       {
+               api.POST("/model-registrations", handler.RegisterModel)
+               api.POST("/model-registrations/updateArtifact/:modelname/:modelversion/:artifactversion", handler.UpdateArtifact)
+               api.GET("/model-registrations/:modelRegistrationId", handler.GetModelInfoById)
+               api.PUT("/model-registrations/:modelRegistrationId", handler.UpdateModel)
+               api.DELETE("/model-registrations/:modelRegistrationId", handler.DeleteModel)
+               api.GET("/getModelInfo/:modelName", handler.GetModelInfoByName)
+               api.POST("/uploadModel/:modelName/:modelVersion/:artifactVersion", handler.UploadModel)
+               api.GET("/downloadModel/:modelName/:modelVersion/:artifactVersion/model.zip", handler.DownloadModel)
+       }
        // As per R1-AP v6
 
-    modelDiscovery:= r.Group("/ai-ml-model-discovery/v1")
-    {
-        modelDiscovery.GET("/models", handler.GetModelInfo)
-    }
+       modelDiscovery := r.Group("/ai-ml-model-discovery/v1")
+       {
+               modelDiscovery.GET("/models", handler.GetModelInfo)
+       }
        return r
 }