From a566129971f1a29b1d42679befa27c63b73a7167 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 27 Aug 2024 17:43:27 -0400 Subject: move chat tag labels to tags_chat and updated tagsView --- src/client/views/TagsView.tsx | 32 ++++++++++++++++++++-- .../collectionFreeForm/ImageLabelBox.tsx | 15 +++++----- 2 files changed, 37 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx index d2ca77446..89025d668 100644 --- a/src/client/views/TagsView.tsx +++ b/src/client/views/TagsView.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, Colors, IconButton } from 'browndash-components'; -import { action, computed, makeObservable, observable } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import React from 'react'; import ResizeObserver from 'resize-observer-polyfill'; @@ -248,11 +248,25 @@ export class TagsView extends ObservableReactComponent { makeObservable(this); } + @observable _panelHeightDirty = 0; @observable _currentInput = ''; @observable _isEditing = !StrListCast(this._props.View.dataDoc.tags).length; + _heightDisposer: IReactionDisposer | undefined; + + componentDidMount() { + this._heightDisposer = reaction( + () => this._props.View.screenToContentsTransform(), + xf => { + this._panelHeightDirty = this._panelHeightDirty + 1; + } + ); + } + componentWillUnmount() { + this._heightDisposer?.(); + } @computed get currentScale() { - return NumCast((this._props.View.Document.embedContainer as Doc)?._freeform_scale, 1); + return NumCast(DocCast(this._props.View.Document.embedContainer)?._freeform_scale, 1); } @computed get isEditing() { return this._isEditing && DocumentView.SelectedDocs().includes(this._props.View.Document); @@ -289,11 +303,13 @@ export class TagsView extends ObservableReactComponent { */ render() { const tagsList = new Set(StrListCast(this._props.View.dataDoc.tags)); + const chatTagsList = new Set(StrListCast(this._props.View.dataDoc.tags_chat)); const facesList = new Set( DocListCast(this._props.View.dataDoc[Doc.LayoutFieldKey(this._props.View.Document) + '_annotations']) .filter(d => d.face) .map(doc => StrCast(DocCast(doc.face)?.title)) ); + this._panelHeightDirty; return !this._props.View.Document.showTags ? null : (
{ /> ); })} + {Array.from(chatTagsList).map(tag => { + return ( +
) : null} diff --git a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx index 5d3154e3c..e419e522c 100644 --- a/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx +++ b/src/client/views/collections/collectionFreeForm/ImageLabelBox.tsx @@ -163,7 +163,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { // Converts the images into a Base64 format, afterwhich the information is sent to GPT to label them. const imageInfos = this._selectedImages.map(async doc => { - if (!doc[DocData].tags) { + if (!doc[DocData].tags_chat) { const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.'); return CollectionCardView.imageUrlToBase64(`${name}_o.${type}`).then(hrefBase64 => !hrefBase64 ? undefined : @@ -174,7 +174,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { (await Promise.all(imageInfos)).forEach(imageInfo => { if (imageInfo) { - imageInfo.doc[DocData].tags = (imageInfo.doc[DocData].tags as List) ?? new List(); + imageInfo.doc[DocData].tags_chat = (imageInfo.doc[DocData].tags_chat as List) ?? new List(); const labels = imageInfo.labels.split('\n'); labels.forEach(label => { @@ -184,8 +184,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { .replace(/^\d+\.\s*|-|f\*/, '') .replace(/^#/, '') .trim(); - imageInfo.doc[DocData][label] = true; - (imageInfo.doc[DocData].tags as List).push(label); + (imageInfo.doc[DocData].tags_chat as List).push(label); }); } }); @@ -200,8 +199,8 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { this.startLoading(); for (const doc of this._selectedImages) { - for (let index = 0; index < (doc[DocData].tags as List).length; index++) { - const label = (doc[DocData].tags as List)[index]; + for (let index = 0; index < (doc[DocData].tags_chat as List).length; index++) { + const label = (doc[DocData].tags_chat as List)[index]; const embedding = await gptGetEmbedding(label); doc[DocData][`tags_embedding_${index + 1}`] = new List(embedding); } @@ -214,7 +213,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { // For each image, loop through the labels, and calculate similarity. Associate it with the // most similar one. this._selectedImages.forEach(doc => { - const embedLists = numberRange((doc[DocData].tags as List).length).map(n => Array.from(NumListCast(doc[DocData][`tags_embedding_${n + 1}`]))); + const embedLists = numberRange((doc[DocData].tags_chat as List).length).map(n => Array.from(NumListCast(doc[DocData][`tags_embedding_${n + 1}`]))); const bestEmbedScore = (embedding: Opt) => Math.max(...embedLists.map((l, index) => (embedding && similarity(Array.from(embedding), l)!) || 0)); const {label: mostSimilarLabelCollect} = this._labelGroups.map(label => ({ label, similarityScore: bestEmbedScore(labelToEmbedding.get(label)) })) @@ -321,7 +320,7 @@ export class ImageLabelBox extends ViewBoxBaseComponent() { await DocumentView.showDocument(doc, { willZoomCentered: true }); }}>
this._props.addDocTab(doc, OpenWhere.addRightKeyvalue)}> - {(doc[DocData].tags as List).map(label => { + {(doc[DocData].tags_chat as List).map(label => { return (
{label} -- cgit v1.2.3-70-g09d2 From e2a1db72c103b7ed878fe876c5fb9eacc7a8c893 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 27 Aug 2024 19:09:31 -0400 Subject: enabled any image Doc to be added to a face Doc --- src/client/views/TagsView.tsx | 1 + .../collectionFreeForm/FaceCollectionBox.tsx | 17 +++++++++-------- src/client/views/search/FaceRecognitionHandler.tsx | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx index 89025d668..0ac015b36 100644 --- a/src/client/views/TagsView.tsx +++ b/src/client/views/TagsView.tsx @@ -306,6 +306,7 @@ export class TagsView extends ObservableReactComponent { const chatTagsList = new Set(StrListCast(this._props.View.dataDoc.tags_chat)); const facesList = new Set( DocListCast(this._props.View.dataDoc[Doc.LayoutFieldKey(this._props.View.Document) + '_annotations']) + .concat(this._props.View.Document) .filter(d => d.face) .map(doc => StrCast(DocCast(doc.face)?.title)) ); diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx index c62303dc0..717081666 100644 --- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx +++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx @@ -95,17 +95,18 @@ export class UniqueFaceBox extends ViewBoxBaseComponent() { const faceDescriptorsAsFloat32Array = FaceRecognitionHandler.UniqueFaceDescriptors(this.Document).map(fd => new Float32Array(Array.from(fd))); const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(this.Document), faceDescriptorsAsFloat32Array); const faceMatcher = new FaceMatcher([labeledFaceDescriptor], 1); - const { faceAnno } = FaceRecognitionHandler.ImageDocFaceAnnos(imgDoc).reduce( - (prev, faceAnno) => { - const match = faceMatcher.matchDescriptor(new Float32Array(Array.from(faceAnno.faceDescriptor as List))); - return match.distance < prev.dist ? { dist: match.distance, faceAnno } : prev; - }, - { dist: 1, faceAnno: undefined as Opt } - ); + const faceAnno = + FaceRecognitionHandler.ImageDocFaceAnnos(imgDoc).reduce( + (prev, faceAnno) => { + const match = faceMatcher.matchDescriptor(new Float32Array(Array.from(faceAnno.faceDescriptor as List))); + return match.distance < prev.dist ? { dist: match.distance, faceAnno } : prev; + }, + { dist: 1, faceAnno: undefined as Opt } + ).faceAnno ?? imgDoc; // assign the face in the image that's closest to the face collection's face if (faceAnno) { - FaceRecognitionHandler.UniqueFaceRemoveFaceImage(faceAnno, DocCast(faceAnno.face)); + faceAnno.face && FaceRecognitionHandler.UniqueFaceRemoveFaceImage(faceAnno, DocCast(faceAnno.face)); FaceRecognitionHandler.UniqueFaceAddFaceImage(faceAnno, this.Document); faceAnno.face = this.Document; } diff --git a/src/client/views/search/FaceRecognitionHandler.tsx b/src/client/views/search/FaceRecognitionHandler.tsx index 4c10307e6..4f6f5d314 100644 --- a/src/client/views/search/FaceRecognitionHandler.tsx +++ b/src/client/views/search/FaceRecognitionHandler.tsx @@ -101,7 +101,7 @@ export class FaceRecognitionHandler { * @param faceDoc unique face Doc * @returns image Docs */ - public static UniqueFaceImages = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_annos).map(face => DocCast(face.annotationOn)); + public static UniqueFaceImages = (faceDoc: Doc) => DocListCast(faceDoc[DocData].face_annos).map(face => DocCast(face.annotationOn, face)); /** * Adds a face image to a unique face Doc, adds the unique face Doc to the images list of reognized faces, -- cgit v1.2.3-70-g09d2 From 9776e4584b61d3c67622d8ea1f2338a7dfbe857d Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 27 Aug 2024 21:57:43 -0400 Subject: fixed type --- src/client/views/pdf/Annotation.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 3bd42873c..1891cfd4c 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -13,6 +13,7 @@ import { FieldViewProps } from '../nodes/FieldView'; import { OpenWhere } from '../nodes/OpenWhere'; import { AnchorMenu } from './AnchorMenu'; import './Annotation.scss'; +import { Property } from 'csstype'; interface IRegionAnnotationProps { x: number; @@ -45,7 +46,7 @@ interface IAnnotationProps extends FieldViewProps { annoDoc: Doc; containerDataDoc: Doc; fieldKey: string; - pointerEvents?: () => Opt; + pointerEvents?: () => Opt; } @observer export class Annotation extends ObservableReactComponent { -- cgit v1.2.3-70-g09d2