-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(opentrons-ai-client, opentrons-ai-server): add folders for opent…
…rons-ai (#14788) * feat(opentrons-ai-client, opentrons-ai-server): add folders for opentrons-ai
- Loading branch information
Showing
24 changed files
with
527 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# opentrons ai client makefile | ||
|
||
# using bash instead of /bin/bash in SHELL prevents macOS optimizing away our PATH update | ||
SHELL := bash | ||
|
||
# add node_modules/.bin to PATH | ||
PATH := $(shell cd .. && yarn bin):$(PATH) | ||
|
||
benchmark_output := $(shell node -e 'console.log(new Date());') | ||
|
||
# These variables can be overriden when make is invoked to customize the | ||
# behavior of jest | ||
tests ?= | ||
cov_opts ?= --coverage=true | ||
test_opts ?= | ||
|
||
# standard targets | ||
##################################################################### | ||
|
||
.PHONY: all | ||
all: clean build | ||
|
||
.PHONY: setup | ||
setup: | ||
yarn | ||
|
||
.PHONY: clean | ||
clean: | ||
shx rm -rf dist | ||
|
||
# artifacts | ||
##################################################################### | ||
|
||
.PHONY: build | ||
build: export NODE_ENV := production | ||
build: | ||
vite build | ||
git rev-parse HEAD > dist/.commit | ||
|
||
# development | ||
##################################################################### | ||
|
||
.PHONY: dev | ||
dev: export NODE_ENV := development | ||
dev: | ||
vite serve | ||
|
||
# production assets server | ||
.PHONY: serve | ||
serve: all | ||
node ../scripts/serve-static dist | ||
|
||
.PHONY: test | ||
test: | ||
$(MAKE) -C .. test-js-ai-client tests="$(tests)" test_opts="$(test_opts)" | ||
|
||
.PHONY: test-cov | ||
test-cov: | ||
make -C .. test-js-ai-client tests=$(tests) test_opts="$(test_opts)" cov_opts="$(cov_opts)" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Opentrons AI Frontend | ||
|
||
[![JavaScript Style Guide][style-guide-badge]][style-guide] | ||
|
||
[Download][] | [Support][] | ||
|
||
## Overview | ||
|
||
The Opentrons AI application helps you to create a protocol with natural language. | ||
|
||
## Developing | ||
|
||
To get started: clone the `Opentrons/opentrons` repository, set up your computer for development as specified in the [contributing guide][contributing-guide-setup], and then: | ||
|
||
```shell | ||
# change into the cloned directory | ||
cd opentrons | ||
# prerequisite: install dependencies as specified in project setup | ||
make setup | ||
# launch the dev server | ||
make -C opentrons-ai-client dev | ||
``` | ||
|
||
## Stack and structure | ||
|
||
The UI stack is built using: | ||
|
||
- [React][] | ||
- [Babel][] | ||
- [Vite][] | ||
|
||
Some important directories: | ||
|
||
- `opentrons-ai-server` — Opentrons AI application's server | ||
|
||
## Copy management | ||
|
||
We use [i18next](https://www.i18next.com) for copy management and internationalization. | ||
|
||
## Testing | ||
|
||
Tests for the Opentrons App are run from the top level along with all other JS project tests. | ||
|
||
- `make test-js` - Run all JavaScript tests | ||
|
||
Test tasks can also be run with the following arguments: | ||
|
||
| Argument | Default | Description | Example | | ||
| -------- | -------- | ----------------------- | --------------------------------- | | ||
| watch | `false` | Run tests in watch mode | `make test-unit watch=true` | | ||
| cover | `!watch` | Calculate code coverage | `make test watch=true cover=true` | | ||
|
||
## Building | ||
|
||
TBD | ||
|
||
[style-guide]: https://standardjs.com | ||
[style-guide-badge]: https://img.shields.io/badge/code_style-standard-brightgreen.svg?style=flat-square&maxAge=3600 | ||
[contributing-guide-setup]: ../CONTRIBUTING.md#development-setup | ||
[contributing-guide-running-the-api]: ../CONTRIBUTING.md#opentrons-api | ||
[react]: https://react.dev/ | ||
[babel]: https://babeljs.io/ | ||
[vite]: https://vitejs.dev/ | ||
[bundle-analyzer]: https://github.com/webpack-contrib/webpack-bundle-analyzer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
'use strict' | ||
|
||
module.exports = { | ||
env: { | ||
// Must have babel-plugin-styled-components in each env, | ||
// see here for further details: s https://styled-components.com/docs/tooling#babel-plugin | ||
production: { | ||
plugins: ['babel-plugin-styled-components', 'babel-plugin-unassert'], | ||
}, | ||
development: { | ||
plugins: ['babel-plugin-styled-components'], | ||
}, | ||
test: { | ||
plugins: [ | ||
// disable ssr, displayName to fix toHaveStyleRule | ||
// https://github.com/styled-components/jest-styled-components/issues/294 | ||
['babel-plugin-styled-components', { ssr: false, displayName: false }], | ||
], | ||
}, | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Opentrons AI</title> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
<script type="module" src="/src/main.tsx"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"name": "opentrons-ai-client", | ||
"type": "module", | ||
"version": "0.0.0-dev", | ||
"description": "Opentrons AI application UI", | ||
"source": "src/index.tsx", | ||
"types": "lib/index.d.ts", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/Opentrons/opentrons.git" | ||
}, | ||
"author": { | ||
"name": "Opentrons Labworks", | ||
"email": "[email protected]" | ||
}, | ||
"license": "Apache-2.0", | ||
"bugs": { | ||
"url": "https://github.com/Opentrons/opentrons/issues" | ||
}, | ||
"homepage": "https://github.com/Opentrons/opentrons", | ||
"dependencies": { | ||
"@fontsource/dejavu-sans": "5.0.3", | ||
"@fontsource/public-sans": "5.0.3", | ||
"@opentrons/components": "link:../components", | ||
"i18next": "^19.8.3", | ||
"react": "18.2.0", | ||
"react-dom": "18.2.0", | ||
"react-error-boundary": "^4.0.10", | ||
"react-i18next": "13.5.0", | ||
"styled-components": "5.3.6" | ||
}, | ||
"engines": { | ||
"node": ">=18.19.0" | ||
}, | ||
"devDependencies": { | ||
"@types/styled-components": "^5.1.26" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import React from 'react' | ||
import { screen } from '@testing-library/react' | ||
import { describe, it } from 'vitest' | ||
|
||
import { renderWithProviders } from './__testing-utils__' | ||
|
||
import { App } from './App' | ||
|
||
const render = (): ReturnType<typeof renderWithProviders> => { | ||
return renderWithProviders(<App />) | ||
} | ||
|
||
describe('App', () => { | ||
it('should render text', () => { | ||
render() | ||
screen.getByText('Opentrons AI') | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import React from 'react' | ||
import { Flex, StyledText } from '@opentrons/components' | ||
export function App(): JSX.Element { | ||
return ( | ||
<Flex> | ||
<StyledText as="h1">Opentrons AI</StyledText> | ||
</Flex> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './renderWithProviders' | ||
export * from './matchers' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import type { Matcher } from '@testing-library/react' | ||
|
||
// Match things like <p>Some <strong>nested</strong> text</p> | ||
// Use with either string match: getByText(nestedTextMatcher("Some nested text")) | ||
// or regexp: getByText(nestedTextMatcher(/Some nested text/)) | ||
export const nestedTextMatcher = (textMatch: string | RegExp): Matcher => ( | ||
content, | ||
node | ||
) => { | ||
const hasText = (n: typeof node): boolean => { | ||
if (n == null || n.textContent === null) return false | ||
return typeof textMatch === 'string' | ||
? Boolean(n?.textContent.match(textMatch)) | ||
: textMatch.test(n.textContent) | ||
} | ||
const nodeHasText = hasText(node) | ||
const childrenDontHaveText = | ||
node != null && Array.from(node.children).every(child => !hasText(child)) | ||
|
||
return nodeHasText && childrenDontHaveText | ||
} | ||
|
||
// need componentPropsMatcher | ||
// need partialComponentPropsMatcher |
53 changes: 53 additions & 0 deletions
53
opentrons-ai-client/src/__testing-utils__/renderWithProviders.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// render using targetted component using @testing-library/react | ||
// with wrapping providers for i18next and redux | ||
import * as React from 'react' | ||
import { QueryClient, QueryClientProvider } from 'react-query' | ||
import { I18nextProvider } from 'react-i18next' | ||
import { Provider } from 'react-redux' | ||
import { vi } from 'vitest' | ||
import { render } from '@testing-library/react' | ||
import { createStore } from 'redux' | ||
|
||
import type { PreloadedState, Store } from 'redux' | ||
import type { RenderOptions, RenderResult } from '@testing-library/react' | ||
|
||
export interface RenderWithProvidersOptions<State> extends RenderOptions { | ||
initialState?: State | ||
i18nInstance: React.ComponentProps<typeof I18nextProvider>['i18n'] | ||
} | ||
|
||
export function renderWithProviders<State>( | ||
Component: React.ReactElement, | ||
options?: RenderWithProvidersOptions<State> | ||
): [RenderResult, Store<State>] { | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions | ||
const { initialState = {}, i18nInstance = null } = options || {} | ||
|
||
const store: Store<State> = createStore( | ||
vi.fn(), | ||
initialState as PreloadedState<State> | ||
) | ||
store.dispatch = vi.fn() | ||
store.getState = vi.fn(() => initialState) as () => State | ||
|
||
const queryClient = new QueryClient() | ||
|
||
const ProviderWrapper: React.ComponentType<React.PropsWithChildren<{}>> = ({ | ||
children, | ||
}) => { | ||
const BaseWrapper = ( | ||
<QueryClientProvider client={queryClient}> | ||
<Provider store={store}>{children}</Provider> | ||
</QueryClientProvider> | ||
) | ||
if (i18nInstance != null) { | ||
return ( | ||
<I18nextProvider i18n={i18nInstance}>{BaseWrapper}</I18nextProvider> | ||
) | ||
} else { | ||
return BaseWrapper | ||
} | ||
} | ||
|
||
return [render(Component, { wrapper: ProviderWrapper }), store] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import shared from './shared.json' | ||
import protocol_generator from './protocol_generator.json' | ||
|
||
export const en = { | ||
shared, | ||
protocol_generator, | ||
} |
23 changes: 23 additions & 0 deletions
23
opentrons-ai-client/src/assets/localization/en/protocol_generator.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"api": "API: An API level is 2.15", | ||
"application": "Application: Your protocol's name, describing what it does.", | ||
"commands": "Commands: List the protocol's steps, specifying quantities in microliters and giving exact source and destination locations.", | ||
"make_sure_your_prompt": "Make sure your prompt includes the following:", | ||
"metadata": "Metadata: Three pieces of information.", | ||
"modules": "Modules: Thermocycler or Temperature Module.", | ||
"opentronsai_asks_you": "OpentronsAI asks you to provide it!", | ||
"ot2_pipettes": "OT-2 pipettes: Include volume, number of channels, and generation.", | ||
"prc_flex": "PRC (Flex)", | ||
"prc": "PCR", | ||
"reagent_transfer_flex": "Reagent Transfer (Flex)", | ||
"reagent_transfer": "Reagent Transfer", | ||
"robot": "Robot: OT-2.", | ||
"sidebar_body": "Write a prompt in natural language to generate a Reagent Transfer or a PCR protocol for the OT-2 or Opentrons Flex using the Opentrons Python Protocol API.", | ||
"sidebar_header": "Use natural language to generate protocols with OpentronsAI powered by OpenAI", | ||
"stuck": "Stuck? Try these example prompts to get started.", | ||
"tipracks_and_labware": "Tip racks and labware: Use names from the Opentrons Labware Library.", | ||
"type_your_prompt": "Type your prompt...", | ||
"well_allocations": "Well allocations: Describe where liquids should go in labware.", | ||
"what_if_you": "What if you don’t provide all of those pieces of information?", | ||
"what_typeof_protocol": "What type of protocol do you need?" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"send": "Send" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { en } from './en' | ||
|
||
export const resources = { | ||
en, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import i18n from 'i18next' | ||
import capitalize from 'lodash/capitalize' | ||
import startCase from 'lodash/startCase' | ||
import { initReactI18next } from 'react-i18next' | ||
import { resources } from './assets/localization' | ||
import { titleCase } from '@opentrons/shared-data' | ||
|
||
i18n.use(initReactI18next).init( | ||
{ | ||
resources, | ||
lng: 'en', | ||
fallbackLng: 'en', | ||
debug: process.env.NODE_ENV === 'development', | ||
ns: ['shared'], | ||
defaultNS: 'shared', | ||
interpolation: { | ||
escapeValue: false, // not needed for react as it escapes by default | ||
format: function (value, format, lng) { | ||
if (format === 'upperCase') return value.toUpperCase() | ||
if (format === 'lowerCase') return value.toLowerCase() | ||
if (format === 'capitalize') return capitalize(value) | ||
if (format === 'sentenceCase') return startCase(value) | ||
if (format === 'titleCase') return titleCase(value) | ||
return value | ||
}, | ||
}, | ||
keySeparator: false, // use namespaces and context instead | ||
saveMissing: true, | ||
missingKeyHandler: (lng, ns, key) => { | ||
process.env.NODE_ENV === 'test' | ||
? console.error(`Missing ${lng} Translation: key={${key}} ns={${ns}}`) | ||
: console.warn(`Missing ${lng} Translation: key={${key}} ns={${ns}}`) | ||
}, | ||
}, | ||
err => { | ||
if (err) { | ||
console.error( | ||
'Internationalization was not initialized properly. error: ', | ||
err | ||
) | ||
} | ||
} | ||
) | ||
|
||
export { i18n } |
Oops, something went wrong.