predictor/internal/api/v2/profile.go
2026-05-23 00:55:35 +09:00

87 lines
2.2 KiB
Go

package v2
import (
"fmt"
"predictor-refactored/internal/engine"
)
// buildProfile translates a PredictionRequest into an engine.Profile via
// the engine registry.
func buildProfile(req PredictionRequest, deps engine.BuildDeps) (engine.Profile, error) {
if len(req.Profile) == 0 {
return engine.Profile{}, fmt.Errorf("profile must contain at least one stage")
}
step := req.Options.StepSeconds
if step == 0 {
step = 60
}
tol := req.Options.Tolerance
if tol == 0 {
tol = 0.01
}
dir := engine.Forward
switch req.Direction {
case "", "forward":
dir = engine.Forward
case "reverse":
dir = engine.Reverse
default:
return engine.Profile{}, fmt.Errorf("unknown direction %q", req.Direction)
}
props := make([]*engine.Propagator, len(req.Profile))
for i, stage := range req.Profile {
if stage.Name == "" {
return engine.Profile{}, fmt.Errorf("stage %d: name is required", i)
}
built, err := engine.BuildModel(stage.Model, deps)
if err != nil {
return engine.Profile{}, fmt.Errorf("stage %q model: %w", stage.Name, err)
}
constraints, err := buildConstraintList(stage.Constraints, deps)
if err != nil {
return engine.Profile{}, fmt.Errorf("stage %q: %w", stage.Name, err)
}
props[i] = &engine.Propagator{
Name: stage.Name,
Step: step,
Model: built.Model,
BuildModel: built.Build,
Constraints: constraints,
Tolerance: tol,
}
}
for i, stage := range req.Profile {
if stage.FallbackIndex == nil {
continue
}
idx := *stage.FallbackIndex
if idx < 0 || idx >= len(props) {
return engine.Profile{}, fmt.Errorf("stage %q: fallback_index %d out of range", stage.Name, idx)
}
props[i].Fallback = props[idx]
}
globals, err := buildConstraintList(req.Globals, deps)
if err != nil {
return engine.Profile{}, fmt.Errorf("globals: %w", err)
}
return engine.Profile{Stages: props, Direction: dir, Globals: globals}, nil
}
func buildConstraintList(specs []engine.ConstraintSpec, deps engine.BuildDeps) ([]engine.Constraint, error) {
out := make([]engine.Constraint, 0, len(specs))
for i, spec := range specs {
c, err := engine.BuildConstraint(spec, deps)
if err != nil {
return nil, fmt.Errorf("constraint[%d]: %w", i, err)
}
out = append(out, c)
}
return out, nil
}