Skip to content

Commit

Permalink
Merge pull request #484 from microbit-foundation/v3.2
Browse files Browse the repository at this point in the history
V3.2 - Vector representation, fixed prettier pipeline, improved training page
  • Loading branch information
Karlo-Emilo authored Oct 10, 2024
2 parents a90b7f1 + 49b5d22 commit dba27e1
Show file tree
Hide file tree
Showing 138 changed files with 2,315 additions and 1,194 deletions.
24 changes: 3 additions & 21 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
- uses: actions/checkout@v3
- name: Run Tests
run: |
npm install
npm ci
npm test
formatting_and_linting:
name: Prettier / svelte Check
Expand All @@ -44,29 +44,11 @@ jobs:
- name: Run prettier
shell: bash
run: |
npm install
npm run prettier
# if we find the string modified after running git status, it indicates that prettier has changed files!
if git status | grep -c "modified" -eq 0; then
exit 1
else
exit 0
fi
- name: Missing format report
shell: bash
if: ${{ failure() }}
run: |
echo "Missing prettier formatting. Please format files using 'npm run prettier' and resubmit!"
exit 1
npm ci
npm run checkFormat
- name: Svelte check
shell: bash
run: npm run check
- name: Svelte check report
shell: bash
if: ${{ failure() }}
run: |
echo "Running npm run check found warnings, please resolve them before merging!"
exit 1

build_and_deploy:
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
- uses: actions/checkout@v3
- name: Run Tests
run: |
npm install
npm ci
npm test
build_and_deploy:
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
Expand Down
4 changes: 3 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
src/translations.ts
src/translations.ts
src/appInsights.ts
src/messages/*
15 changes: 12 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,16 @@
"a11y-structure": "ignore",
"a11y-click-events-have-key-events": "ignore",
"a11y-missing-content": "ignore",
"a11y-no-noninteractive-element-interactions":"ignore",
"a11y-no-noninteractive-element-interactions": "ignore",
"a11y-no-static-element-interactions": "ignore"
}
}
},
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true
},
"hide-files.files": []
}
5 changes: 5 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
services:
ml:
build: .
ports:
- "5174:8080"
25 changes: 25 additions & 0 deletions dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# A Dockerfile must begin with a FROM instruction.
# New base image will be built based on the Node.js version 20
# Image that is based on Debian Linux.
FROM node:20

# Create app directory
WORKDIR /usr/src/app

# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package*.json ./

# Install app dependencies
RUN npm install
RUN npm install express

# Bundle app source
COPY . .

# Creates a "dist" folder with the production build
RUN npm run build

EXPOSE 8080

# Start the server using the production build
CMD [ "node", "dist/main.cjs" ]
6 changes: 4 additions & 2 deletions features.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"title": "Learning tool",
"knnModel": true
}
"knnModel": true,
"lossGraph": true,
"makecode": true
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "module",
"license": "MIT",
"scripts": {
"build": "node prepEnv.js simple && vite build",
"build": "node prepEnv.js branded && vite build",
"dev": "node prepEnv.js unbranded && vite",
"devML": "node prepEnv.js branded && vite",
"devSimple": "node prepEnv.js simple && vite",
Expand Down
13 changes: 7 additions & 6 deletions prepEnv.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
// This script is used to setup different build configurations
// run by ` node prepEnv.js branded ` for ml-machine-branded config
import { copyFile } from 'node:fs/promises';
import { copyFile } from 'fs';

// Validate input
const args = process.argv;
Expand All @@ -31,6 +31,7 @@ const fileMoveTargets = {
['./src/__viteBuildVariants__/ml-machine-simple/features.json', './features.json']
]
}

const availableTargets = Object.getOwnPropertyNames(fileMoveTargets);
const buildVariantTarget = args[2];
if (!availableTargets.includes(buildVariantTarget)) {
Expand All @@ -41,14 +42,14 @@ if (!availableTargets.includes(buildVariantTarget)) {

// The actual work
const copyFiles = fileMoveTargets[buildVariantTarget];

copyFiles.forEach(element => {
const source = element[0];
const destination = element[1];
copyFile(source, destination).then(() => {
copyFile(source, destination, (err) => {
console.log("Copied ", element[0], " -> ", element[1])
}).catch((err) => {
console.error("Failed to move ", source, " to ", destination)
throw new Error(err)
if (err) {
console.error("Failed to move ", source, " to ", destination)
throw new Error(err)
}
})
});
6 changes: 6 additions & 0 deletions public/imgs/dotted_graph_line.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions public/imgs/graph_left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions public/imgs/graph_line_rounded.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions public/imgs/parallel.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions public/main.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const express = require('express');
const path = require('path');
const app = express();

app.use(express.static(path.join(__dirname, '.')));

app.get('/', async (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'));
});

app.listen(8080, () => {
console.log("Server successfully running on port 8080");
});
2 changes: 2 additions & 0 deletions src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import { DeviceRequestStates } from './script/stores/connectDialogStore';
import Router from './router/Router.svelte';
import { Feature, getFeature } from './script/FeatureToggles';
import { welcomeLog } from './script/utils/Logger';
welcomeLog();
ConnectionBehaviours.setInputBehaviour(new InputBehaviour());
ConnectionBehaviours.setOutputBehaviour(new OutputBehaviour());
Expand Down
26 changes: 20 additions & 6 deletions src/StaticConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class StaticConfiguration {

// Link to the MakeCode firmware template
public static readonly makecodeFirmwareUrl =
'https://makecode.microbit.org/#pub:54705-16835-80762-83855';
'https://makecode.microbit.org/#pub:52042-28239-00563-08630';

public static readonly isMicrobitOutdated = (origin: HexOrigin, version: number) => {
// Current versions, remember to update these, whenever changes to firmware are made!
Expand All @@ -58,13 +58,22 @@ class StaticConfiguration {
};

// Line colors are picked in the order of this array.
public static readonly liveGraphColors = ['#f9808e', '#80f98e', '#808ef9'];
public static readonly liveGraphColors = [
'#ff606e',
'#30f09e',
'#3030ff',
'#58355E',
'#E0FF4F',
'#FF2ECC',
'#F28F3B',
'#C8553D',
];

// Colors to assign to gestures, useful for identifying gestures on graphs.
public static readonly gestureColors = [
'#FCA311',
'#65334D',
'#CB04A5',
'#00ff81',
'#b1e400',
'#ADFCF9',
'#89A894',
'#4B644A',
Expand Down Expand Up @@ -114,7 +123,9 @@ class StaticConfiguration {
*/
public static readonly minNoOfGestures = 2;

// The settings given to the LayersModelTrainer
/**
* The neural network training settings
*/
public static readonly layersModelTrainingSettings: LayersModelTrainingSettings = {
noOfEpochs: 80,
batchSize: 16,
Expand All @@ -123,6 +134,9 @@ class StaticConfiguration {
noOfUnits: 16, // size of hidden layer
};

public static readonly knnNeighbourCount = 3;
/**
* How many samples should the KNN model use for prediction? i.e the k-value.
*/
public static readonly defaultKnnNeighbourCount = 3;
}
export default StaticConfiguration;
32 changes: 16 additions & 16 deletions src/__tests__/classifier.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,37 @@
* SPDX-License-Identifier: MIT
*/

import { classifier, gestures } from '../script/stores/Stores';
import { stores } from '../script/stores/Stores';
import TestMLModelTrainer from './mocks/mlmodel/TestMLModelTrainer';

describe('Classifier tests', () => {
test('Changing matrix does not mark model as untrained', async () => {
const gesture = gestures.createGesture('some gesture');
gestures.createGesture('some gesture2');
await classifier.getModel().train(new TestMLModelTrainer(2));
const gesture = stores.getGestures().createGesture('some gesture');
stores.getGestures().createGesture('some gesture2');
await stores.getClassifier().getModel().train(new TestMLModelTrainer(2));

gesture.setLEDOutput(new Array(25).fill(false) as boolean[]);
expect(classifier.getModel().isTrained()).toBe(true);
expect(stores.getClassifier().getModel().isTrained()).toBe(true);
});

test('Adding gesture marks model as untrained', async () => {
gestures.createGesture('some gesture');
gestures.createGesture('some gesture2');
await classifier.getModel().train(new TestMLModelTrainer(2));
stores.getGestures().createGesture('some gesture');
stores.getGestures().createGesture('some gesture2');
await stores.getClassifier().getModel().train(new TestMLModelTrainer(2));

gestures.createGesture('Added gesture');
stores.getGestures().createGesture('Added gesture');

expect(classifier.getModel().isTrained()).toBe(false);
expect(stores.getClassifier().getModel().isTrained()).toBe(false);
});

test('Removing gesture marks model as untrained', async () => {
gestures.createGesture('some gesture');
gestures.createGesture('some gesture2');
const gesture3 = gestures.createGesture('some gesture2');
await classifier.getModel().train(new TestMLModelTrainer(2));
stores.getGestures().createGesture('some gesture');
stores.getGestures().createGesture('some gesture2');
const gesture3 = stores.getGestures().createGesture('some gesture2');
await stores.getClassifier().getModel().train(new TestMLModelTrainer(2));

gestures.removeGesture(gesture3.getId());
stores.getGestures().removeGesture(gesture3.getId());

expect(classifier.getModel().isTrained()).toBe(false);
expect(stores.getClassifier().getModel().isTrained()).toBe(false);
});
});
Loading

0 comments on commit dba27e1

Please sign in to comment.