From 700d96452463e26ee22a732d47f8c3d20a2af080 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Tue, 12 May 2026 13:52:53 +0800 Subject: [PATCH] feat: device capabilities from agent /v1/capabilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agent 新增 /v1/capabilities 接口,返回设备检测能力列表。 Managerd 控制台查询此接口,仅显示设备真实支持的功能。 - Agent: capabilities.go — 根据插件节点类型映射能力 - Managerd: pageConsole 查询 /v1/capabilities 过滤可选功能 - ConsoleFeature 增加 Description 字段,hover 显示说明 - 旧 agent 无此接口时回退为显示已持久化的功能 --- internal/service/auto_config.go | 49 ++++++++++++++++++++- internal/web/ui.go | 60 ++++++++++++++++++++------ internal/web/ui/templates/console.html | 2 +- 3 files changed, 96 insertions(+), 15 deletions(-) diff --git a/internal/service/auto_config.go b/internal/service/auto_config.go index 73bfff1..df16301 100644 --- a/internal/service/auto_config.go +++ b/internal/service/auto_config.go @@ -19,6 +19,9 @@ type FeatureDef struct { // FeatureRegistry centralises which templates cover which detection features. type FeatureRegistry struct { features map[string]*FeatureDef + // nodeTypeRequirements maps feature key → required media-server node types. + // If a device lacks any required node type, the feature is unavailable. + nodeTypeRequirements map[string][]string } // NewFeatureRegistry creates a registry with the built-in feature definitions. @@ -50,7 +53,16 @@ func NewFeatureRegistry() *FeatureRegistry { Templates: []string{}, // 模板就绪后再补充 }, } - r := &FeatureRegistry{features: make(map[string]*FeatureDef, len(defs))} + r := &FeatureRegistry{ + features: make(map[string]*FeatureDef, len(defs)), + nodeTypeRequirements: map[string][]string{ + "face": {"ai_face_recog"}, // face recognition plugin + "shoe": {"ai_shoe_det"}, // shoe detection plugin + "helmet": {"ai_yolo"}, // YOLO for helmet (model pending) + "smoking": {"action_recog"}, // action recognition for smoking + "intrusion": {"region_event"}, // region-based intrusion + }, + } for i := range defs { r.features[defs[i].Key] = &defs[i] } @@ -68,6 +80,41 @@ func (r *FeatureRegistry) FeatureKeys() []string { } // Feature returns the definition for a feature key, or nil. +// AvailableFeatures returns the subset of registered features that are supported +// by the given device node types (from /v1/graph-node-types). +// If nodeTypes is nil/empty, all features are considered available (fallback for +// old agents that don't expose node types). +func (r *FeatureRegistry) AvailableFeatures(nodeTypes []string) []FeatureDef { + all := r.AllFeatures() + if len(nodeTypes) == 0 { + return all // no info → assume all available + } + typeSet := make(map[string]bool, len(nodeTypes)) + for _, t := range nodeTypes { + typeSet[t] = true + } + out := make([]FeatureDef, 0, len(all)) + for _, f := range all { + if r.featureAvailable(f.Key, typeSet) { + out = append(out, f) + } + } + return out +} + +func (r *FeatureRegistry) featureAvailable(key string, nodeTypes map[string]bool) bool { + required, ok := r.nodeTypeRequirements[key] + if !ok || len(required) == 0 { + return true // no specific plugin requirement → always available + } + for _, t := range required { + if !nodeTypes[t] { + return false + } + } + return true +} + func (r *FeatureRegistry) Feature(key string) *FeatureDef { return r.features[key] } diff --git a/internal/web/ui.go b/internal/web/ui.go index 9b8a8a8..32388f1 100644 --- a/internal/web/ui.go +++ b/internal/web/ui.go @@ -909,13 +909,36 @@ func (u *UI) pageConsole(w http.ResponseWriter, r *http.Request) { sourceNames[s.Name] = s.Name } - // Feature definitions - featureDefs := []ConsoleFeature{ - {Key: "face", Label: "人脸识别"}, - {Key: "shoe", Label: "劳保鞋检测"}, - {Key: "helmet", Label: "安全帽检测"}, - {Key: "smoking", Label: "抽烟检测"}, - {Key: "intrusion", Label: "区域入侵"}, + // Query each device's capabilities from agent to filter available features. + deviceAvailableFeatures := map[string][]ConsoleFeature{} + if u.agent != nil { + for _, dev := range devices { + if dev == nil || !dev.Online || dev.DeviceID == "" { + continue + } + body, code, err := u.agent.Do("GET", dev.IP, dev.AgentPort, "/v1/capabilities", nil) + if err != nil || code != 200 { + continue + } + var capsResp struct { + Capabilities []struct { + Key string `json:"key"` + Label string `json:"label"` + Available bool `json:"available"` + Description string `json:"description"` + } `json:"capabilities"` + } + if json.Unmarshal(body, &capsResp) != nil { + continue + } + features := make([]ConsoleFeature, 0, len(capsResp.Capabilities)) + for _, c := range capsResp.Capabilities { + if c.Available { + features = append(features, ConsoleFeature{Key: c.Key, Label: c.Label, Description: c.Description, Enabled: false}) + } + } + deviceAvailableFeatures[dev.DeviceID] = features + } } // Load persisted device features as the source of truth. @@ -1015,10 +1038,20 @@ func (u *UI) pageConsole(w http.ResponseWriter, r *http.Request) { activeKeys = map[string]bool{} } + // Features from device capabilities (filtered by agent /v1/capabilities). + // Fall back to persisted keys if agent doesn't respond. + available := deviceAvailableFeatures[dev.DeviceID] var features []ConsoleFeature - for _, fd := range featureDefs { - f := ConsoleFeature{Key: fd.Key, Label: fd.Label, Enabled: activeKeys[fd.Key]} - features = append(features, f) + if len(available) > 0 { + for _, f := range available { + f.Enabled = activeKeys[f.Key] + features = append(features, f) + } + } else { + // Old agent: use persisted keys to show at least what's configured. + for key := range activeKeys { + features = append(features, ConsoleFeature{Key: key, Label: key, Enabled: true}) + } } npu, diskUsage, temp, cpuUsage, memUsage := 0.0, 0.0, 0.0, 0.0, 0.0 @@ -4695,7 +4728,8 @@ type ConsoleChannel struct { } type ConsoleFeature struct { - Key string - Label string - Enabled bool + Key string + Label string + Description string + Enabled bool } diff --git a/internal/web/ui/templates/console.html b/internal/web/ui/templates/console.html index 896daf0..231e124 100644 --- a/internal/web/ui/templates/console.html +++ b/internal/web/ui/templates/console.html @@ -62,7 +62,7 @@ {{range $f := $cd.Features}} - {{$f.Label}} + {{$f.Label}} {{end}}