226 lines
6.8 KiB
Go
226 lines
6.8 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/easyai/easyai-ai-gateway/apps/api/internal/store"
|
|
)
|
|
|
|
func (s *Server) platformModelResponse(ctx context.Context, model store.PlatformModel) store.PlatformModel {
|
|
return s.platformModelResponseWithRuleSets(model, s.responsePricingRuleSetConfigs(ctx, []store.PlatformModel{model}))
|
|
}
|
|
|
|
func (s *Server) platformModelResponseWithRuleSets(model store.PlatformModel, ruleSetConfigs map[string]map[string]any) store.PlatformModel {
|
|
model.Capabilities = store.EffectivePlatformModelCapabilities(model.BaseCapabilities, model.Capabilities)
|
|
model.Capabilities = enrichResponseCapabilities(model)
|
|
model = withEffectiveResponseBillingConfig(model, ruleSetConfigs)
|
|
return store.FilterPlatformModelBillingConfig(model)
|
|
}
|
|
|
|
func (s *Server) platformModelResponses(ctx context.Context, models []store.PlatformModel) []store.PlatformModel {
|
|
ruleSetConfigs := s.responsePricingRuleSetConfigs(ctx, models)
|
|
items := make([]store.PlatformModel, len(models))
|
|
for i, model := range models {
|
|
items[i] = s.platformModelResponseWithRuleSets(model, ruleSetConfigs)
|
|
}
|
|
return items
|
|
}
|
|
|
|
func (s *Server) responsePricingRuleSetConfigs(ctx context.Context, models []store.PlatformModel) map[string]map[string]any {
|
|
configs := map[string]map[string]any{}
|
|
if s.store == nil {
|
|
return configs
|
|
}
|
|
ids := map[string]bool{}
|
|
for _, model := range models {
|
|
for _, id := range []string{firstNonEmpty(model.BasePricingRuleSetID, model.PlatformPricingRuleSetID), model.PricingRuleSetID} {
|
|
if id != "" {
|
|
ids[id] = true
|
|
}
|
|
}
|
|
}
|
|
for id := range ids {
|
|
if config, err := s.store.PricingRuleSetBillingConfig(ctx, id); err == nil && len(config) > 0 {
|
|
configs[id] = config
|
|
}
|
|
}
|
|
return configs
|
|
}
|
|
|
|
func withEffectiveResponseBillingConfig(model store.PlatformModel, ruleSetConfigs map[string]map[string]any) store.PlatformModel {
|
|
inheritedRuleSetConfig := ruleSetConfigs[firstNonEmpty(model.BasePricingRuleSetID, model.PlatformPricingRuleSetID)]
|
|
modelRuleSetConfig := ruleSetConfigs[model.PricingRuleSetID]
|
|
model.BillingConfig = store.ResolveEffectiveBillingConfig(store.EffectiveBillingConfigInput{
|
|
BaseConfig: model.BaseBillingConfig,
|
|
LegacyPlatformModelConfig: model.BillingConfig,
|
|
InheritedRuleSetConfig: inheritedRuleSetConfig,
|
|
ModelRuleSetConfig: modelRuleSetConfig,
|
|
Override: model.BillingConfigOverride,
|
|
})
|
|
return model
|
|
}
|
|
|
|
func enrichResponseCapabilities(model store.PlatformModel) map[string]any {
|
|
if len(model.Capabilities) == 0 {
|
|
return model.Capabilities
|
|
}
|
|
textGenerate, ok := enrichedTextGenerateCapabilities(model)
|
|
if !ok {
|
|
return model.Capabilities
|
|
}
|
|
|
|
out := make(map[string]any, len(model.Capabilities)+1)
|
|
for key, value := range model.Capabilities {
|
|
out[key] = value
|
|
}
|
|
out["text_generate"] = textGenerate
|
|
return out
|
|
}
|
|
|
|
func enrichedTextGenerateCapabilities(model store.PlatformModel) (map[string]any, bool) {
|
|
textGenerate := nestedCapabilities(model.Capabilities, "text_generate")
|
|
if textGenerate == nil && !declaresModelType(model, "text_generate") {
|
|
return nil, false
|
|
}
|
|
|
|
patch := map[string]any{}
|
|
if _, ok := textGenerate["max_context_tokens"]; !ok {
|
|
if value, ok := textGenerateContextTokens(model, textGenerate); ok {
|
|
patch["max_context_tokens"] = value
|
|
}
|
|
}
|
|
if _, ok := textGenerate["supportThinking"]; !ok {
|
|
if value, ok := textGenerateSupportThinking(model, textGenerate); ok {
|
|
patch["supportThinking"] = value
|
|
}
|
|
}
|
|
if _, ok := textGenerate["thinkingEffortLevels"]; !ok {
|
|
if value, ok := textGenerateThinkingEffortLevels(model, textGenerate); ok {
|
|
patch["thinkingEffortLevels"] = value
|
|
}
|
|
}
|
|
if len(patch) == 0 {
|
|
return nil, false
|
|
}
|
|
|
|
out := make(map[string]any, len(textGenerate)+len(patch))
|
|
for key, value := range textGenerate {
|
|
out[key] = value
|
|
}
|
|
for key, value := range patch {
|
|
out[key] = value
|
|
}
|
|
return out, true
|
|
}
|
|
|
|
func textGenerateContextTokens(model store.PlatformModel, textGenerate map[string]any) (any, bool) {
|
|
if value, ok := capabilityValue(textGenerate, "maxContextTokens"); ok {
|
|
return value, true
|
|
}
|
|
return capabilityValue(model.Capabilities, "max_context_tokens", "maxContextTokens", "contextWindow")
|
|
}
|
|
|
|
func textGenerateSupportThinking(model store.PlatformModel, textGenerate map[string]any) (any, bool) {
|
|
if value, ok := capabilityValue(model.Capabilities, "supportThinking"); ok {
|
|
return value, true
|
|
}
|
|
if _, ok := capabilityValue(textGenerate, "thinkingEffortLevels"); ok {
|
|
return true, true
|
|
}
|
|
if _, ok := capabilityValue(model.Capabilities, "thinkingEffortLevels"); ok {
|
|
return true, true
|
|
}
|
|
return capabilityValue(model.Capabilities, "reasoning")
|
|
}
|
|
|
|
func textGenerateThinkingEffortLevels(model store.PlatformModel, textGenerate map[string]any) (any, bool) {
|
|
if value, ok := capabilityValue(model.Capabilities, "thinkingEffortLevels"); ok {
|
|
return value, true
|
|
}
|
|
if hasTextGenerateThinkingCapability(model, textGenerate) {
|
|
return []string{}, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func hasTextGenerateThinkingCapability(model store.PlatformModel, textGenerate map[string]any) bool {
|
|
if boolCapabilityValue(textGenerate, "supportThinking", "supportThinkingModeSwitch") {
|
|
return true
|
|
}
|
|
if boolCapabilityValue(model.Capabilities, "supportThinking", "supportThinkingModeSwitch", "reasoning") {
|
|
return true
|
|
}
|
|
_, ok := capabilityValue(textGenerate, "max_thinking_tokens", "maxThinkingTokens")
|
|
return ok
|
|
}
|
|
|
|
func declaresModelType(model store.PlatformModel, modelType string) bool {
|
|
if containsString(model.ModelType, modelType) {
|
|
return true
|
|
}
|
|
if originalTypes, ok := stringListValue(model.Capabilities["originalTypes"]); ok {
|
|
return containsString(originalTypes, modelType)
|
|
}
|
|
return false
|
|
}
|
|
|
|
func containsString(items []string, want string) bool {
|
|
for _, item := range items {
|
|
if item == want {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func nestedCapabilities(capabilities map[string]any, key string) map[string]any {
|
|
if nested, ok := capabilities[key].(map[string]any); ok {
|
|
return nested
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func capabilityValue(capabilities map[string]any, keys ...string) (any, bool) {
|
|
if len(capabilities) == 0 {
|
|
return nil, false
|
|
}
|
|
for _, key := range keys {
|
|
if value, ok := capabilities[key]; ok {
|
|
return value, true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func boolCapabilityValue(capabilities map[string]any, keys ...string) bool {
|
|
if len(capabilities) == 0 {
|
|
return false
|
|
}
|
|
for _, key := range keys {
|
|
flag, ok := capabilities[key].(bool)
|
|
if ok && flag {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func stringListValue(value any) ([]string, bool) {
|
|
switch items := value.(type) {
|
|
case []string:
|
|
return items, len(items) > 0
|
|
case []any:
|
|
out := make([]string, 0, len(items))
|
|
for _, item := range items {
|
|
text, ok := item.(string)
|
|
if !ok || text == "" {
|
|
continue
|
|
}
|
|
out = append(out, text)
|
|
}
|
|
return out, len(out) > 0
|
|
default:
|
|
return nil, false
|
|
}
|
|
}
|