feat: 测试路径

This commit is contained in:
tbphp
2025-07-23 14:35:52 +08:00
parent e40f33190a
commit ec04555a50
10 changed files with 164 additions and 79 deletions

View File

@@ -9,6 +9,7 @@ import (
"gpt-load/internal/models"
"io"
"net/http"
"net/url"
"strings"
"github.com/gin-gonic/gin"
@@ -67,7 +68,14 @@ func (ch *AnthropicChannel) ValidateKey(ctx context.Context, key string) (bool,
return false, fmt.Errorf("no upstream URL configured for channel %s", ch.Name)
}
reqURL := upstreamURL.String() + "/v1/messages"
validationEndpoint := ch.ValidationEndpoint
if validationEndpoint == "" {
validationEndpoint = "/v1/messages"
}
reqURL, err := url.JoinPath(upstreamURL.String(), validationEndpoint)
if err != nil {
return false, fmt.Errorf("failed to join upstream URL and validation endpoint: %w", err)
}
// Use a minimal, low-cost payload for validation
payload := gin.H{

View File

@@ -23,12 +23,13 @@ type UpstreamInfo struct {
// BaseChannel provides common functionality for channel proxies.
type BaseChannel struct {
Name string
Upstreams []UpstreamInfo
HTTPClient *http.Client
StreamClient *http.Client
TestModel string
upstreamLock sync.Mutex
Name string
Upstreams []UpstreamInfo
HTTPClient *http.Client
StreamClient *http.Client
TestModel string
ValidationEndpoint string
upstreamLock sync.Mutex
// Cached fields from the group for stale check
channelType string
@@ -96,6 +97,9 @@ func (b *BaseChannel) IsConfigStale(group *models.Group) bool {
if b.TestModel != group.TestModel {
return true
}
if b.ValidationEndpoint != group.ValidationEndpoint {
return true
}
if !bytes.Equal(b.groupUpstreams, group.Upstreams) {
return true
}

View File

@@ -140,13 +140,14 @@ func (f *Factory) newBaseChannel(name string, group *models.Group) (*BaseChannel
streamClient := f.clientManager.GetClient(&streamConfig)
return &BaseChannel{
Name: name,
Upstreams: upstreamInfos,
HTTPClient: httpClient,
StreamClient: streamClient,
TestModel: group.TestModel,
channelType: group.ChannelType,
groupUpstreams: group.Upstreams,
effectiveConfig: &group.EffectiveConfig,
Name: name,
Upstreams: upstreamInfos,
HTTPClient: httpClient,
StreamClient: streamClient,
TestModel: group.TestModel,
ValidationEndpoint: group.ValidationEndpoint,
channelType: group.ChannelType,
groupUpstreams: group.Upstreams,
effectiveConfig: &group.EffectiveConfig,
}, nil
}

View File

@@ -9,6 +9,7 @@ import (
"gpt-load/internal/models"
"io"
"net/http"
"net/url"
"strings"
"github.com/gin-gonic/gin"
@@ -65,7 +66,12 @@ func (ch *GeminiChannel) ValidateKey(ctx context.Context, key string) (bool, err
return false, fmt.Errorf("no upstream URL configured for channel %s", ch.Name)
}
reqURL := fmt.Sprintf("%s/v1beta/models/%s:generateContent?key=%s", upstreamURL.String(), ch.TestModel, key)
// Safely join the path segments
reqURL, err := url.JoinPath(upstreamURL.String(), "v1beta", "models", ch.TestModel+":generateContent")
if err != nil {
return false, fmt.Errorf("failed to create gemini validation path: %w", err)
}
reqURL += "?key=" + key
payload := gin.H{
"contents": []gin.H{

View File

@@ -9,6 +9,7 @@ import (
"gpt-load/internal/models"
"io"
"net/http"
"net/url"
"strings"
"github.com/gin-gonic/gin"
@@ -66,7 +67,14 @@ func (ch *OpenAIChannel) ValidateKey(ctx context.Context, key string) (bool, err
return false, fmt.Errorf("no upstream URL configured for channel %s", ch.Name)
}
reqURL := upstreamURL.String() + "/v1/chat/completions"
validationEndpoint := ch.ValidationEndpoint
if validationEndpoint == "" {
validationEndpoint = "/v1/chat/completions"
}
reqURL, err := url.JoinPath(upstreamURL.String(), validationEndpoint)
if err != nil {
return false, fmt.Errorf("failed to join upstream URL and validation endpoint: %w", err)
}
// Use a minimal, low-cost payload for validation
payload := gin.H{