Andrejus Baranovski

Subscribe to Andrejus Baranovski feed
Blog about Oracle technology
Updated: 58 min 12 sec ago

ADF Task Flow Performance Boost with JET UI Shell Wrapper

22 hours 15 min ago
ADF application with UI Shell and ADF Task Flows rendered in dynamic tabs would not offer instant switch from one tab to another experience. Thats because tab switch request goes to the server and only when browser gets response - tab switch happens. There is more to this - even if tab in ADF is not currently active (tab is disclosed), tab content (e.g. region rendered from ADF Task Flow) still may participate in the request processing. If user opens many tabs, this could result in slightly slower request processing time overall.

ADF allows to render ADF Task Flows directly by accessing them through URL, if it is configured with page support on the root level. ADF Task Flow can be accessed by URL, this means we can include it into iframe. Imagine using iframe for each tab and rendering ADF Task Flows inside. This will enable ADF Task Flow independent processing in each tab, similar to opening them in separate browser tab.

Iframe can be managed in Oracle JET, using plain JavaScript and HTML code. My sample implements dynamic JET tabs with iframe support. Iframe renders ADF Task Flow. While navigating between tabs, I simply hide/show iframes, this allows to keep the state of ADF Task Flow and return to the same state, when opening back the tab. Huge advantage in this case - tab navigation and switching between tabs with ADF Task Flows works very fast - it takes only client time processing. Look at this recorded gif, where I navigate between tabs with ADF content:


Main functions are listed below.

1. Add dynamic iframe. Here we check if frame for given ADF Task Flow is already created, if no we create it and append to HTML element


2. Select iframe, when switching tabs. Hide all frames first, select frame which belongs to the selected tab


3. Remove iframe. Remove frame, when tab is closed


4. Select frame after remove. This method helps to set focus to the next frame, after current tab was removed


We can control when iframe or regular JET module is rendered, by using flag computed function assigned to main div:


In this app I have defined static URL's for displayed ADF Task Flows. Same can be loaded by fetching menu, etc.:


To be able to load ADF Task Flow by URL, make sure to use ADF Task Flow with page (you can include ADF region with fragments into that page). Set url-invoke-allowed property:


This is how it looks like. By default, JET dashboard module is displayed, select item from the menu list to load tab with ADF Task Flow:


JET tab rendering iframe with ADF table:


You can monitor ADF content loading in iframe within JET application:


JET tab rendering iframe with ADF form:


Download sample app from GitHub repository.

Oracle Offline Persistence Toolkit - Applying Server Changes

Wed, 2018-10-10 09:00
This is my final post related to Oracle Offline Persistence Toolkit. I will show simple example, which explains how to apply server changes, if data conflict comes up. Read previous post about - Oracle Offline Persistence Toolkit - Submitting Client Changes.

To apply server changes is easier, than to apply client changes. You need to remove failed request from sync queue and fetch server data to client by key.

Example of data conflict during sync:


User decides to cancel his changes and bring data from the server. GET is executed to fetch latest data and push it to the client:


In JS code, first of all we remove request from sync queue, in promise we read key value for that request and then refetch data:


Download sample code from GitHub repository.

Oracle Offline Persistence Toolkit - Submitting Client Changes

Sat, 2018-10-06 20:30
One of the key topics related to Oracle Offline Persistence toolkit - submitting client changes to backend when data conflict exists. If data was updated on the backend, while client was offline and client wants to submit his changes - we inform about the conflict and ask what client really wants to do. If client choose to submit changes, this means we should push client changes to the backend with the latest change indicator.

There is a special case, when client updates same data multiple times while offline - during online sync we need to make sure, change indicator will be retrieved in after sync and applied in before sync listeners, to make sure subsequent requests execute correctly. Check my previous post about before request sync listener - Oracle Offline Persistence Toolkit - Before Request Sync Listener.

Example - let's update a record and submit change to the backend:


Assume another user is offline and updates same record:


User updates same record again, before going online. Now we will have two requests in the sync queue:


Once going online, sync will be executed and we will get conflict for the first request (same row was updated already by another user). At this moment, after sync listener will get info about conflict and will cache latest change indicator value returned from backend. If user decides to apply his changes, requests is removed, new request is constructed with the latest change indicator value received from backend and this request is inserted into sync queue:


If same record was updated multiple times, second request will fail too - because this request wasn't updated yet with latest change indicator:


Assuming user decided to apply changes from the second request too, we will update request with latest change indicator and submit it for sync. In after sync listener, change indicator value stored in local cache will be updated.

Successful sync with change indicator = 296:


New change indicator value will be retrieved in after sync listener and applied in before sync listener for the second request, updating same data row:


Here is the code, which allows user to apply changes to backend. We remove failed request, update it and create new request in sync queue, resuming sync process:


Download sample code for the described use case from my GitHub repository.

Oracle Offline Persistence Toolkit - Before Request Sync Listener

Tue, 2018-10-02 15:09
One more post from me related to Oracle Offline Persistence Toolkit. I already described how after request listener could be useful to read response data after sync - Oracle Offline Persistence Toolkit - After Request Sync Listener. Today will explain when before request listener could be useful. Same as after request listener, it is defined during persistence manager registration:


Before request listener must return promise. We can control resolved action. For example if there is no need to update request, we simply return continue. We would need to update request, if same row is updated multiple times during sync. Change indicator value must be updated in request payload. We read latest change indicator value from array, initialised in after request listener. Request payload is converted to JSON, value updated and then we construct new request and resolve it with replay. API allows to provide new request, by replacing original:


Here is the use case. While offline - update value:


While remaining offline, update same value again:


We should trace executed requests during sync, when going online. First request, initiated by first change is using change indicator value 292:


Second request is using updated change indicator value 293:


Without before and after request listener logic, second request would execute with same change indicator value as the first one. This would lead to data conflict on backend.

Sample application code is available on GitHub.

Oracle Offline Persistence Toolkit - After Request Sync Listener

Fri, 2018-09-28 11:15
In my previous post, we learned how to handle replay conflict - Oracle Offline Persistence Toolkit - Reacting to Replay Conflict. Additional important thing to know - how to handle response from request which was replayed during sync (we are talking here about PATCH). It is not as obvious as handling response from direct REST call in callback (there is no callback for response which is sinchronised later). You may think, why you would need to handle response, after successful sync. Well there could be multiple reasons - for instance you may read returned value and update value stored on the client.

Listener is registered in Persistence Manager configuration, by adding event listener of type syncRequest for given endpoint:


This is listener code. We are getting response, reading change indicator value (it was updated on the backend and new value is returned in response) and storing it locally on the client. Additionally we maintain array with mapping of change indicator value to updated row ID (in my next post I will explain why this is needed). After request listener must return promise:


On runtime - when request sync is executed, you should see in the log message printed, which shows new change indicator value:


Double check in payload, to make sure request was submitted with previous value:


Check response, you will see new value for change indicator (same as in after request listener):


Sample code can be downloaded from GitHub repository.

Oracle Offline Persistence Toolkit - Reacting to Replay Conflict

Sat, 2018-09-22 08:01
This is next post related to Oracle Offline Persistence Toolkit. Check my previous writing on same subject - Implementing Handle Patch Method in JET Offline Toolkit. Read more about toolkit on GitHub repo.

When application goes online, we call synchronisation method. If at least one of the requests fails, then synchronisation is stopped and error callback is invoked, where we can handle failure. In error callback, we check if failure is related to the conflict - then we open dialog, where user will decide what to do (to force client changes or take server changes). Reading latest change indicator value from response in error callback (to apply it, if user decides to force client changes in the next request):


Dialog is simple - it displays dynamic text for conflicted value and provides user with a choice of actions:


Let's see how it works.

User A editing value Lex and saving it to backend:


User B is offline, editing same value B and saving it in local storage:


We can check it in the log - changes value was stored in local storage:


When going online, pending requests logged offline, will be re-executed. Obviously above request will fail, because same value was changed by another user. Conflict will be reported:


PATCH operation fails with conflict code 409:


User will be asked - how to proceed. To apply changes and override changes in the backend, or on opposite take changes from the backend and bring them to the client:


I will explain how to implement these actions in my next post. In the meantime you can study complete application available on GitHub repo.

Query Logic Implementation in VBCS for ADF BC REST

Wed, 2018-09-19 14:19
Oracle Visual Builder Cloud Service allows to define external REST service connections. In this post I will explain how to implement query logic against such service. Connection is defined for ADF BC REST service.

Wizard provides option to add query parameters, both static and dynamic. I have set one static parameter onlyData=true, to return data only from the service. Also I have created multiple dynamic parameters, the one used in this use case - q parameter. This parameter accepts query expression to filter data. Later in VBCS action chain, I will assign value to this parameter and service will be re-executed to bring filtered data:


Search form elements will be assigned with page scope variables, to hold user query input. On search button click, VBCS action chain will be invoked to read these values and update query parameter. Page scope variables:


Variables firstNameQueryVar and lastNameQueryVar are assigned to search form fields, here is example:


Search button invokes action chain:


Action chain does two things - calls JS function to construct query parameter and then assigns returned value to rest service query parameter to execute search:


JS function is mapped to accept input parameters from search form input fields:


JS function code - parameters are joined into ADF BC REST query string:


JS function result is mapped with page scope variable - result is assigned to this variable:


REST service query parameter q variable is assigned with this value. Once value changes, query is automatically re-executed:


In my next post I will explain how to implement filtering and pagination with transformation function, on top of service connection:


VBCS sample application code is available on GitHub (if you download ZIP from GitHub, make sure to extract it and create new archive including extracted content directly, without top folder).

Implementing Handle Patch Method in JET Offline Toolkit

Wed, 2018-09-12 13:41
When executing PATCH requests offline, JET Offline Persistence Toolkit will record that request and synch it to the backend, once online. But it will not update data stored in cache, this is by design. Since cached data will not be updated, search queries against offline cache would not bring results based on latest changes. To solve this we need to implement cache update ourself by providing handle patch method.

Handle patch is configured through requestHandlerOverride property while registering persistence manager:


Sample implementation for handle patch. This method is invoked, when PATCH is executed while offline only. We must read information from request and pass it to cache store. Search for entry in cache based on key, updating record and updating info back to the store:


Let's do offline test - switch browser tab to be offline (you can do it Chrome browser developer tools). Do search and check log from JET Offline Persistence Toolkit - it executes search automatically against cache store:


Update same record, while offline - PATCH request will be recorded for later synchronisation. Our handle patch method will be invoked to write changes to cache store:


You will notice in the log, actions executed from handle patch method. It finds record by key in cache and updates it:


Search by updated value - updated value is found and returned from cache store:


Code is available in GitHub repository.

ADF BC REST Query and SQL Nesting Control Solution

Thu, 2018-08-16 15:04
I will talk about expert mode View Object (with hand written SQL), this View Object is created based on SQL join. So, thats my use case for today example. I will describe issue related to generated SQL statement and give a hint how to solve it. This is in particular useful, if you want to expose complex VO (SQL with joins and calculating totals) over ADF BC REST service and then run queries against this REST resource.

Code is available on my GitHub repository.

Here is SQL join and expert mode VO (the one where you can modify SQL by hand):


This VO is exposed through ADF BC REST, I will not go through those details, you can find more info about it online. Once application is running, REST resource is accessible through GET. ADF BC REST syntax allows to pass query string along with REST request, here I'm filtering based on StreetAddress='ABC':


On backend this works OK by default and generates nested query (this is expected behaviour for expert mode VOs, all additional criteria clauses will be added through SQL wrapping). While such query executes just fine, this is not what we want in some use cases. If we calculate totals or average aggregated values in SQL, we don't want it to be wrapped:


To prevent SQL wrapping we can call ADF BC API method in VO constructor:


While probably this works with regular ADF BC, it doesn't work with criteria coming from ADF BC REST. SQL query is generated with two WHERE clauses, after query nesting was disabled:


Possible solution proposed by me - override executeQueryForCollection method, do some parsing and change second WHERE to be AND, apply changed query string and then execute super:


This trick helps and query is generated as we would expect, criteria added from ADF BC REST query call is appended at the end of WHERE clause:

Flow Navigation Menu Control in Oracle VBCS

Sun, 2018-08-12 14:33
Oracle VBCS allows us to build multiple flows within the application. This is great - this helps to split application logic into different smaller modules. Although VBCS doesn't offer (in the current version) declarative support to build menu structure to navigate between the flows. Luckily this requirement can be achieved in few simple steps, please read John Ceccarelli post - Adding a Navigation Bar to a VBCS Application. I thought to go through instructions listed by John and test it out, today post is based on this. In my next posts I will take a look how to replace navigation bar menu structure with something more advanced, for example - menu slider on the left.

I think VBCS have great potential as JavaScript declarative development IDE. I see many concepts are similar to other Oracle declarative development tools, e.g. Forms, Oracle ADF. VBCS runs Oracle JET, all you build in VBCS is Oracle JET. Oracle takes care upgrading Oracle JET version in VBCS, I have applied recent patch (by click of the button) and latest JET version is available within our VBCS environment:


Coming back to flows in VBCS. We can create as many flows we want. Each flow could be based on one or multiple fragments (HTML/JS modules). Here I have created three flows, each with single fragment:


We can select flow and this will bring us flow diagram, where we could have navigation implementation between flow elements/fragments:


Fragment - this is where UI part is done:


So thats about flows and fragments. For someone with ADF background, this sounds very similar to task flows and fragments. Next we should see how to implement flow navigation, to be able to select flow from the top menu. VBCS application comes with so called shell page. This page is top UI wrapper, which contains application name, logged user info, etc. Here we can implement top level menu, which would navigate through application flows:


There must be default flow, which is displayed once application is loaded. Default flow is set in settings of the shell page. Go to settings and choose default flow, dashboard-flow in my case:


Next we need to add JET component - navigation list to the shell page, to render menu UI. You can do it by drag and drop, but easier is to switch shell page to source view and add navigation list HTML portion manually (you can copy paste it from source code uploaded to GitHub, see link at the end of this post) - highlighted HTML will render menu bar to navigate between flows:


Initially you will notice error related to JET navigation list not recognised, we need to import it. Another error - selection listener is not found, we will implement it.

To import JET navigation list component, go to source implementation of the shell page and add oj-navigation-list in component imports section - this will solve issue with unknown navigation list entry:


To execute action in VBCS, we must create Action Chain. Crete Action Chain within shell page - navigateToPage:


We need input parameter - flow name, which want navigate to. Create variable in Action Chain - currentFlow:


Add action of type Navigate to Action Chain, this will trigger navigation logic:


Go to Action Chain source and add "page": "{{$variables.currentFlow}}" under actions. This will force navigation to the flow, which will be passed through parameter:


Finally we create navigation list selection event (within shell page), this event will trigger action chain created above and pass current flow ID. We must create custom event and its name should match even name defined in JET navigation list in HTML (see above):


Choose to create custom event (it didn't work for me in Chrome, only in Safari browser. VBCS bug?) and provide same name as in navigation list component listener:


Choose our navigation Action Chain to be triggered from this event:


Just a reminder, event is called from navigation list selection:


Event is passing flow ID from currently selected tab item:


On runtime, dashboard flow is loaded by default:


We can switch to Jobs, etc.:


Download exported (runnable only in VBCS) VBCS app from GitHub repo.

Oracle Offline Persistence Toolkit - Controlling Online Replay

Thu, 2018-08-09 13:25
Few months ago I had a post about Oracle Offline Persistence toolkit, which integrates well with Oracle JET (JavaScript toolkit from Oracle) - Oracle JET Offline Persistence Toolkit - Offline Update Handling. I'm back to this topic with sample application upgraded to JET 5.1 and offline toolkit upgraded to 1.1.5. In this post I will describe how to control online replay by filtering out some of the requests, to be excluded from replay.

Source code is available on GitHub. Below I describe changes and functionality in the latest commit.

To test online replay, go offline and execute some actions in the sample app - change few records and try to search by first name, also try to use page navigation buttons. You will be able to save changes in offline mode, but if this is your first time loading app and data from other pages wasn't fetch yet, then page navigation would not bring any new results in offline mode (make sure to load more records while online and then go offline):


In online replay manager, I'm filtering out GET requests intentionally. Once going online, I replay only PATCH requests. This is done mainly for a test, to learn how to control replay process. PATCH requests are executed during replay:


Printing out in the log, each GET request which was removed from replay loop:


Replay implementation (I would recommend to read Offline Persistence Toolkit usage doc for more info):


This code is executed, after transition to online status. Calling getSyncLog method from Sync Manager - returns a list of requests pending replay. Promise returns function with array of requests waiting for online replay. I have marked function to be async, this allows to implement sequential loop, where each GET request will be removed one by one in order. This is needed, since removeRequest from Sync Manager is executed in promise and loop would complete too late - after we pass execute replay phase. Read more about sequential loop implementation in JS, when promise is used - JavaScript - Method to Call Backend Logic in Sequential Loop. Once all GET requests are removed, we execute sync method, this will force all remaining requests in queue to be replayed.

Data Conflict Solution for ADF BC REST with Versioning

Mon, 2018-08-06 10:06
I would like to share sample solution for data conflict processing in ADF BC REST using versioning. When multiple users are editing concurrently the same data row - it is important to inform user before overriding changes already committed by another user. There are other approaches to implement data conflict control, you should evaluate if solution explained below is suitable for your use case, before applying it.

Sample code can be obtained from GitHub repository.

I'm using custom change indicator property, to evaluate if client data is expired. Change indicator value is sent to the client together with request data. PATCH request must include current client side change indicator value, if change indicator will match value in backend - PATCH is allowed, otherwise new change indicator will be returned to the client and response will be marked with 409 Conflict status code. Based on this, client could decide either to resubmit PATCH request with new change indicator and overwrite current data in DB or refresh client side data and try to submit changes later.

In this example - PATCH was executed with valid change indicator, response status is 200 OK. New change indicator value is returned to the client (it should be submitted for the next PATCH call for current row):


To test data change conflict, I would go directly to DB and change same record. Change indicator will be updated too:


Client doesn't know about change indicator update (data was changed by another user). Client will include currently known change indicator value and execute PATCH. This will result in 409 Conflict status. Backend returns latest change indicator value in the response:


Data wasn't updated, PATCH request was stopped on the backend:


Client knows latest change indicator value and can submit it again - this time successful (no one else changed data in the meantime):


Status 200 OK is returned, along with new change indicator value. Data is changed in DB as expected:


Backend implementation is not complex. You need DB trigger, which will get value from DB sequence and assign it for each changed row:


ADF BC REST includes change indicator attribute, it is marked with Refresh on Update support. This allows to get latest value assigned from DB trigger and return it to the client:


In doDML method we compare change indicator attribute value currently stored in DB and the one which comes from the client. If values do not match (client doesn't have the latest value) - update is not allowed:


When update is not allowed, we also must change HTTP response code to be 409 Conflict. This will allow to execute error callback on client side and take required action to process data conflict on the client. HTTP response code is set from custom ADF BC REST filter:

Text Classification with Deep Neural Network in TensorFlow - Simple Explanation

Mon, 2018-07-30 13:05
Text classification implementation with TensorFlow can be simple. One of the areas where text classification can be applied - chatbot text processing and intent resolution. I will describe step by step in this post, how to build TensorFlow model for text classification and how classification is done. Please refer to my previous post related to similar topic - Contextual Chatbot with TensorFlow, Node.js and Oracle JET - Steps How to Install and Get It Working. I would recommend to go through this great post about chatbot implementation - Contextual Chatbots with Tensorflow.

Complete source code is available in GitHub repo (refer to the steps described in the blog referenced above).

Text classification implementation:

Step 1: Preparing Data
  • Tokenise patterns into array of words
  • Lower case and stem all words. Example: Pharmacy = pharm. Attempt to represent related words 
  • Create list of classes - intents
  • Create list of documents - combination between list of patterns and list of intents
Python implementation:


Step 2: Preparing TensorFlow Input
  • [X: [0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, ...N], Y: [0, 0, 1, 0, 0, 0, ...M]]
  • [X: [0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, ...N], Y: [0, 0, 0, 1, 0, 0, ...M]]
  • Array representing pattern with 0/1. N = vocabulary size. 1 when word position in vocabulary is matching word from pattern
  • Array representing intent with 0/1. M = number of intents. 1 when intent position in list of intents/classes is matching current intent
Python implementation:


Step 3: Training Neural Network
  • Use tflearn - deep learning library featuring a higher-level API for TensorFlow
  • Define X input shape - equal to word vocabulary size
  • Define two layers with 8 hidden neurones - optimal for text classification task (based on experiments)
  • Define Y input shape - equal to number of intents
  • Apply regression to find the best equation parameters
  • Define Deep Neural Network model (DNN)
  • Run model.fit to construct classification model. Provide X/Y inputs, number of epochs and batch size
  • Per each epoch, multiple operations are executed to find optimal model parameters to classify future input converted to array of 0/1
  • Batch size
    • Smaller batch size requires less memory. Especially important for datasets with large vocabulary
    • Typically networks train faster with smaller batches. Weights and network parameters are updated after each propagation
    • The smaller the batch the less accurate estimate of the gradient (function which describes the data) could be
Python implementation:


Step 4: Initial Model Testing
  • Tokenise input sentence - split it into array of words
  • Create bag of words (array with 0/1) for the input sentence - array equal to the size of vocabulary, with 1 for each word found in input sentence
  • Run model.predict with given bag of words array, this will return probability for each intent
Python implementation:


Step 5: Reuse Trained Model
  • For better reusability, it is recommended to create separate TensorFlow notebook, to handle classification requests
  • We can reuse previously created DNN model, by loading it with TensorFlow pickle
Python implementation:


Step 6: Text Classification
  • Define REST interface, so that function will be accessible outside TensorFlow
  • Convert incoming sentence into bag of words array and run model.predict
  • Consider results with probability higher than 0.25 to filter noise
  • Return multiple identified intents (if any), together with assigned probability
Python implementation:

Oracle VBCS - Pay As You Go Cloud Model Experience Explained

Thu, 2018-07-19 14:03
If you are considering starting using VBCS cloud service from Oracle, may be this post will be useful. I will share my experience with pay as you go model.

Two payment models are available:

1. Pay As You Go - good when accessing VBCS time to time. Can be terminated at any time
2. Monthly Flex - good when need to run VBCS 24/7. Requires commitment, can't be terminated at any time

When you create Oracle Cloud account, initially you will get 30 days free trial period. At the end of that period (or earlier), you can upgrade to billable plan. To upgrade, go to account management and choose to upgrade promotional offer - you will be given choice to go with Pay As You Go or Monthly Flex:


As soon as you upgrade to Pay As You Go, you will start seeing monthly usage amount in the dashboard. Also it shows hourly usage of VBCS instance, for the one you will be billed:


Click on monthly usage amount, you will see detail view per each service billing. When VBCS instance is stopped (in case of Pay As You Go) - you will be billed only for hardware storage (Compute Classic) - this is relatively very small amount:


There are two options, how you can create VBCS instance - either autonomous VBCS or customer managed VBCS. To be able to stop/start VBCS instance and avoid billing when instance is not used (in case of Pay As You Go) - make sure to go with customer managed VBCS. In this example, VBCS instance was used only for 1 hour and then it was stopped, it can be started again at anytime:


To manage VBCS instance, you would need to navigate to Oracle Cloud Stack UI. From here you can start stop both DB and VBCS in single action. It is not enough to stop VBCS, make sure to stop DB too, if you are not using it:

ADF Postback Payload Size Optimization

Sun, 2018-07-15 01:45
Recently I came across property called oracle.adf.view.rich.POSTBACK_PAYLOAD_TYPE. This property helps to optimize postback payload size. It is described in ADF Faces configuration section - A.2.3.16 Postback Payload Size Optimization. ADF partial request is executing HTTP post with values from all fields included. When postback property is set to dirty, it will include into HTTP post only changed values. As result - server will get only changed attributes, potentially this can reduce server time processing and make HTTP request size smaller. This especially can be important for large forms, with many fields.

Let's take a look into example. After clicking on any button in the form, go to network monitor and study Form Data section. You will see ID's and values for all fields included in the UI. All fields are submitted with HTTP request by default, even these fields were not changed:


Postback optimization property can be set in web.xml. By default it's value is full, change it to dirty:


With value set to dirty, try to change at least one field and then press any button. Observe Form Data section in network monitor - only fields with changed values will be submitted:


Try to test it in your project and see the difference.

Check my sample app for this use case on GitHub.

Contextual Chatbot with TensorFlow, Node.js and Oracle JET - Steps How to Install and Get It Working

Tue, 2018-07-10 12:15
Blog reader was asking to provide a list of steps, to guide through install and run process for chatbot solution with TensorFlow, Node.JS and Oracle JET.

Resources:

1. Chatbot UI and context handling backend implementation - Machine Learning Applied - TensorFlow Chatbot UI with Oracle JET Custom Component

2. Classification implementation - Classification - Machine Learning Chatbot with TensorFlow

3. TensorFlow installation - TensorFlow - Getting Started with Docker Container and Jupyter Notebook

4. Source code - GitHub

Install and run steps:

1. Download source code from GitHub repository:


2. Install TensorFlow and configure Flask (TensorFlow Linear Regression Model Access with Custom REST API using Flask)

3. Upload intents.json file to TensorFlow root folder:


4. Upload both TensorFlow notebooks:


5. Open and execute (click Run for each section, step by step) model notebook:


6. Repeat training step few times, to get minimum loss:


7. Open and execute response notebook:


8. Make sure REST interface is running, see message below:


9. Test classification from external REST client:


10. Go to socketioserver folder and run (install Node.js before that) npm install express --save and npm install socket.io --save commands:


11. Run npm start to startup Node.js backend:


12. Go to socketiojet folder and run (install Oracle JET before that) ojet restore:


13. Run ojet serve to start chatbot UI. Type questions to chatbot prompt:

JavaScript - Method to Call Backend Logic in Sequential Loop

Thu, 2018-06-21 15:54
When we call backend REST service from JavaScript - call by default is executed async. This means it will not wait until response from backend is received, but will continue executing code. This is expected and desired functionality in most of the cases. But it might be requirement, where you want to call backend in synchronised way. Example - calling backend service multiple times in the loop, next call must be invoked only after previous call is complete. With default async functionality, loop will complete before first REST call.

Here is the example of calling backend REST service (through Oracle JET API, using JQuery in the background). Call is made 3 times, with success callback printing a message. One more message is printed at the end of each loop iteration:


Three backend REST calls are executed in the loop:


Loop completes earlier than REST call from the first iteration, we can see it from the log:


It might be valid and expected behaviour for most of the cases. But depending on backend logic, may be you would like to guarantee no call from second iteration will be invoked, until first iteration call not complete. This can be achieved by specifying async function and using Promise inside the loop. We should use await new Promise syntax and resolve it in success callback by calling next():


With promise applied, loop is executed sequentially - next loop iteration is started, only after backend service success callback is invoked. You can see it from the log:


Source code is available on my GutHub repository.

Custom JavaScript Client Code in Oracle Visual Builder

Mon, 2018-06-18 16:17
Hey, this is my first post about VBCS, you should expect more posts in the future about this topic. Red Samurai decided to choose VBCS as our primary JavaScript development IDE in the cloud. We are going to use it for declarative JS development, similar as we use JDeveloper for ADF.

I was going through the custom JS client code functionality in VBCS and thought it would be good idea to describe how it works. There is good material available for the same topic from Oracle, I recommend to go through it - Variables, Modules, and Functions, OH MY! Custom Client Code in Visual Builder.

I have created simple UI with one input and one output field. Button calls custom JS method, where value from input field will be processed and returned to be displayed in disabled field:


Below I will describe how all parts are wired together. Across different parts of VBCS there is a lot of resemblance with the way how ADF development done - this helps to reuse ADF skills for VBCS.

VBCS allows to define variables on 3 levels:

1. Page - page scope
2. Flow - flow scope
3. Application - application scope

In my example I decided to go with page scope variables (defined in page called main-start) - first one is assigned with input field and second with output:


There is property inspector, it allows to assign expressions to UI fields. Below you can see first variable assigned to input field:


Second variable is assigned to output field:


Button is assigned with action chain call - in VBCS we can call action chains. In ADF we call action listener and code Java logic in the method, here action chain gives more flexibility, you will see this below in action chain implementation:


VBCS allows to switch to code view and check HTML structure built with JET components. This is useful when you want to adjust generated code by yourself or copy layout to external JET project:


There is JS tab, associated with each VBCS page. There we can find JS file, where custom code can be included. I have created basic custom function, just for a test purpose:


VBCS JS code editor offers extensive auto suggest functionality - great help during development:


In case of syntax issues - errors are reported in audit window:


There is separate tab for action chains, I have already one - called from button (see above):


Action chain editor view - along with diagram, we have various components available. This looks slightly similar to SOA/BPM extension in JDeveloper, isn't it? In this action chain, first of all we call custom action - custom JS method define above:


Input parameter for JS call is assigned from page variable (input component):


In the next step - assign variables logic is called, this helps to assign function return value to page variable, which is mapped with output UI field:


Function return value mapping with page variable:


Application can be tested with single click, our message is printed in the log:


I have exported VBCS application and uploaded to GitHub repository. Once you export from VBCS, can access and check generated code. Here is main page code:


In main-start-page.json we can see metadata definition. For example, there we can find button event mapping with action chain:


VBCS looks very promising to me and I think this might be declarative JS development future.

CDN Support in Oracle JET

Sun, 2018-06-17 02:12
With the recent releases of Oracle JET - CDN support in your app can be enabled easily. By default JET app is set to download all JET toolkit related scripts and static files from the same host, where application is hosted. You can track it easily through network monitor, you should see such files as ojknockout.js, etc. fetched from same host:


CDN can be enabled by changing use property from local to cdn in path_mapping.json and restarting the app:


After this change, you should see all JET toolkit content to be downloaded from static.oracle.com host:


Benefit - you reduce load on your host, from where only application specific files will be downloaded, with JET toolkit code downloaded from external Oracle host. Same achievable on your own host, but JET toolkit content downloaded from Oracle host - is compressed out of the box (another benefit):

Machine Learning Applied - TensorFlow Chatbot UI with Oracle JET Custom Component

Mon, 2018-06-11 16:22
This post is based on Oracle Code 2018 Shenzhen, Warsaw and Berlin talks. View presentation on SlideShare:


In my previous post I have outlined how to build chatbot backend with TensorFlow - Classification - Machine Learning Chatbot with TensorFlow. Today post is the next step - I will explain how to build custom UI on top of TensorFlow chatbot with Oracle JET.

You can download complete source code (which includes TensorFlow part, backend for chatbot context processing and JET custom component chatbot UI) from my GitHub repository.

Here is solution architecture snapshot:


TensorFlow is used for machine learning and text classification task. Flask allows to communicate through REST to TensorFlow from outside. Contextual chatbot conversation processing is implemented in Node.js backend, communication with Oracle JET client is handled by Socket.io.

Key point in chatbot implementation - correct data structure construction for machine training process. More accurate learning will be, better classification results will be achieved afterwards. Chatbot training data can come in the form of JSON. Training data quality can be measured by overlap between intents and sample sentences. As more overlaps you have, weaker machine learning output will be produced and classification will be less accurate. Training data can contain information which is not used directly by TensorFlow - we can include intent context processing into the same structure, it will be used by context processing algorithm. Sample JSON structure for training data:


Accurate classification by TensorFlow is only one piece of chatbot functionality. We need to maintain conversation context. This can be achieved in Node.js backend, by custom algorithm. In my example, when context is not set - TensorFlow is called to classify statement and produce intent probability. There might be multiple intents classified for the same sentence - TensorFlow will return multiple probabilities. It is up to you, either to always choose intent with top probability or ask user to choose. Communication back to the client is handled through Socket.io by calling socket.emit function:


If context was already set, we don't call classification function - we don't need it in this step. Rather we check by intent context mapping - what should be the next step. Based on that information, we send back question or action to the client, again through Socket.io by calling socket.emit function:


Chatbot UI is implemented with JET custom component (check how it works in JET cookbook). This makes it easy to reuse the same component in various applications:


Here is example, when chatbot UI is included into consuming application. It comes with custom listener, where any custom actions are executed. Custom listener allows to move any custom logic outside of chatbot component, making it truly reusable:


Example for custom logic - based on chatbot reply, we can load application module, assign parameter values, etc.:


Chatbot UI implementation is based on the list, which renders bot and client messages using the template. This template detects if message belongs to client or bot and applies required style - this helps to render readable list. Also there is input area and control buttons:


JS module executes logic which helps to display bot message, by adding it to the list of messages generates event to be handled by custom logic listener. Message is sent from the client to the bot server by calling Socket.io socket.emit function:


Here is the final result - chatbot box implemented with Oracle JET:

Pages