diff --git a/api/core/app_server.go b/api/core/app_server.go
index 6d236e73..dd99a755 100644
--- a/api/core/app_server.go
+++ b/api/core/app_server.go
@@ -237,6 +237,7 @@ func needLogin(c *gin.Context) bool {
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/user/clogin") ||
strings.HasPrefix(c.Request.URL.Path, "/api/config/") ||
strings.HasPrefix(c.Request.URL.Path, "/api/function/") ||
strings.HasPrefix(c.Request.URL.Path, "/api/sms/") ||
diff --git a/api/go.mod b/api/go.mod
index 28516363..2a8efd45 100644
--- a/api/go.mod
+++ b/api/go.mod
@@ -29,7 +29,8 @@ require github.com/xxl-job/xxl-job-executor-go v1.2.0
require (
github.com/go-pay/gopay v1.5.101
github.com/google/go-tika v0.3.1
- github.com/mojocn/base64Captcha v1.3.1
+ github.com/microcosm-cc/bluemonday v1.0.26
+ github.com/mojocn/base64Captcha v1.3.6
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/shopspring/decimal v1.3.1
github.com/syndtr/goleveldb v1.0.0
@@ -47,7 +48,6 @@ require (
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
github.com/gorilla/css v1.0.0 // indirect
- github.com/microcosm-cc/bluemonday v1.0.26 // indirect
github.com/tklauser/go-sysconf v0.3.13 // indirect
github.com/tklauser/numcpus v0.7.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
diff --git a/api/go.sum b/api/go.sum
index e88deff9..c0179e87 100644
--- a/api/go.sum
+++ b/api/go.sum
@@ -157,8 +157,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/mojocn/base64Captcha v1.3.1 h1:2Wbkt8Oc8qjmNJ5GyOfSo4tgVQPsbKMftqASnq8GlT0=
-github.com/mojocn/base64Captcha v1.3.1/go.mod h1:wAQCKEc5bDujxKRmbT6/vTnTt5CjStQ8bRfPWUuz/iY=
+github.com/mojocn/base64Captcha v1.3.6 h1:gZEKu1nsKpttuIAQgWHO+4Mhhls8cAKyiV2Ew03H+Tw=
+github.com/mojocn/base64Captcha v1.3.6/go.mod h1:i5CtHvm+oMbj1UzEPXaA8IH/xHFZ3DGY3Wh3dBpZ28E=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
@@ -265,7 +265,7 @@ golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
-golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk=
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -321,6 +321,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
diff --git a/api/handler/admin/captcha_handler.go b/api/handler/admin/captcha_handler.go
deleted file mode 100644
index e6b81cbf..00000000
--- a/api/handler/admin/captcha_handler.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package admin
-
-// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-// * 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 (
- "geekai/core"
- "geekai/handler"
- "geekai/utils/resp"
- "github.com/gin-gonic/gin"
- "github.com/mojocn/base64Captcha"
-)
-
-type CaptchaHandler struct {
- handler.BaseHandler
-}
-
-func NewCaptchaHandler(app *core.AppServer) *CaptchaHandler {
- return &CaptchaHandler{BaseHandler: handler.BaseHandler{App: app}}
-}
-
-type CaptchaVo struct {
- CaptchaId string `json:"captcha_id"`
- PicPath string `json:"pic_path"`
-}
-
-// GetCaptcha 获取验证码
-func (h *CaptchaHandler) GetCaptcha(c *gin.Context) {
- var captchaVo CaptchaVo
- driver := base64Captcha.NewDriverDigit(48, 130, 4, 0.4, 10)
- cp := base64Captcha.NewCaptcha(driver, base64Captcha.DefaultMemStore)
- // b64s是图片的base64编码
- id, b64s, err := cp.Generate()
- if err != nil {
- resp.ERROR(c, "生成验证码错误!")
- return
- }
- captchaVo.CaptchaId = id
- captchaVo.PicPath = b64s
-
- resp.SUCCESS(c, captchaVo)
-}
diff --git a/api/handler/admin/chat_model_handler.go b/api/handler/admin/chat_model_handler.go
index 74f187cc..3a1e6328 100644
--- a/api/handler/admin/chat_model_handler.go
+++ b/api/handler/admin/chat_model_handler.go
@@ -54,7 +54,6 @@ func (h *ChatModelHandler) Save(c *gin.Context) {
Name: data.Name,
Value: data.Value,
Enabled: data.Enabled,
- SortNum: data.SortNum,
Open: data.Open,
MaxTokens: data.MaxTokens,
MaxContext: data.MaxContext,
@@ -64,6 +63,7 @@ func (h *ChatModelHandler) Save(c *gin.Context) {
var res *gorm.DB
if data.Id > 0 {
item.Id = data.Id
+ item.SortNum = data.SortNum
res = h.DB.Select("*").Omit("created_at").Updates(&item)
} else {
res = h.DB.Create(&item)
diff --git a/api/handler/admin/user_handler.go b/api/handler/admin/user_handler.go
index 95da105f..34747d77 100644
--- a/api/handler/admin/user_handler.go
+++ b/api/handler/admin/user_handler.go
@@ -139,7 +139,6 @@ func (h *UserHandler) Save(c *gin.Context) {
salt := utils.RandString(8)
u := model.User{
Username: data.Username,
- Nickname: fmt.Sprintf("极客学长@%d", utils.RandomNumber(6)),
Password: utils.GenPassword(data.Password, salt),
Avatar: "/images/avatar/user.png",
Salt: salt,
@@ -149,6 +148,11 @@ func (h *UserHandler) Save(c *gin.Context) {
ChatModels: utils.JsonEncode(data.ChatModels),
ExpiredTime: utils.Str2stamp(data.ExpiredTime),
}
+ if h.licenseService.GetLicense().Configs.DeCopy {
+ u.Nickname = fmt.Sprintf("用户@%d", utils.RandomNumber(6))
+ } else {
+ u.Nickname = fmt.Sprintf("极客学长@%d", utils.RandomNumber(6))
+ }
res = h.DB.Create(&u)
_ = utils.CopyObject(u, &userVo)
userVo.Id = u.Id
diff --git a/api/handler/chat_role_handler.go b/api/handler/chat_role_handler.go
index 707e7f4f..e220009a 100644
--- a/api/handler/chat_role_handler.go
+++ b/api/handler/chat_role_handler.go
@@ -65,7 +65,7 @@ func (h *ChatRoleHandler) List(c *gin.Context) {
}
for _, r := range roles {
- if !utils.ContainsStr(roleKeys, r.Key) {
+ if !utils.Contains(roleKeys, r.Key) {
continue
}
var v vo.ChatRole
diff --git a/api/handler/chatimpl/openai_handler.go b/api/handler/chatimpl/openai_handler.go
index 86089410..97f76531 100644
--- a/api/handler/chatimpl/openai_handler.go
+++ b/api/handler/chatimpl/openai_handler.go
@@ -74,6 +74,9 @@ func (h *ChatHandler) sendOpenAiMessage(
if len(responseBody.Choices) == 0 { // Fixed: 兼容 Azure API 第一个输出空行
continue
}
+ if responseBody.Choices[0].Delta.Content == nil {
+ continue
+ }
if responseBody.Choices[0].FinishReason == "stop" && len(contents) == 0 {
utils.ReplyMessage(ws, "抱歉😔😔😔,AI助手由于未知原因已经停止输出内容。")
diff --git a/api/handler/sms_handler.go b/api/handler/sms_handler.go
index 7740a77e..38a61da6 100644
--- a/api/handler/sms_handler.go
+++ b/api/handler/sms_handler.go
@@ -64,13 +64,13 @@ func (h *SmsHandler) SendCode(c *gin.Context) {
code := utils.RandomNumber(6)
var err error
if strings.Contains(data.Receiver, "@") { // email
- if !utils.ContainsStr(h.App.SysConfig.RegisterWays, "email") {
+ if !utils.Contains(h.App.SysConfig.RegisterWays, "email") {
resp.ERROR(c, "系统已禁用邮箱注册!")
return
}
err = h.smtp.SendVerifyCode(data.Receiver, code)
} else {
- if !utils.ContainsStr(h.App.SysConfig.RegisterWays, "mobile") {
+ if !utils.Contains(h.App.SysConfig.RegisterWays, "mobile") {
resp.ERROR(c, "系统已禁用手机号注册!")
return
}
diff --git a/api/handler/user_handler.go b/api/handler/user_handler.go
index 74723c78..deae433d 100644
--- a/api/handler/user_handler.go
+++ b/api/handler/user_handler.go
@@ -16,6 +16,7 @@ import (
"geekai/store/vo"
"geekai/utils"
"geekai/utils/resp"
+ "github.com/imroc/req/v3"
"strings"
"time"
@@ -97,7 +98,7 @@ func (h *UserHandler) Register(c *gin.Context) {
}
}
- // check if the username is exists
+ // check if the username is existing
var item model.User
res := h.DB.Where("username = ?", data.Username).First(&item)
if item.Id > 0 {
@@ -255,6 +256,40 @@ func (h *UserHandler) Logout(c *gin.Context) {
resp.SUCCESS(c)
}
+// CLoginRequest 第三方登录请求二维码
+func (h *UserHandler) CLoginRequest(c *gin.Context) {
+ returnURL := h.GetTrim(c, "return_url")
+ var res types.BizVo
+ apiURL := fmt.Sprintf("%s/api/clogin/request", h.App.Config.ApiConfig.ApiURL)
+ r, err := req.C().R().SetBody(gin.H{"login_type": "wx", "return_url": returnURL}).
+ SetHeader("AppId", h.App.Config.ApiConfig.AppId).
+ SetHeader("Authorization", fmt.Sprintf("Bearer %s", h.App.Config.ApiConfig.Token)).
+ SetSuccessResult(&res).
+ Post(apiURL)
+ if err != nil {
+ resp.ERROR(c, err.Error())
+ return
+ }
+ if r.IsErrorState() {
+ resp.ERROR(c, "error with login http status: "+r.Status)
+ return
+ }
+
+ if res.Code != types.Success {
+ resp.ERROR(c, "error with http response: "+res.Message)
+ return
+ }
+
+ resp.SUCCESS(c, res.Data)
+}
+
+// CLoginCallback 第三方登录回调
+func (h *UserHandler) CLoginCallback(c *gin.Context) {
+ //platform := h.GetTrim(c, "type")
+ //code := h.GetTrim(c, "code")
+
+}
+
// Session 获取/验证会话
func (h *UserHandler) Session(c *gin.Context) {
user, err := h.GetLoginUser(c)
diff --git a/api/main.go b/api/main.go
index b2c40dd6..d95358f9 100644
--- a/api/main.go
+++ b/api/main.go
@@ -240,6 +240,8 @@ func main() {
group.POST("password", h.UpdatePass)
group.POST("bind/username", h.BindUsername)
group.POST("resetPass", h.ResetPass)
+ group.GET("clogin/request", h.CLoginRequest)
+ group.GET("clogin/callback", h.CLoginCallback)
}),
fx.Invoke(func(s *core.AppServer, h *chatimpl.ChatHandler) {
group := s.Engine.Group("/api/chat/")
@@ -416,13 +418,6 @@ func main() {
group.GET("token", h.GenToken)
}),
- // 验证码
- fx.Provide(admin.NewCaptchaHandler),
- fx.Invoke(func(s *core.AppServer, h *admin.CaptchaHandler) {
- group := s.Engine.Group("/api/admin/login/")
- group.GET("captcha", h.GetCaptcha)
- }),
-
fx.Provide(admin.NewUploadHandler),
fx.Invoke(func(s *core.AppServer, h *admin.UploadHandler) {
s.Engine.POST("/api/admin/upload", h.Upload)
diff --git a/api/service/mj/pool.go b/api/service/mj/pool.go
index 3eacfd78..7cf84a60 100644
--- a/api/service/mj/pool.go
+++ b/api/service/mj/pool.go
@@ -16,6 +16,7 @@ import (
"geekai/service/sd"
"geekai/store"
"geekai/store/model"
+ "geekai/utils"
"github.com/go-redis/redis/v8"
"strings"
"time"
@@ -58,13 +59,13 @@ func (p *ServicePool) InitServices(plusConfigs []types.MjPlusConfig, proxyConfig
}
p.services = make([]*Service, 0)
- for k, config := range plusConfigs {
+ for _, config := range plusConfigs {
if config.Enabled == false {
continue
}
cli := NewPlusClient(config, p.licenseService)
- name := fmt.Sprintf("mj-plus-service-%d", k)
+ name := utils.Md5(config.ApiURL)
plusService := NewService(name, p.taskQueue, p.notifyQueue, p.db, cli)
go func() {
plusService.Run()
@@ -73,12 +74,12 @@ func (p *ServicePool) InitServices(plusConfigs []types.MjPlusConfig, proxyConfig
}
// for mid-journey proxy
- for k, config := range proxyConfigs {
+ for _, config := range proxyConfigs {
if config.Enabled == false {
continue
}
cli := NewProxyClient(config)
- name := fmt.Sprintf("mj-proxy-service-%d", k)
+ name := utils.Md5(config.ApiURL)
proxyService := NewService(name, p.taskQueue, p.notifyQueue, p.db, cli)
go func() {
proxyService.Run()
@@ -209,7 +210,6 @@ func (p *ServicePool) SyncTaskProgress() {
}
continue
}
-
if servicePlus := p.getService(job.ChannelId); servicePlus != nil {
_ = servicePlus.Notify(job)
}
diff --git a/api/store/model/user.go b/api/store/model/user.go
index 41d09905..bc2bafec 100644
--- a/api/store/model/user.go
+++ b/api/store/model/user.go
@@ -15,5 +15,7 @@ type User struct {
Status bool `gorm:"default:true"` // 当前状态
LastLoginAt int64 // 最后登录时间
LastLoginIp string // 最后登录 IP
+ OpenId string `gorm:"column:openid"`
+ Platform string `json:"platform"`
Vip bool // 是否 VIP 会员
}
diff --git a/api/store/vo/user.go b/api/store/vo/user.go
index 560f57db..8e0faabe 100644
--- a/api/store/vo/user.go
+++ b/api/store/vo/user.go
@@ -14,4 +14,6 @@ type User struct {
LastLoginAt int64 `json:"last_login_at"` // 最后登录时间
LastLoginIp string `json:"last_login_ip"` // 最后登录 IP
Vip bool `json:"vip"`
+ OpenId string `json:"openid"` // 第三方登录 OpenID
+ Platform string `json:"platform"` // 第三方登录平台
}
diff --git a/api/utils/strings.go b/api/utils/strings.go
index ff5c28e6..feb377de 100644
--- a/api/utils/strings.go
+++ b/api/utils/strings.go
@@ -31,11 +31,11 @@ func RandString(length int) string {
}
func RandomNumber(bit int) int {
- min := intPow(10, bit-1)
- max := intPow(10, bit) - 1
+ minNum := intPow(10, bit-1)
+ maxNum := intPow(10, bit) - 1
- rand.Seed(time.Now().UnixNano())
- return rand.Intn(max-min+1) + min
+ rand.NewSource(time.Now().UnixNano())
+ return rand.Intn(maxNum-minNum+1) + minNum
}
func intPow(x, y int) int {
@@ -46,7 +46,7 @@ func intPow(x, y int) int {
return result
}
-func ContainsStr(slice []string, item string) bool {
+func Contains(slice []string, item string) bool {
for _, e := range slice {
if e == item {
return true
diff --git a/database/update-v4.1.0.sql b/database/update-v4.1.0.sql
index ba309dc9..61ed1a8a 100644
--- a/database/update-v4.1.0.sql
+++ b/database/update-v4.1.0.sql
@@ -1 +1,3 @@
-ALTER TABLE `chatgpt_chat_models` CHANGE `power` `power` SMALLINT NOT NULL COMMENT '消耗算力点数';
\ No newline at end of file
+ALTER TABLE `chatgpt_chat_models` CHANGE `power` `power` SMALLINT NOT NULL COMMENT '消耗算力点数';
+ALTER TABLE `chatgpt_users` ADD `openid` VARCHAR(100) NULL COMMENT '第三方登录账号ID' AFTER `last_login_ip`;
+ALTER TABLE `chatgpt_users` ADD `platform` VARCHAR(30) NULL COMMENT '登录平台' AFTER `openid`;
\ No newline at end of file
diff --git a/web/src/components/ChatPrompt.vue b/web/src/components/ChatPrompt.vue
index 56fc4987..746a9907 100644
--- a/web/src/components/ChatPrompt.vue
+++ b/web/src/components/ChatPrompt.vue
@@ -312,6 +312,7 @@ onMounted(() => {
.chat-item {
padding: 0;
overflow: hidden;
+ max-width 60%
.file-list-box {
display flex
diff --git a/web/src/components/ChatReply.vue b/web/src/components/ChatReply.vue
index 60982347..033fefe5 100644
--- a/web/src/components/ChatReply.vue
+++ b/web/src/components/ChatReply.vue
@@ -364,6 +364,7 @@ const reGenerate = (prompt) => {
position: relative;
padding: 0;
overflow: hidden;
+ max-width 60%
.content-wrapper {
display flex
diff --git a/web/src/views/Login.vue b/web/src/views/Login.vue
index bb71ed43..ee8a0332 100644
--- a/web/src/views/Login.vue
+++ b/web/src/views/Login.vue
@@ -34,12 +34,17 @@
登录
-
- 注册
-
+
+
+
+
+
+
+ 注册
+
重置密码
-
+
首页
@@ -57,7 +62,7 @@