Skip to Content
Technical Articles

Combine CAP (M) with Machine Learning SDK – UI Part

In this blog I’m going to add a UI to my CAP service that consumes the Machine Learning Service: https://blogs.sap.com/2019/08/19/combine-cap-m-with-machine-learning-sdk-api-part/

I’m aware of the many other blogs that show how to add a UI module to an MTA project. I also noticed that, even with all these other blogs, it’s not that straightforward. Depending on which wizard or toolset you use, this can generate different code and will behave differently. Therefore, I think it’s worth sharing how I did it and especially the parts that I struggled with.

Start by adding an HTML5 module to the existing project

For this app, I’m going to use the “SAPUI5 Application template” but you could use any other template as well. One remark, the wizard will generate different code in the configuration files depending on your template. I will add all the required configuration options you need to add at the end of this blog just to make sure you have everything.

Fill in a name for the UI module. In this example, I call it “FaceConvertor”.

Give the generated view a name:

The wizard for the UI module will generate the UI5 app and add the required configuration to your project. I’ve noticed that it generates the file “xs-security.json” which contains the scopes of your app:

But it’s not being used in the yml file. You need to define the path to this configuration in the yml configuration of the “uaa” service. This is needed to deploy the app to CF and provide authorizations.

If you don’t add this parameter to the uaa service in the mta.yml, you’ll receive an internal server error from the approuter. In the logs of the approuter, you’ll find the following error:

Next step is to add a connection to the service in the UI5 app. This can be done in the manifest.json by using the wizard in “Data Sources”

This wizard allows you to create a destination to the service immediately. Which makes it possible to test the UI5 module in NEO directly from SAP Web IDE. Although this is not really needed anymore since SAP Web IDE can also run the UI module directly on CF.

This wizard requires a destination for generating all the configuration settings of the service in the UI module but it’s not required for running the app. You will notice that not all wizards require this destination.

I created the destination because this is required for the wizard for the OData connection and it allows me to test on NEO as well. I used the generated Service url for the destination

https://tgof47lihmjegk7ucapmwithmlapp-srv.cfapps.eu10.hana.ondemand.com

In the “Service URL” section, you can now select your destination and add the path to the “CatalogService”. The wizard will then load the entities for your service, and you’ll be able to click on next.

Set is as “default model”

Just as an example, the master detail template for the UI module will give you the option to select a service from your current project. Then you even don’t need a destination on NEO at all!

I just added this to show you that a different wizard can do something totally different.

In the view, I added the following code to show the converted faces:

<List items="{/Faces}" headerText="Faces">
	<items>
		<ObjectListItem title="{Firstname} {Lastname}" type="Active" press="onListItemPress" number="{ID}">
			<attributes>
				<ObjectAttribute text="{Image}"/>
				<ObjectAttribute text="{Vectors}"/>
			</attributes>
		</ObjectListItem>
	</items>
</List>

Running this will deploy the approuter from in you SAP Web IDE to CF and run it.

You can always choose to run it in NEO by changing the configuration settings:

If everything went fine, you should be able to run the app and see already the created record from the previous blog:

In case no data is showing up, check if all the configuration is generated correctly. I’ve added everything that you need to check at the end of the blog so you can validate this.

We also want to use the app to upload new faces to our database. Therefore, add an upload button in the view:

<headerContent>
	<u:FileUploader buttonOnly="true" icon="sap-icon://upload" iconOnly="true" sameFilenameAllowed="true" change=".onUploadFace"/>
</headerContent>


Next to that, I include the file “CoreService”. This is a file that wraps each OData request into a promise. Full code can be found here:
https://github.com/lemaiwo/MyCAPMAppWithML/blob/master/FaceConvertor/webapp/service/CoreService.js

For uploading images, I add the file “ImageHandler”. This is code I found on the web to resize images that are too large for ML and convert it to a base64 string. You can find the full code here: https://github.com/lemaiwo/MyCAPMAppWithML/blob/master/FaceConvertor/webapp/util/ImageHandler.js

I’m going to add one more file, FaceService. This service will extend from the CoreService. It will be the place for building the real odata requests to send images to the Java service.

  • getMaxFaceId: this will give me the highest ID of the faces already in the databse
  • createFace: will create a new entity for the face and pass the base64 image to the service

Full code: https://github.com/lemaiwo/MyCAPMAppWithML/blob/master/FaceConvertor/webapp/service/FaceService.js

The controller will set the model in the FaceService so it uses the OData model defined in the manifest for all the requests.

The controller also contains the eventhandler for the upload button. This will be called after the end-user has selected an image. It will then open a dialog with two fields, one for the firstname and one for the lastname.

The dialog contains two fields with a save and close button:

The close button won’t do anything except for closing the dialog:

The Save button will first resize the image to speed up the upload but also because the upload size of the ML service is limited. (This could also be done on the Java service but this would still slow down the upload to the Java service)

After resizing the image, it will send the image with the first and last name to the Java Service.

If everything went well, it will show a success message and update the list. Otherwise, it will show an error.

Last but not least, it will close the dialog.

After selecting an image, it will show a dialog to enter the first and last name:

After clicking on save, it will update the list and you should have two lines. Each line contains the name of the face and the vector:

You should now be able to upload images to the Java Service that uses ML to convert the image to a vector.

Optional

SAP Web IDE will generate different configuration parameters depending on which wizard you use. The app should simple work by following all the previous steps. If you used any other wizard or did some small steps different, it could break everything. Therefore, I will add here some parts you need to check to make sure that the configuration is correct.

The most important part for running the app on NEO is the destination. Cloud Foundry requires more than just a destination, especially to have access to the service. For testing in CF, you should check the following:

Make the OData service of your MTA work in the SAP Web IDE:

For NEO, it should add the following in the neo-app .json where the path has the name of the destination.

The manifest will have the uri to the service starting with the name of destination. This is need for NEO and CF:

The neo-app.json file won’t be used by CF. Instead it requires similar configuration in the xs-app.json:

It will map all requests with the name of the destination and forward it to a destination that references to the OData service

The destination for CF needs to be defined in the mta.yml file in the part of the app router:

When testing CF in the SAP Web IDE, you can test without uaa or with it. For deployment uncomment the uaa part and put the “ALLOW_MOCKED_AUTH_HEADER” in comment.

If all this configuration is complete, the app should run on NEO and CF in the SAP Web IDE

Be the first to leave a comment
You must be Logged on to comment or reply to a post.