From b440901843a930c6c87ec23c59f90f1349c25b50 Mon Sep 17 00:00:00 2001 From: IEatChili Date: Thu, 6 Jun 2024 15:23:12 -0400 Subject: feat: updated ui --- .../collectionFreeForm/ImageLabelBox.scss | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/client/views/collections/collectionFreeForm/ImageLabelBox.scss (limited to 'src/client/views/collections/collectionFreeForm/ImageLabelBox.scss') diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss b/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss new file mode 100644 index 000000000..d0c12814c --- /dev/null +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss @@ -0,0 +1,26 @@ +.image-label-list { + display: flex; + flex-direction: column; + align-items: center; // Centers the content vertically in the flex container + width: 100%; + + > div { + display: flex; + justify-content: space-between; // Puts the content and delete button on opposite ends + align-items: center; + width: 100%; + margin-top: 8px; // Adds space between label rows + background-color: black; + + p { + text-align: center; // Centers the text of the paragraph + font-size: large; + vertical-align: middle; + } + + .IconButton { + // Styling for the delete button + margin-left: auto; // Pushes the button to the far right + } + } +} -- cgit v1.2.3-70-g09d2 From 56568bbb0db34c0129b6a3c8770ce3f889dcbd31 Mon Sep 17 00:00:00 2001 From: IEatChili Date: Mon, 10 Jun 2024 11:06:02 -0400 Subject: feat: ui changes --- package-lock.json | 6 +++ package.json | 1 + .../collectionFreeForm/ImageLabelBox.scss | 23 +++++++++ .../collectionFreeForm/ImageLabelBox.tsx | 60 ++++++++++++++++++---- .../collectionFreeForm/MarqueeOptionsMenu.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 9 ++-- 6 files changed, 86 insertions(+), 15 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/ImageLabelBox.scss') diff --git a/package-lock.json b/package-lock.json index 9b3904ff7..6cd2ab605 100644 --- a/package-lock.json +++ b/package-lock.json @@ -136,6 +136,7 @@ "js-datepicker": "^5.18.2", "jsonschema": "^1.4.1", "jszip": "^3.10.1", + "ldrs": "^1.0.2", "lodash": "^4.17.21", "mapbox-gl": "^3.0.1", "markdown-it": "^14.1.0", @@ -23613,6 +23614,11 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/ldrs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ldrs/-/ldrs-1.0.2.tgz", + "integrity": "sha512-sYJmivdkIiHrUEqTrEWccBoLdaENpzbzkABI5rk8rRxTXrg9i2xVuDvUUuhOhJY3RmQyaoxs046pM1DCRdcIpg==" + }, "node_modules/leac": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", diff --git a/package.json b/package.json index ed05c4f45..bbd2a4c46 100644 --- a/package.json +++ b/package.json @@ -221,6 +221,7 @@ "js-datepicker": "^5.18.2", "jsonschema": "^1.4.1", "jszip": "^3.10.1", + "ldrs": "^1.0.2", "lodash": "^4.17.21", "mapbox-gl": "^3.0.1", "markdown-it": "^14.1.0", diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss b/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss index d0c12814c..5f2ce4e14 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss @@ -1,3 +1,18 @@ +.image-box-container { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + font-size: 10px; + line-height: 1; + background: none; + z-index: 1000; + padding: 0px; + overflow: auto; + cursor: default; +} + .image-label-list { display: flex; flex-direction: column; @@ -16,6 +31,7 @@ text-align: center; // Centers the text of the paragraph font-size: large; vertical-align: middle; + margin-left: 10px; } .IconButton { @@ -24,3 +40,10 @@ } } } + +.image-information { + display: flex; + flex-direction: column; + //align-items: center; + width: 100%; +} diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index 1c0035f0d..83ae69cfb 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -12,6 +12,11 @@ import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './ImageLabelBox.scss'; import { MainView } from '../../MainView'; import { MarqueeView } from './MarqueeView'; +import 'ldrs/ring'; +import { ring } from 'ldrs'; +import { SnappingManager } from '../../../util/SnappingManager'; +import { ImageCast } from '../../../../fields/Types'; +import { DocData } from '../../../../fields/DocSymbols'; @observer export class ImageLabelBox extends ViewBoxBaseComponent() { @@ -24,12 +29,14 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { @observable _loading: boolean = true; @observable _currentLabel: string = ''; @observable _labelGroups: string[] = []; + @observable _selectedImages: Doc[] = []; + @observable _displayImageInformation: boolean = false; constructor(props: any) { super(props); makeObservable(this); ImageLabelBox.Instance = this; - + ring.register(); console.log('Image Box Has Been Initialized'); } @@ -77,14 +84,32 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { this._loading = false; }; + @action + setSelectedImages = (selected: Doc[]) => { + this._selectedImages = selected; + }; + render() { if (this._loading) { - return
Loading...
; + return ( +
+ +
+ ); } return ( -
-
+
+
+ { + this._displayImageInformation = !this._displayImageInformation; + }} + icon={this._displayImageInformation ? : } + color={MarqueeOptionsMenu.Instance.userColor} + style={{ width: '19px' }} + /> () { // e.stopPropagation(); // }} type="text" - placeholder="Input a group to put images into..." + placeholder="Input labels for image groupings..." aria-label="label-input" id="new-label" className="searchBox-input" @@ -101,7 +126,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { ref={this._inputRef} /> { const input = document.getElementById('new-label') as HTMLInputElement; const newLabel = input.value; @@ -113,11 +138,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { color={MarqueeOptionsMenu.Instance.userColor} style={{ width: '19px' }} /> - {this._labelGroups.length > 0 ? ( - } color={MarqueeOptionsMenu.Instance.userColor} style={{ width: '19px' }} /> - ) : ( -
- )} + {this._labelGroups.length > 0 ? } color={Colors.MEDIUM_BLUE} style={{ width: '19px' }} /> :
}
@@ -139,6 +160,23 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { })}
+ {this._displayImageInformation ? ( +
+ {this._selectedImages.map(doc => { + const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); + return ( +
+ + {(doc[DocData].data_labels as string).split('\n').map(label => { + return
{label}
; + })} +
+ ); + })} +
+ ) : ( +
+ )}
); } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index f02cd9d45..b94a22d04 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -39,7 +39,7 @@ export class MarqueeOptionsMenu extends AntimodeMenu { } color={this.userColor} /> } color={this.userColor} /> } color={this.userColor} /> - } color={this.userColor} /> + } color={this.userColor} /> ); return this.getElement(buttons); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index bb5a2a66e..f98883bff 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -456,6 +456,7 @@ export class MarqueeView extends ObservableReactComponent { if (!doc[DocData].data_labels) { @@ -478,7 +479,7 @@ export class MarqueeView extends ObservableReactComponent Date: Wed, 12 Jun 2024 12:32:19 -0400 Subject: feat: updated and fixed ui --- src/client/util/CurrentUserUtils.ts | 2 +- src/client/views/MainView.tsx | 2 +- .../collectionFreeForm/ImageLabelBox.scss | 40 +++++- .../collectionFreeForm/ImageLabelBox.tsx | 159 +++++++++++++++------ .../collections/collectionFreeForm/MarqueeView.tsx | 46 +----- 5 files changed, 164 insertions(+), 85 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm/ImageLabelBox.scss') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 486b6815a..cb3d9df62 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -458,7 +458,7 @@ pie title Minerals in my tap water { title: "Shared", toolTip: "Shared Docs", target: Doc.MySharedDocs, ignoreClick: true, icon: "users", funcs: {badgeValue: badgeValue}}, { title: "Trails", toolTip: "Trails ⌘R", target: Doc.UserDoc(), ignoreClick: true, icon: "pres-trail", funcs: {target: getActiveDashTrails}}, { title: "User Doc", toolTip: "User Doc", target: this.setupUserDocView(doc, "myUserDocView"), ignoreClick: true, icon: "address-card",funcs: {hidden: "IsNoviceMode()"} }, - { title: "Image Grouper", toolTip: "Image Grouper", target: this.setupImageGrouper(doc, "myImageGrouper"), ignoreClick: true, icon: "folder-open", hidden: true } + { title: "Image Grouper", toolTip: "Image Grouper", target: this.setupImageGrouper(doc, "myImageGrouper"), ignoreClick: true, icon: "folder-open", hidden: false } ].map(tuple => ({...tuple, scripts:{onClick: 'selectMainMenu(this)'}})); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 5b4c2b5ba..716edc22d 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -76,7 +76,7 @@ import { PresBox } from './nodes/trails'; import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; -import { ImageLabelBox } from './collections/collectionFreeForm/ImageLabelBox'; +import { ImageLabelBox, ImageLabelBoxData } from './collections/collectionFreeForm/ImageLabelBox'; const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore const _global = (window /* browser */ || global) /* node */ as any; diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss b/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss index 5f2ce4e14..819c72760 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.scss @@ -41,9 +41,45 @@ } } -.image-information { +.image-information-list { display: flex; flex-direction: column; - //align-items: center; + align-items: center; + width: 100%; + margin-top: 10px; +} + +.image-information { + border: 1px solid; width: 100%; + display: inline-flex; + flex-direction: column; + justify-content: center; + align-items: center; + overflow: hidden; + padding: 2px; + overflow-x: auto; + overflow-y: auto; + + img { + max-width: 200px; + max-height: 200px; + width: auto; + height: auto; + } +} + +.image-information-labels { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + .image-label { + margin-top: 5px; + margin-bottom: 5px; + padding: 3px; + border-radius: 2px; + border: solid 1px; + } } diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index 83ae69cfb..f5530ccc4 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Colors, IconButton } from 'browndash-components'; -import { action, makeObservable, observable } from 'mobx'; +import { action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; import { Doc } from '../../../../fields/Doc'; @@ -11,12 +11,51 @@ import { FieldView, FieldViewProps } from '../../nodes/FieldView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './ImageLabelBox.scss'; import { MainView } from '../../MainView'; -import { MarqueeView } from './MarqueeView'; import 'ldrs/ring'; import { ring } from 'ldrs'; import { SnappingManager } from '../../../util/SnappingManager'; import { ImageCast } from '../../../../fields/Types'; import { DocData } from '../../../../fields/DocSymbols'; +import { SettingsManager } from '../../../util/SettingsManager'; +import { CollectionCardView } from '../CollectionCardDeckView'; +import { gptGetEmbedding, gptImageLabel } from '../../../apis/gpt/GPT'; +import { numberRange, Utils } from '../../../../Utils'; +import { List } from '../../../../fields/List'; + +export class ImageLabelBoxData { + static _instance: ImageLabelBoxData; + @observable _docs: Doc[] = []; + @observable _labelGroups: string[] = []; + + constructor() { + makeObservable(this); + ImageLabelBoxData._instance = this; + } + public static get Instance() { + return ImageLabelBoxData._instance ?? new ImageLabelBoxData(); + } + + @action + public setData = (docs: Doc[]) => { + this._docs = docs; + }; + + @action + addLabel = (label: string) => { + label = label.toUpperCase().trim(); + if (label.length > 0) { + if (!this._labelGroups.includes(label)) { + this._labelGroups = [...this._labelGroups, label]; + } + } + }; + + @action + removeLabel = (label: string) => { + const labelUp = label.toUpperCase(); + this._labelGroups = this._labelGroups.filter(group => group !== labelUp); + }; +} @observer export class ImageLabelBox extends ViewBoxBaseComponent() { @@ -24,59 +63,53 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(ImageLabelBox, fieldKey); } - public static Instance: ImageLabelBox | null = null; + public static Instance: ImageLabelBox; private _inputRef = React.createRef(); - @observable _loading: boolean = true; - @observable _currentLabel: string = ''; - @observable _labelGroups: string[] = []; - @observable _selectedImages: Doc[] = []; + @observable _loading: boolean = false; + private _currentLabel: string = ''; + + @computed get _labelGroups() { + return ImageLabelBoxData.Instance._labelGroups; + } + + @computed get _selectedImages() { + // return DocListCast(this.dataDoc.data); + return ImageLabelBoxData.Instance._docs; + } @observable _displayImageInformation: boolean = false; constructor(props: any) { super(props); makeObservable(this); - ImageLabelBox.Instance = this; ring.register(); + ImageLabelBox.Instance = this; console.log('Image Box Has Been Initialized'); } + // ImageLabelBox.Instance.setData() /** * This method is called when the SearchBox component is first mounted. When the user opens * the search panel, the search input box is automatically selected. This allows the user to * type in the search input box immediately, without needing clicking on it first. */ componentDidMount() { - // if (this._inputRef.current) { - // this._inputRef.current.focus(); - // } + this.classifyImagesInBox(); + reaction( + () => this._selectedImages, + () => this.classifyImagesInBox() + ); } - @action - addLabel = (label: string) => { - label = label.toUpperCase().trim(); - if (label.length > 0) { - if (!this._labelGroups.includes(label)) { - this._labelGroups = [...this._labelGroups, label]; - } - } - }; - - @action - removeLabel = (label: string) => { - const labelUp = label.toUpperCase(); - this._labelGroups = this._labelGroups.filter(group => group !== labelUp); - }; - @action groupImages = () => { MarqueeOptionsMenu.Instance.groupImages(); - this._labelGroups = []; MainView.Instance.closeFlyout(); }; @action startLoading = () => { this._loading = true; + console.log('Start loading has been called!'); }; @action @@ -85,8 +118,38 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { }; @action - setSelectedImages = (selected: Doc[]) => { - this._selectedImages = selected; + toggleDisplayInformation = () => { + this._displayImageInformation = !this._displayImageInformation; + }; + + onInputChange = action((e: React.ChangeEvent) => { + this._currentLabel = e.target.value; + }); + + classifyImagesInBox = async () => { + this.startLoading(); + + const imageInfos = this._selectedImages.map(async doc => { + if (!doc[DocData].data_labels) { + const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); + return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => + !hrefBase64 ? undefined : + gptImageLabel(hrefBase64).then(labels => + Promise.all(labels.split('\n').map(label => gptGetEmbedding(label))).then(embeddings => + ({ doc, embeddings, labels }))) ); // prettier-ignore + } + }); // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them. + + (await Promise.all(imageInfos)).forEach(imageInfo => { + if (imageInfo && imageInfo.embeddings && Array.isArray(imageInfo.embeddings)) { + imageInfo.doc[DocData].data_labels = imageInfo.labels; + numberRange(3).forEach(n => { + imageInfo.doc[`data_labels_embedding_${n + 1}`] = new List(imageInfo.embeddings[n]); + }); + } + }); // Add the labels as fields to each image. + + this.endLoading(); }; render() { @@ -98,14 +161,20 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { ); } + if (this._selectedImages.length === 0) { + return ( +
+

In order to classify and sort images, marquee select the desired images and press the 'Classify and Sort Images' button. Then, add the desired groups for the images to be put in.

+
+ ); + } + return (
{ - this._displayImageInformation = !this._displayImageInformation; - }} + onPointerDown={this.toggleDisplayInformation} icon={this._displayImageInformation ? : } color={MarqueeOptionsMenu.Instance.userColor} style={{ width: '19px' }} @@ -113,6 +182,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { { // e.key === 'Enter' ? this.submitSearch() : null; // e.stopPropagation(); @@ -129,8 +199,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { tooltip={'Add a label'} onPointerDown={() => { const input = document.getElementById('new-label') as HTMLInputElement; - const newLabel = input.value; - this.addLabel(newLabel); + ImageLabelBoxData.Instance.addLabel(this._currentLabel); this._currentLabel = ''; input.value = ''; }} @@ -144,12 +213,12 @@ export class ImageLabelBox extends ViewBoxBaseComponent() {
{this._labelGroups.map(group => { return ( -
+

{group}

{ - this.removeLabel(group); + ImageLabelBoxData.Instance.removeLabel(group); }} icon={'x'} color={MarqueeOptionsMenu.Instance.userColor} @@ -161,15 +230,21 @@ export class ImageLabelBox extends ViewBoxBaseComponent() {
{this._displayImageInformation ? ( -
+
{this._selectedImages.map(doc => { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return ( -
+
- {(doc[DocData].data_labels as string).split('\n').map(label => { - return
{label}
; - })} +
+ {(doc[DocData].data_labels as string).split('\n').map(label => { + return ( +
+ {label} +
+ ); + })} +
); })} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index f98883bff..81f2a94c1 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -37,7 +37,7 @@ import { ImageLabelHandler } from './ImageLabelHandler'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; import { MainView } from '../../MainView'; -import { ImageLabelBox } from './ImageLabelBox'; +import { ImageLabelBox, ImageLabelBoxData } from './ImageLabelBox'; import { SearchBox } from '../../search/SearchBox'; interface MarqueeViewProps { @@ -442,44 +442,12 @@ export class MarqueeView extends ObservableReactComponent { - if (e) { - const groupButton = DocListCast(Doc.MyLeftSidebarMenu.data).find(d => d.target === Doc.MyImageGrouper); - if (groupButton) { - MainView.Instance.expandFlyout(groupButton); - while (!ImageLabelBox.Instance) { - await new Promise(resolve => setTimeout(resolve, 1000)).then(() => { - console.log('Waiting for Image Label Box'); - }); - } - ImageLabelBox.Instance.startLoading(); - } + const groupButton = DocListCast(Doc.MyLeftSidebarMenu.data).find(d => d.target === Doc.MyImageGrouper); + if (groupButton) { + this._selectedDocs = this.marqueeSelect(false, DocumentType.IMG); + ImageLabelBoxData.Instance.setData(this._selectedDocs); + MainView.Instance.expandFlyout(groupButton); } - - this._selectedDocs = this.marqueeSelect(false, DocumentType.IMG); // Get the selected documents from the marquee select. - ImageLabelBox.Instance!.setSelectedImages(this._selectedDocs); - - const imageInfos = this._selectedDocs.map(async doc => { - if (!doc[DocData].data_labels) { - const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); - return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => - !hrefBase64 ? undefined : - gptImageLabel(hrefBase64).then(labels => - Promise.all(labels.split('\n').map(label => gptGetEmbedding(label))).then(embeddings => - ({ doc, embeddings, labels }))) ); // prettier-ignore - } - }); // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them. - - (await Promise.all(imageInfos)).forEach(imageInfo => { - if (imageInfo && imageInfo.embeddings && Array.isArray(imageInfo.embeddings)) { - imageInfo.doc[DocData].data_labels = imageInfo.labels; - numberRange(3).forEach(n => { - imageInfo.doc[`data_labels_embedding_${n + 1}`] = new List(imageInfo.embeddings[n]); - }); - } - }); // Add the labels as fields to each image. - - ImageLabelBox.Instance!.endLoading(); - console.log(this._selectedDocs); }); /** @@ -496,7 +464,7 @@ export class MarqueeView extends ObservableReactComponent { const embedLists = numberRange(3).map(n => Array.from(NumListCast(doc[`data_labels_embedding_${n + 1}`]))); - const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map(l => (embedding && similarity(Array.from(embedding), l)) || 0)); + const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map((l, index) => (embedding && (1 - index * 0.1) * similarity(Array.from(embedding), l)!) || 0)); const {label: mostSimilarLabelCollect} = labelGroups.map(label => ({ label, similarityScore: bestEmbedScore(labelToEmbedding.get(label)) })) .reduce((prev, cur) => cur.similarityScore < 0.3 || cur.similarityScore <= prev.similarityScore ? prev: cur, -- cgit v1.2.3-70-g09d2