Files
ragflow/internal/ingestion/pipeline/component_params.go
Jack 10c00a9614 Feat: add built in DSL file API (#17003)
### Summary

1. list and get by id API for builtin DSL
2. add DSL default component param values validation
3. remove all hard code keys for parser config
2026-07-18 11:00:08 +08:00

102 lines
3.2 KiB
Go

package pipeline
import (
"encoding/json"
"fmt"
)
// ComponentParamsSchema describes the full set of user-configurable parameters
// for one component in a DSL. The frontend uses this to render editable forms;
// the API uses it for validation.
type ComponentParamsSchema struct {
// CpnID is the component instance identifier in the DSL, e.g. "Parser:HipSignsRhyme".
CpnID string `json:"cpn_id"`
// ComponentName is the logical component type, e.g. "Parser", "Tokenizer".
ComponentName string `json:"component_name"`
// ParamsDefaults holds the params map from the DSL with "outputs" excluded.
// Keys are param names (e.g. "setups", "fields", "chunk_token_size");
// values are their DSL-baked defaults.
ParamsDefaults map[string]any `json:"params_defaults"`
}
// ExtractAllComponentParams extracts the params schema for every component
// present in the DSL JSON. It excludes the internal "outputs" key from each
// component's params — those are wire-format definitions, not user-configurable.
func ExtractAllComponentParams(dslJSON []byte) ([]ComponentParamsSchema, error) {
var dsl struct {
Components map[string]struct {
Obj struct {
ComponentName string `json:"component_name"`
Params map[string]any `json:"params"`
} `json:"obj"`
} `json:"components"`
}
if err := json.Unmarshal(dslJSON, &dsl); err != nil {
return nil, fmt.Errorf("ExtractAllComponentParams: decode DSL: %w", err)
}
if dsl.Components == nil {
return nil, fmt.Errorf("ExtractAllComponentParams: DSL has no components")
}
out := make([]ComponentParamsSchema, 0, len(dsl.Components))
for cpnID, comp := range dsl.Components {
params := make(map[string]any, len(comp.Obj.Params))
for k, v := range comp.Obj.Params {
if k == "outputs" {
continue
}
params[k] = deepCopyValue(v)
}
out = append(out, ComponentParamsSchema{
CpnID: cpnID,
ComponentName: comp.Obj.ComponentName,
ParamsDefaults: params,
})
}
return out, nil
}
// deepCopyValue returns a deep copy of a value that might be a nested map or slice.
func deepCopyValue(v any) any {
switch val := v.(type) {
case map[string]any:
cp := make(map[string]any, len(val))
for mk, mv := range val {
cp[mk] = deepCopyValue(mv)
}
return cp
case []any:
cp := make([]any, len(val))
for i, item := range val {
cp[i] = deepCopyValue(item)
}
return cp
default:
return v
}
}
// deepCopyMapStr deep-copies a map[string]any so the caller can safely mutate the result.
func deepCopyMapStr(src map[string]any) map[string]any {
cp := make(map[string]any, len(src))
for k, v := range src {
cp[k] = deepCopyValue(v)
}
return cp
}
// ComponentParamsDefaults extracts component params from DSL JSON and returns
// them in the component_params storage format {cpnID: {param: value}}.
// Values are deep-copied from the DSL so callers can safely mutate the result.
func ComponentParamsDefaults(dslJSON []byte) (map[string]map[string]any, error) {
schemas, err := ExtractAllComponentParams(dslJSON)
if err != nil {
return nil, err
}
out := make(map[string]map[string]any, len(schemas))
for _, s := range schemas {
out[s.CpnID] = deepCopyMapStr(s.ParamsDefaults)
}
return out, nil
}