Powerful to write up functions, convert between languages, and even draft web apps. All with examples you can run online.
You’ve probably seen the hype with OpenAI’s ChatGPT these days. But that’s not the only new product from the AI company. The new wave of GPT “3.5” models also includes a more powerful davinci model, now version 003, and a new model specialized for writing code, called code-davinci-002. For the moment, this model is free to use, meaning it won’t consume your tokens. I tried code-davinci-002 to test how useful it could be to write up code, specifically JavaScript code which I use a lot for my work and hobbies. And I’m amazed at the results. As I show here in the examples, code-davinci-002 can not only write code from prompts but also correct mistakes and suggest alternatives, convert code from other languages to JavaScript, and even write up some quite complete web apps dealing with complex things such as media devices. Read on to witness the power of this tool, following the links to see these programs actually running in your web browser.
A JavaScript function to compute basic statistics on the numbers of an input array
Simply that, as a first example to warm up.
Where did I run this (and all other code generations)? In the official OpenAI playground for GPT models:
https://beta.openai.com/playground?model=code-davinci-002
Notice that the link already automatically invokes code-davinci-002, which is the model specialized for code.
/* Write a JavaScript function that returns all basic statistics for an array of numbers. Input is an array with numbers, output is another array with median, average, standard deviation, etc.*/
function statistics(arr) {
var sum = 0;
var min = arr[0];
var max = arr[0];
var avg = 0;
var median = 0;
var stdDev = 0;
var result = [];
for (var i = 0; i < arr.length; i++) {
sum += arr[i];
if (arr[i] < min) {
min = arr[i];
}
if (arr[i] > max) {
max = arr[i];
}
}
avg = sum / arr.length;
arr.sort(function (a, b) {
return a — b;
});
if (arr.length % 2 === 0) {
median = (arr[arr.length / 2–1] + arr[arr.length / 2]) / 2;
} else {
median = arr[(arr.length — 1) / 2];
}
for (var j = 0; j < arr.length; j++) {
stdDev += Math.pow((arr[j] — avg), 2);
}
stdDev = Math.sqrt(stdDev / arr.length);
result.push(min, max, avg, median, stdDev);
return result;
}
console.log(statistics([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));
console.log(statistics([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]));
You can try out that code in this page (I edited the last lines to display the output right in the web page rather than in the console log, but the rest of the code is untouched!) http://lucianoabriata.altervista.org/tests/gpt3.5-code-davinci002/statistics.html
JavaScript function to convert DNA sequences to protein sequences using the genetic code
Let’s see how it handles strings, and at the same time if it can apply GPT3.5’s general knowledge, for example of the genetic code and how biology works.
/* Write a JavaScript function that translates a DNA sequence into a protein sequence*/
function translate(sequence) {
var codons = {
‘ATA’:’I’, ‘ATC’:’I’, ‘ATT’:’I’, ‘ATG’:’M’,
‘ACA’:’T’, ‘ACC’:’T’, ‘ACG’:’T’, ‘ACT’:’T’,
‘AAC’:’N’, ‘AAT’:’N’, ‘AAA’:’K’, ‘AAG’:’K’,
‘AGC’:’S’, ‘AGT’:’S’, ‘AGA’:’R’, ‘AGG’:’R’,
‘CTA’:’L’, ‘CTC’:’L’, ‘CTG’:’L’, ‘CTT’:’L’,
‘CCA’:’P’, ‘CCC’:’P’, ‘CCG’:’P’, ‘CCT’:’P’,
‘CAC’:’H’, ‘CAT’:’H’, ‘CAA’:’Q’, ‘CAG’:’Q’,
‘CGA’:’R’, ‘CGC’:’R’, ‘CGG’:’R’, ‘CGT’:’R’,
‘GTA’:’V’, ‘GTC’:’V’, ‘GTG’:’V’, ‘GTT’:’V’,
‘GCA’:’A’, ‘GCC’:’A’, ‘GCG’:’A’, ‘GCT’:’A’,
‘GAC’:’D’, ‘GAT’:’D’, ‘GAA’:’E’, ‘GAG’:’E’,
‘GGA’:’G’, ‘GGC’:’G’, ‘GGG’:’G’, ‘GGT’:’G’,
‘TCA’:’S’, ‘TCC’:’S’, ‘TCG’:’S’, ‘TCT’:’S’,
‘TTC’:’F’, ‘TTT’:’F’, ‘TTA’:’L’, ‘TTG’:’L’,
‘TAC’:’Y’, ‘TAT’:’Y’, ‘TAA’:’_’, ‘TAG’:’_’,
‘TGC’:’C’, ‘TGT’:’C’, ‘TGA’:’_’, ‘TGG’:’W’
};
var protein = ‘’;
for (var i = 0; i < sequence.length; i += 3) {
protein += codons[sequence.substring(i, i + 3)];
}
return protein;
}
console.log(translate(‘ATCGATCGATCGTTGCTTATCGATCAG’));
You can test this example here (modified just in the last line to display the output on the page rather than on the console): http://lucianoabriata.altervista.org/tests/gpt3.5-code-davinci002/translatednasequence.html
A full JS-based sound frequency analyzer for web browsers, in seconds!
I tried to ask the bot for some complete web apps, and although it had some failures, it did come up with good answers in some cases. For example, when I asked it to create a spectrogram app that reads the microphone’s input and draws the corresponding output, I got a functional app that was almost there in just my first attempt!
/*Create the JavaScript, HTML and CSS of a web app that hears sounds through the microphone and shows a spectrogram updating it real time*/
//Create the canvas
var canvas = document.createElement(‘canvas’);
canvas.id = ‘canvas’;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
//Create the audio context
var audioContext = new AudioContext();
//Create the analyser
var analyser = audioContext.createAnalyser();
analyser.fftSize = 2048;
//Create the microphone
navigator.mediaDevices.getUserMedia({audio: true, video: false})
.then(function(stream) {
var microphone = audioContext.createMediaStreamSource(stream);
microphone.connect(analyser);
})
.catch(function(err) {
console.log(‘The following gUM error occured: ‘ + err);
});
//Create the buffer
var bufferLength = analyser.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
//Create the canvas context
var canvasContext = canvas.getContext(‘2d’);
//Create the gradient
var gradient = canvasContext.createLinearGradient(0, 0, 0, canvas.height);
gradient.addColorStop(1, ‘#000000’);
gradient.addColorStop(0.75, ‘#ff0000’);
gradient.addColorStop(0.25, ‘#ffff00’);
gradient.addColorStop(0, ‘#ffffff’);
//Draw the spectrogram
function draw() {
requestAnimationFrame(draw);
analyser.getByteTimeDomainData(dataArray); // Only this line wrong
canvasContext.fillStyle = ‘rgb(0, 0, 0)’;
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
canvasContext.lineWidth = 2;
canvasContext.strokeStyle = gradient;
canvasContext.beginPath();
var sliceWidth = canvas.width * 1.0 / bufferLength;
var x = 0;
for (var i = 0; i < bufferLength; i++) {
var v = dataArray[i] / 128.0;
var y = v * canvas.height / 2;
if (i === 0) {
canvasContext.moveTo(x, y);
} else {
canvasContext.lineTo(x, y);
}
x += sliceWidth;
}
canvasContext.lineTo(canvas.width, canvas.height / 2);
canvasContext.stroke();
}
draw();
I marked with a comment the only line that wasn’t exactly what I needed: I asked for a spectrum of frequencies, and this app plots the time domain data. With a simple request (first line in the code below, saying “Nice but show me the spectrum of frequencies” as a JavaScript comment), the bot corrected this by replacing getByteTimeDomainData with getByteFrequencyData. Here is the request in the format of a JavaScript comment, after which I hit Submit and get the result in seconds -which now worked out perfectly without any intervention!:
/*Nice but show me the spectrum of frequencies*/
//Create the canvas
var canvas = document.createElement(‘canvas’);
canvas.id = ‘canvas’;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);
//Create the audio context
var audioContext = new AudioContext();
//Create the analyser
var analyser = audioContext.createAnalyser();
analyser.fftSize = 2048;
//Create the microphone
navigator.mediaDevices.getUserMedia({audio: true, video: false})
.then(function(stream) {
var microphone = audioContext.createMediaStreamSource(stream);
microphone.connect(analyser);
})
.catch(function(err) {
console.log(‘The following gUM error occured: ‘ + err);
});
//Create the buffer
var bufferLength = analyser.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
//Create the canvas context
var canvasContext = canvas.getContext(‘2d’);
//Create the gradient
var gradient = canvasContext.createLinearGradient(0, 0, 0, canvas.height);
gradient.addColorStop(1, ‘#000000’);
gradient.addColorStop(0.75, ‘#ff0000’);
gradient.addColorStop(0.25, ‘#ffff00’);
gradient.addColorStop(0, ‘#ffffff’);
//Draw the spectrogram
function draw() {
requestAnimationFrame(draw);
analyser.getByteFrequencyData(dataArray); //Correction here
canvasContext.fillStyle = ‘rgb(0, 0, 0)’;
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
canvasContext.lineWidth = 2;
canvasContext.strokeStyle = gradient;
canvasContext.beginPath();
var sliceWidth = canvas.width * 1.0 / bufferLength;
var x = 0;
for (var i = 0; i < bufferLength; i++) {
var v = dataArray[i] / 128.0;
var y = v * canvas.height / 2;
if (i === 0) {
canvasContext.moveTo(x, y);
} else {
canvasContext.lineTo(x, y);
}
x += sliceWidth;
}
canvasContext.lineTo(canvas.width, canvas.height / 2);
canvasContext.stroke();
}
draw();
You can see this app running at this link (exactly the code above except that I edited a few heights and scale factors to better see the plots): https://lucianoabriata.altervista.org/tests/gpt3.5-code-davinci002/audioapp.html And here’s a snapshot of the app running… see it’s complete with color gradients!
The spectrogram created by GPT3.5’s code-davinci002 after a single correction.
Creating a JavaScript function from a piece of C code!
I tried to have the program create a JavaScript function to compute the isoelectric point of a protein from its sequence, and despite several attempts, this didn’t work. However, I found online (here) the C code of a program that does this. So I gave this source code to code-davinci-002 together with a prompt asking to convert it to JavaScript, as a function. And it seems to have worked!
// Write a JavaScript function to compute the isoelectric point of a protein from its sequence. I found this C code that does this:
#include <iostream>
#include <cmath>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
std::string protein;
ifstream aa;
aa.open(“aa.txt”); //we are getting the data from the file (we assume that we have aa.txt file)
aa>>protein; //the sequence should be in one letter code (uppercase letters)
aa.close();
int ProtLength; //now we are getting protein length
ProtLength = protein.length();
char Asp = ‘D’;
char Glu = ‘E’;
char Cys = ‘C’;
char Tyr = ‘Y’;
char His = ‘H’;
char Lys = ‘K’;
char Arg = ‘R’;
int AspNumber = 0;
int GluNumber = 0;
int CysNumber = 0;
int TyrNumber = 0;
int HisNumber = 0;
int LysNumber = 0;
int ArgNumber = 0;
int i=0;
for ( i = 0; i <= protein.length() — 1; ++i) // we are looking for charged amino acids
{
if (protein[i] == Asp)
++AspNumber;
if (protein[i] == Glu)
++GluNumber;
if (protein[i] == Cys)
++CysNumber;
if (protein[i] == Tyr)
++TyrNumber;
if (protein[i] == His)
++HisNumber;
if (protein[i] == Lys)
++LysNumber;
if (protein[i] == Arg)
++ArgNumber;
}
double NQ = 0.0; //net charge in given pH
double QN1=0; //C-terminal charge
double QN2=0; //D charge
double QN3=0; //E charge
double QN4=0; //C charge
double QN5=0; //Y charge
double QP1=0; //H charge
double QP2=0; //NH2 charge
double QP3=0; //K charge
double QP4=0; //R charge
double pH = 0.0;
for(;;) //the infinite loop
{
// we are using pK values form Wikipedia as they give quite good approximation
// if you want you can change it
QN1=-1/(1+pow(10,(3.65-pH)));
QN2=-AspNumber/(1+pow(10,(3.9-pH)));
QN3=-GluNumber/(1+pow(10,(4.07-pH)));
QN4=-CysNumber/(1+pow(10,(8.18-pH)));
QN5=-TyrNumber/(1+pow(10,(10.46-pH)));
QP1=HisNumber/(1+pow(10,(pH-6.04)));
QP2=1/(1+pow(10,(pH-8.2)));
QP3=LysNumber/(1+pow(10,(pH-10.54)));
QP4=ArgNumber/(1+pow(10,(pH-12.48)));
NQ=QN1+QN2+QN3+QN4+QN5+QP1+QP2+QP3+QP4;
//if you want to see how the program works step by step uncomment below line
// cout<<”NQ=”<<NQ<<”\tat pH =”<<pH<<”\ti:” <<i++<<endl;
if (pH>=14.0)
{ //you should never see this message
cout<<”Something is wrong — pH is higher than 14"<<endl; //
break;
}
if (NQ<=0) // if this condition is true we can stop calculate
break;
pH+=0.01; // if not increase pH
}
ofstream outfile; //we are writing results to outfile.txt
outfile.open(“outfile.txt”);
outfile << “Protein length: “<<ProtLength<<endl;
outfile << “Number of Asp = “<<AspNumber<<endl;
outfile << “Number of Glu = “<<GluNumber<<endl;
outfile << “Number of Cys = “<<CysNumber<<endl;
outfile << “Number of Tyr = “<<TyrNumber<<endl;
outfile << “Number of His = “<<HisNumber<<endl;
outfile << “Number of Lys = “<<LysNumber<<endl;
outfile << “Number of Arg = “<<ArgNumber<<endl;
outfile << “Protein isoelectric point: “<<pH<<endl;
outfile.close();
cout << “Protein isoelectric point: “<<pH<<endl;
system(“PAUSE”);
return EXIT_SUCCESS;
}
*/
function isoelectricPoint(protein) {
var Asp = ‘D’;
var Glu = ‘E’;
var Cys = ‘C’;
var Tyr = ‘Y’;
var His = ‘H’;
var Lys = ‘K’;
var Arg = ‘R’;
var AspNumber = 0;
var GluNumber = 0;
var CysNumber = 0;
var TyrNumber = 0;
var HisNumber = 0;
var LysNumber = 0;
var ArgNumber = 0;
var i = 0;
for (i = 0; i <= protein.length — 1; ++i) {
if (protein[i] == Asp)
++AspNumber;
if (protein[i] == Glu)
++GluNumber;
if (protein[i] == Cys)
++CysNumber;
if (protein[i] == Tyr)
++TyrNumber;
if (protein[i] == His)
++HisNumber;
if (protein[i ] == Lys)
++LysNumber;
if (protein[i] == Arg)
++ArgNumber;
}
var NQ = 0.0; //net charge in given pH
var QN1 = 0; //C-terminal charge
var QN2 = 0; //D charge
var QN3 = 0; //E charge
var QN4 = 0; //C charge
var QN5 = 0; //Y charge
var QP1 = 0; //H charge
var QP2 = 0; //NH2 charge
var QP3 = 0; //K charge
var QP4 = 0; //R charge
var pH = 0.0;
for (;;) {
// we are using pK values form Wikipedia as they give quite good approximation
// if you want you can change it
QN1 = -1 / (1 + Math.pow(10, (3.65 — pH)));
QN2 = -AspNumber / (1 + Math.pow(10, (3.9 — pH)));
QN3 = -GluNumber / (1 + Math.pow(10, (4.07 — pH)));
QN4 = -CysNumber / (1 + Math.pow(10, (8.18 — pH)));
QN5 = -TyrNumber / (1 + Math.pow(10, (10.46 — pH)));
QP1 = HisNumber / (1 + Math.pow(10, (pH — 6.04)));
QP2 = 1 / (1 + Math.pow(10, (pH — 8.2)));
QP3 = LysNumber / (1 + Math.pow(10, (pH — 10.54)));
QP4 = ArgNumber / (1 + Math.pow(10, (pH — 12.48)));
NQ = QN1 + QN2 + QN3 + QN4 + QN5 + QP1 + QP2 + QP3 + QP4;
//if you want to see how the program works step
// by step uncomment below line
// cout<<”NQ=”<<NQ<<”\tat pH =”<<pH<<”\ti:” <<i++<<endl;
if (pH >= 14.0) {
//you should never see this message
console.log(“Something is wrong — pH is higher than 14”);
//
break;
}
if (NQ <= 0) // if this condition is true we can stop calculate
break;
pH += 0.01; // if not increase pH
}
console.log(“Protein length: “ + protein.length);
console.log(“Number of Asp = “ + AspNumber);
console.log(“Number of Glu = “ + GluNumber);
console.log(“Number of Cys = “ + CysNumber);
console.log(“Number of Tyr = “ + TyrNumber);
console.log(“Number of His = “ + HisNumber);
console.log(“Number of Lys = “ + LysNumber);
console.log(“Number of Arg = “ + ArgNumber);
console.log(“Protein isoelectric point: “ + pH);
}
//To test
isoelectricPoint(“DEEECYYHHKKRR”);
It was almost, almost there… it just missed that I asked for a function, so it should ideally return the calculated number. By adding this line at the end of the first block of code:
Good but I’d like it to return the calculated isoelectric point
The system responds by re-writing the whole JavaScript function, but now with this added at the end:
return pH;
You can see this running here: https://lucianoabriata.altervista.org/tests/gpt3.5-code-davinci002/proteinisoelectricpoint.html
Interacting to optimize code
In this last example, I asked the model to write a function to fetch data from Wikipedia, but it used jQuery so I asked it to write it again without using that. The new function didn’t use jQuery, but it used XMLHttpRequest which is old and might become deprecated soon… So I asked code-davinci-002 to use the more modern fetch() command. Finally, I asked it for an async version of the function. You can see in yellow all my indications, and even some questions I asked the bot so that it would explain me what it was doing:
More?
Thousands have been posting about ChatGPT’s capabilities to write and correct code, but my article comes with a twist as I focus on JavaScript and I show you the actual apps running. I wonder if you dear reader have been trying ChatGPT or other GPT3.5 models for writing programs or at least creating, cleaning up, or checking pieces of code. Naturally, I’m especially interested in JavaScript code, so if you have interesting observations to share, for good or bad, please do so in the comments -or perhaps write your own article featuring more good and bad use cases.
Fascinated by GPT-3 like me?
Then check out all my articles so far: And some articles published after that collection: www.lucianoabriata.com I write and photoshoot about everything that lies in my broad sphere of interests: nature, science, technology, programming, etc. Become a Medium member to access all its stories (affiliate links of the platform for which I get small revenues without cost to you) and subscribe to get my new stories by email. To consult about small jobs check my services page here. You can contact me here.