nodejs搭建chatgpt服务
5分钟快速搭建基于nodejs的chatgpt服务
写在前面
首先大家都知道,在国内是无法成功调用openapi的接口,甚至openai的官网都很难打开。所以如果想使用chatgpt的几乎是不可能,不过咱们可以抱着了解的心态去体验一下。
*阅读本文档您可以了解以下内容*
- eggjs框架
- egg-mysql的使用
- openai的实例创建聊天和图片
准备工作
- apiKey: 这是调用chatgpt的密钥。目前有两种获取方式:
- 通过openai的官网去申请,不过这需要一个国外的手机号。
- 去某宝直接购买,大概1块钱。
- 国外服务器: chatgpt必须用国外的服务器访问。可以:去各大厂购买云服务
就绪
- 准备环境,本文默认使用的centos7.6
- 开发环境,nodejs >=16,目前centos只能安装node16及以下版本,所以大家安装时需要注意,不要直接安装最新的nodejs。为了方便切换,可以安装nvm来管理node版本,
nvm install nodejs版本
,nvm use nodejs版本
- 安装eggjs,和所需插件:
npm init egg --type=simple
npm install
npm install egg-mysql
npm install openai
npm install egg-validate
说明: mysql是为了保存聊天上下文,当然你也可以保存在前端本地,validate是校验参数插件
数据库请自行创建,数据表的创建后面会写在代码中
修改配置文件
- 在config/config.default.js中添加
config.security = {
csrf: {
enable: false,
ignoreJSON: true
},
domainWhiteList: ['*']
}
config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,POST,DELETE,PATCH'
}
config.mysql = {
client: {
host: 'localhost',
port: '3306',
user: 'root',
password: 'Chat9527', // 数据库密码
database: 'chatDB', // 数据库名称
},
app: true,
agent: false,
}
config.validate = {
convert: true,
widelyUndefined: true,
async formatter(ctx, error) {
ctx.status = 400;
ctx.body = {
code: 'INVALID_PARAM',
errors: error.errors,
};
},
}
config.constant = {
API_KEY: 'sk-xxxx', // 你的apiKey
};
- 在config/plugin.js中添加
cors: {
enable: true,
package: 'egg-cors'
},
validate: {
enable: true,
package: 'egg-validate'
},
mysql: {
enable: true,
package: 'egg-mysql',
}
api接口
分析目前只有两个接口,一个是openai的聊天,另一个是生成图片
具体代码如下:
module.exports = app => {
const { router, controller } = app;
app.beforeStart(async () => {
const ctx = app.createAnonymousContext();
await ctx.app.mysql.query(`
CREATE TABLE IF NOT EXISTS user_contexts (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
memory INT(11) DEFAULT NULL,
affinity INT(11) DEFAULT NULL,
context TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
});
router.post('/creatChat', controller.chat.createChat);
router.post('/creatImg', controller.chat.creatImg);
};
user_id 表示访问服务的用户;context 为聊天的记录;memory和affinity为保留字段可以不要。
openai使用
- nodejs中使用
new openai({ opentions })
来创建实例; - 使用
实例.chat.completions.create({ messages, model: "gpt-3.5-turbo", });
来创建一个聊天
具体代码如下:app/controller/chat.js
const { Controller } = require('egg');
const OpenAI = require('openai');
class ChatController extends Controller {
// 创建图片
async creatImg() {
const { ctx } = this;
const { prompt, n=1, size="1024x1024" } = ctx.request.body;
const openai = new OpenAI({
apiKey: this.app.config.constant.API_KEY,
});
const response = await openai.images.generate({ prompt, n, size });
ctx.body = {
data: response.data
};
}
// 创建聊天
async createChat() {
const { ctx } = this;
const { request, service } = ctx;
const { prompt, userId } = request.body;
try {
ctx.validate(this.indexRule, request.body);
const openai = new OpenAI({
apiKey: this.app.config.constant.API_KEY,
});
const userContext = await service.chat.getUserContext(userId);
const messages = this.buildMessageList(userContext, prompt);
const response = await openai.chat.completions.create({
messages,
model: "gpt-3.5-turbo",
});
const assistantResponse = response.choices[0].message.content.trim();
const updatedUserContext = this.updateUserContext(userContext, prompt, assistantResponse);
service.chat.updateUserContext(userId, updatedUserContext);
const shouldEndConversation = this.isConversationEnding(assistantResponse);
if (shouldEndConversation) {
service.chat.deleteUserContext(userId);
ctx.body = { code: 0, message: "拜拜!" };
} else {
ctx.body = { code: 0, message: assistantResponse };
}
} catch (err) {
ctx.status = 442;
ctx.body = {
code: -1,
message: '系统错误',
error: err.errors,
}
}
}
// 构建消息列表
buildMessageList = (userContext, prompt) => {
return [
...userContext,
{ role: "system", content: "You are a helpful assistant that answers questions." },
{ role: "user", content: prompt }
];
}
// 更新用户上下文
updateUserContext = (userContext, prompt, assistantResponse) => {
return [
...userContext,
{ role: "user", content: prompt },
{ role: "assistant", content: assistantResponse }
];
}
// 判断是否结束聊天
isConversationEnding(response) {
const keywords = ["再见", "退出", "滚", "拜拜"];
return keywords.some(keyword => response.includes(keyword));
}
// 定义参数校验规则
get indexRule() {
return {
userId: {
type: 'string',
required: true,
format: /^[A-Za-z0-9]+$/,
message: 'userId不能为空,且只能包含字母和数字',
},
prompt: {
type: 'string',
required: true,
max: 300,
message: 'content不能为空,且长度不能超过300',
},
};
}
}
module.exports = ChatController;
- app/service/chat.js里是数据的存储逻辑,如下:
const { Service } = require('egg');
class ChatService extends Service {
// 获取用户上下文
async getUserContext(userId) {
const result = await this.app.mysql.select('user_contexts', {
where: { user_id: userId },
orders: [['created_at', 'desc']],
limit: 1,
});
return result[0] ? JSON.parse(result[0].context) : [];
}
// 更新用户上下文
async updateUserContext(userId, context) {
const existingData = await this.app.mysql.get('user_contexts', { user_id: userId });
const record = {
user_id: userId,
context: JSON.stringify(context),
created_at: new Date(),
};
if (existingData) {
await this.app.mysql.update('user_contexts', record, {
where: { user_id: userId },
});
} else {
await this.app.mysql.insert('user_contexts', record);
}
}
// 删除用户上下文
async deleteUserContext(userId) {
await this.app.mysql.delete('user_contexts', {
user_id: userId
});
}
}
module.exports = ChatService;
一切完成就绪
- 使用
npm run dev
来运行服务器 - 用Postman 访问
ip:7001/creatChat
,参数userId: '1'
,prompt: '你好'
- 使用
npm start
来后台运行服务 - 使用
npm stop
来停止服务
花费了不止5分钟?
- 直接克隆项目
git clone https://github.com/812781385/chatgptService.git
npm i
npm run dev
nodejs搭建chatgpt服务的更多相关文章
- nodejs搭建web服务教程
nodejs搭建web服务教程 先安装nodejs 然后 命令node js文件 即可开启服务了 输出如下 Magic happens on port 9011 你查看端口可以看到tcp 0 0 :: ...
- nodejs搭建简单的websocket服务端
创建websocket服务端使用了nodejs-websocket ,首先要安装nodejs-websocket,在项目的目录下: npm install nodejs-websocket 1.搭建w ...
- mock---前端搭建模拟服务
在做前端开发接口的时候,往往接口都是从后端来的,这让前端很苦恼,但是有了 MockServer ,前端也可以搭建API服务了. server-mock是什么? 是一款nodejs的应用,用于搭建web ...
- 用nodejs搭建类似于C++的服务器后台.类似网易pomelo
实际的情况,用nodejs跑业务,非常的快,只要用好其无阻塞和回调这两点,处理速度真的是杠杠的. 从年初开始,我用nodejs搭建了类似C++的服务器后台,也想和做同样的事情的朋友分享,本服务平台因为 ...
- 使用 Node.js 搭建微服务网关
目录 Node.js 是什么 安装 node.js Node.js 入门 Node.js 应用场景 npm 镜像 使用 Node.js 搭建微服务网关 什么是微服务架构 使用 Node.js 实现反向 ...
- nodejs搭建web服务器初级
nodejs搭建简单的web服务器 1.1简介 Node.js是基于Chrome JavaScript运行时建立的一个平台,实际上它是对Google Chrome V8引擎进行了封装,它主要用于创建快 ...
- 用nodejs搭建代理服务器
题图 From 极客时间 From Clm 前端开发者在工作中常常遇到跨域的问题,一般我们遇到跨域问题主要使用以下办法来解决: 1.jsonp 2.cors 3.配置代理服务器. jsonp不是很灵活 ...
- 利用 nodeJS 搭建一个简单的Web服务器(转)
下面的代码演示如何利用 nodeJS 搭建一个简单的Web服务器: 1. 文件 WebServer.js: //-------------------------------------------- ...
- 使用node+puppeteer+express搭建截图服务
使用node+puppeteer+express搭建截图服务 转载请注明出处https://www.cnblogs.com/funnyzpc/p/14222807.html 写在之前 一开始我们的需求 ...
- 如何搭建DNS服务
继NTP时间服务器后,继续搭建DNS服务,鉴于昨晚撰写时间超过预期,这次改变策略,先把自己需要用到的部分写出来(主要是基于RAC的搭建,只涉及正向和反向DNS解析),后面再添加必要的说明和阐述. 试验 ...
随机推荐
- PicGo图床配置码云gitee仓库上传typora图片
(前提是已注册gitee并新建一个仓库作为你上传图片的位置) 首先在PicGo官网下载软件:https://picgo.github.io/PicGo-Doc/zh/ 打开typora,找到偏好设置. ...
- nginx集成brotli压缩算法
本文于2017年2月中旬完成,发布在个人博客网站上. 考虑个人博客因某种原因无法修复,于是在博客园安家,之前发布的文章逐步搬迁过来. Google开源Brotli压缩算法 Brotli是一种全新的数据 ...
- Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
目录 简介 Spring基础 Core核心技术 Testing测试 Data Access Web Servlet Web Reactive 总结 简介 是什么让java世界变得更好,程序员变得更友爱 ...
- 陈海波:OpenHarmony技术领先,产学研深度协同,生态蓬勃发展
11月4日,以"技术筑生态,智联赢未来"为主题的第二届OpenHarmony技术大会在北京隆重举办.本次大会由OpenAtom OpenHarmony(简称"Open ...
- 及刻周边惠:拥抱HarmonyOS原子化服务
原文链接:https://mp.weixin.qq.com/s/Y75eiRlvDLXzoZWzAiZdeg,点击链接查看更多技术内容: 开发背景 及刻周边惠是梦享网络旗下本地生活服务平台,旨在为消费 ...
- Hypium框架使能ArkTS应用高效测试
原文链接:https://mp.weixin.qq.com/s/Ncc-x_4zy4wBZmSjknw1lQ,点击链接查看更多技术内容: HarmonyOS发布了声明式开发框架ArkUI,带来了 ...
- linux 性能自我学习 ———— 理解平均负载 [一]
前言 linux 系统上性能调查的自我学习. 正文 什么是平均负载? 使用uptime: 可以看到后面有: 0.03, 0.06, 0.09 这个表示1分钟,5分钟,15分钟的平均负载. 平均负债是指 ...
- 纯钧chunjun的http-x插件修复
简介 chunjun是一款基于flink的开源数据同步工具,官方文档,其提供了很多flink官方未提供的插件供大家来使用,特别是达梦插件在国产化环境中很方便! 本次介绍的是chunjun中的一款htt ...
- java使用Selenium操作谷歌浏览器学习笔记(二)
使用WebDriver操作浏览器之前必须设置对应的driver System.setProperty("webdriver.chrome.driver", "D:\\Ne ...
- 力扣507(java)-完美数(简单)
题目: 对于一个 正整数,如果它和除了它自身以外的所有 正因子 之和相等,我们称它为 「完美数」. 给定一个 整数 n, 如果是完美数,返回 true:否则返回 false. 示例 1: 输入:num ...