187 lines
5.5 KiB
Go
187 lines
5.5 KiB
Go
package runner
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/easyai/easyai-ai-gateway/apps/api/internal/store"
|
|
)
|
|
|
|
type paramProcessContext struct {
|
|
kind string
|
|
modelCapability map[string]any
|
|
candidate store.RuntimeModelCandidate
|
|
log *parameterPreprocessingLog
|
|
aspectRatio string
|
|
resolution string
|
|
err error
|
|
}
|
|
|
|
type paramProcessor interface {
|
|
Name() string
|
|
ShouldProcess(params map[string]any, modelType string, context *paramProcessContext) bool
|
|
Process(params map[string]any, modelType string, context *paramProcessContext) bool
|
|
}
|
|
|
|
type ParamProcessorChain struct {
|
|
processors []paramProcessor
|
|
}
|
|
|
|
type parameterPreprocessResult struct {
|
|
Body map[string]any
|
|
Log parameterPreprocessingLog
|
|
Err error
|
|
}
|
|
|
|
type parameterPreprocessingLog struct {
|
|
ModelType string `json:"modelType"`
|
|
Input map[string]any `json:"actualInput"`
|
|
Output map[string]any `json:"convertedOutput"`
|
|
Changed bool `json:"changed"`
|
|
Changes []parameterPreprocessChange `json:"changes"`
|
|
Model map[string]any `json:"model,omitempty"`
|
|
}
|
|
|
|
type parameterPreprocessChange struct {
|
|
Processor string `json:"processor"`
|
|
Action string `json:"action"`
|
|
Path string `json:"path"`
|
|
Before any `json:"before"`
|
|
After any `json:"after"`
|
|
Reason string `json:"reason"`
|
|
CapabilityPath string `json:"capabilityPath,omitempty"`
|
|
CapabilityValue any `json:"capabilityValue,omitempty"`
|
|
}
|
|
|
|
func NewParamProcessorChain() ParamProcessorChain {
|
|
return ParamProcessorChain{
|
|
processors: []paramProcessor{
|
|
resolutionNormalizeProcessor{},
|
|
aspectRatioProcessor{},
|
|
messageContentProcessor{},
|
|
contentFilterProcessor{},
|
|
inputAudioProcessor{},
|
|
durationProcessor{},
|
|
audioProcessor{},
|
|
imageCountProcessor{},
|
|
},
|
|
}
|
|
}
|
|
|
|
func preprocessRequest(kind string, body map[string]any, candidate store.RuntimeModelCandidate) map[string]any {
|
|
return preprocessRequestWithLog(kind, body, candidate).Body
|
|
}
|
|
|
|
func preprocessRequestWithLog(kind string, body map[string]any, candidate store.RuntimeModelCandidate) parameterPreprocessResult {
|
|
params := cloneMap(body)
|
|
modelType := strings.TrimSpace(candidate.ModelType)
|
|
if modelType == "" {
|
|
modelType = modelTypeFromKind(kind, params)
|
|
}
|
|
log := parameterPreprocessingLog{
|
|
ModelType: modelType,
|
|
Input: cloneMap(params),
|
|
Changes: []parameterPreprocessChange{},
|
|
Model: map[string]any{
|
|
"modelName": candidate.ModelName,
|
|
"modelAlias": candidate.ModelAlias,
|
|
"providerModelName": candidate.ProviderModelName,
|
|
"provider": candidate.Provider,
|
|
"platformId": candidate.PlatformID,
|
|
"platformModelId": candidate.PlatformModelID,
|
|
},
|
|
}
|
|
context := ¶mProcessContext{
|
|
kind: kind,
|
|
modelCapability: effectiveModelCapability(candidate),
|
|
candidate: candidate,
|
|
log: &log,
|
|
}
|
|
if kind == "videos.generations" {
|
|
ensureVideoContent(params, context)
|
|
}
|
|
chain := NewParamProcessorChain()
|
|
processed := chain.Process(params, modelType, context)
|
|
log.Output = cloneMap(processed)
|
|
log.Changed = len(log.Changes) > 0
|
|
return parameterPreprocessResult{Body: processed, Log: log, Err: context.err}
|
|
}
|
|
|
|
func (chain ParamProcessorChain) Process(params map[string]any, modelType string, context *paramProcessContext) map[string]any {
|
|
if params == nil {
|
|
return map[string]any{}
|
|
}
|
|
for _, processor := range chain.processors {
|
|
if !processor.ShouldProcess(params, modelType, context) {
|
|
continue
|
|
}
|
|
if !processor.Process(params, modelType, context) {
|
|
break
|
|
}
|
|
if context != nil && context.err != nil {
|
|
break
|
|
}
|
|
}
|
|
return params
|
|
}
|
|
|
|
func (context *paramProcessContext) recordChange(processor string, action string, path string, before any, after any, reason string, capabilityPath string, capabilityValue any) {
|
|
if context == nil || context.log == nil {
|
|
return
|
|
}
|
|
context.log.Changes = append(context.log.Changes, parameterPreprocessChange{
|
|
Processor: processor,
|
|
Action: action,
|
|
Path: path,
|
|
Before: cloneAny(before),
|
|
After: cloneAny(after),
|
|
Reason: reason,
|
|
CapabilityPath: capabilityPath,
|
|
CapabilityValue: cloneAny(capabilityValue),
|
|
})
|
|
}
|
|
|
|
func (context *paramProcessContext) reject(processor string, path string, before any, reason string, capabilityPath string, capabilityValue any) bool {
|
|
if context != nil {
|
|
context.recordChange(processor, "reject", path, before, nil, reason, capabilityPath, capabilityValue)
|
|
context.err = parameterValidationError(reason)
|
|
}
|
|
return false
|
|
}
|
|
|
|
type parameterValidationError string
|
|
|
|
func (e parameterValidationError) Error() string {
|
|
return string(e)
|
|
}
|
|
|
|
func parameterPreprocessingMetrics(log parameterPreprocessingLog) map[string]any {
|
|
return map[string]any{
|
|
"parameterPreprocessingSummary": parameterPreprocessingSummary(log),
|
|
}
|
|
}
|
|
|
|
func parameterPreprocessingSummary(log parameterPreprocessingLog) map[string]any {
|
|
summary := map[string]any{
|
|
"modelType": log.ModelType,
|
|
"changed": log.Changed,
|
|
"changeCount": len(log.Changes),
|
|
}
|
|
if len(log.Changes) == 0 {
|
|
return summary
|
|
}
|
|
actions := make([]string, 0)
|
|
paths := make([]string, 0)
|
|
capabilityPaths := make([]string, 0)
|
|
for _, change := range log.Changes {
|
|
appendUniqueString(&actions, change.Action)
|
|
appendUniqueString(&paths, change.Path)
|
|
appendUniqueString(&capabilityPaths, change.CapabilityPath)
|
|
}
|
|
summary["actions"] = actions
|
|
summary["paths"] = paths
|
|
if len(capabilityPaths) > 0 {
|
|
summary["capabilityPaths"] = capabilityPaths
|
|
}
|
|
return summary
|
|
}
|