mirror of
https://github.com/linux-do/new-api.git
synced 2025-09-21 01:36:37 +08:00
merge upstream
Signed-off-by: wozulong <>
This commit is contained in:
commit
918690701d
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,4 +5,5 @@ upload
|
|||||||
*.db
|
*.db
|
||||||
build
|
build
|
||||||
*.db-journal
|
*.db-journal
|
||||||
logs
|
logs
|
||||||
|
web/dist
|
32
common/email-outlook-auth.go
Normal file
32
common/email-outlook-auth.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/smtp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type outlookAuth struct {
|
||||||
|
username, password string
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoginAuth(username, password string) smtp.Auth {
|
||||||
|
return &outlookAuth{username, password}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *outlookAuth) Start(_ *smtp.ServerInfo) (string, []byte, error) {
|
||||||
|
return "LOGIN", []byte{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *outlookAuth) Next(fromServer []byte, more bool) ([]byte, error) {
|
||||||
|
if more {
|
||||||
|
switch string(fromServer) {
|
||||||
|
case "Username:":
|
||||||
|
return []byte(a.username), nil
|
||||||
|
case "Password:":
|
||||||
|
return []byte(a.password), nil
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unknown fromServer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
@ -62,6 +62,9 @@ func SendEmail(subject string, receiver string, content string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else if strings.HasSuffix(SMTPAccount, "outlook.com") {
|
||||||
|
auth = LoginAuth(SMTPAccount, SMTPToken)
|
||||||
|
err = smtp.SendMail(addr, auth, SMTPAccount, to, mail)
|
||||||
} else {
|
} else {
|
||||||
err = smtp.SendMail(addr, auth, SMTPAccount, to, mail)
|
err = smtp.SendMail(addr, auth, SMTPAccount, to, mail)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package common
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// from songquanpeng/one-api
|
// from songquanpeng/one-api
|
||||||
@ -183,8 +184,14 @@ var defaultModelPrice = map[string]float64{
|
|||||||
"swap_face": 0.05,
|
"swap_face": 0.05,
|
||||||
}
|
}
|
||||||
|
|
||||||
var modelPrice map[string]float64 = nil
|
var (
|
||||||
var modelRatio map[string]float64 = nil
|
modelPriceMap = make(map[string]float64)
|
||||||
|
modelPriceMapMutex = sync.RWMutex{}
|
||||||
|
)
|
||||||
|
var (
|
||||||
|
modelRatioMap map[string]float64 = nil
|
||||||
|
modelRatioMapMutex = sync.RWMutex{}
|
||||||
|
)
|
||||||
|
|
||||||
var CompletionRatio map[string]float64 = nil
|
var CompletionRatio map[string]float64 = nil
|
||||||
var defaultCompletionRatio = map[string]float64{
|
var defaultCompletionRatio = map[string]float64{
|
||||||
@ -194,11 +201,18 @@ var defaultCompletionRatio = map[string]float64{
|
|||||||
"gpt-4o-all": 2,
|
"gpt-4o-all": 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
func ModelPrice2JSONString() string {
|
func GetModelPriceMap() map[string]float64 {
|
||||||
if modelPrice == nil {
|
modelPriceMapMutex.Lock()
|
||||||
modelPrice = defaultModelPrice
|
defer modelPriceMapMutex.Unlock()
|
||||||
|
if modelPriceMap == nil {
|
||||||
|
modelPriceMap = defaultModelPrice
|
||||||
}
|
}
|
||||||
jsonBytes, err := json.Marshal(modelPrice)
|
return modelPriceMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func ModelPrice2JSONString() string {
|
||||||
|
GetModelPriceMap()
|
||||||
|
jsonBytes, err := json.Marshal(modelPriceMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
SysError("error marshalling model price: " + err.Error())
|
SysError("error marshalling model price: " + err.Error())
|
||||||
}
|
}
|
||||||
@ -206,21 +220,21 @@ func ModelPrice2JSONString() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdateModelPriceByJSONString(jsonStr string) error {
|
func UpdateModelPriceByJSONString(jsonStr string) error {
|
||||||
modelPrice = make(map[string]float64)
|
modelPriceMapMutex.Lock()
|
||||||
return json.Unmarshal([]byte(jsonStr), &modelPrice)
|
defer modelPriceMapMutex.Unlock()
|
||||||
|
modelPriceMap = make(map[string]float64)
|
||||||
|
return json.Unmarshal([]byte(jsonStr), &modelPriceMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetModelPrice 返回模型的价格,如果模型不存在则返回-1,false
|
// GetModelPrice 返回模型的价格,如果模型不存在则返回-1,false
|
||||||
func GetModelPrice(name string, printErr bool) (float64, bool) {
|
func GetModelPrice(name string, printErr bool) (float64, bool) {
|
||||||
if modelPrice == nil {
|
GetModelPriceMap()
|
||||||
modelPrice = defaultModelPrice
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(name, "gpt-4-gizmo") {
|
if strings.HasPrefix(name, "gpt-4-gizmo") {
|
||||||
name = "gpt-4-gizmo-*"
|
name = "gpt-4-gizmo-*"
|
||||||
} else if strings.HasPrefix(name, "g-") {
|
} else if strings.HasPrefix(name, "g-") {
|
||||||
name = "g-*"
|
name = "g-*"
|
||||||
}
|
}
|
||||||
price, ok := modelPrice[name]
|
price, ok := modelPriceMap[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
if printErr {
|
if printErr {
|
||||||
SysError("model price not found: " + name)
|
SysError("model price not found: " + name)
|
||||||
@ -230,18 +244,18 @@ func GetModelPrice(name string, printErr bool) (float64, bool) {
|
|||||||
return price, true
|
return price, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetModelPriceMap() map[string]float64 {
|
func GetModelRatioMap() map[string]float64 {
|
||||||
if modelPrice == nil {
|
modelRatioMapMutex.Lock()
|
||||||
modelPrice = defaultModelPrice
|
defer modelRatioMapMutex.Unlock()
|
||||||
|
if modelRatioMap == nil {
|
||||||
|
modelRatioMap = defaultModelRatio
|
||||||
}
|
}
|
||||||
return modelPrice
|
return modelRatioMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func ModelRatio2JSONString() string {
|
func ModelRatio2JSONString() string {
|
||||||
if modelRatio == nil {
|
GetModelRatioMap()
|
||||||
modelRatio = defaultModelRatio
|
jsonBytes, err := json.Marshal(modelRatioMap)
|
||||||
}
|
|
||||||
jsonBytes, err := json.Marshal(modelRatio)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
SysError("error marshalling model ratio: " + err.Error())
|
SysError("error marshalling model ratio: " + err.Error())
|
||||||
}
|
}
|
||||||
@ -249,20 +263,20 @@ func ModelRatio2JSONString() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UpdateModelRatioByJSONString(jsonStr string) error {
|
func UpdateModelRatioByJSONString(jsonStr string) error {
|
||||||
modelRatio = make(map[string]float64)
|
modelRatioMapMutex.Lock()
|
||||||
return json.Unmarshal([]byte(jsonStr), &modelRatio)
|
defer modelRatioMapMutex.Unlock()
|
||||||
|
modelRatioMap = make(map[string]float64)
|
||||||
|
return json.Unmarshal([]byte(jsonStr), &modelRatioMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetModelRatio(name string) float64 {
|
func GetModelRatio(name string) float64 {
|
||||||
if modelRatio == nil {
|
GetModelRatioMap()
|
||||||
modelRatio = defaultModelRatio
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(name, "gpt-4-gizmo") {
|
if strings.HasPrefix(name, "gpt-4-gizmo") {
|
||||||
name = "gpt-4-gizmo-*"
|
name = "gpt-4-gizmo-*"
|
||||||
} else if strings.HasPrefix(name, "g-") {
|
} else if strings.HasPrefix(name, "g-") {
|
||||||
name = "g-*"
|
name = "g-*"
|
||||||
}
|
}
|
||||||
ratio, ok := modelRatio[name]
|
ratio, ok := modelRatioMap[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
SysError("model ratio not found: " + name)
|
SysError("model ratio not found: " + name)
|
||||||
return 30
|
return 30
|
||||||
|
@ -43,12 +43,13 @@ func Relay(c *gin.Context) {
|
|||||||
requestId := c.GetString(common.RequestIdKey)
|
requestId := c.GetString(common.RequestIdKey)
|
||||||
channelId := c.GetInt("channel_id")
|
channelId := c.GetInt("channel_id")
|
||||||
channelType := c.GetInt("channel_type")
|
channelType := c.GetInt("channel_type")
|
||||||
|
channelName := c.GetString("channel_name")
|
||||||
group := c.GetString("group")
|
group := c.GetString("group")
|
||||||
originalModel := c.GetString("original_model")
|
originalModel := c.GetString("original_model")
|
||||||
openaiErr := relayHandler(c, relayMode)
|
openaiErr := relayHandler(c, relayMode)
|
||||||
c.Set("use_channel", []string{fmt.Sprintf("%d", channelId)})
|
c.Set("use_channel", []string{fmt.Sprintf("%d", channelId)})
|
||||||
if openaiErr != nil {
|
if openaiErr != nil {
|
||||||
go processChannelError(c, channelId, channelType, openaiErr)
|
go processChannelError(c, channelId, channelType, channelName, openaiErr)
|
||||||
} else {
|
} else {
|
||||||
retryTimes = 0
|
retryTimes = 0
|
||||||
}
|
}
|
||||||
@ -60,7 +61,7 @@ func Relay(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
channelId = channel.Id
|
channelId = channel.Id
|
||||||
useChannel := c.GetStringSlice("use_channel")
|
useChannel := c.GetStringSlice("use_channel")
|
||||||
useChannel = append(useChannel, fmt.Sprintf("%d", channelId))
|
useChannel = append(useChannel, fmt.Sprintf("%d", channel.Id))
|
||||||
c.Set("use_channel", useChannel)
|
c.Set("use_channel", useChannel)
|
||||||
common.LogInfo(c.Request.Context(), fmt.Sprintf("using channel #%d to retry (remain times %d)", channel.Id, i))
|
common.LogInfo(c.Request.Context(), fmt.Sprintf("using channel #%d to retry (remain times %d)", channel.Id, i))
|
||||||
middleware.SetupContextForSelectedChannel(c, channel, originalModel)
|
middleware.SetupContextForSelectedChannel(c, channel, originalModel)
|
||||||
@ -69,7 +70,7 @@ func Relay(c *gin.Context) {
|
|||||||
c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
|
c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
|
||||||
openaiErr = relayHandler(c, relayMode)
|
openaiErr = relayHandler(c, relayMode)
|
||||||
if openaiErr != nil {
|
if openaiErr != nil {
|
||||||
go processChannelError(c, channelId, channel.Type, openaiErr)
|
go processChannelError(c, channel.Id, channel.Type, channel.Name, openaiErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
useChannel := c.GetStringSlice("use_channel")
|
useChannel := c.GetStringSlice("use_channel")
|
||||||
@ -128,11 +129,10 @@ func shouldRetry(c *gin.Context, channelId int, openaiErr *dto.OpenAIErrorWithSt
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func processChannelError(c *gin.Context, channelId int, channelType int, err *dto.OpenAIErrorWithStatusCode) {
|
func processChannelError(c *gin.Context, channelId int, channelType int, channelName string, err *dto.OpenAIErrorWithStatusCode) {
|
||||||
autoBan := c.GetBool("auto_ban")
|
autoBan := c.GetBool("auto_ban")
|
||||||
common.LogError(c.Request.Context(), fmt.Sprintf("relay error (channel #%d, status code: %d): %s", channelId, err.StatusCode, err.Error.Message))
|
common.LogError(c.Request.Context(), fmt.Sprintf("relay error (channel #%d, status code: %d): %s", channelId, err.StatusCode, err.Error.Message))
|
||||||
if service.ShouldDisableChannel(channelType, err) && autoBan {
|
if service.ShouldDisableChannel(channelType, err) && autoBan {
|
||||||
channelName := c.GetString("channel_name")
|
|
||||||
service.DisableChannel(channelId, channelName, err.Error.Message)
|
service.DisableChannel(channelId, channelName, err.Error.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"one-api/common"
|
"one-api/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func abortWithOpenAiMessage(c *gin.Context, statusCode int, message string) {
|
func abortWithOpenAiMessage(c *gin.Context, statusCode int, message string) {
|
||||||
|
userId := c.GetInt("id")
|
||||||
c.JSON(statusCode, gin.H{
|
c.JSON(statusCode, gin.H{
|
||||||
"error": gin.H{
|
"error": gin.H{
|
||||||
"message": common.MessageWithRequestId(message, c.GetString(common.RequestIdKey)),
|
"message": common.MessageWithRequestId(message, c.GetString(common.RequestIdKey)),
|
||||||
@ -13,7 +15,7 @@ func abortWithOpenAiMessage(c *gin.Context, statusCode int, message string) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
c.Abort()
|
c.Abort()
|
||||||
common.LogError(c.Request.Context(), message)
|
common.LogError(c.Request.Context(), fmt.Sprintf("user %d | %s", userId, message))
|
||||||
}
|
}
|
||||||
|
|
||||||
func abortWithMidjourneyMessage(c *gin.Context, statusCode int, code int, description string) {
|
func abortWithMidjourneyMessage(c *gin.Context, statusCode int, code int, description string) {
|
||||||
|
@ -100,8 +100,8 @@ func SearchChannels(keyword string, group string, model string) ([]*Channel, err
|
|||||||
var whereClause string
|
var whereClause string
|
||||||
var args []interface{}
|
var args []interface{}
|
||||||
if group != "" {
|
if group != "" {
|
||||||
whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + groupCol + " LIKE ? AND " + modelsCol + " LIKE ?"
|
whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + groupCol + " = ? AND " + modelsCol + " LIKE ?"
|
||||||
args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, "%"+group+"%", "%"+model+"%")
|
args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, group, "%"+model+"%")
|
||||||
} else {
|
} else {
|
||||||
whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + modelsCol + " LIKE ?"
|
whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + modelsCol + " LIKE ?"
|
||||||
args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, "%"+model+"%")
|
args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, "%"+model+"%")
|
||||||
|
@ -222,9 +222,11 @@ func awsStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
service.Done(c)
|
service.Done(c)
|
||||||
err = resp.Body.Close()
|
if resp != nil {
|
||||||
if err != nil {
|
err = resp.Body.Close()
|
||||||
return service.OpenAIErrorWrapperLocal(err, "close_response_body_failed", http.StatusInternalServerError), nil
|
if err != nil {
|
||||||
|
return service.OpenAIErrorWrapperLocal(err, "close_response_body_failed", http.StatusInternalServerError), nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil, &usage
|
return nil, &usage
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cloudflare
|
package cloudflare
|
||||||
|
|
||||||
var ModelList = []string{
|
var ModelList = []string{
|
||||||
|
"@cf/meta/llama-3.1-8b-instruct",
|
||||||
"@cf/meta/llama-2-7b-chat-fp16",
|
"@cf/meta/llama-2-7b-chat-fp16",
|
||||||
"@cf/meta/llama-2-7b-chat-int8",
|
"@cf/meta/llama-2-7b-chat-int8",
|
||||||
"@cf/mistral/mistral-7b-instruct-v0.1",
|
"@cf/mistral/mistral-7b-instruct-v0.1",
|
||||||
|
@ -53,7 +53,7 @@ func streamResponseDify2OpenAI(difyResponse DifyChunkChatCompletionResponse) *dt
|
|||||||
choice.Delta.SetContentString("Workflow: " + difyResponse.Data.WorkflowId + "\n")
|
choice.Delta.SetContentString("Workflow: " + difyResponse.Data.WorkflowId + "\n")
|
||||||
} else if constant.DifyDebug && difyResponse.Event == "node_started" {
|
} else if constant.DifyDebug && difyResponse.Event == "node_started" {
|
||||||
choice.Delta.SetContentString("Node: " + difyResponse.Data.NodeId + "\n")
|
choice.Delta.SetContentString("Node: " + difyResponse.Data.NodeId + "\n")
|
||||||
} else if difyResponse.Event == "message" {
|
} else if difyResponse.Event == "message" || difyResponse.Event == "agent_message" {
|
||||||
choice.Delta.SetContentString(difyResponse.Answer)
|
choice.Delta.SetContentString(difyResponse.Answer)
|
||||||
}
|
}
|
||||||
response.Choices = append(response.Choices, choice)
|
response.Choices = append(response.Choices, choice)
|
||||||
|
@ -83,13 +83,28 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest) *GeminiChatReques
|
|||||||
if imageNum > GeminiVisionMaxImageNum {
|
if imageNum > GeminiVisionMaxImageNum {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mimeType, data, _ := common.GetImageFromUrl(part.ImageUrl.(dto.MessageImageUrl).Url)
|
// 判断是否是url
|
||||||
parts = append(parts, GeminiPart{
|
if strings.HasPrefix(part.ImageUrl.(dto.MessageImageUrl).Url, "http") {
|
||||||
InlineData: &GeminiInlineData{
|
// 是url,获取图片的类型和base64编码的数据
|
||||||
MimeType: mimeType,
|
mimeType, data, _ := common.GetImageFromUrl(part.ImageUrl.(dto.MessageImageUrl).Url)
|
||||||
Data: data,
|
parts = append(parts, GeminiPart{
|
||||||
},
|
InlineData: &GeminiInlineData{
|
||||||
})
|
MimeType: mimeType,
|
||||||
|
Data: data,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
_, format, base64String, err := common.DecodeBase64ImageData(part.ImageUrl.(dto.MessageImageUrl).Url)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parts = append(parts, GeminiPart{
|
||||||
|
InlineData: &GeminiInlineData{
|
||||||
|
MimeType: "image/" + format,
|
||||||
|
Data: base64String,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
content.Parts = parts
|
content.Parts = parts
|
||||||
|
@ -3,14 +3,18 @@ package ollama
|
|||||||
import "one-api/dto"
|
import "one-api/dto"
|
||||||
|
|
||||||
type OllamaRequest struct {
|
type OllamaRequest struct {
|
||||||
Model string `json:"model,omitempty"`
|
Model string `json:"model,omitempty"`
|
||||||
Messages []dto.Message `json:"messages,omitempty"`
|
Messages []dto.Message `json:"messages,omitempty"`
|
||||||
Stream bool `json:"stream,omitempty"`
|
Stream bool `json:"stream,omitempty"`
|
||||||
Temperature float64 `json:"temperature,omitempty"`
|
Temperature float64 `json:"temperature,omitempty"`
|
||||||
Seed float64 `json:"seed,omitempty"`
|
Seed float64 `json:"seed,omitempty"`
|
||||||
Topp float64 `json:"top_p,omitempty"`
|
Topp float64 `json:"top_p,omitempty"`
|
||||||
TopK int `json:"top_k,omitempty"`
|
TopK int `json:"top_k,omitempty"`
|
||||||
Stop any `json:"stop,omitempty"`
|
Stop any `json:"stop,omitempty"`
|
||||||
|
Tools []dto.ToolCall `json:"tools,omitempty"`
|
||||||
|
ResponseFormat *dto.ResponseFormat `json:"response_format,omitempty"`
|
||||||
|
FrequencyPenalty float64 `json:"frequency_penalty,omitempty"`
|
||||||
|
PresencePenalty float64 `json:"presence_penalty,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OllamaEmbeddingRequest struct {
|
type OllamaEmbeddingRequest struct {
|
||||||
@ -21,6 +25,3 @@ type OllamaEmbeddingRequest struct {
|
|||||||
type OllamaEmbeddingResponse struct {
|
type OllamaEmbeddingResponse struct {
|
||||||
Embedding []float64 `json:"embedding,omitempty"`
|
Embedding []float64 `json:"embedding,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//type OllamaOptions struct {
|
|
||||||
//}
|
|
||||||
|
@ -28,14 +28,18 @@ func requestOpenAI2Ollama(request dto.GeneralOpenAIRequest) *OllamaRequest {
|
|||||||
Stop, _ = request.Stop.([]string)
|
Stop, _ = request.Stop.([]string)
|
||||||
}
|
}
|
||||||
return &OllamaRequest{
|
return &OllamaRequest{
|
||||||
Model: request.Model,
|
Model: request.Model,
|
||||||
Messages: messages,
|
Messages: messages,
|
||||||
Stream: request.Stream,
|
Stream: request.Stream,
|
||||||
Temperature: request.Temperature,
|
Temperature: request.Temperature,
|
||||||
Seed: request.Seed,
|
Seed: request.Seed,
|
||||||
Topp: request.TopP,
|
Topp: request.TopP,
|
||||||
TopK: request.TopK,
|
TopK: request.TopK,
|
||||||
Stop: Stop,
|
Stop: Stop,
|
||||||
|
Tools: request.Tools,
|
||||||
|
ResponseFormat: request.ResponseFormat,
|
||||||
|
FrequencyPenalty: request.FrequencyPenalty,
|
||||||
|
PresencePenalty: request.PresencePenalty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import (
|
|||||||
|
|
||||||
func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (*dto.OpenAIErrorWithStatusCode, *dto.Usage) {
|
func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (*dto.OpenAIErrorWithStatusCode, *dto.Usage) {
|
||||||
containStreamUsage := false
|
containStreamUsage := false
|
||||||
responseId := ""
|
var responseId string
|
||||||
var createAt int64 = 0
|
var createAt int64 = 0
|
||||||
var systemFingerprint string
|
var systemFingerprint string
|
||||||
model := info.UpstreamModelName
|
model := info.UpstreamModelName
|
||||||
@ -86,7 +86,13 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel
|
|||||||
var lastStreamResponse dto.ChatCompletionsStreamResponse
|
var lastStreamResponse dto.ChatCompletionsStreamResponse
|
||||||
err := json.Unmarshal(common.StringToByteSlice(lastStreamData), &lastStreamResponse)
|
err := json.Unmarshal(common.StringToByteSlice(lastStreamData), &lastStreamResponse)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if lastStreamResponse.Usage != nil && service.ValidUsage(lastStreamResponse.Usage) {
|
responseId = lastStreamResponse.Id
|
||||||
|
createAt = lastStreamResponse.Created
|
||||||
|
systemFingerprint = lastStreamResponse.GetSystemFingerprint()
|
||||||
|
model = lastStreamResponse.Model
|
||||||
|
if service.ValidUsage(lastStreamResponse.Usage) {
|
||||||
|
containStreamUsage = true
|
||||||
|
usage = lastStreamResponse.Usage
|
||||||
if !info.ShouldIncludeUsage {
|
if !info.ShouldIncludeUsage {
|
||||||
shouldSendLastResp = false
|
shouldSendLastResp = false
|
||||||
}
|
}
|
||||||
@ -109,14 +115,9 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel
|
|||||||
var streamResponse dto.ChatCompletionsStreamResponse
|
var streamResponse dto.ChatCompletionsStreamResponse
|
||||||
err := json.Unmarshal(common.StringToByteSlice(item), &streamResponse)
|
err := json.Unmarshal(common.StringToByteSlice(item), &streamResponse)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
responseId = streamResponse.Id
|
//if service.ValidUsage(streamResponse.Usage) {
|
||||||
createAt = streamResponse.Created
|
// usage = streamResponse.Usage
|
||||||
systemFingerprint = streamResponse.GetSystemFingerprint()
|
//}
|
||||||
model = streamResponse.Model
|
|
||||||
if service.ValidUsage(streamResponse.Usage) {
|
|
||||||
usage = streamResponse.Usage
|
|
||||||
containStreamUsage = true
|
|
||||||
}
|
|
||||||
for _, choice := range streamResponse.Choices {
|
for _, choice := range streamResponse.Choices {
|
||||||
responseTextBuilder.WriteString(choice.Delta.GetContentString())
|
responseTextBuilder.WriteString(choice.Delta.GetContentString())
|
||||||
if choice.Delta.ToolCalls != nil {
|
if choice.Delta.ToolCalls != nil {
|
||||||
@ -133,14 +134,10 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, streamResponse := range streamResponses {
|
for _, streamResponse := range streamResponses {
|
||||||
responseId = streamResponse.Id
|
//if service.ValidUsage(streamResponse.Usage) {
|
||||||
createAt = streamResponse.Created
|
// usage = streamResponse.Usage
|
||||||
systemFingerprint = streamResponse.GetSystemFingerprint()
|
// containStreamUsage = true
|
||||||
model = streamResponse.Model
|
//}
|
||||||
if service.ValidUsage(streamResponse.Usage) {
|
|
||||||
usage = streamResponse.Usage
|
|
||||||
containStreamUsage = true
|
|
||||||
}
|
|
||||||
for _, choice := range streamResponse.Choices {
|
for _, choice := range streamResponse.Choices {
|
||||||
responseTextBuilder.WriteString(choice.Delta.GetContentString())
|
responseTextBuilder.WriteString(choice.Delta.GetContentString())
|
||||||
if choice.Delta.ToolCalls != nil {
|
if choice.Delta.ToolCalls != nil {
|
||||||
|
@ -121,7 +121,8 @@ func ImageHelper(c *gin.Context, relayMode int) *dto.OpenAIErrorWithStatusCode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quota := int(modelPrice*groupRatio*common.QuotaPerUnit*sizeRatio*qualityRatio) * imageRequest.N
|
imageRatio := modelPrice * sizeRatio * qualityRatio * float64(imageRequest.N)
|
||||||
|
quota := int(imageRatio * groupRatio * common.QuotaPerUnit)
|
||||||
|
|
||||||
if userQuota-quota < 0 {
|
if userQuota-quota < 0 {
|
||||||
return service.OpenAIErrorWrapperLocal(errors.New("user quota is not enough"), "insufficient_user_quota", http.StatusForbidden)
|
return service.OpenAIErrorWrapperLocal(errors.New("user quota is not enough"), "insufficient_user_quota", http.StatusForbidden)
|
||||||
@ -180,7 +181,7 @@ func ImageHelper(c *gin.Context, relayMode int) *dto.OpenAIErrorWithStatusCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logContent := fmt.Sprintf("大小 %s, 品质 %s", imageRequest.Size, quality)
|
logContent := fmt.Sprintf("大小 %s, 品质 %s", imageRequest.Size, quality)
|
||||||
postConsumeQuota(c, relayInfo, imageRequest.Model, usage, 0, 0, userQuota, 0, groupRatio, modelPrice, true, logContent)
|
postConsumeQuota(c, relayInfo, imageRequest.Model, usage, 0, 0, userQuota, 0, groupRatio, imageRatio, true, logContent)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
|
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
import { UserContext } from '../context/User';
|
import { UserContext } from '../context/User';
|
||||||
import { API, getLogo, showError, showInfo, showSuccess } from '../helpers';
|
import {
|
||||||
|
API,
|
||||||
|
getLogo,
|
||||||
|
showError,
|
||||||
|
showInfo,
|
||||||
|
showSuccess,
|
||||||
|
updateAPI,
|
||||||
|
} from '../helpers';
|
||||||
import { onGitHubOAuthClicked, onLinuxDoOAuthClicked } from './utils';
|
import { onGitHubOAuthClicked, onLinuxDoOAuthClicked } from './utils';
|
||||||
import Turnstile from 'react-turnstile';
|
import Turnstile from 'react-turnstile';
|
||||||
import {
|
import {
|
||||||
@ -102,6 +109,7 @@ const LoginForm = () => {
|
|||||||
if (success) {
|
if (success) {
|
||||||
userDispatch({ type: 'login', payload: data });
|
userDispatch({ type: 'login', payload: data });
|
||||||
setUserData(data);
|
setUserData(data);
|
||||||
|
updateAPI();
|
||||||
showSuccess('登录成功!');
|
showSuccess('登录成功!');
|
||||||
if (username === 'root' && password === '123456') {
|
if (username === 'root' && password === '123456') {
|
||||||
Modal.error({
|
Modal.error({
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { getUserIdFromLocalStorage, showError } from './utils';
|
import { getUserIdFromLocalStorage, showError } from './utils';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
export const API = axios.create({
|
export let API = axios.create({
|
||||||
baseURL: import.meta.env.VITE_REACT_APP_SERVER_URL
|
baseURL: import.meta.env.VITE_REACT_APP_SERVER_URL
|
||||||
? import.meta.env.VITE_REACT_APP_SERVER_URL
|
? import.meta.env.VITE_REACT_APP_SERVER_URL
|
||||||
: '',
|
: '',
|
||||||
@ -10,6 +10,17 @@ export const API = axios.create({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export function updateAPI() {
|
||||||
|
API = axios.create({
|
||||||
|
baseURL: import.meta.env.VITE_REACT_APP_SERVER_URL
|
||||||
|
? import.meta.env.VITE_REACT_APP_SERVER_URL
|
||||||
|
: '',
|
||||||
|
headers: {
|
||||||
|
'New-API-User': getUserIdFromLocalStorage(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
API.interceptors.response.use(
|
API.interceptors.response.use(
|
||||||
(response) => response,
|
(response) => response,
|
||||||
(error) => {
|
(error) => {
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import TokensTable from '../../components/TokensTable';
|
import TokensTable from '../../components/TokensTable';
|
||||||
import { Layout } from '@douyinfe/semi-ui';
|
import { Banner, Layout } from '@douyinfe/semi-ui';
|
||||||
const Token = () => (
|
const Token = () => (
|
||||||
<>
|
<>
|
||||||
<Layout>
|
<Layout>
|
||||||
<Layout.Header>
|
<Layout.Header>
|
||||||
<h3>我的令牌</h3>
|
<Banner
|
||||||
|
type='warning'
|
||||||
|
description='令牌无法精确控制使用额度,请勿直接将令牌分发给用户。'
|
||||||
|
/>
|
||||||
</Layout.Header>
|
</Layout.Header>
|
||||||
<Layout.Content>
|
<Layout.Content>
|
||||||
<TokensTable />
|
<TokensTable />
|
||||||
|
Loading…
Reference in New Issue
Block a user