aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSophie Zhang <sophie_zhang@brown.edu>2023-07-20 00:54:07 -0400
committerSophie Zhang <sophie_zhang@brown.edu>2023-07-20 00:54:07 -0400
commit078d595cb498592667a653a937b8ba25bcbf41bb (patch)
tree999f99e69d9122e4ce0f1f10bd7ba58782883d08
parent40784b7265851b27e043c07e5f9038a0b29af8b7 (diff)
refactoring gpt functionalities
-rw-r--r--src/client/views/MainView.tsx2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx2
-rw-r--r--src/client/views/pdf/AnchorMenu.tsx157
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.scss12
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx102
-rw-r--r--src/client/views/pdf/PDFViewer.tsx5
6 files changed, 130 insertions, 150 deletions
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index a129c35cf..f6829a4cb 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -67,6 +67,7 @@ import { PropertiesView } from './PropertiesView';
import { DashboardStyleProvider, DefaultStyleProvider } from './StyleProvider';
import { TopBar } from './topbar/TopBar';
import GenerativeFill from './nodes/generativeFill/GenerativeFill';
+import { GPTPopup } from './pdf/GPTPopup/GPTPopup';
const _global = (window /* browser */ || global) /* node */ as any;
@observer
@@ -1032,6 +1033,7 @@ export class MainView extends React.Component {
<InkTranscription />
{this.snapLines}
<LightboxView key="lightbox" PanelWidth={this._windowWidth} PanelHeight={this._windowHeight} maxBorder={[200, 50]} />
+ <GPTPopup key="gptpopup" />
<GenerativeFill imageEditorOpen={this.imageEditorOpen} imageEditorSource={this.imageEditorSource} imageRootDoc={this.imageRootDoc} addDoc={this.addDoc} />
{/* <NewLightboxView key="newLightbox" PanelWidth={this._windowWidth} PanelHeight={this._windowHeight} maxBorder={[200, 50]} /> */}
</div>
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 20a176c58..212d24165 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -909,7 +909,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
// breakupdictiation for reference
// prepareForTyping
// stored marks - userMark and timestamp, setStoredMarks
- //the._editorView.dispatch(state.tr.setSelection(updatted).insertText('\n, to))
+ // the._editorView.dispatch(state.tr.setSelection(updated).insertText('\n, to))
askGPT = action(async () => {
try {
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 07b2afd91..e6b9cb382 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -48,9 +48,6 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@observable public Status: 'marquee' | 'annotation' | '' = '';
// GPT additions
- @observable private GPTpopupText: string = '';
- @observable private loadingGPT: boolean = false;
- @observable private showGPTPopup: boolean = false;
@observable private GPTMode: GPTPopupMode = GPTPopupMode.SUMMARY;
@observable private selectedText: string = '';
@observable private editorView?: EditorView;
@@ -59,25 +56,11 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
private selectionRange: number[] | undefined;
@action
- setGPTPopupVis = (vis: boolean) => {
- this.showGPTPopup = vis;
- };
- @action
setGPTMode = (mode: GPTPopupMode) => {
this.GPTMode = mode;
};
@action
- setGPTPopupText = (txt: string) => {
- this.GPTpopupText = txt;
- };
-
- @action
- setLoading = (loading: boolean) => {
- this.loadingGPT = loading;
- };
-
- @action
setHighlightRange(r: number[] | undefined) {
this.highlightRange = r;
}
@@ -130,19 +113,12 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
componentDidMount() {
this._disposer2 = reaction(
() => this._opacity,
- opacity => {
- if (!opacity) {
- this.setGPTPopupVis(false);
- this.setGPTPopupText('');
- }
- },
+ opacity => {},
{ fireImmediately: true }
);
this._disposer = reaction(
() => SelectionManager.Views().slice(),
selected => {
- this.setGPTPopupVis(false);
- this.setGPTPopupText('');
AnchorMenu.Instance.fadeOut(true);
}
);
@@ -153,23 +129,22 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
* @param e pointer down event
*/
gptSummarize = async (e: React.PointerEvent) => {
+ GPTPopup.Instance.setVisible(true);
this.setHighlightRange(undefined);
- this.setGPTPopupVis(true);
this.setGPTMode(GPTPopupMode.SUMMARY);
- this.setLoading(true);
+ GPTPopup.Instance.setLoading(true);
try {
const res = await gptAPICall(this.selectedText, GPTCallType.SUMMARY);
if (res) {
- this.setGPTPopupText(res);
+ GPTPopup.Instance.setText(res);
} else {
- this.setGPTPopupText('Something went wrong.');
+ GPTPopup.Instance.setText('Something went wrong.');
}
} catch (err) {
console.error(err);
}
-
- this.setLoading(false);
+ GPTPopup.Instance.setLoading(false);
};
/**
@@ -184,9 +159,9 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
const fullText = state.doc.textBetween(0, this.editorView.state.doc.content.size, ' \n');
const selectedText = state.doc.textBetween(sel.from, sel.to);
- this.setGPTPopupVis(true);
+ GPTPopup.Instance.setVisible(true);
this.setGPTMode(GPTPopupMode.EDIT);
- this.setLoading(true);
+ GPTPopup.Instance.setLoading(true);
try {
let res = await gptAPICall(selectedText, GPTCallType.EDIT);
@@ -196,16 +171,16 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
const resultText = fullText.slice(0, sel.from - 1) + res + fullText.slice(sel.to - 1);
if (res) {
- this.setGPTPopupText(resultText);
+ GPTPopup.Instance.setText(resultText);
this.setHighlightRange([sel.from - 1, sel.from - 1 + res.length]);
} else {
- this.setGPTPopupText('Something went wrong.');
+ GPTPopup.Instance.setText('Something went wrong.');
}
} catch (err) {
console.error(err);
}
- this.setLoading(false);
+ GPTPopup.Instance.setLoading(false);
};
/**
@@ -253,21 +228,18 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
};
@computed get highlighter() {
- return <Group>
- <IconButton
- icon={<FontAwesomeIcon icon="highlighter" style={{ transition: 'transform 0.1s', transform: 'rotate(-45deg)' }} />}
- tooltip={'Click to Highlight'}
- onClick={this.highlightClicked}
- colorPicker={this.highlightColor}
- color={StrCast(Doc.UserDoc().userColor)}
- />
- <ColorPicker
- colorPickerType={'github'}
- selectedColor={this.highlightColor}
- setSelectedColor={color => this.changeHighlightColor(color)}
- size={Size.XSMALL}
- />
- </Group>
+ return (
+ <Group>
+ <IconButton
+ icon={<FontAwesomeIcon icon="highlighter" style={{ transition: 'transform 0.1s', transform: 'rotate(-45deg)' }} />}
+ tooltip={'Click to Highlight'}
+ onClick={this.highlightClicked}
+ colorPicker={this.highlightColor}
+ color={StrCast(Doc.UserDoc().userColor)}
+ />
+ <ColorPicker colorPickerType={'github'} selectedColor={this.highlightColor} setSelectedColor={color => this.changeHighlightColor(color)} size={Size.XSMALL} />
+ </Group>
+ );
}
@action changeHighlightColor = (color: string) => {
@@ -312,12 +284,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
this.Status === 'marquee' ? (
<>
{this.highlighter}
- <IconButton
- tooltip={'Drag to Place Annotation'}
- onPointerDown={this.pointerDown}
- icon={<FontAwesomeIcon icon="comment-alt"/>}
- color={StrCast(Doc.UserDoc().userColor)}
- />
+ <IconButton tooltip={'Drag to Place Annotation'} onPointerDown={this.pointerDown} icon={<FontAwesomeIcon icon="comment-alt" />} color={StrCast(Doc.UserDoc().userColor)} />
{/* GPT Summarize icon only shows up when text is highlighted, not on marquee selection*/}
{AnchorMenu.Instance.StartCropDrag === unimplementedFunction && this.canSummarize() && (
<Tooltip key="gpt" title={<div className="dash-tooltip">Summarize with AI</div>}>
@@ -326,7 +293,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
</button>
</Tooltip>
)}
- <GPTPopup
+ {/* <GPTPopup
key="gptpopup"
visible={this.showGPTPopup}
text={this.GPTpopupText}
@@ -336,68 +303,32 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
callEditApi={this.gptEdit}
replaceText={this.replaceText}
mode={this.GPTMode}
- />
+ /> */}
{AnchorMenu.Instance.OnAudio === unimplementedFunction ? null : (
- <IconButton
- tooltip={'Click to Record Annotation'}
- onPointerDown={this.audioDown}
- icon={<FontAwesomeIcon icon="microphone" />}
- color={StrCast(Doc.UserDoc().userColor)}
- />
- )}
- {this.canEdit() && (
- <IconButton
- tooltip={'AI edit suggestions'}
- onPointerDown={this.gptEdit}
- icon={<FontAwesomeIcon icon="pencil-alt" />}
- color={StrCast(Doc.UserDoc().userColor)}
- />
+ <IconButton tooltip={'Click to Record Annotation'} onPointerDown={this.audioDown} icon={<FontAwesomeIcon icon="microphone" />} color={StrCast(Doc.UserDoc().userColor)} />
)}
- <Popup
- tooltip='Find document to link to selected text'
- type={Type.PRIM}
- icon={<FontAwesomeIcon icon={'search'} />}
- popup={<LinkPopup key="popup" linkCreateAnchor={this.onMakeAnchor} />}
- color={StrCast(Doc.UserDoc().userColor)}
- />
+ {this.canEdit() && <IconButton tooltip={'AI edit suggestions'} onPointerDown={this.gptEdit} icon={<FontAwesomeIcon icon="pencil-alt" />} color={StrCast(Doc.UserDoc().userColor)} />}
+ <Popup tooltip="Find document to link to selected text" type={Type.PRIM} icon={<FontAwesomeIcon icon={'search'} />} popup={<LinkPopup key="popup" linkCreateAnchor={this.onMakeAnchor} />} color={StrCast(Doc.UserDoc().userColor)} />
{AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? null : (
- <IconButton
- tooltip={'Click/Drag to create cropped image'}
- onPointerDown={this.cropDown}
- icon={<FontAwesomeIcon icon="image"/>}
- color={StrCast(Doc.UserDoc().userColor)}
- />
+ <IconButton tooltip={'Click/Drag to create cropped image'} onPointerDown={this.cropDown} icon={<FontAwesomeIcon icon="image" />} color={StrCast(Doc.UserDoc().userColor)} />
)}
</>
) : (
<>
- {this.Delete !== returnFalse && <IconButton
- tooltip={'Remove Link Anchor'}
- onPointerDown={this.Delete}
- icon={<FontAwesomeIcon icon="trash-alt" />}
- color={StrCast(Doc.UserDoc().userColor)}
- />}
- {this.PinToPres !== returnFalse && <IconButton
- tooltip={'Pin to Presentation'}
- onPointerDown={this.PinToPres}
- icon={<FontAwesomeIcon icon="map-pin" />}
- color={StrCast(Doc.UserDoc().userColor)}
- />}
- {this.ShowTargetTrail !== returnFalse && <IconButton
- tooltip={'Show Linked Trail'}
- onPointerDown={this.ShowTargetTrail}
- icon={<FontAwesomeIcon icon="taxi" />}
- color={StrCast(Doc.UserDoc().userColor)}
- />}
- {this.IsTargetToggler !== returnFalse && <Toggle
- tooltip={'Make target visibility toggle on click'}
- type={Type.PRIM}
- toggleType={ToggleType.BUTTON}
- toggleStatus={this.IsTargetToggler()}
- onClick={this.MakeTargetToggle}
- icon={<FontAwesomeIcon icon="thumbtack" />}
- color={StrCast(Doc.UserDoc().userColor)}
- />}
+ {this.Delete !== returnFalse && <IconButton tooltip={'Remove Link Anchor'} onPointerDown={this.Delete} icon={<FontAwesomeIcon icon="trash-alt" />} color={StrCast(Doc.UserDoc().userColor)} />}
+ {this.PinToPres !== returnFalse && <IconButton tooltip={'Pin to Presentation'} onPointerDown={this.PinToPres} icon={<FontAwesomeIcon icon="map-pin" />} color={StrCast(Doc.UserDoc().userColor)} />}
+ {this.ShowTargetTrail !== returnFalse && <IconButton tooltip={'Show Linked Trail'} onPointerDown={this.ShowTargetTrail} icon={<FontAwesomeIcon icon="taxi" />} color={StrCast(Doc.UserDoc().userColor)} />}
+ {this.IsTargetToggler !== returnFalse && (
+ <Toggle
+ tooltip={'Make target visibility toggle on click'}
+ type={Type.PRIM}
+ toggleType={ToggleType.BUTTON}
+ toggleStatus={this.IsTargetToggler()}
+ onClick={this.MakeTargetToggle}
+ icon={<FontAwesomeIcon icon="thumbtack" />}
+ color={StrCast(Doc.UserDoc().userColor)}
+ />
+ )}
</>
);
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.scss b/src/client/views/pdf/GPTPopup/GPTPopup.scss
index 44413ede7..2f0ff83e2 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.scss
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.scss
@@ -6,12 +6,6 @@ $button: #5b97ff;
$highlightedText: #82e0ff;
.summary-box {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- background-color: #ffffff;
- box-shadow: 0 2px 5px #7474748d;
- color: $textgrey;
position: fixed;
bottom: 10px;
right: 10px;
@@ -21,6 +15,12 @@ $highlightedText: #82e0ff;
padding: 15px;
padding-bottom: 0;
z-index: 999;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ background-color: #ffffff;
+ box-shadow: 0 2px 5px #7474748d;
+ color: $textgrey;
.summary-heading {
display: flex;
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index 8bd060d4f..9f28cb5d1 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -5,56 +5,96 @@ import { observer } from 'mobx-react';
import ReactLoading from 'react-loading';
import Typist from 'react-typist';
import { Doc } from '../../../../fields/Doc';
-import { Docs } from '../../../documents/Documents';
+import { DocUtils, Docs } from '../../../documents/Documents';
import './GPTPopup.scss';
+import { Button, IconButton } from 'browndash-components';
+import { StrCast } from '../../../../fields/Types';
export enum GPTPopupMode {
SUMMARY,
EDIT,
}
-interface GPTPopupProps {
- visible: boolean;
- text: string;
- loading: boolean;
- mode: GPTPopupMode;
- callSummaryApi: (e: React.PointerEvent) => Promise<void>;
- callEditApi: (e: React.PointerEvent) => Promise<void>;
- replaceText: (replacement: string) => void;
- highlightRange?: number[];
-}
+interface GPTPopupProps {}
@observer
export class GPTPopup extends React.Component<GPTPopupProps> {
static Instance: GPTPopup;
@observable
- private done: boolean = false;
+ public visible: boolean = false;
+ @action
+ public setVisible = (vis: boolean) => {
+ this.visible = vis;
+ };
@observable
- private sidebarId: string = '';
+ public loading: boolean = false;
+ @action
+ public setLoading = (loading: boolean) => {
+ this.loading = loading;
+ };
+ @observable
+ public text: string = '';
+ @action
+ public setText = (text: string) => {
+ this.text = text;
+ };
+ @observable
+ public mode: GPTPopupMode = GPTPopupMode.SUMMARY;
+ @action
+ public setMode = (mode: GPTPopupMode) => {
+ this.mode = mode;
+ };
+ @observable
+ public highlightRange: number[] = [];
+ @action callSummaryApi = () => {};
+ @action callEditApi = () => {};
+ @action replaceText = (replacement: string) => {};
+
+ @observable
+ private done: boolean = false;
@action
public setDone = (done: boolean) => {
this.done = done;
};
+ @observable
+ private sidebarId: string = '';
@action
public setSidebarId = (id: string) => {
this.sidebarId = id;
};
+ // reference
+ // if (focusNode) {
+ // const anchor = srcWeb?.ComponentView?.getAnchor?.(true);
+ // anchor && DocUtils.MakeLink(htmlDoc, anchor, {});
+ // }
+ @observable
+ private pdfAnchor: Doc | undefined;
+ @action
+ public setPdfAnchor = (anchor: Doc) => {
+ this.pdfAnchor = anchor;
+ };
+
public addDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean = () => false;
/**
* Transfers the summarization text to a sidebar annotation text document.
*/
private transferToText = () => {
- const newDoc = Docs.Create.TextDocument(this.props.text.trim(), {
+ const newDoc = Docs.Create.TextDocument(this.text.trim(), {
_width: 200,
_height: 50,
_layout_fitWidth: true,
_layout_autoHeight: true,
});
this.addDoc(newDoc, this.sidebarId);
+ if (this.pdfAnchor) {
+ DocUtils.MakeLink(newDoc, this.pdfAnchor, {
+ link_relationship: 'GPT Summary',
+ });
+ }
};
constructor(props: GPTPopupProps) {
@@ -63,7 +103,7 @@ export class GPTPopup extends React.Component<GPTPopupProps> {
}
componentDidUpdate = () => {
- if (this.props.loading) {
+ if (this.loading) {
this.setDone(false);
}
};
@@ -73,10 +113,10 @@ export class GPTPopup extends React.Component<GPTPopupProps> {
<div>
{this.heading('SUMMARY')}
<div className="content-wrapper">
- {!this.props.loading &&
+ {!this.loading &&
(!this.done ? (
<Typist
- key={this.props.text}
+ key={this.text}
avgTypingDelay={15}
cursor={{ hideWhenDone: true }}
onTypingDone={() => {
@@ -84,18 +124,18 @@ export class GPTPopup extends React.Component<GPTPopupProps> {
this.setDone(true);
}, 500);
}}>
- {this.props.text}
+ {this.text}
</Typist>
) : (
- this.props.text
+ this.text
))}
</div>
</div>
- {!this.props.loading && (
+ {!this.loading && (
<div className="btns-wrapper">
{this.done ? (
<>
- <button className="icon-btn" onPointerDown={e => this.props.callSummaryApi(e)}>
+ {/* <button className="icon-btn" onClick={this.callSummaryApi}>
<FontAwesomeIcon icon="redo-alt" size="lg" />
</button>
<button
@@ -104,7 +144,9 @@ export class GPTPopup extends React.Component<GPTPopupProps> {
this.transferToText();
}}>
Transfer to Text
- </button>
+ </button> */}
+ <IconButton onClick={this.callSummaryApi} icon={<FontAwesomeIcon icon="redo-alt" size="lg" />} color={StrCast(Doc.UserDoc().userVariantColor)} />
+ <Button text="Transfer To Text" onClick={this.transferToText} color={StrCast(Doc.UserDoc().userVariantColor)} />
</>
) : (
<div className="summarizing">
@@ -125,7 +167,7 @@ export class GPTPopup extends React.Component<GPTPopupProps> {
);
editBox = () => {
- const hr = this.props.highlightRange;
+ const hr = this.highlightRange;
return (
<>
<div>
@@ -133,22 +175,22 @@ export class GPTPopup extends React.Component<GPTPopupProps> {
<div className="content-wrapper">
{hr && (
<div>
- {this.props.text.slice(0, hr[0])} <span className="highlighted-text">{this.props.text.slice(hr[0], hr[1])}</span> {this.props.text.slice(hr[1])}
+ {this.text.slice(0, hr[0])} <span className="highlighted-text">{this.text.slice(hr[0], hr[1])}</span> {this.text.slice(hr[1])}
</div>
)}
</div>
</div>
- {hr && !this.props.loading && (
+ {hr && !this.loading && (
<>
<div className="btns-wrapper">
<>
- <button className="icon-btn" onPointerDown={e => this.props.callEditApi(e)}>
+ <button className="icon-btn" onPointerDown={this.callEditApi}>
<FontAwesomeIcon icon="redo-alt" size="lg" />
</button>
<button
className="text-btn"
onClick={e => {
- this.props.replaceText(this.props.text);
+ this.replaceText(this.text);
}}>
Replace Text
</button>
@@ -174,14 +216,14 @@ export class GPTPopup extends React.Component<GPTPopupProps> {
heading = (headingText: string) => (
<div className="summary-heading">
<label className="summary-text">{headingText}</label>
- {this.props.loading && <ReactLoading type="spin" color="#bcbcbc" width={14} height={14} />}
+ {this.loading && <ReactLoading type="spin" color="#bcbcbc" width={14} height={14} />}
</div>
);
render() {
return (
- <div className="summary-box" style={{ display: this.props.visible ? 'flex' : 'none' }}>
- {this.props.mode === GPTPopupMode.SUMMARY ? this.summaryBox() : this.editBox()}
+ <div className="summary-box" style={{ display: this.visible ? 'flex' : 'none' }}>
+ {this.mode === GPTPopupMode.SUMMARY ? this.summaryBox() : this.editBox()}
</div>
);
}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 0fd93868a..4fc31ffe3 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -423,6 +423,11 @@ export class PDFViewer extends React.Component<IViewerProps> {
// Changing which document to add the annotation to (the currently selected PDF)
GPTPopup.Instance.setSidebarId('data_sidebar');
+ const anchor = this._getAnchor(undefined, false);
+ if (anchor) {
+ console.log(anchor);
+ GPTPopup.Instance.setPdfAnchor(anchor);
+ }
GPTPopup.Instance.addDoc = this.props.sidebarAddDoc;
};