Skip to content
Closed
13 changes: 13 additions & 0 deletions internal/api/docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1204,6 +1204,8 @@ components:
type: string
name:
type: string
require_model:
type: boolean
required:
- id
- name
Expand Down Expand Up @@ -1332,6 +1334,8 @@ components:
type: string
readme:
type: string
require_model:
type: boolean
status:
type: string
used_by_apps:
Expand Down Expand Up @@ -1365,6 +1369,8 @@ components:
type: string
name:
type: string
require_model:
type: boolean
status:
type: string
variables:
Expand All @@ -1384,8 +1390,15 @@ components:
type: string
id:
type: string
models:
items:
type: string
nullable: true
type: array
name:
type: string
require_model:
type: boolean
status:
type: string
type: object
Expand Down
23 changes: 14 additions & 9 deletions internal/e2e/client/client.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions internal/e2e/daemon/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -783,9 +783,10 @@ func TestAppDetails(t *testing.T) {
require.Len(t, *detailsResp.JSON200.Bricks, 1)
require.Equal(t,
client.AppDetailedBrick{
Id: ImageClassifactionBrickID,
Name: "Image Classification",
Category: f.Ptr("video"),
Id: ImageClassifactionBrickID,
Name: "Image Classification",
Category: f.Ptr("video"),
RequireModel: f.Ptr(true),
},
(*detailsResp.JSON200.Bricks)[0],
)
Expand Down
1 change: 1 addition & 0 deletions internal/e2e/daemon/brick_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ func TestBricksList(t *testing.T) {
require.Equal(t, bIdx.Description, *brick.Description)
require.Equal(t, "Arduino", *brick.Author)
require.Equal(t, "installed", *brick.Status)
require.Equal(t, bIdx.RequireModel, *brick.RequireModel)
}
}

Expand Down
19 changes: 13 additions & 6 deletions internal/orchestrator/bricks/bricks.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,16 @@ func (s *Service) List() (BrickListResult, error) {
res := BrickListResult{Bricks: make([]BrickListItem, len(s.bricksIndex.Bricks))}
for i, brick := range s.bricksIndex.Bricks {
res.Bricks[i] = BrickListItem{
ID: brick.ID,
Name: brick.Name,
Author: "Arduino", // TODO: for now we only support our bricks
Description: brick.Description,
Category: brick.Category,
Status: "installed",
ID: brick.ID,
Name: brick.Name,
Author: "Arduino", // TODO: for now we only support our bricks
Description: brick.Description,
Category: brick.Category,
Status: "installed",
RequireModel: brick.RequireModel,
Models: f.Map(s.modelsIndex.GetModelsByBrick(brick.ID), func(m modelsindex.AIModel) string {
return m.ID
}),
}
}
return res, nil
Expand All @@ -85,6 +89,7 @@ func (s *Service) AppBrickInstancesList(a *app.ArduinoApp) (AppBrickInstancesRes
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?
ConfigVariables: configVariables,
Expand Down Expand Up @@ -118,6 +123,7 @@ func (s *Service) AppBrickInstanceDetails(a *app.ArduinoApp, brickID string) (Br
Author: "Arduino", // TODO: for now we only support our bricks
Category: brick.Category,
Status: "installed", // For now every Arduino brick are installed
RequireModel: brick.RequireModel,
Variables: variables,
ConfigVariables: configVariables,
ModelID: modelID,
Expand Down Expand Up @@ -203,6 +209,7 @@ func (s *Service) BricksDetails(id string, idProvider *app.IDProvider,
Author: "Arduino", // TODO: for now we only support our bricks
Description: brick.Description,
Category: brick.Category,
RequireModel: brick.RequireModel,
Status: "installed", // For now every Arduino brick are installed
Variables: variables,
Readme: readme,
Expand Down
13 changes: 9 additions & 4 deletions internal/orchestrator/bricks/bricks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,12 +503,14 @@ func TestAppBrickInstanceModelsDetails(t *testing.T) {
{Name: "EI_OBJ_DETECTION_MODEL", DefaultValue: "default_path", Description: "path to the model file"},
{Name: "CUSTOM_MODEL_PATH", DefaultValue: "/home/arduino/.arduino-bricks/ei-models", Description: "path to the custom model directory"},
},
RequireModel: true,
},
{
ID: "arduino:weather_forecast",
Name: "Weather Forecast",
Category: "miscellaneous",
ModelName: "",
ID: "arduino:weather_forecast",
Name: "Weather Forecast",
Category: "miscellaneous",
ModelName: "",
RequireModel: false,
},
},
}
Expand Down Expand Up @@ -577,6 +579,7 @@ func TestAppBrickInstanceModelsDetails(t *testing.T) {
require.Equal(t, "installed", res.Status)
require.Empty(t, res.ModelID)
require.Empty(t, res.CompatibleModels)
require.False(t, res.RequireModel)
},
},
{
Expand All @@ -597,6 +600,7 @@ func TestAppBrickInstanceModelsDetails(t *testing.T) {
require.Len(t, res.CompatibleModels, 2)
require.Equal(t, "yolox-object-detection", res.CompatibleModels[0].ID)
require.Equal(t, "face-detection", res.CompatibleModels[1].ID)
require.True(t, res.RequireModel)
},
},
{
Expand All @@ -618,6 +622,7 @@ func TestAppBrickInstanceModelsDetails(t *testing.T) {
require.Len(t, res.CompatibleModels, 2)
require.Equal(t, "yolox-object-detection", res.CompatibleModels[0].ID)
require.Equal(t, "face-detection", res.CompatibleModels[1].ID)
require.True(t, res.RequireModel)
},
},
}
Expand Down
20 changes: 20 additions & 0 deletions internal/orchestrator/bricks/testdata/bricks-list.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,23 @@ bricks:
mount_devices_into_container: false
ports: []
category: storage
- id: arduino:image_classification
name: Image Classification
description: "Brick for image classification using a pre-trained model. It processes\
\ images and returns the predicted class label and confidence score.\nBrick is\
\ designed to work with pre-trained models provided by framework or with custom\
\ image classification models trained on Edge Impulse platform. \n"
require_container: true
require_model: true
require_devices: false
mount_devices_into_container: false
ports: []
category: video
model_name: mobilenet-image-classification
variables:
- name: CUSTOM_MODEL_PATH
default_value: /home/arduino/.arduino-bricks/ei-models
description: path to the custom model directory
- name: EI_CLASSIFICATION_MODEL
default_value: /models/ootb/ei/mobilenet-v2-224px.eim
description: path to the model file
16 changes: 10 additions & 6 deletions internal/orchestrator/bricks/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ type BrickListResult struct {
}

type BrickListItem struct {
ID string `json:"id"`
Name string `json:"name"`
Author string `json:"author"`
Description string `json:"description"`
Category string `json:"category"`
Status string `json:"status"`
ID string `json:"id"`
Name string `json:"name"`
Author string `json:"author"`
Description string `json:"description"`
Category string `json:"category"`
Status string `json:"status"`
RequireModel bool `json:"require_model"`
Models []string `json:"models"`
}

type AppBrickInstancesResult struct {
Expand All @@ -40,6 +42,7 @@ type BrickInstance struct {
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"`
CompatibleModels []AIModel `json:"compatible_models"`
}
Expand Down Expand Up @@ -78,6 +81,7 @@ type BrickDetailsResult struct {
Description string `json:"description"`
Category string `json:"category"`
Status string `json:"status"`
RequireModel bool `json:"require_model"`
Variables map[string]BrickVariable `json:"variables,omitempty"`
Readme string `json:"readme"`
ApiDocsPath string `json:"api_docs_path"`
Expand Down
2 changes: 1 addition & 1 deletion internal/orchestrator/bricksindex/bricks_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ type Brick struct {
Category string `yaml:"category,omitempty"`
RequiresDisplay string `yaml:"requires_display,omitempty"`
RequireContainer bool `yaml:"require_container"`
RequireModel bool `yaml:"require_model"`
Variables []BrickVariable `yaml:"variables,omitempty"`
Ports []string `yaml:"ports,omitempty"`
RequireModel bool `yaml:"require_model"`
ModelName string `yaml:"model_name,omitempty"`
MountDevicesIntoContainer bool `yaml:"mount_devices_into_container,omitempty"`
RequiredDevices []string `yaml:"required_devices,omitempty"`
Expand Down
45 changes: 29 additions & 16 deletions internal/orchestrator/bricksindex/bricks_index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,31 +156,44 @@ func TestBricksIndex(t *testing.T) {
- name: EI_V_ANOMALY_DETECTION_MODEL
default_value: /models/ootb/ei/concrete-crack-anomaly-detection.eim
description: path to the model file
- id: arduino:missing-model-require
name: Camera Scanner
description: Scans a camera for barcodes and QR codes
require_container: false
ports: []
`

var index BricksIndex
err := yaml.Unmarshal([]byte(x), &index)
require.NoError(t, err)
require.Len(t, index.Bricks, 11)
require.Len(t, index.Bricks, 12)

// Check if ports are correctly set
b, found := index.FindBrickByID("arduino:web_ui")
bWebUI, found := index.FindBrickByID("arduino:web_ui")
require.True(t, found)
require.Equal(t, []string{"7000"}, b.Ports)
require.Equal(t, []string{"7000"}, bWebUI.Ports)

// Check if variables are correctly set
b, found = index.FindBrickByID("arduino:image_classification")
bWebUI, found = index.FindBrickByID("arduino:image_classification")
require.True(t, found)
require.Equal(t, "Image Classification", bWebUI.Name)
require.Equal(t, "mobilenet-image-classification", bWebUI.ModelName)
require.True(t, bWebUI.RequireModel)
require.Len(t, bWebUI.Variables, 2)
require.Equal(t, "CUSTOM_MODEL_PATH", bWebUI.Variables[0].Name)
require.Equal(t, "/opt/models/ei/", bWebUI.Variables[0].DefaultValue)
require.Equal(t, "path to the custom model directory", bWebUI.Variables[0].Description)
require.Equal(t, "EI_CLASSIFICATION_MODEL", bWebUI.Variables[1].Name)
require.Equal(t, "/models/ootb/ei/mobilenet-v2-224px.eim", bWebUI.Variables[1].DefaultValue)
require.Equal(t, "path to the model file", bWebUI.Variables[1].Description)
require.False(t, bWebUI.Variables[0].IsRequired())
require.False(t, bWebUI.Variables[1].IsRequired())

bDb, found := index.FindBrickByID("arduino:dbstorage_tsstore")
require.True(t, found)
require.False(t, bDb.RequireModel)

bNoRequireModel, found := index.FindBrickByID("arduino:missing-model-require")
require.True(t, found)
require.Equal(t, "Image Classification", b.Name)
require.Equal(t, "mobilenet-image-classification", b.ModelName)
require.True(t, b.RequireModel)
require.Len(t, b.Variables, 2)
require.Equal(t, "CUSTOM_MODEL_PATH", b.Variables[0].Name)
require.Equal(t, "/opt/models/ei/", b.Variables[0].DefaultValue)
require.Equal(t, "path to the custom model directory", b.Variables[0].Description)
require.Equal(t, "EI_CLASSIFICATION_MODEL", b.Variables[1].Name)
require.Equal(t, "/models/ootb/ei/mobilenet-v2-224px.eim", b.Variables[1].DefaultValue)
require.Equal(t, "path to the model file", b.Variables[1].Description)
require.False(t, b.Variables[0].IsRequired())
require.False(t, b.Variables[1].IsRequired())
require.False(t, bNoRequireModel.RequireModel)
}
8 changes: 5 additions & 3 deletions internal/orchestrator/orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -673,9 +673,10 @@ type AppDetailedInfo struct {
}

type AppDetailedBrick struct {
ID string `json:"id" required:"true"`
Name string `json:"name" required:"true"`
Category string `json:"category,omitempty"`
ID string `json:"id" required:"true"`
Name string `json:"name" required:"true"`
Category string `json:"category,omitempty"`
RequireModel bool `json:"require_model"`
}

func AppDetails(
Expand Down Expand Up @@ -738,6 +739,7 @@ func AppDetails(
}
res.Name = bi.Name
res.Category = bi.Category
res.RequireModel = bi.RequireModel
return res
}),
}, nil
Expand Down