关于node.js:通过-ChatGPT-做一个终端对话玩具xx再也不怕我xx了

5次阅读

共计 4489 个字符,预计需要花费 12 分钟才能阅读完成。

疏导篇

从去年 12 月初理解到 ChatGPT,也注册了账号,然而始终没去应用(真是太懒了)。

置信大家就算没应用过,也听闻过它的传说,简略来说就是一个解答性聊天机器人。

最近呢,有几位敌人也始终在向我征询一些 ChatGPT 的问题,想了想还是做个小利用,带各位来理解并应用上ChatGPT

申明一下,此篇文章真不是用 ChatGPT 生成的。

注册篇

曾经有很多大佬来介绍这个注册形式了,我简略的说一下步骤吧。

  1. 筹备好迷信上网的节点(香港、越南的不行);
  2. 在 https://sms-activate.org/ 验证码平台上充值个 1$;
  3. 去 https://chat.openai.com/auth/login 通过邮箱注册(举荐谷歌间接注册);
  4. 在验证码平台上找一个 openai 的验证码服务(最便宜的是印尼的,有效期 20 分钟);
  5. 输出验证码平台上的手机号进行验证;
  6. 期待验证码呈现,粘贴之后即可实现注册;
  7. 能够间接在 https://platform.openai.com/account/api-keys 生成 apiKey;

实战篇

本次做的小工具,是一个终端对话助手。通过用户的输出内容,让 ChatGPT 进行辨认答复并输入。

效果图

筹备工作

初始化

yarn init -y

装置插件

  1. openai(对话性能)
  2. inquirer(解决命令行输出等操作)
  3. cli-spinner(Loading 成果)

筹备 openaiapiKey

对接 OpenAI

引入 openai,并且写一个调用入口函数。

const {Configuration, OpenAIApi} = require("openai");

async function main() {
    // 创立 openai 配置
    const configuration = new Configuration({apiKey: 'apiKey'});
    // 初始化 openai
    const openai = new OpenAIApi(configuration);
    const {data: { choices} } = await openai.createCompletion({
        model: 'text-davinci-003', // 对话机器人模型
        prompt: 'js 是什么?', // 问题
        temperature: 0.5, // 准确性的概率,0 是最精准的
        max_tokens: 150, // 输入内容长度
        top_p: 1.0, // 防止反复和不相干的内容
        frequency_penalty: 0.0, // 管制语言模型中呈现的词语频率,惩办
        presence_penalty: 0.0, // 管制语言模型中呈现的词语频率,惩办
    })
    console.log(choices[0].text); // 输入的内容
}

main()

输入的后果如下图

这一步曾经将 openai 对接完了。

让用户配置和发问

咱们须要让用户发问,不应该间接将问题写在文件里,短少与用户之间的交互。

这时候 inquirer 呈现了,它是一个命令行交互工具,能够做很多事件,比方各种 cli 的一些问题及抉择配置的形式,如 VueCli 的创立的这种多选、单选它都能够做到。

应用形式也很简略

const {prompt} = await inquirer.prompt({
    type: 'input', // 能够是 password|list 等
    name: 'prompt', // 定义的字段名
    message: '请输出问题', // 提示信息
});

console.log('输出的内容 =>>>', prompt)

当初能够拿到用户的输出内容了,咱们就能够做很多事件了。

  1. 获取用户输出的 apiKey
  2. 获取用户抉择的对话机器人模型;
  3. 获取用户发问内容;

引入 & 定义配置

const inquirer = require('inquirer');
// 定义一个配置 config
const config = Object.create(null);
const fs = require('fs');

写入 Key 到文件

让用户输出密钥,为了长久化存储,我抉择间接创立文件来进行存 key,免得每次都须要从新输出。

// 判断文件是否存在
const keysIsExist = fs.existsSync('openai_keys');
// 如果不存在
if (!keysIsExist) {const { apiKey} = await inquirer.prompt({
        type: 'password',
        name: 'apiKey',
        message: '请输出 Open AI 的 Key',
    })

    // 笼罩写入
    fs.writeFile('openai_keys', apiKey.trim(), {flag: 'w'}, (err) => {if (err) console.error(err)
        else main() // 从新执行})
} else {
      // 存在此文件间接读取赋值给 config.apiKey
    fs.readFile('openai_keys', (err, data) => {if (err) {console.error(err)
            return
        }
        config.apiKey = data.toString();})
}

让用户抉择机器人

const {model} = await inquirer.prompt({
    type: 'list',
    name: 'model',
    message: '请抉择对话机器人',
    choices: [{ name: 'text-ada-001', value: 'text-ada-001'},
        {name: 'text-curie-001', value: 'text-curie-001'},
        {name: 'text-babbage-001', value: 'text-babbage-001'},
        {name: 'text-davinci-003', value: 'text-davinci-003'},
    ],
    default: 'text-davinci-003'
})
config.model = model;

让用户发问

const {prompt} = await inquirer.prompt({
    type: 'input',
    name: 'prompt',
    message: '请输出问题',
});

加个 Loading 成果

因为 openai 响应有点慢,所以为了缩小蕉绿,引入了 cli-spinner

const Spinner = require('cli-spinner').Spinner;
// %s 会被上面的 ▂ ▃ ▄ ▅ ▆ ▇ █ 代替,是个占位符
const spinner = new Spinner('Loading.. %s');
// 这里是 loading 字符,依照这个程序去渲染
spinner.setSpinnerString('▂ ▃ ▄ ▅ ▆ ▇ █');

在申请 openai 之前调用

// 申请开始
spinner.start();
// 申请实现之后暂停
spinner.stop(true); // 参数 bool,是否须要革除输入内容

全副代码

终于完结撒花了,当初曾经是凌晨一点半了。

const {Configuration, OpenAIApi} = require("openai");
const inquirer = require('inquirer');
const fs = require('fs');
const config = Object.create(null);
const Spinner = require('cli-spinner').Spinner;
const spinner = new Spinner('Loading.. %s');
spinner.setSpinnerString('▂ ▃ ▄ ▅ ▆ ▇ █');

async function main() {
  // 判断文件是否存在
  const keysIsExist = fs.existsSync('openai_keys');
  if(!keysIsExist) {const { apiKey} = await inquirer.prompt({
      type: 'password',
      name: 'apiKey',
      message: '请输出 Open AI 的 Key',
    })

    // 笼罩写入
    fs.writeFile('openai_keys', apiKey.trim(), {flag: 'w'}, (err) => {if (err) console.error(err)
      else main()})
  } else {fs.readFile('openai_keys', (err, data) => {if (err) {console.error(err)
        return
      }
      config.apiKey = data.toString();})
  }

    const {model} = await inquirer.prompt({
        type: 'list',
        name: 'model',
        message: '请抉择对话机器人',
        choices: [{ name: 'text-ada-001', value: 'text-ada-001'},
            {name: 'text-curie-001', value: 'text-curie-001'},
            {name: 'text-babbage-001', value: 'text-babbage-001'},
            {name: 'text-davinci-003', value: 'text-davinci-003'},
        ],
        default: 'text-davinci-003'
    })
    config.model = model;

  const {apiKey} = config;
    console.log('\033[42;30m LGOIN \033[40;32m 登录胜利 \033[0m');
    const configuration = new Configuration({apiKey});
    config.openai = new OpenAIApi(configuration);
    start()}

async function start() {const { model} = config;
    const {prompt} = await inquirer.prompt({
        type: 'input',
        name: 'prompt',
        message: '请输出问题',
    });
    if(!prompt.trim()) {start()
        return false
    }
    try {spinner.start();
        const {data: { choices} } = await config.openai.createCompletion({
            model,
            prompt,
            temperature: 0.5,
            max_tokens: 150,
            top_p: 1.0,
            frequency_penalty: 0.0,
            presence_penalty: 0.0,
        })
        const answer = choices[0]?.text?.replace(/\ +/g, '');
        spinner.stop(true);
        console.log('\033[32mOpen AI:' + answer?.trim() + '\033[0m');
        start()} catch (error) {spinner.stop(true);
        console.log(error);
    } 
}

main();
正文完
 0