Compare commits

...

8 Commits

Author SHA1 Message Date
JustSong
c134604cee fix: use channel type to determine api type (close #321) 2023-07-24 23:34:14 +08:00
mrhaoji
929e43ef81 fix: baseURL not working in APITypePaLM (#317)
* fix: baseURL not working in APITypePaLM

* chore: use the same logic as claude

---------

Co-authored-by: JustSong <songquanpeng@foxmail.com>
2023-07-24 22:37:57 +08:00
mrhaoji
dce8bbe1ca fix: relay router typo for List models (#320)
via: https://platform.openai.com/docs/api-reference/models/list
2023-07-24 22:28:16 +08:00
JustSong
bc2f48b1f2 chore: send a notice to user indicating that the current channel type does not support testing 2023-07-23 23:23:56 +08:00
JustSong
889af8b2db fix: fix redemption can be used multiple times in some cases 2023-07-23 19:34:23 +08:00
JustSong
4eea096654 chore: do not hardcode cache time (close #302) 2023-07-23 19:26:37 +08:00
JustSong
4ab3211c0e fix: fix blank screen after refresh 2023-07-23 17:59:30 +08:00
JustSong
3da119efba perf: reuse http client to reduce delay 2023-07-23 15:18:58 +08:00
11 changed files with 46 additions and 28 deletions

View File

@@ -77,6 +77,8 @@ var IsMasterNode = os.Getenv("NODE_TYPE") != "slave"
var requestInterval, _ = strconv.Atoi(os.Getenv("POLLING_INTERVAL"))
var RequestInterval = time.Duration(requestInterval) * time.Second
var SyncFrequency = 10 * 60 // unit is second, will be overwritten by SYNC_FREQUENCY
const (
RoleGuestUser = 0
RoleCommonUser = 1

View File

@@ -85,7 +85,6 @@ func GetAuthHeader(token string) http.Header {
}
func GetResponseBody(method, url string, channel *model.Channel, headers http.Header) ([]byte, error) {
client := &http.Client{}
req, err := http.NewRequest(method, url, nil)
if err != nil {
return nil, err
@@ -93,7 +92,7 @@ func GetResponseBody(method, url string, channel *model.Channel, headers http.He
for k := range headers {
req.Header.Add(k, headers.Get(k))
}
res, err := client.Do(req)
res, err := httpClient.Do(req)
if err != nil {
return nil, err
}

View File

@@ -16,6 +16,14 @@ import (
func testChannel(channel *model.Channel, request ChatRequest) (error, *OpenAIError) {
switch channel.Type {
case common.ChannelTypePaLM:
fallthrough
case common.ChannelTypeAnthropic:
fallthrough
case common.ChannelTypeBaidu:
fallthrough
case common.ChannelTypeZhipu:
return errors.New("该渠道类型当前版本不支持测试,请手动测试"), nil
case common.ChannelTypeAzure:
request.Model = "gpt-35-turbo"
default:
@@ -45,8 +53,7 @@ func testChannel(channel *model.Channel, request ChatRequest) (error, *OpenAIErr
req.Header.Set("Authorization", "Bearer "+channel.Key)
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
resp, err := httpClient.Do(req)
if err != nil {
return err, nil
}

View File

@@ -109,8 +109,7 @@ func relayImageHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode
req.Header.Set("Content-Type", c.Request.Header.Get("Content-Type"))
req.Header.Set("Accept", c.Request.Header.Get("Accept"))
client := &http.Client{}
resp, err := client.Do(req)
resp, err := httpClient.Do(req)
if err != nil {
return errorWrapper(err, "do_request_failed", http.StatusInternalServerError)
}

View File

@@ -115,7 +115,7 @@ func openaiHandler(c *gin.Context, resp *http.Response, consumeQuota bool) (*Ope
}
// We shouldn't set the header before we parse the response body, because the parse part may fail.
// And then we will have to send an error response, but in this case, the header has already been set.
// So the client will be confused by the response.
// So the httpClient will be confused by the response.
// For example, Postman will report error, and we cannot check the response at all.
for k, v := range resp.Header {
c.Writer.Header().Set(k, v[0])

View File

@@ -22,6 +22,12 @@ const (
APITypeZhipu
)
var httpClient *http.Client
func init() {
httpClient = &http.Client{}
}
func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
channelType := c.GetInt("channel")
tokenId := c.GetInt("token_id")
@@ -79,13 +85,14 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
}
}
apiType := APITypeOpenAI
if strings.HasPrefix(textRequest.Model, "claude") {
switch channelType {
case common.ChannelTypeAnthropic:
apiType = APITypeClaude
} else if strings.HasPrefix(textRequest.Model, "ERNIE") {
case common.ChannelTypeBaidu:
apiType = APITypeBaidu
} else if strings.HasPrefix(textRequest.Model, "PaLM") {
case common.ChannelTypePaLM:
apiType = APITypePaLM
} else if strings.HasPrefix(textRequest.Model, "chatglm_") {
case common.ChannelTypeZhipu:
apiType = APITypeZhipu
}
baseURL := common.ChannelBaseURLs[channelType]
@@ -134,6 +141,9 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
fullRequestURL += "?access_token=" + apiKey // TODO: access token expire in 30 days
case APITypePaLM:
fullRequestURL = "https://generativelanguage.googleapis.com/v1beta2/models/chat-bison-001:generateMessage"
if baseURL != "" {
fullRequestURL = fmt.Sprintf("%s/v1beta2/models/chat-bison-001:generateMessage", baseURL)
}
apiKey := c.Request.Header.Get("Authorization")
apiKey = strings.TrimPrefix(apiKey, "Bearer ")
fullRequestURL += "?key=" + apiKey
@@ -244,8 +254,7 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
req.Header.Set("Content-Type", c.Request.Header.Get("Content-Type"))
req.Header.Set("Accept", c.Request.Header.Get("Accept"))
//req.Header.Set("Connection", c.Request.Header.Get("Connection"))
client := &http.Client{}
resp, err := client.Do(req)
resp, err := httpClient.Do(req)
if err != nil {
return errorWrapper(err, "do_request_failed", http.StatusInternalServerError)
}

View File

@@ -54,6 +54,7 @@ func main() {
if err != nil {
common.FatalLog("failed to parse SYNC_FREQUENCY: " + err.Error())
}
common.SyncFrequency = frequency
go model.SyncOptions(frequency)
if common.RedisEnabled {
go model.SyncChannelCache(frequency)

View File

@@ -12,11 +12,11 @@ import (
"time"
)
const (
TokenCacheSeconds = 60 * 60
UserId2GroupCacheSeconds = 60 * 60
UserId2QuotaCacheSeconds = 10 * 60
UserId2StatusCacheSeconds = 60 * 60
var (
TokenCacheSeconds = common.SyncFrequency
UserId2GroupCacheSeconds = common.SyncFrequency
UserId2QuotaCacheSeconds = common.SyncFrequency
UserId2StatusCacheSeconds = common.SyncFrequency
)
func CacheGetTokenByKey(key string) (*Token, error) {
@@ -35,7 +35,7 @@ func CacheGetTokenByKey(key string) (*Token, error) {
if err != nil {
return nil, err
}
err = common.RedisSet(fmt.Sprintf("token:%s", key), string(jsonBytes), TokenCacheSeconds*time.Second)
err = common.RedisSet(fmt.Sprintf("token:%s", key), string(jsonBytes), time.Duration(TokenCacheSeconds)*time.Second)
if err != nil {
common.SysError("Redis set token error: " + err.Error())
}
@@ -55,7 +55,7 @@ func CacheGetUserGroup(id int) (group string, err error) {
if err != nil {
return "", err
}
err = common.RedisSet(fmt.Sprintf("user_group:%d", id), group, UserId2GroupCacheSeconds*time.Second)
err = common.RedisSet(fmt.Sprintf("user_group:%d", id), group, time.Duration(UserId2GroupCacheSeconds)*time.Second)
if err != nil {
common.SysError("Redis set user group error: " + err.Error())
}
@@ -73,7 +73,7 @@ func CacheGetUserQuota(id int) (quota int, err error) {
if err != nil {
return 0, err
}
err = common.RedisSet(fmt.Sprintf("user_quota:%d", id), fmt.Sprintf("%d", quota), UserId2QuotaCacheSeconds*time.Second)
err = common.RedisSet(fmt.Sprintf("user_quota:%d", id), fmt.Sprintf("%d", quota), time.Duration(UserId2QuotaCacheSeconds)*time.Second)
if err != nil {
common.SysError("Redis set user quota error: " + err.Error())
}
@@ -91,7 +91,7 @@ func CacheUpdateUserQuota(id int) error {
if err != nil {
return err
}
err = common.RedisSet(fmt.Sprintf("user_quota:%d", id), fmt.Sprintf("%d", quota), UserId2QuotaCacheSeconds*time.Second)
err = common.RedisSet(fmt.Sprintf("user_quota:%d", id), fmt.Sprintf("%d", quota), time.Duration(UserId2QuotaCacheSeconds)*time.Second)
return err
}
@@ -106,7 +106,7 @@ func CacheIsUserEnabled(userId int) bool {
status = common.UserStatusEnabled
}
enabled = fmt.Sprintf("%d", status)
err = common.RedisSet(fmt.Sprintf("user_enabled:%d", userId), enabled, UserId2StatusCacheSeconds*time.Second)
err = common.RedisSet(fmt.Sprintf("user_enabled:%d", userId), enabled, time.Duration(UserId2StatusCacheSeconds)*time.Second)
if err != nil {
common.SysError("Redis set user enabled error: " + err.Error())
}

View File

@@ -51,20 +51,21 @@ func Redeem(key string, userId int) (quota int, err error) {
redemption := &Redemption{}
err = DB.Transaction(func(tx *gorm.DB) error {
err := DB.Where("`key` = ?", key).First(redemption).Error
err := tx.Set("gorm:query_option", "FOR UPDATE").Where("`key` = ?", key).First(redemption).Error
if err != nil {
return errors.New("无效的兑换码")
}
if redemption.Status != common.RedemptionCodeStatusEnabled {
return errors.New("该兑换码已被使用")
}
err = DB.Model(&User{}).Where("id = ?", userId).Update("quota", gorm.Expr("quota + ?", redemption.Quota)).Error
err = tx.Model(&User{}).Where("id = ?", userId).Update("quota", gorm.Expr("quota + ?", redemption.Quota)).Error
if err != nil {
return err
}
redemption.RedeemedTime = common.GetTimestamp()
redemption.Status = common.RedemptionCodeStatusUsed
return redemption.SelectUpdate()
err = tx.Save(redemption).Error
return err
})
if err != nil {
return 0, errors.New("兑换失败," + err.Error())

View File

@@ -12,7 +12,7 @@ func SetRelayRouter(router *gin.Engine) {
modelsRouter := router.Group("/v1/models")
modelsRouter.Use(middleware.TokenAuth())
{
modelsRouter.GET("/", controller.ListModels)
modelsRouter.GET("", controller.ListModels)
modelsRouter.GET("/:model", controller.RetrieveModel)
}
relayV1Router := router.Group("/v1")

View File

@@ -288,7 +288,7 @@ const PersonalSetting = () => {
<Form size='large'>
<Form.Input
fluid
placeholder={`输入你的账户名 ${userState.user.username} 以确认删除`}
placeholder={`输入你的账户名 ${userState?.user?.username} 以确认删除`}
name='self_account_deletion_confirmation'
value={inputs.self_account_deletion_confirmation}
onChange={handleInputChange}