mirror of
				https://github.com/songquanpeng/one-api.git
				synced 2025-11-04 15:53:42 +08:00 
			
		
		
		
	Merge remote-tracking branch 'origin/upstream/main'
This commit is contained in:
		@@ -132,10 +132,10 @@ var ValidThemes = map[string]bool{
 | 
			
		||||
// All duration's unit is seconds
 | 
			
		||||
// Shouldn't larger then RateLimitKeyExpirationDuration
 | 
			
		||||
var (
 | 
			
		||||
	GlobalApiRateLimitNum            = env.Int("GLOBAL_API_RATE_LIMIT", 180)
 | 
			
		||||
	GlobalApiRateLimitNum            = env.Int("GLOBAL_API_RATE_LIMIT", 240)
 | 
			
		||||
	GlobalApiRateLimitDuration int64 = 3 * 60
 | 
			
		||||
 | 
			
		||||
	GlobalWebRateLimitNum            = env.Int("GLOBAL_WEB_RATE_LIMIT", 60)
 | 
			
		||||
	GlobalWebRateLimitNum            = env.Int("GLOBAL_WEB_RATE_LIMIT", 120)
 | 
			
		||||
	GlobalWebRateLimitDuration int64 = 3 * 60
 | 
			
		||||
 | 
			
		||||
	UploadRateLimitNum            = 10
 | 
			
		||||
 
 | 
			
		||||
@@ -43,11 +43,19 @@ func SysLog(s string) {
 | 
			
		||||
	_, _ = fmt.Fprintf(gin.DefaultWriter, "[SYS] %v | %s \n", t.Format("2006/01/02 - 15:04:05"), s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SysLogf(format string, a ...any) {
 | 
			
		||||
	SysLog(fmt.Sprintf(format, a...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SysError(s string) {
 | 
			
		||||
	t := time.Now()
 | 
			
		||||
	_, _ = fmt.Fprintf(gin.DefaultErrorWriter, "[SYS] %v | %s \n", t.Format("2006/01/02 - 15:04:05"), s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SysErrorf(format string, a ...any) {
 | 
			
		||||
	SysError(fmt.Sprintf(format, a...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Debug(ctx context.Context, msg string) {
 | 
			
		||||
	if config.DebugEnabled {
 | 
			
		||||
		logHelper(ctx, loggerDEBUG, msg)
 | 
			
		||||
 
 | 
			
		||||
@@ -12,8 +12,6 @@ import (
 | 
			
		||||
	"github.com/songquanpeng/one-api/common"
 | 
			
		||||
	"github.com/songquanpeng/one-api/common/config"
 | 
			
		||||
	"github.com/songquanpeng/one-api/common/ctxkey"
 | 
			
		||||
	"github.com/songquanpeng/one-api/common/helper"
 | 
			
		||||
	"github.com/songquanpeng/one-api/common/logger"
 | 
			
		||||
	"github.com/songquanpeng/one-api/common/random"
 | 
			
		||||
	"github.com/songquanpeng/one-api/model"
 | 
			
		||||
)
 | 
			
		||||
@@ -117,7 +115,6 @@ func Logout(c *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Register(c *gin.Context) {
 | 
			
		||||
	ctx := c.Request.Context()
 | 
			
		||||
	if !config.RegisterEnabled {
 | 
			
		||||
		c.JSON(http.StatusOK, gin.H{
 | 
			
		||||
			"message": "管理员关闭了新用户注册",
 | 
			
		||||
@@ -182,28 +179,6 @@ func Register(c *gin.Context) {
 | 
			
		||||
		})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	go func() {
 | 
			
		||||
		err := user.ValidateAndFill()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logger.Errorf(ctx, "user.ValidateAndFill failed: %v", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		cleanToken := model.Token{
 | 
			
		||||
			UserId:         user.Id,
 | 
			
		||||
			Name:           "default",
 | 
			
		||||
			Key:            random.GenerateKey(),
 | 
			
		||||
			CreatedTime:    helper.GetTimestamp(),
 | 
			
		||||
			AccessedTime:   helper.GetTimestamp(),
 | 
			
		||||
			ExpiredTime:    -1,
 | 
			
		||||
			RemainQuota:    -1,
 | 
			
		||||
			UnlimitedQuota: true,
 | 
			
		||||
		}
 | 
			
		||||
		err = cleanToken.Insert()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logger.Errorf(ctx, "cleanToken.Insert failed: %v", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	c.JSON(http.StatusOK, gin.H{
 | 
			
		||||
		"success": true,
 | 
			
		||||
		"message": "",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.go
									
									
									
									
									
								
							@@ -26,7 +26,7 @@ var buildFS embed.FS
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	logger.SetupLogger()
 | 
			
		||||
	logger.SysLog(fmt.Sprintf("One API %s started", common.Version))
 | 
			
		||||
	logger.SysLogf("One API %s started", common.Version)
 | 
			
		||||
	if os.Getenv("GIN_MODE") != "debug" {
 | 
			
		||||
		gin.SetMode(gin.ReleaseMode)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -91,26 +91,28 @@ func SetupContextForSelectedChannel(c *gin.Context, channel *model.Channel, mode
 | 
			
		||||
	c.Set(ctxkey.BaseURL, channel.GetBaseURL())
 | 
			
		||||
	cfg, _ := channel.LoadConfig()
 | 
			
		||||
	// this is for backward compatibility
 | 
			
		||||
	switch channel.Type {
 | 
			
		||||
	case channeltype.Azure:
 | 
			
		||||
		if cfg.APIVersion == "" {
 | 
			
		||||
			cfg.APIVersion = channel.Other
 | 
			
		||||
		}
 | 
			
		||||
	case channeltype.Xunfei:
 | 
			
		||||
		if cfg.APIVersion == "" {
 | 
			
		||||
			cfg.APIVersion = channel.Other
 | 
			
		||||
		}
 | 
			
		||||
	case channeltype.Gemini:
 | 
			
		||||
		if cfg.APIVersion == "" {
 | 
			
		||||
			cfg.APIVersion = channel.Other
 | 
			
		||||
		}
 | 
			
		||||
	case channeltype.AIProxyLibrary:
 | 
			
		||||
		if cfg.LibraryID == "" {
 | 
			
		||||
			cfg.LibraryID = channel.Other
 | 
			
		||||
		}
 | 
			
		||||
	case channeltype.Ali:
 | 
			
		||||
		if cfg.Plugin == "" {
 | 
			
		||||
			cfg.Plugin = channel.Other
 | 
			
		||||
	if channel.Other != nil {
 | 
			
		||||
		switch channel.Type {
 | 
			
		||||
		case channeltype.Azure:
 | 
			
		||||
			if cfg.APIVersion == "" {
 | 
			
		||||
				cfg.APIVersion = *channel.Other
 | 
			
		||||
			}
 | 
			
		||||
		case channeltype.Xunfei:
 | 
			
		||||
			if cfg.APIVersion == "" {
 | 
			
		||||
				cfg.APIVersion = *channel.Other
 | 
			
		||||
			}
 | 
			
		||||
		case channeltype.Gemini:
 | 
			
		||||
			if cfg.APIVersion == "" {
 | 
			
		||||
				cfg.APIVersion = *channel.Other
 | 
			
		||||
			}
 | 
			
		||||
		case channeltype.AIProxyLibrary:
 | 
			
		||||
			if cfg.LibraryID == "" {
 | 
			
		||||
				cfg.LibraryID = *channel.Other
 | 
			
		||||
			}
 | 
			
		||||
		case channeltype.Ali:
 | 
			
		||||
			if cfg.Plugin == "" {
 | 
			
		||||
				cfg.Plugin = *channel.Other
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	c.Set(ctxkey.Config, cfg)
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ type Channel struct {
 | 
			
		||||
	TestTime           int64   `json:"test_time" gorm:"bigint"`
 | 
			
		||||
	ResponseTime       int     `json:"response_time"` // in milliseconds
 | 
			
		||||
	BaseURL            *string `json:"base_url" gorm:"column:base_url;default:''"`
 | 
			
		||||
	Other              string  `json:"other"`   // DEPRECATED: please save config to field Config
 | 
			
		||||
	Other              *string `json:"other"`   // DEPRECATED: please save config to field Config
 | 
			
		||||
	Balance            float64 `json:"balance"` // in USD
 | 
			
		||||
	BalanceUpdatedTime int64   `json:"balance_updated_time" gorm:"bigint"`
 | 
			
		||||
	Models             string  `json:"models"`
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"github.com/songquanpeng/one-api/common"
 | 
			
		||||
	"github.com/songquanpeng/one-api/common/blacklist"
 | 
			
		||||
	"github.com/songquanpeng/one-api/common/config"
 | 
			
		||||
	"github.com/songquanpeng/one-api/common/helper"
 | 
			
		||||
	"github.com/songquanpeng/one-api/common/logger"
 | 
			
		||||
	"github.com/songquanpeng/one-api/common/random"
 | 
			
		||||
	"gorm.io/gorm"
 | 
			
		||||
@@ -141,6 +142,22 @@ func (user *User) Insert(inviterId int) error {
 | 
			
		||||
			RecordLog(inviterId, LogTypeSystem, fmt.Sprintf("邀请用户赠送 %s", common.LogQuota(config.QuotaForInviter)))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// create default token
 | 
			
		||||
	cleanToken := Token{
 | 
			
		||||
		UserId:         user.Id,
 | 
			
		||||
		Name:           "default",
 | 
			
		||||
		Key:            random.GenerateKey(),
 | 
			
		||||
		CreatedTime:    helper.GetTimestamp(),
 | 
			
		||||
		AccessedTime:   helper.GetTimestamp(),
 | 
			
		||||
		ExpiredTime:    -1,
 | 
			
		||||
		RemainQuota:    -1,
 | 
			
		||||
		UnlimitedQuota: true,
 | 
			
		||||
	}
 | 
			
		||||
	result.Error = cleanToken.Insert()
 | 
			
		||||
	if result.Error != nil {
 | 
			
		||||
		// do not block
 | 
			
		||||
		logger.SysError(fmt.Sprintf("create default token for user %d failed: %s", user.Id, result.Error.Error()))
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -244,8 +244,10 @@ func responseGeminiChat2OpenAI(response *ChatResponse) *openai.TextResponse {
 | 
			
		||||
func streamResponseGeminiChat2OpenAI(geminiResponse *ChatResponse) *openai.ChatCompletionsStreamResponse {
 | 
			
		||||
	var choice openai.ChatCompletionsStreamResponseChoice
 | 
			
		||||
	choice.Delta.Content = geminiResponse.GetResponseText()
 | 
			
		||||
	choice.FinishReason = &constant.StopFinishReason
 | 
			
		||||
	//choice.FinishReason = &constant.StopFinishReason
 | 
			
		||||
	var response openai.ChatCompletionsStreamResponse
 | 
			
		||||
	response.Id = fmt.Sprintf("chatcmpl-%s", random.GetUUID())
 | 
			
		||||
	response.Created = helper.GetTimestamp()
 | 
			
		||||
	response.Object = "chat.completion.chunk"
 | 
			
		||||
	response.Model = "gemini"
 | 
			
		||||
	response.Choices = []openai.ChatCompletionsStreamResponseChoice{choice}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,14 +28,6 @@ func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
 | 
			
		||||
 | 
			
		||||
func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error {
 | 
			
		||||
	adaptor.SetupCommonRequestHeader(c, req, meta)
 | 
			
		||||
	version := parseAPIVersionByModelName(meta.ActualModelName)
 | 
			
		||||
	if version == "" {
 | 
			
		||||
		version = a.meta.Config.APIVersion
 | 
			
		||||
	}
 | 
			
		||||
	if version == "" {
 | 
			
		||||
		version = "v1.1"
 | 
			
		||||
	}
 | 
			
		||||
	a.meta.Config.APIVersion = version
 | 
			
		||||
	// check DoResponse for auth part
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -70,6 +62,14 @@ func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Met
 | 
			
		||||
	if a.request == nil {
 | 
			
		||||
		return nil, openai.ErrorWrapper(errors.New("request is nil"), "request_is_nil", http.StatusBadRequest)
 | 
			
		||||
	}
 | 
			
		||||
	version := parseAPIVersionByModelName(meta.ActualModelName)
 | 
			
		||||
	if version == "" {
 | 
			
		||||
		version = a.meta.Config.APIVersion
 | 
			
		||||
	}
 | 
			
		||||
	if version == "" {
 | 
			
		||||
		version = "v1.1"
 | 
			
		||||
	}
 | 
			
		||||
	a.meta.Config.APIVersion = version
 | 
			
		||||
	if meta.IsStream {
 | 
			
		||||
		err, usage = StreamHandler(c, meta, *a.request, splits[0], splits[1], splits[2])
 | 
			
		||||
	} else {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import (
 | 
			
		||||
	"crypto/sha256"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
@@ -29,11 +30,7 @@ import (
 | 
			
		||||
 | 
			
		||||
func requestOpenAI2Xunfei(request model.GeneralOpenAIRequest, xunfeiAppId string, domain string) *ChatRequest {
 | 
			
		||||
	messages := make([]Message, 0, len(request.Messages))
 | 
			
		||||
	var lastToolCalls []model.Tool
 | 
			
		||||
	for _, message := range request.Messages {
 | 
			
		||||
		if message.ToolCalls != nil {
 | 
			
		||||
			lastToolCalls = message.ToolCalls
 | 
			
		||||
		}
 | 
			
		||||
		messages = append(messages, Message{
 | 
			
		||||
			Role:    message.Role,
 | 
			
		||||
			Content: message.StringContent(),
 | 
			
		||||
@@ -46,9 +43,10 @@ func requestOpenAI2Xunfei(request model.GeneralOpenAIRequest, xunfeiAppId string
 | 
			
		||||
	xunfeiRequest.Parameter.Chat.TopK = request.N
 | 
			
		||||
	xunfeiRequest.Parameter.Chat.MaxTokens = request.MaxTokens
 | 
			
		||||
	xunfeiRequest.Payload.Message.Text = messages
 | 
			
		||||
	if len(lastToolCalls) != 0 {
 | 
			
		||||
		for _, toolCall := range lastToolCalls {
 | 
			
		||||
			xunfeiRequest.Payload.Functions.Text = append(xunfeiRequest.Payload.Functions.Text, toolCall.Function)
 | 
			
		||||
 | 
			
		||||
	if strings.HasPrefix(domain, "generalv3") {
 | 
			
		||||
		xunfeiRequest.Payload.Functions = &Functions{
 | 
			
		||||
			Text: request.Tools,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -204,7 +202,7 @@ func Handler(c *gin.Context, meta *meta.Meta, textRequest model.GeneralOpenAIReq
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(xunfeiResponse.Payload.Choices.Text) == 0 {
 | 
			
		||||
		return openai.ErrorWrapper(err, "xunfei_empty_response_detected", http.StatusInternalServerError), nil
 | 
			
		||||
		return openai.ErrorWrapper(errors.New("xunfei empty response detected"), "xunfei_empty_response_detected", http.StatusInternalServerError), nil
 | 
			
		||||
	}
 | 
			
		||||
	xunfeiResponse.Payload.Choices.Text[0].Content = content
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,10 @@ type Message struct {
 | 
			
		||||
	Content string `json:"content"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Functions struct {
 | 
			
		||||
	Text []model.Tool `json:"text,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ChatRequest struct {
 | 
			
		||||
	Header struct {
 | 
			
		||||
		AppId string `json:"app_id"`
 | 
			
		||||
@@ -26,9 +30,7 @@ type ChatRequest struct {
 | 
			
		||||
		Message struct {
 | 
			
		||||
			Text []Message `json:"text"`
 | 
			
		||||
		} `json:"message"`
 | 
			
		||||
		Functions struct {
 | 
			
		||||
			Text []model.Function `json:"text,omitempty"`
 | 
			
		||||
		} `json:"functions,omitempty"`
 | 
			
		||||
		Functions *Functions `json:"functions,omitempty"`
 | 
			
		||||
	} `json:"payload"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -163,7 +163,7 @@ const EditModal = ({ open, channelId, onCancel, onOk }) => {
 | 
			
		||||
      values.other = 'v2.1';
 | 
			
		||||
    }
 | 
			
		||||
    if (values.key === '') {
 | 
			
		||||
      if (values.config.ak !== '' && values.config.sk !== '' && values.config.region !== '') {
 | 
			
		||||
      if (values.config.ak && values.config.sk && values.config.region) {
 | 
			
		||||
        values.key = `${values.config.ak}|${values.config.sk}|${values.config.region}`;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -181,9 +181,6 @@ const EditChannel = () => {
 | 
			
		||||
    if (localInputs.type === 3 && localInputs.other === '') {
 | 
			
		||||
      localInputs.other = '2024-03-01-preview';
 | 
			
		||||
    }
 | 
			
		||||
    if (localInputs.type === 18 && localInputs.other === '') {
 | 
			
		||||
      localInputs.other = 'v2.1';
 | 
			
		||||
    }
 | 
			
		||||
    let res;
 | 
			
		||||
    localInputs.models = localInputs.models.join(',');
 | 
			
		||||
    localInputs.group = localInputs.groups.join(',');
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user