feat: 算力引擎 Go 后端核心(new-api)
- 统一 OpenAI 兼容 /v1 中继 + 渠道/额度/令牌/流水 - 各领域包:relay 模型网关、model 数据层、controller 管理 API
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/QuantumNous/new-api/constant"
|
||||
"github.com/QuantumNous/new-api/model"
|
||||
)
|
||||
|
||||
func FetchCodexChannelModels(channel *model.Channel) ([]string, error) {
|
||||
if channel == nil || channel.Type != constant.ChannelTypeCodex {
|
||||
return nil, fmt.Errorf("channel type is not Codex")
|
||||
}
|
||||
if channel.ChannelInfo.IsMultiKey {
|
||||
return nil, fmt.Errorf("codex channel does not support multi-key model discovery")
|
||||
}
|
||||
|
||||
client, err := NewProxyHttpClient(channel.GetSetting().Proxy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||||
defer cancel()
|
||||
|
||||
clientVersion, err := GetLatestCodexClientVersion(ctx, client)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get Codex client version: %w", err)
|
||||
}
|
||||
|
||||
baseURL := channel.GetBaseURL()
|
||||
if baseURL == "" {
|
||||
baseURL = constant.ChannelBaseURLs[constant.ChannelTypeCodex]
|
||||
}
|
||||
return fetchCodexChannelModels(ctx, channel, baseURL, client, clientVersion)
|
||||
}
|
||||
|
||||
func fetchCodexChannelModels(
|
||||
ctx context.Context,
|
||||
channel *model.Channel,
|
||||
baseURL string,
|
||||
client *http.Client,
|
||||
clientVersion string,
|
||||
) ([]string, error) {
|
||||
oauthKey, err := parseCodexOAuthKey(strings.TrimSpace(channel.Key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
statusCode, models, err := FetchCodexModels(ctx, client, baseURL, oauthKey, clientVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if statusCode == http.StatusUnauthorized {
|
||||
if channel.Id <= 0 {
|
||||
return nil, fmt.Errorf("codex channel credential expired; save the channel before retrying model fetch")
|
||||
}
|
||||
refreshedKey, _, refreshErr := RefreshCodexChannelCredential(
|
||||
ctx,
|
||||
channel.Id,
|
||||
CodexCredentialRefreshOptions{ResetCaches: true},
|
||||
)
|
||||
if refreshErr != nil {
|
||||
return nil, fmt.Errorf("failed to refresh Codex channel credential: %w", refreshErr)
|
||||
}
|
||||
statusCode, models, err = FetchCodexModels(ctx, client, baseURL, &CodexOAuthKey{
|
||||
AccessToken: refreshedKey.AccessToken,
|
||||
AccountID: refreshedKey.AccountID,
|
||||
}, clientVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if statusCode < http.StatusOK || statusCode >= http.StatusMultipleChoices {
|
||||
return nil, fmt.Errorf("upstream status: %d", statusCode)
|
||||
}
|
||||
return models, nil
|
||||
}
|
||||
Reference in New Issue
Block a user