diff options
author | alyssaf16 <alyssa_feinberg@brown.edu> | 2024-07-19 15:11:29 -0400 |
---|---|---|
committer | alyssaf16 <alyssa_feinberg@brown.edu> | 2024-07-19 15:11:29 -0400 |
commit | 0b2a8c0d718940ddc06a966d4e027a79bb06ed6e (patch) | |
tree | d608b092b9f0bc409b058ef77eb4ddb2a68a595c /src | |
parent | 3c873d191feec296aef82c48a912617a8d66eb18 (diff) |
simple image label
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/nodes/ComparisonBox.tsx | 1 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.scss | 18 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 179 |
3 files changed, 115 insertions, 83 deletions
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 0c42f662b..139978a13 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -26,6 +26,7 @@ import { DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; import ReactLoading from 'react-loading'; + import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { tickStep } from 'd3'; diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index be68ac8cd..4690e255f 100644 --- a/src/client/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss @@ -155,6 +155,24 @@ color: #17175e; } +.check-icon { + position: absolute; + right: 150; + bottom: 10; + color: green; + display: inline-block; + font-size: 100px; +} + +.redo-icon { + position: absolute; + right: 10; + bottom: 10; + color: black; + display: inline-block; + font-size: 100px; +} + @keyframes spin { to { transform: rotate(360deg); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index faf96d616..37827a43a 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -46,6 +46,7 @@ import { canvasSize } from './generativeFill/generativeFillUtils/generativeFillC import Tesseract from 'tesseract.js'; import axios from 'axios'; import { TupleType } from 'typescript'; +// import stringSimilarity from 'string-similarity'; export class ImageEditorData { // eslint-disable-next-line no-use-before-define @@ -87,9 +88,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); private _imageRef: HTMLImageElement | null = null; // <video> ref + @observable private _quizBoxes: Doc[] = []; @observable private _width: number = 0; @observable private _height: number = 0; @observable private searchInput = ''; + @observable private _quizMode = false; @observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>(); @observable _curSuffix = ''; @observable _error = ''; @@ -357,7 +360,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { }; pushInfo = async () => { - const formData = new FormData(); + this._quizMode = true; const img = { file: this.paths[0], @@ -396,6 +399,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { newCol.zIndex = 1000; newCol.forceActive = true; newCol.quiz = text; + this._quizBoxes.push(newCol); this.addDocument(newCol); } }; @@ -429,95 +433,93 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { this._loading = false; }; - getImageLabels = async () => { - this._loading = true; - try { - const hrefBase64 = await this.createCanvas(); - // const hw = await gptImageLabel(hrefBase64, 'Find the image dimensions. Return as height and width.'); - const response = await gptImageLabel( - hrefBase64, - //'What is the height and width of the image' - 'For each group of words in the image, find the x-coordinate and ycoordinate of the top left corner. Find the width and height of the group. Return this information in this format with the correct information replacing the underscores: "observed word: _, x: _, y: _, width: _, height: _," No additional text, asterisks and put it all in one line. Divide the x and width by the width of the image. Divide the y and the height by the height of the image.' - ); - // console.log(hw); - console.log('RESPONSE: ' + response); - this.createTextboxes(response); + levenshteinDistance = (a: string, b: string) => { + const an = a.length; + const bn = b.length; + const matrix = []; - //AnchorMenu.Instance.transferToFlashcard(response, NumCast(this.layoutDoc['x']), NumCast(this.layoutDoc['y'])); - } catch (error) { - console.log('Error'); + // Ensure non-zero length strings + if (an === 0) return bn; + if (bn === 0) return an; + + // Initialize the matrix + for (let i = 0; i <= an; i++) { + matrix[i] = [i]; } - this._loading = false; + for (let j = 0; j <= bn; j++) { + matrix[0][j] = j; + } + + // Populate the matrix + for (let i = 1; i <= an; i++) { + for (let j = 1; j <= bn; j++) { + if (a[i - 1] === b[j - 1]) { + matrix[i][j] = matrix[i - 1][j - 1]; + } else { + matrix[i][j] = Math.min( + matrix[i - 1][j - 1] + 1, // substitution + Math.min( + matrix[i][j - 1] + 1, // insertion + matrix[i - 1][j] + 1 // deletion + ) + ); + } + } + } + + return matrix[an][bn]; + }; + + @computed get checkIcon() { + return ( + <Tooltip title={<div className="dash-tooltip">Check</div>}> + <div className="check-icon" onPointerDown={this.check}> + <FontAwesomeIcon icon="circle-check" size="lg" /> + </div> + </Tooltip> + ); + } + + @computed get redoIcon() { + return ( + <Tooltip title={<div className="dash-tooltip">Redo</div>}> + <div className="redo-icon" onPointerDown={this.redo}> + <FontAwesomeIcon icon="redo-alt" size="lg" /> + </div> + </Tooltip> + ); + } + + compareWords = (input: string, target: string) => { + const distance = this.levenshteinDistance(input.toLowerCase(), target.toLowerCase()); + const threshold = Math.max(input.length, target.length) * 0.2; // Allow up to 20% of the length as difference + return distance <= threshold; }; - getText = () => { - console.log(StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text)); + check = () => { + this._quizBoxes.forEach(doc => { + const input = StrCast(RTFCast(DocCast(doc).text)?.Text); + console.log('INP: ' + StrCast(input) + '; DOC: ' + StrCast(doc.quiz)); + const match = this.compareWords(input, StrCast(doc.quiz)); + doc.backgroundColor = match ? '#11c249' : '#eb2d2d'; + // console.log(this.compareWords(input, StrCast(doc.quiz)) ? 'Match' : 'No Match'); + }); }; - getImageLabels2 = async () => { - this._loading = true; - try { - // const hrefBase64 = await this.createCanvas(); - // const hw = await gptImageLabel(hrefBase64, 'Find the image dimensions. Return as height and width.'); - // const response = await gptImageLabel( - // hrefBase64, - // //'What is the height and width of the image' - // 'For each group of words in the image, find the x-coordinate and ycoordinate of the top left corner. Find the width and height of the group. Return this information in this format with the correct information replacing the underscores: "observed word: _, x: _, y: _, width: _, height: _," No additional text, asterisks and put it all in one line. Divide the x and width by the width of the image. Divide the y and the height by the height of the image.' - // ); - // console.log(hw); - // console.log('RESPONSE: ' + response); - // this.createTextboxes(response); - Tesseract.recognize(this.paths[0], 'eng', { - logger: m => console.log(m), - }).then(({ data: { text, words } }) => { - console.log('OCR Result:', text); - console.log('Words with bounding boxes:', words); - }); - //AnchorMenu.Instance.transferToFlashcard(response, NumCast(this.layoutDoc['x']), NumCast(this.layoutDoc['y'])); - } catch (error) { - console.log('Error'); - } - this._loading = false; + redo = () => { + this._quizBoxes.forEach(doc => { + DocCast(doc)[DocData].text = ''; + doc.backgroundColor = '#e4e4e4'; + }); }; - createTextboxes = (response: string) => { - const groups = response.replace('*', '').toLowerCase().split('observed word: '); - groups.shift(); - for (var i = 0; i < groups.length; i++) { - console.log('Group ' + i + ': ' + groups[i]); - } - // console.log('GROUPS: ' + groups); - groups.forEach( - group => { - const groupArr = group.split(', '); - const word = groupArr[0]; - const x = parseFloat(groupArr[1].substring(3)); - const y = parseFloat(groupArr[2].substring(3)); - const width = parseFloat(groupArr[3].substring(7)); - const height = parseFloat(groupArr[4].substring(8)); - const scaling = 1 / (this._props.NativeDimScaling?.() || 1); - const w = AnchorMenu.Instance.marqueeWidth * scaling; - const h = AnchorMenu.Instance.marqueeHeight * scaling; - - const newCol = Docs.Create.TextDocument(word, { - _width: w * width, - //width * NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']), - _height: h * height + 20, - //height * NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']), - _layout_fitWidth: true, - _layout_autoHeight: true, - }); - newCol.x = x * w; - newCol.y = y * h; - // newCol.x = x * NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']); - // newCol.y = y * NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']); - newCol.zIndex = 1000; - newCol.forceActive = true; - newCol.quiz = true; - this.addDocument(newCol); - } - // console.log(group); - ); + exitQuizMode = () => { + this._quizMode = false; + this._quizBoxes.forEach(doc => { + // this._props.removeDocument?.(DocCast(doc)); + // this._props.DocumentView?.()._props.removeDocument?.(doc); + }); + this._quizBoxes = []; }; @action @@ -530,7 +532,16 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { if (field) { const funcs: ContextMenuProps[] = []; // funcs.push({ description: 'Create ai flashcards', event: () => this.getImageDesc(), icon: 'id-card' }); - funcs.push({ description: 'Push info', event: this.pushInfo, icon: 'redo-alt' }); + funcs.push({ + description: 'Quiz Mode', + event: !this._quizMode + ? this.pushInfo + : () => { + this._quizMode = false; + }, + icon: 'redo-alt', + }); + // funcs.push({ description: 'Get Text', event: this.check, icon: 'redo-alt' }); // funcs.push({ description: 'Get Labels2', event: this.getImageLabels2, icon: 'redo-alt' }); // funcs.push({ description: 'Get Labels', event: this.getImageLabels, icon: 'redo-alt' }); funcs.push({ description: 'Rotate Clockwise 90', event: this.rotate, icon: 'redo-alt' }); @@ -678,6 +689,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { )} </div> {this.overlayImageIcon} + {this._quizMode ? this.checkIcon : null} + {this._quizMode ? this.redoIcon : null} </div> ); } |