Skip to Content

SAP Leonardo

SAP Leonardo is a holistic digital innovation system that seamlessly integrates future-facing technologies and capabilities into the SAP Cloud Platform, using Design Thinking services. This powerful portfolio enables you to rapidly innovate, scale new models, and continually redefine your business.

SAP Leonardo Machine learning  ?

SAP Leonardo Machine Learning Foundation, built on SAP Cloud Platform, provides enterprise-grade machine learning capabilities to augment existing and new business processes with intelligent algorithms. Instantly consumable services and customized intelligent algorithms allow you to enrich your business processes to an extent that has never been possible before. Everything you need to create, run and maintain intelligent applications based on a common platform is already provided for you – no prior infrastructure or skills are required.

SAP Leonardo Machine Learning Foundation offers developers an ever-growing set of intelligent functional services, accessible via REST APIs, to perform a variety of tasks, such as detecting objects in images and videos or analysing written text.

Create, run, consume, and maintain machine self-learning apps with ease by using algorithms that require no data-science skills.

Use case :

As a part of annual physical inventory management process in the warehouse ,it is always a challenge to determine the product from the warehouse and collect the related information as most of the time it needs a qualified trained person who knows about each product in the warehouse.

For an instance , during physical inventory process , the warehouse team have to evaluate and enter the number of products available for each product .This activity is a manual process which also needs a adequate knowledge about each product .

 

 

This could be addressed easily by using Image classification API of SAP Leonardo Machine learning. In our use case we have built a simple browser based intelligent application which could identify the product  by simply uploading the image of the product by using the  Image classification API of SAP Leonardo and display the contents of a the related product available in SAP and allow us to update the count of that particular product .

Here is the workflow architecture for the same

Step 1 : Create ODATA Service

In our demo , we used the S/4 instance which has the core Netweaver Gateway components which we used as a embedded environment (both front end and back end in the same system)

Create a custom Z table in the SAP system (Embedded system or in the backend system)

Create a project using SEGW

Create the corresponding entity type and entity sets and edit the service implementation class for GetEntity , GetEntitySet  and Update as shown below

Generate the run time objects.

Activate the ODATA service using TCODE /IWFND/MAINT_SERVICE

For demo purpose we have entered the SAP login credentials in the particular SICF service .

Now test the GET and PUT method using SAP Gateway Client

Now we could use the ODATA service to GET and Update the product

Step 2 :Register for the SAP Leonardo Machine Learning API and get the API key for the service

a) Get Your Sandbox URL

In order to consume the Image Classification Machine Learning Functional Services, you will first need to get the service URI, your API Key and the request and response parameters.

Go to https://api.sap.com/ and click on the Browse tile.

Then you will be able to search for the SAP Leonardo Machine Learning – Functional Services, then click on the package found.

Click on Artifacts, then click on the Image Classification API.

On the Resource tab, you can notice the Image Classification API has only one resource (or service): /inference_sync.

If you expand the /inference_sync resource and look for the Parameters section, you will not that the service request require the following:

  • files (required) : The list of file(s) to be uploaded. Either:
    • one image file (image formats, such as .jpeg, .png, .tif, or .bmp)
    • one archive file containing multiple image files (format .zip, .tar.gz, or tar

Now click on the Overview tab.

Note: the term inference refers to the application phase (scoring) an existing model (as opposed to the training or inception phase) and sync for synchronous.

As displayed on the screen, the sandbox URL for the Image Classification API where we need to append the API resource:

  1. b) Get Your API key

When using any of the APIs outside of the SAP API Business Hub, an application key will be needed in every request header of your APIs calls.

To get to your API key, click on the    icon in the top right corner of the page. Click on the key icon.

The following pop-up should appear. Click on the Copy API Key button and save it in a text editor.

 

Now, let’s build a SAPUI5 application!

Step 3 : Build SAPUI5 application in Eclipse

 Create a new SAPUI5 development project in eclipse with Javascript as a development paradigm

 

Use the below codes for the index.html,controller.js and view.js

INDEX.HTML

<!DOCTYPE HTML>
<html>
	<head>
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>
		<script src="resources/sap-ui-core.js"
				id="sap-ui-bootstrap"
				data-sap-ui-libs="sap.m,sap.ui.commons,sap.ui.table,sap.ui.unified"
				data-sap-ui-theme="sap_bluecrystal">
		</script>
		<!-- only load the mobile lib "sap.m" and the "sap_bluecrystal" theme -->
		<script>
				sap.ui.localResources("demotable2");
				var app = new sap.m.App({initialPage:"idDemoTable2"});
				var page = sap.ui.view({id:"idDemoTable2", viewName:"demotable2.DemoTable2", type:sap.ui.core.mvc.ViewType.JS});
				app.addPage(page);
				app.placeAt("content");
		</script>
	</head>
	<body class="sapUiBody" role="application">
	    		<div id="content"></div>
	</body>
</html>

view.js

sap.ui.jsview("demotable2.DemoTable2", {

	/** Specifies the Controller belonging to this View. 
	* In the case that it is not implemented, or that "null" is returned, this View does not have a Controller.
	* @memberOf demotable2.DemoTable2
	*/ 
	getControllerName : function() {
		return "demotable2.DemoTable2";
	},

	/** Is initially called once after the Controller has been instantiated. It is the place where the UI is constructed. 
	* Since the Controller is given to this method, its event handlers can be attached right away. 
	* @memberOf demotable2.DemoTable2
	*/ 
	createContent : function(oController) {
			var oTable = new sap.ui.table.Table("tableId",{
			title: "Product Details",
			visibleRowCount:5,
			editable:false
		});
		oTable.addColumn(new sap.ui.table.Column({
			label: new sap.ui.commons.Label({text:"Product ID"}),
			visible: true,
		template: new sap.ui.commons.TextView({text:"{products>ProductId}"})
		}) );
		oTable.addColumn(new sap.ui.table.Column({
			label: new sap.ui.commons.Label({text:"Product Name"}),
			visible: true,
			template: new sap.ui.commons.TextView({text:"{products>ProductName}"})
		}) );
		
		oTable.addColumn(new sap.ui.table.Column({
			label: new sap.ui.commons.Label({text:"Product Count"}),
			visible: true,
			template: new sap.ui.commons.TextView({text:"{products>ProductCount}"})
		}) );
		oTable.bindRows("products>/d/results");
		
               //Create a form to Update the Product
		var oLayout = new sap.ui.layout.form.SimpleForm("formId",{
			title: "Product Maintainance",
			content: [
		      new sap.ui.commons.Label({text: "Product ID"}),
		          		          new sap.ui.commons.TextField({
		        	  id: 'ProductId',
		        	  width: '200px',
		        	  value:'{singleproduct>/d/ProductId}',
		        	  editable: false
		        	  }),    
		          new sap.ui.commons.Label({text: "Product Name"}),
		          		          new sap.ui.commons.TextField({
		        	  id: 'ProductName',
		        	  width: '200px',
		        	  value:'{singleproduct>/d/ProductName}',
		        	  editable: false
		        	  }), 
                  
		          new sap.ui.commons.Label({text: "Product Count"}),
		         		          new sap.ui.commons.TextField({
		        	  id: 'ProductCount',
		        	  width: '200px',
		        	  value:'{singleproduct>/d/ProductCount}'
		        	  }), 
		          new sap.ui.commons.Label({text: ""}),
		          new sap.ui.commons.Button({
		        	  text: "Save",
		        	  width: '100px',
		        	  press: function() {
		        		  oController.update()
		        	  }
		          })
		          
            ]
			
		});
	
		//Create a file uploader form
var oUploadLayout = new sap.ui.layout.form.SimpleForm("uploadformId",{
			
			//title: "Product Maintainance",
			content: [
       new sap.ui.unified.FileUploader("fileUploader",{
      				width: "400px",
    				tooltip: "Upload your image",
    				placeholder: "Upload a product image to search...",
    				fileType: ["jpg", "png"],
    				maximumFileSize: 2,
    				uploadOnChange: false,
    				multiple: true,
    				buttonText: "Browse",
    				additionalData: "abc=123&test=456",
                  }),
		          new sap.ui.commons.Label({text: ""}),
		          new sap.ui.commons.Button({
		        	  text: "Search",
		        	  width: '150px',
		        	  height: '50px',
		        	  press: function() {
		        		  oController.onUpload()
		        	  }
		          })
		          
            ]
			
		});
		
		        var ele = [oTable,oLayout,oUploadLayout];
		return ele;
 	}
});

Controller.js

sap.ui.controller("demotable2.DemoTable2", {

/**
* Called when a controller is instantiated and its View controls (if available) are already created.
* Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
* @memberOf demotable2.DemoTable2
*/
	onInit: function() {
		
					
		//use your ODATA URL of the app here
		var sUrl = "http://x.y.z.w:port/sap/opu/odata/sap/ZML_SRV/ProductSet";
		var oModel = sap.ui.model.json.JSONModel(sUrl);
		console.log(oModel);
		sap.ui.getCore().setModel(oModel,'products');
	},

	onAfterRendering: function() {
		$("#formId").hide();
	},

mode: 0,	
showform: function(){
	this.mode="showform";
$("#formId").slideDown(function() {
	})
	
},
onUpload: function(){
	var SingleID="";
	var oFileUploader = sap.ui.getCore().byId("fileUploader");
	if (!oFileUploader.getValue()) {
		sap.m.MessageToast.show("Choose a file first");
	}
	var that = this;
	var f = document.querySelector('input[type="file"]').files[0];
	//Create form object and append file to the same
	var data = new FormData();
	data.append('files', document.getElementById("fileUploader-fu").files[0], document.getElementById(
		"fileUploader-fu").files[0].name);
	var xhr = new XMLHttpRequest();
	xhr.addEventListener("readystatechange", function() {
		if (this.readyState === 4) {
			var vjson = JSON.parse(this.responseText);
			//set the model for the UI5 table to populate product classification results
			var oModel1 = new sap.ui.model.json.JSONModel();
			oModel1.setData(vjson.predictions[0]);
			that.getView().setModel(oModel1);
			var label = vjson.predictions[0].results[0].label;
			var score = vjson.predictions[0].results[0].score;
		}
		var ProductImage=vjson.predictions[0].results[0].label;
		new sap.ui.commons.MessageBox.confirm("The uploaded product is "+ProductImage+".Do you want to update the product count?",rCallAlertBack, "Confirmation");
		function rCallAlertBack(rValue)       {
			if(rValue)    //If User presses ‘Ok’
			            {
			       $("#uploadformId").hide();
        //mapped the retrieved value with the product ID for demo purpose ,we could write a simple logic to retrive the product ID from the Odata table as well
				
				 SingleID=0;
				 if (ProductImage =='printer'){
					 SingleID=2;
					 
				 }
				 else if(ProductImage =='notebook'){
					 SingleID=1;
				 }
				 else if(ProductImage =='hard disc'){
					 SingleID=99;
				 }
				 else if(ProductImage =='reflex camera'){
					 SingleID=98;
				 }
				 else if(ProductImage =='mouse'){
					 SingleID=3;
				 }
				 else{
					 SingleID=0;
					 alert("Product "+ProductImage+" not found in the SAP");
				 }
				 
				//Get the single product details , use the ODATA URL
				 		 
				var sUrl2 = "http://x.y.z:port/sap/opu/odata/sap/ZML_SRV/ProductSet("+SingleID+")";
								var oModel2 = new sap.ui.model.json.JSONModel(sUrl2);
				console.log(oModel2);
				sap.ui.getCore().setModel(oModel2,'singleproduct');
				
				$("#formId").slideDown(function() {					
				})
				        
			        return false;
			            }
			else  // If the user presses ‘Cancel’
			           {
			            sap.ui.commons.MessageBox.alert("You are refussed to edit the product count",'',"Notification");
			            }
			    }
		
	});

	xhr.open("POST", "https://sandbox.api.sap.com/ml/imageclassifier/inference_sync");
	xhr.setRequestHeader("apikey", "enter your api key which you have got from step 2");
	xhr.setRequestHeader("accept", "application/json");
	xhr.send(data);
	
},
update: function(){
	this.mode = 'update';
	var productid = sap.ui.getCore().byId("ProductId").getValue();
	var productname = sap.ui.getCore().byId("ProductName").getValue();
	var productcount = sap.ui.getCore().byId("ProductCount").getValue();
	var sUrl = "http://x.y.z:port/sap/opu/odata/sap/ZML_SRV/";
	var oModels = new sap.ui.model.odata.v2.ODataModel(sUrl);
	var newData = {
			
		    "ProductId" : productid,
		    "ProductName" : productname,
		    "ProductCount" : productcount		
}
	
    OData.request({
        requestUri : "proxy/http/x.y.z:port/sap/opu/odata/sap/ZML_SRV/ProductSet",
        method : "GET",
        headers : {
                                "X-Requested-With" : "XMLHttpRequest",

                                "Content-Type" : "application/atom+xml; charset=utf-8",

                                "DataServiceVersion" : "2.0",
                                }

                    },function(data,request) {
                    	var id = $("#id").val();
                    	OData.request({
                            requestUri : "proxy/http/x.y.z:port/sap/opu/odata/sap/ZML_SRV/ProductSet("+productid+")",
                            method : "PUT",
                            headers : {

                                                    "X-Requested-With" : "XMLHttpRequest",
                                                    "Content-Type" : "application/atom+xml; charset=utf-8",
                                                    "DataServiceVersion" : "2.0",
                                                    "Accept": "application/xml"
                                                    },
                              data:newData
                                        },function(data,request) {
                                        	
                                           alert("Update Success");
    location.reload(true);
                                 }, function(err) {

                                          alert("Update Failed");
                                 });
                    	
            },          function(err) {
            	var request = err.request;
                var response = err.response;
                alert("Error in Get — Request " + request + " Response " + response);
            });
    
}
	
});

 

Step 4 : Test the application

Run the application using Tomcat server which is installed as part of Eclipse IDE.

Note : If there are any CORS issues , you could allow all the origin by passing the below parameter with the request header “Allow-Control-Allow-Origin:*”

Click on the browse button to Upload a product image as shown below

Now click “Search” button , which will call the SAP Leonardo Machine Learning API (Image processing API in our case) and return the product name which has secured highest score .

The product name would be displayed in a confirmation message box and you could click on “OK” button to proceed further to update the product count

Now the details of the particular product is been retrieved and displayed for update . In our demo we allowed to edit only the Product Count field . We could update the number of counts here and click on “Save” button.

The current count value of the product ‘Printer” is 15 we would update to 20 and save .

We would get a alert with a message “Update is success”

Clicking on “OK” will reload the ‘Product Details’ table with updated contents

 

Conclusion:

This is a demo for a simple use case of just updating the product details using SAP Leonardo Machine Learning API .

The use case could be extended with a custom Fiori app , from where the image could be captured and sent to the application .

There were also use cases where Image processing API could be used to detect the broken part in a product and use the ML to suggest for the replacement parts .

As the future roadmap for SAP Leonardo ML would allow us to create ,deploy and train our own ML model , which gives us the option to trim and train a model with enterprise specific products where the ML consumption could happen on a more enterprise specific mode.

Thanks.

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply