A large language model is basically a machine that can understand and generate text. Depends on how it is trained, sometimes the model can generate something other than text. ChatGPT is such a large language model. It can generate programming code if you prompt it correctly. In this post, you will learn how to make ChatGPT to generate a program for you. Specifically, you will learn
- How to make ChatGPT to bootstrap your programming project
- How to use ChatGPT as your programming helper
Let’s get started.
Overview
This post is divided into two parts; they are:
- Start a Programming Project
- Understanding Code and Generating Function Snippets
Start a Programming Project
Let’s consider a simple project: You want to set up a REST API server that can help you take a “screen capture” of an entire web page of a provided URL. Optionally, the REST API can accept an additional optional parameter of an email address. In that case, the screen capture is not returned but emailed out.
This is a project that involves multiple components. You need something that can act like a REST API server that listens to HTTP requests and responds accordingly. You also need something to fetch a URL and take a screenshot like a normal web browser. There is also a logic in it that depends on whether an email address is provided; the output can be an image file returned, or an email with an attachment is sent out.
If you are unfamiliar with how to create a REST API server or don’t know the tools available, you can ask ChatGPT for help. Simply put down all the detail in your prompt and ask:
I need to create a REST API server that accepts a URL as input, captures the web page screenshot into JPEG format and returns it as output. Optionally, the user may provide an email address as an additional input. In that case, the screenshot should be emailed out instead of returned. Can you help me with this program?
With this, ChatGPT produces the following suggestion:
Certainly! I can help you with that. To create a REST API server that captures web page screenshots and handles optional email functionality, you can use Node.js along with a few additional packages. Here’s an outline of the steps you can follow:
1. Set up a new Node.js project and initialize it using npm:
mkdir screenshot–api
cd screenshot–api
npm init
2. Install the necessary packages. You’ll need
express
for the API server,puppeteer
for capturing screenshots, andnodemailer
for sending emails:
npm install express puppeteer nodemailer
3. Create an
index.js
file and set up the basic server using Express:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const express = require(‘express’);
const app = express();
const port = 3000;
app.get(‘/screenshot’, async (req, res) => {
const url = req.query.url;
const email = req.query.email;
// Capture the screenshot using Puppeteer
// Handle the response based on whether an email is provided
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
4. Inside the
/screenshot
route, use Puppeteer to capture the web page screenshot and handle the response accordingly:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const puppeteer = require(‘puppeteer’);
app.get(‘/screenshot’, async (req, res) => {
const url = req.query.url;
const email = req.query.email;
// Launch Puppeteer
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Navigate to the provided URL
await page.goto(url);
// Capture the screenshot
const screenshotBuffer = await page.screenshot({ fullPage: true });
// Close the browser
await browser.close();
// Handle the response based on whether an email is provided
if (email) {
// Send the email with the screenshot attachment using Nodemailer
} else {
// Send the screenshot as the response
res.type(‘image/jpeg’);
res.send(screenshotBuffer);
}
});
5. To handle sending emails with the screenshot attachment, add the following code inside the
if (email)
block:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const nodemailer = require(‘nodemailer’);
// Create a transporter using your email service provider’s details
const transporter = nodemailer.createTransport({
service: ‘your-email-service-provider’,
auth: {
pass: ‘your-email-password’,
},
});
// Define the email options
const mailOptions = {
to: email,
subject: ‘Web Page Screenshot’,
text: ‘Please find the attached screenshot.’,
attachments: [
{
filename: ‘screenshot.jpg’,
content: screenshotBuffer,
},
],
};
// Send the email
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.error(error);
res.status(500).send(‘Failed to send email.’);
} else {
console.log(`Email sent: ${info.response}`);
res.send(‘Screenshot emailed successfully!’);
}
});
Make sure to replace
'your-email-service-provider'
,'[email protected]'
, and'your-email-password'
with your actual email service provider’s details.6. Finally, start the server:
Now, when you make a GET request to
http://localhost:3000/screenshot?url={URL}
, the server will capture a screenshot of the provided URL. If an email address is also provided asemail={EMAIL}
, the server will send the screenshot as an email attachment instead of returning it directly.Remember to handle errors and add any necessary error checking or validation based on your requirements.
That’s it! You now have a basic REST API server that captures web page screenshots and optionally sends them via email. Feel free to enhance it further according to your needs.
This is a very detailed result that tells you how to finish this programming task. The response covered all the requirements, but you should notice that when you didn’t specify explicitly in the prompt, ChatGPT will make some design decisions for you, such as what programming language to use.
It is not easy to think for all the details at the first run, but the nature of ChatGPT allows you to provide follow up prompt to revise the answer, such as:
For the above problem, I want to use Python and FastAPI as the web framework and Selenium for the web browser. Can you rewrite this?
The response from ChatGPT now becomes:
Certainly! Here’s a revised version of the solution using Python, FastAPI as the web framework, and Selenium for the web browser automation.
1. Install the necessary packages. You’ll need
fastapi
,uvicorn
for running the server,selenium
, andwebdriver_manager
for managing the web driver:
pip install fastapi uvicorn selenium webdriver_manager
2. Create a new file called
main.py
and import the required modules:
from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse
from pydantic import BaseModel
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import WebDriverException
from io import BytesIO
app = FastAPI()
3. Define a request model to handle the input data:
class ScreenshotRequest(BaseModel):
url: str
email: str = None
4. Create a route to capture the web page screenshot:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@app.get(“/screenshot”)
async def capture_screenshot(request: ScreenshotRequest):
options = Options()
options.headless = True
try:
# Set up the Chrome webdriver
driver = webdriver.Chrome(ChromeDriverManager().install(), options=options)
driver.set_window_size(1280, 720)
# Navigate to the provided URL
driver.get(request.url)
# Capture the screenshot
screenshot = driver.get_screenshot_as_png()
screenshot_buffer = BytesIO(screenshot)
# Close the browser
driver.quit()
if request.email:
# Send the email with the screenshot attachment
return “Screenshot emailed successfully!”
else:
# Return the screenshot as a response
return FileResponse(screenshot_buffer, media_type=“image/png”)
except WebDriverException:
raise HTTPException(status_code=400, detail=“Failed to capture screenshot.”)
5. Start the server using Uvicorn:
uvicorn main:app —reload
Now, when you make a GET request to
http://localhost:8000/screenshot?url={URL}
, the server will capture a screenshot of the provided URL. If an email address is also provided asemail={EMAIL}
, you can handle sending the email with the screenshot attachment using theRemember to handle errors and add any necessary error checking or validation based on your requirements.
Note: This solution assumes you have Chrome installed on your machine. If you’re using a different browser, you’ll need to adjust the webdriver accordingly.
That’s it! You now have a REST API server using Python, FastAPI, and Selenium to capture web page screenshots and handle optional email functionality.
You can see that, you didn’t provide any unnecessary detail in your follow-up prompt except referencing to “the above problem” but ChatGPT can accurately “translated” the Node.js implementation into Python and using the libraries you specified.
It is a fantastic result, although you may still need to polish the code. One example is that the browser screen size is certainly affecting how a web page is rendered, but the size was hard-coded in the above since you didn’t specify that it should be adjustable in your prompt. Another potential reason to polish the generated code is to catch other coding style issues or add defensive measures against security concerns.
In summary, as in the other use case, the more detail you put in the prompt with sufficient clarity is the key to a useful response. In the case of a programming task, it is crucial to lay out the details of
- What is the objective
- What is the input and output format
- What are the tools the program should use
- What are the different situations that the program may encounter and how should these situations be handled
Understanding Code and Generating Function Snippets
Sometimes, it is not a large program that you want to write but a smaller function. You can ask ChatGPT to generate a function for you using a prompt similar to the above, except you need to specify the output format, such as a function or a class.
Indeed you can also do the other way round, namely, provide a code to ChatGPT and ask it to explain in English. It is sometimes useful, especially to decipher other people’s code. Let’s consider the following example:
Please explain what the following code is doing:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
```
float det(float** a, float k) {
float s = 1, ret = 0, **b;
int i, j, m, n, c;
if (k == 1) {
return a[0][0];
} else {
b = (float**) malloc(sizeof(float*)*k);
for (i = 0; i < k; i++)
b[i] = (float*) malloc(sizeof(float)*k);
ret = 0;
for (c = 0; c < k; c++) {
m = 0;
n = 0;
for (i = 0; i < k; i++) {
for (j = 0; j < k; j++) {
b[i][j] = 0;
if (i != 0 && j != c) {
b[m][n] = a[i][j];
if (n < (k – 2))
n++;
else {
n = 0;
m++;
}
}
}
}
ret = ret + s * (a[0][c] * det(b, k – 1));
s = s * –1;
};
for (i = 0; i < k; i++)
free(b[i]);
};
free(b);
return ret;
}
```
This prompt is very simple: There is only one keyword, “explain”. But pay attention to how you provide the code to ChatGPT: The use of backticks follows the Markdown’s code fence syntax to quote the program. This helps identify which is your instruction and which is not.
While this is not a very long program, ChatGPT explained the code with great verbosity. It also identifies the intent at a high level, namely, it is to calculate the determinant of a matrix. The following is the response:
The code you provided is a recursive implementation of calculating the determinant of a square matrix using the Laplace expansion.
Here’s a step-by-step breakdown of what the code does:
- The function
det
takes two parameters: a pointer to a 2D array (float** a
) representing the matrix and the size of the matrix (float k
).- It declares some variables:
s
for sign,ret
for the determinant value, and**b
as a temporary matrix.- It checks if
k
is equal to 1. If so, it means we have reached the base case of a 1×1 matrix, and the function returns the single value in the matrix, which is the determinant.- If
k
is greater than 1, it proceeds with the calculation.- It dynamically allocates memory for the temporary matrix
b
with sizek
xk
.- It initializes
ret
to 0.- It enters a loop that iterates over each column of the first row of the matrix
a
.- Inside the loop, it resets the indices
m
andn
to 0.- It enters a nested loop that iterates over each element of the matrix
a
.- Inside the nested loop, it sets the element in the temporary matrix
b
at positionm
,n
to 0.- It checks if the current element is not in the first row (
i != 0
) and not in the current column (j != c
).- If the element is not in the first row or the current column, it copies the value from matrix
a
to the temporary matrixb
at positionm
,n
.- It updates the indices
m
andn
based on the position of the next element inb
.- After the nested loop, it calculates the determinant of the submatrix
b
by recursively calling thedet
function with the temporary matrixb
and sizek - 1
.- It multiplies the determinant of the submatrix by the sign
s
(alternating sign).- It multiplies the sign
s
by -1 to switch the sign for the next iteration.- It adds the product of the sign, the element in the first row (
a[0][c]
), and the determinant of the submatrix to the running sumret
.- The loop continues to the next column.
- After the loop, it frees the memory allocated for each row of the temporary matrix
b
.- It frees the memory allocated for the temporary matrix
b
.- Finally, it returns the calculated determinant value
ret
.In summary, the code recursively calculates the determinant of a square matrix by performing a Laplace expansion along the first row. It uses a temporary matrix to store the submatrices obtained by excluding the first row and the selected column. The recursion continues until it reaches the base case of a 1×1 matrix.
Follow-up to improve the code
This code is not easy to understand at first glance. There may be a way to make it easier to read. Indeed, ChatGPT can do a good job in this case, with just a very simple follow-up prompt:
Can you rewrite this code for clarity and add comments?
The keywords here are “for clarity” and “add comments”. ChatGPT provides the following in response:
Certainly! Here’s a revised version of the code with comments explaining each step:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
float determinant(float** matrix, int size) {
float sign = 1; // Sign of the determinant
float result = 0; // Determinant value
float** submatrix; // Temporary submatrix
int i, j, m, n, c; // Loop variables
// Base case: 1×1 matrix
if (size == 1) {
return matrix[0][0];
}
else {
// Allocate memory for the temporary submatrix
submatrix = (float**)malloc(sizeof(float*) * size);
for (i = 0; i < size; i++) {
submatrix[i] = (float*)malloc(sizeof(float) * size);
}
// Calculate the determinant
for (c = 0; c < size; c++) {
m = 0;
n = 0;
// Create the submatrix by excluding the first row and the current column
for (i = 0; i < size; i++) {
for (j = 0; j < size; j++) {
submatrix[i][j] = 0;
// Copy values to the submatrix
if (i != 0 && j != c) {
submatrix[m][n] = matrix[i][j];
// Update submatrix indices
if (n < (size – 2)) {
n++;
}
else {
n = 0;
m++;
}
}
}
}
// Calculate the determinant of the submatrix recursively
result += sign * matrix[0][c] * determinant(submatrix, size – 1);
// Flip the sign for the next iteration
sign *= –1;
}
// Free the memory allocated for the submatrix
for (i = 0; i < size; i++) {
free(submatrix[i]);
}
free(submatrix);
return result;
}
}
I’ve added comments above each significant section of the code to explain what it does. This should make the code more readable and easier to understand.
This version is undoubtedly easier to read.
Besides, you can ask for more. Such as ask to catch bugs or potential security issues in the code. Let’s ask ChatGPT to produce some unit test code:
Can you give me a few unit test cases to ensure this function works well?
Not require any further explanation, the following is the response:
Certainly! Here are a few unit test cases to verify the correctness of the
determinant
function:Test Case 1: 2×2 Matrix
float matrix1[2][2] = {{2, 3},
{1, 4}};
float** ptrMatrix1 = (float**)matrix1;
float det1 = determinant(ptrMatrix1, 2);
// Expected output: 5
Test Case 2: 3×3 Matrix
float matrix2[3][3] = {{6, 1, 1},
{4, –2, 5},
{2, 8, 7}};
float** ptrMatrix2 = (float**)matrix2;
float det2 = determinant(ptrMatrix2, 3);
// Expected output: -306
Test Case 3: 4×4 Matrix
float matrix3[4][4] = {{1, 0, 2, –1},
{3, 0, 0, 5},
{2, 1, 4, –3},
{1, 0, 5, 0}};
float** ptrMatrix3 = (float**)matrix3;
float det3 = determinant(ptrMatrix3, 4);
// Expected output: -20
These test cases cover matrices of different sizes (2×2, 3×3, and 4×4) and include positive, negative, and zero determinant values. By comparing the calculated determinant values with the expected outputs, you can verify if the
determinant
function is working correctly.
But it is quite obvious, the unit test code missed a corner case: The 1×1 matrix. This reveals that ChatGPT is not always perfect. You should only use it as your assistant not replacement. You should always verify the result.
Summary
In this post, you saw how ChatGPT can help you with programming. Not only can it generate code as part of its response to your question, but also it can figure out the intention of a code that you provided. Specifically, you have learned that:
- You can use ChatGPT to generate the initial code for your software project, or generate test code for a function
- You can ask ChatGPT to explain the code to you
- You can make use of ChatGPT to refactor and clean up code