讲编程的学习经验,用了比较大的篇幅,如果不感兴趣,想了解ChatGPT的更多内容可以直接跳到“关于ChatGPT机器人”的部分。
想必大家对ChatGPT有所耳闻,最近火的不得了,它是OpenAI开发的,一种聊天式的自然语言处理(NLP)技术。
简单说,它会理解我们说话的内容,并用我们人类的说话方式进行回复,比如:
搜索问题、内容的关键字,然后再去搜索引擎返回的网页中找答案,通常来讲,搜索是基于关键字找相关内容,而ChatGPT是尝试理解我们想要的,直接返回一个答案,推特上很多大佬甚至认为ChatGPT有望颠覆Google搜索。
当我第一次接触到ChatGPT时,我第一时间也想过要不要做个机器人,方便在Mixin中使用,但是,仅仅,仅仅是一想。
缘起
Lyric歌词经理,为了能够方便大家能够方便交流编程方面的问题、分享知识,建立了一个 “程序设计综合讨论群”(7000104760)。
有一天,牙医晓杰大佬在群中问:
Chatgpt接到mixin里做个机器人并且支持mixin支付,这个好做吗?各位大佬?
根据我这几天的观察,因为ChatGPT是有注册地区和手机号地区限制的,因此对于很多用户,想体验、使用ChatGPT是很不方便的。
再加上牙医晓杰大佬的问题,我一开始也萌生过一点想法,想实践编程以及希望能在编程群中有所交流,于是我迅速着手试着写起了机器人。
关于编程如何突破
基础概念阶段
无论是我自己,还是我观察到的一些身边的学编程的朋友,大家都会从一些基本的概念学起,比如布尔、循环、判断、数据类型、数据结构等等。
学习编程的过程难免会遇到不理解、难理解的地方,于是,很多时候,我们学编程特别容易像是背一本以字母顺序开头的英文词典,总是在背abandon
这个单词,总是重复的在看不同的学习材料的基础部分。
而编程知识涉及很多前置引用,需要我们通过后面遇到的知识更好的理解前面的概念。
这种心理预期是应该有的,这样才更容易持续走下去。
编程中的基础概念是通用的,无论哪种编程语言都绕不开这些基础概念,大部分情况,只是不同的编程语言,有着不同的语法规则。
作为基础知识,概念,各种语言的官方教程也都是不错的,比如Go,Python,李笑来老师也有一本《自学是门手艺》可以用来自学和入门Python,市面上也有大量的书籍可以供参考学习这些基础知识。
Lyric歌词经理推荐了Go作为入门,可以参考这篇文章:《几个学写程序的错误认知》 - Lyric🌀 (quill.im)
既然,需要通过后面的知识,实际的练习,实际的代码去进一步理解知识,那就不应该停步在一直只打基础的阶段,不应该停步在一直觉得没有准备好的阶段,下一步,就是找一个切入点了。
实践编程的切入点
最好的切入点就是生活中用的到的场景,容易接触的到的场景,比如Excel,Mixin。
Excel是我们各行各业都会常用的工具,我第一个写的小工具就是帮我爱人统计他们单位排班表的班次,实际上这个需求就是把Excel表格的班次取出来,然后统计词频。
所以,就可以大概拆解为:
- 读取每个单元格的内容;
- 放到一个数组中;
- 遍历,统计词频;
- 输出结果到excel文件。
之后,又找了如何把python文件直接生成一个可以直接执行的程序的工具,这样其他人也就都可以用这个工具统计自己部门的排班频次了。
为了便于更没有编程基础的人理解,我再说明一下,学编程初期,我们可以通过编程自动化解决一些我们需要手工去做的费时费力的工作。
这些工作基本上不外乎,把数据拿到,把数据存到一个地方,编程处理这些数据,再把处理好的数据输出。
有了编程基础概念后,就可以看懂简单代码了,把需求拆解后,就可以去找每个小功能的代码,然后把他们组合到一起。
比如:
退而求其次,哪怕不我们不能编写丰富的输入,输出,但是可以通过一些代码片段,编写一些代码给自己使用了。
这个过程,可能写一段东西很慢,但是没有关系,这就像上学时的做题,会不会决定了我们能不能做出来,熟不熟才决定了快慢,所以,通过查询一些代码功能片段,虽然慢,我们也可以把一个需求凑出来,写多了,自然就快了。
仿别人的代码
有了前面的基础,我们就可以开始仿别人的代码,看别人如何实现功能。
然后,在别人的代码基础上修改,实现自己想要的功能。
以Mixin为例:
比如,通过李安导演的这篇文章:《做个 Mixin 机器人:flomo 机器人》 - 李安 (quill.im),我们可以学习:
- 初始化 Node.js 项目
- 配置好 Mixin 机器人的密钥信息
- 利用 sdk 可以让机器人接收消息,发送消息
其实,接受消息就是我们程序的输入,程序本身对消息处理,发送消息就是对处理结果的输出。
这还是一个输入,处理,输出的例子。
我们有了一些基础,我们就可以试着修改里面的内容,实现我们的一些简单的接收、处理、发送的需求,并在过程中熟悉Mixin的开发。
整个《做个Mixin机器人》系列文章都值得看一遍。
学习SDK
无论是前面的Excel的例子还是后面Mixin的例子,我们发现我们编程中可以直接使用别人编好的功能,我们把它们称为SDK。这些功能通过import的方式引入后,我们就可以直接使用了。
比如pandas库,提供了很多操作excel表格的方法可以直接使用,mixin-node-sdk,提供了很多Mixin的交互功能,比如发各种消息,查询资产,转账等等。
接下来,我们就需要进一步了解这些SDK的用法,比如mixin-node-sdk,由刘泽美大佬开发,编写:
SDK文档:[简介 & 安装 & 快速上手 | Mixin JS SDK (liuzemei.github.io)](https://liuzemei.github.io/mixin-js-sdk-docs/docs/server/intro) |
我把这个过程概括为,学习编程基础知识=>找到自己的主攻方向=>找到该方向领域的最主流SDK=>学习SDK使用=>用基础知识,将SDK组合到一起。
模块化编程
这一步,又是抄,看看专业的开发,写出来的东西是什么样子的。
有了前面的这些知识,实践,大概可以写出这样的代码,代码就不用细看了,反正就是一大坨,堆在一起,逻辑基本上是按顺序依次从上向下执行:
// Import Key
const { CLIENT_CONFIG, API_KEY } = require("./constants");
// Import modules
const request = require("request");
const { MixinSocket } = require("mixin-node-sdk");
// const datetime = require("datetime");
// New object
const socketClient = new MixinSocket(CLIENT_CONFIG, true, true);
// Variables
const MODEL = "text-davinci-003";
// const MODEL = "text-curie-001";
const API_URL = "https://api.openai.com/v1/completions";
let counter = 500;
let requests = 0;
let workList = {};
const vipList = ["cbb20923-9020-490a-b8f6-e816883c9c99"];
// Message handling
socketClient.get_message_handler = async function (message) {
// Read message
await this.read_message(message);
// Error handling
if (
!message.action ||
message.action === "ACKNOWLEDGE_MESSAGE_RECEIPT" ||
message.action === "LIST_PENDING_MESSAGES" ||
!message.data ||
!message.data.data
) {
return;
}
if (message.error) return console.log(message.error);
// console.log(message);
// Get input
const TEXT = message.data.parseData;
if (TEXT) {
requests += 1;
console.log("收到用户查询次数:", requests);
}
const user_id = message.data.user_id;
if (!workList.hasOwnProperty(user_id)) {
workList[user_id] = 20;
// console.log(workList);
if (vipList.includes(user_id)) {
workList[user_id] = 60;
}
}
// console.log(workList);
// Post input to OpenAI
const options = {
method: "POST",
url: API_URL,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${API_KEY}`,
},
json: {
prompt: TEXT,
max_tokens: 1024,
temperature: 0.6,
model: MODEL,
user: message.data.user_id,
},
};
// Request and Output handling
if (workList[user_id] > 0 && counter > 0) {
if (message.data.category === "PLAIN_TEXT") {
const self = this;
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
const q = message.data.parseData;
const a = body.choices[0].text.replace(/\n[\n]+/g, "");
// const result = "Q: " + q + "\n" + "A: " + a;
const result = a + "\n" + "[" + workList[user_id] + "]";
self.send_text(result, message);
} else {
console.error(error);
}
});
} else {
await this.send_text("Not text", message);
}
counter -= 1;
console.log("总查询次数剩余:", counter);
workList[user_id] -= 1;
// this.send_text(
// "今日您的可用总查询次数还剩余: " + workList[user_id] + " 次。",
// message
// );
} else if (counter === 0) {
await this.send_text("机器人总对话次数已用完,将在02:00重置。", message);
} else {
await this.send_text("每天只能和我对话20次,将在02:00重置。", message);
console.log(user_id, "今日次数已用尽。");
}
};
// 设置每天0点重置计数
setInterval(function () {
// 获取当前时间
let date = new Date();
// 如果当前时间是0点
if (
date.getHours() === 2 &&
date.getMinutes() === 0 &&
date.getSeconds() === 0
) {
// 重置计数
console.log("今日用户统计");
console.log(workList);
counter = 300;
workList = {};
console.log("总可用次数已重置。");
}
}, 1000);
socketClient.start();
学习了刘泽美大佬的课程:
配套文字:Mixin 开放社区 (mixinbots.com)
代码变成了这个样子:
//import module
const { BlazeClient } = require("mixin-node-sdk");
const { writeFile } = require("fs");
const request = require("request");
//import constants
const config = require("../config.json");
//new client
const client = new BlazeClient(config, { parse: true, syncAck: true });
//global constants
let totalLimit = 1000;
let userLimit = 15;
let workList = {};
//ws
client.loopBlaze({
onMessage(msg) {
query(msg);
sendHelpMsgWithInfo(msg);
handleClaim(msg);
handleDonate(msg);
},
onTransfer(msg) {
// console.log(msg);
if (msg.data.asset_id === config.usdt_asset_id && msg.data.amount >= 2.99) {
addLifecycle(msg, 30);
}
},
onAckReceipt() {},
});
setInterval(() => {
reset();
}, 1000);
//funcionts
function updateLifecycle() {
}
async function addLifecycle({ user_id }, lifeCycle) {
}
function generateWorkinglist(user_id) {
}
function query({ user_id, data, category }) {
}
async function handleClaim({ data, user_id }) {
}
async function handleDonate({ data, user_id }) {
}
async function sendHelpMsgWithInfo({ user_id, data }) {
}
function reset() {
}
可以看出来,每个功能点,都变成了一个独立的function,最后,再用一个整体的逻辑组织起来,方便维护,拥有每个功能的独立性。
看上去,好像更那么像一点事了。
总结
- 通过学习编程的基础知识,能够看懂代码;
- 通过身边的需求,作为切入点解决问题,从简单需求入手,哪怕是仅解决一部分需求;
- 练的少的情况下,可能会不熟练,慢,但是足以寻找参考代码,看懂参考代码,实践过程中会强化概念的理解,变得熟练;
- 仿别人的简单代码,或一部分代码,作为上手编程的起点;
- 找到领域,找到该领域中的SDK,学习SDK,用基础编程知识,调用SDK提供的方法解决问题;
- 找到更专业的代码,仿写,让自己变得越来越专业;
- 让夯实基础和简单实践两条腿走路;
- 最后一点,别不好意思问问题。
关于ChatGPT机器人
经过一顿折腾,ChatGPT机器人1.0版本算是上线了,机器人ID是:7000104341,相比最开始的简单功能实现,增加了使用次数限制,每日重置次数,打赏后使用限制解除等一些功能。
这个项目从一开始就考虑到很难有高付费,并不能通过这个项目直接挣到钱,又因为很多人没法注册使用,因此这个项目更多的为了给大家、自己提供一个方便使用ChatGPT的途径,还有,通过这个项目,实践编程。
但是,ChatGPT的API是按照字数收费的,包括问题和答案的字数,目前是每1000个token 0.02美元,所以还是希望能够有一些该项目本身的收入,能够持续让它良性运行下去让更多的人免费使用,因此,做了一些限制,说明如下:
-
在程序中发送
/?
可以获得该说明信息; -
考虑到防止滥用、运行成本,每位用户24小时内限制使用15次,2:00重置使用次数,对于绝大部分用户不会天天超过15次查询;
-
如果您觉得本项目为您带来了方便,也愿意共担一些运行成本,欢迎打赏,请发送
/donate
或点击打赏; -
打赏金额设置为了2.99 USDT,为了表示对您的感谢,打赏用户将获得30天内的24小时内无限次使用,但受总次数限制;
-
本应用总请求限制为每日1000次,过2:00重置,虽然最高峰达到3800多次查询,但随着尝鲜期结束,根据目前的统计,1000次还是足以满足大家日常使用的;
-
为了维持一定的活跃度,本应用支持每日领取 1CNB 作为感谢,请发送
/claim
或点击签到;
本人开发新手,程序如有不健壮之处,还请多多包涵,再次感谢大家的支持,如上述内容有调整,将对外公示。
利用Mixin Messenger,可以方便的检索到历史聊天,这算是与Mixin结合的额外福利,感谢马尚尚大佬的提示:
欢迎加入:ChatGPT 中文群 交流、反馈相关问题;Mumu Wu的”小密圈” 交流编程,BTC相关知识。