疏导篇
从去年12月初理解到 ChatGPT
,也注册了账号,然而始终没去应用(真是太懒了)。
置信大家就算没应用过,也听闻过它的传说,简略来说就是一个解答性聊天机器人。
最近呢,有几位敌人也始终在向我征询一些 ChatGPT
的问题,想了想还是做个小利用,带各位来理解并应用上ChatGPT
。
申明一下,此篇文章真不是用 ChatGPT
生成的。
注册篇
曾经有很多大佬来介绍这个注册形式了,我简略的说一下步骤吧。
- 筹备好迷信上网的节点(香港、越南的不行);
- 在 https://sms-activate.org/ 验证码平台上充值个1$;
- 去 https://chat.openai.com/auth/login 通过邮箱注册(举荐谷歌间接注册);
- 在验证码平台上找一个
openai
的验证码服务(最便宜的是印尼的,有效期20分钟); - 输出验证码平台上的手机号进行验证;
- 期待验证码呈现,粘贴之后即可实现注册;
- 能够间接在 https://platform.openai.com/account/api-keys 生成
apiKey
;
实战篇
本次做的小工具,是一个终端对话助手。通过用户的输出内容,让 ChatGPT
进行辨认答复并输入。
效果图
筹备工作
初始化
yarn init -y
装置插件
openai
(对话性能)inquirer
(解决命令行输出等操作)cli-spinner
(Loading成果)
筹备 openai
的 apiKey
对接 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)
当初能够拿到用户的输出内容了,咱们就能够做很多事件了。
- 获取用户输出的
apiKey
; - 获取用户抉择的对话机器人模型;
- 获取用户发问内容;
引入&定义配置
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();