mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-11-13 20:53:47 +08:00
optimize styles and release v4.0.4
This commit is contained in:
@@ -8,11 +8,11 @@ import (
|
||||
"chatplus/utils/resp"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/chai2010/webp"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/nfnt/resize"
|
||||
"golang.org/x/image/webp"
|
||||
"gorm.io/gorm"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
|
||||
@@ -23,7 +23,7 @@ func NewDefaultConfig() *types.AppConfig {
|
||||
SecretKey: utils.RandString(64),
|
||||
MaxAge: 86400,
|
||||
},
|
||||
ApiConfig: types.ChatPlusApiConfig{},
|
||||
ApiConfig: types.ApiConfig{},
|
||||
OSS: types.OSSConfig{
|
||||
Active: "local",
|
||||
Local: types.LocalStorageConfig{
|
||||
|
||||
@@ -14,7 +14,7 @@ type AppConfig struct {
|
||||
StaticDir string // 静态资源目录
|
||||
StaticUrl string // 静态资源 URL
|
||||
Redis RedisConfig // redis 连接信息
|
||||
ApiConfig ChatPlusApiConfig // ChatPlus API authorization configs
|
||||
ApiConfig ApiConfig // ChatPlus API authorization configs
|
||||
SMS SMSConfig // send mobile message config
|
||||
OSS OSSConfig // OSS config
|
||||
MjProxyConfigs []MjProxyConfig // MJ proxy config
|
||||
@@ -38,7 +38,7 @@ type SmtpConfig struct {
|
||||
Password string // 发件人邮箱密码
|
||||
}
|
||||
|
||||
type ChatPlusApiConfig struct {
|
||||
type ApiConfig struct {
|
||||
ApiURL string
|
||||
AppId string
|
||||
Token string
|
||||
@@ -115,6 +115,17 @@ type RedisConfig struct {
|
||||
DB int
|
||||
}
|
||||
|
||||
// LicenseKey 存储许可证书的 KEY
|
||||
const LicenseKey = "Geek-AI-License"
|
||||
|
||||
type License struct {
|
||||
Key string // 许可证书密钥
|
||||
MachineId string // 机器码
|
||||
UserNum int // 用户数量
|
||||
ExpiredAt int64 // 过期时间
|
||||
IsActive bool // 是否激活
|
||||
}
|
||||
|
||||
func (c RedisConfig) Url() string {
|
||||
return fmt.Sprintf("%s:%d", c.Host, c.Port)
|
||||
}
|
||||
@@ -137,7 +148,7 @@ type SystemConfig struct {
|
||||
InvitePower int `json:"invite_power,omitempty"` // 邀请新用户赠送算力值
|
||||
VipMonthPower int `json:"vip_month_power,omitempty"` // VIP 会员每月赠送的算力值
|
||||
|
||||
RegisterWays []string `json:"register_ways,omitempty"` // 注册方式:支持手机,邮箱注册,账号密码注册
|
||||
RegisterWays []string `json:"register_ways,omitempty"` // 注册方式:支持手机(mobile),邮箱注册(email),账号密码注册
|
||||
EnabledRegister bool `json:"enabled_register,omitempty"` // 是否开放注册
|
||||
|
||||
RewardImg string `json:"reward_img,omitempty"` // 众筹收款二维码地址
|
||||
|
||||
10
api/go.mod
10
api/go.mod
@@ -27,15 +27,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/chai2010/webp v1.1.1 // indirect
|
||||
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
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // 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
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -108,6 +112,6 @@ require (
|
||||
go.uber.org/fx v1.19.3
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
golang.org/x/crypto v0.12.0
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
gorm.io/gorm v1.25.1
|
||||
)
|
||||
|
||||
18
api/go.sum
18
api/go.sum
@@ -12,8 +12,6 @@ github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chai2010/webp v1.1.1 h1:jTRmEccAJ4MGrhFOrPMpNGIJ/eybIgwKpcACsrTEapk=
|
||||
github.com/chai2010/webp v1.1.1/go.mod h1:0XVwvZWdjjdxpUEIf7b9g9VkHFnInUSYujwqTLEuldU=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
@@ -42,6 +40,8 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU
|
||||
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-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/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
@@ -177,6 +177,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=
|
||||
@@ -205,6 +207,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.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
|
||||
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
|
||||
github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
|
||||
github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
|
||||
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=
|
||||
@@ -217,6 +223,8 @@ github.com/xxl-job/xxl-job-executor-go v1.2.0 h1:MTl2DpwrK2+hNjRRks2k7vB3oy+3onq
|
||||
github.com/xxl-job/xxl-job-executor-go v1.2.0/go.mod h1:bUFhz/5Irp9zkdYk5MxhQcDDT6LlZrI8+rv5mHtQ1mo=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
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=
|
||||
@@ -241,7 +249,6 @@ golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75 h1:TbGuee8sSq15Iguxu4deQ7+Bqq/d2rsQejGcEtADAMQ=
|
||||
golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
@@ -267,6 +274,7 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -278,8 +286,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
||||
@@ -33,7 +33,7 @@ func (h *ChatModelHandler) Save(c *gin.Context) {
|
||||
MaxTokens int `json:"max_tokens"` // 最大响应长度
|
||||
MaxContext int `json:"max_context"` // 最大上下文长度
|
||||
Temperature float32 `json:"temperature"` // 模型温度
|
||||
KeyId int `json:"key_id"`
|
||||
KeyId int `json:"key_id,omitempty"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&data); err != nil {
|
||||
|
||||
@@ -4,20 +4,24 @@ import (
|
||||
"chatplus/core"
|
||||
"chatplus/core/types"
|
||||
"chatplus/handler"
|
||||
"chatplus/service"
|
||||
"chatplus/store"
|
||||
"chatplus/store/model"
|
||||
"chatplus/utils"
|
||||
"chatplus/utils/resp"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/shirou/gopsutil/host"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ConfigHandler struct {
|
||||
handler.BaseHandler
|
||||
levelDB *store.LevelDB
|
||||
licenseService *service.LicenseService
|
||||
}
|
||||
|
||||
func NewConfigHandler(app *core.AppServer, db *gorm.DB) *ConfigHandler {
|
||||
return &ConfigHandler{BaseHandler: handler.BaseHandler{App: app, DB: db}}
|
||||
func NewConfigHandler(app *core.AppServer, db *gorm.DB, levelDB *store.LevelDB, licenseService *service.LicenseService) *ConfigHandler {
|
||||
return &ConfigHandler{BaseHandler: handler.BaseHandler{App: app, DB: db}, levelDB: levelDB, licenseService: licenseService}
|
||||
}
|
||||
|
||||
func (h *ConfigHandler) Update(c *gin.Context) {
|
||||
@@ -87,3 +91,27 @@ 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)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"chatplus/core/types"
|
||||
"chatplus/handler"
|
||||
logger2 "chatplus/logger"
|
||||
"chatplus/service"
|
||||
"chatplus/service/oss"
|
||||
"chatplus/store/model"
|
||||
"chatplus/store/vo"
|
||||
@@ -35,15 +36,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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,6 +481,15 @@ func (h *ChatHandler) doRequest(ctx context.Context, req types.ApiRequest, sessi
|
||||
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 {
|
||||
err := h.licenseService.IsValidApiURL(apiKey.ApiURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var apiURL string
|
||||
switch session.Model.Platform {
|
||||
case types.Azure:
|
||||
|
||||
@@ -34,22 +34,16 @@ func (h *ChatHandler) sendOpenAiMessage(
|
||||
response, err := h.doRequest(ctx, req, session, &apiKey)
|
||||
logger.Info("HTTP请求完成,耗时:", time.Now().Sub(start))
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
if strings.Contains(err.Error(), "context canceled") {
|
||||
logger.Info("用户取消了请求:", prompt)
|
||||
return nil
|
||||
} else if strings.Contains(err.Error(), "no available key") {
|
||||
utils.ReplyMessage(ws, "抱歉😔😔😔,系统已经没有可用的 API KEY,请联系管理员!")
|
||||
return nil
|
||||
} else {
|
||||
logger.Error(err)
|
||||
}
|
||||
|
||||
utils.ReplyMessage(ws, ErrorMsg)
|
||||
utils.ReplyMessage(ws, ErrImg)
|
||||
if response.Body != nil {
|
||||
all, _ := io.ReadAll(response.Body)
|
||||
logger.Error(string(all))
|
||||
}
|
||||
utils.ReplyMessage(ws, err.Error())
|
||||
return err
|
||||
} else {
|
||||
defer response.Body.Close()
|
||||
@@ -80,6 +74,10 @@ func (h *ChatHandler) sendOpenAiMessage(
|
||||
utils.ReplyMessage(ws, ErrImg)
|
||||
break
|
||||
}
|
||||
if responseBody.Choices[0].FinishReason == "stop" && len(contents) == 0 {
|
||||
utils.ReplyMessage(ws, "抱歉😔😔😔,AI助手由于未知原因已经停止输出内容。")
|
||||
break
|
||||
}
|
||||
|
||||
var tool types.ToolCall
|
||||
if len(responseBody.Choices[0].Delta.ToolCalls) > 0 {
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
type FunctionHandler struct {
|
||||
BaseHandler
|
||||
config types.ChatPlusApiConfig
|
||||
config types.ApiConfig
|
||||
uploadManager *oss.UploaderManager
|
||||
dallService *dalle.Service
|
||||
}
|
||||
|
||||
@@ -260,9 +260,10 @@ func (h *SdJobHandler) getData(finish bool, userId uint, page int, pageSize int,
|
||||
|
||||
if item.Progress < 100 {
|
||||
// 从 leveldb 中获取图片预览数据
|
||||
imageData, err := h.leveldb.Get(item.TaskId)
|
||||
var imageData string
|
||||
err = h.leveldb.Get(item.TaskId, &imageData)
|
||||
if err == nil {
|
||||
job.ImgURL = "data:image/png;base64," + string(imageData)
|
||||
job.ImgURL = "data:image/png;base64," + imageData
|
||||
}
|
||||
}
|
||||
jobs = append(jobs, job)
|
||||
|
||||
13
api/main.go
13
api/main.go
@@ -44,13 +44,13 @@ type AppLifecycle struct {
|
||||
|
||||
// OnStart 应用程序启动时执行
|
||||
func (l *AppLifecycle) OnStart(context.Context) error {
|
||||
log.Println("AppLifecycle OnStart")
|
||||
logger.Info("AppLifecycle OnStart")
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnStop 应用程序停止时执行
|
||||
func (l *AppLifecycle) OnStop(context.Context) error {
|
||||
log.Println("AppLifecycle OnStop")
|
||||
logger.Info("AppLifecycle OnStop")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -164,6 +164,8 @@ func main() {
|
||||
|
||||
// 邮件服务
|
||||
fx.Provide(service.NewSmtpService),
|
||||
// License 服务
|
||||
fx.Provide(service.NewLicenseService),
|
||||
|
||||
// 微信机器人服务
|
||||
fx.Provide(wx.NewWeChatBot),
|
||||
@@ -285,9 +287,10 @@ func main() {
|
||||
|
||||
// 管理后台控制器
|
||||
fx.Invoke(func(s *core.AppServer, h *admin.ConfigHandler) {
|
||||
group := s.Engine.Group("/api/admin/config/")
|
||||
group.POST("update", h.Update)
|
||||
group.GET("get", h.Get)
|
||||
group := s.Engine.Group("/api/admin/")
|
||||
group.POST("config/update", h.Update)
|
||||
group.GET("config/get", h.Get)
|
||||
group.POST("active", h.Active)
|
||||
}),
|
||||
fx.Invoke(func(s *core.AppServer, h *admin.ManagerHandler) {
|
||||
group := s.Engine.Group("/api/admin/")
|
||||
|
||||
@@ -9,11 +9,11 @@ import (
|
||||
)
|
||||
|
||||
type CaptchaService struct {
|
||||
config types.ChatPlusApiConfig
|
||||
config types.ApiConfig
|
||||
client *req.Client
|
||||
}
|
||||
|
||||
func NewCaptchaService(config types.ChatPlusApiConfig) *CaptchaService {
|
||||
func NewCaptchaService(config types.ApiConfig) *CaptchaService {
|
||||
return &CaptchaService{
|
||||
config: config,
|
||||
client: req.C().SetTimeout(10 * time.Second),
|
||||
|
||||
108
api/service/license_service.go
Normal file
108
api/service/license_service.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"chatplus/core"
|
||||
"chatplus/core/types"
|
||||
"chatplus/store"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/imroc/req/v3"
|
||||
"github.com/shirou/gopsutil/host"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type LicenseService struct {
|
||||
config types.ApiConfig
|
||||
levelDB *store.LevelDB
|
||||
license types.License
|
||||
machineId string
|
||||
}
|
||||
|
||||
func NewLicenseService(server *core.AppServer, levelDB *store.LevelDB) * LicenseService {
|
||||
var license types.License
|
||||
var machineId string
|
||||
_ = levelDB.Get(types.LicenseKey, &license)
|
||||
info, err := host.Info()
|
||||
if err == nil {
|
||||
machineId = info.HostID
|
||||
}
|
||||
return &LicenseService{
|
||||
config: server.Config.ApiConfig,
|
||||
levelDB: levelDB,
|
||||
license: license,
|
||||
machineId: machineId,
|
||||
}
|
||||
}
|
||||
|
||||
// ActiveLicense 激活 License
|
||||
func (s *LicenseService) ActiveLicense(license string, machineId string) error {
|
||||
var res struct {
|
||||
Code types.BizCode `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
Name string `json:"name"`
|
||||
License string `json:"license"`
|
||||
Mid string `json:"mid"`
|
||||
ExpiredAt int64 `json:"expired_at"`
|
||||
UserNum int `json:"user_num"`
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
err = s.levelDB.Put(types.LicenseKey, types.License{
|
||||
Key: license,
|
||||
MachineId: machineId,
|
||||
UserNum: res.Data.UserNum,
|
||||
ExpiredAt: res.Data.ExpiredAt,
|
||||
IsActive: true,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("保存许可证书失败:%v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLicense 获取许可信息
|
||||
func (s *LicenseService) GetLicense() types.License {
|
||||
return s.license
|
||||
}
|
||||
|
||||
// IsValidApiURL 判断是否合法的中转 URL
|
||||
func (s *LicenseService) IsValidApiURL(uri string) error {
|
||||
// 获得许可授权的直接放行
|
||||
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 !strings.HasPrefix(uri, "https://gpt.bemore.lol") &&
|
||||
!strings.HasPrefix(uri, "https://api.openai.com") &&
|
||||
!strings.HasPrefix(uri, "http://cdn.chat-plus.net") &&
|
||||
!strings.HasPrefix(uri, "https://api.chat-plus.net") {
|
||||
return fmt.Errorf("当前 API 地址 %s 不在白名单列表当中。",uri)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package mj
|
||||
import (
|
||||
"chatplus/core/types"
|
||||
logger2 "chatplus/logger"
|
||||
"chatplus/service"
|
||||
"chatplus/service/oss"
|
||||
"chatplus/service/sd"
|
||||
"chatplus/store"
|
||||
@@ -26,7 +27,7 @@ type ServicePool struct {
|
||||
|
||||
var logger = logger2.GetLogger()
|
||||
|
||||
func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderManager, appConfig *types.AppConfig) *ServicePool {
|
||||
func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderManager, appConfig *types.AppConfig, licenseService *service.LicenseService) *ServicePool {
|
||||
services := make([]*Service, 0)
|
||||
taskQueue := store.NewRedisQueue("MidJourney_Task_Queue", redisCli)
|
||||
notifyQueue := store.NewRedisQueue("MidJourney_Notify_Queue", redisCli)
|
||||
@@ -35,13 +36,19 @@ func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderMa
|
||||
if config.Enabled == false {
|
||||
continue
|
||||
}
|
||||
err := licenseService.IsValidApiURL(config.ApiURL)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
cli := NewPlusClient(config)
|
||||
name := fmt.Sprintf("mj-plus-service-%d", k)
|
||||
service := NewService(name, taskQueue, notifyQueue, db, cli)
|
||||
plusService := NewService(name, taskQueue, notifyQueue, db, cli)
|
||||
go func() {
|
||||
service.Run()
|
||||
plusService.Run()
|
||||
}()
|
||||
services = append(services, service)
|
||||
services = append(services, plusService)
|
||||
}
|
||||
|
||||
for k, config := range appConfig.MjProxyConfigs {
|
||||
@@ -50,11 +57,11 @@ func NewServicePool(db *gorm.DB, redisCli *redis.Client, manager *oss.UploaderMa
|
||||
}
|
||||
cli := NewProxyClient(config)
|
||||
name := fmt.Sprintf("mj-proxy-service-%d", k)
|
||||
service := NewService(name, taskQueue, notifyQueue, db, cli)
|
||||
proxyService := NewService(name, taskQueue, notifyQueue, db, cli)
|
||||
go func() {
|
||||
service.Run()
|
||||
proxyService.Run()
|
||||
}()
|
||||
services = append(services, service)
|
||||
services = append(services, proxyService)
|
||||
}
|
||||
|
||||
return &ServicePool{
|
||||
|
||||
@@ -35,13 +35,12 @@ func (db *LevelDB) Put(key string, value interface{}) error {
|
||||
return db.driver.Put([]byte(key), byteData, nil)
|
||||
}
|
||||
|
||||
func (db *LevelDB) Get(key string) ([]byte, error) {
|
||||
func (db *LevelDB) Get(key string, dist interface{}) error {
|
||||
bytes, err := db.driver.Get([]byte(key), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
return bytes, nil
|
||||
return json.Unmarshal(bytes, dist)
|
||||
}
|
||||
|
||||
func (db *LevelDB) Search(prefix string) []string {
|
||||
|
||||
@@ -83,4 +83,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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user