aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/StyleProviderQuiz.tsx31
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx41
-rw-r--r--src/client/views/nodes/trails/PresElementBox.tsx5
-rw-r--r--src/client/views/pdf/AnchorMenu.tsx26
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.scss16
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx160
-rw-r--r--src/client/views/pdf/PDFViewer.tsx21
7 files changed, 152 insertions, 148 deletions
diff --git a/src/client/views/StyleProviderQuiz.tsx b/src/client/views/StyleProviderQuiz.tsx
index acda38dd7..f9ee8d3db 100644
--- a/src/client/views/StyleProviderQuiz.tsx
+++ b/src/client/views/StyleProviderQuiz.tsx
@@ -9,7 +9,7 @@ import { DocData } from '../../fields/DocSymbols';
import { List } from '../../fields/List';
import { NumCast, StrCast } from '../../fields/Types';
import { Networking } from '../Network';
-import { GPTCallType, gptAPICall, gptImageLabel } from '../apis/gpt/GPT';
+import { GPTCallType, gptAPICall } from '../apis/gpt/GPT';
import { Docs } from '../documents/Documents';
import { ContextMenu } from './ContextMenu';
import { ContextMenuProps } from './ContextMenuItem';
@@ -110,20 +110,21 @@ export namespace styleProviderQuiz {
const blob = await ImageUtility.canvasToBlob(canvas);
return selectUrlToBase64(blob);
}
- /**
- * Create flashcards from an image.
- */
- async function makeFlashcardsForImage(img: ImageBox) {
- img.Loading = true;
- try {
- const hrefBase64 = await createCanvas(img);
- const response = await gptImageLabel(hrefBase64, 'Make flashcards out of this image with each question and answer labeled as "question" and "answer". Do not label each flashcard and do not include asterisks: ');
- AnchorMenu.Instance.transferToFlashcard(response, NumCast(img.layoutDoc.x), NumCast(img.layoutDoc.y));
- } catch (error) {
- console.log('Error', error);
- }
- img.Loading = false;
- }
+
+ // /**
+ // * Create flashcards from an image.
+ // */
+ // async function makeFlashcardsForImage(img: ImageBox) {
+ // img.Loading = true;
+ // try {
+ // const hrefBase64 = await createCanvas(img);
+ // const response = await gptImageLabel(hrefBase64, 'Make flashcards out of this image with each question and answer labeled as "question" and "answer". Do not label each flashcard and do not include asterisks: ');
+ // AnchorMenu.Instance.transferToFlashcard(response, NumCast(img.layoutDoc.x), NumCast(img.layoutDoc.y));
+ // } catch (error) {
+ // console.log('Error', error);
+ // }
+ // img.Loading = false;
+ // }
/**
* Calls the createCanvas and pushInfo methods to convert the
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index b86536f86..7b24125e7 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -13,7 +13,7 @@ import { EditorState, NodeSelection, Plugin, Selection, TextSelection, Transacti
import { EditorView, NodeViewConstructor } from 'prosemirror-view';
import * as React from 'react';
import { BsMarkdownFill } from 'react-icons/bs';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, ClientUtils, DivWidth, imageUrlToBase64, returnFalse, returnZero, setupMoveUpEvents, simMouseEvent, smoothScroll, StopEvent } from '../../../../ClientUtils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, ClientUtils, DivWidth, returnFalse, returnZero, setupMoveUpEvents, simMouseEvent, smoothScroll, StopEvent } from '../../../../ClientUtils';
import { DateField } from '../../../../fields/DateField';
import { CreateLinkToActiveAudio, Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../../fields/Doc';
import { AclAdmin, AclAugment, AclEdit, AclSelfEdit, DocCss, DocData, ForceServerWrite, UpdatingFromServer } from '../../../../fields/DocSymbols';
@@ -26,7 +26,7 @@ import { ComputedField } from '../../../../fields/ScriptField';
import { BoolCast, Cast, DateCast, DocCast, FieldValue, NumCast, RTFCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util';
import { emptyFunction, numberRange, unimplementedFunction, Utils } from '../../../../Utils';
-import { gptAPICall, GPTCallType, gptImageLabel } from '../../../apis/gpt/GPT';
+import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT';
import { DocServer } from '../../../DocServer';
import { Docs } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
@@ -226,18 +226,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
return anchor;
};
- selectionToFlashcards = async () => {
- const queryText = window.getSelection()?.toString() ?? '';
- try {
- if (queryText) {
- const res = await gptAPICall(queryText, GPTCallType.FLASHCARD);
- AnchorMenu.Instance.transferToFlashcard(res || 'Something went wrong', NumCast(this.layoutDoc.x), NumCast(this.layoutDoc.y));
- }
- } catch (err) {
- console.error(err);
- }
- };
-
@action
setupAnchorMenu = () => {
AnchorMenu.Instance.Status = 'marquee';
@@ -1012,31 +1000,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
!help && cm.addItem({ description: 'Help...', subitems: helpItems, icon: 'eye' });
};
- findImageTags = async () => {
- const c = this.ProseRef?.getElementsByTagName('img');
- if (c) {
- for (const i of c) {
- // console.log(canvas.toDataURL());
- // canvas.style.zIndex = '2000000';
- // document.body.appendChild(canvas);
- if (i.className !== 'ProseMirror-separator') this.getImageDesc(i.src);
- }
- }
- };
-
- getImageDesc = async (u: string) => {
- try {
- const hrefBase64 = await imageUrlToBase64(u);
- const response = await gptImageLabel(
- hrefBase64,
- 'Make flashcards out of this text and image with each question and answer labeled as question and answer. Do not label each flashcard and do not include asterisks: ' + (this.dataDoc.text as RichTextField)?.Text
- );
- AnchorMenu.Instance.transferToFlashcard(response || 'Something went wrong', NumCast(this.dataDoc['x']), NumCast(this.dataDoc['y']));
- } catch (error) {
- console.log('Error', error);
- }
- };
-
animateRes = (resIndex: number, newText: string) => {
if (resIndex < newText.length) {
const marks = this.EditorView?.state.storedMarks ?? [];
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 957df894c..31cd1603f 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -239,10 +239,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
e.clientY,
undefined,
action(() => {
- Array.from(classesToRestore).forEach(pair => {
- // eslint-disable-next-line prefer-destructuring
- pair[0].className = pair[1];
- });
+ Array.from(classesToRestore).forEach(pair => (pair[0].className = pair[1]));
this._dragging = false;
})
);
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 6ae659ac1..eb6516403 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -10,7 +10,6 @@ import { Doc, Opt } from '../../../fields/Doc';
import { SettingsManager } from '../../util/SettingsManager';
import { AntimodeMenu, AntimodeMenuProps } from '../AntimodeMenu';
import { LinkPopup } from '../linking/LinkPopup';
-import { ComparisonBox } from '../nodes/ComparisonBox';
import { DocumentView } from '../nodes/DocumentView';
import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
import './AnchorMenu.scss';
@@ -69,7 +68,6 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
public MakeTargetToggle: () => void = unimplementedFunction;
public ShowTargetTrail: () => void = unimplementedFunction;
public IsTargetToggler: () => boolean = returnFalse;
- public gptFlashcards: () => void = unimplementedFunction;
public makeLabels: () => void = unimplementedFunction;
public marqueeWidth = 0;
public marqueeHeight = 0;
@@ -94,22 +92,9 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
* Invokes the API with the selected text and stores it in the summarized text.
* @param e pointer down event
*/
- gptSummarize = () => GPTPopup.Instance.generateSummary(this._selectedText);
-
- /*
- * Transfers the flashcard text generated by GPT on flashcards and creates a collection out them.
- */
-
- transferToFlashcard = (text: string, x: number, y: number) => {
- ComparisonBox.createFlashcardDeck(text, 250, 200, 'data_front', 'data_back').then(
- action(newCol => {
- newCol.x = x;
- newCol.y = y;
- newCol.zIndex = 1000;
- this.addToCollection?.(newCol);
- this._loading = false;
- })
- );
+ gptAskAboutSelection = () => {
+ GPTPopup.Instance.askAIAboutSelection(this._selectedText);
+ AnchorMenu.Instance.fadeOut(true);
};
pointerDown = (e: React.PointerEvent) => {
@@ -188,14 +173,13 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
{/* GPT Summarize icon only shows up when text is highlighted, not on marquee selection */}
{this._selectedText && (
<IconButton
- tooltip="Summarize with AI" //
- onPointerDown={this.gptSummarize}
+ tooltip="Ask AI..." //
+ onPointerDown={this.gptAskAboutSelection}
icon={<FontAwesomeIcon icon="comment-dots" size="lg" />}
color={SettingsManager.userColor}
/>
)}
{/* Adds a create flashcards option to the anchor menu, which calls the gptFlashcard method. */}
- {this.gptFlashcards === unimplementedFunction ? null : <IconButton tooltip="Create flashcards" onPointerDown={this.gptFlashcards} icon={<FontAwesomeIcon icon="layer-group" size="lg" />} color={SettingsManager.userColor} />}
{this.makeLabels === unimplementedFunction ? null : <IconButton tooltip="Create labels" onPointerDown={this.makeLabels} icon={<FontAwesomeIcon icon="tag" size="lg" />} color={SettingsManager.userColor} />}
{this._selectedText && RichTextMenu.Instance?.createLinkButton()}
{AnchorMenu.Instance.OnAudio === unimplementedFunction ? null : (
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.scss b/src/client/views/pdf/GPTPopup/GPTPopup.scss
index c8903e09f..18441f76e 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.scss
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.scss
@@ -15,12 +15,8 @@ $headingHeight: 32px;
height: 100%;
top: 0;
left: 0;
- pointer-events: none;
border-top: solid gray 20px;
border-radius: 16px;
- padding: 16px;
- padding-bottom: 0;
- padding-top: 0px;
z-index: 999;
display: flex;
flex-direction: column;
@@ -29,11 +25,13 @@ $headingHeight: 32px;
box-shadow: 0 2px 5px #7474748d;
color: $textgrey;
- .gptPopup-sortBox {
+ .gptPopup-summaryBox-content {
+ padding-right: 16px;
+ padding-left: 16px;
+ position: relative;
+ overflow: hidden;
display: flex;
flex-direction: column;
- height: calc(100% - $inputHeight - $headingHeight);
- pointer-events: all;
}
.summary-heading {
@@ -65,7 +63,9 @@ $headingHeight: 32px;
.gptPopup-content-wrapper {
padding-top: 10px;
min-height: 50px;
- height: calc(100% - 32px);
+ white-space: pre-line;
+ overflow: auto;
+ margin-bottom: 10px;
}
.inputWrapper {
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index 4dc45e6a0..67213382d 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -31,6 +31,7 @@ import { OpenWhere } from '../../nodes/OpenWhere';
import { DrawingFillHandler } from '../../smartdraw/DrawingFillHandler';
import { ImageField } from '../../../../fields/URLField';
import { List } from '../../../../fields/List';
+import { ComparisonBox } from '../../nodes/ComparisonBox';
export enum GPTPopupMode {
SUMMARY, // summary of seleted document text
@@ -56,7 +57,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
private _dataJson: string = '';
private _documentDescriptions: Promise<string> | undefined; // a cache of the descriptions of all docs in the selected collection. makes it more efficient when asking GPT multiple questions about the collection.
private _sidebarFieldKey: string = '';
- private _textToSummarize: string = '';
+ private _aiReferenceText: string = '';
private _imageDescription: string = '';
private _textToDocMap = new Map<string, Doc>(); // when GPT answers with a doc's content, this helps us find the Doc
private _addToCollection: ((doc: Doc | Doc[], annotationKey?: string | undefined) => boolean) | undefined;
@@ -79,7 +80,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
};
componentDidUpdate() {
- this._gptProcessing && this.setStopAnimatingResponse(false);
+ //this._gptProcessing && this.setStopAnimatingResponse(false);
}
componentDidMount(): void {
reaction(
@@ -100,14 +101,14 @@ export class GPTPopup extends ObservableReactComponent<object> {
);
}
+ @observable private _showOriginal = true;
+ @observable private _responseText: string = '';
@observable private _conversationArray: string[] = ['Hi! In this pop up, you can ask ChatGPT questions about your documents and filter / sort them. '];
@observable private _fireflyArray: string[] = ['Hi! In this pop up, you can ask Firefly to create images. '];
@observable private _chatEnabled: boolean = false;
@action private setChatEnabled = (start: boolean) => (this._chatEnabled = start);
@observable private _gptProcessing: boolean = false;
@action private setGptProcessing = (loading: boolean) => (this._gptProcessing = loading);
- @observable private _responseText: string = '';
- @action private setResponseText = (text: string) => (this._responseText = text);
@observable private _imgUrls: string[][] = [];
@action private setImgUrls = (imgs: string[][]) => (this._imgUrls = imgs);
@observable private _collectionContext: Doc | undefined = undefined;
@@ -286,18 +287,30 @@ export class GPTPopup extends ObservableReactComponent<object> {
/**
* Completes an API call to generate a summary of the specified text
*
- * @param text the text to summarizz
+ * @param text the text to summarize
*/
- generateSummary = (text: string) => {
+ private generateSummary = action((text: string) => {
SnappingManager.SetChatVisible(true);
- this._textToSummarize = text;
- this.setMode(GPTPopupMode.SUMMARY);
+ this._showOriginal = false;
this.setGptProcessing(true);
return gptAPICall(text, GPTCallType.SUMMARY)
- .then(res => this.setResponseText(res || 'Something went wrong.'))
+ .then(action(res => (this._responseText = res || 'Something went wrong.')))
.catch(err => console.error(err))
.finally(() => this.setGptProcessing(false));
- };
+ });
+
+ /**
+ * Completes an API call to generate a summary of the specified text
+ *
+ * @param text the text to summarizz
+ */
+ askAIAboutSelection = action((text: string) => {
+ SnappingManager.SetChatVisible(true);
+ this._aiReferenceText = text;
+ this._responseText = '';
+ this._showOriginal = true;
+ this.setMode(GPTPopupMode.SUMMARY);
+ });
/**
* Completes an API call to generate an analysis of
@@ -306,14 +319,16 @@ export class GPTPopup extends ObservableReactComponent<object> {
generateDataAnalysis = () => {
this.setGptProcessing(true);
return gptAPICall(this._dataJson, GPTCallType.DATA, this._dataChatPrompt)
- .then(res => {
- const json = JSON.parse(res! as string);
- const keys = Object.keys(json);
- this._correlatedColumns = [];
- this._correlatedColumns.push(json[keys[0]]);
- this._correlatedColumns.push(json[keys[1]]);
- this.setResponseText(json[keys[2]] || 'Something went wrong.');
- })
+ .then(
+ action(res => {
+ const json = JSON.parse(res! as string);
+ const keys = Object.keys(json);
+ this._correlatedColumns = [];
+ this._correlatedColumns.push(json[keys[0]]);
+ this._correlatedColumns.push(json[keys[1]]);
+ this._responseText = json[keys[2]] || 'Something went wrong.';
+ })
+ )
.catch(err => console.error(err))
.finally(() => this.setGptProcessing(false));
};
@@ -336,6 +351,24 @@ export class GPTPopup extends ObservableReactComponent<object> {
});
}
};
+ /**
+ * Create Flashcards for the selected text
+ */
+ private createFlashcards = action(
+ () =>
+ this.setGptProcessing(true) &&
+ gptAPICall(this._aiReferenceText, GPTCallType.FLASHCARD, undefined, true)
+ .then(res =>
+ ComparisonBox.createFlashcardDeck(res, 250, 200, 'data_front', 'data_back').then(
+ action(newCol => {
+ newCol.zIndex = 1000;
+ DocumentViewInternal.addDocTabFunc(newCol, OpenWhere.addRight);
+ })
+ )
+ )
+ .catch(console.error)
+ .finally(action(() => (this._gptProcessing = false)))
+ );
/**
* Creates a histogram to show the correlation relationship that was found
@@ -536,35 +569,80 @@ export class GPTPopup extends ObservableReactComponent<object> {
summaryBox = () => (
<>
- <div style={{ height: 'calc(100% - 60px)', overflow: 'auto' }}>
- {this.heading('SUMMARY')}
+ <div className="gptPopup-summaryBox-content">
+ <div onClick={action(() => (this._showOriginal = !this._showOriginal))}>{this.heading(this._showOriginal ? 'SELECTION' : 'SUMMARY')}</div>
<div className="gptPopup-content-wrapper">
- {!this._gptProcessing &&
- (!this._stopAnimatingResponse ? (
- <TypeAnimation
- speed={50}
- sequence={[
- this._responseText,
- () => {
- setTimeout(() => this.setStopAnimatingResponse(true), 500);
- },
- ]}
- />
+ {!this._gptProcessing && !this._stopAnimatingResponse && this._responseText ? (
+ <TypeAnimation
+ speed={50}
+ sequence={[
+ this._responseText,
+ () => {
+ setTimeout(() => this.setStopAnimatingResponse(true), 500);
+ },
+ ]}
+ />
+ ) : this._showOriginal ? (
+ this._gptProcessing ? (
+ '...generating cards...'
) : (
- this._responseText
- ))}
+ this._aiReferenceText
+ )
+ ) : (
+ this._responseText || (this._gptProcessing ? '...generating summary...' : '-no ai summary-')
+ )}
</div>
</div>
- {!this._gptProcessing && (
- <div className="btns-wrapper" style={{ position: 'absolute', bottom: 0, width: 'calc(100% - 32px)' }}>
- {this._stopAnimatingResponse ? (
- <>
- <IconButton tooltip="Generate Again" onClick={() => this.generateSummary(this._textToSummarize + ' ')} icon={<FontAwesomeIcon icon="redo-alt" size="lg" />} color={StrCast(SettingsManager.userVariantColor)} />
- <Button tooltip="Transfer to text" text="Transfer To Text" onClick={this.transferToText} color={StrCast(SettingsManager.userVariantColor)} type={Type.TERT} />
- </>
+ {this._gptProcessing ? null : (
+ <div className="btns-wrapper" style={{ position: 'relative', width: 'calc(100% - 32px)' }}>
+ {this._stopAnimatingResponse || !this._responseText ? (
+ <div style={{ display: 'flex' }}>
+ {!this._showOriginal ? (
+ <>
+ <Button
+ tooltip="Show originally selected text" //
+ text="Selection"
+ onClick={action(() => (this._showOriginal = true))}
+ color={StrCast(SettingsManager.userVariantColor)}
+ type={Type.TERT}
+ />
+ <Button
+ tooltip="Create a text Doc with this text and link to the text selection" //
+ text="Transfer To Text"
+ onClick={this.transferToText}
+ color={StrCast(SettingsManager.userVariantColor)}
+ type={Type.TERT}
+ />
+ </>
+ ) : (
+ <>
+ <Button
+ tooltip="Show AI summary of original selection text (Shift+Click to regenerate)"
+ text="Summary"
+ onClick={action(e => {
+ if (e.shiftKey) {
+ this.setStopAnimatingResponse(false);
+ this._aiReferenceText += ' ';
+ this._responseText = '';
+ }
+ this.generateSummary(this._aiReferenceText);
+ })}
+ color={StrCast(SettingsManager.userVariantColor)}
+ type={Type.TERT}
+ />
+ <Button
+ tooltip="Create Flashcards" //
+ text="Create Flashcards"
+ onClick={this.createFlashcards}
+ color={StrCast(SettingsManager.userVariantColor)}
+ type={Type.TERT}
+ />
+ </>
+ )}
+ </div>
) : (
<div className="summarizing">
- <span>Summarizing</span>
+ <span>{this._showOriginal ? 'Creating Cards...' : 'Summarizing'}</span>
<ReactLoading type="bubbles" color="#bcbcbc" width={20} height={20} />
<Button text="Stop Animation" onClick={() => this.setStopAnimatingResponse(true)} color={StrCast(SettingsManager.userVariantColor)} type={Type.TERT} />
</div>
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index a50526223..83b3dffe5 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -28,7 +28,6 @@ import { AnchorMenu } from './AnchorMenu';
import { Annotation } from './Annotation';
import { GPTPopup } from './GPTPopup/GPTPopup';
import './PDFViewer.scss';
-import { GPTCallType, gptAPICall } from '../../apis/gpt/GPT';
import ReactLoading from 'react-loading';
import { Transform } from '../../util/Transform';
@@ -392,23 +391,6 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
}
};
- /**
- * Create a flashcard pile based on the selected text of a pdf.
- */
- gptPDFFlashcards = async () => {
- const queryText = this._selectionText;
- runInAction(() => (this._loading = true));
- try {
- const res = await gptAPICall(queryText, GPTCallType.FLASHCARD);
-
- AnchorMenu.Instance.transferToFlashcard(res || 'Something went wrong', NumCast(this._props.layoutDoc['x']), NumCast(this._props.layoutDoc['y']));
- this._selectionText = '';
- } catch (err) {
- console.error(err);
- }
- runInAction(() => (this._loading = false));
- };
-
@action
finishMarquee = (/* x?: number, y?: number */) => {
AnchorMenu.Instance.makeLabels = unimplementedFunction;
@@ -430,7 +412,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
if (sel) {
AnchorMenu.Instance.setSelectedText(sel.toString());
- AnchorMenu.Instance.setLocation(NumCast(this._props.layoutDoc['x']), NumCast(this._props.layoutDoc['y']));
+ AnchorMenu.Instance.setLocation(NumCast(this._props.layoutDoc.x), NumCast(this._props.layoutDoc.y));
}
if (sel?.type === 'Range') {
@@ -442,7 +424,6 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
GPTPopup.Instance.addDoc = this._props.sidebarAddDoc;
// allows for creating collection
AnchorMenu.Instance.addToCollection = this._props.DocumentView?.()._props.addDocument;
- AnchorMenu.Instance.gptFlashcards = this.gptPDFFlashcards;
AnchorMenu.Instance.makeLabels = unimplementedFunction;
AnchorMenu.Instance.AddDrawingAnnotation = this.addDrawingAnnotation;
};