学会用 AI帮助您编程-成为你的编程助手
这篇文章分为两部分;开始一个编程项目理解代码并生成函数片段。
面向读者:软件工程师、架构师、IT人士、设计人员等
文章目标:提高我们的工作效率
目录
- 如何让 ChatGPT 引导您的编程项目
- 如何使用 ChatGPT 作为您的编程助手
让我们开始吧。
概述
这篇文章分为两部分;他们是:
- 开始一个编程项目
- 理解代码并生成函数片段
开始一个编程项目
让我们考虑一个简单的项目:您想要设置一个 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 对其进行初始化:
mkdir screenshot-api cd screenshot-api npm init
2. 安装必要的软件包。您需要express
API 服务器puppeteer
来捕获屏幕截图和nodemailer
发送电子邮件:npm install express puppeteer nodemailer
3. 创建index.js
文件并使用 Express 设置基本服务器: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 捕获网页屏幕截图并相应处理响应: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. 要处理发送带有屏幕截图附件的电子邮件,请在块内添加以下代码
if (email)
:const nodemailer = require('nodemailer'); // Create a transporter using your email service provider's details const transporter = nodemailer.createTransport({ service: 'your-email-service-provider', auth: { user: 'your-email@example.com', pass: 'your-email-password', }, }); // Define the email options const 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 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!'); } });
请务必将
'your-email-service-provider'
、'your-email@example.com'
、 和替换'your-email-password'
为您实际的电子邮件服务提供商的详细信息。6.最后启动服务器:
node index.js
现在,当您向 发出 GET 请求时http://localhost:3000/screenshot?url={URL}
,服务器将捕获所提供 URL 的屏幕截图。如果还提供了电子邮件地址email={EMAIL}
,服务器会将屏幕截图作为电子邮件附件发送,而不是直接返回。请记住根据您的要求处理错误并添加任何必要的错误检查或验证。
就是这样!您现在拥有一个基本的 REST API 服务器,可以捕获网页屏幕截图并可以选择通过电子邮件发送它们。请随意根据您的需要进一步增强它。
这是一个非常详细的结果,告诉您如何完成此编程任务。响应涵盖了所有要求,但您应该注意到,当您没有在提示中明确指定时,ChatGPT 将为您做出一些设计决策,例如使用哪种编程语言。
第一次运行时考虑到所有细节并不容易,但 ChatGPT 的性质允许您提供后续提示以修改答案,例如:
对于上述问题,我想使用Python和FastAPI作为Web框架,并使用Selenium作为Web浏览器。你能重写这个吗?
ChatGPT 的响应现在变为:
当然!这是该解决方案的修订版本,使用 Python、FastAPI 作为 Web 框架,以及 Selenium 用于 Web 浏览器自动化。
1. 安装必要的软件包。您需要
fastapi
,uvicorn
来运行服务器,selenium
,webdriver_manager
来管理网络驱动程序:pip install fastapi uvicorn selenium webdriver_manager
2. 创建一个名为 的新文件main.py
并导入所需的模块: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. 定义请求模型来处理输入数据:
class ScreenshotRequest(BaseModel): url: str email: str = None
4、创建网页截图的路由:
@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.使用Uvicorn启动服务器:
uvicorn main:app --reload
现在,当您向 发出 GET 请求时http://localhost:8000/screenshot?url={URL},服务器将捕获所提供 URL 的屏幕截图。如果还提供了电子邮件地址,您可以使用请求中的字段email={EMAIL}处理发送带有屏幕截图附件的电子邮件。email
请记住根据您的要求处理错误并添加任何必要的错误检查或验证。
注意:此解决方案假设您的计算机上安装了 Chrome。如果您使用不同的浏览器,则需要相应地调整网络驱动程序。
就是这样!您现在拥有一个使用 Python、FastAPI 和 Selenium 的 REST API 服务器来捕获网页屏幕截图并处理可选的电子邮件功能。
您可以看到,除了提到“上述问题”之外,您没有在后续提示中提供任何不必要的细节,但 ChatGPT 可以准确地将 Node.js 实现“翻译”为 Python 并使用您指定的库。
这是一个非常棒的结果,尽管您可能仍然需要完善代码。一个例子是,浏览器屏幕大小肯定会影响网页的呈现方式,但在上面的大小是硬编码的,因为您没有指定它应该在提示中调整。完善生成的代码的另一个潜在原因是捕获其他编码风格问题或针对安全问题添加防御措施。
总之,与其他用例一样,在提示中足够清晰地输入更多详细信息是获得有用响应的关键。在编程任务的情况下,布置细节至关重要
- 目标是什么
- 输入输出格式是什么
- 程序应该使用哪些工具
- 程序可能会遇到哪些不同的情况以及这些情况应该如何处理
理解代码并生成函数片段
有时,您想要编写的不是一个大程序,而是一个较小的函数。您可以使用类似于上面的提示要求 ChatGPT 为您生成一个函数,但您需要指定输出格式,例如函数或类。
事实上,你也可以反过来,即向 ChatGPT 提供代码并要求其用英文解释。它有时很有用,特别是在破译别人的代码时。让我们考虑以下示例:
请解释以下代码的作用:
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 非常详细地解释了代码。它还确定了高层的意图,即计算矩阵的行列式。以下是回应:
您提供的代码是使用拉普拉斯展开计算方阵行列式的递归实现。
以下是代码功能的逐步细分:
- 该函数
det
采用两个参数:指向表示矩阵的二维数组 (float** a
) 的指针和矩阵的大小 (float k
)。- 它声明了一些变量:
s
用于符号、ret
用于行列式值以及**b
作为临时矩阵。- 它检查是否
k
等于 1。如果是,则意味着我们已经达到 1×1 矩阵的基本情况,并且该函数返回矩阵中的单个值,即行列式。- 如果
k
大于1,则继续计算。b
它为大小为k
x 的临时矩阵动态分配内存k
。- 它初始化
ret
为0。- 它进入一个循环,迭代矩阵第一行的每一列
a
。- 在循环内,它将索引
m
和重置n
为 0。- 它进入一个嵌套循环,迭代矩阵的每个元素
a
。b
在嵌套循环内,它将临时矩阵中位置m
,处的元素设置n
为 0。- 它检查当前元素是否不在第一行 (
i != 0
) 且不在当前列 (j != c
) 中。- 如果该元素不在第一行或当前列中,则会将值从矩阵复制到位置 , 处的
a
临时矩阵。b
m
n
m
它根据n
中下一个元素的位置更新索引b
。- 嵌套循环之后,它通过使用临时矩阵和 size
b
递归调用该函数来计算子矩阵的行列式。det
b
k - 1
- 它将子矩阵的行列式乘以符号
s
(交替符号)。- 它将符号
s
乘以 -1 以切换下一次迭代的符号。- 它将符号、第一行中的元素 (
a[0][c]
) 以及子矩阵的行列式的乘积添加到运行和 中ret
。- 循环继续到下一列。
- 循环结束后,它释放为临时矩阵的每一行分配的内存
b
。- 它释放为临时矩阵分配的内存
b
。- 最后,它返回计算出的行列式值
ret
。总之,代码通过沿第一行执行拉普拉斯展开来递归计算方阵的行列式。它使用一个临时矩阵来存储排除第一行和所选列得到的子矩阵。递归继续直到到达 1×1 矩阵的基本情况。
后续改进代码
这段代码乍一看不太容易理解。可能有一种方法可以让它更容易阅读。确实,ChatGPT 在这种情况下可以做得很好,只需一个非常简单的后续提示:
为了清晰起见,您可以重写此代码并添加注释吗?
这里的关键词是“为了清晰起见”和“添加评论”。ChatGPT 提供以下响应:
当然!这是代码的修订版本,其中包含解释每个步骤的注释:
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: 1x1 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; } }
我在代码的每个重要部分上方添加了注释来解释它的作用。这应该使代码更具可读性和更容易理解。
这个版本无疑更容易阅读。
此外,你还可以要求更多。例如要求捕获代码中的错误或潜在的安全问题。让我们要求 ChatGPT 生成一些单元测试代码:
你能给我一些单元测试用例来确保这个功能运行良好吗?
不需要任何进一步的解释,以下是响应:
当然!下面是几个单元测试用例来验证函数的正确性
determinant
:测试用例 1:2×2 矩阵
float matrix1[2][2] = {{2, 3}, {1, 4}}; float** ptrMatrix1 = (float**)matrix1; float det1 = determinant(ptrMatrix1, 2); // Expected output: 5
测试用例2:3×3矩阵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矩阵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 并不总是完美的。您只能将其用作您的助手,而不是替代品。您应该始终验证结果。
概括
在这篇文章中,您了解了 ChatGPT 如何帮助您进行编程。它不仅可以生成代码作为对您的问题的响应的一部分,而且还可以弄清楚您提供的代码的意图。具体来说,您已经了解到:
- 您可以使用 ChatGPT 生成软件项目的初始代码,或生成功能的测试代码
- 您可以要求 ChatGPT 向您解释代码
- 您可以利用 ChatGPT 来重构和清理代码
更多推荐
所有评论(0)