From 0b2a8c0d718940ddc06a966d4e027a79bb06ed6e Mon Sep 17 00:00:00 2001
From: alyssaf16 <alyssa_feinberg@brown.edu>
Date: Fri, 19 Jul 2024 15:11:29 -0400
Subject: simple image label

---
 src/client/views/nodes/ImageBox.tsx | 179 +++++++++++++++++++-----------------
 1 file changed, 96 insertions(+), 83 deletions(-)

(limited to 'src/client/views/nodes/ImageBox.tsx')

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>
         );
     }
-- 
cgit v1.2.3-70-g09d2

