Hi there AppWorks fans,
Welcome to a new installment of AppWorks tips.
You couldn’t miss it; Only when you live under a rock! ChatGPT is the new hype…Who am I to not embed it into our platform; Just because we can and because I’m always interested how these types of integrations can benefit our solution. ChatGPT is all about questioning/answering and for that we have off-course an interesting building block available on our platform. In entity modelling principles we call it the ‘Discussion’ BB, and we make it a 2.0 version with this post…
Let get right into it…
First, some basic questions from my own curiosity:
- Where is “GPT” standing for? Well, a quick google brought me this answer: Generative Pre-trained Transformer.
- Where can we find this ChatGPT? This is the direct link. You see it’s part of the OpenAI platform
- Do you need an account? Yes, you can create it via this link!
- Is it free? Yes and No; Yes, when you just use the regular chat UI as far as I’ve seen; No, when you want to call it though the API layer. Your account creation is granted with $18.00 credits to consume the API for a 3 months free trial; Every 1K calls/tokens will cost you $0.002 😁. More information on pricing can be found here. The free alternative? Well, this one was helpful too, but less smart!?
- Is it great? Ohw yeah!, but let’s find out when we call it; keep on reading…
The first ChatGPT API call
Once you have your account available, login to the OpenAI platform, and open the API-keys section:
Hit the button ‘Create new secret key’ and just copy that magic string; Via this string you gain access to the API layer without username/password, so keep it to yourself!
The next step is to make an HTTP POST request (with valid body) to a special API link. I make this post request via a tool called CURL for Windows, but you can also use Postman or any other fancy tool you like. This will be our first call to make; Make sure to update those three ...
with your just copied API key:
1 | curl -X POST https://api.openai.com/v1/chat/completions -H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: Bearer ..." -d "{""model"": ""gpt-3.5-turbo"", ""messages"": [{""role"": ""user"", ""content"": ""What is your name?""}], ""temperature"": 0.5}" |
NOTES:
- Watch those double quotes in Windows! JSON wants to have them, but Windows is the culprit here!
- Check the correct URL (the one with
/chat
); You can also find this URL:https://api.openai.com/v1/completions
, but this uses the oldertext-davinci-003
model; Which is also more expensive to call!
These are 2 locations to read more about this POST call and those parameters:
Once this post is online there is most likely a version “GPT 4”…Have a “Google” yourself!
This is the response JSON message from my CURL command:
1 | { |
NICEEEE!…Hello “OpenAI”! Next step…
Implementation into an AppWorks entity ‘Discussion’ BB
If your VM is already up and running, login to it with your developer account. Jump into your favorite workspace and related project. We will start with a first simple ‘Case’ entity. Give it a case_name
property, generate all the default BBs and make it nice for a first publication.
Now add the ‘Discussion’ BB to the entity and open the related ‘Discussions’ entity (behind the ‘Advanced configuration’!). You see it’s just a new entity with a new set of building blocks. Add the ‘Web service’ BB to this related entity with the ‘Read’ and ‘Update’ operations exposed. We will call these operations from a BPM which we trigger from a new ‘Rule’ BB on the related ‘Discussions’ entity. Give the new discussions rule the name e_on_create_start_bpm
and let it start a BPM; Like this:
Notes:
- There is no service operation ‘Create’ on a ‘Discussion’ BB! So, that’s why we do a workaround with the ‘Update’ service call. My first intention was to just create new ‘Discussions’ entity instances as a REPLY, but there is no possibility to make it like that…Too bad! Also, the
/app/admin
Typed ReST layer is not exposing discussion magic to play with it; It’s what it is!- That
bpm_call_chat_gpt
BPM is just a simple 1 activity BPM for now; Short-lived! because of direct/synched feedback and saved in thebpms
folder of our project. We’ll update this BPM later; Comment me if you don’t have a clue how to start this on your own!?
This will be the result on the related ‘Discussions’ entity:
So, what have we created? When we create a new discussion entity instance, we start a BPM that will eventually call ChatGPT and will manage the response for us with an update on the discussion entity instance.
Great, but how to manually create a new discussion instance? For this we add the ‘Discussions’ panel in the default layout of our ‘Case’ entity! I place it next to the form panel:
Let’s do a full publication of the project, create a new case instance, open it, and add a discussion topic. After this, check the PIM for that BPM instance!
I do this with my
awdev
developer account, so we don’t have any security issues!
Trust me on the BPM instance in the PIM…It’s there! 😇
…
So far, so good. Now that we have a discussion instance we can also ‘Read’ and ‘Update’ it through service calls! Only, before we can try it we need to create a new service container managing the requests for us. Use these steps to create one in your own organization (all other setting in the wizard can be left as is):
- Open the ‘System Resource Manager’ artifact
- Create a new service group and go through the wizard
- The type will be
Application Server Connector
- I use
sg_app_server
for the group name- Select the one web service interface from our entity ‘Discussions’ BB
- I use
sc_app_server
for the service name- Set the startup type to ‘Automatic’
- Mark the option ‘Assign OS Process’
When the service container is up and running we can open the ‘Web Service Interface Explorer’ artifact and search for ReadDiscussions
. Right-click it and evaluate it. This will be the input:
1 | <SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/"> |
Hit the ‘Invoke’ button and verify a correct response…It’s a green light from my side!
Where did I get those 2 ItemIds from? Well, that’s the power of the Chrome developer console
<F12>
. Make sure to only filter on ‘Fetch/XHR’ calls; After a page refresh, you can find out this information:
With this knowledge in the pocket, we can now also make the UpdateDiscussions
call where we can now update the body text:
1 | <SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/"> |
A refresh in runtime will have my Topic1
get an up-to-date body:
…
Right, the first services are in place where we can manipulate our discussion entity instance! All great, but we miss one service call!? Yes, that’s the service call to ChatGPT! Almost forgotten! 🤣
How can we make this possible from the AppWorks platform? There is only one ring to rule them all; In our case that will be a call over the HTTP connector. In this post I already shared my HTTP connector experiences. I just follow it (starting at section “Add a run-time reference of type ‘Application Connector’”) with new parts of content.
The config.xml
configuration file in the HTTP connector service container, which is saved in the XML Store location /OpenText/HttpConnector/config.xml
, will have this content:
1 | <configurations xmlns="http://httpconnector.opentext.com/1.0/configuration"> |
We will create a new ‘XML Schema’ type of document (in a schemas
folder) with this content part on document name scm_chat_gpt_input
:
1 | <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="open_ai" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="open_ai"> |
We also create a second ‘XML Schema’ type of document with this content part on document name scm_chat_gpt_output
:
1 | <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="open_ai" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="open_ai"> |
Have a close look at the XSDs and recognize the input/output parameters we used in the CURL-HTTP-POST request in the beginning of the post. We will use these schema documents during the creation of the custom webservice…continue reading in the referenced post!
Is there a person in the audience asking where the hell I got those XSD parts from? If so, check this URL to convert JSON to XML, XML to XSD, and some extra input/effort from yourself! 😉
…
During the creation of a new ‘Web Service’ type of document, I will use the name ChatGPTWebService
and namespace open_ai
:
In the next screen of the webservice creation wizard, we will use this input (with the corresponding schema fragments!):
Once the service is generated, it needs an implementation! You can use this XML part:
1 | <implementation xmlns:c="http://schemas.cordys.com/cws/1.0" xmlns="http://httpconnector.opentext.com/1.0/implementation" xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/" type="HTTP"> |
Notes:
- Watch again those 3
...
in the authorization header which you need to replace with your own API key!- The
enable-schema-validation
element solves an issue during my testing.- See also the advanced development guide section “Developing Web services using the HTTP connector” for more information on this implementation part.
When all is fine and published (I hope you didn’t forget to create the HTTP service container like I forgot! 🤣), you can evaluate the HTTP ‘sendRequest’ service with this input…I hope it starts to fall in place now; correct?
1 | <SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/"> |
This is my interesting response:
We’re one step closer to our end goal!
…
Now, let’s glue it all together in our bpm_call_chat_gpt
BPM. We left off with a one-activity flow which we first extend with 2 extra activities, and have a double-check on the execution mode:
The next step is to insert a ‘Web Service Operation’ to each activity (it’s in the right-click context menu for an activity). In pseudocode the BPM will look like this:
1 | var discussion = ReadDiscussions({parent.ItemId}, {rootEntityInstanceId.ItemId1}); |
Because the ChatGPT is an external service call out of our control, we add a fallback scenario where we catch the exception if the service is not responding. The end-result (incl. that catch) will look like this:
Now what? Well, we need to add mappings for all the service calls. So, in the bottom you can go to the ‘Message Map’ tab and apply all the mappings like this consolidated overview:
Notes:
- You need to read the consolidated view from right (the source) to left (the target). Please, don’t shoot the messenger! 😅
- Where is
bpm:Discussions-id/bpm:ItemId/text()
magically come from? Well, have a second look at the first BPM instance in the PIM! Look at the full message map (in XML format!) when you enabled the monitoring for it on the BPM document itself. Copy this full message map XML of the BPM instance and reuse it into your XPath editor during your BPM activity manipulations! The advantage here is that you also have real values to test with…That’s a free tip of the bro’s. Again, comment me if you have no clue at all.- The
sendRequest
input is partly hard-coded, but you can use the ‘Application configuration’ entity (right-click on your project) to make it configurable…Your administrators will love you for it!- You see the concatenation of the body part in the
UpdateDiscussions
section; Smart copy it from below!chr(10)
is the ASCII character for\n
; Or in dummy talk a ‘New Line/Line Feed’.- My lesson learned: The order of input properties is important. So
<temperature>0.5</temperature>
must be last!- I also make use of 2 process specific messages looking like this:
This is for you to make that “smart” copy! 😉
1 | concat(ns2:ReadDiscussionsOutput/ns2:ReadDiscussionsResponse/ns3:Discussions/ns5:Discussion/ns5:Body/text(), chr(10), 'ChatGPT: ', ns6:sendRequestOutput/ns6:sendRequestResponse/ns6:choices/ns6:message/ns6:content/text()) |
…
When ready, do your publication and have a check into runtime…Interesting stuff!
Ohw boy, what fun will we have with this…It’s a party. 🎉
Trust me…The first time you’ll fail, but eventually you will make it come alive. The BPM service calls took the most of my time making the calls correct. I have faith in you! 😇
Other resources
My RSS reader (Yes, it’s old but works perfectly!) provided me this post on creating their own chatroom calling ChatGPT…Well, my next thought was the AWP entity ‘Discussion’ BB!
After some research someone even created a nice Java Maven dependency for OpenAI; For this post I used version 0.11.0
which supports the ChatCompletionRequest
object (using gpt-3.5-turbo
)!
Have a start with you own API on https://start.spring.io/ with a ReST implementation like this:
1 |
|
You can also follow this as head start for your Swagger OpenAPI!
Does this follow the happy flow? For sure! Does it oversee the fail-scenarios? NOPE…That’s for you to manage.
Is it Unit tested? My friend, sometimes you need to do some things on your own! 🙃
The CURL command for this local API will eventually be: curl -X POST http://localhost:8080/api/v1/chat -H "Content-Type: application/json" -d "{""message"": ""What is your name?""}"
The above information is just a bunch of statements to trigger your creativity! Nice stuff to play with…trust me on that one.
“DONE”, DONE, DONE…The world of API is now open for consumption from our beloved platform! We saw interesting new insights again and the first question after this post will be: WHAT ELSE!?. That’s a thing for you to find out, but here is a list for some AI inspiration:
Yes, we’re only at the beginning of machine learning; Have a search for “Quantum ML”. Sweet dreams and a great weekend; Till next week in other great AppWorks Tips topic.
An extra assignment for you this time: Check the discussion topic on a certain keyword before it starts communicating externally; Like Ask ChatGPT
or Simon says
…Have fun! 🤠
Don’t forget to subscribe to get updates on the activities happening on this site. Have you noticed the quiz where you find out if you are also “The AppWorks guy”?