// Cloned by Juraj Kuruc on 30 Nov 2023 from World "Chat with GPT model" by Starter user
// Please leave this clone trail here.
// talk to OpenAI GPT model (ChatGPT)
// adapted from:
// https://platform.openai.com/docs/api-reference/making-requests
let sandboxApikey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiOTE3ZDRiODYtNmExZi00Mjk2LWJmOGUtODI2ODA3NDIzOWMyIiwidHlwZSI6InNhbmRib3hfYXBpX3Rva2VuIn0.QJseruzX_KLVWbckHOJoXm8vQ5ZGzMnPMckxk2c2Ovo";
let realApikey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiOTE3ZDRiODYtNmExZi00Mjk2LWJmOGUtODI2ODA3NDIzOWMyIiwidHlwZSI6ImFwaV90b2tlbiJ9.LFMtO0qoMmncAwcP8uL82p-h2zZBFbL9-JP0n6pGmes";
let apiKey=sandboxApikey;
let question="What's in the picture?";
let painting = false;
let penSize = 10;
let penColor;
let prevX, prevY;
let uploadedImage;
let rubberMode = false;
let pictureDescriptionInput;
let statusPanelText;
let resolution='256x256';
let temperature=0,maxTokens=64;
let describeProvider="alephalpha";
let generatorProvider="deepai";
let panelStyle=`
background-color: #f1f1f1;
padding: 20px;
border-radius: 10px;
width: 500px;
height: 500px;
overflow-y: scroll;
overflow-x: hidden;
font-size: 14px;
font-family: monospace;
line-height: 1.5;
color: #000000;
font-weight: bold;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
border: 1px solid rgba(0, 0, 0, 0.2);
position: absolute;
left: 10px;
z-index: 1;
cursor: pointer;
`;
$('body').css( "margin", "20px" );
$('body').css( "padding", "20px" );
$('head').append( `
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<title>UI API Showcase</title>
<style>
body {
margin: 0;
overflow: hidden; /* Prevent scrolling when canvas is larger than window */
}
.statusText{
font-weight: normal;
}
.defaultAllign {
margin-top: 10px;
margin-bottom: 10px;
margin-left: 5px;
color: black;
}
.penButton {
margin-top: 10px;
margin-bottom: 10px;
margin-left: 5px;
cursor: pointer;
}
.aiButton {
margin-bottom: 10px;
margin-top: 10px;
margin-left: 5px;
cursor: pointer;
}
.canvas{
border: 2px solid #333;
left: 100px;
}
.wrappingContainer {
display: flex;
align-items: center;
}
.defaultLabel {
font-size: 14px;
margin-right: 5px;
}
</style>
`);
function setup() {
let toolPanelWidth = 560;
background(255);
penColor = color(0); // Set pen color to black
createPenPanel();
canvas=createCanvas(windowWidth-600, windowHeight-20);
canvas.position(560, 10);
canvas.class('canvas');
createAiPanel();
}
function createPenPanel() {
let penPanel = createDiv("Pen Panel:");
penPanel.style(panelStyle);
penPanel.style("height: 120px;");
penPanel.id('penPanel');
penPanel.child(createDiv());
penPanel.child(createStyleButton('Small Pen','penButton',() => {
penSize = 5;
rubberMode = false;
}));
penPanel.child(createStyleButton('Medium Pen','penButton',() => {
penSize = 15;
rubberMode = false;
}));
penPanel.child(createStyleButton('Large Pen','penButton',() => {
penSize = 45;
rubberMode = false;
}));
penPanel.child(createStyleButton('Rubber','penButton',() => {
rubberMode = !rubberMode;
}));
penPanel.child(createStyleButton('Clear Canvas','penButton',() => {
background(255);
document.getElementById('uploadButton').value='';
}));
let colorPickerContainer = createDiv();
colorPickerContainer.class('wrappingContainer');
penPanel.child(colorPickerContainer);
let colorPickerLabel = createDiv('Color:');
colorPickerLabel.class('defaultLabel');
colorPickerContainer.child(colorPickerLabel);
let colorPicker = createInput('#000000', 'color');
colorPicker.id('colorPicker');
colorPicker.input(() => {
penColor = color(colorPicker.value());
rubberMode = false;
});
colorPickerContainer.child(colorPicker);
uploadButton = createFileInput(handleFile);
uploadButton.id('uploadButton');
uploadButton.class('uploadButton');
penPanel.child(uploadButton);
}
function createAiPanel() {
aiPanel = createDiv();
aiPanel.id('aiPanel');
aiPanel.position(0, 250);
aiPanel.style(panelStyle);
//aiPanel.mousePressed(() => {aiPanel.style('display', 'none');});
let aiPanelTitle = createDiv('AI Panel');
aiPanel.child(aiPanelTitle);
/*
* Add labeled "Picture description" text field into AI Panel
*/
let pictureDescriptionLabel = createDiv('Picture description:');
pictureDescriptionLabel.style('font-weight', 'bold');
pictureDescriptionInput = createInput('Two green apples');
pictureDescriptionInput.attribute('type', 'text');
pictureDescriptionInput.attribute('id', 'pictureDescription');
pictureDescriptionInput.size(aiPanel.size().width-50,pictureDescriptionInput.size().height)
aiPanel.child(pictureDescriptionLabel);
aiPanel.child(pictureDescriptionInput);
/*
* Butons
*/
aiPanel.child(createStyleButton('Generate','aiButton',generateImage));
aiPanel.child(createStyleButton('Describe','aiButton',describeImage));
aiPanel.child(createStyleButton('Redraw','aiButton',() => describeImage(generateImage)));
//Resolution
aiPanel.child(createSelector('Resolution:',null,['256x256','512x512','1024x1024'],(value) => {
resolution=value;}));
//Temperature
container = createDiv('');
container.class('wrappingContainer');
container.child(createDiv('Temperature:').class('defaultLabel'));
var temperatureValueLabel = createDiv(temperature).class('defaultLabel');
var temperatureSlider = createSlider(0,1,0,0.01).class('defaultAllign');
temperatureSlider.input(() => {
temperature=temperatureSlider.value();
temperatureValueLabel.html(temperature);
});
container.child(temperatureSlider);
container.child(temperatureValueLabel);
aiPanel.child(container);
// Max Tokens
container = createDiv('');
container.class('wrappingContainer');
container.child(createDiv('Max tokens:').class('defaultLabel'));
var tokenValueLabel = createDiv(maxTokens).class('defaultLabel');
var tokenSlider = createSlider(1,2048,maxTokens,1).class('defaultAllign');
tokenSlider.input(() => {
maxTokens=tokenSlider.value();
tokenValueLabel.html(maxTokens);
});
container.child(tokenSlider);
container.child(tokenValueLabel);
aiPanel.child(container);
// Generator Provider
aiPanel.child(createSelector('Generator Provider:',(selector) => getImageProviders('image','generation',selector),['deepai'],(value) => { generatorProvider=value; }));
// Describe Provider
aiPanel.child(createSelector('Describe Provider:',(selector) => getImageProviders('image','question_answer',selector),['alephalpha'],(value) => {describeProvider=value;}));
// Api key
aiPanel.child(createSelector('Api Key:',null,['Sanbox Key','Real Key'],(value) => {
if(value === "Real Key"){
apiKey=realApikey;
}else{
apiKey=sandboxApikey;
}
}));
// Status panel
statusPanelText = createDiv('');
statusPanelReset();
statusPanelText.class('statusText');
aiPanel.child(createDiv('Info:').child(statusPanelText));
}
function isSandboxMode(){
return apiKey===sandboxApikey;
}
/*
* Creates selector with given options.
* If populateSelectorCallback is not null, it will be used to re-populate options.
* setValueCallback function is called anytime selector changes it value.
*/
function createSelector(name,populateSelectorCallback,options,setValueCallback){
var container = createDiv('');
container.class('wrappingContainer');
container.child(createDiv(name).class('defaultLabel'));
var selector = createSelect(name).class('defaultAllign');
options.forEach(option => selector.option(option));
container.child(selector);
if(populateSelectorCallback!==null){
populateSelectorCallback(selector);
}
selector.input(()=>{
setValueCallback(selector.value());
});
return container;
}
/*
* Calls edenai and populate given selector with name of image providers for given subfeature
*/
function getImageProviders(featureName,subfeatureName,selector){
console.log("Getting all image providers for "+subfeatureName);
const settings = {
async: true,
crossDomain: true,
url: 'https://api.edenai.run/v2/info/provider_subfeatures?feature__name='+featureName+'&subfeature__name='+subfeatureName,
method: 'GET',
headers: {
accept: 'application/json'
}
}
$.ajax(settings)
.done(function (response) {
console.log(response);
response.forEach(item => {
selector.option(item.provider.name,item.provider.name);
console.log(item.provider.name);
});
})
.fail(error => {
console.error(error);
});
}
function createStyleButton(name, styleClass, mousePressCallback){
let btn = createButton(name);
btn.class(styleClass);
btn.mousePressed(mousePressCallback);
return btn;
}
function handleFile(file) {
if (file.type === 'image') {
loadImage(file.data, img => {
uploadedImage = img;
image(uploadedImage, 0, 0);
});
} else {
console.log('Please upload a valid image file (JPEG).')
}
}
function generateImage() {
statusPanelText.html(htmlTextInColor("Generating image...","blue"));
var description=pictureDescriptionInput.value();
console.log("Generating image for description: "+description);
//'stabilityai,openai,deepai,replicate'
var provider=generatorProvider;
if(description === ''){
console.log("No Image description provided!");
statusPanelText.html("No Image description provided!");
return;
}
const settings = {
"url": 'https://api.edenai.run/v2/image/generation',
"method": 'POST',
"headers": {
"Accept": 'application/json',
'content-type': 'application/json',
"Authorization": "Bearer " + apiKey,
},
"processData": false,
"data": JSON.stringify({
response_as_dict: true,
attributes_as_list: false,
show_original_response: false,
resolution: resolution,
num_images: 1,
providers: provider,
text: description
})
};
$.ajax(settings)
.fail(error => handleErrorResponse(error))
.done(response => {
console.log(response);
if(response[provider].status === 'fail'){
console.error(response[provider].error);
statusPanelText.html(htmlTextInColor(response[provider].error.message,'red'));
}else{
background(255);
console.log("Image data...");
console.log("data:image/png;base64,"+response[provider].items[0].image);
img=createImg("data:image/png;base64,"+response[provider].items[0].image,'generated', 'anonymous', img => {
image(img, 0, 0);
})
img.remove();
displayCost(response[provider].cost);
}
});
}
/**
* Calls edenai api to
*/
function describeImage(additionalCallback) {
statusPanelText.html(htmlTextInColor("Guessing what is in the image...","blue"));
var provider=describeProvider;
var form = getFormDataImageQuestion(question,provider);
const settings = {
"url": "https://api.edenai.run/v2/image/question_answer",
"method": "POST",
"headers": {
"Authorization": "Bearer " + apiKey,
"Accept": "application/json"
},
"processData": false,
"mimeType": "multipart/form-data",
"contentType": false,
"data": form,
"success": function (response) {console.log(response);}
};
$.ajax(settings)
.fail(error => handleErrorResponse(error))
.done(response => {
responseJson = JSON.parse(response);
// remove question from answer
description=responseJson[provider].answers[0].replace(question, '');
pictureDescriptionInput.value(description);
displayCost(responseJson[provider].cost);
if(additionalCallback!== undefined && additionalCallback!==null ){
additionalCallback();
}
});
}
function displayCost(cost){
if(!isSandboxMode()){
statusPanelText.html(htmlTextInColor("Last call price: "+cost+"$","blue"));
}else{
statusPanelReset();
}
}
/*
* Returns FormData to be sent for answer question feature
*/
function getFormDataImageQuestion(question,providers){
var form = new FormData();
form.append("providers", providers);
form.append("response_as_dict", "true");
form.append("attributes_as_list", "false");
form.append("show_original_response", "false");
//form.append("settings", "[object Object]");
var base64Image = document.getElementById("defaultCanvas0").toDataURL('image/png').split(',')[1];
// Convert base64 to Blob
var byteCharacters = atob(base64Image);
var byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
var blob = new Blob([byteArray], { type: 'image/png' }); // Adjust the MIME type accordingly
form.append("file", blob, 'image.png');
form.append("temperature", temperature);
form.append("question", question);
form.append("max_tokens", maxTokens);
return form;
}
function htmlTextInColor(text,color){
return "<font color="+color+"><b>"+text+"</b></font>"
}
function statusPanelReset(){
statusPanelText.html(htmlTextInColor("In the Sandbox mode the api calls are free of charge.","blue"));
}
function handleErrorResponse(response){
console.error(response.responseText);
statusPanelText.html(htmlTextInColor(response.responseText,"red"));
}
/*
* Bellow are p5 methods definitions
*/
function draw() {
if (painting) {
stroke(penColor);
strokeWeight(penSize);
if (rubberMode) {
// Erase by drawing with a white stroke
stroke(255);
}
line(prevX, prevY, mouseX, mouseY);
prevX = mouseX;
prevY = mouseY;
}
}
function mousePressed() {
painting = true;
prevX = mouseX;
prevY = mouseY;
}
function mouseReleased() {
painting = false;
}