aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralyssaf16 <alyssa_feinberg@brown.edu>2024-04-17 13:17:51 -0400
committeralyssaf16 <alyssa_feinberg@brown.edu>2024-04-17 13:17:51 -0400
commitc5b2912cc4f44c5e12d8b5dc123d99bf9c4d9b85 (patch)
treef61ca56109ac51161f2877c4dc3038e9d5b91b9c
parente95d25eb8159bb7c753fa27e74e9baa8d3bffea6 (diff)
ai flashcards
-rw-r--r--src/client/apis/gpt/GPT.ts4
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx71
-rw-r--r--src/client/views/pdf/AnchorMenu.tsx24
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx42
-rw-r--r--src/client/views/pdf/PDFViewer.tsx1
5 files changed, 79 insertions, 63 deletions
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index 968b45273..2757fc830 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -17,7 +17,7 @@ type GPTCallOpts = {
const callTypeMap: { [type: string]: GPTCallOpts } = {
summary: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: 'Summarize this text in simpler terms: ' },
edit: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: 'Reword this: ' },
- flashcard: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: 'Make flashcards out of this text with questions on the front and answers on the back: ' },
+ flashcard: { model: 'gpt-3.5-turbo-instruct', maxTokens: 512, temp: 0.5, prompt: 'Make flashcards out of this text with questions and answers: ' },
completion: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: '' },
};
@@ -28,7 +28,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
* @returns AI Output
*/
const gptAPICall = async (inputText: string, callType: GPTCallType) => {
- if (callType === GPTCallType.SUMMARY) inputText += '.';
+ if (callType === GPTCallType.SUMMARY || callType == GPTCallType.FLASHCARD) inputText += '.';
const opts: GPTCallOpts = callTypeMap[callType];
try {
const configuration: ClientOptions = {
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index ce862cd22..76631f071 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -3,7 +3,7 @@ import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { emptyFunction, returnFalse, returnNone, returnZero, setupMoveUpEvents } from '../../../Utils';
-import { Doc, Opt } from '../../../fields/Doc';
+import { Doc, Opt, DocListCast } from '../../../fields/Doc';
import { DocCast, NumCast, RTFCast, StrCast } from '../../../fields/Types';
import { DocUtils, Docs } from '../../documents/Documents';
import { DragManager, dropActionType } from '../../util/DragManager';
@@ -21,6 +21,7 @@ import { FormattedTextBox } from './formattedText/FormattedTextBox';
import { RichTextField } from '../../../fields/RichTextField';
import { GPTCallType, gptAPICall } from '../../apis/gpt/GPT';
import { DocData } from '../../../fields/DocSymbols';
+import { KeyValueBox } from './KeyValueBox';
@observer
export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
@@ -200,6 +201,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
console.log(this.layoutDoc[`_${this._props.fieldKey}_revealOp`]);
if (!this.layoutDoc[`_${this._props.fieldKey}_revealOp`] || this.layoutDoc[`_${this._props.fieldKey}_revealOp`] == 'flip') {
this.flipFlashcard();
+ console.log('Print context of cards: ' + DocCast(this.dataDoc[this.fieldKey + '_1']).text);
}
})
}
@@ -214,6 +216,18 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
);
}
+ askGPT = async (): Promise<string | undefined> => {
+ try {
+ let res = await gptAPICall(StrCast(this.dataDoc.data), GPTCallType.COMPLETION);
+ if (!res) {
+ console.error('GPT call failed');
+ return;
+ }
+ } catch (err) {
+ console.error('GPT call failed');
+ }
+ };
+
render() {
const clearButton = (which: string) => {
return (
@@ -232,24 +246,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
const whichDoc = DocCast(this.dataDoc[which]);
const targetDoc = DocCast(whichDoc?.annotationOn, whichDoc);
// if there is no Doc in the first comparison slot, but the comparison box's fieldKey slot has a RichTextField, then render a text box to show the contents of the document's field key slot
- //const layoutTemplateString = !targetDoc && which.endsWith('1') && this.Document[this.fieldKey] instanceof RichTextField ? FormattedTextBox.LayoutString(this.fieldKey) : undefined;
- const subjectText = RTFCast(this.Document[this.fieldKey])?.Text;
- const layoutTemplateString = !targetDoc
- ? which.endsWith('0') && subjectText !== undefined
- ? FormattedTextBox.LayoutString(this.fieldKey)
- : which.endsWith('1') && (this.Document[which] instanceof RichTextField || typeof this.Document[which] === 'string')
- ? FormattedTextBox.LayoutString(which)
- : undefined
- : undefined;
-
- if (which.endsWith('1') && !layoutTemplateString && targetDoc) {
- const queryText = RTFCast(this.Document[this.fieldKey + '_1'])?.Text;
- console.log('QUER' + queryText);
- if (queryText?.includes('--TEXT--') && subjectText) {
- this.Document[DocData][this.fieldKey + '_1'] = '';
- gptAPICall(queryText?.replace('--TEXT--', subjectText), GPTCallType.COMPLETION).then(value => (this.Document[DocData][this.fieldKey + '_1'] = value.trim()));
- }
- }
+ const layoutTemplateString = !targetDoc && which.endsWith('1') && this.Document[this.fieldKey] instanceof RichTextField ? FormattedTextBox.LayoutString(this.fieldKey) : undefined;
return targetDoc || layoutTemplateString ? (
<>
@@ -315,15 +312,20 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
if (this.Document._layout_isFlashcard) {
const side = this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 1 : 0;
-
// add text box when first created
+
if (!(this.dataDoc[this.fieldKey + '_0'] || this.dataDoc[this.fieldKey + '_0'] == 'empty')) {
- console.log('TEXT HERE' + this.dataDoc.data);
- const newDoc = Docs.Create.TextDocument(StrCast(this.dataDoc.data));
+ const dataSplit = StrCast(this.dataDoc.data).split('Answer');
+ const newDoc = Docs.Create.TextDocument(dataSplit[1]);
+ newDoc.text = dataSplit[1];
this.addDoc(newDoc, this.fieldKey + '_0');
}
- // if (!(this.dataDoc[this.fieldKey + '_0'] || this.dataDoc[this.fieldKey + '_0'] == 'empty')) this.dataDoc[this.fieldKey + '_0'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc);
- if (!(this.dataDoc[this.fieldKey + '_1'] || this.dataDoc[this.fieldKey + '_1'] == 'empty')) this.dataDoc[this.fieldKey + '_1'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc);
+ if (!(this.dataDoc[this.fieldKey + '_1'] || this.dataDoc[this.fieldKey + '_1'] == 'empty')) {
+ const dataSplit = StrCast(this.dataDoc.data).split('Answer');
+ const newDoc = Docs.Create.TextDocument(dataSplit[0]);
+ newDoc.text = 'jhkhkjh';
+ this.addDoc(newDoc, this.fieldKey + '_1');
+ }
if (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] == 'hide/reveal') {
{
@@ -333,21 +335,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
{displayBox(`${this.fieldKey}_1`, 1, this._props.PanelHeight() - 3)}
</div>
);
- // return (
- // <div className={`comparisonBox${this._props.isContentActive() ? '-interactive' : ''}` /* change className to easily disable/enable pointer events in CSS */} style={{ display: 'flex', flexDirection: 'column' }}>
- // {displayBox(`${this.fieldKey}_2`, 1, this._props.PanelHeight() - 3)}
- // <div className="clip-div" style={{ height: this.clipHeight + '%', transition: this._animating, background: StrCast(this.layoutDoc._backgroundColor, 'gray') }}>
- // {displayBox(`${this.fieldKey}_1`, 0, 0)}
- // </div>
- // </div>
- // );
- // return (
- // <div className={`comparisonBox${this._props.isContentActive() ? '-interactive' : ''}` /* change className to easily disable/enable pointer events in CSS */}>
- // {displayBox(`${this.fieldKey}_${side === 0 ? 1 : 0}`, side, this._props.PanelHeight() / 2)}
- // {displayBox(`${this.fieldKey}_${side === 0 ? 0 : 1}`, 1, this._props.PanelHeight() / 2)}
-
- // </div>
- // );
}
} else {
return (
@@ -362,12 +349,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
this.hoverFlip(undefined);
}}>
{displayBox(`${this.fieldKey}_${side === 0 ? 1 : 0}`, side, this._props.PanelWidth() - 3)}
- {/* {displayBoxReveal(`${this.fieldKey}_${side}`, side, this._props.PanelWidth() - 3)}
- {displayBoxReveal(`${this.fieldKey}_${side === 0 ? 1 : 0}`, side === 0 ? 1 : 0, this._props.PanelWidth() - 3)} */}
- {/* <div>{displayBoxReveal(`${this.fieldKey}_${side}`, side, this._props.PanelWidth() - 3)}</div> */}
- {/* <div style={{ display: this.layoutDoc[`_${this._props.fieldKey}_revealOp`] == 'hide/reveal' ? 'block' : 'none' }} className={`comparisonBox${this._props.isContentActive() ? '-interactive' : ''}`}>
- {displayBox(`${this.fieldKey}_${side === 0 ? 1 : 0}`, side === 0 ? 1 : 0, this._props.PanelWidth() - 3)}
- </div> */}
{this.overlayAlternateIcon}
</div>
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 844c1e36d..7cb6a20f4 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -15,6 +15,7 @@ import { AntimodeMenu, AntimodeMenuProps } from '../AntimodeMenu';
import { LinkPopup } from '../linking/LinkPopup';
import './AnchorMenu.scss';
import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup';
+import { PDFViewer } from 'pdfjs-dist/web/pdf_viewer.mjs';
@observer
export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -57,6 +58,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
public get Active() {
return this._left > 0;
}
+ public addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined;
componentWillUnmount() {
this._disposer?.();
@@ -96,14 +98,34 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
try {
const res = await gptAPICall(this.selectedText, GPTCallType.FLASHCARD);
+
GPTPopup.Instance.setText(res || 'Something went wrong.');
- GPTPopup.Instance.transferToFlashcard();
+ this.transferToFlashcard(res);
} catch (err) {
console.error(err);
}
GPTPopup.Instance.setLoading(false);
};
+ transferToFlashcard = (text: string) => {
+ const senArr = text.split('Question');
+ const collectionArr: Doc[] = [];
+ for (var i = 1; i < senArr.length; i++) {
+ console.log('Arr ' + i + ': ' + senArr[i]);
+ const newDoc = Docs.Create.ComparisonDocument(senArr[i], { _layout_isFlashcard: true, _width: 300, _height: 300 });
+ newDoc.text = senArr[i];
+ collectionArr.push(newDoc);
+ }
+ const newCol = Docs.Create.CarouselDocument(collectionArr, {
+ _width: 200,
+ _height: 200,
+ _layout_fitWidth: true,
+ _layout_autoHeight: true,
+ });
+
+ this.addToCollection?.(newCol);
+ };
+
pointerDown = (e: React.PointerEvent) => {
setupMoveUpEvents(
this,
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index dbcdd4e3a..32c1721ec 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -144,6 +144,15 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
_layout_autoHeight: true,
});
this.addDoc(newDoc, this.sidebarId);
+ // const arr = [newDoc];
+ // const newCol = Docs.Create.CarouselDocument(arr, {
+ // _width: 200,
+ // _height: 200,
+ // _layout_fitWidth: true,
+ // _layout_autoHeight: true,
+ // });
+ // this.addDoc(newDoc, this.sidebarId);
+ // this.addDoc(newCol, this.sidebarId);
const anchor = AnchorMenu.Instance?.GetAnchor(undefined, false);
if (anchor) {
DocUtils.MakeLink(newDoc, anchor, {
@@ -152,21 +161,24 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
}
};
- transferToFlashcard = () => {
- const senArr = this.text.split('.');
- for (var i = 0; i < senArr.length; i += 2) {
- console.log('SEN: ' + senArr[i]);
- const newDoc = Docs.Create.ComparisonDocument(senArr[i], { _layout_isFlashcard: true, _width: 300, _height: 300 });
- newDoc.text = senArr[i];
- this.addDoc(newDoc, this.sidebarId);
- const anchor = AnchorMenu.Instance?.GetAnchor(undefined, false);
- if (anchor) {
- DocUtils.MakeLink(newDoc, anchor, {
- link_relationship: 'GPT Summary',
- });
- }
- }
- };
+ // transferToFlashcard = () => {
+ // const senArr = this.text.split('Question');
+ // const collectionArr: Doc[] = [];
+ // for (var i = 1; i < senArr.length; i++) {
+ // console.log('Arr ' + i + ': ' + senArr[i]);
+ // const newDoc = Docs.Create.ComparisonDocument(senArr[i], { _layout_isFlashcard: true, _width: 300, _height: 300 });
+ // newDoc.text = senArr[i];
+ // collectionArr.push(newDoc);
+ // }
+ // const newCol = Docs.Create.CarouselDocument(collectionArr, {
+ // _width: 200,
+ // _height: 200,
+ // _layout_fitWidth: true,
+ // _layout_autoHeight: true,
+ // });
+ // this.addDoc(newCol, this.sidebarId);
+ // this.addToCollection?.(newCol);
+ // };
/**
* Transfers the image urls to actual image docs
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 7d8529a1c..cecaf17ff 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -417,6 +417,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
// Changing which document to add the annotation to (the currently selected PDF)
GPTPopup.Instance.setSidebarId('data_sidebar');
GPTPopup.Instance.addDoc = this._props.sidebarAddDoc;
+ AnchorMenu.Instance.addToCollection = this._props.DocumentView?.()._props.addDocument;
// const newDoc = Docs.Create.ComparisonDocument({ _layout_isFlashcard: true, _width: 300, _height: 300 });
// this.props.addDocument?.(newDoc);
};