Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ The front end of the project is built with [Preact](https://preactjs.com/).
To work on the project, you need to install [NodeJS and NPM](https://nodejs.org/en/download/)
for your operating system.

_**Note:** If you'd like to make use of RAG (optional), you'll also need to ensure that [CMake](http://cmake.org)
is installed. CMake is required for installing `faiss` which is pulled in by the optional depenency `faiss-node`._

Then, clone the project from GitHub. [Create a fork](https://help.github.com/en/github/getting-started-with-github/fork-a-repo)
with your GitHub account, then enter the following in your command line
(make sure to replace `your-username` with your username):
Expand All @@ -27,6 +30,10 @@ to install dependencies:
npm ci
```

_**Note:** If CMake is not available on the device, the optional dependency `faiss-node` will fail to install but
will not prevent the application from installing. However, if you wish to use RAG, you'll need to install CMake and
re-run `npm ci`._

## Development

### Start a Server
Expand Down Expand Up @@ -90,6 +97,12 @@ Follow these steps to complete a one-time setup to enable RAG in the system:

Follow the instruction in the [Start a Server](./README.md#start-a-server) section.

#### Troubleshooting

In order to use RAG, `fais-node` must be installed. `faise-node` is an optional dependency and requires that
[CMake](https://cmake.org/) be installed on the machine first. If this has not been done, install CMake and re-run
the application install steps.

### Lint

To lint the source code, run:
Expand Down
9 changes: 7 additions & 2 deletions package-lock.json

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

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
"@xenova/transformers": "^2.17.2",
"bliss-svg-builder": "^0.1.0-alpha.10",
"express": "^4.19.2",
"faiss-node": "^0.5.1",
"htm": "^3.1.1",
"ollama": "^0.5.8",
"preact": "^10.23.2",
"sass": "^1.77.8 ",
"serve-static": "^1.15.0"
},
"optionalDependencies": {
"faiss-node": "^0.5.1"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the README to indicate the RAG support is optional. Can you also document the npm install commands for enabling or skipping this functionality.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cindyli I added some information in the README. Please let me know if it makes sense or if you'd like further changes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The update on README looks good to me. Thanks, @jobara.

},
"devDependencies": {
"@babel/preset-env": "^7.25.4",
"@eslint/eslintrc": "^3.1.0",
Expand Down
12 changes: 2 additions & 10 deletions src/client/CommandCursorBackward.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import { VNode } from "preact";
import { html } from "htm/preact";
import { BlissSymbol } from "./BlissSymbol";
import { changeEncodingContents } from "./GlobalData";
import { decrementCursor } from "./ContentBmwEncoding";
import { BlissSymbolInfoType, LayoutInfoType } from "./index.d";
import { generateGridStyle, speak } from "./GlobalUtils";

Expand All @@ -33,15 +33,7 @@ export function CommandCursorBackward (props: CommandCursorBackwardProps): VNode
const gridStyles = generateGridStyle(columnStart, columnSpan, rowStart, rowSpan);

const cellClicked = (): void => {
// Move the caret position back one. Note that the new caretPosition can
// equal -1 indicating that the caret is before the first symbol in the
// `payloads` array. But, it cannot be less than -1.
if (changeEncodingContents.value.caretPosition > -1) {
changeEncodingContents.value = {
payloads: changeEncodingContents.value.payloads,
caretPosition: changeEncodingContents.value.caretPosition - 1
};
}
decrementCursor();
speak(label);
};

Expand Down
9 changes: 2 additions & 7 deletions src/client/CommandCursorForward.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import { VNode } from "preact";
import { html } from "htm/preact";
import { BlissSymbol } from "./BlissSymbol";
import { changeEncodingContents } from "./GlobalData";
import { incrementCursor } from "./ContentBmwEncoding";
import { BlissSymbolInfoType, LayoutInfoType } from "./index.d";
import { generateGridStyle, speak } from "./GlobalUtils";

Expand All @@ -33,12 +33,7 @@ export function CommandCursorForward (props: CommandCursorForwardProps): VNode {
const gridStyles = generateGridStyle(columnStart, columnSpan, rowStart, rowSpan);

const cellClicked = (): void => {
if (changeEncodingContents.value.caretPosition < changeEncodingContents.value.payloads.length - 1) {
changeEncodingContents.value = {
payloads: changeEncodingContents.value.payloads,
caretPosition: changeEncodingContents.value.caretPosition + 1
};
}
incrementCursor();
speak(label);
};

Expand Down
2 changes: 1 addition & 1 deletion src/client/ContentBmwEncoding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import { render, screen } from "@testing-library/preact";
import "@testing-library/jest-dom";
import { html } from "htm/preact";
import { ContentBmwEncoding } from "./ContentBmwEncoding";
import { ContentBmwEncoding, } from "./ContentBmwEncoding";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extraneous trailing comma after ContentBmwEncoding.

import { initAdaptivePaletteGlobals } from "./GlobalData";

test("The BMW Encoding content area is rendered correctly", async (): Promise<void> => {
Expand Down
42 changes: 40 additions & 2 deletions src/client/ContentBmwEncoding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { html } from "htm/preact";
import { BlissSymbol } from "./BlissSymbol";
import { changeEncodingContents } from "./GlobalData";
import { ContentBmwEncodingType, EncodingType } from "./index.d";
import { generateGridStyle } from "./GlobalUtils";
import { generateGridStyle, clamp } from "./GlobalUtils";
import "./ContentBmwEncoding.scss";

export const INPUT_AREA_ID = "bmw-encoding-area"; // better way?
Expand Down Expand Up @@ -66,6 +66,36 @@ function generateMarkupArray (payloadArray: Array<EncodingType>, caretPos: numbe
});
}

export function moveCursor (positionChange = 1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Provide the type of positionChange (number).

positionChange = Math.round(positionChange);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I think the use of Math.round() here is a good idea in general, I'm not sure it's necessary in this case.

First, the moveCursor() function is only used within this file, by incrementCursor() and decrementCursor(). It need not be exported.

Secondly, since the calling functions always pass 1 or -1, is it necessary to round the argument?

If it were exported because of broader use, then rounding is useful.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you saying that moveCursor also shouldn't be imported? I have it exported in case you may want to use it later, maybe with something like home and end functions, or maybe there will be some need to jump to different parts of a phrase.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm saying that moveCursor() is not in fact imported anywhere now. My rule of thumb is to not export functions/data when exporting is unnecessary. If it turns out later that an export is needed, then it can be done at that point, along with the changes that made it a requirement.

Regarding home, end, and other related potential functions, they might be defined here locally the way incrementCursor() and decrementCursor() are. If so, moveCursor() would not need to be exported in that case either.

But you are also giving me ideas. Would you like to extend this PR to include the home and end keystrokes? They strike me as useful.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added keyboard handlers for home and end.


// Note: the new caretPosition can equal -1 indicating that the caret is before the
// first symbol in the `payloads` array. But, it cannot be less than -1.
const newPosition = clamp(changeEncodingContents.value.caretPosition + positionChange, -1, changeEncodingContents.value.payloads.length - 1);
changeEncodingContents.value = {
payloads: changeEncodingContents.value.payloads,
caretPosition: newPosition
};
};

export function incrementCursor () {
moveCursor(1);
}

export function decrementCursor () {
moveCursor(-1);
}

function handleKeyDown(event: KeyboardEvent) {
if (event.key === "ArrowLeft" || event.key === "ArrowDown") {
decrementCursor();
}

if (event.key === "ArrowRight" || event.key === "ArrowUp") {
incrementCursor();
}
}

export function ContentBmwEncoding (props: ContentBmwEncodingProps): VNode {
const { id, options } = props;
const { columnStart, columnSpan, rowStart, rowSpan } = options;
Expand All @@ -76,7 +106,15 @@ export function ContentBmwEncoding (props: ContentBmwEncodingProps): VNode {
);

return html`
<div id="${id}" class="bmwEncodingArea" role="textbox" aria-label="Input Area" aria-readonly="true" style="${gridStyles}">
<div
id="${id}"
class="bmwEncodingArea"
role="textbox"
aria-label="Input Area"
aria-readonly="true"
style="${gridStyles}"
tabindex="0"
onKeyDown=${handleKeyDown}>
${contentsMarkupArray}
</div>
`;
Expand Down
14 changes: 13 additions & 1 deletion src/client/GlobalUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,24 @@
* https://github.com/inclusive-design/adaptive-palette/blob/main/LICENSE
*/

import { generateGridStyle } from "./GlobalUtils";
import { generateGridStyle, clamp } from "./GlobalUtils";

describe("Test global utility functions", (): void => {

test("Test generateGridStyle()", (): void => {
expect(generateGridStyle(2, 1, 3, 2)).toBe("grid-column: 2 / span 1;grid-row: 3 / span 2;");
expect(generateGridStyle(undefined, undefined, undefined, undefined)).toBe("grid-column: undefined / span undefined;grid-row: undefined / span undefined;");
});

test("Test clamp function where value is below min", (): void => {
expect(clamp(-1, 0, 1)).toBe(0);
});

test("Test clamp function where value is above max", (): void => {
expect(clamp(2, 0, 1)).toBe(1);
});

test("Test clamp function where value is in range", (): void => {
expect(clamp(1, 0, 2)).toBe(1);
});
});
19 changes: 18 additions & 1 deletion src/client/GlobalUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,26 @@ function insertWordAtCaret (wordToAdd: SymbolEncodingType, symbolSet: SymbolEnco
return newSymbolSet;
}

/**
* Returns the inputted value constrained to the `min` and `max` values.
* The returned value will:
* - `min` if `value` was less than `min`
* - `max` if the `value` was greater than `max`
* - `value` if it fell within the `min` `max` range.
*
* @param {number} value - The value to evaluate
* @param {number} min - The minimum value to be returned
* @param {number} max - The maximum value to be returned
* @returns {number} - The constrained value
*/
function clamp (value: number, min: number, max: number) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note -- no change necessary. I thought that a clamp() function might already exist as a built-in within TypeScript or JavaScript, and asked duck.ai if there was one. Its reply was that there was none, and then provided the code. It was the same as yours, but without the type declarations. So, your implementation must be right :-)

return Math.min(Math.max(value, min), max);
}

export {
generateGridStyle,
speak,
loadPaletteFromJsonFile,
insertWordAtCaret
insertWordAtCaret,
clamp
};