疏导篇

从去年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');// 定义一个配置 configconst 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();