Files
sub2api/backend/internal/service/openai_model_alias.go
T

154 lines
4.5 KiB
Go

package service
import (
"strings"
"github.com/Wei-Shaw/sub2api/internal/pkg/openai"
)
func lastOpenAIModelSegment(model string) string {
model = strings.TrimSpace(model)
if model == "" {
return ""
}
if strings.Contains(model, "/") {
parts := strings.Split(model, "/")
model = parts[len(parts)-1]
}
return strings.TrimSpace(model)
}
func canonicalizeOpenAIModelAliasSpelling(model string) string {
return openai.CanonicalizeOpenAIModelAliasSpelling(model)
}
func normalizeKnownOpenAICodexModel(model string) string {
normalized := canonicalizeOpenAIModelAliasSpelling(model)
if normalized == "" {
return ""
}
if mapped := getNormalizedCodexModel(normalized); mapped != "" {
return mapped
}
if strings.HasSuffix(normalized, "-openai-compact") {
if mapped := getNormalizedCodexModel(strings.TrimSuffix(normalized, "-openai-compact")); mapped != "" {
return mapped
}
}
switch {
case normalized == "gpt-6" || normalized == "gpt-6-astra":
return "gpt-6-astra"
case strings.Contains(normalized, "gpt-5.6-sol"):
return "gpt-5.6-sol"
case strings.Contains(normalized, "gpt-5.6-terra"):
return "gpt-5.6-terra"
case strings.Contains(normalized, "gpt-5.6-luna"):
return "gpt-5.6-luna"
case normalized == "gpt-5.6":
return "gpt-5.6-sol"
case strings.HasPrefix(normalized, "gpt-5.6-"):
suffix := strings.TrimPrefix(normalized, "gpt-5.6-")
if suffix == "max" || isKnownCodexModelSuffix(suffix) {
return "gpt-5.6-sol"
}
return ""
case strings.Contains(normalized, "gpt-5.5-pro"):
return "gpt-5.5-pro"
case strings.Contains(normalized, "gpt-5.5"):
return "gpt-5.5"
case strings.Contains(normalized, "gpt-5.4-mini"):
return "gpt-5.4-mini"
case strings.Contains(normalized, "gpt-5.4-nano"):
return "gpt-5.4-nano"
case strings.Contains(normalized, "gpt-5.4"):
return "gpt-5.4"
case strings.Contains(normalized, "gpt-5.2"):
return "gpt-5.2"
case strings.Contains(normalized, "gpt-5.3-codex-spark"):
return "gpt-5.3-codex-spark"
case strings.Contains(normalized, "gpt-5.3-codex"):
return "gpt-5.3-codex"
case strings.Contains(normalized, "gpt-5.3"):
return "gpt-5.3-codex"
case strings.Contains(normalized, "codex"):
return "gpt-5.3-codex"
case strings.Contains(normalized, "gpt-5"):
return "gpt-5.4"
default:
return ""
}
}
// isOpenAIGPT56Model 判断是否 GPT-5.6 系列模型;入参可为原始模型名
// (含大小写/路径/后缀变体)或已归一化的基名,两者均能正确识别。
func isOpenAIGPT56Model(model string) bool {
normalized := canonicalizeOpenAIModelAliasSpelling(model)
if normalized == "gpt-5.6" {
return true
}
if suffix, ok := strings.CutPrefix(normalized, "gpt-5.6-"); ok && (suffix == "max" || isKnownCodexModelSuffix(suffix)) {
return true
}
for _, prefix := range []string{"gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"} {
if normalized == prefix || strings.HasPrefix(normalized, prefix+"-") {
return true
}
}
return false
}
// isOpenAIGPT6AstraModel reports GPT-6 Astra and dated/provider-prefixed variants.
// The public "gpt-6" alias routes to Astra; unrelated GPT-6 families stay excluded.
func isOpenAIGPT6AstraModel(model string) bool {
normalized := canonicalizeOpenAIModelAliasSpelling(model)
return normalized == "gpt-6" || normalized == "gpt-6-astra" || strings.HasPrefix(normalized, "gpt-6-astra-")
}
func appendUsageBillingModelCandidate(candidates []string, seen map[string]struct{}, model string) []string {
trimmed := strings.TrimSpace(model)
if trimmed == "" {
return candidates
}
add := func(candidate string) {
candidate = strings.TrimSpace(candidate)
if candidate == "" {
return
}
key := strings.ToLower(candidate)
if _, ok := seen[key]; ok {
return
}
seen[key] = struct{}{}
candidates = append(candidates, candidate)
}
add(trimmed)
if canonical := canonicalizeOpenAIModelAliasSpelling(trimmed); canonical != "" {
add(canonical)
}
if normalized := normalizeKnownOpenAICodexModel(trimmed); normalized != "" {
add(normalized)
}
return candidates
}
func usageBillingModelCandidates(primary string, alternates ...string) []string {
seen := make(map[string]struct{}, 1+len(alternates))
candidates := appendUsageBillingModelCandidate(nil, seen, primary)
for _, alternate := range alternates {
candidates = appendUsageBillingModelCandidate(candidates, seen, alternate)
}
return candidates
}
func firstUsageBillingModel(candidates []string) string {
for _, candidate := range candidates {
if trimmed := strings.TrimSpace(candidate); trimmed != "" {
return trimmed
}
}
return ""
}