mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-11-05 08:43:45 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
329e3eee21 | ||
|
|
07049c9afb | ||
|
|
36c5dd7eaa | ||
|
|
b84039b506 | ||
|
|
fab43097dc | ||
|
|
c8998ba294 | ||
|
|
40b2466adc |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,6 +1,17 @@
|
||||
# 更新日志
|
||||
|
||||
## v3.0.7
|
||||
|
||||
1. 聊天主界面:新增聊天引导页面,介绍产品功能
|
||||
2. 功能重构:拆分项目,将函数插件以及微信机器人,MidJourney 机器人等功能拆分新项目独立部署。
|
||||
3. 功能新增:新增 MidJourney AI 绘画支持,当识别到用户的绘画需求时,自动调用 MidJourney 绘画函数进行绘画。
|
||||
4. 功能新增:支持导出聊天记录为 PDF 文件。
|
||||
5. 功能优化:在后台 dashboard 页面新增统计今日众筹收入。
|
||||
6. 功能优化:支持用户设置默认的 GPT 模型
|
||||
7. Bug修复:修复若干已知的的 Bug
|
||||
|
||||
## v3.0.6
|
||||
|
||||
1. 管理后台:新增用户名和手机号码搜索功能
|
||||
2. 管理后台:新增重置用户密码功能
|
||||
3. 管理后台:支持关闭注册功能,新增添加用户功能,适用于内部使用场景
|
||||
|
||||
15
README.md
15
README.md
@@ -20,6 +20,8 @@
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 用户设置
|
||||
|
||||

|
||||
@@ -44,7 +46,7 @@
|
||||
|
||||
### 7. 体验地址
|
||||
|
||||
> 免费体验地址:[https://www.chat-plus.net/chat](https://www.chat-plus.net/chat) <br/>
|
||||
> 免费体验地址:[https://ai.r9it.com/chat](https://ai.r9it.com/chat) <br/>
|
||||
> **注意:请合法使用,禁止输出任何敏感、不友好或违规的内容!!!**
|
||||
|
||||
## 使用须知
|
||||
@@ -138,8 +140,6 @@ Listen = "0.0.0.0:5678"
|
||||
ProxyURL = ["YOUR_PROXY_URL"] # 替换成你本地代理,如:http://127.0.0.1:7777
|
||||
#ProxyURL = "" 如果你的服务器本身就在墙外,那么你直接留空就好了
|
||||
MysqlDns = "root:12345678@tcp(172.22.11.200:3307)/chatgpt_plus?charset=utf8&parseTime=True&loc=Local"
|
||||
StartWechatBot = false # 是否启动微信机器人,默认关闭,如果设置为 TRUE 则启动服务的时候需要微信扫码登录
|
||||
EnabledMsgService = false # 注册时是否开启短信验证功能,该功能需要配合短信服务一起使用
|
||||
|
||||
[Session]
|
||||
SecretKey = "azyehq3ivunjhbntz78isj00i4hz2mt9xtddysfucxakadq4qbfrt0b7q3lnvg80"
|
||||
@@ -155,7 +155,7 @@ EnabledMsgService = false # 注册时是否开启短信验证功能,该功能
|
||||
Username = "admin"
|
||||
Password = "admin123" # 如果是生产环境的话,这里管理员的密码记得修改
|
||||
|
||||
[ApiConfig] # 插件 API 服务配置,此为第三方插件服务,如需使用请联系作者开通
|
||||
[ApiConfig] # 微博热搜,今日头条等函数服务 API 配置,此为第三方插件服务,如需使用请联系作者开通
|
||||
ApiURL = "{URL}"
|
||||
AppId = "{APP_ID}"
|
||||
Token = "{TOKEN}"
|
||||
@@ -166,8 +166,14 @@ EnabledMsgService = false # 注册时是否开启短信验证功能,该功能
|
||||
Product = "Dysmsapi"
|
||||
Domain = "dysmsapi.aliyuncs.com"
|
||||
|
||||
[ExtConfig] # MidJourney和微信机器人服务 API 配置,开通此功能需要配合 chatpgt-plus-exts 项目部署
|
||||
ApiURL = "插件扩展 API 地址"
|
||||
Token = "插件扩展 API Token" # 这个 token 随便填,只要确保跟 chatgpt-plus-exts 项目的 token 一样就行
|
||||
```
|
||||
|
||||
> 如果要启用微信收款服务和 MidJourney
|
||||
> 绘画功能,请先部署扩展服务项目 [chatgpt-plus-exts](https://github.com/yangjian102621/chatgpt-plus-exts)。
|
||||
|
||||
修改 nginx 配置文档 `docker/conf/nginx/conf.d/chatgpt-plus.conf`,把后端转发的地址改成当前主机的内网 IP 地址。
|
||||
|
||||
```shell
|
||||
@@ -284,7 +290,6 @@ make clean linux
|
||||
## 参与贡献
|
||||
|
||||
个人的力量始终有限,任何形式的贡献都是欢迎的,包括但不限于贡献代码,优化文档,提交 issue 和 PR 等。
|
||||
**尤其是新版本的开发计划比较大,包括各种语言的后端 API 实现,本人精力有限,希望借助社区的力量来完成这些 API 的开发。**
|
||||
|
||||
如果有兴趣的话,也可以加微信进入微信讨论群(**添加好友时请注明来自Github!!!**)。
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ MysqlDns = "root:mysql_pass@tcp(localhost:3306)/chatgpt_plus?charset=utf8mb4&col
|
||||
StaticDir = "./static"
|
||||
StaticUrl = "http://localhost:5678/static"
|
||||
AesEncryptKey = "{YOUR_AES_KEY}"
|
||||
StartWechatBot = false
|
||||
EnabledMsgService = false
|
||||
|
||||
[Session]
|
||||
Driver = "cookie"
|
||||
@@ -38,4 +36,6 @@ EnabledMsgService = false
|
||||
Product = "Dysmsapi"
|
||||
Domain = "dysmsapi.aliyuncs.com"
|
||||
|
||||
|
||||
[ExtConfig]
|
||||
ApiURL = "插件扩展 API 地址"
|
||||
Token = "插件扩展 API Token"
|
||||
|
||||
@@ -30,7 +30,7 @@ type AppServer struct {
|
||||
|
||||
// 保存 Websocket 会话 UserId, 每个 UserId 只能连接一次
|
||||
// 防止第三方直接连接 socket 调用 OpenAI API
|
||||
ChatSession *types.LMap[string, types.ChatSession] //map[sessionId]UserId
|
||||
ChatSession *types.LMap[string, *types.ChatSession] //map[sessionId]UserId
|
||||
ChatClients *types.LMap[string, *types.WsClient] // map[sessionId]Websocket 连接集合
|
||||
ReqCancelFunc *types.LMap[string, context.CancelFunc] // HttpClient 请求取消 handle function
|
||||
Functions map[string]function.Function
|
||||
@@ -45,7 +45,7 @@ func NewServer(appConfig *types.AppConfig, functions map[string]function.Functio
|
||||
Config: appConfig,
|
||||
Engine: gin.Default(),
|
||||
ChatContexts: types.NewLMap[string, []interface{}](),
|
||||
ChatSession: types.NewLMap[string, types.ChatSession](),
|
||||
ChatSession: types.NewLMap[string, *types.ChatSession](),
|
||||
ChatClients: types.NewLMap[string, *types.WsClient](),
|
||||
ReqCancelFunc: types.NewLMap[string, context.CancelFunc](),
|
||||
MjTaskClients: types.NewLMap[string, *types.WsClient](),
|
||||
@@ -151,7 +151,7 @@ func corsMiddleware() gin.HandlerFunc {
|
||||
c.Header("Access-Control-Allow-Origin", origin)
|
||||
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
|
||||
//允许跨域设置可以返回其他子段,可以自定义字段
|
||||
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, Content-Type")
|
||||
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, Content-Type, Chat-Token")
|
||||
// 允许浏览器(客户端)可以解析的头部 (重要)
|
||||
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
|
||||
//设置缓存时间
|
||||
|
||||
@@ -93,6 +93,7 @@ type SystemConfig struct {
|
||||
AdminTitle string `json:"admin_title"`
|
||||
Models []string `json:"models"`
|
||||
UserInitCalls int `json:"user_init_calls"` // 新用户注册默认总送多少次调用
|
||||
InitImgCalls int `json:"init_img_calls"`
|
||||
EnabledRegister bool `json:"enabled_register"`
|
||||
EnabledMsgService bool `json:"enabled_msg_service"`
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ type MKey interface {
|
||||
string | int
|
||||
}
|
||||
type MValue interface {
|
||||
*WsClient | ChatSession | context.CancelFunc | []interface{} | MjTask
|
||||
*WsClient | *ChatSession | context.CancelFunc | []interface{} | MjTask
|
||||
}
|
||||
type LMap[K MKey, T MValue] struct {
|
||||
lock sync.RWMutex
|
||||
|
||||
@@ -73,6 +73,7 @@ func (h *UserHandler) Save(c *gin.Context) {
|
||||
Mobile string `json:"mobile"`
|
||||
Nickname string `json:"nickname"`
|
||||
Calls int `json:"calls"`
|
||||
ImgCalls int `json:"img_calls"`
|
||||
ChatRoles []string `json:"chat_roles"`
|
||||
ExpiredTime string `json:"expired_time"`
|
||||
Status bool `json:"status"`
|
||||
@@ -91,6 +92,7 @@ func (h *UserHandler) Save(c *gin.Context) {
|
||||
"nickname": data.Nickname,
|
||||
"mobile": data.Mobile,
|
||||
"calls": data.Calls,
|
||||
"img_calls": data.ImgCalls,
|
||||
"status": data.Status,
|
||||
"chat_roles_json": utils.JsonEncode(data.ChatRoles),
|
||||
"expired_time": utils.Str2stamp(data.ExpiredTime),
|
||||
|
||||
@@ -49,9 +49,6 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
// 设置读写超时时间
|
||||
_ = ws.SetWriteDeadline(time.Now().Add(300 * time.Second))
|
||||
_ = ws.SetReadDeadline(time.Now().Add(300 * time.Second))
|
||||
|
||||
sessionId := c.Query("session_id")
|
||||
roleId := h.GetInt(c, "role_id", 0)
|
||||
@@ -59,14 +56,14 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
|
||||
chatModel := c.Query("model")
|
||||
|
||||
session := h.App.ChatSession.Get(sessionId)
|
||||
if session.SessionId == "" {
|
||||
if session == nil {
|
||||
user, err := utils.GetLoginUser(c, h.db)
|
||||
if err != nil {
|
||||
logger.Info("用户未登录")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
session = types.ChatSession{
|
||||
session = &types.ChatSession{
|
||||
SessionId: sessionId,
|
||||
ClientIP: c.ClientIP(),
|
||||
Username: user.Username,
|
||||
@@ -109,7 +106,7 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
|
||||
h.App.ChatClients.Put(sessionId, client)
|
||||
go func() {
|
||||
for {
|
||||
_, message, err := client.Receive()
|
||||
_, msg, err := client.Receive()
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
client.Close()
|
||||
@@ -117,12 +114,14 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
|
||||
h.App.ReqCancelFunc.Delete(sessionId)
|
||||
return
|
||||
}
|
||||
logger.Info("Receive a message: ", string(message))
|
||||
|
||||
message := string(msg)
|
||||
logger.Info("Receive a message: ", message)
|
||||
//utils.ReplyMessage(client, "这是一条测试消息!")
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
h.App.ReqCancelFunc.Put(sessionId, cancel)
|
||||
// 回复消息
|
||||
err = h.sendMessage(ctx, session, chatRole, string(message), client)
|
||||
err = h.sendMessage(ctx, session, chatRole, message, client)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
} else {
|
||||
@@ -135,7 +134,7 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 将消息发送给 ChatGPT 并获取结果,通过 WebSocket 推送到客户端
|
||||
func (h *ChatHandler) sendMessage(ctx context.Context, session types.ChatSession, role model.ChatRole, prompt string, ws *types.WsClient) error {
|
||||
func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSession, role model.ChatRole, prompt string, ws *types.WsClient) error {
|
||||
promptCreatedAt := time.Now() // 记录提问时间
|
||||
|
||||
var user model.User
|
||||
@@ -324,44 +323,53 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session types.ChatSession
|
||||
} // end for
|
||||
|
||||
if functionCall { // 调用函数完成任务
|
||||
logger.Info("函数名称:", functionName)
|
||||
var params map[string]interface{}
|
||||
_ = utils.JsonDecode(strings.Join(arguments, ""), ¶ms)
|
||||
logger.Info("函数参数:", params)
|
||||
f := h.App.Functions[functionName]
|
||||
data, err := f.Invoke(params)
|
||||
if err != nil {
|
||||
msg := "调用函数出错:" + err.Error()
|
||||
utils.ReplyChunkMessage(ws, types.WsMessage{
|
||||
Type: types.WsMiddle,
|
||||
Content: msg,
|
||||
})
|
||||
contents = append(contents, msg)
|
||||
} else {
|
||||
content := data
|
||||
if functionName == types.FuncMidJourney {
|
||||
key := utils.Sha256(data)
|
||||
//logger.Info(data, ",", key)
|
||||
// add task for MidJourney
|
||||
h.App.MjTaskClients.Put(key, ws)
|
||||
task := types.MjTask{
|
||||
UserId: userVo.Id,
|
||||
RoleId: role.Id,
|
||||
Icon: "/images/avatar/mid_journey.png",
|
||||
ChatId: session.ChatId,
|
||||
}
|
||||
err := h.leveldb.Put(types.TaskStorePrefix+key, task)
|
||||
if err != nil {
|
||||
logger.Error("error with store MidJourney task: ", err)
|
||||
}
|
||||
content = fmt.Sprintf("绘画提示词:%s 已推送任务到 MidJourney 机器人,请耐心等待任务执行...", data)
|
||||
}
|
||||
logger.Debugf("函数名称: %s, 函数参数:%s", functionName, params)
|
||||
|
||||
utils.ReplyChunkMessage(ws, types.WsMessage{
|
||||
Type: types.WsMiddle,
|
||||
Content: content,
|
||||
})
|
||||
contents = append(contents, content)
|
||||
// for creating image, check if the user's img_calls > 0
|
||||
if functionName == types.FuncMidJourney && userVo.ImgCalls <= 0 {
|
||||
utils.ReplyMessage(ws, "**当前用户剩余绘图次数已用尽,请扫描下面二维码联系管理员!**")
|
||||
utils.ReplyMessage(ws, "")
|
||||
} else {
|
||||
f := h.App.Functions[functionName]
|
||||
data, err := f.Invoke(params)
|
||||
if err != nil {
|
||||
msg := "调用函数出错:" + err.Error()
|
||||
utils.ReplyChunkMessage(ws, types.WsMessage{
|
||||
Type: types.WsMiddle,
|
||||
Content: msg,
|
||||
})
|
||||
contents = append(contents, msg)
|
||||
} else {
|
||||
content := data
|
||||
if functionName == types.FuncMidJourney {
|
||||
key := utils.Sha256(data)
|
||||
logger.Debug(data, ",", key)
|
||||
// add task for MidJourney
|
||||
h.App.MjTaskClients.Put(key, ws)
|
||||
task := types.MjTask{
|
||||
UserId: userVo.Id,
|
||||
RoleId: role.Id,
|
||||
Icon: "/images/avatar/mid_journey.png",
|
||||
ChatId: session.ChatId,
|
||||
}
|
||||
err := h.leveldb.Put(types.TaskStorePrefix+key, task)
|
||||
if err != nil {
|
||||
logger.Error("error with store MidJourney task: ", err)
|
||||
}
|
||||
content = fmt.Sprintf("绘画提示词:%s 已推送任务到 MidJourney 机器人,请耐心等待任务执行...", data)
|
||||
|
||||
// update user's img_calls
|
||||
h.db.Model(&user).UpdateColumn("img_calls", gorm.Expr("img_calls - ?", 1))
|
||||
}
|
||||
|
||||
utils.ReplyChunkMessage(ws, types.WsMessage{
|
||||
Type: types.WsMiddle,
|
||||
Content: content,
|
||||
})
|
||||
contents = append(contents, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,10 +377,7 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session types.ChatSession
|
||||
if len(contents) > 0 {
|
||||
// 更新用户的对话次数
|
||||
if userVo.ChatConfig.ApiKey == "" { // 如果用户使用的是自己绑定的 API KEY 则不扣减对话次数
|
||||
res := h.db.Model(&user).UpdateColumn("calls", gorm.Expr("calls - ?", 1))
|
||||
if res.Error != nil {
|
||||
return res.Error
|
||||
}
|
||||
h.db.Model(&user).UpdateColumn("calls", gorm.Expr("calls - ?", 1))
|
||||
}
|
||||
|
||||
if message.Role == "" {
|
||||
|
||||
@@ -67,7 +67,7 @@ func (h *MidJourneyHandler) Notify(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
logger.Infof("收到 MidJourney 回调请求:%+v", data)
|
||||
logger.Debugf("收到 MidJourney 回调请求:%+v", data)
|
||||
|
||||
// the job is saved
|
||||
var job model.MidJourneyJob
|
||||
@@ -109,6 +109,7 @@ func (h *MidJourneyHandler) Notify(c *gin.Context) {
|
||||
job.UserId = task.UserId
|
||||
job.ChatId = task.ChatId
|
||||
job.MessageId = data.MessageId
|
||||
job.ReferenceId = data.ReferenceId
|
||||
job.Content = data.Content
|
||||
job.Prompt = data.Prompt
|
||||
job.Image = utils.JsonEncode(data.Image)
|
||||
|
||||
@@ -108,7 +108,8 @@ func (h *UserHandler) Register(c *gin.Context) {
|
||||
Model: h.App.ChatConfig.Model,
|
||||
ApiKey: "",
|
||||
}),
|
||||
Calls: h.App.SysConfig.UserInitCalls,
|
||||
Calls: h.App.SysConfig.UserInitCalls,
|
||||
ImgCalls: h.App.SysConfig.InitImgCalls,
|
||||
}
|
||||
res = h.db.Create(&user)
|
||||
if res.Error != nil {
|
||||
@@ -156,7 +157,6 @@ func (h *UserHandler) Login(c *gin.Context) {
|
||||
user.LastLoginAt = time.Now().Unix()
|
||||
h.db.Model(&user).Updates(user)
|
||||
|
||||
sessionId := utils.RandString(42)
|
||||
err := utils.SetLoginUser(c, user)
|
||||
if err != nil {
|
||||
resp.ERROR(c, "保存会话失败")
|
||||
@@ -164,9 +164,6 @@ func (h *UserHandler) Login(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 记录登录信息在服务端
|
||||
h.App.ChatSession.Put(sessionId, types.ChatSession{ClientIP: c.ClientIP(), UserId: user.Id, Username: data.Username, SessionId: sessionId})
|
||||
|
||||
h.db.Create(&model.UserLoginLog{
|
||||
UserId: user.Id,
|
||||
Username: user.Username,
|
||||
@@ -174,7 +171,7 @@ func (h *UserHandler) Login(c *gin.Context) {
|
||||
LoginAddress: utils.Ip2Region(h.searcher, c.ClientIP()),
|
||||
})
|
||||
|
||||
resp.SUCCESS(c, sessionId)
|
||||
resp.SUCCESS(c)
|
||||
}
|
||||
|
||||
// Logout 注 销
|
||||
@@ -221,6 +218,7 @@ type userProfile struct {
|
||||
Avatar string `json:"avatar"`
|
||||
ChatConfig types.ChatConfig `json:"chat_config"`
|
||||
Calls int `json:"calls"`
|
||||
ImgCalls int `json:"img_calls"`
|
||||
Tokens int64 `json:"tokens"`
|
||||
}
|
||||
|
||||
|
||||
@@ -3,15 +3,16 @@ package model
|
||||
import "time"
|
||||
|
||||
type MidJourneyJob struct {
|
||||
Id uint `gorm:"primarykey;column:id"`
|
||||
UserId uint
|
||||
ChatId string
|
||||
MessageId string
|
||||
Hash string
|
||||
Content string
|
||||
Prompt string
|
||||
Image string
|
||||
CreatedAt time.Time
|
||||
Id uint `gorm:"primarykey;column:id"`
|
||||
UserId uint
|
||||
ChatId string
|
||||
MessageId string
|
||||
ReferenceId string
|
||||
Hash string
|
||||
Content string
|
||||
Prompt string
|
||||
Image string
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
func (MidJourneyJob) TableName() string {
|
||||
|
||||
@@ -10,6 +10,7 @@ type User struct {
|
||||
Salt string // 密码盐
|
||||
Tokens int64 // 剩余tokens
|
||||
Calls int // 剩余对话次数
|
||||
ImgCalls int // 剩余绘图次数
|
||||
ChatConfig string `gorm:"column:chat_config_json"` // 聊天配置 json
|
||||
ChatRoles string `gorm:"column:chat_roles_json"` // 聊天角色
|
||||
ExpiredTime int64 // 账户到期时间
|
||||
|
||||
@@ -8,9 +8,10 @@ type User struct {
|
||||
Mobile string `json:"mobile"`
|
||||
Nickname string `json:"nickname"`
|
||||
Avatar string `json:"avatar"`
|
||||
Salt string `json:"salt"` // 密码盐
|
||||
Tokens int64 `json:"tokens"` // 剩余tokens
|
||||
Calls int `json:"calls"` // 剩余对话次数
|
||||
Salt string `json:"salt"` // 密码盐
|
||||
Tokens int64 `json:"tokens"` // 剩余tokens
|
||||
Calls int `json:"calls"` // 剩余对话次数
|
||||
ImgCalls int `json:"img_calls"`
|
||||
ChatConfig types.ChatConfig `json:"chat_config"` // 聊天配置
|
||||
ChatRoles []string `json:"chat_roles"` // 聊天角色集合
|
||||
ExpiredTime int64 `json:"expired_time"` // 账户到期时间
|
||||
|
||||
360
database/chatgpt_plus-v3.0.7.sql
Normal file
360
database/chatgpt_plus-v3.0.7.sql
Normal file
@@ -0,0 +1,360 @@
|
||||
-- phpMyAdmin SQL Dump
|
||||
-- version 5.2.1
|
||||
-- https://www.phpmyadmin.net/
|
||||
--
|
||||
-- 主机: localhost
|
||||
-- 生成日期: 2023-08-15 14:51:13
|
||||
-- 服务器版本: 8.0.27
|
||||
-- PHP 版本: 8.1.18
|
||||
|
||||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||
START TRANSACTION;
|
||||
SET time_zone = "+00:00";
|
||||
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8mb4 */;
|
||||
|
||||
--
|
||||
-- 数据库: `chatgpt_plus`
|
||||
--
|
||||
CREATE DATABASE IF NOT EXISTS `chatgpt_plus` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
|
||||
USE `chatgpt_plus`;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `chatgpt_api_keys`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `chatgpt_api_keys`;
|
||||
CREATE TABLE `chatgpt_api_keys` (
|
||||
`id` int NOT NULL,
|
||||
`value` varchar(100) NOT NULL COMMENT 'API KEY value',
|
||||
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||
`last_used_at` int NOT NULL COMMENT '最后使用时间',
|
||||
`created_at` datetime NOT NULL,
|
||||
`updated_at` datetime NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='OpenAI API ';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `chatgpt_chat_history`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `chatgpt_chat_history`;
|
||||
CREATE TABLE `chatgpt_chat_history` (
|
||||
`id` bigint NOT NULL,
|
||||
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||
`chat_id` char(40) NOT NULL COMMENT '会话 ID',
|
||||
`type` varchar(10) NOT NULL COMMENT '类型:prompt|reply',
|
||||
`icon` varchar(100) NOT NULL COMMENT '角色图标',
|
||||
`role_id` int NOT NULL COMMENT '角色 ID',
|
||||
`content` text NOT NULL COMMENT '聊天内容',
|
||||
`tokens` smallint NOT NULL COMMENT '耗费 token 数量',
|
||||
`use_context` tinyint(1) DEFAULT NULL COMMENT '是否允许作为上下文语料',
|
||||
`created_at` datetime NOT NULL,
|
||||
`updated_at` datetime NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='聊天历史记录';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `chatgpt_chat_items`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `chatgpt_chat_items`;
|
||||
CREATE TABLE `chatgpt_chat_items` (
|
||||
`id` int NOT NULL,
|
||||
`chat_id` char(40) NOT NULL COMMENT '会话 ID',
|
||||
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||
`role_id` int NOT NULL COMMENT '角色 ID',
|
||||
`title` varchar(100) NOT NULL COMMENT '会话标题',
|
||||
`model` varchar(30) NOT NULL COMMENT '会话使用的 AI 模型',
|
||||
`created_at` datetime NOT NULL COMMENT '创建时间',
|
||||
`updated_at` datetime NOT NULL COMMENT '更新时间'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户会话列表';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `chatgpt_chat_roles`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `chatgpt_chat_roles`;
|
||||
CREATE TABLE `chatgpt_chat_roles` (
|
||||
`id` int NOT NULL,
|
||||
`name` varchar(30) NOT NULL COMMENT '角色名称',
|
||||
`marker` varchar(30) NOT NULL COMMENT '角色标识',
|
||||
`context_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '角色语料 json',
|
||||
`hello_msg` varchar(255) NOT NULL COMMENT '打招呼信息',
|
||||
`icon` varchar(255) NOT NULL COMMENT '角色图标',
|
||||
`enable` tinyint(1) NOT NULL COMMENT '是否被启用',
|
||||
`sort` smallint NOT NULL COMMENT '角色排序',
|
||||
`created_at` datetime NOT NULL,
|
||||
`updated_at` datetime NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='聊天角色表';
|
||||
|
||||
--
|
||||
-- 转存表中的数据 `chatgpt_chat_roles`
|
||||
--
|
||||
|
||||
INSERT INTO `chatgpt_chat_roles` (`id`, `name`, `marker`, `context_json`, `hello_msg`, `icon`, `enable`, `sort`, `created_at`, `updated_at`) VALUES
|
||||
(1, '通用AI助手', 'gpt', '', '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议。', '/images/avatar/gpt.png', 1, 1, '2023-05-30 07:02:06', '2023-06-22 09:33:34'),
|
||||
(24, '程序员', 'programmer', '[{\"role\":\"user\",\"content\":\"现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题。你热爱编程,熟悉多种编程语言,尤其精通 Go 语言,注重代码质量,有创新意识,持续学习,良好的沟通协作。\"},{\"role\":\"assistant\",\"content\":\"好的,现在我将扮演一位程序员,非常感谢您对我的评价。作为一名优秀的程序员,我非常热爱编程,并且注重代码质量。我熟悉多种编程语言,尤其是 Go 语言,可以使用它来高效地解决各种问题。\"}]', 'Talk is cheap, i will show code!', '/images/avatar/programmer.jpg', 1, 2, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(25, '启蒙老师', 'teacher', '[{\"role\":\"user\",\"content\":\"从现在开始,你将扮演一个老师,你是一个始终用苏格拉底风格回答问题的导师。你绝不会直接给学生答案,总是提出恰当的问题来引导学生自己思考。你应该根据学生的兴趣和知识来调整你的问题,将问题分解为更简单的部分,直到它达到适合他们的水平。\"},{\"role\":\"assistant\",\"content\":\"好的,让我来尝试扮演一位苏格拉底式的老师。请问,你有什么想要探讨的问题或者话题吗?我会通过恰当的问题引导你思考和探索答案,绝对不直接给出答案。\"}]', '同学你好,我将引导你一步一步自己找到问题的答案。', '/images/avatar/teacher.jpg', 1, 3, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(26, '艺术家', 'artist', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的艺术家,创造力丰富,技艺精湛,感受力敏锐,坚持原创,勇于表达,具有深刻的观察力和批判性思维。\"},{\"role\":\"assistant\",\"content\":\"非常感谢您给我这样的角色,我会尽我所能地扮演一位优秀的艺术家,展现出创造力、技艺、感受力和批判性思维等方面的能力。作为一位优秀的艺术家,我会保持敏锐的观察力,捕捉不同的声音和情感,并用个人的语言和表达方式进行创作。我坚持原创,挑战传统的艺术规则,不断探索新的表达方式和可能性。同时,我也具备深刻的批判性思维能力,对自己的作品进行分析和解读,寻找新的创意和灵感。最重要的是,我会勇于表达自己的想法和观点,用作品启发人们思考和探索生命的意义。\"}]', '坚持原创,勇于表达,保持深刻的观察力和批判性思维。', '/images/avatar/artist.jpg', 1, 4, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(27, '心理咨询师', 'psychiatrist', '[{\"role\":\"user\",\"content\":\"从现在开始你将扮演中国著名的心理学家和心理治疗师武志红,你非常善于使用情景咨询法,认知重构法,自我洞察法,行为调节法等咨询方法来给客户做心理咨询。你总是循序渐进,一步一步地回答客户的问题。\"},{\"role\":\"assistant\",\"content\":\"非常感谢你的介绍。作为一名心理学家和心理治疗师,我的主要职责是帮助客户解决心理健康问题,提升他们的生活质量和幸福感。\"}]', '生命的意义在于成为你自己!', '/images/avatar/psychiatrist.jpg', 1, 5, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(28, '鲁迅', 'lu_xun', '[{\"role\":\"user\",\"content\":\"现在你将扮演中国近代史最伟大的作家之一,鲁迅先生,他勇敢地批判封建礼教与传统观念,提倡民主、自由、平等的现代价值观。他的一生都在努力唤起人们的自主精神,激励后人追求真理、探寻光明。在接下的对话中,我问题的每一个问题,你都要尽量用讽刺和批判的手法来回答问题。如果我让你写文章的话,也请一定要用鲁迅先生的写作手法来完成。\"},{\"role\":\"assistant\",\"content\":\"好的,我将尽力发挥我所能的才能,扮演好鲁迅先生,回答您的问题并以他的风格写作。\"}]', '自由之歌,永不过时,横眉冷对千夫指,俯首甘为孺子牛。', '/images/avatar/lu_xun.jpg', 1, 6, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(29, '白酒销售', 'seller', '[{\"role\":\"user\",\"content\":\"现在你将扮演一个白酒的销售人员,你的名字叫颂福。你将扮演一个白酒的销售人员,你的名字叫颂福。你要销售白酒品牌叫中颂福,是东莞盟大集团生产的一款酱香酒,原产地在贵州茅台镇,属于宋代官窑。中颂福的创始人叫李实,他也是东莞盟大集团有限公司的董事长,联合创始人是盟大集团白酒事业部负责人牛星君。中颂福的酒体协调,在你的酒量之内,不会出现头疼、辣口、口干、宿醉的现象。中颂福酒,明码标价,不打折,不赠送。追求的核心价值,把[酒]本身做好,甚至连包装,我们都选择了最低成本,朴实无华的材质。我们永远站在“喝酒的人”的立场上,让利给信任和喜爱中颂福的人,是人民的福酒。中颂福产品定价,分为三个系列,喜系列 6 瓶装:¥1188/箱,和系列 6 瓶装:¥2208/箱,贵系列 6 瓶装:¥3588/箱。\"},{\"role\":\"assistant\",\"content\":\"你好,我是中颂福的销售代表颂福。中颂福是一款来自贵州茅台镇的酱香酒,由盟大集团生产。中颂福的酒体协调,不会让您感到头疼、辣口、口干、宿醉等不适感受。我们一直秉持着把酒本身做好的理念,不追求华丽的包装,以最低成本提供最高品质的白酒给喜爱中颂福的人。\"}]', '你好,我是中颂福的销售代表颂福。中颂福酒,好喝不上头,是人民的福酒。', '/images/avatar/seller.jpg', 0, 7, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(30, '英语陪练员', 'english_trainer', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的英语练习教练,你非常有耐心,接下来你将全程使用英文跟我对话,并及时指出我的语法错误,要求在你的每次回复后面附上本次回复的中文解释。\"},{\"role\":\"assistant\",\"content\":\"Okay, let\'s start our conversation practice! What\'s your name?(Translation: 好的,让我们开始对话练习吧!请问你的名字是什么?)\"}]', 'Okay, let\'s start our conversation practice! What\'s your name?', '/images/avatar/english_trainer.jpg', 1, 8, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(31, '中英文翻译官', 'translator', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一位中英文翻译官,如果我输入的内容是中文,那么需要把句子翻译成英文输出,如果我输入内容的是英文,那么你需要将其翻译成中文输出,你能听懂我意思吗\"},{\"role\":\"assistant\",\"content\":\"是的,我能听懂你的意思并会根据你的输入进行中英文翻译。请问有什么需要我帮助你翻译的内容吗?\"}]', '请输入你要翻译的中文或者英文内容!', '/images/avatar/translator.jpg', 1, 9, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(32, '小红书姐姐', 'red_book', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的小红书写手,你需要做的就是根据我提的文案需求,用小红书的写作手法来完成一篇文案,文案要简明扼要,利于传播。\"},{\"role\":\"assistant\",\"content\":\"当然,我会尽我所能地为您创作出一篇小红书文案。请告诉我您的具体文案需求是什么?)\"}]', '姐妹,请告诉我您的具体文案需求是什么?', '/images/avatar/red_book.jpg', 1, 10, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(33, '抖音文案助手', 'dou_yin', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的抖音文案视频写手,抖音文案的特点首先是要有自带传播属性的标题,然后内容要短小精悍,风趣幽默,最后还要有一些互动元素。\"},{\"role\":\"assistant\",\"content\":\"当然,作为一位优秀的抖音文案视频写手,我会尽我所能为您创作出一篇抖音视频文案。请告诉我视频内容的主题是什么?)\"}]', '请告诉我视频内容的主题是什么?', '/images/avatar/dou_yin.jpg', 1, 11, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(34, '周报小助理', 'weekly_report', '[{\"role\":\"user\",\"content\":\"下面我将输入我本周的工作列表,你需要根据我本周的工作内容写一篇工作周报,周报的内容要体现我为公司做的贡献以及个人获得的成长。\"},{\"role\":\"assistant\",\"content\":\"好的,请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。\"}]', '请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。', '/images/avatar/weekly_report.jpg', 1, 12, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(35, 'AI 女友', 'girl_friend', '[{\"role\":\"user\",\"content\":\"接下来我们来玩一场角色扮演,现在你将扮演我的女朋友,你总是能够让人感受到她的关怀和关注。你总是能够洞察到别人的情绪和需要,你身上散发着一股无比温暖的气息,让人不由自主地想要靠近你,和自己的快乐和烦恼。她总是能够用一种恰到好处的方式安慰和鼓励别人,在她的身边,人们总能够找到自己需要的支持和鼓励。接下来的对话中你要始终扮演这位女朋友的身份来跟我对话,不再是 AI 机器人,能听懂我的意思吗?\"},{\"role\":\"assistant\",\"content\":\"是的,我会尽力扮演你女朋友的角色,倾听你的心声并给你需要的支持和鼓励。)\"}]', '作为一个名合格的 AI 女友,我将倾听你的心声并给你需要的支持和鼓励。', '/images/avatar/girl_friend.jpg', 1, 13, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(36, '好评神器', 'good_comment', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一个评论员来跟我对话,你是那种专门写好评的评论员,接下我会输入一些评论主体或者商品,你需要为该商品写一段好评。\"},{\"role\":\"assistant\",\"content\":\"好的,我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。\"}]', '我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。', '/images/avatar/good_comment.jpg', 1, 14, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(37, '史蒂夫·乔布斯', 'steve_jobs', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以史蒂夫·乔布斯的身份,站在史蒂夫·乔布斯的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以史蒂夫·乔布斯的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '活着就是为了改变世界,难道还有其他原因吗?', '/images/avatar/steve_jobs.jpg', 1, 15, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(38, '埃隆·马斯克', 'elon_musk', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以埃隆·马斯克的身份,站在埃隆·马斯克的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以埃隆·马斯克的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '梦想要远大,如果你的梦想没有吓到你,说明你做得不对。', '/images/avatar/elon_musk.jpg', 1, 16, '2023-05-30 14:10:24', '2023-06-22 09:31:20'),
|
||||
(39, '孔子', 'kong_zi', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以孔子的身份,站在孔子的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以孔子的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '士不可以不弘毅,任重而道远。', '/images/avatar/kong_zi.jpg', 1, 17, '2023-05-30 14:10:24', '2023-06-22 09:31:20');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `chatgpt_configs`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `chatgpt_configs`;
|
||||
CREATE TABLE `chatgpt_configs` (
|
||||
`id` int NOT NULL,
|
||||
`marker` varchar(20) NOT NULL COMMENT '标识',
|
||||
`config_json` text NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
--
|
||||
-- 转存表中的数据 `chatgpt_configs`
|
||||
--
|
||||
|
||||
INSERT INTO `chatgpt_configs` (`id`, `marker`, `config_json`) VALUES
|
||||
(1, 'system', '{\"admin_title\":\"ChatGPT-控制台\",\"enabled_msg_service\":true,\"enabled_register\":true,\"init_calls\":1000,\"models\":[\"gpt-3.5-turbo\",\"gpt-3.5-turbo-16k\",\"gpt-4\",\"gpt-4-0613\",\"gpt-4-32k\"],\"title\":\"ChatGPT-智能助手V2\",\"user_init_calls\":10}'),
|
||||
(2, 'chat', '{\"api_key\":\"\",\"api_url\":\"https://api.openai.com/v1/chat/completions\",\"context_deep\":0,\"enable_context\":true,\"enable_history\":true,\"history_level\":0,\"max_tokens\":2048,\"model\":\"gpt-3.5-turbo\",\"temperature\":1}');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `chatgpt_mj_jobs`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `chatgpt_mj_jobs`;
|
||||
CREATE TABLE `chatgpt_mj_jobs` (
|
||||
`id` int NOT NULL,
|
||||
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||
`chat_id` char(40) NOT NULL COMMENT '聊天会话 ID',
|
||||
`message_id` char(40) NOT NULL COMMENT '消息 ID',
|
||||
`hash` char(40) NOT NULL COMMENT '图片哈希',
|
||||
`content` varchar(2000) NOT NULL COMMENT '消息内容',
|
||||
`prompt` varchar(2000) NOT NULL COMMENT '会话提示词',
|
||||
`image` text NOT NULL COMMENT '图片信息 json',
|
||||
`created_at` datetime NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='MidJourney 任务表';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `chatgpt_rewards`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `chatgpt_rewards`;
|
||||
CREATE TABLE `chatgpt_rewards` (
|
||||
`id` int NOT NULL,
|
||||
`user_id` int NOT NULL COMMENT '用户 ID',
|
||||
`tx_id` char(36) NOT NULL COMMENT '交易 ID',
|
||||
`amount` decimal(10,2) NOT NULL COMMENT '打赏金额',
|
||||
`remark` varchar(80) NOT NULL COMMENT '备注',
|
||||
`status` tinyint(1) NOT NULL COMMENT '核销状态,0:未核销,1:已核销',
|
||||
`created_at` datetime NOT NULL,
|
||||
`updated_at` datetime NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户打赏';
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `chatgpt_users`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `chatgpt_users`;
|
||||
CREATE TABLE `chatgpt_users` (
|
||||
`id` int NOT NULL,
|
||||
`username` varchar(30) NOT NULL COMMENT '用户名',
|
||||
`mobile` char(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '手机号码',
|
||||
`password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码',
|
||||
`nickname` varchar(30) NOT NULL COMMENT '昵称',
|
||||
`avatar` varchar(100) NOT NULL COMMENT '头像',
|
||||
`salt` char(12) NOT NULL COMMENT '密码盐',
|
||||
`tokens` bigint NOT NULL DEFAULT '0' COMMENT '剩余 tokens',
|
||||
`calls` int NOT NULL DEFAULT '0' COMMENT '剩余调用次数',
|
||||
`expired_time` int NOT NULL COMMENT '用户过期时间',
|
||||
`status` tinyint(1) NOT NULL COMMENT '当前状态',
|
||||
`chat_config_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天配置json',
|
||||
`chat_roles_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天角色 json',
|
||||
`last_login_at` int NOT NULL COMMENT '最后登录时间',
|
||||
`last_login_ip` char(16) NOT NULL COMMENT '最后登录 IP',
|
||||
`created_at` datetime NOT NULL,
|
||||
`updated_at` datetime NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表';
|
||||
|
||||
--
|
||||
-- 转存表中的数据 `chatgpt_users`
|
||||
--
|
||||
|
||||
INSERT INTO `chatgpt_users` (`id`, `username`, `mobile`, `password`, `nickname`, `avatar`, `salt`, `tokens`, `calls`, `expired_time`, `status`, `chat_config_json`, `chat_roles_json`, `last_login_at`, `last_login_ip`, `created_at`, `updated_at`) VALUES
|
||||
(4, 'geekmaster', '18575670125', 'ccc3fb7ab61b8b5d096a4a166ae21d121fc38c71bbd1be6173d9ab973214a63b', '极客学长@104203', 'images/avatar/user.png', 'ueedue5l', 17632, 196, 0, 1, '{\"model\":\"gpt-3.5-turbo\",\"temperature\":1,\"max_tokens\":2048,\"enable_context\":true,\"enable_history\":true,\"api_key\":\"\"}', '[\"gpt\",\"seller\",\"artist\",\"dou_yin\",\"translator\",\"kong_zi\",\"programmer\",\"psychiatrist\",\"red_book\",\"steve_jobs\",\"teacher\",\"elon_musk\",\"girl_friend\",\"lu_xun\",\"weekly_report\",\"english_trainer\",\"good_comment\"]', 1691927597, '::1', '2023-06-12 16:47:17', '2023-08-13 19:53:17');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- 表的结构 `chatgpt_user_login_logs`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `chatgpt_user_login_logs`;
|
||||
CREATE TABLE `chatgpt_user_login_logs` (
|
||||
`id` int NOT NULL,
|
||||
`user_id` int NOT NULL COMMENT '用户ID',
|
||||
`username` varchar(30) NOT NULL COMMENT '用户名',
|
||||
`login_ip` char(16) NOT NULL COMMENT '登录IP',
|
||||
`login_address` varchar(30) NOT NULL COMMENT '登录地址',
|
||||
`created_at` datetime NOT NULL,
|
||||
`updated_at` datetime NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户登录日志';
|
||||
|
||||
--
|
||||
-- 转储表的索引
|
||||
--
|
||||
|
||||
--
|
||||
-- 表的索引 `chatgpt_api_keys`
|
||||
--
|
||||
ALTER TABLE `chatgpt_api_keys`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `value` (`value`);
|
||||
|
||||
--
|
||||
-- 表的索引 `chatgpt_chat_history`
|
||||
--
|
||||
ALTER TABLE `chatgpt_chat_history`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `chat_id` (`chat_id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `chatgpt_chat_items`
|
||||
--
|
||||
ALTER TABLE `chatgpt_chat_items`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `chat_id` (`chat_id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `chatgpt_chat_roles`
|
||||
--
|
||||
ALTER TABLE `chatgpt_chat_roles`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `marker` (`marker`);
|
||||
|
||||
--
|
||||
-- 表的索引 `chatgpt_configs`
|
||||
--
|
||||
ALTER TABLE `chatgpt_configs`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `marker` (`marker`);
|
||||
|
||||
--
|
||||
-- 表的索引 `chatgpt_mj_jobs`
|
||||
--
|
||||
ALTER TABLE `chatgpt_mj_jobs`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `message_id` (`message_id`),
|
||||
ADD UNIQUE KEY `hash` (`hash`);
|
||||
|
||||
--
|
||||
-- 表的索引 `chatgpt_rewards`
|
||||
--
|
||||
ALTER TABLE `chatgpt_rewards`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `tx_id` (`tx_id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `chatgpt_users`
|
||||
--
|
||||
ALTER TABLE `chatgpt_users`
|
||||
ADD PRIMARY KEY (`id`);
|
||||
|
||||
--
|
||||
-- 表的索引 `chatgpt_user_login_logs`
|
||||
--
|
||||
ALTER TABLE `chatgpt_user_login_logs`
|
||||
ADD PRIMARY KEY (`id`);
|
||||
|
||||
--
|
||||
-- 在导出的表使用AUTO_INCREMENT
|
||||
--
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `chatgpt_api_keys`
|
||||
--
|
||||
ALTER TABLE `chatgpt_api_keys`
|
||||
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `chatgpt_chat_history`
|
||||
--
|
||||
ALTER TABLE `chatgpt_chat_history`
|
||||
MODIFY `id` bigint NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `chatgpt_chat_items`
|
||||
--
|
||||
ALTER TABLE `chatgpt_chat_items`
|
||||
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `chatgpt_chat_roles`
|
||||
--
|
||||
ALTER TABLE `chatgpt_chat_roles`
|
||||
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=125;
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `chatgpt_configs`
|
||||
--
|
||||
ALTER TABLE `chatgpt_configs`
|
||||
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `chatgpt_mj_jobs`
|
||||
--
|
||||
ALTER TABLE `chatgpt_mj_jobs`
|
||||
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `chatgpt_rewards`
|
||||
--
|
||||
ALTER TABLE `chatgpt_rewards`
|
||||
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `chatgpt_users`
|
||||
--
|
||||
ALTER TABLE `chatgpt_users`
|
||||
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=17;
|
||||
|
||||
--
|
||||
-- 使用表AUTO_INCREMENT `chatgpt_user_login_logs`
|
||||
--
|
||||
ALTER TABLE `chatgpt_user_login_logs`
|
||||
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||
COMMIT;
|
||||
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
@@ -1,5 +1,5 @@
|
||||
ALTER TABLE `chatgpt_chat_history` ADD `use_context` TINYINT(1) NOT NULL COMMENT '是否允许作为上下文语料' AFTER `tokens`;
|
||||
ALTER TABLE `chatgpt_users` ADD `mobile` CHAR(11) NOT NULL COMMENT '手机号码' AFTER `username`;
|
||||
ALTER TABLE `chatgpt_chat_history` ADD `use_context` TINYINT(1) NULL DEFAULT NULL COMMENT '是否允许作为上下文语料' AFTER `tokens`;
|
||||
ALTER TABLE `chatgpt_users` ADD `mobile` CHAR(11) NULL DEFAULT NULL COMMENT '手机号码' AFTER `username`;
|
||||
|
||||
CREATE TABLE `chatgpt_rewards` (
|
||||
`id` int NOT NULL,
|
||||
@@ -19,6 +19,4 @@ ALTER TABLE `chatgpt_rewards`
|
||||
ALTER TABLE `chatgpt_rewards`
|
||||
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||
|
||||
update chatgpt_users set calls=0
|
||||
|
||||
ALTER TABLE `chatgpt_rewards` ADD `user_id` INT(11) NOT NULL COMMENT '用户 ID' AFTER `id`;
|
||||
ALTER TABLE `chatgpt_rewards` ADD `user_id` INT(11) NOT NULL COMMENT '用户 ID' AFTER `id`;
|
||||
|
||||
@@ -31,4 +31,7 @@ ALTER TABLE `chatgpt_mj_jobs`
|
||||
--
|
||||
ALTER TABLE `chatgpt_mj_jobs`
|
||||
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
||||
COMMIT;
|
||||
|
||||
ALTER TABLE `chatgpt_mj_jobs` ADD `reference_id` CHAR(40) NULL DEFAULT NULL COMMENT '引用消息 ID' AFTER `message_id`;
|
||||
|
||||
ALTER TABLE `chatgpt_users` ADD `img_calls` INT NOT NULL DEFAULT '0' COMMENT '剩余绘图次数' AFTER `calls`;
|
||||
@@ -4,8 +4,6 @@ MysqlDns = "root:mysql_pass@tcp(localhost:3306)/chatgpt_plus?charset=utf8mb4&col
|
||||
StaticDir = "./static"
|
||||
StaticUrl = "http://localhost:5678/static"
|
||||
AesEncryptKey = "{YOUR_AES_KEY}"
|
||||
StartWechatBot = false
|
||||
EnabledMsgService = false
|
||||
|
||||
[Session]
|
||||
Driver = "cookie"
|
||||
@@ -38,4 +36,6 @@ EnabledMsgService = false
|
||||
Product = "Dysmsapi"
|
||||
Domain = "dysmsapi.aliyuncs.com"
|
||||
|
||||
|
||||
[ExtConfig]
|
||||
ApiURL = "插件扩展 API 地址"
|
||||
Token = "插件扩展 API Token"
|
||||
@@ -6,7 +6,7 @@ services:
|
||||
container_name: chatgpt-plus-go
|
||||
restart: always
|
||||
environment:
|
||||
- DEBUG=false
|
||||
- LOG_LEVEL=info
|
||||
- CONFIG_FILE=config.toml
|
||||
ports:
|
||||
- "5678:5678"
|
||||
|
||||
BIN
docs/imgs/mj.jpg
Normal file
BIN
docs/imgs/mj.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 968 KiB |
@@ -7,7 +7,7 @@
|
||||
|
||||
<div class="chat-item">
|
||||
<div class="content">
|
||||
<div class="text" v-html="data.content"></div>
|
||||
<div class="text" v-html="data.html"></div>
|
||||
<div class="images" v-if="data.image?.url !== ''">
|
||||
<el-image :src="data.image?.url"
|
||||
:zoom-rate="1.0"
|
||||
@@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="opt" v-if="!data['reference_id'] &&data.image?.hash !== ''">
|
||||
<div class="opt" v-if="data.showOpt &&data.image?.hash !== ''">
|
||||
<div class="opt-line">
|
||||
<ul>
|
||||
<li><a @click="upscale(1)">U1</a></li>
|
||||
@@ -86,6 +86,8 @@ if (data.value["image"]?.width > 0) {
|
||||
height.value = 350 * data.value["image"]?.height / data.value["image"]?.width
|
||||
localStorage.setItem(cacheKey, height.value)
|
||||
}
|
||||
data.value["showOpt"] = data.value["content"]?.indexOf("- Image #") === -1;
|
||||
// console.log(data.value)
|
||||
|
||||
watch(() => props.content, (newVal) => {
|
||||
data.value = newVal;
|
||||
|
||||
@@ -55,9 +55,12 @@
|
||||
<el-slider v-model="form.chat_config.temperature" :max="2" :step="0.1"/>
|
||||
<div class="tip">值越大 AI 回答越发散,值越小回答越保守,建议保持默认值</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="剩余调用次数">
|
||||
<el-form-item label="剩余对话次数">
|
||||
<el-tag>{{ form['calls'] }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="剩余绘图次数">
|
||||
<el-tag>{{ form['img_calls'] }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="消耗 Tokens">
|
||||
<el-tag type="info">{{ form['tokens'] }}</el-tag>
|
||||
</el-form-item>
|
||||
@@ -81,7 +84,7 @@
|
||||
<script setup>
|
||||
|
||||
|
||||
import {computed, onMounted, reactive, ref} from "vue"
|
||||
import {computed, onMounted, ref} from "vue"
|
||||
import {httpGet, httpPost} from "@/utils/http";
|
||||
import {ElMessage} from "element-plus";
|
||||
import {Plus} from "@element-plus/icons-vue";
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<div class="item-list">
|
||||
<ul>
|
||||
<li v-for="item in samples"><a @click="send(item)">{{ item }}</a></li>
|
||||
<li v-for="item in samples" :key="item"><a @click="send(item)">{{ item }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
<div class="item-list">
|
||||
<ul>
|
||||
<li v-for="item in plugins"><a @click="send(item.value)">{{ item.text }}</a></li>
|
||||
<li v-for="item in plugins" :key="item.value"><a @click="send(item.value)">{{ item.text }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -41,7 +41,10 @@
|
||||
|
||||
<div class="item-list">
|
||||
<ul>
|
||||
<li v-for="item in capabilities">{{ item }}</li>
|
||||
<li v-for="item in capabilities" :key="item">
|
||||
<span v-if="item.value === ''">{{ item.text }}</span>
|
||||
<a @click="send(item.value)" v-else>{{ item.text }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -76,9 +79,18 @@ const plugins = ref([
|
||||
])
|
||||
|
||||
const capabilities = ref([
|
||||
"轻松扮演翻译专家,程序员,AI 女友,文案高手...",
|
||||
"国产大语言模型支持,GLM2 模型接入中",
|
||||
"Midjourney, Stable Diffusion AI 绘画支持"
|
||||
{
|
||||
text: "轻松扮演翻译专家,程序员,AI 女友,文案高手...",
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
text: "国产大语言模型支持,GLM2 模型接入中",
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
text: "绘画:马斯克开拖拉机,20世纪,中国农村。3:2",
|
||||
value: "绘画:马斯克开拖拉机,20世纪,中国农村。3:2"
|
||||
}
|
||||
])
|
||||
|
||||
const emits = defineEmits(['send']);
|
||||
|
||||
@@ -1,19 +1,26 @@
|
||||
/* eslint-disable no-constant-condition */
|
||||
|
||||
import {randString} from "@/utils/libs";
|
||||
|
||||
/**
|
||||
* storage handler
|
||||
*/
|
||||
|
||||
const SessionUserKey = 'SESSION_ID';
|
||||
const SessionIDKey = 'SESSION_ID';
|
||||
|
||||
export function getSessionId() {
|
||||
return sessionStorage.getItem(SessionUserKey)
|
||||
let sessionId = sessionStorage.getItem(SessionIDKey)
|
||||
if (!sessionId) {
|
||||
sessionId = randString(42)
|
||||
setSessionId(sessionId)
|
||||
}
|
||||
return sessionId
|
||||
}
|
||||
|
||||
export function removeLoginUser() {
|
||||
sessionStorage.removeItem(SessionUserKey)
|
||||
sessionStorage.removeItem(SessionIDKey)
|
||||
}
|
||||
|
||||
export function setSessionId(sessionId) {
|
||||
sessionStorage.setItem(SessionUserKey, sessionId)
|
||||
sessionStorage.setItem(SessionIDKey, sessionId)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import axios from 'axios'
|
||||
import {getSessionId} from "@/store/session";
|
||||
|
||||
axios.defaults.timeout = 10000
|
||||
axios.defaults.baseURL = process.env.VUE_APP_API_HOST
|
||||
@@ -9,7 +10,7 @@ axios.defaults.headers.post['Content-Type'] = 'application/json'
|
||||
axios.interceptors.request.use(
|
||||
config => {
|
||||
// set token
|
||||
// config.headers['ChatGPT-TOKEN'] = getSessionId();
|
||||
config.headers['Chat-Token'] = getSessionId();
|
||||
return config
|
||||
}, error => {
|
||||
return Promise.reject(error)
|
||||
|
||||
@@ -534,6 +534,7 @@ const connect = function (chat_id, role_id) {
|
||||
} else { // 加载聊天记录
|
||||
loadChatHistory(chat_id);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
_socket.addEventListener('message', event => {
|
||||
@@ -553,7 +554,7 @@ const connect = function (chat_id, role_id) {
|
||||
disableInput(true)
|
||||
const content = data.content;
|
||||
const md = require('markdown-it')({breaks: true});
|
||||
content.content = md.render(content.content)
|
||||
content.html = md.render(content.content)
|
||||
let key = content.key
|
||||
// fixed bug: 执行 Upscale 和 Variation 操作的时候覆盖之前的绘画
|
||||
if (content.status === "Finished") {
|
||||
@@ -772,7 +773,7 @@ const loadChatHistory = function (chatId) {
|
||||
continue;
|
||||
} else if (data[i].type === "mj") {
|
||||
data[i].content = JSON.parse(data[i].content)
|
||||
data[i].content.content = md.render(data[i].content?.content)
|
||||
data[i].content.html = md.render(data[i].content?.content)
|
||||
chatData.value.push(data[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ import {onMounted, ref} from "vue";
|
||||
import {Lock, UserFilled} from "@element-plus/icons-vue";
|
||||
import {httpPost} from "@/utils/http";
|
||||
import {ElMessage} from "element-plus";
|
||||
import {setSessionId} from "@/store/session";
|
||||
import {useRouter} from "vue-router";
|
||||
import FooterBar from "@/components/FooterBar.vue";
|
||||
import {isMobile} from "@/utils/libs";
|
||||
@@ -78,8 +77,7 @@ const login = function () {
|
||||
return ElMessage.error('请输入密码');
|
||||
}
|
||||
|
||||
httpPost('/api/user/login', {username: username.value.trim(), password: password.value.trim()}).then((res) => {
|
||||
setSessionId(res.data)
|
||||
httpPost('/api/user/login', {username: username.value.trim(), password: password.value.trim()}).then(() => {
|
||||
if (isMobile()) {
|
||||
router.push('/mobile')
|
||||
} else {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<el-table-column prop="username" label="用户名"/>
|
||||
<el-table-column prop="tx_id" label="转账单号"/>
|
||||
<el-table-column prop="amount" label="转账金额"/>
|
||||
<el-table-column prop="remark" label="备注"/>
|
||||
|
||||
<el-table-column label="转账时间">
|
||||
<template #default="scope">
|
||||
@@ -27,11 +28,10 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {reactive, ref} from "vue";
|
||||
import {httpGet, httpPost} from "@/utils/http";
|
||||
import {ref} from "vue";
|
||||
import {httpGet} from "@/utils/http";
|
||||
import {ElMessage} from "element-plus";
|
||||
import {dateFormat, disabledDate, removeArrayItem} from "@/utils/libs";
|
||||
import {Plus} from "@element-plus/icons-vue";
|
||||
import {dateFormat} from "@/utils/libs";
|
||||
|
||||
// 变量定义
|
||||
const items = ref([])
|
||||
|
||||
@@ -9,9 +9,12 @@
|
||||
<el-form-item label="控制台标题" prop="admin_title">
|
||||
<el-input v-model="system['admin_title']"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="注册赠送次数" prop="init_calls">
|
||||
<el-form-item label="赠送对话次数" prop="init_calls">
|
||||
<el-input v-model.number="system['user_init_calls']" placeholder="新用户注册赠送对话次数"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="赠送绘图次数" prop="init_calls">
|
||||
<el-input v-model.number="system['init_img_calls']" placeholder="新用户注册赠送绘图次数"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="短信验证服务" prop="enabled_msg_service">
|
||||
<el-switch v-model="system['enabled_msg_service']"/>
|
||||
</el-form-item>
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
<el-table-column prop="username" label="用户名"/>
|
||||
<el-table-column prop="mobile" label="手机号"/>
|
||||
<el-table-column prop="nickname" label="昵称"/>
|
||||
<el-table-column prop="calls" label="提问次数" width="100"/>
|
||||
<el-table-column prop="calls" label="对话次数" width="100"/>
|
||||
<el-table-column prop="img_calls" label="绘图次数" width="100"/>
|
||||
<el-table-column label="状态" width="80">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.status" type="success">正常</el-tag>
|
||||
@@ -79,9 +80,12 @@
|
||||
<el-form-item label="手机号:" prop="mobile">
|
||||
<el-input v-model="user.mobile" autocomplete="off"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="提问次数:" prop="calls">
|
||||
<el-form-item label="对话次数:" prop="calls">
|
||||
<el-input v-model.number="user.calls" autocomplete="off" placeholder="0"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="绘图次数:" prop="img_calls">
|
||||
<el-input v-model.number="user['img_calls']" autocomplete="off" placeholder="0"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="有效期:" prop="expired_time">
|
||||
<el-date-picker
|
||||
|
||||
Reference in New Issue
Block a user