mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-11-07 09:43:43 +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
|
## v3.0.6
|
||||||
|
|
||||||
1. 管理后台:新增用户名和手机号码搜索功能
|
1. 管理后台:新增用户名和手机号码搜索功能
|
||||||
2. 管理后台:新增重置用户密码功能
|
2. 管理后台:新增重置用户密码功能
|
||||||
3. 管理后台:支持关闭注册功能,新增添加用户功能,适用于内部使用场景
|
3. 管理后台:支持关闭注册功能,新增添加用户功能,适用于内部使用场景
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

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

|

|
||||||
@@ -44,7 +46,7 @@
|
|||||||
|
|
||||||
### 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 = ["YOUR_PROXY_URL"] # 替换成你本地代理,如:http://127.0.0.1:7777
|
||||||
#ProxyURL = "" 如果你的服务器本身就在墙外,那么你直接留空就好了
|
#ProxyURL = "" 如果你的服务器本身就在墙外,那么你直接留空就好了
|
||||||
MysqlDns = "root:12345678@tcp(172.22.11.200:3307)/chatgpt_plus?charset=utf8&parseTime=True&loc=Local"
|
MysqlDns = "root:12345678@tcp(172.22.11.200:3307)/chatgpt_plus?charset=utf8&parseTime=True&loc=Local"
|
||||||
StartWechatBot = false # 是否启动微信机器人,默认关闭,如果设置为 TRUE 则启动服务的时候需要微信扫码登录
|
|
||||||
EnabledMsgService = false # 注册时是否开启短信验证功能,该功能需要配合短信服务一起使用
|
|
||||||
|
|
||||||
[Session]
|
[Session]
|
||||||
SecretKey = "azyehq3ivunjhbntz78isj00i4hz2mt9xtddysfucxakadq4qbfrt0b7q3lnvg80"
|
SecretKey = "azyehq3ivunjhbntz78isj00i4hz2mt9xtddysfucxakadq4qbfrt0b7q3lnvg80"
|
||||||
@@ -155,7 +155,7 @@ EnabledMsgService = false # 注册时是否开启短信验证功能,该功能
|
|||||||
Username = "admin"
|
Username = "admin"
|
||||||
Password = "admin123" # 如果是生产环境的话,这里管理员的密码记得修改
|
Password = "admin123" # 如果是生产环境的话,这里管理员的密码记得修改
|
||||||
|
|
||||||
[ApiConfig] # 插件 API 服务配置,此为第三方插件服务,如需使用请联系作者开通
|
[ApiConfig] # 微博热搜,今日头条等函数服务 API 配置,此为第三方插件服务,如需使用请联系作者开通
|
||||||
ApiURL = "{URL}"
|
ApiURL = "{URL}"
|
||||||
AppId = "{APP_ID}"
|
AppId = "{APP_ID}"
|
||||||
Token = "{TOKEN}"
|
Token = "{TOKEN}"
|
||||||
@@ -166,8 +166,14 @@ EnabledMsgService = false # 注册时是否开启短信验证功能,该功能
|
|||||||
Product = "Dysmsapi"
|
Product = "Dysmsapi"
|
||||||
Domain = "dysmsapi.aliyuncs.com"
|
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 地址。
|
修改 nginx 配置文档 `docker/conf/nginx/conf.d/chatgpt-plus.conf`,把后端转发的地址改成当前主机的内网 IP 地址。
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
@@ -284,7 +290,6 @@ make clean linux
|
|||||||
## 参与贡献
|
## 参与贡献
|
||||||
|
|
||||||
个人的力量始终有限,任何形式的贡献都是欢迎的,包括但不限于贡献代码,优化文档,提交 issue 和 PR 等。
|
个人的力量始终有限,任何形式的贡献都是欢迎的,包括但不限于贡献代码,优化文档,提交 issue 和 PR 等。
|
||||||
**尤其是新版本的开发计划比较大,包括各种语言的后端 API 实现,本人精力有限,希望借助社区的力量来完成这些 API 的开发。**
|
|
||||||
|
|
||||||
如果有兴趣的话,也可以加微信进入微信讨论群(**添加好友时请注明来自Github!!!**)。
|
如果有兴趣的话,也可以加微信进入微信讨论群(**添加好友时请注明来自Github!!!**)。
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ MysqlDns = "root:mysql_pass@tcp(localhost:3306)/chatgpt_plus?charset=utf8mb4&col
|
|||||||
StaticDir = "./static"
|
StaticDir = "./static"
|
||||||
StaticUrl = "http://localhost:5678/static"
|
StaticUrl = "http://localhost:5678/static"
|
||||||
AesEncryptKey = "{YOUR_AES_KEY}"
|
AesEncryptKey = "{YOUR_AES_KEY}"
|
||||||
StartWechatBot = false
|
|
||||||
EnabledMsgService = false
|
|
||||||
|
|
||||||
[Session]
|
[Session]
|
||||||
Driver = "cookie"
|
Driver = "cookie"
|
||||||
@@ -38,4 +36,6 @@ EnabledMsgService = false
|
|||||||
Product = "Dysmsapi"
|
Product = "Dysmsapi"
|
||||||
Domain = "dysmsapi.aliyuncs.com"
|
Domain = "dysmsapi.aliyuncs.com"
|
||||||
|
|
||||||
|
[ExtConfig]
|
||||||
|
ApiURL = "插件扩展 API 地址"
|
||||||
|
Token = "插件扩展 API Token"
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ type AppServer struct {
|
|||||||
|
|
||||||
// 保存 Websocket 会话 UserId, 每个 UserId 只能连接一次
|
// 保存 Websocket 会话 UserId, 每个 UserId 只能连接一次
|
||||||
// 防止第三方直接连接 socket 调用 OpenAI API
|
// 防止第三方直接连接 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 连接集合
|
ChatClients *types.LMap[string, *types.WsClient] // map[sessionId]Websocket 连接集合
|
||||||
ReqCancelFunc *types.LMap[string, context.CancelFunc] // HttpClient 请求取消 handle function
|
ReqCancelFunc *types.LMap[string, context.CancelFunc] // HttpClient 请求取消 handle function
|
||||||
Functions map[string]function.Function
|
Functions map[string]function.Function
|
||||||
@@ -45,7 +45,7 @@ func NewServer(appConfig *types.AppConfig, functions map[string]function.Functio
|
|||||||
Config: appConfig,
|
Config: appConfig,
|
||||||
Engine: gin.Default(),
|
Engine: gin.Default(),
|
||||||
ChatContexts: types.NewLMap[string, []interface{}](),
|
ChatContexts: types.NewLMap[string, []interface{}](),
|
||||||
ChatSession: types.NewLMap[string, types.ChatSession](),
|
ChatSession: types.NewLMap[string, *types.ChatSession](),
|
||||||
ChatClients: types.NewLMap[string, *types.WsClient](),
|
ChatClients: types.NewLMap[string, *types.WsClient](),
|
||||||
ReqCancelFunc: types.NewLMap[string, context.CancelFunc](),
|
ReqCancelFunc: types.NewLMap[string, context.CancelFunc](),
|
||||||
MjTaskClients: types.NewLMap[string, *types.WsClient](),
|
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-Origin", origin)
|
||||||
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
|
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")
|
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"`
|
AdminTitle string `json:"admin_title"`
|
||||||
Models []string `json:"models"`
|
Models []string `json:"models"`
|
||||||
UserInitCalls int `json:"user_init_calls"` // 新用户注册默认总送多少次调用
|
UserInitCalls int `json:"user_init_calls"` // 新用户注册默认总送多少次调用
|
||||||
|
InitImgCalls int `json:"init_img_calls"`
|
||||||
EnabledRegister bool `json:"enabled_register"`
|
EnabledRegister bool `json:"enabled_register"`
|
||||||
EnabledMsgService bool `json:"enabled_msg_service"`
|
EnabledMsgService bool `json:"enabled_msg_service"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ type MKey interface {
|
|||||||
string | int
|
string | int
|
||||||
}
|
}
|
||||||
type MValue interface {
|
type MValue interface {
|
||||||
*WsClient | ChatSession | context.CancelFunc | []interface{} | MjTask
|
*WsClient | *ChatSession | context.CancelFunc | []interface{} | MjTask
|
||||||
}
|
}
|
||||||
type LMap[K MKey, T MValue] struct {
|
type LMap[K MKey, T MValue] struct {
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ func (h *UserHandler) Save(c *gin.Context) {
|
|||||||
Mobile string `json:"mobile"`
|
Mobile string `json:"mobile"`
|
||||||
Nickname string `json:"nickname"`
|
Nickname string `json:"nickname"`
|
||||||
Calls int `json:"calls"`
|
Calls int `json:"calls"`
|
||||||
|
ImgCalls int `json:"img_calls"`
|
||||||
ChatRoles []string `json:"chat_roles"`
|
ChatRoles []string `json:"chat_roles"`
|
||||||
ExpiredTime string `json:"expired_time"`
|
ExpiredTime string `json:"expired_time"`
|
||||||
Status bool `json:"status"`
|
Status bool `json:"status"`
|
||||||
@@ -91,6 +92,7 @@ func (h *UserHandler) Save(c *gin.Context) {
|
|||||||
"nickname": data.Nickname,
|
"nickname": data.Nickname,
|
||||||
"mobile": data.Mobile,
|
"mobile": data.Mobile,
|
||||||
"calls": data.Calls,
|
"calls": data.Calls,
|
||||||
|
"img_calls": data.ImgCalls,
|
||||||
"status": data.Status,
|
"status": data.Status,
|
||||||
"chat_roles_json": utils.JsonEncode(data.ChatRoles),
|
"chat_roles_json": utils.JsonEncode(data.ChatRoles),
|
||||||
"expired_time": utils.Str2stamp(data.ExpiredTime),
|
"expired_time": utils.Str2stamp(data.ExpiredTime),
|
||||||
|
|||||||
@@ -49,9 +49,6 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
|
|||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 设置读写超时时间
|
|
||||||
_ = ws.SetWriteDeadline(time.Now().Add(300 * time.Second))
|
|
||||||
_ = ws.SetReadDeadline(time.Now().Add(300 * time.Second))
|
|
||||||
|
|
||||||
sessionId := c.Query("session_id")
|
sessionId := c.Query("session_id")
|
||||||
roleId := h.GetInt(c, "role_id", 0)
|
roleId := h.GetInt(c, "role_id", 0)
|
||||||
@@ -59,14 +56,14 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
|
|||||||
chatModel := c.Query("model")
|
chatModel := c.Query("model")
|
||||||
|
|
||||||
session := h.App.ChatSession.Get(sessionId)
|
session := h.App.ChatSession.Get(sessionId)
|
||||||
if session.SessionId == "" {
|
if session == nil {
|
||||||
user, err := utils.GetLoginUser(c, h.db)
|
user, err := utils.GetLoginUser(c, h.db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Info("用户未登录")
|
logger.Info("用户未登录")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session = types.ChatSession{
|
session = &types.ChatSession{
|
||||||
SessionId: sessionId,
|
SessionId: sessionId,
|
||||||
ClientIP: c.ClientIP(),
|
ClientIP: c.ClientIP(),
|
||||||
Username: user.Username,
|
Username: user.Username,
|
||||||
@@ -109,7 +106,7 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
|
|||||||
h.App.ChatClients.Put(sessionId, client)
|
h.App.ChatClients.Put(sessionId, client)
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
_, message, err := client.Receive()
|
_, msg, err := client.Receive()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
client.Close()
|
client.Close()
|
||||||
@@ -117,12 +114,14 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
|
|||||||
h.App.ReqCancelFunc.Delete(sessionId)
|
h.App.ReqCancelFunc.Delete(sessionId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.Info("Receive a message: ", string(message))
|
|
||||||
|
message := string(msg)
|
||||||
|
logger.Info("Receive a message: ", message)
|
||||||
//utils.ReplyMessage(client, "这是一条测试消息!")
|
//utils.ReplyMessage(client, "这是一条测试消息!")
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
h.App.ReqCancelFunc.Put(sessionId, cancel)
|
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 {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
} else {
|
} else {
|
||||||
@@ -135,7 +134,7 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 将消息发送给 ChatGPT 并获取结果,通过 WebSocket 推送到客户端
|
// 将消息发送给 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() // 记录提问时间
|
promptCreatedAt := time.Now() // 记录提问时间
|
||||||
|
|
||||||
var user model.User
|
var user model.User
|
||||||
@@ -324,44 +323,53 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session types.ChatSession
|
|||||||
} // end for
|
} // end for
|
||||||
|
|
||||||
if functionCall { // 调用函数完成任务
|
if functionCall { // 调用函数完成任务
|
||||||
logger.Info("函数名称:", functionName)
|
|
||||||
var params map[string]interface{}
|
var params map[string]interface{}
|
||||||
_ = utils.JsonDecode(strings.Join(arguments, ""), ¶ms)
|
_ = utils.JsonDecode(strings.Join(arguments, ""), ¶ms)
|
||||||
logger.Info("函数参数:", params)
|
logger.Debugf("函数名称: %s, 函数参数:%s", functionName, 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
utils.ReplyChunkMessage(ws, types.WsMessage{
|
// for creating image, check if the user's img_calls > 0
|
||||||
Type: types.WsMiddle,
|
if functionName == types.FuncMidJourney && userVo.ImgCalls <= 0 {
|
||||||
Content: content,
|
utils.ReplyMessage(ws, "**当前用户剩余绘图次数已用尽,请扫描下面二维码联系管理员!**")
|
||||||
})
|
utils.ReplyMessage(ws, "")
|
||||||
contents = append(contents, content)
|
} 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 len(contents) > 0 {
|
||||||
// 更新用户的对话次数
|
// 更新用户的对话次数
|
||||||
if userVo.ChatConfig.ApiKey == "" { // 如果用户使用的是自己绑定的 API KEY 则不扣减对话次数
|
if userVo.ChatConfig.ApiKey == "" { // 如果用户使用的是自己绑定的 API KEY 则不扣减对话次数
|
||||||
res := h.db.Model(&user).UpdateColumn("calls", gorm.Expr("calls - ?", 1))
|
h.db.Model(&user).UpdateColumn("calls", gorm.Expr("calls - ?", 1))
|
||||||
if res.Error != nil {
|
|
||||||
return res.Error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if message.Role == "" {
|
if message.Role == "" {
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ func (h *MidJourneyHandler) Notify(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Infof("收到 MidJourney 回调请求:%+v", data)
|
logger.Debugf("收到 MidJourney 回调请求:%+v", data)
|
||||||
|
|
||||||
// the job is saved
|
// the job is saved
|
||||||
var job model.MidJourneyJob
|
var job model.MidJourneyJob
|
||||||
@@ -109,6 +109,7 @@ func (h *MidJourneyHandler) Notify(c *gin.Context) {
|
|||||||
job.UserId = task.UserId
|
job.UserId = task.UserId
|
||||||
job.ChatId = task.ChatId
|
job.ChatId = task.ChatId
|
||||||
job.MessageId = data.MessageId
|
job.MessageId = data.MessageId
|
||||||
|
job.ReferenceId = data.ReferenceId
|
||||||
job.Content = data.Content
|
job.Content = data.Content
|
||||||
job.Prompt = data.Prompt
|
job.Prompt = data.Prompt
|
||||||
job.Image = utils.JsonEncode(data.Image)
|
job.Image = utils.JsonEncode(data.Image)
|
||||||
|
|||||||
@@ -108,7 +108,8 @@ func (h *UserHandler) Register(c *gin.Context) {
|
|||||||
Model: h.App.ChatConfig.Model,
|
Model: h.App.ChatConfig.Model,
|
||||||
ApiKey: "",
|
ApiKey: "",
|
||||||
}),
|
}),
|
||||||
Calls: h.App.SysConfig.UserInitCalls,
|
Calls: h.App.SysConfig.UserInitCalls,
|
||||||
|
ImgCalls: h.App.SysConfig.InitImgCalls,
|
||||||
}
|
}
|
||||||
res = h.db.Create(&user)
|
res = h.db.Create(&user)
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
@@ -156,7 +157,6 @@ func (h *UserHandler) Login(c *gin.Context) {
|
|||||||
user.LastLoginAt = time.Now().Unix()
|
user.LastLoginAt = time.Now().Unix()
|
||||||
h.db.Model(&user).Updates(user)
|
h.db.Model(&user).Updates(user)
|
||||||
|
|
||||||
sessionId := utils.RandString(42)
|
|
||||||
err := utils.SetLoginUser(c, user)
|
err := utils.SetLoginUser(c, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.ERROR(c, "保存会话失败")
|
resp.ERROR(c, "保存会话失败")
|
||||||
@@ -164,9 +164,6 @@ func (h *UserHandler) Login(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 记录登录信息在服务端
|
|
||||||
h.App.ChatSession.Put(sessionId, types.ChatSession{ClientIP: c.ClientIP(), UserId: user.Id, Username: data.Username, SessionId: sessionId})
|
|
||||||
|
|
||||||
h.db.Create(&model.UserLoginLog{
|
h.db.Create(&model.UserLoginLog{
|
||||||
UserId: user.Id,
|
UserId: user.Id,
|
||||||
Username: user.Username,
|
Username: user.Username,
|
||||||
@@ -174,7 +171,7 @@ func (h *UserHandler) Login(c *gin.Context) {
|
|||||||
LoginAddress: utils.Ip2Region(h.searcher, c.ClientIP()),
|
LoginAddress: utils.Ip2Region(h.searcher, c.ClientIP()),
|
||||||
})
|
})
|
||||||
|
|
||||||
resp.SUCCESS(c, sessionId)
|
resp.SUCCESS(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logout 注 销
|
// Logout 注 销
|
||||||
@@ -221,6 +218,7 @@ type userProfile struct {
|
|||||||
Avatar string `json:"avatar"`
|
Avatar string `json:"avatar"`
|
||||||
ChatConfig types.ChatConfig `json:"chat_config"`
|
ChatConfig types.ChatConfig `json:"chat_config"`
|
||||||
Calls int `json:"calls"`
|
Calls int `json:"calls"`
|
||||||
|
ImgCalls int `json:"img_calls"`
|
||||||
Tokens int64 `json:"tokens"`
|
Tokens int64 `json:"tokens"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,16 @@ package model
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type MidJourneyJob struct {
|
type MidJourneyJob struct {
|
||||||
Id uint `gorm:"primarykey;column:id"`
|
Id uint `gorm:"primarykey;column:id"`
|
||||||
UserId uint
|
UserId uint
|
||||||
ChatId string
|
ChatId string
|
||||||
MessageId string
|
MessageId string
|
||||||
Hash string
|
ReferenceId string
|
||||||
Content string
|
Hash string
|
||||||
Prompt string
|
Content string
|
||||||
Image string
|
Prompt string
|
||||||
CreatedAt time.Time
|
Image string
|
||||||
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func (MidJourneyJob) TableName() string {
|
func (MidJourneyJob) TableName() string {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ type User struct {
|
|||||||
Salt string // 密码盐
|
Salt string // 密码盐
|
||||||
Tokens int64 // 剩余tokens
|
Tokens int64 // 剩余tokens
|
||||||
Calls int // 剩余对话次数
|
Calls int // 剩余对话次数
|
||||||
|
ImgCalls int // 剩余绘图次数
|
||||||
ChatConfig string `gorm:"column:chat_config_json"` // 聊天配置 json
|
ChatConfig string `gorm:"column:chat_config_json"` // 聊天配置 json
|
||||||
ChatRoles string `gorm:"column:chat_roles_json"` // 聊天角色
|
ChatRoles string `gorm:"column:chat_roles_json"` // 聊天角色
|
||||||
ExpiredTime int64 // 账户到期时间
|
ExpiredTime int64 // 账户到期时间
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ type User struct {
|
|||||||
Mobile string `json:"mobile"`
|
Mobile string `json:"mobile"`
|
||||||
Nickname string `json:"nickname"`
|
Nickname string `json:"nickname"`
|
||||||
Avatar string `json:"avatar"`
|
Avatar string `json:"avatar"`
|
||||||
Salt string `json:"salt"` // 密码盐
|
Salt string `json:"salt"` // 密码盐
|
||||||
Tokens int64 `json:"tokens"` // 剩余tokens
|
Tokens int64 `json:"tokens"` // 剩余tokens
|
||||||
Calls int `json:"calls"` // 剩余对话次数
|
Calls int `json:"calls"` // 剩余对话次数
|
||||||
|
ImgCalls int `json:"img_calls"`
|
||||||
ChatConfig types.ChatConfig `json:"chat_config"` // 聊天配置
|
ChatConfig types.ChatConfig `json:"chat_config"` // 聊天配置
|
||||||
ChatRoles []string `json:"chat_roles"` // 聊天角色集合
|
ChatRoles []string `json:"chat_roles"` // 聊天角色集合
|
||||||
ExpiredTime int64 `json:"expired_time"` // 账户到期时间
|
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_chat_history` ADD `use_context` TINYINT(1) NULL DEFAULT NULL COMMENT '是否允许作为上下文语料' AFTER `tokens`;
|
||||||
ALTER TABLE `chatgpt_users` ADD `mobile` CHAR(11) NOT NULL COMMENT '手机号码' AFTER `username`;
|
ALTER TABLE `chatgpt_users` ADD `mobile` CHAR(11) NULL DEFAULT NULL COMMENT '手机号码' AFTER `username`;
|
||||||
|
|
||||||
CREATE TABLE `chatgpt_rewards` (
|
CREATE TABLE `chatgpt_rewards` (
|
||||||
`id` int NOT NULL,
|
`id` int NOT NULL,
|
||||||
@@ -19,6 +19,4 @@ ALTER TABLE `chatgpt_rewards`
|
|||||||
ALTER TABLE `chatgpt_rewards`
|
ALTER TABLE `chatgpt_rewards`
|
||||||
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
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`
|
ALTER TABLE `chatgpt_mj_jobs`
|
||||||
MODIFY `id` int NOT NULL AUTO_INCREMENT;
|
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"
|
StaticDir = "./static"
|
||||||
StaticUrl = "http://localhost:5678/static"
|
StaticUrl = "http://localhost:5678/static"
|
||||||
AesEncryptKey = "{YOUR_AES_KEY}"
|
AesEncryptKey = "{YOUR_AES_KEY}"
|
||||||
StartWechatBot = false
|
|
||||||
EnabledMsgService = false
|
|
||||||
|
|
||||||
[Session]
|
[Session]
|
||||||
Driver = "cookie"
|
Driver = "cookie"
|
||||||
@@ -38,4 +36,6 @@ EnabledMsgService = false
|
|||||||
Product = "Dysmsapi"
|
Product = "Dysmsapi"
|
||||||
Domain = "dysmsapi.aliyuncs.com"
|
Domain = "dysmsapi.aliyuncs.com"
|
||||||
|
|
||||||
|
[ExtConfig]
|
||||||
|
ApiURL = "插件扩展 API 地址"
|
||||||
|
Token = "插件扩展 API Token"
|
||||||
@@ -6,7 +6,7 @@ services:
|
|||||||
container_name: chatgpt-plus-go
|
container_name: chatgpt-plus-go
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
- DEBUG=false
|
- LOG_LEVEL=info
|
||||||
- CONFIG_FILE=config.toml
|
- CONFIG_FILE=config.toml
|
||||||
ports:
|
ports:
|
||||||
- "5678:5678"
|
- "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="chat-item">
|
||||||
<div class="content">
|
<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 !== ''">
|
<div class="images" v-if="data.image?.url !== ''">
|
||||||
<el-image :src="data.image?.url"
|
<el-image :src="data.image?.url"
|
||||||
:zoom-rate="1.0"
|
:zoom-rate="1.0"
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="opt-line">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a @click="upscale(1)">U1</a></li>
|
<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
|
height.value = 350 * data.value["image"]?.height / data.value["image"]?.width
|
||||||
localStorage.setItem(cacheKey, height.value)
|
localStorage.setItem(cacheKey, height.value)
|
||||||
}
|
}
|
||||||
|
data.value["showOpt"] = data.value["content"]?.indexOf("- Image #") === -1;
|
||||||
|
// console.log(data.value)
|
||||||
|
|
||||||
watch(() => props.content, (newVal) => {
|
watch(() => props.content, (newVal) => {
|
||||||
data.value = newVal;
|
data.value = newVal;
|
||||||
|
|||||||
@@ -55,9 +55,12 @@
|
|||||||
<el-slider v-model="form.chat_config.temperature" :max="2" :step="0.1"/>
|
<el-slider v-model="form.chat_config.temperature" :max="2" :step="0.1"/>
|
||||||
<div class="tip">值越大 AI 回答越发散,值越小回答越保守,建议保持默认值</div>
|
<div class="tip">值越大 AI 回答越发散,值越小回答越保守,建议保持默认值</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="剩余调用次数">
|
<el-form-item label="剩余对话次数">
|
||||||
<el-tag>{{ form['calls'] }}</el-tag>
|
<el-tag>{{ form['calls'] }}</el-tag>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="剩余绘图次数">
|
||||||
|
<el-tag>{{ form['img_calls'] }}</el-tag>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="消耗 Tokens">
|
<el-form-item label="消耗 Tokens">
|
||||||
<el-tag type="info">{{ form['tokens'] }}</el-tag>
|
<el-tag type="info">{{ form['tokens'] }}</el-tag>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -81,7 +84,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
|
|
||||||
import {computed, onMounted, reactive, ref} from "vue"
|
import {computed, onMounted, ref} from "vue"
|
||||||
import {httpGet, httpPost} from "@/utils/http";
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import {Plus} from "@element-plus/icons-vue";
|
import {Plus} from "@element-plus/icons-vue";
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<div class="item-list">
|
<div class="item-list">
|
||||||
<ul>
|
<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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
<div class="item-list">
|
<div class="item-list">
|
||||||
<ul>
|
<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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -41,7 +41,10 @@
|
|||||||
|
|
||||||
<div class="item-list">
|
<div class="item-list">
|
||||||
<ul>
|
<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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -76,9 +79,18 @@ const plugins = ref([
|
|||||||
])
|
])
|
||||||
|
|
||||||
const capabilities = ref([
|
const capabilities = ref([
|
||||||
"轻松扮演翻译专家,程序员,AI 女友,文案高手...",
|
{
|
||||||
"国产大语言模型支持,GLM2 模型接入中",
|
text: "轻松扮演翻译专家,程序员,AI 女友,文案高手...",
|
||||||
"Midjourney, Stable Diffusion AI 绘画支持"
|
value: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "国产大语言模型支持,GLM2 模型接入中",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "绘画:马斯克开拖拉机,20世纪,中国农村。3:2",
|
||||||
|
value: "绘画:马斯克开拖拉机,20世纪,中国农村。3:2"
|
||||||
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
const emits = defineEmits(['send']);
|
const emits = defineEmits(['send']);
|
||||||
|
|||||||
@@ -1,19 +1,26 @@
|
|||||||
/* eslint-disable no-constant-condition */
|
/* eslint-disable no-constant-condition */
|
||||||
|
|
||||||
|
import {randString} from "@/utils/libs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* storage handler
|
* storage handler
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const SessionUserKey = 'SESSION_ID';
|
const SessionIDKey = 'SESSION_ID';
|
||||||
|
|
||||||
export function getSessionId() {
|
export function getSessionId() {
|
||||||
return sessionStorage.getItem(SessionUserKey)
|
let sessionId = sessionStorage.getItem(SessionIDKey)
|
||||||
|
if (!sessionId) {
|
||||||
|
sessionId = randString(42)
|
||||||
|
setSessionId(sessionId)
|
||||||
|
}
|
||||||
|
return sessionId
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeLoginUser() {
|
export function removeLoginUser() {
|
||||||
sessionStorage.removeItem(SessionUserKey)
|
sessionStorage.removeItem(SessionIDKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setSessionId(sessionId) {
|
export function setSessionId(sessionId) {
|
||||||
sessionStorage.setItem(SessionUserKey, sessionId)
|
sessionStorage.setItem(SessionIDKey, sessionId)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import {getSessionId} from "@/store/session";
|
||||||
|
|
||||||
axios.defaults.timeout = 10000
|
axios.defaults.timeout = 10000
|
||||||
axios.defaults.baseURL = process.env.VUE_APP_API_HOST
|
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(
|
axios.interceptors.request.use(
|
||||||
config => {
|
config => {
|
||||||
// set token
|
// set token
|
||||||
// config.headers['ChatGPT-TOKEN'] = getSessionId();
|
config.headers['Chat-Token'] = getSessionId();
|
||||||
return config
|
return config
|
||||||
}, error => {
|
}, error => {
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
|
|||||||
@@ -534,6 +534,7 @@ const connect = function (chat_id, role_id) {
|
|||||||
} else { // 加载聊天记录
|
} else { // 加载聊天记录
|
||||||
loadChatHistory(chat_id);
|
loadChatHistory(chat_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
_socket.addEventListener('message', event => {
|
_socket.addEventListener('message', event => {
|
||||||
@@ -553,7 +554,7 @@ const connect = function (chat_id, role_id) {
|
|||||||
disableInput(true)
|
disableInput(true)
|
||||||
const content = data.content;
|
const content = data.content;
|
||||||
const md = require('markdown-it')({breaks: true});
|
const md = require('markdown-it')({breaks: true});
|
||||||
content.content = md.render(content.content)
|
content.html = md.render(content.content)
|
||||||
let key = content.key
|
let key = content.key
|
||||||
// fixed bug: 执行 Upscale 和 Variation 操作的时候覆盖之前的绘画
|
// fixed bug: 执行 Upscale 和 Variation 操作的时候覆盖之前的绘画
|
||||||
if (content.status === "Finished") {
|
if (content.status === "Finished") {
|
||||||
@@ -772,7 +773,7 @@ const loadChatHistory = function (chatId) {
|
|||||||
continue;
|
continue;
|
||||||
} else if (data[i].type === "mj") {
|
} else if (data[i].type === "mj") {
|
||||||
data[i].content = JSON.parse(data[i].content)
|
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]);
|
chatData.value.push(data[i]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ import {onMounted, ref} from "vue";
|
|||||||
import {Lock, UserFilled} from "@element-plus/icons-vue";
|
import {Lock, UserFilled} from "@element-plus/icons-vue";
|
||||||
import {httpPost} from "@/utils/http";
|
import {httpPost} from "@/utils/http";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import {setSessionId} from "@/store/session";
|
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
import FooterBar from "@/components/FooterBar.vue";
|
import FooterBar from "@/components/FooterBar.vue";
|
||||||
import {isMobile} from "@/utils/libs";
|
import {isMobile} from "@/utils/libs";
|
||||||
@@ -78,8 +77,7 @@ const login = function () {
|
|||||||
return ElMessage.error('请输入密码');
|
return ElMessage.error('请输入密码');
|
||||||
}
|
}
|
||||||
|
|
||||||
httpPost('/api/user/login', {username: username.value.trim(), password: password.value.trim()}).then((res) => {
|
httpPost('/api/user/login', {username: username.value.trim(), password: password.value.trim()}).then(() => {
|
||||||
setSessionId(res.data)
|
|
||||||
if (isMobile()) {
|
if (isMobile()) {
|
||||||
router.push('/mobile')
|
router.push('/mobile')
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
<el-table-column prop="username" label="用户名"/>
|
<el-table-column prop="username" label="用户名"/>
|
||||||
<el-table-column prop="tx_id" label="转账单号"/>
|
<el-table-column prop="tx_id" label="转账单号"/>
|
||||||
<el-table-column prop="amount" label="转账金额"/>
|
<el-table-column prop="amount" label="转账金额"/>
|
||||||
|
<el-table-column prop="remark" label="备注"/>
|
||||||
|
|
||||||
<el-table-column label="转账时间">
|
<el-table-column label="转账时间">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@@ -27,11 +28,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {reactive, ref} from "vue";
|
import {ref} from "vue";
|
||||||
import {httpGet, httpPost} from "@/utils/http";
|
import {httpGet} from "@/utils/http";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import {dateFormat, disabledDate, removeArrayItem} from "@/utils/libs";
|
import {dateFormat} from "@/utils/libs";
|
||||||
import {Plus} from "@element-plus/icons-vue";
|
|
||||||
|
|
||||||
// 变量定义
|
// 变量定义
|
||||||
const items = ref([])
|
const items = ref([])
|
||||||
|
|||||||
@@ -9,9 +9,12 @@
|
|||||||
<el-form-item label="控制台标题" prop="admin_title">
|
<el-form-item label="控制台标题" prop="admin_title">
|
||||||
<el-input v-model="system['admin_title']"/>
|
<el-input v-model="system['admin_title']"/>
|
||||||
</el-form-item>
|
</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-input v-model.number="system['user_init_calls']" placeholder="新用户注册赠送对话次数"/>
|
||||||
</el-form-item>
|
</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-form-item label="短信验证服务" prop="enabled_msg_service">
|
||||||
<el-switch v-model="system['enabled_msg_service']"/>
|
<el-switch v-model="system['enabled_msg_service']"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
<el-table-column prop="username" label="用户名"/>
|
<el-table-column prop="username" label="用户名"/>
|
||||||
<el-table-column prop="mobile" label="手机号"/>
|
<el-table-column prop="mobile" label="手机号"/>
|
||||||
<el-table-column prop="nickname" 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">
|
<el-table-column label="状态" width="80">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag v-if="scope.row.status" type="success">正常</el-tag>
|
<el-tag v-if="scope.row.status" type="success">正常</el-tag>
|
||||||
@@ -79,9 +80,12 @@
|
|||||||
<el-form-item label="手机号:" prop="mobile">
|
<el-form-item label="手机号:" prop="mobile">
|
||||||
<el-input v-model="user.mobile" autocomplete="off"/>
|
<el-input v-model="user.mobile" autocomplete="off"/>
|
||||||
</el-form-item>
|
</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-input v-model.number="user.calls" autocomplete="off" placeholder="0"/>
|
||||||
</el-form-item>
|
</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-form-item label="有效期:" prop="expired_time">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
|
|||||||
Reference in New Issue
Block a user