大型语言模型本质上是一种能够理解和生成文本的机器。根据训练方式的不同,有时模型除了文本之外还可以生成其他内容。ChatGPT 就是这样一种大型语言模型。如果您提示得当,它可以生成编程代码。在本博文中,您将学习如何让 ChatGPT 为您生成程序。具体来说,您将学习
- 如何让 ChatGPT 启动您的编程项目
- 如何使用 ChatGPT 作为您的编程助手
开始并应用 ChatGPT,阅读我的书籍 《使用 ChatGPT 最大化生产力》。它提供了真实世界的用例和提示示例,旨在帮助您快速开始使用 ChatGPT。
让我们开始吧。

使用 ChatGPT 作为你的编程助手
图片由作者使用 Stable Diffusion 生成。保留部分权利。
概述
这篇文章分为两部分:
- 启动一个编程项目
- 理解代码和生成代码片段
启动一个编程项目
让我们来看一个简单的项目:您想设置一个 REST API 服务器,该服务器可以帮助您截取给定 URL 的整个网页的“屏幕截图”。可选地,REST API 可以接受一个额外的可选参数——电子邮件地址。在这种情况下,截图不会被返回,而是被发送出去。
这是一个涉及多个组件的项目。您需要一个能够充当 REST API 服务器的东西,它可以监听 HTTP 请求并做出相应的响应。您还需要一些东西来像普通浏览器一样抓取 URL 并进行屏幕截图。此外,根据是否提供电子邮件地址,还有相应的逻辑:输出可以是返回的图像文件,或者发送带有附件的电子邮件。
如果您不熟悉如何创建 REST API 服务器,或者不知道可用的工具,您可以向 ChatGPT 寻求帮助。只需在您的提示中放入所有详细信息并提问:
我需要创建一个 REST API 服务器,该服务器接受一个 URL 作为输入,将网页截图保存为 JPEG 格式并将其作为输出返回。可选地,用户可以提供一个电子邮件地址作为附加输入。在这种情况下,截图应该被发送出去而不是返回。你能帮我编写这个程序吗?
有了这个,ChatGPT 会给出以下建议:
当然!我很乐意为您提供帮助。要创建捕获网页截图并处理可选电子邮件功能的 REST API 服务器,您可以使用 Node.js 以及一些附加包。以下是您可以遵循的步骤大纲:
1. 设置一个新的 Node.js 项目并使用 npm 初始化它
123 mkdir screenshot-apicd screenshot-apinpm init2. 安装必要的包。您需要
express
用于 API 服务器,puppeteer
用于捕获屏幕截图,以及nodemailer
用于发送电子邮件。
1 npm install express puppeteer nodemailer3. 创建一个
index.js
文件并使用 Express 设置基本服务器
1234567891011121314151617 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. 在
/screenshot
路由中,使用 Puppeteer 捕获网页截图并相应地处理响应。
1234567891011121314151617181920212223242526272829 const puppeteer = require('puppeteer');app.get('/screenshot', async (req, res) => {const url = req.query.url;const email = req.query.email;// Launch Puppeteerconst browser = await puppeteer.launch();const page = await browser.newPage();// Navigate to the provided URLawait page.goto(url);// Capture the screenshotconst screenshotBuffer = await page.screenshot({ fullPage: true });// Close the browserawait browser.close();// Handle the response based on whether an email is providedif (email) {// Send the email with the screenshot attachment using Nodemailer} else {// Send the screenshot as the responseres.type('image/jpeg');res.send(screenshotBuffer);}});5. 要处理带有截图附件的电子邮件发送,请在
if (email)
块中添加以下代码:
1234567891011121314151617181920212223242526272829303132333435 const nodemailer = require('nodemailer');// Create a transporter using your email service provider's detailsconst transporter = nodemailer.createTransport({service: 'your-email-service-provider',auth: {user: 'your-email@example.com',pass: 'your-email-password',},});// Define the email optionsconst mailOptions = {from: 'your-email@example.com',to: email,subject: 'Web Page Screenshot',text: 'Please find the attached screenshot.',attachments: [{filename: 'screenshot.jpg',content: screenshotBuffer,},],};// Send the emailtransporter.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!');}});请确保将
'your-email-service-provider'
、'your-email@example.com'
和'your-email-password'
替换为您实际的电子邮件服务提供商的详细信息。6. 最后,启动服务器
1 node index.js现在,当您向
https://:3000/screenshot?url={URL}
发送 GET 请求时,服务器将捕获提供的 URL 的屏幕截图。如果还提供了电子邮件地址email={EMAIL}
,服务器将把截图作为电子邮件附件发送,而不是直接返回。请记住根据您的要求处理错误并添加任何必要的错误检查或验证。
就是这样!您现在拥有了一个基本的 REST API 服务器,可以捕获网页截图并选择性地通过电子邮件发送。您可以根据需要进一步增强它。
这是一个非常详细的结果,告诉您如何完成这项编程任务。响应涵盖了所有要求,但您应该注意到,当您在提示中没有明确说明时,ChatGPT 会为您做出一些设计决策,例如使用哪种编程语言。
初次运行时,很难考虑所有细节,但是 ChatGPT 的特性允许您提供后续提示来修改答案,例如:
对于上述问题,我想使用 Python 和 FastAPI 作为 Web 框架,并使用 Selenium 作为浏览器。你能重写这个吗?
ChatGPT 的响应现在变为:
当然!这是使用 Python、FastAPI 作为 Web 框架和 Selenium 作为浏览器自动化改写的解决方案。
1. 安装必要的包。您需要
fastapi
、用于运行服务器的uvicorn
、selenium
以及用于管理 Web 驱动程序的webdriver_manager
。
12 pip install fastapi uvicorn selenium webdriver_manager2. 创建一个名为
main.py
的新文件并导入所需的模块。
1234567891011 from fastapi import FastAPI, HTTPExceptionfrom fastapi.responses import FileResponsefrom pydantic import BaseModelfrom selenium import webdriverfrom webdriver_manager.chrome import ChromeDriverManagerfrom selenium.webdriver.chrome.options import Optionsfrom selenium.common.exceptions import WebDriverExceptionfrom io import BytesIOapp = FastAPI()3. 定义一个请求模型来处理输入数据。
1234 class ScreenshotRequest(BaseModel):url: stremail: str = None4. 创建一个路由来捕获网页截图。
123456789101112131415161718192021222324252627282930 @app.get("/screenshot")async def capture_screenshot(request: ScreenshotRequest):options = Options()options.headless = Truetry:# Set up the Chrome webdriverdriver = webdriver.Chrome(ChromeDriverManager().install(), options=options)driver.set_window_size(1280, 720)# Navigate to the provided URLdriver.get(request.url)# Capture the screenshotscreenshot = driver.get_screenshot_as_png()screenshot_buffer = BytesIO(screenshot)# Close the browserdriver.quit()if request.email:# Send the email with the screenshot attachmentreturn "Screenshot emailed successfully!"else:# Return the screenshot as a responsereturn FileResponse(screenshot_buffer, media_type="image/png")except WebDriverException:raise HTTPException(status_code=400, detail="Failed to capture screenshot.")5. 使用 Uvicorn 启动服务器
1 uvicorn main:app --reload现在,当您向
https://:8000/screenshot?url={URL}
发送 GET 请求时,服务器将捕获提供的 URL 的屏幕截图。如果还提供了电子邮件地址email={EMAIL}
,您可以通过请求中的请记住根据您的要求处理错误并添加任何必要的错误检查或验证。
注意:此解决方案假定您的计算机上已安装 Chrome。如果您使用的是其他浏览器,则需要相应地调整 webdriver。
就是这样!您现在拥有一个使用 Python、FastAPI 和 Selenium 来捕获网页截图并处理可选电子邮件功能的 REST API 服务器。
您可以看到,您在后续提示中没有提供任何不必要的细节,除了引用“上述问题”,但 ChatGPT 可以准确地将 Node.js 实现“翻译”成 Python 并使用您指定的库。
这是一个很棒的结果,尽管您可能仍需要打磨代码。一个例子是浏览器屏幕尺寸肯定会影响网页的渲染方式,但在您的提示中没有指定它应该是可调整的,因此上面的代码是硬编码的。润饰生成代码的另一个潜在原因是捕获其他编码风格问题或添加针对安全考虑的防御性措施。
总之,与用例一样,在提示中提供足够清晰的细节是获得有用响应的关键。在编程任务中,制定以下细节至关重要:
- 目标是什么
- 输入和输出格式是什么
- 程序应使用哪些工具
- 程序可能遇到的不同情况是什么,以及应如何处理这些情况
理解代码和生成代码片段
有时,您不想要编写一个大型程序,而是一个较小的函数。您可以使用与上面类似的提示来要求 ChatGPT 生成一个函数,但您需要指定输出格式,例如函数或类。
确实,您也可以反过来做,即提供代码给 ChatGPT 并要求它用英语解释。这有时很有用,尤其是要解读别人的代码时。让我们看下面的例子:
请解释以下代码的作用
1234567891011121314151617181920212223242526272829303132333435363738 ```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;}```
这个提示非常简单:只有一个关键词,“解释”。但请注意您提供代码的方式:使用反引号遵循 Markdown 的代码围栏语法来引用程序。这有助于区分您的指令和非指令内容。
虽然这段程序不算很长,但 ChatGPT 却非常详尽地解释了这段代码。它还从高层次上识别了意图,即计算矩阵的行列式。响应如下:
您提供的代码是使用拉普拉斯展开式递归计算方阵行列式的实现。
以下是代码功能的逐步分解:
- 函数
det
接受两个参数:指向表示矩阵的二维数组的指针(float** a
)和矩阵的大小(float k
)。- 它声明了一些变量:
s
用于符号,ret
用于行列式值,**b
作为临时矩阵。- 它检查
k
是否等于 1。如果是,这意味着我们已经达到了 1x1 矩阵的基础情况,函数返回矩阵中的单个值,即行列式。- 如果
k
大于 1,它将继续进行计算。- 它为大小为
k
xk
的临时矩阵b
分配内存。- 它将
ret
初始化为 0。- 它进入一个循环,该循环遍历矩阵
a
的第一行的每一列。- 在循环内,它将索引
m
和n
重置为 0。- 它进入一个嵌套循环,该循环遍历矩阵
a
的每个元素。- 在嵌套循环内,它将临时矩阵
b
中位置m
,n
的元素设置为 0。- 它检查当前元素是否不在第一行(
i != 0
)且不在当前列(j != c
)。- 如果元素不在第一行或当前列,它会将矩阵
a
中的值复制到临时矩阵b
的位置m
,n
。- 它根据
b
中下一个元素的位置更新索引m
和n
。- 嵌套循环结束后,它通过递归调用
det
函数(使用临时矩阵b
和大小k - 1
)来计算子矩阵b
的行列式。- 它将子矩阵的行列式乘以符号
s
(交替符号)。- 它将符号
s
乘以 -1,为下一次迭代切换符号。- 它将符号
s
、第一行的元素(a[0][c]
)和子矩阵的行列式的乘积加到运行总和ret
中。- 循环继续到下一列。
- 循环结束后,它释放为临时矩阵
b
的每一行分配的内存。- 它释放为临时矩阵
b
分配的内存。- 最后,它返回计算出的行列式值
ret
。总而言之,该代码通过沿第一行进行拉普拉斯展开,递归地计算方阵的行列式。它使用一个临时矩阵来存储通过排除第一行和选定列获得的子矩阵。递归一直持续到达到 1x1 矩阵的基础情况。
后续改进代码
这段代码乍一看并不容易理解。可能有一种方法可以使其更易于阅读。确实,ChatGPT 在这种情况下可以做得很好,只需一个非常简单的后续提示。
你能重写这段代码使其更清晰并添加注释吗?
这里的关键词是“为了清晰”和“添加注释”。ChatGPT 在响应中提供了以下内容:
当然!这是修改后的代码版本,其中包含解释每个步骤的注释。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 float determinant(float** matrix, int size) {float sign = 1; // Sign of the determinantfloat result = 0; // Determinant valuefloat** submatrix; // Temporary submatrixint i, j, m, n, c; // Loop variables// Base case: 1x1 matrixif (size == 1) {return matrix[0][0];}else {// Allocate memory for the temporary submatrixsubmatrix = (float**)malloc(sizeof(float*) * size);for (i = 0; i < size; i++) {submatrix[i] = (float*)malloc(sizeof(float) * size);}// Calculate the determinantfor (c = 0; c < size; c++) {m = 0;n = 0;// Create the submatrix by excluding the first row and the current columnfor (i = 0; i < size; i++) {for (j = 0; j < size; j++) {submatrix[i][j] = 0;// Copy values to the submatrixif (i != 0 && j != c) {submatrix[m][n] = matrix[i][j];// Update submatrix indicesif (n < (size - 2)) {n++;}else {n = 0;m++;}}}}// Calculate the determinant of the submatrix recursivelyresult += sign * matrix[0][c] * determinant(submatrix, size - 1);// Flip the sign for the next iterationsign *= -1;}// Free the memory allocated for the submatrixfor (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.
这个版本无疑更容易阅读。
此外,您可以要求更多。例如要求捕获代码中的错误或潜在的安全问题。让我们要求 ChatGPT 生成一些单元测试代码。
你能给我一些单元测试用例来确保这个函数能正常工作吗?
无需进一步解释,以下是响应:
当然!以下是一些单元测试用例,用于验证
determinant
函数的正确性。测试用例 1:2x2 矩阵
12345 float matrix1[2][2] = {{2, 3},{1, 4}};float** ptrMatrix1 = (float**)matrix1;float det1 = determinant(ptrMatrix1, 2);// Expected output: 5测试用例 2:3x3 矩阵
123456 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测试用例 3:4x4 矩阵
1234567 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这些测试用例涵盖了不同大小的矩阵(2x2、3x3 和 4x4),并包括正数、负数和零行列式值。通过将计算出的行列式值与预期输出进行比较,您可以验证
determinant
函数是否正常工作。
但很明显,单元测试代码遗漏了一个边缘情况:1x1 矩阵。这表明 ChatGPT 并非总是完美的。您应该只将其用作您的助手,而不是替代品。您应该始终验证结果。
总结
在本博文中,您了解了 ChatGPT 如何帮助您进行编程。它不仅可以在响应您的问题时生成代码,还可以弄清楚您提供的代码的意图。具体来说,您已经了解到:
- 您可以使用 ChatGPT 为您的软件项目生成初始代码,或者为函数生成测试代码。
- 您可以要求 ChatGPT 向您解释代码。
- 您可以使用 ChatGPT 重构和清理代码。
请发送关于 ChatGPT 的完整 PDF 学习资料。
感谢您的建议!如果您注册我们的时事通讯,我们将及时向您通报与 ChatGPT 相关的新内容。
要以一种非常简化的方式使用 LLM 分析源代码,请参阅 https://simonwillison.net/2023/Jun/18/symbex/