@@ -61,6 +61,17 @@ func (ch *AnthropicChannel) IsStreamRequest(c *gin.Context, bodyBytes []byte) bo
|
||||
return false
|
||||
}
|
||||
|
||||
func (ch *AnthropicChannel) ExtractModel(c *gin.Context, bodyBytes []byte) string {
|
||||
type modelPayload struct {
|
||||
Model string `json:"model"`
|
||||
}
|
||||
var p modelPayload
|
||||
if err := json.Unmarshal(bodyBytes, &p); err == nil {
|
||||
return p.Model
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ValidateKey checks if the given API key is valid by making a messages request.
|
||||
func (ch *AnthropicChannel) ValidateKey(ctx context.Context, key string) (bool, error) {
|
||||
upstreamURL := ch.getUpstreamURL()
|
||||
|
@@ -29,6 +29,9 @@ type ChannelProxy interface {
|
||||
// IsStreamRequest checks if the request is for a streaming response,
|
||||
IsStreamRequest(c *gin.Context, bodyBytes []byte) bool
|
||||
|
||||
// ExtractModel extracts the model name from the request.
|
||||
ExtractModel(c *gin.Context, bodyBytes []byte) string
|
||||
|
||||
// ValidateKey checks if the given API key is valid.
|
||||
ValidateKey(ctx context.Context, key string) (bool, error)
|
||||
}
|
||||
|
@@ -71,6 +71,29 @@ func (ch *GeminiChannel) IsStreamRequest(c *gin.Context, bodyBytes []byte) bool
|
||||
return false
|
||||
}
|
||||
|
||||
func (ch *GeminiChannel) ExtractModel(c *gin.Context, bodyBytes []byte) string {
|
||||
// gemini format
|
||||
path := c.Request.URL.Path
|
||||
parts := strings.Split(path, "/")
|
||||
for i, part := range parts {
|
||||
if part == "models" && i+1 < len(parts) {
|
||||
modelPart := parts[i+1]
|
||||
return strings.Split(modelPart, ":")[0]
|
||||
}
|
||||
}
|
||||
|
||||
// openai format
|
||||
type modelPayload struct {
|
||||
Model string `json:"model"`
|
||||
}
|
||||
var p modelPayload
|
||||
if err := json.Unmarshal(bodyBytes, &p); err == nil && p.Model != "" {
|
||||
return strings.TrimPrefix(p.Model, "models/")
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// ValidateKey checks if the given API key is valid by making a generateContent request.
|
||||
func (ch *GeminiChannel) ValidateKey(ctx context.Context, key string) (bool, error) {
|
||||
upstreamURL := ch.getUpstreamURL()
|
||||
|
@@ -60,6 +60,17 @@ func (ch *OpenAIChannel) IsStreamRequest(c *gin.Context, bodyBytes []byte) bool
|
||||
return false
|
||||
}
|
||||
|
||||
func (ch *OpenAIChannel) ExtractModel(c *gin.Context, bodyBytes []byte) string {
|
||||
type modelPayload struct {
|
||||
Model string `json:"model"`
|
||||
}
|
||||
var p modelPayload
|
||||
if err := json.Unmarshal(bodyBytes, &p); err == nil {
|
||||
return p.Model
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ValidateKey checks if the given API key is valid by making a chat completion request.
|
||||
func (ch *OpenAIChannel) ValidateKey(ctx context.Context, key string) (bool, error) {
|
||||
upstreamURL := ch.getUpstreamURL()
|
||||
|
@@ -83,6 +83,7 @@ type RequestLog struct {
|
||||
GroupID uint `gorm:"not null;index" json:"group_id"`
|
||||
GroupName string `gorm:"type:varchar(255);index" json:"group_name"`
|
||||
KeyValue string `gorm:"type:varchar(700)" json:"key_value"`
|
||||
Model string `gorm:"type:varchar(255);index" json:"model"`
|
||||
IsSuccess bool `gorm:"not null" json:"is_success"`
|
||||
SourceIP string `gorm:"type:varchar(64)" json:"source_ip"`
|
||||
StatusCode int `gorm:"not null" json:"status_code"`
|
||||
|
@@ -114,11 +114,11 @@ func (ps *ProxyServer) executeRequestWithRetry(
|
||||
}
|
||||
logrus.Debugf("Max retries exceeded for group %s after %d attempts. Parsed Error: %s", group.Name, retryCount, logMessage)
|
||||
|
||||
ps.logRequest(c, group, &models.APIKey{KeyValue: lastError.KeyValue}, startTime, lastError.StatusCode, retryCount, errors.New(logMessage), isStream, lastError.UpstreamAddr)
|
||||
ps.logRequest(c, group, &models.APIKey{KeyValue: lastError.KeyValue}, startTime, lastError.StatusCode, retryCount, errors.New(logMessage), isStream, lastError.UpstreamAddr, channelHandler, bodyBytes)
|
||||
} else {
|
||||
response.Error(c, app_errors.ErrMaxRetriesExceeded)
|
||||
logrus.Debugf("Max retries exceeded for group %s after %d attempts.", group.Name, retryCount)
|
||||
ps.logRequest(c, group, nil, startTime, http.StatusServiceUnavailable, retryCount, app_errors.ErrMaxRetriesExceeded, isStream, "")
|
||||
ps.logRequest(c, group, nil, startTime, http.StatusServiceUnavailable, retryCount, app_errors.ErrMaxRetriesExceeded, isStream, "", channelHandler, bodyBytes)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -127,7 +127,7 @@ func (ps *ProxyServer) executeRequestWithRetry(
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to select a key for group %s on attempt %d: %v", group.Name, retryCount+1, err)
|
||||
response.Error(c, app_errors.NewAPIError(app_errors.ErrNoKeysAvailable, err.Error()))
|
||||
ps.logRequest(c, group, nil, startTime, http.StatusServiceUnavailable, retryCount, err, isStream, "")
|
||||
ps.logRequest(c, group, nil, startTime, http.StatusServiceUnavailable, retryCount, err, isStream, "", channelHandler, bodyBytes)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ func (ps *ProxyServer) executeRequestWithRetry(
|
||||
if err != nil || (resp != nil && resp.StatusCode >= 400) {
|
||||
if err != nil && app_errors.IsIgnorableError(err) {
|
||||
logrus.Debugf("Client-side ignorable error for key %s, aborting retries: %v", utils.MaskAPIKey(apiKey.KeyValue), err)
|
||||
ps.logRequest(c, group, apiKey, startTime, 499, retryCount+1, err, isStream, upstreamURL)
|
||||
ps.logRequest(c, group, apiKey, startTime, 499, retryCount+1, err, isStream, upstreamURL, channelHandler, bodyBytes)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ func (ps *ProxyServer) executeRequestWithRetry(
|
||||
|
||||
// ps.keyProvider.UpdateStatus(apiKey, group, true) // 请求成功不再重置成功次数,减少IO消耗
|
||||
logrus.Debugf("Request for group %s succeeded on attempt %d with key %s", group.Name, retryCount+1, utils.MaskAPIKey(apiKey.KeyValue))
|
||||
ps.logRequest(c, group, apiKey, startTime, resp.StatusCode, retryCount+1, nil, isStream, upstreamURL)
|
||||
ps.logRequest(c, group, apiKey, startTime, resp.StatusCode, retryCount+1, nil, isStream, upstreamURL, channelHandler, bodyBytes)
|
||||
|
||||
for key, values := range resp.Header {
|
||||
for _, value := range values {
|
||||
@@ -254,6 +254,8 @@ func (ps *ProxyServer) logRequest(
|
||||
finalError error,
|
||||
isStream bool,
|
||||
upstreamAddr string,
|
||||
channelHandler channel.ChannelProxy,
|
||||
bodyBytes []byte,
|
||||
) {
|
||||
if ps.requestLogService == nil {
|
||||
return
|
||||
@@ -274,6 +276,11 @@ func (ps *ProxyServer) logRequest(
|
||||
IsStream: isStream,
|
||||
UpstreamAddr: utils.TruncateString(upstreamAddr, 500),
|
||||
}
|
||||
|
||||
if channelHandler != nil && bodyBytes != nil {
|
||||
logEntry.Model = channelHandler.ExtractModel(c, bodyBytes)
|
||||
}
|
||||
|
||||
if apiKey != nil {
|
||||
logEntry.KeyValue = apiKey.KeyValue
|
||||
}
|
||||
|
@@ -45,6 +45,9 @@ func logFiltersScope(c *gin.Context) func(db *gorm.DB) *gorm.DB {
|
||||
}
|
||||
db = db.Where("key_value LIKE ?", likePattern)
|
||||
}
|
||||
if model := c.Query("model"); model != "" {
|
||||
db = db.Where("model LIKE ?", "%"+model+"%")
|
||||
}
|
||||
if isSuccessStr := c.Query("is_success"); isSuccessStr != "" {
|
||||
if isSuccess, err := strconv.ParseBool(isSuccessStr); err == nil {
|
||||
db = db.Where("is_success = ?", isSuccess)
|
||||
|
Reference in New Issue
Block a user