Skip to content

Commit

Permalink
Use ml tool output with Python Editor POC
Browse files Browse the repository at this point in the history
  • Loading branch information
microbit-robert committed May 23, 2024
1 parent e77d65f commit a8bf451
Show file tree
Hide file tree
Showing 27 changed files with 20,805 additions and 19,427 deletions.
444 changes: 434 additions & 10 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@microbit/microbit-fs": "^0.9.2",
"@sanity/block-content-to-react": "^3.0.0",
"@sanity/image-url": "^1.0.1",
"@tensorflow/tfjs": "^4.19.0",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
Expand Down
33 changes: 18 additions & 15 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import SettingsProvider from "./settings/settings";
import BeforeUnloadDirtyCheck from "./workbench/BeforeUnloadDirtyCheck";
import { SelectionProvider } from "./workbench/use-selection";
import Workbench from "./workbench/Workbench";
import MlDataProvider from "./documentation/ml/use-model-data";

const isMockDeviceMode = () =>
// We use a cookie set from the e2e tests. Avoids having separate test and live builds.
Expand Down Expand Up @@ -76,21 +77,23 @@ const App = () => {
<LanguageServerClientProvider>
<BeforeUnloadDirtyCheck />
<DocumentationProvider>
<SearchProvider>
<SelectionProvider>
<DialogProvider>
<RouterProvider>
<ConsentProvider>
<ProjectDropTarget>
<ActiveEditorProvider>
<Workbench />
</ActiveEditorProvider>
</ProjectDropTarget>
</ConsentProvider>
</RouterProvider>
</DialogProvider>
</SelectionProvider>
</SearchProvider>
<MlDataProvider>
<SearchProvider>
<SelectionProvider>
<DialogProvider>
<RouterProvider>
<ConsentProvider>
<ProjectDropTarget>
<ActiveEditorProvider>
<Workbench />
</ActiveEditorProvider>
</ProjectDropTarget>
</ConsentProvider>
</RouterProvider>
</DialogProvider>
</SelectionProvider>
</SearchProvider>
</MlDataProvider>
</DocumentationProvider>
</LanguageServerClientProvider>
</DeviceContextProvider>
Expand Down
223 changes: 223 additions & 0 deletions src/documentation/ModelArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
/**
* (c) 2021-2022, Micro:bit Educational Foundation and contributors
*
* SPDX-License-Identifier: MIT
*/
import {
Box,
Collapse,
Divider,
Flex,
HStack,
List,
ListItem,
Select,
Stack,
Text,
useDisclosure,
} from "@chakra-ui/react";
import AreaHeading from "../common/AreaHeading";
import HeadedScrollablePanel from "../common/HeadedScrollablePanel";
import { docStyles } from "../common/documentation-styles";
import { useRouterTabSlug } from "../router-hooks";
import DocumentationHeading from "./common/DocumentationHeading";
import ShowMoreButton from "./common/ShowMoreButton";
import Highlight from "./reference/Highlight";
import CodeEmbed from "./common/CodeEmbed";
import OpenButton from "../project/OpenButton";
import { useModelData } from "./ml/use-model-data";
import { ChangeEvent, useCallback, useState } from "react";

interface ModelTopicEntry {
name: string;
text: string;
code: string | ((actionName: string) => string);
slug: string;
detail?: string;
alternativesLabel?: string;
}

const modelTopicEntries: ModelTopicEntry[] = [
{
name: "Class names",
text: "Return the class names of the current model.",
code: "import model\n\n\nnamesList = model.get_class_names()",
slug: "class-names",
},
{
name: "Current action",
text: "Return the current recognised action.",
code: "import model\n\n\ndisplay.scroll(model.current_action())",
slug: "current-action",
},
{
name: "Is action",
text: "Check if an action is currently being performed.",
code: (actionName) =>
`import model\n\n\nwhile True:\n if model.is_action('${actionName}'):\n display.scroll('Yes')`,
slug: "is-action",
detail: "Triggered on the current recognised action.",
alternativesLabel: "Select action:",
},
{
name: "Was action",
text: "Check if an action was performed.",
code: (actionName) =>
`import model\n\n\nwhile True:\n if model.was_action('${actionName}'):\n display.scroll('Yes')`,
slug: "was-action",
detail: "Triggered if the specified action was recognised since last time.",
alternativesLabel: "Select action:",
},
];

const ModelArea = () => {
const [modelData] = useModelData();
return (
<HeadedScrollablePanel
heading={
<AreaHeading
name="Machine learning"
description="Use the machine learning model that was trained"
/>
}
>
<Box
p={5}
pb={1}
fontSize="sm"
sx={{
...docStyles,
}}
>
<Stack spacing={3}>
<Text>Open your data.json file to get started.</Text>
<OpenButton alignSelf="flex-start" fileType="mljson" mode="button" />
</Stack>
</Box>
{modelData.length > 0 && (
<>
<Box
p={5}
pb={1}
fontSize="sm"
sx={{
...docStyles,
}}
>
<Text>Some optional introduction text</Text>
</Box>
<List flex="1 1 auto">
{modelTopicEntries.map((entry) => (
<ListItem key={entry.slug}>
<ModelTopicEntry content={entry} />
<Divider />
</ListItem>
))}
</List>
</>
)}
</HeadedScrollablePanel>
);
};

interface MlItemProps {
content: ModelTopicEntry;
}

const ModelTopicEntry = ({ content }: MlItemProps) => {
const { name, text, slug, code, detail, alternativesLabel } = content;
const hasMore = true;
const disclosure = useDisclosure();
const [anchor] = useRouterTabSlug("model");
const [modelData] = useModelData();
const [selectedAlternative, setSelectedAlternative] = useState<
string | undefined
>(alternativesLabel ? modelData[0].ID.toString() : undefined);
const [processedCode, setProcessedCode] = useState<string>(() => {
return typeof code === "string" ? code : code(modelData[0].name);
});

const handleSelectChange = useCallback(
(e: ChangeEvent<HTMLSelectElement>) => {
const actionName = modelData.find(
(action) => action.ID === parseInt(e.currentTarget.value)
)?.name;
if (actionName && typeof code === "function") {
setProcessedCode(code(actionName));
}
setSelectedAlternative(e.currentTarget.value);
},
[code, modelData]
);
return (
<Highlight
anchor={anchor}
id={name}
active={anchor?.id === slug}
disclosure={disclosure}
>
<Box
fontSize="sm"
p={5}
pr={3}
mt={1}
mb={1}
className="docs-code"
sx={{
...docStyles,
}}
>
<HStack justifyContent="space-between" flexWrap="nowrap">
<DocumentationHeading name={name} isV2Only={false} />
{hasMore && (
<ShowMoreButton
isBrief
onClick={disclosure.onToggle}
isOpen={disclosure.isOpen}
/>
)}
</HStack>
<Stack spacing={3} mt={3}>
<Text noOfLines={disclosure.isOpen ? undefined : 1}>{text}</Text>
{alternativesLabel && (
<Flex wrap="wrap" as="label">
<Text alignSelf="center" mr={2} as="span">
{alternativesLabel}
</Text>
<Select
w="fit-content"
onChange={handleSelectChange}
value={selectedAlternative}
size="sm"
>
{modelData.map((action) => (
<option key={action.ID} value={action.ID}>
{action.name}
</option>
))}
</Select>
</Flex>
)}
<CodeEmbed
code={processedCode}
parentSlug={slug}
toolkitType="model"
/>
</Stack>
{hasMore && (
<Collapse in={disclosure.isOpen}>
<Stack
spacing={3}
pt={detail ? 3 : 0}
noOfLines={!disclosure.isOpen ? 1 : undefined}
>
<Text>{detail}</Text>
</Stack>
</Collapse>
)}
</Box>
</Highlight>
);
};

export default ModelArea;
1 change: 1 addition & 0 deletions src/documentation/common/CodeEmbed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const CodeEmbed = ({
parentSlug,
title,
}: CodeEmbedProps) => {
codeWithImports = codeWithImports.replace("radio.on()", "");
const copyCodeButton = useDisclosure();
const [state, originalSetState] = useState<CodeEmbedState>("default");
// We want to debounce raising so that we don't raise very briefly during scroll.
Expand Down
Loading

0 comments on commit a8bf451

Please sign in to comment.