ChatGPT是一个理解自然语言的工具箱

ChatGPT的话题在2023年2月格外火热,以聊天对话的形式,为人类提供大量的专业知识。

万能的神ChatGPT

ChatGPT 擅长产出符合逻辑的答案,人类的逻辑能力其实并不好。作为一个开发工程师,我发现代码80%的BUG,都是程序逻辑有问题,即使是常年写码的工程师,也会写出逻辑有问题的程序,ChatGPT非常适合排查代码片段,辅助工程师写出逻辑正确的代码,在这方面, ChatGPT最大的竞品是Github Copilot

Github Copilot

ChatGPT拟人化的问答模式,非常适合当老师。学会一门知识,本身是枯燥的,如果把知识转换为ChatGPT问答的形式,将会极大提升课堂的趣味性,玩过RPG游戏的人,要进行大量的问答,这些问答往往是几个固定的问题,再给几个固定的选项,如果将知识转换为RPG游戏的形式,并给予极大的问答自由度,学生就变成了玩家。

ChatGPT适合仿制3A游戏,3A游戏需要大量的人力,海量的资金投入,巨长的开发周期;引入ChatGPT,游戏开发者只需定义玩法,ChatGPT就可以生成中规中矩的罐头游戏,罐头游戏并非贬义词,市面上绝大多数游戏都是没什么特色的罐头游戏,ChatGPT能生成罐头游戏,反而让开发者们,更有时间去研究特色玩法。

ChatGPT适合生成产品发布会,因为发布会的套路都是固定的;ChantGPT也适合做直播,因为直播的套路也是固定的;ChatGPT最适合做的是公务员,我们一直谈法制,但不好搞,ChatGPT代替法官来判案,代替律师来辩护,会让罪与罚更容易一一对应。

ChatGPT 会员终于开放了,支持万事达,Visa,每月20美元,开通后有两个模型可选,开通会员后,会默认使用提升回答速度的版本,当然也可以选择普通速度的Legacy版本。

ChatGPT会员可选两个模型

买ChatGPT PLUS会员并不容易,需要用海外信用卡支付,我办了Depay的海外万事达卡,特色是支持USDT充值,如果50美元开卡,可以免月租;如果需要海外信用卡,可以通过我的邀请链接开卡 https://depay.depay.one/web-app/register-h5?invitCode=620375&lang=zh-cn

ChatGPT非常适合写脚本,但小概率会出现类型错误,变量名的语义和实际进行的操作产生了误差(命名不规范坑人也坑ChatGPT)

ChatGPT生成代码错误

ChatGPT可以帮忙写很多前端样式,对汉语描述的理解非常到位,我们还可以不断追加要求,要求ChatGPT对代码进行改写,真的是理想的乙方

ChatGPT写样式

ChatGPT改写代码

让ChatGPT用Node.js写一个同步脚本

  • 输入需求
写一个基于rsync命令同步服务器目录(比如 /opt)到本地目录(比如 ~/cloud-backup/ )的Node.js每日定时备份脚本;

支持配置登陆用户, 和登录服务器信息, 服务器IP, 登录端口, 登录用户, 无需配置密码, 默认使用ssh key登录;

每天的备份目录用YYYY-MM-DD日期格式命名,如果从服务器同步的文件夹为 `/opt/` , 则在本地的存放位置为 `${用户目录}/cloud-backup/YYYY-MM-DD/opt/` ,传输速度限制为每秒100KB,如果同步失败, 则1分钟后自动重试, 只保留最近14天的备份, 过期的备份自动删除;

如果本地文件夹不存在,则自动创建;

同步过程中, 打印同步文件进度的log; log同步输出到脚本同级目录下的log.txt文件, log.txt只保存最近14天的log, 过期的log自动删除;

将功能点细分为函数, 便于后续扩展;

列出以上脚本依赖包相关的 package.json

我需要使用pm2守护运行这个脚本,请给出pm2凌晨2点25分运行脚本的方法

ChatGPT输出代码

const { exec } = require("child_process");
const { format } = require("date-fns");
const fs = require("fs");
const path = require("path");
const { promisify } = require("util");

const execAsync = promisify(exec);

const SSH_KEY_PATH = process.env.SSH_KEY_PATH || "~/.ssh/id_rsa";
const SYNC_FOLDER = "/opt";
const BACKUP_FOLDER = `${process.env.HOME}/cloud-backup`;

const SSH_CONFIG = {
  host: "example.com",
  port: 22,
  username: "example",
};

const MAX_SPEED = 100; // KB/s
const RETRY_INTERVAL = 60 * 1000; // 1 minute
const MAX_BACKUPS = 14;

const now = new Date();
const backupFolderName = format(now, "yyyy-MM-dd");
const backupFolderPath = path.join(BACKUP_FOLDER, backupFolderName);
const logFilePath = path.join(__dirname, "log.txt");

async function syncWithRetry() {
  let success = false;
  while (!success) {
    try {
      await sync();
      success = true;
    } catch (err) {
      console.error(err);
      console.log(`Sync failed, retrying in ${RETRY_INTERVAL / 1000} seconds...`);
      await new Promise((resolve) => setTimeout(resolve, RETRY_INTERVAL));
    }
  }
}

async function sync() {
  const command = `rsync -a --progress --max-size=${MAX_SPEED}K --delete -e "ssh -i ${SSH_KEY_PATH}" ${SSH_CONFIG.username}@${SSH_CONFIG.host}:${SYNC_FOLDER} ${backupFolderPath}`;
  console.log(`Syncing ${SSH_CONFIG.username}@${SSH_CONFIG.host}:${SYNC_FOLDER} to ${backupFolderPath}...`);
  await execAsync(command);
  console.log("Sync finished.");
}

async function removeExpiredBackups() {
  const backupFolders = await fs.promises.readdir(BACKUP_FOLDER);
  const expiredBackups = backupFolders
    .filter((folder) => folder !== backupFolderName)
    .sort()
    .slice(0, -MAX_BACKUPS);
  await Promise.all(
    expiredBackups.map((folder) =>
      fs.promises.rm(path.join(BACKUP_FOLDER, folder), { recursive: true, force: true })
    )
  );
}

async function removeExpiredLogs() {
  const logs = await fs.promises.readdir(__dirname);
  const expiredLogs = logs
    .filter((log) => log.endsWith(".log") && log !== `${backupFolderName}.log`)
    .sort()
    .slice(0, -MAX_BACKUPS);
  await Promise.all(expiredLogs.map((log) => fs.promises.rm(path.join(__dirname, log))));
}

async function createBackupFolder() {
  try {
    await fs.promises.mkdir(backupFolderPath, { recursive: true });
    console.log(`Created backup folder: ${backupFolderPath}`);
  } catch (err) {
    if (err.code !== "EEXIST") {
      throw err;
    }
  }
}

async function main() {
  await createBackupFolder();
  await syncWithRetry();
  await removeExpiredBackups();
  await removeExpiredLogs();

  const logText = `Synced ${SSH_CONFIG.username}@${SSH_CONFIG.host}:${SYNC_FOLDER} to ${backupFolderPath} at ${new Date().toISOString()}\n`;
  await fs.promises.appendFile(logFilePath, logText);
}

main().catch((err) => console.error(err));

如果输出中断,我们可以要求ChatGPT继续上次的输出,而不用重新生成

继续输出

内容输出

然而,ChatGPT 还是漏了package.json的输出,我们可以要求ChatGPT对package.json内容重新输出

image-20230219152951399

前面我们明确要求了ChatGPT进行函数式编程,如果我们需要优化某个函数的输出,可以直接让ChatGPT继续修改

继续修改

运行ChatGPT修改后的脚本

运行结果

修改后的脚本可以顺利完成同步任务,由于rsync可以自动跳过已同步的文件,当天,多次运行同步脚本,也可以快速进行增量同步。

让ChatGPT推荐一些WordPress主题

WordPress主题推荐

如果我们有自己的WordPress网站,个人服务器带宽有限,首屏打开速度不理想,也可以让ChatGPT给出一些轻量化主题推荐

小结

2023年,用中文在搜索引擎(Google, Bing, baidu)查点儿东西(凯恩斯陷阱),大概率都会指向知乎,但知乎产品又做的非常粪坑,强迫用户装App, App各种无厘头的弹窗广告,搞的推荐和热榜话题简直是兢兢业业的给用户喂shi

凯恩斯陷阱

ChatGPT确实可以当搜索引擎来用,用中文问内容,几乎是有问必答,而且干净无废话,不懂还可以追问,一言以蔽之,搜索引擎本身也不生产内容,和ChatGPT一样,都是内容的搬运工,但ChatGPT和搜索引擎的用户体验简直是天壤之别,而且ChatGPT还可以通过加入新数据,不断成长,搜索引擎确实应该努努力了,一个无法持续优化的搜索引擎,是无法和ChatGPT竞争的。

本文永久更新地址:

https://fangyuanxiaozhan.com/p/2023-02-12-11-51-20-chatgpt-tools/