Skip to content
30 changes: 1 addition & 29 deletions internal/api/docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,7 @@ components:
properties:
bricks:
items:
$ref: '#/components/schemas/BrickInstanceListItem'
$ref: '#/components/schemas/BrickInstance'
nullable: true
type: array
type: object
Expand Down Expand Up @@ -1355,7 +1355,6 @@ components:
$ref: '#/components/schemas/BrickVariable'
description: 'Deprecated: use config_variables instead. This field is kept
for backward compatibility.'
nullable: true
type: object
type: object
BrickInstance:
Expand Down Expand Up @@ -1390,33 +1389,6 @@ components:
for backward compatibility.'
type: object
type: object
BrickInstanceListItem:
properties:
author:
type: string
category:
type: string
config_variables:
items:
$ref: '#/components/schemas/BrickConfigVariable'
type: array
id:
type: string
model:
type: string
name:
type: string
require_model:
type: boolean
status:
type: string
variables:
additionalProperties:
type: string
description: 'Deprecated: use config_variables instead. This field is kept
for backward compatibility.'
type: object
type: object
BrickListItem:
properties:
author:
Expand Down
31 changes: 21 additions & 10 deletions internal/orchestrator/bricks/bricks.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package bricks

import (
"cmp"
"errors"
"fmt"
"log/slog"
Expand Down Expand Up @@ -71,7 +72,7 @@ func (s *Service) List() (BrickListResult, error) {
}

func (s *Service) AppBrickInstancesList(a *app.ArduinoApp) (AppBrickInstancesResult, error) {
res := AppBrickInstancesResult{BrickInstances: make([]BrickInstanceListItem, len(a.Descriptor.Bricks))}
res := AppBrickInstancesResult{BrickInstances: make([]BrickInstance, len(a.Descriptor.Bricks))}
for i, brickInstance := range a.Descriptor.Bricks {
brick, found := s.bricksIndex.FindBrickByID(brickInstance.ID)
if !found {
Expand All @@ -80,16 +81,23 @@ func (s *Service) AppBrickInstancesList(a *app.ArduinoApp) (AppBrickInstancesRes

variablesMap, configVariables := getInstanceBrickConfigVariableDetails(brick, brickInstance.Variables)

res.BrickInstances[i] = BrickInstanceListItem{
res.BrickInstances[i] = BrickInstance{
ID: brick.ID,
Name: brick.Name,
Author: "Arduino", // TODO: for now we only support our bricks
Category: brick.Category,
Status: "installed",
RequireModel: brick.RequireModel,
ModelID: brickInstance.Model, // TODO: in case is not set by the user, should we return the default model?
Variables: variablesMap, // TODO: do we want to show also the default value of not explicitly set variables?
ModelID: getSelectedModelOrDefault(brickInstance, brick),
Variables: variablesMap,
ConfigVariables: configVariables,
CompatibleModels: f.Map(s.modelsIndex.GetModelsByBrick(brick.ID), func(m modelsindex.AIModel) AIModel {
return AIModel{
ID: m.ID,
Name: m.Name,
Description: m.ModuleDescription,
}
}),
}

}
Expand All @@ -109,11 +117,6 @@ func (s *Service) AppBrickInstanceDetails(a *app.ArduinoApp, brickID string) (Br

variables, configVariables := getInstanceBrickConfigVariableDetails(brick, a.Descriptor.Bricks[brickIndex].Variables)

modelID := a.Descriptor.Bricks[brickIndex].Model
if modelID == "" {
modelID = brick.ModelName
}

return BrickInstance{
ID: brickID,
Name: brick.Name,
Expand All @@ -123,7 +126,7 @@ func (s *Service) AppBrickInstanceDetails(a *app.ArduinoApp, brickID string) (Br
RequireModel: brick.RequireModel,
Variables: variables,
ConfigVariables: configVariables,
ModelID: modelID,
ModelID: getSelectedModelOrDefault(a.Descriptor.Bricks[brickIndex], brick),
CompatibleModels: f.Map(s.modelsIndex.GetModelsByBrick(brick.ID), func(m modelsindex.AIModel) AIModel {
return AIModel{
ID: m.ID,
Expand All @@ -134,6 +137,14 @@ func (s *Service) AppBrickInstanceDetails(a *app.ArduinoApp, brickID string) (Br
}, nil
}

func getSelectedModelOrDefault(appBrick app.Brick, brickIndex *bricksindex.Brick) string {
if appBrick.Model != "" {
return appBrick.Model
}
f.Assert(brickIndex != nil, "bricksindex should be set")
return cmp.Or(brickIndex.ModelName, appBrick.Model)
}

func getInstanceBrickConfigVariableDetails(
brick *bricksindex.Brick, userVariables map[string]string,
) (map[string]string, []BrickConfigVariable) {
Expand Down
44 changes: 43 additions & 1 deletion internal/orchestrator/bricks/bricks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,21 @@ func TestAppBrickInstancesList(t *testing.T) {

svc := &Service{
bricksIndex: bIndex,
modelsIndex: &modelsindex.ModelsIndex{},
modelsIndex: &modelsindex.ModelsIndex{
Models: []modelsindex.AIModel{
{
ID: "yolox-object-detection",
Name: "General purpose object detection - YoloX",
ModuleDescription: "a-model-description",
Bricks: []string{"arduino:object_detection"},
},
{
ID: "face-detection",
Name: "Lightweight-Face-Detection",
Bricks: []string{"arduino:object_detection"},
},
},
},
}

tests := []struct {
Expand Down Expand Up @@ -809,6 +823,10 @@ func TestAppBrickInstancesList(t *testing.T) {
require.Equal(t, "video", brick.Category)
require.True(t, brick.RequireModel)
require.Equal(t, "face-detection", brick.ModelID)
require.Equal(t, []AIModel{
{ID: "yolox-object-detection", Name: "General purpose object detection - YoloX", Description: "a-model-description"},
{ID: "face-detection", Name: "Lightweight-Face-Detection", Description: ""},
}, brick.CompatibleModels)

foundCustom := false
for _, v := range brick.ConfigVariables {
Expand All @@ -820,6 +838,30 @@ func TestAppBrickInstancesList(t *testing.T) {
require.True(t, foundCustom, "Variable CUSTOM_MODEL_PATH should be present and overridden")
},
},
{
name: "Success - Brick using brick default model",
app: &app.ArduinoApp{
Descriptor: app.AppDescriptor{
Bricks: []app.Brick{
{
ID: "arduino:object_detection",
},
},
},
},
validate: func(t *testing.T, res AppBrickInstancesResult) {
require.Len(t, res.BrickInstances, 1)
brick := res.BrickInstances[0]

require.Equal(t, "arduino:object_detection", brick.ID)
require.True(t, brick.RequireModel)
require.Equal(t, "yolox-object-detection", brick.ModelID)
require.Equal(t, []AIModel{
{ID: "yolox-object-detection", Name: "General purpose object detection - YoloX", Description: "a-model-description"},
{ID: "face-detection", Name: "Lightweight-Face-Detection", Description: ""},
}, brick.CompatibleModels)
},
},
{
name: "Success - Multiple Bricks",
app: &app.ArduinoApp{
Expand Down
14 changes: 2 additions & 12 deletions internal/orchestrator/bricks/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,9 @@ type BrickListItem struct {
}

type AppBrickInstancesResult struct {
BrickInstances []BrickInstanceListItem `json:"bricks"`
}
type BrickInstanceListItem struct {
ID string `json:"id"`
Name string `json:"name"`
Author string `json:"author"`
Category string `json:"category"`
Status string `json:"status"`
Variables map[string]string `json:"variables,omitempty" description:"Deprecated: use config_variables instead. This field is kept for backward compatibility."`
ConfigVariables []BrickConfigVariable `json:"config_variables,omitempty"`
RequireModel bool `json:"require_model"`
ModelID string `json:"model,omitempty"`
BrickInstances []BrickInstance `json:"bricks"`
}

type BrickInstance struct {
ID string `json:"id"`
Name string `json:"name"`
Expand Down