diff --git a/README.md b/README.md index aa1bf80f..303fc242 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ ChatGLM,讯飞星火,文心一言等多个平台的大语言模型。集成了 **演示站不提供任何充值点卡售卖或者VIP充值服务。** 如果您体验过后觉得还不错的话,可以花两分钟用下面的一键部署脚本自己部署一套。 ```shell -bash -c "$(curl -fsSL https://img.r9it.com/tmp/install-v3.2.7-6c232bdaf8.sh)" +bash -c "$(curl -fsSL https://img.r9it.com/tmp/install-v4.0.1-5f1a7c3fc9.sh)" ``` 最新版本的一键部署脚本请参考 [**ChatGPT-Plus 文档**](https://ai.r9it.com/docs/install/)。 diff --git a/api/core/app_server.go b/api/core/app_server.go index d633fc18..2fca4ea7 100644 --- a/api/core/app_server.go +++ b/api/core/app_server.go @@ -217,6 +217,7 @@ func needLogin(c *gin.Context) bool { c.Request.URL.Path == "/api/sd/client" || c.Request.URL.Path == "/api/config/get" || c.Request.URL.Path == "/api/product/list" || + c.Request.URL.Path == "/api/menu/list" || strings.HasPrefix(c.Request.URL.Path, "/api/test") || strings.HasPrefix(c.Request.URL.Path, "/api/function/") || strings.HasPrefix(c.Request.URL.Path, "/api/sms/") || diff --git a/api/core/types/config.go b/api/core/types/config.go index 324c3cad..24a94e78 100644 --- a/api/core/types/config.go +++ b/api/core/types/config.go @@ -144,13 +144,13 @@ type SystemConfig struct { PowerPrice float64 `json:"power_price,omitempty"` // 算力单价 OrderPayTimeout int `json:"order_pay_timeout,omitempty"` //订单支付超时时间 - VipInfoText string `json:"vip_info_text"` // 会员页面充值说明 + VipInfoText string `json:"vip_info_text,omitempty"` // 会员页面充值说明 DefaultModels []int `json:"default_models,omitempty"` // 默认开通的 AI 模型 - MjPower int `json:"mj_power,omitempty"` // MJ 绘画消耗算力 - MjActionPower int `json:"mj_action_power"` // MJ 操作(放大,变换)消耗算力 - SdPower int `json:"sd_power,omitempty"` // SD 绘画消耗算力 - DallPower int `json:"dall_power,omitempty"` // DALLE3 绘图消耗算力 + MjPower int `json:"mj_power,omitempty"` // MJ 绘画消耗算力 + MjActionPower int `json:"mj_action_power,omitempty"` // MJ 操作(放大,变换)消耗算力 + SdPower int `json:"sd_power,omitempty"` // SD 绘画消耗算力 + DallPower int `json:"dall_power,omitempty"` // DALLE3 绘图消耗算力 WechatCardURL string `json:"wechat_card_url,omitempty"` // 微信客服地址 diff --git a/api/handler/admin/menu_handler.go b/api/handler/admin/menu_handler.go new file mode 100644 index 00000000..7358ffa9 --- /dev/null +++ b/api/handler/admin/menu_handler.go @@ -0,0 +1,121 @@ +package admin + +import ( + "chatplus/core" + "chatplus/core/types" + "chatplus/handler" + "chatplus/store/model" + "chatplus/store/vo" + "chatplus/utils" + "chatplus/utils/resp" + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +type MenuHandler struct { + handler.BaseHandler +} + +func NewMenuHandler(app *core.AppServer, db *gorm.DB) *MenuHandler { + return &MenuHandler{BaseHandler: handler.BaseHandler{App: app, DB: db}} +} + +func (h *MenuHandler) Save(c *gin.Context) { + var data struct { + Id uint `json:"id"` + Name string `json:"name"` + Icon string `json:"icon"` + URL string `json:"url"` + SortNum int `json:"sort_num"` + Enabled bool `json:"enabled"` + } + if err := c.ShouldBindJSON(&data); err != nil { + resp.ERROR(c, types.InvalidArgs) + return + } + + res := h.DB.Save(&model.Menu{ + Id: data.Id, + Name: data.Name, + Icon: data.Icon, + URL: data.URL, + SortNum: data.SortNum, + Enabled: data.Enabled, + }) + if res.Error != nil { + resp.ERROR(c, "更新数据库失败!") + return + } + resp.SUCCESS(c) +} + +// List 数据列表 +func (h *MenuHandler) List(c *gin.Context) { + var items []model.Menu + var list = make([]vo.Menu, 0) + res := h.DB.Order("sort_num ASC").Find(&items) + if res.Error == nil { + for _, item := range items { + var product vo.Menu + err := utils.CopyObject(item, &product) + if err == nil { + list = append(list, product) + } + } + } + resp.SUCCESS(c, list) +} + +func (h *MenuHandler) Enable(c *gin.Context) { + var data struct { + Id uint `json:"id"` + Enabled bool `json:"enabled"` + } + + if err := c.ShouldBindJSON(&data); err != nil { + resp.ERROR(c, types.InvalidArgs) + return + } + + res := h.DB.Model(&model.Menu{}).Where("id", data.Id).UpdateColumn("enabled", data.Enabled) + if res.Error != nil { + resp.ERROR(c, "更新数据库失败!") + return + } + resp.SUCCESS(c) +} + +func (h *MenuHandler) Sort(c *gin.Context) { + var data struct { + Ids []uint `json:"ids"` + Sorts []int `json:"sorts"` + } + + if err := c.ShouldBindJSON(&data); err != nil { + resp.ERROR(c, types.InvalidArgs) + return + } + + for index, id := range data.Ids { + res := h.DB.Model(&model.Menu{}).Where("id", id).Update("sort_num", data.Sorts[index]) + if res.Error != nil { + resp.ERROR(c, "更新数据库失败!") + return + } + } + + resp.SUCCESS(c) +} + +func (h *MenuHandler) Remove(c *gin.Context) { + id := h.GetInt(c, "id", 0) + + if id > 0 { + res := h.DB.Where("id", id).Delete(&model.Menu{}) + if res.Error != nil { + resp.ERROR(c, "更新数据库失败!") + return + } + } + resp.SUCCESS(c) +} diff --git a/api/handler/admin/product_handler.go b/api/handler/admin/product_handler.go index 8e960c24..42eff03f 100644 --- a/api/handler/admin/product_handler.go +++ b/api/handler/admin/product_handler.go @@ -65,21 +65,11 @@ func (h *ProductHandler) Save(c *gin.Context) { resp.SUCCESS(c, itemVo) } -// List 模型列表 +// List 数据列表 func (h *ProductHandler) List(c *gin.Context) { - if err := utils.CheckPermission(c, h.DB); err != nil { - resp.NotPermission(c) - return - } - - session := h.DB.Session(&gorm.Session{}) - enable := h.GetBool(c, "enable") - if enable { - session = session.Where("enabled", enable) - } var items []model.Product var list = make([]vo.Product, 0) - res := session.Order("sort_num ASC").Find(&items) + res := h.DB.Order("sort_num ASC").Find(&items) if res.Error == nil { for _, item := range items { var product vo.Product @@ -128,7 +118,7 @@ func (h *ProductHandler) Sort(c *gin.Context) { } for index, id := range data.Ids { - res := h.DB.Model(&model.Product{}).Where("id = ?", id).Update("sort_num", data.Sorts[index]) + res := h.DB.Model(&model.Product{}).Where("id", id).Update("sort_num", data.Sorts[index]) if res.Error != nil { resp.ERROR(c, "更新数据库失败!") return @@ -142,7 +132,7 @@ func (h *ProductHandler) Remove(c *gin.Context) { id := h.GetInt(c, "id", 0) if id > 0 { - res := h.DB.Where("id = ?", id).Delete(&model.Product{}) + res := h.DB.Where("id", id).Delete(&model.Product{}) if res.Error != nil { resp.ERROR(c, "更新数据库失败!") return diff --git a/api/handler/chat_role_handler.go b/api/handler/chat_role_handler.go index 4e48a60b..a555256d 100644 --- a/api/handler/chat_role_handler.go +++ b/api/handler/chat_role_handler.go @@ -25,9 +25,10 @@ func (h *ChatRoleHandler) List(c *gin.Context) { all := h.GetBool(c, "all") userId := h.GetLoginUserId(c) var roles []model.ChatRole + var roleVos = make([]vo.ChatRole, 0) res := h.DB.Where("enable", true).Order("sort_num ASC").Find(&roles) if res.Error != nil { - resp.ERROR(c, "No roles found,"+res.Error.Error()) + resp.SUCCESS(c, roleVos) return } @@ -55,8 +56,7 @@ func (h *ChatRoleHandler) List(c *gin.Context) { resp.ERROR(c, "角色解析失败!") return } - // 转成 vo - var roleVos = make([]vo.ChatRole, 0) + for _, r := range roles { if !utils.ContainsStr(roleKeys, r.Key) { continue diff --git a/api/handler/menu_handler.go b/api/handler/menu_handler.go new file mode 100644 index 00000000..b922f54c --- /dev/null +++ b/api/handler/menu_handler.go @@ -0,0 +1,36 @@ +package handler + +import ( + "chatplus/core" + "chatplus/store/model" + "chatplus/store/vo" + "chatplus/utils" + "chatplus/utils/resp" + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +type MenuHandler struct { + BaseHandler +} + +func NewMenuHandler(app *core.AppServer, db *gorm.DB) *MenuHandler { + return &MenuHandler{BaseHandler: BaseHandler{App: app, DB: db}} +} + +// List 数据列表 +func (h *MenuHandler) List(c *gin.Context) { + var items []model.Menu + var list = make([]vo.Menu, 0) + res := h.DB.Where("enabled", true).Order("sort_num ASC").Find(&items) + if res.Error == nil { + for _, item := range items { + var product vo.Menu + err := utils.CopyObject(item, &product) + if err == nil { + list = append(list, product) + } + } + } + resp.SUCCESS(c, list) +} diff --git a/api/handler/sd_handler.go b/api/handler/sd_handler.go index 9881a35d..09b35d49 100644 --- a/api/handler/sd_handler.go +++ b/api/handler/sd_handler.go @@ -3,6 +3,7 @@ package handler import ( "chatplus/core" "chatplus/core/types" + "chatplus/service" "chatplus/service/oss" "chatplus/service/sd" "chatplus/store/model" @@ -23,15 +24,17 @@ import ( type SdJobHandler struct { BaseHandler - redis *redis.Client - pool *sd.ServicePool - uploader *oss.UploaderManager + redis *redis.Client + pool *sd.ServicePool + uploader *oss.UploaderManager + snowflake *service.Snowflake } -func NewSdJobHandler(app *core.AppServer, db *gorm.DB, pool *sd.ServicePool, manager *oss.UploaderManager) *SdJobHandler { +func NewSdJobHandler(app *core.AppServer, db *gorm.DB, pool *sd.ServicePool, manager *oss.UploaderManager, snowflake *service.Snowflake) *SdJobHandler { return &SdJobHandler{ - pool: pool, - uploader: manager, + pool: pool, + uploader: manager, + snowflake: snowflake, BaseHandler: BaseHandler{ App: app, DB: db, @@ -116,8 +119,13 @@ func (h *SdJobHandler) Image(c *gin.Context) { } idValue, _ := c.Get(types.LoginUserID) userId := utils.IntValue(utils.InterfaceToString(idValue), 0) + taskId, err := h.snowflake.Next(true) + if err != nil { + resp.ERROR(c, "error with generate task id: "+err.Error()) + return + } params := types.SdTaskParams{ - TaskId: fmt.Sprintf("task(%s)", utils.RandString(15)), + TaskId: taskId, Prompt: data.Prompt, NegativePrompt: data.NegativePrompt, Steps: data.Steps, diff --git a/api/main.go b/api/main.go index c5ce4baa..6d82fccb 100644 --- a/api/main.go +++ b/api/main.go @@ -417,6 +417,20 @@ func main() { group := s.Engine.Group("/api/admin/powerLog/") group.POST("list", h.List) }), + fx.Provide(admin.NewMenuHandler), + fx.Invoke(func(s *core.AppServer, h *admin.MenuHandler) { + group := s.Engine.Group("/api/admin/menu/") + group.POST("save", h.Save) + group.GET("list", h.List) + group.POST("enable", h.Enable) + group.POST("sort", h.Sort) + group.GET("remove", h.Remove) + }), + fx.Provide(handler.NewMenuHandler), + fx.Invoke(func(s *core.AppServer, h *handler.MenuHandler) { + group := s.Engine.Group("/api/menu/") + group.GET("list", h.List) + }), fx.Invoke(func(s *core.AppServer, db *gorm.DB) { err := s.Run(db) if err != nil { diff --git a/api/service/mj/pool.go b/api/service/mj/pool.go index 14ea1da4..0143467f 100644 --- a/api/service/mj/pool.go +++ b/api/service/mj/pool.go @@ -181,6 +181,7 @@ func (p *ServicePool) SyncTaskProgress() { CreatedAt: time.Now(), }) } + continue } if servicePlus := p.getService(job.ChannelId); servicePlus != nil { diff --git a/api/service/mj/service.go b/api/service/mj/service.go index 861095d4..f73a9c63 100644 --- a/api/service/mj/service.go +++ b/api/service/mj/service.go @@ -77,6 +77,13 @@ func (s *Service) Run() { } } + var job model.MidJourneyJob + tx := s.db.Where("id = ?", task.Id).First(&job) + if tx.Error != nil { + logger.Error("任务不存在,任务ID:", task.TaskId) + continue + } + logger.Infof("%s handle a new MidJourney task: %+v", s.Name, task) var res ImageRes switch task.Type { @@ -97,8 +104,6 @@ func (s *Service) Run() { break } - var job model.MidJourneyJob - s.db.Where("id = ?", task.Id).First(&job) if err != nil || (res.Code != 1 && res.Code != 22) { errMsg := fmt.Sprintf("%v,%s", err, res.Description) logger.Error("绘画任务执行失败:", errMsg) @@ -127,14 +132,17 @@ func (s *Service) canHandleTask() bool { return handledNum < s.maxHandleTaskNum } -// remove the expired tasks +// remove the timeout tasks func (s *Service) checkTasks() { for k, t := range s.taskStartTimes { if time.Now().Unix()-t.Unix() > s.taskTimeout { delete(s.taskStartTimes, k) atomic.AddInt32(&s.HandledTaskNum, -1) - // delete task from database - s.db.Delete(&model.MidJourneyJob{Id: uint(k)}, "progress < 100") + + s.db.Model(&model.MidJourneyJob{Id: uint(k)}).UpdateColumns(map[string]interface{}{ + "progress": -1, + "err_msg": "任务超时", + }) } } } diff --git a/api/service/sd/service.go b/api/service/sd/service.go index ccb56974..f87067a3 100644 --- a/api/service/sd/service.go +++ b/api/service/sd/service.go @@ -114,6 +114,7 @@ func (s *Service) Txt2Img(task types.SdTask) error { Width: task.Params.Width, Height: task.Params.Height, SamplerName: task.Params.Sampler, + ForceTaskId: task.Params.TaskId, } if task.Params.Seed > 0 { body.Seed = task.Params.Seed diff --git a/api/store/model/menu.go b/api/store/model/menu.go new file mode 100644 index 00000000..e215e204 --- /dev/null +++ b/api/store/model/menu.go @@ -0,0 +1,11 @@ +package model + +// Menu 系统菜单 +type Menu struct { + Id uint `gorm:"primarykey;column:id"` + Name string // 菜单名称 + Icon string // 菜单图标 + URL string // 菜单跳转地址 + SortNum int // 排序 + Enabled bool // 启用状态 +} diff --git a/api/store/vo/menu.go b/api/store/vo/menu.go new file mode 100644 index 00000000..c9975a45 --- /dev/null +++ b/api/store/vo/menu.go @@ -0,0 +1,11 @@ +package vo + +// Menu 系统菜单 +type Menu struct { + Id uint `json:"id"` + Name string `json:"name"` + Icon string `json:"icon"` + URL string `json:"url"` + SortNum int `json:"sort_num"` + Enabled bool `json:"enabled"` +} diff --git a/api/test/test.go b/api/test/test.go index 14362448..79058077 100644 --- a/api/test/test.go +++ b/api/test/test.go @@ -1,11 +1,5 @@ package main -import ( - "chatplus/utils" - "fmt" -) - func main() { - text := "一只 蜗牛在树干上爬,阳光透过树叶照在蜗牛的背上 --ar 1:1 --iw 0.250000 --v 6" - fmt.Println(utils.HasChinese(text)) + } diff --git a/database/update-v4.0.2.sql b/database/update-v4.0.2.sql new file mode 100644 index 00000000..00d7708f --- /dev/null +++ b/database/update-v4.0.2.sql @@ -0,0 +1,19 @@ +-- 菜单表 +CREATE TABLE `chatgpt_plus`.`chatgpt_menus` ( + `id` INT(11) NOT NULL AUTO_INCREMENT , + `name` VARCHAR(30) NOT NULL COMMENT '菜单名称' , + `icon` VARCHAR(150) NOT NULL COMMENT '菜单图标' , + `url` VARCHAR(100) NOT NULL COMMENT '地址' , + `sort_num` SMALLINT(3) NOT NULL COMMENT '排序' , + `enabled` TINYINT(1) NOT NULL COMMENT '是否启用' , + PRIMARY KEY (`id`)) ENGINE = InnoDB COMMENT = '前端菜单表'; + +INSERT INTO `chatgpt_menus` (`id`, `name`, `icon`, `url`, `sort_num`, `enabled`) VALUES + (1, '对话聊天', '/images/menu/chat.png', '/chat', 0, 1), + (5, 'MJ 绘画', '/images/menu/mj.png', '/mj', 1, 1), + (6, 'SD 绘画', '/images/menu/sd.png', '/sd', 2, 1), + (7, '算力日志', '/images/menu/log.png', '/powerLog', 5, 1), + (8, '应用中心', '/images/menu/app.png', '/apps', 3, 1), + (9, '作品展示', '/images/menu/img-wall.png', '/images-wall', 4, 1), + (10, '会员计划', '/images/menu/member.png', '/member', 6, 1), + (11, '分享计划', '/images/menu/share.png', '/invite', 7, 1); \ No newline at end of file diff --git a/deploy/data/mysql/init.d/chatgpt_plus-v4.0.0.sql b/deploy/data/mysql/init.d/chatgpt_plus.sql similarity index 88% rename from deploy/data/mysql/init.d/chatgpt_plus-v4.0.0.sql rename to deploy/data/mysql/init.d/chatgpt_plus.sql index c69f85c2..64850728 100644 --- a/deploy/data/mysql/init.d/chatgpt_plus-v4.0.0.sql +++ b/deploy/data/mysql/init.d/chatgpt_plus.sql @@ -3,7 +3,7 @@ -- https://www.phpmyadmin.net/ -- -- 主机: localhost:3307 --- 生成日期: 2024-03-28 17:27:20 +-- 生成日期: 2024-03-29 17:26:02 -- 服务器版本: 8.0.33 -- PHP 版本: 8.1.18 @@ -47,7 +47,7 @@ CREATE TABLE `chatgpt_admin_users` ( -- INSERT INTO `chatgpt_admin_users` (`id`, `username`, `password`, `salt`, `status`, `last_login_at`, `last_login_ip`, `created_at`, `updated_at`) VALUES -(1, 'admin', '6d17e80c87d209efb84ca4b2e0824f549d09fac8b2e1cc698de5bb5e1d75dfd0', 'mmrql75o', 1, 1711594316, '172.22.11.200', '2024-03-11 16:30:20', '2024-03-28 10:51:57'), +(1, 'admin', '6d17e80c87d209efb84ca4b2e0824f549d09fac8b2e1cc698de5bb5e1d75dfd0', 'mmrql75o', 1, 1711704342, '::1', '2024-03-11 16:30:20', '2024-03-29 17:25:42'), (108, 'test', '9ed720ce03e0a69885455271b4b3e1710bff79434f2a95d0de6406dd88cc9f79', '4b9orqjh', 0, 1710396975, '::1', '2024-03-13 16:06:43', '2024-03-21 15:15:04'); -- -------------------------------------------------------- @@ -71,21 +71,6 @@ CREATE TABLE `chatgpt_api_keys` ( `updated_at` datetime NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='OpenAI API '; --- --- 转存表中的数据 `chatgpt_api_keys` --- - -INSERT INTO `chatgpt_api_keys` (`id`, `platform`, `name`, `value`, `type`, `last_used_at`, `api_url`, `enabled`, `proxy_url`, `created_at`, `updated_at`) VALUES -(11, 'ChatGLM', '智普', 'c3694f748a33d4d163bfa4b77ec1a153.p6s2NUZf5kAb0M6w', 'chat', 1710498745, 'https://open.bigmodel.cn/api/paas/v3/model-api/{model}/sse-invoke', 1, '', '2023-09-04 16:25:54', '2024-03-15 13:54:00'), -(14, 'Baidu', '千帆', 'Wdpi8o3T8UWrxgVqjtq7HODS|SeseBNp9Y5rQdwlVG60isEofEMT8y9zz', 'chat', 1699519822, 'https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/{model}', 0, '', '2023-10-10 18:11:50', '2024-03-15 13:53:54'), -(15, 'XunFei', '星火', 'b54dd11b|dbdcf59c74f8ea05e1792cad54409065|MTAxNjQ1MTVlODliNWM0NTVkOWM2ZTVm', 'chat', 1710497804, 'wss://spark-api.xf-yun.com/{version}/chat', 1, '', '2023-10-11 15:10:09', '2024-03-15 13:54:13'), -(22, 'OpenAI', '官方', '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', 'img', 0, 'https://api.openai.com/v1/images/generations', 0, 'http://127.0.0.1:7777', '2023-12-07 11:48:36', '2024-03-18 15:32:58'), -(24, 'OpenAI', '官方', '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', 'chat', 1710747118, 'https://api.openai.com/v1/chat/completions', 0, 'http://127.0.0.1:7777', '2024-01-04 10:10:58', '2024-03-18 15:32:59'), -(25, 'OpenAI', '极客学长', 'sk-qR5kdnAhTPuiXf2r7d9bEbBdD6F64d9e81Dd9c75D716BdD4', 'chat', 1711586301, 'https://api.chat-plus.net/v1/chat/completions', 1, '', '2024-01-04 15:58:30', '2024-03-18 15:33:02'), -(26, 'OpenAI', '极客学长', 'sk-n3JghlwzY6JaTIbv7064F94155F942D386F3F685F6Bd3b97', 'img', 1711007339, 'https://gpt.bemore.lol/v1/images/generations', 1, '', '2024-01-05 14:31:45', '2024-03-18 15:33:03'), -(27, 'QWen', '通义千问', 'sk-6241c622828c44b1a2c70f495b16efac', 'chat', 1711334875, 'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation', 1, '', '2024-01-19 10:39:22', '2024-03-15 11:55:02'), -(28, 'OpenAI', '丈母娘', 'sk-tAKgJwKbi9cHzFMdC9C34f0207B74225977256F65972Fb94', 'img', 1708593118, 'https://www.jiujiuai.net/v1/images/generations', 0, '', '2024-02-22 17:06:02', '2024-02-23 09:29:26'); - -- -------------------------------------------------------- -- @@ -172,7 +157,8 @@ INSERT INTO `chatgpt_chat_models` (`id`, `platform`, `name`, `value`, `sort_num` (18, 'QWen', '通义千问-Plus', 'qwen-plus', 8, 1, 1, 1.0, 1024, 32768, 1, '2024-01-19 10:42:49', '2024-03-18 14:27:19'), (19, 'QWen', '通义千问-Max', 'qwen-max-1201', 9, 1, 1, 1.0, 1024, 32768, 1, '2024-01-19 10:51:03', '2024-03-18 14:27:19'), (21, 'OpenAI', '董宇辉小作文助手', 'gpt-4-gizmo-g-dse9iXvor', 6, 1, 30, 1.0, 8192, 32768, 0, '2024-03-18 14:24:20', '2024-03-18 14:27:19'), -(22, 'OpenAI', 'LOGO生成神器', 'gpt-4-gizmo-g-YL87j8C7S', 0, 1, 30, 1.0, 1024, 4096, 1, '2024-03-20 14:02:11', '2024-03-20 14:02:18'); +(22, 'OpenAI', 'LOGO生成神器', 'gpt-4-gizmo-g-YL87j8C7S', 0, 1, 30, 1.0, 1024, 4096, 1, '2024-03-20 14:02:11', '2024-03-20 14:02:18'), +(23, 'OpenAI', '音乐生成器', 'suno-v3', 0, 1, 50, 0.8, 1024, 4096, 1, '2024-03-29 15:43:40', '2024-03-29 15:45:15'); -- -------------------------------------------------------- @@ -236,7 +222,7 @@ CREATE TABLE `chatgpt_configs` ( INSERT INTO `chatgpt_configs` (`id`, `marker`, `config_json`) VALUES (1, 'system', '{\"title\":\"ChatPlus AI 智能助手\",\"admin_title\":\"ChatPlus 控制台\",\"logo\":\"http://localhost:5678/static/upload/2024/3/1711334798556619.png\",\"init_power\":100,\"daily_power\":99,\"invite_power\":10,\"vip_month_power\":1000,\"register_ways\":[\"mobile\",\"username\",\"email\"],\"enabled_register\":true,\"reward_img\":\"http://localhost:5678/static/upload/2024/3/1710753716309668.jpg\",\"enabled_reward\":true,\"power_price\":0.1,\"order_pay_timeout\":1800,\"vip_info_text\":\"月度会员,年度会员每月赠送 1000 点算力,赠送算力当月有效当月没有消费完的算力不结余到下个月。 点卡充值的算力长期有效。\",\"default_models\":[11,7,1,10,12,19,18,17,3],\"mj_power\":20,\"mj_action_power\":10,\"sd_power\":5,\"dall_power\":15,\"wechat_card_url\":\"/images/wx.png\",\"enable_context\":true,\"context_deep\":4}'), -(3, 'notice', '{\"content\":\"注意:当前站点仅为开源项目 \\u003ca style=\\\"color: #F56C6C\\\" href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003eChatPlus\\u003c/a\\u003e 的演示项目,本项目单纯就是给大家体验项目功能使用。\\n体验额度用完之后请不要在当前站点进行任何充值操作!!!\\n体验额度用完之后请不要在当前站点进行任何充值操作!!!\\n体验额度用完之后请不要在当前站点进行任何充值操作!!!\\n 如果觉得好用你就花几分钟自己部署一套,没有API KEY 的同学可以去 \\u003ca href=\\\"https://gpt.bemore.lol\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://gpt.bemore.lol\\u003c/a\\u003e 购买,现在有超级优惠,价格远低于 OpenAI 官方。\\nGPT-3.5,GPT-4,DALL-E3 绘图......你都可以随意使用,无需魔法。\\nMidJourney API 购买地址:\\u003ca href=\\\"https://api.chat-plus.net\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.chat-plus.net\\u003c/a\\u003e\\n接入教程: \\u003ca href=\\\"https://ai.r9it.com/docs/install/\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://ai.r9it.com/docs/install/\\u003c/a\\u003e\\n本项目源码地址:\\u003ca href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003ehttps://github.com/yangjian102621/chatgpt-plus\\u003c/a\\u003e\",\"updated\":true}'); +(3, 'notice', '{\"content\":\"系统每日会给免费会员赠送10算力值,用完请第二天再来领取。\\n## v4.0.1 更新日志\\n* 功能重构:重构 Stable-Diffusion 绘画实现,使用 SDAPI 替换之前的 websocket 接口,SDAPI 兼容各种 stable-diffusion 发行版,稳定性更强一些\\n* 功能优化:使用 [midjouney-proxy](https://github.com/novicezk/midjourney-proxy) 项目替换内置的原生 MidJourney API,兼容 MJ-Plus 中转\\n* 功能新增:用户算力消费日志增加统计功能,统计一段时间内用户消费的算力\\n* Bug修复:修复 iphone 手机无法通过图形验证码的Bug,使用滑动验证码替换\\n* Bug修复:修复手机端 MidJourney 绘画页面滚动条无法滚动的Bug\\n\\n 如果觉得好用你就花几分钟自己部署一套,没有API KEY 的同学可以去\\u003ca href=\\\"https://api.chat-plus.net\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.chat-plus.net\\u003c/a\\u003e (支持MidJourney,GPT,Claude,Google Gemmi 各种表格模型) 或者 \\u003ca href=\\\"https://gpt.bemore.lol\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://gpt.bemore.lol\\u003c/a\\u003e(不支持 Midjourney) 购买,现在有超级优惠,价格远低于 OpenAI 官方。关于中转 API 的优势和劣势请参考 [中转API技术原理](https://ai.r9it.com/docs/install/errors-handle.html#%E8%B0%83%E7%94%A8%E4%B8%AD%E8%BD%AC-api-%E6%8A%A5%E9%94%99%E6%97%A0%E5%8F%AF%E7%94%A8%E6%B8%A0%E9%81%93)。\\nGPT-3.5,GPT-4,DALL-E3 绘图......你都可以随意使用,无需魔法。\\n接入教程: \\u003ca href=\\\"https://ai.r9it.com/docs/install/\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://ai.r9it.com/docs/install/\\u003c/a\\u003e\\n\\n本项目源码地址:\\u003ca href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003ehttps://github.com/yangjian102621/chatgpt-plus\\u003c/a\\u003e\",\"updated\":true}'); -- -------------------------------------------------------- @@ -411,18 +397,6 @@ CREATE TABLE `chatgpt_products` ( `url` varchar(255) DEFAULT NULL COMMENT '跳转地址' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会员套餐表'; --- --- 转存表中的数据 `chatgpt_products` --- - -INSERT INTO `chatgpt_products` (`id`, `name`, `price`, `discount`, `days`, `power`, `enabled`, `sales`, `sort_num`, `created_at`, `updated_at`, `app_url`, `url`) VALUES -(1, '会员1个月', '19.90', '10.00', 30, 0, 1, 2, 0, '2023-08-28 10:48:57', '2024-03-15 15:19:52', 'snssdk1128://ec_goods_detail?promotion_id=3668220199204683930', 'snssdk1128://ec_goods_detail?promotion_id=3668220199204683930'), -(2, '会员3个月', '140.00', '30.00', 90, 0, 1, 1, 0, '2023-08-28 10:52:22', '2024-02-27 11:34:26', NULL, NULL), -(3, '会员6个月', '290.00', '100.00', 180, 0, 1, 1, 0, '2023-08-28 10:53:39', '2023-08-31 16:24:36', NULL, NULL), -(4, '会员12个月', '580.00', '200.00', 365, 0, 1, 1, 0, '2023-08-28 10:54:15', '2023-08-31 16:24:42', NULL, NULL), -(5, '100算力', '10.00', '9.90', 0, 100, 1, 10, 0, '2023-08-28 10:55:08', '2024-03-15 15:20:29', NULL, 'snssdk1128://ec_goods_detail?promotion_id=3668220199204683930'), -(6, '200算力', '29.90', '20.00', 0, 200, 1, 1, 0, '2023-12-15 16:55:12', '2024-03-15 15:20:37', NULL, NULL); - -- -------------------------------------------------------- -- @@ -496,7 +470,7 @@ CREATE TABLE `chatgpt_users` ( -- INSERT INTO `chatgpt_users` (`id`, `username`, `nickname`, `password`, `avatar`, `salt`, `power`, `expired_time`, `status`, `chat_config_json`, `chat_roles_json`, `chat_models_json`, `last_login_at`, `vip`, `last_login_ip`, `created_at`, `updated_at`) VALUES -(4, '18575670125', '极客学长@830270', 'ccc3fb7ab61b8b5d096a4a166ae21d121fc38c71bbd1be6173d9ab973214a63b', 'http://localhost:5678/static/upload/2024/2/1708682650912429.png', 'ueedue5l', 9434, 1717292086, 1, '{\"api_keys\":{\"Azure\":\"\",\"ChatGLM\":\"\",\"OpenAI\":\"\"}}', '[\"red_book\",\"gpt\",\"programmer\",\"seller\"]', '[1,11]', 1711608964, 1, '::1', '2023-06-12 16:47:17', '2024-03-28 14:56:05'), +(4, '18575670125', '极客学长@830270', 'ccc3fb7ab61b8b5d096a4a166ae21d121fc38c71bbd1be6173d9ab973214a63b', 'http://localhost:5678/static/upload/2024/2/1708682650912429.png', 'ueedue5l', 9384, 1717292086, 1, '{\"api_keys\":{\"Azure\":\"\",\"ChatGLM\":\"\",\"OpenAI\":\"\"}}', '[\"red_book\",\"gpt\",\"programmer\",\"seller\"]', '[1,11]', 1711698298, 1, '::1', '2023-06-12 16:47:17', '2024-03-29 15:44:58'), (91, '18575670126', '极客学长@204872', '5e4050b8dd403f593260395d9edeb9f273dbe92d15dfdd929c4a182e95da10c4', '/images/avatar/user.png', '6fj0otl8', 33, 0, 1, '{\"api_keys\":{\"Azure\":\"\",\"ChatGLM\":\"\",\"OpenAI\":\"\"}}', '[\"gpt\"]', '[1,11]', 1697184324, 1, '::1', '2023-10-13 16:01:56', '2024-03-25 11:07:45'), (100, '13777777777', '极客学长@292245', 'dcaf31b154432310bd700349e7de7e9dde2a3d6955a035a01fe527c7917a4f99', '/images/avatar/user.png', 'i8a53f8f', 99, 0, 1, '{\"api_keys\":{\"Azure\":\"\",\"ChatGLM\":\"\",\"OpenAI\":\"\"}}', '[\"gpt\"]', '[1,11]', 0, 0, '', '2023-11-23 16:55:45', '2024-03-18 15:08:12'), (102, 'yangjian102621@gmail.com', '极客学长@207163', 'd51cec21942737083943e5c3a8f063dea034e40622ac8bd47d771f13707e4676', '/images/avatar/user.png', 'eqezapgk', 99, 0, 1, '{\"api_keys\":{\"Azure\":\"\",\"ChatGLM\":\"\",\"OpenAI\":\"\"}}', '[\"gpt\"]', '[1,11]', 1704448377, 0, '::1', '2024-01-05 17:48:00', '2024-03-18 15:08:41'), @@ -667,7 +641,7 @@ ALTER TABLE `chatgpt_admin_users` -- 使用表AUTO_INCREMENT `chatgpt_api_keys` -- ALTER TABLE `chatgpt_api_keys` - MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=32; + MODIFY `id` int NOT NULL AUTO_INCREMENT; -- -- 使用表AUTO_INCREMENT `chatgpt_chat_history` @@ -685,7 +659,7 @@ ALTER TABLE `chatgpt_chat_items` -- 使用表AUTO_INCREMENT `chatgpt_chat_models` -- ALTER TABLE `chatgpt_chat_models` - MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=23; + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=24; -- -- 使用表AUTO_INCREMENT `chatgpt_chat_roles` @@ -745,7 +719,7 @@ ALTER TABLE `chatgpt_power_logs` -- 使用表AUTO_INCREMENT `chatgpt_products` -- ALTER TABLE `chatgpt_products` - MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7; + MODIFY `id` int NOT NULL AUTO_INCREMENT; -- -- 使用表AUTO_INCREMENT `chatgpt_rewards` diff --git a/web/public/images/menu/app.png b/web/public/images/menu/app.png new file mode 100644 index 00000000..2785231c Binary files /dev/null and b/web/public/images/menu/app.png differ diff --git a/web/public/images/chat.png b/web/public/images/menu/chat.png similarity index 100% rename from web/public/images/chat.png rename to web/public/images/menu/chat.png diff --git a/web/public/images/menu/img-wall.png b/web/public/images/menu/img-wall.png new file mode 100644 index 00000000..61f9fdb8 Binary files /dev/null and b/web/public/images/menu/img-wall.png differ diff --git a/web/public/images/menu/log.png b/web/public/images/menu/log.png new file mode 100644 index 00000000..03870d66 Binary files /dev/null and b/web/public/images/menu/log.png differ diff --git a/web/public/images/menu/member.png b/web/public/images/menu/member.png new file mode 100644 index 00000000..cceac4ca Binary files /dev/null and b/web/public/images/menu/member.png differ diff --git a/web/public/images/mj.png b/web/public/images/menu/mj.png similarity index 100% rename from web/public/images/mj.png rename to web/public/images/menu/mj.png diff --git a/web/public/images/sd.png b/web/public/images/menu/sd.png similarity index 100% rename from web/public/images/sd.png rename to web/public/images/menu/sd.png diff --git a/web/public/images/menu/share.png b/web/public/images/menu/share.png new file mode 100644 index 00000000..8d84b074 Binary files /dev/null and b/web/public/images/menu/share.png differ diff --git a/web/src/router.js b/web/src/router.js index f4c81e61..968b0690 100644 --- a/web/src/router.js +++ b/web/src/router.js @@ -173,7 +173,7 @@ const routes = [ name: 'admin-manger', meta: {title: '管理员'}, component: () => import('@/views/admin/Manager.vue'), - }, + } ] }, diff --git a/web/src/views/ChatPlus.vue b/web/src/views/ChatPlus.vue index 19a729a6..0914358f 100644 --- a/web/src/views/ChatPlus.vue +++ b/web/src/views/ChatPlus.vue @@ -313,12 +313,16 @@ httpGet("/api/config/get?key=system").then(res => { // 获取系统公告 httpGet("/api/config/get?key=notice").then(res => { - notice.value = md.render(res.data['content']) - const oldNotice = localStorage.getItem(noticeKey.value); - // 如果公告有更新,则显示公告 - if (oldNotice !== notice.value && notice.value.length > 10) { - showNotice.value = true + try { + notice.value = md.render(res.data['content']) + const oldNotice = localStorage.getItem(noticeKey.value); + // 如果公告有更新,则显示公告 + if (oldNotice !== notice.value && notice.value.length > 10) { + showNotice.value = true + } + } catch (e) { } + }).catch(e => { ElMessage.error("获取系统配置失败:" + e.message) }) diff --git a/web/src/views/Home.vue b/web/src/views/Home.vue index db214038..aecf0915 100644 --- a/web/src/views/Home.vue +++ b/web/src/views/Home.vue @@ -7,14 +7,10 @@ @@ -37,21 +33,12 @@ import {ElMessage} from "element-plus"; const router = useRouter(); const logo = ref('/images/logo.png'); -const navs = ref([ - {path: "/chat", icon_path: "/images/chat.png", title: "对话聊天"}, - {path: "/mj", icon_path: "/images/mj.png", title: "MJ 绘画"}, - {path: "/sd", icon_path: "/images/sd.png", title: "SD 绘画"}, - {path: "/apps", icon: "menu", title: "应用中心"}, - {path: "/images-wall", icon: "image-list", title: "作品展示"}, - {path: "/powerLog", icon: "log", title: "消费日志"}, - {path: "/member", icon: "vip-user", title: "会员计划"}, - {path: "/invite", icon: "share", title: "推广计划"}, -]) +const navs = ref([]) const curPath = ref(router.currentRoute.value.path) const changeNav = (item) => { - curPath.value = item.path - router.push(item.path) + curPath.value = item.url + router.push(item.url) } onMounted(() => { @@ -60,6 +47,12 @@ onMounted(() => { }).catch(e => { ElMessage.error("获取系统配置失败:" + e.message) }) + // 获取菜单 + httpGet("/api/menu/list").then(res => { + navs.value = res.data + }).catch(e => { + ElMessage.error("获取系统菜单失败:" + e.message) + }) }) diff --git a/web/src/views/admin/Menu.vue b/web/src/views/admin/Menu.vue new file mode 100644 index 00000000..66123e1d --- /dev/null +++ b/web/src/views/admin/Menu.vue @@ -0,0 +1,247 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/admin/Product.vue b/web/src/views/admin/Product.vue index 3f4bd8a5..eae3e812 100644 --- a/web/src/views/admin/Product.vue +++ b/web/src/views/admin/Product.vue @@ -1,5 +1,5 @@