前言
最近公司裁员风波,很不幸成为了裁员名单中的一员;此时又恰逢一波AIGC浪潮,首当其冲的就是GPT这样的大语言模型的诞生,是整个AI领域的一个质的飞跃。正好在这样一个空挡期,我就基于Chat-GPT 做了一些深入的实践,并将整个过程记录下来。
准备工作
-
需要在OpenAI官方平台注册一个账号
首先访问官网需要梯子,不然无法访问;
账号注册时,最好使用谷歌邮箱,用国内的邮箱注册会返回一些异常的错误;
注册第二步,需要接受一个短信验证,这里我使用的是sms-activate平台(可以百度一下使用方式),主要就是获取一个临时的国际号码,来获取验证码,我买的印尼🇮🇩的号码,比较便宜,充值1$能用好几次; -
获取API-Key
注册成功后,点击头像,选择Views API Keys
,然后+ Create New Secret Key
接入
OpenAI 提供了多种接入方式,包括Python,Node,云API等等
1.Python方式
//安装OpenAI模块
pip install openai
import os
import openai
//组织信息(如果存在多组织)
openai.organization = "org-CfErNk1yqg8HSj5mzWA6AUwA"
//OpenAI-Key
openai.api_key = os.getenv("OPENAI_API_KEY")
//获取训练模型列表
openai.Model.list()
//Completion方式互动
response = openai.Completion.create(
model="text-davinci-003",
prompt="Say this is a test",
temperature=0,
max_tokens=7
)
2.Node.js 方式
npm install openai
const { Configuration, OpenAIApi } = require("openai");
const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);
//Completion方式互动
const response = await openai.createCompletion({
model: "text-davinci-003",
prompt: "Say this is a test",
temperature: 0,
max_tokens: 7,
});
//ChatCompletion方式互动
const response1 = await openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Who won the world series in 2020?"},
{"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
{"role": "user", "content": "Where was it played?"}
]
)
//ChatCompletion Respones
/*
{
'id': 'chatcmpl-6p9XYPYSTTRi0xEviKjjilqrWU2Ve',
'object': 'chat.completion',
'created': 1677649420,
'model': 'gpt-3.5-turbo',
'usage': {'prompt_tokens': 56, 'completion_tokens': 31, 'total_tokens': 87},
'choices': [
{
'message': {
'role': 'assistant',
'content': 'The 2020 World Series was played in Arlington, Texas at the Globe Life Field, which was the new home stadium for the Texas Rangers.'},
'finish_reason': 'stop',
'index': 0
}
]
}
*/
3.云API
- Completions 方式
POST https://api.openai.com/v1/completions
header:
{
"Content-Type: application/json",
"Authorization: Bearer $OPENAI_API_KEY"
}
body:
{
"model": "text-davinci-003", //使用的模型id
"prompt": "Say this is a test", //用户输入的内容(提示词)
"max_tokens": 7, //最大token数(消费token 来计费)
"temperature": 0, //采样精度(0~2) 值越小,精度越高
"top_p": 1, //概率质量系数, 默认为1
"n": 1, //为prompt生成的Completions个数
"stream": false, //是否采用流式响应
"stop": "\n" //生成结果 停止标识符
}
respones:
{
"id": "cmpl-uqkvlQyYK7bGYrRHQ0eXlWi7",
"object": "text_completion",
"created": 1589478378,
"model": "text-davinci-003",
"choices": [
{
"text": "\n\nThis is indeed a test", //互动返回的结果
"index": 0,
"logprobs": null,
"finish_reason": "length"
}
],
"usage": { // token 消费信息
"prompt_tokens": 5,
"completion_tokens": 7,
"total_tokens": 12
}
}
- Chat 方式
POST https://api.openai.com/v1/chat/completions
header:
{
"Content-Type: application/json",
"Authorization: Bearer $OPENAI_API_KEY"
}
body:
{
"model": "gpt-3.5-turbo",
"messages": [ //消息对象列表,每个对象都包含一个角色(user,system,assistant)和内容字段,支持填充默认/预设的上下文内容
{"role": "system", "content": "你是一个得力助手,无所不能"},
{"role": "assistant", "content": "我是得力小助手"},
{"role": "user", "content": "说你好"}
]
}
response:
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "\n\nHello there, how may I assist you today?",
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21
}
}
上面是关于Chat-GPT相关的内容铺垫,接下看微信相关
WeChaty
GitHub地址:https://github.com/wechaty/wechaty
官方介绍:Wechaty is a RPA (Robotic Process Automation) SDK for Chatbot Makers which can help you create a bot in 6 lines of JavaScript, Python, Go, and Java, with cross-platform support including Linux, Windows, MacOS, and Docker.
更多
参考:什么是无头浏览器,它的用途是什么?
总之,使用WeChaty,可以模拟一个微信客户端,用户通过扫码登陆后,它会捕获登陆用户的所以会话,并可以通过提供的API 完成一些自动回复的功能(思考:微信同意这样搞吗?难道没有安全隐患吗?),当前在WeChaty社区也看到了很多被封号的情况,说明在微信的生态下还是不能随便玩的。
在这个基础上,小助理的实现逻辑思路就很清晰了,也非常简单
开始模块组装
核心依赖的3个模块:
"chatgpt": "^4.8.3", //对openai 的云api 做了上层的封装和管理
"wechaty": "^1.20.2", //微信机器人模块
"wechaty-puppet-wechat": "^1.18.4"
初始化Wechaty
async function initProject() {
try {
await initChatGPT();
bot = WechatyBuilder.build({
name: 'zezefamily',
puppet: 'wechaty-puppet-wechat',
puppetOptions: {
uos: true,
},
});
bot
.on('scan', onScan)
.on('login', onLogin)
.on('logout', onLogout)
.on('message', onMessage);
if (config.friendShipRule) {
bot.on('friendship', onFriendShip);
}
bot
.start()
.then(() => console.log('Start to log in WeChat...'))
.catch((e) => console.error(e));
} catch (error) {
console.log('init error: ', error);
}
}
处理bot 的回调
//扫码登陆
function onScan(qrcode) {
qrcodeTerminal.generate(qrcode); // 在console端显示二维码
const qrcodeImageUrl = [
'https://api.qrserver.com/v1/create-qr-code/?data=',
encodeURIComponent(qrcode),
].join('');
console.log(qrcodeImageUrl);
}
//登陆
async function onLogin(user) {
console.log(`${user} has logged in`);
const date = new Date();
console.log(`Current time:${date}`);
if (config.autoReply) {
console.log(`Automatic robot chat mode has been activated`);
}
}
//登出
function onLogout(user) {
console.log(`${user} has logged out`);
}
//添加好友
async function onFriendShip(friendship) {
if (friendship.type() === 2) {
if (config.friendShipRule.test(friendship.hello())) {
await friendship.accept();
}
}
}
// 收到消息
async function onMessage(msg) {
// 避免重复发送
if (msg.date() < startTime) {
return;
}
const contact = msg.talker(); //消息发送者
const receiver = msg.to(); //消息接收者
const content = msg.text().trim(); //消息体
const room = msg.room(); //是否为群消息
const alias = (await contact.alias()) || (await contact.name());
const isText = msg.type() === bot.Message.Type.Text; //判断是否为文本消息
if (msg.self()) { //如果是自己给自己发送
return;
}
if (room && isText) { //只处理文本类消息
const topic = await room.topic();
console.log(
`Group name: ${topic} talker: ${await contact.name()} content: ${content}`
);
// console.log("receiver.name() ==>",receiver.name())
if (await msg.mentionSelf()) { //群消息,是否@的是自己
// console.log("是自我提及:",content);
if (content.startsWith("@小泽玛利亚")){
const groupContent = content.replace("@小泽玛利亚", '');
console.log("groupContent ==>",groupContent)
replyMessage(room, groupContent); //提取内容发送给Chat-gpt
return;
}else {
console.log(
'Content is not within the scope of the customizition format'
);
}
}
} else if (isText) { //单聊消息
console.log(`talker: ${alias} content: ${content}`);
if (config.autoReply) {
if (content.startsWith(config.privateKey) || config.privateKey === '') {
let privateContent = content;
if (config.privateKey === '') {
privateContent = content.substring(config.privateKey.length).trim();
}
replyMessage(contact, privateContent); //提取内容给Chat-gpt
} else {
console.log(
'Content is not within the scope of the customizition format'
);
}
}
}
}
Chat-GPT 内部,对外导出了几个function
//chat-gpt 模块初始化
export function initChatGPT() {
chatGPT = new ChatGPTAPI({
apiKey: config.OPENAI_API_KEY,
completionParams: {
model: 'gpt-3.5-turbo',
},
});
}
//contact : talker实例 content:发送的内容
export async function replyMessage(contact, content) {
const { id: contactId } = contact;
try {
if (
content.trim().toLocaleLowerCase() === config.resetKey.toLocaleLowerCase()
) {
chatOption = {
...chatOption,
[contactId]: {},
};
await contact.say('Previous conversation has been reset.');
return;
}
const message = await retryRequest(
() => getChatGPTReply(content, contactId),
config.retryTimes,
500
);
if (
(contact.topic && contact?.topic() && config.groupReplyMode) ||
(!contact.topic && config.privateReplyMode)
) {
const result = content + '\n-----------\n' + message;
await contact.say(result);
return;
} else {
await contact.say(message);
}
} catch (e: any) {
console.error(e);
if (e.message.includes('timed out')) {
await contact.say(
content +
'\n-----------\nERROR: Please try again, ChatGPT timed out for waiting response.'
);
}
}
}
//请求OpenAI接口
async function getChatGPTReply(content, contactId) {
//调用封装的chatGPT模块发起请求
const { conversationId, text, id } = await chatGPT.sendMessage(
content,
chatOption[contactId]
);
chatOption = {
[contactId]: {
conversationId,
parentMessageId: id,
},
};
console.log('response: ', conversationId, text);
// response is a markdown-formatted string
return text;
}
核心的内容基本完成,演示一下结果吧
单聊:
群聊:
至此,一个简单Chat-GPT 助理就搞定了。
注意:以上案例仅供学习,不能商业运作;