大型语言模型基本上是一台可以理解和生成文本的机器。取决于它的训练方式,有时模型可以生成文本以外的内容。ChatGPT就是这样一个大型语言模型。如果您正确提示,它可以生成编程代码。在这篇文章中,您将学习如何使 ChatGPT 为您生成程序。
概述
这篇文章分为两部分;它们是:
- 启动编程项目
- 了解代码和生成函数片段
启动编程项目
让我们考虑一个简单的项目:你想要设置一个 REST API 服务器,它可以帮助你对提供的 URL 的整个网页进行“屏幕截图”。(可选)REST API 可以接受电子邮件地址的其他可选参数。在这种情况下,屏幕捕获不会返回,而是通过电子邮件发送出去。
这是一个涉及多个组件的项目。你需要一些可以像 REST API 服务器一样监听 HTTP 请求并做出相应响应的东西。您还需要一些东西来获取 URL 并像普通 Web 浏览器一样截取屏幕截图。其中还有一个逻辑,取决于是否提供了电子邮件地址;输出可以是返回的图像文件,也可以是发送带有附件的电子邮件。
如果您不熟悉如何创建 REST API 服务器或不知道可用的工具,可以向 ChatGPT 寻求帮助。只需在提示中写下所有细节并询问:
我需要创建一个 REST API 服务器,该服务器接受 URL 作为输入,将网页屏幕截图捕获为 JPEG 格式并将其作为输出返回。(可选)用户可以提供电子邮件地址作为附加输入。在这种情况下,屏幕截图应通过电子邮件发送而不是返回。你能帮我这个程序吗?
有了这个,ChatGPT产生以下建议:
当然!我可以帮你。要创建捕获网页屏幕截图并处理可选电子邮件功能的 REST API 服务器,您可以使用 Node.js以及一些其他包。以下是您可以遵循的步骤的概述:
1. 设置一个新的 Node.js 项目并使用 npm 对其进行初始化:
123 mkdir screenshot-apicd screenshot-apinpm init2. 安装必要的软件包。您需要 API 服务器、捕获屏幕截图和发送电子邮件:
express
puppeteer
nodemailer
1 npm install express puppeteer nodemailer3. 使用 Express 创建文件并设置基本服务器:
index.js
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. 在路由内,使用 Puppeteer 捕获网页截图并相应地处理响应:
/screenshot
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现在,当您向 发出 GET 请求时,服务器将捕获所提供 URL 的屏幕截图。如果电子邮件地址也作为 提供,服务器会将屏幕截图作为电子邮件附件发送,而不是直接返回。
http://localhost:3000/screenshot?url={URL}
email={EMAIL}
请记住处理错误,并根据您的要求添加任何必要的错误检查或验证。
就是这样!您现在有一个基本的 REST API 服务器,该服务器可以捕获网页屏幕截图并选择性地通过电子邮件发送它们。请随时根据您的需要进一步增强它。
这是一个非常详细的结果,告诉您如何完成此编程任务。响应涵盖了所有要求,但您应该注意到,当您没有在提示中明确指定时,ChatGPT 将为您做出一些设计决策,例如使用哪种编程语言。
在第一次运行时考虑所有细节并不容易,但 ChatGPT 的性质允许您提供后续提示来修改答案,例如:
对于上述问题,我想使用Python和FastAPI作为Web框架,Selenium作为Web浏览器。你能重写这个吗?
来自 ChatGPT 的响应现在变为:
当然!以下是该解决方案的修订版本,使用Python,FastAPI作为Web框架,Selenium用于Web浏览器自动化。
1. 安装必要的软件包。您需要 来运行服务器和管理 Web 驱动程序:
fastapi
uvicorn
selenium
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现在,当您向 发出 GET 请求时,服务器将捕获所提供 URL 的屏幕截图。如果电子邮件地址也以 形式提供,则可以使用请求中的字段处理发送带有屏幕截图附件的电子邮件。
http://localhost:8000/screenshot?url={URL}
email={EMAIL}
请记住处理错误,并根据您的要求添加任何必要的错误检查或验证。
注意:此解决方案假定您的计算机上安装了 Chrome。如果您使用的是其他浏览器,则需要相应地调整网络驱动程序。
就是这样!您现在有一个使用 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;}```
这个提示很简单:只有一个关键字,“解释”。但请注意如何向 ChatGPT 提供代码:反引号的使用遵循 Markdown 的代码围栏语法来引用程序。这有助于确定哪些是您的指令,哪些不是。
虽然这不是一个很长的程序,但 ChatGPT 非常详细地解释了代码。它还在高层次上确定了意图,即计算矩阵的行列式。以下是响应:
您提供的代码是使用拉普拉斯展开计算方阵行列式的递归实现。
以下是代码功能的分步细分:
- 该函数采用两个参数:指向表示矩阵的 2D 数组 () 和矩阵大小的指针 ()。
det
float** a
float k
- 它声明了一些变量:符号、行列式值和临时矩阵。
s
ret
**b
- 它检查是否等于 1。如果是这样,则意味着我们已经达到了 1×1 矩阵的基本情况,并且该函数返回矩阵中的单个值,这是行列式。
k
- 如果大于 1,则继续计算。
k
- 它为大小为 x 的临时矩阵动态分配内存。
b
k
k
- 它初始化为 0。
ret
- 它进入一个循环,循环遍历矩阵第一行的每一列。
a
- 在循环内部,它将索引重置为 0。
m
n
- 它进入一个嵌套循环,该循环遍历矩阵的每个元素。
a
- 在嵌套循环中,它将临时矩阵中位置 的元素设置为 0。
b
m
n
- 它检查当前元素是否不在第一行 () 中,也不在当前列 () 中。
i != 0
j != c
- 如果元素不在第一行或当前列中,它将值从矩阵复制到位置 ,的临时矩阵。
a
b
m
n
- 它更新索引,并根据下一个元素在 中的位置。
m
n
b
- 在嵌套循环之后,它通过使用临时矩阵和大小递归调用函数来计算子矩阵的行列式。
b
det
b
k - 1
- 它将子矩阵的行列式乘以符号(交替符号)。
s
- 它将符号乘以 -1 以将符号切换为下一次迭代。
s
- 它将符号的乘积、第一行 () 中的元素和子矩阵的行列式添加到运行和中。
a[0][c]
ret
- 循环继续到下一列。
- 循环后,它释放为临时矩阵的每一行分配的内存。
b
- 它释放了为临时矩阵分配的内存。
b
- 最后,它返回计算出的行列式值。
ret
总之,该代码通过沿第一行执行拉普拉斯展开来递归计算方阵的行列式。它使用临时矩阵来存储通过排除第一行和所选列获得的子矩阵。递归一直持续到达到 1×1 矩阵的基数。
跟进以改进代码
乍一看,这段代码并不容易理解。可能有一种方法可以使其更易于阅读。事实上,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;}}我在代码的每个重要部分上方添加了注释,以解释它的作用。这应该使代码更具可读性和更易于理解。
这个版本无疑更容易阅读。
此外,您可以要求更多。例如要求捕获代码中的错误或潜在的安全问题。让我们让 ChatGPT 生成一些单元测试代码:
你能给我几个单元测试用例来确保这个函数运行良好吗?
不需要任何进一步的解释,以下是响应:
当然!以下是一些单元测试用例,用于验证函数的正确性:
determinant
测试用例 1:2×2 矩阵
12345 float matrix1[2][2] = {{2, 3},{1, 4}};float** ptrMatrix1 = (float**)matrix1;float det1 = determinant(ptrMatrix1, 2);// Expected output: 5测试用例 2:3×3 矩阵
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:4×4 矩阵
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这些测试用例涵盖不同大小(2×2、3×3 和 4×4)的矩阵,并包括正、负和零行列式值。通过将计算出的行列式值与预期输出进行比较,可以验证函数是否正常工作。
determinant
但很明显,单元测试代码遗漏了一个极端情况:1×1 矩阵。这表明ChatGPT并不总是完美的。您应该仅将其用作助手,而不应将其用作替代品。您应始终验证结果。
学习分享,感谢Adrian Tam知识分享,感谢Dear_MrJack的学习分享