Experimenting with ChatGPT App Dev Skills.
For this experiment I am using ChatGPT+ with the plugins "Prompt Perfect" and "WebPilot". Each commit will be a prompt and response with the associated code and recommendations. You will see the progression through git commits.
Prompt: perfect I would like to build a simple single file webpage that has a field to specify genre and a button that will invoke a call to chatgpt api to return chord progressions for an original verse, bridge, and chorus in that style
Response: I understand your request. You want to create a single-file webpage with the following features:
- A field where users can specify a musical genre.
- A button that, when clicked, will make a call to the ChatGPT API.
- The API call should return chord progressions for an original verse, bridge, and chorus in the specified genre.
Let's start by building the HTML structure for your webpage. Would you like me to provide you with a basic HTML template to achieve this?
Prompt: yes
Response: Alright, here's a basic HTML template for your webpage:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chord Progression Generator</title>
<style>
/* Add your CSS styles here */
body {
font-family: Arial, sans-serif;
text-align: center;
margin-top: 50px;
}
</style>
</head>
<body>
<h1>Chord Progression Generator</h1>
<label for="genre">Select Genre:</label>
<select id="genre">
<option value="pop">Pop</option>
<option value="rock">Rock</option>
<option value="jazz">Jazz</option>
<!-- Add more genres as needed -->
</select>
<button onclick="getChordProgression()">Generate Chord Progression</button>
<div id="result">
<!-- The chord progression will be displayed here -->
</div>
<script>
function getChordProgression() {
const genre = document.getElementById('genre').value;
// Make an API call to ChatGPT with the selected genre
// Display the result in the 'result' div
}
</script>
</body>
</html>
This is a basic structure. You'll need to implement the getChordProgression function to make the API call to ChatGPT and handle the response. If you're unfamiliar with making API calls in JavaScript, I can guide you through that as well. Would you like assistance with that?
Prompt: yes, please add the api call to the file generated previously
Response: Certainly! To make an API call to ChatGPT, you'll typically use the fetch
function in JavaScript. Here's how you can integrate it into the provided template:
-
First, you'll need your OpenAI API key. For security reasons, never expose your API key directly in client-side code. Instead, set up a server-side endpoint that your webpage can call, which will then make the request to OpenAI's API.
-
For the sake of this example, I'll show you how to make the API call directly from the client-side, but remember this is not recommended for production due to security concerns.
Here's the updated code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chord Progression Generator</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
margin-top: 50px;
}
</style>
</head>
<body>
<h1>Chord Progression Generator</h1>
<label for="genre">Select Genre:</label>
<select id="genre">
<option value="pop">Pop</option>
<option value="rock">Rock</option>
<option value="jazz">Jazz</option>
</select>
<button onclick="getChordProgression()">Generate Chord Progression</button>
<div id="result">
<!-- The chord progression will be displayed here -->
</div>
<script>
async function getChordProgression() {
const genre = document.getElementById('genre').value;
const promptText = `Generate a chord progression for a ${genre} song with a verse, bridge, and chorus.`;
const response = await fetch('https://api.openai.com/v1/engines/davinci/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY', // Replace 'YOUR_API_KEY' with your actual API key
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: promptText,
max_tokens: 150
})
});
const data = await response.json();
document.getElementById('result').innerText = data.choices[0].text.trim();
}
</script>
</body>
</html>
Important Notes:
- Replace
'YOUR_API_KEY'
with your actual OpenAI API key. As mentioned earlier, do not expose your API key in client-side code for production use. - The
fetch
function is used to make the API call. It's asynchronous, so we useasync/await
to handle the response. - The response from the API is parsed as JSON, and the result is displayed in the
result
div.
If you plan to deploy this, make sure to set up a server-side function to handle the API call to OpenAI to keep your API key secure.
Prompt: create the server-side function and necessary scaffolding for me
Response: Certainly! For simplicity, I'll use Node.js with the Express framework to create a server-side function. This server will expose an endpoint that the client-side can call, and this server-side function will then make the request to OpenAI's API.
Here's a step-by-step guide:
-
Setup:
- Make sure you have Node.js installed.
- Create a new directory for your project.
- Navigate to the directory in your terminal and run
npm init -y
to initialize a new Node.js project. - Install the necessary packages:
npm install express axios
-
Server Code (
server.js
):
const express = require('express');
const axios = require('axios');
const app = express();
const PORT = 3000;
// Middleware to parse JSON requests
app.use(express.json());
app.post('/generate-chords', async (req, res) => {
const genre = req.body.genre;
const promptText = `Generate a chord progression for a ${genre} song with a verse, bridge, and chorus.`;
try {
const response = await axios.post('https://api.openai.com/v1/engines/davinci/completions', {
prompt: promptText,
max_tokens: 150
}, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY', // Replace with your OpenAI API key
'Content-Type': 'application/json'
}
});
res.json(response.data.choices[0].text.trim());
} catch (error) {
res.status(500).send('Error generating chord progression');
}
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
- Client-side Update:
Update the client-side getChordProgression
function to call your server endpoint instead of OpenAI directly:
async function getChordProgression() {
const genre = document.getElementById('genre').value;
try {
const response = await fetch('/generate-chords', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ genre: genre })
});
const data = await response.text();
document.getElementById('result').innerText = data;
} catch (error) {
console.error('Error:', error);
}
}
- Run the Server:
In your terminal, navigate to your project directory and run:
node server.js
Your server will start, and you can access your webpage at http://localhost:3000
. When you select a genre and click the button, it will call the server-side function, which will then call the OpenAI API and return the chord progression.
Remember to replace 'YOUR_API_KEY'
in the server code with your actual OpenAI API key.
Note: Maybe it was my prompt, maybe it was chatgpt but the piece used by node express to serve up index.html was missing. Grabbed a snippet from Digital Ocean to make it happen: https://www.digitalocean.com/community/tutorials/use-expressjs-to-deliver-html-files
Note: I was receiving failed requests. Added some debugging code to get to the bottom of it with a breakpoint. (Commented out currently) Turns out you need to purchase credits to use the API. It's not included with Apple's iOS ChatGPT Plus subscription. After debugging got responses to come in successfully...even though we'll need some decent prompt engineering to get the type of result we're looking for. See these horrible results...
Note: So the prompt itself wasn't bad. ChatGPT had just advised me to use either a legacy (https://help.openai.com/en/articles/6283125-what-happened-to-engines) or the wrong API endpoint. I figured this out by going to the OpenAPI Platform Playground: https://platform.openai.com/playground.
The nice thing about Playgroud is that it gave me a pretty nice snippet so that I could determine how to tweak the request payload. After that all I needed was a little "\n" handling in the display and off the to the races!