likes
comments
collection
share

大漠老师ChatGPT说你犯了99个错误,可我还是你的爱豆

作者站长头像
站长
· 阅读数 33

牙叔教程 简单易懂

好评如潮

大漠老师ChatGPT说你犯了99个错误,可我还是你的爱豆

但是来喽,

课程里面有一些微不足道的错误, 趁着ChatGPT的热度,

我来道一道, 大漠老师文章里的小错误,

底部有本文的代码仓库链接


流程图草稿

大漠老师ChatGPT说你犯了99个错误,可我还是你的爱豆

由于ChatGPT直接手文字, 所以我把这个流程图用文字描述一下

ChatGPT生成项目目录

prompt提示语

ChatGPT生成的目录

爬课程目录

由于是付费课程, 所以肯定要Cookie, 因此我的prompt是这样的

ChatGPT回答

这里涉及到一点爬虫的知识, 找目录链接之类的知识, 打开开发者, 一个一看看就找出来了,

我不会提供url, 爬虫有风险, 你们懂的

这是我修改后的代码

const axios = require("axios");
const config = require("./config");
async function getDir() {
  const url = config.url.目录;
  const headers = config.headers.目录;
  let res = await axios.post(
    url,
    {
      booklet_id: "7161370789680250917",
    },
    {
      headers: headers,
    }
  );
  const sections = res.data.data.sections;
  console.log(sections[0]);
  return res;
}
getDir();

至此我们获取到了目录

{
  id: 88871,
  section_id: '7161370789768347685',
  title: 'Web 布局技术演进:了解 Web 布局发展史 ',
  user_id: '1908407916041614',
  booklet_id: '7161370789680250917',
  status: 1,
  content: '',
  draft_content: '',
  draft_title: 'Web 布局技术演进:了解 Web 布局发展史 ',
  markdown_content: '',
  markdown_show: '',
  is_free: 1,
  read_time: 1786,
  read_count: 9234,
  comment_count: 38,
  ctime: 1667444849,
  mtime: 1667444849,
  is_update: 0,
  draft_read_time: 0,
  vid: '',
  reading_progress: {
    id: 0,
    booklet_id: '7161370789680250917',
    user_id: '2295436007442622',
    section_id: '7161370789768347685',
    reading_end: 0,
    reading_progress: 97,
    reading_position: 0,
    has_update: 1,
    last_rtime: 1669955278,
    ctime: 1669888750,
    mtime: 1669952433
  }
}

和网页内容比对一下, 是正确的

大漠老师ChatGPT说你犯了99个错误,可我还是你的爱豆

爬取第一篇文章

这是文章对应的属性

大漠老师ChatGPT说你犯了99个错误,可我还是你的爱豆

我们要以下属性

  • title 用来保存错误的文件名
  • markdown_show 文章正文

代码, 和上面一模一样, 只是字段不一样;

瞧这代码, 基本没变

async function getFirst() {
  const url = config.url.first;
  const headers = config.headers.first;
  let res = await axios.post(
    url,
    {
      section_id: "7161370789768347685",
    },
    {
      headers: headers,
    }
  );
  const section = res.data.data.section;
  console.log(section);
  return res;
}

下载所有文章

如果网络发生错误, 或者其他异常, 我们要重启程序;

还要再爬一遍数据, 所以我们先把文章都下载下来, 这样就不用再次下载了,

一次下载, 终身使用

这里其实不需要prompt, 但是我还是要用它, 就是这么有鸟性

prompt 请教ChatGPT如何批量下载文章

我要下载一个课程中的所有章节
提取课程的目录信息的代码是这样的
```
async function getDir() {
  const url = config.url.目录;
  const headers = config.headers.目录;
  let res = await axios.post(
    url,
    {
      booklet_id: "7161370789680250917",
    },
    {
      headers: headers,
    }
  );
  const sections = res.data.data.sections;
  return sections;
}
```
sections里面保存的是目录信息,
sections是一个数组, 数组中都是对象, 数组的内容如下
```
[
          {
              "id": 88871,
              "section_id": "7161370789768347685",
              "title": "Web 布局技术演进:了解 Web 布局发展史 ",
              "user_id": "1908407916041614",
              "booklet_id": "7161370789680250917",
              "status": 1,
              "content": "",
              "draft_content": "",
              "draft_title": "Web 布局技术演进:了解 Web 布局发展史 ",
              "markdown_content": "",
              "markdown_show": "",
              "is_free": 1,
              "read_time": 1786,
              "read_count": 9234,
              "comment_count": 38,
              "ctime": 1667444849,
              "mtime": 1667444849,
              "is_update": 0,
              "draft_read_time": 0,
              "vid": "",
          },
          ...
]

```
我们要提取的目录中每个章节的以下属性
- section_id
- title

提取到所有章节的属性以后, 我们要开始获取所有的文章数据,
获取文章数据的代码是这样的
```
async function getSection(section_id) {
  const url = config.url.first;
  const headers = config.headers.first;
  let res = await axios.post(
    url,
    {
      section_id: section_id
    },
    {
      headers: headers,
    }
  );
  const section = res.data.data.section;
  return section;
}
```
获取到的section是一个对象, 内容一般是这样的
```
{
            "title": "Flexbox 中的计算:通过扩展因子比例来扩展 Flex 项目",
            "markdown_show": "文章的正文..."
}

```
获取到section以后, 我们要保存数据到本地,
文件的数量由之前的, 从目录获取章节的数量决定,
每个章节的正文, 就是section的字段markdown_show的值,
我们要保存每个章节的内容,到一个指定的文件夹, 文件夹名字是sections
文件的名字是section的字段title的值, 记住要去掉title的值的所有特殊符号, 因为文件名不能含有特殊符号, 比如空格, 冒号等特殊字符;

现在请你编写程序, 下载课程所有的章节,
使用语言: Node.js

ChatGPT的回答

首先需要安装axios和fs模块,可以使用以下命令进行安装:

Copy
npm install axios fs
然后可以编写代码:

Copy
const axios = require('axios');
const fs = require('fs');
const sanitize = require("sanitize-filename");

const config = {
  url: {
    目录: 'https://www.xxx.com/api/booklet/sections',
    first: 'https://www.xxx.com/api/section/first',
  },
  headers: {
    目录: {
      'Content-Type': 'application/json;charset=UTF-8',
      'Cookie': 'xxx'
    },
    first: {
      'Content-Type': 'application/json;charset=UTF-8',
      'Cookie': 'xxx'
    }
  }
};

async function getDir() {
  const url = config.url.目录;
  const headers = config.headers.目录;
  let res = await axios.post(
    url,
    {
      booklet_id: "7161370789680250917",
    },
    {
      headers: headers,
    }
  );
  const sections = res.data.data.sections;
  return sections;
}

async function getSection(section_id) {
  const url = config.url.first;
  const headers = config.headers.first;
  let res = await axios.post(
    url,
    {
      section_id: section_id
    },
    {
      headers: headers,
    }
  );
  const section = res.data.data.section;
  return section;
}

async function downloadCourse() {
  const sections = await getDir();
  const dirPath = './sections';
  if (!fs.existsSync(dirPath)) {
    fs.mkdirSync(dirPath);
  }
  for (let i = 0; i < sections.length; i++) {
    const section = await getSection(sections[i].section_id);
    const filename = sanitize(sections[i].title) + '.md';
    fs.writeFileSync(dirPath + '/' + filename, section.markdown_show);
    console.log('Downloaded: ' + filename);
  }
}

downloadCourse();
在代码中,首先通过调用getDir函数获取课程的目录信息,然后创建一个名为sections的文件夹用于保存所有的章节文件。

接着使用一个循环遍历每个章节,通过调用getSection函数获取章节的具体内容,将获取到的内容保存到本地的文件中。

在保存文件时,需要使用sanitize-filename模块对文件名进行处理,去除所有的特殊符号,保证文件名的合法性。

最后运行downloadCourse函数即可开始下载课程所有的章节。

大漠老师ChatGPT说你犯了99个错误,可我还是你的爱豆

  • 我都没有给ChatGPT说我的config字段的配置是什么, 他自己就推测出来了,Oh my God
  • sanitize-filename, 这又是啥? 我都没见过, 就问你服不服气? 我是服了

我们来执行以下他给的代码, 我略加修改, 运行看效果

$ npm run main

> my-project@1.0.0 main
> node src/main.js

Downloaded: Web 布局技术演进:了解 Web 布局发展史.md
Downloaded: 现代 Web 布局技术术语.md
Downloaded: Flexbox 布局基础使用.md
Downloaded: Flexbox 布局中的对齐方式.md
Downloaded: Flexbox 布局中的 flex 属性的基础运用.md
Downloaded: Flexbox 中的计算:通过扩展因子比例来扩展 Flex 项目.md
Downloaded: Flexbox 中的计算:通过收缩因子比例收缩 Flex 项目.md
Downloaded: Flexbox 布局中的 flex-basis:谁能决定 Flex 项目的大小?.md
Downloaded: 使用 Flexbox 构建经典布局:10 种经典 Web 布局.md
Downloaded: Grid 布局的基础知识.md
Downloaded: 定义一个网格布局.md
Downloaded:  Grid 布局中的计算.md
Downloaded: 可用于 Grid 布局中的函数.md
Downloaded: 网格项目的放置和层叠.md
Downloaded: Grid 布局中的对齐方式.md
Downloaded: 网格布局中的子网格和嵌套网格.md
Downloaded: 使用子网格构建 Web 布局.md
Downloaded: 使用 Grid 构建经典布局:10 种经典布局.md
Downloaded: 使用 Grid 构建创意性 Web 布局.md
Downloaded: Flexbox or Grid:如何选择合适的布局?.md
Downloaded: display:contents 改变 Flexbox 和 Grid 布局模式.md
Downloaded: Web 中的向左向右:Flexbox 和 Grid 布局中的 LTR 与 RTL.md
Downloaded: Web 中的向左向右:Web 布局中 LTR 切换到 RTL 常见错误.md
Downloaded: 内在 Web 设计.md
Downloaded: 创建不规则 Web 布局.md
Downloaded: 如何构建响应式 UI?.md
Downloaded: 下一代响应式 Web 设计:组件式驱动式 Web 设计.md
Downloaded: 下一代响应式 Web 设计:容器查询.md

大漠老师ChatGPT说你犯了99个错误,可我还是你的爱豆大漠老师ChatGPT说你犯了99个错误,可我还是你的爱豆

没有一点点错误, 执行以后, 完全达到了我想要的效果,

数据已经搞下来了, 接下来就开始找大漠老师的文章中的错误了

找大漠老师的错误

构造prompt, 让ChatGPT找文章的错误

在本地有一个文件夹sections, 里面是markdown文件, 你要遍历sections中的所有markdown文件, 找出文章中的错误;

找每篇文章的错误的步骤:
1. 从sections中读取markdown文件内容, 比如:  Grid 布局中的计算.md
2. 通过https://api.openai.com/v1/chat/completions 接口, 传入markdown文件内容, 得到返回结果
3. 把返回的结果中的文本字段保存到文件夹errors中,  文件名就是你读取的那个文件的名字, 比如: Grid 布局中的计算.md

以上是找错误的大概步骤, 下面有一些注意事项
1. 由于completions 接口有次数限制, 每次的问题和答案都不能超过1024个字符, 所以你要把markdown文件内容分段, 每段最多1024个字符, 一共分成几段, 然后每段都调用一次completions 接口, 把返回的结果都保存到errors文件夹中
2. 你给completions 接口提交数据的时候, 要指示ChatGPT返回的格式, 格式要求如下:
   1. 返回的必须是markdown格式的内容
   2. 必须包含4个标题, 分别是: 错误所在的文件名, 错误的所在的段落, 错误的理由, 改正错误的方法
以上是我想到的, 你可以自己再想想, 有什么要补充的你可以补充, 在符合我的要求的情况下, 你可以自己决定怎么做

现在, 请你用Nodejs写代码, 完成以上要求.

ChatGPT的回答

首先需要安装axios和fs模块,可以使用以下命令进行安装:

Copy
npm install axios fs
然后可以编写代码:

Copy
const axios = require('axios');
const fs = require('fs');
const sanitize = require('sanitize-filename');

const config = {
  url: 'https://api.openai.com/v1/chat/completions',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY',
  },
};

async function findErrors() {
  const dirPath = './sections';
  const errorsPath = './errors';
  if (!fs.existsSync(errorsPath)) {
    fs.mkdirSync(errorsPath);
  }
  const files = fs.readdirSync(dirPath);
  for (let i = 0; i < files.length; i++) {
    const filePath = dirPath + '/' + files[i];
    if (fs.statSync(filePath).isFile()) {
      const content = fs.readFileSync(filePath, 'utf-8');
      const chunks = splitContent(content);
      let errors = '';
      for (let j = 0; j < chunks.length; j++) {
        const result = await getCompletions(chunks[j]);
        if (result.choices.length > 0) {
          const text = result.choices[0].text;
          const errorText = generateErrorText(files[i], chunks[j], text);
          errors += errorText + '\n\n';
        }
      }
      if (errors !== '') {
        const filename = sanitize(files[i]);
        fs.writeFileSync(errorsPath + '/' + filename, errors);
        console.log('Found errors in: ' + filename);
      }
    }
  }
}

function splitContent(content) {
  const chunks = [];
  const lines = content.split('\n');
  let chunk = '';
  for (let i = 0; i < lines.length; i++) {
    if (chunk.length + lines[i].length + 1 <= 1024) {
      chunk += lines[i] + '\n';
    } else {
      chunks.push(chunk);
      chunk = lines[i] + '\n';
    }
  }
  if (chunk !== '') {
    chunks.push(chunk);
  }
  return chunks;
}

async function getCompletions(prompt) {
  const data = {
    prompt: prompt,
    max_tokens: 1024,
    temperature: 0.7,
    n: 1,
    stop: '\n',
    format: 'markdown',
  };
  const res = await axios.post(config.url, data, { headers: config.headers });
  return res.data;
}

function generateErrorText(filename, chunk, text) {
  const errorText = '## 文件名\n\n' + filename + '\n\n' +
    '## 段落\n\n' + chunk + '\n\n' +
    '## 错误原因\n\n' + text + '\n\n' +
    '## 改正方法\n\n';
  return errorText;
}

findErrors();
在代码中,首先通过调用fs.readdirSync函数获取sections文件夹中的所有文件,然后循环遍历每个文件,读取其内容并将内容分成多个段落。

接着,调用getCompletions函数将每个段落提交给ChatGPT,获取返回结果中的文本,并使用generateErrorText函数将文件名、段落、错误原因和改正方法组合成错误文本。

将所有的错误文本组合成一个字符串,如果该字符串不为空,则将其保存到errors文件夹中,文件名与原文件名相同。

在调用getCompletions函数时,需要指定ChatGPT返回的格式为markdown格式,并且包含4个标题,分别是错误所在的文件名、错误的所在的段落、错误的理由和改正错误的方法。

注意,由于ChatGPT有次数限制,每次提交的数据不能超过1024个字符,因此需要将文章内容分成多个段落,并分别提交给ChatGPT。

最后运行findErrors函数即可开始查找所有文章中的错误,并将错误信息保存到本地的文件中。

这个代码也要略加修改才能用, 尤其要注意的一点是

max_tokens: 1024

这个限制的是chatgpt响应的tokens, 不包括你的prompt, 也就是你给chatgpt提出的问题;

但是,

总的字数是4096 tokens, 因此你这里如果过写3000, 那么你的问题就最多写1096,

再次但是,

prompt, 也就是问题, 你是可以控制的, chatgpt返回的值你控制不了,

因此, 为了尽可能的给chatgpt的回答, 提供足够的tokens, 我们的提问的字数应该尽量少一些;

代码里的错误

async function getCompletions(prompt) {
  const data = {
    prompt: prompt,
    max_tokens: 1024,
    temperature: 0.7,
    n: 1,
    stop: '\n',
    format: 'markdown',
  };
  const res = await axios.post(config.url, data, { headers: config.headers });
  return res.data;
}

他这个api已经更新了, 但是chatgpt的库中的数据还没更新, 还是老接口, 这个接口要自己改一下

const data = {
  model: "gpt-3.5-turbo",
  messages: [{ role: "user", content: role + prompt + suffix }],
  temperature: 0.7,
  max_tokens: 3000,
  top_p: 1,
  frequency_penalty: 0,
  presence_penalty: 0,
  stream: false,
};
const res = await axios.post("https://api.openai.com/v1/chat/completions", data, {
  headers: config.headers.chatgpt,
  httpsAgent: agent,
});
return res.data.choices[0].message.content;

由于ChatGPT有字数限制, 因此我们把文章拆开了, 一小段一小段的纠错,

prompt用于文章纠错

const role = `
现在给你看一篇文章, 如果文章里面有错误, 请你把它指出来,
你要按照以下要求回复内容:
1. 生成的回复内容长度禁止超过1500个字, 如果超出了, 后面的内容丢弃, 此条规则, 优先级最高;
2. 返回的必须是markdown格式的内容
3. 必须包含这些标题, 分别是: 错误所在的段落, 错误的理由, 改正错误的方法
4. 其中, 标题为"错误误所在的段落", 写段落中的10个字即可
分割线后面是你要分析的文章内容, 请你分析文章, 并且把错误指出来, 并且按照我的要求回复.
-----------------------------------------------------------------------
`;

ChatGPT的回答

# 错误所在的段落
第二段

# 错误的理由
错误地描述了CSS的writing-modedirectionHTML的dir对Flexbox布局中对齐属性的影响。

# 改正错误的方法
CSS的writing-modedirectionHTML的dir对Flexbox布局中对齐属性并没有影响,它们只是影响Web排版的方向。因此,应该将描述修改为:在Flexbox布局中,对齐属性都会受到flex-direction属性的影响,其中justify-属性始终用于在主轴上对齐,align-属性始终用于在侧轴上对齐。

无限等待

接下来就交给chatgpt, 批量查找文章的错误了,

api缓慢运行中, 大概过了很久, 很久, long, long, ago

大漠老师ChatGPT说你犯了99个错误,可我还是你的爱豆

刺客深深的体会到了, 什么叫做慢, 都运行几个小时了, 还没跑完, 早知道, 我就去找个速度快的接口, 向chargpt提问了, 现在这个特别慢, 😭

...

又过了很久, 终于跑完了😄

大漠老师ChatGPT说你犯了99个错误,可我还是你的爱豆

展示几个微小的错误

他说大漠老师的CSS写的不规范, 我不要你觉得, 我要我觉得,

我觉得大漠老师写的CSS老棒了, 是我的100倍

## 错误所在的段落
第一段

## 错误的理由
文中的CSS代码存在一些语法错误和不规范的写法。

## 改正错误的方法
1. 文中的 `container-type: inline-size;` 应该改为 `contain: inline-size;`,正确的写法是 `contain`。
2. 文中在 `.card` 样式中设置 `border-radius: 0;`,然后在 `@container` 中再设置 `border-radius: 8px;`,这样不够简洁。可以将 `.card` 样式的 `border-radius` 放到 `:root` 中定义一个变量,然后在 `@container` 中使用 `clamp()` 函数改变变量的值,再使用变量设置 `border-radius`,这样更加简洁规范。

更正后的代码如下:

```
:root { 
    --w: 760px; 
    --max-radius: 8px; 
    --min-radius: 0px; /* 这里的单位不能省略 */ 
    --radius: calc(100vw - var(--w)); 
    --responsive-radius: clamp(var(--min-radius), var(--radius), var(--max-radius)); 
    --card-radius: 0; /* 定义卡片的圆角 */
} 

.card { 
    border-radius: var(--card-radius); /* 使用定义好的变量 */
} 

@container (width > 700px) { 
    :root { 
        --card-radius: var(--max-radius); /* 使用clamp()函数改变变量的值 */
    } 
}
```

修改后的代码更加规范,也更加清晰易懂。

这个说大漠老师命令不规范

### 错误所在的段落
第二段

### 错误的理由
该段代码中的命名方式不规范,容易混淆和出错。

### 改正错误的方法
统一使用小写字母和连字符来命名,同时遵循语义化命名规则,使命名更加清晰易懂。

修改后的代码如下:

```CSS
.title {
    grid-area: title;
}

.aside {
    grid-area: aside;
}

.main {
    grid-area: main;
}

.banner {
    grid-area: banner;
}

.fig-1 {
    grid-area: fig-1;
}

.fig-2 {
    grid-area: fig-2;
}
```

同时,在CSS中使用BEM命名规范或其他命名规范可以进一步提高代码的可读性和可维护性。

大漠老师用词不准

## 错误所在的段落

第一段

## 错误的理由

该段落中的用语不准确,存在歧义和语病。

## 改正错误的方法

1. 将“受众”改为“用户”更加准确和通俗易懂;
2. “受众”与“一个人”并不是完全对立的关系,可以改为“我们将更加注重用户个性化需求,提供更好的内容和体验。”;
3. “Web 真正的可移植”不太准确,可以改为“使得网站在各种设备上均可正常显示和使用”。

修改后的文章如下:

我们不再是为用户群体设计。我们对 "用户"一词的理解将发生变化,因为我们将更加注重用户个性化需求,提供更好的内容和体验。 组件驱动的响应式 Web 设计将使得网站在各种设备上均可正常显示和使用,并能适应甚至还没有发明的设备。与其在今天的技术范围内追赶和设计,我们将只为用户设计。

这种就不是错误了, 可能是提交给ChatGPT的字数太少, 上下文信息不足, 导致了ChatGPT的误判

## 错误所在的段落

第二段

## 错误的理由

文章中错误地将 `inline` 写成了 `inline-flex`

## 改正错误的方法

将错误的 `inline-flex` 改为正确的 `inline` 即可。正确的句子为:

只需要在 HTML 元素上显式设置 `display` 的值为 `flex``inline` 即可。

到这里基本就完成了我最初的想法, 其中最大的问题是ChatGPT的接口太慢了, 大家如果要做这种批量的操作,

一定要先找到速度够快的ChatGPT渠道

我只爬了大漠老师的一个小册啊, 🙀

大漠老师ChatGPT说你犯了99个错误,可我还是你的爱豆

本文代码仓库

码云: gitee.com/yashujs/art…

github: github.com/steelan9199…

Git小技巧

如果你要删除远端的文件夹或者文件, 并且保留本地的文件, 按照这个步骤做

1. 把文件myfile添加到 .gitignore
2. 如果是文件, 执行 git rm --cached myfile
3. 如果是文件夹, 执行 git rm --cached myfile -r
4. git commit -m "Remove myfile from remote repository"
5. git push

公众号 牙叔教程

转载自:https://juejin.cn/post/7222862599842299963
评论
请登录