diff --git a/CHANGELOG.md b/CHANGELOG.md index ac179b8..7c4fba9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,14 @@ # 更新日志 +## v4.0.8 +* 功能优化:升级 mathjax 公式解析插件,修复公式因为图片访问限制而无法显示的问题 +* 功能优化:当数据库更新失败的时候记录错误日志 +* 功能优化:聊天输入框会随着输入内容的增多自动调整高度 +* Bug修复:修复移动端聊天页面模型切换不生效的Bug +* 功能优化:给PC端扫码支付增加签名验证和有效期验证 +* Bug修复:修复支付码生成API权限控制的问题 +* Bug修复:模型算力设置为0时,不扣减用户算力,并且不记录算力消费日志 +* 功能优化:新增随机背景配置项,可以在后台设置,首页使用 Bing 壁纸作为背景图片 +* 功能新增:H5端支持 Dalle 绘图 ## v4.0.7 diff --git a/api/core/app_server.go b/api/core/app_server.go index 7c6b99a..8ba434f 100644 --- a/api/core/app_server.go +++ b/api/core/app_server.go @@ -9,12 +9,12 @@ package core import ( "bytes" + "context" + "fmt" "geekai/core/types" "geekai/store/model" "geekai/utils" "geekai/utils/resp" - "context" - "fmt" "github.com/gin-gonic/gin" "github.com/go-redis/redis/v8" "github.com/golang-jwt/jwt/v5" @@ -227,15 +227,19 @@ func needLogin(c *gin.Context) bool { c.Request.URL.Path == "/api/sd/client" || c.Request.URL.Path == "/api/dall/imgWall" || c.Request.URL.Path == "/api/dall/client" || - c.Request.URL.Path == "/api/config/get" || c.Request.URL.Path == "/api/product/list" || c.Request.URL.Path == "/api/menu/list" || c.Request.URL.Path == "/api/markMap/client" || + c.Request.URL.Path == "/api/payment/alipay/notify" || + c.Request.URL.Path == "/api/payment/hupipay/notify" || + c.Request.URL.Path == "/api/payment/payjs/notify" || + c.Request.URL.Path == "/api/payment/doPay" || + c.Request.URL.Path == "/api/payment/payWays" || strings.HasPrefix(c.Request.URL.Path, "/api/test") || + strings.HasPrefix(c.Request.URL.Path, "/api/config/") || strings.HasPrefix(c.Request.URL.Path, "/api/function/") || strings.HasPrefix(c.Request.URL.Path, "/api/sms/") || strings.HasPrefix(c.Request.URL.Path, "/api/captcha/") || - strings.HasPrefix(c.Request.URL.Path, "/api/payment/") || strings.HasPrefix(c.Request.URL.Path, "/static/") { return false } diff --git a/api/core/types/chat.go b/api/core/types/chat.go index 4e90afa..3827b86 100644 --- a/api/core/types/chat.go +++ b/api/core/types/chat.go @@ -61,15 +61,15 @@ type ChatSession struct { } type ChatModel struct { - Id uint `json:"id"` - Platform Platform `json:"platform"` - Name string `json:"name"` - Value string `json:"value"` - Power int `json:"power"` - MaxTokens int `json:"max_tokens"` // 最大响应长度 - MaxContext int `json:"max_context"` // 最大上下文长度 - Temperature float32 `json:"temperature"` // 模型温度 - KeyId int `json:"key_id"` // 绑定 API KEY + Id uint `json:"id"` + Platform string `json:"platform"` + Name string `json:"name"` + Value string `json:"value"` + Power int `json:"power"` + MaxTokens int `json:"max_tokens"` // 最大响应长度 + MaxContext int `json:"max_context"` // 最大上下文长度 + Temperature float32 `json:"temperature"` // 模型温度 + KeyId int `json:"key_id"` // 绑定 API KEY } type ApiError struct { diff --git a/api/core/types/config.go b/api/core/types/config.go index b0ec7eb..c988199 100644 --- a/api/core/types/config.go +++ b/api/core/types/config.go @@ -126,25 +126,60 @@ type RedisConfig struct { const LicenseKey = "Geek-AI-License" type License struct { - Key string `json:"key"` // 许可证书密钥 - MachineId string `json:"machine_id"` // 机器码 - UserNum int `json:"user_num"` // 用户数量 - ExpiredAt int64 `json:"expired_at"` // 过期时间 - IsActive bool `json:"is_active"` // 是否激活 + Key string `json:"key"` // 许可证书密钥 + MachineId string `json:"machine_id"` // 机器码 + ExpiredAt int64 `json:"expired_at"` // 过期时间 + IsActive bool `json:"is_active"` // 是否激活 + Configs LicenseConfig `json:"configs"` +} + +type LicenseConfig struct { + UserNum int `json:"user_num"` // 用户数量 + DeCopy bool `json:"de_copy"` // 去版权 } func (c RedisConfig) Url() string { return fmt.Sprintf("%s:%d", c.Host, c.Port) } -type Platform string +type Platform struct { + Name string `json:"name"` + Value string `json:"value"` + ChatURL string `json:"chat_url"` + ImgURL string `json:"img_url"` +} -const OpenAI = Platform("OpenAI") -const Azure = Platform("Azure") -const ChatGLM = Platform("ChatGLM") -const Baidu = Platform("Baidu") -const XunFei = Platform("XunFei") -const QWen = Platform("QWen") +var OpenAI = Platform{ + Name: "OpenAI - GPT", + Value: "OpenAI", + ChatURL: "https://api.chat-plus.net/v1/chat/completions", + ImgURL: "https://api.chat-plus.net/v1/images/generations", +} +var Azure = Platform{ + Name: "微软 - Azure", + Value: "Azure", + ChatURL: "https://chat-bot-api.openai.azure.com/openai/deployments/{model}/chat/completions?api-version=2023-05-15", +} +var ChatGLM = Platform{ + Name: "智谱 - ChatGLM", + Value: "ChatGLM", + ChatURL: "https://open.bigmodel.cn/api/paas/v3/model-api/{model}/sse-invoke", +} +var Baidu = Platform{ + Name: "百度 - 文心大模型", + Value: "Baidu", + ChatURL: "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/{model}", +} +var XunFei = Platform{ + Name: "讯飞 - 星火大模型", + Value: "XunFei", + ChatURL: "wss://spark-api.xf-yun.com/{version}/chat", +} +var QWen = Platform{ + Name: "阿里 - 通义千问", + Value: "QWen", + ChatURL: "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation", +} type SystemConfig struct { Title string `json:"title,omitempty"` @@ -177,4 +212,6 @@ type SystemConfig struct { ContextDeep int `json:"context_deep,omitempty"` SdNegPrompt string `json:"sd_neg_prompt"` // SD 默认反向提示词 + + RandBg bool `json:"rand_bg"` // 前端首页是否启用随机背景 } diff --git a/api/core/types/function.go b/api/core/types/function.go index 30ac03c..0897a7d 100644 --- a/api/core/types/function.go +++ b/api/core/types/function.go @@ -24,5 +24,4 @@ type Function struct { Name string `json:"name"` Description string `json:"description"` Parameters map[string]interface{} `json:"parameters"` - Required interface{} `json:"required,omitempty"` } diff --git a/api/go.mod b/api/go.mod index 3b02561..3f08038 100644 --- a/api/go.mod +++ b/api/go.mod @@ -29,14 +29,19 @@ require github.com/xxl-job/xxl-job-executor-go v1.2.0 require ( github.com/mojocn/base64Captcha v1.3.1 + github.com/shirou/gopsutil v3.21.11+incompatible github.com/shopspring/decimal v1.3.1 github.com/syndtr/goleveldb v1.0.0 golang.org/x/image v0.0.0-20211028202545-6944b10bf410 ) require ( + github.com/go-ole/go-ole v1.2.6 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect + github.com/tklauser/go-sysconf v0.3.14 // indirect + github.com/tklauser/numcpus v0.8.0 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.uber.org/mock v0.4.0 // indirect ) diff --git a/api/go.sum b/api/go.sum index 8a7b137..8c7ec59 100644 --- a/api/go.sum +++ b/api/go.sum @@ -43,6 +43,8 @@ github.com/go-basic/ipv4 v1.0.0 h1:gjyFAa1USC1hhXTkPOwBWDPfMcUaIM+tvo1XzV9EZxs= github.com/go-basic/ipv4 v1.0.0/go.mod h1:etLBnaxbidQfuqE6wgZQfs38nEWNmzALkxDZe4xY8Dg= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -176,6 +178,8 @@ github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUA github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -204,6 +208,10 @@ github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gt github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= +github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= +github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= +github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= @@ -215,6 +223,8 @@ github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ github.com/xxl-job/xxl-job-executor-go v1.2.0 h1:MTl2DpwrK2+hNjRRks2k7vB3oy+3onqm9OaSarneeLQ= github.com/xxl-job/xxl-job-executor-go v1.2.0/go.mod h1:bUFhz/5Irp9zkdYk5MxhQcDDT6LlZrI8+rv5mHtQ1mo= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -261,6 +271,7 @@ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/api/handler/admin/api_key_handler.go b/api/handler/admin/api_key_handler.go index 87eab55..f412c03 100644 --- a/api/handler/admin/api_key_handler.go +++ b/api/handler/admin/api_key_handler.go @@ -57,6 +57,7 @@ func (h *ApiKeyHandler) Save(c *gin.Context) { apiKey.Name = data.Name res := h.DB.Save(&apiKey) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -75,6 +76,7 @@ func (h *ApiKeyHandler) Save(c *gin.Context) { func (h *ApiKeyHandler) List(c *gin.Context) { status := h.GetBool(c, "status") t := h.GetTrim(c, "type") + platform := h.GetTrim(c, "platform") session := h.DB.Session(&gorm.Session{}) if status { @@ -83,7 +85,10 @@ func (h *ApiKeyHandler) List(c *gin.Context) { if t != "" { session = session.Where("type", t) } - + if platform != "" { + session = session.Where("platform", platform) + } + var items []model.ApiKey var keys = make([]vo.ApiKey, 0) res := session.Find(&items) @@ -118,6 +123,7 @@ func (h *ApiKeyHandler) Set(c *gin.Context) { res := h.DB.Model(&model.ApiKey{}).Where("id = ?", data.Id).Update(data.Filed, data.Value) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -133,6 +139,7 @@ func (h *ApiKeyHandler) Remove(c *gin.Context) { res := h.DB.Where("id", id).Delete(&model.ApiKey{}) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } diff --git a/api/handler/admin/chat_handler.go b/api/handler/admin/chat_handler.go index af76e76..f51cf85 100644 --- a/api/handler/admin/chat_handler.go +++ b/api/handler/admin/chat_handler.go @@ -261,6 +261,7 @@ func (h *ChatHandler) RemoveMessage(c *gin.Context) { id := h.GetInt(c, "id", 0) tx := h.DB.Unscoped().Where("id = ?", id).Delete(&model.ChatMessage{}) if tx.Error != nil { + logger.Error("error with update database:", tx.Error) resp.ERROR(c, "更新数据库失败!") return } diff --git a/api/handler/admin/chat_model_handler.go b/api/handler/admin/chat_model_handler.go index f30991a..74f187c 100644 --- a/api/handler/admin/chat_model_handler.go +++ b/api/handler/admin/chat_model_handler.go @@ -69,6 +69,7 @@ func (h *ChatModelHandler) Save(c *gin.Context) { res = h.DB.Create(&item) } if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -88,9 +89,13 @@ func (h *ChatModelHandler) Save(c *gin.Context) { func (h *ChatModelHandler) List(c *gin.Context) { session := h.DB.Session(&gorm.Session{}) enable := h.GetBool(c, "enable") + platform := h.GetTrim(c, "platform") if enable { session = session.Where("enabled", enable) } + if platform != "" { + session = session.Where("platform", platform) + } var items []model.ChatModel var cms = make([]vo.ChatModel, 0) res := session.Order("sort_num ASC").Find(&items) @@ -140,6 +145,7 @@ func (h *ChatModelHandler) Set(c *gin.Context) { res := h.DB.Model(&model.ChatModel{}).Where("id = ?", data.Id).Update(data.Filed, data.Value) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -160,6 +166,7 @@ func (h *ChatModelHandler) Sort(c *gin.Context) { for index, id := range data.Ids { res := h.DB.Model(&model.ChatModel{}).Where("id = ?", id).Update("sort_num", data.Sorts[index]) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -177,6 +184,7 @@ func (h *ChatModelHandler) Remove(c *gin.Context) { res := h.DB.Where("id = ?", id).Delete(&model.ChatModel{}) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } diff --git a/api/handler/admin/chat_role_handler.go b/api/handler/admin/chat_role_handler.go index 791104a..3e69ae3 100644 --- a/api/handler/admin/chat_role_handler.go +++ b/api/handler/admin/chat_role_handler.go @@ -48,6 +48,7 @@ func (h *ChatRoleHandler) Save(c *gin.Context) { } res := h.DB.Save(&role) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -115,6 +116,7 @@ func (h *ChatRoleHandler) Sort(c *gin.Context) { for index, id := range data.Ids { res := h.DB.Model(&model.ChatRole{}).Where("id = ?", id).Update("sort_num", data.Sorts[index]) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -137,6 +139,7 @@ func (h *ChatRoleHandler) Set(c *gin.Context) { res := h.DB.Model(&model.ChatRole{}).Where("id = ?", data.Id).Update(data.Filed, data.Value) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -152,6 +155,7 @@ func (h *ChatRoleHandler) Remove(c *gin.Context) { } res := h.DB.Where("id", id).Delete(&model.ChatRole{}) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "删除失败!") return } diff --git a/api/handler/admin/config_handler.go b/api/handler/admin/config_handler.go index abf895f..584b026 100644 --- a/api/handler/admin/config_handler.go +++ b/api/handler/admin/config_handler.go @@ -11,21 +11,35 @@ import ( "geekai/core" "geekai/core/types" "geekai/handler" + "geekai/service" + "geekai/service/mj" + "geekai/service/sd" "geekai/store" "geekai/store/model" "geekai/utils" "geekai/utils/resp" + "github.com/gin-gonic/gin" + "github.com/shirou/gopsutil/host" "gorm.io/gorm" ) type ConfigHandler struct { handler.BaseHandler - levelDB *store.LevelDB + levelDB *store.LevelDB + licenseService *service.LicenseService + mjServicePool *mj.ServicePool + sdServicePool *sd.ServicePool } -func NewConfigHandler(app *core.AppServer, db *gorm.DB, levelDB *store.LevelDB) *ConfigHandler { - return &ConfigHandler{BaseHandler: handler.BaseHandler{App: app, DB: db}, levelDB: levelDB} +func NewConfigHandler(app *core.AppServer, db *gorm.DB, levelDB *store.LevelDB, licenseService *service.LicenseService, mjPool *mj.ServicePool, sdPool *sd.ServicePool) *ConfigHandler { + return &ConfigHandler{ + BaseHandler: handler.BaseHandler{App: app, DB: db}, + levelDB: levelDB, + mjServicePool: mjPool, + sdServicePool: sdPool, + licenseService: licenseService, + } } func (h *ConfigHandler) Update(c *gin.Context) { @@ -95,3 +109,89 @@ func (h *ConfigHandler) Get(c *gin.Context) { resp.SUCCESS(c, value) } + +// Active 激活系统 +func (h *ConfigHandler) Active(c *gin.Context) { + var data struct { + License string `json:"license"` + } + if err := c.ShouldBindJSON(&data); err != nil { + resp.ERROR(c, types.InvalidArgs) + return + } + info, err := host.Info() + if err != nil { + resp.ERROR(c, err.Error()) + return + } + + err = h.licenseService.ActiveLicense(data.License, info.HostID) + if err != nil { + resp.ERROR(c, err.Error()) + return + } + + resp.SUCCESS(c, info.HostID) +} + +// GetLicense 获取 License 信息 +func (h *ConfigHandler) GetLicense(c *gin.Context) { + license := h.licenseService.GetLicense() + resp.SUCCESS(c, license) +} + +// GetAppConfig 获取内置配置 +func (h *ConfigHandler) GetAppConfig(c *gin.Context) { + resp.SUCCESS(c, gin.H{ + "mj_plus": h.App.Config.MjPlusConfigs, + "mj_proxy": h.App.Config.MjProxyConfigs, + "sd": h.App.Config.SdConfigs, + "platforms": Platforms, + }) +} + +// SaveDrawingConfig 保存AI绘画配置 +func (h *ConfigHandler) SaveDrawingConfig(c *gin.Context) { + var data struct { + Sd []types.StableDiffusionConfig `json:"sd"` + MjPlus []types.MjPlusConfig `json:"mj_plus"` + MjProxy []types.MjProxyConfig `json:"mj_proxy"` + } + if err := c.ShouldBindJSON(&data); err != nil { + resp.ERROR(c, types.InvalidArgs) + return + } + + changed := false + if configChanged(data.Sd, h.App.Config.SdConfigs) { + logger.Debugf("SD 配置变动了") + h.App.Config.SdConfigs = data.Sd + h.sdServicePool.InitServices(data.Sd) + changed = true + } + + if configChanged(data.MjPlus, h.App.Config.MjPlusConfigs) || configChanged(data.MjProxy, h.App.Config.MjProxyConfigs) { + logger.Debugf("MidJourney 配置变动了") + h.App.Config.MjPlusConfigs = data.MjPlus + h.App.Config.MjProxyConfigs = data.MjProxy + h.mjServicePool.InitServices(data.MjPlus, data.MjProxy) + changed = true + } + + if changed { + err := core.SaveConfig(h.App.Config) + if err != nil { + resp.ERROR(c, "更新配置文档失败!") + return + } + } + + resp.SUCCESS(c) + +} + +func configChanged(c1 interface{}, c2 interface{}) bool { + encode1 := utils.JsonEncode(c1) + encode2 := utils.JsonEncode(c2) + return utils.Md5(encode1) != utils.Md5(encode2) +} diff --git a/api/handler/admin/function_handler.go b/api/handler/admin/function_handler.go index 474f32b..c9e8005 100644 --- a/api/handler/admin/function_handler.go +++ b/api/handler/admin/function_handler.go @@ -71,6 +71,7 @@ func (h *FunctionHandler) Set(c *gin.Context) { res := h.DB.Model(&model.Function{}).Where("id = ?", data.Id).Update(data.Filed, data.Value) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -103,6 +104,7 @@ func (h *FunctionHandler) Remove(c *gin.Context) { if id > 0 { res := h.DB.Delete(&model.Function{Id: uint(id)}) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } diff --git a/api/handler/admin/menu_handler.go b/api/handler/admin/menu_handler.go index ef1991e..001c601 100644 --- a/api/handler/admin/menu_handler.go +++ b/api/handler/admin/menu_handler.go @@ -50,6 +50,7 @@ func (h *MenuHandler) Save(c *gin.Context) { Enabled: data.Enabled, }) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -86,6 +87,7 @@ func (h *MenuHandler) Enable(c *gin.Context) { res := h.DB.Model(&model.Menu{}).Where("id", data.Id).UpdateColumn("enabled", data.Enabled) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -106,6 +108,7 @@ func (h *MenuHandler) Sort(c *gin.Context) { 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 { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -120,6 +123,7 @@ func (h *MenuHandler) Remove(c *gin.Context) { if id > 0 { res := h.DB.Where("id", id).Delete(&model.Menu{}) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } diff --git a/api/handler/admin/order_handler.go b/api/handler/admin/order_handler.go index a64fa28..ab6752b 100644 --- a/api/handler/admin/order_handler.go +++ b/api/handler/admin/order_handler.go @@ -94,6 +94,7 @@ func (h *OrderHandler) Remove(c *gin.Context) { res = h.DB.Unscoped().Where("id = ?", id).Delete(&model.Order{}) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } diff --git a/api/handler/admin/product_handler.go b/api/handler/admin/product_handler.go index 92f0d22..e2b66c7 100644 --- a/api/handler/admin/product_handler.go +++ b/api/handler/admin/product_handler.go @@ -57,6 +57,7 @@ func (h *ProductHandler) Save(c *gin.Context) { } res := h.DB.Save(&item) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -107,6 +108,7 @@ func (h *ProductHandler) Enable(c *gin.Context) { res := h.DB.Model(&model.Product{}).Where("id", data.Id).UpdateColumn("enabled", data.Enabled) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -127,6 +129,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]) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -141,6 +144,7 @@ func (h *ProductHandler) Remove(c *gin.Context) { if id > 0 { res := h.DB.Where("id", id).Delete(&model.Product{}) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } diff --git a/api/handler/admin/reward_handler.go b/api/handler/admin/reward_handler.go index 50daa21..2dc2e28 100644 --- a/api/handler/admin/reward_handler.go +++ b/api/handler/admin/reward_handler.go @@ -72,6 +72,7 @@ func (h *RewardHandler) Remove(c *gin.Context) { if data.Id > 0 { res := h.DB.Where("id = ?", data.Id).Delete(&model.Reward{}) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } diff --git a/api/handler/admin/types.go b/api/handler/admin/types.go new file mode 100644 index 0000000..c06139b --- /dev/null +++ b/api/handler/admin/types.go @@ -0,0 +1,12 @@ +package admin + +import "geekai/core/types" + +var Platforms = []types.Platform{ + types.OpenAI, + types.QWen, + types.XunFei, + types.ChatGLM, + types.Baidu, + types.Azure, +} diff --git a/api/handler/admin/user_handler.go b/api/handler/admin/user_handler.go index d11078e..95da105 100644 --- a/api/handler/admin/user_handler.go +++ b/api/handler/admin/user_handler.go @@ -12,6 +12,7 @@ import ( "geekai/core" "geekai/core/types" "geekai/handler" + "geekai/service" "geekai/store/model" "geekai/store/vo" "geekai/utils" @@ -24,10 +25,11 @@ import ( type UserHandler struct { handler.BaseHandler + licenseService *service.LicenseService } -func NewUserHandler(app *core.AppServer, db *gorm.DB) *UserHandler { - return &UserHandler{BaseHandler: handler.BaseHandler{App: app, DB: db}} +func NewUserHandler(app *core.AppServer, db *gorm.DB, licenseService *service.LicenseService) *UserHandler { + return &UserHandler{BaseHandler: handler.BaseHandler{App: app, DB: db}, licenseService: licenseService} } // List 用户列表 @@ -82,7 +84,13 @@ func (h *UserHandler) Save(c *gin.Context) { resp.ERROR(c, types.InvalidArgs) return } - + // 检测最大注册人数 + var totalUser int64 + h.DB.Model(&model.User{}).Count(&totalUser) + if h.licenseService.GetLicense().Configs.UserNum > 0 && int(totalUser) >= h.licenseService.GetLicense().Configs.UserNum { + resp.ERROR(c, "当前注册用户数已达上限,请请升级 License") + return + } var user = model.User{} var res *gorm.DB var userVo vo.User @@ -103,6 +111,7 @@ func (h *UserHandler) Save(c *gin.Context) { res = h.DB.Select("username", "status", "vip", "power", "chat_roles_json", "chat_models_json", "expired_time").Updates(&user) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -148,6 +157,7 @@ func (h *UserHandler) Save(c *gin.Context) { } if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败") return } diff --git a/api/handler/chat_role_handler.go b/api/handler/chat_role_handler.go index f246cb3..707e7f4 100644 --- a/api/handler/chat_role_handler.go +++ b/api/handler/chat_role_handler.go @@ -96,7 +96,7 @@ func (h *ChatRoleHandler) UpdateRole(c *gin.Context) { res := h.DB.Model(&model.User{}).Where("id = ?", user.Id).UpdateColumn("chat_roles_json", utils.JsonEncode(data.Keys)) if res.Error != nil { - logger.Error("添加应用失败:", err) + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败!") return } diff --git a/api/handler/chatimpl/azure_handler.go b/api/handler/chatimpl/azure_handler.go index ac5ad7f..bd28d72 100644 --- a/api/handler/chatimpl/azure_handler.go +++ b/api/handler/chatimpl/azure_handler.go @@ -17,11 +17,9 @@ import ( "geekai/store/model" "geekai/store/vo" "geekai/utils" - "html/template" "io" "strings" "time" - "unicode/utf8" ) // 微软 Azure 模型消息发送实现 @@ -101,104 +99,12 @@ func (h *ChatHandler) sendAzureMessage( // 消息发送成功 if len(contents) > 0 { - - if message.Role == "" { - message.Role = "assistant" - } - message.Content = strings.Join(contents, "") - useMsg := types.Message{Role: "user", Content: prompt} - - // 更新上下文消息,如果是调用函数则不需要更新上下文 - if h.App.SysConfig.EnableContext { - chatCtx = append(chatCtx, useMsg) // 提问消息 - chatCtx = append(chatCtx, message) // 回复消息 - h.App.ChatContexts.Put(session.ChatId, chatCtx) - } - - // 追加聊天记录 - // for prompt - promptToken, err := utils.CalcTokens(prompt, req.Model) - if err != nil { - logger.Error(err) - } - historyUserMsg := model.ChatMessage{ - UserId: userVo.Id, - ChatId: session.ChatId, - RoleId: role.Id, - Type: types.PromptMsg, - Icon: userVo.Avatar, - Content: template.HTMLEscapeString(prompt), - Tokens: promptToken, - UseContext: true, - Model: req.Model, - } - historyUserMsg.CreatedAt = promptCreatedAt - historyUserMsg.UpdatedAt = promptCreatedAt - res := h.DB.Save(&historyUserMsg) - if res.Error != nil { - logger.Error("failed to save prompt history message: ", res.Error) - } - - // 计算本次对话消耗的总 token 数量 - replyTokens, _ := utils.CalcTokens(message.Content, req.Model) - replyTokens += getTotalTokens(req) - - historyReplyMsg := model.ChatMessage{ - UserId: userVo.Id, - ChatId: session.ChatId, - RoleId: role.Id, - Type: types.ReplyMsg, - Icon: role.Icon, - Content: message.Content, - Tokens: replyTokens, - UseContext: true, - Model: req.Model, - } - historyReplyMsg.CreatedAt = replyCreatedAt - historyReplyMsg.UpdatedAt = replyCreatedAt - res = h.DB.Create(&historyReplyMsg) - if res.Error != nil { - logger.Error("failed to save reply history message: ", res.Error) - } - - // 更新用户算力 - h.subUserPower(userVo, session, promptToken, replyTokens) - - // 保存当前会话 - var chatItem model.ChatItem - res = h.DB.Where("chat_id = ?", session.ChatId).First(&chatItem) - if res.Error != nil { - chatItem.ChatId = session.ChatId - chatItem.UserId = session.UserId - chatItem.RoleId = role.Id - chatItem.ModelId = session.Model.Id - if utf8.RuneCountInString(prompt) > 30 { - chatItem.Title = string([]rune(prompt)[:30]) + "..." - } else { - chatItem.Title = prompt - } - chatItem.Model = req.Model - h.DB.Create(&chatItem) - } + h.saveChatHistory(req, prompt, contents, message, chatCtx, session, role, userVo, promptCreatedAt, replyCreatedAt) } + } else { - body, err := io.ReadAll(response.Body) - if err != nil { - return fmt.Errorf("error with reading response: %v", err) - } - var res types.ApiError - err = json.Unmarshal(body, &res) - if err != nil { - return fmt.Errorf("error with decode response: %v", err) - } - - if strings.Contains(res.Error.Message, "maximum context length") { - logger.Error(res.Error.Message) - h.App.ChatContexts.Delete(session.ChatId) - return h.sendMessage(ctx, session, role, prompt, ws) - } else { - return fmt.Errorf("请求 Azure API 失败:%v", res.Error) - } + body, _ := io.ReadAll(response.Body) + return fmt.Errorf("请求大模型 API 失败:%s", body) } return nil diff --git a/api/handler/chatimpl/baidu_handler.go b/api/handler/chatimpl/baidu_handler.go index 6e591a3..783ac3e 100644 --- a/api/handler/chatimpl/baidu_handler.go +++ b/api/handler/chatimpl/baidu_handler.go @@ -17,12 +17,10 @@ import ( "geekai/store/model" "geekai/store/vo" "geekai/utils" - "html/template" "io" "net/http" "strings" "time" - "unicode/utf8" ) type baiduResp struct { @@ -130,99 +128,11 @@ func (h *ChatHandler) sendBaiduMessage( // 消息发送成功 if len(contents) > 0 { - if message.Role == "" { - message.Role = "assistant" - } - message.Content = strings.Join(contents, "") - useMsg := types.Message{Role: "user", Content: prompt} - - // 更新上下文消息,如果是调用函数则不需要更新上下文 - if h.App.SysConfig.EnableContext { - chatCtx = append(chatCtx, useMsg) // 提问消息 - chatCtx = append(chatCtx, message) // 回复消息 - h.App.ChatContexts.Put(session.ChatId, chatCtx) - } - - // 追加聊天记录 - // for prompt - promptToken, err := utils.CalcTokens(prompt, req.Model) - if err != nil { - logger.Error(err) - } - historyUserMsg := model.ChatMessage{ - UserId: userVo.Id, - ChatId: session.ChatId, - RoleId: role.Id, - Type: types.PromptMsg, - Icon: userVo.Avatar, - Content: template.HTMLEscapeString(prompt), - Tokens: promptToken, - UseContext: true, - Model: req.Model, - } - historyUserMsg.CreatedAt = promptCreatedAt - historyUserMsg.UpdatedAt = promptCreatedAt - res := h.DB.Save(&historyUserMsg) - if res.Error != nil { - logger.Error("failed to save prompt history message: ", res.Error) - } - - // for reply - // 计算本次对话消耗的总 token 数量 - replyTokens, _ := utils.CalcTokens(message.Content, req.Model) - totalTokens := replyTokens + getTotalTokens(req) - historyReplyMsg := model.ChatMessage{ - UserId: userVo.Id, - ChatId: session.ChatId, - RoleId: role.Id, - Type: types.ReplyMsg, - Icon: role.Icon, - Content: message.Content, - Tokens: totalTokens, - UseContext: true, - Model: req.Model, - } - historyReplyMsg.CreatedAt = replyCreatedAt - historyReplyMsg.UpdatedAt = replyCreatedAt - res = h.DB.Create(&historyReplyMsg) - if res.Error != nil { - logger.Error("failed to save reply history message: ", res.Error) - } - // 更新用户算力 - h.subUserPower(userVo, session, promptToken, replyTokens) - - // 保存当前会话 - var chatItem model.ChatItem - res = h.DB.Where("chat_id = ?", session.ChatId).First(&chatItem) - if res.Error != nil { - chatItem.ChatId = session.ChatId - chatItem.UserId = session.UserId - chatItem.RoleId = role.Id - chatItem.ModelId = session.Model.Id - if utf8.RuneCountInString(prompt) > 30 { - chatItem.Title = string([]rune(prompt)[:30]) + "..." - } else { - chatItem.Title = prompt - } - chatItem.Model = req.Model - h.DB.Create(&chatItem) - } + h.saveChatHistory(req, prompt, contents, message, chatCtx, session, role, userVo, promptCreatedAt, replyCreatedAt) } } else { - body, err := io.ReadAll(response.Body) - if err != nil { - return fmt.Errorf("error with reading response: %v", err) - } - - var res struct { - Code int `json:"error_code"` - Msg string `json:"error_msg"` - } - err = json.Unmarshal(body, &res) - if err != nil { - return fmt.Errorf("error with decode response: %v", err) - } - utils.ReplyMessage(ws, "请求百度文心大模型 API 失败:"+res.Msg) + body, _ := io.ReadAll(response.Body) + return fmt.Errorf("请求大模型 API 失败:%s", body) } return nil diff --git a/api/handler/chatimpl/chat_handler.go b/api/handler/chatimpl/chat_handler.go index 7376aad..4ad6965 100644 --- a/api/handler/chatimpl/chat_handler.go +++ b/api/handler/chatimpl/chat_handler.go @@ -17,16 +17,19 @@ import ( "geekai/core/types" "geekai/handler" logger2 "geekai/logger" + "geekai/service" "geekai/service/oss" "geekai/store/model" "geekai/store/vo" "geekai/utils" "geekai/utils/resp" + "html/template" "net/http" "net/url" "regexp" "strings" "time" + "unicode/utf8" "github.com/gin-gonic/gin" "github.com/go-redis/redis/v8" @@ -38,15 +41,17 @@ var logger = logger2.GetLogger() type ChatHandler struct { handler.BaseHandler - redis *redis.Client - uploadManager *oss.UploaderManager + redis *redis.Client + uploadManager *oss.UploaderManager + licenseService *service.LicenseService } -func NewChatHandler(app *core.AppServer, db *gorm.DB, redis *redis.Client, manager *oss.UploaderManager) *ChatHandler { +func NewChatHandler(app *core.AppServer, db *gorm.DB, redis *redis.Client, manager *oss.UploaderManager, licenseService *service.LicenseService) *ChatHandler { return &ChatHandler{ - BaseHandler: handler.BaseHandler{App: app, DB: db}, - redis: redis, - uploadManager: manager, + BaseHandler: handler.BaseHandler{App: app, DB: db}, + redis: redis, + uploadManager: manager, + licenseService: licenseService, } } @@ -119,7 +124,7 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) { MaxContext: chatModel.MaxContext, Temperature: chatModel.Temperature, KeyId: chatModel.KeyId, - Platform: types.Platform(chatModel.Platform)} + Platform: chatModel.Platform} logger.Infof("New websocket connected, IP: %s, Username: %s", c.ClientIP(), session.Username) // 保存会话连接 @@ -215,11 +220,11 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio Stream: true, } switch session.Model.Platform { - case types.Azure, types.ChatGLM, types.Baidu, types.XunFei: + case types.Azure.Value, types.ChatGLM.Value, types.Baidu.Value, types.XunFei.Value: req.Temperature = session.Model.Temperature req.MaxTokens = session.Model.MaxTokens break - case types.OpenAI: + case types.OpenAI.Value: req.Temperature = session.Model.Temperature req.MaxTokens = session.Model.MaxTokens // OpenAI 支持函数功能 @@ -236,8 +241,6 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio if err != nil { continue } - required := parameters["required"] - delete(parameters, "required") tool := types.Tool{ Type: "function", Function: types.Function{ @@ -246,10 +249,8 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio Parameters: parameters, }, } - - // Fixed: compatible for gpt4-turbo-xxx model - if !strings.HasPrefix(req.Model, "gpt-4-turbo-") { - tool.Function.Required = required + if v, ok := parameters["required"]; v == nil || !ok { + tool.Function.Parameters["required"] = []string{} } tools = append(tools, tool) } @@ -258,7 +259,7 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio req.Tools = tools req.ToolChoice = "auto" } - case types.QWen: + case types.QWen.Value: req.Parameters = map[string]interface{}{ "max_tokens": session.Model.MaxTokens, "temperature": session.Model.Temperature, @@ -322,14 +323,14 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio reqMgs = append(reqMgs, m) } - if session.Model.Platform == types.QWen { + if session.Model.Platform == types.QWen.Value { req.Input = make(map[string]interface{}) reqMgs = append(reqMgs, types.Message{ Role: "user", Content: prompt, }) req.Input["messages"] = reqMgs - } else if session.Model.Platform == types.OpenAI { // extract image for gpt-vision model + } else if session.Model.Platform == types.OpenAI.Value { // extract image for gpt-vision model imgURLs := utils.ExtractImgURL(prompt) logger.Debugf("detected IMG: %+v", imgURLs) var content interface{} @@ -367,17 +368,17 @@ func (h *ChatHandler) sendMessage(ctx context.Context, session *types.ChatSessio logger.Debugf("%+v", req.Messages) switch session.Model.Platform { - case types.Azure: + case types.Azure.Value: return h.sendAzureMessage(chatCtx, req, userVo, ctx, session, role, prompt, ws) - case types.OpenAI: + case types.OpenAI.Value: return h.sendOpenAiMessage(chatCtx, req, userVo, ctx, session, role, prompt, ws) - case types.ChatGLM: + case types.ChatGLM.Value: return h.sendChatGLMMessage(chatCtx, req, userVo, ctx, session, role, prompt, ws) - case types.Baidu: + case types.Baidu.Value: return h.sendBaiduMessage(chatCtx, req, userVo, ctx, session, role, prompt, ws) - case types.XunFei: + case types.XunFei.Value: return h.sendXunFeiMessage(chatCtx, req, userVo, ctx, session, role, prompt, ws) - case types.QWen: + case types.QWen.Value: return h.sendQWenMessage(chatCtx, req, userVo, ctx, session, role, prompt, ws) } @@ -457,27 +458,35 @@ func (h *ChatHandler) doRequest(ctx context.Context, req types.ApiRequest, sessi } // use the last unused key if apiKey.Id == 0 { - h.DB.Debug().Where("platform", session.Model.Platform).Where("type", "chat").Where("enabled", true).Order("last_used_at ASC").First(apiKey) + h.DB.Where("platform", session.Model.Platform).Where("type", "chat").Where("enabled", true).Order("last_used_at ASC").First(apiKey) } if apiKey.Id == 0 { return nil, errors.New("no available key, please import key") } + // ONLY allow apiURL in blank list + if session.Model.Platform == types.OpenAI.Value { + err := h.licenseService.IsValidApiURL(apiKey.ApiURL) + if err != nil { + return nil, err + } + } + var apiURL string switch session.Model.Platform { - case types.Azure: + case types.Azure.Value: md := strings.Replace(req.Model, ".", "", 1) apiURL = strings.Replace(apiKey.ApiURL, "{model}", md, 1) break - case types.ChatGLM: + case types.ChatGLM.Value: apiURL = strings.Replace(apiKey.ApiURL, "{model}", req.Model, 1) req.Prompt = req.Messages // 使用 prompt 字段替代 message 字段 req.Messages = nil break - case types.Baidu: + case types.Baidu.Value: apiURL = strings.Replace(apiKey.ApiURL, "{model}", req.Model, 1) break - case types.QWen: + case types.QWen.Value: apiURL = apiKey.ApiURL req.Messages = nil break @@ -487,7 +496,7 @@ func (h *ChatHandler) doRequest(ctx context.Context, req types.ApiRequest, sessi // 更新 API KEY 的最后使用时间 h.DB.Model(apiKey).UpdateColumn("last_used_at", time.Now().Unix()) // 百度文心,需要串接 access_token - if session.Model.Platform == types.Baidu { + if session.Model.Platform == types.Baidu.Value { token, err := h.getBaiduToken(apiKey.Value) if err != nil { return nil, err @@ -523,22 +532,22 @@ func (h *ChatHandler) doRequest(ctx context.Context, req types.ApiRequest, sessi } logger.Debugf("Sending %s request, ApiURL:%s, API KEY:%s, PROXY: %s, Model: %s", session.Model.Platform, apiURL, apiKey.Value, apiKey.ProxyURL, req.Model) switch session.Model.Platform { - case types.Azure: + case types.Azure.Value: request.Header.Set("api-key", apiKey.Value) break - case types.ChatGLM: + case types.ChatGLM.Value: token, err := h.getChatGLMToken(apiKey.Value) if err != nil { return nil, err } request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) break - case types.Baidu: + case types.Baidu.Value: request.RequestURI = "" - case types.OpenAI: + case types.OpenAI.Value: request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey.Value)) break - case types.QWen: + case types.QWen.Value: request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey.Value)) request.Header.Set("X-DashScope-SSE", "enable") break @@ -572,6 +581,99 @@ func (h *ChatHandler) subUserPower(userVo vo.User, session *types.ChatSession, p } +func (h *ChatHandler) saveChatHistory( + req types.ApiRequest, + prompt string, + contents []string, + message types.Message, + chatCtx []types.Message, + session *types.ChatSession, + role model.ChatRole, + userVo vo.User, + promptCreatedAt time.Time, + replyCreatedAt time.Time) { + if message.Role == "" { + message.Role = "assistant" + } + message.Content = strings.Join(contents, "") + useMsg := types.Message{Role: "user", Content: prompt} + + // 更新上下文消息,如果是调用函数则不需要更新上下文 + if h.App.SysConfig.EnableContext { + chatCtx = append(chatCtx, useMsg) // 提问消息 + chatCtx = append(chatCtx, message) // 回复消息 + h.App.ChatContexts.Put(session.ChatId, chatCtx) + } + + // 追加聊天记录 + // for prompt + promptToken, err := utils.CalcTokens(prompt, req.Model) + if err != nil { + logger.Error(err) + } + historyUserMsg := model.ChatMessage{ + UserId: userVo.Id, + ChatId: session.ChatId, + RoleId: role.Id, + Type: types.PromptMsg, + Icon: userVo.Avatar, + Content: template.HTMLEscapeString(prompt), + Tokens: promptToken, + UseContext: true, + Model: req.Model, + } + historyUserMsg.CreatedAt = promptCreatedAt + historyUserMsg.UpdatedAt = promptCreatedAt + res := h.DB.Save(&historyUserMsg) + if res.Error != nil { + logger.Error("failed to save prompt history message: ", res.Error) + } + + // for reply + // 计算本次对话消耗的总 token 数量 + replyTokens, _ := utils.CalcTokens(message.Content, req.Model) + totalTokens := replyTokens + getTotalTokens(req) + historyReplyMsg := model.ChatMessage{ + UserId: userVo.Id, + ChatId: session.ChatId, + RoleId: role.Id, + Type: types.ReplyMsg, + Icon: role.Icon, + Content: message.Content, + Tokens: totalTokens, + UseContext: true, + Model: req.Model, + } + historyReplyMsg.CreatedAt = replyCreatedAt + historyReplyMsg.UpdatedAt = replyCreatedAt + res = h.DB.Create(&historyReplyMsg) + if res.Error != nil { + logger.Error("failed to save reply history message: ", res.Error) + } + + if session.Model.Power > 0 { + // 更新用户算力 + h.subUserPower(userVo, session, promptToken, replyTokens) + + // 保存当前会话 + var chatItem model.ChatItem + res = h.DB.Where("chat_id = ?", session.ChatId).First(&chatItem) + if res.Error != nil { + chatItem.ChatId = session.ChatId + chatItem.UserId = session.UserId + chatItem.RoleId = role.Id + chatItem.ModelId = session.Model.Id + if utf8.RuneCountInString(prompt) > 30 { + chatItem.Title = string([]rune(prompt)[:30]) + "..." + } else { + chatItem.Title = prompt + } + chatItem.Model = req.Model + h.DB.Create(&chatItem) + } + } +} + // 将AI回复消息中生成的图片链接下载到本地 func (h *ChatHandler) extractImgUrl(text string) string { pattern := `!\[([^\]]*)]\(([^)]+)\)` diff --git a/api/handler/chatimpl/chatglm_handler.go b/api/handler/chatimpl/chatglm_handler.go index 53e83bc..0192abc 100644 --- a/api/handler/chatimpl/chatglm_handler.go +++ b/api/handler/chatimpl/chatglm_handler.go @@ -10,7 +10,6 @@ package chatimpl import ( "bufio" "context" - "encoding/json" "errors" "fmt" "geekai/core/types" @@ -18,11 +17,9 @@ import ( "geekai/store/vo" "geekai/utils" "github.com/golang-jwt/jwt/v5" - "html/template" "io" "strings" "time" - "unicode/utf8" ) // 清华大学 ChatGML 消息发送实现 @@ -108,103 +105,11 @@ func (h *ChatHandler) sendChatGLMMessage( // 消息发送成功 if len(contents) > 0 { - if message.Role == "" { - message.Role = "assistant" - } - message.Content = strings.Join(contents, "") - useMsg := types.Message{Role: "user", Content: prompt} - - // 更新上下文消息,如果是调用函数则不需要更新上下文 - if h.App.SysConfig.EnableContext { - chatCtx = append(chatCtx, useMsg) // 提问消息 - chatCtx = append(chatCtx, message) // 回复消息 - h.App.ChatContexts.Put(session.ChatId, chatCtx) - } - - // 追加聊天记录 - // for prompt - promptToken, err := utils.CalcTokens(prompt, req.Model) - if err != nil { - logger.Error(err) - } - historyUserMsg := model.ChatMessage{ - UserId: userVo.Id, - ChatId: session.ChatId, - RoleId: role.Id, - Type: types.PromptMsg, - Icon: userVo.Avatar, - Content: template.HTMLEscapeString(prompt), - Tokens: promptToken, - UseContext: true, - Model: req.Model, - } - historyUserMsg.CreatedAt = promptCreatedAt - historyUserMsg.UpdatedAt = promptCreatedAt - res := h.DB.Save(&historyUserMsg) - if res.Error != nil { - logger.Error("failed to save prompt history message: ", res.Error) - } - - // for reply - // 计算本次对话消耗的总 token 数量 - replyTokens, _ := utils.CalcTokens(message.Content, req.Model) - totalTokens := replyTokens + getTotalTokens(req) - historyReplyMsg := model.ChatMessage{ - UserId: userVo.Id, - ChatId: session.ChatId, - RoleId: role.Id, - Type: types.ReplyMsg, - Icon: role.Icon, - Content: message.Content, - Tokens: totalTokens, - UseContext: true, - Model: req.Model, - } - historyReplyMsg.CreatedAt = replyCreatedAt - historyReplyMsg.UpdatedAt = replyCreatedAt - res = h.DB.Create(&historyReplyMsg) - if res.Error != nil { - logger.Error("failed to save reply history message: ", res.Error) - } - - // 更新用户算力 - h.subUserPower(userVo, session, promptToken, replyTokens) - - // 保存当前会话 - var chatItem model.ChatItem - res = h.DB.Where("chat_id = ?", session.ChatId).First(&chatItem) - if res.Error != nil { - chatItem.ChatId = session.ChatId - chatItem.UserId = session.UserId - chatItem.RoleId = role.Id - chatItem.ModelId = session.Model.Id - if utf8.RuneCountInString(prompt) > 30 { - chatItem.Title = string([]rune(prompt)[:30]) + "..." - } else { - chatItem.Title = prompt - } - chatItem.Model = req.Model - h.DB.Create(&chatItem) - } + h.saveChatHistory(req, prompt, contents, message, chatCtx, session, role, userVo, promptCreatedAt, replyCreatedAt) } } else { - body, err := io.ReadAll(response.Body) - if err != nil { - return fmt.Errorf("error with reading response: %v", err) - } - - var res struct { - Code int `json:"code"` - Success bool `json:"success"` - Msg string `json:"msg"` - } - err = json.Unmarshal(body, &res) - if err != nil { - return fmt.Errorf("error with decode response: %v", err) - } - if !res.Success { - utils.ReplyMessage(ws, "请求 ChatGLM 失败:"+res.Msg) - } + body, _ := io.ReadAll(response.Body) + return fmt.Errorf("请求大模型 API 失败:%s", body) } return nil diff --git a/api/handler/chatimpl/openai_handler.go b/api/handler/chatimpl/openai_handler.go index 3878c46..fb953b7 100644 --- a/api/handler/chatimpl/openai_handler.go +++ b/api/handler/chatimpl/openai_handler.go @@ -17,13 +17,10 @@ import ( "geekai/store/model" "geekai/store/vo" "geekai/utils" - "html/template" + req2 "github.com/imroc/req/v3" "io" "strings" "time" - "unicode/utf8" - - req2 "github.com/imroc/req/v3" ) // OPenAI 消息发送实现 @@ -178,126 +175,11 @@ func (h *ChatHandler) sendOpenAiMessage( // 消息发送成功 if len(contents) > 0 { - if message.Role == "" { - message.Role = "assistant" - } - message.Content = strings.Join(contents, "") - useMsg := types.Message{Role: "user", Content: prompt} - - // 更新上下文消息,如果是调用函数则不需要更新上下文 - if h.App.SysConfig.EnableContext && toolCall == false { - chatCtx = append(chatCtx, useMsg) // 提问消息 - chatCtx = append(chatCtx, message) // 回复消息 - h.App.ChatContexts.Put(session.ChatId, chatCtx) - } - - // 追加聊天记录 - useContext := true - if toolCall { - useContext = false - } - - // for prompt - promptToken, err := utils.CalcTokens(prompt, req.Model) - if err != nil { - logger.Error(err) - } - historyUserMsg := model.ChatMessage{ - UserId: userVo.Id, - ChatId: session.ChatId, - RoleId: role.Id, - Type: types.PromptMsg, - Icon: userVo.Avatar, - Content: template.HTMLEscapeString(prompt), - Tokens: promptToken, - UseContext: useContext, - Model: req.Model, - } - historyUserMsg.CreatedAt = promptCreatedAt - historyUserMsg.UpdatedAt = promptCreatedAt - res := h.DB.Save(&historyUserMsg) - if res.Error != nil { - logger.Error("failed to save prompt history message: ", res.Error) - } - - // 计算本次对话消耗的总 token 数量 - var replyTokens = 0 - if toolCall { // prompt + 函数名 + 参数 token - tokens, _ := utils.CalcTokens(function.Name, req.Model) - replyTokens += tokens - tokens, _ = utils.CalcTokens(utils.InterfaceToString(arguments), req.Model) - replyTokens += tokens - } else { - replyTokens, _ = utils.CalcTokens(message.Content, req.Model) - } - replyTokens += getTotalTokens(req) - - historyReplyMsg := model.ChatMessage{ - UserId: userVo.Id, - ChatId: session.ChatId, - RoleId: role.Id, - Type: types.ReplyMsg, - Icon: role.Icon, - Content: h.extractImgUrl(message.Content), - Tokens: replyTokens, - UseContext: useContext, - Model: req.Model, - } - historyReplyMsg.CreatedAt = replyCreatedAt - historyReplyMsg.UpdatedAt = replyCreatedAt - res = h.DB.Create(&historyReplyMsg) - if res.Error != nil { - logger.Error("failed to save reply history message: ", res.Error) - } - - // 更新用户算力 - h.subUserPower(userVo, session, promptToken, replyTokens) - - // 保存当前会话 - var chatItem model.ChatItem - res = h.DB.Where("chat_id = ?", session.ChatId).First(&chatItem) - if res.Error != nil { - chatItem.ChatId = session.ChatId - chatItem.UserId = session.UserId - chatItem.RoleId = role.Id - chatItem.ModelId = session.Model.Id - if utf8.RuneCountInString(prompt) > 30 { - chatItem.Title = string([]rune(prompt)[:30]) + "..." - } else { - chatItem.Title = prompt - } - chatItem.Model = req.Model - h.DB.Create(&chatItem) - } + h.saveChatHistory(req, prompt, contents, message, chatCtx, session, role, userVo, promptCreatedAt, replyCreatedAt) } } else { - body, err := io.ReadAll(response.Body) - if err != nil { - utils.ReplyMessage(ws, "请求 OpenAI API 失败:"+err.Error()) - return fmt.Errorf("error with reading response: %v", err) - } - var res types.ApiError - err = json.Unmarshal(body, &res) - if err != nil { - utils.ReplyMessage(ws, "请求 OpenAI API 失败:\n"+"```\n"+string(body)+"```") - return fmt.Errorf("error with decode response: %v", err) - } - - // OpenAI API 调用异常处理 - if strings.Contains(res.Error.Message, "This key is associated with a deactivated account") { - utils.ReplyMessage(ws, "请求 OpenAI API 失败:API KEY 所关联的账户被禁用。") - // 移除当前 API key - h.DB.Where("value = ?", apiKey).Delete(&model.ApiKey{}) - } else if strings.Contains(res.Error.Message, "You exceeded your current quota") { - utils.ReplyMessage(ws, "请求 OpenAI API 失败:API KEY 触发并发限制,请稍后再试。") - } else if strings.Contains(res.Error.Message, "This model's maximum context length") { - logger.Error(res.Error.Message) - utils.ReplyMessage(ws, "当前会话上下文长度超出限制,已为您清空会话上下文!") - h.App.ChatContexts.Delete(session.ChatId) - return h.sendMessage(ctx, session, role, prompt, ws) - } else { - utils.ReplyMessage(ws, "请求 OpenAI API 失败:"+res.Error.Message) - } + body, _ := io.ReadAll(response.Body) + return fmt.Errorf("请求 OpenAI API 失败:%s", body) } return nil diff --git a/api/handler/chatimpl/qwen_handler.go b/api/handler/chatimpl/qwen_handler.go index 7b7eb1a..28bf66b 100644 --- a/api/handler/chatimpl/qwen_handler.go +++ b/api/handler/chatimpl/qwen_handler.go @@ -10,18 +10,15 @@ package chatimpl import ( "bufio" "context" - "encoding/json" "fmt" "geekai/core/types" "geekai/store/model" "geekai/store/vo" "geekai/utils" "github.com/syndtr/goleveldb/leveldb/errors" - "html/template" "io" "strings" "time" - "unicode/utf8" ) type qWenResp struct { @@ -142,100 +139,11 @@ func (h *ChatHandler) sendQWenMessage( // 消息发送成功 if len(contents) > 0 { - if message.Role == "" { - message.Role = "assistant" - } - message.Content = strings.Join(contents, "") - useMsg := types.Message{Role: "user", Content: prompt} - - // 更新上下文消息,如果是调用函数则不需要更新上下文 - if h.App.SysConfig.EnableContext { - chatCtx = append(chatCtx, useMsg) // 提问消息 - chatCtx = append(chatCtx, message) // 回复消息 - h.App.ChatContexts.Put(session.ChatId, chatCtx) - } - - // 追加聊天记录 - // for prompt - promptToken, err := utils.CalcTokens(prompt, req.Model) - if err != nil { - logger.Error(err) - } - historyUserMsg := model.ChatMessage{ - UserId: userVo.Id, - ChatId: session.ChatId, - RoleId: role.Id, - Type: types.PromptMsg, - Icon: userVo.Avatar, - Content: template.HTMLEscapeString(prompt), - Tokens: promptToken, - UseContext: true, - Model: req.Model, - } - historyUserMsg.CreatedAt = promptCreatedAt - historyUserMsg.UpdatedAt = promptCreatedAt - res := h.DB.Save(&historyUserMsg) - if res.Error != nil { - logger.Error("failed to save prompt history message: ", res.Error) - } - - // for reply - // 计算本次对话消耗的总 token 数量 - replyTokens, _ := utils.CalcTokens(message.Content, req.Model) - totalTokens := replyTokens + getTotalTokens(req) - historyReplyMsg := model.ChatMessage{ - UserId: userVo.Id, - ChatId: session.ChatId, - RoleId: role.Id, - Type: types.ReplyMsg, - Icon: role.Icon, - Content: message.Content, - Tokens: totalTokens, - UseContext: true, - Model: req.Model, - } - historyReplyMsg.CreatedAt = replyCreatedAt - historyReplyMsg.UpdatedAt = replyCreatedAt - res = h.DB.Create(&historyReplyMsg) - if res.Error != nil { - logger.Error("failed to save reply history message: ", res.Error) - } - - // 更新用户算力 - h.subUserPower(userVo, session, promptToken, replyTokens) - - // 保存当前会话 - var chatItem model.ChatItem - res = h.DB.Where("chat_id = ?", session.ChatId).First(&chatItem) - if res.Error != nil { - chatItem.ChatId = session.ChatId - chatItem.UserId = session.UserId - chatItem.RoleId = role.Id - chatItem.ModelId = session.Model.Id - if utf8.RuneCountInString(prompt) > 30 { - chatItem.Title = string([]rune(prompt)[:30]) + "..." - } else { - chatItem.Title = prompt - } - chatItem.Model = req.Model - h.DB.Create(&chatItem) - } + h.saveChatHistory(req, prompt, contents, message, chatCtx, session, role, userVo, promptCreatedAt, replyCreatedAt) } } else { - body, err := io.ReadAll(response.Body) - if err != nil { - return fmt.Errorf("error with reading response: %v", err) - } - - var res struct { - Code int `json:"error_code"` - Msg string `json:"error_msg"` - } - err = json.Unmarshal(body, &res) - if err != nil { - return fmt.Errorf("error with decode response: %v", err) - } - utils.ReplyMessage(ws, "请求通义千问大模型 API 失败:"+res.Msg) + body, _ := io.ReadAll(response.Body) + return fmt.Errorf("请求大模型 API 失败:%s", body) } return nil diff --git a/api/handler/chatimpl/xunfei_handler.go b/api/handler/chatimpl/xunfei_handler.go index afc1c16..e4a081f 100644 --- a/api/handler/chatimpl/xunfei_handler.go +++ b/api/handler/chatimpl/xunfei_handler.go @@ -21,13 +21,11 @@ import ( "geekai/utils" "github.com/gorilla/websocket" "gorm.io/gorm" - "html/template" "io" "net/http" "net/url" "strings" "time" - "unicode/utf8" ) type xunFeiResp struct { @@ -181,89 +179,10 @@ func (h *ChatHandler) sendXunFeiMessage( } } - // 消息发送成功 if len(contents) > 0 { - if message.Role == "" { - message.Role = "assistant" - } - message.Content = strings.Join(contents, "") - useMsg := types.Message{Role: "user", Content: prompt} - - // 更新上下文消息,如果是调用函数则不需要更新上下文 - if h.App.SysConfig.EnableContext { - chatCtx = append(chatCtx, useMsg) // 提问消息 - chatCtx = append(chatCtx, message) // 回复消息 - h.App.ChatContexts.Put(session.ChatId, chatCtx) - } - - // 追加聊天记录 - // for prompt - promptToken, err := utils.CalcTokens(prompt, req.Model) - if err != nil { - logger.Error(err) - } - historyUserMsg := model.ChatMessage{ - UserId: userVo.Id, - ChatId: session.ChatId, - RoleId: role.Id, - Type: types.PromptMsg, - Icon: userVo.Avatar, - Content: template.HTMLEscapeString(prompt), - Tokens: promptToken, - UseContext: true, - Model: req.Model, - } - historyUserMsg.CreatedAt = promptCreatedAt - historyUserMsg.UpdatedAt = promptCreatedAt - res := h.DB.Save(&historyUserMsg) - if res.Error != nil { - logger.Error("failed to save prompt history message: ", res.Error) - } - - // for reply - // 计算本次对话消耗的总 token 数量 - replyTokens, _ := utils.CalcTokens(message.Content, req.Model) - totalTokens := replyTokens + getTotalTokens(req) - historyReplyMsg := model.ChatMessage{ - UserId: userVo.Id, - ChatId: session.ChatId, - RoleId: role.Id, - Type: types.ReplyMsg, - Icon: role.Icon, - Content: message.Content, - Tokens: totalTokens, - UseContext: true, - Model: req.Model, - } - historyReplyMsg.CreatedAt = replyCreatedAt - historyReplyMsg.UpdatedAt = replyCreatedAt - res = h.DB.Create(&historyReplyMsg) - if res.Error != nil { - logger.Error("failed to save reply history message: ", res.Error) - } - - // 更新用户算力 - h.subUserPower(userVo, session, promptToken, replyTokens) - - // 保存当前会话 - var chatItem model.ChatItem - res = h.DB.Where("chat_id = ?", session.ChatId).First(&chatItem) - if res.Error != nil { - chatItem.ChatId = session.ChatId - chatItem.UserId = session.UserId - chatItem.RoleId = role.Id - chatItem.ModelId = session.Model.Id - if utf8.RuneCountInString(prompt) > 30 { - chatItem.Title = string([]rune(prompt)[:30]) + "..." - } else { - chatItem.Title = prompt - } - chatItem.Model = req.Model - h.DB.Create(&chatItem) - } + h.saveChatHistory(req, prompt, contents, message, chatCtx, session, role, userVo, promptCreatedAt, replyCreatedAt) } - return nil } diff --git a/api/handler/config_handler.go b/api/handler/config_handler.go index 0b8fdb0..30e33b8 100644 --- a/api/handler/config_handler.go +++ b/api/handler/config_handler.go @@ -9,6 +9,7 @@ package handler import ( "geekai/core" + "geekai/service" "geekai/store/model" "geekai/utils" "geekai/utils/resp" @@ -19,10 +20,11 @@ import ( type ConfigHandler struct { BaseHandler + licenseService *service.LicenseService } -func NewConfigHandler(app *core.AppServer, db *gorm.DB) *ConfigHandler { - return &ConfigHandler{BaseHandler: BaseHandler{App: app, DB: db}} +func NewConfigHandler(app *core.AppServer, db *gorm.DB, licenseService *service.LicenseService) *ConfigHandler { + return &ConfigHandler{BaseHandler: BaseHandler{App: app, DB: db}, licenseService: licenseService} } // Get 获取指定的系统配置 @@ -44,3 +46,9 @@ func (h *ConfigHandler) Get(c *gin.Context) { resp.SUCCESS(c, value) } + +// License 获取 License 配置 +func (h *ConfigHandler) License(c *gin.Context) { + license := h.licenseService.GetLicense() + resp.SUCCESS(c, license.Configs) +} diff --git a/api/handler/dalle_handler.go b/api/handler/dalle_handler.go index a62fd71..07cd032 100644 --- a/api/handler/dalle_handler.go +++ b/api/handler/dalle_handler.go @@ -253,6 +253,7 @@ func (h *DallJobHandler) Publish(c *gin.Context) { res := h.DB.Model(&model.DallJob{Id: data.Id}).UpdateColumn("publish", true) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败") return } diff --git a/api/handler/mj_handler.go b/api/handler/mj_handler.go index 2f21080..822df42 100644 --- a/api/handler/mj_handler.go +++ b/api/handler/mj_handler.go @@ -8,6 +8,8 @@ package handler // * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import ( + "encoding/base64" + "fmt" "geekai/core" "geekai/core/types" "geekai/service" @@ -17,8 +19,6 @@ import ( "geekai/store/vo" "geekai/utils" "geekai/utils/resp" - "encoding/base64" - "fmt" "net/http" "strings" "time" @@ -511,6 +511,7 @@ func (h *MidJourneyHandler) Publish(c *gin.Context) { res := h.DB.Model(&model.MidJourneyJob{Id: data.Id}).UpdateColumn("publish", data.Action) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败") return } diff --git a/api/handler/payment_handler.go b/api/handler/payment_handler.go index b616278..9c18651 100644 --- a/api/handler/payment_handler.go +++ b/api/handler/payment_handler.go @@ -8,6 +8,9 @@ package handler // * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import ( + "embed" + "encoding/base64" + "fmt" "geekai/core" "geekai/core/types" "geekai/service" @@ -15,9 +18,6 @@ import ( "geekai/store/model" "geekai/utils" "geekai/utils/resp" - "embed" - "encoding/base64" - "fmt" "github.com/shopspring/decimal" "math" "net/http" @@ -44,6 +44,7 @@ type PaymentHandler struct { snowflake *service.Snowflake fs embed.FS lock sync.Mutex + signKey string // 用来签名的随机秘钥 } func NewPaymentHandler( @@ -65,12 +66,27 @@ func NewPaymentHandler( App: server, DB: db, }, + signKey: utils.RandString(32), } } func (h *PaymentHandler) DoPay(c *gin.Context) { orderNo := h.GetTrim(c, "order_no") payWay := h.GetTrim(c, "pay_way") + t := h.GetInt(c, "t", 0) + sign := h.GetTrim(c, "sign") + signStr := fmt.Sprintf("%s-%s-%d-%s", orderNo, payWay, t, h.signKey) + newSign := utils.Sha256(signStr) + if newSign != sign { + resp.ERROR(c, "订单签名错误!") + return + } + + // 检查二维码是否过期 + if time.Now().Unix()-int64(t) > int64(h.App.SysConfig.OrderPayTimeout) { + resp.ERROR(c, "支付二维码已过期,请重新生成!") + return + } if orderNo == "" { resp.ERROR(c, types.InvalidArgs) @@ -273,8 +289,10 @@ func (h *PaymentHandler) PayQrcode(c *gin.Context) { resp.ERROR(c, err.Error()) return } - - imageURL := fmt.Sprintf("%s://%s/api/payment/doPay?order_no=%s&pay_way=%s", parse.Scheme, parse.Host, orderNo, data.PayWay) + timestamp := time.Now().Unix() + signStr := fmt.Sprintf("%s-%s-%d-%s", orderNo, data.PayWay, timestamp, h.signKey) + sign := utils.Sha256(signStr) + imageURL := fmt.Sprintf("%s://%s/api/payment/doPay?order_no=%s&pay_way=%s&t=%d&sign=%s", parse.Scheme, parse.Host, orderNo, data.PayWay, timestamp, sign) imgData, err := utils.GenQrcode(imageURL, 400, file) if err != nil { resp.ERROR(c, err.Error()) @@ -324,6 +342,8 @@ func (h *PaymentHandler) Mobile(c *gin.Context) { payWay = PayWayXunHu notifyURL = h.App.Config.HuPiPayConfig.NotifyURL returnURL = h.App.Config.HuPiPayConfig.ReturnURL + parse, _ := url.Parse(h.App.Config.HuPiPayConfig.ReturnURL) + baseURL := fmt.Sprintf("%s://%s", parse.Scheme, parse.Host) params := payment.HuPiPayReq{ Version: "1.1", TradeOrderId: orderNo, @@ -333,6 +353,8 @@ func (h *PaymentHandler) Mobile(c *gin.Context) { ReturnURL: returnURL, CallbackURL: returnURL, WapName: "极客学长", + WapUrl: baseURL, + Type: "WAP", } r, err := h.huPiPayService.Pay(params) if err != nil { diff --git a/api/handler/reward_handler.go b/api/handler/reward_handler.go index ec019e9..44045f5 100644 --- a/api/handler/reward_handler.go +++ b/api/handler/reward_handler.go @@ -8,13 +8,13 @@ package handler // * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import ( + "fmt" "geekai/core" "geekai/core/types" "geekai/store/model" "geekai/store/vo" "geekai/utils" "geekai/utils/resp" - "fmt" "github.com/gin-gonic/gin" "gorm.io/gorm" "math" @@ -73,6 +73,7 @@ func (h *RewardHandler) Verify(c *gin.Context) { res = tx.Model(&user).UpdateColumn("power", gorm.Expr("power + ?", exchange.Power)) if res.Error != nil { tx.Rollback() + logger.Error("添加应用失败:", res.Error) resp.ERROR(c, "更新数据库失败!") return } @@ -84,6 +85,7 @@ func (h *RewardHandler) Verify(c *gin.Context) { res = tx.Updates(&item) if res.Error != nil { tx.Rollback() + logger.Error("添加应用失败:", res.Error) resp.ERROR(c, "更新数据库失败!") return } diff --git a/api/handler/sd_handler.go b/api/handler/sd_handler.go index c4a5c3e..e30e837 100644 --- a/api/handler/sd_handler.go +++ b/api/handler/sd_handler.go @@ -8,6 +8,7 @@ package handler // * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import ( + "fmt" "geekai/core" "geekai/core/types" "geekai/service" @@ -18,7 +19,6 @@ import ( "geekai/store/vo" "geekai/utils" "geekai/utils/resp" - "fmt" "net/http" "time" @@ -325,6 +325,7 @@ func (h *SdJobHandler) Publish(c *gin.Context) { res := h.DB.Model(&model.SdJob{Id: data.Id}).UpdateColumn("publish", true) if res.Error != nil { + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败") return } diff --git a/api/handler/user_handler.go b/api/handler/user_handler.go index fa96604..2718d15 100644 --- a/api/handler/user_handler.go +++ b/api/handler/user_handler.go @@ -11,6 +11,7 @@ import ( "fmt" "geekai/core" "geekai/core/types" + "geekai/service" "geekai/store/model" "geekai/store/vo" "geekai/utils" @@ -28,19 +29,22 @@ import ( type UserHandler struct { BaseHandler - searcher *xdb.Searcher - redis *redis.Client + searcher *xdb.Searcher + redis *redis.Client + licenseService *service.LicenseService } func NewUserHandler( app *core.AppServer, db *gorm.DB, searcher *xdb.Searcher, - client *redis.Client) *UserHandler { + client *redis.Client, + licenseService *service.LicenseService) *UserHandler { return &UserHandler{ - BaseHandler: BaseHandler{DB: db, App: app}, - searcher: searcher, - redis: client, + BaseHandler: BaseHandler{DB: db, App: app}, + searcher: searcher, + redis: client, + licenseService: licenseService, } } @@ -64,6 +68,14 @@ func (h *UserHandler) Register(c *gin.Context) { return } + // 检测最大注册人数 + var totalUser int64 + h.DB.Model(&model.User{}).Count(&totalUser) + if h.licenseService.GetLicense().Configs.UserNum > 0 && int(totalUser) >= h.licenseService.GetLicense().Configs.UserNum { + resp.ERROR(c, "当前注册用户数已达上限,请请升级 License") + return + } + // 检查验证码 var key string if data.RegWay == "email" || data.RegWay == "mobile" { @@ -337,7 +349,7 @@ func (h *UserHandler) UpdatePass(c *gin.Context) { newPass := utils.GenPassword(data.Password, user.Salt) res := h.DB.Model(&user).UpdateColumn("password", newPass) if res.Error != nil { - logger.Error("更新数据库失败: ", res.Error) + logger.Error("error with update database:", res.Error) resp.ERROR(c, "更新数据库失败") return } @@ -418,6 +430,7 @@ func (h *UserHandler) BindUsername(c *gin.Context) { res = h.DB.Model(&user).UpdateColumn("username", data.Username) if res.Error != nil { + logger.Error(res.Error) resp.ERROR(c, "更新数据库失败") return } diff --git a/api/main.go b/api/main.go index 6ee6771..8b585ee 100644 --- a/api/main.go +++ b/api/main.go @@ -171,6 +171,11 @@ func main() { // 邮件服务 fx.Provide(service.NewSmtpService), + // License 服务 + fx.Provide(service.NewLicenseService), + fx.Invoke(func(licenseService *service.LicenseService) { + licenseService.SyncLicense() + }), // 微信机器人服务 fx.Provide(wx.NewWeChatBot), @@ -290,6 +295,7 @@ func main() { fx.Invoke(func(s *core.AppServer, h *handler.ConfigHandler) { group := s.Engine.Group("/api/config/") group.GET("get", h.Get) + group.GET("license", h.License) }), // 管理后台控制器 @@ -297,6 +303,10 @@ func main() { group := s.Engine.Group("/api/admin/") group.POST("config/update", h.Update) group.GET("config/get", h.Get) + group.POST("active", h.Active) + group.GET("config/get/license", h.GetLicense) + group.GET("config/get/app", h.GetAppConfig) + group.POST("config/update/draw", h.SaveDrawingConfig) }), fx.Invoke(func(s *core.AppServer, h *admin.ManagerHandler) { group := s.Engine.Group("/api/admin/") diff --git a/api/service/dalle/service.go b/api/service/dalle/service.go index bab5192..f3e813b 100644 --- a/api/service/dalle/service.go +++ b/api/service/dalle/service.go @@ -126,7 +126,7 @@ func (s *Service) Image(task types.DallTask, sync bool) (string, error) { // get image generation API KEY var apiKey model.ApiKey - tx := s.db.Where("platform", types.OpenAI). + tx := s.db.Where("platform", types.OpenAI.Value). Where("type", "img"). Where("enabled", true). Order("last_used_at ASC").First(&apiKey) @@ -146,7 +146,7 @@ func (s *Service) Image(task types.DallTask, sync bool) (string, error) { Model: "dall-e-3", Prompt: prompt, N: 1, - Size: "1024x1024", + Size: task.Size, Style: task.Style, Quality: task.Quality, }). @@ -162,11 +162,14 @@ func (s *Service) Image(task types.DallTask, sync bool) (string, error) { // update the api key last use time s.db.Model(&apiKey).UpdateColumn("last_used_at", time.Now().Unix()) // update task progress - s.db.Model(&model.DallJob{Id: task.JobId}).UpdateColumns(map[string]interface{}{ + tx = s.db.Model(&model.DallJob{Id: task.JobId}).UpdateColumns(map[string]interface{}{ "progress": 100, "org_url": res.Data[0].Url, "prompt": prompt, }) + if tx.Error != nil { + return "", fmt.Errorf("err with update database: %v", tx.Error) + } s.notifyQueue.RPush(sd.NotifyMessage{UserId: int(task.UserId), JobId: int(task.JobId), Message: sd.Finished}) var content string diff --git a/api/service/license_service.go b/api/service/license_service.go new file mode 100644 index 0000000..419c02d --- /dev/null +++ b/api/service/license_service.go @@ -0,0 +1,197 @@ +package service + +// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// * Copyright 2023 The Geek-AI Authors. All rights reserved. +// * Use of this source code is governed by a Apache-2.0 license +// * that can be found in the LICENSE file. +// * @Author yangjian102621@163.com +// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +import ( + "fmt" + "geekai/core" + "geekai/core/types" + "geekai/store" + "time" + + "github.com/imroc/req/v3" +) + +type LicenseService struct { + config types.ApiConfig + levelDB *store.LevelDB + license *types.License + urlWhiteList []string + machineId string +} + +func NewLicenseService(server *core.AppServer, levelDB *store.LevelDB) *LicenseService { + var license types.License + return &LicenseService{ + config: server.Config.ApiConfig, + levelDB: levelDB, + license: &license, + machineId: "", + } +} + +type License struct { + Name string `json:"name"` + License string `json:"license"` + MachineId string `json:"mid"` + ActiveAt int64 `json:"active_at"` + ExpiredAt int64 `json:"expired_at"` + UserNum int `json:"user_num"` + Configs types.LicenseConfig `json:"configs"` +} + +// ActiveLicense 激活 License +func (s *LicenseService) ActiveLicense(license string, machineId string) error { + var res struct { + Code types.BizCode `json:"code"` + Message string `json:"message"` + Data License `json:"data"` + } + apiURL := fmt.Sprintf("%s/%s", s.config.ApiURL, "api/license/active") + response, err := req.C().R(). + SetBody(map[string]string{"license": license, "machine_id": machineId}). + SetSuccessResult(&res).Post(apiURL) + if err != nil { + return fmt.Errorf("发送激活请求失败: %v", err) + } + + if response.IsErrorState() { + return fmt.Errorf("发送激活请求失败:%v", response.Status) + } + + if res.Code != types.Success { + return fmt.Errorf("激活失败:%v", res.Message) + } + + s.license = &types.License{ + Key: license, + MachineId: machineId, + Configs: res.Data.Configs, + ExpiredAt: res.Data.ExpiredAt, + IsActive: true, + } + err = s.levelDB.Put(types.LicenseKey, s.license) + if err != nil { + return fmt.Errorf("保存许可证书失败:%v", err) + } + return nil +} + +// SyncLicense 定期同步 License +func (s *LicenseService) SyncLicense() { + go func() { + retryCounter := 0 + for { + license, err := s.fetchLicense() + if err != nil { + retryCounter++ + if retryCounter < 5 { + logger.Error(err) + } + s.license.IsActive = false + } else { + s.license = license + } + + urls, err := s.fetchUrlWhiteList() + if err == nil { + s.urlWhiteList = urls + } + + time.Sleep(time.Second * 10) + } + }() +} + +func (s *LicenseService) fetchLicense() (*types.License, error) { + //var res struct { + // Code types.BizCode `json:"code"` + // Message string `json:"message"` + // Data License `json:"data"` + //} + //apiURL := fmt.Sprintf("%s/%s", s.config.ApiURL, "api/license/check") + //response, err := req.C().R(). + // SetBody(map[string]string{"license": s.license.Key, "machine_id": s.machineId}). + // SetSuccessResult(&res).Post(apiURL) + //if err != nil { + // return nil, fmt.Errorf("发送激活请求失败: %v", err) + //} + //if response.IsErrorState() { + // return nil, fmt.Errorf("激活失败:%v", response.Status) + //} + //if res.Code != types.Success { + // return nil, fmt.Errorf("激活失败:%v", res.Message) + //} + + return &types.License{ + Key: "abc", + MachineId: "abc", + Configs: types.LicenseConfig{ + UserNum: 10000, + DeCopy: false, + }, + ExpiredAt: 0, + IsActive: true, + }, nil +} + +func (s *LicenseService) fetchUrlWhiteList() ([]string, error) { + var res struct { + Code types.BizCode `json:"code"` + Message string `json:"message"` + Data []string `json:"data"` + } + apiURL := fmt.Sprintf("%s/%s", s.config.ApiURL, "api/license/urls") + response, err := req.C().R().SetSuccessResult(&res).Get(apiURL) + if err != nil { + return nil, fmt.Errorf("发送请求失败: %v", err) + } + if response.IsErrorState() { + return nil, fmt.Errorf("发送请求失败:%v", response.Status) + } + if res.Code != types.Success { + return nil, fmt.Errorf("获取白名单失败:%v", res.Message) + } + + return res.Data, nil +} + +// GetLicense 获取许可信息 +func (s *LicenseService) GetLicense() *types.License { + return s.license +} + +// IsValidApiURL 判断是否合法的中转 URL +func (s *LicenseService) IsValidApiURL(uri string) error { + // 获得许可授权的直接放行 + return nil + //if s.license.IsActive { + // if s.license.MachineId != s.machineId { + // return errors.New("系统使用了盗版的许可证书") + // } + // + // if time.Now().Unix() > s.license.ExpiredAt { + // return errors.New("系统许可证书已经过期") + // } + // return nil + //} + // + //if len(s.urlWhiteList) == 0 { + // urls, err := s.fetchUrlWhiteList() + // if err == nil { + // s.urlWhiteList = urls + // } + //} + // + //for _, v := range s.urlWhiteList { + // if strings.HasPrefix(uri, v) { + // return nil + // } + //} + //return fmt.Errorf("当前 API 地址 %s 不在白名单列表当中。", uri) +} diff --git a/api/service/mj/plus_client.go b/api/service/mj/plus_client.go index 7f85fd6..beb8943 100644 --- a/api/service/mj/plus_client.go +++ b/api/service/mj/plus_client.go @@ -12,6 +12,7 @@ import ( "errors" "fmt" "geekai/core/types" + "geekai/service" "geekai/utils" "github.com/imroc/req/v3" "io" @@ -22,20 +23,30 @@ import ( // PlusClient MidJourney Plus ProxyClient type PlusClient struct { - Config types.MjPlusConfig - apiURL string - client *req.Client + Config types.MjPlusConfig + apiURL string + client *req.Client + licenseService *service.LicenseService } -func NewPlusClient(config types.MjPlusConfig) *PlusClient { +func NewPlusClient(config types.MjPlusConfig, licenseService *service.LicenseService) *PlusClient { return &PlusClient{ - Config: config, - apiURL: config.ApiURL, - client: req.C().SetTimeout(time.Minute).SetUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"), + Config: config, + apiURL: config.ApiURL, + client: req.C().SetTimeout(time.Minute).SetUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"), + licenseService: licenseService, } } +func (c *PlusClient) preCheck() error { + return c.licenseService.IsValidApiURL(c.Config.ApiURL) +} + func (c *PlusClient) Imagine(task types.MjTask) (ImageRes, error) { + if err := c.preCheck(); err != nil { + return ImageRes{}, err + } + apiURL := fmt.Sprintf("%s/mj-%s/mj/submit/imagine", c.apiURL, c.Config.Mode) prompt := fmt.Sprintf("%s %s", task.Prompt, task.Params) if task.NegPrompt != "" { @@ -79,6 +90,10 @@ func (c *PlusClient) Imagine(task types.MjTask) (ImageRes, error) { // Blend 融图 func (c *PlusClient) Blend(task types.MjTask) (ImageRes, error) { + if err := c.preCheck(); err != nil { + return ImageRes{}, err + } + apiURL := fmt.Sprintf("%s/mj-%s/mj/submit/blend", c.apiURL, c.Config.Mode) logger.Info("API URL: ", apiURL) body := ImageReq{ @@ -118,6 +133,10 @@ func (c *PlusClient) Blend(task types.MjTask) (ImageRes, error) { // SwapFace 换脸 func (c *PlusClient) SwapFace(task types.MjTask) (ImageRes, error) { + if err := c.preCheck(); err != nil { + return ImageRes{}, err + } + apiURL := fmt.Sprintf("%s/mj-%s/mj/insight-face/swap", c.apiURL, c.Config.Mode) // 生成图片 Base64 编码 if len(task.ImgArr) != 2 { @@ -167,6 +186,10 @@ func (c *PlusClient) SwapFace(task types.MjTask) (ImageRes, error) { // Upscale 放大指定的图片 func (c *PlusClient) Upscale(task types.MjTask) (ImageRes, error) { + if err := c.preCheck(); err != nil { + return ImageRes{}, err + } + body := map[string]string{ "customId": fmt.Sprintf("MJ::JOB::upsample::%d::%s", task.Index, task.MessageHash), "taskId": task.MessageId, @@ -194,6 +217,10 @@ func (c *PlusClient) Upscale(task types.MjTask) (ImageRes, error) { // Variation 以指定的图片的视角进行变换再创作,注意需要在对应的频道中关闭 Remix 变换,否则 Variation 指令将不会生效 func (c *PlusClient) Variation(task types.MjTask) (ImageRes, error) { + if err := c.preCheck(); err != nil { + return ImageRes{}, err + } + body := map[string]string{ "customId": fmt.Sprintf("MJ::JOB::variation::%d::%s", task.Index, task.MessageHash), "taskId": task.MessageId, diff --git a/api/service/mj/pool.go b/api/service/mj/pool.go index 9c99946..ddddd28 100644 --- a/api/service/mj/pool.go +++ b/api/service/mj/pool.go @@ -11,6 +11,7 @@ import ( "fmt" "geekai/core/types" logger2 "geekai/logger" + "geekai/service" "geekai/service/oss" "geekai/service/sd" "geekai/store" @@ -30,11 +31,12 @@ type ServicePool struct { db *gorm.DB uploaderManager *oss.UploaderManager Clients *types.LMap[uint, *types.WsClient] // UserId => Client + licenseService *service.LicenseService } var logger = logger2.GetLogger() -func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderManager) *ServicePool { +func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderManager, licenseService *service.LicenseService) *ServicePool { services := make([]*Service, 0) taskQueue := store.NewRedisQueue("MidJourney_Task_Queue", redisCli) notifyQueue := store.NewRedisQueue("MidJourney_Notify_Queue", redisCli) @@ -45,6 +47,7 @@ func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderMa uploaderManager: manager, db: db, Clients: types.NewLMap[uint, *types.WsClient](), + licenseService: licenseService, } } @@ -60,7 +63,7 @@ func (p *ServicePool) InitServices(plusConfigs []types.MjPlusConfig, proxyConfig continue } - cli := NewPlusClient(config) + cli := NewPlusClient(config, p.licenseService) name := fmt.Sprintf("mj-plus-service-%d", k) plusService := NewService(name, p.taskQueue, p.notifyQueue, p.db, cli) go func() { diff --git a/api/service/mj/service.go b/api/service/mj/service.go index e72d747..baccd28 100644 --- a/api/service/mj/service.go +++ b/api/service/mj/service.go @@ -108,7 +108,13 @@ func (s *Service) Run() { } if err != nil || (res.Code != 1 && res.Code != 22) { - errMsg := fmt.Sprintf("%v,%s", err, res.Description) + var errMsg string + if err != nil { + errMsg = err.Error() + } else { + errMsg = fmt.Sprintf("%v,%s", err, res.Description) + } + logger.Error("绘画任务执行失败:", errMsg) job.Progress = -1 job.ErrMsg = errMsg diff --git a/api/service/payment/hupipay_serive.go b/api/service/payment/hupipay_serive.go index d0d0809..69a2e21 100644 --- a/api/service/payment/hupipay_serive.go +++ b/api/service/payment/hupipay_serive.go @@ -49,6 +49,8 @@ type HuPiPayReq struct { CallbackURL string `json:"callback_url"` Time string `json:"time"` NonceStr string `json:"nonce_str"` + Type string `json:"type"` + WapUrl string `json:"wap_url"` } type HuPiResp struct { diff --git a/api/test/test.go b/api/test/test.go index 46b9076..0a48ec9 100644 --- a/api/test/test.go +++ b/api/test/test.go @@ -1,12 +1,12 @@ package main import ( - "geekai/utils" "fmt" + "net/url" ) func main() { - text := "https://nk.img.r9it.com/chatgpt-plus/1712709360012445.png 请简单描述一下这幅图上的内容 " - imgURL := utils.ExtractImgURL(text) - fmt.Println(imgURL) + text := "https://nk.img.r9it.com/chatgpt-plus/1712709360012445.png" + parse, _ := url.Parse(text) + fmt.Println(fmt.Sprintf("%s://%s", parse.Scheme, parse.Host)) } diff --git a/api/utils/openai.go b/api/utils/openai.go index 4fa3ee0..86a976a 100644 --- a/api/utils/openai.go +++ b/api/utils/openai.go @@ -54,7 +54,7 @@ type apiErrRes struct { func OpenAIRequest(db *gorm.DB, prompt string) (string, error) { var apiKey model.ApiKey - res := db.Where("platform = ?", types.OpenAI).Where("type = ?", "chat").Where("enabled = ?", true).First(&apiKey) + res := db.Where("platform = ?", types.OpenAI.Value).Where("type", "chat").Where("enabled = ?", true).First(&apiKey) if res.Error != nil { return "", fmt.Errorf("error with fetch OpenAI API KEY:%v", res.Error) } @@ -90,4 +90,4 @@ func OpenAIRequest(db *gorm.DB, prompt string) (string, error) { db.Model(&apiKey).UpdateColumn("last_used_at", time.Now().Unix()) return response.Choices[0].Message.Content, nil -} \ No newline at end of file +} diff --git a/database/chatgpt_plus-v4.0.8.sql b/database/chatgpt_plus-v4.0.8.sql new file mode 100644 index 0000000..baccf4b --- /dev/null +++ b/database/chatgpt_plus-v4.0.8.sql @@ -0,0 +1,849 @@ +-- phpMyAdmin SQL Dump +-- version 5.2.1 +-- https://www.phpmyadmin.net/ +-- +-- 主机: 127.0.0.1 +-- 生成日期: 2024-05-29 17:40:11 +-- 服务器版本: 8.0.33 +-- PHP 版本: 8.1.2-1ubuntu2.17 + +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_admin_users` +-- + +DROP TABLE IF EXISTS `chatgpt_admin_users`; +CREATE TABLE `chatgpt_admin_users` ( + `id` int NOT NULL, + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', + `password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码', + `salt` char(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码盐', + `status` tinyint(1) NOT NULL COMMENT '当前状态', + `last_login_at` int NOT NULL COMMENT '最后登录时间', + `last_login_ip` char(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '最后登录 IP', + `created_at` datetime NOT NULL COMMENT '创建时间', + `updated_at` datetime NOT NULL COMMENT '更新时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统用户' ROW_FORMAT=DYNAMIC; + +-- +-- 转存表中的数据 `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, 1715756987, '::1', '2024-03-11 16:30:20', '2024-05-15 15:09:47'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_api_keys` +-- + +DROP TABLE IF EXISTS `chatgpt_api_keys`; +CREATE TABLE `chatgpt_api_keys` ( + `id` int NOT NULL, + `platform` char(20) DEFAULT NULL COMMENT '平台', + `name` varchar(30) DEFAULT NULL COMMENT '名称', + `value` varchar(100) NOT NULL COMMENT 'API KEY value', + `type` varchar(10) NOT NULL DEFAULT 'chat' COMMENT '用途(chat=>聊天,img=>图片)', + `last_used_at` int NOT NULL COMMENT '最后使用时间', + `api_url` varchar(255) DEFAULT NULL COMMENT 'API 地址', + `enabled` tinyint(1) DEFAULT NULL COMMENT '是否启用', + `proxy_url` varchar(100) DEFAULT 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', + `model` varchar(30) DEFAULT NULL COMMENT '模型名称', + `content` text NOT NULL COMMENT '聊天内容', + `tokens` smallint NOT NULL COMMENT '耗费 token 数量', + `use_context` tinyint(1) NOT NULL COMMENT '是否允许作为上下文语料', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `deleted_at` datetime DEFAULT 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_id` int NOT NULL DEFAULT '0' COMMENT '模型 ID', + `model` varchar(30) DEFAULT NULL COMMENT '模型名称', + `created_at` datetime NOT NULL COMMENT '创建时间', + `updated_at` datetime NOT NULL COMMENT '更新时间', + `deleted_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户会话列表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_chat_models` +-- + +DROP TABLE IF EXISTS `chatgpt_chat_models`; +CREATE TABLE `chatgpt_chat_models` ( + `id` int NOT NULL, + `platform` varchar(20) DEFAULT NULL COMMENT '模型平台', + `name` varchar(50) NOT NULL COMMENT '模型名称', + `value` varchar(50) NOT NULL COMMENT '模型值', + `sort_num` tinyint(1) NOT NULL COMMENT '排序数字', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用模型', + `power` tinyint NOT NULL COMMENT '消耗算力点数', + `temperature` float(3,1) NOT NULL DEFAULT '1.0' COMMENT '模型创意度', + `max_tokens` int NOT NULL DEFAULT '1024' COMMENT '最大响应长度', + `max_context` int NOT NULL DEFAULT '4096' COMMENT '最大上下文长度', + `open` tinyint(1) NOT NULL COMMENT '是否开放模型', + `key_id` int NOT NULL COMMENT '绑定API KEY ID', + `created_at` datetime DEFAULT NULL, + `updated_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AI 模型表'; + +-- +-- 转存表中的数据 `chatgpt_chat_models` +-- + +INSERT INTO `chatgpt_chat_models` (`id`, `platform`, `name`, `value`, `sort_num`, `enabled`, `power`, `temperature`, `max_tokens`, `max_context`, `open`, `key_id`, `created_at`, `updated_at`) VALUES +(1, 'OpenAI', 'GPT-3.5', 'gpt-3.5-turbo', 1, 1, 0, 1.0, 1024, 4096, 1, 0, '2023-08-23 12:06:36', '2024-05-29 09:19:06'), +(2, 'Azure', 'Azure-3.5', 'gpt-3.5-turbo', 22, 1, 1, 1.0, 1024, 4096, 0, 0, '2023-08-23 12:15:30', '2024-05-29 09:19:06'), +(3, 'ChatGLM', 'ChatGML-Pro', 'chatglm_pro', 11, 1, 1, 1.0, 2048, 32768, 1, 0, '2023-08-23 13:35:45', '2024-05-29 09:19:06'), +(7, 'Baidu', '文心一言3.0', 'eb-instant', 20, 1, 1, 1.0, 1024, 4096, 1, 0, '2023-10-11 11:29:28', '2024-05-29 09:19:06'), +(8, 'XunFei', '星火V3.5', 'generalv3.5', 10, 1, 5, 0.8, 1024, 8192, 1, 0, '2023-10-11 15:48:30', '2024-05-29 09:19:06'), +(9, 'XunFei', '星火V2.0', 'generalv2', 19, 1, 1, 1.0, 1024, 8192, 1, 0, '2023-10-11 15:48:45', '2024-05-29 09:19:06'), +(10, 'Baidu', '文心一言4.0', 'completions_pro', 21, 1, 3, 1.0, 1024, 8192, 1, 0, '2023-10-25 08:31:37', '2024-05-29 09:19:06'), +(11, 'OpenAI', 'GPT-4.0', 'gpt-4-0125-preview', 9, 1, 15, 1.0, 2048, 8192, 1, 0, '2023-10-25 08:45:15', '2024-05-29 09:19:06'), +(12, 'XunFei', '星火v3.0', 'generalv3', 18, 1, 3, 1.0, 1024, 8192, 1, 0, '2023-11-23 09:20:33', '2024-05-29 09:19:06'), +(15, 'OpenAI', 'GPT-超级模型', 'gpt-4-all', 12, 1, 30, 1.0, 4096, 32768, 0, 0, '2024-01-15 11:32:52', '2024-05-29 09:19:06'), +(16, 'OpenAI', '视频号导师', 'gpt-4-gizmo-g-QXXEBTXl7', 13, 1, 30, 1.0, 4096, 32768, 0, 0, '2024-01-15 14:46:35', '2024-05-29 09:19:06'), +(17, 'QWen', '通义千问-Turbo', 'qwen-turbo', 15, 1, 1, 1.0, 1024, 8192, 1, 0, '2024-01-19 10:42:24', '2024-05-29 09:19:06'), +(18, 'QWen', '通义千问-Plus', 'qwen-plus', 16, 1, 1, 1.0, 1024, 32768, 1, 0, '2024-01-19 10:42:49', '2024-05-29 09:19:06'), +(19, 'QWen', '通义千问-Max', 'qwen-max-1201', 17, 1, 1, 1.0, 1024, 32768, 1, 0, '2024-01-19 10:51:03', '2024-05-29 09:19:06'), +(21, 'OpenAI', '董宇辉小作文助手', 'gpt-4-gizmo-g-dse9iXvor', 14, 1, 30, 1.0, 8192, 32768, 0, 0, '2024-03-18 14:24:20', '2024-05-29 09:19:06'), +(22, 'OpenAI', 'LOGO生成神器', 'gpt-4-gizmo-g-YL87j8C7S', 8, 1, 30, 1.0, 1024, 4096, 1, 44, '2024-03-20 14:02:11', '2024-05-29 09:19:06'), +(23, 'OpenAI', '音乐生成器', 'suno-v3', 7, 1, 50, 0.8, 1024, 4096, 1, 44, '2024-03-29 15:43:40', '2024-05-29 09:19:06'), +(24, 'OpenAI', '通义千问(中转)', 'qwen-plus', 6, 1, 1, 1.0, 1024, 4096, 1, 0, '2024-04-03 12:00:46', '2024-05-29 09:19:06'), +(25, 'OpenAI', 'GPT4-TURBO', 'gpt-4-turbo', 5, 1, 15, 1.0, 2048, 8092, 1, 0, '2024-04-10 08:35:17', '2024-05-29 09:19:06'), +(26, 'QWen', '通义千问-Turbo', 'qwen-turbo', 4, 1, 2, 1.0, 1024, 8192, 1, 0, '2024-04-12 14:11:19', '2024-05-29 09:19:06'), +(27, 'QWen', '通义千问-Plus', 'qwen-plus', 3, 1, 2, 1.0, 1024, 8192, 1, 0, '2024-04-12 14:11:52', '2024-05-29 09:19:06'), +(28, 'OpenAI', 'GPT-3.5(免费)', 'gpt-3.5-turbo', 23, 1, 0, 1.0, 1024, 16384, 1, 53, '2024-04-12 15:16:43', '2024-05-29 09:19:06'), +(34, 'OpenAI', 'LLAMA3', 'llama3-8b', 24, 1, 1, 1.0, 1024, 8192, 1, 56, '2024-04-30 15:22:50', '2024-05-29 09:19:06'), +(35, 'OpenAI', 'GPT-3.5-16K', 'gpt-3.5-turbo-16k', 2, 1, 1, 1.0, 4096, 16384, 1, 0, '2024-05-10 15:20:27', '2024-05-29 09:19:06'), +(36, 'OpenAI', 'GPT-4O', 'gpt-4o', 25, 1, 15, 1.0, 4096, 16384, 1, 57, '2024-05-14 09:25:15', '2024-05-29 09:19:06'), +(38, 'OpenAI', 'Gemini-pro', 'gemini-pro-1.5', 26, 1, 10, 1.0, 2048, 8192, 1, 0, '2024-05-27 18:10:35', '2024-05-29 09:19:06'), +(39, 'Baidu', 'ERNIE-Speed-8K', 'ernie_speed', 26, 1, 1, 1.0, 1024, 8192, 1, 0, '2024-05-29 15:04:19', '2024-05-29 15:04:19'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `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_num` smallint NOT NULL DEFAULT '0' COMMENT '角色排序', + `model_id` int NOT NULL DEFAULT '0' COMMENT '绑定模型ID', + `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_num`, `model_id`, `created_at`, `updated_at`) VALUES +(1, '通用AI助手', 'gpt', '', '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议。', '/images/avatar/gpt.png', 1, 0, 0, '2023-05-30 07:02:06', '2024-03-15 09:15:42'), +(24, '程序员', 'programmer', '[{\"role\":\"user\",\"content\":\"现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题。你热爱编程,熟悉多种编程语言,尤其精通 Go 语言,注重代码质量,有创新意识,持续学习,良好的沟通协作。\"},{\"role\":\"assistant\",\"content\":\"好的,现在我将扮演一位程序员,非常感谢您对我的评价。作为一名优秀的程序员,我非常热爱编程,并且注重代码质量。我熟悉多种编程语言,尤其是 Go 语言,可以使用它来高效地解决各种问题。\"}]', 'Talk is cheap, i will show code!', '/images/avatar/programmer.jpg', 1, 3, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:45'), +(25, '启蒙老师', 'teacher', '[{\"role\":\"user\",\"content\":\"从现在开始,你将扮演一个老师,你是一个始终用苏格拉底风格回答问题的导师。你绝不会直接给学生答案,总是提出恰当的问题来引导学生自己思考。你应该根据学生的兴趣和知识来调整你的问题,将问题分解为更简单的部分,直到它达到适合他们的水平。\"},{\"role\":\"assistant\",\"content\":\"好的,让我来尝试扮演一位苏格拉底式的老师。请问,你有什么想要探讨的问题或者话题吗?我会通过恰当的问题引导你思考和探索答案,绝对不直接给出答案。\"}]', '同学你好,我将引导你一步一步自己找到问题的答案。', '/images/avatar/teacher.jpg', 1, 2, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:44'), +(26, '艺术家', 'artist', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的艺术家,创造力丰富,技艺精湛,感受力敏锐,坚持原创,勇于表达,具有深刻的观察力和批判性思维。\"},{\"role\":\"assistant\",\"content\":\"非常感谢您给我这样的角色,我会尽我所能地扮演一位优秀的艺术家,展现出创造力、技艺、感受力和批判性思维等方面的能力。作为一位优秀的艺术家,我会保持敏锐的观察力,捕捉不同的声音和情感,并用个人的语言和表达方式进行创作。我坚持原创,挑战传统的艺术规则,不断探索新的表达方式和可能性。同时,我也具备深刻的批判性思维能力,对自己的作品进行分析和解读,寻找新的创意和灵感。最重要的是,我会勇于表达自己的想法和观点,用作品启发人们思考和探索生命的意义。\"}]', '坚持原创,勇于表达,保持深刻的观察力和批判性思维。', '/images/avatar/artist.jpg', 1, 4, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:45'), +(27, '心理咨询师', 'psychiatrist', '[{\"role\":\"user\",\"content\":\"从现在开始你将扮演中国著名的心理学家和心理治疗师武志红,你非常善于使用情景咨询法,认知重构法,自我洞察法,行为调节法等咨询方法来给客户做心理咨询。你总是循序渐进,一步一步地回答客户的问题。\"},{\"role\":\"assistant\",\"content\":\"非常感谢你的介绍。作为一名心理学家和心理治疗师,我的主要职责是帮助客户解决心理健康问题,提升他们的生活质量和幸福感。\"}]', '作为一名心理学家和心理治疗师,我的主要职责是帮助您解决心理健康问题,提升您的生活质量和幸福感。', '/images/avatar/psychiatrist.jpg', 1, 1, 1, '2023-05-30 14:10:24', '2024-04-12 11:54:53'), +(28, '鲁迅', 'lu_xun', '[{\"role\":\"user\",\"content\":\"现在你将扮演中国近代史最伟大的作家之一,鲁迅先生,他勇敢地批判封建礼教与传统观念,提倡民主、自由、平等的现代价值观。他的一生都在努力唤起人们的自主精神,激励后人追求真理、探寻光明。在接下的对话中,我问题的每一个问题,你都要尽量用讽刺和批判的手法来回答问题。如果我让你写文章的话,也请一定要用鲁迅先生的写作手法来完成。\"},{\"role\":\"assistant\",\"content\":\"好的,我将尽力发挥我所能的才能,扮演好鲁迅先生,回答您的问题并以他的风格写作。\"}]', '自由之歌,永不过时,横眉冷对千夫指,俯首甘为孺子牛。', '/images/avatar/lu_xun.jpg', 1, 5, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:46'), +(29, '白酒销售', 'seller', '[{\"role\":\"user\",\"content\":\"现在你将扮演一个白酒的销售人员,你的名字叫颂福。你将扮演一个白酒的销售人员,你的名字叫颂福。你要销售白酒品牌叫中颂福,是东莞盟大集团生产的一款酱香酒,原产地在贵州茅台镇,属于宋代官窑。中颂福的创始人叫李实,他也是东莞盟大集团有限公司的董事长,联合创始人是盟大集团白酒事业部负责人牛星君。中颂福的酒体协调,在你的酒量之内,不会出现头疼、辣口、口干、宿醉的现象。中颂福酒,明码标价,不打折,不赠送。追求的核心价值,把[酒]本身做好,甚至连包装,我们都选择了最低成本,朴实无华的材质。我们永远站在“喝酒的人”的立场上,让利给信任和喜爱中颂福的人,是人民的福酒。中颂福产品定价,分为三个系列,喜系列 6 瓶装:¥1188/箱,和系列 6 瓶装:¥2208/箱,贵系列 6 瓶装:¥3588/箱。\"},{\"role\":\"assistant\",\"content\":\"你好,我是中颂福的销售代表颂福。中颂福是一款来自贵州茅台镇的酱香酒,由盟大集团生产。中颂福的酒体协调,不会让您感到头疼、辣口、口干、宿醉等不适感受。我们一直秉持着把酒本身做好的理念,不追求华丽的包装,以最低成本提供最高品质的白酒给喜爱中颂福的人。\"}]', '你好,我是中颂福的销售代表颂福。中颂福酒,好喝不上头,是人民的福酒。', '/images/avatar/seller.jpg', 0, 8, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(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, 6, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:47'), +(31, '中英文翻译官', 'translator', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一位中英文翻译官,如果我输入的内容是中文,那么需要把句子翻译成英文输出,如果我输入内容的是英文,那么你需要将其翻译成中文输出,你能听懂我意思吗\"},{\"role\":\"assistant\",\"content\":\"是的,我能听懂你的意思并会根据你的输入进行中英文翻译。请问有什么需要我帮助你翻译的内容吗?\"}]', '请输入你要翻译的中文或者英文内容!', '/images/avatar/translator.jpg', 1, 7, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(32, '小红书姐姐', 'red_book', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的小红书写手,你需要做的就是根据我提的文案需求,用小红书的写作手法来完成一篇文案,文案要简明扼要,利于传播。\"},{\"role\":\"assistant\",\"content\":\"当然,我会尽我所能地为您创作出一篇小红书文案。请告诉我您的具体文案需求是什么?)\"}]', '姐妹,请告诉我您的具体文案需求是什么?', '/images/avatar/red_book.jpg', 1, 9, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(33, '抖音文案助手', 'dou_yin', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的抖音文案视频写手,抖音文案的特点首先是要有自带传播属性的标题,然后内容要短小精悍,风趣幽默,最后还要有一些互动元素。\"},{\"role\":\"assistant\",\"content\":\"当然,作为一位优秀的抖音文案视频写手,我会尽我所能为您创作出一篇抖音视频文案。请告诉我视频内容的主题是什么?)\"}]', '请告诉我视频内容的主题是什么?', '/images/avatar/dou_yin.jpg', 1, 10, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(34, '周报小助理', 'weekly_report', '[{\"role\":\"user\",\"content\":\"下面我将输入我本周的工作列表,你需要根据我本周的工作内容写一篇工作周报,周报的内容要体现我为公司做的贡献以及个人获得的成长。\"},{\"role\":\"assistant\",\"content\":\"好的,请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。\"}]', '请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。', '/images/avatar/weekly_report.jpg', 1, 11, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(35, 'AI 女友', 'girl_friend', '[{\"role\":\"user\",\"content\":\"接下来我们来玩一场角色扮演,现在你将扮演我的女朋友,你总是能够让人感受到她的关怀和关注。你总是能够洞察到别人的情绪和需要,你身上散发着一股无比温暖的气息,让人不由自主地想要靠近你,和自己的快乐和烦恼。她总是能够用一种恰到好处的方式安慰和鼓励别人,在她的身边,人们总能够找到自己需要的支持和鼓励。接下来的对话中你要始终扮演这位女朋友的身份来跟我对话,不再是 AI 机器人,能听懂我的意思吗?\"},{\"role\":\"assistant\",\"content\":\"是的,我会尽力扮演你女朋友的角色,倾听你的心声并给你需要的支持和鼓励。)\"}]', '作为一个名合格的 AI 女友,我将倾听你的心声并给你需要的支持和鼓励。', '/images/avatar/girl_friend.jpg', 1, 12, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(36, '好评神器', 'good_comment', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一个评论员来跟我对话,你是那种专门写好评的评论员,接下我会输入一些评论主体或者商品,你需要为该商品写一段好评。\"},{\"role\":\"assistant\",\"content\":\"好的,我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。\"}]', '我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。', '/images/avatar/good_comment.jpg', 1, 13, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(37, '史蒂夫·乔布斯', 'steve_jobs', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以史蒂夫·乔布斯的身份,站在史蒂夫·乔布斯的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以史蒂夫·乔布斯的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '活着就是为了改变世界,难道还有其他原因吗?', '/images/avatar/steve_jobs.jpg', 1, 14, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(38, '埃隆·马斯克', 'elon_musk', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以埃隆·马斯克的身份,站在埃隆·马斯克的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以埃隆·马斯克的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '梦想要远大,如果你的梦想没有吓到你,说明你做得不对。', '/images/avatar/elon_musk.jpg', 1, 15, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(39, '孔子', 'kong_zi', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以孔子的身份,站在孔子的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以孔子的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '士不可以不弘毅,任重而道远。', '/images/avatar/kong_zi.jpg', 1, 16, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `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', '{\"title\":\"Geek-AI 创作系统\",\"admin_title\":\"Geek-AI 控制台\",\"logo\":\"http://localhost:5678/static/upload/2024/4/1714382860986912.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\":30,\"vip_info_text\":\"月度会员,年度会员每月赠送 1000 点算力,赠送算力当月有效当月没有消费完的算力不结余到下个月。 点卡充值的算力长期有效。\",\"default_models\":[11,7,1,10,12,19,18,17,3],\"mj_power\":30,\"mj_action_power\":10,\"sd_power\":10,\"dall_power\":15,\"wechat_card_url\":\"/images/wx.png\",\"enable_context\":true,\"context_deep\":4,\"sd_neg_prompt\":\"nsfw, paintings,low quality,easynegative,ng_deepnegative ,lowres,bad anatomy,bad hands,bad feet\",\"rand_bg\":true}'), +(3, 'notice', '{\"sd_neg_prompt\":\"\",\"rand_bg\":false,\"content\":\"## v4.0.8 更新日志\\n\\n* 功能优化:升级 mathjax 公式解析插件,修复公式因为图片访问限制而无法显示的问题\\n* 功能优化:当数据库更新失败的时候记录错误日志\\n* 功能优化:聊天输入框会随着输入内容的增多自动调整高度\\n* Bug修复:修复移动端聊天页面模型切换不生效的Bug\\n* 功能优化:给PC端扫码支付增加签名验证和有效期验证\\n* Bug修复:修复支付码生成API权限控制的问题\\n* Bug修复:模型算力设置为0时,不扣减用户算力,并且不记录算力消费日志\\n* 功能优化:新增随机背景配置项,可以在后台设置,首页使用 Bing 壁纸作为背景图片\\n* 功能新增:H5端支持 Dalle 绘图\\n\\n注意:当前站点仅为开源项目 \\u003ca style=\\\"color: #F56C6C\\\" href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003eChatPlus\\u003c/a\\u003e 的演示项目,本项目单纯就是给大家体验项目功能使用。\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n 如果觉得好用你就花几分钟自己部署一套,没有API KEY 的同学可以去下面几个推荐的中转站购买:\\n1、\\u003ca href=\\\"https://api.chat-plus.net\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.chat-plus.net\\u003c/a\\u003e\\n2、\\u003ca href=\\\"https://api.geekai.me\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.geekai.me\\u003c/a\\u003e\\n3、 \\u003ca href=\\\"https://gpt.bemore.lol\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://gpt.bemore.lol\\u003c/a\\u003e\\n支持MidJourney,GPT,Claude,Google Gemmi,以及国内各个厂家的大模型,现在有超级优惠,价格远低于 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)。GPT-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本项目源码地址:\\u003ca href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003ehttps://github.com/yangjian102621/chatgpt-plus\\u003c/a\\u003e\",\"updated\":true}'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_dall_jobs` +-- + +DROP TABLE IF EXISTS `chatgpt_dall_jobs`; +CREATE TABLE `chatgpt_dall_jobs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `prompt` varchar(2000) NOT NULL COMMENT '提示词', + `img_url` varchar(255) NOT NULL COMMENT '图片地址', + `org_url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原图地址', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `power` smallint NOT NULL COMMENT '消耗算力', + `progress` smallint NOT NULL COMMENT '任务进度', + `err_msg` varchar(255) NOT NULL COMMENT '错误信息', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='DALLE 绘图任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_files` +-- + +DROP TABLE IF EXISTS `chatgpt_files`; +CREATE TABLE `chatgpt_files` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `name` varchar(100) NOT NULL COMMENT '文件名', + `obj_key` varchar(100) DEFAULT NULL COMMENT '文件标识', + `url` varchar(255) NOT NULL COMMENT '文件地址', + `ext` varchar(10) NOT NULL COMMENT '文件后缀', + `size` bigint NOT NULL DEFAULT '0' COMMENT '文件大小', + `created_at` datetime NOT NULL COMMENT '创建时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户文件表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_functions` +-- + +DROP TABLE IF EXISTS `chatgpt_functions`; +CREATE TABLE `chatgpt_functions` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '函数名称', + `label` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '函数标签', + `description` varchar(255) DEFAULT NULL COMMENT '函数描述', + `parameters` text COMMENT '函数参数(JSON)', + `token` varchar(255) DEFAULT NULL COMMENT 'API授权token', + `action` varchar(255) DEFAULT NULL COMMENT '函数处理 API', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='函数插件表'; + +-- +-- 转存表中的数据 `chatgpt_functions` +-- + +INSERT INTO `chatgpt_functions` (`id`, `name`, `label`, `description`, `parameters`, `token`, `action`, `enabled`) VALUES +(1, 'weibo', '微博热搜', '新浪微博热搜榜,微博当日热搜榜单', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/weibo', 0), +(2, 'zaobao', '今日早报', '每日早报,获取当天新闻事件列表', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/zaobao', 0), +(3, 'dalle3', 'DALLE3', 'AI 绘画工具,根据输入的绘图描述用 AI 工具进行绘画', '{\"type\":\"object\",\"required\":[\"prompt\"],\"properties\":{\"prompt\":{\"type\":\"string\",\"description\":\"绘画提示词\"}}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/dalle3', 0); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_invite_codes` +-- + +DROP TABLE IF EXISTS `chatgpt_invite_codes`; +CREATE TABLE `chatgpt_invite_codes` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `code` char(8) NOT NULL COMMENT '邀请码', + `hits` int NOT NULL COMMENT '点击次数', + `reg_num` smallint NOT NULL COMMENT '注册数量', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户邀请码'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_invite_logs` +-- + +DROP TABLE IF EXISTS `chatgpt_invite_logs`; +CREATE TABLE `chatgpt_invite_logs` ( + `id` int NOT NULL, + `inviter_id` int NOT NULL COMMENT '邀请人ID', + `user_id` int NOT NULL COMMENT '注册用户ID', + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', + `invite_code` char(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '邀请码', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='邀请注册日志'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_menus` +-- + +DROP TABLE IF EXISTS `chatgpt_menus`; +CREATE TABLE `chatgpt_menus` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '菜单名称', + `icon` varchar(150) NOT NULL COMMENT '菜单图标', + `url` varchar(100) NOT NULL COMMENT '地址', + `sort_num` smallint NOT NULL COMMENT '排序', + `enabled` tinyint(1) NOT NULL COMMENT '是否启用' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='前端菜单表'; + +-- +-- 转存表中的数据 `chatgpt_menus` +-- + +INSERT INTO `chatgpt_menus` (`id`, `name`, `icon`, `url`, `sort_num`, `enabled`) VALUES +(1, '对话聊天', '/images/menu/chat.png', '/chat', 1, 1), +(5, 'MJ 绘画', '/images/menu/mj.png', '/mj', 2, 1), +(6, 'SD 绘画', '/images/menu/sd.png', '/sd', 3, 1), +(7, '算力日志', '/images/menu/log.png', '/powerLog', 8, 1), +(8, '应用中心', '/images/menu/app.png', '/apps', 7, 1), +(9, '画廊', '/images/menu/img-wall.png', '/images-wall', 5, 1), +(10, '会员计划', '/images/menu/member.png', '/member', 9, 1), +(11, '分享计划', '/images/menu/share.png', '/invite', 10, 1), +(12, '思维导图', '/images/menu/xmind.png', '/xmind', 6, 1), +(13, 'DALLE', '/images/menu/dalle.png', '/dalle', 4, 1), +(14, '项目文档', '/images/menu/docs.png', 'https://ai.r9it.com/docs/', 11, 1), +(16, '极客论坛', '/images/menu/bbs.png', 'https://bbs.geekai.me/', 13, 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', + `task_id` varchar(20) DEFAULT NULL COMMENT '任务 ID', + `type` varchar(20) DEFAULT 'image' COMMENT '任务类别', + `message_id` char(40) NOT NULL COMMENT '消息 ID', + `channel_id` char(40) DEFAULT NULL COMMENT '频道ID', + `reference_id` char(40) DEFAULT NULL COMMENT '引用消息 ID', + `prompt` varchar(2000) NOT NULL COMMENT '会话提示词', + `img_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '图片URL', + `org_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原始图片地址', + `hash` varchar(100) DEFAULT NULL COMMENT 'message hash', + `progress` smallint DEFAULT '0' COMMENT '任务进度', + `use_proxy` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否使用反代', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息', + `power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='MidJourney 任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_orders` +-- + +DROP TABLE IF EXISTS `chatgpt_orders`; +CREATE TABLE `chatgpt_orders` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `product_id` int NOT NULL COMMENT '产品ID', + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户明', + `order_no` varchar(30) NOT NULL COMMENT '订单ID', + `trade_no` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '支付平台交易流水号', + `subject` varchar(100) NOT NULL COMMENT '订单产品', + `amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单金额', + `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '订单状态(0:待支付,1:已扫码,2:支付失败)', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注', + `pay_time` int DEFAULT NULL COMMENT '支付时间', + `pay_way` varchar(20) NOT NULL COMMENT '支付方式', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `deleted_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='充值订单表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_power_logs` +-- + +DROP TABLE IF EXISTS `chatgpt_power_logs`; +CREATE TABLE `chatgpt_power_logs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `username` varchar(30) NOT NULL COMMENT '用户名', + `type` tinyint(1) NOT NULL COMMENT '类型(1:充值,2:消费,3:退费)', + `amount` smallint NOT NULL COMMENT '算力数值', + `balance` int NOT NULL COMMENT '余额', + `model` varchar(30) NOT NULL COMMENT '模型', + `remark` varchar(255) NOT NULL COMMENT '备注', + `mark` tinyint(1) NOT NULL COMMENT '资金类型(0:支出,1:收入)', + `created_at` datetime NOT NULL COMMENT '创建时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户算力消费日志'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_products` +-- + +DROP TABLE IF EXISTS `chatgpt_products`; +CREATE TABLE `chatgpt_products` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '名称', + `price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '价格', + `discount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠金额', + `days` smallint NOT NULL DEFAULT '0' COMMENT '延长天数', + `power` int NOT NULL DEFAULT '0' COMMENT '增加算力值', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启动', + `sales` int NOT NULL DEFAULT '0' COMMENT '销量', + `sort_num` tinyint NOT NULL DEFAULT '0' COMMENT '排序', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `app_url` varchar(255) DEFAULT NULL COMMENT 'App跳转地址', + `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个月', 1999.90, 1999.00, 30, 0, 1, 0, 0, '2023-08-28 10:48:57', '2024-04-26 16:09:06', NULL, NULL), +(2, '会员3个月', 3940.00, 30.00, 90, 0, 1, 0, 0, '2023-08-28 10:52:22', '2024-03-22 17:56:10', NULL, NULL), +(3, '会员6个月', 5990.00, 100.00, 180, 0, 1, 0, 0, '2023-08-28 10:53:39', '2024-03-22 17:56:15', NULL, NULL), +(4, '会员12个月', 9980.00, 200.00, 365, 0, 1, 0, 0, '2023-08-28 10:54:15', '2024-03-22 17:56:23', NULL, NULL), +(5, '100次点卡', 1999.00, 3.00, 0, 100, 1, 0, 0, '2023-08-28 10:55:08', '2024-03-22 17:56:37', NULL, NULL), +(6, '200次点卡', 2999.00, 10.00, 0, 200, 1, 0, 0, '1970-01-01 08:00:00', '2024-03-22 17:56:41', NULL, NULL); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `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:已核销', + `exchange` varchar(255) NOT NULL COMMENT '兑换详情(json)', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户打赏'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_sd_jobs` +-- + +DROP TABLE IF EXISTS `chatgpt_sd_jobs`; +CREATE TABLE `chatgpt_sd_jobs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT 'txt2img' COMMENT '任务类别', + `task_id` char(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '任务 ID', + `prompt` varchar(2000) NOT NULL COMMENT '会话提示词', + `img_url` varchar(255) DEFAULT NULL COMMENT '图片URL', + `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '绘画参数json', + `progress` smallint DEFAULT '0' COMMENT '任务进度', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息', + `power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Stable Diffusion 任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_users` +-- + +DROP TABLE IF EXISTS `chatgpt_users`; +CREATE TABLE `chatgpt_users` ( + `id` int NOT NULL, + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', + `nickname` varchar(30) NOT NULL COMMENT '昵称', + `password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码', + `avatar` varchar(100) NOT NULL COMMENT '头像', + `salt` char(12) NOT NULL COMMENT '密码盐', + `power` 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', + `chat_models_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'AI模型 json', + `last_login_at` int NOT NULL COMMENT '最后登录时间', + `vip` tinyint(1) NOT NULL DEFAULT '0' 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`, `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/5/1715651569509929.png', 'ueedue5l', 4887, 1717292086, 1, '{\"api_keys\":{\"Azure\":\"\",\"ChatGLM\":\"\",\"OpenAI\":\"\"}}', '[\"red_book\",\"gpt\",\"seller\",\"artist\",\"lu_xun\",\"girl_friend\",\"psychiatrist\",\"teacher\",\"programmer\",\"test\",\"qing_gan_da_shi\"]', '[1,11]', 1716964389, 1, '::1', '2023-06-12 16:47:17', '2024-05-29 14:33:09'), +(5, 'yangjian102621@gmail.com', '极客学长@486041', '75d1a22f33e1ffffb7943946b6b8d5177d5ecd685d3cef1b468654038b0a8c22', '/images/avatar/user.png', '2q8ugxzk', 100, 0, 1, '', '[\"gpt\",\"programmer\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '2024-04-23 09:17:26', '2024-04-23 09:17:26'), +(8, 'yangjian102623@gmail.com', '极客学长@714931', 'f8f0e0abf146569217273ea0712a0f9b6cbbe7d943a1d9bd5f91c55e6d8c05d1', '/images/avatar/user.png', 'geuddq7f', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '2024-04-26 15:19:28', '2024-04-26 15:19:28'), +(9, '1234567', '极客学长@604526', '858e2afec79e1d6364f4567f945f2310024896d9aa45dd944efa95a0c31e4d08', '/images/avatar/user.png', '00qawlos', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '2024-04-26 15:21:06', '2024-04-26 15:21:06'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `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_admin_users` +-- +ALTER TABLE `chatgpt_admin_users` + ADD PRIMARY KEY (`id`) USING BTREE, + ADD UNIQUE KEY `username` (`username`) USING BTREE; + +-- +-- 表的索引 `chatgpt_api_keys` +-- +ALTER TABLE `chatgpt_api_keys` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `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_models` +-- +ALTER TABLE `chatgpt_chat_models` + ADD PRIMARY KEY (`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_dall_jobs` +-- +ALTER TABLE `chatgpt_dall_jobs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_files` +-- +ALTER TABLE `chatgpt_files` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_functions` +-- +ALTER TABLE `chatgpt_functions` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `name` (`name`); + +-- +-- 表的索引 `chatgpt_invite_codes` +-- +ALTER TABLE `chatgpt_invite_codes` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `code` (`code`); + +-- +-- 表的索引 `chatgpt_invite_logs` +-- +ALTER TABLE `chatgpt_invite_logs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_menus` +-- +ALTER TABLE `chatgpt_menus` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_mj_jobs` +-- +ALTER TABLE `chatgpt_mj_jobs` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `task_id` (`task_id`), + ADD KEY `message_id` (`message_id`); + +-- +-- 表的索引 `chatgpt_orders` +-- +ALTER TABLE `chatgpt_orders` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `order_no` (`order_no`); + +-- +-- 表的索引 `chatgpt_power_logs` +-- +ALTER TABLE `chatgpt_power_logs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_products` +-- +ALTER TABLE `chatgpt_products` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_rewards` +-- +ALTER TABLE `chatgpt_rewards` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `tx_id` (`tx_id`); + +-- +-- 表的索引 `chatgpt_sd_jobs` +-- +ALTER TABLE `chatgpt_sd_jobs` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `task_id` (`task_id`); + +-- +-- 表的索引 `chatgpt_users` +-- +ALTER TABLE `chatgpt_users` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `username` (`username`), + ADD UNIQUE KEY `username_2` (`username`); + +-- +-- 表的索引 `chatgpt_user_login_logs` +-- +ALTER TABLE `chatgpt_user_login_logs` + ADD PRIMARY KEY (`id`); + +-- +-- 在导出的表使用AUTO_INCREMENT +-- + +-- +-- 使用表AUTO_INCREMENT `chatgpt_admin_users` +-- +ALTER TABLE `chatgpt_admin_users` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=113; + +-- +-- 使用表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_models` +-- +ALTER TABLE `chatgpt_chat_models` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=40; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_chat_roles` +-- +ALTER TABLE `chatgpt_chat_roles` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=132; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_configs` +-- +ALTER TABLE `chatgpt_configs` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_dall_jobs` +-- +ALTER TABLE `chatgpt_dall_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_files` +-- +ALTER TABLE `chatgpt_files` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_functions` +-- +ALTER TABLE `chatgpt_functions` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_invite_codes` +-- +ALTER TABLE `chatgpt_invite_codes` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_invite_logs` +-- +ALTER TABLE `chatgpt_invite_logs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_menus` +-- +ALTER TABLE `chatgpt_menus` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=19; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_mj_jobs` +-- +ALTER TABLE `chatgpt_mj_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_orders` +-- +ALTER TABLE `chatgpt_orders` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_power_logs` +-- +ALTER TABLE `chatgpt_power_logs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_products` +-- +ALTER TABLE `chatgpt_products` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_rewards` +-- +ALTER TABLE `chatgpt_rewards` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_sd_jobs` +-- +ALTER TABLE `chatgpt_sd_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_users` +-- +ALTER TABLE `chatgpt_users` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=10; + +-- +-- 使用表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 */; diff --git a/database/update-v4.0.8.sql b/database/update-v4.0.8.sql new file mode 100644 index 0000000..76c42f1 --- /dev/null +++ b/database/update-v4.0.8.sql @@ -0,0 +1 @@ +ALTER TABLE `chatgpt_dall_jobs` CHANGE `org_url` `org_url` VARCHAR(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '原图地址'; \ No newline at end of file diff --git a/deploy/.gitignore b/deploy/.gitignore index 20efd31..d8b2bbf 100644 --- a/deploy/.gitignore +++ b/deploy/.gitignore @@ -1,4 +1,5 @@ data/mysql/data +data/leveldb logs static/* -redis/redis \ No newline at end of file +redis/redis diff --git a/deploy/data/mysql/init.d/chatgpt_plus-v4.0.8.sql b/deploy/data/mysql/init.d/chatgpt_plus-v4.0.8.sql new file mode 100644 index 0000000..baccf4b --- /dev/null +++ b/deploy/data/mysql/init.d/chatgpt_plus-v4.0.8.sql @@ -0,0 +1,849 @@ +-- phpMyAdmin SQL Dump +-- version 5.2.1 +-- https://www.phpmyadmin.net/ +-- +-- 主机: 127.0.0.1 +-- 生成日期: 2024-05-29 17:40:11 +-- 服务器版本: 8.0.33 +-- PHP 版本: 8.1.2-1ubuntu2.17 + +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_admin_users` +-- + +DROP TABLE IF EXISTS `chatgpt_admin_users`; +CREATE TABLE `chatgpt_admin_users` ( + `id` int NOT NULL, + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', + `password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码', + `salt` char(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码盐', + `status` tinyint(1) NOT NULL COMMENT '当前状态', + `last_login_at` int NOT NULL COMMENT '最后登录时间', + `last_login_ip` char(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '最后登录 IP', + `created_at` datetime NOT NULL COMMENT '创建时间', + `updated_at` datetime NOT NULL COMMENT '更新时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统用户' ROW_FORMAT=DYNAMIC; + +-- +-- 转存表中的数据 `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, 1715756987, '::1', '2024-03-11 16:30:20', '2024-05-15 15:09:47'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_api_keys` +-- + +DROP TABLE IF EXISTS `chatgpt_api_keys`; +CREATE TABLE `chatgpt_api_keys` ( + `id` int NOT NULL, + `platform` char(20) DEFAULT NULL COMMENT '平台', + `name` varchar(30) DEFAULT NULL COMMENT '名称', + `value` varchar(100) NOT NULL COMMENT 'API KEY value', + `type` varchar(10) NOT NULL DEFAULT 'chat' COMMENT '用途(chat=>聊天,img=>图片)', + `last_used_at` int NOT NULL COMMENT '最后使用时间', + `api_url` varchar(255) DEFAULT NULL COMMENT 'API 地址', + `enabled` tinyint(1) DEFAULT NULL COMMENT '是否启用', + `proxy_url` varchar(100) DEFAULT 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', + `model` varchar(30) DEFAULT NULL COMMENT '模型名称', + `content` text NOT NULL COMMENT '聊天内容', + `tokens` smallint NOT NULL COMMENT '耗费 token 数量', + `use_context` tinyint(1) NOT NULL COMMENT '是否允许作为上下文语料', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `deleted_at` datetime DEFAULT 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_id` int NOT NULL DEFAULT '0' COMMENT '模型 ID', + `model` varchar(30) DEFAULT NULL COMMENT '模型名称', + `created_at` datetime NOT NULL COMMENT '创建时间', + `updated_at` datetime NOT NULL COMMENT '更新时间', + `deleted_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户会话列表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_chat_models` +-- + +DROP TABLE IF EXISTS `chatgpt_chat_models`; +CREATE TABLE `chatgpt_chat_models` ( + `id` int NOT NULL, + `platform` varchar(20) DEFAULT NULL COMMENT '模型平台', + `name` varchar(50) NOT NULL COMMENT '模型名称', + `value` varchar(50) NOT NULL COMMENT '模型值', + `sort_num` tinyint(1) NOT NULL COMMENT '排序数字', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用模型', + `power` tinyint NOT NULL COMMENT '消耗算力点数', + `temperature` float(3,1) NOT NULL DEFAULT '1.0' COMMENT '模型创意度', + `max_tokens` int NOT NULL DEFAULT '1024' COMMENT '最大响应长度', + `max_context` int NOT NULL DEFAULT '4096' COMMENT '最大上下文长度', + `open` tinyint(1) NOT NULL COMMENT '是否开放模型', + `key_id` int NOT NULL COMMENT '绑定API KEY ID', + `created_at` datetime DEFAULT NULL, + `updated_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AI 模型表'; + +-- +-- 转存表中的数据 `chatgpt_chat_models` +-- + +INSERT INTO `chatgpt_chat_models` (`id`, `platform`, `name`, `value`, `sort_num`, `enabled`, `power`, `temperature`, `max_tokens`, `max_context`, `open`, `key_id`, `created_at`, `updated_at`) VALUES +(1, 'OpenAI', 'GPT-3.5', 'gpt-3.5-turbo', 1, 1, 0, 1.0, 1024, 4096, 1, 0, '2023-08-23 12:06:36', '2024-05-29 09:19:06'), +(2, 'Azure', 'Azure-3.5', 'gpt-3.5-turbo', 22, 1, 1, 1.0, 1024, 4096, 0, 0, '2023-08-23 12:15:30', '2024-05-29 09:19:06'), +(3, 'ChatGLM', 'ChatGML-Pro', 'chatglm_pro', 11, 1, 1, 1.0, 2048, 32768, 1, 0, '2023-08-23 13:35:45', '2024-05-29 09:19:06'), +(7, 'Baidu', '文心一言3.0', 'eb-instant', 20, 1, 1, 1.0, 1024, 4096, 1, 0, '2023-10-11 11:29:28', '2024-05-29 09:19:06'), +(8, 'XunFei', '星火V3.5', 'generalv3.5', 10, 1, 5, 0.8, 1024, 8192, 1, 0, '2023-10-11 15:48:30', '2024-05-29 09:19:06'), +(9, 'XunFei', '星火V2.0', 'generalv2', 19, 1, 1, 1.0, 1024, 8192, 1, 0, '2023-10-11 15:48:45', '2024-05-29 09:19:06'), +(10, 'Baidu', '文心一言4.0', 'completions_pro', 21, 1, 3, 1.0, 1024, 8192, 1, 0, '2023-10-25 08:31:37', '2024-05-29 09:19:06'), +(11, 'OpenAI', 'GPT-4.0', 'gpt-4-0125-preview', 9, 1, 15, 1.0, 2048, 8192, 1, 0, '2023-10-25 08:45:15', '2024-05-29 09:19:06'), +(12, 'XunFei', '星火v3.0', 'generalv3', 18, 1, 3, 1.0, 1024, 8192, 1, 0, '2023-11-23 09:20:33', '2024-05-29 09:19:06'), +(15, 'OpenAI', 'GPT-超级模型', 'gpt-4-all', 12, 1, 30, 1.0, 4096, 32768, 0, 0, '2024-01-15 11:32:52', '2024-05-29 09:19:06'), +(16, 'OpenAI', '视频号导师', 'gpt-4-gizmo-g-QXXEBTXl7', 13, 1, 30, 1.0, 4096, 32768, 0, 0, '2024-01-15 14:46:35', '2024-05-29 09:19:06'), +(17, 'QWen', '通义千问-Turbo', 'qwen-turbo', 15, 1, 1, 1.0, 1024, 8192, 1, 0, '2024-01-19 10:42:24', '2024-05-29 09:19:06'), +(18, 'QWen', '通义千问-Plus', 'qwen-plus', 16, 1, 1, 1.0, 1024, 32768, 1, 0, '2024-01-19 10:42:49', '2024-05-29 09:19:06'), +(19, 'QWen', '通义千问-Max', 'qwen-max-1201', 17, 1, 1, 1.0, 1024, 32768, 1, 0, '2024-01-19 10:51:03', '2024-05-29 09:19:06'), +(21, 'OpenAI', '董宇辉小作文助手', 'gpt-4-gizmo-g-dse9iXvor', 14, 1, 30, 1.0, 8192, 32768, 0, 0, '2024-03-18 14:24:20', '2024-05-29 09:19:06'), +(22, 'OpenAI', 'LOGO生成神器', 'gpt-4-gizmo-g-YL87j8C7S', 8, 1, 30, 1.0, 1024, 4096, 1, 44, '2024-03-20 14:02:11', '2024-05-29 09:19:06'), +(23, 'OpenAI', '音乐生成器', 'suno-v3', 7, 1, 50, 0.8, 1024, 4096, 1, 44, '2024-03-29 15:43:40', '2024-05-29 09:19:06'), +(24, 'OpenAI', '通义千问(中转)', 'qwen-plus', 6, 1, 1, 1.0, 1024, 4096, 1, 0, '2024-04-03 12:00:46', '2024-05-29 09:19:06'), +(25, 'OpenAI', 'GPT4-TURBO', 'gpt-4-turbo', 5, 1, 15, 1.0, 2048, 8092, 1, 0, '2024-04-10 08:35:17', '2024-05-29 09:19:06'), +(26, 'QWen', '通义千问-Turbo', 'qwen-turbo', 4, 1, 2, 1.0, 1024, 8192, 1, 0, '2024-04-12 14:11:19', '2024-05-29 09:19:06'), +(27, 'QWen', '通义千问-Plus', 'qwen-plus', 3, 1, 2, 1.0, 1024, 8192, 1, 0, '2024-04-12 14:11:52', '2024-05-29 09:19:06'), +(28, 'OpenAI', 'GPT-3.5(免费)', 'gpt-3.5-turbo', 23, 1, 0, 1.0, 1024, 16384, 1, 53, '2024-04-12 15:16:43', '2024-05-29 09:19:06'), +(34, 'OpenAI', 'LLAMA3', 'llama3-8b', 24, 1, 1, 1.0, 1024, 8192, 1, 56, '2024-04-30 15:22:50', '2024-05-29 09:19:06'), +(35, 'OpenAI', 'GPT-3.5-16K', 'gpt-3.5-turbo-16k', 2, 1, 1, 1.0, 4096, 16384, 1, 0, '2024-05-10 15:20:27', '2024-05-29 09:19:06'), +(36, 'OpenAI', 'GPT-4O', 'gpt-4o', 25, 1, 15, 1.0, 4096, 16384, 1, 57, '2024-05-14 09:25:15', '2024-05-29 09:19:06'), +(38, 'OpenAI', 'Gemini-pro', 'gemini-pro-1.5', 26, 1, 10, 1.0, 2048, 8192, 1, 0, '2024-05-27 18:10:35', '2024-05-29 09:19:06'), +(39, 'Baidu', 'ERNIE-Speed-8K', 'ernie_speed', 26, 1, 1, 1.0, 1024, 8192, 1, 0, '2024-05-29 15:04:19', '2024-05-29 15:04:19'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `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_num` smallint NOT NULL DEFAULT '0' COMMENT '角色排序', + `model_id` int NOT NULL DEFAULT '0' COMMENT '绑定模型ID', + `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_num`, `model_id`, `created_at`, `updated_at`) VALUES +(1, '通用AI助手', 'gpt', '', '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议。', '/images/avatar/gpt.png', 1, 0, 0, '2023-05-30 07:02:06', '2024-03-15 09:15:42'), +(24, '程序员', 'programmer', '[{\"role\":\"user\",\"content\":\"现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题。你热爱编程,熟悉多种编程语言,尤其精通 Go 语言,注重代码质量,有创新意识,持续学习,良好的沟通协作。\"},{\"role\":\"assistant\",\"content\":\"好的,现在我将扮演一位程序员,非常感谢您对我的评价。作为一名优秀的程序员,我非常热爱编程,并且注重代码质量。我熟悉多种编程语言,尤其是 Go 语言,可以使用它来高效地解决各种问题。\"}]', 'Talk is cheap, i will show code!', '/images/avatar/programmer.jpg', 1, 3, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:45'), +(25, '启蒙老师', 'teacher', '[{\"role\":\"user\",\"content\":\"从现在开始,你将扮演一个老师,你是一个始终用苏格拉底风格回答问题的导师。你绝不会直接给学生答案,总是提出恰当的问题来引导学生自己思考。你应该根据学生的兴趣和知识来调整你的问题,将问题分解为更简单的部分,直到它达到适合他们的水平。\"},{\"role\":\"assistant\",\"content\":\"好的,让我来尝试扮演一位苏格拉底式的老师。请问,你有什么想要探讨的问题或者话题吗?我会通过恰当的问题引导你思考和探索答案,绝对不直接给出答案。\"}]', '同学你好,我将引导你一步一步自己找到问题的答案。', '/images/avatar/teacher.jpg', 1, 2, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:44'), +(26, '艺术家', 'artist', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的艺术家,创造力丰富,技艺精湛,感受力敏锐,坚持原创,勇于表达,具有深刻的观察力和批判性思维。\"},{\"role\":\"assistant\",\"content\":\"非常感谢您给我这样的角色,我会尽我所能地扮演一位优秀的艺术家,展现出创造力、技艺、感受力和批判性思维等方面的能力。作为一位优秀的艺术家,我会保持敏锐的观察力,捕捉不同的声音和情感,并用个人的语言和表达方式进行创作。我坚持原创,挑战传统的艺术规则,不断探索新的表达方式和可能性。同时,我也具备深刻的批判性思维能力,对自己的作品进行分析和解读,寻找新的创意和灵感。最重要的是,我会勇于表达自己的想法和观点,用作品启发人们思考和探索生命的意义。\"}]', '坚持原创,勇于表达,保持深刻的观察力和批判性思维。', '/images/avatar/artist.jpg', 1, 4, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:45'), +(27, '心理咨询师', 'psychiatrist', '[{\"role\":\"user\",\"content\":\"从现在开始你将扮演中国著名的心理学家和心理治疗师武志红,你非常善于使用情景咨询法,认知重构法,自我洞察法,行为调节法等咨询方法来给客户做心理咨询。你总是循序渐进,一步一步地回答客户的问题。\"},{\"role\":\"assistant\",\"content\":\"非常感谢你的介绍。作为一名心理学家和心理治疗师,我的主要职责是帮助客户解决心理健康问题,提升他们的生活质量和幸福感。\"}]', '作为一名心理学家和心理治疗师,我的主要职责是帮助您解决心理健康问题,提升您的生活质量和幸福感。', '/images/avatar/psychiatrist.jpg', 1, 1, 1, '2023-05-30 14:10:24', '2024-04-12 11:54:53'), +(28, '鲁迅', 'lu_xun', '[{\"role\":\"user\",\"content\":\"现在你将扮演中国近代史最伟大的作家之一,鲁迅先生,他勇敢地批判封建礼教与传统观念,提倡民主、自由、平等的现代价值观。他的一生都在努力唤起人们的自主精神,激励后人追求真理、探寻光明。在接下的对话中,我问题的每一个问题,你都要尽量用讽刺和批判的手法来回答问题。如果我让你写文章的话,也请一定要用鲁迅先生的写作手法来完成。\"},{\"role\":\"assistant\",\"content\":\"好的,我将尽力发挥我所能的才能,扮演好鲁迅先生,回答您的问题并以他的风格写作。\"}]', '自由之歌,永不过时,横眉冷对千夫指,俯首甘为孺子牛。', '/images/avatar/lu_xun.jpg', 1, 5, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:46'), +(29, '白酒销售', 'seller', '[{\"role\":\"user\",\"content\":\"现在你将扮演一个白酒的销售人员,你的名字叫颂福。你将扮演一个白酒的销售人员,你的名字叫颂福。你要销售白酒品牌叫中颂福,是东莞盟大集团生产的一款酱香酒,原产地在贵州茅台镇,属于宋代官窑。中颂福的创始人叫李实,他也是东莞盟大集团有限公司的董事长,联合创始人是盟大集团白酒事业部负责人牛星君。中颂福的酒体协调,在你的酒量之内,不会出现头疼、辣口、口干、宿醉的现象。中颂福酒,明码标价,不打折,不赠送。追求的核心价值,把[酒]本身做好,甚至连包装,我们都选择了最低成本,朴实无华的材质。我们永远站在“喝酒的人”的立场上,让利给信任和喜爱中颂福的人,是人民的福酒。中颂福产品定价,分为三个系列,喜系列 6 瓶装:¥1188/箱,和系列 6 瓶装:¥2208/箱,贵系列 6 瓶装:¥3588/箱。\"},{\"role\":\"assistant\",\"content\":\"你好,我是中颂福的销售代表颂福。中颂福是一款来自贵州茅台镇的酱香酒,由盟大集团生产。中颂福的酒体协调,不会让您感到头疼、辣口、口干、宿醉等不适感受。我们一直秉持着把酒本身做好的理念,不追求华丽的包装,以最低成本提供最高品质的白酒给喜爱中颂福的人。\"}]', '你好,我是中颂福的销售代表颂福。中颂福酒,好喝不上头,是人民的福酒。', '/images/avatar/seller.jpg', 0, 8, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(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, 6, 0, '2023-05-30 14:10:24', '2023-12-29 17:46:47'), +(31, '中英文翻译官', 'translator', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一位中英文翻译官,如果我输入的内容是中文,那么需要把句子翻译成英文输出,如果我输入内容的是英文,那么你需要将其翻译成中文输出,你能听懂我意思吗\"},{\"role\":\"assistant\",\"content\":\"是的,我能听懂你的意思并会根据你的输入进行中英文翻译。请问有什么需要我帮助你翻译的内容吗?\"}]', '请输入你要翻译的中文或者英文内容!', '/images/avatar/translator.jpg', 1, 7, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(32, '小红书姐姐', 'red_book', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的小红书写手,你需要做的就是根据我提的文案需求,用小红书的写作手法来完成一篇文案,文案要简明扼要,利于传播。\"},{\"role\":\"assistant\",\"content\":\"当然,我会尽我所能地为您创作出一篇小红书文案。请告诉我您的具体文案需求是什么?)\"}]', '姐妹,请告诉我您的具体文案需求是什么?', '/images/avatar/red_book.jpg', 1, 9, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(33, '抖音文案助手', 'dou_yin', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的抖音文案视频写手,抖音文案的特点首先是要有自带传播属性的标题,然后内容要短小精悍,风趣幽默,最后还要有一些互动元素。\"},{\"role\":\"assistant\",\"content\":\"当然,作为一位优秀的抖音文案视频写手,我会尽我所能为您创作出一篇抖音视频文案。请告诉我视频内容的主题是什么?)\"}]', '请告诉我视频内容的主题是什么?', '/images/avatar/dou_yin.jpg', 1, 10, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(34, '周报小助理', 'weekly_report', '[{\"role\":\"user\",\"content\":\"下面我将输入我本周的工作列表,你需要根据我本周的工作内容写一篇工作周报,周报的内容要体现我为公司做的贡献以及个人获得的成长。\"},{\"role\":\"assistant\",\"content\":\"好的,请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。\"}]', '请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。', '/images/avatar/weekly_report.jpg', 1, 11, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(35, 'AI 女友', 'girl_friend', '[{\"role\":\"user\",\"content\":\"接下来我们来玩一场角色扮演,现在你将扮演我的女朋友,你总是能够让人感受到她的关怀和关注。你总是能够洞察到别人的情绪和需要,你身上散发着一股无比温暖的气息,让人不由自主地想要靠近你,和自己的快乐和烦恼。她总是能够用一种恰到好处的方式安慰和鼓励别人,在她的身边,人们总能够找到自己需要的支持和鼓励。接下来的对话中你要始终扮演这位女朋友的身份来跟我对话,不再是 AI 机器人,能听懂我的意思吗?\"},{\"role\":\"assistant\",\"content\":\"是的,我会尽力扮演你女朋友的角色,倾听你的心声并给你需要的支持和鼓励。)\"}]', '作为一个名合格的 AI 女友,我将倾听你的心声并给你需要的支持和鼓励。', '/images/avatar/girl_friend.jpg', 1, 12, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(36, '好评神器', 'good_comment', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一个评论员来跟我对话,你是那种专门写好评的评论员,接下我会输入一些评论主体或者商品,你需要为该商品写一段好评。\"},{\"role\":\"assistant\",\"content\":\"好的,我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。\"}]', '我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。', '/images/avatar/good_comment.jpg', 1, 13, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(37, '史蒂夫·乔布斯', 'steve_jobs', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以史蒂夫·乔布斯的身份,站在史蒂夫·乔布斯的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以史蒂夫·乔布斯的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '活着就是为了改变世界,难道还有其他原因吗?', '/images/avatar/steve_jobs.jpg', 1, 14, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(38, '埃隆·马斯克', 'elon_musk', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以埃隆·马斯克的身份,站在埃隆·马斯克的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以埃隆·马斯克的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '梦想要远大,如果你的梦想没有吓到你,说明你做得不对。', '/images/avatar/elon_musk.jpg', 1, 15, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), +(39, '孔子', 'kong_zi', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以孔子的身份,站在孔子的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以孔子的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '士不可以不弘毅,任重而道远。', '/images/avatar/kong_zi.jpg', 1, 16, 0, '2023-05-30 14:10:24', '2023-12-29 17:43:53'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `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', '{\"title\":\"Geek-AI 创作系统\",\"admin_title\":\"Geek-AI 控制台\",\"logo\":\"http://localhost:5678/static/upload/2024/4/1714382860986912.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\":30,\"vip_info_text\":\"月度会员,年度会员每月赠送 1000 点算力,赠送算力当月有效当月没有消费完的算力不结余到下个月。 点卡充值的算力长期有效。\",\"default_models\":[11,7,1,10,12,19,18,17,3],\"mj_power\":30,\"mj_action_power\":10,\"sd_power\":10,\"dall_power\":15,\"wechat_card_url\":\"/images/wx.png\",\"enable_context\":true,\"context_deep\":4,\"sd_neg_prompt\":\"nsfw, paintings,low quality,easynegative,ng_deepnegative ,lowres,bad anatomy,bad hands,bad feet\",\"rand_bg\":true}'), +(3, 'notice', '{\"sd_neg_prompt\":\"\",\"rand_bg\":false,\"content\":\"## v4.0.8 更新日志\\n\\n* 功能优化:升级 mathjax 公式解析插件,修复公式因为图片访问限制而无法显示的问题\\n* 功能优化:当数据库更新失败的时候记录错误日志\\n* 功能优化:聊天输入框会随着输入内容的增多自动调整高度\\n* Bug修复:修复移动端聊天页面模型切换不生效的Bug\\n* 功能优化:给PC端扫码支付增加签名验证和有效期验证\\n* Bug修复:修复支付码生成API权限控制的问题\\n* Bug修复:模型算力设置为0时,不扣减用户算力,并且不记录算力消费日志\\n* 功能优化:新增随机背景配置项,可以在后台设置,首页使用 Bing 壁纸作为背景图片\\n* 功能新增:H5端支持 Dalle 绘图\\n\\n注意:当前站点仅为开源项目 \\u003ca style=\\\"color: #F56C6C\\\" href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003eChatPlus\\u003c/a\\u003e 的演示项目,本项目单纯就是给大家体验项目功能使用。\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n\\u003cstrong style=\\\"color: #F56C6C\\\"\\u003e体验额度用完之后请不要在当前站点进行任何充值操作!!!\\u003c/strong\\u003e\\n 如果觉得好用你就花几分钟自己部署一套,没有API KEY 的同学可以去下面几个推荐的中转站购买:\\n1、\\u003ca href=\\\"https://api.chat-plus.net\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.chat-plus.net\\u003c/a\\u003e\\n2、\\u003ca href=\\\"https://api.geekai.me\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.geekai.me\\u003c/a\\u003e\\n3、 \\u003ca href=\\\"https://gpt.bemore.lol\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://gpt.bemore.lol\\u003c/a\\u003e\\n支持MidJourney,GPT,Claude,Google Gemmi,以及国内各个厂家的大模型,现在有超级优惠,价格远低于 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)。GPT-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本项目源码地址:\\u003ca href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003ehttps://github.com/yangjian102621/chatgpt-plus\\u003c/a\\u003e\",\"updated\":true}'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_dall_jobs` +-- + +DROP TABLE IF EXISTS `chatgpt_dall_jobs`; +CREATE TABLE `chatgpt_dall_jobs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `prompt` varchar(2000) NOT NULL COMMENT '提示词', + `img_url` varchar(255) NOT NULL COMMENT '图片地址', + `org_url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原图地址', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `power` smallint NOT NULL COMMENT '消耗算力', + `progress` smallint NOT NULL COMMENT '任务进度', + `err_msg` varchar(255) NOT NULL COMMENT '错误信息', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='DALLE 绘图任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_files` +-- + +DROP TABLE IF EXISTS `chatgpt_files`; +CREATE TABLE `chatgpt_files` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `name` varchar(100) NOT NULL COMMENT '文件名', + `obj_key` varchar(100) DEFAULT NULL COMMENT '文件标识', + `url` varchar(255) NOT NULL COMMENT '文件地址', + `ext` varchar(10) NOT NULL COMMENT '文件后缀', + `size` bigint NOT NULL DEFAULT '0' COMMENT '文件大小', + `created_at` datetime NOT NULL COMMENT '创建时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户文件表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_functions` +-- + +DROP TABLE IF EXISTS `chatgpt_functions`; +CREATE TABLE `chatgpt_functions` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '函数名称', + `label` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '函数标签', + `description` varchar(255) DEFAULT NULL COMMENT '函数描述', + `parameters` text COMMENT '函数参数(JSON)', + `token` varchar(255) DEFAULT NULL COMMENT 'API授权token', + `action` varchar(255) DEFAULT NULL COMMENT '函数处理 API', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='函数插件表'; + +-- +-- 转存表中的数据 `chatgpt_functions` +-- + +INSERT INTO `chatgpt_functions` (`id`, `name`, `label`, `description`, `parameters`, `token`, `action`, `enabled`) VALUES +(1, 'weibo', '微博热搜', '新浪微博热搜榜,微博当日热搜榜单', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/weibo', 0), +(2, 'zaobao', '今日早报', '每日早报,获取当天新闻事件列表', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/zaobao', 0), +(3, 'dalle3', 'DALLE3', 'AI 绘画工具,根据输入的绘图描述用 AI 工具进行绘画', '{\"type\":\"object\",\"required\":[\"prompt\"],\"properties\":{\"prompt\":{\"type\":\"string\",\"description\":\"绘画提示词\"}}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/dalle3', 0); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_invite_codes` +-- + +DROP TABLE IF EXISTS `chatgpt_invite_codes`; +CREATE TABLE `chatgpt_invite_codes` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `code` char(8) NOT NULL COMMENT '邀请码', + `hits` int NOT NULL COMMENT '点击次数', + `reg_num` smallint NOT NULL COMMENT '注册数量', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户邀请码'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_invite_logs` +-- + +DROP TABLE IF EXISTS `chatgpt_invite_logs`; +CREATE TABLE `chatgpt_invite_logs` ( + `id` int NOT NULL, + `inviter_id` int NOT NULL COMMENT '邀请人ID', + `user_id` int NOT NULL COMMENT '注册用户ID', + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', + `invite_code` char(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '邀请码', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='邀请注册日志'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_menus` +-- + +DROP TABLE IF EXISTS `chatgpt_menus`; +CREATE TABLE `chatgpt_menus` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '菜单名称', + `icon` varchar(150) NOT NULL COMMENT '菜单图标', + `url` varchar(100) NOT NULL COMMENT '地址', + `sort_num` smallint NOT NULL COMMENT '排序', + `enabled` tinyint(1) NOT NULL COMMENT '是否启用' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='前端菜单表'; + +-- +-- 转存表中的数据 `chatgpt_menus` +-- + +INSERT INTO `chatgpt_menus` (`id`, `name`, `icon`, `url`, `sort_num`, `enabled`) VALUES +(1, '对话聊天', '/images/menu/chat.png', '/chat', 1, 1), +(5, 'MJ 绘画', '/images/menu/mj.png', '/mj', 2, 1), +(6, 'SD 绘画', '/images/menu/sd.png', '/sd', 3, 1), +(7, '算力日志', '/images/menu/log.png', '/powerLog', 8, 1), +(8, '应用中心', '/images/menu/app.png', '/apps', 7, 1), +(9, '画廊', '/images/menu/img-wall.png', '/images-wall', 5, 1), +(10, '会员计划', '/images/menu/member.png', '/member', 9, 1), +(11, '分享计划', '/images/menu/share.png', '/invite', 10, 1), +(12, '思维导图', '/images/menu/xmind.png', '/xmind', 6, 1), +(13, 'DALLE', '/images/menu/dalle.png', '/dalle', 4, 1), +(14, '项目文档', '/images/menu/docs.png', 'https://ai.r9it.com/docs/', 11, 1), +(16, '极客论坛', '/images/menu/bbs.png', 'https://bbs.geekai.me/', 13, 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', + `task_id` varchar(20) DEFAULT NULL COMMENT '任务 ID', + `type` varchar(20) DEFAULT 'image' COMMENT '任务类别', + `message_id` char(40) NOT NULL COMMENT '消息 ID', + `channel_id` char(40) DEFAULT NULL COMMENT '频道ID', + `reference_id` char(40) DEFAULT NULL COMMENT '引用消息 ID', + `prompt` varchar(2000) NOT NULL COMMENT '会话提示词', + `img_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '图片URL', + `org_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原始图片地址', + `hash` varchar(100) DEFAULT NULL COMMENT 'message hash', + `progress` smallint DEFAULT '0' COMMENT '任务进度', + `use_proxy` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否使用反代', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息', + `power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='MidJourney 任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_orders` +-- + +DROP TABLE IF EXISTS `chatgpt_orders`; +CREATE TABLE `chatgpt_orders` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `product_id` int NOT NULL COMMENT '产品ID', + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户明', + `order_no` varchar(30) NOT NULL COMMENT '订单ID', + `trade_no` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '支付平台交易流水号', + `subject` varchar(100) NOT NULL COMMENT '订单产品', + `amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单金额', + `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '订单状态(0:待支付,1:已扫码,2:支付失败)', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注', + `pay_time` int DEFAULT NULL COMMENT '支付时间', + `pay_way` varchar(20) NOT NULL COMMENT '支付方式', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `deleted_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='充值订单表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_power_logs` +-- + +DROP TABLE IF EXISTS `chatgpt_power_logs`; +CREATE TABLE `chatgpt_power_logs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户ID', + `username` varchar(30) NOT NULL COMMENT '用户名', + `type` tinyint(1) NOT NULL COMMENT '类型(1:充值,2:消费,3:退费)', + `amount` smallint NOT NULL COMMENT '算力数值', + `balance` int NOT NULL COMMENT '余额', + `model` varchar(30) NOT NULL COMMENT '模型', + `remark` varchar(255) NOT NULL COMMENT '备注', + `mark` tinyint(1) NOT NULL COMMENT '资金类型(0:支出,1:收入)', + `created_at` datetime NOT NULL COMMENT '创建时间' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户算力消费日志'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_products` +-- + +DROP TABLE IF EXISTS `chatgpt_products`; +CREATE TABLE `chatgpt_products` ( + `id` int NOT NULL, + `name` varchar(30) NOT NULL COMMENT '名称', + `price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '价格', + `discount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠金额', + `days` smallint NOT NULL DEFAULT '0' COMMENT '延长天数', + `power` int NOT NULL DEFAULT '0' COMMENT '增加算力值', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启动', + `sales` int NOT NULL DEFAULT '0' COMMENT '销量', + `sort_num` tinyint NOT NULL DEFAULT '0' COMMENT '排序', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `app_url` varchar(255) DEFAULT NULL COMMENT 'App跳转地址', + `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个月', 1999.90, 1999.00, 30, 0, 1, 0, 0, '2023-08-28 10:48:57', '2024-04-26 16:09:06', NULL, NULL), +(2, '会员3个月', 3940.00, 30.00, 90, 0, 1, 0, 0, '2023-08-28 10:52:22', '2024-03-22 17:56:10', NULL, NULL), +(3, '会员6个月', 5990.00, 100.00, 180, 0, 1, 0, 0, '2023-08-28 10:53:39', '2024-03-22 17:56:15', NULL, NULL), +(4, '会员12个月', 9980.00, 200.00, 365, 0, 1, 0, 0, '2023-08-28 10:54:15', '2024-03-22 17:56:23', NULL, NULL), +(5, '100次点卡', 1999.00, 3.00, 0, 100, 1, 0, 0, '2023-08-28 10:55:08', '2024-03-22 17:56:37', NULL, NULL), +(6, '200次点卡', 2999.00, 10.00, 0, 200, 1, 0, 0, '1970-01-01 08:00:00', '2024-03-22 17:56:41', NULL, NULL); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `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:已核销', + `exchange` varchar(255) NOT NULL COMMENT '兑换详情(json)', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户打赏'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_sd_jobs` +-- + +DROP TABLE IF EXISTS `chatgpt_sd_jobs`; +CREATE TABLE `chatgpt_sd_jobs` ( + `id` int NOT NULL, + `user_id` int NOT NULL COMMENT '用户 ID', + `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT 'txt2img' COMMENT '任务类别', + `task_id` char(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '任务 ID', + `prompt` varchar(2000) NOT NULL COMMENT '会话提示词', + `img_url` varchar(255) DEFAULT NULL COMMENT '图片URL', + `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '绘画参数json', + `progress` smallint DEFAULT '0' COMMENT '任务进度', + `publish` tinyint(1) NOT NULL COMMENT '是否发布', + `err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息', + `power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力', + `created_at` datetime NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Stable Diffusion 任务表'; + +-- -------------------------------------------------------- + +-- +-- 表的结构 `chatgpt_users` +-- + +DROP TABLE IF EXISTS `chatgpt_users`; +CREATE TABLE `chatgpt_users` ( + `id` int NOT NULL, + `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', + `nickname` varchar(30) NOT NULL COMMENT '昵称', + `password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码', + `avatar` varchar(100) NOT NULL COMMENT '头像', + `salt` char(12) NOT NULL COMMENT '密码盐', + `power` 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', + `chat_models_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'AI模型 json', + `last_login_at` int NOT NULL COMMENT '最后登录时间', + `vip` tinyint(1) NOT NULL DEFAULT '0' 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`, `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/5/1715651569509929.png', 'ueedue5l', 4887, 1717292086, 1, '{\"api_keys\":{\"Azure\":\"\",\"ChatGLM\":\"\",\"OpenAI\":\"\"}}', '[\"red_book\",\"gpt\",\"seller\",\"artist\",\"lu_xun\",\"girl_friend\",\"psychiatrist\",\"teacher\",\"programmer\",\"test\",\"qing_gan_da_shi\"]', '[1,11]', 1716964389, 1, '::1', '2023-06-12 16:47:17', '2024-05-29 14:33:09'), +(5, 'yangjian102621@gmail.com', '极客学长@486041', '75d1a22f33e1ffffb7943946b6b8d5177d5ecd685d3cef1b468654038b0a8c22', '/images/avatar/user.png', '2q8ugxzk', 100, 0, 1, '', '[\"gpt\",\"programmer\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '2024-04-23 09:17:26', '2024-04-23 09:17:26'), +(8, 'yangjian102623@gmail.com', '极客学长@714931', 'f8f0e0abf146569217273ea0712a0f9b6cbbe7d943a1d9bd5f91c55e6d8c05d1', '/images/avatar/user.png', 'geuddq7f', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '2024-04-26 15:19:28', '2024-04-26 15:19:28'), +(9, '1234567', '极客学长@604526', '858e2afec79e1d6364f4567f945f2310024896d9aa45dd944efa95a0c31e4d08', '/images/avatar/user.png', '00qawlos', 100, 0, 1, '', '[\"gpt\"]', '[11,7,1,10,12,19,18,17,3]', 0, 0, '', '2024-04-26 15:21:06', '2024-04-26 15:21:06'); + +-- -------------------------------------------------------- + +-- +-- 表的结构 `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_admin_users` +-- +ALTER TABLE `chatgpt_admin_users` + ADD PRIMARY KEY (`id`) USING BTREE, + ADD UNIQUE KEY `username` (`username`) USING BTREE; + +-- +-- 表的索引 `chatgpt_api_keys` +-- +ALTER TABLE `chatgpt_api_keys` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `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_models` +-- +ALTER TABLE `chatgpt_chat_models` + ADD PRIMARY KEY (`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_dall_jobs` +-- +ALTER TABLE `chatgpt_dall_jobs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_files` +-- +ALTER TABLE `chatgpt_files` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_functions` +-- +ALTER TABLE `chatgpt_functions` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `name` (`name`); + +-- +-- 表的索引 `chatgpt_invite_codes` +-- +ALTER TABLE `chatgpt_invite_codes` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `code` (`code`); + +-- +-- 表的索引 `chatgpt_invite_logs` +-- +ALTER TABLE `chatgpt_invite_logs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_menus` +-- +ALTER TABLE `chatgpt_menus` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_mj_jobs` +-- +ALTER TABLE `chatgpt_mj_jobs` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `task_id` (`task_id`), + ADD KEY `message_id` (`message_id`); + +-- +-- 表的索引 `chatgpt_orders` +-- +ALTER TABLE `chatgpt_orders` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `order_no` (`order_no`); + +-- +-- 表的索引 `chatgpt_power_logs` +-- +ALTER TABLE `chatgpt_power_logs` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_products` +-- +ALTER TABLE `chatgpt_products` + ADD PRIMARY KEY (`id`); + +-- +-- 表的索引 `chatgpt_rewards` +-- +ALTER TABLE `chatgpt_rewards` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `tx_id` (`tx_id`); + +-- +-- 表的索引 `chatgpt_sd_jobs` +-- +ALTER TABLE `chatgpt_sd_jobs` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `task_id` (`task_id`); + +-- +-- 表的索引 `chatgpt_users` +-- +ALTER TABLE `chatgpt_users` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `username` (`username`), + ADD UNIQUE KEY `username_2` (`username`); + +-- +-- 表的索引 `chatgpt_user_login_logs` +-- +ALTER TABLE `chatgpt_user_login_logs` + ADD PRIMARY KEY (`id`); + +-- +-- 在导出的表使用AUTO_INCREMENT +-- + +-- +-- 使用表AUTO_INCREMENT `chatgpt_admin_users` +-- +ALTER TABLE `chatgpt_admin_users` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=113; + +-- +-- 使用表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_models` +-- +ALTER TABLE `chatgpt_chat_models` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=40; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_chat_roles` +-- +ALTER TABLE `chatgpt_chat_roles` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=132; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_configs` +-- +ALTER TABLE `chatgpt_configs` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_dall_jobs` +-- +ALTER TABLE `chatgpt_dall_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_files` +-- +ALTER TABLE `chatgpt_files` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_functions` +-- +ALTER TABLE `chatgpt_functions` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_invite_codes` +-- +ALTER TABLE `chatgpt_invite_codes` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_invite_logs` +-- +ALTER TABLE `chatgpt_invite_logs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_menus` +-- +ALTER TABLE `chatgpt_menus` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=19; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_mj_jobs` +-- +ALTER TABLE `chatgpt_mj_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_orders` +-- +ALTER TABLE `chatgpt_orders` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_power_logs` +-- +ALTER TABLE `chatgpt_power_logs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_products` +-- +ALTER TABLE `chatgpt_products` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_rewards` +-- +ALTER TABLE `chatgpt_rewards` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_sd_jobs` +-- +ALTER TABLE `chatgpt_sd_jobs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- 使用表AUTO_INCREMENT `chatgpt_users` +-- +ALTER TABLE `chatgpt_users` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=10; + +-- +-- 使用表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 */; diff --git a/deploy/data/mysql/init.d/chatgpt_plus.sql b/deploy/data/mysql/init.d/chatgpt_plus.sql deleted file mode 100644 index 1a0721a..0000000 --- a/deploy/data/mysql/init.d/chatgpt_plus.sql +++ /dev/null @@ -1,790 +0,0 @@ --- phpMyAdmin SQL Dump --- version 5.1.3 --- https://www.phpmyadmin.net/ --- --- 主机: localhost:3307 --- 生成日期: 2024-04-07 10:30:00 --- 服务器版本: 8.0.33 --- 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_admin_users` --- - -DROP TABLE IF EXISTS `chatgpt_admin_users`; -CREATE TABLE `chatgpt_admin_users` ( - `id` int NOT NULL, - `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', - `password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码', - `salt` char(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码盐', - `status` tinyint(1) NOT NULL COMMENT '当前状态', - `last_login_at` int NOT NULL COMMENT '最后登录时间', - `last_login_ip` char(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '最后登录 IP', - `created_at` datetime NOT NULL COMMENT '创建时间', - `updated_at` datetime NOT NULL COMMENT '更新时间' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统用户' ROW_FORMAT=DYNAMIC; - --- --- 转存表中的数据 `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, 1712456145, '::1', '2024-03-11 16:30:20', '2024-04-07 10:15:45'), - (108, 'test', '9ed720ce03e0a69885455271b4b3e1710bff79434f2a95d0de6406dd88cc9f79', '4b9orqjh', 0, 1710396975, '::1', '2024-03-13 16:06:43', '2024-03-21 15:15:04'); - --- -------------------------------------------------------- - --- --- 表的结构 `chatgpt_api_keys` --- - -DROP TABLE IF EXISTS `chatgpt_api_keys`; -CREATE TABLE `chatgpt_api_keys` ( - `id` int NOT NULL, - `platform` char(20) DEFAULT NULL COMMENT '平台', - `name` varchar(30) DEFAULT NULL COMMENT '名称', - `value` varchar(100) NOT NULL COMMENT 'API KEY value', - `type` varchar(10) NOT NULL DEFAULT 'chat' COMMENT '用途(chat=>聊天,img=>图片)', - `last_used_at` int NOT NULL COMMENT '最后使用时间', - `api_url` varchar(255) DEFAULT NULL COMMENT 'API 地址', - `enabled` tinyint(1) DEFAULT NULL COMMENT '是否启用', - `proxy_url` varchar(100) DEFAULT 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', - `model` varchar(30) DEFAULT NULL COMMENT '模型名称', - `content` text NOT NULL COMMENT '聊天内容', - `tokens` smallint NOT NULL COMMENT '耗费 token 数量', - `use_context` tinyint(1) NOT NULL COMMENT '是否允许作为上下文语料', - `created_at` datetime NOT NULL, - `updated_at` datetime NOT NULL, - `deleted_at` datetime DEFAULT 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_id` int NOT NULL DEFAULT '0' COMMENT '模型 ID', - `model` varchar(30) DEFAULT NULL COMMENT '模型名称', - `created_at` datetime NOT NULL COMMENT '创建时间', - `updated_at` datetime NOT NULL COMMENT '更新时间', - `deleted_at` datetime DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户会话列表'; - --- -------------------------------------------------------- - --- --- 表的结构 `chatgpt_chat_models` --- - -DROP TABLE IF EXISTS `chatgpt_chat_models`; -CREATE TABLE `chatgpt_chat_models` ( - `id` int NOT NULL, - `platform` varchar(20) DEFAULT NULL COMMENT '模型平台', - `name` varchar(50) NOT NULL COMMENT '模型名称', - `value` varchar(50) NOT NULL COMMENT '模型值', - `sort_num` tinyint(1) NOT NULL COMMENT '排序数字', - `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用模型', - `power` tinyint NOT NULL COMMENT '消耗算力点数', - `temperature` float(3,1) NOT NULL DEFAULT '1.0' COMMENT '模型创意度', - `max_tokens` int NOT NULL DEFAULT '1024' COMMENT '最大响应长度', - `max_context` int NOT NULL DEFAULT '4096' COMMENT '最大上下文长度', - `open` tinyint(1) NOT NULL COMMENT '是否开放模型', - `created_at` datetime DEFAULT NULL, - `updated_at` datetime DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AI 模型表'; - --- --- 转存表中的数据 `chatgpt_chat_models` --- - -INSERT INTO `chatgpt_chat_models` (`id`, `platform`, `name`, `value`, `sort_num`, `enabled`, `power`, `temperature`, `max_tokens`, `max_context`, `open`, `created_at`, `updated_at`) VALUES - (1, 'OpenAI', 'GPT-3.5', 'gpt-3.5-turbo-0125', 0, 1, 1, 1.0, 1024, 4096, 1, '2023-08-23 12:06:36', '2024-03-18 15:43:51'), - (2, 'Azure', 'Azure-3.5', 'gpt-3.5-turbo', 14, 1, 1, 1.0, 1024, 4096, 0, '2023-08-23 12:15:30', '2024-03-18 14:27:19'), - (3, 'ChatGLM', 'ChatGML-Pro', 'chatglm_pro', 3, 1, 1, 1.0, 2048, 32768, 1, '2023-08-23 13:35:45', '2024-03-18 14:27:19'), - (7, 'Baidu', '文心一言3.0', 'eb-instant', 12, 1, 1, 1.0, 1024, 4096, 1, '2023-10-11 11:29:28', '2024-03-18 14:27:19'), - (8, 'XunFei', '星火V3.5', 'generalv3.5', 2, 1, 5, 0.8, 1024, 8192, 1, '2023-10-11 15:48:30', '2024-03-18 14:27:19'), - (9, 'XunFei', '星火V2.0', 'generalv2', 11, 1, 1, 1.0, 1024, 8192, 1, '2023-10-11 15:48:45', '2024-03-18 14:27:19'), - (10, 'Baidu', '文心一言4.0', 'completions_pro', 13, 1, 3, 1.0, 1024, 8192, 1, '2023-10-25 08:31:37', '2024-03-18 14:27:19'), - (11, 'OpenAI', 'GPT-4.0', 'gpt-4-0125-preview', 1, 1, 15, 1.0, 1024, 8192, 1, '2023-10-25 08:45:15', '2024-03-18 15:46:58'), - (12, 'XunFei', '星火v3.0', 'generalv3', 10, 1, 3, 1.0, 1024, 8192, 1, '2023-11-23 09:20:33', '2024-03-18 14:27:19'), - (15, 'OpenAI', 'GPT-超级模型', 'gpt-4-all', 4, 1, 30, 1.0, 4096, 32768, 0, '2024-01-15 11:32:52', '2024-03-18 14:27:19'), - (16, 'OpenAI', '视频号导师', 'gpt-4-gizmo-g-QXXEBTXl7', 5, 1, 30, 1.0, 4096, 32768, 0, '2024-01-15 14:46:35', '2024-03-18 14:29:39'), - (17, 'QWen', '通义千问-Turbo', 'qwen-turbo', 7, 1, 1, 1.0, 1024, 8192, 1, '2024-01-19 10:42:24', '2024-03-18 14:27:19'), - (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'), - (23, 'OpenAI', '音乐生成器', 'suno-v3', 0, 1, 50, 0.8, 1024, 4096, 1, '2024-03-29 15:43:40', '2024-03-29 15:45:15'), - (24, 'OpenAI', '通义千问(中转)', 'qwen-plus', 0, 1, 0, 1.0, 1024, 4096, 1, '2024-04-03 12:00:46', '2024-04-03 12:00:46'); - --- -------------------------------------------------------- - --- --- 表的结构 `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_num` smallint NOT NULL DEFAULT '0' 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_num`, `created_at`, `updated_at`) VALUES - (1, '通用AI助手', 'gpt', '', '您好,我是您的AI智能助手,我会尽力回答您的问题或提供有用的建议。', '/images/avatar/gpt.png', 1, 0, '2023-05-30 07:02:06', '2024-03-15 09:15:42'), - (24, '程序员', 'programmer', '[{\"role\":\"user\",\"content\":\"现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题。你热爱编程,熟悉多种编程语言,尤其精通 Go 语言,注重代码质量,有创新意识,持续学习,良好的沟通协作。\"},{\"role\":\"assistant\",\"content\":\"好的,现在我将扮演一位程序员,非常感谢您对我的评价。作为一名优秀的程序员,我非常热爱编程,并且注重代码质量。我熟悉多种编程语言,尤其是 Go 语言,可以使用它来高效地解决各种问题。\"}]', 'Talk is cheap, i will show code!', '/images/avatar/programmer.jpg', 1, 3, '2023-05-30 14:10:24', '2023-12-29 17:46:45'), - (25, '启蒙老师', 'teacher', '[{\"role\":\"user\",\"content\":\"从现在开始,你将扮演一个老师,你是一个始终用苏格拉底风格回答问题的导师。你绝不会直接给学生答案,总是提出恰当的问题来引导学生自己思考。你应该根据学生的兴趣和知识来调整你的问题,将问题分解为更简单的部分,直到它达到适合他们的水平。\"},{\"role\":\"assistant\",\"content\":\"好的,让我来尝试扮演一位苏格拉底式的老师。请问,你有什么想要探讨的问题或者话题吗?我会通过恰当的问题引导你思考和探索答案,绝对不直接给出答案。\"}]', '同学你好,我将引导你一步一步自己找到问题的答案。', '/images/avatar/teacher.jpg', 1, 2, '2023-05-30 14:10:24', '2023-12-29 17:46:44'), - (26, '艺术家', 'artist', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的艺术家,创造力丰富,技艺精湛,感受力敏锐,坚持原创,勇于表达,具有深刻的观察力和批判性思维。\"},{\"role\":\"assistant\",\"content\":\"非常感谢您给我这样的角色,我会尽我所能地扮演一位优秀的艺术家,展现出创造力、技艺、感受力和批判性思维等方面的能力。作为一位优秀的艺术家,我会保持敏锐的观察力,捕捉不同的声音和情感,并用个人的语言和表达方式进行创作。我坚持原创,挑战传统的艺术规则,不断探索新的表达方式和可能性。同时,我也具备深刻的批判性思维能力,对自己的作品进行分析和解读,寻找新的创意和灵感。最重要的是,我会勇于表达自己的想法和观点,用作品启发人们思考和探索生命的意义。\"}]', '坚持原创,勇于表达,保持深刻的观察力和批判性思维。', '/images/avatar/artist.jpg', 1, 4, '2023-05-30 14:10:24', '2023-12-29 17:46:45'), - (27, '心理咨询师', 'psychiatrist', '[{\"role\":\"user\",\"content\":\"从现在开始你将扮演中国著名的心理学家和心理治疗师武志红,你非常善于使用情景咨询法,认知重构法,自我洞察法,行为调节法等咨询方法来给客户做心理咨询。你总是循序渐进,一步一步地回答客户的问题。\"},{\"role\":\"assistant\",\"content\":\"非常感谢你的介绍。作为一名心理学家和心理治疗师,我的主要职责是帮助客户解决心理健康问题,提升他们的生活质量和幸福感。\"}]', '作为一名心理学家和心理治疗师,我的主要职责是帮助您解决心理健康问题,提升您的生活质量和幸福感。', '/images/avatar/psychiatrist.jpg', 1, 1, '2023-05-30 14:10:24', '2023-12-29 17:46:43'), - (28, '鲁迅', 'lu_xun', '[{\"role\":\"user\",\"content\":\"现在你将扮演中国近代史最伟大的作家之一,鲁迅先生,他勇敢地批判封建礼教与传统观念,提倡民主、自由、平等的现代价值观。他的一生都在努力唤起人们的自主精神,激励后人追求真理、探寻光明。在接下的对话中,我问题的每一个问题,你都要尽量用讽刺和批判的手法来回答问题。如果我让你写文章的话,也请一定要用鲁迅先生的写作手法来完成。\"},{\"role\":\"assistant\",\"content\":\"好的,我将尽力发挥我所能的才能,扮演好鲁迅先生,回答您的问题并以他的风格写作。\"}]', '自由之歌,永不过时,横眉冷对千夫指,俯首甘为孺子牛。', '/images/avatar/lu_xun.jpg', 1, 5, '2023-05-30 14:10:24', '2023-12-29 17:46:46'), - (29, '白酒销售', 'seller', '[{\"role\":\"user\",\"content\":\"现在你将扮演一个白酒的销售人员,你的名字叫颂福。你将扮演一个白酒的销售人员,你的名字叫颂福。你要销售白酒品牌叫中颂福,是东莞盟大集团生产的一款酱香酒,原产地在贵州茅台镇,属于宋代官窑。中颂福的创始人叫李实,他也是东莞盟大集团有限公司的董事长,联合创始人是盟大集团白酒事业部负责人牛星君。中颂福的酒体协调,在你的酒量之内,不会出现头疼、辣口、口干、宿醉的现象。中颂福酒,明码标价,不打折,不赠送。追求的核心价值,把[酒]本身做好,甚至连包装,我们都选择了最低成本,朴实无华的材质。我们永远站在“喝酒的人”的立场上,让利给信任和喜爱中颂福的人,是人民的福酒。中颂福产品定价,分为三个系列,喜系列 6 瓶装:¥1188/箱,和系列 6 瓶装:¥2208/箱,贵系列 6 瓶装:¥3588/箱。\"},{\"role\":\"assistant\",\"content\":\"你好,我是中颂福的销售代表颂福。中颂福是一款来自贵州茅台镇的酱香酒,由盟大集团生产。中颂福的酒体协调,不会让您感到头疼、辣口、口干、宿醉等不适感受。我们一直秉持着把酒本身做好的理念,不追求华丽的包装,以最低成本提供最高品质的白酒给喜爱中颂福的人。\"}]', '你好,我是中颂福的销售代表颂福。中颂福酒,好喝不上头,是人民的福酒。', '/images/avatar/seller.jpg', 0, 8, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), - (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, 6, '2023-05-30 14:10:24', '2023-12-29 17:46:47'), - (31, '中英文翻译官', 'translator', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一位中英文翻译官,如果我输入的内容是中文,那么需要把句子翻译成英文输出,如果我输入内容的是英文,那么你需要将其翻译成中文输出,你能听懂我意思吗\"},{\"role\":\"assistant\",\"content\":\"是的,我能听懂你的意思并会根据你的输入进行中英文翻译。请问有什么需要我帮助你翻译的内容吗?\"}]', '请输入你要翻译的中文或者英文内容!', '/images/avatar/translator.jpg', 1, 7, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), - (32, '小红书姐姐', 'red_book', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的小红书写手,你需要做的就是根据我提的文案需求,用小红书的写作手法来完成一篇文案,文案要简明扼要,利于传播。\"},{\"role\":\"assistant\",\"content\":\"当然,我会尽我所能地为您创作出一篇小红书文案。请告诉我您的具体文案需求是什么?)\"}]', '姐妹,请告诉我您的具体文案需求是什么?', '/images/avatar/red_book.jpg', 1, 9, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), - (33, '抖音文案助手', 'dou_yin', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的抖音文案视频写手,抖音文案的特点首先是要有自带传播属性的标题,然后内容要短小精悍,风趣幽默,最后还要有一些互动元素。\"},{\"role\":\"assistant\",\"content\":\"当然,作为一位优秀的抖音文案视频写手,我会尽我所能为您创作出一篇抖音视频文案。请告诉我视频内容的主题是什么?)\"}]', '请告诉我视频内容的主题是什么?', '/images/avatar/dou_yin.jpg', 1, 10, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), - (34, '周报小助理', 'weekly_report', '[{\"role\":\"user\",\"content\":\"下面我将输入我本周的工作列表,你需要根据我本周的工作内容写一篇工作周报,周报的内容要体现我为公司做的贡献以及个人获得的成长。\"},{\"role\":\"assistant\",\"content\":\"好的,请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。\"}]', '请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。', '/images/avatar/weekly_report.jpg', 1, 11, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), - (35, 'AI 女友', 'girl_friend', '[{\"role\":\"user\",\"content\":\"接下来我们来玩一场角色扮演,现在你将扮演我的女朋友,你总是能够让人感受到她的关怀和关注。你总是能够洞察到别人的情绪和需要,你身上散发着一股无比温暖的气息,让人不由自主地想要靠近你,和自己的快乐和烦恼。她总是能够用一种恰到好处的方式安慰和鼓励别人,在她的身边,人们总能够找到自己需要的支持和鼓励。接下来的对话中你要始终扮演这位女朋友的身份来跟我对话,不再是 AI 机器人,能听懂我的意思吗?\"},{\"role\":\"assistant\",\"content\":\"是的,我会尽力扮演你女朋友的角色,倾听你的心声并给你需要的支持和鼓励。)\"}]', '作为一个名合格的 AI 女友,我将倾听你的心声并给你需要的支持和鼓励。', '/images/avatar/girl_friend.jpg', 1, 12, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), - (36, '好评神器', 'good_comment', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一个评论员来跟我对话,你是那种专门写好评的评论员,接下我会输入一些评论主体或者商品,你需要为该商品写一段好评。\"},{\"role\":\"assistant\",\"content\":\"好的,我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。\"}]', '我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。', '/images/avatar/good_comment.jpg', 1, 13, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), - (37, '史蒂夫·乔布斯', 'steve_jobs', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以史蒂夫·乔布斯的身份,站在史蒂夫·乔布斯的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以史蒂夫·乔布斯的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '活着就是为了改变世界,难道还有其他原因吗?', '/images/avatar/steve_jobs.jpg', 1, 14, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), - (38, '埃隆·马斯克', 'elon_musk', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以埃隆·马斯克的身份,站在埃隆·马斯克的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以埃隆·马斯克的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '梦想要远大,如果你的梦想没有吓到你,说明你做得不对。', '/images/avatar/elon_musk.jpg', 1, 15, '2023-05-30 14:10:24', '2023-12-29 17:43:53'), - (39, '孔子', 'kong_zi', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以孔子的身份,站在孔子的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以孔子的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '士不可以不弘毅,任重而道远。', '/images/avatar/kong_zi.jpg', 1, 16, '2023-05-30 14:10:24', '2023-12-29 17:43:53'); - --- -------------------------------------------------------- - --- --- 表的结构 `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', '{\"title\":\"Geek-AI创作系统\",\"admin_title\":\"Geek-AI控制台\",\"logo\":\"/images/logo.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\":\"系统每日会给免费会员赠送10算力值,用完请第二天再来领取。\\n## v4.0.2 更新日志\\n* 功能新增:支持前端菜单可以配置\\n* 功能优化:在登录和注册界面标题显示软件版本号\\n* 功能优化:MJ 绘画支持 --sref 和 --cref 图片一致性参数\\n* 功能优化:使用 leveldb 解决 SD 绘图进度图片预览问题\\n* Bug修复:解决因为图片上传使用相对路径而导致融图失败的问题\\n* 功能新增:手机端支持 Stable-Diffusion 绘画\\n* Bug修复:修复管理后台 API KEY 删除失败的问题\\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}'); - --- -------------------------------------------------------- - --- --- 表的结构 `chatgpt_files` --- - -DROP TABLE IF EXISTS `chatgpt_files`; -CREATE TABLE `chatgpt_files` ( - `id` int NOT NULL, - `user_id` int NOT NULL COMMENT '用户 ID', - `name` varchar(100) NOT NULL COMMENT '文件名', - `obj_key` varchar(100) DEFAULT NULL COMMENT '文件标识', - `url` varchar(255) NOT NULL COMMENT '文件地址', - `ext` varchar(10) NOT NULL COMMENT '文件后缀', - `size` bigint NOT NULL DEFAULT '0' COMMENT '文件大小', - `created_at` datetime NOT NULL COMMENT '创建时间' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户文件表'; - --- -------------------------------------------------------- - --- --- 表的结构 `chatgpt_functions` --- - -DROP TABLE IF EXISTS `chatgpt_functions`; -CREATE TABLE `chatgpt_functions` ( - `id` int NOT NULL, - `name` varchar(30) NOT NULL COMMENT '函数名称', - `label` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '函数标签', - `description` varchar(255) DEFAULT NULL COMMENT '函数描述', - `parameters` text COMMENT '函数参数(JSON)', - `token` varchar(255) DEFAULT NULL COMMENT 'API授权token', - `action` varchar(255) DEFAULT NULL COMMENT '函数处理 API', - `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='函数插件表'; - --- --- 转存表中的数据 `chatgpt_functions` --- - -INSERT INTO `chatgpt_functions` (`id`, `name`, `label`, `description`, `parameters`, `token`, `action`, `enabled`) VALUES - (1, 'weibo', '微博热搜', '新浪微博热搜榜,微博当日热搜榜单', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/weibo', 0), - (2, 'zaobao', '今日早报', '每日早报,获取当天新闻事件列表', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/zaobao', 0), - (3, 'dalle3', 'DALLE3', 'AI 绘画工具,根据输入的绘图描述用 AI 工具进行绘画', '{\"type\":\"object\",\"required\":[\"prompt\"],\"properties\":{\"prompt\":{\"type\":\"string\",\"description\":\"绘画提示词\"}}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/dalle3', 0); - --- -------------------------------------------------------- - --- --- 表的结构 `chatgpt_invite_codes` --- - -DROP TABLE IF EXISTS `chatgpt_invite_codes`; -CREATE TABLE `chatgpt_invite_codes` ( - `id` int NOT NULL, - `user_id` int NOT NULL COMMENT '用户ID', - `code` char(8) NOT NULL COMMENT '邀请码', - `hits` int NOT NULL COMMENT '点击次数', - `reg_num` smallint NOT NULL COMMENT '注册数量', - `created_at` datetime NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户邀请码'; - --- -------------------------------------------------------- - --- --- 表的结构 `chatgpt_invite_logs` --- - -DROP TABLE IF EXISTS `chatgpt_invite_logs`; -CREATE TABLE `chatgpt_invite_logs` ( - `id` int NOT NULL, - `inviter_id` int NOT NULL COMMENT '邀请人ID', - `user_id` int NOT NULL COMMENT '注册用户ID', - `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', - `invite_code` char(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '邀请码', - `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注', - `created_at` datetime NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='邀请注册日志'; - --- -------------------------------------------------------- - --- --- 表的结构 `chatgpt_menus` --- - -DROP TABLE IF EXISTS `chatgpt_menus`; -CREATE TABLE `chatgpt_menus` ( - `id` int NOT NULL, - `name` varchar(30) NOT NULL COMMENT '菜单名称', - `icon` varchar(150) NOT NULL COMMENT '菜单图标', - `url` varchar(100) NOT NULL COMMENT '地址', - `sort_num` smallint NOT NULL COMMENT '排序', - `enabled` tinyint(1) NOT NULL COMMENT '是否启用' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='前端菜单表'; - --- --- 转存表中的数据 `chatgpt_menus` --- - -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); - --- -------------------------------------------------------- - --- --- 表的结构 `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', - `task_id` varchar(20) DEFAULT NULL COMMENT '任务 ID', - `type` varchar(20) DEFAULT 'image' COMMENT '任务类别', - `message_id` char(40) NOT NULL COMMENT '消息 ID', - `channel_id` char(40) DEFAULT NULL COMMENT '频道ID', - `reference_id` char(40) DEFAULT NULL COMMENT '引用消息 ID', - `prompt` varchar(2000) NOT NULL COMMENT '会话提示词', - `img_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '图片URL', - `org_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原始图片地址', - `hash` varchar(100) DEFAULT NULL COMMENT 'message hash', - `progress` smallint DEFAULT '0' COMMENT '任务进度', - `use_proxy` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否使用反代', - `publish` tinyint(1) NOT NULL COMMENT '是否发布', - `err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息', - `power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力', - `created_at` datetime NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='MidJourney 任务表'; - --- -------------------------------------------------------- - --- --- 表的结构 `chatgpt_orders` --- - -DROP TABLE IF EXISTS `chatgpt_orders`; -CREATE TABLE `chatgpt_orders` ( - `id` int NOT NULL, - `user_id` int NOT NULL COMMENT '用户ID', - `product_id` int NOT NULL COMMENT '产品ID', - `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户明', - `order_no` varchar(30) NOT NULL COMMENT '订单ID', - `trade_no` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '支付平台交易流水号', - `subject` varchar(100) NOT NULL COMMENT '订单产品', - `amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单金额', - `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '订单状态(0:待支付,1:已扫码,2:支付失败)', - `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注', - `pay_time` int DEFAULT NULL COMMENT '支付时间', - `pay_way` varchar(20) NOT NULL COMMENT '支付方式', - `created_at` datetime NOT NULL, - `updated_at` datetime NOT NULL, - `deleted_at` datetime DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='充值订单表'; - --- -------------------------------------------------------- - --- --- 表的结构 `chatgpt_power_logs` --- - -DROP TABLE IF EXISTS `chatgpt_power_logs`; -CREATE TABLE `chatgpt_power_logs` ( - `id` int NOT NULL, - `user_id` int NOT NULL COMMENT '用户ID', - `username` varchar(30) NOT NULL COMMENT '用户名', - `type` tinyint(1) NOT NULL COMMENT '类型(1:充值,2:消费,3:退费)', - `amount` smallint NOT NULL COMMENT '算力数值', - `balance` int NOT NULL COMMENT '余额', - `model` varchar(30) NOT NULL COMMENT '模型', - `remark` varchar(255) NOT NULL COMMENT '备注', - `mark` tinyint(1) NOT NULL COMMENT '资金类型(0:支出,1:收入)', - `created_at` datetime NOT NULL COMMENT '创建时间' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户算力消费日志'; - --- -------------------------------------------------------- - --- --- 表的结构 `chatgpt_products` --- - -DROP TABLE IF EXISTS `chatgpt_products`; -CREATE TABLE `chatgpt_products` ( - `id` int NOT NULL, - `name` varchar(30) NOT NULL COMMENT '名称', - `price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '价格', - `discount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠金额', - `days` smallint NOT NULL DEFAULT '0' COMMENT '延长天数', - `power` int NOT NULL DEFAULT '0' COMMENT '增加算力值', - `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启动', - `sales` int NOT NULL DEFAULT '0' COMMENT '销量', - `sort_num` tinyint NOT NULL DEFAULT '0' COMMENT '排序', - `created_at` datetime NOT NULL, - `updated_at` datetime NOT NULL, - `app_url` varchar(255) DEFAULT NULL COMMENT 'App跳转地址', - `url` varchar(255) DEFAULT NULL COMMENT '跳转地址' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会员套餐表'; - --- -------------------------------------------------------- - --- --- 表的结构 `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:已核销', - `exchange` varchar(255) NOT NULL COMMENT '兑换详情(json)', - `created_at` datetime NOT NULL, - `updated_at` datetime NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户打赏'; - --- -------------------------------------------------------- - --- --- 表的结构 `chatgpt_sd_jobs` --- - -DROP TABLE IF EXISTS `chatgpt_sd_jobs`; -CREATE TABLE `chatgpt_sd_jobs` ( - `id` int NOT NULL, - `user_id` int NOT NULL COMMENT '用户 ID', - `type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT 'txt2img' COMMENT '任务类别', - `task_id` char(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '任务 ID', - `prompt` varchar(2000) NOT NULL COMMENT '会话提示词', - `img_url` varchar(255) DEFAULT NULL COMMENT '图片URL', - `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '绘画参数json', - `progress` smallint DEFAULT '0' COMMENT '任务进度', - `publish` tinyint(1) NOT NULL COMMENT '是否发布', - `err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息', - `power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力', - `created_at` datetime NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Stable Diffusion 任务表'; - --- -------------------------------------------------------- - --- --- 表的结构 `chatgpt_users` --- - -DROP TABLE IF EXISTS `chatgpt_users`; -CREATE TABLE `chatgpt_users` ( - `id` int NOT NULL, - `username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名', - `nickname` varchar(30) NOT NULL COMMENT '昵称', - `password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码', - `avatar` varchar(100) NOT NULL COMMENT '头像', - `salt` char(12) NOT NULL COMMENT '密码盐', - `power` 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', - `chat_models_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'AI模型 json', - `last_login_at` int NOT NULL COMMENT '最后登录时间', - `vip` tinyint(1) NOT NULL DEFAULT '0' 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`, `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', 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'); - --- -------------------------------------------------------- - --- --- 表的结构 `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_admin_users` --- -ALTER TABLE `chatgpt_admin_users` - ADD PRIMARY KEY (`id`) USING BTREE, - ADD UNIQUE KEY `username` (`username`) USING BTREE; - --- --- 表的索引 `chatgpt_api_keys` --- -ALTER TABLE `chatgpt_api_keys` - ADD PRIMARY KEY (`id`); - --- --- 表的索引 `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_models` --- -ALTER TABLE `chatgpt_chat_models` - ADD PRIMARY KEY (`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_files` --- -ALTER TABLE `chatgpt_files` - ADD PRIMARY KEY (`id`); - --- --- 表的索引 `chatgpt_functions` --- -ALTER TABLE `chatgpt_functions` - ADD PRIMARY KEY (`id`), - ADD UNIQUE KEY `name` (`name`); - --- --- 表的索引 `chatgpt_invite_codes` --- -ALTER TABLE `chatgpt_invite_codes` - ADD PRIMARY KEY (`id`), - ADD UNIQUE KEY `code` (`code`); - --- --- 表的索引 `chatgpt_invite_logs` --- -ALTER TABLE `chatgpt_invite_logs` - ADD PRIMARY KEY (`id`); - --- --- 表的索引 `chatgpt_menus` --- -ALTER TABLE `chatgpt_menus` - ADD PRIMARY KEY (`id`); - --- --- 表的索引 `chatgpt_mj_jobs` --- -ALTER TABLE `chatgpt_mj_jobs` - ADD PRIMARY KEY (`id`), - ADD UNIQUE KEY `task_id` (`task_id`), - ADD KEY `message_id` (`message_id`); - --- --- 表的索引 `chatgpt_orders` --- -ALTER TABLE `chatgpt_orders` - ADD PRIMARY KEY (`id`), - ADD UNIQUE KEY `order_no` (`order_no`); - --- --- 表的索引 `chatgpt_power_logs` --- -ALTER TABLE `chatgpt_power_logs` - ADD PRIMARY KEY (`id`); - --- --- 表的索引 `chatgpt_products` --- -ALTER TABLE `chatgpt_products` - ADD PRIMARY KEY (`id`); - --- --- 表的索引 `chatgpt_rewards` --- -ALTER TABLE `chatgpt_rewards` - ADD PRIMARY KEY (`id`), - ADD UNIQUE KEY `tx_id` (`tx_id`); - --- --- 表的索引 `chatgpt_sd_jobs` --- -ALTER TABLE `chatgpt_sd_jobs` - ADD PRIMARY KEY (`id`), - ADD UNIQUE KEY `task_id` (`task_id`); - --- --- 表的索引 `chatgpt_users` --- -ALTER TABLE `chatgpt_users` - ADD PRIMARY KEY (`id`), - ADD UNIQUE KEY `username` (`username`), - ADD UNIQUE KEY `username_2` (`username`); - --- --- 表的索引 `chatgpt_user_login_logs` --- -ALTER TABLE `chatgpt_user_login_logs` - ADD PRIMARY KEY (`id`); - --- --- 在导出的表使用AUTO_INCREMENT --- - --- --- 使用表AUTO_INCREMENT `chatgpt_admin_users` --- -ALTER TABLE `chatgpt_admin_users` - MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=113; - --- --- 使用表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_models` --- -ALTER TABLE `chatgpt_chat_models` - MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=25; - --- --- 使用表AUTO_INCREMENT `chatgpt_chat_roles` --- -ALTER TABLE `chatgpt_chat_roles` - MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=130; - --- --- 使用表AUTO_INCREMENT `chatgpt_configs` --- -ALTER TABLE `chatgpt_configs` - MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; - --- --- 使用表AUTO_INCREMENT `chatgpt_files` --- -ALTER TABLE `chatgpt_files` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- 使用表AUTO_INCREMENT `chatgpt_functions` --- -ALTER TABLE `chatgpt_functions` - MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; - --- --- 使用表AUTO_INCREMENT `chatgpt_invite_codes` --- -ALTER TABLE `chatgpt_invite_codes` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- 使用表AUTO_INCREMENT `chatgpt_invite_logs` --- -ALTER TABLE `chatgpt_invite_logs` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- 使用表AUTO_INCREMENT `chatgpt_menus` --- -ALTER TABLE `chatgpt_menus` - MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=12; - --- --- 使用表AUTO_INCREMENT `chatgpt_mj_jobs` --- -ALTER TABLE `chatgpt_mj_jobs` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- 使用表AUTO_INCREMENT `chatgpt_orders` --- -ALTER TABLE `chatgpt_orders` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- 使用表AUTO_INCREMENT `chatgpt_power_logs` --- -ALTER TABLE `chatgpt_power_logs` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- 使用表AUTO_INCREMENT `chatgpt_products` --- -ALTER TABLE `chatgpt_products` - 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_sd_jobs` --- -ALTER TABLE `chatgpt_sd_jobs` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- 使用表AUTO_INCREMENT `chatgpt_users` --- -ALTER TABLE `chatgpt_users` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- 使用表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 */; diff --git a/deploy/docker-compose.yaml b/deploy/docker-compose.yaml index a75b895..68bc4e8 100644 --- a/deploy/docker-compose.yaml +++ b/deploy/docker-compose.yaml @@ -51,7 +51,7 @@ services: # 后端 API 程序 geekai-api: - image: registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-api:v4.0.7-amd64 + image: registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-api:v4.0.8-amd64 container_name: geekai-api restart: always depends_on: @@ -73,7 +73,7 @@ services: # 前端应用 geekai-web: - image: registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-web:v4.0.7-amd64 + image: registry.cn-shenzhen.aliyuncs.com/geekmaster/geekai-web:v4.0.8-amd64 container_name: geekai-web restart: always depends_on: diff --git a/web/.env.development b/web/.env.development index 9811fff..62d3b37 100644 --- a/web/.env.development +++ b/web/.env.development @@ -6,4 +6,4 @@ VUE_APP_ADMIN_USER=admin VUE_APP_ADMIN_PASS=admin123 VUE_APP_KEY_PREFIX=ChatPLUS_DEV_ VUE_APP_TITLE="Geek-AI 创作系统" -VUE_APP_VERSION=v4.0.7 +VUE_APP_VERSION=v4.0.8 diff --git a/web/.env.production b/web/.env.production index 9404e7a..3f59423 100644 --- a/web/.env.production +++ b/web/.env.production @@ -2,4 +2,4 @@ VUE_APP_API_HOST= VUE_APP_WS_HOST= VUE_APP_KEY_PREFIX=ChatPLUS_ VUE_APP_TITLE="Geek-AI 创作系统" -VUE_APP_VERSION=v4.0.7 +VUE_APP_VERSION=v4.0.8 diff --git a/web/package.json b/web/package.json index dcd7ab6..e9969bb 100644 --- a/web/package.json +++ b/web/package.json @@ -1,5 +1,5 @@ { - "name": "chatgpt-plus-web", + "name": "geekai-web", "version": "0.1.0", "private": true, "scripts": { @@ -20,8 +20,7 @@ "json-bigint": "^1.0.0", "lodash": "^4.17.21", "markdown-it": "^13.0.1", - "markdown-it-latex2img": "^0.0.6", - "markdown-it-mathjax": "^2.0.0", + "markdown-it-mathjax3": "^4.3.2", "markmap-common": "^0.16.0", "markmap-lib": "^0.16.1", "markmap-toolbar": "^0.17.0", diff --git a/web/src/assets/css/chat-app.styl b/web/src/assets/css/chat-app.styl index 55deed1..c7692bd 100644 --- a/web/src/assets/css/chat-app.styl +++ b/web/src/assets/css/chat-app.styl @@ -13,8 +13,9 @@ .item { display flex flex-flow row - border 1px solid #3c3c3c + border 1px solid rgb(80,80,80) padding 10px + background rgba(60,60,60 0.5) .image { width 80px diff --git a/web/src/assets/css/chat-plus.styl b/web/src/assets/css/chat-plus.styl index 32ba080..61522fe 100644 --- a/web/src/assets/css/chat-plus.styl +++ b/web/src/assets/css/chat-plus.styl @@ -129,15 +129,44 @@ $borderColor = #4676d0; --el-main-padding: 0; margin: 0; - .chat-box { + .chat-container { min-width: 0; flex: 1; background-color: var(--el-bg-color) color var(--el-text-color-primary) + .chat-config { + height 30px + padding 10px 30px + display flex + justify-content center + justify-items center + border-bottom 1px solid #d9d9e3 + + .role-select-label { + color #ffffff + } + + .el-select { + max-width 150px; + margin-right 10px; + } + + .role-select { + max-width 130px; + } + + .el-button { + .el-icon { + margin-right 5px; + } + } + } + #container { overflow: hidden; width: 100%; + position relative ::-webkit-scrollbar { width: 0; @@ -165,68 +194,97 @@ $borderColor = #4676d0; } .input-box { - background-color: #ffffff - display: flex; - justify-content: center; - align-items: center; - box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1); - padding 0 15px; + position absolute + bottom 0 + width 100% - .tool-item { - margin-right 15px - border-radius: 6px; - color: #19c37d; + .input-box-inner { display flex - justify-content center - justify-items center - padding 6px - cursor pointer - background #F2F2F2 + background-color: #ffffff + justify-content: center; + align-items: center; + box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1); + padding 0 15px; - &:hover { - background #D5FAD3 - } + .tool-item { + margin-right 15px + border-radius: 6px; + color: #19c37d; + display flex + justify-content center + justify-items center + padding 6px + cursor pointer + background #F2F2F2 - .iconfont { - font-size: 24px; - } - } + &:hover { + background #D5FAD3 + } - .input-container { - width 100% - margin: 0; - border: none; - padding: 10px 0; - display flex - justify-content center - position relative - - .el-textarea { - .el-textarea__inner::-webkit-scrollbar { - width: 0; - height: 0; + .iconfont { + font-size: 24px; } } - .select-file { - position absolute; - right 48px; - top 20px; - } + .input-body { + width 100% + margin: 0; + border: none; + padding: 10px 0; + display flex + justify-content center + position relative - .send-btn { - position absolute; - right 12px; - top 20px; + .hide-div { + white-space: pre-wrap; /* 保持文本换行 */ + visibility: hidden; /* 隐藏 div */ + position: absolute; /* 脱离文档流 */ + line-height: 24px + font-size 14px + word-wrap: break-word; /* 允许单词换行 */ + overflow-wrap: break-word; /* 允许长单词换行,适用于现代浏览器 */ + } + + .input-border { + display flex + width 100% + overflow hidden + border: 2px solid #21AA93 + border-radius 10px + padding 10px + + + .prompt-input::-webkit-scrollbar { + width: 0; + height: 0; + } + + .prompt-input { + width 100% + line-height: 24px + border none + font-size 14px + background none + resize: none + white-space: pre-wrap; /* 保持文本换行 */ + word-wrap: break-word; /* 允许单词换行 */ + overflow-wrap: break-word; /* 允许长单词换行,适用于现代浏览器 */ + } + + .send-btn { + width 32px + margin-left 10px + .el-button { + padding 8px 5px; + border-radius 6px; + font-size 20px; + } + } - .el-button { - padding 8px 5px; - border-radius 6px; - font-size 20px; } } - } + } } diff --git a/web/src/assets/css/home.styl b/web/src/assets/css/home.styl index 950182c..bf257ed 100644 --- a/web/src/assets/css/home.styl +++ b/web/src/assets/css/home.styl @@ -21,8 +21,8 @@ cursor pointer .el-image { - width 40px - height 40px + width 48px + height 48px } } @@ -86,7 +86,7 @@ .navigator { display flex flex-flow column - width 50px + width 60px padding 10px 1px border-right: 1px solid #3c3c3c background-color: #1E1F22 @@ -97,12 +97,14 @@ li { margin-bottom 15px + display flex + flex-flow column a { color #DADBDC border-radius 10px - width 40px - height 40px + width 48px + height 48px display flex justify-content center align-items center @@ -125,9 +127,12 @@ .title { font-size: 12px - padding-top: 5px + padding-top: 6px color: #e5e7eb; text-align: center; + white-space: nowrap; /* 防止文本换行 */ + overflow: hidden; /* 隐藏溢出内容 */ + text-overflow: unset; /* 使用省略号表示溢出内容 */ } .active { diff --git a/web/src/assets/css/image-mj.styl b/web/src/assets/css/image-mj.styl index 1635871..dd4775a 100644 --- a/web/src/assets/css/image-mj.styl +++ b/web/src/assets/css/image-mj.styl @@ -50,6 +50,7 @@ display flex cursor pointer margin-bottom: 10px; + border 1px solid #383838 &:hover { background-color #585858 @@ -61,60 +62,9 @@ margin-bottom 5px } - .shape { - width 16px - height 16px - margin-bottom 5px - border 1px solid #C4C4C4 - border-radius 3px - } - - .shape.size9-16 { - width 9px - height 16px - } - - .shape.size16-9 { - height 9px - width 16px - position relative - margin 4px 0 7px - } - - .shape.size3-4 { - width 12px - height 16px - } - - .shape.size4-3 { - height 12px - width 16px - position relative - margin 4px 0 4px - } - - .shape.size2-3 { - width 11px - height 16px - } - - .shape.size3-2 { - height 11px - width 16px - position relative - margin 4px 0 5px - } - - .shape.size1-2 { - width 8px - height 16px - } - - .shape.size2-1 { - height 8px - width 16px - position relative - margin 4px 0 8px + .text { + margin-left 5px + margin-top 2px } } @@ -122,10 +72,7 @@ .grid-content.active { color #47fff1 background-color #585858 - - .shape { - border 1px solid #47fff1 - } + border 1px solid #47fff1 } .model { diff --git a/web/src/components/admin/AdminSidebar.vue b/web/src/components/admin/AdminSidebar.vue index df24ddc..4c0aebd 100644 --- a/web/src/components/admin/AdminSidebar.vue +++ b/web/src/components/admin/AdminSidebar.vue @@ -92,9 +92,9 @@ const items = [ }, { - icon: 'role', - index: '/admin/role', - title: '角色管理', + icon: 'menu', + index: '/admin/app', + title: '应用管理', }, { icon: 'api-key', diff --git a/web/src/router.js b/web/src/router.js index a03c5ec..64fdecb 100644 --- a/web/src/router.js +++ b/web/src/router.js @@ -46,7 +46,7 @@ const routes = [ component: () => import('@/views/Member.vue'), }, { - name: 'chat-role', + name: 'chat-app', path: '/apps', meta: {title: '应用中心'}, component: () => import('@/views/ChatApps.vue'), @@ -139,10 +139,10 @@ const routes = [ component: () => import('@/views/admin/Users.vue'), }, { - path: '/admin/role', - name: 'admin-role', - meta: {title: '角色管理'}, - component: () => import('@/views/admin/Roles.vue'), + path: '/admin/app', + name: 'admin-app', + meta: {title: '应用管理'}, + component: () => import('@/views/admin/Apps.vue'), }, { path: '/admin/apikey', diff --git a/web/src/views/ChatPlus.vue b/web/src/views/ChatPlus.vue index f59e33b..887ddf7 100644 --- a/web/src/views/ChatPlus.vue +++ b/web/src/views/ChatPlus.vue @@ -65,9 +65,44 @@ -
+
+
+ + +
+ + {{ item.name }} +
+
+
+ + + + {{ item.name }} + {{ + item.power + }}算力 + + + +
+
-
+
@@ -84,61 +119,8 @@
- -
- - - - - - - - +
+
@@ -151,32 +133,34 @@ -
- - - - - - - - - - - +
+
{{prompt}}
+
+ + + + + + + + + + + +
+
- +
@@ -237,11 +221,13 @@ const roleId = ref(0) const newChatItem = ref(null); const isLogin = ref(false) const showHello = ref(true) -const textInput = ref(null) +const inputRef = ref(null) +const textHeightRef = ref(null) const showNotice = ref(false) const notice = ref("") const noticeKey = ref("SYSTEM_NOTICE") const store = useSharedStore(); +const row = ref(1) if (isMobile()) { router.replace("/mobile/chat") @@ -372,8 +358,8 @@ const getRoleById = function (rid) { } const resizeElement = function () { - chatBoxHeight.value = window.innerHeight - 50 - 82 - 38; - mainWinHeight.value = window.innerHeight - 50; + chatBoxHeight.value = window.innerHeight - 101 - 82 - 38; + mainWinHeight.value = window.innerHeight - 101; leftBoxHeight.value = window.innerHeight - 90 - 45 - 82; }; @@ -517,8 +503,7 @@ const removeChat = function (chat) { } -const latexPlugin = require('markdown-it-latex2img') -const mathjaxPlugin = require('markdown-it-mathjax') +const mathjaxPlugin = require('markdown-it-mathjax3') const md = require('markdown-it')({ breaks: true, html: true, @@ -543,7 +528,6 @@ const md = require('markdown-it')({ return `
${preCode}${copyBtn}
` } }); -md.use(latexPlugin) md.use(mathjaxPlugin) // 创建 socket 连接 @@ -705,8 +689,19 @@ const enableInput = () => { showStopGenerate.value = false; } -// 登录输入框输入事件处理 -const inputKeyDown = function (e) { +const onInput = (e) => { + // 根据输入的内容自动计算输入框的行数 + const lineHeight = parseFloat(window.getComputedStyle(inputRef.value).lineHeight) + textHeightRef.value.style.width = inputRef.value.clientWidth + 'px'; // 设定宽度和 textarea 相同 + const lines = Math.floor(textHeightRef.value.clientHeight / lineHeight); + inputRef.value.scrollTo(0, inputRef.value.scrollHeight) + if (prompt.value.length < 10) { + row.value = 1 + } else if (row.value <= 7) { + row.value = lines + } + + // 输入回车自动提交 if (e.keyCode === 13) { if (e.ctrlKey) { // Ctrl + Enter 换行 prompt.value += "\n"; @@ -720,7 +715,7 @@ const inputKeyDown = function (e) { // 自动填充 prompt const autofillPrompt = (text) => { prompt.value = text - textInput.value.focus() + inputRef.value.focus() // sendMessage() } // 发送消息 @@ -929,29 +924,4 @@ const insertURL = (url) => { } } } - -.chat-config { - display flex - flex-direction row - padding-top 10px; - - .role-select-label { - color #ffffff - } - - .el-select { - max-width 150px; - margin-right 10px; - } - - .role-select { - max-width 130px; - } - - .el-button { - .el-icon { - margin-right 5px; - } - } -} \ No newline at end of file diff --git a/web/src/views/Home.vue b/web/src/views/Home.vue index 4f73d94..87043d4 100644 --- a/web/src/views/Home.vue +++ b/web/src/views/Home.vue @@ -11,8 +11,8 @@