aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoralyssaf16 <alyssa_feinberg@brown.edu>2024-07-19 15:11:29 -0400
committeralyssaf16 <alyssa_feinberg@brown.edu>2024-07-19 15:11:29 -0400
commit0b2a8c0d718940ddc06a966d4e027a79bb06ed6e (patch)
treed608b092b9f0bc409b058ef77eb4ddb2a68a595c /src
parent3c873d191feec296aef82c48a912617a8d66eb18 (diff)
simple image label
Diffstat (limited to 'src')
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx1
-rw-r--r--src/client/views/nodes/ImageBox.scss18
-rw-r--r--src/client/views/nodes/ImageBox.tsx179
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>
);
}