Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
quovadis
Product and Topic Expert
Product and Topic Expert
1,126




















Image created with DALL·E



Piet Mondrian's artwork.


I have recently attended HILMA AF KLINT & PIET MONDRIAN FORMS OF LIFE exhibition at Tate Modern.

At the end of the exhibition there was a shop where people could buy different memorabilia. There were Piet Mondrian's  t-shirts, socks, mugs and pencils... Well, I bought a t-shirt.

Still, I wanted a Piet Mondrian's mug. However, my kitchen cupboard has no more overflow space...

I had to get creative....

Disclaimer:

  • The ideas presented in this blog are personal insights thus are not necessarily endorsed by SAP.



  • Images/data in this blog post is from personal SAP BTP Free Tier and/or OpenAI accounts. Any resemblance to real data is purely coincidental.

  • Access to some online resources referenced in this blog may be subject to a contractual relationship with either SAP and/or OpenAI.











Putting it all together


Here goes the agenda for this brief.









Image generation with DALL·E API.


With DALL·E API it is possible to integrate state of the art image generation capabilities directly into apps and products...with little or no code.

A wish come true. SAP BTP, Kyma runtime serverless to the rescue...


With a few lines of code my wish of owning a digital mug has eventually come true.
const { Configuration, OpenAIApi } = require("openai");

const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

async function PietMondrianMug() {
try
{
const response = await openai.createImage({
prompt: "create Piet Mondrian mug",
n: 4, //1,
size: "1024x1024",
});
const data = response.data;
console.log(data);
return JSON.stringify(data,0,2);
}
catch (err) {
console.log(err.message);
return JSON.stringify(err, 0, 2);
}
}

module.exports = {
main: async function (event) {

switch(event.extensions.request.url) {
case '/mug':
return PietMondrianMug();
}

return "no mug today";
}
}

Here goes the serverless payload with 4 mug images:
{
"created": *********,
"data": [
{
"url": "https://***.blob.***/private/org-*****"
},
################# truncated payload ############################
]
}





No code today. DALL·E API with SAP API Management


In my quest for simplicity, I personally find SAP API Management, part of SAP BTP platform, one of the best low code/no code API middlewares ever.

It allows to create API proxies with built-in security and CORS policies and even have HTTP streaming to cope with the large payloads. With little or no code at all.

SAP APIM can be used to create an API proxy, as follows:













OpenAPI proxy resources Security policy

The API Keys are stored in a kvm ( key value map), as depicted below:
<!-- Key/value pairs can be stored, retrieved, and deleted from named existing maps by configuring this policy by specifying PUT, GET, or DELETE operations -->
<!-- https://help.sap.com/viewer/66d066d903c2473f81ec33acfe2ccdb4/Cloud/en-US/b72dc3f262c1441587e76d0e808... -->
<!-- mapIdentifier refers to the name of the key value map -->
<KeyValueMapOperations mapIdentifier="openapi" async="true" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt">
<Get assignTo="sapapim.apiKey" index="1">
<Key><Parameter>api_key</Parameter></Key>
</Get>
<!-- the scope of the key value map. Valid values are environment, organization, apiproxy and policy -->
<Scope>environment</Scope>
</KeyValueMapOperations>

Good to know:

  • kvm values can be encrypted


CORS policy settings













handler options cors settings

Streaming settings. Configure an API proxy to enable HTTP request and response streaming.


Configure an API proxy to enable HTTP request and response streaming. | SAP Help











Target endpoint Proxy endpoint

Good to know:

Piet Mondrian's mug with SAP Appgyver / SAP Build Apps


Data source logic:

















Set Custom Request Body schema Test Create Record

Page logic:






























Record properties: custom schema object Create record: openai_models data source
JS inputs JS custom object
Page variable definition Page variable assignment

Eventually, we can use the  appgyver platform web preview and inspect the behaviour of the java script custom code, as follows:



Quovadis ?


Time to reflect on the accomplished achievement.

That's how I took le taureau par les cornes by combining the power of simplicity of the modern generative AI models with the power of integration of SAP BTP platform with its enterprise-grade runtimes (kyma) and application building services (SAP API Management and SAP Build Apps).

Just wondering what your wish come true may be? So let me ask again, quovadis ? Your feedback is welcome...




SAP Kyma Community and SAP BTP, Kyma runtime Q&A Tags


Be balsamiq; You can follow me in SAP Community: piotr.tesny






Appendix.


SAP Build Apps JS custom code


var data  = inputs.input1;

console.log(data);
const b64_json = data.data[0].b64_json;

try
{
const bytes = myBase64.atob(b64_json)
.split('')
.map(c => c.charCodeAt(0));
console.log('bytes: ', bytes.length)
const blob = new Blob([ new Uint8Array(bytes) ], { type: 'image/jpeg' });

//console.log('blob: ', blob)

const url = (URL || webkitURL).createObjectURL(blob);
console.log(url)

return { result: url };
} catch (err) {
const error = {
code: 'Unknown Error',
message: 'Something went wrong with the blob.',
rawError: err,
}

console.log(error)
return [1, { error }]
}

const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const myBase64 = {
btoa: (input = '') => {
let str = input;
let output = '';

for (let block = 0, charCode, i = 0, map = chars;
str.charAt(i | 0) || (map = '=', i % 1);
output += map.charAt(63 & block >> 8 - i % 1 * 8)) {

charCode = str.charCodeAt(i += 3/4);

if (charCode > 0xFF) {
throw new Error("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
}

block = block << 8 | charCode;
}

return output;
},

atob: (input = '') => {
let str = input.replace(/=+$/, '');
let output = '';

if (str.length % 4 == 1) {
throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");
}
for (let bc = 0, bs = 0, buffer, i = 0;
buffer = str.charAt(i++);

~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
) {
buffer = chars.indexOf(buffer);
}

return output;
}
};

Additional resources