Monday, December 11, 2017

TensorFlow Linear Regression Model Access with Custom REST API using Flask

In my previous post - TensorFlow - Getting Started with Docker Container and Jupyter Notebook I have described basics about how to install and run TensorFlow using Docker. Today I will describe how to give access to the machine learning model from outside of TensorFlow with REST. This is particularly useful while building JS UIs on top of TensorFlow (for example with Oracle JET).

TensorFlow supports multiple languages, but most common one is Python. I have implemented linear regression model using Python and now would like to give access to this model from the outside. For this reason I'm going to use Flask, micro-framework for Python to allow simple REST annotations directly in Python code.

To install Flask, enter into TensorFlow container:

docker exec -it RedSamuraiTensorFlowUI bash

Run Flask install:

pip install flask

Run Flask CORS install:

pip install -U flask-cors

I'm going to call REST from JS, this means TensorFlow should support CORS, otherwise request will be blocked. No worries, we can import Flask CORS support.

REST is enabled for TensorFlow model with Flask in these two lines of code:


As soon as Flask is imported and enabled we can annotate a method with REST operations and endpoint URL:


There is option to check what kind of REST operation is executed and read input parameters from POST request. This is useful to control model learning steps, for example:


If we want to collect all x/y value pairs and return in REST response, we can do that by collecting values into array:


And construct JSON response directly out of the array structure using Flask jsonify:


After we run TensorFlow model in Jupyter, it will print URL endpoint for REST service. For URL to be accessible outside TensorFlow Docker container, make sure to run TensorFlow model with 0.0.0.0 as in the screenshot below:


Here is example of TensorFlow model REST call from Postman. POST operation is executed payload and response:


All REST calls are logged in TensorFlow:


Download TensorFlow model enabled with REST from my GitHub.

Tuesday, December 5, 2017

JET Composite Component in ADF Faces UI - Deep Integration

Oracle JET team doesn't recommend or support integrating JET into ADF Faces. This post is based on my own research and doesn't reflect best practices recommended by Oracle. If you want to try the same - do it on your own risk. 

All this said, I still think finding ways of further JET integration into ADF Faces is important. Next step would be to implement editable grid JET based component and integrate it into ADF to improve fast user data entry experience.

Today post focus is around read-only JET composite component integration into ADF Faces. I would recommend to read my previous posts on similar topic, today I'm using methods described in these posts:

1. JET Composite Component - JET 4.1.0 Composite - List Item Action and Defferred Loading

2. JET and ADF integration - Improved JET Rendering in ADF

You can access source code for ADF and JET Composite Component application in my GitHub repository - jetadfcomposite.

Let's start from UI. I have implemented ADF application with regions. One of the regions contains JET Composite. There is ADF Query which sends result into JET Composite. There is integration between JET Composite and ADF - when link is clicked in JET Composite - ADF form is refreshed and it displays current row corresponding to selected item in JET Composite. List on the left is rendered from series of JET components, component implements one list item:


As you can see, there are two type calls:

1. ADF Query sends result and JET Composite. ADF -> JET call
2. JET Composite is forcing ADF form to display row data for selected item. JET -> ADF call

Very important to mention - JET Composite is getting data directly from ADF Bindings, there is no REST layer here. This simplifies JET implementation in ADF Faces significantly.

What is the advantage of using JET Composite in ADF Faces? Answer - improved client side performance. For example, this component allows to expand item. Such action in pure ADF Faces component would produce request to the server. While in JET it happens on the client, since processing is done in JS:


There is no call to the server made when item is expanded:


Out of the box - JET Composite works well with ADF Faces geometry. In this example, JET Composite is located inside ADF Panel Splitter. When Panel Splitter is resized, JET Composite UI is nicely resized too, since it is out of the box responsive. Another advantage of using JET Composite in ADF Faces UI:


When link "Open" is clicked in JET Composite - JS call is made and through ADF Server Listener we update current row in ADF to corresponding data. This shows how we can send events from JET Composite to ADF Faces:


It works to navigate to another region:


And come back - JET content is displayed fine even after ADF Faces PPR was executed (simple trick is required for this to work, see below). If we explore page source, we will see that each JET Composite element is stamped in HTML within ADF Faces HTML structure:


Great thing is - JET Composite which runs in JET, doesnt require any changes to run in ADF Faces. In my example, I only added hidden ID field value to JET Composite, to be able to pass it to ADF to set current row later:


I should give couple of hints regarding infrastructure. It is not convenient to copy JET Composite code directly into ADF application. More convenient is to wrap JET code into JAR and attach it this way to ADF. To achieve that, I would recommend to create empty Web project in JDEV, copy JET Composite code there (into public_html folder) and build JAR out of it:


Put all JET content into JAR:


If Web project is located within main ADF app, make sure to use Working Sets and filter it out to avoid it to be included into EAR during build process:


Now you can add JAR with JET into ADF app:


In order for JET HTML/JS resources to be accessible from JAR file, make sure to add required config into main ADF application web.xml file. Add ADF resources servlet, if it is not added already:


Add servlet mapping, this will allow to load content from ADF JAR library:


To load such resources as JSON, CSS, etc. from ADF JAR, add ADF library filter and list all extensions to be loaded from JAR:


Add FORWARD and REQUEST dispatcher filter mapping for ADF library filter from above:


As I mentioned above, JET Composite is rendered directly with ADF Bindings data, without calling any REST service. This simplifies JET Composite implementation in ADF Faces. It is simply rendered through ADF Faces iterator. JET Composite properties are assigned with ADF Faces EL expressions to get data from ADF Bindings:


JET is not compatible with ADF PPR request/response. If JET content is included into ADF PPR response - context gets corrupted and is not displayed anymore. To overcome this we are re-drawing JET context, if it was included into PPR response. This doesn't reload JET modules, but simply re-draws UI. In my example, ADF Query sends PPR request to the area where JET Composite renders result. I have overridden query listener:


Other methods, where PPR is generated for JET Composite - tab switch and More link, which loads more results. All these actions are overridden to call methods in the bean:


Method reDrawJet is invoked, which calls simple utility method to invoke JS function which actually re-draws JET UI:


JET UI re-draw happens in JS function, which cleans Knockout.JS nodes and reapplies current JET model bindings:


JET -> ADF call is made through JET Composite event. This event is assigned with JS function implemented in ADF Faces context. This allows to call JS located in ADF Faces, without changing JET Composite code. I'm using regular ADF server listener to initiate JS -> server side call:


ADF server listener is attached to generic button in ADF Faces:


ADF server listener does it job and applies received key to set current row in ADF. Which automatically triggers ADF form to display correct data: