通过ChatGPT做一个终端对话玩具(xx再也不怕我xx了)
引导篇
从去年12月初了解到ChatGPT,也注册了账号,但是一直没去使用(真是太懒了)。
相信大家就算没使用过,也听闻过它的传说,简单来说就是一个解答性聊天机器人。
最近呢,有几位朋友也一直在向我咨询一些ChatGPT的问题,想了想还是做个小应用,带各位来了解并使用上ChatGPT。
声明一下,此篇文章真不是用ChatGPT生成的。注册篇
已经有很多大佬来介绍这个注册方式了,我简单的说一下步骤吧。准备好科学上网的节点(香港、越南的不行);在https:smsactivate。org验证码平台上充值个1;去https:chat。openai。comauthlogin通过邮箱注册(推荐谷歌直接注册);在验证码平台上找一个openai的验证码服务(最便宜的是印尼的,有效期20分钟);输入验证码平台上的手机号进行验证;等待验证码出现,粘贴之后即可完成注册;可以直接在https:platform。openai。comaccountapikeys生成apiKey;实战篇
本次做的小工具,是一个终端对话助手。通过用户的输入内容,让ChatGPT进行识别回答并输出。
效果图
准备工作
初始化yarninity
安装插件openai(对话功能)inquirer(处理命令行输入等操作)clispinner(Loading效果)
准备openai的apiKey对接OpenAI
引入openai,并且写一个调用入口函数。const{Configuration,OpenAIApi}require(openai);asyncfunctionmain(){创建openai配置constconfigurationnewConfiguration({apiKey:apiKey});初始化openaiconstopenainewOpenAIApi(configuration);const{data:{choices}}awaitopenai。createCompletion({model:textdavinci003,对话机器人模型prompt:js是什么?,问题temperature:0。5,准确性的概率,0是最精准的maxtokens:150,输出内容长度topp:1。0,避免重复和不相关的内容frequencypenalty:0。0,控制语言模型中出现的词语频率,惩罚presencepenalty:0。0,控制语言模型中出现的词语频率,惩罚})console。log(choices〔0〕。text);输出的内容}main()
输出的结果如下图
这一步已经将openai对接完了。
让用户配置和提问
我们需要让用户提问,不应该直接将问题写在文件里,缺少与用户之间的交互。
这时候inquirer出现了,它是一个命令行交互工具,可以做很多事情,比如各种cli的一些问题及选择配置的方式,如VueCli的创建的这种多选、单选它都可以做到。
使用方式也很简单const{prompt}awaitinquirer。prompt({type:input,可以是passwordlist等name:prompt,定义的字段名message:请输入问题,提示信息});console。log(输入的内容,prompt)
现在可以拿到用户的输入内容了,我们就可以做很多事情了。获取用户输入的apiKey;获取用户选择的对话机器人模型;获取用户提问内容;引入定义配置constinquirerrequire(inquirer);定义一个配置configconstconfigObject。create(null);constfsrequire(fs);写入Key到文件
让用户输入密钥,为了持久化存储,我选择直接创建文件来进行存key,以免每次都需要重新输入。判断文件是否存在constkeysIsExistfs。existsSync(openaikeys);如果不存在if(!keysIsExist){const{apiKey}awaitinquirer。prompt({type:password,name:apiKey,message:请输入OpenAI的Key,})覆盖写入fs。writeFile(openaikeys,apiKey。trim(),{flag:w},(err){if(err)console。error(err)elsemain()重新执行})}else{存在此文件直接读取赋值给config。apiKeyfs。readFile(openaikeys,(err,data){if(err){console。error(err)return}config。apiKeydata。toString();})}
WX202303010051292x。png让用户选择机器人const{model}awaitinquirer。prompt({type:list,name:model,message:请选择对话机器人,choices:〔{name:textada001,value:textada001},{name:textcurie001,value:textcurie001},{name:textbabbage001,value:textbabbage001},{name:textdavinci003,value:textdavinci003},〕,default:textdavinci003})config。modelmodel;
WX202303010051572x。png让用户提问const{prompt}awaitinquirer。prompt({type:input,name:prompt,message:请输入问题,});
WX202303010052142x。png加个Loading效果
因为openai响应有点慢,所以为了减少蕉绿,引入了clispinnerconstSpinnerrequire(clispinner)。Spinner;s会被下面的替代,是个占位符constspinnernewSpinner(Loading。。s);这里是loading字符,按照这个顺序去渲染spinner。setSpinnerString();
在请求openai之前调用请求开始spinner。start();请求完成之后暂停spinner。stop(true);参数bool,是否需要清除输出内容全部代码
终于完结撒花了,现在已经是凌晨一点半了。const{Configuration,OpenAIApi}require(openai);constinquirerrequire(inquirer);constfsrequire(fs);constconfigObject。create(null);constSpinnerrequire(clispinner)。Spinner;constspinnernewSpinner(Loading。。s);spinner。setSpinnerString();asyncfunctionmain(){判断文件是否存在constkeysIsExistfs。existsSync(openaikeys);if(!keysIsExist){const{apiKey}awaitinquirer。prompt({type:password,name:apiKey,message:请输入OpenAI的Key,})覆盖写入fs。writeFile(openaikeys,apiKey。trim(),{flag:w},(err){if(err)console。error(err)elsemain()})}else{fs。readFile(openaikeys,(err,data){if(err){console。error(err)return}config。apiKeydata。toString();})}const{model}awaitinquirer。prompt({type:list,name:model,message:请选择对话机器人,choices:〔{name:textada001,value:textada001},{name:textcurie001,value:textcurie001},{name:textbabbage001,value:textbabbage001},{name:textdavinci003,value:textdavinci003},〕,default:textdavinci003})config。modelmodel;const{apiKey}config;console。log(33〔42;30mLGOIN33〔40;32m登录成功33〔0m);constconfigurationnewConfiguration({apiKey});config。openainewOpenAIApi(configuration);start()}asyncfunctionstart(){const{model}config;const{prompt}awaitinquirer。prompt({type:input,name:prompt,message:请输入问题,});if(!prompt。trim()){start()returnfalse}try{spinner。start();const{data:{choices}}awaitconfig。openai。createCompletion({model,prompt,temperature:0。5,maxtokens:150,topp:1。0,frequencypenalty:0。0,presencepenalty:0。0,})constanswerchoices〔0〕?。text?。replace(g,);spinner。stop(true);console。log(33〔32mOpenAI:answer?。trim()33〔0m);start()}catch(error){spinner。stop(true);console。log(error);}}main();